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

Tzafrir Cohen tzafrir-guest at costa.debian.org
Sat Jul 15 23:02:31 UTC 2006


Author: tzafrir-guest
Date: 2006-07-15 23:02:30 +0000 (Sat, 15 Jul 2006)
New Revision: 2068

Removed:
   zaptel/trunk/debian/patches/xpp_xorcom_debian.dpatch
Modified:
   zaptel/trunk/debian/changelog
   zaptel/trunk/debian/control
   zaptel/trunk/debian/copyright
   zaptel/trunk/debian/patches/00list
   zaptel/trunk/debian/patches/Makefile_bristuff.dpatch
   zaptel/trunk/debian/patches/Makefile_uname.dpatch
Log:
* New upstream release
* xpp_xorcom_debian.dpatch obsolete by new version
* Makefile_uname.dpatch: Updated. Note: watch for PWD issues.
* Makefile_bristuff.dpatch: updated to reflect Makefile change.


Modified: zaptel/trunk/debian/changelog
===================================================================
--- zaptel/trunk/debian/changelog	2006-07-15 22:22:19 UTC (rev 2067)
+++ zaptel/trunk/debian/changelog	2006-07-15 23:02:30 UTC (rev 2068)
@@ -1,6 +1,7 @@
-zaptel (1:1.2.6-3) UNRELEASED; urgency=low
+zaptel (1:1.2.7-1) UNRELEASED; urgency=low
 
   * NOT RELEASED YET
+  * New upstream release
 
   [ Kilian Krause ]
   * Add vzaphfc driver (enhanced zaphfc) by Jens Wilke.
@@ -11,16 +12,7 @@
   * Removing some unneeded dirs from zaptel-source
   * debian/patches/Makefile_kbuild: a small part of the original one.
     Fixes building on Sarge
-  * xpp revision r1608 (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.
+  * genzaptelconf is now in zaptel
   * xpp/utils/Makefile has a decent install target
   * debian/rules: Use CURDIR
   * debian/modulestest: Building modules for -3 kernels
@@ -30,10 +22,12 @@
   * debian/control: require libusb-dev for building xpp firmware loader.
   * debian/control: Recommend package xpp-firmware (should be added to
     non-free)
-  * bristuff_local_zaptelh.dpatch: Build bristuff modules with correct 
+  * bristuff_local_zaptelh.dpatch: Build bristuff modules with correct
     zaptel.conf (in Sarge)
+  * Makefile_uname.dpatch: Updated. Note: watch for PWD issues.
+  * Makefile_bristuff.dpatch: updated to reflect Makefile change.
 
- -- Kilian Krause <kilian at debian.org>  Sat, 17 Jun 2006 16:05:32 +0200
+ -- Tzafrir Cohen <tzafrir.cohen at xorcom.com>  Sat, 15 Jul 2006 01:59:23 +0300
 
 zaptel (1:1.2.6-2) unstable; urgency=high
 

Modified: zaptel/trunk/debian/control
===================================================================
--- zaptel/trunk/debian/control	2006-07-15 22:22:19 UTC (rev 2067)
+++ zaptel/trunk/debian/control	2006-07-15 23:02:30 UTC (rev 2068)
@@ -12,7 +12,6 @@
 # Xorcom packages depend on xpp-firmware. Debian zaptel will probably 
 # just recommend it.
 Depends: ${shlibs:Depends}, procps, fxload
-Recommends: xpp-firmware
 Description: zapata telephony utilities
  Userspace utilities for configuring the Zapata telephony kernel driver, 
  which supports various telephony hardware, such as Wildcard series of

Modified: zaptel/trunk/debian/copyright
===================================================================
--- zaptel/trunk/debian/copyright	2006-07-15 22:22:19 UTC (rev 2067)
+++ zaptel/trunk/debian/copyright	2006-07-15 23:02:30 UTC (rev 2068)
@@ -54,6 +54,6 @@
 *
 * Modify from wctdm.c by MiaoLin<miaolin at openvox.com.cn>
 
-opvxa1200.c is not availble for download from the author's site yet 
+opvxa1200.c is not available for download from the author's site yet 
 (it is distributed with the CD that is included with the product).
 Author promisses to set up a public mirror soon.

Modified: zaptel/trunk/debian/patches/00list
===================================================================
--- zaptel/trunk/debian/patches/00list	2006-07-15 22:22:19 UTC (rev 2067)
+++ zaptel/trunk/debian/patches/00list	2006-07-15 23:02:30 UTC (rev 2068)
@@ -8,6 +8,5 @@
 # touches the Makefile as well:
 echocan_env
 ukcid
-xpp_xorcom_debian
 bristuff
 bristuff_local_zaptelh

Modified: zaptel/trunk/debian/patches/Makefile_bristuff.dpatch
===================================================================
--- zaptel/trunk/debian/patches/Makefile_bristuff.dpatch	2006-07-15 22:22:19 UTC (rev 2067)
+++ zaptel/trunk/debian/patches/Makefile_bristuff.dpatch	2006-07-15 23:02:30 UTC (rev 2068)
@@ -56,6 +56,6 @@
 +	cp $^ $@
 +
 +
- $(MODULESO): %.o: %.c zaptel.h
- 	$(HOSTCC) $(KFLAGS) -o $@ -c $<
+ $(filter-out wct4xxp.o,$(MODULESO)) wct4xxp_base.o: %.o: %.c zaptel.h
+ 	$(CC) $(KFLAGS) -o $@ -c $<
  

Modified: zaptel/trunk/debian/patches/Makefile_uname.dpatch
===================================================================
--- zaptel/trunk/debian/patches/Makefile_uname.dpatch	2006-07-15 22:22:19 UTC (rev 2067)
+++ zaptel/trunk/debian/patches/Makefile_uname.dpatch	2006-07-15 23:02:30 UTC (rev 2068)
@@ -12,9 +12,9 @@
 --- zaptel-1.2.0-rc1~/Makefile	2005-11-09 21:22:00.000000000 +0000
 +++ zaptel-1.2.0-rc1/Makefile	2005-11-09 21:24:20.000000000 +0000
 @@ -7,6 +7,11 @@
- BASEADDR=0xd0000
- 
- HOSTCC=gcc
+ ifeq ($(PWD),)
+ PWD:=$(shell pwd)
+ endif
 +ifeq ($(DEB_HOST_GNU_TYPE),)
 +UNAME_M:=$(shell uname -m)
 +else
@@ -30,7 +30,7 @@
 +KVERS_MAJ:=$(shell echo $(KVERS) | cut -d. -f1-2)
  KINCLUDES:=$(KSRC)/include
  
- CFLAGS+=-I. -O4 -g -Wall -DBUILDING_TONEZONE #-DTONEZONE_DRIVER
+ CFLAGS+=-I. -Iinclude -O4 -g -Wall -DBUILDING_TONEZONE #-DTONEZONE_DRIVER
 -CFLAGS_PPC:=$(shell if uname -m | grep -q ppc; then echo "-fsigned-char"; fi)
 -CFLAGS_X86-64:=$(shell if uname -m | grep -q x86_64; then echo "-m64"; fi)
 +ifneq (,$(findstring ppc,$(UNAME_M)))

Deleted: zaptel/trunk/debian/patches/xpp_xorcom_debian.dpatch
===================================================================
--- zaptel/trunk/debian/patches/xpp_xorcom_debian.dpatch	2006-07-15 22:22:19 UTC (rev 2067)
+++ zaptel/trunk/debian/patches/xpp_xorcom_debian.dpatch	2006-07-15 23:02:30 UTC (rev 2068)
@@ -1,13973 +0,0 @@
-#! /bin/sh /usr/share/dpatch/dpatch-run
-## 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 r1608 (branches/RELEASE-1.1.0)
-
-## DP: This version omites the .version file and the firmware files.
-
- at DPATCH@
-diff -uNr -x .svn -x debian zaptel-1.2.6/.version zaptel-xpp-LJNBCn_dist/.version
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/card_fxo.c zaptel-xpp-LJNBCn_dist/xpp/card_fxo.c
---- zaptel-1.2.6/xpp/card_fxo.c	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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
-+ *
-+ * All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/fs.h>
-+#include <linux/delay.h>
-+#include <version.h>		/* For zaptel version */
-+#include "xpd.h"
-+#include "xproto.h"
-+#include "xpp_zap.h"
-+#include "card_fxo.h"
-+#include "zap_debug.h"
-+
-+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,
-+};
-+
-+#define	NUM_LEDS		1
-+#define	DELAY_UNTIL_DIALTONE	3000
-+
-+/*---------------- FXO Protocol Commands ----------------------------------*/
-+
-+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	PROC_DAA_FNAME		"slics"
-+#define	PROC_FXO_INFO_FNAME	"fxo_info"
-+
-+struct FXO_priv_data {
-+	struct proc_dir_entry		*xpd_slic;
-+	struct proc_dir_entry		*fxo_info;
-+	slic_reply_t			requested_reply;
-+	slic_reply_t			last_reply;
-+	xpp_line_t			battery;
-+	xpp_line_t			ledstate[NUM_LEDS];	/* 0 - OFF, 1 - ON */
-+	int				blinking[NUM_LEDS][CHANNELS_PERXPD];
-+};
-+
-+/*---------------- FXO: Static functions ----------------------------------*/
-+
-+#define	IS_BLINKING(priv,pos,color)	((priv)->blinking[color][pos] != 0)
-+#define	DO_BLINK(priv,pos,color,val)	((priv)->blinking[color][pos] = (val))
-+
-+/*
-+ * LED control is done via DAA register 0x20
-+ */
-+static int do_led(xpd_t *xpd, lineno_t pos, byte which, bool on)
-+{
-+	int			ret = 0;
-+	xpacket_t		*pack;
-+	slic_cmd_t		*sc;
-+	int			len;
-+	struct FXO_priv_data	*priv;
-+	xpp_line_t		lines;
-+	xbus_t			*xbus;
-+
-+	BUG_ON(!xpd);
-+	xbus = xpd->xbus;
-+	priv = xpd->priv;
-+	which = which % NUM_LEDS;
-+	if(IS_SET(xpd->digital_outputs, pos) || IS_SET(xpd->digital_inputs, pos))
-+		goto out;
-+	if(pos == ALL_LINES) {
-+		lines = ~0;
-+		priv->ledstate[which] = (on) ? ~0 : 0;
-+	} else {
-+		lines = BIT(pos);
-+		if(on) {
-+			BIT_SET(priv->ledstate[which], pos);
-+		} else {
-+			BIT_CLR(priv->ledstate[which], pos);
-+		}
-+	}
-+	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);
-+	sc = &RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd);
-+	len = slic_cmd_direct_write(sc, lines, 0x20, on);
-+	// DBG("LED pack: line=%d %s\n", i, (on)?"on":"off");
-+	pack->datalen = len;
-+	packet_send(xbus, pack);
-+out:
-+	return ret;
-+}
-+
-+static void handle_fxo_leds(xpd_t *xpd)
-+{
-+	int		i;
-+	unsigned long	flags;
-+	const enum fxo_leds	color = LED_GREEN;
-+	unsigned int	timer_count;
-+	struct FXO_priv_data	*priv;
-+
-+	BUG_ON(!xpd);
-+	spin_lock_irqsave(&xpd->lock, flags);
-+	priv = xpd->priv;
-+	timer_count = xpd->timer_count;
-+	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)) {
-+			// led state is toggled
-+			if((timer_count % LED_BLINK_PERIOD) == 0) {
-+				DBG("%s/%s/%d: led_state=%s\n", xpd->xbus->busname, xpd->xpdname, i,
-+						(IS_SET(priv->ledstate[color], i))?"ON":"OFF");
-+				if(!IS_SET(priv->ledstate[color], i)) {
-+					do_led(xpd, i, color, 1);
-+				} else {
-+					do_led(xpd, i, color, 0);
-+				}
-+			}
-+		}
-+	}
-+	spin_unlock_irqrestore(&xpd->lock, flags);
-+}
-+
-+static void do_sethook(xpd_t *xpd, int pos, bool offhook)
-+{
-+	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);
-+	if(offhook) {
-+		BIT_SET(xpd->hookstate, pos);
-+	} else {
-+		BIT_CLR(xpd->hookstate, pos);
-+		xpd->delay_until_dialtone[pos] = 0;
-+	}
-+	spin_unlock_irqrestore(&xpd->lock, flags);
-+	if(offhook)
-+		wake_up_interruptible(&xpd->txstateq[pos]);
-+}
-+
-+/*---------------- FXO: Methods -------------------------------------------*/
-+
-+static xpd_t *FXO_card_new(xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, byte revision)
-+{
-+	xpd_t		*xpd = NULL;
-+	int		channels = min(8, CHANNELS_PERXPD);
-+
-+	xpd = xpd_alloc(sizeof(struct FXO_priv_data), xbus, xpd_num, proto_table, channels, revision);
-+	if(!xpd)
-+		return NULL;
-+	xpd->direction = TO_PSTN;
-+	xpd->revision = revision;
-+	return xpd;
-+}
-+
-+static void clean_proc(xbus_t *xbus, xpd_t *xpd)
-+{
-+	struct FXO_priv_data	*priv;
-+
-+	BUG_ON(!xpd);
-+	priv = xpd->priv;
-+	DBG("%s/%s\n", xbus->busname, xpd->xpdname);
-+#ifdef	CONFIG_PROC_FS
-+	if(priv->xpd_slic) {
-+		DBG("Removing xpd DAA file %s/%s\n", xbus->busname, xpd->xpdname);
-+		remove_proc_entry(PROC_DAA_FNAME, xpd->proc_xpd_dir);
-+	}
-+	if(priv->fxo_info) {
-+		DBG("Removing xpd FXO_INFO file %s/%s\n", xbus->busname, xpd->xpdname);
-+		remove_proc_entry(PROC_FXO_INFO_FNAME, xpd->proc_xpd_dir);
-+	}
-+#endif
-+}
-+
-+static int FXO_card_init(xbus_t *xbus, xpd_t *xpd)
-+{
-+	struct FXO_priv_data	*priv;
-+	int			ret = 0;
-+	int			i;
-+
-+	BUG_ON(!xpd);
-+	priv = xpd->priv;
-+#ifdef	CONFIG_PROC_FS
-+	DBG("Creating FXO_INFO file for %s/%s\n", xbus->busname, xpd->xpdname);
-+	priv->fxo_info = create_proc_read_entry(PROC_FXO_INFO_FNAME, 0444, xpd->proc_xpd_dir, proc_fxo_info_read, xpd);
-+	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 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);
-+		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
-+	ret = run_initialize_registers(xpd);
-+	if(ret < 0)
-+		goto err;
-+	// Hanghup all lines
-+	for_each_line(xpd, i) {
-+		init_waitqueue_head(&xpd->txstateq[i]);
-+		do_sethook(xpd, i, 0);
-+	}
-+	DBG("done: %s/%s\n", xbus->busname, xpd->xpdname);
-+	return 0;
-+err:
-+	clean_proc(xbus, xpd);
-+	ERR("%s/%s: Failed initializing registers (%d)\n", xbus->busname, xpd->xpdname, ret);
-+	return ret;
-+}
-+
-+static int FXO_card_remove(xbus_t *xbus, xpd_t *xpd)
-+{
-+	struct FXO_priv_data	*priv;
-+
-+	BUG_ON(!xpd);
-+	priv = xpd->priv;
-+	DBG("%s/%s\n", xbus->busname, xpd->xpdname);
-+	clean_proc(xbus, xpd);
-+	return 0;
-+}
-+
-+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);
-+	xbus = xpd->xbus;
-+	BUG_ON(!xbus);
-+	priv = xpd->priv;
-+	BUG_ON(!priv);
-+	DBG("%s/%s (%d)\n", xbus->busname, xpd->xpdname, on);
-+	for_each_line(xpd, i) {
-+		do_led(xpd, i, LED_GREEN, LED_OFF);
-+		mdelay(50);
-+	}
-+	return 0;
-+}
-+
-+#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 */
-+	switch(txsig) {
-+		case ZT_TXSIG_START:
-+			break;
-+		case ZT_TXSIG_OFFHOOK:
-+			do_sethook(xpd, pos, 1);
-+			break;
-+		case ZT_TXSIG_ONHOOK:
-+			do_sethook(xpd, pos, 0);
-+			break;
-+		default:
-+			NOTICE("Can't set tx state to %s (%d)\n", txsig2str(txsig), txsig);
-+			return -EINVAL;
-+	}
-+	return 0;
-+}
-+
-+#else
-+int FXO_card_sethook(xbus_t *xbus, xpd_t *xpd, int pos, int hookstate)
-+{
-+	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.  */
-+		case ZT_ONHOOK:
-+			do_sethook(xpd, pos, 0);
-+			break;
-+		case ZT_START:
-+			DBG("%s/%s/%d: fall through ZT_OFFHOOK\n", xbus->busname, xpd->xpdname, pos);
-+			xpd->delay_until_dialtone[pos] = DELAY_UNTIL_DIALTONE;
-+			// Fall through
-+		case ZT_OFFHOOK:
-+			do_sethook(xpd, pos, 1);
-+			wait_event_interruptible(xpd->txstateq[pos], xpd->delay_until_dialtone[pos] <= 0);
-+			break;
-+		case ZT_WINK:
-+			WARN("No code yet\n");
-+			break;
-+		case ZT_FLASH:
-+			WARN("No code yet\n");
-+			break;
-+		case ZT_RING:
-+			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");
-+			break;
-+	}
-+	return ret;
-+}
-+#endif
-+
-+static void poll_battery(xbus_t *xbus, xpd_t *xpd)
-+{
-+	int	i;
-+
-+	for_each_line(xpd, i) {
-+		CALL_PROTO(FXO, DAA_QUERY, xbus, xpd, i, DAA_VBAT_REGISTER);
-+	}
-+}
-+
-+
-+static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd)
-+{
-+	static unsigned		rate_limit = 0;
-+	struct FXO_priv_data	*priv;
-+
-+	BUG_ON(!xpd);
-+	priv = xpd->priv;
-+	BUG_ON(!priv);
-+	rate_limit++;
-+	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 -------------------------------------*/
-+
-+static /* 0x0F */ HOSTCMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on)
-+{
-+	unsigned long		flags;
-+	int	ret = 0;
-+	int	i;
-+
-+	BUG_ON(!xbus);
-+	BUG_ON(!xpd);
-+	if(!lines) {
-+		return 0;
-+	}
-+	DBG("Channel Activation: 0x%4X %s\n", lines, (on) ? "on" : "off");
-+	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(20);
-+		}
-+		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(20);
-+		}
-+	}
-+	return ret;
-+}
-+
-+static /* 0x0F */ HOSTCMD(FXO, CHAN_CID, int pos)
-+{
-+	int		ret = 0;
-+	xpp_line_t	lines = BIT(pos);
-+
-+	BUG_ON(!xbus);
-+	BUG_ON(!xpd);
-+	if(!lines) {
-+		return 0;
-+	}
-+	DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, pos);
-+	return ret;
-+}
-+
-+
-+static /* 0x0F */ HOSTCMD(FXO, RING, int pos, bool on)
-+{
-+	int		ret = 0;
-+	xpacket_t	*pack;
-+	slic_cmd_t	*sc;
-+	xpp_line_t	mask = BIT(pos);
-+	int		len;
-+
-+	BUG_ON(!xbus);
-+	BUG_ON(!xpd);
-+	if(!mask) {
-+		return 0;
-+	}
-+	DBG("%s/%s/%d %s\n", xpd->xbus->busname, xpd->xpdname, pos, (on) ? "on" : "off");
-+	XPACKET_NEW(pack, xbus, FXO, DAA_WRITE, xpd->id);
-+	sc = &RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd);
-+	len = slic_cmd_direct_write(sc, mask, 0x40, (on)?0x04:0x01);
-+	pack->datalen = len;
-+
-+	packet_send(xbus, pack);
-+	return ret;
-+}
-+
-+static /* 0x0F */ HOSTCMD(FXO, SETHOOK, int pos, bool offhook)
-+{
-+	int		ret = 0;
-+	xpacket_t	*pack;
-+	slic_cmd_t	*sc;
-+	int		len;
-+	unsigned long	flags;
-+	bool		value;
-+
-+	BUG_ON(!xbus);
-+	BUG_ON(!xpd);
-+	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);
-+	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);
-+	spin_unlock_irqrestore(&xpd->lock, flags);
-+	return ret;
-+}
-+
-+static /* 0x0F */ HOSTCMD(FXO, RELAY_OUT, byte which, bool on)
-+{
-+	return -ENOSYS;
-+}
-+
-+static /* 0x0F */ HOSTCMD(FXO, DAA_QUERY, int pos, byte reg_num)
-+{
-+	int	ret = 0;
-+	xpacket_t	*pack;
-+	slic_cmd_t	*sc;
-+	int		len;
-+
-+	BUG_ON(!xbus);
-+	BUG_ON(!xpd);
-+	// DBG("\n");
-+	XPACKET_NEW(pack, xbus, FXO, DAA_WRITE, xpd->id);
-+	sc = &RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd);
-+	len = slic_cmd_direct_read(sc, BIT(pos), reg_num);
-+
-+	pack->datalen = len;
-+
-+	packet_send(xbus, pack);
-+	return ret;
-+}
-+
-+/*---------------- FXO: Astribank Reply Handlers --------------------------*/
-+
-+HANDLER_DEF(FXO, SIG_CHANGED)
-+{
-+	xpp_line_t	sig_status = RPACKET_FIELD(pack, FXO, SIG_CHANGED, sig_status);
-+	xpp_line_t	sig_toggles = RPACKET_FIELD(pack, FXO, SIG_CHANGED, sig_toggles);
-+	unsigned long	flags;
-+	int		i;
-+
-+	if(!xpd) {
-+		NOTICE("%s: received %s for non-existing xpd: %d\n",
-+				__FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
-+		return -EPROTO;
-+	}
-+	DBG("%s/%s: (PSTN) sig_toggles=0x%04X sig_status=0x%04X\n", xpd->xbus->busname, xpd->xpdname, sig_toggles, sig_status);
-+	spin_lock_irqsave(&xpd->lock, flags);
-+	for_each_line(xpd, i) {
-+		if(IS_SET(sig_status, i)) {
-+			xpd->ringing[i] = 1;
-+		} else {
-+			xpd->ringing[i] = 0;
-+		}
-+	}
-+	spin_unlock_irqrestore(&xpd->lock, flags);
-+	return 0;
-+}
-+
-+HANDLER_DEF(FXO, DAA_REPLY)
-+{
-+	slic_reply_t		*info = &RPACKET_FIELD(pack, FXO, DAA_REPLY, info);
-+	xpp_line_t		lines = RPACKET_FIELD(pack, FXO, DAA_REPLY, lines);
-+	unsigned long		flags;
-+	struct FXO_priv_data	*priv;
-+
-+	if(!xpd) {
-+		NOTICE("%s: received %s for non-existing xpd: %d\n",
-+				__FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
-+		return -EPROTO;
-+	}
-+	spin_lock_irqsave(&xpd->lock, flags);
-+	priv = xpd->priv;
-+	BUG_ON(!priv);
-+	if(!info->indirect && info->reg_num == DAA_VBAT_REGISTER) {
-+		xpp_line_t	last_batt_on = priv->battery;
-+		xpp_line_t	changed_lines;
-+		int		i;
-+
-+		if(abs(info->data_low) < BAT_THRESHOLD) {
-+			priv->battery &= ~lines;
-+			// DBG("%s/%s: BATTERY OFF (%04X) = %d\n", xpd->xbus->busname, xpd->xpdname, lines, info->data_low);
-+		} else {
-+			priv->battery |= lines;
-+			// 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)) {
-+				update_line_status(xpd, i, IS_SET(priv->battery, i));
-+			}
-+		}
-+	}
-+#if 0
-+	DBG("DAA_REPLY: xpd #%d %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
-+			xpd->id, (info->indirect)?"I":"D",
-+			info->reg_num, info->data_low, info->data_high);
-+#endif
-+
-+	/* Update /proc info only if reply relate to the last slic read request */
-+	if(priv->requested_reply.indirect == info->indirect &&
-+			priv->requested_reply.reg_num == info->reg_num) {
-+		priv->last_reply = *info;
-+	}
-+	spin_unlock_irqrestore(&xpd->lock, flags);
-+	return 0;
-+}
-+
-+
-+xproto_table_t PROTO_TABLE(FXO) = {
-+	.owner = THIS_MODULE,
-+	.entries = {
-+		/*	Card	Opcode		*/
-+		XENTRY(	FXO,	SIG_CHANGED	),
-+		XENTRY(	FXO,	DAA_REPLY	),
-+	},
-+	.name = "FXO",
-+	.type = XPD_TYPE_FXO,
-+	.xops = {
-+		.card_new	= FXO_card_new,
-+		.card_init	= FXO_card_init,
-+		.card_remove	= FXO_card_remove,
-+		.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),
-+		.RELAY_OUT	= XPROTO_CALLER(FXO, RELAY_OUT),
-+		.CHAN_ENABLE	= XPROTO_CALLER(FXO, CHAN_ENABLE),
-+		.CHAN_CID	= XPROTO_CALLER(FXO, CHAN_CID),
-+
-+		.SYNC_SOURCE	= XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
-+		.PCM_WRITE	= XPROTO_CALLER(GLOBAL, PCM_WRITE),
-+	},
-+	.packet_is_valid = fxo_packet_is_valid,
-+	.packet_dump = fxo_packet_dump,
-+};
-+
-+static bool fxo_packet_is_valid(xpacket_t *pack)
-+{
-+	const xproto_entry_t	*xe;
-+
-+	//DBG("\n");
-+	xe = xproto_card_entry(&PROTO_TABLE(FXO), pack->content.opcode);
-+	return xe != NULL;
-+}
-+
-+static void fxo_packet_dump(xpacket_t *pack)
-+{
-+	DBG("\n");
-+}
-+
-+/*------------------------- DAA Handling --------------------------*/
-+
-+static int proc_fxo_info_read(char *page, char **start, off_t off, int count, int *eof, void *data)
-+{
-+	int			len = 0;
-+	unsigned long		flags;
-+	xpd_t			*xpd = data;
-+	struct FXO_priv_data	*priv;
-+	int			i;
-+
-+	if(!xpd)
-+		return -ENODEV;
-+	spin_lock_irqsave(&xpd->lock, flags);
-+	priv = xpd->priv;
-+	BUG_ON(!priv);
-+	len += sprintf(page + len, "\t%-17s: ", "Channel");
-+	for_each_line(xpd, i) {
-+		if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
-+			len += sprintf(page + len, "%d ", i % 10);
-+	}
-+	len += sprintf(page + len, "\n\t%-17s: ", "ledstate");
-+	for_each_line(xpd, i) {
-+		if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
-+			len += sprintf(page + len, "%d ", IS_SET(priv->ledstate[LED_GREEN], i));
-+	}
-+	len += sprintf(page + len, "\n\t%-17s: ", "blinking");
-+	for_each_line(xpd, i) {
-+		if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
-+			len += sprintf(page + len, "%d ", IS_BLINKING(priv,i,LED_GREEN));
-+	}
-+	len += sprintf(page + len, "\n\t%-17s: ", "battery");
-+	for_each_line(xpd, i) {
-+		len += sprintf(page + len, "%d ", IS_SET(priv->battery, i));
-+	}
-+	len += sprintf(page + len, "\n");
-+	spin_unlock_irqrestore(&xpd->lock, flags);
-+	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 proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data)
-+{
-+	int			len = 0;
-+	unsigned long		flags;
-+	xpd_t			*xpd = data;
-+	slic_reply_t		*info;
-+	struct FXO_priv_data	*priv;
-+
-+	BUG_ON(!xpd);
-+	spin_lock_irqsave(&xpd->lock, flags);
-+	priv = xpd->priv;
-+	BUG_ON(!priv);
-+	info = &priv->last_reply;
-+	len += sprintf(page + len, "# Writing bad data into this file may damage your hardware!\n");
-+	len += sprintf(page + len, "# Consult firmware docs first\n");
-+	len += sprintf(page + len, "DAA_REPLY: %s reg_num=0x%X, dataH=0x%X dataL=0x%X\n",
-+			(info->indirect)?"I":"D",
-+			info->reg_num, info->data_high, info->data_low);
-+	spin_unlock_irqrestore(&xpd->lock, flags);
-+	if (len <= off+count)
-+		*eof = 1;
-+	*start = page + off;
-+	len -= off;
-+	if (len > count)
-+		len = count;
-+	if (len < 0)
-+		len = 0;
-+	return len;
-+}
-+
-+/*
-+ *        Direct/Indirect
-+ *              v
-+ * FF FF FF FF WD 06 1
-+ * ^---------^ ^  Reg
-+ *      | Write/Read
-+ *      |
-+ *    DAA #
-+ */
-+static int parse_slic_cmd(const char *buf, slic_cmd_t *sc, slic_reply_t *requested_reply)
-+{
-+	char		op;		/* [W]rite, [R]ead */
-+	char		reg_type;	/* [D]irect, [I]ndirect */
-+	int		s1, s2, s3, s4;
-+	int		reg_num;
-+	int		data_low, data_high;
-+	xpp_line_t	lines;
-+	int		ret;
-+
-+	ret = sscanf(buf, "%x %x %x %x %c%c %x %x %x",
-+			&s1, &s2, &s3, &s4, &op, &reg_type, &reg_num, &data_high, &data_low);
-+	lines = (s4 << 24) | (s3 << 16) | (s2 << 8) | (s1);
-+	switch(op) {
-+		case 'R':
-+			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);
-+				if(requested_reply) {
-+					requested_reply->indirect = 0;
-+					requested_reply->reg_num = reg_num;
-+				}
-+			} else if(reg_type == 'I' && 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_indirect_read(sc, lines, reg_num);
-+				if(requested_reply) {
-+					requested_reply->indirect = 1;
-+					requested_reply->reg_num = reg_num;
-+				}
-+			} else {
-+				NOTICE("%s: Bad read input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
-+				goto err;
-+			}
-+			break;
-+		case 'W':
-+			if(reg_type == 'D' && ret == 8) {
-+				// DBG("0x%X 0x%X 0x%X 0x%X %c %x %X\n", s1, s2, s3, s4, reg_type, reg_num, data_high);
-+				ret = slic_cmd_direct_write(sc, lines, reg_num, data_high);
-+			} else if(reg_type == 'I' && ret == 9) {
-+				// DBG("0x%X 0x%X 0x%X 0x%X %c %x %X %X\n", s1, s2, s3, s4, reg_type, reg_num, data_high, data_low);
-+				ret = slic_cmd_indirect_write(sc, lines, reg_num, data_low, data_high);
-+			} else {
-+				NOTICE("%s: Bad write input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
-+				goto err;
-+			}
-+			break;
-+		default:
-+			NOTICE("%s: Bad input: ret=%d buf='%s' op=%c\n", __FUNCTION__, ret, buf, op);
-+			goto err;
-+	}
-+	return ret;
-+err:
-+	return -EINVAL;
-+}
-+
-+static int process_slic_cmdline(xpd_t *xpd, char *cmdline)
-+{
-+	xbus_t			*xbus;
-+	struct FXO_priv_data	*priv;
-+	slic_cmd_t		sc;
-+	xpacket_t		*pack;
-+	char			*p;
-+	int			len = strlen(cmdline);
-+
-+	BUG_ON(!xpd);
-+	xbus = xpd->xbus;
-+	priv = xpd->priv;
-+	if((p = strchr(cmdline, '#')) != NULL)	/* Truncate comments */
-+		*p = '\0';
-+	if((p = strchr(cmdline, ';')) != NULL)	/* Truncate comments */
-+		*p = '\0';
-+	for(p = cmdline; *p && (*p == ' ' || *p == '\t'); p++) /* Trim leading whitespace */
-+		;
-+	if(*p == '\0')
-+		return 0;
-+	len = parse_slic_cmd(p, &sc, &priv->requested_reply);
-+	if(len < 0)
-+		return len;
-+	if(!sc.lines) {
-+		NOTICE("%s: no channels are marked. Skip.\n", __FUNCTION__);
-+		return 0;
-+	}
-+	dump_slic_cmd("WRITE_DAA", &sc);
-+	XPACKET_NEW(pack, xbus, FXO, DAA_WRITE, xpd->id);
-+	RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd) = sc;
-+	pack->datalen = len;
-+	packet_send(xbus, pack);
-+	return 0;
-+}
-+
-+static int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
-+{
-+	xpd_t		*xpd = data;
-+	const int	LINE_LEN = 500;
-+	char		buf[LINE_LEN];
-+	char		*p;
-+	int		i;
-+	int		ret;
-+
-+	if(!xpd)
-+		return -ENODEV;
-+	for(i = 0; i < count; /* noop */) {
-+		for(p = buf; p < buf + LINE_LEN; p++) {	/* read a line */
-+			if(i >= count)
-+				break;
-+			if(get_user(*p, buffer + i))
-+				return -EFAULT;
-+			i++;
-+			if(*p == '\n' || *p == '\r')	/* whatever */
-+				break;
-+		}
-+		if(p >= buf + LINE_LEN)
-+			return -E2BIG;
-+		*p = '\0';
-+		ret = process_slic_cmdline(xpd, buf);
-+		if(ret < 0)
-+			return ret;
-+		mdelay(1);
-+	}
-+	return count;
-+}
-+
-+
-+int __init card_fxo_startup(void)
-+{
-+	INFO("%s revision %s\n", THIS_MODULE->name, ZAPTEL_VERSION);
-+	xproto_register(&PROTO_TABLE(FXO));
-+	return 0;
-+}
-+
-+void __exit card_fxo_cleanup(void)
-+{
-+	xproto_unregister(&PROTO_TABLE(FXO));
-+}
-+
-+MODULE_DESCRIPTION("XPP FXO Card Driver");
-+MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
-+MODULE_LICENSE("GPL");
-+MODULE_VERSION(ZAPTEL_VERSION);
-+MODULE_ALIAS_XPD(XPD_TYPE_FXO);
-+
-+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-LJNBCn_dist/xpp/card_fxo.h
---- zaptel-1.2.6/xpp/card_fxo.h	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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
-+/*
-+ * Written by Oron Peled <oron at actcom.co.il>
-+ * Copyright (C) 2004-2006, Xorcom
-+ *
-+ * All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#include "xpd.h"
-+#include "slic.h"
-+
-+enum fxo_opcodes {
-+	XPROTO_NAME(FXO, SIG_CHANGED)		= 0x06,
-+/**/
-+	XPROTO_NAME(FXO, DAA_WRITE)		= 0x0F,	/* Write to DAA */
-+	XPROTO_NAME(FXO, CHAN_ENABLE)		= 0x0F,	/* Write to DAA */
-+	XPROTO_NAME(FXO, CHAN_CID)		= 0x0F,	/* Write to DAA */
-+	XPROTO_NAME(FXO, RING)			= 0x0F,	/* Write to DAA */
-+	XPROTO_NAME(FXO, SETHOOK)		= 0x0F,	/* Write to DAA */
-+	XPROTO_NAME(FXO, LED)			= 0x0F,	/* Write to DAA */
-+	XPROTO_NAME(FXO, RELAY_OUT)		= 0x0F,	/* Write to DAA */
-+	XPROTO_NAME(FXO, DAA_INIT)		= 0x0F,	/* Write to DAA */
-+	XPROTO_NAME(FXO, DAA_QUERY)		= 0x0F,	/* Write to DAA */
-+/**/
-+	XPROTO_NAME(FXO, DAA_REPLY)		= 0x10,
-+};
-+
-+
-+DEF_RPACKET_DATA(FXO, SIG_CHANGED,
-+	byte		type;		/* unused -- we have it from DEV_DESC */
-+	xpp_line_t	sig_status;	/* channels: lsb=1, msb=8 */
-+	xpp_line_t	sig_toggles;	/* channels: lsb=1, msb=8 */
-+	);
-+DEF_RPACKET_DATA(FXO, DAA_REPLY,	/* Get status of a single DAA (for debugging) */
-+	xpp_line_t	lines;
-+	slic_reply_t	info;
-+	);
-+DEF_RPACKET_DATA(FXO, DAA_WRITE,
-+	slic_cmd_t	slic_cmd;
-+	);
-+
-+#define	DAA_VBAT_REGISTER	29
-+#define	BAT_THRESHOLD		3
-+
-+#endif	/* CARD_FXO_H */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/card_fxs.c zaptel-xpp-LJNBCn_dist/xpp/card_fxs.c
---- zaptel-1.2.6/xpp/card_fxs.c	2006-04-03 10:08:13.000000000 +0300
-+++ zaptel-xpp-LJNBCn_dist/xpp/card_fxs.c	2006-07-10 12:13:42.526183000 +0300
-@@ -1,6 +1,6 @@
- /*
-  * Written by Oron Peled <oron at actcom.co.il>
-- * Copyright (C) 2004-2005, Xorcom
-+ * Copyright (C) 2004-2006, Xorcom
-  *
-  * All rights reserved.
-  *
-@@ -23,65 +23,232 @@
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/fs.h>
-+#include <linux/delay.h>
-+#include <version.h>		/* For zaptel version */
- #include "xpd.h"
- #include "xproto.h"
- #include "xpp_zap.h"
--#include <linux/delay.h>
-+#include "card_fxo.h"
-+#include "zap_debug.h"
- 
--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 1604 2006-07-10 09:13:42Z tzafrir $";
- 
- 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
- 
- #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)
-+{
-+	xpacket_t	*pack;
-+	slic_cmd_t	*sc;
-+	int		len;
-+
-+	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, reg, dL);
-+	pack->datalen = len;
-+	packet_send(xbus, pack);
-+	return 0;
-+}
- 
- /*---------------- FXS Protocol Commands ----------------------------------*/
- 
--/* 0x0F */ DECLARE_CMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on);
--/* 0x0F */ DECLARE_CMD(FXS, CHAN_POWER, xpp_line_t lines, bool on);
--/* 0x0F */ DECLARE_CMD(FXS, CHAN_CID, xpp_line_t lines);
--/* 0x0F */ DECLARE_CMD(FXS, RING, int pos, bool on);
--/* 0x0F */ DECLARE_CMD(FXS, SETHOOK, xpp_line_t hook_status);
--/* 0x0F */ DECLARE_CMD(FXS, LED, xpp_line_t lines, byte which, bool on);
--/* 0x0F */ DECLARE_CMD(FXS, RELAY_OUT, byte which, bool on);
--/* 0x0F */ DECLARE_CMD(FXS, SLIC_INIT);
--/* 0x0F */ DECLARE_CMD(FXS, SLIC_QUERY, int pos, byte reg_num);
-+static /* 0x0F */ DECLARE_CMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on);
-+static /* 0x0F */ DECLARE_CMD(FXS, CHAN_CID, int pos);
-+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_QUERY, int pos, byte reg_num);
- 
- static bool fxs_packet_is_valid(xpacket_t *pack);
- static void fxs_packet_dump(xpacket_t *pack);
-+static int proc_fxs_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);
- 
--#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"
--};
--#undef	S_
--
- #define	PROC_SLIC_FNAME		"slics"
-+#define	PROC_FXS_INFO_FNAME	"fxs_info"
- 
- struct FXS_priv_data {
--	struct proc_dir_entry	*xpd_slic;
--	slic_reply_t		last_reply;
-+	struct proc_dir_entry		*xpd_slic;
-+	struct proc_dir_entry		*fxs_info;
-+	slic_reply_t			requested_reply;
-+	slic_reply_t			last_reply;
-+	xpp_line_t			ledstate[NUM_LEDS];	/* 0 - OFF, 1 - ON */
-+	xpp_line_t			ledcontrol[NUM_LEDS];	/* 0 - OFF, 1 - ON */
-+	int				blinking[NUM_LEDS][CHANNELS_PERXPD];
- };
- 
-+/*---------------- FXS: Static functions ----------------------------------*/
-+static int do_chan_power(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, bool on)
-+{
-+	int		ret = 0;
-+	xpacket_t	*pack;
-+	slic_cmd_t	*sc;
-+	int		len;
-+
-+	BUG_ON(!xbus);
-+	BUG_ON(!xpd);
-+	if(!lines) {
-+		return 0;
-+	}
-+	DBG("%s/%s: 0x%04X %s\n", xbus->busname, xpd->xpdname, lines, (on) ? "up" : "down");
-+	XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
-+	sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
-+	if(on) {
-+		// Power up
-+		len = slic_cmd_direct_write(sc, lines, 0x42, 0x06);
-+	} else {
-+		// Power down
-+		len = slic_cmd_direct_write(sc, lines, 0x42, 0x00);
-+	}
-+	pack->datalen = len;
-+
-+	packet_send(xbus, pack);
-+	return ret;
-+}
-+
-+#define	IS_BLINKING(priv,pos,color)	((priv)->blinking[color][pos] != 0)
-+#define	MARK_BLINK(priv,pos,color,val)	((priv)->blinking[color][pos] = (val))
-+#define	MARK_LED(priv,pos,color,val)	((val)?BIT_SET((priv)->ledcontrol[color],(pos)):BIT_CLR((priv)->ledcontrol[color],(pos)))
-+
-+/*
-+ * LED and RELAY control is done via SLIC register 0x06:
-+ *         7     6     5     4     3     2     1     0
-+ * 	+-----+-----+-----+-----+-----+-----+-----+-----+
-+ * 	| M2  | M1  | M3  | C2  | O1  | O3  | C1  | C3  |
-+ * 	+-----+-----+-----+-----+-----+-----+-----+-----+
-+ *
-+ * 	Cn	- Control bit (control one digital line)
-+ * 	On	- Output bit (program a digital line for output)
-+ * 	Mn	- Mask bit (only the matching output control bit is affected)
-+ *
-+ * 	C3	- OUTPUT RELAY (0 - OFF, 1 - ON)
-+ * 	C1	- GREEN LED (0 - OFF, 1 - ON)
-+ * 	O3	- Output RELAY (this line is output)
-+ * 	O1	- Output GREEN (this line is output)
-+ * 	C2	- RED LED (0 - OFF, 1 - ON)
-+ * 	M3	- Mask RELAY. (1 - C3 effect the OUTPUT RELAY)
-+ * 	M2	- Mask RED. (1 - C2 effect the RED LED)
-+ * 	M1	- Mask GREEN. (1 - C1 effect the GREEN LED)
-+ *
-+ * 	The OUTPUT RELAY (actually a relay out) is connected to line 0 and 4 only.
-+ */
-+
-+//		        		       		GREEN	RED	OUTPUT RELAY
-+static const int	led_register_mask[] = { 	BIT(7),	BIT(6),	BIT(5) };
-+static const int	led_register_vals[] = { 	BIT(4),	BIT(1),	BIT(0) };
-+
-+/*
-+ * pos can be:
-+ * 	- A line number
-+ * 	- ALL_LINES
-+ */
-+static int do_led(xpd_t *xpd, lineno_t pos, byte which, bool on)
-+{
-+	int			ret = 0;
-+	xpacket_t		*pack;
-+	slic_cmd_t		*sc;
-+	int			len;
-+	int			value;
-+	struct FXS_priv_data	*priv;
-+	xpp_line_t		lines;
-+	xbus_t			*xbus;
-+
-+	BUG_ON(!xpd);
-+	xbus = xpd->xbus;
-+	priv = xpd->priv;
-+	which = which % NUM_LEDS;
-+	if(IS_SET(xpd->digital_outputs, pos) || IS_SET(xpd->digital_inputs, pos))
-+		goto out;
-+	if(pos == ALL_LINES) {
-+		lines = ~0;
-+		priv->ledstate[which] = (on) ? ~0 : 0;
-+	} else {
-+		lines = BIT(pos);
-+		if(on) {
-+			BIT_SET(priv->ledstate[which], pos);
-+		} else {
-+			BIT_CLR(priv->ledstate[which], pos);
-+		}
-+	}
-+	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);
-+	value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[which]);
-+	if(on)
-+		value |= led_register_vals[which];
-+	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);
-+	pack->datalen = len;
-+	packet_send(xbus, pack);
-+
-+out:
-+	return ret;
-+}
-+
-+static void handle_fxs_leds(xpd_t *xpd)
-+{
-+	int			i;
-+	unsigned long		flags;
-+	const enum fxs_leds	colors[] = { LED_GREEN, LED_RED };
-+	int			color;
-+	unsigned int		timer_count;
-+	struct FXS_priv_data	*priv;
-+
-+	BUG_ON(!xpd);
-+	spin_lock_irqsave(&xpd->lock, flags);
-+	priv = xpd->priv;
-+	timer_count = xpd->timer_count;
-+	for(color = 0; color < ARRAY_SIZE(colors); color++) {
-+		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
-+				// led state is toggled
-+				if((timer_count % LED_BLINK_PERIOD) == 0) {
-+					DBG("%s/%s/%d ledstate=%s\n", xpd->xbus->busname, xpd->xpdname, i,
-+							(IS_SET(priv->ledstate[color], i))?"ON":"OFF");
-+					if(!IS_SET(priv->ledstate[color], i)) {
-+						do_led(xpd, i, color, 1);
-+					} else {
-+						do_led(xpd, i, color, 0);
-+					}
-+				}
-+			} else if(IS_SET(priv->ledcontrol[color], i) && !IS_SET(priv->ledstate[color], i)) {
-+						do_led(xpd, i, color, 1);
-+			} else if(!IS_SET(priv->ledcontrol[color], i) && IS_SET(priv->ledstate[color], i)) {
-+						do_led(xpd, i, color, 0);
-+			}
-+
-+		}
-+	}
-+	spin_unlock_irqrestore(&xpd->lock, flags);
-+}
-+
- /*---------------- FXS: Methods -------------------------------------------*/
- 
- static xpd_t *FXS_card_new(xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, byte revision)
-@@ -100,29 +267,82 @@
- 		xpd->digital_inputs = MASK_DIGI_INP;
- 	}
- 	xpd->direction = TO_PHONE;
-+	xpd->revision = revision;
- 	return xpd;
- }
- 
-+static void clean_proc(xbus_t *xbus, xpd_t *xpd)
-+{
-+	struct FXS_priv_data	*priv;
-+
-+	BUG_ON(!xpd);
-+	priv = xpd->priv;
-+#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) {
-+		DBG("Removing xpd FXS_INFO file %s/%s\n", xbus->busname, xpd->xpdname);
-+		remove_proc_entry(PROC_FXS_INFO_FNAME, xpd->proc_xpd_dir);
-+	}
-+#endif
-+}
-+
- static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
- {
- 	struct FXS_priv_data	*priv;
-+	int			ret = 0;
- 
- 	BUG_ON(!xpd);
- 	priv = xpd->priv;
--	CALL_PROTO(FXS, SLIC_INIT, xbus, xpd);
- #ifdef	CONFIG_PROC_FS
-+	DBG("Creating FXS_INFO file for %s/%s\n", xbus->busname, xpd->xpdname);
-+	priv->fxs_info = create_proc_read_entry(PROC_FXS_INFO_FNAME, 0444, xpd->proc_xpd_dir, proc_fxs_info_read, xpd);
-+	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 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 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
-+	ret = run_initialize_registers(xpd);
-+	if(ret < 0)
-+		goto err;
-+	/*
-+	 * Setup ring timers
-+	 */
-+#ifdef	WITH_RBS
-+	/* Software controled ringing (for CID) */
-+	ret = SLIC_DIRECT_REQUEST(xbus, xpd, ALL_LINES, 0x22, 0x00);	/* Ringing Oscilator Control */
-+#else
-+	/* Hardware controled ringing (no CID) */
-+	ret += SLIC_DIRECT_REQUEST(xbus, xpd, ALL_LINES, 0x30, 0x80);	/* Active timer low byte */
-+	ret += SLIC_DIRECT_REQUEST(xbus, xpd, ALL_LINES, 0x31, 0x3E);	/* Active timer high byte */
-+	ret += SLIC_DIRECT_REQUEST(xbus, xpd, ALL_LINES, 0x32, 0x80);	/* Inactive timer low byte */
-+	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
-+	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 +352,210 @@
- 	BUG_ON(!xpd);
- 	priv = xpd->priv;
- 	DBG("%s/%s\n", xbus->busname, xpd->xpdname);
--#ifdef	CONFIG_PROC_FS
--	if(priv->xpd_slic) {
--		DBG("Removing xpd SLIC file %s/%s\n", xbus->busname, xpd->xpdname);
--		remove_proc_entry(PROC_SLIC_FNAME, xpd->proc_xpd_dir);
-+	clean_proc(xbus, xpd);
-+	return 0;
-+}
-+
-+static int FXS_card_zaptel_preregistration(xpd_t *xpd, bool on)
-+{
-+	xbus_t			*xbus;
-+	struct FXS_priv_data	*priv;
-+	int			i;
-+	unsigned long		flags;
-+	const enum fxs_leds     color = (on) ? LED_GREEN : LED_RED;
-+
-+	BUG_ON(!xpd);
-+	xbus = xpd->xbus;
-+	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);
- 	}
--#endif
- 	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);
-+	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);
-+	}
-+	return 0;
-+}
-+
-+#ifdef WITH_RBS
-+int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
-+{
-+	int		ret = 0;
-+
-+	DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, pos, txsig2str(txsig));
-+	BUG_ON(xpd->direction != TO_PHONE);
-+	if (IS_SET(xpd->digital_inputs, pos)) {
-+		DBG("Ignoring signal sent to digital input line\n");
-+		return 0;
-+	}
-+	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) {
-+				case ZT_SIG_EM:
-+				case ZT_SIG_FXOKS:
-+				case ZT_SIG_FXOLS:
-+					xpd->lasttxhook[pos] = xpd->idletxhookstate[pos];
-+					break;
-+				case ZT_SIG_FXOGS:
-+					xpd->lasttxhook[pos] = FXS_LINE_TIPOPEN;
-+					break;
-+			}
-+#endif
-+			break;
-+		case ZT_TXSIG_OFFHOOK:
-+			if(xpd->ringing[pos]) {
-+				BIT_SET(xpd->cid_on, pos);
-+				ret = CALL_XMETHOD(CHAN_CID, xpd->xbus, xpd, pos);		// CALLER ID
-+			}
-+			xpd->ringing[pos] = 0;
-+#if 0
-+			switch(chan->sig) {
-+				case ZT_SIG_EM:
-+					xpd->lasttxhook[pos] = FXS_LINE_REV_ACTIVE;
-+					break;
-+				default:
-+					xpd->lasttxhook[pos] = xpd->idletxhookstate[pos];
-+					break;
-+			}
-+#endif
-+			break;
-+		case ZT_TXSIG_START:
-+			xpd->lasttxhook[pos] = FXS_LINE_RING;
-+			xpd->ringing[pos] = 1;
-+			BIT_CLR(xpd->cid_on, pos);
-+			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;
-+		case ZT_TXSIG_KEWL:
-+			xpd->lasttxhook[pos] = FXS_LINE_DISABLED;
-+			break;
-+		default:
-+			NOTICE("%s: Can't set tx state to %s (%d)\n", __FUNCTION__, txsig2str(txsig), txsig);
-+			ret = -EINVAL;
-+	}
-+	return ret;
-+}
-+
-+#else
-+int FXS_card_sethook(xbus_t *xbus, xpd_t *xpd, int pos, int hookstate)
-+{
-+	int	ret = 0;
-+
-+	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
-+		 */
-+		case ZT_ONHOOK:
-+			if(IS_SET(xpd->digital_inputs, pos)) {
-+				NOTICE("%s: Trying to ONHOOK a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
-+				ret = -EINVAL;
-+				break;
-+			}
-+			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);
-+				break;
-+			}
-+			xpd->ringing[pos] = 0;
-+			DBG("%s/%s/%d: stop ringing\n", xbus->busname, xpd->xpdname, pos);
-+#if 1	// FIXME: Not needed -- verify
-+			ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0);			// RING off
-+#endif
-+			if(ret) {
-+				DBG("ZT_ONHOOK(stop ring) Failed: ret=0x%02X\n", ret);
-+				break;
-+			}
-+			break;
-+		case ZT_START:
-+			DBG("%s/%s/%d: fall through ZT_OFFHOOK\n", xbus->busname, xpd->xpdname, pos);
-+			// Fall through
-+		case ZT_OFFHOOK:
-+			DBG("%s/%s/%d: ZT_OFFHOOK (ignoring for PHONES)\n", xbus->busname, xpd->xpdname, pos);
-+			break;
-+		case ZT_WINK:
-+			WARN("No code yet\n");
-+			break;
-+		case ZT_FLASH:
-+			WARN("No code yet\n");
-+			break;
-+		case ZT_RING:
-+			DBG("%s/%s/%d: ZT_RING: %d\n", xbus->busname, xpd->xpdname, pos, xpd->ringing[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: digital output ON\n", xbus->busname, xpd->xpdname, pos);
-+				ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
-+				return ret;
-+			}
-+			xpd->ringing[pos] = 1;
-+			ret = CALL_XMETHOD(RING, xbus, xpd, pos, 1);		// RING on
-+			if(ret) {
-+				DBG("ZT_RING Failed: ret=0x%02X\n", ret);
-+			}
-+			break;
-+		case ZT_RINGOFF:
-+			WARN("No code yet\n");
-+			break;
-+	}
-+	return ret;
-+}
-+#endif
-+
- /*
-  * INPUT polling is done via SLIC register 0x06 (same as LEDS):
-  *         7     6     5     4     3     2     1     0
-@@ -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 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;
- }
- 
- /*---------------- FXS: HOST COMMANDS -------------------------------------*/
- 
--/* 0x0F */ HOSTCMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on)
-+static /* 0x0F */ HOSTCMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on)
- {
- 	int		ret = 0;
- 	xpacket_t	*pack;
- 	slic_cmd_t	*sc;
- 	int		len;
-+	enum fxs_state	value = (on) ? 0x01 : 0x00;
-+	unsigned long	flags;
-+	int		i;
- 
- 	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");
-+	// Make sure we use normal (low battery) power
-+	for_each_line(xpd, i)
-+		if (BIT_SET(lines,i))
-+			do_chan_power(xbus, xpd, BIT(i), 0);
- 	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, 0x40, (on)?0x01:0x00);
-+	len = slic_cmd_direct_write(sc, lines, 0x40, value);
- 	pack->datalen = len;
-+	for_each_line(xpd, i)
-+		xpd->lasttxhook[i] = value;
- 
- 	packet_send(xbus, pack);
--	return ret;
--}
--
--/* 0x0F */ HOSTCMD(FXS, CHAN_POWER, xpp_line_t lines, bool on)
--{
--	int		ret = 0;
--	xpacket_t	*pack;
--	slic_cmd_t	*sc;
--	int		len;
--
--	BUG_ON(!xbus);
--	BUG_ON(!xpd);
--	lines &= xpd->enabled_chans;	// Ignore disabled channels
--	if(!lines) {
--		return 0;
--	}
--	DBG("Channel Power: 0x%04X %s\n", lines, (on) ? "up" : "down");
--	XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
--	sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
-+	spin_lock_irqsave(&xpd->lock, flags);
- 	if(on) {
--		// Power up
--		len = slic_cmd_direct_write(sc, lines, 0x42, 0x06);
-+		do_led(xpd, ALL_LINES, LED_GREEN, LED_ON);
- 	} else {
--		// Power down
--		len = slic_cmd_direct_write(sc, lines, 0x42, 0x00);
-+		do_led(xpd, ALL_LINES, LED_GREEN, LED_OFF);
- 	}
--	pack->datalen = len;
--
--	packet_send(xbus, pack);
-+	spin_unlock_irqrestore(&xpd->lock, flags);
- 	return ret;
- }
- 
--/* 0x0F */ HOSTCMD(FXS, CHAN_CID, xpp_line_t lines)
-+static /* 0x0F */ HOSTCMD(FXS, CHAN_CID, int pos)
- {
- 	int		ret = 0;
- 	xpacket_t	*pack;
- 	slic_cmd_t	*sc;
-+	int		i;
-+	xpp_line_t	lines = BIT(pos);
- 
- 	BUG_ON(!xbus);
- 	BUG_ON(!xpd);
--	lines &= xpd->enabled_chans;	// Ignore disabled channels
- 	if(!lines) {
- 		return 0;
- 	}
--	DBG("Channel CID: 0x%04X\n", lines);
-+	DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, pos);
-+	//do_chan_power(xbus, xpd, BIT(pos), 0);	// Low battery for normal (non-ring) operation
- 	XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
- 	sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
--	pack->datalen = slic_cmd_direct_write(sc, lines, 0x40, 0x02);
-+	pack->datalen = slic_cmd_direct_write(sc, lines, 0x40, FXS_LINE_CID);
- 	packet_send(xbus, pack);
-+	for_each_line(xpd, i)
-+		xpd->lasttxhook[i] = FXS_LINE_CID;
- 	return ret;
- }
- 
- 
--/* 0x0F */ HOSTCMD(FXS, RING, int pos, bool on)
-+static /* 0x0F */ HOSTCMD(FXS, RING, int pos, bool on)
- {
- 	int		ret = 0;
-+	struct FXS_priv_data	*priv;
- 	xpacket_t	*pack;
- 	slic_cmd_t	*sc;
--	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;
- 	if(!mask) {
- 		return 0;
- 	}
--	DBG("%s pos=%d %s\n", xpd->xpdname, pos, (on) ? "on" : "off");
-+	DBG("%s/%s/%d %s\n", xbus->busname, xpd->xpdname, pos, (on) ? "on" : "off");
-+	do_chan_power(xbus, xpd, BIT(pos), on);		// Power up (for ring)
- 	XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
- 	sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
--	len = slic_cmd_direct_write(sc, mask, 0x40, (on)?0x04:0x01);
-+	len = slic_cmd_direct_write(sc, mask, 0x40, value);
-+	xpd->lasttxhook[pos] = value;
- 	pack->datalen = len;
- 
- 	packet_send(xbus, pack);
-+	if(on) {
-+		MARK_BLINK(priv,pos,LED_GREEN,LED_BLINK);
-+	} else {
-+		if(IS_BLINKING(priv, pos, LED_GREEN))
-+			MARK_BLINK(priv,pos,LED_GREEN,0);
-+	}
- 	return ret;
- }
- 
--/* 0x0F */ HOSTCMD(FXS, SETHOOK, xpp_line_t hook_status)
-+static /* 0x0F */ HOSTCMD(FXS, SETHOOK, int pos, bool offhook)
- {
--	DBG("\n");
-+	BUG();	// Should never be called
- 	return 0;
- }
- 
--/*
-- * LED control is done via SLIC register 0x06:
-- *         7     6     5     4     3     2     1     0
-- * 	+-----+-----+-----+-----+-----+-----+-----+-----+
-- * 	| MR  | MG  | MB  |  R  | OG  | OB  |  G  | B   |
-- * 	+-----+-----+-----+-----+-----+-----+-----+-----+
-- *
-- * 	B	- BLUE LED (0 - OFF, 1 - ON)
-- * 	G	- GREEN LED (0 - OFF, 1 - ON)
-- * 	OB	- Output BLUE (this line is output)
-- * 	OG	- Output GREEN (this line is output)
-- * 	R	- RED LED (0 - OFF, 1 - ON)
-- * 	MB	- Mask BLUE. (1 - B effect the BLUE LED)
-- * 	MR	- Mask RED. (1 - R effect the RED LED)
-- * 	MG	- Mask GREEN. (1 - G effect the GREEN LED)
-- *
-- * 	The BLUE LED (actually a relay out) is connected to line 0 and 4 only.
-- */
--
--//		                 		GREEN	RED	BLUE
--static const int	led_mask[NUM_LEDS] = { 	BIT(7),	BIT(6),	BIT(5) };
--static const int	led_vals[NUM_LEDS] = { 	BIT(4),	BIT(1),	BIT(0) };
--
--/* 0x0F */ HOSTCMD(FXS, LED, xpp_line_t lines, byte which, bool on)
--{
--	int		ret = 0;
--	xpacket_t	*pack;
--	slic_cmd_t	*sc;
--	int		len;
--	int		value;
--	int		i;
--
--	BUG_ON(!xbus);
--	BUG_ON(!xpd);
--	lines &= xpd->enabled_chans;	// Ignore disabled channels
--	if(!lines) {
--		return 0;
--	}
--	DBG("LED: lines=0x%04X which=%d -- %s\n", lines, which, (on) ? "on" : "off");
--	which = which % NUM_LEDS;
--	value = BIT(2) | BIT(3);
--	value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_mask[which]);
--	if(on)
--		value |= led_vals[which];
--	for(i = 0; i < CHANNELS_PERXPD; i++) {
--		if(!IS_SET(lines, i))
--				continue;
--		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);
--		DBG("LED pack: line=%d value=0x%04X\n", i, value);
--		pack->datalen = len;
--		packet_send(xbus, pack);
--	}
--	return ret;
--}
--
--/* 0x0F */ HOSTCMD(FXS, RELAY_OUT, byte which, bool on)
-+static /* 0x0F */ HOSTCMD(FXS, RELAY_OUT, byte which, bool on)
- {
- 	int		ret = 0;
- 	xpacket_t	*pack;
-@@ -351,9 +719,9 @@
- 	which = which % ARRAY_SIZE(relay_channels);
- 	lines = BIT(relay_channels[which]);
- 	value = BIT(2) | BIT(3);
--	value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_mask[LED_BLUE]);
-+	value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[OUTPUT_RELAY]);
- 	if(on)
--		value |= led_vals[LED_BLUE];
-+		value |= led_register_vals[OUTPUT_RELAY];
- 	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,34 +732,7 @@
- 	return ret;
- }
- 
--/* 0x0F */ HOSTCMD(FXS, SLIC_INIT)
--{
--	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
--	}
--	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 +741,7 @@
- 
- 	BUG_ON(!xbus);
- 	BUG_ON(!xpd);
--	DBG("\n");
-+	// DBG("\n");
- 	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 +757,39 @@
- HANDLER_DEF(FXS, SIG_CHANGED)
- {
- 	xpp_line_t	sig_status = RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_status);
-+	xpp_line_t	sig_toggles = RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_toggles);
-+	struct FXS_priv_data	*priv;
-+	int		i;
- 
--	if(!xpd) {
--		NOTICE("%s: received %s for non-existing xpd: %d\n",
--				__FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
--		return -EPROTO;
--	}
--	if(xpd->direction == TO_PHONE) {		/* Hook state changes */
--		DBG("%s (PHONE) sig_status=0x%04X\n", xpd->xpdname, sig_status);
--		xpp_check_hookstate(xpd, sig_status);
--	} 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++) {
-+	BUG_ON(!xpd);
-+	BUG_ON(xpd->direction != TO_PHONE);
-+	priv = xpd->priv;
-+	DBG("%s/%s: (PHONE) sig_toggles=0x%04X sig_status=0x%04X\n", xbus->busname, xpd->xpdname, sig_toggles, sig_status);
-+	if(!SPAN_REGISTERED(xpd)) {
-+		NOTICE("%s: %s/%s is not registered. Skipping.\n", __FUNCTION__, xbus->busname, xpd->xpdname);
-+		return -ENODEV;
-+	}
-+	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];
-+
-+			xpd->ringing[i] = 0;		// No more ringing...
-+			do_chan_power(xpd->xbus, xpd, BIT(i), 0);	// When not ringing, VBAT is always Low
-+			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);
-+				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);
-+				MARK_LED(priv,i,LED_GREEN,LED_OFF);
-+				BIT_CLR(xpd->hookstate, i);
-+				zt_hooksig(chan, ZT_RXSIG_ONHOOK);
- 			}
- 		}
--		spin_unlock_irqrestore(&xpd->lock, flags);
- 	}
- 	return 0;
- }
-@@ -460,52 +809,75 @@
- 	spin_lock_irqsave(&xpd->lock, flags);
- 	priv = xpd->priv;
- 	BUG_ON(!priv);
-+#if 0
- 	DBG("SLIC_REPLY: xpd #%d %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
- 			xpd->id, (info->indirect)?"I":"D",
- 			info->reg_num, info->data_low, info->data_high);
--	priv->last_reply = *info;
-+#endif
- 	if(xpd->id == 0 && info->indirect == 0 && info->reg_num == 0x06) {	/* Digital Inputs Poll Result */
- 		int	i;
- 		bool	offhook = (info->data_low & 0x1) == 0;
- 
- 		/* Map SLIC number into line number */
- 		for(i = 0; i < ARRAY_SIZE(input_channels); i++) {
--			int	channo = input_channels[i];
--			int	newchanno;
-+			int		channo = input_channels[i];
-+			int		newchanno;
-+			struct zt_chan	*chan;
- 
- 			if(IS_SET(lines, channo)) {
- 				newchanno = LINES_REGULAR + LINES_DIGI_OUT + i;
- 				BIT_CLR(lines, channo);
- 				BIT_SET(lines, newchanno);
--				phone_hook(xpd, newchanno, offhook);
-+				chan = &xpd->span.chans[newchanno];
-+				xpd->ringing[newchanno] = 0;			// Stop ringing. No leds for digital inputs.
-+				if(offhook && !IS_SET(xpd->hookstate, newchanno)) {		// OFFHOOK
-+					DBG("OFFHOOK: channo=%d\n", chan->channo);
-+					BIT_SET(xpd->hookstate, newchanno);
-+					zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
-+				} else if(!offhook && IS_SET(xpd->hookstate, newchanno)) {	// ONHOOK
-+					DBG("ONHOOK channo=%d\n", chan->channo);
-+					BIT_CLR(xpd->hookstate, newchanno);
-+					zt_hooksig(chan, ZT_RXSIG_ONHOOK);
-+				}
- 			}
- 		}
- 	}
-+
-+	/* Update /proc info only if reply relate to the last slic read request */
-+	if(priv->requested_reply.indirect == info->indirect &&
-+			priv->requested_reply.reg_num == info->reg_num) {
-+		priv->last_reply = *info;
-+	}
- 	spin_unlock_irqrestore(&xpd->lock, flags);
- 	return 0;
- }
- 
--
- xproto_table_t PROTO_TABLE(FXS) = {
-+	.owner = THIS_MODULE,
- 	.entries = {
- 		/*	Card	Opcode		*/
- 		XENTRY(	FXS,	SIG_CHANGED	),
- 		XENTRY(	FXS,	SLIC_REPLY	),
- 	},
- 	.name = "FXS",
--	.type = XPD_TYPE(FXS),
-+	.type = XPD_TYPE_FXS,
- 	.xops = {
- 		.card_new	= FXS_card_new,
- 		.card_init	= FXS_card_init,
- 		.card_remove	= FXS_card_remove,
-+		.card_zaptel_preregistration	= FXS_card_zaptel_preregistration,
-+		.card_zaptel_postregistration	= FXS_card_zaptel_postregistration,
-+#ifdef WITH_RBS
-+		.card_hooksig	= FXS_card_hooksig,
-+#else
-+		.card_sethook	= FXS_card_sethook,
-+#endif
- 		.card_tick	= FXS_card_tick,
- 
- 		.RING		= XPROTO_CALLER(FXS, RING),
- 		.SETHOOK	= XPROTO_CALLER(FXS, SETHOOK),
--		.LED		= XPROTO_CALLER(FXS, LED),
- 		.RELAY_OUT	= XPROTO_CALLER(FXS, RELAY_OUT),
- 		.CHAN_ENABLE	= XPROTO_CALLER(FXS, CHAN_ENABLE),
--		.CHAN_POWER	= XPROTO_CALLER(FXS, CHAN_POWER),
- 		.CHAN_CID	= XPROTO_CALLER(FXS, CHAN_CID),
- 
- 		.SYNC_SOURCE	= XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
-@@ -519,7 +891,7 @@
- {
- 	const xproto_entry_t	*xe;
- 
--	DBG("\n");
-+	// DBG("\n");
- 	xe = xproto_card_entry(&PROTO_TABLE(FXS), pack->content.opcode);
- 	return xe != NULL;
- }
-@@ -531,6 +903,57 @@
- 
- /*------------------------- SLIC Handling --------------------------*/
- 
-+static int proc_fxs_info_read(char *page, char **start, off_t off, int count, int *eof, void *data)
-+{
-+	int			len = 0;
-+	unsigned long		flags;
-+	xpd_t			*xpd = data;
-+	struct FXS_priv_data	*priv;
-+	int			i;
-+	int			led;
-+
-+	if(!xpd)
-+		return -ENODEV;
-+	spin_lock_irqsave(&xpd->lock, flags);
-+	priv = xpd->priv;
-+	BUG_ON(!priv);
-+	len += sprintf(page + len, "\t%-17s: ", "Channel");
-+	for_each_line(xpd, i) {
-+		if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
-+			len += sprintf(page + len, "%d ", i % 10);
-+	}
-+	len += sprintf(page + len, "\n");
-+	for(led = 0; led < NUM_LEDS; led++) {
-+		len += sprintf(page + len, "LED #%d", led);
-+		len += sprintf(page + len, "\n\t%-17s: ", "ledstate");
-+		for_each_line(xpd, i) {
-+			if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
-+				len += sprintf(page + len, "%d ", IS_SET(priv->ledstate[led], i));
-+		}
-+		len += sprintf(page + len, "\n\t%-17s: ", "ledcontrol");
-+		for_each_line(xpd, i) {
-+			if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
-+				len += sprintf(page + len, "%d ", IS_SET(priv->ledcontrol[led], i));
-+		}
-+		len += sprintf(page + len, "\n\t%-17s: ", "blinking");
-+		for_each_line(xpd, i) {
-+			if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
-+				len += sprintf(page + len, "%d ", IS_BLINKING(priv,i,led));
-+		}
-+		len += sprintf(page + len, "\n");
-+	}
-+	spin_unlock_irqrestore(&xpd->lock, flags);
-+	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 proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data)
- {
- 	int			len = 0;
-@@ -570,7 +993,7 @@
-  *      |
-  *    SLIC #
-  */
--static int parse_slic_cmd(const char *buf, slic_cmd_t *sc)
-+static int parse_slic_cmd(const char *buf, slic_cmd_t *sc, slic_reply_t *requested_reply)
- {
- 	char		op;		/* [W]rite, [R]ead */
- 	char		reg_type;	/* [D]irect, [I]ndirect */
-@@ -588,9 +1011,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);
-+				if(requested_reply) {
-+					requested_reply->indirect = 0;
-+					requested_reply->reg_num = reg_num;
-+				}
- 			} else if(reg_type == 'I' && 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_indirect_read(sc, lines, reg_num);
-+				if(requested_reply) {
-+					requested_reply->indirect = 1;
-+					requested_reply->reg_num = reg_num;
-+				}
- 			} else {
- 				NOTICE("%s: Bad read input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
- 				goto err;
-@@ -619,14 +1050,16 @@
- 
- static int process_slic_cmdline(xpd_t *xpd, char *cmdline)
- {
--	xbus_t		*xbus;
--	slic_cmd_t	sc;
--	xpacket_t	*pack;
--	char		*p;
--	int		len = strlen(cmdline);
-+	xbus_t			*xbus;
-+	struct FXS_priv_data	*priv;
-+	slic_cmd_t		sc;
-+	xpacket_t		*pack;
-+	char			*p;
-+	int			len = strlen(cmdline);
- 
- 	BUG_ON(!xpd);
- 	xbus = xpd->xbus;
-+	priv = xpd->priv;
- 	if((p = strchr(cmdline, '#')) != NULL)	/* Truncate comments */
- 		*p = '\0';
- 	if((p = strchr(cmdline, ';')) != NULL)	/* Truncate comments */
-@@ -635,12 +1068,11 @@
- 		;
- 	if(*p == '\0')
- 		return 0;
--	len = parse_slic_cmd(p, &sc);
-+	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_SLIC", &sc);
-@@ -660,7 +1092,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 +1110,7 @@
- 		ret = process_slic_cmdline(xpd, buf);
- 		if(ret < 0)
- 			return ret;
-+		mdelay(1);
- 	}
- 	return count;
- }
-@@ -684,7 +1118,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 +1137,8 @@
- MODULE_DESCRIPTION("XPP FXS Card Driver");
- MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
- MODULE_LICENSE("GPL");
--MODULE_VERSION("$Id: card_fxs.c 995 2006-04-03 07:08:13Z tzafrir $");
-+MODULE_VERSION(ZAPTEL_VERSION);
-+MODULE_ALIAS_XPD(XPD_TYPE_FXS);
- 
- 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-LJNBCn_dist/xpp/card_fxs.h
---- zaptel-1.2.6/xpp/card_fxs.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/card_fxs.h	2006-07-02 17:17:18.812352000 +0300
-@@ -2,7 +2,7 @@
- #define	CARD_FXS_H
- /*
-  * Written by Oron Peled <oron at actcom.co.il>
-- * Copyright (C) 2004-2005, Xorcom
-+ * Copyright (C) 2004-2006, Xorcom
-  *
-  * All rights reserved.
-  *
-@@ -25,6 +25,24 @@
- #include "xpd.h"
- #include "slic.h"
- 
-+enum fxs_opcodes {
-+	XPROTO_NAME(FXS, SIG_CHANGED)		= 0x06,
-+/**/
-+	XPROTO_NAME(FXS, SLIC_WRITE)		= 0x0F,	/* Write to SLIC */
-+	XPROTO_NAME(FXS, CHAN_ENABLE)		= 0x0F,	/* Write to SLIC */
-+	XPROTO_NAME(FXS, CHAN_POWER)		= 0x0F,	/* Write to SLIC */
-+	XPROTO_NAME(FXS, CHAN_CID)		= 0x0F,	/* Write to SLIC */
-+	XPROTO_NAME(FXS, RING)			= 0x0F,	/* Write to SLIC */
-+	XPROTO_NAME(FXS, SETHOOK)		= 0x0F,	/* Write to SLIC */
-+	XPROTO_NAME(FXS, LED)			= 0x0F,	/* Write to SLIC */
-+	XPROTO_NAME(FXS, RELAY_OUT)		= 0x0F,	/* Write to SLIC */
-+	XPROTO_NAME(FXS, SLIC_INIT)		= 0x0F,	/* Write to SLIC */
-+	XPROTO_NAME(FXS, SLIC_QUERY)		= 0x0F,	/* Write to SLIC */
-+/**/
-+	XPROTO_NAME(FXS, SLIC_REPLY)		= 0x10,
-+};
-+
-+
- 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 */
-@@ -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-LJNBCn_dist/xpp/card_global.c
---- zaptel-1.2.6/xpp/card_global.c	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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>
-- * Copyright (C) 2004-2005, Xorcom
-+ * Copyright (C) 2004-2006, Xorcom
-  *
-  * All rights reserved.
-  *
-@@ -24,9 +24,10 @@
- #include "xpd.h"
- #include "xpp_zap.h"
- #include "xproto.h"
-+#include "zap_debug.h"
- #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 1549 2006-07-03 11:04:21Z oron $";
- 
- extern	int print_dbg;
- static bool pcm_valid(xpd_t *xpd, xpacket_t *pack);
-@@ -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;
--	if(pcm_gen != 0)
--		return 0;
-+	lines &= ~xpd->no_pcm;
- //	if(lines == 0)
- //		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);
--	for(i = 0; i < CHANNELS_PERXPD; i++) {
-+	for_each_line(xpd, i) {
- 		if(IS_SET(lines, i)) {
- 			memcpy(pcm, (byte *)buf, ZT_CHUNKSIZE);
- 			pcm += ZT_CHUNKSIZE;
-@@ -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 +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);
- 		return -EPROTO;
- 	}
--	DBG("SYNC_REPLY: 0x%X\n", RPACKET_FIELD(pack, GLOBAL, SYNC_REPLY, mask));
-+	DBG("%s/%s: SYNC_REPLY: 0x%X %s\n", xpd->xbus->busname, xpd->xpdname,
-+			mask, (setit) ? "SET SYNC MASTER" : "");
-+	if(setit)
-+		sync_master_is(xpd);
- 	return 0;
- }
- 
-@@ -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));
--	for (i = 0; i < CHANNELS_PERXPD; i++)
-+	for_each_line(xpd, i)
- 		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-LJNBCn_dist/xpp/card_global.h
---- zaptel-1.2.6/xpp/card_global.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/card_global.h	2006-07-03 13:44:48.152691000 +0300
-@@ -2,7 +2,7 @@
- #define	CARD_GLOBAL_H
- /*
-  * Written by Oron Peled <oron at actcom.co.il>
-- * Copyright (C) 2004-2005, Xorcom
-+ * Copyright (C) 2004-2006, Xorcom
-  *
-  * All rights reserved.
-  *
-@@ -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,
--	xpp_line_t	lines;	// Must be 0xFF
-+	xpp_line_t	lines;
- 	byte		pcm[PCM_CHUNKSIZE];
- 	);
- DEF_RPACKET_DATA(GLOBAL, PCM_READ,
--	xpp_line_t	lines;	// Must be 0xFF
-+	xpp_line_t	lines;
- 	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-LJNBCn_dist/xpp/cards.c
---- zaptel-1.2.6/xpp/cards.c	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/cards.c	1970-01-01 02:00:00.000000000 +0200
-@@ -1,394 +0,0 @@
--#include <linux/module.h>
--#include "xpd.h"
--#include "xpp_zap.h"
--#include "xpp_proto.h"
--#include "cards.h"
--
--static char rcsid[] = "$Id: cards.c 949 2006-02-15 02:24:18Z kpfleming $";
--
--extern	int print_dbg;
--#include "zap_debug.h"
--
--#define	MAX_SLIC_REGISTERS	100
--
--struct FXS_private_data {
--	slic_reply_t	last_slic_reply;
--};
--
--/*------------------------- FXS Functions --------------------------*/
--int	FXS_card_new(xpd_t *xpd)
--{
--	xpd->direction = TO_PHONE;
--	xpd->channels = min(8, CHANNELS_PERXPD);
--	if(xpd->id == 0) {
--		DBG("First XPD detected. Initialize digital outputs\n");
--		xpd->channels += 2;
--		xpd->digital_outputs = BIT(8) | BIT(9);	// Two extra channels
--	}
--	return 0;
--}
--
--int	FXS_card_remove(xpd_t *xpd)
--{
--	return 0;
--}
--
--static int FXS_card_startup(struct zt_span *span)
--{
--	DBG("\n");
--	return 0;
--}
--
--/*
-- * Called only for 'span' keyword in /etc/zaptel.conf
-- */
--static int FXS_card_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
--{
--	xpd_t *xpd = span->pvt;
--
--	DBG("%s\n", xpd->xpdname);
--	return 0;
--}
--
--/* Set signalling type (if appropriate) */
--static int FXS_card_chanconfig(struct zt_chan *chan, int sigtype)
--{
--	DBG("channel %d (%s), sigtype %d.\n", chan->channo, chan->name, sigtype);
--	dump_sigtype(print_dbg, "  ", sigtype);
--	// FIXME: sanity checks:
--	// - should be supported (within the sigcap)
--	// - should not replace fxs <->fxo ??? (covered by previous?)
--	return 0;
--}
--
--/*
-- * Called only for 'span' keyword in /etc/zaptel.conf
-- */
--static int FXS_card_shutdown(struct zt_span *span)
--{
--	xpd_t *xpd = span->pvt;
--
--	DBG("%s\n", xpd->xpdname);
--	return 0;
--}
--
--static int FXS_card_sethook(struct zt_chan *chan, int hookstate)
--{
--	int pos = chan->chanpos - 1;
--	xpd_t	*xpd = chan->pvt;
--	xbus_t	*xbus;
--	int ret = 0;
--
--	if(!xpd) {
--		ERR("%s: channel=%d without an XPD!\n", __FUNCTION__, pos);
--		return -EINVAL;
--	}
--	xbus = xpd->xbus;
--	// DBG("%s (%d) (old=0x%04X, hook-command=%d)\n", chan->name, pos, xpd->hookstate, hookstate);
--	switch(hookstate) {
--		/* On-hook, off-hook: The PBX is playing a phone on an FXO line. 
--		 * Can be ignored for an FXS line
--		 */
--		case ZT_ONHOOK:
--			if(IS_SET(xpd->digital_outputs, pos)) {
--				DBG("ZT_ONHOOK %s digital output OFF\n", chan->name);
--				ret = CALL_PROTO(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
--				return ret;
--			}
--			DBG("ZT_ONHOOK: %s hookstate=0x%04X (stop ringing pos=%d)\n", chan->name, xpd->hookstate, pos);
--			xpd->ringing[pos] = 0;
--#if 1	// FIXME: Not needed -- verify
--			ret = CALL_PROTO(RING, xbus, xpd, pos, 0);			// RING off
--#endif
--			ret = CALL_PROTO(LED, xpd->xbus, xpd, BIT(pos), LED_GREEN, 0);
--			ret = CALL_PROTO(CHAN_POWER, xbus, xpd, BIT(pos), 0);		// Power down (prevent overheating!!!)
--			if(ret) {
--				DBG("ZT_ONHOOK(stop ring) Failed: ret=0x%02X\n", ret);
--				break;
--			}
--			break;
--		case ZT_START:
--			DBG("ZT_START: %s hookstate=0x%04X (fall through ZT_OFFHOOK)\n", chan->name, xpd->hookstate);
--			// Fall through
--		case ZT_OFFHOOK:
--			DBG("ZT_OFFHOOK: %s hookstate=0x%04X -- ignoring (FXS)\n", chan->name, xpd->hookstate);
--			break;
--		case ZT_WINK:
--			DBG("ZT_WINK %s\n", chan->name);
--			break;
--		case ZT_FLASH:
--			DBG("ZT_FLASH %s\n", chan->name);
--			break;
--		case ZT_RING:
--			DBG("ZT_RING %s pos=%d (ringing[pos]=%d)\n", chan->name, pos, xpd->ringing[pos]);
--			if(IS_SET(xpd->digital_outputs, pos)) {
--				DBG("ZT_ONHOOK %s digital output ON\n", chan->name);
--				ret = CALL_PROTO(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
--				return ret;
--			}
--			xpd->ringing[pos] = RINGS_NUM*2;
--			ret = CALL_PROTO(CHAN_POWER, xbus, xpd, (1 << pos), 1);	// Power up (for ring)
--			ret = CALL_PROTO(RING, xbus, xpd, pos, 1);			// RING on
--			if(ret) {
--				DBG("ZT_RING Failed: ret=0x%02X\n", ret);
--			}
--			break;
--		case ZT_RINGOFF:
--			DBG("ZT_RINGOFF %s\n", chan->name);
--			break;
--		default:
--			DBG("UNKNOWN hookstate=0x%X\n", hookstate);
--	}
--	return ret;
--}
--
--static int FXS_card_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
--{
--	switch (cmd) {
--	default:
--		return xpp_ioctl(chan, cmd, arg);
--	}
--	return 0;
--}
--
--#if 0
--int FXS_zaptel_setup(xpd_t *xpd)
--{
--	struct zt_chan	*cur_chan;
--	struct zt_span	*span;
--	xbus_t		*xbus;
--	int		i;
--	int		cn;
--
--	BUG_ON(!xpd);
--
--	sigfxs = ! (xpd->direction == TO_PHONE);	/* signaling is opposite */
--	cn = xpd->channels;
--	DBG("Initializing span: xpd %d have %d channels.\n", xpd->id, cn);
--
--	xpd->chans = kmalloc(sizeof(struct zt_chan)*cn, GFP_ATOMIC);
--	if (xpd->chans == NULL) {
--		ERR("xpd: Unable to allocate channels\n");
--		return -ENOMEM;
--	}
--	memset(xpd->chans, 0, sizeof(struct zt_chan)*cn);
--	memset(&xpd->span, 0, sizeof(struct zt_span));
--
--	span = &xpd->span;
--	xbus = xpd->xbus;
--	snprintf(span->name, MAX_SPANNAME, "%s/%s",
--			xbus->busname, xpd->xpdname);
--	{
--		char tmp[MAX_SPANNAME];
--		struct xpd_sim	*sim = &xbus->sim[xpd->id];
--
--		if(sim->simulated)
--			snprintf(tmp, MAX_SPANNAME, " (sim to=%d)", sim->loopto);
--		else
--			tmp[0] = '\0';
--
--		snprintf(span->desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: %s%s",
--				xbus->num, xpd->id,
--				(xpd->direction == TO_PHONE) ? "FXS" : "FXO",
--				tmp
--				);
--	}
--	for(i = 0; i < cn; i++) {
--		
--		cur_chan = &xpd->chans[i];
--		DBG("setting channel %d\n", i);
--		snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXS/%d-%d", xpd->id, i);
--		cur_chan->chanpos = i + 1;
--		cur_chan->pvt = xpd;
--		cur_chan->sigcap =
--#if 1
--				ZT_SIG_FXOKS	|
--				ZT_SIG_FXOLS	|
--				ZT_SIG_FXOGS	|
--#else
--				ZT_SIG_SF	|
--				ZT_SIG_EM	|
--#endif
--				0;
--	}
--	span->deflaw = ZT_LAW_MULAW;
--	init_waitqueue_head(&span->maintq);
--	span->pvt = xpd;
--	span->channels = cn;
--	span->chans = xpd->chans;
--
--	span->startup = FXS_xpp_startup;
--	span->shutdown = FXS_xpp_shutdown;
--	span->spanconfig = FXS_xpp_spanconfig;
--	span->chanconfig = FXS_xpp_chanconfig;
--	span->open = xpp_open;
--	span->close = xpp_close;
--#ifdef	WITH_RBS
--	span->flags = ZT_FLAG_RBS;
--	span->hooksig = xpp_hooksig;	/* Only with RBS bits */
--#else
--	span->sethook = FXS_xpp_sethook;
--#endif
--	span->ioctl = FXS_xpp_ioctl;
--	span->maint = xpp_maint;
--#ifdef	CONFIG_ZAPTEL_WATCHDOG
--	span->watchdog = xpp_watchdog;
--#endif
--
--	return 0;
--}
--#endif
--
--int FXS_zaptel_cleanup(xpd_t *xpd)
--{
--	return 0;
--}
--
--/*------------------------- FXO Functions --------------------------*/
--static int FXO_card_new(xpd_t *xpd)
--{
--	xpd->direction = TO_TRUNK;
--	xpd->channels = min(8, CHANNELS_PERXPD);
--	return 0;
--}
--
--static int FXO_card_remove(xpd_t *xpd)
--{
--	return 0;
--}
--
--static int FXO_card_startup(struct zt_span *span)
--{
--	DBG("\n");
--	return 0;
--}
--
--/*
-- * Called only for 'span' keyword in /etc/zaptel.conf
-- */
--static int FXO_card_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
--{
--	xpd_t *xpd = span->pvt;
--
--	DBG("%s\n", xpd->xpdname);
--	return 0;
--}
--
--/* Set signalling type (if appropriate) */
--static int FXO_card_chanconfig(struct zt_chan *chan, int sigtype)
--{
--	DBG("channel %d (%s), sigtype %d.\n", chan->channo, chan->name, sigtype);
--	dump_sigtype(print_dbg, "  ", sigtype);
--	// FIXME: sanity checks:
--	// - should be supported (within the sigcap)
--	// - should not replace fxs <->fxo ??? (covered by previous?)
--	return 0;
--}
--
--/*
-- * Called only for 'span' keyword in /etc/zaptel.conf
-- */
--static int FXO_card_shutdown(struct zt_span *span)
--{
--	xpd_t *xpd = span->pvt;
--
--	DBG("%s\n", xpd->xpdname);
--	return 0;
--}
--
--
--static int FXO_card_sethook(struct zt_chan *chan, int hookstate)
--{
--	int pos = chan->chanpos - 1;
--	xpd_t	*xpd = chan->pvt;
--	xbus_t	*xbus;
--	int ret = 0;
--
--	BUG_ON(!xpd);
--	xbus = xpd->xbus;
--	// DBG("%s (%d) (old=0x%04X, hook-command=%d)\n", chan->name, pos, xpd->hookstate, hookstate);
--	switch(hookstate) {
--		/* On-hook, off-hook: The PBX is playing a phone on an FXO line. 
--		 * Can be ignored for an FXS line
--		 */
--		case ZT_ONHOOK:
--			if(IS_SET(xpd->digital_outputs, pos)) {
--				DBG("ZT_ONHOOK %s digital output OFF\n", chan->name);
--				ret = CALL_PROTO(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
--				return ret;
--			}
--			DBG("ZT_ONHOOK: %s hookstate=0x%04X (pos=%d)\n", chan->name, xpd->hookstate, pos);
--			xpd->ringing[pos] = 0;
--			BIT_CLR(xpd->hookstate, pos);
--			ret = CALL_PROTO(SETHOOK, xbus, xpd, xpd->hookstate);
--			if(ret) {
--				DBG("ZT_ONHOOK Failed: ret=0x%02X\n", ret);
--				break;
--			}
--			break;
--		case ZT_START:
--			DBG("ZT_START: %s hookstate=0x%04X (fall through ZT_OFFHOOK)\n", chan->name, xpd->hookstate);
--			// Fall through
--		case ZT_OFFHOOK:
--			DBG("ZT_OFFHOOK: %s hookstate=0x%04X (pos=%d)\n", chan->name, xpd->hookstate, pos);
--			BIT_SET(xpd->hookstate, pos);
--			xpd->ringing[pos] = 0;
--			ret = CALL_PROTO(SETHOOK, xbus, xpd, xpd->hookstate);
--			if(ret) {
--				DBG("ZT_OFFHOOK Failed: ret=0x%02X\n", ret);
--				break;
--			}
--			break;
--		case ZT_WINK:
--			DBG("ZT_WINK %s\n", chan->name);
--			break;
--		case ZT_FLASH:
--			DBG("ZT_FLASH %s\n", chan->name);
--			break;
--		case ZT_RING:
--			DBG("ZT_RING %s pos=%d (ringing[pos]=%d)\n", chan->name, pos, xpd->ringing[pos]);
--			break;
--		case ZT_RINGOFF:
--			DBG("ZT_RINGOFF %s\n", chan->name);
--			break;
--		default:
--			DBG("UNKNOWN hookstate=0x%X\n", hookstate);
--	}
--	return ret;
--}
--
--static int FXO_card_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
--{
--	switch (cmd) {
--	default:
--		return xpp_ioctl(chan, cmd, arg);
--	}
--	return 0;
--}
--
--
--/*------------------------- Function table -------------------------*/
--
--#define	DEF_(t)	\
--	[XPD_TYPE_ ## t] {					\
--		.card_new = t ## _card_new,			\
--		.card_remove = t ## _card_remove,		\
--		.card_startup = t ## _card_startup,		\
--		.card_shutdown = t ## _card_shutdown,		\
--		.card_spanconfig = t ## _card_spanconfig,	\
--		.card_chanconfig = t ## _card_chanconfig,	\
--		.card_sethook = t ## _card_sethook,		\
--		.card_ioctl = t ## _card_ioctl,			\
--		}
--
--xops_t	xpd_card_ops[XPD_TYPE_NOMODULE] = {
--	DEF_(FXS),
--	DEF_(FXO)
--};
--
--xops_t	*get_xops(xpd_type_t xpd_type)
--{
--	if(xpd_type >= XPD_TYPE_NOMODULE)
--		return NULL;
--	return &xpd_card_ops[xpd_type];
--}
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/cards.h zaptel-xpp-LJNBCn_dist/xpp/cards.h
---- zaptel-1.2.6/xpp/cards.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/cards.h	1970-01-01 02:00:00.000000000 +0200
-@@ -1,23 +0,0 @@
--#ifndef	CARDS_H
--#define	CARDS_H
--
--#include "xpd.h"
--
--struct xpd_card_ops {
--	int	(*card_new)(xpd_t *xpd);
--	int	(*card_remove)(xpd_t *xpd);
--#if 0
--	int	(*zaptel_setup)(xpd_t *xpd);
--	int	(*zaptel_cleanup)(xpd_t *xpd);
--#endif
--	int	(*card_startup)(struct zt_span *span);
--	int	(*card_shutdown)(struct zt_span *span);
--	int	(*card_spanconfig)(struct zt_span *span, struct zt_lineconfig *lc);
--	int	(*card_chanconfig)(struct zt_chan *chan, int sigtype);
--	int	(*card_sethook)(struct zt_chan *chan, int hookstate);
--	int	(*card_ioctl)(struct zt_chan *chan, unsigned int cmd, unsigned long arg);
--};
--
--xops_t *get_xops(xpd_type_t xpd_type);
--
--#endif	/* CARDS_H */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/FPGA_XPD.hex zaptel-xpp-LJNBCn_dist/xpp/FPGA_XPD.hex
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/gen_slic_init zaptel-xpp-LJNBCn_dist/xpp/gen_slic_init
---- zaptel-1.2.6/xpp/gen_slic_init	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/gen_slic_init	1970-01-01 02:00:00.000000000 +0200
-@@ -1,37 +0,0 @@
--#! /usr/bin/perl -w
--
--use strict;
--
--my $input;
--my $header;
--my $comment;
--
-- at ARGV == 2 or die "Usage: $0 <infile> <outfile>\n";
--$input = $ARGV[0];
--$header = $ARGV[1];
--open(IF, "$input") or die "Failed to write '$input': $!\n";
--open(HF, ">$header") or die "Failed to write '$header': $!\n";
--
--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, $len, @data) = split;
--	die "Bad input (len=$len)" if hex($len) != @data;
--	my $slic = "$slic3$slic2$slic1$slic0";
--	die "Bad slic address '$slic'" if length($slic) != 8;
--	grep(s/\w+/0x$&/g, ($slic, $len, @data));
--	my $str = join(", ", @data);
--	print HF "S_($slic,\t$len,\t$str),\t";
--} continue {
--	if(defined($comment)) {
--		print HF "// $comment";
--	}
--	print HF "\n";
--}
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/init_data_3_19.cmd zaptel-xpp-LJNBCn_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-LJNBCn_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>
-+# Copyright (C) 2006, Xorcom
-+#
-+# All rights reserved.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 2 of the License, or
-+# (at your option) any later version.
-+#
-+# See the file LICENSE in the top level of this tarball.
-+#
-+
-+;
-+; $Id: init_data_fxs.cmd 540 2006-03-01 12:30:36Z oron $
-+;
-+; SLICS		CMD	Reg	High	Low
-+
-+; ----------------------------------==== 8-channel FXS unit initialization ===-----------------------------------------
-+; INTERNAL PS
-+; Change SLICs states to "Open state"s  (Off,all transfers tristated to avoid data collision), Voltage sense
-+
-+FF 00 00 00	WD	40	00
-+FF 00 00 00	WD	6C	01
-+
-+; ------------------------------------- Initialization of indirect registers ------------------------------------------
-+
-+FF 00 00 00	WI	00	55	C2
-+FF 00 00 00	WI	01	51	E6
-+FF 00 00 00	WI	02	4B	85
-+FF 00 00 00	WI	03	49	37
-+
-+FF 00 00 00	WI	04	33	33
-+FF 00 00 00	WI	05	02	02
-+FF 00 00 00	WI	06	02	02
-+FF 00 00 00	WI	07	01	98
-+
-+FF 00 00 00	WI	08	01	98
-+FF 00 00 00	WI	09	06	11
-+FF 00 00 00	WI	0A	02	02
-+FF 00 00 00	WI	0B	00	E5
-+
-+FF 00 00 00	WI	0C	0A	1C
-+FF 00 00 00	WI	0D	7B	30
-+FF 00 00 00	WI	0E	00	63
-+FF 00 00 00	WI	0F	00	00
-+
-+FF 00 00 00	WI	10	78	70
-+FF 00 00 00	WI	11	00	7D
-+FF 00 00 00	WI	12	00	00
-+FF 00 00 00	WI	13	00	00
-+
-+FF 00 00 00	WI	14	7E	F0
-+FF 00 00 00	WI	15	01	60
-+FF 00 00 00	WI	16	00	00
-+FF 00 00 00	WI	17	20	00
-+
-+FF 00 00 00	WI	18	20	00
-+FF 00 00 00	WI	19	00	00
-+FF 00 00 00	WI	1A	40	00
-+FF 00 00 00	WI	1B	40	00
-+
-+FF 00 00 00	WI	1C	18	00
-+FF 00 00 00	WI	1D	40	00
-+FF 00 00 00	WI	1E	10	00
-+FF 00 00 00	WI	1F	00	80
-+
-+FF 00 00 00	WI	20	0F	F4
-+FF 00 00 00	WI	21	6E	7E
-+FF 00 00 00	WI	22	0F	F4
-+FF 00 00 00	WI	23	88	00
-+
-+FF 00 00 00	WI	24	03	20
-+FF 00 00 00	WI	25	00	12
-+FF 00 00 00	WI	26	00	12
-+FF 00 00 00	WI	27	00	12
-+
-+FF 00 00 00	WI	28	0C	00
-+FF 00 00 00	WI	29	0C	00
-+FF 00 00 00	WI	2B	08	00
-+
-+FF 00 00 00	WI	63	00	DA
-+FF 00 00 00	WI	64	6B	60
-+FF 00 00 00	WI	65	00	74
-+FF 00 00 00	WI	66	79	C0
-+
-+FF 00 00 00	WI	67	11	20
-+FF 00 00 00	WI	68	3B	E0	
-+
-+; ------------------------------------- Initialization of direct registers --------------------------------------------
-+
-+; Mode(8-bit,u-Law,1 PCLK ) setting, Loopbacks and Interrupts clear
-+
-+FF 00 00 00	WD	01 29
-+FF 00 00 00	WD	08 00
-+FF 00 00 00	WD	09 00
-+FF 00 00 00	WD	0E 00  
-+
-+FF 00 00 00	WD	15 00
-+FF 00 00 00	WD	16 03
-+FF 00 00 00	WD	17 00
-+FF 00 00 00	WD	12 FF
-+FF 00 00 00	WD	13 FF
-+FF 00 00 00	WD	14 FF 
-+
-+; Automatic/Manual Control: defaults - Cancel Power Alarm
-+FF 00 00 00	WD	43 1E
-+
-+FF 00 00 00	WD	4A 31
-+FF 00 00 00	WD	4B 10
-+
-+; Battery Feed Control: Battery low (DCSW low)
-+FF 00 00 00	WD	42 00
-+
-+; Slic Calibration
-+FF 00 00 00	WD	61 1F
-+FF 00 00 00	WD	60 5F
-+
-+; Loop Closure Debounce Interval
-+FF 00 00 00	WD	45 0A
-+
-+; Ring Detect Debounce Interval
-+FF 00 00 00	WD	46 0B
-+
-+; Loop Current Limit
-+FF 00 00 00	WD	47 07
-+
-+; Setting of SLICs offsets
-+
-+01 00 00 00	WD	02 01
-+01 00 00 00	WD	03 00
-+01 00 00 00	WD	04 01
-+01 00 00 00	WD	05 00
-+
-+02 00 00 00	WD	02 09
-+02 00 00 00	WD	03 00
-+02 00 00 00	WD	04 09
-+02 00 00 00	WD	05 00
-+
-+04 00 00 00	WD	02 11
-+04 00 00 00	WD	03 00
-+04 00 00 00	WD	04 11
-+04 00 00 00	WD	05 00
-+
-+08 00 00 00	WD	02 19
-+08 00 00 00	WD	03 00
-+08 00 00 00	WD	04 19
-+08 00 00 00	WD	05 00
-+
-+10 00 00 00	WD	02 21
-+10 00 00 00	WD	03 00
-+10 00 00 00	WD	04 21
-+10 00 00 00	WD	05 00
-+
-+20 00 00 00	WD	02 29
-+20 00 00 00	WD	03 00
-+20 00 00 00	WD	04 29
-+20 00 00 00	WD	05 00
-+
-+40 00 00 00	WD	02 31
-+40 00 00 00	WD	03 00
-+40 00 00 00	WD	04 31
-+40 00 00 00	WD	05 00
-+
-+80 00 00 00	WD	02 39
-+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-LJNBCn_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-LJNBCn_dist/xpp/init_data_3_20.cmd	2006-07-10 12:13:42.526183000 +0300
-@@ -0,0 +1,172 @@
-+#
-+# Written by Oron Peled <oron at actcom.co.il>
-+# Copyright (C) 2006, Xorcom
-+#
-+# All rights reserved.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 2 of the License, or
-+# (at your option) any later version.
-+#
-+# See the file LICENSE in the top level of this tarball.
-+#
-+
-+;
-+; $Id: init_data_fxs.cmd 540 2006-03-01 12:30:36Z oron $
-+;
-+; SLICS		CMD	Reg	High	Low
-+
-+; ----------------------------------==== 8-channel FXS unit initialization ===-----------------------------------------
-+; INTERNAL PS
-+; Change SLICs states to "Open state"s  (Off,all transfers tristated to avoid data collision), Voltage sense
-+
-+FF 00 00 00	WD	40	00
-+FF 00 00 00	WD	6C	01
-+
-+; ------------------------------------- Initialization of indirect registers ------------------------------------------
-+
-+FF 00 00 00	WI	00	55	C2
-+FF 00 00 00	WI	01	51	E6
-+FF 00 00 00	WI	02	4B	85
-+FF 00 00 00	WI	03	49	37
-+
-+FF 00 00 00	WI	04	33	33
-+FF 00 00 00	WI	05	02	02
-+FF 00 00 00	WI	06	02	02
-+FF 00 00 00	WI	07	01	98
-+
-+FF 00 00 00	WI	08	01	98
-+FF 00 00 00	WI	09	06	11
-+FF 00 00 00	WI	0A	02	02
-+FF 00 00 00	WI	0B	00	E5
-+
-+FF 00 00 00	WI	0C	0A	1C
-+FF 00 00 00	WI	0D	7B	30
-+FF 00 00 00	WI	0E	00	63
-+FF 00 00 00	WI	0F	00	00
-+
-+FF 00 00 00	WI	10	78	70
-+FF 00 00 00	WI	11	00	7D
-+FF 00 00 00	WI	12	00	00
-+FF 00 00 00	WI	13	00	00
-+
-+FF 00 00 00	WI	14	7E	F0
-+FF 00 00 00	WI	15	01	60
-+FF 00 00 00	WI	16	00	00
-+FF 00 00 00	WI	17	20	00
-+
-+FF 00 00 00	WI	18	20	00
-+FF 00 00 00	WI	19	00	00
-+FF 00 00 00	WI	1A	40	00
-+FF 00 00 00	WI	1B	40	00
-+
-+FF 00 00 00	WI	1C	18	00
-+FF 00 00 00	WI	1D	40	00
-+FF 00 00 00	WI	1E	10	00
-+FF 00 00 00	WI	1F	00	80
-+
-+FF 00 00 00	WI	20	0F	F4
-+FF 00 00 00	WI	21	6E	7E
-+FF 00 00 00	WI	22	0F	F4
-+FF 00 00 00	WI	23	88	00
-+
-+FF 00 00 00	WI	24	03	20
-+FF 00 00 00	WI	25	00	12
-+FF 00 00 00	WI	26	00	12
-+FF 00 00 00	WI	27	00	12
-+
-+FF 00 00 00	WI	28	0C	00
-+FF 00 00 00	WI	29	0C	00
-+FF 00 00 00	WI	2B	08	00
-+
-+FF 00 00 00	WI	63	00	DA
-+FF 00 00 00	WI	64	6B	60
-+FF 00 00 00	WI	65	00	74
-+FF 00 00 00	WI	66	79	C0
-+
-+FF 00 00 00	WI	67	11	20
-+FF 00 00 00	WI	68	3B	E0	
-+
-+; ------------------------------------- Initialization of direct registers --------------------------------------------
-+
-+; Mode(8-bit,u-Law,1 PCLK ) setting, Loopbacks and Interrupts clear
-+
-+FF 00 00 00	WD	01 29
-+FF 00 00 00	WD	08 00
-+FF 00 00 00	WD	09 00
-+FF 00 00 00	WD	0E 00  
-+
-+FF 00 00 00	WD	15 00
-+FF 00 00 00	WD	16 03
-+FF 00 00 00	WD	17 00
-+FF 00 00 00	WD	12 FF
-+FF 00 00 00	WD	13 FF
-+FF 00 00 00	WD	14 FF 
-+
-+; Automatic/Manual Control:
-+; Manual BATL/BATH select. NOTE: bit 08 switches VBAT to Low AND to High!
-+FF 00 00 00	WD	43 16
-+
-+FF 00 00 00	WD	4A 31
-+FF 00 00 00	WD	4B 10
-+
-+; Battery Feed Control: Battery low (DCSW low)
-+FF 00 00 00	WD	42 00
-+
-+; Slic Calibration
-+FF 00 00 00	WD	61 1F
-+FF 00 00 00	WD	60 5F
-+
-+; Loop Closure Debounce Interval
-+FF 00 00 00	WD	45 0A
-+
-+; Ring Detect Debounce Interval
-+FF 00 00 00	WD	46 0B
-+
-+; Loop Current Limit
-+; 23 milliampere for line current 
-+FF 00 00 00	WD	47 01
-+
-+; Setting of SLICs offsets
-+
-+# New card initialization
-+01 00 00 00	WD	02 00
-+01 00 00 00	WD	03 00
-+01 00 00 00	WD	04 00
-+01 00 00 00	WD	05 00
-+
-+02 00 00 00	WD	02 08
-+02 00 00 00	WD	03 00
-+02 00 00 00	WD	04 08
-+02 00 00 00	WD	05 00
-+
-+04 00 00 00	WD	02 10
-+04 00 00 00	WD	03 00
-+04 00 00 00	WD	04 10
-+04 00 00 00	WD	05 00
-+
-+08 00 00 00	WD	02 18
-+08 00 00 00	WD	03 00
-+08 00 00 00	WD	04 18
-+08 00 00 00	WD	05 00
-+
-+10 00 00 00	WD	02 20
-+10 00 00 00	WD	03 00
-+10 00 00 00	WD	04 20
-+10 00 00 00	WD	05 00
-+
-+20 00 00 00	WD	02 28
-+20 00 00 00	WD	03 00
-+20 00 00 00	WD	04 28
-+20 00 00 00	WD	05 00
-+
-+40 00 00 00	WD	02 30
-+40 00 00 00	WD	03 00
-+40 00 00 00	WD	04 30
-+40 00 00 00	WD	05 00
-+
-+80 00 00 00	WD	02 38
-+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-LJNBCn_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-LJNBCn_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>
-+# Copyright (C) 2006, Xorcom
-+#
-+# All rights reserved.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 2 of the License, or
-+# (at your option) any later version.
-+#
-+# See the file LICENSE in the top level of this tarball.
-+#
-+
-+;
-+; $Id: init_data_fxo.cmd 540 2006-03-01 12:30:36Z oron $
-+;
-+; DAA's 	CMD	Reg	High	Low
-+
-+; ----------------------------------==== 8-channel FXO unit initialization ===-----------------------------------------
-+
-+FF FF 00 00	WD	21	28
-+FF FF 00 00	WD	18	99
-+FF FF 00 00	WD	06	00
-+
-+; ----------- DAA PCM start offset ----------
-+
-+01 00 00 00	WD	22 01
-+01 00 00 00	WD	23 00
-+01 00 00 00	WD	24 01
-+01 00 00 00	WD	25 00
-+
-+02 00 00 00	WD	22 09
-+02 00 00 00	WD	23 00
-+02 00 00 00	WD	24 09
-+02 00 00 00	WD	25 00
-+
-+04 00 00 00	WD	22 11
-+04 00 00 00	WD	23 00
-+04 00 00 00	WD	24 11
-+04 00 00 00	WD	25 00
-+
-+08 00 00 00	WD	22 19
-+08 00 00 00	WD	23 00
-+08 00 00 00	WD	24 19
-+08 00 00 00	WD	25 00
-+
-+10 00 00 00	WD	22 21
-+10 00 00 00	WD	23 00
-+10 00 00 00	WD	24 21
-+10 00 00 00	WD	25 00
-+
-+20 00 00 00	WD	22 29
-+20 00 00 00	WD	23 00
-+20 00 00 00	WD	24 29
-+20 00 00 00	WD	25 00
-+
-+40 00 00 00	WD	22 31
-+40 00 00 00	WD	23 00
-+40 00 00 00	WD	24 31
-+40 00 00 00	WD	25 00
-+
-+80 00 00 00	WD	22 39
-+80 00 00 00	WD	23 00
-+80 00 00 00	WD	24 39
-+80 00 00 00	WD	25 00
-+
-+; ----------- 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-LJNBCn_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-LJNBCn_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
-+#
-+# All rights reserved.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 2 of the License, or
-+# (at your option) any later version.
-+#
-+# See the file LICENSE in the top level of this tarball.
-+#
-+
-+;
-+; $Id: init_data_fxo.cmd 540 2006-03-01 12:30:36Z oron $
-+;
-+; 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
-+; 99 also sets ring validation
-+;FF FF 00 00	WD	18	99
-+FF FF 00 00	WD	06	00
-+
-+; ----------- DAA PCM start offset ----------
-+
-+FF FF 00 00	WD	23	00
-+FF FF 00 00	WD	25	00
-+
-+01 00 00 00	WD	22	00
-+01 00 00 00	WD	24	00
-+
-+02 00 00 00	WD	22	08
-+02 00 00 00	WD	24	08
-+
-+04 00 00 00	WD	22	10
-+04 00 00 00	WD	24	10
-+
-+08 00 00 00	WD	22	18
-+08 00 00 00	WD	24	18
-+
-+10 00 00 00	WD	22	20
-+10 00 00 00	WD	24	20
-+
-+20 00 00 00	WD	22	28
-+20 00 00 00	WD	24	28
-+
-+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	08
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/initialize_registers zaptel-xpp-LJNBCn_dist/xpp/initialize_registers
---- zaptel-1.2.6/xpp/initialize_registers	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/initialize_registers	2006-05-01 12:49:12.732258000 +0300
-@@ -0,0 +1,39 @@
-+#! /bin/sh
-+# XPD_BUS	- bus name
-+# XPD_NAME	- xpd name
-+# XPD_TYPE	- xpd type number (from protocol reply):
-+#			3 - FXS
-+#			4 - FXO
-+# XPD_REVISION	- xpd revision number
-+
-+set -e
-+
-+LOGGER="logger -i -t `basename $0`"
-+
-+INIT_DIR=`dirname $0`
-+BASE=/proc/xpp
-+
-+SLICS="$BASE/$XPD_BUS/$XPD_NAME/slics"
-+FILE="$INIT_DIR/init_data_${XPD_TYPE}_${XPD_REVISION}.cmd"
-+
-+if [ ! -f "$SLICS" ]; then
-+	$LOGGER "missing slics file '$SLICS'"
-+	exit 1
-+fi
-+
-+if [ ! -f "$FILE" ]; then
-+	$LOGGER "missing register initialization file '$FILE'"
-+	exit 1
-+fi
-+
-+case "$XPD_TYPE" in
-+3|4)
-+	cat "$FILE" > "$SLICS" 
-+	;;
-+*)
-+	$LOGGER "Unknown type '$XPD_TYPE'"
-+	exit 2
-+esac
-+$LOGGER "Wrote '$FILE' into '$SLICS'"
-+
-+exit 0
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/LICENSE.firmware zaptel-xpp-LJNBCn_dist/xpp/LICENSE.firmware
---- zaptel-1.2.6/xpp/LICENSE.firmware	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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. 
-+They are generally freely distriributable (see exact terms below).
-+
-+/****************************************************************************/
-+/*  Copyright (c) 2004-2006 Xorcom Inc. All Rights Reserved.                */
-+/*  Redistribution and use of the microcode software ( Firmware ) is        */
-+/*  permitted provided that the following conditions are met:               */
-+/*                                                                          */
-+/*          1. Firmware is redistributed verbatim without any modification; */
-+/*          2. Any reproduction of Firmware must contain the above          */
-+/*             copyright notice, this list of conditions and the below      */
-+/*             disclaimer in the documentation and/or other materials       */
-+/*             provided with the distribution; and                          */
-+/*          3. The name of Xorcom may not be used to endorse or promote     */
-+/*             products derived from this Firmware without specific prior   */
-+/*             written consent.                                             */
-+/*                                                                          */
-+/*  Disclaimer: Xorcom provides this firmware "as is" with no warranties    */
-+/*  or indemnities whatsoever. Xorcom expressly disclaims any express,      */
-+/*  statutory or implied warranties, including, but not limited to, the     */
-+/*  implied warranties of merchantability, fitness for a particular         */
-+/*  purpose and non-infringement. In no event shall Xorcom be liable for    */
-+/*  any direct, indirect, incidental, special, exemplary, or consequential  */
-+/*  damages (including, but not limited to, procurement of substitute       */
-+/*  goods or services; loss of use, data, or profits; or business           */
-+/*  interruption) however caused and on any theory of liability, whether    */
-+/*  in contract, strict liability, or tort (including negligence or         */
-+/*  otherwise) arising in any way out of the use of this firmware, even     */
-+/*  if advised of the possibility of such damage. User acknowledges and     */
-+/*  agrees that the purchase or use of the firmware will not create or      */
-+/*  give grounds for a license by implication, estoppel, or otherwise in    */
-+/*  any intellectual property rights (patent, copyright, trade secret,      */
-+/*  mask work, or other proprietary right) embodied in any other Xorcom     */
-+/*  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-LJNBCn_dist/xpp/Makefile
---- zaptel-1.2.6/xpp/Makefile	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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 -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 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
-+
-+ctags:
-+	ctags *.[ch]
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/README.Astribank zaptel-xpp-LJNBCn_dist/xpp/README.Astribank
---- zaptel-1.2.6/xpp/README.Astribank	2006-03-03 21:11:53.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/README.Astribank	2006-06-19 11:29:10.334411000 +0300
-@@ -5,15 +5,63 @@
- Building and Installation:
- """""""""""""""""""""""""
- Building and installation is basically like the normal procedure of 
--installing Zaptel. Follow the rest of the documentation here.
-+installing Zaptel with some additions.
- 
--In addition, the file xpp/xpp_modprobe contains modprobe settings. It
--should be copied verbatim into /etc/modprobe.conf or (better) copied to
--/etc/modprobe.d/ . If you fail to do so, xpp_usb.ko will fail to load
--xpd_fxs.ko and as a result will not detect your Astribank.
--
--Loading Firmware
-+Building drivers:
- """"""""""""""""
-+From the toplevel zaptel directory run a command similar to (I used line
-+continuation to prevent line wrapping):
-+
-+ $ make \
-+        KSRC=/usr/src/kernel-headers-2.6.12-1-386       \
-+        KVERS=2.6.12-1-386                              \
-+        XPPMOD=xpp/                                     \
-+        EC_TYPE=CAN_KB1
-+
-+ - The KSRC= points to a configured kernel source tree.
-+ - The KVERS= should match the relevant tree version.
-+ - The XPPMOD= instructs the Zaptel Makefile to descend into the xpp/
-+   subdirectory. The slash (/) in the end is mandatory.
-+ - The EC_TYPE= select the echo canceler.
-+
-+Building firmware utilities:
-+"""""""""""""""""""""""""""
-+Then you should compile the firmware loading utilities. Simply go
-+to the zaptel/xpp/utils and run make.
-+
-+Those who don't use prepackaged drivers should make sure they also
-+install the (externally available) fxload utility.
-+
-+Installation:
-+""""""""""""
-+
-+apart from the standard 'make install' in the zaptel directory, 
-+run:
-+
-+  make -C xpp/utils install
-+
-+Alternatively, do the following manually:
-+
-+All firmware files should be copied to a new directory:
-+  /usr/share/zaptel/
-+
-+The xpp_fxloader and xpp_fxloader.usbmap should be copied to:
-+ /etc/hotplug/usb/
-+
-+In addition, the file xpp/xpp_modprobe contains optional modprobe settings.
-+It may be copied verbatim into /etc/modprobe.conf or (better) copied to
-+/etc/modprobe.d/ .
-+
-+
-+Note that loading through udev is not yet provided. Run 
-+
-+  /etc/hotplug/usb/xpp_fxloader xppdetect
-+
-+to load firmware.
-+
-+
-+Loading Firmware Details:
-+""""""""""""""""""""""""
- The Astribank needs a firmware loaded into it. Without the firmware, 
- the device will appear in lsusb with vendor ID 04b4 and product ID 8613
- The firmware is provided in the Intel hex format. It can be loaded using 
-@@ -21,12 +69,11 @@
- 'hotplug-utils' . 
- 
- To load the firmware automatically using the standard hotplug script, 
--place xpp/xpp_fxloader and xpp/xpp_fxloader.usermap in /etc/hotplug/usb
--and place xpp/FPGA_XPD.hex in /etc/xortel (or edit xpp_fxloader
--accordingly). 
-+place xpp/utils/xpp_fxloader and xpp/utils/xpp_fxloader.usermap in 
-+/etc/hotplug/usb and place xpp/utils/*.hex in /usr/share/zaptel .
- 
- Alternatively, xpp_fxloader when given the parameter 'xppdetect' will load 
--the firmware from /etc/xortel/FPGA_XPD.hex . You can use it to load the 
-+the firmwares from /usr/share/zaptel/ . You can use it to load the 
- firmware manually.
- 
- You should then get in lsusb the vendor ID e4e4 and device ID 2121
-@@ -128,6 +175,25 @@
- (There are a bunch of other status files under /proc/xpp/ )
- 
- 
-+Useful Module Parameters:
-+""""""""""""""""""""""""
-+zap_autoreg: (xpp)
-+Register spans automatically (1) or not (0). Default: 1. 
-+Unsetting this could be useful if you have several Astribanks and you 
-+want to set their registration order manually using zt_registration in 
-+the /proc interface.
-+
-+initialize_registers (xpd_fxs)
-+The script that is run to initilize registers of the device. The default is 
-+/usr/share/zaptel/initialize_registers . 
-+Setting this value could be useful if that location is inconvient for you.
-+
-+print_dbg: (all modules)
-+It will make the driver print tons of debugging messages. Can be sometime 
-+even handy, but overly-verbose in the case of xpp_usb. Can be safely 
-+set/unset at run-time using /sys/modules .
-+
-+
- 
- 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-LJNBCn_dist/xpp/slic.c
---- zaptel-1.2.6/xpp/slic.c	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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>
-- * Copyright (C) 2004-2005, Xorcom
-+ * Copyright (C) 2004-2006, Xorcom
-  *
-  * All rights reserved.
-  *
-@@ -23,13 +23,16 @@
- #include "xproto.h"
- #include "slic.h"
- 
--static const char rcsid[] = "$Id: slic.c 949 2006-02-15 02:24:18Z kpfleming $";
-+static const char rcsid[] = "$Id: slic.c 1097 2006-05-01 09:37:15Z oron $";
- 
- #ifdef	__KERNEL__
- #include <linux/module.h>
- 
- extern	int print_dbg;
- #include "zap_debug.h"
-+
-+DEF_PARM(charp,initialize_registers, "/usr/share/zaptel/initialize_registers", "The script to initialize detected cards slics");
-+
- #else
- #include <stdio.h>
- #endif
-@@ -120,6 +123,50 @@
- 
- #ifdef	__KERNEL__
- 
-+#define	MAX_ENV_STR	20
-+
-+int run_initialize_registers(xpd_t *xpd)
-+{
-+	int	ret;
-+	xbus_t	*xbus;
-+	char	busstr[MAX_ENV_STR];
-+	char	xpdstr[MAX_ENV_STR];
-+	char	typestr[MAX_ENV_STR];
-+	char	revstr[MAX_ENV_STR];
-+	char	*argv[] = {
-+		initialize_registers,
-+		NULL
-+	};
-+	char	*envp[] = {
-+		busstr,
-+		xpdstr,
-+		typestr,
-+		revstr,
-+		NULL
-+	};
-+
-+	BUG_ON(!xpd);
-+	xbus = xpd->xbus;
-+	if(!initialize_registers || !initialize_registers[0]) {
-+		NOTICE("%s/%s: No runtime register initialization\n", xbus->busname, xpd->xpdname);
-+		return 0;
-+	}
-+	DBG("%s/%s: running: '%s'\n", xbus->busname, xpd->xpdname, initialize_registers);
-+	snprintf(busstr, MAX_ENV_STR, "XPD_BUS=%s", xbus->busname);
-+	snprintf(xpdstr, MAX_ENV_STR, "XPD_NAME=%s", xpd->xpdname);
-+	snprintf(typestr, MAX_ENV_STR, "XPD_TYPE=%d", xpd->type);
-+	snprintf(revstr, MAX_ENV_STR, "XPD_REVISION=%d", xpd->revision);
-+	DBG("%s/%s: type=%d revision=%d\n", xbus->busname, xpd->xpdname, xpd->type, xpd->revision);
-+	ret = call_usermodehelper(initialize_registers, argv, envp, 1);
-+	if(ret != 0) {
-+		ERR("%s/%s: Failed running '%s' (errno %d, sig=%d)\n",
-+				xbus->busname, xpd->xpdname, initialize_registers,
-+				((unsigned)ret >> 8) & 0xFF, ret & 0xFF);
-+		ret = -EFAULT;
-+	}
-+	return ret;
-+}
-+
- 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-LJNBCn_dist/xpp/slic.h
---- zaptel-1.2.6/xpp/slic.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/slic.h	2006-07-02 17:17:18.812352000 +0300
-@@ -1,5 +1,26 @@
- #ifndef	SLIC_H
- #define	SLIC_H
-+/*
-+ * Written by Oron Peled <oron at actcom.co.il>
-+ * Copyright (C) 2004-2006, Xorcom
-+ *
-+ * All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
- 
- #include "xdefs.h"
- 
-@@ -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);
-+int run_initialize_registers(xpd_t *xpd);
- 
- 
- #endif	/* SLIC_H */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/slic_init.inc zaptel-xpp-LJNBCn_dist/xpp/slic_init.inc
---- zaptel-1.2.6/xpp/slic_init.inc	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/slic_init.inc	1970-01-01 02:00:00.000000000 +0200
-@@ -1,65 +0,0 @@
--// ----------------------------------==== 8-channel FXS unit initialization ===-----------------------------------------
--
--// INTERNAL PS
--// Change SLICs states to "Open state"s  (Off,all transfers tristated to avoid data collision), Voltage sense
--S_(0x000000FF,	0x04,	0x40, 0x00, 0x6C, 0x01),	
--
--
--// ------------------------------------- Initialization of indirect registers ------------------------------------------
--S_(0x000000FF,	0x02,	0x40, 0x00),	
--S_(0x000000FF,	0x18,	0x1C, 0xC2, 0x1D, 0x55, 0x1E, 0x00, 0x1C, 0xE6, 0x1D, 0x51, 0x1E, 0x01, 0x1C, 0x85, 0x1D, 0x4B, 0x1E, 0x02, 0x1C, 0x37, 0x1D, 0x49, 0x1E, 0x03),	
--S_(0x000000FF,	0x18,	0x1C, 0x33, 0x1D, 0x33, 0x1E, 0x04, 0x1C, 0x02, 0x1D, 0x02, 0x1E, 0x05, 0x1C, 0x02, 0x1D, 0x02, 0x1E, 0x06, 0x1C, 0x98, 0x1D, 0x01, 0x1E, 0x07),	
--S_(0x000000FF,	0x18,	0x1C, 0x98, 0x1D, 0x01, 0x1E, 0x08, 0x1C, 0x11, 0x1D, 0x06, 0x1E, 0x09, 0x1C, 0x02, 0x1D, 0x02, 0x1E, 0x0A, 0x1C, 0xE5, 0x1D, 0x00, 0x1E, 0x0B),	
--S_(0x000000FF,	0x18,	0x1C, 0x1C, 0x1D, 0x0A, 0x1E, 0x0C, 0x1C, 0x30, 0x1D, 0x7B, 0x1E, 0x0D, 0x1C, 0x63, 0x1D, 0x00, 0x1E, 0x0E, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x0F),	
--
--S_(0x000000FF,	0x18,	0x1C, 0x70, 0x1D, 0x78, 0x1E, 0x10, 0x1C, 0x7D, 0x1D, 0x00, 0x1E, 0x11, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x12, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x13),	
--S_(0x000000FF,	0x18,	0x1C, 0xF0, 0x1D, 0x7E, 0x1E, 0x14, 0x1C, 0x60, 0x1D, 0x01, 0x1E, 0x15, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x16, 0x1C, 0x00, 0x1D, 0x20, 0x1E, 0x17),	
--S_(0x000000FF,	0x18,	0x1C, 0x00, 0x1D, 0x20, 0x1E, 0x18, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x19, 0x1C, 0x00, 0x1D, 0x40, 0x1E, 0x1A, 0x1C, 0x00, 0x1D, 0x40, 0x1E, 0x1B),	
--S_(0x000000FF,	0x18,	0x1C, 0x00, 0x1D, 0x18, 0x1E, 0x1C, 0x1C, 0x00, 0x1D, 0x40, 0x1E, 0x1D, 0x1C, 0x00, 0x1D, 0x10, 0x1E, 0x1E, 0x1C, 0x80, 0x1D, 0x00, 0x1E, 0x1F),	
--
--S_(0x000000FF,	0x18,	0x1C, 0xF4, 0x1D, 0x0F, 0x1E, 0x20, 0x1C, 0x7E, 0x1D, 0x6E, 0x1E, 0x21, 0x1C, 0xF4, 0x1D, 0x0F, 0x1E, 0x22, 0x1C, 0x00, 0x1D, 0x88, 0x1E, 0x23),	
--S_(0x000000FF,	0x18,	0x1C, 0x20, 0x1D, 0x03, 0x1E, 0x24, 0x1C, 0x12, 0x1D, 0x00, 0x1E, 0x25, 0x1C, 0x12, 0x1D, 0x00, 0x1E, 0x26, 0x1C, 0x12, 0x1D, 0x00, 0x1E, 0x27),	
--S_(0x000000FF,	0x12,	0x1C, 0x00, 0x1D, 0x0C, 0x1E, 0x28, 0x1C, 0x00, 0x1D, 0x0C, 0x1E, 0x29, 0x1C, 0x00, 0x1D, 0x08, 0x1E, 0x2B),	
--
--S_(0x000000FF,	0x18,	0x1C, 0xDA, 0x1D, 0x00, 0x1E, 0x63, 0x1C, 0x60, 0x1D, 0x6B, 0x1E, 0x64, 0x1C, 0x74, 0x1D, 0x00, 0x1E, 0x65, 0x1C, 0xC0, 0x1D, 0x79, 0x1E, 0x66),	
--S_(0x000000FF,	0x0C,	0x1C, 0x20, 0x1D, 0x11, 0x1E, 0x67, 0x1C, 0xE0, 0x1D, 0x3B, 0x1E, 0x68),	
--
--// ------------------------------------- Initialization of direct registers --------------------------------------------
--
--// Mode(8-bit,u-Law,1 PCLK ) setting, Loopbacks and Interrupts clear
--// --Temporary digital loopback
--S_(0x000000FF,	0x08,	0x01, 0x29, 0x08, 0x00, 0x09, 0x00, 0x0E, 0x00),	
--S_(0x000000FF,	0x0C,	0x15, 0x00, 0x16, 0x03, 0x17, 0x00, 0x12, 0xFF, 0x13, 0xFF, 0x14, 0xFF),	
--
--// Ring timers settings
--S_(0x000000FF,	0x06,	0x30, 0x80, 0x31, 0x3E, 0x32, 0x80),	
--S_(0x000000FF,	0x02,	0x33, 0x3E),	
--S_(0x000000FF,	0x02,	0x22, 0x18),	
--
--// Battery feed control(DCSW), Automatic control of Ring Trip and Loop Closure, VBATH, VBATL
--S_(0x000000FF,	0x02,	0x42, 0x00),	
--S_(0x000000FF,	0x02,	0x43, 0x1E),	
--S_(0x000000FF,	0x04,	0x4A, 0x31, 0x4B, 0x10),	
--
--S_(0x000000FF,	0x02,	0x45, 0x0A),	
--S_(0x000000FF,	0x02,	0x46, 0x0B),	
--S_(0x000000FF,	0x02,	0x47, 0x07),	
--
--
--// Setting of SLICs offsets
--S_(0x00000001,	0x08,	0x02, 0x01, 0x03, 0x00, 0x04, 0x01, 0x05, 0x00),	
--S_(0x00000002,	0x08,	0x02, 0x09, 0x03, 0x00, 0x04, 0x09, 0x05, 0x00),	
--S_(0x00000004,	0x08,	0x02, 0x11, 0x03, 0x00, 0x04, 0x11, 0x05, 0x00),	
--S_(0x00000008,	0x08,	0x02, 0x19, 0x03, 0x00, 0x04, 0x19, 0x05, 0x00),	
--S_(0x00000010,	0x08,	0x02, 0x21, 0x03, 0x00, 0x04, 0x21, 0x05, 0x00),	
--S_(0x00000020,	0x08,	0x02, 0x29, 0x03, 0x00, 0x04, 0x29, 0x05, 0x00),	
--S_(0x00000040,	0x08,	0x02, 0x31, 0x03, 0x00, 0x04, 0x31, 0x05, 0x00),	
--S_(0x00000080,	0x08,	0x02, 0x39, 0x03, 0x00, 0x04, 0x39, 0x05, 0x00),	
--
--// Change SLICs states to "Normal state"s (On, after offsets are set already)
--
--
--S_(0x000000FF,	0x02,	0x40, 0x1),	
--S_(0x000000FF,	0x02,	0x42, 0x06),	
--// -------------------------------------------------------------
--
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/supress/ec_xpp.h zaptel-xpp-LJNBCn_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-LJNBCn_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__
-+
-+#ifdef __KERNEL__
-+#	include <linux/kernel.h>
-+#	include <linux/slab.h>
-+#	define EC_MALLOC(a) kmalloc((a), GFP_ATOMIC)
-+#	define EC_FREE(a) kfree(a)
-+#	define printf printk
-+#else
-+#	include <stdlib.h>
-+#	include <unistd.h>
-+#	include <stdint.h>
-+#	include <string.h>
-+#include <math.h>
-+#	define EC_MALLOC(a) malloc(a)
-+#	define EC_FREE(a) free(a)
-+#endif
-+
-+#include "suppressor.c"
-+
-+typedef struct {
-+#define	XPP_EC_MAGIC	0xfee1dead
-+	int	magic;
-+	int	objSize;
-+	void*	pEchoSuppressionObj;
-+} xpp_echo_can_state_t;
-+
-+static inline echo_can_state_t* xpp_echo_can_create(int len, int adaption_mode)
-+{
-+	xpp_echo_can_state_t	*state;
-+	ES_WINDOW_SIZE_ID	currentWindowId;
-+	
-+	DBG("EC: len=%d adaption_mode=%d\n", len, adaption_mode);
-+	switch (len) {
-+		case 32:	currentWindowId = ES_WINDOW_SIZE_ID_32_MSEC;	break;
-+		case 64:	currentWindowId = ES_WINDOW_SIZE_ID_64_MSEC;	break;
-+		case 128:	currentWindowId = ES_WINDOW_SIZE_ID_128_MSEC;	break;
-+		case 256:	currentWindowId = ES_WINDOW_SIZE_ID_256_MSEC;	break;
-+		default:
-+				NOTICE("%s: Unknown len=%d\n", __FUNCTION__, len);
-+				currentWindowId = ES_WINDOW_SIZE_ID_64_MSEC;	break;
-+	}
-+
-+	if ( 0 == (state = EC_MALLOC(sizeof(*state)) ))
-+		return NULL;
-+	
-+	if (0 > (state->objSize = ES_GetObjectSize(currentWindowId))){
-+		EC_FREE(state);
-+		return NULL;
-+	}
-+		
-+	if (NULL == (state->pEchoSuppressionObj = EC_MALLOC(state->objSize))) {
-+		EC_FREE(state);
-+		return NULL;
-+	}
-+		
-+	if ( !ES_Initialize(state->pEchoSuppressionObj, currentWindowId, ES_HYBRID_LOSS_LEVEL_6_DB)){
-+		EC_FREE(state->pEchoSuppressionObj);
-+		EC_FREE(state);
-+		return NULL;
-+	}
-+	state->magic = XPP_EC_MAGIC;
-+	return (echo_can_state_t *)state;
-+}
-+
-+static inline void xpp_echo_can_free(echo_can_state_t *ec)
-+{
-+	xpp_echo_can_state_t	*mystate;
-+
-+	DBG("EC: %p\n", ec);
-+	if (!ec)
-+		return;
-+	mystate = (xpp_echo_can_state_t *)ec;
-+	if(mystate->magic != XPP_EC_MAGIC) {
-+		ERR("%s: corrupted EC\n", __FUNCTION__);
-+		return;
-+	}
-+	ES_Reset(mystate->pEchoSuppressionObj);
-+	EC_FREE(mystate);
-+}
-+
-+static inline int16_t xpp_echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx)
-+{
-+	xpp_echo_can_state_t	*mystate;
-+
-+	if(!ec) {
-+		ERR("%s: missing EC\n", __FUNCTION__);
-+		return -EINVAL;
-+	}
-+	mystate = (xpp_echo_can_state_t *)ec;
-+	if(mystate->magic != XPP_EC_MAGIC) {
-+		ERR("%s: corrupted EC\n", __FUNCTION__);
-+		return -EINVAL;
-+	}
-+	return ES_ProcessSamples(mystate->pEchoSuppressionObj, tx, rx);
-+}
-+
-+#endif
-+
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/supress/suppressor.c zaptel-xpp-LJNBCn_dist/xpp/supress/suppressor.c
---- zaptel-1.2.6/xpp/supress/suppressor.c	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/supress/suppressor.c	2006-06-25 14:42:21.798100000 +0300
-@@ -0,0 +1,321 @@
-+ /***********************************************************************
-+ * Written by Sergey Serik.
-+ * Copyright (C) 2006, Xorcom Ltd.
-+ * All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ ***********************************************************************/
-+
-+
-+
-+#include "suppressor.h"
-+
-+#define PRINTF(fmt, ...)
-+
-+static inline ES_BOOL IsFirstMoreThanSecond(
-+	ES_LONG_VALUE*			pFirstValue,
-+	ES_LONG_VALUE*			pSecondValue)
-+{
-+    if(   (pFirstValue->integer > pSecondValue->integer)
-+       || (   (pFirstValue->integer == pSecondValue->integer)
-+		   && (pFirstValue->fractional > pSecondValue->fractional)))
-+	{
-+       return ES_TRUE;
-+	}
-+
-+    return ES_FALSE;
-+}
-+
-+
-+static inline ES_BOOL IsFirstLessThanSecond(
-+	ES_LONG_VALUE*			pFirstValue,
-+	ES_LONG_VALUE*			pSecondValue)
-+{
-+    if(   (pFirstValue->integer < pSecondValue->integer)
-+       || (   (pFirstValue->integer == pSecondValue->integer)
-+		   && (pFirstValue->fractional < pSecondValue->fractional)))
-+	{
-+       return ES_TRUE;
-+	}
-+
-+    return ES_FALSE;
-+}
-+
-+static inline ES_LONG_VALUE* MultiplyByFactor(
-+	ES_LONG_VALUE*		pValue,
-+	ES_LONG_VALUE*		pNewValue,
-+	int					factor)
-+{
-+	pNewValue->integer    = pValue->integer * factor + (pValue->fractional * factor) / ES_ALFA_INT;
-+	pNewValue->fractional = (pValue->fractional * factor) % ES_ALFA_INT;
-+
-+	return pNewValue;
-+}
-+
-+static inline int GetWindowSize(
-+	ES_WINDOW_SIZE_ID		sizeId)
-+{
-+	switch(sizeId)
-+	{
-+	case ES_WINDOW_SIZE_ID_4_MSEC:
-+		return ES_SAMPLES_IN_4_MSEC;
-+
-+	case ES_WINDOW_SIZE_ID_8_MSEC:
-+		return ES_SAMPLES_IN_8_MSEC;
-+
-+	case ES_WINDOW_SIZE_ID_16_MSEC:
-+		return ES_SAMPLES_IN_16_MSEC;
-+
-+	case ES_WINDOW_SIZE_ID_32_MSEC:
-+		return ES_SAMPLES_IN_32_MSEC;
-+
-+	case ES_WINDOW_SIZE_ID_64_MSEC:
-+		return ES_SAMPLES_IN_64_MSEC;
-+
-+	case ES_WINDOW_SIZE_ID_128_MSEC:
-+		return ES_SAMPLES_IN_128_MSEC;
-+
-+	case ES_WINDOW_SIZE_ID_256_MSEC:
-+		return ES_SAMPLES_IN_256_MSEC;
-+
-+	default:
-+		PRINTF("GetWindowSize - error: unsupported Search Window Size ID <%d>\n", sizeId);
-+		return -1;
-+	}
-+}
-+
-+static inline void ObtainFarMaximum(
-+	SUPPRESSOR*	pES_Obj)
-+{
-+    if(pES_Obj->tailIndex == pES_Obj->maximalFar.index)
-+    {
-+        if(IsFirstMoreThanSecond(&pES_Obj->maximalFar.value, &pES_Obj->previousFar))
-+        {
-+			int n;
-+
-+			memset(&pES_Obj->maximalFar, 0, sizeof(pES_Obj->maximalFar));
-+
-+			for(n = 0; n < pES_Obj->windowSize; n++)
-+			{
-+				if(IsFirstMoreThanSecond(&pES_Obj->pHistoryOfFar[n], &pES_Obj->maximalFar.value))
-+				{
-+					pES_Obj->maximalFar.value.integer	 = pES_Obj->pHistoryOfFar[n].integer;
-+					pES_Obj->maximalFar.value.fractional = pES_Obj->pHistoryOfFar[n].fractional;
-+					pES_Obj->maximalFar.index = n;
-+				}
-+			}
-+        }
-+        else
-+        {
-+            pES_Obj->maximalFar.value.integer	 = pES_Obj->previousFar.integer;
-+			pES_Obj->maximalFar.value.fractional = pES_Obj->previousFar.fractional;
-+        }
-+    }
-+    else if(IsFirstLessThanSecond(&pES_Obj->maximalFar.value, &pES_Obj->previousFar))
-+    {
-+        pES_Obj->maximalFar.value.integer	 = pES_Obj->previousFar.integer;
-+		pES_Obj->maximalFar.value.fractional = pES_Obj->previousFar.fractional;
-+        pES_Obj->maximalFar.index			 = pES_Obj->tailIndex;
-+    }
-+}
-+
-+int ES_GetObjectSize(
-+	ES_WINDOW_SIZE_ID		sizeId)
-+{
-+	int longValueSize = sizeof(ES_LONG_VALUE);
-+	switch(sizeId)
-+	{
-+	case ES_WINDOW_SIZE_ID_4_MSEC:
-+		return (sizeof(SUPPRESSOR) + ES_SAMPLES_IN_4_MSEC * longValueSize - longValueSize);
-+
-+	case ES_WINDOW_SIZE_ID_8_MSEC:
-+		return (sizeof(SUPPRESSOR) + ES_SAMPLES_IN_8_MSEC * longValueSize - longValueSize);
-+
-+	case ES_WINDOW_SIZE_ID_16_MSEC:
-+		return (sizeof(SUPPRESSOR) + ES_SAMPLES_IN_16_MSEC * longValueSize - longValueSize);
-+
-+	case ES_WINDOW_SIZE_ID_32_MSEC:
-+		return (sizeof(SUPPRESSOR) + ES_SAMPLES_IN_32_MSEC * longValueSize - longValueSize);
-+
-+	case ES_WINDOW_SIZE_ID_64_MSEC:
-+		return (sizeof(SUPPRESSOR) + ES_SAMPLES_IN_64_MSEC * longValueSize - longValueSize);
-+
-+	case ES_WINDOW_SIZE_ID_128_MSEC:
-+		return (sizeof(SUPPRESSOR) + ES_SAMPLES_IN_128_MSEC * longValueSize - longValueSize);
-+
-+	case ES_WINDOW_SIZE_ID_256_MSEC:
-+		return (sizeof(SUPPRESSOR) + ES_SAMPLES_IN_256_MSEC * longValueSize - longValueSize);
-+
-+	default:
-+		PRINTF("ES_GetObjectSize - error: unsupported Search Window Size ID <%d>\n", sizeId);
-+		return -1;
-+	}
-+}
-+
-+ES_BOOL ES_Initialize(
-+	void*					pObject,
-+	ES_WINDOW_SIZE_ID		sizeId,
-+	ES_HYBRID_LOSS_LEVEL	level)
-+{
-+	SUPPRESSOR* pES_Obj = (SUPPRESSOR*) pObject;
-+	int				 objectSize;
-+
-+	if(NULL == pES_Obj)
-+	{
-+		PRINTF("ES_Initialize - error: wrong pObject value <NULL>\n");
-+		return ES_FALSE;
-+	}
-+
-+	if(0 > (objectSize = ES_GetObjectSize(sizeId)))
-+	{
-+		PRINTF("ES_Initialize - error: on ES_GetObjectSize(%d) call\n", sizeId);
-+		pES_Obj->initialized = ES_FALSE;
-+		return ES_FALSE;
-+	}
-+
-+	memset(pES_Obj, 0, objectSize);
-+
-+    switch(level)
-+    {
-+    case ES_HYBRID_LOSS_LEVEL_0_DB:
-+        pES_Obj->comparer.factorNear		 = ES_COMPARE_MULTI_0_DB_NEAR;
-+        pES_Obj->comparer.factorFar			 = ES_COMPARE_MULTI_0_DB_FAR;
-+        pES_Obj->doubleTalkDetectionCountMax = ES_MAX_DTD_COUNT_0_DB;
-+		pES_Obj->echoDetectionCountMax		 = ES_MAX_DTD_COUNT_0_DB;
-+        break;
-+
-+    case ES_HYBRID_LOSS_LEVEL_3_DB:
-+        pES_Obj->comparer.factorNear		 = ES_COMPARE_MULTI_3_DB_NEAR;
-+        pES_Obj->comparer.factorFar			 = ES_COMPARE_MULTI_3_DB_FAR;
-+        pES_Obj->doubleTalkDetectionCountMax = ES_MAX_DTD_COUNT_3_DB;
-+		pES_Obj->echoDetectionCountMax		 = ES_MAX_DTD_COUNT_3_DB;
-+        break;
-+
-+    case ES_HYBRID_LOSS_LEVEL_6_DB:
-+        pES_Obj->comparer.factorNear		 = ES_COMPARE_MULTI_6_DB_NEAR;
-+        pES_Obj->comparer.factorFar			 = ES_COMPARE_MULTI_6_DB_FAR;
-+        pES_Obj->doubleTalkDetectionCountMax = ES_MAX_DTD_COUNT_6_DB;
-+		pES_Obj->echoDetectionCountMax		 = ES_MAX_DTD_COUNT_6_DB;
-+		break;
-+
-+	default:
-+		PRINTF("ES_Initialize - error: unsupported Hybrid Loss Level <%d>\n", level);
-+		return ES_FALSE;
-+    }
-+
-+	pES_Obj->windowSize = GetWindowSize(sizeId);
-+
-+    return (pES_Obj->initialized = ES_TRUE);
-+}
-+
-+
-+ES_BOOL ES_Reset(
-+	void*					pObject)
-+{
-+	SUPPRESSOR*	pES_Obj = (SUPPRESSOR*) pObject;
-+
-+	if(NULL == pES_Obj)
-+	{
-+		PRINTF("ES_Reset - error: wrong pObject value <NULL>\n");
-+		return ES_FALSE;
-+	}
-+
-+	if(!pES_Obj->initialized)
-+	{
-+		PRINTF("ES_Reset - error: the pObject is not initialized\n");
-+		return ES_FALSE;
-+	}
-+
-+	memset(pES_Obj->pHistoryOfFar, 0, pES_Obj->windowSize * sizeof(ES_LONG_VALUE));
-+	return ES_TRUE;
-+}
-+
-+
-+short ES_NEAR_CLEAN ES_ProcessSamples(
-+	void*					pObject,
-+	ES_FAR_CLEAN short		farSample,
-+	ES_NEAR_MIX  short		nearSample)
-+{
-+	SUPPRESSOR*	pES_Obj = (SUPPRESSOR*) pObject;
-+	unsigned long		temp;
-+	ES_LONG_VALUE		newNear, newFar;
-+
-+	if(NULL == pES_Obj)
-+	{
-+		PRINTF("ES_ProcessSamples - error: wrong pObject value <NULL>\n");
-+		return nearSample;
-+	}
-+
-+    if(!pES_Obj->initialized)
-+	{
-+		PRINTF("ES_ProcessSamples - error: the pObject is not initialized\n");
-+        return nearSample;
-+	}
-+
-+    temp = pES_Obj->previousNear.integer % ES_ALFA_INT + pES_Obj->previousNear.fractional;
-+    pES_Obj->previousNear.fractional = temp % ES_ALFA_INT;
-+    pES_Obj->previousNear.integer	 =  (ES_ALFA_INT - 1) * pES_Obj->previousNear.integer / ES_ALFA_INT
-+									  + temp / ES_ALFA_INT + pES_Obj->moduleOfPreviousNear;
-+
-+    temp = pES_Obj->previousFar.integer % ES_ALFA_INT + pES_Obj->previousFar.fractional;
-+    pES_Obj->previousFar.fractional	= temp % ES_ALFA_INT;
-+    pES_Obj->previousFar.integer	=  (ES_ALFA_INT - 1) * pES_Obj->previousFar.integer / ES_ALFA_INT
-+									 + temp / ES_ALFA_INT + pES_Obj->moduleOfPreviousFar;
-+
-+    pES_Obj->pHistoryOfFar[pES_Obj->tailIndex].integer	  = pES_Obj->previousFar.integer;
-+	pES_Obj->pHistoryOfFar[pES_Obj->tailIndex].fractional = pES_Obj->previousFar.fractional;
-+
-+    pES_Obj->moduleOfPreviousNear = nearSample * ((nearSample < 0) ? -1 : 1);
-+    pES_Obj->moduleOfPreviousFar = farSample  * ((farSample  < 0) ? -1 : 1);
-+
-+    ObtainFarMaximum(pES_Obj);
-+
-+    if(IsFirstLessThanSecond(MultiplyByFactor(&pES_Obj->previousNear, &newNear, pES_Obj->comparer.factorNear),
-+							 MultiplyByFactor(&pES_Obj->maximalFar.value, &newFar, pES_Obj->comparer.factorFar)))
-+    {
-+		if(0 == pES_Obj->echoDetectionCount)
-+		{
-+			nearSample /= ES_DIVISOR_VALUE;
-+			pES_Obj->doubleTalkDetectionCount = pES_Obj->doubleTalkDetectionCountMax;
-+		}
-+		else
-+		{
-+			pES_Obj->echoDetectionCount--;
-+			pES_Obj->doubleTalkDetectionCount = 0;
-+		}
-+    }
-+    else
-+	{
-+		pES_Obj->echoDetectionCount = pES_Obj->echoDetectionCountMax;
-+
-+		if(0 < pES_Obj->doubleTalkDetectionCount)
-+		{
-+			if(IsFirstLessThanSecond(MultiplyByFactor(&pES_Obj->maximalFar.value, &newFar, pES_Obj->comparer.factorFar + 1),
-+									 MultiplyByFactor(&pES_Obj->previousNear, &newNear, pES_Obj->comparer.factorNear)))
-+			{
-+				pES_Obj->doubleTalkDetectionCount = 0;
-+			}
-+			else
-+			{
-+				pES_Obj->doubleTalkDetectionCount--;
-+				nearSample /= ES_DIVISOR_VALUE;
-+			}
-+		}
-+	}
-+
-+    pES_Obj->tailIndex = (pES_Obj->tailIndex + 1) % pES_Obj->windowSize;
-+
-+    return nearSample;
-+}
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/supress/suppressor.h zaptel-xpp-LJNBCn_dist/xpp/supress/suppressor.h
---- zaptel-1.2.6/xpp/supress/suppressor.h	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/supress/suppressor.h	2006-06-25 14:42:21.798100000 +0300
-@@ -0,0 +1,160 @@
-+#if 0  /* File Header */
-+************************************************************************
-+ * Copyright (C) 2006, Xorcom Ltd.
-+ * All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+************************************************************************
-+#endif /* File Header */
-+
-+
-+#ifndef __SUPPRESSOR_H__
-+#define __SUPPRESSOR_H__
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+
-+#ifndef WIN32
-+#define FILE void
-+#endif
-+
-+#define ES_NEAR_MIX
-+#define ES_NEAR_CLEAN
-+#define ES_FAR_CLEAN
-+
-+#define ES_ALFA_INT					32  
-+
-+#define ES_DIVISOR_VALUE			64	
-+
-+#define ES_MAX_DTD_COUNT_6_DB		16  
-+#define ES_MAX_DTD_COUNT_3_DB		32  
-+#define ES_MAX_DTD_COUNT_0_DB		64  
-+
-+#define ES_COMPARE_MULTI_6_DB_NEAR	2	
-+#define ES_COMPARE_MULTI_6_DB_FAR	1	
-+
-+#define ES_COMPARE_MULTI_3_DB_NEAR	3
-+#define ES_COMPARE_MULTI_3_DB_FAR	2
-+
-+#define ES_COMPARE_MULTI_0_DB_NEAR	1
-+#define ES_COMPARE_MULTI_0_DB_FAR	1
-+
-+#define ES_SAMPLES_IN_4_MSEC		(4 * 8)
-+#define ES_SAMPLES_IN_8_MSEC		(8 * 8)
-+#define ES_SAMPLES_IN_16_MSEC		(16 * 8)
-+#define ES_SAMPLES_IN_32_MSEC		(32 * 8)
-+#define ES_SAMPLES_IN_64_MSEC		(64 * 8)
-+#define ES_SAMPLES_IN_128_MSEC		(128 * 8)
-+#define ES_SAMPLES_IN_256_MSEC		(256 * 8)
-+
-+
-+typedef enum
-+{
-+	ES_FALSE						= 0,
-+	ES_TRUE							= 1
-+}
-+ES_BOOL;
-+
-+
-+typedef enum
-+{
-+    ES_HYBRID_LOSS_LEVEL_6_DB		= 0,
-+    ES_HYBRID_LOSS_LEVEL_3_DB		= 1,
-+    ES_HYBRID_LOSS_LEVEL_0_DB		= 2
-+}
-+ES_HYBRID_LOSS_LEVEL;
-+
-+
-+typedef	enum
-+{
-+	ES_WINDOW_SIZE_ID_4_MSEC		= 0,
-+	ES_WINDOW_SIZE_ID_8_MSEC		= 1,
-+	ES_WINDOW_SIZE_ID_16_MSEC		= 2,
-+	ES_WINDOW_SIZE_ID_32_MSEC		= 3,
-+	ES_WINDOW_SIZE_ID_64_MSEC		= 4,
-+	ES_WINDOW_SIZE_ID_128_MSEC		= 5,
-+	ES_WINDOW_SIZE_ID_256_MSEC		= 6
-+}
-+ES_WINDOW_SIZE_ID;
-+
-+
-+typedef struct
-+{
-+    unsigned char					factorNear;
-+    unsigned char					factorFar;
-+}
-+ES_COMPARER;
-+
-+
-+typedef struct
-+{
-+    unsigned long					integer;
-+    unsigned long					fractional;
-+}
-+ES_LONG_VALUE;
-+
-+
-+typedef struct
-+{
-+	int								index;
-+	ES_LONG_VALUE					value;
-+}
-+ES_MAXIMAL_FAR;
-+
-+
-+typedef struct
-+{
-+    ES_BOOL							initialized;
-+	int								windowSize;
-+	ES_MAXIMAL_FAR					maximalFar;
-+    int								moduleOfPreviousFar;
-+    ES_LONG_VALUE					previousFar;
-+    int								moduleOfPreviousNear;
-+    ES_LONG_VALUE					previousNear;
-+    int								tailIndex;
-+    int								doubleTalkDetectionCount;
-+    int								doubleTalkDetectionCountMax;
-+	int								echoDetectionCount;
-+    int								echoDetectionCountMax;
-+    ES_COMPARER						comparer;
-+	ES_LONG_VALUE					pHistoryOfFar[1];
-+}
-+SUPPRESSOR;
-+
-+
-+static inline int ES_GetObjectSize(
-+	ES_WINDOW_SIZE_ID				sizeId);
-+
-+static inline ES_BOOL ES_Initialize(
-+	void*							pObject,
-+	ES_WINDOW_SIZE_ID				sizeId,
-+	ES_HYBRID_LOSS_LEVEL			level);
-+
-+static inline ES_BOOL ES_Reset(
-+	void*							pObject);
-+
-+static inline short ES_NEAR_CLEAN ES_ProcessSamples(
-+	void*							pObject,
-+	ES_FAR_CLEAN short				farSample,
-+	ES_NEAR_MIX  short				nearSample);
-+
-+
-+#if __cplusplus
-+}
-+#endif
-+
-+#endif /* __SUPPRESSOR_H__ */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/sync.sh zaptel-xpp-LJNBCn_dist/xpp/sync.sh
---- zaptel-1.2.6/xpp/sync.sh	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/sync.sh	1970-01-01 02:00:00.000000000 +0200
-@@ -1,31 +0,0 @@
--#!/bin/sh
--
--set -e
--
--SVN_ROOT=/home/tzafrir/Proj/Svn
--XORTEL_DIR=$SVN_ROOT/xpp-zaptel/trunk/xortel
--XPP_DIR=$SVN_ROOT/xpp-zaptel/trunk/zaptel/xpp
--TARGET_DIR=xpp
--FIRMWARE=$SVN_ROOT/fpgafirmware/init.dat
--
--curdir=$PWD
--cd $XORTEL_DIR
--  cd ..; svn update; 
--  cd xortel
--  make FIRMWARE="$FIRMWARE" ../zaptel/xpp/slic_init.inc
--cd $curdir
--
--cp -a $XORTEL_DIR/FPGA_XPD.hex ${TARGET_DIR}/
--cp -a $XORTEL_DIR/xpd.h ${TARGET_DIR}/
--cp -a $XORTEL_DIR/xpp_zap.[ch] ${TARGET_DIR}/
--cp -a $XORTEL_DIR/xproto.[ch] ${TARGET_DIR}/
--cp -a $XORTEL_DIR/xdefs.h ${TARGET_DIR}/
--cp -a $XORTEL_DIR/xpp_usb.c ${TARGET_DIR}/
--cp -a $XORTEL_DIR/zap_debug.[ch] ${TARGET_DIR}/
--cp -a $XORTEL_DIR/slic.[ch] ${TARGET_DIR}/
--cp -a $XORTEL_DIR/card_*.[ch] ${TARGET_DIR}/
--cp -a $XORTEL_DIR/xpp_fxloader{,.usermap} ${TARGET_DIR}/
--cp -a $XORTEL_DIR/xpp_modprobe ${TARGET_DIR}/
--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-LJNBCn_dist/xpp/utils/FPGA_FXS.hex
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/fpga_load.8 zaptel-xpp-LJNBCn_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-LJNBCn_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" "" ""
-+
-+.SH NAME
-+ztcfg \- reads and loads zaptel.conf
-+.SH SYNOPSIS
-+
-+.B fpga_load 
-+[\fB-g\fR|\fB-d\fR] [\fB-v\fR] \fB-D\fR/proc/bus/usb/\fIBUS/DEV\fR 
-+
-+.B fpga_load 
-+[\fB-g\fR] [\fB-v\fR] \fB-D\fR/proc/bus/usb/\fIBUS/DEV\fR \fB-I \fIfirmware.hex\fR [\fB-b \fIdump.bin\fR]
-+
-+.B fpga_load -h
-+
-+.SH DESCRIPTION
-+.B fpga_load 
-+loads the FPGA firmware to the Xorcom Astribank device.
-+The syntax resembles that of fxload(8).
-+
-+.SH OPTIONS
-+.B -d
-+.I dump.bin
-+.RS
-+Before writing firmware, bump the processed binary file to 
-+.I dump.bin\fR.
-+.RE
-+
-+.B -d
-+.RS
-+Print Version number bytes from eeprom (to standard output). Implies -g.
-+.RE
-+
-+.B -D 
-+.I DEVICE
-+.RS
-+Required. The device to read from/write to. This is normally 
-+/proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR , where \fIbus_num\fR and 
-+\fIdevice_num\fR are the first two numbers in the output of lsusb(8).
-+.RE
-+
-+.B -g
-+.RS
-+Dump all eeprom data to standard error.
-+.RE
-+
-+.B -I
-+.I fireware_file
-+.RS
-+The firmware file to write to the device.
-+.RE
-+
-+.B -v
-+.RS
-+Be verobse.
-+.RE
-+
-+.B -h
-+.RS
-+Displays usage message.
-+.RE
-+
-+.SH SEE ALSO
-+fxload(8), lsusb(8)
-+
-+.SH AUTHOR
-+This manual page was written by Tzafrir Cohen <tzafrir.cohen at xorcom.com> .
-+Permission is granted to copy, distribute and/or modify this document under
-+the terms of the GNU General Public License, Version 2 any 
-+later version published by the Free Software Foundation.
-+
-+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-LJNBCn_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-LJNBCn_dist/xpp/utils/fpga_load.c	2006-06-01 11:50:28.294045000 +0300
-@@ -0,0 +1,822 @@
-+#include <stdio.h>
-+#include <assert.h>
-+#include <string.h>
-+#include <stdint.h>
-+#include <errno.h>
-+#include <sys/types.h>
-+#include <sys/param.h>
-+#include <usb.h>
-+#include "hexfile.h"
-+
-+static const char rcsid[] = "$Id: fpga_load.c 1304 2006-06-01 08:50:28Z tzafrir $";
-+
-+#define	ERR(fmt, arg...)	fprintf(stderr, "%s: ERROR: " fmt, progname, ## arg)
-+#define	INFO(fmt, arg...)	fprintf(stderr, "%s: " fmt, progname, ## arg)
-+
-+static int	verbose = LOG_WARNING;
-+static char	*progname;
-+
-+#define	MAX_HEX_LINES	2000
-+#define	PACKET_SIZE	512
-+#define	EEPROM_SIZE	16
-+#define	SERIAL_SIZE	8
-+
-+enum fpga_load_packet_types {
-+	STATUS_REPLY	= 0x01,
-+	DATA_PACKET	= 0x01,
-+#ifdef	XORCOM_INTERNAL
-+	EEPROM_SET	= 0x04,
-+#endif
-+	EEPROM_GET	= 0x08,
-+	RENUMERATE	= 0x10,
-+	BAD_COMMAND	= 0xAA
-+};
-+
-+struct myeeprom {
-+	uint8_t		source;
-+	uint16_t	vendor;
-+	uint16_t	product;
-+	uint8_t		release_major;
-+	uint8_t		release_minor;
-+	uint8_t		reserved;
-+	uint8_t		serial[SERIAL_SIZE];
-+} PACKED;
-+
-+struct fpga_packet_header {
-+	struct {
-+		uint8_t		op;
-+	} PACKED header;
-+	union {
-+		struct {
-+			uint16_t	seq;
-+			uint8_t		status;
-+		} PACKED status_reply;
-+		struct {
-+			uint16_t	seq;
-+			uint8_t		reserved;
-+			uint8_t		data[ZERO_SIZE];
-+		} PACKED data_packet;
-+		struct {
-+			struct myeeprom		data;
-+		} PACKED eeprom_set;
-+		struct {
-+			struct myeeprom		data;
-+		} PACKED eeprom_get;
-+	} d;
-+} PACKED;
-+
-+enum fpga_load_status {
-+	FW_FAIL_RESET	= 1,
-+	FW_FAIL_TRANS	= 2,
-+	FW_TRANS_OK	= 4,
-+	FW_CONFIG_DONE	= 8
-+};
-+
-+int my_usb_device(struct usb_device *dev, usb_dev_handle *handle);
-+
-+const char *load_status2str(enum fpga_load_status s)
-+{
-+	switch(s) {
-+		case FW_FAIL_RESET: return "FW_FAIL_RESET";
-+		case FW_FAIL_TRANS: return "FW_FAIL_TRANS";
-+		case FW_TRANS_OK: return "FW_TRANS_OK";
-+		case FW_CONFIG_DONE: return "FW_CONFIG_DONE";
-+		default: return "UNKNOWN";
-+	}
-+}
-+
-+int path_of_dev(char buf[], unsigned int buflen, struct usb_device *dev)
-+{
-+	return snprintf(buf, buflen, "/proc/bus/usb/%s/%s", dev->bus->dirname, dev->filename);
-+}
-+
-+struct usb_device *dev_of_path(const char *path)
-+{
-+	struct usb_bus		*bus;
-+	struct usb_device	*dev;
-+	char			dirname[PATH_MAX];
-+	char			filename[PATH_MAX];
-+	const char		prefix[] = "/proc/bus/usb/";
-+	const int		prefix_len = strlen(prefix);
-+	const char		*p;
-+	int			bnum;
-+	int			dnum;
-+	int			ret;
-+
-+	assert(path != NULL);
-+	if(strncmp(prefix, path, prefix_len) != 0) {
-+		ERR("wrong path: '%s'\n", path);
-+		return NULL;
-+	}
-+	p = path + prefix_len;
-+	ret = sscanf(p, "%d/%d", &bnum, &dnum);
-+	if(ret != 2) {
-+		ERR("wrong path tail: '%s'\n", p);
-+		return NULL;
-+	}
-+	sprintf(dirname, "%03d", bnum);
-+	sprintf(filename, "%03d", dnum);
-+	for (bus = usb_busses; bus; bus = bus->next) {
-+		if(strcmp(bus->dirname, dirname) != 0)
-+			continue;
-+		for (dev = bus->devices; dev; dev = dev->next) {
-+			if(strcmp(dev->filename, filename) == 0)
-+				return dev;
-+		}
-+	}
-+	ERR("no usb device match '%s'\n", path);
-+	return NULL;
-+}
-+
-+int get_usb_string(char *buf, unsigned int len, uint16_t item, usb_dev_handle *handle)
-+{
-+	char	tmp[BUFSIZ];
-+	int	ret;
-+
-+	if (!item)
-+		return 0;
-+	ret = usb_get_string_simple(handle, item, tmp, BUFSIZ);
-+	if (ret <= 0)
-+		return ret;
-+	return snprintf(buf, len, "%s", tmp);
-+}
-+
-+/* My device parameters */
-+#define	MY_INTERFACE	0
-+#define	MY_CONFIG	1
-+#define	MY_ENDPOINTS	4
-+
-+#define	MY_EP_OUT	0x04
-+#define	MY_EP_IN	0x88
-+
-+#define	TIMEOUT		5000
-+
-+static const int my_endpoints[MY_ENDPOINTS] = {
-+	0x02,
-+	0x04,
-+	0x86,
-+	0x88
-+};
-+
-+void usb_cleanup(usb_dev_handle *handle)
-+{
-+	if(usb_release_interface(handle, MY_INTERFACE) != 0) {
-+		ERR("Releasing interface: usb: %s\n", usb_strerror());
-+	}
-+	if(usb_close(handle) != 0) {
-+		ERR("Closing device: usb: %s\n", usb_strerror());
-+	}
-+}
-+
-+void print_bcd_ver(const struct myeeprom *eeprom)
-+{
-+	/* In this case, print only the version. Also note that this 
-+	 * is an output, and sent to stdout
-+	 */
-+	printf("%d.%03d\n", eeprom->release_major, eeprom->release_minor);
-+	return;
-+}
-+
-+void dump_eeprom(const struct myeeprom *eeprom)
-+{
-+	const uint8_t	*data = eeprom->serial;
-+
-+	INFO("Source:  0x%02X\n", eeprom->source);
-+	INFO("Vendor:  0x%04X\n", eeprom->vendor);
-+	INFO("Product: 0x%04X\n", eeprom->product);
-+	INFO("Release: %d.%03d\n", eeprom->release_major, eeprom->release_minor);
-+	INFO("Data:    0x[%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X]\n",
-+			data[0], data[1], data[2], data[3],
-+			data[4], data[5], data[6], data[7]); 
-+}
-+
-+void dump_packet(const char *buf, int len)
-+{
-+	int	i;
-+
-+	for(i = 0; i < len; i++)
-+		INFO("dump: %2d> 0x%02X\n", i, (uint8_t)buf[i]);
-+}
-+
-+#ifdef	XORCOM_INTERNAL
-+int eeprom_set(struct usb_dev_handle *handle, const struct myeeprom *eeprom)
-+{
-+	int				ret;
-+	int				len;
-+	char				buf[PACKET_SIZE];
-+	struct fpga_packet_header	*phead = (struct fpga_packet_header *)buf;
-+
-+	if(verbose >= LOG_INFO)
-+		INFO("%s Start...\n", __FUNCTION__);
-+	assert(handle != NULL);
-+	phead->header.op = EEPROM_SET;
-+	memcpy(&phead->d.eeprom_set.data, eeprom, EEPROM_SIZE);
-+	len = sizeof(phead->d.eeprom_set) + sizeof(phead->header.op);
-+	if(verbose >= LOG_INFO) {
-+		INFO("%s write %d bytes\n", __FUNCTION__, len);
-+		dump_packet((char *)phead, len);
-+	}
-+	ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
-+	if(ret < 0) {
-+		ERR("usb: bulk_write failed (%d)\n", ret);
-+		return ret;
-+	} else if(ret != len) {
-+		ERR("usb: bulk_write short write (%d)\n", ret);
-+		return -EFAULT;
-+	}
-+	ret = usb_bulk_read(handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
-+	if(ret < 0) {
-+		ERR("usb: bulk_read failed (%d)\n", ret);
-+		return ret;
-+	} else if(ret == 0)
-+		return 0;
-+	phead = (struct fpga_packet_header *)buf;
-+	if(phead->header.op == BAD_COMMAND) {
-+		ERR("BAD_COMMAND\n");
-+		return -EINVAL;
-+	} else if(phead->header.op != EEPROM_SET) {
-+		ERR("Got unexpected reply op=%d\n", phead->header.op);
-+		return -EINVAL;
-+	}
-+	if(verbose >= LOG_INFO) {
-+		INFO("%s read %d bytes\n", __FUNCTION__, ret);
-+		dump_packet(buf, ret);
-+	}
-+	return 0;
-+}
-+#endif
-+
-+int eeprom_get(struct usb_dev_handle *handle, struct myeeprom *eeprom)
-+{
-+	int				ret;
-+	int				len;
-+	char				buf[PACKET_SIZE];
-+	struct fpga_packet_header	*phead = (struct fpga_packet_header *)buf;
-+
-+	assert(handle != NULL);
-+	if(verbose >= LOG_INFO)
-+		INFO("%s Start...\n", __FUNCTION__);
-+	phead->header.op = EEPROM_GET;
-+	len = sizeof(phead->header.op);		/* warning: sending small packet */
-+	if(verbose >= LOG_INFO) {
-+		INFO("%s write %d bytes\n", __FUNCTION__, len);
-+		dump_packet(buf, len);
-+	}
-+	ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
-+	if(ret < 0) {
-+		ERR("usb: bulk_write failed (%d)\n", ret);
-+		return ret;
-+	} else if(ret != len) {
-+		ERR("usb: bulk_write short write (%d)\n", ret);
-+		return -EFAULT;
-+	}
-+	ret = usb_bulk_read(handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
-+	if(ret < 0) {
-+		ERR("usb: bulk_read failed (%d)\n", ret);
-+		return ret;
-+	} else if(ret == 0)
-+		return 0;
-+	phead = (struct fpga_packet_header *)buf;
-+	if(phead->header.op == BAD_COMMAND) {
-+		ERR("BAD_COMMAND\n");
-+		return -EINVAL;
-+	} else if(phead->header.op != EEPROM_GET) {
-+		ERR("Got unexpected reply op=%d\n", phead->header.op);
-+		return -EINVAL;
-+	}
-+	if(verbose >= LOG_INFO) {
-+		INFO("%s read %d bytes\n", __FUNCTION__, ret);
-+		dump_packet(buf, ret);
-+	}
-+	memcpy(eeprom, &phead->d.eeprom_get.data, EEPROM_SIZE);
-+	return 0;
-+}
-+
-+int send_hexline(struct usb_dev_handle *handle, struct hexline *hexline, int seq)
-+{
-+	int				ret;
-+	int				len;
-+	uint8_t				*data;
-+	char				buf[PACKET_SIZE];
-+	struct fpga_packet_header	*phead = (struct fpga_packet_header *)buf;
-+	enum fpga_load_status		status;
-+
-+	assert(handle != NULL);
-+	assert(hexline != NULL);
-+	len = hexline->d.content.header.ll;	/* don't send checksum */
-+	data = hexline->d.content.tt_data.data;
-+	if(hexline->d.content.header.tt != TT_DATA) {
-+		ERR("Bad record %d type = %d\n", seq, hexline->d.content.header.tt);
-+		return -EINVAL;
-+	}
-+	phead->header.op = DATA_PACKET;
-+	phead->d.data_packet.seq = seq;
-+	phead->d.data_packet.reserved = 0x00;
-+	memcpy(phead->d.data_packet.data, data, len);
-+	len += sizeof(phead);
-+	if(verbose >= LOG_INFO)
-+		INFO("%04d+\r", seq);
-+	ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
-+	if(ret < 0) {
-+		ERR("usb: bulk_write failed (%d)\n", ret);
-+		return ret;
-+	} else if(ret != len) {
-+		ERR("usb: bulk_write short write (%d)\n", ret);
-+		return -EFAULT;
-+	}
-+	ret = usb_bulk_read(handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
-+	if(ret < 0) {
-+		ERR("usb: bulk_read failed (%d)\n", ret);
-+		return ret;
-+	} else if(ret == 0)
-+		return 0;
-+	if(verbose >= LOG_INFO)
-+		INFO("%04d-\r", seq);
-+	phead = (struct fpga_packet_header *)buf;
-+	if(phead->header.op != STATUS_REPLY) {
-+		ERR("Got unexpected reply op=%d\n", phead->header.op);
-+		return -EINVAL;
-+	}
-+	status = (enum fpga_load_status)phead->d.status_reply.status;
-+	switch(status) {
-+		case FW_TRANS_OK:
-+		case FW_CONFIG_DONE:
-+			break;
-+		case FW_FAIL_RESET:
-+		case FW_FAIL_TRANS:
-+			ERR("status reply %s (%d)\n", load_status2str(status), status);
-+			if(verbose >= LOG_INFO)
-+				dump_packet(buf, ret);
-+			return -EPROTO;
-+		default:
-+			ERR("Unknown status reply %d\n", status);
-+			if(verbose >= LOG_INFO)
-+				dump_packet(buf, ret);
-+			return -EPROTO;
-+	}
-+	return 0;
-+}
-+
-+//. returns > 0 - ok, the number of lines sent
-+//. returns < 0 - error number
-+int send_splited_hexline(struct usb_dev_handle *handle, struct hexline *hexline, int seq, uint8_t maxwidth)
-+{
-+	struct hexline *extraline;
-+	int linessent = 0;
-+	int allocsize;
-+	int extra_offset = 0;
-+	unsigned int this_line = 0;
-+	uint8_t bytesleft = 0;
-+	
-+	if(!hexline) {
-+		ERR("Bad record %d type = %d\n", seq, hexline->d.content.header.tt);
-+		return -EINVAL;
-+	}
-+	bytesleft = hexline->d.content.header.ll;
-+	// split the line into several lines
-+	while (bytesleft > 0) {
-+		int status;
-+		this_line = (bytesleft >= maxwidth) ? maxwidth : bytesleft;
-+		allocsize = sizeof(struct hexline) + this_line + 1;
-+		// generate the new line
-+		if((extraline = (struct hexline *)malloc(allocsize)) == NULL) {
-+			ERR("Not enough memory for spliting the lines\n" );
-+			return -EINVAL;
-+		}
-+		memset( extraline, 0, allocsize );
-+		extraline->d.content.header.ll		= this_line;
-+		extraline->d.content.header.offset	= hexline->d.content.header.offset + extra_offset;
-+		extraline->d.content.header.tt		= hexline->d.content.header.tt;
-+		memcpy( extraline->d.content.tt_data.data, hexline->d.content.tt_data.data+extra_offset, this_line);
-+		status = send_hexline( handle, extraline, seq+linessent );
-+		// cleanups
-+		free(extraline);
-+		extra_offset += this_line;
-+		bytesleft -= this_line;
-+		if (status)
-+			return status;
-+		linessent++;
-+	}
-+	return linessent;
-+}
-+
-+int my_usb_device(struct usb_device *dev, usb_dev_handle *handle)
-+{
-+	struct usb_device_descriptor	*dev_desc;
-+	struct usb_config_descriptor	*config_desc;
-+	struct usb_interface		*interface;
-+	struct usb_interface_descriptor	*iface_desc;
-+	struct usb_endpoint_descriptor	*endpoint;
-+	char				iManufacturer[BUFSIZ];
-+	char				iProduct[BUFSIZ];
-+	int				ret;
-+	int				i;
-+
-+	assert(dev != NULL);
-+	dev_desc = &dev->descriptor;
-+	config_desc = dev->config;
-+	interface = config_desc->interface;
-+	iface_desc = interface->altsetting;
-+	if(verbose >= LOG_INFO)
-+		INFO("Vendor:Product=%04X:%04X Class=%d (endpoints=%d)\n",
-+				dev_desc->idVendor, dev_desc->idProduct, dev_desc->bDeviceClass, iface_desc->bNumEndpoints);
-+	if(iface_desc->bInterfaceClass != 0xFF) {
-+		ERR("Wrong Interface class %d\n", iface_desc->bInterfaceClass);
-+		return -EINVAL;
-+	}
-+	if(iface_desc->bInterfaceNumber != MY_INTERFACE) {
-+		ERR("Wrong Interface number %d\n", iface_desc->bInterfaceNumber);
-+		return -EINVAL;
-+	}
-+	if(iface_desc->bNumEndpoints != MY_ENDPOINTS) {
-+		ERR("Wrong number of endpoints: %d\n", iface_desc->bNumEndpoints);
-+		return -EINVAL;
-+	}
-+	endpoint = iface_desc->endpoint;
-+	for(i = 0; i < iface_desc->bNumEndpoints; i++, endpoint++) {
-+		if(endpoint->bEndpointAddress != my_endpoints[i]) {
-+			ERR("Wrong endpoint %d: address = 0x%X\n", i, endpoint->bEndpointAddress);
-+			return -EINVAL;
-+		}
-+		if(endpoint->bEndpointAddress == MY_EP_OUT || endpoint->bEndpointAddress == MY_EP_IN) {
-+			if(endpoint->wMaxPacketSize > PACKET_SIZE) {
-+				ERR("Endpoint #%d wMaxPacketSize too large (%d)\n", i, endpoint->wMaxPacketSize);
-+				return -EINVAL;
-+			}
-+		}
-+	}
-+	if(usb_reset(handle) != 0) {
-+		ERR("Reseting device: usb: %s\n", usb_strerror());
-+	}
-+	if(usb_set_configuration(handle, MY_CONFIG) != 0) {
-+		ERR("usb: %s\n", usb_strerror());
-+		return -EINVAL;
-+	}
-+	if(usb_claim_interface(handle, MY_INTERFACE) != 0) {
-+		ERR("usb: %s\n", usb_strerror());
-+		return -EINVAL;
-+	}
-+	if(usb_resetep(handle, MY_EP_OUT) != 0) {
-+		ERR("usb: %s\n", usb_strerror());
-+		return -EINVAL;
-+	}
-+	if(usb_resetep(handle, MY_EP_IN) != 0) {
-+		ERR("usb: %s\n", usb_strerror());
-+		return -EINVAL;
-+	}
-+	ret = get_usb_string(iManufacturer, BUFSIZ, dev_desc->iManufacturer, handle);
-+	ret = get_usb_string(iProduct, BUFSIZ, dev_desc->iProduct, handle);
-+	if(verbose >= LOG_INFO)
-+		INFO("iManufacturer=%s iProduct=%s\n", iManufacturer, iProduct);
-+	return 0;
-+}
-+
-+int renumerate_device(struct usb_dev_handle *handle)
-+{
-+	char				buf[PACKET_SIZE];
-+	struct fpga_packet_header	*phead = (struct fpga_packet_header *)buf;
-+	int				ret;
-+
-+	assert(handle != NULL);
-+	if(verbose >= LOG_INFO)
-+		INFO("Renumerating\n");
-+	phead->header.op = RENUMERATE;
-+	ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, 1, TIMEOUT);
-+	if(ret < 0) {
-+		ERR("usb: bulk_write failed (%d)\n", ret);
-+		return ret;
-+	} else if(ret != 1) {
-+		ERR("usb: bulk_write short write (%d)\n", ret);
-+		return -EFAULT;
-+	}
-+	return 0;
-+}
-+
-+int fpga_load(struct usb_dev_handle *handle, const struct hexdata *hexdata)
-+{
-+	unsigned int	i;
-+	int		ret;
-+	int		finished = 0;
-+	
-+	assert(handle != NULL);
-+	if(verbose >= LOG_INFO)
-+		INFO("Start...\n");
-+		
-+	for(i = 0; i < hexdata->maxlines; i++) {
-+		struct hexline	*hexline = hexdata->lines[i];
-+
-+		if(!hexline)
-+			break;
-+		if(finished) {
-+			ERR("Extra data after End Of Data Record (line %d)\n", i);
-+			return 0;
-+		}
-+		if(hexline->d.content.header.tt == TT_EOF) {
-+			INFO("End of data\n");
-+			finished = 1;
-+			continue;
-+		}
-+		if((ret = send_hexline(handle, hexline, i)) != 0) {
-+			perror("Failed sending hexline");
-+			return 0;
-+		}
-+	}
-+	if(verbose >= LOG_INFO)
-+		INFO("Finished...\n");
-+	return 1;
-+}
-+
-+int fpga_load_usb1(struct usb_dev_handle *handle, const struct hexdata *hexdata)
-+{
-+	unsigned int	i,j=0;
-+	int		ret;
-+	int		finished = 0;
-+	
-+	assert(handle != NULL);
-+	if(verbose >= LOG_INFO)
-+		INFO("Start...\n");
-+		
-+	// i - is the line number
-+	// j - is the sequence number, on USB 2, i=j, but on
-+	//     USB 1 send_splited_hexline may increase the sequence
-+	//     number, as it needs 
-+	for(i = 0; i < hexdata->maxlines; i++) {
-+		struct hexline	*hexline = hexdata->lines[i];
-+		
-+
-+		if(!hexline)
-+			break;
-+		if(finished) {
-+			ERR("Extra data after End Of Data Record (line %d)\n", i);
-+			return 0;
-+		}
-+		if(hexline->d.content.header.tt == TT_EOF) {
-+			INFO("End of data\n");
-+			finished = 1;
-+			continue;
-+		}
-+		
-+		if((ret = send_splited_hexline(handle, hexline, j, 60)) < 0) {
-+			perror("Failed sending hexline (splitting did not help)");
-+			return 0;
-+		}
-+		j += ret;
-+	}
-+	if(verbose >= LOG_INFO)
-+		INFO("Finished...\n");
-+	return 1;
-+}
-+
-+#include <getopt.h>
-+
-+void usage()
-+{
-+	fprintf(stderr, "Usage: %s -D /proc/bus/usb/<bus>/<dev> [options...]\n", progname);
-+	fprintf(stderr, "\tOptions:\n");
-+	fprintf(stderr, "\t\t[-b <binfile>]	# output to <binfile>\n");
-+	fprintf(stderr, "\t\t[-d]		# Get device version from eeprom\n");
-+	fprintf(stderr, "\t\t[-I <hexfile>]	# Input from <hexfile>\n");
-+	fprintf(stderr, "\t\t[-g]		# Get eeprom from device\n");
-+	fprintf(stderr, "\t\t[-C srC byte]	# Set Address sourCe (default: C0)\n");
-+	fprintf(stderr, "\t\t[-V vendorid]	# Set Vendor id on device\n");
-+	fprintf(stderr, "\t\t[-P productid]	# Set Product id on device\n");
-+	fprintf(stderr, "\t\t[-R release]	# Set Release. 2 dot separated decimals\n");
-+	fprintf(stderr, "\t\t[-S serial]	# Set Serial. 8 comma separated numbers\n");
-+	exit(1);
-+}
-+
-+static void parse_report_func(int level, const char *msg, ...)
-+{
-+	va_list ap;
-+
-+	va_start(ap, msg);
-+	if(level <= verbose)
-+		vfprintf(stderr, msg, ap);
-+	va_end(ap);
-+}
-+
-+int hasUSB2( struct usb_device	*dev )
-+{
-+	if (dev->config->interface->altsetting->endpoint->wMaxPacketSize != 512)
-+		return 0;
-+	else
-+		return 1;
-+}
-+
-+// usb_interface_descriptor->usb_endpoint_descriptor.wMaxPacketSize
-+
-+int main(int argc, char *argv[])
-+{
-+	struct usb_device	*dev;
-+	usb_dev_handle		*handle;
-+	const char		*devpath = NULL;
-+	const char		*binfile = NULL;
-+	const char		*hexfile = NULL;
-+	struct hexdata		*hexdata = NULL;
-+	struct myeeprom		eeprom_buf;
-+	int			opt_read_eeprom = 0;
-+	int			opt_print_bcdver_only = 0;
-+#ifdef	XORCOM_INTERNAL
-+	int			opt_write_eeprom = 0;
-+	char			*vendor = NULL;
-+	char			*source = NULL;
-+	int			is_source_given = 0;
-+	char			*product = NULL;
-+	char			*release = NULL;
-+	char			*serial = NULL;
-+	uint8_t			serial_buf[SERIAL_SIZE];
-+	const char		options[] = "b:C:dD:ghI:vV:P:R:S:";
-+#else
-+	const char		options[] = "b:dD:ghI:v";
-+#endif
-+	int			ret = 0;
-+
-+	progname = argv[0];
-+	assert(sizeof(struct fpga_packet_header) <= PACKET_SIZE);
-+	assert(sizeof(struct myeeprom) == EEPROM_SIZE);
-+	while (1) {
-+		int	c;
-+
-+		c = getopt (argc, argv, options);
-+		if (c == -1)
-+			break;
-+
-+		switch (c) {
-+			case 'D':
-+				devpath = optarg;
-+				break;
-+			case 'b':
-+				binfile = optarg;
-+				break;
-+			case 'd':
-+				opt_print_bcdver_only = 1;
-+				opt_read_eeprom = 1;
-+				break;
-+			case 'g':
-+				opt_read_eeprom = 1;
-+				break;
-+			case 'I':
-+				hexfile = optarg;
-+				break;
-+#ifdef	XORCOM_INTERNAL
-+			case 'V':
-+				vendor = optarg;
-+				break;
-+			case 'C':
-+				source = optarg;
-+				is_source_given = 1;
-+				break;
-+			case 'P':
-+				product = optarg;
-+				break;
-+			case 'R':
-+				release = optarg;
-+				break;
-+			case 'S':
-+				serial = optarg;
-+				{
-+					int		i;
-+					char		*p;
-+					unsigned long	val;
-+
-+					p = strtok(serial, ",");
-+					for(i = 0; i < SERIAL_SIZE && p; i++) {
-+						val = strtoul(p, NULL, 0);
-+						if(val > 0xFF) {
-+							ERR("Value #%d for -S option is too large (%lu)\n", i+1, val);
-+							usage();
-+						}
-+						serial_buf[i] = val;
-+						p = strtok(NULL, ",");
-+					}
-+					if(i < SERIAL_SIZE) {
-+						ERR("got only %d values for -S option. Need %d\n", i, SERIAL_SIZE);
-+						usage();
-+					}
-+				}
-+
-+				break;
-+#endif
-+			case 'v':
-+				verbose++;
-+				break;
-+			case 'h':
-+			default:
-+				ERR("Unknown option '%c'\n", c);
-+				usage();
-+		}
-+	}
-+
-+	if (optind != argc) {
-+		usage();
-+	}
-+	if(hexfile) {
-+		parse_hexfile_set_reporting(parse_report_func);
-+		hexdata = parse_hexfile(hexfile, MAX_HEX_LINES);
-+		if(!hexdata) {
-+			ERR("Bailing out\n");
-+			exit(1);
-+		}
-+		if(binfile) {
-+			dump_binary(hexdata, binfile);
-+			return 0;
-+		}
-+	}
-+	if(!devpath) {
-+		ERR("Missing device path\n");
-+		usage();
-+	}
-+	if(verbose)
-+		INFO("Startup %s\n", devpath);
-+
-+	usb_init();
-+	usb_find_busses();
-+	usb_find_devices();
-+	dev = dev_of_path(devpath);
-+	if(!dev) {
-+		ERR("Bailing out\n");
-+		exit(1);
-+	}
-+	handle = usb_open(dev);
-+	if(!handle) {
-+		ERR("Failed to open usb device '%s/%s': %s\n", dev->bus->dirname, dev->filename, usb_strerror());
-+		return -ENODEV;
-+	}
-+	if(my_usb_device(dev, handle)) {
-+		ERR("Foreign usb device '%s/%s'\n", dev->bus->dirname, dev->filename);
-+		ret = -ENODEV;
-+		goto dev_err;
-+	}
-+	
-+	if(hexdata) {
-+		int status;
-+
-+		if (hasUSB2(dev))
-+			status = fpga_load(handle, hexdata);
-+		else {
-+			INFO("Warning: working on a low end USB1 backend\n");
-+			status = fpga_load_usb1(handle, hexdata);
-+		}
-+
-+		if(!status) {
-+			ERR("FPGA loading failed\n");
-+			ret = -ENODEV;
-+			goto dev_err;
-+		}
-+		ret = renumerate_device(handle);
-+		if(ret < 0) {
-+			ERR("Renumeration failed: errno=%d\n", ret);
-+			goto dev_err;
-+		}
-+	}
-+#ifdef	XORCOM_INTERNAL
-+	if(vendor || product || release || serial || source )
-+		opt_read_eeprom = opt_write_eeprom = 1;
-+#endif
-+	if(opt_read_eeprom) {
-+		ret = eeprom_get(handle, &eeprom_buf);
-+		if(ret < 0) {
-+			ERR("Failed reading eeprom: %d\n", ret);
-+			goto dev_err;
-+		}
-+		if (opt_print_bcdver_only)
-+			print_bcd_ver(&eeprom_buf);
-+		else
-+			dump_eeprom(&eeprom_buf);
-+	}
-+#ifdef XORCOM_INTERNAL
-+	if(opt_write_eeprom) {
-+		// FF: address source is from device. C0: from eeprom
-+		if (is_source_given)
-+			eeprom_buf.source = strtoul(source, NULL, 0);
-+		else
-+			eeprom_buf.source = 0xC0;
-+		if(vendor)
-+			eeprom_buf.vendor = strtoul(vendor, NULL, 0);
-+		if(product)
-+			eeprom_buf.product = strtoul(product, NULL, 0);
-+		if(release) {
-+			int	release_major = 0;
-+			int	release_minor = 0;
-+
-+			sscanf(release, "%d.%d", &release_major, &release_minor);
-+			eeprom_buf.release_major = release_major;
-+			eeprom_buf.release_minor = release_minor;
-+		}
-+		if(serial) {
-+			memcpy(eeprom_buf.serial, serial_buf, SERIAL_SIZE);
-+		}
-+		dump_eeprom(&eeprom_buf);
-+		ret = eeprom_set(handle, &eeprom_buf);
-+		if(ret < 0) {
-+			ERR("Failed writing eeprom: %d\n", ret);
-+			goto dev_err;
-+		}
-+	}
-+#endif
-+	if(verbose)
-+		INFO("Exiting\n");
-+dev_err:
-+	usb_cleanup(handle);
-+	return ret;
-+}
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/genzaptelconf zaptel-xpp-LJNBCn_dist/xpp/utils/genzaptelconf
---- zaptel-1.2.6/xpp/utils/genzaptelconf	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/utils/genzaptelconf	2006-07-10 14:41:08.140923000 +0300
-@@ -0,0 +1,944 @@
-+#! /bin/bash
-+
-+# genzaptelconf: generate as smartly as you can:
-+#		/etc/zaptel.conf
-+#		/etc/asterisk/zapata-channels.conf (to be #include-d into zapata.conf)
-+#	update:
-+#		With '-M' /etc/modules (list of modules to load)
-+#
-+# Copyright (C) 2005 by Xorcom <support at xorcom.com>
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 2 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software
-+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-+#
-+#
-+# If you have any technical questions, contact 
-+# Tzafrir Cohen <tzafrir.cohen at xorcom.com>
-+#	
-+
-+# The script uses a number of bash-specific features
-+# TODO: either ditch them or convert to perl
-+# Don't override variables here. Override them in /etc/default/zaptel
-+#
-+# 0.5.3:
-+# * Experimental support for Sangoma analog cards (A20x)
-+# * Support OpenVox A1200P (A TDM400P clone refactored)
-+# * Fixed timeout for Astribank load
-+# * Delete unsuccessfully-probe modules
-+# * Pass callerid from trunks
-+# * A simpler wait_for_xpp using new proc wait_for_xpds
-+# * fixed confusion between framing and coding for E1/{il/nl}
-+# 0.5.2:
-+# * Now it should detect most PRI cards and even wcusb
-+# 0.5.1:
-+# * Initial support for ztgsm (Junghanns's PCI GSM card)
-+# * Wait for the xpp module to register if just loaded
-+# 0.5.0:
-+# * Not trying to read from zaptel channels: we can run genzaptelconf even 
-+#   with asterisk up.
-+# * Don't add ztdummy to the list of detected modules
-+# 0.4.4:
-+# * remove ztdummy when rewriting modules file
-+# * Better ISDN PRI behaviour in Israel (il)
-+# 0.4.3:
-+# * Added -F: to disable writing about FXS ports in zapata.conf
-+# * if we have an astribank: start zaptel rather than simple ztcfg (xpd sync)
-+# 0.4.2: 
-+# * support for digital input/output ports of Astribank
-+# * Different ISDN parameters for the Netherlands (nl)
-+# * unload zaptel and its dependencies, not a hard-coded list
-+# * hence we can reduce the list of modules
-+
-+# /etc/default/zaptel may override the following variables
-+VERSION=0.5.3
-+VERSION_FULL="$VERSION $Id: genzaptelconf 1202 2006-05-16 03:16:41Z tzafrir $"
-+lc_country=us
-+base_exten=6000
-+# If set: no context changes are made in zapata-channels.conf
-+#context_manual=yes
-+context_lines=from-pstn      # context into which PSTN calls go
-+context_phones=from-internal # context for internal phones calls.
-+# The two below apply to input and output ports of the Xorcom Astribank:
-+context_input=astbank-input
-+context_output=astbank-output # useless, but helps marking the channels :-)
-+# TODO: what about PRI/BRI?
-+# If set: no group changes are made in zapata-channels.conf
-+#group_manual=yes
-+group_phones=5 # group for phones
-+group_lines=0  # group for lines
-+# set 'immediate=yes' for Asteribank input channels and 'immediate=no' 
-+# for others. Note that if an Astribank is not detected, the script 
-+# will set this to "no", so you can safely leave it as "yes".
-+set_immediate=yes
-+
-+ZAPCONF_FILE=/etc/zaptel.conf
-+ZAPATA_FILE=/etc/asterisk/zapata-channels.conf
-+ZAPTEL_BOOT=/etc/default/zaptel
-+MODLIST_FILE=/etc/modules
-+exten_base_dir=/etc/asterisk/extensions-phones.d
-+exten_defs_file=/etc/asterisk/extensions-defs.conf
-+ZTCFG=/sbin/ztcfg
-+
-+# a temporary directory. Created when the switch -r is parsed on getopts
-+# and deleted in the end on update_extensions_defs
-+tmp_dir=
-+
-+# A list of all modules:
-+# - the list of modules which will be probed (in this order) if -d is used
-+# - The module that will be deleted from /etc/modules , if -d -M is used
-+ALL_MODULES="zaphfc qozap ztgsm wctdm wctdm24xxp wcfxo wcfxs pciradio tor2 torisa wct1xxp wct4xxp wcte11xp wanpipe wcusb xpp_usb"
-+
-+# read default configuration from /etc/default/zaptel
-+if [ -r $ZAPTEL_BOOT ]; then . $ZAPTEL_BOOT; fi
-+
-+# it is safe to use -c twice: the last one will be used.
-+ztcfg_cmd="$ZTCFG -c $ZAPCONF_FILE"
-+
-+# work around a bug (that was already fixed) in the installer:
-+if [ "$lc_country" = '' ]; then lc_country=us; fi
-+
-+force_stop_ast=no
-+do_detect=no
-+do_unload=no
-+do_module_list=no
-+verbose=no
-+fxsdisable=no
-+rapid_extens=''
-+# global: current extension number in extensions list. Should only be 
-+# changed in print_pattern:
-+rapid_cur_exten=1 
-+# set the TRUNK in extensidialplan dialplan defs file  rapid_conf_mode=no
-+
-+die() {
-+	echo "$@" >&2
-+	exit 1
-+}
-+
-+say() {
-+	if [ "$verbose" = no ]; then
-+		return
-+	fi
-+	echo "$@"   >&2
-+}
-+
-+run_ztcfg() {
-+	if [ "$verbose" = no ]; then
-+		$ztcfg_cmd "$@"
-+	else
-+		say "Reconfiguring identified channels"
-+		$ztcfg_cmd -vv "$@"
-+	fi
-+}
-+
-+update_module_list() {
-+	del_args=`for i in $ALL_MODULES ztdummy
-+	do
-+		echo "$i" | sed s:.\*:-e\ '/^&/d':
-+	done`
-+	add_args=`for i in $*
-+	do
-+		echo "$i" | sed s:.\*:-e\ '\$a&':
-+	done`
-+	
-+	sed -i.bak $del_args "$MODLIST_FILE"
-+	for i in $*
-+	do
-+		echo "$i"
-+	done >> "$MODLIST_FILE"
-+}
-+
-+do_update() {
-+	if [ ! -d `dirname ${ZAPTEL_BOOT}` ]
-+	then
-+		return
-+	fi
-+	sed -i.bak "s/^$1=.*\$/$1=\"$2\"/" ${ZAPTEL_BOOT}
-+	if ! grep -q "^$1=" ${ZAPTEL_BOOT}; then
-+		echo "$1=\"$2\"" >> ${ZAPTEL_BOOT}
-+	fi
-+}
-+
-+update_extensions_defs() {
-+	if [ "$rapid_conf_mode" = 'yes' ]
-+	then
-+		say "DEBUG: Updating dialplan defs file $exten_defs_file"
-+		if [ "`echo $tmp_dir/fxo_* | grep -v '*'`" != '' ]
-+		then
-+			trunk_nums=`cat $tmp_dir/fxo_* | sort -n | xargs`
-+			say "Configuring TRUNK to be [first of] zaptel channels: $trunk_nums"
-+			trunk_dev=`echo $trunk_nums| sed -e 's/ /\\\\\\&/g' -e 's/[0-9a-zA-Z]\+/Zap\\\\\\/&/g'`
-+			echo >&2 sed -i "s/^TRUNK.*=>.*/TRUNK => $trunk_dev/" $exten_defs_file
-+			sed -i "s/^TRUNK.*=>.*/TRUNK => $trunk_dev/" $exten_defs_file
-+			if ! grep -q "^TRUNK =>" $exten_defs_file; then
-+				trunk_dev=`echo $trunk_nums| sed -e 's/ /&/g' -e 's/[0-9a-zA-Z]*/Zap\\/&/g'`
-+				echo "TRUNK => $trunk_dev" >> $exten_defs_file
-+			fi
-+		else
-+			say "Warning: No FXO channel for trunk. Moving on."
-+		fi
-+		if [ "`echo $tmp_dir/fxs_* | grep -v '*'`" != '' ]
-+		then
-+			fxs_nums=`cat $tmp_dir/fxs_* | sort -n | xargs`
-+			zap_nums=`grep '^[^;].*Zap/\${CHAN_ZAP_' $exten_base_dir/*.conf | \
-+				sed -e 's/.*Zap\/\${CHAN_ZAP_\([0-9]*\)}.*/\1/' | sort -u | xargs`
-+			say "Configuring channels: $fxs_nums as channel placeholders: $zap_nums"
-+			j=1
-+			for i in $zap_nums
-+			do
-+				chan=`echo $fxs_nums | awk "{print \\$$i}"`
-+				if [ "$chan" = '' ]
-+				then
-+					# if the result is empty, we probably got past the last one.
-+					# bail out.
-+					say "Warning: No FXS channel for CHAN_ZAP_$i. Moving on"
-+					break
-+				fi
-+				say "DEBUG: setting channel $chan to placeholder $i"
-+				if grep -q "^CHAN_ZAP_$i " $exten_defs_file
-+				then
-+					sed -i -e "s/^CHAN_ZAP_$i .*/CHAN_ZAP_$i => Zap\/$chan/" $exten_defs_file
-+				else
-+					echo "CHAN_ZAP_$i => Zap/$chan" >> $exten_defs_file
-+				fi
-+			done
-+		fi	
-+		# cleaning up the temp dir
-+	fi
-+	if [ -d "$tmp_dir" ]; then rm -rf "$tmp_dir"; fi
-+}
-+
-+check_for_astribank(){
-+	if ! grep -q XPP_IN/ /proc/zaptel/* 2>/dev/null
-+	then
-+		# we only get here is if we find no Astribank input channels
-+		# in /proc/zaptel . Hence we can safely disable their special settings:
-+		set_immediate=no
-+	fi
-+}
-+
-+usage() {
-+	program=`basename $0`
-+
-+	echo >&2 "$program: generate zaptel.conf and zapata.conf"
-+	echo >&2 "(version $VERSION_FULL)"
-+	echo >&2 "usage:"
-+	echo >&2 " $program [-sdv] [-m k|l|g] [-c <country_code>] [-r |-e <base_exten>] "
-+	echo >&2 " $program [-sdv] -l"
-+	echo >&2 " $program -su"
-+	echo >&2 " $program -h (this screen)"
-+	echo >&2 ""
-+	echo >&2 "Options:"
-+	echo >&2 "  -c CODE: set the country code (default: $lc_country)"
-+	echo >&2 "  -e NUM: set the base extension number (default: $base_exten)"
-+	echo >&2 "  -F: Don't print FXSs in zapata.conf"
-+	echo >&2 "  -l: output a list of detected channels instead of zaptel.conf"
-+	echo >&2 "  -d: Perform hardware detection"
-+	echo >&2 "  -u: Unload zaptel modules"
-+	echo >&2 "  -v: verbose"
-+	echo >&2 "  -s: Don't fail if asterisk is running. Stop it"
-+	echo >&2 "  -r: rapid configuration mode: configure Zaptel FXS channels from "
-+	echo >&2 "      existing Rapid extension files. FXOs will all be TRUNK "
-+}
-+
-+# $1: channel number
-+print_pattern() {
-+	local astbank_type=''
-+	OPTIND=1
-+	while getopts 'a:' arg
-+	do
-+		case "$arg" in
-+			a) case "$OPTARG" in input|output) astbank_type=$OPTARG;;esac ;;
-+		esac
-+	done
-+	shift $(( $OPTIND-1 ))
-+
-+
-+	local chan=$1
-+	local sig=$2 #fxs/fxo
-+	local mode=$3
-+	local method='ks'
-+	if [ "$lc_country" = il ] && [ "$sig" = 'fxs' ]
-+	then method=ls
-+	fi
-+	case "$mode" in
-+	zaptel)
-+		# sadly, both input ports and output ports go into the same span as 
-+		# the FXS ports. Thus we need to separate between them. See also 
-+		# the zapata.conf section:
-+		if [ "$astbank_type" != '' ]; then echo "# astbanktype: $astbank_type"; fi
-+		echo "${sig}$method=$chan" 
-+		;;
-+	list) echo $chan $sig $astbanktype;;
-+	zapata)
-+		# zap2amp will rewrite those from zaptel.conf and hints there
-+		if [ "$fxsdisable" = 'yes' ] && [ $sig = 'fxo' ]; then return; fi
-+			
-+		echo "signalling=${sig}_$method"
-+		if [ "$sig" = 'fxo' ]
-+		then
-+			# to preconfigure channel 1's extension to 550, set
-+			# chan_1_exten=550
-+			# in, e.g, /etc/default/zaptel
-+		  var_name=`echo chan_${chan}_exten`
-+			cfg_exten=`echo ${!var_name} | tr -d -c 0-9`
-+		  var_name=`echo chan_${chan}_vmbox`
-+			cfg_vmbox=`echo ${!var_name} | tr -d -c 0-9`
-+		  var_name=`echo chan_${chan}_cntxt`
-+			cfg_cntxt=`echo ${!var_name} | tr -d -c 0-9`
-+			
-+			# if option -E was given, get configuration from current extension
-+			if [ "$rapid_conf_mode" = 'yes' ]
-+			then
-+				rap_exten=`echo $rapid_extens |awk "{print \\$$rapid_cur_exten}"`
-+				if [ "$rap_exten" != '' ]
-+				then
-+					rap_cfgfile="$exten_base_dir/$rap_exten.conf"
-+					if [ -r "$rap_exten" ]
-+					then
-+						cfg_exten=$rap_exten
-+						# the vmbox is the third parameter to stdexten
-+						rap_vmbox=`grep '^[^;].*Macro(stdexten' $rap_exten | cut -d, -f3 \
-+							| cut -d')' -f1 | tr -d -c '0-9 at a-zA-Z'`
-+						if [ "$rap_vmbox" ]!= '' ; then cfg_vmbox=$rap_vmbox; fi
-+					fi
-+				fi
-+				rapid_cur_exten=$(($rapid_cur_exten + 1))
-+			fi
-+			
-+			if [ "$cfg_exten" = '' ]
-+			then # No extension number set for this channel
-+				exten=$(($chan+$base_exten))
-+			else # use the pre-configured extension number
-+				exten=$cfg_exten
-+			fi
-+			# is there any real need to set 'mailbox=' ?
-+			if [ "x$cfg_vmbox" = x ]
-+			then # No extension number set for this channel
-+				vmbox=$exten
-+			else # use the pre-configured extension number
-+				vmbox=$cfg_vmbox
-+			fi
-+			echo "callerid=\"Channel $chan\" <$exten>"
-+			echo "mailbox=$exten"
-+			if [ "$group_manual" != "yes" ]
-+			then 
-+				echo "group=$group_phones"
-+			fi
-+			if [ "$context_manual" != "yes" ]
-+			then
-+				if [ "$astbank_type" != '' ];
-+				then 
-+					context_var_name=context_$astbank_type
-+					echo context=${!context_var_name}
-+				else
-+					echo "context=$context_phones"
-+				fi
-+			fi
-+		else # this is an FXO (trunk/phone: FXO signalling)
-+		  # we have may have set it. So reset it:
-+			echo "callerid=asrecieved"
-+			echo "mailbox="
-+			if [ "$group_manual" != "yes" ]
-+			then 
-+				echo "group=$group_lines"
-+			fi
-+			if [ "$context_manual" != "yes" ]
-+			then 
-+				echo "context=$context_lines"
-+			fi
-+			if [ "$lc_country" = 'uk' ]
-+			then
-+			  echo "cidsignalling=v23"
-+			  case $line in 
-+			  *WCFXO*) echo "cidstart=history";;
-+			  *)       echo "cidstart=polarity";; #a TDM400
-+			  esac
-+			fi
-+			echo ";;; line=\"$line\""
-+			# if kewlstart is not used, busydetect has to be employed:
-+			if [ "$method" = 'ls' ]
-+			then echo 'busydetect=yes'
-+			else echo 'busydetect=no'
-+			fi
-+		fi
-+
-+		if [ "$set_immediate" = 'yes' ]
-+		then
-+			if [ "$astbank_type" = 'input' ]
-+			then echo 'immediate=yes'
-+			else echo 'immediate=no'
-+			fi
-+		fi
-+		echo "channel => $chan"
-+		echo ""
-+
-+		# Keep a note of what channels we have identified
-+		say "DEBUG: adding to channels list: channel: $chan, sig: $sig"
-+		case "$sig" in
-+		fxs)
-+			echo $chan >$tmp_dir/fxo_$chan
-+			say "DEBUG: FXO list now contains: `cat $tmp_dir/fxo_* |xargs`"
-+			;;
-+		fxo)
-+			echo $chan >$tmp_dir/fxs_$chan
-+			say "DEBUG: FXS list now contains: `cat $tmp_dir/fxs_* |xargs`"
-+			;;
-+		esac
-+		;;
-+	esac
-+	
-+}
-+
-+# the number of channels from /proc/zaptel
-+# must always print a number as its output.
-+count_proc_zap_lines() {
-+	# if zaptel is not loaded there are 0 channels:
-+	if [ ! -d /proc/zaptel ]; then echo '0'; return; fi
-+	
-+	(
-+		for file in `echo /proc/zaptel/* |grep -v '\*'`
-+		do sed -e 1,2d $file # remove the two header lines
-+		done
-+	) | wc -l # the total number of lines
-+}
-+
-+load_modules() {
-+	say "Test Loading modules:"
-+	for i in $ALL_MODULES
-+	do
-+		lines_before=`count_proc_zap_lines`
-+		args="${i}_args"
-+		eval "args=\$$args"
-+		# a module is worth listing if it:
-+		# a. loaded successfully, and
-+		# b. added channels lines under /proc/zaptel/*
-+		if /sbin/modprobe $i $args 2> /dev/null 
-+		then
-+		  check=0
-+		  case "$i" in
-+			xpp_usb) check=`grep 'STATUS=connected' 2>/dev/null /proc/xpp/xbuses | wc -l` ;;
-+			*) if [ $lines_before -lt `count_proc_zap_lines` ]; then check=1; fi ;;
-+			esac
-+			if [ "$check" != 0 ]
-+			then
-+			  probed_modules="$probed_modules $i"
-+			  say "	ok	$i	$args"
-+		  else
-+			  say "	- 	$i	$args"
-+				rmmod $i
-+		  fi
-+		else
-+			say "	- 	$i	$args"
-+		fi
-+	done
-+}
-+
-+# recursively unload a module and its dependencies, if possible.
-+# where's modprobe -r when you need it?
-+# inputs: module to unload.
-+# returns: the result from 
-+unload_module() {
-+	module="$1"
-+	line=`lsmod 2>/dev/null | grep "^$1 "`
-+	if [ "$line" = '' ]; then return; fi # module was not loaded
-+
-+	set -- $line
-+	# $1: the original module, $2: size, $3: refcount, $4: deps list
-+	mods=`echo $4 | tr , ' '`
-+	# old versions of xpd_fxs actually depend on xpp, but forget to tell it.
-+	# bug has already been fixed but the code will remain here for a while
-+	# just in case
-+	case "$module" in xpd_*) mods="xpp_usb $mods";; esac
-+	for mod in $mods; do
-+		# run in a subshell, so it won't step over our vars:
-+		(unload_module $mod) 
-+		# TODO: the following is probably the error handling we want:
-+		# if [ $? != 0 ]; then return 1; fi
-+	done
-+	rmmod $module
-+}
-+
-+unload_modules() {
-+	if
-+		pids="$(pgrep asterisk)"
-+		[ "$pids" != '' ]
-+	then
-+		die "Before unloading -- STOP asterisk (pids=$pids)."
-+	fi
-+	say "Unloading zaptel modules:"
-+	unload_module zaptel
-+	say ''
-+}
-+
-+# sleep a while until the xpp modules fully register
-+wait_for_xpp() {
-+	if [ -d /proc/xpp ] && \
-+	   [ "`cat /sys/module/xpp/parameters/zap_autoreg`" = 'Y' ]
-+	then
-+		# wait for the XPDs to register:
-+		# TODO: improve error reporting and produce a messagee here
-+		cat /proc/xpp/XBUS-*/wait_for_xpds 2>/dev/null >/dev/null  || true
-+	fi
-+}
-+
-+detect() {
-+	unload_modules
-+	load_modules
-+	modlist="$probed_modules"
-+	#for i in $ALL_MODULES
-+	#do
-+	#	if lsmod | grep "^$i  *" > /dev/null; then
-+	#		modlist="$modlist $i"
-+	#	fi
-+	#done
-+	modlist="$(echo $modlist)"		# clean spaces
-+	if [ "$do_module_list" = yes ]
-+	then
-+		say "Updating '${MODLIST_FILE}'"
-+		update_module_list "$modlist"
-+	fi
-+	if echo $modlist | grep -q xpp_usb; then wait_for_xpp; fi
-+}
-+
-+# TODO: kill this function. It is now unreferenced from anywhere.
-+check_tdm_sigtype() {
-+	chan_num=$1
-+	sig_type=$2
-+	mode=$3
-+	
-+	case "$sig_type" in
-+	fxs)chan_sig_type=fxo;;
-+	fxo)chan_sig_type=fxs;;
-+	esac
-+
-+#	print_pattern $chan_num $chan_sig_type $mode
-+	
-+  # if you get syntax error from this line, make sure you use 'bash' 
-+  # rather than 'sh'
-+	$ztcfg_cmd -c <(print_pattern $chan_num $chan_sig_type zaptel) 2>/dev/null  \
-+		|| return 1
-+	if head -c1 /dev/zap/$chan_num >/dev/null 2>/dev/null
-+	then 
-+		print_pattern $chan_num $chan_sig_type $mode
-+		return 0
-+	else
-+		return 1
-+	fi	
-+}
-+
-+# output a list of extensions that need a channel
-+get_rapid_extens() {
-+	if [ "$rapid_conf_mode" = 'yes' ]
-+	then
-+		rapid_extens=`grep -l '^[^;].*Zap/\${CHAN_ZAP_' $exten_base_dir/*.conf 2>/dev/null | \
-+			rev | cut -d/ -f1 | cut -d. -f2- | rev | xargs`
-+		say "Need to configure extensions: $rapid_extens"
-+	fi
-+}
-+
-+genconf() {
-+	local mode=$1
-+
-+	# reset FXO list (global)
-+	#say "DEBUG: resetting channels lists"
-+	rm -f $tmp_dir/fx{s,o}_*
-+
-+	if [ "$mode" = 'zapata' ]
-+	then
-+		rem_char=';'
-+	else
-+		rem_char='#'
-+	fi
-+
-+	spanlist=`echo /proc/zaptel/* |  grep -v '\*'`
-+
-+	#if [ "$spanlist" == "" ]; then
-+	#	die "No zapata interfaces in /proc/zaptel"
-+	#fi
-+
-+
-+	case "$mode" in 
-+		zaptel)
-+			cat <<EOF
-+# Autogenerated by $0 -- do not hand edit
-+# Zaptel Configuration File
-+#
-+# This file is parsed by the Zaptel Configurator, ztcfg
-+#
-+
-+# It must be in the module loading order
-+
-+EOF
-+			;;
-+		zapata)
-+			cat <<EOF
-+; Autogenerated by $0 -- do not hand edit
-+; Zaptel Channels Configurations (zapata.conf)
-+;
-+; This is not intended to be a complete zapata.conf. Rather, it is intended 
-+; to be #include-d by /etc/zapata.conf that will include the global settings
-+;
-+EOF
-+		;;
-+	esac
-+
-+	# For each line in the spanlist: see if it represents a channel.
-+	# if it does, test that the channel is usable.
-+	# we do that by configuring it (using ztcfg with a 1-line config file)
-+	# and then trying to read 1 byte from the device file.
-+	#
-+	# The '<(command)' syntax creates a temporary file whose content is is the
-+	# output of 'command'.
-+	#
-+	# This approach failed with the T1 card we have: the read operation simply 
-+	# hung. 
-+	#
-+	# Another problem with such an approach is how to include an existing 
-+	# configuration file. For instance: how to include some default settings.
-+	#
-+	# Maybe an 'include' directive should be added to zaptel.conf ?
-+	#cat $spanlist | 
-+	for procfile in $spanlist
-+	do
-+		span_num=`basename $procfile`
-+		# the first line is the title line. It states the model name
-+		# the second line is empty
-+		title=`head -n 1 $procfile`
-+		echo ""
-+		# stuff that needs to be remembered accross lines (for PRI support)
-+		echo "$rem_char $title"
-+		echo '-1'  >$tmp_dir/span_begin
-+		echo '-1'  >$tmp_dir/span_end
-+		echo '1'   >$tmp_dir/span_timing
-+		echo '1'   >$tmp_dir/span_lbo
-+		echo ''    >$tmp_dir/span_framing
-+		echo 'ami' >$tmp_dir/span_coding
-+		echo ''    >$tmp_dir/span_switchtype
-+		echo ''    >$tmp_dir/span_signalling
-+
-+		if echo $title | egrep -q '((quad|octo)BRI PCI ISDN Card.* \[NT\]\ |octoBRI \[NT\] |HFC-S PCI A ISDN.* \[NT\] )'
-+		then
-+			echo 'nt' >$tmp_dir/span_termtype
-+		else 
-+			if echo $title | egrep -q '((quad|octo)BRI PCI ISDN Card.* \[TE\]\ |octoBRI \[TE\] |HFC-S PCI A ISDN.* \[TE\] )'
-+			then
-+				echo 'te' >$tmp_dir/span_termtype
-+			fi
-+		fi
-+		# The rest of the lines are per-channel lines
-+		sed -e 1,2d $procfile | \
-+		while read line
-+		do 
-+			# in case this is a real channel. 
-+			chan_num=`echo $line |awk '{print $1}'`
-+			case "$line" in
-+			*WCTDM/*|*/WRTDM/*|*OPVXA1200/*) 
-+				# this can be either FXS or FXO
-+				maybe_fxs=0
-+				maybe_fxo=0
-+				$ztcfg_cmd -c <(print_pattern $chan_num fxo zaptel) &>/dev/null && maybe_fxs=1
-+				$ztcfg_cmd -c <(print_pattern $chan_num fxs zaptel) &>/dev/null && maybe_fxo=1
-+				if [ $maybe_fxs = 1 ] && [ $maybe_fxo = 1 ]
-+				then 
-+				  # An installed module won't accept both FXS and FXO signalling types:
-+					# this is an empty slot.
-+					# TODO: I believe that the Sangoma A20x will reject both and thus 
-+					# print nothing here. 
-+				  echo "$rem_char channel $chan_num, WCTDM, no module."
-+					continue
-+				fi
-+				
-+				if [ $maybe_fxs = 1 ]; then print_pattern $chan_num fxo $mode; fi
-+				if [ $maybe_fxo = 1 ]; then print_pattern $chan_num fxs $mode; fi
-+				;;
-+			*WCFXO/*) 
-+				print_pattern $chan_num fxs $mode || \
-+				echo "$rem_char channel $chan_num, WCFXO, inactive."
-+				;;
-+			*WCUSB/*)
-+				print_pattern $chan_num fxo $mode
-+				;;
-+			*XPP_FXO/*)
-+				print_pattern $chan_num fxs $mode
-+				;;
-+			*XPP_FXS/*)
-+				print_pattern $chan_num fxo $mode
-+				;;
-+			*XPP_OUT/*)
-+				print_pattern -a output $chan_num fxo $mode
-+				;;
-+			*XPP_IN/*)
-+				print_pattern -a input $chan_num fxo $mode
-+				;;
-+			*ZTHFC*/*|*ztqoz*/*|*ztgsm/*|*TE4/*|*TE2/*|*WCT1/*|*Tor2/*|*TorISA/*) # should also be used for other PRI channels
-+				if [ "`cat $tmp_dir/span_begin`" = "-1" ]
-+				then
-+					echo $chan_num      >$tmp_dir/span_begin
-+					echo $span_num      >$tmp_dir/span_num
-+					case "$line" in
-+					*ZTHFC*/*|*ztqoz*/*)
-+						echo 'ccs'          >$tmp_dir/span_framing
-+						echo 'euroisdn'     >$tmp_dir/span_switchtype
-+						if [ "`cat $tmp_dir/span_termtype`" = 'nt' 2>/dev/null ]
-+						then
-+							echo 'bri_net' >$tmp_dir/span_signalling
-+						else
-+							echo 'bri_cpe' >$tmp_dir/span_signalling
-+						fi
-+						;;
-+					*ztgsm*/*)
-+						echo 'ccs'          >$tmp_dir/span_framing
-+            # what switch type? Any meaning to it?
-+						echo 'gsm'          >$tmp_dir/span_signalling
-+						;;
-+					*TE4/*|*TE2/*|*WCT1/*|*Tor2/*|*TorISA/*)
-+						echo 'esf'       >$tmp_dir/span_framing
-+						echo 'b8zs'      >$tmp_dir/span_coding
-+						echo 'national'  >$tmp_dir/span_switchtype
-+						echo 'pri_cpe'   >$tmp_dir/span_signalling
-+						# an example of country-specific setup. This is probably not accurate
-+						# Contributions are welcome
-+						case "$lc_country" in 
-+						nl)
-+							# (Just an example for per-country info)
-+							echo 'ccs'       >$tmp_dir/span_framing
-+							echo 'ami'       >$tmp_dir/span_coding
-+							#echo 'crc4'      >$tmp_dir/span_yellow
-+							#echo 'euroisdn'  >$tmp_dir/span_switchtype
-+							#echo 'pri_cpe'   >$tmp_dir/span_signalling
-+							;;
-+						il)
-+							echo 'ccs'       >$tmp_dir/span_framing
-+							echo 'hdb3'      >$tmp_dir/span_coding
-+							echo 'crc4'      >$tmp_dir/span_yellow
-+							echo 'euroisdn'  >$tmp_dir/span_switchtype
-+						esac
-+					;;
-+					esac
-+				fi
-+				# span_lastd is always the one before last 
-+				# channel. span_bchan is the last:
-+				echo $chan_num      >$tmp_dir/span_end
-+				;;
-+			'') ;;		# Empty line (after span header)
-+			*) echo "$rem_char ??: $line";;
-+			esac
-+		done
-+		if [ "`cat $tmp_dir/span_begin`" != -1 ]
-+		then # write PRI span ocnfig:
-+			# read files to variables:
-+			for suffix in num begin end timing lbo framing \
-+				coding switchtype signalling yellow termtype
-+			do
-+				eval span_$suffix=`cat $tmp_dir/span_$suffix 2>/dev/null`
-+			done
-+			if [ "$span_yellow" != '' ]; then span_yellow=",$span_yellow"; fi
-+			# exactly the same logic is used in asterisk's chan_zap.c.
-+			# also not that $(( )) is bash-specific
-+			case "$((1+ $span_end - $span_begin))" in
-+			2|3|24) #ztgsm, BRI or T1
-+			  dchan=$span_end
-+				bchans="$span_begin-$(($span_end-1))"
-+				;;
-+			31) #E1
-+			  dchan="$(($span_begin+15))"
-+				bchans="$span_begin-$(($span_begin+14)),$(($span_begin+16))-$span_end"
-+				;;
-+			esac
-+			case "$mode" in
-+			zaptel)
-+				echo span=$span_num,$span_timing,$span_lbo,$span_framing,$span_coding$span_yellow
-+				if [ "$span_termtype" != '' ]
-+				then echo "# termtype: $span_termtype"
-+				fi
-+				echo bchan=$bchans
-+				echo dchan=$dchan
-+				;;
-+			zapata)
-+				if [ "$span_termtype" != '' ]
-+				then
-+					# an ISDN card's span that we know if it is in NT mode or TE mode.
-+					# NT is the same as FXS for us and TE is the same as FXO
-+					if [ "$span_termtype" = 'nt' ]
-+					then
-+						echo "callerid=\"Channels $span_begin - $span_end\" <$span_begin>"
-+						#echo "mailbox=$exten"
-+						if [ "$group_manual" != "yes" ]
-+						then 
-+							echo "group=$group_phones"
-+						fi
-+						if [ "$context_manual" != "yes" ]
-+						then 
-+							echo "context=$context_phones"
-+						fi
-+					else # we have may have set it. So reset it:
-+						echo "callerid=asrecieved"
-+						#echo "mailbox="
-+						if [ "$group_manual" != "yes" ]
-+						then 
-+							echo "group=$group_lines"
-+						fi
-+						if [ "$context_manual" != "yes" ]
-+						then 
-+							echo "context=$context_lines"
-+						fi
-+					fi
-+				fi
-+				echo "switchtype = $span_switchtype"
-+				echo "signalling = $span_signalling"
-+				echo "channel => $bchans"
-+				;;
-+			list)
-+				echo BRI/PRI: chans: $bchans, control: $dchan
-+				;;
-+			esac
-+		fi
-+	done
-+
-+	if [ "$mode" = 'zaptel' ]
-+	then
-+		cat <<EOF
-+
-+# Global data
-+
-+EOF
-+		echo "loadzone	= $loadzone"
-+		echo "defaultzone	= $defaultzone"
-+	fi
-+	
-+	if [ "$mode" = 'zapata' ] || [ "$mode" = 'list' ]
-+	then 
-+		update_extensions_defs 
-+	fi
-+}
-+
-+while getopts 'c:de:Fhlm:Mrsuv' arg
-+do
-+	case "$arg" in
-+		e) # guarantee that it is a number:
-+			new_base_exten=`echo $OPTARG | tr -d -c 0-9`
-+			if [ "x$new_base_exten" != x ]; then base_exten=$new_base_exten; fi
-+			;;
-+		c) lc_country=`echo $OPTARG | tr -d -c a-z` ;;
-+		d) do_detect=yes ;;
-+		F) fxsdisable=yes;;
-+		u) do_unload=yes ;;
-+		v) verbose=yes ;;
-+		l) mode='list' ;;
-+		M) do_module_list=yes; do_detect=yes ;;
-+		s) force_stop_ast=yes ;;
-+		r) 
-+			rapid_conf_mode=yes 
-+			;;
-+		h) usage; exit 0;;
-+		*) echo >&2 "unknown parameter -$arg, Aborting"; usage; exit 1;;
-+	esac
-+done
-+shift $(( $OPTIND-1 ))
-+if [ $# != 0 ]; then
-+	echo >&2 "$0: too many parameters"
-+	usage
-+	exit 1
-+fi
-+
-+tmp_dir=`mktemp -d -t` || \
-+	die "$0: failed to create temporary directory. Aborting"
-+
-+
-+case "$lc_country" in
-+	# the list was generated from the source of zaptel:
-+	#grep '{.*[0-9]\+,.*"[a-z][a-z]"' zonedata.c | cut -d'"' -f 2 | xargs |tr ' ' '|'
-+	us|au|fr|nl|uk|fi|es|jp|no|at|nz|it|gr|tw|cl|se|be|sg|il|br|hu|lt|pl|za|pt|ee|mx|in|de|ch|dk|cz|cn):;;
-+	*) 
-+		lc_country=us
-+		echo >&2 "unknown country-code $lc_country, defaulting to \"us\""
-+		;;
-+esac
-+# any reason for loadzone and defaultzone to be different? If so, this is
-+# the place to make that difference
-+loadzone=$lc_country
-+defaultzone=$loadzone
-+
-+# make sure asterisk is not in our way
-+if [ "$force_stop_ast" = 'yes' ]
-+then
-+  /etc/init.d/asterisk stop 1>&2
-+else
-+  # if asterisk is running and we wanted to detect modules
-+	# or simply to unload modules, asterisk needs to go away.
-+	if ( [ "$do_unload" = yes ] || [ "$do_detect" = yes ] ) && \
-+	  pidof asterisk >/dev/null 
-+	then
-+	  echo >&2 "Asterisk is already running. Configuration left untouched"
-+		echo >&2 "You can use the option -s to shut down Asterisk for the"
-+		echo >&2 "duration of the detection."
-+		exit 1
-+	fi
-+fi
-+
-+if [ "$do_unload" = yes ]
-+then
-+	unload_modules
-+	exit
-+fi
-+
-+if [ "$do_detect" = yes ]
-+then
-+	detect
-+fi
-+
-+if [ "$mode" = list ]; then
-+	genconf list
-+else
-+	check_for_astribank
-+	get_rapid_extens
-+	say "Generating '${ZAPCONF_FILE}'"
-+	mv "${ZAPCONF_FILE}" "${ZAPCONF_FILE}.bak"
-+	genconf zaptel > "${ZAPCONF_FILE}"
-+	say "Generating '${ZAPATA_FILE}'"
-+	mv "${ZAPATA_FILE}" "${ZAPATA_FILE}.bak"
-+	genconf zapata > "${ZAPATA_FILE}"
-+	if [ "$set_immediate" = 'yes' ] && [ -x /etc/init.d/zaptel ]
-+	then /etc/init.d/zaptel start
-+	else run_ztcfg
-+	fi
-+fi
-+
-+if [ "$tmp_dir" != '' ]
-+then
-+  rm -rf "$tmp_dir"
-+fi
-+
-+if [ "$force_stop_ast" = 'yes' ]
-+then
-+  if [ -x /etc/init.d/asterisk ]
-+  then
-+    /etc/init.d/asterisk start 1>&2
-+  fi
-+fi
-+
-+# if in verbose mode: verify that asterisk is running
-+if [ "$verbose" != 'no' ] && [ "$force_stop_ast" = 'yes' ]
-+	then
-+	say "Checking channels configured in Asterisk:"
-+	sleep 1 # give it some time. This is enough on our simple test server
-+	if [ -x ast-cmd ]
-+	then
-+		ast-cmd cmd "zap show channels"
-+	else
-+		asterisk -rx "zap show channels"
-+	fi
-+fi
-+
-+# vim:ts=2:
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/genzaptelconf.8 zaptel-xpp-LJNBCn_dist/xpp/utils/genzaptelconf.8
---- zaptel-1.2.6/xpp/utils/genzaptelconf.8	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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" 
-+.B genzaptelconf 
-+-- generates zaptel configuration (TDM adaptors)
-+.SH SYNOPSIS
-+.PP 
-+.B genzaptelconf 
-+[-sdv] [-c <country_code>] [-r |-e <base_exten>] [ -F ]
-+
-+.B genzaptelconf 
-+[-sdv] -l -- only list to standard output
-+   
-+.B genzaptelconf 
-+-su -- only unload zaptel modules
-+
-+.B genzaptelconf 
-+-h -- Help screen
-+    
-+.SH DESCRIPTION
-+.B genzaptelconf 
-+is a script to detect zaptel devices (currently mostly TDM cards are 
-+supported). It generates both 
-+.I /etc/zaptel.conf
-+and 
-+.I /etc/asterisk/zapata-channels.conf
-+
-+.I PRI
-+and 
-+.I BRI
-+(HFC, with ZapBRI) cards are basically identified as well. However the span
-+configiration is a default that I only hope is sane. Looking for feedback
-+
-+.SH OPTIONS
-+.B -c
-+.I country_code
-+.RS
-+A two-letter country code. Sets the country-code for the zonezone 
-+entries in 
-+.I zaptel.conf
-+, The default is the value of
-+.I lc_country
-+from 
-+.I /etc/default/zaptel
-+and failing that, "us".
-+.RE
-+
-+.B -d
-+.RS
-+Also try to detect modules. Unloads all zaptel modules and loads them
-+one by one. Considers a module useful if it loaded successfully and if 
-+loading it has generated at least one zapata channel.
-+
-+The list of detected modules is written as the value of 
-+.I ZAPTEL_MODS
-+in 
-+.I /etc/default/zaptel
-+.RE
-+
-+.B -e
-+.I base_exten_num
-+.RS
-+Configure channel 
-+.I i 
-+as extension 
-+.I exten_num
-++
-+.I i 
-+. This is mostly for the caller-id values. Crude, but may be good enough. 
-+See also
-+.I -r
-+.RE
-+
-+.B -F
-+.RS
-+Disable writing FXS extensions in zapata.conf
-+.RE
-+
-+.B -l
-+.RS
-+Only list deceted channels and their signalling. Don't write 
-+configuration files. Note, however that 
-+.I -ld
-+will still rewrite the modules line in 
-+.I /etc/default/zaptel
-+(see 
-+.I -d
-+above).
-+.RE
-+
-+.B -M
-+.RS
-+Update
-+.I /etc/modules
-+with a list of our modules, thereby
-+triggers their loading via modprobe on the next boot.
-+
-+This triggers the
-+.I -d
-+option as well.
-+.RE
-+
-+.B -r
-+.RS
-+Try to guess a useful
-+.I zapata-channels
-+configuration for Xorcom Rapid .
-+.RE
-+
-+.B -s
-+.RS
-+Stop asterisk for the duration of the test. The detection will only
-+work if nobody uses the zaptel channels: 
-+
-+* To allow unloading of modules
-+
-+* to allow reading configuration files.
-+
-+By default the script will check if asterisk is running and alert if so.
-+This option tells the script to stop asterisk (if it was running) and to 
-+try to start it after the end of the test.
-+.RE
-+
-+.B -v
-+.RS
-+Be verbose. lists the detected modules if 
-+.I -d
-+is used. Lists detected channls. In the end tries to connect to asterisk
-+to get a list of configured zaptel channels.
-+.RE
-+.SH FILES
-+.I /etc/zaptel.conf
-+.RS
-+The configuration file used by 
-+.I ztcfg
-+to configure zaptel devices. re-written by 
-+.I genzaptelconf
-+.RE
-+
-+.I /etc/zaptel.conf.bak
-+.RS
-+When 
-+.I zaptel.conf
-+The original zaptel.conf
-+.RE
-+
-+.I /etc/asterisk/zapata.conf
-+.RS
-+The configuration file of Asterisk's 
-+.I chan_zap.
-+Not modified directly by 
-+.I genzaptelconf.
-+If you want genzaptelconf's setting to take effect, add the following 
-+line at the end of 
-+.I zapata.conf:
-+.RS
-+#include "zapata-channels.conf"
-+.RE
-+.RE
-+
-+.I /etc/asterisk/zapata-channels.conf
-+.RS
-+This is the snippet of 
-+.I chan_zap
-+configuration file that 
-+.I genzaptelconf generates.
-+.RE
-+
-+.I /etc/asterisk/zapata-channels.conf.bak
-+.RS
-+The backup copy of 
-+.I zapata-channels.conf
-+.RE
-+
-+.I /etc/default/zaptel
-+.RS
-+This file holds configuration for both 
-+.I genzaptelconf
-+and
-+.I /etc/init.d/zaptel .
-+It is sourced by both scripts and can thus be used to override settings 
-+of variables from those scripts.
-+Some of the variables that can be set in /etc/default/zaptel and affect 
-+genzaptelconf:
-+
-+.I lc_country
-+.RS
-+The default country. Can be also overriden by the option -c
-+.RE
-+
-+.I base_exten
-+.RS
-+The base number used for automatic numbering
-+.RE
-+
-+.I context_manual
-+.RS
-+If set to 'yes', no context changes are made in zapata-channels.conf
-+.RE
-+
-+.I context_lines
-+.RS
-+The context into which calls will go from zaptel trunks.
-+.RE
-+
-+.I context_phones
-+.RS
-+The context into which calls will go from zaptel phones.
-+.RE
-+
-+.I context_manual
-+.RS
-+If set to 'yes', no group settings are made in zapata-channels.conf
-+.RE
-+
-+.I group_lines
-+.RS
-+The group number for zaptel trunks.
-+.RE
-+
-+.I group_phones
-+.RS
-+The group number for zaptel phones.
-+.RE
-+
-+.I ALL_MODULES
-+.RS
-+modules list. Used for unloading and modules detection. The order of modules
-+is the same for both.
-+.RE
-+.RE
-+
-+.I /etc/modules
-+.RS
-+A debian-specific list of kernel modules to be loaded by modprobe at 
-+boot time. When the option 
-+.I -d
-+(detect) is used, genzaptelconf will write in this file zaptel modules
-+to be loaded. If you want to use a different file, set 
-+.I MOD_FILELIST
-+.RE
-+
-+.I /etc/modules.bak
-+.RS
-+The backup copy of 
-+.I /etc/modules
-+.RE
-+
-+.SH "SEE ALSO" 
-+ztcfg(8) asterisk(8). 
-+
-+.SH "AUTHOR" 
-+This manual page was written by Tzafrir Cohen <tzafrir.cohen at xorcom.com> 
-+Permission is granted to copy, distribute and/or modify this document under 
-+the terms of the GNU General Public License, Version 2 any  
-+later version published by the Free Software Foundation. 
-+
-+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-LJNBCn_dist/xpp/utils/hexfile.c
---- zaptel-1.2.6/xpp/utils/hexfile.c	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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>
-+ * Copyright (C) 2006, Xorcom
-+ *
-+ * All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#include <stdio.h>
-+#include <assert.h>
-+#include <string.h>
-+#include <stdlib.h>
-+#include <errno.h>
-+#include "hexfile.h"
-+
-+static const char rcsid[] = "$Id:$";
-+
-+static parse_hexfile_report_func_t	report_func = NULL;
-+
-+parse_hexfile_report_func_t parse_hexfile_set_reporting(parse_hexfile_report_func_t rf)
-+{
-+	parse_hexfile_report_func_t	old_rf = report_func;
-+	report_func = rf;
-+	return old_rf;
-+}
-+
-+static void chomp(char buf[])
-+{
-+	size_t	last = strlen(buf) - 1;
-+	while(last >= 0 && (buf[last] == '\n' || buf[last] == '\r'))
-+		buf[last--] = '\0';
-+}
-+
-+int checksum(struct hexline *hexline)
-+{
-+	unsigned int	i;
-+	unsigned int	chksm = 0;
-+	int		ll = hexline->d.content.header.ll;
-+
-+	for(i = 0; i <= sizeof(hexline->d.content.header) + ll; i++) {
-+		chksm += hexline->d.raw[i];
-+	}
-+	return chksm & 0xFF;
-+}
-+
-+static int update_hexline(struct hexdata *hexdata, char *buf)
-+{
-+	int		ret;
-+	unsigned int	ll, offset, tt;
-+	char		*p;
-+	struct hexline	*hexline;
-+	unsigned int	i;
-+	int		allocsize;
-+	unsigned int	last_line = hexdata->last_line;
-+
-+	if(hexdata->got_eof) {
-+		if(report_func)
-+			report_func(LOG_ERR, "Extranous data after EOF record\n");
-+		return -EINVAL;
-+	}
-+	if(last_line >= hexdata->maxlines) {
-+		if(report_func)
-+			report_func(LOG_ERR, "Hexfile too large (maxline %d)\n", hexdata->maxlines);
-+		return -ENOMEM;
-+	}
-+	ret = sscanf(buf, "%02X%04X%02X", &ll, &offset, &tt);
-+	if(ret != 3) {
-+		if(report_func)
-+			report_func(LOG_ERR, "Bad line header (only %d items out of 3 parsed)\n", ret);
-+		return -EINVAL;
-+	}
-+	switch(tt) {
-+		case TT_DATA:
-+			break;
-+		case TT_EOF:
-+			if(ll != 0) {
-+				if(report_func)
-+					report_func(LOG_ERR, "Bad EOF record len = %d\n", ll);
-+				return -EINVAL;
-+			}
-+			if(offset != 0) {
-+				if(report_func)
-+					report_func(LOG_ERR, "Bad EOF record offset = %d\n", offset);
-+				return -EINVAL;
-+			}
-+			hexdata->got_eof = 1;
-+			break;
-+		case TT_EXT_SEG:	/* Unimplemented */
-+		case TT_START_SEG:	/* Unimplemented */
-+		case TT_EXT_LIN:	/* Unimplemented */
-+		case TT_START_LIN:	/* Unimplemented */
-+			return 1;
-+		default:
-+			if(report_func)
-+				report_func(LOG_ERR, "Unknown record type %d\n", tt);
-+			return -EINVAL;
-+	}
-+	buf += 8;	/* Skip header */
-+	ll++;		/* include the checksum for now */
-+	allocsize = sizeof(struct hexline) + ll;
-+	if((hexline = (struct hexline *)malloc(allocsize)) == NULL) {
-+		if(report_func)
-+			report_func(LOG_ERR, "No more memory for hexfile lines\n");
-+		return -EINVAL;
-+	}
-+	memset(hexline, 0, allocsize);
-+	hexline->d.content.header.ll = ll;
-+	hexline->d.content.header.offset = offset;
-+	hexline->d.content.header.tt = tt;
-+	hexdata->lines[last_line++] = hexline;
-+	p = buf;
-+	for(i = 0; i < ll; i++) {
-+		unsigned int	val;
-+
-+		if((*p == '\0') || (*(p+1) == '\0')) {
-+			if(report_func)
-+				report_func(LOG_ERR, "Short data string '%s'\n", buf);
-+			return -EINVAL;
-+		}
-+		ret = sscanf(p, "%02X", &val);
-+		if(ret != 1) {
-+			if(report_func)
-+				report_func(LOG_ERR, "Bad data byte #%d\n", i);
-+			return -EINVAL;
-+		}
-+		hexline->d.content.tt_data.data[i] = val;
-+		p += 2;
-+	}
-+	hexline->d.content.header.ll--;	/* Fix the checksum */
-+	if(checksum(hexline) != 0) {
-+		if(report_func)
-+			report_func(LOG_ERR, "Bad checksum\n");
-+		return -EINVAL;
-+	}
-+	if(hexdata->got_eof)
-+		return 0;
-+	hexdata->last_line++;
-+	return 1;
-+}
-+
-+void free_hexdata(struct hexdata *hexdata)
-+{
-+	if(hexdata) {
-+		unsigned int	i;
-+
-+		for(i = 0; i < hexdata->maxlines; i++)
-+			if(hexdata->lines[i] != NULL)
-+				free(hexdata->lines[i]);
-+		free(hexdata);
-+	}
-+}
-+
-+int dump_hexfile(struct hexdata *hexdata, FILE *outfile)
-+{
-+	uint8_t		ll;
-+	uint16_t	offset;
-+	uint8_t		tt;
-+	uint8_t		old_chksum;
-+	uint8_t		new_chksum;
-+	uint8_t		*data;
-+	unsigned int	i;
-+	unsigned int	j;
-+
-+	for(i = 0; i <= hexdata->last_line; i++) {
-+		struct hexline	*line = hexdata->lines[i];
-+		if(!line) {
-+			if(report_func)
-+				report_func(LOG_ERR, "Missing line at #%d\n", i);
-+			return -EINVAL;
-+		}
-+		ll = line->d.content.header.ll;
-+		offset = line->d.content.header.offset;
-+		tt = line->d.content.header.tt;
-+		fprintf(outfile, ":%02X%04X%02X", ll, offset, tt);
-+		data = line->d.content.tt_data.data;
-+		for(j = 0; j < ll; j++) {
-+			fprintf(outfile, "%02X", data[j]);
-+		}
-+		old_chksum = data[ll];
-+		data[ll] = 0;
-+		new_chksum = 0xFF - checksum(line) + 1;
-+		data[ll] = old_chksum;
-+		assert(new_chksum == old_chksum);
-+		fprintf(outfile, "%02X\n", new_chksum);
-+	}
-+	return 0;
-+}
-+
-+int dump_hexfile2(struct hexdata *hexdata, FILE *outfile, uint8_t maxwidth)
-+{
-+	uint8_t		ll;
-+	uint8_t		tt;
-+	uint8_t		new_chksum;
-+	uint8_t		*data;
-+	unsigned int	i;
-+	unsigned int	j;
-+
-+	if (maxwidth <= sizeof(hexdata->lines[0]->d.content.header) ){
-+		if(report_func) 
-+			report_func(LOG_ERR, "Line width too small %d\n", maxwidth);
-+		return -EINVAL;
-+	}
-+	
-+	for(i = 0; i <= hexdata->last_line; i++) {
-+		struct hexline	*line = hexdata->lines[i];
-+		struct hexline *extraline;
-+		int allocsize;
-+		int bytesleft = 0;
-+		int extra_offset = 0;
-+		unsigned int this_line = 0;
-+		
-+		if(!line) {
-+			if(report_func)
-+				report_func(LOG_ERR, "Missing line at #%d\n", i);
-+			return -EINVAL;
-+		}
-+		ll = line->d.content.header.ll;
-+		bytesleft = ll;
-+		/* split the line into several lines */
-+		tt = line->d.content.header.tt;
-+		while (bytesleft > 0) {
-+			this_line = (bytesleft >= maxwidth) ? maxwidth : bytesleft;
-+			allocsize = sizeof(struct hexline) + this_line + 1;
-+			/* generate the new line */
-+			if((extraline = (struct hexline *)malloc(allocsize)) == NULL) {
-+				if(report_func)
-+					report_func(LOG_ERR, "No more memory for hexfile lines\n");
-+				return -EINVAL;
-+			}
-+			memset( extraline, 0, allocsize );
-+			extraline->d.content.header.ll		= this_line;
-+			extraline->d.content.header.offset	= line->d.content.header.offset + extra_offset;
-+			extraline->d.content.header.tt		= tt;
-+			memcpy( extraline->d.content.tt_data.data, line->d.content.tt_data.data+extra_offset, this_line);
-+			new_chksum = 0xFF - checksum(extraline) + 1;
-+			/* print it */
-+			data = extraline->d.content.tt_data.data;
-+			fprintf(outfile, ":%02X%04X%02X", extraline->d.content.header.ll, extraline->d.content.header.offset, tt);
-+			for(j = 0; j < this_line; j++) {
-+				fprintf(outfile, "%02X", data[j]);
-+			}
-+			fprintf(outfile, "%02X\n", new_chksum);
-+			/* cleanups */
-+			free( extraline);
-+			extra_offset += this_line;
-+			bytesleft -= this_line;
-+		}
-+	}
-+	return 0;
-+}
-+
-+struct hexdata *parse_hexfile(const char *fname, unsigned int maxlines)
-+{
-+	FILE			*fp;
-+	struct hexdata		*hexdata = NULL;
-+	int			datasize;
-+	char			buf[BUFSIZ];
-+	int			line;
-+	int			ret;
-+
-+	assert(fname != NULL);
-+	if(report_func)
-+		report_func(LOG_INFO, "Parsing %s\n", fname);
-+	datasize = sizeof(struct hexdata) + maxlines * sizeof(char *);
-+	hexdata = (struct hexdata *)malloc(datasize);
-+	if(!hexdata) {
-+		if(report_func)
-+			report_func(LOG_ERR, "Failed to allocate %d bytes for hexfile contents\n", datasize);
-+		goto err;
-+	}
-+	memset(hexdata, 0, datasize);
-+	hexdata->maxlines = maxlines;
-+	if((fp = fopen(fname, "r")) == NULL) {
-+		if(report_func)
-+			report_func(LOG_ERR, "Failed to open hexfile '%s'\n", fname);
-+		goto err;
-+	}
-+	line = 0;
-+	while(fgets(buf, BUFSIZ, fp)) {
-+		line++;
-+		if(buf[0] == '\0') {
-+				if(report_func)
-+					report_func(LOG_ERR, "Short line at %s:%d\n", fname, line);
-+				goto err;
-+		}
-+		chomp(buf);
-+		if(buf[0] == '#') {
-+			if(report_func)
-+				report_func(LOG_INFO, "Comment '%s'\n", buf + 1);
-+			continue;
-+		}
-+		if(buf[0] != ':') {
-+			if(report_func)
-+				report_func(LOG_ERR, "Line begins with 0x%X at %s:%d\n", buf[0], fname, line);
-+			goto err;
-+		}
-+		if((ret = update_hexline(hexdata, buf + 1)) < 0) {
-+			if(report_func)
-+				report_func(LOG_ERR, "Failed parsing %s at line: %d\n", fname, line);
-+			goto err;
-+		}
-+	}
-+	fclose(fp);
-+	if(report_func)
-+		report_func(LOG_INFO, "%s parsed OK\n", fname);
-+	return hexdata;
-+err:
-+	free_hexdata(hexdata);
-+	return NULL;
-+}
-+
-+void dump_binary(struct hexdata *hexdata, const char *outfile)
-+{
-+	FILE		*fp;
-+	unsigned int	i;
-+	size_t		len;
-+
-+	if(report_func)
-+		report_func(LOG_INFO, "Dumping binary data into '%s'\n", outfile);
-+	if((fp = fopen(outfile, "w")) == NULL) {
-+		perror(outfile);
-+		exit(1);
-+	}
-+	for(i = 0; i < hexdata->maxlines; i++) {
-+		struct hexline	*hexline = hexdata->lines[i];
-+
-+		if(!hexline)
-+			break;
-+		if(hexline->d.content.header.tt == TT_EOF) {
-+			if(report_func)
-+				report_func(LOG_INFO, "\ndump: good EOF record");
-+			continue;
-+		}
-+		if(report_func)
-+			report_func(LOG_INFO, "dump: %6d\r", i);
-+		len = hexline->d.content.header.ll;
-+		if(fwrite(hexline->d.content.tt_data.data, 1, len, fp) != len) {
-+			perror("write");
-+			exit(1);
-+		}
-+	}
-+	if(report_func)
-+		report_func(LOG_INFO, "\nDump finished\n");
-+	fclose(fp);
-+}
-+
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/hexfile.h zaptel-xpp-LJNBCn_dist/xpp/utils/hexfile.h
---- zaptel-1.2.6/xpp/utils/hexfile.h	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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>
-+ * Copyright (C) 2006, Xorcom
-+ *
-+ * All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#ifndef	PARSE_HEXFILE_H
-+#define	PARSE_HEXFILE_H
-+
-+#include <stdarg.h>
-+
-+/*
-+ * Some portability workarounds
-+ */
-+#ifdef	_WINDOWS
-+
-+#include <windows.h>	/* for UCHAR USHORT */
-+typedef UCHAR	uint8_t;
-+typedef USHORT	uint16_t;
-+#define	PACKED
-+#define	sscanf	sscanf_s
-+#define	ZERO_SIZE	1
-+
-+/* From /usr/include/syslog.h */
-+#define	LOG_EMERG	0	/* system is unusable */
-+#define	LOG_ALERT	1	/* action must be taken immediately */
-+#define	LOG_CRIT	2	/* critical conditions */
-+#define	LOG_ERR		3	/* error conditions */
-+#define	LOG_WARNING	4	/* warning conditions */
-+#define	LOG_NOTICE	5	/* normal but significant condition */
-+#define	LOG_INFO	6	/* informational */
-+#define	LOG_DEBUG	7	/* debug-level messages */
-+
-+#ifdef  __cplusplus
-+# define __BEGIN_DECLS  extern "C" {
-+# define __END_DECLS    }
-+#else
-+# define __BEGIN_DECLS
-+# define __END_DECLS
-+#endif
-+
-+#elif	__GNUC__
-+
-+#include <stdint.h>
-+#include <syslog.h>
-+#define	PACKED	__attribute__((packed))
-+#define	ZERO_SIZE	1
-+
-+#else
-+
-+#error "Cannot compile on this platform"
-+
-+#endif
-+
-+/* Record types in hexfile */
-+enum {
-+	TT_DATA		= 0,
-+	TT_EOF		= 1,
-+	TT_EXT_SEG	= 2,
-+	TT_START_SEG	= 3,
-+	TT_EXT_LIN	= 4,
-+	TT_START_LIN	= 5,
-+	TT_NO_SUCH_TT
-+};
-+
-+#pragma pack(1)
-+struct hexline {
-+	union {
-+		uint8_t		raw[ZERO_SIZE];
-+		struct content {
-+			struct header {
-+				uint8_t		ll;	/* len */
-+				uint16_t	offset;	/* offset */
-+				uint8_t		tt;	/* type */
-+			} PACKED header;
-+			struct tt_data {
-+				uint8_t		data[ZERO_SIZE];
-+			} tt_data;
-+		} PACKED content;
-+	} d;
-+} PACKED;
-+#pragma pack()
-+
-+struct hexdata {
-+	unsigned int		maxlines;
-+	unsigned int		last_line;
-+	int			got_eof;
-+	struct hexline		*lines[ZERO_SIZE];
-+};
-+
-+
-+__BEGIN_DECLS
-+
-+typedef void (*parse_hexfile_report_func_t)(int level, const char *msg, ...);
-+
-+parse_hexfile_report_func_t parse_hexfile_set_reporting(parse_hexfile_report_func_t rf);
-+void free_hexdata(struct hexdata *hexdata);
-+struct hexdata *parse_hexfile(const char *fname, unsigned int maxlines);
-+int dump_hexfile(struct hexdata *hexdata, FILE *outfile);
-+int dump_hexfile2(struct hexdata *hexdata, FILE *outfile, uint8_t maxwidth);
-+void dump_binary(struct hexdata *hexdata, const char *outfile);
-+__END_DECLS
-+
-+#endif
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/Makefile zaptel-xpp-LJNBCn_dist/xpp/utils/Makefile
---- zaptel-1.2.6/xpp/utils/Makefile	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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
-+MANDIR    = /usr/share/man/man8
-+HOTPLUG_USB_DIR = /etc/hotplug/usb
-+
-+DATA_FILES = $(wildcard ../init_data_*.cmd *.hex) 
-+
-+CFLAGS		= -g -Wall $(EXTRA_CFLAGS)
-+
-+TARGETS	= libhexfile.a fpga_load test_parse
-+
-+all: $(TARGETS)
-+
-+install: all
-+	$(INSTALL) -d $(DESTDIR)$(BINDIR)
-+	$(INSTALL) genzaptelconf fpga_load $(DESTDIR)$(BINDIR)/
-+	$(INSTALL) -d $(DESTDIR)$(DATADIR)
-+	$(INSTALL_DATA) $(DATA_FILES) $(DESTDIR)$(DATADIR)/
-+	$(INSTALL) ../initialize_registers  $(DESTDIR)$(DATADIR)/
-+	$(INSTALL) -d $(DESTDIR)$(MANDIR)
-+	$(INSTALL_DATA) fpga_load.8 genzaptelconf.8 $(DESTDIR)$(MANDIR)/
-+	$(INSTALL) -d $(DESTDIR)$(HOTPLUG_USB_DIR)
-+	$(INSTALL_DATA) xpp_fxloader.usermap $(DESTDIR)$(HOTPLUG_USB_DIR)/
-+	$(INSTALL) xpp_fxloader $(DESTDIR)$(HOTPLUG_USB_DIR)/
-+
-+libhexfile.a: hexfile.o
-+	$(AR) cru $@ $^
-+	$(RANLIB) $@
-+
-+fpga_load: fpga_load.o libhexfile.a
-+	$(CC) -L. -o $@ $@.o $(EXTRA_LIBS) -lhexfile -lusb
-+
-+hexfile.o: hexfile.c hexfile.h
-+	$(CC) $(CFLAGS) $(PEDANTIC) -c $*.c
-+
-+test_parse.o: test_parse.c hexfile.h
-+	$(CC) $(CFLAGS) $(PEDANTIC) -c $*.c
-+
-+test_parse: test_parse.o libhexfile.a
-+	$(CC) -L. -o $@ $@.o $(EXTRA_LIBS) -lhexfile -lusb
-+
-+clean:
-+	$(RM) *.o $(TARGETS)
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/test_parse.c zaptel-xpp-LJNBCn_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-LJNBCn_dist/xpp/utils/test_parse.c	2006-05-15 17:27:26.264723000 +0300
-@@ -0,0 +1,34 @@
-+#include <stdio.h>
-+#include <stdarg.h>
-+#include "hexfile.h"
-+
-+static void default_report_func(int level, const char *msg, ...)
-+{
-+	va_list ap;
-+
-+	va_start(ap, msg);
-+	vfprintf(stderr, msg, ap);
-+	va_end(ap);
-+}
-+
-+int main(int argc, char *argv[])
-+{
-+	struct hexdata	*hd;
-+	int		i;
-+
-+	if(argc < 2) {
-+		fprintf(stderr, "Usage: program hexfile...\n");
-+		return 1;
-+	}
-+	parse_hexfile_set_reporting(default_report_func);
-+	for(i = 1; i < argc; i++) {
-+		hd = parse_hexfile(argv[i], 2000);
-+		if(!hd) {
-+			fprintf(stderr, "Parsing failed\n");
-+			return 1;
-+		}
-+		dump_hexfile2(hd, stdout, 60 );
-+		free_hexdata(hd);
-+	}
-+	return 0;
-+}
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/USB_1130.hex zaptel-xpp-LJNBCn_dist/xpp/utils/USB_1130.hex
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/USB_8613.hex zaptel-xpp-LJNBCn_dist/xpp/utils/USB_8613.hex
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/xpp_fxloader zaptel-xpp-LJNBCn_dist/xpp/utils/xpp_fxloader
---- zaptel-1.2.6/xpp/utils/xpp_fxloader	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/utils/xpp_fxloader	2006-07-02 17:49:51.471281000 +0300
-@@ -0,0 +1,163 @@
-+#!/bin/sh
-+
-+# xpp_fxload: load XPP firmware
-+#
-+# This script can be run manually or from hotplug. 
-+#
-+# Firmware files should be located in $FIRMWARE_DIR which defaults:
-+# 	1. /usr/share/zaptel
-+#	2. Can be overidden by setting $FIRMWARE_DIR in the environment
-+#	3. Can be overidden by setting $FIRMWARE_DIR in /etc/default/zaptel
-+#
-+# Manual Run
-+# ##########
-+#
-+#   path/to/xpp_fxloader xppdetect
-+#
-+# Make sure the firmware files are in $FIRMWARE_DIR
-+#
-+#
-+# Hotplg Run
-+# ##########
-+#
-+# 1. Copy this file and the file xpp_fxloader.usermap to /etc/hotplug/usb/
-+# 2. tail -f  /var/log/messages...
-+#
-+#
-+# Written by Tzafrir Cohen <tzafrir.cohen at xorcom.com>
-+# Copyright (C) 2006, Xorcom
-+#
-+# All rights reserved.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 2 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software
-+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+
-+set -e
-+
-+me=`basename $0`
-+DEFAULTS="/etc/default/zaptel"
-+
-+if [ -t 2 ]; then
-+	LOGGER="logger -i -t '$me' -s"
-+else
-+	LOGGER="logger -i -t '$me'"
-+fi
-+
-+if [ -r "$DEFAULTS" ]; then
-+	. "$DEFAULTS"
-+fi
-+
-+FIRMWARE_DIR="${FIRMWARE_DIR:-/usr/share/zaptel}"
-+
-+FIRM_FXS=$FIRMWARE_DIR/FPGA_FXS.hex
-+REENUM_SLEEP_TIME=3 # only used on manual runs
-+
-+FPGA_LOAD="/usr/sbin/fpga_load"
-+
-+find_dev() {
-+  v_id=$1
-+  p_id=$2
-+  
-+  lsusb | tr -d : | awk "/ ID $v_id$p_id/{printf \"/proc/bus/usb/%s/%s \",\$2,\$4}"
-+}
-+
-+do_fxload() {
-+  ( fxload -t fx2 $* 2>&1 1>/dev/null || exit 1 ) | $LOGGER
-+}
-+
-+load_fw() {
-+  v_id=$1
-+  p_id=$2
-+  fw=$3
-+  
-+  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
-+
-+  # Allow time for reenumeration: This only matters in the manual case.
-+  if [ "$devices" != '' ]; then sleep $REENUM_SLEEP_TIME; fi
-+}
-+
-+hexfile_version() {
-+	hexfile=$1
-+
-+	grep '$Id:' "$hexfile" | sed -e 's/^.*$Id: *[^ ]\+ *//' -e 's/ .*$//'
-+}
-+
-+load_fpga() {
-+  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 $FIRMWARE_DIR/$fw`
-+
-+	$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
-+}
-+
-+#########################
-+##
-+## Manual run
-+##
-+
-+# 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
-+	load_fpga e4e4 1131 FPGA_FXS.hex
-+
-+	sleep 3		# Let it stabilize
-+	echo "--------- FIRMWARE IS LOADED"
-+	exit $?
-+fi
-+
-+#########################
-+##
-+## Hotplug run
-+##
-+
-+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/*|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/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
-+		;;
-+	esac	
-+fi
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/xpp_fxloader.usermap zaptel-xpp-LJNBCn_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-LJNBCn_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-LJNBCn_dist/xpp/utils/xpp_modprobe
---- zaptel-1.2.6/xpp/utils/xpp_modprobe	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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
-+#options wcfxo debug=1
-+#options xpp print_dbg=1 
-+#options xpp_usb print_dbg=1 
-+#options xpd_fxs print_dbg=1 
-+#options xpd_fxo print_dbg=1 
-+
-+# 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-LJNBCn_dist/xpp/xbus-core.c
---- zaptel-1.2.6/xpp/xbus-core.c	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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
-+ *
-+ * All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-+#  warning "This module is tested only with 2.6 kernels"
-+#endif
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#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 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;
-+
-+/* Forward declarations */
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
-+#define	DEVICE_ATTR_FUNC(name,dev,buf)	\
-+		ssize_t name(struct device *dev, struct device_attribute *attr, char *buf)
-+#else
-+#define	DEVICE_ATTR_FUNC(name,dev,buf)	\
-+		ssize_t name(struct device *dev, char *buf)
-+#endif
-+
-+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;
-+static struct proc_dir_entry	*proc_xbuses = NULL;
-+
-+static	DEVICE_ATTR(connector, S_IRUGO, connector_show, NULL);
-+static	DEVICE_ATTR(status, S_IRUGO, status_show, NULL);
-+
-+/*------------------------- Packet Handling ------------------------*/
-+static kmem_cache_t	*packet_cache = NULL;
-+static atomic_t	xpacket_count = ATOMIC_INIT(0);
-+
-+/**
-+ * Allocates a new XPP packet.
-+ * @xbus The XPP bus in which the packet will flow (for counters 
-+ *       maintenance)
-+ * @flags Flags for kernel memory allocation.
-+ * @returns A pointer to the new packet, or NULL in case of failure.
-+ * 
-+ * 
-+ * Packet allocation/deallocation:
-+ * 	Sent packets:
-+ * 	  - Allocated by protocol commands
-+ * 	  - Deallocated by xmus_xmitter
-+ * 	Receive packets:
-+ * 	  - Allocated/deallocated by xbus_xmiter
-+ */
-+xpacket_t	*xbus_packet_new(xbus_t *xbus, int flags)
-+{
-+	xpacket_t	*pack;
-+
-+	/* To avoid races we increament counter in advance and decrement it later 
-+	 * in case of failure */
-+	atomic_inc(&xbus->packet_counter); 
-+	//DBG("Incremented packet_counter of bus %s (new packet) to %d\n", 
-+	//		xbus->busname, atomic_read(&xbus->packet_counter));
-+	pack = kmem_cache_alloc(packet_cache, flags);
-+	if (pack) {
-+		memset(pack, 0, sizeof(xpacket_t));
-+		atomic_inc(&xpacket_count);
-+	} else {
-+		atomic_dec(&xbus->packet_counter);
-+		//DBG("Decremented packet_counter of bus %s (failed new packet) to %d\n", 
-+		//		xbus->busname, atomic_read(&xbus->packet_counter));
-+	}
-+	return pack;
-+}
-+
-+void xbus_packet_free(xbus_t *xbus, xpacket_t *p)
-+{
-+	kmem_cache_free(packet_cache, p);
-+	atomic_dec(&xpacket_count);
-+	atomic_dec(&xbus->packet_counter);
-+	//DBG("Decremented packet_counter of bus %s (freed packet) to %d\n", 
-+	//		xbus->busname, atomic_read(&xbus->packet_counter));
-+}
-+
-+/*------------------------- Packet Queues --------------------------*/
-+void init_xbus_packet_queue(packet_queue_t *q, const char name[])
-+{
-+	INIT_LIST_HEAD(&q->head);
-+	spin_lock_init(&q->lock);
-+	q->count = 0;
-+	q->worst_count = 0;
-+	q->overflows = 0;
-+	snprintf(q->qname, XPD_NAMELEN, "%s", name);
-+}
-+
-+#if 0
-+/*
-+ * Assume the queue is locked
-+ */
-+void __dump_packet_queue(const char *msg, packet_queue_t *q)
-+{
-+	xpacket_t *tmp;
-+
-+	list_for_each_entry(tmp, &q->head, list) {
-+		dump_packet(msg, tmp);
-+	}
-+}
-+#endif
-+
-+void drain_xbus_packet_queue(xbus_t *xbus, packet_queue_t *q)
-+{
-+	unsigned long	flags;
-+	xpacket_t	*pack;
-+	xpacket_t	*next;
-+
-+	spin_lock_irqsave(&q->lock, flags);
-+	DBG("queue=%s count=%d\n", q->qname, q->count);
-+	DBG("     total packets count=%d\n", atomic_read(&xpacket_count));
-+	list_for_each_entry_safe(pack, next, &q->head, list) {
-+		list_del(&pack->list);
-+		q->count--;
-+		xbus->ops->packet_free(xbus, pack);
-+	}
-+	if(q->count != 0)
-+		ERR("drain_xbus_packet_queue: queue %s still has %d packets\n",
-+				q->qname, q->count);
-+	spin_unlock_irqrestore(&q->lock, flags);
-+}
-+
-+void xbus_enqueue_packet(xbus_t *xbus, packet_queue_t *q, xpacket_t *pack)
-+{
-+	unsigned long	flags;
-+
-+	spin_lock_irqsave(&q->lock, flags);
-+
-+	if(q->count >= max_queue_len) {
-+		static unsigned long	last_notice = 0;	// rate limit
-+
-+		if((jiffies - last_notice) < HZ) {
-+			NOTICE("xbus_enqueue_packet: dropping packet (queue len = %d, max=%d)\n",
-+				q->count, max_queue_len);
-+			last_notice = jiffies;
-+		}
-+		q->overflows++;
-+		xbus->ops->packet_free(xbus, pack);
-+		goto out;
-+	}
-+	list_add_tail(&pack->list, &q->head);
-+	q->count++;
-+
-+	if(q->count > q->worst_count)
-+		q->worst_count = q->count;
-+
-+	if(q->count < max_queue_len/100 && q->worst_count > q->count)	// Decay worst_count
-+		q->worst_count--;
-+
-+	// dump_packet("ENQUEUED", pack, print_dbg);
-+out:
-+	spin_unlock_irqrestore(&q->lock, flags);
-+}
-+
-+xpacket_t *xbus_dequeue_packet(packet_queue_t *q)
-+{
-+	unsigned long	flags;
-+	struct list_head	*p;
-+	xpacket_t	*pack = NULL;
-+
-+	spin_lock_irqsave(&q->lock, flags);
-+
-+	if(list_empty(&q->head)) {
-+		// DBG("LIST EMPTY (count=%d)\n", q->count);
-+		goto out;
-+	}
-+	p = q->head.next;
-+	list_del(p);
-+	q->count--;
-+	pack = list_entry(p, xpacket_t, list);
-+	// dump_packet("DEQUEUED", pack, print_dbg);
-+out:
-+	spin_unlock_irqrestore(&q->lock, flags);
-+	return pack;
-+}
-+
-+
-+/*------------------------- Bus Management -------------------------*/
-+xbus_t *xbus_of(int xbus_num)
-+{
-+	if(xbus_num < 0 || xbus_num >= MAX_BUSES)
-+		return NULL;
-+	return xbuses_array[xbus_num];
-+}
-+
-+xpd_t	*xpd_of(xbus_t *xbus, int xpd_num)
-+{
-+	if(!VALID_XPD_NUM(xpd_num))
-+		return NULL;
-+	return xbus->xpds[xpd_num];
-+}
-+
-+int xbus_register_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] != 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);
-+
-+	/*
-+	 * Send out the polls
-+	 */
-+	atomic_set(&xbus->count_poll_answers, 0);
-+	for(id = 0; id < MAX_XPDS; id++) {
-+		if(!xbus->hardware_exists)
-+			break;
-+		// 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;
-+}
-+
-+
-+void xbus_activate(xbus_t *xbus)
-+{
-+	xbus_ops_t *ops;
-+
-+	BUG_ON(!xbus);
-+	ops = xbus->ops;
-+	BUG_ON(!ops);
-+	BUG_ON(!xbus->priv);
-+	/* Sanity checks */
-+	BUG_ON(!ops->packet_send);
-+	BUG_ON(!ops->packet_new || !ops->packet_free);
-+	xbus->hardware_exists = 1;
-+	DBG("Activating: %s\n", xbus->busname);
-+	/* Poll it */
-+	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)
-+{
-+	int	i;
-+
-+	BUG_ON(!xbus);
-+	DBG("%s\n", xbus->busname);
-+	xbus->hardware_exists = 0;
-+	for(i = 0; i < MAX_XPDS; i++) {
-+		xpd_t *xpd = xpd_of(xbus, i);
-+		if(!xpd)
-+			continue;
-+		if(xpd->id != i) {
-+			ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i);
-+			continue;
-+		}
-+		xpd_disconnect(xpd);
-+	}
-+	DBG("%s (deactivated)\n", xbus->busname);
-+	if(xbus->open_counter == 0) {
-+		xbus_remove(xbus);
-+	}
-+}
-+
-+static xbus_t *xbus_alloc(void)
-+{
-+	unsigned long	flags;
-+	xbus_t	*xbus;
-+	int	i;
-+
-+	xbus = kmalloc(sizeof(xbus_t), GFP_KERNEL);
-+	if(!xbus) {
-+		ERR("%s: out of memory\n", __FUNCTION__);
-+		return NULL;
-+	}
-+	memset(xbus, 0, sizeof(xbus_t));
-+	spin_lock_irqsave(&xbuses_lock, flags);
-+	for(i = 0; i < MAX_BUSES; i++)
-+		if(xbuses_array[i] == NULL)
-+			break;
-+	if(i >= MAX_BUSES) {
-+		ERR("%s: No free slot for new bus. i=%d\n", __FUNCTION__, i);
-+		kfree(xbus);
-+		return NULL;
-+	}
-+	/* Found empty slot */
-+	xbuses_array[i] = xbus;
-+	xbus->num = i;
-+	bus_count++;
-+	spin_unlock_irqrestore(&xbuses_lock, flags);
-+	return xbus;
-+}
-+
-+
-+static void xbus_free(xbus_t *xbus)
-+{
-+	unsigned long	flags;
-+
-+	if(!xbus)
-+		return;
-+	spin_lock_irqsave(&xbuses_lock, flags);
-+	BUG_ON(xbus != xbus_of(xbus->num));
-+	xbuses_array[xbus->num] = NULL;
-+	bus_count--;
-+	spin_unlock_irqrestore(&xbuses_lock, flags);
-+#ifdef CONFIG_PROC_FS
-+	if(xbus->proc_xbus_dir) {
-+		if(xbus->proc_xbus_summary) {
-+			DBG("Removing proc '%s' for %s\n", PROC_XBUS_SUMMARY, xbus->busname);
-+			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;
-+	}
-+#endif
-+	device_remove_file(&xbus->the_bus, &dev_attr_status);
-+	device_remove_file(&xbus->the_bus, &dev_attr_connector);
-+	device_unregister(&xbus->the_bus);
-+	kfree(xbus);
-+}
-+
-+static void xbus_release(struct device *dev)
-+{
-+	xbus_t	*xbus;
-+
-+	BUG_ON(!dev);
-+	xbus = dev->driver_data;
-+	DBG("%s\n", xbus->busname);
-+}
-+
-+
-+xbus_t *xbus_new(xbus_ops_t *ops)
-+{
-+	int		err;
-+	xbus_t		*xbus = NULL;
-+
-+	BUG_ON(!ops);
-+	xbus = xbus_alloc();
-+	if(!xbus)
-+		return NULL;
-+
-+	/* Init data structures */
-+	spin_lock_init(&xbus->lock);
-+	snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%d", xbus->num);
-+	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);
-+
-+	/* Device-Model */
-+	snprintf(xbus->the_bus.bus_id, BUS_ID_SIZE, "xbus-%d", xbus->num);
-+	xbus->the_bus.driver_data = xbus;
-+	xbus->the_bus.release = xbus_release;
-+
-+	err = device_register(&xbus->the_bus);
-+	if(err) {
-+		ERR("%s: device_register failed: %d\n", __FUNCTION__, err);
-+		goto nobus;
-+	}
-+	err = device_create_file(&xbus->the_bus, &dev_attr_connector);
-+	if(err) {
-+		ERR("%s: device_create_file failed: %d\n", __FUNCTION__, err);
-+		goto nobus;
-+	}
-+	err = device_create_file(&xbus->the_bus, &dev_attr_status);
-+	if(err) {
-+		ERR("%s: device_create_file failed: %d\n", __FUNCTION__, err);
-+		goto nobus;
-+	}
-+
-+#ifdef CONFIG_PROC_FS
-+	DBG("Creating xbus proc directory %s.\n",xbus->busname);
-+	xbus->proc_xbus_dir = proc_mkdir(xbus->busname, xpp_proc_toplevel);
-+	if(!xbus->proc_xbus_dir) {
-+		ERR("Failed to create proc directory for xbus %s\n", xbus->busname);
-+		err = -EIO;
-+		goto nobus;
-+	}
-+	xbus->proc_xbus_summary = create_proc_read_entry(PROC_XBUS_SUMMARY, 0444, xbus->proc_xbus_dir,
-+			xbus_read_proc, xbus);
-+	if (!xbus->proc_xbus_summary) {
-+		ERR("Failed to create '%s' proc file for xbus %s\n", PROC_XBUS_SUMMARY, xbus->busname);
-+		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) {
-+		ERR("%s: missing mandatory handler: packet_send\n", __FUNCTION__);
-+		goto nobus;
-+	}
-+	if(!ops->packet_new || !ops->packet_free) {
-+		NOTICE("%s: Using default packet allocators\n", __FUNCTION__);
-+		ops->packet_new = xbus_packet_new;
-+		ops->packet_free = xbus_packet_free;
-+	}
-+
-+	xbus->ops = ops;
-+	return xbus;
-+nobus:
-+	xbus_free(xbus);
-+	return NULL;
-+}
-+
-+void xbus_remove(xbus_t *xbus)
-+{
-+	int	i;
-+	int	ret;
-+
-+	BUG_ON(!xbus);
-+	DBG("%s\n", xbus->busname);
-+
-+	/* Block until no one use */
-+	down_write(&xbus->in_use);
-+
-+	INFO("Removing xbus(%d) %s\n", xbus->num, xbus->busname);
-+	for(i = 0; i < MAX_XPDS; i++) {
-+		xpd_t *xpd = xpd_of(xbus, i);
-+
-+		if(xpd) {
-+			if(xpd->id != i) {
-+				ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i);
-+				continue;
-+			}
-+			DBG("  Removing xpd id=%d\n", xpd->id);
-+			xpd_remove(xpd);
-+		}
-+		xbus->xpds[i] = NULL;
-+	}
-+	ret = wait_event_interruptible(xbus->packet_cache_empty, 
-+			atomic_read(&xbus->packet_counter) == 0);
-+	if(ret) {
-+		ERR("waiting for packet_cache_empty interrupted!!!\n");
-+	}
-+	xbus_free(xbus);
-+}
-+
-+/*------------------------- Proc handling --------------------------*/
-+
-+void xbus_reset_counters(xbus_t *xbus)
-+{
-+	int	i;
-+
-+	DBG("Reseting counters of %s\n", xbus->busname);
-+	for(i = 0; i < XBUS_COUNTER_MAX; i++) {
-+		xbus->counters[i] = 0;
-+	}
-+}
-+
-+#if CONFIG_PROC_FS
-+static int xbus_read_proc(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;
-+	spin_lock_irqsave(&xbus->lock, flags);
-+
-+	len += sprintf(page + len, "%s: CONNECTOR=%s STATUS=%s bus_type=%d\n",
-+			xbus->busname,
-+			xbus->busdesc,
-+			(xbus->hardware_exists) ? "connected" : "missing",
-+			xbus->bus_type
-+		      );
-+	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)
-+		      );
-+	len += sprintf(page + len, "COUNTERS:\n");
-+	for(i = 0; i < XBUS_COUNTER_MAX; i++) {
-+		len += sprintf(page + len, "\t%-15s = %d\n",
-+				xbus_counters[i].name, xbus->counters[i]);
-+	}
-+	len += sprintf(page + len, "<-- len=%d\n", len);
-+	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 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;
-+	unsigned long flags;
-+	int i;
-+
-+	spin_lock_irqsave(&xbuses_lock, flags);
-+	for(i = 0; i < MAX_BUSES; i++) {
-+		xbus_t *xbus = xbus_of(i);
-+
-+		if(xbus) {
-+			len += sprintf(page + len, "%s: CONNECTOR=%s STATUS=%s bus_type=%d\n",
-+					xbus->busname,
-+					xbus->busdesc,
-+					(xbus->hardware_exists) ? "connected" : "missing",
-+					xbus->bus_type
-+				      );
-+		}
-+	}
-+#if 0
-+	len += sprintf(page + len, "<-- len=%d\n", len);
-+#endif
-+	spin_unlock_irqrestore(&xbuses_lock, flags);
-+	if (len <= off+count)
-+		*eof = 1;
-+	*start = page + off;
-+	len -= off;
-+	if (len > count)
-+		len = count;
-+	if (len < 0)
-+		len = 0;
-+	return len;
-+
-+}
-+#endif
-+
-+/*------------------------- Initialization -------------------------*/
-+
-+static DEVICE_ATTR_FUNC(connector_show, dev, buf)
-+{
-+	xbus_t	*xbus;
-+	int	ret;
-+
-+	xbus = dev->driver_data;
-+	ret = snprintf(buf, PAGE_SIZE, "%s\n", xbus->busdesc);
-+	return ret;
-+}
-+
-+static DEVICE_ATTR_FUNC(status_show, dev, buf)
-+{
-+	xbus_t	*xbus;
-+	int	ret;
-+
-+	xbus = dev->driver_data;
-+	ret = snprintf(buf, PAGE_SIZE, "%s\n", (xbus->hardware_exists)?"connected":"missing");
-+	return ret;
-+}
-+
-+static int xbus_match(struct device *dev, struct device_driver *driver)
-+{
-+	DBG("dev->bus_id = %s, driver->name = %s\n", dev->bus_id, driver->name);
-+	return strncmp(dev->bus_id, driver->name, strlen(driver->name)) == 0;
-+}
-+
-+#if 0
-+/* Hotplug replaced with uevent in 2.6.16 */
-+static int xbus_hotplug(struct device *device, char **envp, int envnum, char *buff, int bufsize)
-+{
-+	envp[0] = buff;
-+	if(snprintf(buff, bufsize, "XBUS_VERSION=%s", revision) >= bufsize)
-+		return -ENOMEM;
-+	envp[1] = NULL;
-+	return 0;
-+}
-+#endif
-+
-+struct bus_type	xbus_bus_type = {
-+	.name = "xbus",
-+	.match = xbus_match,
-+/* FIXME: Hotplug replaced with uevent in 2.6.16 */
-+#if 0
-+	.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);
-+#endif
-+	if(packet_cache)
-+		kmem_cache_destroy(packet_cache);
-+}
-+
-+int __init xbus_core_init(void)
-+{
-+	int	ret;
-+
-+	packet_cache = kmem_cache_create("xpp_packets",
-+			sizeof(xpacket_t),
-+			0, 0,
-+			NULL, NULL);
-+	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) {
-+		ERR("%s: bus_register failed. Error number %d", __FUNCTION__, ret);
-+		xbus_core_cleanup();
-+		return ret;
-+	}
-+	return 0;
-+}
-+
-+
-+void __exit xbus_core_shutdown(void)
-+{
-+	int		i;
-+
-+	for(i = 0; i < MAX_BUSES; i++) {
-+		xbus_t	*xbus = xbus_of(i);
-+		if(xbus)
-+			xbus_remove(xbus);
-+	}
-+	BUG_ON(bus_count);
-+	bus_unregister(&xbus_bus_type);
-+	xbus_core_cleanup();
-+}
-+
-+EXPORT_SYMBOL(xpd_of);
-+EXPORT_SYMBOL(xbus_new);
-+EXPORT_SYMBOL(xbus_remove);
-+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-LJNBCn_dist/xpp/xbus-core.h
---- zaptel-1.2.6/xpp/xbus-core.h	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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
-+ *
-+ * All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+#ifndef	XBUS_CORE_H
-+#define	XBUS_CORE_H
-+
-+#include "xpd.h"
-+
-+#define	MAX_BUSES		16
-+
-+int xbus_core_init(void);		/* Initializer */
-+void xbus_core_shutdown(void);		/* Terminator */
-+
-+/* Packet handling */
-+xpacket_t *xbus_packet_new(xbus_t *xbus, int flags);
-+void xbus_packet_free(xbus_t *xbus, xpacket_t *p);
-+
-+/* packet queues */
-+void init_xbus_packet_queue(packet_queue_t *q, const char name[]);
-+void drain_xbus_packet_queue(xbus_t *xbus, packet_queue_t *q);
-+void xbus_enqueue_packet(xbus_t *xbus, packet_queue_t *q, xpacket_t *pack);
-+xpacket_t *xbus_dequeue_packet(packet_queue_t *q);
-+
-+/* XBUS handling */
-+xbus_t	*xbus_of(int xbus_num);
-+xpd_t	*xpd_of(xbus_t *xbus, int xpd_num);
-+xbus_t	*xbus_new(xbus_ops_t *ops);
-+void xbus_remove(xbus_t *xbus);
-+void xbus_activate(xbus_t *xbus);
-+void xbus_disconnect(xbus_t *xbus);
-+
-+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-LJNBCn_dist/xpp/xdefs.h
---- zaptel-1.2.6/xpp/xdefs.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/xdefs.h	2006-07-03 12:11:26.109424000 +0300
-@@ -2,7 +2,7 @@
- #define	XDEFS_H
- /*
-  * Written by Oron Peled <oron at actcom.co.il>
-- * Copyright (C) 2004-2005, Xorcom
-+ * Copyright (C) 2004-2006, Xorcom
-  *
-  * All rights reserved.
-  *
-@@ -26,15 +26,10 @@
- 
- #include <linux/kernel.h>
- 
--#define	DBG(fmt, ...)	\
--	((print_dbg) && printk(KERN_DEBUG "DBG-%s: %s: " fmt, \
--		THIS_MODULE->name, __FUNCTION__, ## __VA_ARGS__))
--#define	INFO(fmt, ...)	printk(KERN_INFO "INFO-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
--#define	NOTICE(fmt, ...)	printk(KERN_NOTICE "NOTICE-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
--#define	ERR(fmt, ...)	printk(KERN_ERR "ERR-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
--
- #else
- 
-+/* This is to enable user-space programs to include this. */
-+
- #include <stdint.h>
- typedef uint32_t __u32;
- 
-@@ -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 */
-+#define	PACKED	__attribute__((packed))
- 
-+#define	ALL_LINES		((lineno_t)-1)
- 
--#define	BIT_SET(x,i)	((x) |= (1 << (i)))
--#define	BIT_CLR(x,i)	((x) &= ~(1 << (i)))
--#define	IS_SET(x,i)	(((x) & (1 << (i))) != 0)
- #define	BIT(i)		(1 << (i))
-+#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 */
-+#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-LJNBCn_dist/xpp/xpd.h
---- zaptel-1.2.6/xpp/xpd.h	2006-03-03 22:14:09.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/xpd.h	2006-07-03 12:11:26.109424000 +0300
-@@ -3,7 +3,7 @@
- 
- /*
-  * Written by Oron Peled <oron at actcom.co.il>
-- * Copyright (C) 2004-2005, Xorcom
-+ * Copyright (C) 2004-2006, Xorcom
-  *
-  * All rights reserved.
-  *
-@@ -28,6 +28,7 @@
- 
- #ifdef	__KERNEL__
- #include <linux/kernel.h>
-+#include <linux/device.h>
- #include <asm/atomic.h>
- #include <asm/semaphore.h>
- #include <linux/moduleparam.h>
-@@ -61,20 +62,6 @@
- #endif	// __KERNEL__
- 
- 
--#define	MAX_SPANNAME	20
--#define	MAX_SPANDESC	40
--#define	MAX_CHANNAME	20
--
--#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;
- 
- typedef enum xbus_type {
-@@ -100,15 +87,17 @@
- 	void (*packet_free)(xbus_t *xbus, xpacket_t *p);
- };
- 
-+/*
-+ * XBUS statistics counters
-+ */
- enum {
- 	XBUS_N_DESC_REQ,
--	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 {
--	bool		simulated;
--	bool		softloop_xpd;
--	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];
-+	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;
--#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;
-+	/* Simulator data */
-+	xbus_type_t		bus_type;
- 
--	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;
-+	struct proc_dir_entry	*proc_xbus_waitfor_xpds;
- #endif
- 
- 	/* statistics */
- 	int		counters[XBUS_COUNTER_MAX];
--
- };
- #endif
- 
-@@ -190,15 +187,11 @@
- 	TO_PSTN = 1,
- } xpd_direction_t;
- 
--#define	LINE_BITS	(sizeof(xpp_line_t)*8)
--
--
- #ifdef	__KERNEL__
--#define	BIT_SET(x,i)	((x) |= (1 << (i)))
--#define	BIT_CLR(x,i)	((x) &= ~(1 << (i)))
--#define	IS_SET(x,i)	(((x) & (1 << (i))) != 0)
--#define	BIT(i)		(1 << (i))
- 
-+/*
-+ * XPD statistics counters
-+ */
- enum {
- 	XPD_N_PCM_READ,
- 	XPD_N_PCM_WRITE,
-@@ -222,60 +215,74 @@
- 
- #define	XPD_COUNTER_MAX	(sizeof(xpd_counters)/sizeof(xpd_counters[0]))
- 
--enum leds {
--	LED_GREEN,
--	LED_RED,
--	LED_BLUE,
--};
-+#define	LED_BLINK_PERIOD	(HZ/8)
- 
--#define	NUM_LEDS	3
-+#define	LED_ON		1
-+#define	LED_OFF		0
-+#define	LED_BLINK	(-LED_BLINK_PERIOD)
-+
-+/* Values of SLIC register 0x40 */
-+enum fxs_state {
-+	FXS_LINE_DISABLED	= 0x00,
-+	FXS_LINE_ENABLED	= 0x01,
-+	FXS_LINE_CID		= 0x02,
-+	FXS_LINE_TIPOPEN	= 0x03,	/* For GroundStart signalling */
-+	FXS_LINE_RING		= 0x04,
-+	FXS_LINE_REV_ACTIVE	= 0x05
-+};
- 
-+/*
-+ * An XPD is a single Xorcom Protocol Device
-+ */
- struct xpd {
- 	char xpdname[XPD_NAMELEN];
- 	struct zt_span	span;
- 	struct zt_chan	*chans;
- 	int channels;
- 	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	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) */
-+	xpp_line_t	hookstate;		/* Actual chip state: 0 - ONHOOK, 1 - OFHOOK */
-+	xpp_line_t	cid_on;
- 	xpp_line_t	digital_outputs;	/* 0 - no, 1 - yes */
- 	xpp_line_t	digital_inputs;		/* 0 - no, 1 - yes */
- 
--	int	ringing[CHANNELS_PERXPD];
--	bool	ringer_on[CHANNELS_PERXPD];	/* For ring toggling */
--	bool	led_on[CHANNELS_PERXPD];	/* For led toggling */
--	int	lasttxhook[CHANNELS_PERXPD];
-+	int		ringing[CHANNELS_PERXPD];
-+	bool		ringer_on[CHANNELS_PERXPD];	/* For ring toggling */
-+
-+	wait_queue_head_t	txstateq[CHANNELS_PERXPD];	/* waiting on the tx state to change */
-+	int		delay_until_dialtone[CHANNELS_PERXPD];
- 
--	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];
-+
-+	xbus_t *xbus;			/* The XBUS we are connected to */
- 
- 	spinlock_t	lock;
--	atomic_t	open_counter;		/* Number of open channels */
-+	atomic_t	open_counter;	/* Number of open channels */
- 
- 	int		flags;
- 
--	unsigned int	board_flags;
--#define	XPD_BOARD_LOOPBACK	1
--
- #ifdef CONFIG_PROC_FS
- 	struct proc_dir_entry	*proc_xpd_dir;
- 	struct proc_dir_entry	*proc_xpd_summary;
- 	struct proc_dir_entry	*proc_xpd_ztregister;
- #endif
--	// Bit numbers of board_flags
- 
- 	int		counters[XPD_COUNTER_MAX];
- 
--	const xops_t	*xops;		/* Card level operations */
--	void		*priv;		/* Card level private data */
--	atomic_t	card_present;
-+	const xproto_table_t	*xproto;	/* Card level protocol table */
-+	const xops_t	*xops;			/* Card level operations */
-+	void		*priv;			/* Card level private data */
-+	bool		card_present;
- 
- 	unsigned int	recv_errors;
- 	unsigned int	seq_errors;
- 	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)++)
-+
- #endif
- 
- #endif	/* XPD_H */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_fxloader zaptel-xpp-LJNBCn_dist/xpp/xpp_fxloader
---- zaptel-1.2.6/xpp/xpp_fxloader	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/xpp_fxloader	1970-01-01 02:00:00.000000000 +0200
-@@ -1,24 +0,0 @@
--#!/bin/sh
--
--FIRMWARE="/etc/xortel/FPGA_XPD.hex"
--me=`basename $0`
--
--# to run manually, pass the parameter 'xppdetect'
--V_ID=04b4
--P_ID=8613
--if [ "$1" = 'xppdetect' ]; then
--	DEVICES=`lsusb | tr -d : | awk "/ ID $V_ID$P_ID /{printf \"/proc/bus/usb/%s/%s \",\\$2,\\$4}"`
--	echo "Loading firmware for $DEVICES"
--	for dev in $DEVICES
--	do
--		fxload -t fx2 -D $dev -I $FIRMWARE
--	done
--	exit 0
--fi
--
--if [ "$ACTION" = "add" ] && [ -f "$DEVICE" ]
--then
--	logger -i -t "$me" "Loading firmware '$FIRMWARE' into '$DEVICE'"
--	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-LJNBCn_dist/xpp/xpp_fxloader.usermap
---- zaptel-1.2.6/xpp/xpp_fxloader.usermap	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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-LJNBCn_dist/xpp/xpp_modprobe
---- zaptel-1.2.6/xpp/xpp_modprobe	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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
--#options wcfxo debug=1
--#options xpp print_dbg=1 
--
--# For pre-loading of card modules (e.g: xpp_fxs)
--#install xpp_usb /sbin/modprobe xpd_fxs && /sbin/modprobe --ignore-install xpp_usb
--
--# 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-LJNBCn_dist/xpp/xpp_proto.c
---- zaptel-1.2.6/xpp/xpp_proto.c	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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 */
--#include "xpd.h"
--#include "xpp_proto.h"
--#include "xpp_zap.h"
--
--static char rcsid[] = "$Id: xpp_proto.c 949 2006-02-15 02:24:18Z kpfleming $";
--
--extern	int print_dbg;
--#include "zap_debug.h"
--
--typedef struct xpp_command xpp_command_t;
--typedef	int (*xpp_handler_t)(xbus_t *xbus, int id, xpp_command_t *cmd, xpacket_t *packet);
--
--struct xpp_command {
--	xpp_opcode_t	opcode;
--	unsigned int	header_size;
--	bool		varsize;
--	const char	*name;
--	const char	*desc;
--	xpp_handler_t	handler;
--};
--
--#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"
--};
--
--static int packet_process(xbus_t *xbus, int xpd_num, xpacket_t *pack);
--static int simulate_xpd(xbus_t *xbus, int xpd_num, xpacket_t *sent_packet);
--static bool pcm_valid(xpd_t *xpd, xpacket_t *reply);
--
--#define	NEW_PACKET(p, xbus, name, to)	\
--	do {				\
--		p = xbus->ops->packet_new(xbus, GFP_ATOMIC);	\
--		if(!p)				\
--			return -ENOMEM;		\
--		PACKET_INIT(p, name);		\
--		XPD_ADDR_SET(p->content.addr, to); \
--	} while(0);
--
--/*------------------------- SLIC Handling --------------------------*/
--
--int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data)
--{
--	int		len = 0;
--	unsigned long	flags;
--	xpd_t		*xpd = data;
--	//slic_reply_t	*info;
--
--	BUG_ON(!xpd);
--	spin_lock_irqsave(&xpd->lock, flags);
--#if 0
--	info = (slic_reply_t *)&xpd->slic_info;
--	len += sprintf(page + len, "SLIC_REPLY: %s reg_num=0x%X, dataH=0x%X dataL=0x%X\n",
--			(info->indirect)?"I":"D",
--			info->reg_num, info->data_high, info->data_low);
--#endif
--	spin_unlock_irqrestore(&xpd->lock, flags);
--	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 parse_slic_cmd(const char *buf, slic_cmd_t *sc)
--{
--	char		op;		/* [W]rite, [R]ead */
--	char		reg_type;	/* [D]irect, [I]ndirect */
--	int		s1, s2, s3, s4;
--	int		reg_num;
--	int		data_low, data_high;
--	xpp_line_t	lines;
--	int		ret;
--
--	ret = sscanf(buf, "%x %x %x %x %c%c %x %x %x",
--			&s1, &s2, &s3, &s4, &op, &reg_type, &reg_num, &data_high, &data_low);
--	lines = (s4 << 24) | (s3 << 16) | (s2 << 8) | (s1);
--	switch(op) {
--		case 'R':
--			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);
--			} else if(reg_type == 'I' && 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_indirect_read(sc, lines, reg_num);
--			} else {
--				NOTICE("%s: Bad read input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
--				goto err;
--			}
--			break;
--		case 'W':
--			if(reg_type == 'D' && ret == 8) {
--				// DBG("0x%X 0x%X 0x%X 0x%X %c %x %X\n", s1, s2, s3, s4, reg_type, reg_num, data_high);
--				ret = slic_cmd_direct_write(sc, lines, reg_num, data_high);
--			} else if(reg_type == 'I' && ret == 9) {
--				// DBG("0x%X 0x%X 0x%X 0x%X %c %x %X %X\n", s1, s2, s3, s4, reg_type, reg_num, data_high, data_low);
--				ret = slic_cmd_indirect_write(sc, lines, reg_num, data_low, data_high);
--			} else {
--				NOTICE("%s: Bad write input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
--				goto err;
--			}
--			break;
--		default:
--			NOTICE("%s: Bad input: ret=%d buf='%s' op=%c\n", __FUNCTION__, ret, buf, op);
--			goto err;
--	}
--	return ret;
--err:
--	return -EINVAL;
--}
--
--static int process_slic_cmdline(xpd_t *xpd, char *cmdline)
--{
--	xbus_t		*xbus;
--	slic_cmd_t	sc;
--	xpacket_t	*pack_tx;
--	char		*p;
--	int		len = strlen(cmdline);
--
--	BUG_ON(!xpd);
--	xbus = xpd->xbus;
--	if((p = strchr(cmdline, '#')) != NULL)	/* Truncate comments */
--		*p = '\0';
--	if((p = strchr(cmdline, ';')) != NULL)	/* Truncate comments */
--		*p = '\0';
--	for(p = cmdline; *p && (*p == ' ' || *p == '\t'); p++) /* Trim leading whitespace */
--		;
--	if(*p == '\0')
--		return 0;
--	len = parse_slic_cmd(p, &sc);
--	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__);
--		return 0;
--	}
--	dump_slic_cmd("WRITE_SLIC", &sc);
--	NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
--	PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd) = sc;
--	pack_tx->datalen = len;
--	packet_send(xbus, pack_tx);
--	return 0;
--}
--
--int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
--{
--	xpd_t		*xpd = data;
--	const int	LINE_LEN = 500;
--	char		buf[LINE_LEN];
--	char		*p;
--	int		i;
--	int		ret;
--
--	BUG_ON(!xpd);
--	for(i = 0; i < count; /* noop */) {
--		for(p = buf; p < buf + LINE_LEN; p++) {	/* read a line */
--			if(i >= count)
--				break;
--			if(get_user(*p, buffer + i))
--				return -EFAULT;
--			i++;
--			if(*p == '\n' || *p == '\r')	/* whatever */
--				break;
--		}
--		if(p >= buf + LINE_LEN)
--			return -E2BIG;
--		*p = '\0';
--		ret = process_slic_cmdline(xpd, buf);
--		if(ret < 0)
--			return ret;
--	}
--	return count;
--}
--
--
--
--/*------------------------- Protocol Functions ---------------------*/
--
--#define	HOSTCMD(name, ...)		\
--			DECLARE_CMD(name, ## __VA_ARGS__ );	\
--			EXPORT_SYMBOL(xpp_proto_ ## name);	\
--			DECLARE_CMD(name, ## __VA_ARGS__ )
--
--
--/* 0x04 */ HOSTCMD(DESC_REQ, int xpd_num)
--{
--	int	ret = 0;
--	xpacket_t	*pack_tx;
--
--	DBG("\n");
--	if(!xbus) {
--		DBG("NO XBUS\n");
--		return -EINVAL;
--	}
--	NEW_PACKET(pack_tx, xbus, DESC_REQ, xpd_num);
--	DBG("calling packet_send for a DESC_REQ packet.\n");
--	ret = packet_send(xbus, pack_tx);
--	DBG("after packet_send, updating counter (ret=%d)\n", ret);
--	XBUS_COUNTER(xbus, DESC_REQ)++;
--	return ret;
--}
--
--/* 0x0F */ HOSTCMD(CHAN_POWER, xpp_line_t lines, bool on)
--{
--	int		ret = 0;
--	xpacket_t	*pack_tx;
--	slic_cmd_t	*sc;
--	int		len;
--
--	BUG_ON(!xbus);
--	BUG_ON(!xpd);
--	lines &= xpd->enabled_chans;	// Ignore disabled channels
--	if(!lines) {
--		return 0;
--	}
--	DBG("Channel Power: 0x%04X %s\n", lines, (on) ? "up" : "down");
--	NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
--	sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
--	if(on) {
--		// Power up
--		len = slic_cmd_direct_write(sc, lines, 0x42, 0x06);
--	} else {
--		// Power down
--		len = slic_cmd_direct_write(sc, lines, 0x42, 0x00);
--	}
--	pack_tx->datalen = len;
--
--	packet_send(xbus, pack_tx);
--	return ret;
--}
--
--/* 0x0F */ HOSTCMD(CHAN_ENABLE, xpp_line_t lines, bool on)
--{
--	int		ret = 0;
--	xpacket_t	*pack_tx;
--	slic_cmd_t	*sc;
--	int		len;
--
--	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");
--	NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
--	sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
--	len = slic_cmd_direct_write(sc, lines, 0x40, (on)?0x01:0x00);
--	pack_tx->datalen = len;
--
--	packet_send(xbus, pack_tx);
--	return ret;
--}
--
--/* 0x0F */ HOSTCMD(RING, int pos, bool on)
--{
--	int		ret = 0;
--	xpacket_t	*pack_tx;
--	slic_cmd_t	*sc;
--	xpp_line_t	mask = (1 << pos);
--	int		len;
--
--	BUG_ON(!xbus);
--	BUG_ON(!xpd);
--	mask &= xpd->enabled_chans;	// Ignore disabled channels
--	if(!mask) {
--		return 0;
--	}
--	DBG("%s pos=%d %s\n", xpd->xpdname, pos, (on) ? "on" : "off");
--	NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
--	sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
--	len = slic_cmd_direct_write(sc, mask, 0x40, (on)?0x04:0x01);
--	pack_tx->datalen = len;
--
--	packet_send(xbus, pack_tx);
--	return ret;
--}
--
--/* 0x0F */ HOSTCMD(SETHOOK, xpp_line_t hook_status)
--{
--	int		ret = 0;
--	xpacket_t	*pack_tx;
--	slic_cmd_t	*sc;
--	int		len;
--
--	BUG_ON(!xbus);
--	BUG_ON(!xpd);
--	hook_status &= xpd->enabled_chans;	// Ignore disabled channels
--	if(!hook_status) {
--		return 0;
--	}
--	DBG("New hook_status: %d\n", hook_status);
--	NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
--	sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
--	/* FIXME: This is fake, until Dima implements FXO */
--	len = slic_cmd_direct_write(sc, hook_status, 0x02, 0x00);
--	pack_tx->datalen = len;
--
--	packet_send(xbus, pack_tx);
--	return ret;
--}
--
--/*
-- * LED control is done via SLIC register 0x06:
-- *         7     6     5     4     3     2     1     0
-- * 	+-----+-----+-----+-----+-----+-----+-----+-----+
-- * 	| MR  | MG  | MB  |  R  | OG  | OB  |  G  | B   |
-- * 	+-----+-----+-----+-----+-----+-----+-----+-----+
-- *
-- * 	B	- BLUE LED (0 - OFF, 1 - ON)
-- * 	G	- GREEN LED (0 - OFF, 1 - ON)
-- * 	OB	- Output BLUE (this line is output)
-- * 	OG	- Output GREEN (this line is output)
-- * 	R	- RED LED (0 - OFF, 1 - ON)
-- * 	MB	- Mask BLUE. (1 - B effect the BLUE LED)
-- * 	MR	- Mask RED. (1 - R effect the RED LED)
-- * 	MG	- Mask GREEN. (1 - G effect the GREEN LED)
-- *
-- * 	The BLUE LED (actually a relay out) is connected to line 0 and 4 only.
-- */
--
--//		                 	GREEN	RED	BLUE
--static int	led_mask[NUM_LEDS] = { 	BIT(6),	BIT(7),	BIT(5) };
--static int	led_vals[NUM_LEDS] = { 	BIT(1),	BIT(4),	BIT(0) };
--
--/* 0x0F */ HOSTCMD(LED, xpp_line_t lines, byte which, bool on)
--{
--	int		ret = 0;
--	xpacket_t	*pack_tx;
--	slic_cmd_t	*sc;
--	int		len;
--	int		value;
--	int		i;
--
--	BUG_ON(!xbus);
--	BUG_ON(!xpd);
--	lines &= xpd->enabled_chans;	// Ignore disabled channels
--	if(!lines) {
--		return 0;
--	}
--	DBG("LED: lines=0x%04X which=%d -- %s\n", lines, which, (on) ? "on" : "off");
--	which = which % NUM_LEDS;
--	value = BIT(2) | BIT(3);
--	value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_mask[which]);
--	if(on)
--		value |= led_vals[which];
--	for(i = 0; i < CHANNELS_PERXPD; i++) {
--		if(!IS_SET(lines, i))
--				continue;
--		NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
--		sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
--		len = slic_cmd_direct_write(sc, lines, 0x06, value);
--		DBG("LED pack: line=%d value=0x%04X\n", i, value);
--		pack_tx->datalen = len;
--		packet_send(xbus, pack_tx);
--	}
--	return ret;
--}
--
--/* 0x0F */ HOSTCMD(RELAY_OUT, byte which, bool on)
--{
--	int		ret = 0;
--	xpacket_t	*pack_tx;
--	slic_cmd_t	*sc;
--	int		len;
--	int		value;
--	xpp_line_t	lines;
--	int		relay_channels[] = { 0, 4 };
--
--	BUG_ON(!xbus);
--	BUG_ON(!xpd);
--
--	DBG("RELAY_OUT: which=%d -- %s\n", which, (on) ? "on" : "off");
--	which = which % ARRAY_SIZE(relay_channels);
--	lines = BIT(relay_channels[which]);
--	value = BIT(2) | BIT(3);
--	value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_mask[LED_BLUE]);
--	if(on)
--		value |= led_vals[LED_BLUE];
--	NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
--	sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
--	len = slic_cmd_direct_write(sc, lines, 0x06, value);
--
--	DBG("RELAY_OUT pack: line=%d value=0x%04X\n", lines, value);
--	pack_tx->datalen = len;
--	packet_send(xbus, pack_tx);
--	return ret;
--}
--
--/* 0x0F */ HOSTCMD(SLIC_INIT)
--{
--	int	ret = 0;
--	xpacket_t		*pack_tx;
--	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];
--		NEW_PACKET(pack_tx, xbus, SLIC_INIT, xpd->id);
--		PACKET_FIELD(pack_tx, SLIC_INIT, lines) = source->lines;
--
--		slic = &PACKET_FIELD(pack_tx, SLIC_INIT, slic_data);
--		slic->len = source->slic_data.len;
--		memcpy(slic->data, source->slic_data.data, source->slic_data.len);
--		pack_tx->datalen = sizeof(xpp_line_t) + slic->len + 1;
--//		dump_packet("SLIC", pack_tx, print_dbg);
--		packet_send(xbus, pack_tx);
--		mdelay(10);	// FIXME: Temporary -- Dima need to fix it
--	}
--	return ret;
--}
--
--/* 0x0F */ HOSTCMD(SLIC_QUERY, int pos, byte reg_num)
--{
--	int	ret = 0;
--	xpacket_t	*pack_tx;
--	slic_cmd_t	*sc;
--	int		len;
--
--	BUG_ON(!xbus);
--	BUG_ON(!xpd);
--	NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
--	sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
--	len = slic_cmd_direct_read(sc, (1<<pos), reg_num);
--
--	pack_tx->datalen = len;
--
--	packet_send(xbus, pack_tx);
--	return ret;
--}
--
--/* 0x11 */ HOSTCMD(PCM_WRITE, xpp_line_t lines, volatile byte *buf)
--{
--	int	ret = 0;
--	xpacket_t	*pack_tx;
--	byte		*pcm;
--	byte		*start_pcm;
--	int i;
--	extern ulong	pcm_gen;
--
--	BUG_ON(!xbus);
--	BUG_ON(!xpd);
--	lines &= xpd->enabled_chans;
--	// DBG("PCM_WRITE\n");
--	if(pcm_gen != 0)
--		return 0;
--//	if(lines == 0)
--//		return 0;
--
--	/*
--	 * FIXME: Workaround a bug in sync code of the Astribank.
--	 *        Send dummy PCM for sync.
--	 */
--	if(lines == 0)
--		lines = BIT(0);
--
--	NEW_PACKET(pack_tx, xbus, PCM_WRITE, xpd->id);
--	PACKET_FIELD(pack_tx, PCM_WRITE, lines) = lines;
--	start_pcm = pcm = PACKET_FIELD(pack_tx, PCM_WRITE, pcm);
--	for(i = 0; i < CHANNELS_PERXPD; i++) {
--		if(IS_SET(lines, i)) {
--			memcpy(pcm, (byte *)buf, ZT_CHUNKSIZE);
--			pcm += ZT_CHUNKSIZE;
--		}
--		buf += ZT_CHUNKSIZE;
--	}
--	pack_tx->datalen = sizeof(xpp_line_t) + (pcm - start_pcm);
--	packet_send(xbus, pack_tx);
--	XPD_COUNTER(xpd, PCM_WRITE)++;
--	XBUS_COUNTER(xbus, PCM_WRITE)++;
--	return ret;
--}
--
--/* 0x13 */ HOSTCMD(PCM_GEN, xpp_line_t lines,  volatile byte *buf)
--{
--	xpacket_t	*pack_tx;
--	bool		gen_seq = ((lines != 0) && (buf != NULL));
--
--	BUG_ON(!xbus);
--	BUG_ON(!xpd);
--	lines &= xpd->enabled_chans;	// Ignore disabled channels
--	if(!lines) {
--		return 0;
--	}
--	DBG("PCM_GEN lines=0x%04X %s\n", lines, (gen_seq) ? "seq" : "off");
--	NEW_PACKET(pack_tx, xbus, PCM_GEN, xpd->id);
--	PACKET_FIELD(pack_tx, PCM_GEN, lines) = lines;
--	if(gen_seq) {
--		PACKET_FIELD(pack_tx, PCM_GEN, gen) = 0;
--		memcpy(&PACKET_FIELD(pack_tx, PCM_GEN, pcm_seq), (byte *)buf, ZT_CHUNKSIZE);
--	} else {
--		PACKET_FIELD(pack_tx, PCM_GEN, gen) = 2;
--	}
--	packet_send(xbus, pack_tx);
--	return 0;
--}
--
--/*
-- * Sync source is controled by a mask byte to 0x19 command:
-- *         7     6     5     4     3     2     1     0
-- * 	+-----+-----+-----+-----+-----+-----+-----+-----+
-- * 	|     |     |     |     |     |     | RW  | AB  |
-- * 	+-----+-----+-----+-----+-----+-----+-----+-----+
-- *
-- *	RW	- Read or set (0 - Write, 1 - Read)
-- *	AB	- This Astribank provide sync (0 - no, 1 - yes)
-- *
-- */
--
--/* 0x19 */ HOSTCMD(SYNC_SOURCE, bool setit, bool is_master)
--{
--	xpacket_t	*pack_tx;
--	byte		mask = 0;
--
--	BUG_ON(!xbus);
--	BUG_ON(!xpd);
--	if(is_master)
--		mask |= BIT(0);
--	if(!setit)
--		mask |= BIT(1);
--	DBG("SYNC_SOURCE %s setit=%s is_master=%s (mask=0x%X)\n",
--			xpd->xpdname, (setit)?"yes":"no", (is_master)?"yes":"no", mask);
--	NEW_PACKET(pack_tx, xbus, SYNC_SOURCE, xpd->id);
--	PACKET_FIELD(pack_tx, SYNC_SOURCE, mask) = mask;
--	packet_send(xbus, pack_tx);
--	return 0;
--}
--
--/* 0x31 */ HOSTCMD(LOOPBACK_AX, byte *data, unsigned int size)
--{
--	xpacket_t	*pack_tx;
--
--	BUG_ON(!xbus);
--	BUG_ON(!xpd);
--	DBG("LOOPBACK_AX %d bytes\n", size);
--	NEW_PACKET(pack_tx, xbus, LOOPBACK_AX, xpd->id);
--	memcpy(&PACKET_FIELD(pack_tx, LOOPBACK_AX, data), data, size);
--	packet_send(xbus, pack_tx);
--	return 0;
--}
--
--/*------------------------- Protocol Simulator ---------------------*/
--
--
--static int simulate_xpd(xbus_t *xbus, int xpd_num, xpacket_t *sent_packet)
--{
--	xpacket_t	*pack = sent_packet;
--	struct xpd_sim	*xpd_sim;
--	struct xpd_sim	*loopto_sim;
--	xpp_opcode_t	opcode;
--	int		dest_xpd_num;
--	int		ret = 0;
--
--	// Sanity checks
--	BUG_ON(!xbus);
--	BUG_ON(xpd_num > MAX_XPDS || xpd_num < 0);
--	BUG_ON(!sent_packet);
--	BUG_ON(!xbus->sim[xpd_num].simulated);
--
--	XBUS_COUNTER(xbus, SIM_PACKETS)++;
--	xpd_sim = &xbus->sim[xpd_num];
--	opcode = pack->content.opcode;
--	dest_xpd_num = xpd_sim->loopto;
--	loopto_sim = &xbus->sim[dest_xpd_num];
--//	DBG("before: addr=%d, opcode=0x%X\n", xpd_num, opcode);
--	switch(opcode) {
--		case XPP_DESC_REQ:
--			DBG("SIM DESC_REQ (xpd_num=%d)\n", xpd_num);
--			PACKET_INIT(pack, DEV_DESC);
--			PACKET_FIELD(pack, DEV_DESC, type) = xpd_sim->xpd_type;
--			dest_xpd_num = xpd_num;	// Reply as the original XPD
--			break;
--		case XPP_PCM_WRITE:
--			PACKET_INIT(pack, PCM_READ);
--			XPD_ADDR_SET(pack->content.addr, dest_xpd_num);
--			break;
--		case XPP_SLIC_WRITE:
--#if FINISHED_DECODING_SLICS
--			slic_cmd_t	*sc;
--			int		len;
--
--			sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
--			lines = sc->lines;
--			bool	slic_write = ! (slic->data[0] & 0x80);
--			int	slic_reg = slic->data[0] & ~0x80;
--
--			if(slic->len == 2 && slic_write && slic_reg == 0x40) {				// RING
--				bool		on = (slic->data[1] == 0x04);
--				if(on) {
--					loopto_sim->hookstate |= lines;
--				} else {
--					loopto_sim->hookstate &= ~lines;
--				}
--
--				DBG("SIM RING to: xpd=%d (type=%d): (%s) ringing=0x%04X lines=0x%04X\n", dest_xpd_num, loopto_sim->xpd_type,
--						(on)?"on":"off", loopto_sim->hookstate, lines);
--				PACKET_INIT(pack, SIG_CHANGED);
--				PACKET_FIELD(pack, SIG_CHANGED, type) = loopto_sim->xpd_type;
--				PACKET_FIELD(pack, SIG_CHANGED, sig_status) = loopto_sim->hookstate;
--				PACKET_FIELD(pack, SIG_CHANGED, sig_toggles) = lines;
--				dump_packet("SIM RING TO", pack, print_dbg);
--				break;
--			} else if(slic->len == 1 && slic_write && slic_reg == 0x02) {			// SETHOOK
--				DBG("SIM SETHOOK: xpd=%d: hookstate=0x%04X lines=0x%04X\n", dest_xpd_num, loopto_sim->hookstate, lines);
--				PACKET_INIT(pack, SIG_CHANGED);
--				PACKET_FIELD(pack, SIG_CHANGED, type) = loopto_sim->xpd_type;
--				PACKET_FIELD(pack, SIG_CHANGED, sig_status) = lines;
--				PACKET_FIELD(pack, SIG_CHANGED, sig_toggles) = loopto_sim->hookstate ^ lines;
--				loopto_sim->hookstate = lines;
--				break;
--			} else if(slic->len == 2 && slic_write && slic_reg == 0x06) {			// LED
--				DBG("SIM LED: xpd=%d: 0x%04X=%s\n", xpd_num, lines, (0x10)? "on" : "off");
--				ret = 0;
--				goto junk;
--			} else if(slic->len == 2 && ! slic_write) {				// SLIC_QUERY
--				DBG("SIM SLIC_QUERY: xpd=%d: register=0x%02X\n", xpd_num, slic_reg);
--				ret = 0;
--				goto junk;
--			} else if(slic->len >= 4) {						// INITIALIZATION?
--				DBG("SIM INITIALIZATION? xpd=%d len=%d\n", xpd_num, slic->len);
--				ret = 0;
--				goto junk;
--			}
--			NOTICE("%s: xpd=%d: SLIC_WRITE: len=%d\n", __FUNCTION__, xpd_num, slic->len);
--#endif
--			dump_packet("BAD SLIC_WRITE", pack, print_dbg);
--			// FALL THROUGH
--		default:
--			NOTICE("%s: xpd=%d: CANNOT SIMULATE OPCODE=0x%02X\n", 
--					__FUNCTION__, xpd_num, opcode);
--//			dump_packet("BAD OPCODE", pack, print_dbg);
--			ret = -EINVAL;
--			goto junk;
--	}
--//	DBG("after reversing: addr=%d, opcode=0x%X\n", xpd_num, pack->header.opcode);
--	return packet_process(xbus, dest_xpd_num, pack);
--junk:
--	xbus->ops->packet_free(xbus, pack);
--	return ret;
--}
--
--#define	VERBOSE_DEBUG			1
--#define	ERR_REPORT_LIMIT		20
--
--void dump_packet(const char *msg, xpacket_t *packet, bool print_dbg)
--{
--	xpp_opcode_t	op = (byte)packet->content.opcode;
--
--	if(!print_dbg)
--		return;
--	DBG("%s: @0x%02X OP=0x%02X flags=0x%02X LEN=%d\n",
--			msg,
--			XPD_NUM(packet->content.addr),
--			op,
--			(byte)packet->flags,
--			(byte)packet->datalen);
--#if VERBOSE_DEBUG
--	{
--		int i;
--		byte	*p = packet->content.raw;
--
--		for(i = 0; i < packet->datalen; i++) {
--			static int limiter = 0;
--
--			if(i >= sizeof(xpp_packet_r_t)) {
--				if(limiter < ERR_REPORT_LIMIT) {
--					ERR("dump_packet: length overflow i=%d > sizeof(xpp_packet_r_t)=%d\n",
--							i+1, sizeof(xpp_packet_r_t));
--				} else if(limiter == ERR_REPORT_LIMIT) {
--					ERR("dump_packet: error packet #%d... squelsh reports.\n", limiter);
--				}
--				limiter++;
--				break;
--			}
--			DBG("        %2d> %02X\n", i+1, p[i]);
--		}
--	}
--#endif
--}
--
--/*------------------------- Reply Handlers -------------------------*/
--
--#define	HANDLER_DEF(name)		\
--	int CALL_PROTO(name, xbus_t *xbus, int xpd_num, xpp_command_t *cmd, xpacket_t *reply)
--
--/*
--static HANDLER_DEF(notimp)
--{
--	NOTICE("xpp protocol error: command %s is not implemented yet\n", cmd->name);
--	return -EPROTO;
--}
--*/
--static HANDLER_DEF(DEV_DESC)
--{
--	byte		type = PACKET_FIELD(reply, DEV_DESC, type) & 0x7;	// 3 LSB's
--	byte		rev = PACKET_FIELD(reply, DEV_DESC, rev);
--	xpp_line_t	line_status = PACKET_FIELD(reply, DEV_DESC, line_status);
--	xpd_t		*xpd = xpd_of(xbus, xpd_num);
--
--	if(xpd) {
--		NOTICE("Received DEV_DESC packet for an existing xpd %s of type %d\n", 
--				xpd->xpdname, type);
--		return 0;
--	}
--	XBUS_COUNTER(xbus, DEV_DESC)++;
--	DBG("xpd=%d type=%d rev=%d line_status=0x%04X\n", xpd_num, type, rev, line_status);
--	switch(type) {
--	case XPD_TYPE_FXS:
--		break;
--	case XPD_TYPE_FXO:
--		break;
--	case XPD_TYPE_NOMODULE:
--		DBG("No module at address=%d\n", xpd_num);
--		return 0;
--	default:
--		NOTICE("DEV_DESC: unkown type=%d\n", type);
--		return -EPROTO;
--	}
--	if((xpd = xpd_new(xbus, xpd_num, type, rev)) == NULL) {
--		NOTICE("xpd_new failed\n");
--	}
--	xpp_check_hookstate(xpd, line_status);
--	return 0;
--}
--
--/**
-- * Handle signalling
-- */
--static HANDLER_DEF(SIG_CHANGED)
--{
--	xpd_t		*xpd = xpd_of(xbus, xpd_num);
--	xpp_line_t	sig_status = PACKET_FIELD(reply, SIG_CHANGED, sig_status);
--
--	if(!xpd) {
--		NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
--		return -EPROTO;
--	}
--	if(xpd->direction == TO_PHONE) {		/* Hook state changes */
--		DBG("%s (PHONE) sig_status=0x%04X\n", xpd->xpdname, sig_status);
--		xpp_check_hookstate(xpd, sig_status);
--	} else {					/* TO_TRUNK - line ring changes */
--		unsigned long	flags;
--		int		i;
--
--		DBG("%s (TRUNK) sig_status=0x%04X\n", xpd->xpdname, sig_status);
--		spin_lock_irqsave(&xpd->lock, flags);
--		for(i = 0; i < xpd->channels; i++) {
--			if(IS_SET(sig_status, i)) {
--				xpd->ringing[i] = RINGS_NUM*2;
--				zt_hooksig(&xpd->chans[i], ZT_RXSIG_OFFHOOK);
--			} else {
--				zt_hooksig(&xpd->chans[i], ZT_RXSIG_ONHOOK);
--				xpd->ringing[i] = 0;
--			}
--		}
--		spin_unlock_irqrestore(&xpd->lock, flags);
--	}
--	return 0;
--}
--
--static HANDLER_DEF(SLIC_REPLY)
--{
--	slic_reply_t	*info = &PACKET_FIELD(reply, SLIC_REPLY, info);
--	xpd_t		*xpd = xpd_of(xbus, xpd_num);
--	unsigned long	flags;
--
--	if(!xpd) {
--		NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
--		return -EPROTO;
--	}
--	spin_lock_irqsave(&xpd->lock, flags);
--	DBG("SLIC_REPLY: xpd #%d %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
--			xpd_num, (info->indirect)?"I":"D",
--			info->reg_num, info->data_low, info->data_high);
--	spin_unlock_irqrestore(&xpd->lock, flags);
--	return 0;
--}
--
--static HANDLER_DEF(PCM_READ)
--{
--	/* FIXME: work around temporary hardware bug */
--	xpd_num = 0;
--
--	xpp_line_t	lines = PACKET_FIELD(reply, PCM_READ, lines);
--	const byte	*pcm = PACKET_FIELD(reply, PCM_READ, pcm);
--	xpd_t		*xpd = xpd_of(xbus, xpd_num);
--	volatile u_char	*readchunk;
--	volatile u_char	*r;
--	unsigned long	flags;
--	int		i;
--
--	if(!xpd) {
--		NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
--		return -EPROTO;
--	}
--	// DBG("lines=0x%04X\n", lines);
--
--	if(!pcm_valid(xpd, reply)) {
--		return -EPROTO;
--	}
--	spin_lock_irqsave(&xpd->lock, flags);
--	if (xpd->timer_count & 1) {
--		/* First part */
--		r = readchunk = xpd->readchunk;
--	} else {
--		r = readchunk = xpd->readchunk + ZT_CHUNKSIZE * CHANNELS_PERXPD;
--	}
--
--	/* Copy PCM and put each channel in its index */
--	for (i = 0; i < CHANNELS_PERXPD; i++) {
--		if(IS_SET(lines, i)) {
--			memcpy((u_char *)r, pcm, ZT_CHUNKSIZE);
--			//memset((u_char *)r, 0x5A, ZT_CHUNKSIZE);	// DEBUG
--			pcm += ZT_CHUNKSIZE;
--		}
--		r += ZT_CHUNKSIZE;
--	}
--
--	XPD_COUNTER(xpd, PCM_READ)++;
--	XBUS_COUNTER(xpd->xbus, PCM_READ)++;
--	spin_unlock_irqrestore(&xpd->lock, flags);
--	if(xpd->id == 0)
--		xpp_tick(0);
--	return 0;
--}
--
--static HANDLER_DEF(SYNC_REPLY)
--{
--	xpd_t		*xpd = xpd_of(xbus, xpd_num);
--
--	if(!xpd) {
--		NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
--		return -EPROTO;
--	}
--	DBG("SYNC_REPLY: 0x%X\n", PACKET_FIELD(reply, SYNC_REPLY, mask));
--	return 0;
--}
--
--static HANDLER_DEF(LOOPBACK_XA)
--{
--	xpd_t		*xpd = xpd_of(xbus, xpd_num);
--
--	if(!xpd) {
--		NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
--		return -EPROTO;
--	}
--	dump_packet("LOOPBACK_XA", reply, print_dbg);
--	CALL_PROTO(LED, xpd->xbus, xpd, xpd->enabled_chans, LED_RED, 0);		// FIXME: Find usage for extra LED
--	return 0;
--}
--
--static HANDLER_DEF(DIAG_FE)
--{
--	dump_packet("DIAG_FE", reply, print_dbg);
--	return 0;
--}
--
--static const xpp_packet_r_t	FOR_SIZE_CALC;	// Ugly hack, so we have something to sizeof()
--
--#define	C_(op,var,txt)	\
--	   [ XPP_##op ] {	\
--		   .opcode = XPP_##op, \
--		   .varsize = var,	\
--		   .header_size = sizeof(FOR_SIZE_CALC.cmd_##op), \
--		   .name = #op, \
--		   .desc = txt, \
--		   .handler = PROTO_FUNC(op) \
--	   }
--
--static xpp_command_t xpp_commands[] = {
--  /*	OP		V 	DESCRIPTION	*/
--  C_(	DEV_DESC,	0,	"Device description reply"),
--  C_(	SIG_CHANGED,	0,	"Signaling change (hookstate/ringing)"),
--  C_(	SLIC_REPLY,	0,	"Reply to slic state"),
--  C_(	PCM_READ,	1,	"Read PCM data"),
--  C_(	SYNC_REPLY,	0,	"SYNC_REPLY"),
--  C_(	LOOPBACK_XA,	1,	"LOOPBACK Reply"),
--  C_(	DIAG_FE,	1,	"DIAG FE Opcode"),
--};
--
--#undef	C_
--
--static unsigned int xpp_max_opcode(void)
--{
--	return ARRAY_SIZE(xpp_commands);
--}
--
--static bool xpp_valid_opcode(xpp_opcode_t op)
--{
--	if(op <= 0 || op >= xpp_max_opcode())
--		return 0;
--	return xpp_commands[op].opcode != XPP_NOTIMP;
--}
--
--static xpp_command_t *xpp_command(xpp_opcode_t op)
--{
--	if(!xpp_valid_opcode(op))
--		return 0;
--	return &xpp_commands[op];
--}
--
--static bool xpp_valid_size(xpp_opcode_t op, xpacket_t *pack)
--{
--	xpp_command_t	*cmd = xpp_command(op);
--	unsigned int	hsize = cmd->header_size;
--	unsigned int	size = pack->datalen;
--	int		varsize = cmd->varsize;
--
--	// ERR("op=%d hsize=%d size=%d\n", op, hsize, size);
--	return (hsize == size) ||
--		(varsize && size <= sizeof(struct xpp_packet_r));
--}
--
--static bool pcm_valid(xpd_t *xpd, xpacket_t *reply)
--{
--	xpp_opcode_t	op;
--	xpp_command_t	*cmd;
--	xpp_line_t	lines = PACKET_FIELD(reply, PCM_READ, lines);
--	int		i;
--	int		count = 0;
--
--	BUG_ON(!reply);
--	op = reply->content.opcode;
--	cmd = xpp_command(op);
--	if(!cmd) {
--		ERR("xpp: %s -- bad command op=0x%02X\n", __FUNCTION__, op);
--		return 0;
--	}
--	for (i = 0; i < CHANNELS_PERXPD; i++)
--		if(IS_SET(lines, i))
--			count++;
--	if(reply->datalen != (sizeof(xpp_line_t) + count * 8)) {
--		static int rate_limit = 0;
--
--		XPD_COUNTER(xpd, RECV_ERRORS)++;
--		if((rate_limit++ % 1000) <= 10) {
--			ERR("BAD PCM REPLY: reply->datalen=%d, count=%d\n", reply->datalen, count);
--		}
--		return 0;
--	}
--	return 1;
--}
--
--int packet_receive(xbus_t *xbus, xpacket_t *pack)
--{
--	int	xpd_num = XPD_NUM(pack->content.addr);
--
--	if(!VALID_XPD_NUM(xpd_num)) {
--		dump_packet("martian packet", pack, print_dbg);
--		xbus->ops->packet_free(xbus, pack);
--		return -EPROTO;
--	}
--	if(xbus->sim[xpd_num].simulated) {
--		//dump_packet("packet_receive -> simulate", pack, print_dbg);
--		return simulate_xpd(xbus, xpd_num, pack);
--	} else {
--		//dump_packet("packet_receive -> process", pack, print_dbg);
--		return packet_process(xbus, xpd_num, pack);
--	}
--}
--
--static int packet_process(xbus_t *xbus, int xpd_num, xpacket_t *pack)
--{
--	xpp_opcode_t	op;
--	xpp_command_t	*cmd;
--	xpp_handler_t	handler;
--	int		ret = 0;
--
--	BUG_ON(!pack);
--	op = pack->content.opcode;
--	cmd = xpp_command(op);
--	/*-------- Validations -----------*/
--	if(!cmd) {
--		ERR("xpp: %s -- bad command op=0x%02X\n", __FUNCTION__, op);
--		dump_packet("packet_process -- bad command", pack, print_dbg);
--		ret = -EPROTO;
--		goto out;
--	}
--	if(!xpp_valid_size(op, pack)) {
--		ERR("xpp: %s: wrong size %d for op=0x%02X\n",
--					__FUNCTION__, pack->datalen, op);
--		dump_packet("packet_process -- wrong size", pack, print_dbg);
--		ret = -EPROTO;
--		goto out;
--	}
--	handler = cmd->handler;
--	BUG_ON(!handler);
--	XBUS_COUNTER(xbus, RX_BYTES) += pack->datalen;
--	handler(xbus, xpd_num, cmd, pack);
--out:
--	xbus->ops->packet_free(xbus, pack);
--	return ret;
--}
--
--
--void process_sim_queue(void *data)
--{
--	xbus_t 		*xbus = data;
--	xpacket_t	*pack;
--
--//	DBG("\n");
--	BUG_ON(!xbus);
--	while((pack = xbus_dequeue_packet(&xbus->sim_packet_queue)) != NULL) {
--//		DBG("pack->addr=0x%X pack->opcode=0x%X\n", XPD_NUM(pack->addr), pack->header.opcode);
--		packet_receive(xbus, pack);
--	}
--}
--
--/**
-- * processes a packet recieved from the lower-level.
-- * @xbus the data bus
-- * @pack the handled packet
-- * @returns return status (0 for success).
-- * 
-- * Should not be blocking. 
-- * Has separate handling for PCM packets (direct write) and command packets (queued)
-- */
--
--EXPORT_SYMBOL(dump_packet);
--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-LJNBCn_dist/xpp/xpp_proto.h
---- zaptel-1.2.6/xpp/xpp_proto.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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
--
--#include "xpd.h"
--#include "slic.h"
--#ifdef	__KERNEL__
--#include <linux/list.h>
--#endif
--
--#define	PCM_CHUNKSIZE	(CHANNELS_PERXPD * ZT_MAX_CHUNKSIZE)
--
--typedef enum xpp_opcode {
--	XPP_NOTIMP		= 0x00,
--//
--	XPP_DESC_REQ		= 0x04,
--	XPP_DEV_DESC		= 0x05,
--//
--	XPP_SIG_CHANGED		= 0x06,
--//
--	XPP_SLIC_WRITE		= 0x0F,	// Write to SLIC
--	XPP_CHAN_ENABLE		= 0x0F,	// Write to SLIC
--	XPP_CHAN_POWER		= 0x0F,	// Write to SLIC
--	XPP_RING		= 0x0F,	// Write to SLIC
--	XPP_SETHOOK		= 0x0F,	// Write to SLIC
--	XPP_LED			= 0x0F,	// Write to SLIC
--	XPP_RELAY_OUT		= 0x0F,	// Write to SLIC
--	XPP_SLIC_INIT		= 0x0F,	// Write to SLIC
--	XPP_SLIC_QUERY		= 0x0F,	// Write to SLIC
--//
--	XPP_SLIC_REPLY		= 0x10,
--//
--	XPP_PCM_WRITE		= 0x11,
--	XPP_PCM_READ		= 0x12,
--//
--	XPP_PCM_GEN		= 0x13,
--//
--	XPP_SYNC_SOURCE		= 0x19,
--	XPP_SYNC_REPLY		= 0x1A,
--//
--	XPP_LOOPBACK_AX		= 0x31,
--	XPP_LOOPBACK_XA		= 0x32,
--	XPP_DIAG_FE		= 0xFE,
--} xpp_opcode_t;
--
--/*------------------------- PROTOCOL COMMANDS ----------------------*/
--
--#define	XPP_MAX_DATA		50
--
--typedef	struct slic_data {
--	byte	len;
--	byte	data[40];
--} __attribute__((packed)) slic_data_t;
--
--#define	PROTO_FUNC(name)	xpp_proto_ ## name
--#define	CALL_PROTO(name, ...)	PROTO_FUNC(name)( __VA_ARGS__ )
--#define	DECLARE_CMD(name, ...)	\
--	int CALL_PROTO(name, xbus_t *xbus, xpd_t *xpd, ## __VA_ARGS__ )
--
--/* 0x04 */ DECLARE_CMD(DESC_REQ, int xpd_num);
--/* 0x0F */ DECLARE_CMD(CHAN_ENABLE, xpp_line_t lines, bool on);
--/* 0x0F */ DECLARE_CMD(CHAN_POWER, xpp_line_t lines, bool on);
--/* 0x0F */ DECLARE_CMD(RING, int pos, bool on);
--/* 0x0F */ DECLARE_CMD(SETHOOK, xpp_line_t hook_status);
--/* 0x0F */ DECLARE_CMD(LED, xpp_line_t lines, byte which, bool on);
--/* 0x0F */ DECLARE_CMD(RELAY_OUT, byte which, bool on);
--/* 0x0F */ DECLARE_CMD(SLIC_INIT);
--/* 0x0F */ DECLARE_CMD(SLIC_QUERY, int pos, byte reg_num);
--/* 0x11 */ DECLARE_CMD(PCM_WRITE, xpp_line_t hookstate,  volatile byte *buf);
--/* 0x13 */ DECLARE_CMD(PCM_GEN, xpp_line_t lines,  volatile byte *buf);
--/* 0x19 */ DECLARE_CMD(SYNC_SOURCE, bool setit, bool is_master);
--/* 0x31 */ DECLARE_CMD(LOOPBACK_AX, byte *data, unsigned int size);
--
--#define	H_(op, ...)	struct { \
--				__VA_ARGS__ \
--	} __attribute__((packed)) cmd_##op
--
--/*
-- * This struct must be packed exactly as the wire
-- * representation of the packet header after the
-- * XPD address byte
-- */
--typedef struct xpp_packet_r {
--	byte		opcode;
--	xpp_addr_t	addr;
--	union {
--
--		H_(NOTIMP);
--		H_(DESC_REQ);
--		H_(DEV_DESC,
--			byte		rev;					/* Revision number */
--			byte		type;
--			xpp_line_t	line_status;	/* hook/ring status, depending on unit */
--			);
--
--		H_(SIG_CHANGED,
--			byte		type;		/* unused -- we have it from DEV_DESC */
--			xpp_line_t	sig_status;	/* channels: lsb=1, msb=8 */
--			xpp_line_t	sig_toggles;	/* channels: lsb=1, msb=8 */
--			);
--
--		H_(SLIC_INIT,
--			xpp_line_t      lines;
--			slic_data_t     slic_data;
--			);
--		H_(SLIC_WRITE,
--			slic_cmd_t	slic_cmd;
--			);
--		H_(SLIC_REPLY,					/* Get status of a single SLIC (for debugging) */
--			xpp_line_t	lines;
--			slic_reply_t	info;
--			);
--
--		H_(PCM_WRITE,
--			xpp_line_t	lines;	// Must be 0xFF
--			byte		pcm[PCM_CHUNKSIZE];
--			);
--		H_(PCM_READ,
--			xpp_line_t	lines;	// Must be 0xFF
--			byte		pcm[PCM_CHUNKSIZE];
--			);
--
--		H_(PCM_GEN,
--			xpp_line_t	lines;
--			byte		gen;
--			byte		pcm_seq[ZT_CHUNKSIZE];
--			);
--
--		H_(SYNC_SOURCE,
--			byte		mask;
--			);
--		H_(SYNC_REPLY,
--			byte		mask;
--			);
--
--		H_(LOOPBACK_AX,
--			byte		data[XPP_MAX_DATA];	// FIXME: what data size?
--			);
--		H_(LOOPBACK_XA,
--			byte		data[XPP_MAX_DATA];	// FIXME: what data size?
--			);
--		H_(DIAG_FE);
--		unsigned char	raw[0];
--	};
--} __attribute__((packed)) xpp_packet_r_t;
--#undef	H_
--
--#ifdef	__KERNEL__
--
--enum {
--	XPP_PACKET_FIREANDFORGET	= 0x1,
--};
--
--/**
-- * The packet that will actually be sent on the wire.
-- *
-- * TODO: not a good medium-level abstrction
-- */
--struct xpp_packet {
--	struct xpp_packet_r	content;
--	unsigned int		flags;
--	size_t				datalen;
--	struct list_head	list;
--};
--
--#define DATA_LEN(p, name) \
--	sizeof(p->content.cmd_ ## name)
--
--#define	PACKET_LEN(p) \
--	((p)->datalen + sizeof(xpp_addr_t) + 1)
--
--#define	PACKET_INIT(p, name)		\
--	p->content.opcode = XPP_ ## name;	\
--	p->datalen = DATA_LEN(p, name)
--
--#define	PACKET_FIELD(p, name, field)	\
--	p->content.cmd_ ## name.field
--
--void dump_packet(const char *msg, xpacket_t *packet, bool print_dbg);
--void enqueue_xmit(xbus_t *xbus, xpacket_t *pack);
--void process_sim_queue(void *xbus);
--int validate_reply(xpacket_t *reply);
--int packet_receive(xbus_t *xbus, xpacket_t *pack);
--int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
--int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data);
--
--#endif
--
--#endif	/* XPP_PROTO_H */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_usb.c zaptel-xpp-LJNBCn_dist/xpp/xpp_usb.c
---- zaptel-1.2.6/xpp/xpp_usb.c	2006-04-03 10:08:13.000000000 +0300
-+++ zaptel-xpp-LJNBCn_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>
-- * Copyright (C) 2004-2005, Xorcom
-+ * Copyright (C) 2004-2006, Xorcom
-  *
-  * All rights reserved.
-  *
-@@ -30,6 +30,7 @@
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/errno.h>
-+#include <linux/interrupt.h>
- #include <linux/delay.h>	/* for udelay */
- #include <linux/seq_file.h>
- #include <asm/uaccess.h>
-@@ -37,11 +38,16 @@
- #include <asm/timex.h>
- #include <linux/proc_fs.h>
- #include <linux/usb.h>
-+#include <version.h>		/* For zaptel version */
- #include "xpd.h"
- #include "xproto.h"
--#include "xpp_zap.h"
-+#include "xbus-core.h"
-+#ifdef	DEBUG
-+#include "card_fxs.h"
-+#include "card_fxo.h"
-+#endif
- 
--static const char revision[] = "$Revision: 995 $";
-+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 */
- 
-@@ -52,13 +58,11 @@
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
- #  define URB_ASYNC_UNLINK 0
- #endif
--
- #define	USBDEV_MAX	10
- /* Get a minor range for your devices from the usb maintainer */
- #define USB_SKEL_MINOR_BASE	192
- 
- #ifdef CONFIG_PROC_FS
--#define	PROC_XBUSES	"xpp_usb"
- #define	PROC_USBXPP_SUMMARY	"xpp_usb"
- #endif
- 
-@@ -70,8 +74,9 @@
- struct xusb_model_info;
- 
- struct xusb_endpoint {
--	int	epnum;
--	int	max_size;
-+	int		ep_addr;
-+	int		max_size;
-+	usb_complete_t	callback;
- };
- 
- static int xusb_packet_send(xbus_t *xbus, xpacket_t *pack);
-@@ -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,
-+};
-+
- /*
-  * USB XPP Bus (a USB Device)
-  */
--struct xpp_usb_bus {
-+typedef struct xpp_usb_bus {
- 	xbus_t			*xbus;
- 	struct usb_device	*udev;			/* save off the usb device pointer */
- 	struct usb_interface	*interface;		/* the interface for this device */
- 	unsigned char		minor;			/* the starting minor number for this device */
- 
- 	struct xusb_model_info	*model_info;
--	struct xusb_endpoint	ep_in;
--	struct xusb_endpoint	ep_out;
-+	struct xusb_endpoint	endpoints[2];		/* RECV/SEND endpoints */
- 
- 	struct urb		*read_urb;
- 
-@@ -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];
--};
-+} xusb_t;
- 
- static	spinlock_t	xusb_lock = SPIN_LOCK_UNLOCKED;
--static struct xpp_usb_bus *xusb_array[USBDEV_MAX] = {};
-+static xusb_t *xusb_array[USBDEV_MAX] = {};
- static unsigned bus_count = 0;
- 
- 
-@@ -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);
--static struct urb *xpp_urb_new(struct xpp_usb_bus *dev, unsigned int ep_addr, size_t size, usb_complete_t urb_cb);
-+static struct urb *xpp_urb_new(xusb_t *dev, enum xusb_dir dir, size_t size);
- static void xpp_send_callback(struct urb *urb, struct pt_regs *regs);
- static void xpp_receive_callback(struct urb *urb, struct pt_regs *regs);
- 
-@@ -208,42 +220,34 @@
- 	//DBG("Decremented packet_counter of bus %s (freed packet) to %d\n", 
- 	//		xbus->busname, atomic_read(&xbus->packet_counter));
- }
-+
- #endif
- 
--static int xusb_packet_send(xbus_t *xbus, xpacket_t *pack)
--{
--	struct xpp_usb_bus *xusb = xbus->priv;
--	struct urb	*urb;
--	int		ret = 0;
--	size_t		size;
-+#ifndef DEBUG
- 
--	BUG_ON(!pack);
--	if(!xusb->present) {
--		NOTICE("tried to send packets to non-exitant USB device. Ignored\n");
--		goto error;
--	}
--#if SOFT_SIMULATOR
--	{
--		int		toxpd = XPD_NUM(pack->content.addr);
-+#define	packet_debug(m, x, p)
- 
--		if (xbus->sim[toxpd].softloop_xpd) {
--			// "send" through loopback queue
--			//DBG("%s: ENQUEUE toxpd=%d, opcode=%X\n", xbus->busname, toxpd, pack->content.opcode);
--			XBUS_COUNTER(xbus, SOFTSIM_PACKETS)++;
--			xbus_enqueue_packet(xbus, &xbus->sim_packet_queue, pack);
--			ret = queue_work(xbus->sim_workqueue, &xbus->sim_work);
--			if(ret < 0) {
--				ERR("%s: queue_work failed with %d (ignoring)\n", __FUNCTION__, ret);
--				goto error;
--			}
--		}
--		return 0;
--	}
--#endif
--	size = min(PACKET_LEN(pack), (size_t)xusb->ep_out.max_size);
--	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
-+		/*
-+		 * DEBUG: high-res timing of PCM_READ to PCM_WRITE
-+		 */
-+		stamp_last_pcm_read = get_cycles();
-+#endif
-+#if 0
-+		// fill_beep((u_char *)&PACKET_FIELD(pack, PCM_READS, pcm), 2);	// Debugging BEEP
-+		static	int rate_limit;
-+		if((rate_limit++ % 1000) < 10)
-+			dump_packet("USB RECEIVE PCM", pack, print_dbg);
-+#endif
-+		return;
-+	} else if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE)) {
- #ifdef	DEBUG_PCM_TIMING
- 		/*
- 		 * DEBUG: high-res timing of PCM_READ to PCM_WRITE
-@@ -253,50 +257,96 @@
- #endif
- #if 0
- 		static	int rate_limit;
--		if((rate_limit++ % 1009) < 3) {
-+		if((rate_limit++ % 1000) < 10)
- 			dump_packet("USB SEND PCM", pack, print_dbg);
--		}
- #endif
--	} else {
--		dump_packet("USB_PACKET_SEND", pack, print_dbg);
-+		return;
-+	} else if(pack->content.opcode == XPROTO_NAME(FXS, SLIC_WRITE)) {
-+		slic_cmd_t	*sc;
-+
-+		sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
-+		if(sc->bytes == 2 && sc->content.direct.reg_num == 0x06 && sc->content.direct.read)	/* ignore SLIC_QUERY */
-+			return;
-+		if(sc->bytes == 2 && sc->content.direct.reg_num == DAA_VBAT_REGISTER && sc->content.direct.read)	/* ignore DAA_QUERY */
-+			return;
-+	} else if(pack->content.opcode == XPROTO_NAME(FXS, SLIC_REPLY)) {
-+			return;
-+	}
-+	snprintf(title, XBUS_DESCLEN, "%s: %s", msg, xusb->xbus->busname);
-+	dump_packet(title, pack, print_dbg);
-+}
-+#endif
-+
-+static int xusb_packet_send(xbus_t *xbus, xpacket_t *pack)
-+{
-+	xusb_t			*xusb;
-+	struct urb		*urb;
-+	int			ret = 0;
-+	size_t			size;
-+	struct xusb_endpoint	*xusb_ep;
-+
-+	BUG_ON(!pack);
-+	BUG_ON(!xbus);
-+	xusb = xbus->priv;
-+	BUG_ON(!xusb);
-+	if(!xusb->present) {
-+		NOTICE("tried to send packets to non-exitant USB device. Ignored\n");
-+		ret = -ENODEV;
-+		goto out;
- 	}
--	urb = xpp_urb_new(xusb, xusb->ep_out.epnum, size, xpp_send_callback);
-+	size = PACKET_LEN(pack);
-+	xusb_ep = &xusb->endpoints[XUSB_SEND];
-+	urb = xpp_urb_new(xusb, XUSB_SEND, size);
- 	if (!urb) {
- 		ERR("No free urbs available\n");
- 		ret = -ENOMEM;
--		goto error;
-+		goto out;
- 	}
-+	packet_debug("USB_PACKET_SEND", xusb, pack);
- 
- 	/* FIXME: FIXME: FIXME: we use copy+free until low-level drivers allocate memory themselves */
- 	memcpy(urb->transfer_buffer, &pack->content, size);
--	xbus->ops->packet_free(xbus, pack);
- 
--	ret = usb_submit_urb(urb, GFP_KERNEL);
-+	ret = usb_submit_urb(urb, GFP_ATOMIC);
- 	if(ret < 0) {
--		ERR("%s: failed submit_urb\n", __FUNCTION__);
--		XUSB_COUNTER(xusb, TX_ERRORS)++;
-+		ERR("%s: failed submit_urb: %d\n", __FUNCTION__, ret);
- 		xpp_urb_delete(urb);
--		return -EBADF;
-+		ret = -EBADF;
-+		goto out;
- 	}
--	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:
-+	if(ret < 0)
-+		XUSB_COUNTER(xusb, TX_ERRORS)++;
- 	xbus->ops->packet_free(xbus, pack);	// FIXME: eventually will be done in the urb callback
- 	return ret;
- }
- 
- static void xpp_urb_delete(struct urb *urb)
- {
-+	BUG_ON(!urb);
- 	// DBG("%s: (%d) %p %X", __FUNCTION__, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma);
- 	usb_buffer_free (urb->dev, urb->transfer_buffer_length,
- 			urb->transfer_buffer,
- 			urb->transfer_dma);
--	usb_free_urb (urb);
-+	usb_free_urb(urb);
- }
- 
--static struct urb *xpp_urb_new(struct xpp_usb_bus *dev, unsigned int ep_addr, size_t size, usb_complete_t urb_cb)
--
-+static struct urb *xpp_urb_new(xusb_t *xusb, enum xusb_dir dir, size_t size)
- {
--	struct usb_device	*udev = dev->udev;
-+	struct usb_device	*udev = xusb->udev;
-+	struct xusb_endpoint	*xusb_ep = &xusb->endpoints[dir];
-+	unsigned int	ep_addr = xusb_ep->ep_addr;
-+	usb_complete_t	urb_cb = xusb_ep->callback;
- 	struct urb	*urb;
- 	unsigned char	*buffer;	/* the buffer to send data */
- 	unsigned int	epnum = ep_addr & USB_ENDPOINT_NUMBER_MASK;
-@@ -304,6 +354,8 @@
- 					? usb_rcvbulkpipe(udev, epnum)
- 					: usb_sndbulkpipe(udev, epnum);
- 		 
-+	if(size > xusb_ep->max_size)
-+		return NULL;
- 	urb = usb_alloc_urb(0, GFP_ATOMIC);
- 	if (!urb) {
- 		err("No free urbs available");
-@@ -326,32 +378,36 @@
- 		usb_free_urb(urb);
- 		return NULL;
- 	}
--	usb_fill_bulk_urb(urb, udev, pipe, buffer, size, urb_cb, dev);
-+	usb_fill_bulk_urb(urb, udev, pipe, buffer, size, urb_cb, xusb);
- 	return urb;
- }
- 
- /*------------------------- XPP USB Bus Handling -------------------*/
- 
--static	struct xusb_model_info {
-+#define	XUSB_MODEL(ep_in,ep_out,type,str)	\
-+	{					\
-+		.in = { .ep_addr = (ep_in) },	\
-+		.out = { .ep_addr = (ep_out) },	\
-+		.bus_type = (type),		\
-+		.desc = (str)			\
-+	}
-+
-+static const struct xusb_model_info {
- 	const char		*desc;
- 	struct xusb_endpoint	in;
- 	struct xusb_endpoint	out;
- 	xbus_type_t		bus_type;
- } model_table[] = {
--	{ .in = { .epnum = 0x86 }, .out = { .epnum = 0x2 }, .bus_type = FIRMWARE_LOOPBACK, .desc = "bulkloop.hex" },
--	{ .in = { .epnum = 0x86 }, .out = { .epnum = 0x2 }, .bus_type = FIRMWARE_LOOPBACK, .desc = "FPGA_bulkloop.hex" },
--	{ .in = { .epnum = 0x86 }, .out = { .epnum = 0x2 }, .bus_type = FIRMWARE_XPP, .desc = "FPGA_XPD.hex" },
-+	XUSB_MODEL(0x86, 0x02, FIRMWARE_LOOPBACK,	"bulkloop.hex"),
-+	XUSB_MODEL(0x86, 0x02, FIRMWARE_LOOPBACK,	"FPGA_bulkloop.hex"),
-+	XUSB_MODEL(0x86, 0x02, FIRMWARE_XPP,		"FPGA_XPD.hex"),
- };
- 
- /* table of devices that work with this driver */
--static struct usb_device_id xusb_table [] = {
-+static const struct usb_device_id xusb_table [] = {
- //	{ USB_DEVICE(0x04B4, 0x8613) }, // default of cypress
--	{ USB_DEVICE(0x0547, 0x1002), .driver_info=(int)&model_table[0] }, // bulkloop.hex
--//	{ 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(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
- 	/* "Gadget Zero" firmware runs under Linux */
- 	//{ 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)
--        .owner =	THIS_MODULE,
-+	.owner =	THIS_MODULE,
- #endif
- 	.name =		"xpp_usb",
- 	.probe =	xusb_probe,
-@@ -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]
-  */
--static int set_endpoints(struct xpp_usb_bus *xusb, struct usb_interface *interface, struct xusb_model_info *model_info)
-+static int set_endpoints(xusb_t *xusb, struct usb_interface *interface, struct xusb_model_info *model_info)
- {
- 	struct usb_host_interface	*iface_desc;
- 	struct usb_endpoint_descriptor	*endpoint;
-+	struct xusb_endpoint		*xusb_ep;
-+	int				ep_addr;
- 	int i;
- 
- 	iface_desc = &interface->altsetting[0];
-@@ -425,37 +483,40 @@
- 
- 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- 		endpoint = &iface_desc->endpoint[i].desc;
--		int	epnum = endpoint->bEndpointAddress;
-+		ep_addr = endpoint->bEndpointAddress;
- 		
- 		if(!BULK_ENDPOINT(endpoint)) {
- 			DBG("endpoint 0x%x is not bulk: mbAttributes=0x%X\n",
--					epnum, endpoint->bmAttributes);
-+					ep_addr, endpoint->bmAttributes);
- 			continue;
- 		}
--		if(epnum & USB_DIR_IN) {	// Input
--			if(epnum == model_info->in.epnum) {
-+		if(usb_pipein(ep_addr)) {	// Input
-+			if(ep_addr == model_info->in.ep_addr) {
- 				if(endpoint->wMaxPacketSize < sizeof(xpacket_raw_t)) {
--					ERR("USB input endpoint 0x%X support only wMaxPacketSize=%d (need USB-2)\n", epnum, endpoint->wMaxPacketSize);
--					break;
-+					NOTICE("USB input endpoint 0x%X support only wMaxPacketSize=%d (need USB-2)\n", ep_addr, endpoint->wMaxPacketSize);
- 				}
--				xusb->ep_in.epnum = epnum;
--				xusb->ep_in.max_size = endpoint->wMaxPacketSize;
-+				xusb_ep = &xusb->endpoints[XUSB_RECV];
-+				xusb_ep->ep_addr = ep_addr;
-+				xusb_ep->max_size = endpoint->wMaxPacketSize;
-+				xusb_ep->callback = xpp_receive_callback;
- 			}
--		} else {					// Output
--			if(epnum == model_info->out.epnum) {
-+		} else {			// Output
-+			if(ep_addr == model_info->out.ep_addr) {
- 				if(endpoint->wMaxPacketSize < sizeof(xpacket_raw_t)) {
--					ERR("USB output endpoint 0x%X support only wMaxPacketSize=%d (need USB-2)\n", epnum, endpoint->wMaxPacketSize);
--					break;
-+					NOTICE("USB output endpoint 0x%X support only wMaxPacketSize=%d (need USB-2)\n", ep_addr, endpoint->wMaxPacketSize);
- 				}
--				xusb->ep_out.epnum = epnum;
--				xusb->ep_out.max_size = endpoint->wMaxPacketSize;
-+				xusb_ep = &xusb->endpoints[XUSB_SEND];
-+				xusb_ep->ep_addr = ep_addr;
-+				xusb_ep->max_size = endpoint->wMaxPacketSize;
-+				xusb_ep->callback = xpp_send_callback;
- 			}
- 		}
- 	}
--	if (!xusb->ep_in.epnum || !xusb->ep_out.epnum) {
-+	if (!xusb->endpoints[XUSB_RECV].ep_addr || !xusb->endpoints[XUSB_SEND].ep_addr) {
- 		ERR("Couldn't find bulk-in or bulk-out endpoints\n");
- 		return 0;
- 	}
-+	DBG("in=0x%02X out=0x%02X\n", xusb->endpoints[XUSB_RECV].ep_addr, xusb->endpoints[XUSB_SEND].ep_addr);
- 	return 1;
- }
- 
-@@ -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);
--	struct xpp_usb_bus	*xusb = NULL;
-+	xusb_t			*xusb = NULL;
- 	struct xusb_model_info	*model_info = (struct xusb_model_info*)id->driver_info;
--	struct proc_dir_entry	*procsummary;
--	xbus_t			*xbus;
-+	struct proc_dir_entry	*procsummary = NULL;
-+	xbus_t			*xbus = NULL;
-+	struct xusb_endpoint	*xusb_ep;
- 	unsigned long		flags;
- 	int			retval = -ENOMEM;
- 	int			i;
-@@ -490,15 +552,16 @@
- 	}
- 
- 	/* allocate memory for our device state and initialize it */
--	xusb = kmalloc(sizeof(struct xpp_usb_bus), GFP_KERNEL);
-+	xusb = kmalloc(sizeof(xusb_t), GFP_KERNEL);
- 	if (xusb == NULL) {
- 		ERR("xpp_usb: Unable to allocate new xpp usb bus\n");
- 		retval = -ENOMEM;
- 		goto probe_failed;
- 	}
--	memset(xusb, 0, sizeof(struct xpp_usb_bus));
-+	memset(xusb, 0, sizeof(xusb_t));
- 
- 	init_MUTEX (&xusb->sem);
-+	atomic_set(&xusb->pending_writes, 0);
- 	xusb->udev = udev;
- 	xusb->interface = interface;
- 	xusb->model_info = model_info;
-@@ -507,12 +570,14 @@
- 		retval = -ENODEV;
- 		goto probe_failed;
- 	}
--	xusb->read_urb = xpp_urb_new(xusb, xusb->ep_in.epnum, xusb->ep_in.max_size, xpp_receive_callback);
-+	xusb_ep = &xusb->endpoints[XUSB_RECV];
-+	xusb->read_urb = xpp_urb_new(xusb, XUSB_RECV, xusb_ep->max_size);
- 	if (!xusb->read_urb) {
- 		ERR("No free urbs available\n");
- 		retval = -ENOMEM;
- 		goto probe_failed;
- 	}
-+
- 	/* allow device read, write and ioctl */
- 	xusb->present = 1;
- 
-@@ -521,7 +586,7 @@
- 	retval = usb_register_dev (interface, &xusb_class);
- 	if (retval) {
- 		/* something prevented us from registering this driver */
--		ERR ("Not able to get a minor for this device.");
-+		ERR ("Not able to get a minor for this device.\n");
- 		goto probe_failed;
- 	}
- 
-@@ -531,33 +596,31 @@
- 	INFO ("USB XPP device now attached to minor %d\n", xusb->minor);
- 
- 	/* Allocate high level structures */
--	xbus = xbus_new((model_info->bus_type == FIRMWARE_LOOPBACK) ? ~0 : 0);
-+	xbus = xbus_new(&xusb_ops);
- 	if(!xbus) {
- 		retval = -ENOMEM;
- 		goto probe_failed;
- 	}
--	xusb->xbus = xbus;
--	xbus->priv = xusb;
- 	xbus->bus_type = model_info->bus_type;
-+	xbus->max_packet_size = min(xusb->endpoints[XUSB_SEND].max_size , xusb->endpoints[XUSB_RECV].max_size);
- 
- 	spin_lock_irqsave(&xusb_lock, flags);
- 	for(i = 0; i < USBDEV_MAX; i++) {
- 		if(xusb_array[i] == NULL)
- 			break;
- 	}
-+	spin_unlock_irqrestore(&xusb_lock, flags);
- 	if(i >= USBDEV_MAX) {
- 		ERR("xpp_usb: Too many XPP USB buses\n");
- 		retval = -ENOMEM;
- 		goto probe_failed;
- 	}
--	spin_unlock_irqrestore(&xusb_lock, flags);
- 	{
- 		char	path[XBUS_DESCLEN];
- 
- 		usb_make_path(udev, path, XBUS_DESCLEN);	// May trunacte... ignore
- 		snprintf(xbus->busdesc, XBUS_DESCLEN, "%s", path);
- 	}
--	xbus->ops = &xusb_ops;
- 
- 	DBG("GOT XPP USB BUS #%d: %s (type=%d)\n", i, xbus->busdesc, xbus->bus_type);
- 
-@@ -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);
--	//xbus->procsummary = 1; // temporary: not 0, for the condition below
- 	if (!procsummary) {
- 		ERR("Failed to create proc read entry for xbus %s\n", xbus->busname);
- 		// FIXME: better error handling
- 		retval = -EIO;
- 		goto probe_failed;
- 	}
-+	procsummary->owner = THIS_MODULE;
- #endif
-+	bus_count++;
- 	retval = usb_submit_urb(xusb->read_urb, GFP_ATOMIC);
- 	if(retval < 0) {
- 		ERR("%s: Failed to submit the receive URB errno=%d\n", __FUNCTION__, retval);
- 	}
--	bus_count++;
--	xbus_activate(xusb->xbus);
-+	xusb->xbus = xbus;
-+	xbus->priv = xusb;
-+	xbus_activate(xbus);
- 	return retval;
- probe_failed:
- 	ERR("Failed to initialize xpp usb bus: %d\n", retval);
-@@ -593,6 +658,13 @@
- 			usb_deregister_dev(interface, &xusb_class);
- 		kfree(xusb);
- 	}
-+	if(xbus) {
-+		if(procsummary) {
-+			DBG("Remove proc_entry: " PROC_USBXPP_SUMMARY "\n");
-+			remove_proc_entry(PROC_USBXPP_SUMMARY, xbus->proc_xbus_dir);
-+		}
-+		xbus_disconnect(xbus);		// Blocking until fully deactivated!
-+	}
- 	return retval;
- }
- 
-@@ -609,7 +681,7 @@
-  */
- static void xusb_disconnect(struct usb_interface *interface)
- {
--	struct xpp_usb_bus	*xusb;
-+	xusb_t			*xusb;
- 	xbus_t			*xbus;
- 	int			minor;
- 	int			i;
-@@ -636,7 +708,7 @@
- 	}
- #endif
- 	xusb->present = 0;
--	xbus_deactivate(xbus);		// Blocking until fully deactivated!
-+	xbus_disconnect(xbus);		// Blocking until fully deactivated!
- 
- 	down (&xusb->sem);
- 
-@@ -645,6 +717,7 @@
- 	/* give back our minor */
- 	usb_deregister_dev (interface, &xusb_class);
- 
-+	/* terminate an ongoing read */
- 	/* terminate an ongoing write */
- 	// FIXME: Does it really kill pending URB's?
- 
-@@ -657,59 +730,71 @@
- 	kfree(xusb);
- 
- 	up (&disconnect_sem);
--	INFO("XUSB #%d now disconnected", minor);
-+	INFO("XUSB #%d now disconnected\n", minor);
- }
- 
- static void xpp_send_callback(struct urb *urb, struct pt_regs *regs)
- {
--	struct xpp_usb_bus	*xusb = (struct xpp_usb_bus *)urb->context;
-+	xusb_t			*xusb = (xusb_t *)urb->context;
- 	xbus_t			*xbus = xusb->xbus;
- 
- 	BUG_ON(!xbus);
-+	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)
--			DBG("nonzero read bulk status received: %d", urb->status);
-+			DBG("nonzero read bulk status received: %d\n", urb->status);
- 		XUSB_COUNTER(xusb, TX_ERRORS)++;
- 	}
-+	xpp_urb_delete(urb);
- 	if(!xusb->present) {
- 		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)
- {
--	struct xpp_usb_bus	*xusb = (struct xpp_usb_bus *)urb->context;
--	xbus_t			*xbus = xusb->xbus;
--
--	xpacket_t		*pack;
--	size_t			size;
--	int			retval;
-+	xusb_t		*xusb = (xusb_t *)urb->context;
-+	xbus_t		*xbus;
-+	xpacket_t	*pack;
-+	size_t		size;
-+	int		retval;
-+	bool		do_resubmit = 1;
-+	bool		is_inuse = 0;
- 
--	BUG_ON(!xbus);
-+	BUG_ON(!xusb);
-+	xbus = xusb->xbus;
-+	if(!xbus) {
-+		NOTICE("spurious URB\n");
-+		return;
-+	}
- 	if (urb->status) {
--		/* sync/async unlink faults aren't errors */
--		if (!(urb->status == -EOVERFLOW || urb->status == -EMSGSIZE)) {
--			ERR("Dropped connection due to bad URB status: %d\n", urb->status);
--			return;
--		} else {
--			DBG("nonzero read bulk status received: %d\n", urb->status);
--			goto end;
-+		DBG("nonzero read bulk status received: %d\n", urb->status);
-+		XUSB_COUNTER(xusb, RX_ERRORS)++;
-+		/* Free old URB, allocate a fresh one */
-+		if(xusb->read_urb)
-+			xpp_urb_delete(xusb->read_urb);
-+		xusb->read_urb = xpp_urb_new(xusb, XUSB_RECV, xusb->endpoints[XUSB_RECV].max_size);
-+		if (!xusb->read_urb) {
-+			ERR("URB allocation failed\n");
-+			do_resubmit = 0;;
- 		}
-+		goto end;
- 	}
- 	if(!down_read_trylock(&xbus->in_use)) {
- 		ERR("%s: xbus is going down\n", __FUNCTION__);
--		return;
-+		do_resubmit = 0;
-+		goto end;
- 	}
-+	is_inuse = 1;
- 	if(!xusb->present) {
- 		ERR("A packet from non-connected device?\n");
--		up_read(&xbus->in_use);
--		return;
-+		do_resubmit = 0;
-+		goto end;
- 	}
- 	pack = xbus->ops->packet_new(xbus, GFP_ATOMIC);
- 	if(!pack) {
-@@ -723,42 +808,21 @@
- 	pack->datalen = size - sizeof(xpd_addr_t) - 1; 	// opcode size
- 	// DBG("datalen of new packet: %d\n", pack->datalen);
- 
--	// Send UP
--	if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_READ)) {
-+	packet_debug("USB_PACKET_RECEIVE", xusb, pack);
-+	XUSB_COUNTER(xusb, RX_PACKETS)++;
-+	if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_READ))
- 		XUSB_COUNTER(xusb, PCM_READS)++;
--
--#ifdef	DEBUG_PCM_TIMING
--		/*
--		 * DEBUG: high-res timing of PCM_READ to PCM_WRITE
--		 */
--		stamp_last_pcm_read = get_cycles();
--#endif
--		// fill_beep((u_char *)&PACKET_FIELD(pack, PCM_READS, pcm), 2);	// Debugging BEEP
--#if 0
--		static	int rate_limit;
--		if((rate_limit++ % 1000) == 0)
--			dump_packet("USB RECEIVE PCM", pack, print_dbg);
--#endif
--	} else if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE)) {	// FIRMWARE_LOOPBACK
--#if 0
--		static	int rate_limit;
--		if((rate_limit++ % 1000) == 0)
--			dump_packet("USB RECEIVE (LOOPBACK) PCM", pack, print_dbg);
--#endif
--	} else {
--		char	title[XBUS_DESCLEN];
--
--		snprintf(title, XBUS_DESCLEN, "USB_PACKET_RECEIVE callback (%s)", xbus->busname);
--		dump_packet(title, pack, print_dbg);
--	}
-+	// Send UP
- 	packet_receive(xbus, pack);
--	XUSB_COUNTER(xusb, RX_PACKETS)++;
- end:	
--	up_read(&xbus->in_use);
--	retval = usb_submit_urb(urb, GFP_KERNEL);
--	if (retval < 0) {
--		ERR("failed re-submitting read urb, error %d\n", retval);
--		return;
-+	if(is_inuse)
-+		up_read(&xbus->in_use);
-+	if(do_resubmit) {
-+		retval = usb_submit_urb(urb, GFP_ATOMIC);
-+		if (retval < 0) {
-+			ERR("failed re-submitting read urb, error %d\n", retval);
-+			return;
-+		}
- 	}
- }
- 
-@@ -768,14 +832,14 @@
- int __init xpp_usb_init(void)
- {
- 	int result;
--	//struct xpp_usb_bus *xusb;
-+	//xusb_t *xusb;
- 
--	INFO("%s revision %s\n", THIS_MODULE->name, revision);
-+	INFO("%s revision %s\n", THIS_MODULE->name, ZAPTEL_VERSION);
- 
- 	/* register this driver with the USB subsystem */
- 	result = usb_register(&xusb_driver);
- 	if (result) {
--		ERR("usb_register failed. Error number %d", result);
-+		ERR("usb_register failed. Error number %d\n", result);
- 		return result;
- 	}
- 	return 0;
-@@ -784,34 +848,7 @@
- 
- void __exit xpp_usb_cleanup(void)
- {
--	int	i, j;
--
- 	DBG("\n");
--	for(i = 0; i < USBDEV_MAX; i++) {
--		xbus_t	*xbus;
--
--		if(xusb_array[i] == NULL)
--			continue;
--		xbus = xusb_array[i]->xbus;
--		if(!xbus) {
--			ERR("%s: missing xbus. Skipping\n", __FUNCTION__);
--			continue;
--		}
--		for(j = 0; j < MAX_XPDS; j++) {
--			xpd_t *xpd = xpd_of(xbus, j);
--
--			if(xpd) {
--				if(xpd->id != j) {
--					ERR("%s: BUG: xpd->id=%d != j=%d\n", __FUNCTION__, xpd->id, j);
--					continue;
--				}
--#if 0	// FIXME: retest after new driver start working
--				CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, 0xFF, 0);	// Disable all hardware channels
--				CALL_XMETHOD(LED, xbus, xpd, 0xFF, 1, 0);	// FIXME: Show activated channels
--#endif
--			}
--		}
--	}
- 	/* deregister this driver with the USB subsystem */
- 	usb_deregister(&xusb_driver);
- }
-@@ -822,31 +859,31 @@
- 
- static int xusb_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
- {
--	int len = 0;
--	unsigned long flags;
-+	int 		len = 0;
-+	unsigned long	flags;
-+	int		i;
- 	//unsigned long stamp = jiffies;
--	struct xpp_usb_bus	*xusb = data;
-+	xusb_t		*xusb = data;
- 
- 	if(!xusb)
- 		goto out;
- 	// TODO: probably needs a per-xusb lock:
- 	spin_lock_irqsave(&xusb_lock, flags);
--	int i;
--
- 	len += sprintf(page + len, "device: %d, #altsettings: %d, minor: %d\n"
--		"\tBus Type:%d (Model Info: %s)\n"
--		"\tIn:  0x%02X  - Size: %d\n"
--		"\tOut: 0x%02X  - Size: %d\n",
-+		"\tModel Info: Bus Type=%d (%s)\n"
-+		"\tIn:  0x%02X  - Size: %d)\n"
-+		"\tOut: 0x%02X  - Size: %d)\n",
- 		xusb->udev->devnum,
- 		xusb->interface->num_altsetting,
- 		xusb->minor,
- 		xusb->model_info->bus_type,
- 		xusb->model_info->desc,
--		xusb->ep_in.epnum,
--		xusb->ep_in.max_size,
--		xusb->ep_out.epnum,
--		xusb->ep_out.max_size
-+		xusb->endpoints[XUSB_RECV].ep_addr,
-+		xusb->endpoints[XUSB_RECV].max_size,
-+		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);
- #endif
-@@ -878,7 +915,7 @@
- MODULE_DESCRIPTION("XPP USB Driver");
- MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
- MODULE_LICENSE("GPL");
--MODULE_VERSION("$Id: xpp_usb.c 995 2006-04-03 07:08:13Z tzafrir $");
-+MODULE_VERSION(ZAPTEL_VERSION);
- 
- 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-LJNBCn_dist/xpp/xpp_zap.c
---- zaptel-1.2.6/xpp/xpp_zap.c	2006-04-03 10:08:13.000000000 +0300
-+++ zaptel-xpp-LJNBCn_dist/xpp/xpp_zap.c	2006-07-10 23:59:46.263727324 +0300
-@@ -33,245 +33,64 @@
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/module.h>
-+#include <linux/device.h>
- #include <linux/init.h>
- #include <linux/delay.h>	/* for udelay */
- #include <linux/workqueue.h>
- #include <linux/proc_fs.h>
- #include <zaptel.h>
-+#include <version.h>		/* For zaptel version */
-+#include "xbus-core.h"
- #include "xproto.h"
- #include "xpp_zap.h"
- 
--static char revision[] = "$Revision: 995 $";
-+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;
-+struct proc_dir_entry *xpp_proc_toplevel = NULL;
- #define	PROC_DIR		"xpp"
--#define	PROC_XBUSES		"xbuses"
- #define	PROC_SYNC		"sync"
--#define	PROC_XBUS_SUMMARY	"summary"
- #define	PROC_XPD_ZTREGISTER	"zt_registration"
- #define	PROC_XPD_SUMMARY	"summary"
- #endif
- 
--#undef	WITH_RBS
--//#define	WITH_RBS
--
- #define	XPP_CTL_MAJOR		42
--#define	MAX_BUSES		16
- #define	MAX_QUEUE_LEN		10000
--#define	LED_BLINK_PERIOD	(HZ/8)
- #define	SAMPLE_TICKS		10000
-+#define	DELAY_UNTIL_DIALTONE	3000
- 
--static spinlock_t		xbuses_lock = SPIN_LOCK_UNLOCKED;
--static xbus_t			*xbuses_array[MAX_BUSES] = {};
--static int			bus_count = 0;
- static struct timer_list	xpp_timer;
--xpd_t			*sync_master = NULL;	// Start with host based sync
-+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;
--
--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");
--#ifdef SOFT_SIMULATOR
--DEF_PARM(ulong, softloop_xpds, 0, "a bitmask of software xpd numbers");
--#endif
--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)");
- 
- #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 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);
- static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
- static int proc_xpd_ztregister_read(char *page, char **start, off_t off, int count, int *eof, void *data);
- static int proc_xpd_ztregister_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
--xbus_t *xbus_of(int xbus_num);
--static void xpd_cleanup(xpd_t *xpd);
--static void xpd_card_disable(xpd_t *xpd);
--static void update_xpd_status(xpd_t *xpd, int alarm_flag);
--
--#define	SPAN_REGISTERED(xpd)	((xpd)->span.flags & ZT_FLAG_REGISTERED)
--
--/*------------------------- Packet Handling ------------------------*/
--static kmem_cache_t	*packet_cache = NULL;
--static atomic_t	xpacket_count = ATOMIC_INIT(0);
--
--void card_detected(void *data)
--{
--	struct card_desc_struct	*card_desc = (struct card_desc_struct *)data;
--	xbus_t			*xbus;
--	xpd_t			*xpd;
--	int			xpd_num;
--	byte			type;
--	byte			rev;
--	const xops_t		*xops;
--	const xproto_table_t	*proto_table;
--
--	BUG_ON(!card_desc);
--	BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
--	xbus = card_desc->xbus;
--	xpd_num = card_desc->xpd_num;
--	type = card_desc->type;
--	rev = card_desc->rev;
--	BUG_ON(!xbus);
--	DBG("%s: xpd_num=%d type=%d rev=%d\n", xbus->busname, xpd_num, type, rev);
--	xpd = xpd_of(xbus, xpd_num);
--	if(xpd) {
--		if(type == XPD_TYPE(NOMODULE)) {
--			NOTICE("%s: xpd #%d: removed\n", __FUNCTION__, xpd_num);
--			xpd_card_disable(xpd);
--			goto out;
--		}
--		NOTICE("%s: xpd #%d: already exists\n", __FUNCTION__, xpd_num);
--		goto out;
--	}
--	if(type == XPD_TYPE(NOMODULE)) {
--		DBG("No module at address=%d\n", xpd_num);
--		goto out;
--	}
--	proto_table = get_xproto_table(type);
--	if(!proto_table) {
--		NOTICE("%s: xpd #%d: missing protocol table for type=%d. Ignored.\n", __FUNCTION__, xpd_num, type);
--		goto out;
--	}
--	xops = &proto_table->xops;
--	BUG_ON(!xops);
--	xpd = xops->card_new(xbus, xpd_num, proto_table, rev);
--	if(!xpd) {
--		NOTICE("card_new(%s,%d,%d,%d) failed. Ignored.\n", xbus->busname, xpd_num, proto_table->type, rev);
--		goto out;
--	}
--#if 0
--	/*
--	 * Is it nessessary?
--	 */
--	if(xpd->type == XPD_TYPE_FXO) {
--		int i;
--
--		for(i = 0; i < xpd->channels; i++) {
--			zt_hooksig(&xpd->chans[i], ZT_RXSIG_ONHOOK);
--		}
--	}
--#endif
--#ifdef	CONFIG_PROC_FS
--	DBG("Creating xpd proc directory for %s/%s\n", xbus->busname, xpd->xpdname);
--	xpd->proc_xpd_dir = proc_mkdir(xpd->xpdname, xbus->proc_xbus_dir);
--	if(!xpd->proc_xpd_dir) {
--		ERR("Failed to create proc directory for %s/%s\n", xbus->busname, xpd->xpdname);
--		goto err;
--	}
--	xpd->proc_xpd_summary = create_proc_read_entry(PROC_XPD_SUMMARY, 0444, xpd->proc_xpd_dir,
--			xpd_read_proc, xpd);
--	if(!xpd->proc_xpd_summary) {
--		ERR("Failed to create proc '%s' for %s/%s\n", PROC_XPD_SUMMARY, xbus->busname, xpd->xpdname);
--		goto err;
--	}
--	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->data = xpd;
--	xpd->proc_xpd_ztregister->read_proc = proc_xpd_ztregister_read;
--	xpd->proc_xpd_ztregister->write_proc = proc_xpd_ztregister_write;
--#endif
--	list_add(&xpd->xpd_list, &xpd_list);
--	xbus->xpds[xpd->id] = xpd;
--	xbus->num_xpds++;
--	CALL_XMETHOD(card_init, xbus, xpd);
--	// Turn off all channels
--	CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, 0xFF, 0);
--//	CALL_XMETHOD(LED, xbus, xpd, 0xFF, LED_RED, 0);				// FIXME: Show activated channels
--	// Turn on enabled channels
--	CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, xpd->enabled_chans, 1);
--	atomic_set(&xpd->card_present, 1);
--	xpd_zaptel_register(xpd);
--#if 0
--	// FIXME: not yet initialized...
--	xpp_check_hookstate(xpd, line_status);
--#endif
--
--out:
--	memset(card_desc, 0, sizeof(struct card_desc_struct));
--	kfree(card_desc);
--	return;
--err:
--	xpd_cleanup(xpd);
--	goto out;
--}
--
--/**
-- * Allocates a new XPP packet.
-- * @xbus The XPP bus in which the packet will flow (for counters 
-- *       maintenance)
-- * @flags Flags for kernel memory allocation.
-- * @returns A pointer to the new packet, or NULL in case of failure.
-- * 
-- * 
-- * Packet allocation/deallocation:
-- * 	Sent packets:
-- * 	  - Allocated by protocol commands
-- * 	  - Deallocated by xmus_xmitter
-- * 	Receive packets:
-- * 	  - Allocated/deallocated by xbus_xmiter
-- */
--xpacket_t	*softloop_packet_new(xbus_t *xbus, int flags)
--{
--	xpacket_t	*pack;
--
--	/* To avoid races we increament counter in advance and decrement it later 
--	 * in case of failure */
--	atomic_inc(&xbus->packet_counter); 
--	//DBG("Incremented packet_counter of bus %s (new packet) to %d\n", 
--	//		xbus->busname, atomic_read(&xbus->packet_counter));
--	pack = kmem_cache_alloc(packet_cache, flags);
--	if (pack) {
--		memset(pack, 0, sizeof(xpacket_t));
--		atomic_inc(&xpacket_count);
--	} else {
--		atomic_dec(&xbus->packet_counter);
--		//DBG("Decremented packet_counter of bus %s (failed new packet) to %d\n", 
--		//		xbus->busname, atomic_read(&xbus->packet_counter));
--	}
--	return pack;
--}
--
--void softloop_packet_free(xbus_t *xbus, xpacket_t *p)
--{
--	kmem_cache_free(packet_cache, p);
--	atomic_dec(&xpacket_count);
--	atomic_dec(&xbus->packet_counter);
--	//DBG("Decremented packet_counter of bus %s (freed packet) to %d\n", 
--	//		xbus->busname, atomic_read(&xbus->packet_counter));
--}
--
--int call_proto(xbus_t *xbus, xpacket_t *pack)
--{
--	const xproto_entry_t	*xe;
--	int			toxpd = XPD_NUM(pack->content.addr);
--	xpd_t			*xpd = xpd_of(xbus, toxpd);
--
--	xe = find_xproto_entry(xpd, pack->content.opcode);
--	return 0;
--}
-+static void xpd_free(xpd_t *xpd);
- 
- static void external_sync(xpd_t *the_xpd)
- {
- 	int	i, j;
- 
--	DBG("SYNC %s\n", (the_xpd) ? "EXTERNAL" : "HOST");
-+	DBG("SYNC %s (%s sync cable)\n", (the_xpd)?"Astribanks":"HOST", (have_sync_bus)?"with":"without");
-+	// Shut all down
- 	for(i = 0; i < MAX_BUSES; i++) {
- 		xbus_t	*xbus = xbus_of(i);
- 		if(!xbus)
-@@ -279,21 +98,26 @@
- 		if (!xbus->hardware_exists)
- 			continue;
- 		for(j = 0; j < MAX_XPDS; j++) {
--			xpd_t	*xpd = xbus->xpds[j];
--			if(xpd)
--				CALL_XMETHOD(SYNC_SOURCE, xbus, xpd, 1, (the_xpd != NULL));
-+			xpd_t	*xpd = xpd_of(xbus, j);
-+			if(xpd) {
-+				CALL_XMETHOD(SYNC_SOURCE, xbus, xpd, 1, 0);
-+			}
- 		}
- 	}
-+	if(the_xpd)
-+		CALL_XMETHOD(SYNC_SOURCE, the_xpd->xbus, the_xpd, 1, 1);
- }
- 
--void set_sync_master(xpd_t *xpd)
-+void sync_master_is(xpd_t *xpd)
- {
--	DBG("SYNC: %s => %s\n",
-+	DBG("SYNC MASTER CHANGED: %s => %s\n",
- 			(sync_master) ? sync_master->xpdname : "HOST",
--			(xpd) ? xpd->xpdname : "HOST"
--			);
-+			(xpd) ? xpd->xpdname : "HOST");
- 	sync_master = xpd;
--	if(!sync_master) {
-+	if(xpd) {		// XPD
-+		del_timer_sync(&xpp_timer);
-+		xpp_tick((unsigned long)xpd);
-+	} else {		// HOST
- 		external_sync(NULL);
- 		if(!timer_pending(&xpp_timer)) {
- 			xpp_timer.function = xpp_tick;
-@@ -301,10 +125,6 @@
- 			xpp_timer.expires = jiffies + 1;	/* Must be 1KHz rate */
- 			add_timer(&xpp_timer);
- 		}
--	} else {
--		del_timer_sync(&xpp_timer);
--		external_sync(xpd);
--		xpp_tick((unsigned long)xpd);
- 	}
- }
- 
-@@ -337,43 +157,49 @@
- 			continue;
- 		if (!xbus->hardware_exists)
- 			continue;
-+		if(!down_read_trylock(&xbus->in_use)) {
-+			DBG("Dropped packet. %s is in_use\n", xbus->busname);
-+			continue;
-+		}
- #if 0
- 		if(xbus->open_counter == 0)	
- 			continue;		// optimize, but zttool loopback won't function
- #endif
- 		for(j = 0; j < MAX_XPDS; j++) {
--			xpd_t	*xpd = xbus->xpds[j];
-+			xpd_t	*xpd = xpd_of(xbus, j);
- 
- 			if(!xpd)
- 				continue;
--			if(!atomic_read(&xpd->card_present))
-+			if(!xpd->card_present)
- 				continue;
- 			xpd->timer_count++;
- 			CALL_XMETHOD(card_tick, xbus, xpd);
- 			if(!SPAN_REGISTERED(xpd))
- 				continue;
--			xpd_blink_leds(xpd);
- 			if(xpd->direction == TO_PSTN)
- 				xpp_ring_generate(xpd);
- 			xpp_transmitprep(xpd);
- 			xpp_receiveprep(xpd);
- 		}
-+		up_read(&xbus->in_use);
- 	}
- }
- 
- #if HZ != 1000
--#warning This module will not be usable since the kernel HZ setting is not 1000 ticks per second.
-+#warning "xpp_timer must be sampled EXACTLY 1000/per second"
- #endif
- 
--static void xpd_cleanup(xpd_t *xpd)
-+static void xpd_free(xpd_t *xpd)
- {
- 	xbus_t	*xbus = NULL;
- 
- 	if(!xpd)
- 		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) {
- 		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);
- }
- 
--void init_xbus_packet_queue(packet_queue_t *q, const char name[])
--{
--	INIT_LIST_HEAD(&q->head);
--	spin_lock_init(&q->lock);
--	q->count = 0;
--	q->worst_count = 0;
--	q->overflows = 0;
--	snprintf(q->qname, XPD_NAMELEN, "%s", name);
--}
- 
--#if 0
--/*
-- * Assume the queue is locked
-- */
--void __dump_packet_queue(const char *msg, packet_queue_t *q)
--{
--	xpacket_t *tmp;
-+/*------------------------- XPD Management -------------------------*/
- 
--	list_for_each_entry(tmp, &q->head, list) {
--		dump_packet(msg, tmp);
--	}
--}
--#endif
-+#define	REV(x,y)	(10 * (x) + (y))
-+static byte good_revs[] = {
-+	REV(1,9),
-+	REV(2,0),
-+};
-+#undef	REV
- 
--void drain_xbus_packet_queue(xbus_t *xbus, packet_queue_t *q)
-+static bool good_rev(byte rev)
- {
--	unsigned long	flags;
--	xpacket_t	*pack;
--	xpacket_t	*next;
-+	int	i;
- 
--	spin_lock_irqsave(&q->lock, flags);
--	DBG("queue=%s count=%d\n", q->qname, q->count);
--	DBG("     total packets count=%d\n", atomic_read(&xpacket_count));
--	list_for_each_entry_safe(pack, next, &q->head, list) {
--		list_del(&pack->list);
--		q->count--;
--		xbus->ops->packet_free(xbus, pack);
--	}
--	if(q->count != 0)
--		ERR("drain_xbus_packet_queue: queue %s still has %d packets\n",
--				q->qname, q->count);
--	spin_unlock_irqrestore(&q->lock, flags);
-+	for(i = 0; i < ARRAY_SIZE(good_revs); i++) {
-+		if(good_revs[i] == rev)
-+			return 1;
-+	}
-+	return 0;
- }
- 
--void xbus_enqueue_packet(xbus_t *xbus, packet_queue_t *q, xpacket_t *pack)
-+/*
-+ * Synchronous part of XPD detection.
-+ * Called from xbus_poll()
-+ */
-+void card_detected(struct card_desc_struct *card_desc)
- {
--	unsigned long	flags;
--
--	spin_lock_irqsave(&q->lock, flags);
-+	xbus_t			*xbus;
-+	xpd_t			*xpd = NULL;
-+	int			xpd_num;
-+	byte			type;
-+	byte			rev;
-+	const xops_t		*xops;
-+	const xproto_table_t	*proto_table;
- 
--	if(q->count >= max_queue_len) {
--		static unsigned long	last_notice = 0;	// rate limit
- 
--		if((jiffies - last_notice) < HZ) {
--			NOTICE("xbus_enqueue_packet: dropping packet (queue len = %d, max=%d)\n",
--				q->count, max_queue_len);
--			last_notice = jiffies;
-+	BUG_ON(!card_desc);
-+	BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
-+	xbus = card_desc->xbus;
-+	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 (%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 (%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);
-+			BUG();
-+			goto out;
- 		}
--		q->overflows++;
--		xbus->ops->packet_free(xbus, pack);
-+		NOTICE("%s: xpd #%d: already exists\n", __FUNCTION__, xpd_num);
- 		goto out;
- 	}
--	list_add_tail(&pack->list, &q->head);
--	q->count++;
--
--	if(q->count > q->worst_count)
--		q->worst_count = q->count;
--
--	if(q->count < max_queue_len/100 && q->worst_count > q->count)	// Decay worst_count
--		q->worst_count--;
--
--	// dump_packet("ENQUEUED", pack, print_dbg);
--out:
--	spin_unlock_irqrestore(&q->lock, flags);
--}
--
--xpacket_t *xbus_dequeue_packet(packet_queue_t *q)
--{
--	unsigned long	flags;
--	struct list_head	*p;
--	xpacket_t	*pack = NULL;
--
--	spin_lock_irqsave(&q->lock, flags);
--
--	if(list_empty(&q->head)) {
--		// DBG("LIST EMPTY (count=%d)\n", q->count);
-+	if(type == XPD_TYPE_NOMODULE) {
-+		DBG("No module at address=%d\n", xpd_num);
-+		goto out;
-+	}
-+	proto_table = xproto_get(type);
-+	if(!proto_table) {
-+		NOTICE("%s: xpd #%d: missing protocol table for type=%d. Ignored.\n", __FUNCTION__, xpd_num, type);
- 		goto out;
- 	}
--	p = q->head.next;
--	list_del(p);
--	q->count--;
--	pack = list_entry(p, xpacket_t, list);
--	// dump_packet("DEQUEUED", pack, print_dbg);
-+	xops = &proto_table->xops;
-+	BUG_ON(!xops);
-+	xpd = xops->card_new(xbus, xpd_num, proto_table, rev);
-+	if(!xpd) {
-+		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;
-+		NOTICE("%s: max packet size = %d, disabling some PCM channels. no_pcm=0x%04X\n",
-+				xbus->busname, xbus->max_packet_size, xpd->no_pcm);
-+	}
-+#ifdef	CONFIG_PROC_FS
-+	DBG("Creating xpd proc directory for %s/%s\n", xbus->busname, xpd->xpdname);
-+	xpd->proc_xpd_dir = proc_mkdir(xpd->xpdname, xbus->proc_xbus_dir);
-+	if(!xpd->proc_xpd_dir) {
-+		ERR("Failed to create proc directory for %s/%s\n", xbus->busname, xpd->xpdname);
-+		goto err;
-+	}
-+	xpd->proc_xpd_summary = create_proc_read_entry(PROC_XPD_SUMMARY, 0444, xpd->proc_xpd_dir,
-+			xpd_read_proc, xpd);
-+	if(!xpd->proc_xpd_summary) {
-+		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;
-+	// Turn off all channels
-+	CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, ~0, 0);
-+	xpd->card_present = 1;
-+	// Turn on all channels
-+	CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, ALL_LINES, 1);
-+
-+	if(zap_autoreg)
-+		zaptel_register_xpd(xpd);
- out:
--	spin_unlock_irqrestore(&q->lock, flags);
--	return pack;
-+	memset(card_desc, 0, sizeof(struct card_desc_struct));
-+	kfree(card_desc);
-+	return;
-+err:
-+	xpd_free(xpd);
-+	goto out;
- }
- 
- 
--/*------------------------- XPD Management -------------------------*/
--
- #ifdef CONFIG_PROC_FS
- 
- /**
-@@ -510,83 +376,78 @@
- 	int		len = 0;
- 	xpd_t		*xpd = data;
- 	xbus_t		*xbus;
--#if SOFT_SIMULATOR
--	struct xpd_sim	*sim;
--#endif
--	int		channels;
- 	int		i;
- 
- 	if(!xpd)
- 		goto out;
- 
- 	xbus = xpd->xbus;
--#if SOFT_SIMULATOR
--	sim = &xbus->sim[xpd->id];
--#endif
--	channels = xpd->channels;
--	len += sprintf(page + len, "%s (%s ,card %s, span_registered=%s)%s\n"
-+	len += sprintf(page + len, "%s (%s ,card %s, span %s) %s\n"
- 			"timer_count: %d span->mainttimer=%d\n"
- 			,
- 			xpd->xpdname, xproto_name(xpd->type),
--			(atomic_read(&xpd->card_present))?"present":"missing",
--			(SPAN_REGISTERED(xpd))?"yes":"no",
--			(xpd == sync_master) ? " SYNCER" : "",
-+			(xpd->card_present) ? "present" : "missing",
-+			(SPAN_REGISTERED(xpd)) ? "registered" : "NOT registered",
-+			(xpd == sync_master) ? "SYNC MASTER" : "SYNC SLAVE",
- 			xpd->timer_count, xpd->span.mainttimer
- 			);
- 	len += sprintf(page + len, "STATES:");
--	len += sprintf(page + len, "\n\t%-17s: ", "enabled");
--	for(i = 0; i < channels; 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) {
- 		len += sprintf(page + len, "%d ", IS_SET(xpd->digital_outputs, i));
- 	}
- 	len += sprintf(page + len, "\n\t%-17s: ", "input_relays");
--	for(i = 0; i < channels; i++) {
-+	for_each_line(xpd, i) {
- 		len += sprintf(page + len, "%d ", IS_SET(xpd->digital_inputs, i));
- 	}
- 	len += sprintf(page + len, "\n\t%-17s: ", "hookstate");
--	for(i = 0; i < channels; i++) {
-+	for_each_line(xpd, i) {
- 		len += sprintf(page + len, "%d ", IS_SET(xpd->hookstate, i));
- 	}
--	len += sprintf(page + len, "\n\t%-17s: ", "ring-state");
--	for(i = 0; i < channels; i++) {
--		len += sprintf(page + len, "%d ", xpd->lasttxhook[i]);
--	}
- 	len += sprintf(page + len, "\n\t%-17s: ", "ringing");
--	for(i = 0; i < channels; i++) {
-+	for_each_line(xpd, i) {
- 		len += sprintf(page + len, "%d ", xpd->ringing[i]);
- 	}
- #if 1
- 	if(SPAN_REGISTERED(xpd)) {
--		len += sprintf(page + len, "\nreadchunk: ");
--		for(i = 0; i < channels; i++) {
-+		len += sprintf(page + len, "\nPCM:\n            |         [readchunk]       |         [writechunk]      | delay");
-+		for_each_line(xpd, i) {
- 			struct zt_chan	*chans = xpd->span.chans;
--			byte	chunk[ZT_CHUNKSIZE];
-+			byte	rchunk[ZT_CHUNKSIZE];
-+			byte	wchunk[ZT_CHUNKSIZE];
-+			byte	*rp;
-+			byte	*wp;
- 			int j;
- 
--			memcpy(chunk, chans[i].readchunk, ZT_CHUNKSIZE);
--			len += sprintf(page + len, "\n\tport %2d> ", i);
-+			if(IS_SET(xpd->digital_outputs, i))
-+				continue;
-+			if(IS_SET(xpd->digital_inputs, i))
-+				continue;
-+#if 1
-+			rp = chans[i].readchunk;
-+			wp = chans[i].writechunk;
-+#else
-+			rp = (byte *)xpd->readchunk + (ZT_CHUNKSIZE * i);
-+			wp = chans[i].writechunk;
-+#endif
-+			memcpy(rchunk, rp, ZT_CHUNKSIZE);
-+			memcpy(wchunk, wp, ZT_CHUNKSIZE);
-+			len += sprintf(page + len, "\n  port %2d>  |  ", i);
- 			for(j = 0; j < ZT_CHUNKSIZE; j++) {
--				len += sprintf(page + len, "%02X ", chunk[j]);
-+				len += sprintf(page + len, "%02X ", rchunk[j]);
- 			}
--		}
--	}
--#endif
--#if SOFT_SIMULATOR
--	if(sim->simulated) {
--		len += sprintf(page + len, "\nSIMULATED (xpd_type=%d, loopto=%d):", sim->xpd_type, sim->loopto);
--		len += sprintf(page + len, "\n\t%-17s: ", "hookstate");
--		for(i = 0; i < channels; i++) {
--			len += sprintf(page + len, "%d ", IS_SET(sim->hookstate, i));
-+			len += sprintf(page + len, " |  ");
-+			for(j = 0; j < ZT_CHUNKSIZE; j++) {
-+				len += sprintf(page + len, "%02X ", wchunk[j]);
-+			}
-+			len += sprintf(page + len, " | %d ", xpd->delay_until_dialtone[i]);
- 		}
- 	}
- #endif
- #if 0
- 	if(SPAN_REGISTERED(xpd)) {
- 		len += sprintf(page + len, "\nSignalling:\n");
--		for(i = 0; i < channels; i++) {
-+		for_each_line(xpd, i) {
- 			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,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;
-+	size_t		pcm_size;
- 	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);
-+	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;
--	atomic_set(&xpd->card_present, 0);
-+	xpd->card_present = 0;
- 	snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%d", xpd_num);
- 	xpd->hookstate = 0x0;	/* ONHOOK */
- 	xpd->type = proto_table->type;
-+	xpd->xproto = proto_table;
- 	xpd->xops = &proto_table->xops;
--	xpd->enabled_chans = enabled_channels[xpd_num];
- 	xpd->digital_outputs = 0;
- 	xpd->digital_inputs = 0;
-+
-+	for_each_line(xpd, i) {
-+		xpd->idletxhookstate[i] = FXS_LINE_ENABLED;	/* By default, don't send on hook */
-+	}
-+
- 	atomic_set(&xpd->open_counter, 0);
- 
- 	xpd->chans = kmalloc(sizeof(struct zt_chan)*xpd->channels, GFP_KERNEL);
-@@ -660,33 +527,61 @@
- 		ERR("%s: Unable to allocate channels\n", __FUNCTION__);
- 		goto err;
- 	}
--	/* 8 channels, double buffer, Read/Write */
--	int need = ZT_MAX_CHUNKSIZE * CHANNELS_PERXPD * 2 * 2;
--	if((xpd->writechunk = kmalloc(need, GFP_KERNEL)) == NULL) {
-+	pcm_size = ZT_MAX_CHUNKSIZE * CHANNELS_PERXPD * 2;	/* Double Buffer */
-+	alloc_size = pcm_size * 2;				/* Read/Write */
-+	if((xpd->writechunk = kmalloc(alloc_size, GFP_KERNEL)) == NULL) {
- 		ERR("%s: Unable to allocate memory for writechunks\n", __FUNCTION__);
- 		goto err;
- 	}
- 	/* Initialize Write/Buffers to all blank data */
--	memset((void *)xpd->writechunk, 0x00, need);
--	xpd->readchunk = xpd->writechunk + ZT_CHUNKSIZE * CHANNELS_PERXPD * 2;
-+	memset((void *)xpd->writechunk, 0x00, alloc_size);
-+	xpd->readchunk = xpd->writechunk + pcm_size;
- 
- 	return xpd;
- err:
--	if(xpd->chans)
--		kfree((void *)xpd->chans);
--	if(xpd->writechunk)
--		kfree((void *)xpd->writechunk);
--	if(xpd)
-+	if(xpd) {
-+		if(xpd->chans)
-+			kfree((void *)xpd->chans);
-+		if(xpd->writechunk)
-+			kfree((void *)xpd->writechunk);
- 		kfree(xpd);
-+	}
- 	return NULL;
- }
- 
--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)
-+		sync_master_is(NULL);
-+
-+	spin_lock_irqsave(&xpd->lock, flags);
-+	DBG("%s/%s (%p)\n", xpd->xbus->busname, xpd->xpdname, xpd->xproto);
-+	if(!xpd->card_present)	/* Multiple reports */
-+		goto out;
-+	xpd->card_present = 0;
-+	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)
-@@ -695,23 +590,14 @@
- 
- 	BUG_ON(!xpd);
- 	xbus = xpd->xbus;
--	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);
-+
-+	zaptel_unregister_xpd(xpd);
- 	CALL_XMETHOD(card_remove, xbus, xpd);
--	xpd_cleanup(xpd);
--	kfree((void *)xpd->writechunk);
--	kfree(xpd);
-+	xpd_free(xpd);
- }
- 
--static void update_xpd_status(xpd_t *xpd, int alarm_flag)
-+void update_xpd_status(xpd_t *xpd, int alarm_flag)
- {
- 	struct zt_span *span = &xpd->span;
- 
-@@ -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);
-+	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);
--		}
--	} else if(!offhook && IS_SET(xpd->hookstate, channo)) {	// ONHOOK
--		DBG("ONHOOK channo=%d\n", chan->channo);
--		xpd->ringing[channo] = 0;
--		BIT_CLR(xpd->hookstate, channo);
-+	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);
--		}
--	}
--}
--
--void xpp_check_hookstate(xpd_t *xpd, xpp_line_t fxs_off_hook)
--{
--	int	i;
--	unsigned long	flags;
--
--	spin_lock_irqsave(&xpd->lock, flags);
--	if(xpd->direction != TO_PHONE) {
--		ERR("%s: %s: Only PHONE can report hookstate changes\n", __FUNCTION__, xpd->xpdname);
--		goto out;
--	}
--	if(!SPAN_REGISTERED(xpd)) {
--		NOTICE("%s: %s is not registered. Skipping.\n", __FUNCTION__, xpd->xpdname);
--		goto out;
--	}
--	DBG("%s: hookstate=0x%04X fxs_off_hook=0x%04X\n", xpd->xpdname, xpd->hookstate, fxs_off_hook);
--	for(i = 0; i < xpd->channels; i++) {
--		phone_hook(xpd, i, IS_SET(fxs_off_hook, i));
--	}
--out:
--	spin_unlock_irqrestore(&xpd->lock, flags);
--}
--
--static void xpd_blink_leds(xpd_t *xpd)
--{
--	int		i;
--	unsigned long	flags;
--
--	BUG_ON(!xpd);
--
--	spin_lock_irqsave(&xpd->lock, flags);
--	for(i = 0; i < xpd->channels; i++) {
--		if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
--			continue;
--		if(xpd->ringing[i]) {
--			// led state is toggled
--			if((xpd->timer_count % LED_BLINK_PERIOD) == 0) {
--				DBG("%s pos=%d ringing=%d led_on=%d\n", xpd->xpdname, i, xpd->ringing[i], xpd->led_on[i]);
--				if(xpd->ringing[i] && xpd->led_on[i]) {
--					CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 1);
--				} else {
--					CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 0);
--				}
--				xpd->led_on[i] = !xpd->led_on[i];
--			}
--		}
--	}
--	spin_unlock_irqrestore(&xpd->lock, flags);
- }
- 
- static void xpp_ring_generate(xpd_t *xpd)
-@@ -829,7 +653,7 @@
- 	 * Ring detect logic:
- 	 * 	fxo_power is toggled
- 	 */
--	for(i = 0; i < xpd->channels; 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 +663,7 @@
- 				} else {
- 					zt_hooksig(&xpd->chans[i], ZT_RXSIG_RING);
- 				}
--				xpd->ringing[i]--;
- 				xpd->ringer_on[i] = !xpd->ringer_on[i];
--				if (xpd->ringing[i] < 0) 
--					xpd->ringing[i]=0;
- 			}
- 		}
- 	}
-@@ -850,98 +671,13 @@
- 	spin_unlock_irqrestore(&xpd->lock, flags);
- }
- 
--/*------------------------- Bus Management -------------------------*/
--
--xbus_t *xbus_of(int xbus_num)
--{
--	if(xbus_num < 0 || xbus_num >= MAX_BUSES)
--		return NULL;
--	return xbuses_array[xbus_num];
--}
--
--xpd_t	*xpd_of(xbus_t *xbus, int xpd_num)
--{
--	if(!VALID_XPD_NUM(xpd_num))
--		return NULL;
--	return xbus->xpds[xpd_num];
--}
--
--void xbus_reset_counters(xbus_t *xbus)
--{
--	int	i;
--
--	DBG("Reseting counters of %s\n", xbus->busname);
--	for(i = 0; i < XBUS_COUNTER_MAX; i++) {
--		xbus->counters[i] = 0;
--	}
--//	xbus->xmit_queue.worst_count = 0;
--//	xbus->xmit_queue.overflows = 0;
--}
--
- #ifdef CONFIG_PROC_FS
- 
--/**
-- * Prints a general procfs entry for the bus, under xpp/BUSNAME/summary
-- * @page TODO: figure out procfs
-- * @start TODO: figure out procfs
-- * @off TODO: figure out procfs
-- * @count TODO: figure out procfs
-- * @eof TODO: figure out procfs
-- * @data an xbus_t pointer with the bus data.
-- */
--static int xbus_read_proc(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;
--	spin_lock_irqsave(&xbus->lock, flags);
--
--	len += sprintf(page + len, "%s: CONNECTOR=%s STATUS=%s bus_type=%d\n",
--			xbus->busname,
--			xbus->busdesc,
--			(xbus->hardware_exists) ? "connected" : "missing",
--			xbus->bus_type
--		      );
--	len += sprintf(page + len, "open_counter=%d packet_count=%d\n",
--			xbus->open_counter,
--			atomic_read(&xbus->packet_counter)
--		      );
--#if SOFT_SIMULATOR
--	len += sprintf(page + len, "XPDS SIM\n");
--	for(i = 0; i < MAX_XPDS; i++) {
--		struct xpd_sim	*sim = &xbus->sim[i];
--		xpd_t		*xpd = xpd_of(xbus, i);
--		len += sprintf(page + len, "\t%d> ignored=%d simulated=%d softloop_xpd=%d loopto=%d instanciated=%s\n",
--				i, IS_SET(ignore_xpds, i), sim->simulated, sim->softloop_xpd, sim->loopto, (xpd) ? "yes" : "no");
--	}
--#endif
--	len += sprintf(page + len, "COUNTERS:\n");
--	for(i = 0; i < XBUS_COUNTER_MAX; i++) {
--		len += sprintf(page + len, "\t%-15s = %d\n",
--				xbus_counters[i].name, xbus->counters[i]);
--	}
--	len += sprintf(page + len, "<-- len=%d\n", len);
--	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;
--
--}
--
- int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, void *data)
- {
--	int len = 0;
-+	int		len = 0;
-+	unsigned int	xpp_timer_rate;
-+	unsigned int	now;
- 
- 	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 +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);
--	unsigned int xpp_timer_rate = 0;
--	unsigned int now = jiffies;
-+	xpp_timer_rate = 0;
-+	now = jiffies;
- 	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 +707,6 @@
- 
- static int proc_sync_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
- {
--	DBG("%s: count=%ld\n", __FUNCTION__, count);
- 	const int	NUM_SIZE = 100;
- 	char		buf[NUM_SIZE];
- 	int		xbus_num;
-@@ -979,31 +714,47 @@
- 	xbus_t		*xbus;
- 	xpd_t		*xpd;
- 	int		ret;
-+	bool		setit;
- 
-+	// DBG("%s: count=%ld\n", __FUNCTION__, count);
- 	if(count >= NUM_SIZE)
- 		return -EINVAL;
- 	if(copy_from_user(buf, buffer, count))
- 		return -EFAULT;
- 	buf[count] = '\0';
- 	if(strncmp("HOST", buf, 4) == 0) {
--		set_sync_master(NULL);
-+		sync_master_is(NULL);
- 		goto out;
- 	}
--	ret = sscanf(buf, "%d %d", &xbus_num, &xpd_num);
--	if(ret != 2)
-+	ret = sscanf(buf, "%d %d %d", &xbus_num, &xpd_num, &setit);
-+	if(ret == 2) {
-+		// For backward compatibility: before query was introduced,
-+		// only two parameters were possible
-+		setit = 1;
-+		ret = 3;
-+	}
-+	if(ret != 3 || (setit != 0 && setit != 1)) {
-+		ERR("Bad format for SYNC.\n");
-+		ERR("Usage: <bus_num> <xpd_num> <0/1> # 0 - QUERY, 1 - SET\n");
- 		return -EINVAL;
--	DBG("%s: %d/%d\n", __FUNCTION__, xbus_num, xpd_num);
--	if(xbus_num >= MAX_BUSES)
-+	}
-+	if(xbus_num >= MAX_BUSES) {
-+		ERR("Invalid xbus number %d\n", xbus_num);
- 		return -EINVAL;
-+	}
- 	xbus = xbus_of(xbus_num);
--	if(!xbus)
-+	if(!xbus) {
-+		ERR("No bus %d exists\n", xbus_num);
- 		return -EINVAL;
-+	}
- 	xpd = xpd_of(xbus, xpd_num);
- 	if(!xpd) {
- 		ERR("%s: XPD number %d does not exist\n", __FUNCTION__, xpd_num);
- 		return -ENXIO;
- 	}
--	set_sync_master(xpd);
-+	DBG("%s: %d/%d %s\n", __FUNCTION__, xbus_num, xpd_num, (setit)?"SET":"QUERY");
-+	if(setit)
-+		external_sync(xpd);
- out:
- 	return count;
- }
-@@ -1050,346 +801,73 @@
- 	DBG("%s: %s/%s %s\n", __FUNCTION__,
- 			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;
--}
--
--#endif
--
--/**
-- *
-- * Packet is freed:
-- * 	- In case of error, by this function.
-- * 	- Otherwise, by the underlying sending mechanism
-- */
--int packet_send(xbus_t *xbus, xpacket_t *pack_tx)
--{
--	int		ret = -ENODEV;
--	int		toxpd;
--
--	if(!pack_tx) {
--		DBG("null pack\n");
--		return -EINVAL;
--	}
--	toxpd = XPD_NUM(pack_tx->content.addr);
--	if(!xbus) {
--		DBG("null xbus\n");
--		ret = -EINVAL;
--		goto error;
--	}
--	if (!xbus->hardware_exists) {
--		DBG("xbus %s Dropped a packet -- NO HARDWARE.", xbus->busname);
--		ret = -ENODEV;
--		goto error;
--	}
--	if(!VALID_XPD_NUM(toxpd)) {
--		ERR("%s: toxpd=%d > MAX_XPDS\n", __FUNCTION__, toxpd);
--		ret = -EINVAL;
--		goto error;
--	}
--#if 0
--	// DEBUG: For Dima
--	if(pack_tx->content.opcode == XPP_PCM_WRITE) {
--		static	int rate_limit;
--		static	int count;
--
--		if(sync_master == NULL)
--			count = 0;
--		if(count++ > 5) {
--			ret = 0;
--			goto error;
--		}
--		if(rate_limit++ % 1000 == 0)
--			INFO("DEBUG: TRANSMIT (PCM_WRITE)\n");
--	}
--#endif
--	if(down_read_trylock(&xbus->in_use)) {
--		ret = xbus->ops->packet_send(xbus, pack_tx);
--		XBUS_COUNTER(xbus, TX_BYTES) += pack_tx->datalen;
--		up_read(&xbus->in_use);
--	} else {
--		DBG("Dropped packet. %s is in_use\n", xbus->busname);
--	}
--	return ret;
--
--error:	
--	xbus->ops->packet_free(xbus, pack_tx);
--	return ret;
--}
--
--static void xbus_poll(xbus_t *xbus, int probe_all)
--{
--	int id;
--	int ret;
--	xpd_t **xpds;
--	xpd_t *xpd;
--
--	DBG("%s (probe_all=%d)\n", xbus->busname, probe_all);
--	xpds = xbus->xpds;
--	for(id = 0; id < MAX_XPDS; id++) {
--		if(!xbus->hardware_exists)
--			break;
--		xpd = xpd_of(xbus, id);
--		if(!probe_all) {
--			if(!xpd) {
--				DBG("  Skipping XPD #%d is MISSING\n", id);
--				continue;
--			}
--			if(!atomic_read(&xpd->card_present)) {
--				DBG("  Skipping XPD #%d not present\n", id);
--				continue;
--			}
--			if(time_after(xpd->last_response+20, jiffies)) {
--				DBG("  SKIP DESC_REQ\n");
--				continue;
--			}
--		}
--		if(IS_SET(ignore_xpds, id)) {		/* skip xpds */
--			DBG("  Ignoring XPD #%d\n", id);
--			continue;
--		}
--		DBG("  Polling slot %d %s\n", id, xbus->busname);
--		ret = CALL_PROTO(GLOBAL, DESC_REQ, xbus, NULL, id);
--		if(ret < 0) {
--			NOTICE("xpp: %s: Failed sending DESC_REQ to XPD #%d\n", __FUNCTION__, id);
--		}
--	}
--}
--
--void process_xbus_poll(void *data) {
--	xbus_t *xbus = (xbus_t*) data;
--
--	ERR("%s: issuing xbus_poll\n", __FUNCTION__);
--	xbus_poll(xbus, 1);
--}
--
--
--#if SOFT_SIMULATOR
--/*
-- * Assume xbus->lock is held
-- */
--static void simulator_setup(xbus_t *xbus, ulong sim_xpds)
--{
--	int	i;
--	int	last_fxo = 0;
--	bool	first = 1;
--
--	DBG("%s: sim_xpds=0x%lX\n", xbus->busname, sim_xpds);
--	for(i = 0; i < MAX_XPDS; i++) {
--		if (!IS_SET(sim_xpds, i) || xbus->sim[i].simulated)
--			continue;
--		if (first) {
--			last_fxo=i;
--		} else {
--			// setting simulated twice here: in case of odd number of simulated XPDs
--			xbus->sim[i].xpd_type = XPD_TYPE_FXO;
--			xbus->sim[i].loopto = last_fxo;
--			xbus->sim[i].simulated = 1;
--			xbus->sim[last_fxo].xpd_type = XPD_TYPE_FXS;
--			xbus->sim[last_fxo].loopto = i;
--			xbus->sim[last_fxo].simulated = 1;
--			
--		}
--		if(IS_SET(softloop_xpds, i))
--			xbus->sim[i].softloop_xpd = 1;
--		xbus->sim[i].hookstate = 0;
--		
--		first = !first;
--	}
--}
--#endif
--
--void xbus_activate(xbus_t *xbus)
--{
--	xbus_ops_t *ops;
--
--	BUG_ON(!xbus);
--	ops = xbus->ops;
--	BUG_ON(!ops);
--	BUG_ON(!xbus->priv);
--	/* Sanity checks */
--	if(!ops->packet_send) {
--		ERR("%s: missing mandatory handler: packet_send=\n", __FUNCTION__);
--		return;
--	}
--	if(!ops->packet_new || !ops->packet_free) {
--		ops->packet_new = softloop_packet_new;
--		ops->packet_free = softloop_packet_free;
--	}
--
--	xbus->hardware_exists = 1;
--	DBG("Activating: %s\n", xbus->busname);
--	/* Poll it */
--	xbus_poll(xbus, 1);
--}
--
--void xbus_deactivate(xbus_t *xbus)
--{
--	int	i;
--
--	BUG_ON(!xbus);
--	DBG("%s\n", xbus->busname);
--	xbus->hardware_exists = 0;
--	for(i = 0; i < MAX_XPDS; i++) {
--		xpd_t *xpd = xpd_of(xbus, i);
--		if(!xpd)
--			continue;
--		if(xpd->id != i) {
--			ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i);
--			continue;
--		}
--		xpd_card_disable(xpd);
--	}
--	down_write(&xbus->in_use);
--	DBG("%s (deactivated)\n", xbus->busname);
--	if(xbus->open_counter == 0) {
--		xbus_remove(xbus);
--	}
--}
--
--
--static void xbus_cleanup(xbus_t *xbus)
--{
--	BUG_ON(!xbus);
--#ifdef CONFIG_PROC_FS
--	if(xbus->proc_xbus_dir) {
--		if(xbus->proc_xbus_summary) {
--			DBG("Removing proc '%s' for %s\n", PROC_XBUS_SUMMARY, xbus->busname);
--			remove_proc_entry(PROC_XBUS_SUMMARY, xbus->proc_xbus_dir);
--			xbus->proc_xbus_summary = NULL;
--		}
--		DBG("Removing proc directory %s\n", xbus->busname);
--		remove_proc_entry(xbus->busname, xpp_procdir);
--		xbus->proc_xbus_dir = NULL;
--	}
--#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;
--	int		xbus_num;
--	int		err;
--	xbus_t		*xbus;
--
--	xbus = kmalloc(sizeof(xbus_t), GFP_KERNEL);
--	if(!xbus)
--		return NULL;
--	memset(xbus, 0, sizeof(xbus_t));
--
--	spin_lock_irqsave(&xbuses_lock, flags);
--	for(xbus_num = 0; xbus_num < MAX_BUSES; xbus_num++)
--		if(xbuses_array[xbus_num] == NULL)
--			break;
--	if(xbus_num >= MAX_BUSES) {
--		spin_unlock_irqrestore(&xbuses_lock, flags);
--		err = -ENOMEM;
--		goto nobus;
--	}
--	/* Found empty slot */
--	xbuses_array[xbus_num] = xbus;
--	bus_count++;
--	spin_unlock_irqrestore(&xbuses_lock, flags);
--
--	/* Init data structures */
--	spin_lock_init(&xbus->lock);
--	snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%d", xbus_num);
--	INFO("New xbus: %s\n", xbus->busname);
--	init_waitqueue_head(&xbus->packet_cache_empty);
--	atomic_set(&xbus->packet_counter, 0);
--	init_rwsem(&xbus->in_use);
--	xbus->num = xbus_num;
--	xbus->num_xpds = 0;
--#if SOFT_SIMULATOR
--	xbus->sim_workqueue = create_singlethread_workqueue(xbus->busname);
--	if(!xbus->sim_workqueue) {
--		ERR("Failed to create workqueue for xbus %s\n", xbus->busname);
--		err = -ENOMEM;
--		goto nobus;
--	}
--	init_xbus_packet_queue(&xbus->sim_packet_queue, "SIM_PACKET_QUEUE");
--	INIT_WORK(&xbus->sim_work, process_sim_queue, xbus);
--	simulator_setup(xbus, loopback_xpds);	// Hardware loopback must use simulator
--	simulator_setup(xbus, softloop_xpds);	// Add the soft loopback to the simulated set
--#endif
--	xbus_reset_counters(xbus);
--#ifdef CONFIG_PROC_FS
--	DBG("Creating xbus proc directory %s.\n",xbus->busname);
--	xbus->proc_xbus_dir = proc_mkdir(xbus->busname, xpp_procdir);
--	if(!xbus->proc_xbus_dir) {
--		ERR("Failed to create proc directory for xbus %s\n", xbus->busname);
--		err = -EIO;
--		goto nobus;
--	}
--	xbus->proc_xbus_summary = create_proc_read_entry(PROC_XBUS_SUMMARY, 0444, xbus->proc_xbus_dir,
--			xbus_read_proc, xbus);
--	if (!xbus->proc_xbus_summary) {
--		ERR("Failed to create '%s' proc file for xbus %s\n", PROC_XBUS_SUMMARY, xbus->busname);
--		err = -EIO;
--		goto nobus;
--	}
- #endif
--	return xbus;
--nobus:
--	spin_lock_irqsave(&xbuses_lock, flags);
--	xbuses_array[xbus_num] = NULL;
--	bus_count--;
--	spin_unlock_irqrestore(&xbuses_lock, flags);
--	xbus_cleanup(xbus);
--	return NULL;
--}
- 
--static void xbus_remove(xbus_t *xbus)
-+/**
-+ *
-+ * Packet is freed:
-+ * 	- In case of error, by this function.
-+ * 	- Otherwise, by the underlying sending mechanism
-+ */
-+int packet_send(xbus_t *xbus, xpacket_t *pack_tx)
- {
--	int i;
--	unsigned long flags;
-+	int		ret = -ENODEV;
-+	int		toxpd;
- 
--	BUG_ON(!xbus);
--	DBG("%s\n", xbus->busname);
--	spin_lock_irqsave(&xbuses_lock, flags);
--	BUG_ON(xbus != xbus_of(xbus->num));
--	xbuses_array[xbus->num] = NULL;
--	bus_count--;
--	spin_unlock_irqrestore(&xbuses_lock, flags);
--#if SOFT_SIMULATOR
--	if(xbus->sim_workqueue) {
--		cancel_delayed_work(&xbus->sim_work);
-+	if(!pack_tx) {
-+		DBG("null pack\n");
-+		return -EINVAL;
- 	}
--#endif
--	INFO("Removing xbus(%d) %s\n", xbus->num, xbus->busname);
--	for(i = 0; i < MAX_XPDS; i++) {
--		xpd_t *xpd = xpd_of(xbus, i);
--
--		if(xpd) {
--			const xops_t	*xops = xpd->xops;
-+	toxpd = XPD_NUM(pack_tx->content.addr);
-+	if(!xbus) {
-+		DBG("null xbus\n");
-+		ret = -EINVAL;
-+		goto error;
-+	}
-+	if (!xbus->hardware_exists) {
-+		DBG("xbus %s Dropped a packet -- NO HARDWARE.", xbus->busname);
-+		ret = -ENODEV;
-+		goto error;
-+	}
-+	if(!VALID_XPD_NUM(toxpd)) {
-+		ERR("%s: toxpd=%d > MAX_XPDS\n", __FUNCTION__, toxpd);
-+		ret = -EINVAL;
-+		goto error;
-+	}
-+#if 0
-+	// DEBUG: For Dima
-+	if(pack_tx->content.opcode == XPP_PCM_WRITE) {
-+		static	int rate_limit;
-+		static	int count;
- 
--			if(xpd->id != i) {
--				ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i);
--				continue;
--			}
--			BUG_ON(!xops);
--			DBG("  Removing xpd id=%d\n", xpd->id);
--			xpd_remove(xpd);
-+		if(sync_master == NULL)
-+			count = 0;
-+		if(count++ > 5) {
-+			ret = 0;
-+			goto error;
- 		}
--		xbus->xpds[i] = NULL;
--	}
--#if SOFT_SIMULATOR
--	if(xbus->sim_workqueue) {
--		flush_workqueue(xbus->sim_workqueue);
--		destroy_workqueue(xbus->sim_workqueue);
--		xbus->sim_workqueue = NULL;
-+		if(rate_limit++ % 1000 == 0)
-+			INFO("DEBUG: TRANSMIT (PCM_WRITE)\n");
- 	}
--	drain_xbus_packet_queue(xbus, &xbus->sim_packet_queue);
- #endif
--	int ret = wait_event_interruptible(xbus->packet_cache_empty, 
--			atomic_read(&xbus->packet_counter) == 0);
--	if(ret) {
--		ERR("waiting for packet_cache_empty interrupted!!!\n");
-+	if(down_read_trylock(&xbus->in_use)) {
-+		ret = xbus->ops->packet_send(xbus, pack_tx);
-+		XBUS_COUNTER(xbus, TX_BYTES) += pack_tx->datalen;
-+		up_read(&xbus->in_use);
-+	} else {
-+		DBG("Dropped packet. %s is in_use\n", xbus->busname);
- 	}
--	xbus_cleanup(xbus);
-+	return ret;
-+
-+error:	
-+	xbus->ops->packet_free(xbus, pack_tx);
-+	return ret;
- }
- 
- 
-@@ -1407,12 +885,12 @@
- 	int	i;
- 	int	channels = xpd->channels;
- 	struct zt_chan	*chans = xpd->span.chans;
-+	unsigned long	flags;
- 
-+	spin_lock_irqsave(&xpd->lock, flags);
- //	if((xpd->timer_count % PREP_REPORT_RATE) < 10)
- //		DBG("%d\n", xpd->timer_count);
- 
--//	if(xpd->hookstate == 0)
--//		return;
- 	if (xpd->timer_count & 1) {
- 		/* First part */
- 		w = writechunk = xpd->writechunk /* + 1 */;
-@@ -1422,18 +900,26 @@
- 	zt_transmit(&xpd->span);
- 
- 	for (i = 0; i < channels; i++) {
--		if(IS_SET(xpd->hookstate, i)) {
-+		if (xpd->delay_until_dialtone[i] > 0) {
-+			xpd->delay_until_dialtone[i]--;
-+			if (xpd->delay_until_dialtone[i] <= 0) {
-+				xpd->delay_until_dialtone[i] = 0;
-+				wake_up_interruptible(&xpd->txstateq[i]);
-+			}
-+		}
-+		if(IS_SET(xpd->hookstate, i) || IS_SET(xpd->cid_on, i)) {
- 			memcpy((u_char *)w, chans[i].writechunk, ZT_CHUNKSIZE);
- 			// fill_beep((u_char *)w, 5);
- 		}
- 		w += ZT_CHUNKSIZE;
- 	}
--	if(xpd->hookstate != 0 || sync_master == xpd || !sync_master) {
--		ret = CALL_XMETHOD(PCM_WRITE, xpd->xbus, xpd, xpd->hookstate, writechunk);
-+//	if(xpd->hookstate != 0 || sync_master != xpd) {
-+		ret = CALL_XMETHOD(PCM_WRITE, xpd->xbus, xpd, xpd->hookstate | xpd->cid_on, writechunk);
- 		if(ret < 0) {
- 			DBG("failed to write PCM %d\n", ret);
- 		}
--	}
-+//	}
-+	spin_unlock_irqrestore(&xpd->lock, flags);
- }
- 
- void fill_beep(u_char *buf, int duration)
-@@ -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 */
--		0x67, 0x90, 0x89, 0x90, 0xFF, 0x10, 0x09, 0x10,	/* Izzy */
-+//		0x67, 0x90, 0x89, 0x90, 0xFF, 0x10, 0x09, 0x10,	/* Izzy */
- //		0x67, 0xCD, 0xC5, 0xCD, 0xFF, 0x49, 0x41, 0x49,	/* Dima 2 */
--//		0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,	/* silence */
-+		0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,	/* silence */
- 	};
- 	memcpy(buf, &beep[(which*8) % ARRAY_SIZE(beep)], ZT_CHUNKSIZE);
- }
- 
-+#ifdef	XPP_EC_CHUNK
-+/*
-+ * Taken from zaptel.c
-+ */
-+static inline void xpp_ec_chunk(struct zt_chan *chan, unsigned char *rxchunk, const unsigned char *txchunk)
-+{
-+	short rxlin;
-+	int x;
-+	unsigned long flags;
-+
-+	/* Perform echo cancellation on a chunk if necessary */
-+	if (!chan->ec)
-+		return;
-+	spin_lock_irqsave(&chan->lock, flags);
-+	for (x=0;x<ZT_CHUNKSIZE;x++) {
-+		rxlin = ZT_XLAW(rxchunk[x], chan);
-+		rxlin = xpp_echo_can_update(chan->ec, ZT_XLAW(txchunk[x], chan), rxlin);
-+		rxchunk[x] = ZT_LIN2X((int)rxlin, chan);
-+	}
-+	spin_unlock_irqrestore(&chan->lock, flags);
-+}
-+#endif
-+
-+
- static void xpp_receiveprep(xpd_t *xpd)
- {
- 	volatile u_char *readchunk;
- 	int i;
- 	int	channels = xpd->channels;
- 	struct zt_chan	*chans = xpd->span.chans;
-+	unsigned long	flags;
- 
-+	spin_lock_irqsave(&xpd->lock, flags);
- //	if((xpd->timer_count % PREP_REPORT_RATE) == 0)
- //		DBG("%d\n", xpd->timer_count);
- 
-@@ -1472,20 +984,29 @@
- 
- 	for (i = 0; i < channels; i++) {
- 		if(IS_SET(xpd->hookstate, i)) {
-+			// memset((u_char *)readchunk, 0x5A, ZT_CHUNKSIZE);	// DEBUG
-+			// fill_beep((u_char *)readchunk, 1);	// DEBUG: BEEP
- 			memcpy(chans[i].readchunk, (u_char *)readchunk, ZT_CHUNKSIZE);
-+		} else {
-+			memset(chans[i].readchunk, 0x7F, ZT_CHUNKSIZE);	// SILENCE
- 		}
- 		readchunk += ZT_CHUNKSIZE;
- 	}
- 
--#if 0
-+#if WITH_ECHO_SUPPRESSION
- 	/* FIXME: need to Echo cancel double buffered data */
- 	for (i = 0;i < xpd->span.channels; i++) {
-+#ifdef XPP_EC_CHUNK
-+		xpp_ec_chunk(&chans[i], chans[i].readchunk, xpd->ec_chunk2[i]);
-+#else
- 		zt_ec_chunk(&chans[i], chans[i].readchunk, xpd->ec_chunk2[i]);
-+#endif
- 		memcpy(xpd->ec_chunk2[i], xpd->ec_chunk1[i], ZT_CHUNKSIZE);
- 		memcpy(xpd->ec_chunk1[i], chans[i].writechunk, ZT_CHUNKSIZE);
- 	}
- #endif
- 	zt_receive(&xpd->span);
-+	spin_unlock_irqrestore(&xpd->lock, flags);
- }
- 
- static int xpp_startup(struct zt_span *span)
-@@ -1540,13 +1061,18 @@
- 	spin_lock_irqsave(&xbus->lock, flags);
- 	xbus->open_counter--;
- 	atomic_dec(&xpd->open_counter);
-+	if(xpd->direction == TO_PHONE) {	/* Hangup phone */
-+		xpd->idletxhookstate[chan->chanpos - 1] = FXS_LINE_ENABLED;
-+	}
- 	if (!xbus->hardware_exists && xbus->open_counter == 0)
- 		should_remove = 1;
- 	spin_unlock_irqrestore(&xbus->lock, flags);
- 
- 	DBG("chan=%d (open_counter=%d, should_remove=%d)\n", chan->chanpos, xbus->open_counter, should_remove);
--	if(should_remove)
-+	if(should_remove) {
-+		DBG("Going to remove: %s\n", xbus->busname);
- 		xbus_remove(xbus);
-+	}
- 	return 0;
- }
- 
-@@ -1560,10 +1086,11 @@
- 		case ZT_ONHOOKTRANSFER:
- 			if (get_user(x, (int *)arg))
- 				return -EFAULT;
--			if (xpd->lasttxhook[pos] == 0x1) {
-+			xpd->ohttimer[pos] = x << 3;
-+			xpd->idletxhookstate[pos] = FXS_LINE_CID;	/* OHT mode when idle */
-+			if (xpd->lasttxhook[pos] == FXS_LINE_ENABLED) {
- 				/* Apply the change if appropriate */
--				xpd->lasttxhook[pos] = 0x2;
--				// CALL_XMETHOD(CHAN_CID, xpd->xbus, xpd, BIT(pos));		// CALLER ID
-+				CALL_XMETHOD(CHAN_CID, xpd->xbus, xpd, pos);		// CALLER ID
- 			}
- 			DBG("xpd=%d: ZT_ONHOOKTRANSFER (%d millis) chan=%d\n", xpd->id, x, pos);
- 			return -ENOTTY;
-@@ -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;
--	int ret = 0;
--	
--	if(!xpd) {
--		ERR("%s: channel=%d without an XPD!\n", __FUNCTION__, pos);
--		return -EINVAL;
--	}
--	xbus = xpd->xbus;
- 
--	if (txsig == ZT_TXSIG_START) {
--		if(xpd->direction == TO_PHONE) {
--			// A PHONE line: ZT_START will be treated as ZT_RING
--			DBG("Got ZT_START for PHONE channel %d, treated as ZT_RING\n", pos);
--			//hookstate = ZT_TXSIG_RING;
--
--			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("ZT_RING %s digital output ON\n", chan->name);
--				ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
--				return ret;
--			}
--			xpd->ringing[pos] = RINGS_NUM*2;
--			DBG("ZT_RING %s ringing=%d\n", chan->name, xpd->ringing[pos]);
--			ret = CALL_XMETHOD(RING, xbus, xpd, pos, 1);			// RING on
--			if(ret) {
--				DBG("ZT_RING Failed: ret=0x%02X\n", ret);
--				return ret;
--			}
--			return ret;
--		} else {	/* TO_PSTN */
--			// An FXO line: ZT_START will be treated as ZT_OFFHOOK
--			DBG("Got ZT_START for FXO channel %d, treated as ZT_OFFHOOK\n", pos);
--			txsig = ZT_TXSIG_OFFHOOK;
--		}
--	}
--	switch(txsig) {
--		case ZT_TXSIG_START:
--			DBG("ZT_TXSIG_START: (doing OFFHOOK) %s (chan->dialing=%d)\n", chan->name, chan->dialing);
--			break;
--			/* Fall through */
--		case ZT_TXSIG_OFFHOOK:
--			DBG("ZT_TXSIG_OFFHOOK: %s hookstate=0x%04X\n", chan->name, xpd->hookstate);
--			BIT_SET(xpd->hookstate, pos);
--			xpd->ringing[pos] = 0;
--			if(IS_SET(xpd->digital_inputs, pos)) {
--				NOTICE("%s: Trying to OFFHOOK a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
--				return -EINVAL;
--			}
--			if(IS_SET(xpd->digital_outputs, pos)) {
--				DBG("ZT_TXSIG_OFFHOOK %s digital output OFF\n", chan->name);
--				ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
--				return ret;
--			}
--			ret = CALL_XMETHOD(SETHOOK, xbus, xpd->id, xpd->hookstate);
--			if(ret) {
--				DBG("ZT_TXSIG_OFFHOOK Failed: ret=0x%02X\n", ret);
--				break;
--			}
--			CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 0);
--			break;
--			//DBG("ZT_TXSIG_OFFHOOK %d\n", pos);
--			//BIT_SET(xpd->hookstate, pos);
--			//break;
--		case ZT_TXSIG_KEWL:
--			DBG("ZT_TXSIG_KEWL (doing ONHOOK): %d.\n", pos);
--			break;
--			/* Fall through */
--		case ZT_TXSIG_ONHOOK:
--			DBG("ZT_TXSIG_ONHOOK: %s hookstate=0x%04X\n", chan->name, xpd->hookstate);
--			xpd->ringing[pos] = 0;
--			if(IS_SET(xpd->digital_inputs, pos)) {
--				NOTICE("%s: Trying to ONHOOK a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
--				return -EINVAL;
--			}
--			if(IS_SET(xpd->digital_outputs, pos)) {
--				DBG("ZT_TXSIG_ONHOOK %s digital output OFF\n", chan->name);
--				ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
--				return ret;
--			}
--			BIT_CLR(xpd->hookstate, pos);
--			ret = CALL_XMETHOD(SETHOOK, xbus, xpd->id, xpd->hookstate);
--			if(ret) {
--				DBG("ZT_ONHOOK Failed: ret=0x%02X\n", ret);
--				break;
--			}
--			CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 0);
--			break;
--			//DBG("ZT_TXSIG_ONHOOK: %d\n", pos);
--			//BIT_CLR(xpd->hookstate, pos);
--			//break;
--		default:
--			DBG("hooksig: unkown txsig=%d on channel %d\n", txsig, pos);
--			return -EINVAL;
--	}
--	//ret = CALL_XMETHOD(SETHOOK, xbus, xpd->id, xpd->hookstate);
--	//if(ret) {
--	//	DBG("ZT_TXSIG_START Failed: ret=0x%02X\n", ret);
--	//}
--	return ret;
-+	BUG_ON(!xpd);
-+	xbus = xpd->xbus;
-+	BUG_ON(!xbus);
-+	DBG("Setting %s to %s (%d)\n", chan->name, txsig2str(txsig), txsig);
-+	return CALL_XMETHOD(card_hooksig, xbus, xpd, pos, txsig);
- }
--#endif
-+
-+#else
- 
- static int xpp_sethook(struct zt_chan *chan, int hookstate)
- {
-@@ -1701,102 +1141,15 @@
- 	xbus_t	*xbus;
- 	int ret = 0;
- 
--	if(!xpd) {
--		ERR("%s: channel=%d without an XPD!\n", __FUNCTION__, pos);
--		return -EINVAL;
--	}
-+	BUG_ON(!xpd);
- 	xbus = xpd->xbus;
- 	DBG("%s (%d) (old=0x%04X, hook-command=%d)\n", chan->name, pos, xpd->hookstate, hookstate);
--	switch(hookstate) {
--		/* On-hook, off-hook: The PBX is playing a phone on an FXO line. 
--		 * Can be ignored for an FXS line
--		 */
--		case ZT_ONHOOK:
--			if(IS_SET(xpd->digital_inputs, pos)) {
--				NOTICE("%s: Trying to ONHOOK a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
--				return -EINVAL;
--			}
--			if(IS_SET(xpd->digital_outputs, pos)) {
--				DBG("ZT_ONHOOK %s digital output OFF\n", chan->name);
--				ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
--				return ret;
--			}
--			if(xpd->direction == TO_PHONE) {	/* Stop ring */
--				DBG("ZT_ONHOOK: %s hookstate=0x%04X (stop ringing pos=%d)\n", chan->name, xpd->hookstate, pos);
--				xpd->ringing[pos] = 0;
--#if 1	// FIXME: Not needed -- verify
--				ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0);			// RING off
--#endif
--				xpd->lasttxhook[pos] = 1;
--				ret = CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(pos), LED_GREEN, 0);
--				ret = CALL_XMETHOD(CHAN_POWER, xbus, xpd, BIT(pos), 0);		// Power down (prevent overheating!!!)
--				if(ret) {
--					DBG("ZT_ONHOOK(stop ring) Failed: ret=0x%02X\n", ret);
--					break;
--				}
--			} else {
--				DBG("ZT_ONHOOK: %s hookstate=0x%04X (pos=%d)\n", chan->name, xpd->hookstate, pos);
--				xpd->ringing[pos] = 0;
--				BIT_CLR(xpd->hookstate, pos);
--				ret = CALL_XMETHOD(SETHOOK, xbus, xpd, xpd->hookstate);
--				if(ret) {
--					DBG("ZT_ONHOOK Failed: ret=0x%02X\n", ret);
--					break;
--				}
--			}
--			break;
--		case ZT_START:
--			DBG("ZT_START: %s hookstate=0x%04X (fall through ZT_OFFHOOK)\n", chan->name, xpd->hookstate);
--			// Fall through
--		case ZT_OFFHOOK:
--			if(xpd->direction == TO_PHONE) {
--				DBG("ZT_OFFHOOK: %s hookstate=0x%04X -- ignoring (PHONE)\n", chan->name, xpd->hookstate);
--				break;
--			}
--			DBG("ZT_OFFHOOK: %s hookstate=0x%04X (pos=%d)\n", chan->name, xpd->hookstate, pos);
--			BIT_SET(xpd->hookstate, pos);
--			xpd->ringing[pos] = 0;
--			ret = CALL_XMETHOD(SETHOOK, xbus, xpd, xpd->hookstate);
--			if(ret) {
--				DBG("ZT_OFFHOOK Failed: ret=0x%02X\n", ret);
--				break;
--			}
--			break;
--		case ZT_WINK:
--			DBG("ZT_WINK %s\n", chan->name);
--			break;
--		case ZT_FLASH:
--			DBG("ZT_FLASH %s\n", chan->name);
--			break;
--		case ZT_RING:
--			DBG("ZT_RING %s pos=%d (ringing[pos]=%d)\n", chan->name, pos, xpd->ringing[pos]);
--			if(xpd->direction == TO_PHONE) {
--				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("ZT_ONHOOK %s digital output ON\n", chan->name);
--					ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
--					return ret;
--				}
--				xpd->ringing[pos] = RINGS_NUM*2;
--				ret = CALL_XMETHOD(CHAN_POWER, xbus, xpd, BIT(pos), 1);	// Power up (for ring)
--				ret = CALL_XMETHOD(RING, xbus, xpd, pos, 1);			// RING on
--				if(ret) {
--					DBG("ZT_RING Failed: ret=0x%02X\n", ret);
--				}
--			}
--			break;
--		case ZT_RINGOFF:
--			DBG("ZT_RINGOFF %s\n", chan->name);
--			break;
--		default:
--			DBG("UNKNOWN hookstate=0x%X\n", hookstate);
--	}
-+	ret = CALL_XMETHOD(card_sethook, xpd->xbus, xpd, pos, hookstate);
- 	return ret;
- }
- 
-+#endif
-+
- /* 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 +1168,6 @@
- 	switch(cmd) {
- 		case ZT_MAINT_NONE:
- 			printk("XXX Turn off local and remote loops XXX\n");
--			CALL_XMETHOD(LED, xpd->xbus, xpd, xpd->enabled_chans, LED_RED, 0);		// FIXME: Find usage for extra LED
- 			break;
- 		case ZT_MAINT_LOCALLOOP:
- 			printk("XXX Turn on local loopback XXX\n");
-@@ -1825,12 +1177,10 @@
- 			break;
- 		case ZT_MAINT_LOOPUP:
- 			printk("XXX Send loopup code XXX\n");
--			CALL_XMETHOD(LED, xpd->xbus, xpd, xpd->enabled_chans, LED_RED, 1);		// FIXME: Find usage for extra LED
- 			// CALL_XMETHOD(LOOPBACK_AX, xpd->xbus, xpd, loopback_data, ARRAY_SIZE(loopback_data));
- 			break;
- 		case ZT_MAINT_LOOPDOWN:
- 			printk("XXX Send loopdown code XXX\n");
--			CALL_XMETHOD(LED, xpd->xbus, xpd, xpd->enabled_chans, LED_RED, 0);		// FIXME: Find usage for extra LED
- 			break;
- 		case ZT_MAINT_LOOPSTOP:
- 			printk("XXX Stop sending loop codes XXX\n");
-@@ -1848,8 +1198,7 @@
- /* Set signalling type (if appropriate) */
- static int xpp_chanconfig(struct zt_chan *chan, int sigtype)
- {
--	DBG("channel %d (%s), sigtype %d.\n", chan->channo, chan->name, sigtype);
--	dump_sigtype(print_dbg, "  ", sigtype);
-+	DBG("channel %d (%s) -> %s\n", chan->channo, chan->name, sig2str(sigtype));
- 	// FIXME: sanity checks:
- 	// - should be supported (within the sigcap)
- 	// - should not replace fxs <->fxo ??? (covered by previous?)
-@@ -1878,6 +1227,29 @@
- int (*sethook)(struct zt_chan *chan, int hookstate);
- #endif
- 
-+#ifdef	XPP_EC_CHUNK
-+static int xpp_echocan(struct zt_chan *chan, int len)
-+{
-+	if(len == 0) {	/* shut down */
-+		/* zaptel calls this also during channel initialization */
-+		if(chan->ec) {
-+			xpp_echo_can_free(chan->ec);
-+		}
-+		return 0;
-+	}
-+	if(chan->ec) {
-+		ERR("%s: Trying to override an existing EC (%p)\n", __FUNCTION__, chan->ec);
-+		return -EINVAL;
-+	}
-+	chan->ec = xpp_echo_can_create(len, 0);
-+	if(!chan->ec) {
-+		ERR("%s: Failed creating xpp EC (len=%d)\n", __FUNCTION__, len);
-+		return -EINVAL;
-+	}
-+	return 0;
-+}
-+#endif
-+
- #ifdef	CONFIG_ZAPTEL_WATCHDOG
- /*
-  * If the watchdog detects no received data, it will call the
-@@ -1904,33 +1276,40 @@
-  * 	- User action through /proc
-  * 	- During xpd_remove()
-  */
--static int xpd_zaptel_unregister(xpd_t *xpd)
-+static int zaptel_unregister_xpd(xpd_t *xpd)
- {
-+	unsigned long	flags;
-+
- 	BUG_ON(!xpd);
-+	spin_lock_irqsave(&xpd->lock, flags);
- 
- 	if(!SPAN_REGISTERED(xpd)) {
- 		NOTICE("%s: %s is already unregistered\n", __FUNCTION__, xpd->xpdname);
-+		spin_unlock_irqrestore(&xpd->lock, flags);
- 		return -EIDRM;
- 	}
- 	if(sync_master == xpd)
--		set_sync_master(NULL);			// FIXME: it's better to elect a new prince
-+		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)) {
- 		NOTICE("%s: %s is busy (open_counter=%d). Skipping.\n", __FUNCTION__, xpd->xpdname, atomic_read(&xpd->open_counter));
-+		spin_unlock_irqrestore(&xpd->lock, flags);
- 		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_preregistration(xpd, 0);
- 	zt_unregister(&xpd->span);
-+	if(xpd->card_present)
-+		xpd->xops->card_zaptel_postregistration(xpd, 0);
- 	return 0;
- }
- 
--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);
--	{
--		char tmp[MAX_SPANNAME];
--#if SOFT_SIMULATOR
--		struct xpd_sim	*sim = &xbus->sim[xpd->id];
--
--		if(sim->simulated)
--			snprintf(tmp, MAX_SPANNAME, " (sim to=%d)", sim->loopto);
--		else
--#endif
--			tmp[0] = '\0';
--
--		snprintf(span->desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: %s%s",
--				xbus->num, xpd->id,
--				(xpd->direction == TO_PHONE) ? "FXS" : "FXO",
--				tmp
--				);
--	}
--	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);
--		} else if(IS_SET(xpd->digital_inputs, i)) {
--			snprintf(cur_chan->name, MAX_CHANNAME, "XPP_IN/%d-%d", xpd->id, i);
--		} else {
--			snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%d-%d", (sigfxs) ? "FXO" : "FXS", xpd->id, i);
--		}
--		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;
-+#ifdef	XPP_EC_CHUNK
-+	span->echocan = xpp_echocan;
-+#endif
- #ifdef	CONFIG_ZAPTEL_WATCHDOG
- 	span->watchdog = xpp_watchdog;
- #endif
- 
--	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_postregistration(xpd, 1);
- 	return 0;
- }
- 
--
- /*------------------------- Proc debugging interface ---------------*/
- 
- #ifdef CONFIG_PROC_FS
- 
--static int xpp_zap_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
--{
--	int len = 0;
--	unsigned long flags;
--	int i;
--
--	spin_lock_irqsave(&xbuses_lock, flags);
--	for(i = 0; i < MAX_BUSES; i++) {
--		xbus_t *xbus = xbus_of(i);
--
--		if(xbus) {
--			len += sprintf(page + len, "%s: CONNECTOR=%s STATUS=%s bus_type=%d\n",
--					xbus->busname,
--					xbus->busdesc,
--					(xbus->hardware_exists) ? "connected" : "missing",
--					xbus->bus_type
--				      );
--		}
--	}
--#if 0
--	len += sprintf(page + len, "<-- len=%d\n", len);
--#endif
--	spin_unlock_irqrestore(&xbuses_lock, flags);
--	if (len <= off+count)
--		*eof = 1;
--	*start = page + off;
--	len -= off;
--	if (len > count)
--		len = count;
--	if (len < 0)
--		len = 0;
--	return len;
--
--}
--
- #if 0
- static int xpp_zap_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
- {
-@@ -2097,6 +1384,7 @@
- #define	MINOR_XBUS_NUM(m)	((m) >> 4)
- #define	MINOR_XPD_NUM(m)	((m) & 0xF);
- 
-+#if 0
- static int xpp_sys_open (struct inode * inode, struct file * file)
- {
- 	xbus_t *xbus;
-@@ -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,
- };
- 
-+#endif
- 
- /*------------------------- Initialization -------------------------*/
- 
-@@ -2193,42 +1482,47 @@
- {
- 	if(timer_pending(&xpp_timer))
- 		del_timer_sync(&xpp_timer);
-+#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_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;
--	}
--	kmem_cache_destroy(packet_cache);
- }
- 
- int __init xpp_zap_init(void)
- {
--	INFO("%s revision %s\n", THIS_MODULE->name, revision);
-+	int	ret;
-+	struct proc_dir_entry *ent;
-+
-+	INFO("%s revision %s\n", THIS_MODULE->name, ZAPTEL_VERSION);
-+#ifdef WITH_RBS
-+	INFO("FEATURE: %s (RBS signalling)\n", THIS_MODULE->name);
-+#else
-+	INFO("FEATURE: %s (NO RBS signalling)\n", THIS_MODULE->name);
-+#endif
-+#if WITH_ECHO_SUPPRESSION
-+	INFO("FEATURE: %s (with ECHO_SUPPRESSION)\n", THIS_MODULE->name);
-+#else
-+	INFO("FEATURE: %s (without ECHO_SUPPRESSION)\n", THIS_MODULE->name);
-+#endif
-+#ifdef XPP_EC_CHUNK
-+	INFO("FEATURE: %s (with XPP_EC_CHUNK)\n", THIS_MODULE->name);
-+#else
-+	INFO("FEATURE: %s (without XPP_EC_CHUNK)\n", THIS_MODULE->name);
-+#endif
- 
--	packet_cache = kmem_cache_create("xpp_packets",
--			sizeof(xpacket_t),
--			0, 0,
--			NULL, NULL);
--	if(!packet_cache) {
--		return -ENOMEM;
--	}
- #ifdef CONFIG_PROC_FS
--	xpp_procdir = proc_mkdir(PROC_DIR, NULL);
--	if(!xpp_procdir) {
-+	xpp_proc_toplevel = proc_mkdir(PROC_DIR, NULL);
-+	if(!xpp_proc_toplevel) {
- 		do_cleanup();
- 		return -EIO;
- 	}
--	struct proc_dir_entry *ent;
- 
--	ent = create_proc_entry(PROC_SYNC, 0644, xpp_procdir);
-+	ent = create_proc_entry(PROC_SYNC, 0644, xpp_proc_toplevel);
- 	if(!ent) {
- 		do_cleanup();
- 		return -EFAULT;
-@@ -2236,67 +1530,42 @@
- 	ent->read_proc = proc_sync_read;
- 	ent->write_proc = proc_sync_write;
- 	ent->data = NULL;
--	ent = create_proc_read_entry(PROC_XBUSES, 0444, xpp_procdir, xpp_zap_read_proc, 0);
--	if (!ent) {
--		do_cleanup();
--		return -EFAULT;
--	}
- #endif
--	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();
--		return -ENOMEM;
-+		return ret;
- 	}
- 	
-+#if 0
- 	if (register_chrdev(XPP_CTL_MAJOR, THIS_MODULE->name, &xpp_fops)) {
- 		printk (KERN_WARNING "%s: unable to get major %d\n", THIS_MODULE->name, XPP_CTL_MAJOR);
- 		do_cleanup();
- 		return -EIO;
- 	}
-+#endif
- 
- 	/* Only timer init. We add it only *after* zt_register */
- 	init_timer(&xpp_timer);
--	set_sync_master(NULL);			/* Internal ticking */
-+	sync_master_is(NULL);			/* Internal ticking */
- 	return 0;
- }
- 
- void __exit xpp_zap_cleanup(void)
- {
--//	unsigned long	flags;
--	int		i;
--
--	for(i = 0; i < MAX_BUSES; i++) {
--		xbus_t	*xbus = xbus_of(i);
--		if(!xbus)
--			continue;
--		xbus_remove(xbus);
--	}
--//	spin_lock_irqsave(&xbuses_lock, flags);
--	if(bus_count) {
--		ERR("%s: bus_count=%d!\n", __FUNCTION__, bus_count);
--	}
--//	spin_unlock_irqrestore(&xbuses_lock, flags);
-+	xbus_core_shutdown();
- 	do_cleanup();
- }
- 
- EXPORT_SYMBOL(print_dbg);
- EXPORT_SYMBOL(card_detected);
- EXPORT_SYMBOL(xpd_alloc);
--EXPORT_SYMBOL(xbus_activate);
--EXPORT_SYMBOL(xbus_deactivate);
--EXPORT_SYMBOL(xpd_of);
--EXPORT_SYMBOL(xbus_new);
--EXPORT_SYMBOL(xbus_remove);
--EXPORT_SYMBOL(xbus_reset_counters);
-+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);
--EXPORT_SYMBOL(init_xbus_packet_queue);
--EXPORT_SYMBOL(drain_xbus_packet_queue);
--EXPORT_SYMBOL(phone_hook);
--EXPORT_SYMBOL(xpp_check_hookstate);
- EXPORT_SYMBOL(xpp_tick);
- EXPORT_SYMBOL(xpp_open);
- EXPORT_SYMBOL(xpp_close);
-@@ -2306,7 +1575,7 @@
- MODULE_DESCRIPTION("XPP Zaptel Driver");
- MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
- MODULE_LICENSE("GPL");
--MODULE_VERSION("$Id: xpp_zap.c 995 2006-04-03 07:08:13Z tzafrir $");
-+MODULE_VERSION(ZAPTEL_VERSION);
- 
- 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-LJNBCn_dist/xpp/xpp_zap.h
---- zaptel-1.2.6/xpp/xpp_zap.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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
-+/*
-+ * Written by Oron Peled <oron at actcom.co.il>
-+ * Copyright (C) 2004-2006, Xorcom
-+ *
-+ * All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
- 
- #include <linux/workqueue.h>
- #include "xpd.h"
- #include "xproto.h"
- 
--xpacket_t *xpacket_new(xbus_t *xbus, int flags);
--void xpacket_free(xbus_t *xbus, xpacket_t *p);
--
--/* packet queues */
--void init_xbus_packet_queue(packet_queue_t *q, const char name[]);
--void drain_xbus_packet_queue(xbus_t *xbus, packet_queue_t *q);
--void xbus_enqueue_packet(xbus_t *xbus, packet_queue_t *q, xpacket_t *pack);
--xpacket_t *xbus_dequeue_packet(packet_queue_t *q);
--
--xbus_t *xbus_new(ulong loopback_xpds);
--void xbus_activate(xbus_t *xbus);
--void xbus_deactivate(xbus_t *xbus);
--
--void xbus_reset_counters(xbus_t *xbus);
-+void xpd_disconnect(xpd_t *xpd);
- int packet_send(xbus_t *xbus, xpacket_t *pack_tx);
--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(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);
- int xpp_close(struct zt_chan *chan);
- int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg);
- int xpp_maint(struct zt_span *span, int cmd);
-+void sync_master_is(xpd_t *xpd);
- 
--#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;
- 
- #ifdef CONFIG_PROC_FS
- #include <linux/proc_fs.h>
- 
--extern struct proc_dir_entry	*xpp_procdir;
-+extern struct proc_dir_entry	*xpp_proc_toplevel;
- #endif
--extern xpd_t			*sync_master;
- 
--// Number of rings our simulated phone will ring:
--#define RINGS_NUM 3
-+#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-LJNBCn_dist/xpp/xproto.c
---- zaptel-1.2.6/xpp/xproto.c	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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>
-- * Copyright (C) 2004-2005, Xorcom
-+ * Copyright (C) 2004-2006, Xorcom
-  *
-  * All rights reserved.
-  *
-@@ -23,35 +23,36 @@
- #include "xpd.h"
- #include "xproto.h"
- #include "xpp_zap.h"
-+#include "xbus-core.h"
-+#include "zap_debug.h"
- #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 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);
- 
- 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;
- }
- 
--const xproto_handler_t xproto_global_handler(byte opcode)
-+xproto_handler_t xproto_global_handler(byte opcode)
- {
- 	return xproto_card_handler(&PROTO_TABLE(GLOBAL), opcode);
- }
-@@ -87,7 +88,7 @@
- 	return xprotocol_tables[cardtype];
- }
- 
--const xproto_table_t *get_xproto_table(xpd_type_t cardtype)
-+const xproto_table_t *xproto_get(xpd_type_t cardtype)
- {
- 	const xproto_table_t *xtable;
- 
-@@ -95,18 +96,34 @@
- 		return NULL;
- 	xtable = xprotocol_tables[cardtype];
- 	if(!xtable) {	/* Try to load the relevant module */
--		int ret = request_module("xpd-type-%d", cardtype);
-+		int ret = request_module(XPD_TYPE_PREFIX "%d", cardtype);
- 		if(ret != 0) {
- 			NOTICE("%s: Failed to load module for type=%d. exit status=%d.\n",
- 					__FUNCTION__, cardtype, ret);
--			/* Drop through: we may be luck... */
-+			/* Drop through: we may be lucky... */
- 		}
- 		xtable = xprotocol_tables[cardtype];
- 	}
-+	if(xtable) {
-+		BUG_ON(!xtable->owner);
-+		DBG("%s refcount was %d\n", xtable->name, module_refcount(xtable->owner));
-+		if(!try_module_get(xtable->owner)) {
-+			ERR("%s: try_module_get for %s failed.\n", __FUNCTION__, xtable->name);
-+			return NULL;
-+		}
-+	}
- 	return xtable;
- }
- 
--const xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opcode)
-+void xproto_put(const xproto_table_t *xtable)
-+{
-+	BUG_ON(!xtable);
-+	DBG("%s refcount was %d\n", xtable->name, module_refcount(xtable->owner));
-+	BUG_ON(module_refcount(xtable->owner) <= 0);
-+	module_put(xtable->owner);
-+}
-+
-+xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opcode)
- {
- 	const xproto_entry_t *xe;
- 
-@@ -115,7 +132,7 @@
- 	return xe->handler;
- }
- 
--const xproto_entry_t *find_xproto_entry(xpd_t *xpd, byte opcode)
-+static const xproto_entry_t *find_xproto_entry(xpd_t *xpd, byte opcode)
- {
- 	const xproto_entry_t *xe;
- 	
-@@ -136,18 +153,6 @@
- 	return xe;
- }
- 
--const xops_t *get_xops(xpd_type_t xpd_type)
--{
--	const xproto_table_t	*proto_table;
--
--	if(xpd_type >= XPD_TYPE_NOMODULE)
--		return NULL;
--	proto_table = xprotocol_tables[xpd_type];
--	if(!proto_table)
--		return NULL;
--	return &proto_table->xops;
--}
--
- int packet_receive(xbus_t *xbus, xpacket_t *pack)
- {
- 	int	xpd_num;
-@@ -161,7 +166,7 @@
- 		return -EPROTO;
- 	}
- 	xpd_num = XPD_NUM(pack->content.addr);
--#if SOFT_SIMULATOR
-+#ifdef SOFT_SIMULATOR
- 	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;
- 
--	BUG_ON(xpd_type >= XPD_TYPE(NOMODULE));
-+	BUG_ON(xpd_type >= XPD_TYPE_NOMODULE);
- 	proto_table = xprotocol_tables[xpd_type];
- 	if(!proto_table)
- 		return NULL;
-@@ -278,7 +284,7 @@
- 	BUG_ON(!proto_table);
- 	type = proto_table->type;
- 	name = proto_table->name;
--	if(type >= XPD_TYPE(NOMODULE)) {
-+	if(type >= XPD_TYPE_NOMODULE) {
- 		NOTICE("%s: Bad xproto type %d\n", __FUNCTION__, type);
- 		return -EINVAL;
- 	}
-@@ -290,14 +296,20 @@
- 	CHECK_XOP(card_init);
- 	CHECK_XOP(card_remove);
- 	CHECK_XOP(card_tick);
-+	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);
--	CHECK_XOP(CHAN_POWER);
- 	CHECK_XOP(CHAN_CID);
- 	CHECK_XOP(RING);
- 	CHECK_XOP(SETHOOK);
--	CHECK_XOP(LED);
- 	CHECK_XOP(RELAY_OUT);
- 
- 	xprotocol_tables[type] = proto_table;
-@@ -313,7 +325,7 @@
- 	type = proto_table->type;
- 	name = proto_table->name;
- 	DBG("%s (%d)\n", name, type);
--	if(type >= XPD_TYPE(NOMODULE)) {
-+	if(type >= XPD_TYPE_NOMODULE) {
- 		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-LJNBCn_dist/xpp/xproto.h
---- zaptel-1.2.6/xpp/xproto.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_dist/xpp/xproto.h	2006-07-03 13:44:48.152691000 +0300
-@@ -2,7 +2,7 @@
- #define	XPROTO_H
- /*
-  * Written by Oron Peled <oron at actcom.co.il>
-- * Copyright (C) 2004-2005, Xorcom
-+ * Copyright (C) 2004-2006, Xorcom
-  *
-  * All rights reserved.
-  *
-@@ -26,31 +26,39 @@
- 
- #ifdef	__KERNEL__
- #include <linux/list.h>
-+#include <zaptel.h>
- #endif
- 
--#define	XPD_TYPE(n)	XPD_TYPE_ ## n
- #define	PROTO_TABLE(n)	n ## _protocol_table
- 
--typedef enum xpd_type {
--	XPD_TYPE(FXO)		= 0x02,
--	XPD_TYPE(FXS)		= 0x03,
--	XPD_TYPE(NOMODULE)	= 0x0F,
--} xpd_type_t;
-+/*
-+ * 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;
-+
-+#define	XPD_TYPE_PREFIX	"xpd-type-"
-+
-+#define	MODULE_ALIAS_XPD(type)	\
-+	MODULE_ALIAS(XPD_TYPE_PREFIX __stringify(type))
- 
--#define	LINE_BITS	(sizeof(xpp_line_t)*8)
- #define	PCM_CHUNKSIZE	(CHANNELS_PERXPD * 8)	/* samples of 8 bytes */
- 
- typedef struct xpd_addr {
--	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);
- 
--const xproto_entry_t *find_xproto_entry(xpd_t *xpd, byte opcode);
--
--const xproto_table_t *get_xproto_table(xpd_type_t cardtype);
-+const xproto_table_t *xproto_get(xpd_type_t cardtype);
-+void xproto_put(const xproto_table_t *xtable);
- const xproto_entry_t *xproto_card_entry(const xproto_table_t *table, byte opcode);
--const xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opcode);
-+xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opcode);
- 
- const xproto_entry_t *xproto_global_entry(byte opcode);
--const xproto_handler_t xproto_global_handler(byte opcode);
-+xproto_handler_t xproto_global_handler(byte opcode);
- 
- #define	CALL_XMETHOD(name, xbus, xpd, ...)				\
- 			(xpd)->xops->name(xbus, xpd, ## __VA_ARGS__ )
-@@ -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_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);
- 
- 	int (*CHAN_ENABLE)(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, bool on);
--	int (*CHAN_POWER)(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, bool on);
--	int (*CHAN_CID)(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines);
-+	int (*CHAN_CID)(xbus_t *xbus, xpd_t *xpd, int pos);
- 	int (*RING)(xbus_t *xbus, xpd_t *xpd, int pos, bool on);
--	int (*SETHOOK)(xbus_t *xbus, xpd_t *xpd, xpp_line_t hook_status);
--	int (*LED)(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, byte which, bool on);
-+	int (*SETHOOK)(xbus_t *xbus, xpd_t *xpd, int pos, bool offhook);
- 	int (*RELAY_OUT)(xbus_t *xbus, xpd_t *xpd, byte which, bool on);
- };
- 
--const xops_t *get_xops(xpd_type_t xpd_type);
--
--#undef	XMETHOD
--
- struct xproto_entry {
- 	xproto_handler_t	handler;
- 	int			datalen;
-@@ -166,6 +176,7 @@
- };
- 
- struct xproto_table {
-+	struct module	*owner;
- 	xproto_entry_t	entries[255];	/* Indexed by opcode */
- 	xops_t		xops;
- 	xpd_type_t	type;
-@@ -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,
- 	XPROTO_NAME(GLOBAL, DEV_DESC)		= 0x05,
- /**/
-@@ -186,21 +199,6 @@
- /**/
- 	XPROTO_NAME(GLOBAL, SYNC_SOURCE)	= 0x19,
- 	XPROTO_NAME(GLOBAL, SYNC_REPLY)		= 0x1A,
--
--	XPROTO_NAME(FXS, SIG_CHANGED)		= 0x06,
--/**/
--	XPROTO_NAME(FXS, SLIC_WRITE)		= 0x0F,	/* Write to SLIC */
--	XPROTO_NAME(FXS, CHAN_ENABLE)		= 0x0F,	/* Write to SLIC */
--	XPROTO_NAME(FXS, CHAN_POWER)		= 0x0F,	/* Write to SLIC */
--	XPROTO_NAME(FXS, CHAN_CID)		= 0x0F,	/* Write to SLIC */
--	XPROTO_NAME(FXS, RING)			= 0x0F,	/* Write to SLIC */
--	XPROTO_NAME(FXS, SETHOOK)		= 0x0F,	/* Write to SLIC */
--	XPROTO_NAME(FXS, LED)			= 0x0F,	/* Write to SLIC */
--	XPROTO_NAME(FXS, RELAY_OUT)		= 0x0F,	/* Write to SLIC */
--	XPROTO_NAME(FXS, SLIC_INIT)		= 0x0F,	/* Write to SLIC */
--	XPROTO_NAME(FXS, SLIC_QUERY)		= 0x0F,	/* Write to SLIC */
--/**/
--	XPROTO_NAME(FXS, SLIC_REPLY)		= 0x10,
- };
- 
- 
-@@ -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_WRITE);
-+
-+		MEMBER(FXO, SIG_CHANGED);
-+		MEMBER(FXO, DAA_REPLY);
-+		MEMBER(FXO, DAA_WRITE);
- 
- 		byte	data[0];
- 	};
--} __attribute__((packed));
-+} PACKED;
- 
- struct xpacket {
- 	xpacket_raw_t		content;
--	size_t			datalen;
-+	int			datalen;
- 	struct list_head	list;
-+	void			*packet_priv;
- };
- 
- 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-LJNBCn_dist/xpp/zap_debug.c
---- zaptel-1.2.6/xpp/zap_debug.c	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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>
-- * Copyright (C) 2004-2005, Xorcom
-+ * Copyright (C) 2004-2006, Xorcom
-  *
-  * All rights reserved.
-  *
-@@ -31,7 +31,7 @@
- #include <zaptel.h>
- #include "zap_debug.h"
- 
--static const char rcsid[] = "$Id: zap_debug.c 949 2006-02-15 02:24:18Z kpfleming $";
-+static const char rcsid[] = "$Id: zap_debug.c 733 2006-03-30 10:42:46Z oron $";
- 
- #define	P_(x)	[ x ] = { .value = x, .name = #x, }
- static	struct {
-@@ -63,74 +63,5 @@
- 	}
- }
- 
--#define	E_(x)	[ x ] = { .value = x, .name = #x, }
--static	struct {
--	int	value;
--	char	*name;
--} zt_event_names[] = {
--	E_(ZT_EVENT_NONE),
--	E_(ZT_EVENT_ONHOOK),
--	E_(ZT_EVENT_RINGOFFHOOK),
--	E_(ZT_EVENT_WINKFLASH),
--	E_(ZT_EVENT_ALARM),
--	E_(ZT_EVENT_NOALARM),
--	E_(ZT_EVENT_ABORT),
--	E_(ZT_EVENT_OVERRUN),
--	E_(ZT_EVENT_BADFCS),
--	E_(ZT_EVENT_DIALCOMPLETE),
--	E_(ZT_EVENT_RINGERON),
--	E_(ZT_EVENT_RINGEROFF),
--	E_(ZT_EVENT_HOOKCOMPLETE),
--	E_(ZT_EVENT_BITSCHANGED),
--	E_(ZT_EVENT_PULSE_START),
--	E_(ZT_EVENT_TIMER_EXPIRED),
--	E_(ZT_EVENT_TIMER_PING),
--	E_(ZT_EVENT_POLARITY)
--};
--#undef	E_
--
--char *event2str(int event)
--{
--	BUG_ON(event > ARRAY_SIZE(zt_event_names));
--	return zt_event_names[event].name;
--}
--
--#define	S_(x)	[ x ] = { .value = x, .name = #x, }
--static	struct {
--	int	value;
--	char	*name;
--} zt_sig_types[] = {
--	S_(ZT_SIG_NONE),
--	S_(ZT_SIG_FXSLS),
--	S_(ZT_SIG_FXSGS),
--	S_(ZT_SIG_FXSKS),
--	S_(ZT_SIG_FXOLS),
--	S_(ZT_SIG_FXOGS),
--	S_(ZT_SIG_FXOKS),
--	S_(ZT_SIG_EM),
--	S_(ZT_SIG_CLEAR),
--	S_(ZT_SIG_HDLCRAW),
--	S_(ZT_SIG_HDLCFCS),
--	S_(ZT_SIG_HDLCNET),
--	S_(ZT_SIG_SLAVE),
--	S_(ZT_SIG_SF),
--	S_(ZT_SIG_CAS),
--	S_(ZT_SIG_DACS),
--	S_(ZT_SIG_EM_E1),
--	S_(ZT_SIG_DACS_RBS)
--};
--#undef	S_
--
--void dump_sigtype(int print_dbg, const char *msg, int sigtype)
--{
--	int	i;
--
--	for(i = 0; i < ARRAY_SIZE(zt_sig_types); i++) {
--		if(sigtype == zt_sig_types[i].value)
--			DBG("%s: %s\n", msg, zt_sig_types[i].name);
--	}
--}
- 
- 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-LJNBCn_dist/xpp/zap_debug.h
---- zaptel-1.2.6/xpp/zap_debug.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-LJNBCn_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
-+/*
-+ * Written by Oron Peled <oron at actcom.co.il>
-+ * Copyright (C) 2004-2006, Xorcom
-+ *
-+ * All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
- 
-+/* Debugging Macros */
- #define	DBG(fmt, ...)	\
--	((print_dbg) && printk(KERN_DEBUG "DBG-%s: %s: " fmt, \
--		THIS_MODULE->name, __FUNCTION__, ## __VA_ARGS__))
-+	((void)((print_dbg) && printk(KERN_DEBUG "DBG-%s: %s: " fmt, \
-+		THIS_MODULE->name, __FUNCTION__, ## __VA_ARGS__)))
- #define	INFO(fmt, ...)	printk(KERN_INFO "INFO-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
- #define	NOTICE(fmt, ...)	printk(KERN_NOTICE "NOTICE-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
-+#define	WARN(fmt, ...)	printk(KERN_WARNING "WARN-%s: %s: " fmt, THIS_MODULE->name, __FUNCTION__, ## __VA_ARGS__)
- #define	ERR(fmt, ...)	printk(KERN_ERR "ERR-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
- 
--
- void dump_poll(int print_dbg, const char *msg, int poll);
--char *event2str(int event);
--void dump_sigtype(int print_dbg, const char *msg, int sigtype);
-+
-+static inline char *rxsig2str(zt_rxsig_t sig)
-+{
-+	switch(sig) {
-+		case ZT_RXSIG_ONHOOK:	return "ONHOOK";
-+		case ZT_RXSIG_OFFHOOK:	return "OFFHOOK";
-+		case ZT_RXSIG_START:	return "START";
-+		case ZT_RXSIG_RING:	return "RING";
-+		case ZT_RXSIG_INITIAL:	return "INITIAL";
-+	}
-+	return "Unknown rxsig";
-+}
-+
-+static inline char *txsig2str(zt_txsig_t sig)
-+{
-+	switch(sig) {
-+		case ZT_TXSIG_ONHOOK:	return "TXSIG_ONHOOK";
-+		case ZT_TXSIG_OFFHOOK:	return "TXSIG_OFFHOOK";
-+		case ZT_TXSIG_START:	return "TXSIG_START";
-+		case ZT_TXSIG_KEWL:	return "TXSIG_KEWL";				/* Drop battery if possible */
-+	}
-+	return "Unknown txsig";
-+}
-+
-+static inline char *event2str(int event)
-+{
-+	switch(event) {
-+		case ZT_EVENT_NONE:		return "NONE";
-+		case ZT_EVENT_ONHOOK:		return "ONHOOK";
-+		case ZT_EVENT_RINGOFFHOOK:	return "RINGOFFHOOK";
-+		case ZT_EVENT_WINKFLASH:	return "WINKFLASH";
-+		case ZT_EVENT_ALARM:		return "ALARM";
-+		case ZT_EVENT_NOALARM:		return "NOALARM";
-+		case ZT_EVENT_ABORT:		return "ABORT";
-+		case ZT_EVENT_OVERRUN:		return "OVERRUN";
-+		case ZT_EVENT_BADFCS:		return "BADFCS";
-+		case ZT_EVENT_DIALCOMPLETE:	return "DIALCOMPLETE";
-+		case ZT_EVENT_RINGERON:		return "RINGERON";
-+		case ZT_EVENT_RINGEROFF:	return "RINGEROFF";
-+		case ZT_EVENT_HOOKCOMPLETE:	return "HOOKCOMPLETE";
-+		case ZT_EVENT_BITSCHANGED:	return "BITSCHANGED";
-+		case ZT_EVENT_PULSE_START:	return "PULSE_START";
-+		case ZT_EVENT_TIMER_EXPIRED:	return "TIMER_EXPIRED";
-+		case ZT_EVENT_TIMER_PING:	return "TIMER_PING";
-+		case ZT_EVENT_POLARITY:		return "POLARITY";
-+	}
-+	return "Unknown event";
-+}
-+
-+static inline char *hookstate2str(int hookstate)
-+{
-+	switch(hookstate) {
-+		case ZT_ONHOOK:		return "ZT_ONHOOK";
-+		case ZT_START:		return "ZT_START";
-+		case ZT_OFFHOOK:	return "ZT_OFFHOOK";
-+		case ZT_WINK:		return "ZT_WINK";
-+		case ZT_FLASH:		return "ZT_FLASH";
-+		case ZT_RING:		return "ZT_RING";
-+		case ZT_RINGOFF:	return "ZT_RINGOFF";
-+	}
-+	return "Unknown hookstate";
-+}
-+
-+/* From zaptel.c */
-+static inline char *sig2str(int sig)
-+{
-+	switch (sig) {
-+		case ZT_SIG_FXSLS:	return "FXSLS";
-+		case ZT_SIG_FXSKS:	return "FXSKS";
-+		case ZT_SIG_FXSGS:	return "FXSGS";
-+		case ZT_SIG_FXOLS:	return "FXOLS";
-+		case ZT_SIG_FXOKS:	return "FXOKS";
-+		case ZT_SIG_FXOGS:	return "FXOGS";
-+		case ZT_SIG_EM:		return "E&M";
-+		case ZT_SIG_EM_E1:	return "E&M-E1";
-+		case ZT_SIG_CLEAR:	return "Clear";
-+		case ZT_SIG_HDLCRAW:	return "HDLCRAW";
-+		case ZT_SIG_HDLCFCS:	return "HDLCFCS";
-+		case ZT_SIG_HDLCNET:	return "HDLCNET";
-+		case ZT_SIG_SLAVE:	return "Slave";
-+		case ZT_SIG_CAS:	return "CAS";
-+		case ZT_SIG_DACS:	return "DACS";
-+		case ZT_SIG_DACS_RBS:	return "DACS+RBS";
-+		case ZT_SIG_SF:		return "SF (ToneOnly)";
-+		case ZT_SIG_NONE:
-+					break;
-+	}
-+	return "Unconfigured";
-+}
- 
- #endif	/* ZAP_DEBUG_H */




More information about the Pkg-voip-commits mailing list