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

Tzafrir Cohen tzafrir-guest at costa.debian.org
Wed Jan 11 19:27:15 UTC 2006


Author: tzafrir-guest
Date: 2006-01-11 19:27:12 +0000 (Wed, 11 Jan 2006)
New Revision: 1160

Modified:
   zaptel/trunk/debian/changelog
   zaptel/trunk/debian/genzaptelconf
   zaptel/trunk/debian/patches/xpp.dpatch
Log:
new versions of genzaptelconf and xpp.dpatch


Modified: zaptel/trunk/debian/changelog
===================================================================
--- zaptel/trunk/debian/changelog	2006-01-11 19:25:56 UTC (rev 1159)
+++ zaptel/trunk/debian/changelog	2006-01-11 19:27:12 UTC (rev 1160)
@@ -3,6 +3,7 @@
   * Use KSRC as proposed on http://wiki.debian.org/KernelModulesPackaging to
     build zaptel kernel module (Closes: #343521)
   * ukcid.dpatch: for UK Caller ID support (Zaptel part)
+  * newer versions of genzaptelconf and xpp.dpatch
 
  -- Kilian Krause <kilian at debian.org>  Wed, 11 Jan 2006 18:01:39 +0100
 

Modified: zaptel/trunk/debian/genzaptelconf
===================================================================
--- zaptel/trunk/debian/genzaptelconf	2006-01-11 19:25:56 UTC (rev 1159)
+++ zaptel/trunk/debian/genzaptelconf	2006-01-11 19:27:12 UTC (rev 1160)
@@ -35,10 +35,16 @@
 # 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.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.4.1
-VERSION_FULL="$VERSION $Id: genzaptelconf 84 2006-01-01 18:52:28Z tzafrir $"
+VERSION=0.4.2
+VERSION_FULL="$VERSION $Id: genzaptelconf 110 2006-01-11 08:09:58Z tzafrir $"
 lc_country=us
 base_exten=6000
 # If set: no context changes are made in zapata-channels.conf
@@ -48,8 +54,8 @@
 # TODO: what about PRI/BRI?
 # If set: no group changes are made in zapata-channels.conf
 #group_manual=yes
-group_phones=0 # group for phones
-group_lines=1  # group for lines
+group_phones=5 # group for phones
+group_lines=0  # group for lines
 
 ZAPCONF_FILE=/etc/zaptel.conf
 ZAPATA_FILE=/etc/asterisk/zapata-channels.conf
@@ -66,7 +72,8 @@
 # A list of all modules. This is:
 # - the list of modules which will be unloaded (in this order)
 # - the list of modules which will be probed (in this order)
-ALL_MODULES="zaphfc qozap wctdm wctdm24xxp wcfxo wcfxs pciradio tor2 torisa wct1xxp wct4xxp wcte11xp wcusb ztd_eth ztdummy xpp_usb xpp"
+#ALL_MODULES="zaphfc qozap wctdm wctdm24xxp wcfxo wcfxs pciradio tor2 torisa wct1xxp wct4xxp wcte11xp wcusb ztdynamic ztd_eth ztdummy xpp_usb xpd_fxs xpp"
+ALL_MODULES="zaphfc qozap wctdm wctdm24xxp wcfxo wcfxs pciradio tor2 torisa wct1xxp wct4xxp wcte11xp wcusb ztd_eth xpp_usb"
 
 # read default configuration from /etc/default/zaptel
 if [ -r $ZAPTEL_BOOT ]; then . $ZAPTEL_BOOT; fi
@@ -361,7 +368,25 @@
 	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
+	for mod in `echo $4 | tr , ' '`; do
+		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)"
@@ -370,15 +395,7 @@
 		die "Before unloading -- STOP asterisk (pids=$pids)."
 	fi
 	say "Unloading zaptel modules:"
-	modlist=''
-	for i in $ALL_MODULES zaptel
-	do
-		if lsmod | grep "^$i  *" > /dev/null; then
-			modlist="$modlist $i"
-			say -n "$i "
-		fi
-	done
-	/sbin/modprobe -r $modlist
+	unload_module zaptel
 	say ''
 }
 
@@ -545,7 +562,7 @@
 			*XPP_FXO/*)
 				print_pattern $chan_num fxs $mode
 				;;
-			*XPP_FXS/*)
+			*XPP_FXS/*|*XPP_OUT/*|*XPP_IN/*)
 				print_pattern $chan_num fxo $mode
 				;;
 			*ZTHFC*/*|*ztqoz*/*|*WCT1/*) # should also be used for other PRI channels
@@ -571,13 +588,13 @@
 						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 dk)
+						case "$lc_country" in nl)
 							# (Just an example for per-country info)
-							echo 'ccs'       >$tmp_dir/span_framing
-							echo 'hdb3'      >$tmp_dir/span_coding
-							echo 'crc4'      >$tmp_dir/span_yellow
-							echo 'euroisdn'  >$tmp_dir/span_switchtype
-							echo 'pri_cpe'   >$tmp_dir/span_signalling
+							echo 'ami'       >$tmp_dir/span_framing
+							echo 'ccs'      >$tmp_dir/span_coding
+							#echo 'crc4'      >$tmp_dir/span_yellow
+							#echo 'euroisdn'  >$tmp_dir/span_switchtype
+							#echo 'pri_cpe'   >$tmp_dir/span_signalling
 							;;
 						esac
 					;;

Modified: zaptel/trunk/debian/patches/xpp.dpatch
===================================================================
--- zaptel/trunk/debian/patches/xpp.dpatch	2006-01-11 19:25:56 UTC (rev 1159)
+++ zaptel/trunk/debian/patches/xpp.dpatch	2006-01-11 19:27:12 UTC (rev 1160)
@@ -3,13 +3,13 @@
 ##
 ## All lines beginning with `## DP:' are a description of the patch.
 ## DP: The zaptel drivers for the Xorcom Astribank and friends.
-## DP: Revision 168.
+## DP: Revision 186 (trunk)
 
 @DPATCH@
-diff -urNad zaptel-1.0.10/xpp/card_fxs.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_fxs.c
---- zaptel-1.0.10/xpp/card_fxs.c	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_fxs.c	2006-01-03 15:08:38.089954000 +0200
-@@ -0,0 +1,548 @@
+diff -urNad trunk/xpp/card_fxs.c /tmp/dpep.qIz4nf/trunk/xpp/card_fxs.c
+--- trunk/xpp/card_fxs.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/card_fxs.c	2006-01-11 10:12:52.381169000 +0200
+@@ -0,0 +1,703 @@
 +/*
 + * Written by Oron Peled <oron at actcom.co.il>
 + * Copyright (C) 2004-2005, Xorcom
@@ -32,19 +32,44 @@
 + *
 + */
 +
++#include <linux/init.h>
 +#include <linux/module.h>
++#include <linux/fs.h>
 +#include "xpd.h"
 +#include "xproto.h"
 +#include "xpp_zap.h"
 +#include <linux/delay.h>
 +
-+static const char rcsid[] = "$Id: card_fxs.c 168 2006-01-03 12:51:06Z oron $";
++static const char rcsid[] = "$Id: card_fxs.c 185 2006-01-10 14:39:07Z oron $";
++static const char revision[] = "$Revision: 185 $";
 +
-+extern	int print_dbg;
++DEF_PARM(int, print_dbg, 1, "Print DBG statements");	/* must be before zap_debug.h */
 +
++#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	(MASK_BITS(LINES_DIGI_OUT) << LINES_REGULAR)
++#define	MASK_DIGI_INP	(MASK_BITS(LINES_DIGI_INP) << (LINES_REGULAR + LINES_DIGI_OUT))
++
 +/*---------------- 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 bool fxs_packet_is_valid(xpacket_t *pack);
 +static void fxs_packet_dump(xpacket_t *pack);
++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,...)					\
 +	{						\
@@ -62,49 +87,103 @@
 +};
 +#undef	S_
 +
++#define	PROC_SLIC_FNAME		"slics"
++
++struct FXS_priv_data {
++	struct proc_dir_entry	*xpd_slic;
++	slic_reply_t		last_reply;
++};
++
 +/*---------------- FXS: Methods -------------------------------------------*/
 +
-+static int FXS_card_new(xbus_t *xbus, xpd_t *xpd, byte rev)
++static xpd_t *FXS_card_new(xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, byte revision)
 +{
-+	int	channels = min(8, CHANNELS_PERXPD);
++	xpd_t		*xpd = NULL;
++	int		channels = min(8, CHANNELS_PERXPD);
 +
++	if(xpd_num == 0)
++		channels += 6;	/* 2 DIGITAL OUTPUTS, 4 DIGITAL INPUTS */
++	xpd = xpd_alloc(sizeof(struct FXS_priv_data), xbus, xpd_num, proto_table, channels, revision);
++	if(!xpd)
++		return NULL;
++	if(xpd_num == 0) {
++		DBG("First XPD on %s detected. Initialize digital outputs/inputs\n", xbus->busname);
++		xpd->digital_outputs = MASK_DIGI_OUT;
++		xpd->digital_inputs = MASK_DIGI_INP;
++	}
 +	xpd->direction = TO_PHONE;
-+	if(xpd->id == 0) {
-+		DBG("First XPD detected. Initialize digital outputs\n");
-+		channels += 2;
-+		xpd->digital_outputs = BIT(8) | BIT(9);	// Two extra channels
-+	}
-+	xpd->channels = channels;
-+	return 0;
++	return xpd;
 +}
 +
 +static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
 +{
++	struct FXS_priv_data	*priv;
++
++	BUG_ON(!xpd);
++	priv = xpd->priv;
 +	CALL_PROTO(FXS, SLIC_INIT, xbus, xpd);
++#ifdef	CONFIG_PROC_FS
++	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;
++	}
++	priv->xpd_slic->write_proc = proc_xpd_slic_write;
++	priv->xpd_slic->read_proc = proc_xpd_slic_read;
++	priv->xpd_slic->data = xpd;
++out:
++#endif
 +	return 0;
 +}
 +
 +static int FXS_card_remove(xbus_t *xbus, xpd_t *xpd)
 +{
++	struct FXS_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 SLIC file %s/%s\n", xbus->busname, xpd->xpdname);
++		remove_proc_entry(PROC_SLIC_FNAME, xpd->proc_xpd_dir);
++	}
++#endif
 +	return 0;
 +}
 +
-+xops_t FXS_xops = {
-+	.card_new	= FXS_card_new,
-+	.card_init	= FXS_card_init,
-+	.card_remove	= FXS_card_remove,
++/*
++ * INPUT polling is done via SLIC register 0x06 (same as LEDS):
++ *         7     6     5     4     3     2     1     0
++ * 	+-----+-----+-----+-----+-----+-----+-----+-----+
++ * 	| I1  | I3  |     |     | I2  | I4  |     |     |
++ * 	+-----+-----+-----+-----+-----+-----+-----+-----+
++ *
++ */
++static int	input_channels[] = { 6, 7, 2, 3 };	// Slic numbers of input relays
 +
-+	.RING		= XPROTO_CALLER(FXS, RING),
-+	.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),
++static void poll_inputs(xbus_t *xbus, xpd_t *xpd)
++{
++	int	i;
 +
-+	.SYNC_SOURCE	= XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
-+	.PCM_WRITE	= XPROTO_CALLER(GLOBAL, PCM_WRITE),
-+};
++	for(i = 0; i < ARRAY_SIZE(input_channels); i++) {
++		int	pos = input_channels[i];
 +
++		CALL_PROTO(FXS, SLIC_QUERY, xbus, xpd, pos, 0x06);
++	}
++}
++
++static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
++{
++	static	int	rate_limit = 0;
++
++	if((rate_limit++ % 1000) == 0) {
++		poll_inputs(xbus, xpd);
++	}
++	return 0;
++}
++
 +/*---------------- FXS: HOST COMMANDS -------------------------------------*/
 +
 +/* 0x0F */ HOSTCMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on)
@@ -326,8 +405,22 @@
 +
 +/* 0x0F */ HOSTCMD(FXS, SLIC_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");
-+	return 0;
++	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);
++
++	pack->datalen = len;
++
++	packet_send(xbus, pack);
++	return ret;
 +}
 +
 +/*---------------- FXS: Astribank Reply Handlers --------------------------*/
@@ -344,11 +437,11 @@
 +	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 */
++	} else {					/* TO_PSTN - line ring changes */
 +		unsigned long	flags;
 +		int		i;
 +
-+		DBG("%s (TRUNK) sig_status=0x%04X\n", xpd->xpdname, sig_status);
++		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++) {
 +			if(IS_SET(sig_status, i)) {
@@ -366,8 +459,10 @@
 +
 +HANDLER_DEF(FXS, SLIC_REPLY)
 +{
-+	slic_reply_t	*info = &RPACKET_FIELD(pack, FXS, SLIC_REPLY, info);
-+	unsigned long	flags;
++	slic_reply_t		*info = &RPACKET_FIELD(pack, FXS, SLIC_REPLY, info);
++	xpp_line_t		lines = RPACKET_FIELD(pack, FXS, SLIC_REPLY, lines);
++	unsigned long		flags;
++	struct FXS_priv_data	*priv;
 +
 +	if(!xpd) {
 +		NOTICE("%s: received %s for non-existing xpd: %d\n",
@@ -375,9 +470,29 @@
 +		return -EPROTO;
 +	}
 +	spin_lock_irqsave(&xpd->lock, flags);
++	priv = xpd->priv;
++	BUG_ON(!priv);
 +	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;
++	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;
++
++			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);
++			}
++		}
++	}
 +	spin_unlock_irqrestore(&xpd->lock, flags);
 +	return 0;
 +}
@@ -390,6 +505,24 @@
 +		XENTRY(	FXS,	SLIC_REPLY	),
 +	},
 +	.name = "FXS",
++	.type = XPD_TYPE(FXS),
++	.xops = {
++		.card_new	= FXS_card_new,
++		.card_init	= FXS_card_init,
++		.card_remove	= FXS_card_remove,
++		.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),
++		.PCM_WRITE	= XPROTO_CALLER(GLOBAL, PCM_WRITE),
++	},
 +	.packet_is_valid = fxs_packet_is_valid,
 +	.packet_dump = fxs_packet_dump,
 +};
@@ -410,21 +543,24 @@
 +
 +/*------------------------- SLIC Handling --------------------------*/
 +
-+int proc_xpd_slic_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)
 +{
-+	int		len = 0;
-+	unsigned long	flags;
-+	xpd_t		*xpd = data;
-+	//slic_reply_t	*info;
++	int			len = 0;
++	unsigned long		flags;
++	xpd_t			*xpd = data;
++	slic_reply_t		*info;
++	struct FXS_priv_data	*priv;
 +
 +	BUG_ON(!xpd);
 +	spin_lock_irqsave(&xpd->lock, flags);
-+#if 0
-+	info = (slic_reply_t *)&xpd->slic_info;
++	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, "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;
@@ -527,7 +663,7 @@
 +	return 0;
 +}
 +
-+int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
++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;
@@ -558,10 +694,29 @@
 +}
 +
 +
-diff -urNad zaptel-1.0.10/xpp/card_fxs.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_fxs.h
---- zaptel-1.0.10/xpp/card_fxs.h	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_fxs.h	2006-01-03 13:22:53.823218000 +0200
-@@ -0,0 +1,67 @@
++int __init card_fxs_startup(void)
++{
++	INFO("%s revision %s\n", THIS_MODULE->name, revision);
++	xproto_register(&PROTO_TABLE(FXS));
++	return 0;
++}
++
++void __exit card_fxs_cleanup(void)
++{
++	xproto_unregister(&PROTO_TABLE(FXS));
++}
++
++MODULE_DESCRIPTION("XPP FXS Card Driver");
++MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
++MODULE_LICENSE("GPL");
++MODULE_VERSION("$Id: card_fxs.c 185 2006-01-10 14:39:07Z oron $");
++
++module_init(card_fxs_startup);
++module_exit(card_fxs_cleanup);
+diff -urNad trunk/xpp/card_fxs.h /tmp/dpep.qIz4nf/trunk/xpp/card_fxs.h
+--- trunk/xpp/card_fxs.h	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/card_fxs.h	2006-01-09 18:14:37.000000000 +0200
+@@ -0,0 +1,45 @@
 +#ifndef	CARD_FXS_H
 +#define	CARD_FXS_H
 +/*
@@ -588,7 +743,6 @@
 +
 +#include "xpd.h"
 +#include "slic.h"
-+#include "xproto.h"
 +
 +DEF_RPACKET_DATA(FXS, SIG_CHANGED,
 +	byte		type;		/* unused -- we have it from DEV_DESC */
@@ -607,32 +761,11 @@
 +	slic_cmd_t	slic_cmd;
 +	);
 +
-+#ifdef	__KERNEL__
-+
-+#include <linux/fs.h>
-+
-+/* 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);
-+
-+extern xproto_table_t PROTO_TABLE(FXS);
-+extern xops_t FXS_xops;
-+int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data);
-+int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
-+
-+#endif
-+
 +#endif	/* CARD_FXS_H */
-diff -urNad zaptel-1.0.10/xpp/card_global.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_global.c
---- zaptel-1.0.10/xpp/card_global.c	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_global.c	2006-01-03 15:08:38.089954000 +0200
-@@ -0,0 +1,270 @@
+diff -urNad trunk/xpp/card_global.c /tmp/dpep.qIz4nf/trunk/xpp/card_global.c
+--- trunk/xpp/card_global.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/card_global.c	2006-01-11 10:12:52.381169000 +0200
+@@ -0,0 +1,256 @@
 +/*
 + * Written by Oron Peled <oron at actcom.co.il>
 + * Copyright (C) 2004-2005, Xorcom
@@ -661,7 +794,7 @@
 +#include "xproto.h"
 +#include <linux/module.h>
 +
-+static const char rcsid[] = "$Id: card_global.c 165 2006-01-03 12:36:57Z oron $";
++static const char rcsid[] = "$Id: card_global.c 185 2006-01-10 14:39:07Z oron $";
 +
 +extern	int print_dbg;
 +static bool pcm_valid(xpd_t *xpd, xpacket_t *pack);
@@ -749,48 +882,34 @@
 +	return 0;
 +}
 +
-+xops_t GLOBAL_xops = {
-+	.DESC_REQ = XPROTO_CALLER(GLOBAL, DESC_REQ),
-+	.PCM_WRITE = XPROTO_CALLER(GLOBAL, PCM_WRITE),
-+	.SYNC_SOURCE = XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
-+};
-+
 +/*---------------- GLOBAL: Astribank Reply Handlers -----------------------*/
 +
 +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);
-+	xops_t		*xops;
++	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);
++	struct card_desc_struct	*card_desc;
 +
 +	DBG("xpd=%d type=%d rev=%d line_status=0x%04X\n",
 +			xpd_num, type, rev, line_status);
-+	if(xpd) {
-+		if(type == XPD_TYPE(NOMODULE)) {
-+			NOTICE("DEV_DESC: xpd #%d: removed\n", xpd_num);
-+			xpd_remove(xpd);
-+			return 0;
-+		}
-+		NOTICE("DEV_DESC: xpd #%d: already exists\n", xpd_num);
-+		return 0;
++	if((card_desc = kmalloc(sizeof(struct card_desc_struct), GFP_ATOMIC)) == NULL) {
++		ERR("%s: Card description allocation failed.\n", __FUNCTION__);
++		return -ENOMEM;
 +	}
-+	if(type == XPD_TYPE_NOMODULE) {
-+		DBG("No module at address=%d\n", xpd_num);
-+		return 0;
-+	}
-+	xops = get_xops(type);
-+	if(!xops) {
-+		NOTICE("DEV_DESC: xpd #%d: missing xops for type=%d\n", xpd_num, type);
++	memset(card_desc, 0, sizeof(struct card_desc_struct));
++	card_desc->magic = CARD_DESC_MAGIC;
++	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;
 +	}
-+	xpd = xpd_new(xbus, xpd_num, type, rev);
-+	if(!xpd) {
-+		NOTICE("xpd_new failed\n");
-+		return -EINVAL;
-+	}
-+	xpp_check_hookstate(xpd, line_status);
 +	return 0;
 +}
 +
@@ -903,10 +1022,10 @@
 +	return 1;
 +}
 +
-diff -urNad zaptel-1.0.10/xpp/card_global.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_global.h
---- zaptel-1.0.10/xpp/card_global.h	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_global.h	2006-01-03 13:22:53.823218000 +0200
-@@ -0,0 +1,56 @@
+diff -urNad trunk/xpp/card_global.h /tmp/dpep.qIz4nf/trunk/xpp/card_global.h
+--- trunk/xpp/card_global.h	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/card_global.h	2006-01-09 18:14:37.000000000 +0200
+@@ -0,0 +1,55 @@
 +#ifndef	CARD_GLOBAL_H
 +#define	CARD_GLOBAL_H
 +/*
@@ -932,7 +1051,6 @@
 + */
 +
 +#include "xdefs.h"
-+#include "xproto.h"
 +
 +DEF_RPACKET_DATA(GLOBAL, DESC_REQ);
 +DEF_RPACKET_DATA(GLOBAL, DEV_DESC,
@@ -957,15 +1075,15 @@
 +
 +
 +/* 0x04 */ DECLARE_CMD(GLOBAL, DESC_REQ, int xpd_num);
-+/* 0x11 */ DECLARE_CMD(GLOBAL, PCM_WRITE, xpp_line_t hookstate,  volatile byte *buf);
 +/* 0x19 */ DECLARE_CMD(GLOBAL, SYNC_SOURCE, bool setit, bool is_master);
++/* 0x11 */ DECLARE_CMD(GLOBAL, PCM_WRITE, xpp_line_t lines, volatile byte *buf);
 +
 +extern xproto_table_t PROTO_TABLE(GLOBAL);
 +
 +#endif	/* CARD_GLOBAL_H */
-diff -urNad zaptel-1.0.10/xpp/cards.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/cards.c
---- zaptel-1.0.10/xpp/cards.c	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/cards.c	2006-01-03 14:01:24.370308595 +0200
+diff -urNad trunk/xpp/cards.c /tmp/dpep.qIz4nf/trunk/xpp/cards.c
+--- trunk/xpp/cards.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/cards.c	2006-01-11 10:12:40.515108543 +0200
 @@ -0,0 +1,394 @@
 +#include <linux/module.h>
 +#include "xpd.h"
@@ -1361,9 +1479,9 @@
 +		return NULL;
 +	return &xpd_card_ops[xpd_type];
 +}
-diff -urNad zaptel-1.0.10/xpp/cards.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/cards.h
---- zaptel-1.0.10/xpp/cards.h	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/cards.h	2006-01-03 14:01:24.370308595 +0200
+diff -urNad trunk/xpp/cards.h /tmp/dpep.qIz4nf/trunk/xpp/cards.h
+--- trunk/xpp/cards.h	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/cards.h	2006-01-11 10:12:40.515108543 +0200
 @@ -0,0 +1,23 @@
 +#ifndef	CARDS_H
 +#define	CARDS_H
@@ -1388,9 +1506,9 @@
 +xops_t *get_xops(xpd_type_t xpd_type);
 +
 +#endif	/* CARDS_H */
-diff -urNad zaptel-1.0.10/xpp/FPGA_XPD.hex /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/FPGA_XPD.hex
---- zaptel-1.0.10/xpp/FPGA_XPD.hex	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/FPGA_XPD.hex	2006-01-03 13:22:53.823218000 +0200
+diff -urNad trunk/xpp/FPGA_XPD.hex /tmp/dpep.qIz4nf/trunk/xpp/FPGA_XPD.hex
+--- trunk/xpp/FPGA_XPD.hex	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/FPGA_XPD.hex	2006-01-09 18:14:37.000000000 +0200
 @@ -0,0 +1,243 @@
 +:0A0B3C000001020203030404050592
 +:100546005010C0C0F9A4B0999282F880988883C6EA
@@ -1635,9 +1753,9 @@
 +:10093400F0A3C8C582C8CAC583CADFE9DEE780BEA2
 +:0106360000C3
 +:00000001FF
-diff -urNad zaptel-1.0.10/xpp/gen_slic_init /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/gen_slic_init
---- zaptel-1.0.10/xpp/gen_slic_init	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/gen_slic_init	2006-01-03 15:08:38.089954000 +0200
+diff -urNad trunk/xpp/gen_slic_init /tmp/dpep.qIz4nf/trunk/xpp/gen_slic_init
+--- trunk/xpp/gen_slic_init	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/gen_slic_init	2006-01-09 18:14:37.000000000 +0200
 @@ -0,0 +1,37 @@
 +#! /usr/bin/perl -w
 +
@@ -1676,17 +1794,18 @@
 +	}
 +	print HF "\n";
 +}
-diff -urNad zaptel-1.0.10/xpp/Makefile /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/Makefile
---- zaptel-1.0.10/xpp/Makefile	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/Makefile	2006-01-03 13:22:53.565151000 +0200
-@@ -0,0 +1,4 @@
+diff -urNad trunk/xpp/Makefile /tmp/dpep.qIz4nf/trunk/xpp/Makefile
+--- trunk/xpp/Makefile	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/Makefile	2006-01-09 18:14:36.000000000 +0200
+@@ -0,0 +1,5 @@
 +EXTRA_CFLAGS	= -I$(src)/.. 
 +
-+obj-m		= xpp.o xpp_usb.o
-+xpp-y		+= xproto.o card_global.o card_fxs.o slic.o xpp_zap.o zap_debug.o
-diff -urNad zaptel-1.0.10/xpp/slic.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/slic.c
---- zaptel-1.0.10/xpp/slic.c	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/slic.c	2006-01-03 13:22:53.823218000 +0200
++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
+diff -urNad trunk/xpp/slic.c /tmp/dpep.qIz4nf/trunk/xpp/slic.c
+--- trunk/xpp/slic.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/slic.c	2006-01-09 18:14:37.000000000 +0200
 @@ -0,0 +1,129 @@
 +/*
 + * Written by Oron Peled <oron at actcom.co.il>
@@ -1817,9 +1936,9 @@
 +EXPORT_SYMBOL(dump_slic_cmd);
 +
 +#endif
-diff -urNad zaptel-1.0.10/xpp/slic.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/slic.h
---- zaptel-1.0.10/xpp/slic.h	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/slic.h	2006-01-03 13:22:53.823218000 +0200
+diff -urNad trunk/xpp/slic.h /tmp/dpep.qIz4nf/trunk/xpp/slic.h
+--- trunk/xpp/slic.h	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/slic.h	2006-01-09 18:14:37.000000000 +0200
 @@ -0,0 +1,65 @@
 +#ifndef	SLIC_H
 +#define	SLIC_H
@@ -1886,9 +2005,9 @@
 +
 +
 +#endif	/* SLIC_H */
-diff -urNad zaptel-1.0.10/xpp/slic_init.inc /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/slic_init.inc
---- zaptel-1.0.10/xpp/slic_init.inc	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/slic_init.inc	2006-01-03 15:08:39.122220000 +0200
+diff -urNad trunk/xpp/slic_init.inc /tmp/dpep.qIz4nf/trunk/xpp/slic_init.inc
+--- trunk/xpp/slic_init.inc	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/slic_init.inc	2006-01-11 10:12:53.154369000 +0200
 @@ -0,0 +1,65 @@
 +// ----------------------------------==== 8-channel FXS unit initialization ===-----------------------------------------
 +
@@ -1935,7 +2054,7 @@
 +
 +S_(0x000000FF,	0x02,	0x45, 0x0A),	
 +S_(0x000000FF,	0x02,	0x46, 0x0B),	
-+S_(0x000000FF,	0x02,	0x47, 0x00),	
++S_(0x000000FF,	0x02,	0x47, 0x07),	
 +
 +
 +// Setting of SLICs offsets
@@ -1955,24 +2074,25 @@
 +S_(0x000000FF,	0x02,	0x42, 0x06),	
 +// -------------------------------------------------------------
 +
-diff -urNad zaptel-1.0.10/xpp/sync.sh /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/sync.sh
---- zaptel-1.0.10/xpp/sync.sh	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/sync.sh	2006-01-03 15:35:29.050560735 +0200
-@@ -0,0 +1,30 @@
+diff -urNad trunk/xpp/sync.sh /tmp/dpep.qIz4nf/trunk/xpp/sync.sh
+--- trunk/xpp/sync.sh	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/sync.sh	2006-01-11 10:12:40.515108543 +0200
+@@ -0,0 +1,31 @@
 +#!/bin/sh
 +
 +set -e
 +
 +SVN_ROOT=/home/tzafrir/Proj/Svn
-+XORTEL_DIR=$SVN_ROOT/xpp-zaptel/xortel
-+XPP_DIR=$SVN_ROOT/xpp-zaptel/zaptel/xpp
++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 $SVN_ROOT/xpp-zaptel
-+  svn update
++cd $XORTEL_DIR
++  cd ..; svn update; 
 +  cd xortel
-+  make FIRMWARE="$SVN_ROOT/fpgafirmware/init.dat" ../zaptel/xpp/slic_init.inc
++  make FIRMWARE="$FIRMWARE" ../zaptel/xpp/slic_init.inc
 +cd $curdir
 +
 +cp -a $XORTEL_DIR/FPGA_XPD.hex ${TARGET_DIR}/
@@ -1989,9 +2109,9 @@
 +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 -urNad zaptel-1.0.10/xpp/xdefs.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xdefs.h
---- zaptel-1.0.10/xpp/xdefs.h	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xdefs.h	2006-01-03 13:22:53.823218000 +0200
+diff -urNad trunk/xpp/xdefs.h /tmp/dpep.qIz4nf/trunk/xpp/xdefs.h
+--- trunk/xpp/xdefs.h	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/xdefs.h	2006-01-09 18:14:37.000000000 +0200
 @@ -0,0 +1,82 @@
 +#ifndef	XDEFS_H
 +#define	XDEFS_H
@@ -2075,10 +2195,10 @@
 +
 +
 +#endif	/* XDEFS_H */
-diff -urNad zaptel-1.0.10/xpp/xpd.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpd.h
---- zaptel-1.0.10/xpp/xpd.h	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpd.h	2006-01-03 13:22:53.823218000 +0200
-@@ -0,0 +1,294 @@
+diff -urNad trunk/xpp/xpd.h /tmp/dpep.qIz4nf/trunk/xpp/xpd.h
+--- trunk/xpp/xpd.h	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/xpd.h	2006-01-11 10:12:52.381169000 +0200
+@@ -0,0 +1,290 @@
 +#ifndef	XPD_H
 +#define	XPD_H
 +
@@ -2256,9 +2376,8 @@
 +#endif
 +
 +#ifdef CONFIG_PROC_FS
-+	struct proc_dir_entry	*procdir;
-+	struct proc_dir_entry	*procsummary;
-+	struct proc_dir_entry	*proc_ztregister;
++	struct proc_dir_entry	*proc_xbus_dir;
++	struct proc_dir_entry	*proc_xbus_summary;
 +#endif
 +
 +	/* statistics */
@@ -2269,7 +2388,7 @@
 +
 +typedef enum xpd_direction {
 +	TO_PHONE = 0,
-+	TO_TRUNK = 1,
++	TO_PSTN = 1,
 +} xpd_direction_t;
 +
 +#define	LINE_BITS	(sizeof(xpp_line_t)*8)
@@ -2318,11 +2437,12 @@
 +	struct zt_chan	*chans;
 +	int channels;
 +	xpd_type_t	type;
-+	xpd_direction_t	direction;		/* TO_PHONE, TO_LINE */
++	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	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 */
@@ -2335,27 +2455,23 @@
 +	spinlock_t	lock;
 +	atomic_t	open_counter;		/* Number of open channels */
 +
-+	int flags;
-+	enum {
-+		XPD_STATE_OFF = 0x01,
-+		XPD_STATE_NOREPLY = 0x02,
-+		XPD_STATE_ACTIVE = 0x03,
-+		XPD_STATE_ZAPTEL_ERR = 0x04,
-+	} state;
++	int		flags;
 +
 +	unsigned int	board_flags;
 +#define	XPD_BOARD_LOOPBACK	1
 +
 +#ifdef CONFIG_PROC_FS
-+	struct proc_dir_entry	*xpd_proc;
-+	struct proc_dir_entry	*xpd_slic;
++	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];
 +
-+	xops_t		*xops;		/* Card level operations */
-+	void		*card;		/* Card level private data */
++	const xops_t	*xops;		/* Card level operations */
++	void		*priv;		/* Card level private data */
++	atomic_t	card_present;
 +
 +	unsigned int	recv_errors;
 +	unsigned int	seq_errors;
@@ -2373,9 +2489,9 @@
 +#endif
 +
 +#endif	/* XPD_H */
-diff -urNad zaptel-1.0.10/xpp/xpp_fxloader /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_fxloader
---- zaptel-1.0.10/xpp/xpp_fxloader	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_fxloader	2006-01-03 13:22:53.823218000 +0200
+diff -urNad trunk/xpp/xpp_fxloader /tmp/dpep.qIz4nf/trunk/xpp/xpp_fxloader
+--- trunk/xpp/xpp_fxloader	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/xpp_fxloader	2006-01-09 18:14:37.000000000 +0200
 @@ -0,0 +1,11 @@
 +#!/bin/bash
 +
@@ -2388,23 +2504,29 @@
 +	fxload -t fx2 -D "$DEVICE" -I "$FIRMWARE" || exit 1
 +fi
 +
-diff -urNad zaptel-1.0.10/xpp/xpp_fxloader.usermap /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_fxloader.usermap
---- zaptel-1.0.10/xpp/xpp_fxloader.usermap	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_fxloader.usermap	2006-01-03 13:22:53.823218000 +0200
+diff -urNad trunk/xpp/xpp_fxloader.usermap /tmp/dpep.qIz4nf/trunk/xpp/xpp_fxloader.usermap
+--- trunk/xpp/xpp_fxloader.usermap	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/xpp_fxloader.usermap	2006-01-09 18:14:37.000000000 +0200
 @@ -0,0 +1,2 @@
 +# 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 -urNad zaptel-1.0.10/xpp/xpp_modprobe /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_modprobe
---- zaptel-1.0.10/xpp/xpp_modprobe	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_modprobe	2006-01-03 13:22:53.823218000 +0200
-@@ -0,0 +1,4 @@
-+options zaptel debug=1
-+options wcfxo debug=1
-+options xpp print_dbg=1 ignore_xpds=0x00 softloop_xpds=0x00 enabled_channels=0x000000FF pcm_gen=0x00000000 max_queue_len=20000
-+options usb_test vendor=0x4B4 product=0x8613 altsetting=1 innum=2 outnum=4
-diff -urNad zaptel-1.0.10/xpp/xpp_proto.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_proto.c
---- zaptel-1.0.10/xpp/xpp_proto.c	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_proto.c	2006-01-03 14:01:24.370308595 +0200
+diff -urNad trunk/xpp/xpp_modprobe /tmp/dpep.qIz4nf/trunk/xpp/xpp_modprobe
+--- trunk/xpp/xpp_modprobe	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/xpp_modprobe	2006-01-11 10:12:52.381169000 +0200
+@@ -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 
++
++# 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 -urNad trunk/xpp/xpp_proto.c /tmp/dpep.qIz4nf/trunk/xpp/xpp_proto.c
+--- trunk/xpp/xpp_proto.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/xpp_proto.c	2006-01-11 10:12:40.515108543 +0200
 @@ -0,0 +1,1044 @@
 +#include <linux/module.h>
 +#include <linux/delay.h>	/* for udelay */
@@ -3450,9 +3572,9 @@
 +EXPORT_SYMBOL(packet_receive);
 +EXPORT_SYMBOL(proc_xpd_slic_read);
 +EXPORT_SYMBOL(proc_xpd_slic_write);
-diff -urNad zaptel-1.0.10/xpp/xpp_proto.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_proto.h
---- zaptel-1.0.10/xpp/xpp_proto.h	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_proto.h	2006-01-03 14:01:24.370308595 +0200
+diff -urNad trunk/xpp/xpp_proto.h /tmp/dpep.qIz4nf/trunk/xpp/xpp_proto.h
+--- trunk/xpp/xpp_proto.h	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/xpp_proto.h	2006-01-11 10:12:40.515108543 +0200
 @@ -0,0 +1,188 @@
 +#ifndef	XPP_PROTO_H
 +#define	XPP_PROTO_H
@@ -3642,10 +3764,10 @@
 +#endif
 +
 +#endif	/* XPP_PROTO_H */
-diff -urNad zaptel-1.0.10/xpp/xpp_usb.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_usb.c
---- zaptel-1.0.10/xpp/xpp_usb.c	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_usb.c	2006-01-03 13:22:53.823218000 +0200
-@@ -0,0 +1,869 @@
+diff -urNad trunk/xpp/xpp_usb.c /tmp/dpep.qIz4nf/trunk/xpp/xpp_usb.c
+--- trunk/xpp/xpp_usb.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/xpp_usb.c	2006-01-09 18:14:37.000000000 +0200
+@@ -0,0 +1,873 @@
 +/*
 + * Written by Oron Peled <oron at actcom.co.il>
 + * Copyright (C) 2004-2005, Xorcom
@@ -3689,7 +3811,7 @@
 +#include "xproto.h"
 +#include "xpp_zap.h"
 +
-+static char revision[] = "$Revision: 159 $";
++static const char revision[] = "$Revision: 181 $";
 +
 +DEF_PARM(int, print_dbg, 1, "Print DBG statements");	/* must be before zap_debug.h */
 +
@@ -3704,8 +3826,10 @@
 +#define	PROC_USBXPP_SUMMARY	"xpp_usb"
 +#endif
 +
++#ifdef	DEBUG_PCM_TIMING
 +static cycles_t	stamp_last_pcm_read;
 +static cycles_t accumulate_diff;
++#endif
 +
 +struct xusb_model_info;
 +
@@ -3884,7 +4008,7 @@
 +	if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE)) {
 +		XUSB_COUNTER(xusb, PCM_WRITES)++;
 +
-+#if 1
++#ifdef	DEBUG_PCM_TIMING
 +		/*
 +		 * DEBUG: high-res timing of PCM_READ to PCM_WRITE
 +		 */
@@ -4201,7 +4325,7 @@
 +
 +#ifdef CONFIG_PROC_FS
 +	DBG("Creating proc entry " PROC_USBXPP_SUMMARY " in bus proc dir.\n");
-+	procsummary = create_proc_read_entry(PROC_USBXPP_SUMMARY, 0644, xbus->procdir,
++	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) {
@@ -4266,8 +4390,8 @@
 +	xusb_array[i] = NULL;
 +
 +#ifdef CONFIG_PROC_FS
-+	if(xbus->procdir) {
-+		remove_proc_entry(PROC_USBXPP_SUMMARY, xbus->procdir);
++	if(xbus->proc_xbus_dir) {
++		remove_proc_entry(PROC_USBXPP_SUMMARY, xbus->proc_xbus_dir);
 +	}
 +#endif
 +	xusb->present = 0;
@@ -4362,7 +4486,7 @@
 +	if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_READ)) {
 +		XUSB_COUNTER(xusb, PCM_READS)++;
 +
-+#if 1
++#ifdef	DEBUG_PCM_TIMING
 +		/*
 +		 * DEBUG: high-res timing of PCM_READ to PCM_WRITE
 +		 */
@@ -4468,8 +4592,6 @@
 +	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"
@@ -4484,12 +4606,16 @@
 +		xusb->ep_out.epnum,
 +		xusb->ep_out.max_size
 +	);
++#ifdef	DEBUG_PCM_TIMING
 +	len += sprintf(page + len, "\nstamp_last_pcm_read=%lld accumulate_diff=%lld\n", stamp_last_pcm_read, accumulate_diff);
++#endif
 +	len += sprintf(page + len, "\nCOUNTERS:\n");
 +	for(i = 0; i < XUSB_COUNTER_MAX; i++) {
 +		len += sprintf(page + len, "\t%-15s = %d\n", xusb_counters[i].name, xusb->counters[i]);
 +	}
++#if 0
 +	len += sprintf(page + len, "<-- len=%d\n", len);
++#endif
 +	spin_unlock_irqrestore(&xusb_lock, flags);
 +out:
 +	if (len <= off+count)
@@ -4511,14 +4637,14 @@
 +MODULE_DESCRIPTION("XPP USB Driver");
 +MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
 +MODULE_LICENSE("GPL");
-+MODULE_VERSION("$Id: xpp_usb.c 159 2006-01-03 08:49:05Z oron $");
++MODULE_VERSION("$Id: xpp_usb.c 181 2006-01-05 17:13:28Z oron $");
 +
 +module_init(xpp_usb_init);
 +module_exit(xpp_usb_cleanup);
-diff -urNad zaptel-1.0.10/xpp/xpp_zap.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_zap.c
---- zaptel-1.0.10/xpp/xpp_zap.c	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_zap.c	2006-01-03 15:08:38.089954000 +0200
-@@ -0,0 +1,2273 @@
+diff -urNad trunk/xpp/xpp_zap.c /tmp/dpep.qIz4nf/trunk/xpp/xpp_zap.c
+--- trunk/xpp/xpp_zap.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/xpp_zap.c	2006-01-11 10:12:52.381169000 +0200
+@@ -0,0 +1,2312 @@
 +/*
 + * Written by Oron Peled <oron at actcom.co.il>
 + * Copyright (C) 2004, Xorcom
@@ -4562,7 +4688,7 @@
 +#include "xproto.h"
 +#include "xpp_zap.h"
 +
-+static char revision[] = "$Revision: 167 $";
++static char revision[] = "$Revision: 185 $";
 +
 +#ifdef CONFIG_PROC_FS
 +struct proc_dir_entry *xpp_procdir = NULL;
@@ -4570,8 +4696,8 @@
 +#define	PROC_XBUSES		"xbuses"
 +#define	PROC_SYNC		"sync"
 +#define	PROC_XBUS_SUMMARY	"summary"
-+#define	PROC_XBUS_ZTREGISTER	"zt_registration"
-+#define	PROC_SLIC_FNAME		"%s.slic"
++#define	PROC_XPD_ZTREGISTER	"zt_registration"
++#define	PROC_XPD_SUMMARY	"summary"
 +#endif
 +
 +#undef	WITH_RBS
@@ -4583,14 +4709,6 @@
 +#define	LED_BLINK_PERIOD	(HZ/8)
 +#define	SAMPLE_TICKS		10000
 +
-+#define	N_(x)	[ x] = #x
-+static const char *xpd_type_names[] = {
-+	N_(XPD_TYPE_FXO),
-+	N_(XPD_TYPE_FXS),
-+	N_(XPD_TYPE_NOMODULE),
-+};
-+#undef N_
-+
 +static spinlock_t		xbuses_lock = SPIN_LOCK_UNLOCKED;
 +static xbus_t			*xbuses_array[MAX_BUSES] = {};
 +static int			bus_count = 0;
@@ -4598,6 +4716,7 @@
 +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);
 +
@@ -4623,16 +4742,123 @@
 +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);
-+/* global workqueue. needs to be global? */
-+struct workqueue_struct *xpd_init_workqueue=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 
@@ -4702,7 +4928,7 @@
 +		for(j = 0; j < MAX_XPDS; j++) {
 +			xpd_t	*xpd = xbus->xpds[j];
 +			if(xpd)
-+				CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, xpd, 1, (the_xpd != NULL));
++				CALL_XMETHOD(SYNC_SOURCE, xbus, xpd, 1, (the_xpd != NULL));
 +		}
 +	}
 +}
@@ -4767,13 +4993,14 @@
 +
 +			if(!xpd)
 +				continue;
++			if(!atomic_read(&xpd->card_present))
++				continue;
 +			xpd->timer_count++;
-+			if(xpd->state != XPD_STATE_ACTIVE)
-+				continue;
++			CALL_XMETHOD(card_tick, xbus, xpd);
 +			if(!SPAN_REGISTERED(xpd))
 +				continue;
 +			xpd_blink_leds(xpd);
-+			if(xpd->direction == TO_TRUNK)
++			if(xpd->direction == TO_PSTN)
 +				xpp_ring_generate(xpd);
 +			xpp_transmitprep(xpd);
 +			xpp_receiveprep(xpd);
@@ -4785,60 +5012,32 @@
 +#error "xpp_timer must be sampled EXACTLY 1000/per second"
 +#endif
 +
-+/**
-+ * Process a registration request.
-+ *
-+ * A new xpd structure is created when we get a device description packet.
-+ * This happens from a timer interrupt context and we can't call zt_register 
-+ * from there.
-+ *
-+ * Thus the xpd structure is generated and registerted with xpp. However the
-+ * registration to zaptel is done "off-line" by posting a registration to the
-+ * "reg" workqueue that calls this function.
-+ */
-+void xpd_initialize(void *data)
++static void xpd_cleanup(xpd_t *xpd)
 +{
-+	xpd_t		*xpd = (xpd_t *)data;
-+	xbus_t		*xbus;
-+	
-+	if (!xpd) {
-+		ERR("%s: called with a NULL xpd\n", __FUNCTION__);
++	xbus_t	*xbus = NULL;
++
++	if(!xpd)
 +		return;
-+	}
 +	xbus = xpd->xbus;
-+#ifdef	CONFIG_PROC_FS
-+	DBG("Creating xpd proc file %s.\n", xpd->xpdname);
-+	xpd->xpd_proc = create_proc_read_entry(xpd->xpdname, 0644, xbus->procdir,
-+			xpd_read_proc, xpd);
-+	if(!xpd->xpd_proc) {
-+		ERR("Failed to create proc file for xpd %s\n", xpd->xpdname);
-+		return;
-+	}
-+	{
-+		char fname[NAME_MAX];
-+
-+		snprintf(fname, NAME_MAX, PROC_SLIC_FNAME, xpd->xpdname);
-+		DBG("Creating xpd slic file %s.\n", fname);
-+		xpd->xpd_slic = create_proc_entry(fname, 0644, xbus->procdir);
-+		if(!xpd->xpd_slic) {
-+			ERR("Failed to create proc file for SLIC xpd %s\n", fname);
-+			return;
++	xpd_card_disable(xpd);
++	DBG("%s/%s\n", xbus->busname, xpd->xpdname);
++#ifdef CONFIG_PROC_FS
++	if(xpd->proc_xpd_dir) {
++		if(xpd->proc_xpd_summary) {
++			DBG("Removing proc '%s' for %s/%s\n", PROC_XPD_SUMMARY, xbus->busname, xpd->xpdname);
++			remove_proc_entry(PROC_XPD_SUMMARY, xpd->proc_xpd_dir);
++			xpd->proc_xpd_summary = NULL;
 +		}
-+		xpd->xpd_slic->write_proc = proc_xpd_slic_write;
-+		xpd->xpd_slic->read_proc = proc_xpd_slic_read;
-+		xpd->xpd_slic->data = xpd;
++		if(xpd->proc_xpd_ztregister) {
++			DBG("Removing proc '%s' for %s/%s\n", PROC_XPD_ZTREGISTER, xbus->busname, xpd->xpdname);
++			remove_proc_entry(PROC_XPD_ZTREGISTER, xpd->proc_xpd_dir);
++			xpd->proc_xpd_ztregister = NULL;
++		}
++		DBG("Removing proc directory for %s/%s\n", xbus->busname, xpd->xpdname);
++		remove_proc_entry(xpd->xpdname, xbus->proc_xbus_dir);
++		xpd->proc_xpd_dir = NULL;
 +	}
 +#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);
-+	xpd_zaptel_register(xpd);
 +}
 +
 +void init_xbus_packet_queue(packet_queue_t *q, const char name[])
@@ -4972,10 +5171,12 @@
 +	sim = &xbus->sim[xpd->id];
 +#endif
 +	channels = xpd->channels;
-+	len += sprintf(page + len, "%s (%s ,state=%d, span_registered=%s)%s\n"
++	len += sprintf(page + len, "%s (%s ,card %s, span_registered=%s)%s\n"
 +			"timer_count: %d span->mainttimer=%d\n"
 +			,
-+			xpd->xpdname, xpd_type_names[xpd->type], xpd->state, (SPAN_REGISTERED(xpd))?"yes":"no",
++			xpd->xpdname, xproto_name(xpd->type),
++			(atomic_read(&xpd->card_present))?"present":"missing",
++			(SPAN_REGISTERED(xpd))?"yes":"no",
 +			(xpd == sync_master) ? " SYNCER" : "",
 +			xpd->timer_count, xpd->span.mainttimer
 +			);
@@ -4988,6 +5189,10 @@
 +	for(i = 0; i < channels; 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++) {
++		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++) {
 +		len += sprintf(page + len, "%d ", IS_SET(xpd->hookstate, i));
@@ -5055,52 +5260,65 @@
 +
 +#endif
 +
-+xpd_t *xpd_new(xbus_t *xbus, int xpd_num, xpd_type_t type, byte revision)
++/*
++ * xpd_alloc - Allocator for new XPD's
++ *
++ */
++xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, int channels, byte revision)
 +{
-+	unsigned long	flags;
 +	xpd_t		*xpd = NULL;
-+	xops_t		*xops;
++	size_t		alloc_size = sizeof(xpd_t) + privsize;
 +
-+	spin_lock_irqsave(&xbus->lock, flags);
 +	INFO("New XPD #%d (Revision %d.%d) detected on xbus %s\n",
 +			xpd_num, revision / 10, revision % 10, xbus->busname);
 +	if(!VALID_XPD_NUM(xpd_num)) {
 +		ERR("%s: illegal xpd id = %d\n", __FUNCTION__, xpd_num);
 +		goto err;
 +	}
-+	if((xops = get_xops(type)) == NULL) {
-+		ERR("%s: no xops for type=%d\n", __FUNCTION__, type);
++	if(channels > CHANNELS_PERXPD) {
++		ERR("%s: too many channels %d for xpd #%d\n", __FUNCTION__, channels, xpd_num);
 +		goto err;
 +	}
-+	if((xpd = kmalloc(sizeof(xpd_t), GFP_ATOMIC)) == NULL) {
-+		ERR("%s: Unable to allocate memory for xpd\n", __FUNCTION__);
++
++	if((xpd = kmalloc(alloc_size, GFP_KERNEL)) == NULL) {
++		ERR("%s: Unable to allocate memory for xpd #%d\n", __FUNCTION__, xpd_num);
 +		goto err;
 +	}
-+	memset(xpd, 0, sizeof(xpd_t));
++	memset(xpd, 0, alloc_size);
++	xpd->priv = (byte *)xpd + sizeof(xpd_t);
 +
 +	spin_lock_init(&xpd->lock);
-+	xpd->xops = xops;
 +	xpd->xbus = xbus;
 +	xpd->id = xpd_num;
++	xpd->channels = channels;
 +	xpd->chans = NULL;
-+	xpd->state = XPD_STATE_OFF;
++	atomic_set(&xpd->card_present, 0);
 +	snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%d", xpd_num);
 +	xpd->hookstate = 0x0;	/* ONHOOK */
-+	xpd->type = type;
++	xpd->type = proto_table->type;
++	xpd->xops = &proto_table->xops;
 +	xpd->enabled_chans = enabled_channels[xpd_num];
 +	xpd->digital_outputs = 0;
++	xpd->digital_inputs = 0;
 +	atomic_set(&xpd->open_counter, 0);
 +
-+	INIT_WORK(&xpd->xpd_post_init, xpd_initialize, xpd);
-+
-+	CALL_XMETHOD(card_new, xbus, xpd, revision);
-+	if(xpd_setup(xpd) != 0)
++	xpd->chans = kmalloc(sizeof(struct zt_chan)*xpd->channels, GFP_KERNEL);
++	if (xpd->chans == NULL) {
++		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) {
++		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;
 +
-+	spin_unlock_irqrestore(&xbus->lock, flags);
 +	return xpd;
 +err:
-+	spin_unlock_irqrestore(&xbus->lock, flags);
 +	if(xpd->chans)
 +		kfree((void *)xpd->chans);
 +	if(xpd->writechunk)
@@ -5110,44 +5328,12 @@
 +	return NULL;
 +}
 +
-+int xpd_setup(xpd_t *xpd)
++static void xpd_card_disable(xpd_t *xpd)
 +{
-+	xpd->chans = kmalloc(sizeof(struct zt_chan)*xpd->channels, GFP_ATOMIC);
-+	if (xpd->chans == NULL) {
-+		ERR("%s: Unable to allocate channels\n", __FUNCTION__);
-+		return -ENOMEM;
-+	}
-+	/* 8 channels, double buffer, Read/Write */
-+	int need = ZT_MAX_CHUNKSIZE * CHANNELS_PERXPD * 2 * 2;
-+	if((xpd->writechunk = kmalloc(need, GFP_ATOMIC)) == NULL) {
-+		ERR("%s: Unable to allocate memory for writechunks\n", __FUNCTION__);
-+		kfree(xpd->chans);
-+		xpd->chans = NULL;
-+		return -ENOMEM;
-+	}
-+	/* Initialize Write/Buffers to all blank data */
-+	memset((void *)xpd->writechunk, 0x00, need);
-+	xpd->readchunk = xpd->writechunk + ZT_CHUNKSIZE * CHANNELS_PERXPD * 2;
-+
-+#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
-+
-+	DBG("Queueing xpd_post_init for xpd %d\n", xpd->id);
-+	if(!queue_work(xpd_init_workqueue, &xpd->xpd_post_init)) {
-+		ERR("Failed to queue xpd_post_init work\n");
-+		return -EINVAL;
-+	}
-+	return 0;
++	BUG_ON(!xpd);
++	atomic_set(&xpd->card_present, 0);
++	if(SPAN_REGISTERED(xpd))
++		update_xpd_status(xpd, ZT_ALARM_NOTOPEN);
 +}
 +
 +void xpd_remove(xpd_t *xpd)
@@ -5157,31 +5343,22 @@
 +	BUG_ON(!xpd);
 +	xbus = xpd->xbus;
 +	INFO("Remove XPD #%d from xbus=%s\n", xpd->id, xbus->busname);
-+	xpd->state = XPD_STATE_OFF;
++#if 0
++	// TODO: elect a new sync master
++	if(sync_master == xpd)
++		set_sync_master(NULL);
++#endif
 +	xpd_zaptel_unregister(xpd);
-+#ifdef CONFIG_PROC_FS
-+	if(xpd->xpd_proc) {
-+		DBG("Removing proc entry %s\n", xpd->xpdname);
-+		remove_proc_entry(xpd->xpdname, xbus->procdir);
-+	}
-+	if(xpd->xpd_slic) {
-+		char fname[NAME_MAX];
-+
-+		snprintf(fname, NAME_MAX, PROC_SLIC_FNAME, xpd->xpdname);
-+		DBG("Removing proc entry %s\n", fname);
-+		remove_proc_entry(fname, xbus->procdir);
-+	}
-+#endif
 +	xbus->xpds[xpd->id] = NULL;
 +	list_del(&xpd->xpd_list);
 +	xbus->num_xpds--;
-+	cancel_delayed_work(&xpd->xpd_post_init);
 +	CALL_XMETHOD(card_remove, xbus, xpd);
++	xpd_cleanup(xpd);
 +	kfree((void *)xpd->writechunk);
 +	kfree(xpd);
 +}
 +
-+void update_xpd_status(xpd_t *xpd, int alarm_flag)
++static void update_xpd_status(xpd_t *xpd, int alarm_flag)
 +{
 +	struct zt_span *span = &xpd->span;
 +
@@ -5191,12 +5368,8 @@
 +	}
 +	switch (alarm_flag) {
 +		case ZT_ALARM_NONE:
-+			xpd->state = XPD_STATE_ACTIVE;
 +			xpd->last_response = jiffies;
 +			break;
-+		case ZT_ALARM_RED:
-+			xpd->state = XPD_STATE_NOREPLY;
-+			break;
 +		default:
 +			// Nothing
 +			break;
@@ -5208,6 +5381,31 @@
 +	DBG("Update XPD alarms: %s -> %02X\n", xpd->span.name, alarm_flag);
 +}
 +
++void phone_hook(xpd_t *xpd, int channo, bool offhook)
++{
++	struct zt_chan *chan = &xpd->span.chans[channo];
++
++	if(offhook && !IS_SET(xpd->hookstate, channo)) {		// OFFHOOK
++		DBG("OFFHOOK: channo=%d\n", chan->channo);
++		xpd->ringing[channo] = 0;
++		BIT_SET(xpd->hookstate, channo);
++		zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
++		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);
++		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;
@@ -5215,7 +5413,7 @@
 +
 +	spin_lock_irqsave(&xpd->lock, flags);
 +	if(xpd->direction != TO_PHONE) {
-+		ERR("%s: %s: Only FXS can report hookstate changes\n", __FUNCTION__, xpd->xpdname);
++		ERR("%s: %s: Only PHONE can report hookstate changes\n", __FUNCTION__, xpd->xpdname);
 +		goto out;
 +	}
 +	if(!SPAN_REGISTERED(xpd)) {
@@ -5224,22 +5422,7 @@
 +	}
 +	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++) {
-+		struct zt_chan *chan = &xpd->span.chans[i];
-+		if(IS_SET(fxs_off_hook, i) && !IS_SET(xpd->hookstate, i)) {		// OFFHOOK
-+			DBG("OFFHOOK: channo=%d\n", chan->channo);
-+			xpd->ringing[i] = 0;
-+			BIT_SET(xpd->hookstate, i);
-+			zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
-+			CALL_XMETHOD(CHAN_POWER, xpd->xbus, xpd, BIT(i), 0);		// Power down (prevent overheating!!!)
-+			CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 1);
-+		} else if(!IS_SET(fxs_off_hook, i) && IS_SET(xpd->hookstate, i)) {	// ONHOOK
-+			DBG("ONHOOK channo=%d\n", chan->channo);
-+			xpd->ringing[i] = 0;
-+			BIT_CLR(xpd->hookstate, i);
-+			zt_hooksig(chan, ZT_RXSIG_ONHOOK);
-+			CALL_XMETHOD(CHAN_POWER, xpd->xbus, xpd, BIT(i), 0);		// Power down (prevent overheating!!!)
-+			CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 0);
-+		}
++		phone_hook(xpd, i, IS_SET(fxs_off_hook, i));
 +	}
 +out:
 +	spin_unlock_irqrestore(&xpd->lock, flags);
@@ -5254,7 +5437,7 @@
 +
 +	spin_lock_irqsave(&xpd->lock, flags);
 +	for(i = 0; i < xpd->channels; i++) {
-+		if(IS_SET(xpd->digital_outputs, i))
++		if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
 +			continue;
 +		if(xpd->ringing[i]) {
 +			// led state is toggled
@@ -5281,7 +5464,7 @@
 +	BUG_ON(!xpd);
 +
 +	spin_lock_irqsave(&xpd->lock, flags);
-+	if(xpd->direction != TO_TRUNK && ((bug_counter++ % 1000) == 0)) {
++	if(xpd->direction != TO_PSTN && ((bug_counter++ % 1000) == 0)) {
 +		ERR("%s: %s: Only FXO can report ring changes\n", __FUNCTION__, xpd->xpdname);
 +		goto out;
 +	}
@@ -5334,7 +5517,7 @@
 +{
 +	int	i;
 +
-+	NOTICE("Reseting counters of %s\n", xbus->busname);
++	DBG("Reseting counters of %s\n", xbus->busname);
 +	for(i = 0; i < XBUS_COUNTER_MAX; i++) {
 +		xbus->counters[i] = 0;
 +	}
@@ -5364,11 +5547,11 @@
 +		goto out;
 +	spin_lock_irqsave(&xbus->lock, flags);
 +
-+	len += sprintf(page + len, "%s: HW=%s bus_type=%d connected=%s\n",
++	len += sprintf(page + len, "%s: CONNECTOR=%s STATUS=%s bus_type=%d\n",
 +			xbus->busname,
 +			xbus->busdesc,
-+			xbus->bus_type,
-+			(xbus->hardware_exists) ? "yes" : "no"
++			(xbus->hardware_exists) ? "connected" : "missing",
++			xbus->bus_type
 +		      );
 +	len += sprintf(page + len, "open_counter=%d packet_count=%d\n",
 +			xbus->open_counter,
@@ -5407,16 +5590,20 @@
 +{
 +	int len = 0;
 +
++	len += sprintf(page + len, "# To modify sync source write into this file:\n");
++	len += sprintf(page + len, "#     HOST        - For host based sync\n");
++	len += sprintf(page + len, "#     0 0         - XBUS-0/XPD-0 provide sync\n");
++	len += sprintf(page + len, "#     m n         - XBUS-m/XPD-n provide sync\n");
 +	if(!sync_master)
 +		len += sprintf(page + len, "HOST\n");
 +	else
 +		len += sprintf(page + len, "%s/%s\n", sync_master->xbus->busname, sync_master->xpdname);
-+	len += sprintf(page + len, "xpp_timer_count=%d\n", xpp_timer_count);
++	len += sprintf(page + len, "tick: #%d\n", xpp_timer_count);
 +	unsigned int xpp_timer_rate = 0;
 +	unsigned int 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, "xpp_timer_rate=%d\n", xpp_timer_rate);
++		len += sprintf(page + len, "tick rate: %4d/second (average over %d seconds)\n", xpp_timer_rate, SAMPLE_TICKS/HZ);
 +	}
 +	if (len <= off+count)
 +		*eof = 1;
@@ -5468,26 +5655,17 @@
 +	return count;
 +}
 +
-+int proc_xbus_ztregister_read(char *page, char **start, off_t off, int count, int *eof, void *data)
++int proc_xpd_ztregister_read(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;
++	int		len = 0;
++	unsigned long	flags;
++	xpd_t		*xpd = data;
 +
-+	if(!xbus)
-+		goto out;
-+	spin_lock_irqsave(&xbus->lock, flags);
++	BUG_ON(!xpd);
++	spin_lock_irqsave(&xpd->lock, flags);
 +
-+	len += sprintf(page + len, "# To (un)register an XPD write into this file: <ID> <1/0>\n");
-+	len += sprintf(page + len, "# ID\tExists\tRegistered\n");
-+	for(i = 0; i < MAX_XPDS; i++) {
-+		xpd_t	*xpd = xbus->xpds[i];
-+		bool	registered = xpd && SPAN_REGISTERED(xpd);
-+		len += sprintf(page + len, "%d\t%s\t%s\n", i, (xpd)?"yes":"no", (registered)?"yes":"no");
-+	}
-+	spin_unlock_irqrestore(&xbus->lock, flags);
-+out:
++	len += sprintf(page + len, "%d\n", SPAN_REGISTERED(xpd));
++	spin_unlock_irqrestore(&xpd->lock, flags);
 +	if (len <= off+count)
 +		*eof = 1;
 +	*start = page + off;
@@ -5499,31 +5677,25 @@
 +	return len;
 +}
 +
-+static int proc_xbus_ztregister_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
++static int proc_xpd_ztregister_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
 +{
-+	xbus_t		*xbus = data;
-+	xpd_t		*xpd;
-+	int		xpd_num;
++	xpd_t		*xpd = data;
 +	const int	NUM_SIZE = 100;
 +	char		buf[NUM_SIZE];
 +	bool		zt_reg;
 +	int		ret;
 +
-+	BUG_ON(!xbus);
++	BUG_ON(!xpd);
 +	if(count >= NUM_SIZE)
 +		return -EINVAL;
 +	if(copy_from_user(buf, buffer, count))
 +		return -EFAULT;
 +	buf[count] = '\0';
-+	ret = sscanf(buf, "%d %d", &xpd_num, &zt_reg);
-+	if(ret != 2)
++	ret = sscanf(buf, "%d", &zt_reg);
++	if(ret != 1)
 +		return -EINVAL;
-+	xpd = xpd_of(xbus, xpd_num);
-+	if(!xpd) {
-+		ERR("%s: XPD number %d does not exist\n", __FUNCTION__, xpd_num);
-+		return -ENXIO;
-+	}
-+	DBG("%s: %s: xpd #%d %s\n", __FUNCTION__, xbus->busname, xpd_num, (zt_reg) ? "register" : "unregister");
++	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
@@ -5531,14 +5703,6 @@
 +	return (ret < 0) ? ret : count;
 +}
 +
-+int xpd_slic_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
-+{
-+	xpd_t		*xpd = data;
-+
-+	BUG_ON(!xpd);
-+	return count;
-+}
-+
 +#endif
 +
 +/**
@@ -5620,9 +5784,8 @@
 +				DBG("  Skipping XPD #%d is MISSING\n", id);
 +				continue;
 +			}
-+			DBG("  XPD #%d STATE = %d\n", id, xpd->state);
-+			if(xpd->state != XPD_STATE_ACTIVE) {
-+				DBG("  Skipping XPD #%d not in ACTIVE state\n", id);
++			if(!atomic_read(&xpd->card_present)) {
++				DBG("  Skipping XPD #%d not present\n", id);
 +				continue;
 +			}
 +			if(time_after(xpd->last_response+20, jiffies)) {
@@ -5724,9 +5887,7 @@
 +			ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i);
 +			continue;
 +		}
-+		if (!SPAN_REGISTERED(xpd))
-+			continue;
-+		update_xpd_status(xpd, ZT_ALARM_NOTOPEN);
++		xpd_card_disable(xpd);
 +	}
 +	down_write(&xbus->in_use);
 +	DBG("%s (deactivated)\n", xbus->busname);
@@ -5740,20 +5901,15 @@
 +{
 +	BUG_ON(!xbus);
 +#ifdef CONFIG_PROC_FS
-+	if(xbus->procdir) {
-+		if(xbus->procsummary) {
-+			DBG("Removing proc entry " PROC_XBUS_SUMMARY ".\n");
-+			remove_proc_entry(PROC_XBUS_SUMMARY, xbus->procdir);
-+			xbus->procsummary = NULL;
++	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_ztregister) {
-+			DBG("Removing proc entry " PROC_XBUS_ZTREGISTER ".\n");
-+			remove_proc_entry(PROC_XBUS_ZTREGISTER, xbus->procdir);
-+			xbus->proc_ztregister = NULL;
-+		}
-+		DBG("Removing proc entry %s.\n",xbus->busname);
++		DBG("Removing proc directory %s\n", xbus->busname);
 +		remove_proc_entry(xbus->busname, xpp_procdir);
-+		xbus->procdir = NULL;
++		xbus->proc_xbus_dir = NULL;
 +	}
 +#endif
 +	kfree(xbus);
@@ -5809,28 +5965,19 @@
 +	xbus_reset_counters(xbus);
 +#ifdef CONFIG_PROC_FS
 +	DBG("Creating xbus proc directory %s.\n",xbus->busname);
-+	xbus->procdir = proc_mkdir(xbus->busname, xpp_procdir);
-+	if(!xbus->procdir) {
++	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->procsummary = create_proc_read_entry(PROC_XBUS_SUMMARY, 0644, xbus->procdir,
++	xbus->proc_xbus_summary = create_proc_read_entry(PROC_XBUS_SUMMARY, 0444, xbus->proc_xbus_dir,
 +			xbus_read_proc, xbus);
-+	if (!xbus->procsummary) {
++	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_ztregister = create_proc_entry(PROC_XBUS_ZTREGISTER, 0644, xbus->procdir);
-+	if (!xbus->proc_ztregister) {
-+		ERR("Failed to create '%s' proc file for xbus %s\n", PROC_XBUS_ZTREGISTER, xbus->busname);
-+		err = -EIO;
-+		goto nobus;
-+	}
-+	xbus->proc_ztregister->data = xbus;
-+	xbus->proc_ztregister->read_proc = proc_xbus_ztregister_read;
-+	xbus->proc_ztregister->write_proc = proc_xbus_ztregister_write;
 +#endif
 +	return xbus;
 +nobus:
@@ -5864,7 +6011,7 @@
 +		xpd_t *xpd = xpd_of(xbus, i);
 +
 +		if(xpd) {
-+			xops_t	*xops = xpd->xops;
++			const xops_t	*xops = xpd->xops;
 +
 +			if(xpd->id != i) {
 +				ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i);
@@ -5872,7 +6019,6 @@
 +			}
 +			BUG_ON(!xops);
 +			DBG("  Removing xpd id=%d\n", xpd->id);
-+			BUG_ON(!xops->card_remove);
 +			xpd_remove(xpd);
 +		}
 +		xbus->xpds[i] = NULL;
@@ -5929,7 +6075,7 @@
 +		}
 +		w += ZT_CHUNKSIZE;
 +	}
-+	if(xpd->hookstate != 0 || sync_master == xpd) {
++	if(xpd->hookstate != 0 || sync_master == xpd || !sync_master) {
 +		ret = CALL_XMETHOD(PCM_WRITE, xpd->xbus, xpd, xpd->hookstate, writechunk);
 +		if(ret < 0) {
 +			DBG("failed to write PCM %d\n", ret);
@@ -6101,10 +6247,14 @@
 +
 +	if (txsig == ZT_TXSIG_START) {
 +		if(xpd->direction == TO_PHONE) {
-+			// An FXS line: ZT_START will be treated as ZT_RING
-+			DBG("Got ZT_START for FXS channel %d, treated as ZT_RING\n", pos);
++			// 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);
@@ -6118,7 +6268,7 @@
 +				return ret;
 +			}
 +			return ret;
-+		} else {	/* TO_TRUNK */
++		} 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;
@@ -6133,6 +6283,10 @@
 +			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);
@@ -6155,6 +6309,10 @@
 +		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);
@@ -6201,6 +6359,10 @@
 +		 * 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);
@@ -6235,7 +6397,7 @@
 +			// Fall through
 +		case ZT_OFFHOOK:
 +			if(xpd->direction == TO_PHONE) {
-+				DBG("ZT_OFFHOOK: %s hookstate=0x%04X -- ignoring (FXS)\n", chan->name, xpd->hookstate);
++				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);
@@ -6256,6 +6418,10 @@
 +		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);
@@ -6389,18 +6555,17 @@
 +{
 +	BUG_ON(!xpd);
 +
-+	if (!SPAN_REGISTERED(xpd)) {
++	if(!SPAN_REGISTERED(xpd)) {
 +		NOTICE("%s: %s is already unregistered\n", __FUNCTION__, xpd->xpdname);
 +		return -EIDRM;
 +	}
++	if(sync_master == xpd)
++		set_sync_master(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));
 +		return -EBUSY;
 +	}
-+	if(sync_master == xpd)
-+		set_sync_master(NULL);			// FIXME: it's better to elect a new prince
-+	update_xpd_status(xpd, ZT_ALARM_NOTOPEN);
-+	xpd->state = XPD_STATE_OFF;
 +	mdelay(2);	// FIXME: This is to give chance for transmit/receiveprep to finish.
 +	zt_unregister(&xpd->span);
 +	return 0;
@@ -6414,7 +6579,7 @@
 +	int		sigfxs;
 +	int		i;
 +	int		cn;
-+	xops_t		*xops;
++	const xops_t	*xops;
 +
 +	BUG_ON(!xpd);
 +	xops = xpd->xops;
@@ -6455,8 +6620,13 @@
 +		
 +		cur_chan = &xpd->chans[i];
 +		DBG("setting channel %d (sigfxs=%d)\n", i, sigfxs);
-+		snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%d-%d",
-+				(sigfxs) ? "FXO" : "FXS", xpd->id, i);
++		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)
@@ -6513,11 +6683,8 @@
 +		xbus->xpds[xpd->id] = NULL;
 +		list_del(&xpd->xpd_list);
 +		xbus->num_xpds--;
-+		xpd->state = XPD_STATE_ZAPTEL_ERR;
 +		return -ENODEV;
 +	}
-+	xpd->state = XPD_STATE_ACTIVE;
-+	CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, xpd, 0, 0);	// Query SYNC_SOURCE
 +//	if(xpd->id == 0)
 +//		set_sync_master(xpd);
 +
@@ -6534,26 +6701,23 @@
 +	int len = 0;
 +	unsigned long flags;
 +	int i;
-+	unsigned long stamp = jiffies;
 +
 +	spin_lock_irqsave(&xbuses_lock, flags);
-+	len += sprintf(page + len, "Global:\n");
-+	len += sprintf(page + len, "\tjiffies=%ld\n", stamp);
-+	len += sprintf(page + len, "\txpacket_count=%d\n", atomic_read(&xpacket_count));
-+	len += sprintf(page + len, "\tbus_count=%d\n", bus_count);
 +	for(i = 0; i < MAX_BUSES; i++) {
 +		xbus_t *xbus = xbus_of(i);
 +
 +		if(xbus) {
-+			len += sprintf(page + len, "%s: HW=%s bus_type=%d connected=%s\n",
++			len += sprintf(page + len, "%s: CONNECTOR=%s STATUS=%s bus_type=%d\n",
 +					xbus->busname,
 +					xbus->busdesc,
-+					xbus->bus_type,
-+					(xbus->hardware_exists) ? "yes" : "no"
++					(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;
@@ -6684,10 +6848,10 @@
 +		remove_proc_entry(PROC_DIR, NULL);
 +	}
 +#endif
-+	if (xpd_init_workqueue) {
-+		flush_workqueue(xpd_init_workqueue);
-+		destroy_workqueue(xpd_init_workqueue);
-+		xpd_init_workqueue=NULL;
++	if (xpp_worker) {
++		flush_workqueue(xpp_worker);
++		destroy_workqueue(xpp_worker);
++		xpp_worker = NULL;
 +	}
 +	kmem_cache_destroy(packet_cache);
 +}
@@ -6719,15 +6883,15 @@
 +	ent->read_proc = proc_sync_read;
 +	ent->write_proc = proc_sync_write;
 +	ent->data = NULL;
-+	ent = create_proc_read_entry(PROC_XBUSES, 0644, xpp_procdir, xpp_zap_read_proc, 0);
++	ent = create_proc_read_entry(PROC_XBUSES, 0444, xpp_procdir, xpp_zap_read_proc, 0);
 +	if (!ent) {
 +		do_cleanup();
 +		return -EFAULT;
 +	}
 +#endif
-+	xpd_init_workqueue = create_singlethread_workqueue("XppReg");
-+	if(!xpd_init_workqueue) {
-+		ERR("Failed to create registration workqueue.\n");
++	xpp_worker = create_singlethread_workqueue("xppworker");
++	if(!xpp_worker) {
++		ERR("Failed to create card detector workqueue.\n");
 +		do_cleanup();
 +		return -ENOMEM;
 +	}
@@ -6764,7 +6928,8 @@
 +}
 +
 +EXPORT_SYMBOL(print_dbg);
-+EXPORT_SYMBOL(xpd_new);
++EXPORT_SYMBOL(card_detected);
++EXPORT_SYMBOL(xpd_alloc);
 +EXPORT_SYMBOL(xbus_activate);
 +EXPORT_SYMBOL(xbus_deactivate);
 +EXPORT_SYMBOL(xpd_of);
@@ -6777,7 +6942,7 @@
 +EXPORT_SYMBOL(xbus_dequeue_packet);
 +EXPORT_SYMBOL(init_xbus_packet_queue);
 +EXPORT_SYMBOL(drain_xbus_packet_queue);
-+EXPORT_SYMBOL(update_xpd_status);
++EXPORT_SYMBOL(phone_hook);
 +EXPORT_SYMBOL(xpp_check_hookstate);
 +EXPORT_SYMBOL(xpp_tick);
 +EXPORT_SYMBOL(xpp_open);
@@ -6788,18 +6953,20 @@
 +MODULE_DESCRIPTION("XPP Zaptel Driver");
 +MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
 +MODULE_LICENSE("GPL");
-+MODULE_VERSION("$Id: xpp_zap.c 167 2006-01-03 12:39:36Z oron $");
++MODULE_VERSION("$Id: xpp_zap.c 185 2006-01-10 14:39:07Z oron $");
 +
 +module_init(xpp_zap_init);
 +module_exit(xpp_zap_cleanup);
-diff -urNad zaptel-1.0.10/xpp/xpp_zap.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_zap.h
---- zaptel-1.0.10/xpp/xpp_zap.h	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_zap.h	2006-01-03 13:22:53.823218000 +0200
-@@ -0,0 +1,44 @@
+diff -urNad trunk/xpp/xpp_zap.h /tmp/dpep.qIz4nf/trunk/xpp/xpp_zap.h
+--- trunk/xpp/xpp_zap.h	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/xpp_zap.h	2006-01-11 10:12:52.381169000 +0200
+@@ -0,0 +1,58 @@
 +#ifndef	XPP_ZAP_H
 +#define	XPP_ZAP_H
 +
++#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);
@@ -6816,11 +6983,11 @@
 +
 +void xbus_reset_counters(xbus_t *xbus);
 +int packet_send(xbus_t *xbus, xpacket_t *pack_tx);
-+void update_xpd_status(xpd_t *xpd, int alarm_flag);
++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);
-+xpd_t *xpd_new(xbus_t *xbus, int xpd_num, xpd_type_t type, byte revision);
-+int xpd_setup(xpd_t *xpd);
++void card_detected(void *data);
++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 fill_beep(u_char *buf, int duration);
 +void xpp_tick(unsigned long param);
@@ -6829,9 +6996,21 @@
 +int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg);
 +int xpp_maint(struct zt_span *span, int cmd);
 +
++#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>
 +
-+#ifdef CONFIG_PROC_FS
 +extern struct proc_dir_entry	*xpp_procdir;
 +#endif
 +extern xpd_t			*sync_master;
@@ -6840,10 +7019,10 @@
 +#define RINGS_NUM 3
 +
 +#endif	/* XPP_ZAP_H */
-diff -urNad zaptel-1.0.10/xpp/xproto.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xproto.c
---- zaptel-1.0.10/xpp/xproto.c	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xproto.c	2006-01-03 13:22:53.823218000 +0200
-@@ -0,0 +1,244 @@
+diff -urNad trunk/xpp/xproto.c /tmp/dpep.qIz4nf/trunk/xpp/xproto.c
+--- trunk/xpp/xproto.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/xproto.c	2006-01-11 10:12:52.381169000 +0200
+@@ -0,0 +1,334 @@
 +/*
 + * Written by Oron Peled <oron at actcom.co.il>
 + * Copyright (C) 2004-2005, Xorcom
@@ -6871,11 +7050,13 @@
 +#include "xpp_zap.h"
 +#include <linux/module.h>
 +
-+static const char rcsid[] = "$Id: xproto.c 164 2006-01-03 11:14:34Z oron $";
++static const char rcsid[] = "$Id: xproto.c 184 2006-01-10 11:22:14Z 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];
++
 +bool valid_xpd_addr(const xpd_addr_t *addr)
 +{
 +	return ((addr->bank_num & ~0x1) == 0) && ((addr->card_id & ~0x3) == 0);
@@ -6901,11 +7082,14 @@
 +
 +/*---------------- General Protocol Management ----------------------------*/
 +
-+#define	XTABLE_ENTRY(name) [ XPD_TYPE(name) ] &name ## _protocol_table
++const xproto_entry_t *xproto_card_entry(const xproto_table_t *table, byte opcode)
++{
++	const xproto_entry_t *xe;
 +
-+xproto_table_t	*xprotocol_tables[] = {
-+	XTABLE_ENTRY(FXS),
-+};
++	//DBG("\n");
++	xe = &table->entries[opcode];
++	return (xe->handler != NULL) ? xe : NULL;
++}
 +
 +const xproto_entry_t *xproto_global_entry(byte opcode)
 +{
@@ -6921,18 +7105,30 @@
 +	return xproto_card_handler(&PROTO_TABLE(GLOBAL), opcode);
 +}
 +
-+const xproto_table_t *get_xproto_table(xpd_type_t cardtype)
++const xproto_table_t *xproto_table(xpd_type_t cardtype)
 +{
++	if(cardtype >= XPD_TYPE_NOMODULE)
++		return NULL;
 +	return xprotocol_tables[cardtype];
 +}
 +
-+const xproto_entry_t *xproto_card_entry(const xproto_table_t *table, byte opcode)
++const xproto_table_t *get_xproto_table(xpd_type_t cardtype)
 +{
-+	const xproto_entry_t *xe;
++	const xproto_table_t *xtable;
 +
-+	//DBG("\n");
-+	xe = &table->entries[opcode];
-+	return (xe->handler != NULL) ? xe : NULL;
++	if(cardtype >= XPD_TYPE_NOMODULE)
++		return NULL;
++	xtable = xprotocol_tables[cardtype];
++	if(!xtable) {	/* Try to load the relevant module */
++		int ret = request_module("xpd-type-%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... */
++		}
++		xtable = xprotocol_tables[cardtype];
++	}
++	return xtable;
 +}
 +
 +const xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opcode)
@@ -6955,7 +7151,7 @@
 +		
 +		if(!xpd)
 +			return NULL;
-+		xtable = get_xproto_table(xpd->type);
++		xtable = xproto_table(xpd->type);
 +		if(!xtable)
 +			return NULL;
 +		xe = xproto_card_entry(xtable, opcode);
@@ -6965,18 +7161,16 @@
 +	return xe;
 +}
 +
-+#define	DEF_(t)	\
-+	[ XPD_TYPE_ ## t ]  = & t ## _xops
++const xops_t *get_xops(xpd_type_t xpd_type)
++{
++	const xproto_table_t	*proto_table;
 +
-+xops_t	*xpd_card_ops[XPD_TYPE_NOMODULE] = {
-+	DEF_(FXS),
-+};
-+
-+xops_t	*get_xops(xpd_type_t xpd_type)
-+{
 +	if(xpd_type >= XPD_TYPE_NOMODULE)
 +		return NULL;
-+	return xpd_card_ops[xpd_type];
++	proto_table = xprotocol_tables[xpd_type];
++	if(!proto_table)
++		return NULL;
++	return &proto_table->xops;
 +}
 +
 +int packet_receive(xbus_t *xbus, xpacket_t *pack)
@@ -7083,15 +7277,90 @@
 +#endif
 +}
 +
++const char *xproto_name(xpd_type_t xpd_type)
++{
++	const xproto_table_t	*proto_table;
++
++	BUG_ON(xpd_type >= XPD_TYPE(NOMODULE));
++	proto_table = xprotocol_tables[xpd_type];
++	if(!proto_table)
++		return NULL;
++	return proto_table->name;
++}
++
++#define	CHECK_XOP(f)	\
++		if(!(xops)->f) { \
++			ERR("%s: missing xmethod %s [%s (%d)]\n", __FUNCTION__, #f, name, type);	\
++			return -EINVAL;	\
++		}
++
++int xproto_register(const xproto_table_t *proto_table)
++{
++	int		type;
++	const char	*name;
++	const xops_t	*xops;
++	
++	BUG_ON(!proto_table);
++	type = proto_table->type;
++	name = proto_table->name;
++	if(type >= XPD_TYPE(NOMODULE)) {
++		NOTICE("%s: Bad xproto type %d\n", __FUNCTION__, type);
++		return -EINVAL;
++	}
++	DBG("%s (%d)\n", name, type);
++	if(xprotocol_tables[type])
++		NOTICE("%s: overriding registration of %s (%d)\n", __FUNCTION__, name, type);
++	xops = &proto_table->xops;
++	CHECK_XOP(card_new);
++	CHECK_XOP(card_init);
++	CHECK_XOP(card_remove);
++	CHECK_XOP(card_tick);
++	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;
++	return 0;
++}
++
++void xproto_unregister(const xproto_table_t *proto_table)
++{
++	int		type;
++	const char	*name;
++	
++	BUG_ON(!proto_table);
++	type = proto_table->type;
++	name = proto_table->name;
++	DBG("%s (%d)\n", name, type);
++	if(type >= XPD_TYPE(NOMODULE)) {
++		NOTICE("%s: Bad xproto type %s (%d)\n", __FUNCTION__, name, type);
++		return;
++	}
++	if(!xprotocol_tables[type])
++		NOTICE("%s: xproto type %s (%d) is already unregistered\n", __FUNCTION__, name, type);
++	xprotocol_tables[type] = NULL;
++}
++
 +EXPORT_SYMBOL(dump_packet);
 +EXPORT_SYMBOL(packet_receive);
 +EXPORT_SYMBOL(valid_xpd_addr);
 +EXPORT_SYMBOL(xpd_addr2num);
 +EXPORT_SYMBOL(xpd_set_addr);
-diff -urNad zaptel-1.0.10/xpp/xproto.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xproto.h
---- zaptel-1.0.10/xpp/xproto.h	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xproto.h	2006-01-03 13:22:53.823218000 +0200
-@@ -0,0 +1,247 @@
++EXPORT_SYMBOL(xproto_global_entry);
++EXPORT_SYMBOL(xproto_card_entry);
++EXPORT_SYMBOL(xproto_name);
++EXPORT_SYMBOL(xproto_register);
++EXPORT_SYMBOL(xproto_unregister);
+diff -urNad trunk/xpp/xproto.h /tmp/dpep.qIz4nf/trunk/xpp/xproto.h
+--- trunk/xpp/xproto.h	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/xproto.h	2006-01-09 18:14:37.000000000 +0200
+@@ -0,0 +1,239 @@
 +#ifndef	XPROTO_H
 +#define	XPROTO_H
 +/*
@@ -7218,20 +7487,6 @@
 +		const xproto_entry_t *cmd,
 +		xpacket_t *pack);
 +
-+struct xproto_entry {
-+	xproto_handler_t	handler;
-+	int			datalen;
-+	const char		*name;
-+	xproto_table_t		*table;
-+};
-+
-+struct xproto_table {
-+	xproto_entry_t	entries[255];	/* Indexed by opcode */
-+	const char	*name;
-+	bool (*packet_is_valid)(xpacket_t *pack);
-+	void (*packet_dump)(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);
@@ -7241,44 +7496,47 @@
 +const xproto_entry_t *xproto_global_entry(byte opcode);
 +const xproto_handler_t xproto_global_handler(byte opcode);
 +
-+#define	XMETHOD(name, ...)		\
-+	int	(*name)(xbus_t *xbus, xpd_t *xpd, ## __VA_ARGS__ );
-+
-+#if 0
 +#define	CALL_XMETHOD(name, xbus, xpd, ...)				\
-+		(							\
-+		 	(xpd) && (xpd)->xops && (xpd)->xops->name &&	\
-+			(xpd)->xops->name(xbus, xpd, ## __VA_ARGS__ )	\
-+		)
-+#else
-+#define	CALL_XMETHOD(name, xbus, xpd, ...)				\
 +			(xpd)->xops->name(xbus, xpd, ## __VA_ARGS__ )
-+#endif
 +
 +struct xops {
-+	XMETHOD(card_new, byte rev);
-+	XMETHOD(card_init);
-+	XMETHOD(card_remove);
++	 xpd_t *(*card_new)(xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, byte revision);
++	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);
 +
-+	XMETHOD(DESC_REQ, int xpd_num);
-+	XMETHOD(SYNC_SOURCE, bool setit, bool is_master);
-+	XMETHOD(PCM_WRITE, xpp_line_t hookstate,  volatile byte *buf);
++	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);
 +
-+	XMETHOD(CHAN_ENABLE, xpp_line_t lines, bool on);
-+	XMETHOD(CHAN_POWER, xpp_line_t lines, bool on);
-+	XMETHOD(CHAN_CID, xpp_line_t lines);
-+	XMETHOD(RING, int pos, bool on);
-+	XMETHOD(SETHOOK, xpp_line_t hook_status);
-+	XMETHOD(LED, xpp_line_t lines, byte which, bool on);
-+	XMETHOD(RELAY_OUT, byte which, bool on);
-+	XMETHOD(SLIC_INIT);
-+	XMETHOD(SLIC_QUERY, int pos, byte reg_num);
++	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 (*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 (*RELAY_OUT)(xbus_t *xbus, xpd_t *xpd, byte which, bool on);
 +};
 +
-+xops_t	*get_xops(xpd_type_t xpd_type);
++const xops_t *get_xops(xpd_type_t xpd_type);
 +
 +#undef	XMETHOD
 +
++struct xproto_entry {
++	xproto_handler_t	handler;
++	int			datalen;
++	const char		*name;
++	xproto_table_t		*table;
++};
++
++struct xproto_table {
++	xproto_entry_t	entries[255];	/* Indexed by opcode */
++	xops_t		xops;
++	xpd_type_t	type;
++	const char	*name;
++	bool (*packet_is_valid)(xpacket_t *pack);
++	void (*packet_dump)(xpacket_t *pack);
++};
++
 +#include "card_global.h"
 +#include "card_fxs.h"
 +
@@ -7334,14 +7592,17 @@
 +	struct list_head	list;
 +};
 +
-+
 +void dump_packet(const char *msg, xpacket_t *packet, bool print_dbg);
 +int packet_receive(xbus_t *xbus, xpacket_t *pack);
++int xproto_register(const xproto_table_t *proto_table);
++void xproto_unregister(const xproto_table_t *proto_table);
++const xproto_entry_t *xproto_global_entry(byte opcode);
++const char *xproto_name(xpd_type_t xpd_type);
 +
 +#endif	/* XPROTO_H */
-diff -urNad zaptel-1.0.10/xpp/zap_debug.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/zap_debug.c
---- zaptel-1.0.10/xpp/zap_debug.c	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/zap_debug.c	2006-01-03 13:22:53.823218000 +0200
+diff -urNad trunk/xpp/zap_debug.c /tmp/dpep.qIz4nf/trunk/xpp/zap_debug.c
+--- trunk/xpp/zap_debug.c	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/zap_debug.c	2006-01-09 18:14:37.000000000 +0200
 @@ -0,0 +1,136 @@
 +/*
 + * Written by Oron Peled <oron at actcom.co.il>
@@ -7479,9 +7740,9 @@
 +EXPORT_SYMBOL(dump_poll);
 +EXPORT_SYMBOL(event2str);
 +EXPORT_SYMBOL(dump_sigtype);
-diff -urNad zaptel-1.0.10/xpp/zap_debug.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/zap_debug.h
---- zaptel-1.0.10/xpp/zap_debug.h	1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/zap_debug.h	2006-01-03 13:22:53.823218000 +0200
+diff -urNad trunk/xpp/zap_debug.h /tmp/dpep.qIz4nf/trunk/xpp/zap_debug.h
+--- trunk/xpp/zap_debug.h	1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.qIz4nf/trunk/xpp/zap_debug.h	2006-01-09 18:14:37.000000000 +0200
 @@ -0,0 +1,16 @@
 +#ifndef	ZAP_DEBUG_H
 +#define	ZAP_DEBUG_H




More information about the Pkg-voip-commits mailing list