[Pkg-voip-commits] [dahdi-tools] 20/285: xpp: use 'xtalk' for the USB access code

tzafrir at debian.org tzafrir at debian.org
Thu Jul 7 19:18:21 UTC 2016


This is an automated email from the git hooks/post-receive script.

tzafrir pushed a commit to branch master
in repository dahdi-tools.

commit 1c1fe1fd94fe1f43762aabda9e44da2359a3bdec
Author: Oron Peled <oron.peled at xorcom.com>
Date:   Thu Mar 10 18:48:11 2011 +0000

    xpp: use 'xtalk' for the USB access code
    
    * Move most of the USB access code from xpp/ to xpp/xtalk/ .
    * astribank_tool and such tools can now use a shorter -D mmm/nnn rather
      than a full path.
    
    Signed-off-by: Oron Peled <oron.peled at xorcom.com>
    Acked-by: Tzafrir Cohen <tzafrir.cohen at xorcom.com>
    
    git-svn-id: http://svn.astersk.org/svn/dahdi/tools/trunk@9825 17933a7a-c749-41c5-a318-cba88f637d49
---
 xpp/Makefile                   |   17 +-
 xpp/astribank_allow.8          |   10 +-
 xpp/astribank_allow.c          |    6 +-
 xpp/astribank_hexload.8        |   10 +-
 xpp/astribank_hexload.c        |   51 +-
 xpp/astribank_tool.8           |   10 +-
 xpp/astribank_tool.c           |   10 +-
 xpp/astribank_usb.c            |  415 +++------------
 xpp/astribank_usb.h            |   10 +-
 xpp/mpp.h                      |  211 ++------
 xpp/mpp_funcs.c                | 1109 ----------------------------------------
 xpp/mpptalk.c                  |  915 +++++++++++++++++++++++++++++++++
 xpp/{mpp_funcs.h => mpptalk.h} |   22 +-
 xpp/mpptalk_defs.h             |  111 ++++
 xpp/pic_loader.c               |   49 +-
 xpp/xpp_fxloader               |   18 +-
 xpp/{ => xtalk}/debug.c        |   31 +-
 xpp/{ => xtalk}/debug.h        |    5 +-
 xpp/xtalk/xlist.c              |   93 ++++
 xpp/xtalk/xlist.h              |   29 ++
 xpp/xtalk/xtalk.c              |  497 ++++++++++++++++++
 xpp/xtalk/xtalk.h              |  172 +++++++
 xpp/xtalk/xtalk_defs.h         |   40 ++
 xpp/xtalk/xusb.c               |  726 ++++++++++++++++++++++++++
 xpp/xtalk/xusb.h               |   98 ++++
 25 files changed, 2938 insertions(+), 1727 deletions(-)

diff --git a/xpp/Makefile b/xpp/Makefile
index 38b5956..e4f460f 100644
--- a/xpp/Makefile
+++ b/xpp/Makefile
@@ -54,9 +54,12 @@ PERL_SCRIPTS	=	\
 
 PERL_MANS	= $(PERL_SCRIPTS:%=%.8)
 
-ABHEXLOAD_OBJS		= astribank_hexload.o hexfile.o pic_loader.o astribank_usb.o mpp_funcs.o debug.o
-ABTOOL_OBJS		= astribank_tool.o astribank_usb.o mpp_funcs.o debug.o
-ABALLOW_OBJS		= astribank_allow.o astribank_usb.o mpp_funcs.o debug.o
+XTALK_OBJS		= xtalk/xtalk.o xtalk/xusb.o xtalk/xlist.o xtalk/debug.o
+ASTRIBANK_OBJS		= astribank_usb.o mpptalk.o $(XTALK_OBJS)
+
+ABHEXLOAD_OBJS		= astribank_hexload.o hexfile.o pic_loader.o $(ASTRIBANK_OBJS) $(OCT_OBJS)
+ABTOOL_OBJS		= astribank_tool.o $(ASTRIBANK_OBJS)
+ABALLOW_OBJS		= astribank_allow.o $(ASTRIBANK_OBJS)
 
 TARGETS	= .perlcheck astribank_is_starting
 PROG_INSTALL	= astribank_is_starting
@@ -102,6 +105,8 @@ ifneq	(,$(PERLLIBDIR))
 	done
 endif
 
+CFLAGS		+= -I. -Ixtalk
+
 fpga_load: fpga_load.o hexfile.o
 fpga_load: LIBS+=$(EXTRA_LIBS) $(USB_LIB)
 
@@ -130,11 +135,11 @@ test_parse: LIBS+=$(EXTRA_LIBS) $(USB_LIB)
 	touch $@
 
 clean:
-	$(RM) .depend *.o $(TARGETS)
+	$(RM) .depend *.o xtalk/*.o $(TARGETS)
 
 .PHONY: depend
 depend: .depend
-.depend: *.c *.h
-	@$(CC) -MM *.c > $@ || rm -f $@
+.depend: *.c *.h xtalk/*.c xtalk/*.h
+	@$(CC) $(CFLAGS) -MM *.c xtalk/*.c > $@ || rm -f $@
 
 include .depend
diff --git a/xpp/astribank_allow.8 b/xpp/astribank_allow.8
index 0fd48cc..6675432 100644
--- a/xpp/astribank_allow.8
+++ b/xpp/astribank_allow.8
@@ -30,11 +30,11 @@ information used by Xorcom to generate/modify licensed capabilities.
 .B \-D
 .I device-path
 .RS
-Required. The device to read from/write to. On modern UDEV-based system
-this is usually /dev/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).
-On older systems that use usbfs, it is usually
+Required. The device to read from/write to. This is
+\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) or dahdi_hardware(8).
+On older versions of this toolyou needed a complete path to the device,
+which would be /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR, or
 /proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR.
 .RE
 
diff --git a/xpp/astribank_allow.c b/xpp/astribank_allow.c
index b87f6fa..b1e8c52 100644
--- a/xpp/astribank_allow.c
+++ b/xpp/astribank_allow.c
@@ -32,8 +32,8 @@
 #include <arpa/inet.h>
 #include <ctype.h>
 #include "mpp.h"
-#include "mpp_funcs.h"
-#include "debug.h"
+#include "mpptalk.h"
+#include <debug.h>
 
 static const char rcsid[] = "$Id$";
 
@@ -327,7 +327,7 @@ int main(int argc, char *argv[])
 		usage();
 	}
 	DBG("Startup %s\n", devpath);
-	if((astribank = mpp_init(devpath)) == NULL) {
+	if((astribank = mpp_init(devpath, 1)) == NULL) {
 		ERR("Failed initializing MPP\n");
 		return 1;
 	}
diff --git a/xpp/astribank_hexload.8 b/xpp/astribank_hexload.8
index 6808927..08054f6 100644
--- a/xpp/astribank_hexload.8
+++ b/xpp/astribank_hexload.8
@@ -20,11 +20,11 @@ firmware. It is normally run by the script xpp_fxloader.
 .B \-D 
 .I device-path
 .RS
-Required. The device to read from/write to. On modern UDEV-based system
-this is usually /dev/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).
-On older systems that use usbfs, it is usually
+Required. The device to read from/write to. This is
+\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) or dahdi_hardware(8).
+On older versions of this toolyou needed a complete path to the device,
+which would be /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR, or
 /proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR.
 .RE
 
diff --git a/xpp/astribank_hexload.c b/xpp/astribank_hexload.c
index b268e5d..8362ba2 100644
--- a/xpp/astribank_hexload.c
+++ b/xpp/astribank_hexload.c
@@ -27,9 +27,9 @@
 #include <errno.h>
 #include <assert.h>
 #include <arpa/inet.h>
-#include "debug.h"
+#include <debug.h>
 #include "hexfile.h"
-#include "mpp_funcs.h"
+#include "mpptalk.h"
 #include "pic_loader.h"
 #include "astribank_usb.h"
 
@@ -80,12 +80,16 @@ static int load_hexfile(struct astribank_device *astribank, const char *hexfile,
 	int			ret;
 	int			i;
 	char			star[] = "+\\+|+/+-";
+	const char		*devstr;
 
 	if((hexdata  = parse_hexfile(hexfile, MAX_HEX_LINES)) == NULL) {
 		perror(hexfile);
 		return -errno;
 	}
-	INFO("Loading hexfile to %s: %s (version %s)\n",
+	devstr = xusb_devpath(astribank->xusb);
+	INFO("%s [%s]: Loading %s Firmware: %s (version %s)\n",
+		devstr,
+		xusb_serial(astribank->xusb),
 		dev_dest2str(dest),
 		hexdata->fname, hexdata->version_info);
 #if 0
@@ -96,7 +100,7 @@ static int load_hexfile(struct astribank_device *astribank, const char *hexfile,
 	}
 #endif
 	if((ret = mpp_send_start(astribank, dest, hexdata->version_info)) < 0) {
-		ERR("Failed hexfile send start: %d\n", ret);
+		ERR("%s: Failed hexfile send start: %d\n", devstr, ret);
 		return ret;
 	}
 	for(i = 0; i < hexdata->maxlines; i++) {
@@ -109,7 +113,7 @@ static int load_hexfile(struct astribank_device *astribank, const char *hexfile,
 			fflush(stdout);
 		}
 		if(finished) {
-			ERR("Extra data after End Of Data Record (line %d)\n", i);
+			ERR("%s: Extra data after End Of Data Record (line %d)\n", devstr, i);
 			return 0;
 		}
 		if(hexline->d.content.header.tt == TT_EOF) {
@@ -118,7 +122,7 @@ static int load_hexfile(struct astribank_device *astribank, const char *hexfile,
 			continue;
 		}
 		if((ret = handle_hexline(astribank, hexline)) < 0) {
-			ERR("Failed hexfile sending in lineno %d (ret=%d)\n", i, ret);;
+			ERR("%s: Failed hexfile sending in lineno %d (ret=%d)\n", devstr, i, ret);;
 			return ret;
 		}
 	}
@@ -127,7 +131,7 @@ static int load_hexfile(struct astribank_device *astribank, const char *hexfile,
 		fflush(stdout);
 	}
 	if((ret = mpp_send_end(astribank)) < 0) {
-		ERR("Failed hexfile send end: %d\n", ret);
+		ERR("%s: Failed hexfile send end: %d\n", devstr, ret);
 		return ret;
 	}
 #if 0
@@ -208,21 +212,38 @@ int main(int argc, char *argv[])
 		ERR("Missing device path.\n");
 		usage();
 	}
-	if((astribank = astribank_open(devpath, iface_num)) == NULL) {
-		ERR("Opening astribank failed\n");
-		return 1;
-	}
-	show_astribank_info(astribank);
 	if(opt_dest) {
+		/*
+		 * MPP Interface
+		 */
+		struct astribank_device *astribank;
+
+		if((astribank = mpp_init(devpath, iface_num)) == NULL) {
+			ERR("%s: Opening astribank failed\n", devpath);
+			return 1;
+		}
+		//show_astribank_info(astribank);
 		if(load_hexfile(astribank, argv[optind], dest) < 0) {
-			ERR("Loading firmware to %s failed\n", dev_dest2str(dest));
+			ERR("%s: Loading firmware to %s failed\n", devpath, dev_dest2str(dest));
 			return 1;
 		}
+		astribank_close(astribank, 0);
 	} else if(opt_pic) {
-		if((ret = load_pic(astribank, argc - optind, argv + optind)) < 0) {
-			ERR("Loading PIC's failed\n");
+		/*
+		 * XPP Interface
+		 */
+		struct astribank_device *astribank;
+
+		if((astribank = astribank_open(devpath, iface_num)) == NULL) {
+			ERR("%s: Opening astribank failed\n", devpath);
 			return 1;
 		}
+		if (opt_pic) {
+			if ((ret = load_pic(astribank, argc - optind, argv + optind)) < 0) {
+				ERR("%s: Loading PIC's failed\n", devpath);
+				return 1;
+			}
+		}
 	}
 	astribank_close(astribank, 0);
 	return 0;
diff --git a/xpp/astribank_tool.8 b/xpp/astribank_tool.8
index d685470..184b331 100644
--- a/xpp/astribank_tool.8
+++ b/xpp/astribank_tool.8
@@ -17,11 +17,11 @@ to the \-D command line option).
 .B \-D 
 .I device-path
 .RS
-Required. The device to read from/write to. On modern UDEV-based system
-this is usually /dev/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).
-On older systems that use usbfs, it is usually
+Required. The device to read from/write to. This is
+\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) or dahdi_hardware(8).
+On older versions of this toolyou needed a complete path to the device,
+which would be /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR, or
 /proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR.
 .RE
 
diff --git a/xpp/astribank_tool.c b/xpp/astribank_tool.c
index 59ae94c..5cf0dc3 100644
--- a/xpp/astribank_tool.c
+++ b/xpp/astribank_tool.c
@@ -28,8 +28,10 @@
 #include <getopt.h>
 #include <sys/types.h>
 #include <arpa/inet.h>
-#include "mpp_funcs.h"
-#include "debug.h"
+#include "astribank_usb.h"
+#include "mpptalk.h"
+#include <debug.h>
+#include <xusb.h>
 
 #define	DBG_MASK	0x80
 /* if enabled, adds support for resetting pre-MPP USB firmware - if we 
@@ -132,7 +134,7 @@ int old_reset(const char* devpath)
 		DBG("Failed re-opening astribank device for old_reset\n");
 		return -ENODEV;
 	}
-	ret = send_usb(astribank, buf, 1, 5000);
+	ret = xusb_send(astribank->xusb, buf, 1, 5000);
 
 	/* If we just had a reenumeration, we may get -ENODEV */
 	if(ret < 0 && ret != -ENODEV)
@@ -205,7 +207,7 @@ int main(int argc, char *argv[])
 		usage();
 	}
 	DBG("Startup %s\n", devpath);
-	if((astribank = mpp_init(devpath)) == NULL) {
+	if((astribank = mpp_init(devpath, 1)) == NULL) {
 		ERR("Failed initializing MPP\n");
 #ifdef SUPPORT_OLD_RESET
 		DBG("opt_reset = %s\n", opt_reset);
diff --git a/xpp/astribank_usb.c b/xpp/astribank_usb.c
index dce3d47..13af7cd 100644
--- a/xpp/astribank_usb.c
+++ b/xpp/astribank_usb.c
@@ -30,39 +30,44 @@
 #include <stdarg.h>
 #include <syslog.h>
 #include <arpa/inet.h>
+#include <xusb.h>
 #include "astribank_usb.h"
-#include "debug.h"
+#include <debug.h>
 
 static const char rcsid[] = "$Id$";
 
 #define	DBG_MASK	0x01
 #define	TIMEOUT	500
 
-#define	TYPE_ENTRY(t,ni,n,ne,out,in,...)	\
-	[t] = {					\
-		.type_code = (t),		\
+#define	TYPE_ENTRY(t,p,ni,n,ne,out,in,...)	\
+		{				\
+		.my_vendor_id = 0xe4e4,		\
+		.my_product_id = (p),		\
+		.name = #t,			\
 		.num_interfaces = (ni),		\
 		.my_interface_num = (n),	\
 		.num_endpoints = (ne),		\
 		.my_ep_in = (in),		\
 		.my_ep_out = (out),		\
-		.name = #t,			\
-		.endpoints = { __VA_ARGS__ },	\
 		}
 
-static const struct interface_type interface_types[] = {
-	TYPE_ENTRY(USB_11xx,		1, 0, 4, MP_EP_OUT, MP_EP_IN,
-		XPP_EP_OUT,
-		MP_EP_OUT,
-		XPP_EP_IN,
-		MP_EP_IN),
-	TYPE_ENTRY(USB_FIRMWARE_II,	2, 1, 2, MP_EP_OUT, MP_EP_IN,
-		MP_EP_OUT,
-		MP_EP_IN),
-	TYPE_ENTRY(USB_PIC,		2, 0, 2, XPP_EP_OUT, XPP_EP_IN, 
-		XPP_EP_OUT,
-		XPP_EP_IN),
-	 
+#define	ARRAY_SIZE(x)	(sizeof(x)/sizeof(x[0]))
+
+static const struct xusb_spec	astribank_specs[] = {
+	/* OLD Firmwares */
+	TYPE_ENTRY("USB-OLDFXS",	0x1131, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
+	TYPE_ENTRY("FPGA-OLDFXS",	0x1132, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
+	TYPE_ENTRY("USB-BRI",		0x1141, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
+	TYPE_ENTRY("FPGA-BRI",		0x1142, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
+	TYPE_ENTRY("USB-OLD",		0x1151, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
+	TYPE_ENTRY("FPGA-OLD",		0x1152, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
+
+	TYPE_ENTRY("USB-MULTI",		0x1161, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
+	TYPE_ENTRY("FPGA-MULTI",	0x1162, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
+};
+
+static const struct xusb_spec	astribank_pic_specs[] = {
+	TYPE_ENTRY("USB_PIC",		0x1161, 2, 0, 2, XPP_EP_OUT, XPP_EP_IN),
 };
 #undef TYPE_ENTRY
 
@@ -71,262 +76,41 @@ static const struct interface_type interface_types[] = {
 /*
  * USB handling
  */
-
-/* return 1 if:
- * - str has a number
- * - It is larger than 0
- * - It equals num
- */
-static int num_matches(int num, const char* str) {
-	int str_val = atoi(str);
-	if (str_val <= 0)
-		return 0;
-	return (str_val == num);
-}
-
-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		*p;
-	int			bnum;
-	int			dnum;
-	int			ret;
-
-	assert(path != NULL);
-	if(access(path, F_OK) < 0) {
-		perror(path);
-		return NULL;
-	}
-	/* Find last '/' */
-	if((p = memrchr(path, '/', strlen(path))) == NULL) {
-		ERR("Missing a '/' in %s\n", path);
-		return NULL;
-	}
-	/* Get the device number */
-	ret = sscanf(p + 1, "%d", &dnum);
-	if(ret != 1) {
-		ERR("Path tail is not a device number: '%s'\n", p);
-		return NULL;
-	}
-	/* Search for a '/' before that */
-	p = memrchr(path, '/', p - path);
-	if(p == NULL)
-		p = path;		/* Relative path */
-	else
-		p++;			/* skip '/' */
-	/* Get the bus number */
-	ret = sscanf(p, "%d", &bnum);
-	if(ret != 1) {
-		ERR("Path tail is not a bus number: '%s'\n", p);
-		return NULL;
-	}
-	sprintf(dirname, "%03d", bnum);
-	sprintf(filename, "%03d", dnum);
-	for (bus = usb_busses; bus; bus = bus->next) {
-		if (! num_matches(bnum, bus->dirname))
-		//if(strcmp(bus->dirname, dirname) != 0)
-			continue;
-		for (dev = bus->devices; dev; dev = dev->next) {
-			//if(strcmp(dev->filename, filename) == 0)
-			if (num_matches(dnum, dev->filename))
-				return dev;
-		}
-	}
-	ERR("no usb device match '%s'\n", path);
-	return NULL;
-}
-
-int get_usb_string(struct astribank_device *astribank, uint8_t item, char *buf, unsigned int len)
-{
-	char	tmp[BUFSIZ];
-	int	ret;
-
-	assert(astribank->handle);
-	if (!item)
-		return 0;
-	ret = usb_get_string_simple(astribank->handle, item, tmp, BUFSIZ);
-	if (ret <= 0)
-		return ret;
-	return snprintf(buf, len, "%s", tmp);
-}
-
-static int match_interface(const struct astribank_device *astribank,
-	const struct interface_type *itype)
-{
-	struct usb_interface		*interface;
-	struct usb_interface_descriptor	*iface_desc;
-	struct usb_config_descriptor	*config_desc;
-	int				i = itype - interface_types;
-	int				inum;
-	int				num_altsetting;
-
-	DBG("Checking[%d]: interfaces=%d interface num=%d endpoints=%d: \"%s\"\n",
-			i,
-			itype->num_interfaces,
-			itype->my_interface_num,
-			itype->num_endpoints,
-			itype->name);
-	config_desc = astribank->dev->config;
-	if (!config_desc) {
-		ERR("No configuration descriptor: strange USB1 controller?\n");
-		return 0;
-	}
-	if(config_desc->bNumInterfaces <= itype->my_interface_num) {
-		DBG("Too little interfaces: have %d need %d\n",
-			config_desc->bNumInterfaces, itype->my_interface_num + 1);
-		return 0;
-	}
-	if(astribank->my_interface_num != itype->my_interface_num) {
-		DBG("Wrong match -- not my interface num (wanted %d)\n", astribank->my_interface_num);
-		return 0;
-	}
-	inum = itype->my_interface_num;
-	interface = &config_desc->interface[inum];
-	assert(interface != NULL);
-	iface_desc = interface->altsetting;
-	num_altsetting = interface->num_altsetting;
-	assert(num_altsetting != 0);
-	assert(iface_desc != NULL);
-	if(iface_desc->bInterfaceClass != 0xFF) {
-		DBG("Bad interface class 0x%X\n", iface_desc->bInterfaceClass);
-		return 0;
-	}
-	if(iface_desc->bInterfaceNumber != itype->my_interface_num) {
-		DBG("Bad interface number %d\n", iface_desc->bInterfaceNumber);
-		return 0;
-	}
-	if(iface_desc->bNumEndpoints != itype->num_endpoints) {
-		DBG("Different number of endpoints %d\n", iface_desc->bNumEndpoints);
-		return 0;
-	}
-	return	1;
-}
-
-static int astribank_init(struct astribank_device *astribank)
-{
-	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;
-	const struct interface_type	*fwtype;
-	int				i;
-
-	assert(astribank);
-	astribank->handle = usb_open(astribank->dev);
-	if(!astribank->handle) {
-		ERR("Failed to open usb device '%s/%s': %s\n",
-			astribank->dev->bus->dirname, astribank->dev->filename, usb_strerror());
-		return 0;
-	}
-	fwtype = astribank->fwtype;
-	if(usb_claim_interface(astribank->handle, fwtype->my_interface_num) != 0) {
-		ERR("usb_claim_interface: %s\n", usb_strerror());
-		return 0;
-	}
-	dev_desc = &astribank->dev->descriptor;
-	config_desc = astribank->dev->config;
-	if (!config_desc) {
-		ERR("usb interface without a configuration\n");
-		return 0;
-	}
-	DBG("Got config_desc. Looking for interface %d\n", fwtype->my_interface_num);
-	interface = &config_desc->interface[fwtype->my_interface_num];
-	iface_desc = interface->altsetting;
-	endpoint = iface_desc->endpoint;
-	astribank->is_usb2 = (endpoint->wMaxPacketSize == 512);
-	for(i = 0; i < iface_desc->bNumEndpoints; i++, endpoint++) {
-		DBG("Validating endpoint @ %d (interface %d)\n", i, fwtype->my_interface_num);
-		if(endpoint->bEndpointAddress != fwtype->endpoints[i]) {
-			ERR("Wrong endpoint 0x%X != 0x%X (at index %d)\n",
-				endpoint->bEndpointAddress,
-				fwtype->endpoints[i],
-				i);
-			return 0;
-		}
-		if(endpoint->bEndpointAddress == MP_EP_OUT || endpoint->bEndpointAddress == MP_EP_IN) {
-			if(endpoint->wMaxPacketSize > PACKET_SIZE) {
-				ERR("Endpoint #%d wMaxPacketSize too large (%d)\n", i, endpoint->wMaxPacketSize);
-				return 0;
-			}
-		}
-	}
-	astribank->my_ep_in = fwtype->my_ep_in;
-	astribank->my_ep_out = fwtype->my_ep_out;
-	if(get_usb_string(astribank, dev_desc->iManufacturer, astribank->iManufacturer, BUFSIZ) < 0)
-		return 0;
-	if(get_usb_string(astribank, dev_desc->iProduct, astribank->iProduct, BUFSIZ) < 0)
-		return 0;
-	if(get_usb_string(astribank, dev_desc->iSerialNumber, astribank->iSerialNumber, BUFSIZ) < 0)
-		return 0;
-	if(get_usb_string(astribank, iface_desc->iInterface, astribank->iInterface, BUFSIZ) < 0)
-		return 0;
-	DBG("ID=%04X:%04X Manufacturer=[%s] Product=[%s] SerialNumber=[%s] Interface=[%s]\n",
-		dev_desc->idVendor,
-		dev_desc->idProduct,
-		astribank->iManufacturer,
-		astribank->iProduct,
-		astribank->iSerialNumber,
-		astribank->iInterface);
-	if(usb_clear_halt(astribank->handle, astribank->my_ep_out) != 0) {
-		ERR("Clearing output endpoint: %s\n", usb_strerror());
-		return 0;
-	}
-	if(usb_clear_halt(astribank->handle, astribank->my_ep_in) != 0) {
-		ERR("Clearing input endpoint: %s\n", usb_strerror());
-		return 0;
-	}
-	if((i = flush_read(astribank)) < 0) {
-		ERR("flush_read failed: %d\n", i);
-		return 0;
-	}
-	return 1;
-}
-
 struct astribank_device *astribank_open(const char devpath[], int iface_num)
 {
-	struct astribank_device		*astribank;
-	int				i;
+	struct astribank_device	*astribank = NULL;
+	struct xusb		*xusb;
 
 	DBG("devpath='%s' iface_num=%d\n", devpath, iface_num);
-	if((astribank = malloc(sizeof(*astribank))) == NULL) {
-		ERR("Out of memory");
-		return NULL;
+	if((astribank = malloc(sizeof(struct astribank_device))) == NULL) {
+		ERR("Out of memory\n");
+		goto fail;
 	}
 	memset(astribank, 0, sizeof(*astribank));
-	astribank->my_interface_num = iface_num;
-	usb_init();
-	usb_find_busses();
-	usb_find_devices();
-	astribank->dev = dev_of_path(devpath);
-	if(!astribank->dev) {
-		ERR("Bailing out\n");
-		goto fail;
+	if (iface_num) {
+		xusb  = xusb_find_bypath(astribank_specs, ARRAY_SIZE(astribank_specs), devpath);
+	} else {
+		xusb  = xusb_find_bypath(astribank_pic_specs, ARRAY_SIZE(astribank_pic_specs), devpath);
 	}
-	DBG("Scan interface types (astribank has %d interfaces)\n", astribank->dev->config->bNumInterfaces);
-	for(i = 0; i < sizeof(interface_types)/sizeof(interface_types[0]); i++) {
-		if(match_interface(astribank, &interface_types[i])) {
-			DBG("Identified[%d]: interfaces=%d endpoints=%d: \"%s\"\n",
-				i,
-				interface_types[i].num_interfaces,
-				interface_types[i].num_endpoints,
-				interface_types[i].name);
-			astribank->fwtype = &interface_types[i];
-			goto found;
-		}
+	if (!xusb) {
+		ERR("%s: No device found\n", __func__);
+		goto fail;
 	}
-	ERR("Didn't find suitable device\n");
-fail:
-	free(astribank);
-	return NULL;
-found:
-	if(!astribank_init(astribank))
+	astribank->xusb = xusb;
+	astribank->is_usb2 = (xusb_packet_size(xusb) == 512);
+	astribank->my_interface_num = iface_num;
+	if (xusb_claim_interface(astribank->xusb) < 0) {
+		ERR("xusb_claim_interface failed\n");
 		goto fail;
+	}
 	astribank->tx_sequenceno = 1;
 	return astribank;
+fail:
+	if (astribank) {
+		free(astribank);
+		astribank = NULL;
+	}
+	return NULL;
 }
 
 /*
@@ -334,100 +118,36 @@ found:
  */
 void show_astribank_info(const struct astribank_device *astribank)
 {
-	struct usb_device_descriptor	*dev_desc;
-	struct usb_device		*dev;
+	struct xusb			*xusb;
 
 	assert(astribank != NULL);
-	dev = astribank->dev;
-	dev_desc = &dev->descriptor;
+	xusb = astribank->xusb;
+	assert(xusb != NULL);
 	if(verbose <= LOG_INFO) {
-		INFO("usb:%s/%s: ID=%04X:%04X [%s / %s / %s]\n",
-			dev->bus->dirname,
-			dev->filename,
-			dev_desc->idVendor,
-			dev_desc->idProduct,
-			astribank->iManufacturer,
-			astribank->iProduct,
-			astribank->iSerialNumber);
+		xusb_showinfo(xusb);
 	} else {
-		printf("USB    Bus/Device:    [%s/%s]\n", dev->bus->dirname, dev->filename);
-		printf("USB    Firmware Type: [%s]\n", astribank->fwtype->name);
-		printf("USB    iManufacturer: [%s]\n", astribank->iManufacturer);
-		printf("USB    iProduct:      [%s]\n", astribank->iProduct);
-		printf("USB    iSerialNumber: [%s]\n", astribank->iSerialNumber);
+		const struct xusb_spec	*spec;
+
+		spec = xusb_spec(xusb);
+		printf("USB    Bus/Device:    [%s]\n", xusb_devpath(xusb));
+		printf("USB    Firmware Type: [%s]\n", spec->name);
+		printf("USB    iSerialNumber: [%s]\n", xusb_serial(xusb));
+		printf("USB    iManufacturer: [%s]\n", xusb_manufacturer(xusb));
+		printf("USB    iProduct:      [%s]\n", xusb_product(xusb));
 	}
 }
 
 void astribank_close(struct astribank_device *astribank, int disconnected)
 {
 	assert(astribank != NULL);
-	if(!astribank->handle)
-		return;	/* Nothing to do */
-	if(!disconnected) {
-		if(usb_release_interface(astribank->handle, astribank->fwtype->my_interface_num) != 0) {
-			ERR("Releasing interface: usb: %s\n", usb_strerror());
-		}
-	}
-	if(usb_close(astribank->handle) != 0) {
-		ERR("Closing device: usb: %s\n", usb_strerror());
+	if (astribank->xusb) {
+		xusb_close(astribank->xusb);
+		astribank->xusb = NULL;
 	}
 	astribank->tx_sequenceno = 0;
-	astribank->handle = NULL;
-}
-
-int send_usb(struct astribank_device *astribank, char *buf, int len, int timeout)
-{
-	int		ret;
-
-	dump_packet(LOG_DEBUG, __FUNCTION__, buf, len);
-	if(astribank->my_ep_out & USB_ENDPOINT_IN) {
-		ERR("send_usb called with an input endpoint 0x%x\n", astribank->my_ep_out);
-		return -EINVAL;
-	}
-	ret = usb_bulk_write(astribank->handle, astribank->my_ep_out, buf, len, timeout);
-	if(ret < 0) {
-		/*
-		 * If the device was gone, it may be the
-		 * result of renumeration. Ignore it.
-		 */
-		if(ret != -ENODEV) {
-			ERR("bulk_write to endpoint 0x%x failed: (%d) %s\n",
-				astribank->my_ep_out, ret, usb_strerror());
-			dump_packet(LOG_ERR, "send_usb[ERR]", buf, len);
-			exit(2);
-		} else {
-			DBG("bulk_write to endpoint 0x%x got ENODEV\n", astribank->my_ep_out);
-			astribank_close(astribank, 1);
-		}
-		return ret;
-	} else if(ret != len) {
-		ERR("bulk_write to endpoint 0x%x short write: (%d) %s\n",
-			astribank->my_ep_out, ret, usb_strerror());
-		dump_packet(LOG_ERR, "send_usb[ERR]", buf, len);
-		return -EFAULT;
-	}
-	return ret;
-}
-
-int recv_usb(struct astribank_device *astribank, char *buf, size_t len, int timeout)
-{
-	int	ret;
-
-	if(astribank->my_ep_in & USB_ENDPOINT_OUT) {
-		ERR("recv_usb called with an output endpoint 0x%x\n", astribank->my_ep_in);
-		return -EINVAL;
-	}
-	ret = usb_bulk_read(astribank->handle, astribank->my_ep_in, buf, len, timeout);
-	if(ret < 0) {
-		DBG("bulk_read from endpoint 0x%x failed: (%d) %s\n",
-			astribank->my_ep_in, ret, usb_strerror());
-		memset(buf, 0, len);
-		return ret;
-	}
-	dump_packet(LOG_DEBUG, __FUNCTION__, buf, ret);
-	return ret;
 }
 
+#if 0
 int flush_read(struct astribank_device *astribank)
 {
 	char		tmpbuf[BUFSIZ];
@@ -441,10 +161,11 @@ int flush_read(struct astribank_device *astribank)
 		return ret;
 	} else if(ret > 0) {
 		DBG("Got %d bytes:\n", ret);
-		dump_packet(LOG_DEBUG, __FUNCTION__, tmpbuf, ret);
+		dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, tmpbuf, ret);
 	}
 	return 0;
 }
+#endif
 
 
 int release_isvalid(uint16_t release)
@@ -541,12 +262,10 @@ int eeprom_fill(struct eeprom_table *eprm,
 
 int astribank_has_twinstar(struct astribank_device *astribank)
 {
-	struct usb_device_descriptor	*dev_desc;
 	uint16_t			product_series;
 
 	assert(astribank != NULL);
-	dev_desc = &astribank->dev->descriptor;
-	product_series = dev_desc->idProduct;
+	product_series = xusb_product_id(astribank->xusb);
 	product_series &= 0xFFF0;
 	if(product_series == 0x1160)	/* New boards */
 		return 1;
diff --git a/xpp/astribank_usb.h b/xpp/astribank_usb.h
index b3b4d79..b65c1db 100644
--- a/xpp/astribank_usb.h
+++ b/xpp/astribank_usb.h
@@ -23,7 +23,8 @@
  */
 
 #include <stdio.h>
-#include <usb.h>
+#include <xusb.h>
+#include <xtalk.h>
 #include "mpp.h"
 
 /*
@@ -63,14 +64,12 @@ enum eeprom_burn_state {
 };
 
 struct astribank_device {
-	struct usb_device	*dev;
+	struct xusb		*xusb;
+	struct xtalk_device	*xtalk_dev;
 	usb_dev_handle		*handle;
 	int			my_interface_num;
 	int			my_ep_out;
 	int			my_ep_in;
-	char			iManufacturer[BUFSIZ];
-	char			iProduct[BUFSIZ];
-	char			iSerialNumber[BUFSIZ];
 	char			iInterface[BUFSIZ];
 	int			is_usb2;
 	enum eeprom_type	eeprom_type;
@@ -79,7 +78,6 @@ struct astribank_device {
 	uint8_t			mpp_proto_version;
 	struct eeprom_table	*eeprom;
 	struct firmware_versions	fw_versions;
-	const struct interface_type	*fwtype;
 	uint16_t		tx_sequenceno;
 };
 
diff --git a/xpp/mpp.h b/xpp/mpp.h
index 45654b7..23a0ce9 100644
--- a/xpp/mpp.h
+++ b/xpp/mpp.h
@@ -26,6 +26,10 @@
  * MPP - Managment Processor Protocol definitions
  */
 
+#include <mpptalk_defs.h>
+#include <stdint.h>
+#include <xtalk.h>
+
 #ifdef	__GNUC__
 #define	PACKED	__attribute__((packed))
 #else
@@ -63,7 +67,8 @@ struct capabilities {
 	uint8_t		ports_bri;
 	uint8_t		ports_pri;
 	uint8_t		extra_features;	/* BIT(0) - TwinStar */
-	uint8_t		reserved[3];
+	uint8_t		ports_echo;
+	uint8_t		reserved[2];
 	uint32_t	timestamp;
 } PACKED;
 
@@ -81,53 +86,6 @@ struct extrainfo {
 	char		text[24];
 } PACKED;
 
-enum mpp_command_ops {
-	/* MSB of op signifies a reply from device */
-	MPP_ACK			= 0x80,
-
-	MPP_PROTO_QUERY	= 0x01,
-	MPP_PROTO_REPLY	= 0x81,
-
-	MPP_RENUM		= 0x0B,	/* Trigger USB renumeration */
-
-	MPP_EEPROM_SET		= 0x0D,
-
-	MPP_CAPS_GET		= 0x0E,
-	MPP_CAPS_GET_REPLY	= 0x8E,
-	MPP_CAPS_SET		= 0x0F,	/* Set AB capabilities	*/
-
-	MPP_DEV_SEND_START	= 0x05,
-	MPP_DEV_SEND_SEG	= 0x07,
-	MPP_DEV_SEND_END	= 0x09,
-
-	MPP_STATUS_GET		= 0x11,	/* Get Astribank Status	*/
-	MPP_STATUS_GET_REPLY	= 0x91,
-	MPP_STATUS_GET_REPLY_V13	= 0x91,	/* backward compat */
-
-	MPP_EXTRAINFO_GET	= 0x13,	/* Get extra vendor information	*/
-	MPP_EXTRAINFO_GET_REPLY	= 0x93,
-	MPP_EXTRAINFO_SET	= 0x15,	/* Set extra vendor information	*/
-
-	MPP_EEPROM_BLK_RD	= 0x27,
-	MPP_EEPROM_BLK_RD_REPLY	= 0xA7,
-
-	MPP_SER_SEND		= 0x37,
-	MPP_SER_RECV		= 0xB7,
-
-	MPP_RESET		= 0x45,	/* Reset both FPGA and USB firmwares */
-	MPP_HALF_RESET		= 0x47,	/* Reset only FPGA firmware */
-
-	/* Twinstar */
-	MPP_TWS_WD_MODE_SET	= 0x31,	/* Set watchdog off/on guard	*/
-	MPP_TWS_WD_MODE_GET	= 0x32,	/* Current watchdog mode 	*/
-	MPP_TWS_WD_MODE_GET_REPLY = 0xB2,	/* Current watchdog mode 	*/
-	MPP_TWS_PORT_SET	= 0x34,	/* USB-[0/1]			*/
-	MPP_TWS_PORT_GET	= 0x35,	/* USB-[0/1]			*/
-	MPP_TWS_PORT_GET_REPLY	= 0xB5,	/* USB-[0/1]			*/
-	MPP_TWS_PWR_GET		= 0x36,	/* Power: bits -> USB ports	*/
-	MPP_TWS_PWR_GET_REPLY	= 0xB6,	/* Power: bits -> USB ports	*/
-};
-
 struct mpp_header {
 	uint16_t	len;
 	uint16_t	seq;
@@ -141,33 +99,10 @@ enum mpp_ser_op {
 
 /* Individual commands structure */
 
-#define	CMD_DEF(name, ...)	struct d_ ## name { __VA_ARGS__ } PACKED d_ ## name
-
-CMD_DEF(ACK,
-	uint8_t	stat;
-	);
-
-CMD_DEF(PROTO_QUERY,
-	uint8_t	proto_version;
-	uint8_t	reserved;
-	);
-
-CMD_DEF(PROTO_REPLY,
-	uint8_t	proto_version;
-	uint8_t	reserved;
-	);
+CMD_DEF(MPP, STATUS_GET);
 
-CMD_DEF(STATUS_GET);
 
-CMD_DEF(STATUS_GET_REPLY_V13,
-	uint8_t	i2cs_data;
-
-#define	STATUS_FPGA_LOADED(x)	((x) & 0x01)
-	uint8_t	status;		/* BIT(0) - FPGA is loaded */
-	);
-
-
-CMD_DEF(STATUS_GET_REPLY,
+CMD_DEF(MPP, STATUS_GET_REPLY,
 	uint8_t	i2cs_data;
 
 #define	STATUS_FPGA_LOADED(x)	((x) & 0x01)
@@ -175,170 +110,90 @@ CMD_DEF(STATUS_GET_REPLY,
 	struct firmware_versions fw_versions;
 	);
 
-CMD_DEF(EEPROM_SET,
+CMD_DEF(MPP, EEPROM_SET,
 	struct eeprom_table	data;
 	);
 
-CMD_DEF(CAPS_GET);
+CMD_DEF(MPP, CAPS_GET);
 
-CMD_DEF(CAPS_GET_REPLY,
+CMD_DEF(MPP, CAPS_GET_REPLY,
 	struct eeprom_table	data;
 	struct capabilities	capabilities;
 	struct capkey		key;
 	);
 
-CMD_DEF(CAPS_SET,
+CMD_DEF(MPP, CAPS_SET,
 	struct eeprom_table	data;
 	struct capabilities	capabilities;
 	struct capkey		key;
 	);
 
-CMD_DEF(EXTRAINFO_GET);
+CMD_DEF(MPP, EXTRAINFO_GET);
 
-CMD_DEF(EXTRAINFO_GET_REPLY,
+CMD_DEF(MPP, EXTRAINFO_GET_REPLY,
 	struct extrainfo	info;
 	);
 
-CMD_DEF(EXTRAINFO_SET,
+CMD_DEF(MPP, EXTRAINFO_SET,
 	struct extrainfo	info;
 	);
 
-CMD_DEF(RENUM);
+CMD_DEF(MPP, RENUM);
 
-CMD_DEF(EEPROM_BLK_RD,
+CMD_DEF(MPP, EEPROM_BLK_RD,
 	uint16_t	offset;
 	uint16_t	len;
 	);
 
-CMD_DEF(EEPROM_BLK_RD_REPLY,
+CMD_DEF(MPP, EEPROM_BLK_RD_REPLY,
 	uint16_t	offset;
 	uint8_t		data[0];
 	);
 
-CMD_DEF(DEV_SEND_START,
+CMD_DEF(MPP, DEV_SEND_START,
 	uint8_t		dest;
 	char		ihex_version[VERSION_LEN];
 	);
 
-CMD_DEF(DEV_SEND_END);
+CMD_DEF(MPP, DEV_SEND_END);
 
-CMD_DEF(DEV_SEND_SEG,
+CMD_DEF(MPP, DEV_SEND_SEG,
 	uint16_t	offset;
 	uint8_t		data[0];
 	);
 
-CMD_DEF(RESET);
-CMD_DEF(HALF_RESET);
+CMD_DEF(MPP, RESET);
+CMD_DEF(MPP, HALF_RESET);
 
-CMD_DEF(SER_SEND,
+CMD_DEF(MPP, SER_SEND,
 	uint8_t	data[0];
 	);
 
-CMD_DEF(SER_RECV,
+CMD_DEF(MPP, SER_RECV,
 	uint8_t	data[0];
 	);
 
-CMD_DEF(TWS_WD_MODE_SET,
+CMD_DEF(MPP, TWS_WD_MODE_SET,
 	uint8_t		wd_active;
 	);
 
-CMD_DEF(TWS_WD_MODE_GET);
-CMD_DEF(TWS_WD_MODE_GET_REPLY,
+CMD_DEF(MPP, TWS_WD_MODE_GET);
+CMD_DEF(MPP, TWS_WD_MODE_GET_REPLY,
 	uint8_t		wd_active;
 	);
 
-CMD_DEF(TWS_PORT_SET,
+CMD_DEF(MPP, TWS_PORT_SET,
 	uint8_t		portnum;
 	);
 
-CMD_DEF(TWS_PORT_GET);
-CMD_DEF(TWS_PORT_GET_REPLY,
+CMD_DEF(MPP, TWS_PORT_GET);
+CMD_DEF(MPP, TWS_PORT_GET_REPLY,
 	uint8_t		portnum;
 	);
 
-CMD_DEF(TWS_PWR_GET);
-CMD_DEF(TWS_PWR_GET_REPLY,
+CMD_DEF(MPP, TWS_PWR_GET);
+CMD_DEF(MPP, TWS_PWR_GET_REPLY,
 	uint8_t		power;
 	);
 
-#undef	CMD_DEF
-
-#define	MEMBER(n)	struct d_ ## n d_ ## n
-
-struct mpp_command {
-	struct mpp_header	header;
-	union {
-		MEMBER(ACK);
-		MEMBER(PROTO_QUERY);
-		MEMBER(PROTO_REPLY);
-		MEMBER(STATUS_GET);
-		MEMBER(STATUS_GET_REPLY_V13);
-		MEMBER(STATUS_GET_REPLY);
-		MEMBER(EEPROM_SET);
-		MEMBER(CAPS_GET);
-		MEMBER(CAPS_GET_REPLY);
-		MEMBER(CAPS_SET);
-		MEMBER(EXTRAINFO_GET);
-		MEMBER(EXTRAINFO_GET_REPLY);
-		MEMBER(EXTRAINFO_SET);
-		MEMBER(RENUM);
-		MEMBER(EEPROM_BLK_RD);
-		MEMBER(EEPROM_BLK_RD_REPLY);
-		MEMBER(DEV_SEND_START);
-		MEMBER(DEV_SEND_SEG);
-		MEMBER(DEV_SEND_END);
-		MEMBER(RESET);
-		MEMBER(HALF_RESET);
-		MEMBER(SER_SEND);
-		MEMBER(SER_RECV);
-		/* Twinstar */
-		MEMBER(TWS_WD_MODE_SET);
-		MEMBER(TWS_WD_MODE_GET);
-		MEMBER(TWS_WD_MODE_GET_REPLY);
-		MEMBER(TWS_PORT_SET);
-		MEMBER(TWS_PORT_GET);
-		MEMBER(TWS_PORT_GET_REPLY);
-		MEMBER(TWS_PWR_GET);
-		MEMBER(TWS_PWR_GET_REPLY);
-		uint8_t	raw_data[0];
-	} PACKED alt;
-} PACKED;
-#undef MEMBER
-
-#define	CMD_FIELD(cmd, name, field)	((cmd)->alt.d_ ## name.field)
-
-enum mpp_ack_stat {
-	STAT_OK		= 0x00,	/* acknowledges previous command	*/
-	STAT_FAIL	= 0x01,	/* Last command failed		*/
-	STAT_RESET_FAIL	= 0x02,	/* reset failed				*/
-	STAT_NODEST	= 0x03,	/* No destination is selected		*/
-	STAT_MISMATCH	= 0x04,	/* Data mismatch			*/
-	STAT_NOACCESS	= 0x05,	/* No access				*/
-	STAT_BAD_CMD	= 0x06,	/* Bad command				*/
-	STAT_TOO_SHORT	= 0x07,	/* Packet is too short			*/
-	STAT_ERROFFS	= 0x08,	/* Offset error				*/
-	STAT_NOCODE	= 0x09,	/* Source was not burned before		*/
-	STAT_NO_LEEPROM	= 0x0A,	/* Large EEPROM was not found		*/
-	STAT_NO_EEPROM	= 0x0B,	/* No EEPROM was found			*/
-	STAT_WRITE_FAIL	= 0x0C,	/* Writing to device failed		*/
-	STAT_FPGA_ERR	= 0x0D,	/* FPGA error				*/
-	STAT_KEY_ERR	= 0x0E,	/* Bad Capabilities Key			*/
-	STAT_NOCAPS_ERR	= 0x0F,	/* No matching capability		*/
-	STAT_NOPWR_ERR	= 0x10,	/* No power on USB connector		*/
-	STAT_CAPS_FPGA_ERR	= 0x11,	/* Setting of the capabilities while FPGA is loaded */
-};
-
-enum eeprom_type {	/* EEPROM_QUERY: i2cs(ID1, ID0) */
-	EEPROM_TYPE_NONE	= 0,
-	EEPROM_TYPE_SMALL	= 1,
-	EEPROM_TYPE_LARGE	= 2,
-	EEPROM_TYPE_UNUSED	= 3,
-};
-
-enum dev_dest {
-	DEST_NONE	= 0x00,
-	DEST_FPGA	= 0x01,
-	DEST_EEPROM	= 0x02,
-};
-
 #endif	/* MPP_H */
diff --git a/xpp/mpp_funcs.c b/xpp/mpp_funcs.c
deleted file mode 100644
index 457455a..0000000
--- a/xpp/mpp_funcs.c
+++ /dev/null
@@ -1,1109 +0,0 @@
-/*
- * Written by Oron Peled <oron at actcom.co.il>
- * Copyright (C) 2008, 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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-#include <arpa/inet.h>
-#include "hexfile.h"
-#include "astribank_usb.h"
-#include "mpp_funcs.h"
-#include "debug.h"
-
-static const char rcsid[] = "$Id$";
-
-#define	DBG_MASK	0x02
-
-const char *ack_status_msg(uint8_t status)
-{
-	const static char	*msgs[] = {
-		[STAT_OK] = "Acknowledges previous command",
-		[STAT_FAIL] = "Last command failed",
-		[STAT_RESET_FAIL] = "Reset failed",
-		[STAT_NODEST] = "No destination is selected",
-		[STAT_MISMATCH] = "Data mismatch",
-		[STAT_NOACCESS] = "No access",
-		[STAT_BAD_CMD] = "Bad command",
-		[STAT_TOO_SHORT] = "Packet is too short",
-		[STAT_ERROFFS] = "Offset error",
-		[STAT_NOCODE] = "Source was not burned before",
-		[STAT_NO_LEEPROM] = "Large EEPROM was not found",
-		[STAT_NO_EEPROM] = "No EEPROM was found",
-		[STAT_WRITE_FAIL] = "Writing to device failed",
-		[STAT_FPGA_ERR] = "FPGA error",
-		[STAT_KEY_ERR] = "Bad Capabilities Key",
-		[STAT_NOCAPS_ERR]	= "No matching capability",
-		[STAT_NOPWR_ERR]	= "No power on USB connector",
-		[STAT_CAPS_FPGA_ERR]	= "Setting of the capabilities while FPGA is loaded",
-	};
-	if(status > sizeof(msgs)/sizeof(msgs[0]))
-		return "ERROR CODE TOO LARGE";
-	if(!msgs[status])
-		return "MISSING ERROR CODE";
-	return msgs[status];
-}
-
-const char *eeprom_type2str(enum eeprom_type et)
-{
-	const static char	*msgs[] = {
-		[EEPROM_TYPE_NONE]	= "NONE",
-		[EEPROM_TYPE_SMALL]	= "SMALL",
-		[EEPROM_TYPE_LARGE]	= "LARGE",
-		[EEPROM_TYPE_UNUSED]	= "UNUSED",
-	};
-	if(et > sizeof(msgs)/sizeof(msgs[0]))
-		return NULL;
-	return msgs[et];
-};
-
-const char *dev_dest2str(enum dev_dest dest)
-{
-	const static char	*msgs[] = {
-		[DEST_NONE]	= "NONE",
-		[DEST_FPGA]	= "FPGA",
-		[DEST_EEPROM]	= "EEPROM",
-	};
-	if(dest > sizeof(msgs)/sizeof(msgs[0]))
-		return NULL;
-	return msgs[dest];
-};
-
-struct command_desc {
-	uint8_t		op;
-	const char	*name;
-	uint16_t	len;
-};
-
-#define	CMD_RECV(o)	[MPP_ ## o] {	\
-		.op = MPP_ ## o,	\
-		.name = #o,	\
-		.len = sizeof(struct mpp_header) + sizeof(struct d_ ## o),	\
-	}
-
-#define	CMD_SEND(o)	[MPP_ ## o] {	\
-		.op = MPP_ ## o,	\
-		.name = #o,	\
-		.len = sizeof(struct mpp_header) + sizeof(struct d_ ## o),	\
-	}
-
-static const struct command_desc	command_table[] = {
-	CMD_RECV(ACK),
-	CMD_SEND(PROTO_QUERY),
-	CMD_SEND(STATUS_GET),
-	CMD_RECV(STATUS_GET_REPLY),
-	CMD_SEND(EEPROM_SET),
-	CMD_SEND(CAPS_GET),
-	CMD_RECV(CAPS_GET_REPLY),
-	CMD_SEND(CAPS_SET),
-	CMD_SEND(EXTRAINFO_GET),
-	CMD_RECV(EXTRAINFO_GET_REPLY),
-	CMD_SEND(EXTRAINFO_SET),
-	CMD_RECV(PROTO_REPLY),
-	CMD_SEND(RENUM),
-	CMD_SEND(EEPROM_BLK_RD),
-	CMD_RECV(EEPROM_BLK_RD_REPLY),
-	CMD_SEND(DEV_SEND_SEG),
-	CMD_SEND(DEV_SEND_START),
-	CMD_SEND(DEV_SEND_END),
-	CMD_SEND(RESET),
-	CMD_SEND(HALF_RESET),
-	CMD_SEND(SER_SEND),
-	CMD_SEND(SER_RECV),
-	/* Twinstar */
-	CMD_SEND(TWS_WD_MODE_SET),
-	CMD_SEND(TWS_WD_MODE_GET),
-	CMD_RECV(TWS_WD_MODE_GET_REPLY),
-	CMD_SEND(TWS_PORT_SET),
-	CMD_SEND(TWS_PORT_GET),
-	CMD_RECV(TWS_PORT_GET_REPLY),
-	CMD_SEND(TWS_PWR_GET),
-	CMD_RECV(TWS_PWR_GET_REPLY),
-};
-
-static const struct command_desc	command_table_V13[] = {
-	CMD_RECV(ACK),
-	CMD_SEND(PROTO_QUERY),
-	CMD_SEND(STATUS_GET),
-	CMD_RECV(STATUS_GET_REPLY_V13),
-	CMD_SEND(EEPROM_SET),
-	CMD_SEND(CAPS_GET),
-	CMD_RECV(CAPS_GET_REPLY),
-	CMD_SEND(CAPS_SET),
-	CMD_SEND(EXTRAINFO_GET),
-	CMD_RECV(EXTRAINFO_GET_REPLY),
-	CMD_SEND(EXTRAINFO_SET),
-	CMD_RECV(PROTO_REPLY),
-	CMD_SEND(RENUM),
-	CMD_SEND(EEPROM_BLK_RD),
-	CMD_RECV(EEPROM_BLK_RD_REPLY),
-	CMD_SEND(DEV_SEND_SEG),
-	CMD_SEND(DEV_SEND_START),
-	CMD_SEND(DEV_SEND_END),
-	CMD_SEND(RESET),
-	CMD_SEND(HALF_RESET),
-	CMD_SEND(SER_SEND),
-	CMD_SEND(SER_RECV),
-	/* Twinstar */
-	CMD_SEND(TWS_WD_MODE_SET),
-	CMD_SEND(TWS_WD_MODE_GET),
-	CMD_RECV(TWS_WD_MODE_GET_REPLY),
-	CMD_SEND(TWS_PORT_SET),
-	CMD_SEND(TWS_PORT_GET),
-	CMD_RECV(TWS_PORT_GET_REPLY),
-	CMD_SEND(TWS_PWR_GET),
-	CMD_RECV(TWS_PWR_GET_REPLY),
-};
-
-#undef	CMD_SEND
-#undef	CMD_RECV
-
-struct cmd_queue {
-	struct cmd_queue	*next;
-	struct cmd_queue	*prev;
-	struct mpp_command	*cmd;
-};
-
-static struct cmd_queue	output_queue = {
-	.next = &output_queue,
-	.prev = &output_queue,
-	.cmd = NULL
-	};
-
-void free_command(struct mpp_command *cmd)
-{
-	memset(cmd, 0, cmd->header.len);
-	free(cmd);
-}
-
-const struct command_desc *get_command_desc(uint8_t protocol_version, uint8_t op)
-{
-	const struct command_desc	*desc;
-
-	switch(protocol_version) {
-		case MK_PROTO_VERSION(1,3):
-			if(op > sizeof(command_table_V13)/sizeof(command_table_V13[0])) {
-				//ERR("Invalid op=0x%X. Bigger than max valid op\n", op);
-				return NULL;
-			}
-			desc = &command_table_V13[op];
-			if(!desc->name)
-				return NULL;
-			break;
-		default:
-			if(op > sizeof(command_table)/sizeof(command_table[0])) {
-				//ERR("Invalid op=0x%X. Bigger than max valid op\n", op);
-				return NULL;
-			}
-			desc = &command_table[op];
-			if(!desc->name)
-				return NULL;
-			break;
-	}
-	return desc;
-}
-
-struct mpp_command *new_command(uint8_t protocol_version, uint8_t op, uint16_t extra_data)
-{
-	struct mpp_command		*cmd;
-	const struct command_desc	*desc;
-	uint16_t			len;
-
-	desc = get_command_desc(protocol_version, op);
-	if(!desc) {
-		ERR("Unknown op=0x%X.\n", op);
-		return NULL;
-	}
-	DBG("OP=0x%X [%s] (extra_data %d)\n", op, desc->name, extra_data);
-	len = desc->len + extra_data;
-	if((cmd = malloc(len)) == NULL) {
-		ERR("Out of memory\n");
-		return NULL;
-	}
-	cmd->header.op = op;
-	cmd->header.len = len;
-	cmd->header.seq = 0;	/* Overwritten in send_usb() */
-	return cmd;
-}
-
-void dump_command(struct mpp_command *cmd)
-{
-	uint16_t	len;
-	int		i;
-
-	len = cmd->header.len;
-	if(len < sizeof(struct mpp_header)) {
-		ERR("Command too short (%d)\n", len);
-		return;
-	}
-	INFO("DUMP: OP=0x%X len=%d seq=%d\n",
-		cmd->header.op, cmd->header.len, cmd->header.seq);
-	for(i = 0; i < len - sizeof(struct mpp_header); i++) {
-		INFO("  %2d. 0x%X\n", i, cmd->alt.raw_data[i]);
-	}
-}
-
-int send_command(struct astribank_device *astribank, struct mpp_command *cmd, int timeout)
-{
-	int		ret;
-	int		len;
-	char		*buf;
-
-	len = cmd->header.len;
-	cmd->header.seq = astribank->tx_sequenceno;
-
-	buf = (char *)cmd;
-	//printf("%s: len=%d\n", __FUNCTION__, len);
-#if 0
-	extern	FILE	*fp;
-	if(fp) {
-		int	i;
-
-		fprintf(fp, "%05d:", cmd->header.seq);
-		for(i = 0; i < len; i++)
-			fprintf(fp, " %02X", (uint8_t)buf[i]);
-		fprintf(fp, "\n");
-	}
-#endif
-	ret = send_usb(astribank, (char *)cmd, len, timeout);
-	if(ret < 0) {
-		DBG("send_usb failed ret=%d\n", ret);
-	}
-	astribank->tx_sequenceno++;
-	return ret;
-}
-
-struct mpp_command *recv_command(struct astribank_device *astribank, int timeout)
-{
-	struct mpp_command	*reply;
-	int			ret;
-
-	if((reply = malloc(PACKET_SIZE)) == NULL) {
-		ERR("Out of memory\n");
-		goto err;
-	}
-	reply->header.len = 0;
-	ret = recv_usb(astribank, (char *)reply, PACKET_SIZE, timeout);
-	if(ret < 0) {
-		ERR("Receive from usb failed.\n");
-		goto err;
-	} else if(ret == 0) {
-		goto err;	/* No reply */
-	}
-	if(ret != reply->header.len) {
-		ERR("Wrong length received: got %d bytes, but length field says %d bytes%s\n",
-				ret, reply->header.len,
-				(ret == 1)? ". Old USB firmware?": "");
-		goto err;
-	}
-	//dump_packet(LOG_DEBUG, __FUNCTION__, (char *)reply, ret);
-	return reply;
-err:
-	if(reply) {
-		memset(reply, 0, PACKET_SIZE);
-		free_command(reply);
-	}
-	return NULL;
-}
-
-
-__attribute__((warn_unused_result))
-int process_command(struct astribank_device *astribank, struct mpp_command *cmd, struct mpp_command **reply_ref)
-{
-	struct mpp_command		*reply = NULL;
-	const struct command_desc	*reply_desc;
-	const struct command_desc	*expected;
-	const struct command_desc	*cmd_desc;
-	uint8_t				reply_op;
-	int				ret;
-
-	if(reply_ref)
-		*reply_ref = NULL;	/* So the caller knows if a reply was received */
-	reply_op = cmd->header.op | 0x80;
-	if(cmd->header.op == MPP_PROTO_QUERY)
-		astribank->mpp_proto_version = MPP_PROTOCOL_VERSION;	/* bootstrap */
-	cmd_desc = get_command_desc(astribank->mpp_proto_version, cmd->header.op);
-	expected = get_command_desc(astribank->mpp_proto_version, reply_op);
-	//printf("%s: len=%d\n", __FUNCTION__, cmd->header.len);
-	ret = send_command(astribank, cmd, TIMEOUT);
-	if(!reply_ref) {
-		DBG("No reply requested\n");
-		goto out;
-	}
-	if(ret < 0) {
-		ERR("send_command failed: %d\n", ret);
-		goto out;
-	}
-	reply = recv_command(astribank, TIMEOUT);
-	if(!reply) {
-		ERR("recv_command failed\n");
-		ret = -EPROTO;
-		goto out;
-	}
-	*reply_ref = reply;
-	if((reply->header.op & 0x80) != 0x80) {
-		ERR("Unexpected reply op=0x%02X, should have MSB set.\n", reply->header.op);
-		ret = -EPROTO;
-		goto out;
-	}
-	DBG("REPLY OP: 0x%X\n", reply->header.op);
-	reply_desc = get_command_desc(astribank->mpp_proto_version, reply->header.op);
-	if(!reply_desc) {
-		ERR("Unknown reply op=0x%02X\n", reply->header.op);
-		ret = -EPROTO;
-		goto out;
-	}
-	DBG("REPLY NAME: %s\n", reply_desc->name);
-	if(reply->header.op == MPP_ACK) {
-		int	status = CMD_FIELD(reply, ACK, stat);
-
-		if(expected) {
-			ERR("Expected OP=0x%02X: Got ACK(%d): %s\n",
-				reply_op, status, ack_status_msg(status));
-			ret = -EPROTO;
-			goto out;
-		} else if(status != STAT_OK) {
-
-			ERR("Got ACK (for OP=0x%X [%s]): %d - %s\n",
-				cmd->header.op,
-				cmd_desc->name,
-				status,
-				ack_status_msg(status));
-#if 0
-			extern	FILE	*fp;
-			if(fp) {
-				fprintf(fp, "Got ACK(%d)\n", status);
-			}
-#endif
-			ret = -EPROTO;
-			goto out;
-		}
-		/* Good expected ACK ... */
-	} else if(reply->header.op != reply_op) {
-			ERR("Expected OP=0x%02X: Got OP=0x%02X\n",
-				reply_op, reply->header.op);
-			ret = -EPROTO;
-			goto out;
-	}
-	if(expected && expected->op != MPP_SER_RECV && expected->len != reply->header.len) {
-			ERR("Expected len=%d: Got len=%d\n",
-				expected->len, reply->header.len);
-			ret = -EPROTO;
-			goto out;
-	}
-	if(cmd->header.seq != reply->header.seq) {
-			ERR("Expected seq=%d: Got seq=%d\n",
-				cmd->header.seq, reply->header.seq);
-			ret = -EPROTO;
-			goto out;
-	}
-	ret = reply->header.len;	/* All good, return the length */
-	DBG("returning reply op 0x%X (%d bytes)\n", reply->header.op, ret);
-out:
-	free_command(cmd);
-	if(!reply_ref && reply)
-		free_command(reply);
-	return ret;
-}
-
-static int set_ihex_version(char *dst, const char *src)
-{
-	memcpy(dst, src, VERSION_LEN);
-	return 0;
-}
-
-/*
- * Protocol Commands
- */
-
-int mpp_proto_query(struct astribank_device *astribank)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply;
-	int			ret;
-
-	DBG("\n");
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_PROTO_QUERY, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	CMD_FIELD(cmd, PROTO_QUERY, proto_version) = MPP_PROTOCOL_VERSION;	/* Protocol Version */
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	astribank->mpp_proto_version = CMD_FIELD(reply, PROTO_REPLY, proto_version);
-	if(! MPP_SUPPORTED_VERSION(astribank->mpp_proto_version)) {
-		ERR("Got mpp protocol version: %02x (expected %02x)\n",
-			astribank->mpp_proto_version,
-			MPP_PROTOCOL_VERSION);
-		ret = -EPROTO;
-		goto out;
-	}
-	if(astribank->mpp_proto_version != MPP_PROTOCOL_VERSION) {
-		ERR("Deprecated (but working) MPP protocol version [%X]. Please upgrade to [%X] ASAP\n",
-			astribank->mpp_proto_version, MPP_PROTOCOL_VERSION);
-	}
-	DBG("Protocol version: %02x\n", astribank->mpp_proto_version);
-	ret = astribank->mpp_proto_version;
-	free_command(reply);
-out:
-	return ret;
-}
-
-int mpp_status_query(struct astribank_device *astribank)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply;
-	int			ret;
-
-	DBG("\n");
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_STATUS_GET, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	astribank->eeprom_type = 0x3 & (CMD_FIELD(reply, STATUS_GET_REPLY, i2cs_data) >> 3);
-	astribank->status = CMD_FIELD(reply, STATUS_GET_REPLY, status);
-	astribank->fw_versions = CMD_FIELD(reply, STATUS_GET_REPLY, fw_versions);
-	DBG("EEPROM TYPE: %02x\n", astribank->eeprom_type);
-	DBG("FPGA Firmware: %s\n", (astribank->status & 0x1) ? "Loaded" : "Empty");
-	DBG("Firmware Versions: USB='%s' FPGA='%s' EEPROM='%s'\n",
-		astribank->fw_versions.usb,
-		astribank->fw_versions.fpga,
-		astribank->fw_versions.eeprom);
-	free_command(reply);
-	return ret;
-}
-
-int mpp_eeprom_set(struct astribank_device *astribank, const struct eeprom_table *et)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply;
-	int			ret;
-
-	DBG("\n");
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_EEPROM_SET, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	memcpy(&CMD_FIELD(cmd, EEPROM_SET, data), et, sizeof(*et));
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	free_command(reply);
-	return 0;
-}
-
-int mpp_renumerate(struct astribank_device *astribank)
-{
-	struct mpp_command	*cmd;
-	int			ret;
-
-	DBG("\n");
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_RENUM, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	ret = process_command(astribank, cmd, NULL);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	return 0;
-}
-
-int mpp_caps_get(struct astribank_device *astribank,
-	struct eeprom_table *eeprom_table,
-	struct capabilities *capabilities,
-	struct capkey *key)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply;
-	int			ret;
-
-	DBG("\n");
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_CAPS_GET, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	assert(reply->header.op == MPP_CAPS_GET_REPLY);
-	if(eeprom_table) {
-		memcpy(eeprom_table, (void *)&CMD_FIELD(reply, CAPS_GET_REPLY, data), sizeof(*eeprom_table));
-	}
-	if(capabilities) {
-		const struct capabilities	*cap = &CMD_FIELD(reply, CAPS_GET_REPLY, capabilities);
-
-		memcpy(capabilities, cap, sizeof(*capabilities));
-	}
-	if(key) {
-		const struct capkey	*k = &CMD_FIELD(reply, CAPS_GET_REPLY, key);
-
-		memcpy(key, k, sizeof(*key));
-	}
-	free_command(reply);
-	return 0;
-}
-
-int mpp_caps_set(struct astribank_device *astribank,
-	const struct eeprom_table *eeprom_table,
-	const struct capabilities *capabilities,
-	const struct capkey *key)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply;
-	int			ret;
-
-	DBG("\n");
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_CAPS_SET, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	memcpy(&CMD_FIELD(cmd, CAPS_SET, data), eeprom_table, sizeof(*eeprom_table));
-	memcpy(&CMD_FIELD(cmd, CAPS_SET, capabilities), capabilities, sizeof(*capabilities));
-	memcpy(&CMD_FIELD(cmd, CAPS_SET, key), key, sizeof(*key));
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	free_command(reply);
-	return 0;
-}
-
-int mpp_extrainfo_get(struct astribank_device *astribank, struct extrainfo *info)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply;
-	int			ret;
-
-	DBG("\n");
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_EXTRAINFO_GET, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	assert(reply->header.op == MPP_EXTRAINFO_GET_REPLY);
-	if(info) {
-		memcpy(info, (void *)&CMD_FIELD(reply, EXTRAINFO_GET_REPLY, info), sizeof(*info));
-	}
-	free_command(reply);
-	return 0;
-}
-
-int mpp_extrainfo_set(struct astribank_device *astribank, const struct extrainfo *info)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply;
-	int			ret;
-
-	DBG("\n");
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_EXTRAINFO_SET, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	memcpy(&CMD_FIELD(cmd, EXTRAINFO_SET, info), info, sizeof(*info));
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	free_command(reply);
-	return 0;
-}
-
-int mpp_eeprom_blk_rd(struct astribank_device *astribank, uint8_t *buf, uint16_t offset, uint16_t len)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply;
-	int			ret;
-	int			size;
-
-	DBG("len = %d, offset = %d\n", len, offset);
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_EEPROM_BLK_RD, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	CMD_FIELD(cmd, EEPROM_BLK_RD, len) = len;
-	CMD_FIELD(cmd, EEPROM_BLK_RD, offset) = offset;
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		size = ret;
-		goto out;
-	}
-	size = reply->header.len - sizeof(struct mpp_header) - sizeof(struct d_EEPROM_BLK_RD_REPLY);
-	INFO("size=%d offset=0x%X\n", size, CMD_FIELD(reply, EEPROM_BLK_RD_REPLY, offset));
-	dump_packet(LOG_DEBUG, "BLK_RD", (char *)reply, ret);
-	if(size > len) {
-		ERR("Truncating reply (was %d, now %d)\n", size, len);
-		size = len;
-	}
-	memcpy(buf, CMD_FIELD(reply, EEPROM_BLK_RD_REPLY, data), size);
-out:
-	free_command(reply);
-	return size;
-}
-
-int mpp_send_start(struct astribank_device *astribank, enum dev_dest dest, const char *ihex_version)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply = NULL;
-	int			ret = 0;
-
-	DBG("dest = %s ihex_version = '%s'\n", dev_dest2str(dest), ihex_version);
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_DEV_SEND_START, 0)) == NULL) {
-		ERR("new_command failed\n");
-		ret = -ENOMEM;
-		goto out;
-	}
-	CMD_FIELD(cmd, DEV_SEND_START, dest) = dest;
-	set_ihex_version(CMD_FIELD(cmd, DEV_SEND_START, ihex_version), ihex_version);
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		goto out;
-	}
-out:
-	if(reply)
-		free_command(reply);
-	astribank->burn_state = (ret == 0)
-		? BURN_STATE_STARTED
-		: BURN_STATE_FAILED;
-	return ret;
-}
-
-int mpp_send_end(struct astribank_device *astribank)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply = NULL;
-	int			ret = 0;
-
-	DBG("\n");
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_DEV_SEND_END, 0)) == NULL) {
-		ERR("new_command failed\n");
-		ret = -ENOMEM;
-		goto out;
-	}
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		goto out;
-	}
-out:
-	if(reply)
-		free_command(reply);
-	astribank->burn_state = (ret == 0)
-		? BURN_STATE_ENDED
-		: BURN_STATE_FAILED;
-	return ret;
-}
-
-int mpp_send_seg(struct astribank_device *astribank, const uint8_t *data, uint16_t offset, uint16_t len)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply;
-	int			ret;
-
-	if(!astribank->burn_state == BURN_STATE_STARTED) {
-		ERR("Tried to send a segment while burn_state=%d\n",
-				astribank->burn_state);
-		return -EINVAL;
-	}
-	DBG("len = %d, offset = %d (0x%02X, 0x%02X)\n", len, offset, *data, *(data + 1));
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_DEV_SEND_SEG, len)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	CMD_FIELD(cmd, DEV_SEND_SEG, offset) = offset;
-	memcpy(CMD_FIELD(cmd, DEV_SEND_SEG, data), data, len);
-#if 0
-	{
-		FILE			*fp;
-		if((fp = fopen("seg_data.bin", "a")) == NULL) {
-			perror("seg_data.bin");
-			exit(1);
-		}
-		if(fwrite(CMD_FIELD(cmd, DEV_SEND_SEG, data), len, 1, fp) != 1) {
-			perror("fwrite");
-			exit(1);
-		}
-		fclose(fp);
-	}
-#endif
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	free_command(reply);
-	return 0;
-}
-
-int mpp_reset(struct astribank_device *astribank, int full_reset)
-{
-	struct mpp_command	*cmd;
-	int			ret;
-	int			op = (full_reset) ? MPP_RESET: MPP_HALF_RESET;
-
-	DBG("full = %s\n", (full_reset) ? "YES" : "NO");
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, op, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	ret = process_command(astribank, cmd, NULL);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	return 0;
-}
-
-int mpp_serial_cmd(struct astribank_device *astribank, const uint8_t *in, uint8_t *out, uint16_t len)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply;
-	int			ret;
-	uint8_t			*data;
-
-	DBG("len=%d\n", len);
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_SER_SEND, len)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	data = CMD_FIELD(cmd, SER_SEND, data);
-	memcpy(data, in, len);
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	assert(reply->header.op == MPP_SER_RECV);
-	data = CMD_FIELD(reply, SER_RECV, data);
-	memcpy(out, data, len);
-	free_command(reply);
-	return 0;
-}
-
-int mpps_card_info(struct astribank_device *astribank, int unit, uint8_t *card_type, uint8_t *card_status)
-{
-	struct card_info_send {
-		uint8_t	ser_op;
-		uint8_t	addr;
-	} *card_info_send;
-	struct card_info_recv {
-		uint8_t	ser_op_undef;	/* invalid data */
-		uint8_t	addr;
-		uint8_t	card_full_type;	/* (type << 4 | subtype) */
-		uint8_t	card_status;	/* BIT(0) - PIC burned */
-	} *card_info_recv;
-	uint8_t	in[sizeof(struct card_info_recv)];
-	uint8_t	out[sizeof(struct card_info_recv)];
-	int	len;
-	int	ret;
-
-	len = sizeof(struct card_info_recv);
-	memset(in, 0, len);
-	memset(out, 0, len);
-	card_info_send = (struct card_info_send *)∈
-	card_info_recv = (struct card_info_recv *)&out;
-	card_info_send->ser_op = SER_CARD_INFO_GET;
-	card_info_send->addr = (unit << 4);	/* low nibble is subunit */
-	ret = mpp_serial_cmd(astribank, in, out, len);
-	if(ret < 0)
-		return ret;
-	*card_type = card_info_recv->card_full_type;
-	*card_status = card_info_recv->card_status;
-	return 0;
-}
-
-int mpp_tws_watchdog(struct astribank_device *astribank)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply;
-	int			ret;
-
-	DBG("\n");
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_WD_MODE_GET, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	ret = CMD_FIELD(reply, TWS_WD_MODE_GET_REPLY, wd_active);
-	DBG("wd_active=0x%X\n", ret);
-	free_command(reply);
-	return ret == 1;
-}
-
-int mpp_tws_setwatchdog(struct astribank_device *astribank, int yes)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply;
-	int			ret;
-
-	DBG("%s\n", (yes) ? "YES" : "NO");
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_WD_MODE_SET, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	CMD_FIELD(cmd, TWS_WD_MODE_SET, wd_active) = (yes) ? 1 : 0;
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	free_command(reply);
-	return 0;
-}
-
-int mpp_tws_powerstate(struct astribank_device *astribank)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply;
-	int			ret;
-
-	DBG("\n");
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_PWR_GET, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	ret = CMD_FIELD(reply, TWS_PWR_GET_REPLY, power);
-	DBG("power=0x%X\n", ret);
-	free_command(reply);
-	return ret;
-}
-
-int mpp_tws_portnum(struct astribank_device *astribank)
-{
-	struct mpp_command	*cmd;
-	struct mpp_command	*reply;
-	int			ret;
-
-	DBG("\n");
-	assert(astribank != NULL);
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_PORT_GET, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	ret = process_command(astribank, cmd, &reply);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	ret = CMD_FIELD(reply, TWS_PORT_GET_REPLY, portnum);
-	DBG("portnum=0x%X\n", ret);
-	free_command(reply);
-	return ret;
-}
-
-int mpp_tws_setportnum(struct astribank_device *astribank, uint8_t portnum)
-{
-	struct mpp_command	*cmd;
-	int			ret;
-
-	DBG("\n");
-	assert(astribank != NULL);
-	if(portnum >= 2) {
-		ERR("Invalid portnum (%d)\n", portnum);
-		return -EINVAL;
-	}
-	if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_PORT_SET, 0)) == NULL) {
-		ERR("new_command failed\n");
-		return -ENOMEM;
-	}
-	CMD_FIELD(cmd, TWS_PORT_SET, portnum) = portnum;
-	ret = process_command(astribank, cmd, NULL);
-	if(ret < 0) {
-		ERR("process_command failed: %d\n", ret);
-		return ret;
-	}
-	return 0;
-}
-
-/*
- * Wrappers
- */
-
-struct astribank_device *mpp_init(const char devpath[])
-{
-	struct astribank_device *astribank;
-	int			ret;
-
-	DBG("devpath='%s'\n", devpath);
-	if((astribank = astribank_open(devpath, 1)) == NULL) {
-		ERR("Opening astribank failed\n");
-		return NULL;
-	}
-	ret = mpp_proto_query(astribank);
-	if(ret < 0) {
-		ERR("Protocol handshake failed: %d\n", ret);
-		goto err;
-	}
-	ret = mpp_status_query(astribank);
-	if(ret < 0) {
-		ERR("Status query failed: %d\n", ret);
-		goto err;
-	}
-	return astribank;
-
-err:
-	if (astribank)
-		astribank_close(astribank, 0);
-	return NULL;
-}
-
-void mpp_exit(struct astribank_device *astribank)
-{
-	DBG("\n");
-	astribank_close(astribank, 0);
-}
-
-/*
- * data structures
- */
-
-void show_eeprom(const struct eeprom_table *eprm, FILE *fp)
-{
-	int	rmajor = (eprm->release >> 8) & 0xFF;
-	int	rminor = eprm->release & 0xFF;;
-	char	buf[BUFSIZ];
-
-	memset(buf, 0, LABEL_SIZE + 1);
-	memcpy(buf, eprm->label, LABEL_SIZE);
-	fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Source", eprm->source);
-	fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Vendor", eprm->vendor);
-	fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Product", eprm->product);
-	fprintf(fp, "EEPROM: %-15s: %d.%d\n", "Release", rmajor, rminor);
-	fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Config", eprm->config_byte);
-	fprintf(fp, "EEPROM: %-15s: '%s'\n", "Label", buf);
-}
-
-void show_capabilities(const struct capabilities *capabilities, FILE *fp)
-{
-	fprintf(fp, "Capabilities: FXS ports: %2d\n", capabilities->ports_fxs);
-	fprintf(fp, "Capabilities: FXO ports: %2d\n", capabilities->ports_fxo);
-	fprintf(fp, "Capabilities: BRI ports: %2d\n", capabilities->ports_bri);
-	fprintf(fp, "Capabilities: PRI ports: %2d\n", capabilities->ports_pri);
-	fprintf(fp, "Capabilities: TwinStar : %s\n",
-		(CAP_EXTRA_TWINSTAR(capabilities)) ? "Yes" : "No");
-}
-
-void show_astribank_status(struct astribank_device *astribank, FILE *fp)
-{
-	char	version_buf[BUFSIZ];
-	int	is_loaded = STATUS_FPGA_LOADED(astribank->status);
-
-	fprintf(fp, "Astribank: EEPROM      : %s\n",
-		eeprom_type2str(astribank->eeprom_type));
-	fprintf(fp, "Astribank: FPGA status : %s\n",
-		is_loaded ? "Loaded" : "Empty");
-	if(is_loaded) {
-		memset(version_buf, 0, sizeof(version_buf));
-		memcpy(version_buf, astribank->fw_versions.fpga, VERSION_LEN);
-		fprintf(fp, "Astribank: FPGA version: %s\n",
-			version_buf);
-	}
-}
-
-void show_extrainfo(const struct extrainfo *extrainfo, FILE *fp)
-{
-	fprintf(fp, "Extrainfo:             : %s\n", (const char *)(extrainfo->text));
-}
-
-int twinstar_show(struct astribank_device *astribank, FILE *fp)
-{
-	int	watchdog;
-	int	powerstate;
-	int	portnum;
-	int	i;
-
-	if(!astribank_has_twinstar(astribank)) {
-		fprintf(fp, "TwinStar: NO\n");
-		return 0;
-	}
-	if((watchdog = mpp_tws_watchdog(astribank)) < 0) {
-		ERR("Failed getting TwinStar information\n");
-		return watchdog;
-	}
-	if((powerstate = mpp_tws_powerstate(astribank)) < 0) {
-		ERR("Failed getting TwinStar powerstate\n");
-		return powerstate;
-	}
-	if((portnum = mpp_tws_portnum(astribank)) < 0) {
-		ERR("Failed getting TwinStar portnum\n");
-		return portnum;
-	}
-	fprintf(fp, "TwinStar: Connected to : USB-%1d\n", portnum);
-	fprintf(fp, "TwinStar: Watchdog     : %s\n",
-		(watchdog) ? "on-guard" : "off-guard");
-	for(i = 0; i < 2; i++) {
-		int	pw = (1 << i) & powerstate; 
-
-		fprintf(fp, "TwinStar: USB-%1d POWER  : %s\n",
-			i, (pw) ? "ON" : "OFF");
-	}
-	return 0;
-}
-
diff --git a/xpp/mpptalk.c b/xpp/mpptalk.c
new file mode 100644
index 0000000..a8bf12a
--- /dev/null
+++ b/xpp/mpptalk.c
@@ -0,0 +1,915 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008, 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 <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include "hexfile.h"
+#include "astribank_usb.h"
+#include "mpp.h"
+#include "mpptalk.h"
+#include <debug.h>
+#include <xusb.h>
+#include <xtalk.h>
+
+static const char rcsid[] = "$Id$";
+
+#define	DBG_MASK	0x02
+
+const char *ack_status_msg(uint8_t status)
+{
+	const static char	*msgs[] = {
+		[STAT_OK] = "Acknowledges previous command",
+		[STAT_FAIL] = "Last command failed",
+		[STAT_RESET_FAIL] = "Reset failed",
+		[STAT_NODEST] = "No destination is selected",
+		[STAT_MISMATCH] = "Data mismatch",
+		[STAT_NOACCESS] = "No access",
+		[STAT_BAD_CMD] = "Bad command",
+		[STAT_TOO_SHORT] = "Packet is too short",
+		[STAT_ERROFFS] = "Offset error",
+		[STAT_NOCODE] = "Source was not burned before",
+		[STAT_NO_LEEPROM] = "Large EEPROM was not found",
+		[STAT_NO_EEPROM] = "No EEPROM was found",
+		[STAT_WRITE_FAIL] = "Writing to device failed",
+		[STAT_FPGA_ERR] = "FPGA error",
+		[STAT_KEY_ERR] = "Bad Capabilities Key",
+		[STAT_NOCAPS_ERR]	= "No matching capability",
+		[STAT_NOPWR_ERR]	= "No power on USB connector",
+		[STAT_CAPS_FPGA_ERR]	= "Setting of the capabilities while FPGA is loaded",
+	};
+	if(status > sizeof(msgs)/sizeof(msgs[0]))
+		return "ERROR CODE TOO LARGE";
+	if(!msgs[status])
+		return "MISSING ERROR CODE";
+	return msgs[status];
+}
+
+const char *eeprom_type2str(int et)
+{
+	const static char	*msgs[] = {
+		[EEPROM_TYPE_NONE]	= "NONE",
+		[EEPROM_TYPE_SMALL]	= "SMALL",
+		[EEPROM_TYPE_LARGE]	= "LARGE",
+		[EEPROM_TYPE_UNUSED]	= "UNUSED",
+	};
+	if(et > sizeof(msgs)/sizeof(msgs[0]))
+		return NULL;
+	return msgs[et];
+};
+
+const char *dev_dest2str(int dest)
+{
+	const static char	*msgs[] = {
+		[DEST_NONE]	= "NONE",
+		[DEST_FPGA]	= "FPGA",
+		[DEST_EEPROM]	= "EEPROM",
+	};
+	if(dest > sizeof(msgs)/sizeof(msgs[0]))
+		return NULL;
+	return msgs[dest];
+};
+
+union XTALK_PDATA(MPP) {
+		MEMBER(MPP, STATUS_GET);
+		MEMBER(MPP, STATUS_GET_REPLY);
+		MEMBER(MPP, EEPROM_SET);
+		MEMBER(MPP, CAPS_GET);
+		MEMBER(MPP, CAPS_GET_REPLY);
+		MEMBER(MPP, CAPS_SET);
+		MEMBER(MPP, EXTRAINFO_GET);
+		MEMBER(MPP, EXTRAINFO_GET_REPLY);
+		MEMBER(MPP, EXTRAINFO_SET);
+		MEMBER(MPP, RENUM);
+		MEMBER(MPP, EEPROM_BLK_RD);
+		MEMBER(MPP, EEPROM_BLK_RD_REPLY);
+		MEMBER(MPP, DEV_SEND_SEG);
+		MEMBER(MPP, DEV_SEND_START);
+		MEMBER(MPP, DEV_SEND_END);
+		MEMBER(MPP, RESET);
+		MEMBER(MPP, HALF_RESET);
+		MEMBER(MPP, SER_SEND);
+		MEMBER(MPP, SER_RECV);
+		/* Twinstar */
+		MEMBER(MPP, TWS_WD_MODE_SET);
+		MEMBER(MPP, TWS_WD_MODE_GET);
+		MEMBER(MPP, TWS_WD_MODE_GET_REPLY);
+		MEMBER(MPP, TWS_PORT_SET);
+		MEMBER(MPP, TWS_PORT_GET);
+		MEMBER(MPP, TWS_PORT_GET_REPLY);
+		MEMBER(MPP, TWS_PWR_GET);
+		MEMBER(MPP, TWS_PWR_GET_REPLY);
+} PACKED members;
+
+struct xtalk_protocol	astribank_proto = {
+	.name	= "ABNK",
+	.proto_version = 0x14,
+	.commands = {
+		CMD_SEND(MPP, STATUS_GET),
+		CMD_RECV(MPP, STATUS_GET_REPLY, NULL),
+		CMD_SEND(MPP, EEPROM_SET),
+		CMD_SEND(MPP, CAPS_GET),
+		CMD_RECV(MPP, CAPS_GET_REPLY, NULL),
+		CMD_SEND(MPP, CAPS_SET),
+		CMD_SEND(MPP, EXTRAINFO_GET),
+		CMD_RECV(MPP, EXTRAINFO_GET_REPLY, NULL),
+		CMD_SEND(MPP, EXTRAINFO_SET),
+		CMD_SEND(MPP, RENUM),
+		CMD_SEND(MPP, EEPROM_BLK_RD),
+		CMD_RECV(MPP, EEPROM_BLK_RD_REPLY, NULL),
+		CMD_SEND(MPP, DEV_SEND_SEG),
+		CMD_SEND(MPP, DEV_SEND_START),
+		CMD_SEND(MPP, DEV_SEND_END),
+		CMD_SEND(MPP, RESET),
+		CMD_SEND(MPP, HALF_RESET),
+		CMD_SEND(MPP, SER_SEND),
+		CMD_SEND(MPP, SER_RECV),
+		/* Twinstar */
+		CMD_SEND(MPP, TWS_WD_MODE_SET),
+		CMD_SEND(MPP, TWS_WD_MODE_GET),
+		CMD_RECV(MPP, TWS_WD_MODE_GET_REPLY, NULL),
+		CMD_SEND(MPP, TWS_PORT_SET),
+		CMD_SEND(MPP, TWS_PORT_GET),
+		CMD_RECV(MPP, TWS_PORT_GET_REPLY, NULL),
+		CMD_SEND(MPP, TWS_PWR_GET),
+		CMD_RECV(MPP, TWS_PWR_GET_REPLY, NULL),
+	},
+	.ack_statuses = {
+	}
+};
+
+struct cmd_queue {
+	struct cmd_queue	*next;
+	struct cmd_queue	*prev;
+	struct xtalk_command	*cmd;
+};
+
+static struct cmd_queue	output_queue = {
+	.next = &output_queue,
+	.prev = &output_queue,
+	.cmd = NULL
+	};
+
+void dump_command(struct xtalk_command *cmd)
+{
+	uint16_t	len;
+	int		i;
+
+	len = cmd->header.len;
+	if(len < sizeof(struct mpp_header)) {
+		ERR("Command too short (%d)\n", len);
+		return;
+	}
+	INFO("DUMP: OP=0x%X len=%d seq=%d\n",
+		cmd->header.op, cmd->header.len, cmd->header.seq);
+	for(i = 0; i < len - sizeof(struct mpp_header); i++) {
+		INFO("  %2d. 0x%X\n", i, cmd->alt.raw_data[i]);
+	}
+}
+
+
+static int set_ihex_version(char *dst, const char *src)
+{
+	memcpy(dst, src, VERSION_LEN);
+	return 0;
+}
+
+/*
+ * Protocol Commands
+ */
+
+int mpp_status_query(struct astribank_device *astribank)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_STATUS_GET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	astribank->eeprom_type = 0x3 & (CMD_FIELD(reply, MPP, STATUS_GET_REPLY, i2cs_data) >> 3);
+	astribank->status = CMD_FIELD(reply, MPP, STATUS_GET_REPLY, status);
+	astribank->fw_versions = CMD_FIELD(reply, MPP, STATUS_GET_REPLY, fw_versions);
+	DBG("EEPROM TYPE: %02x\n", astribank->eeprom_type);
+	DBG("FPGA Firmware: %s\n", (astribank->status & 0x1) ? "Loaded" : "Empty");
+	DBG("Firmware Versions: USB='%s' FPGA='%s' EEPROM='%s'\n",
+		astribank->fw_versions.usb,
+		astribank->fw_versions.fpga,
+		astribank->fw_versions.eeprom);
+	free_command(reply);
+	return ret;
+}
+
+int mpp_eeprom_set(struct astribank_device *astribank, const struct eeprom_table *et)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_EEPROM_SET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	memcpy(&CMD_FIELD(cmd, MPP, EEPROM_SET, data), et, sizeof(*et));
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	free_command(reply);
+	return 0;
+}
+
+int mpp_renumerate(struct astribank_device *astribank)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_RENUM, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(xtalk_dev, cmd, NULL);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+int mpp_caps_get(struct astribank_device *astribank,
+	struct eeprom_table *eeprom_table,
+	struct capabilities *capabilities,
+	struct capkey *key)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_CAPS_GET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	assert(reply->header.op == MPP_CAPS_GET_REPLY);
+	if(eeprom_table) {
+		memcpy(eeprom_table, (void *)&CMD_FIELD(reply, MPP, CAPS_GET_REPLY, data), sizeof(*eeprom_table));
+	}
+	if(capabilities) {
+		const struct capabilities	*cap = &CMD_FIELD(reply, MPP, CAPS_GET_REPLY, capabilities);
+
+		memcpy(capabilities, cap, sizeof(*capabilities));
+	}
+	if(key) {
+		const struct capkey	*k = &CMD_FIELD(reply, MPP, CAPS_GET_REPLY, key);
+
+		memcpy(key, k, sizeof(*key));
+	}
+	free_command(reply);
+	return 0;
+}
+
+int mpp_caps_set(struct astribank_device *astribank,
+	const struct eeprom_table *eeprom_table,
+	const struct capabilities *capabilities,
+	const struct capkey *key)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_CAPS_SET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, data), eeprom_table, sizeof(*eeprom_table));
+	memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, capabilities), capabilities, sizeof(*capabilities));
+	memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, key), key, sizeof(*key));
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	free_command(reply);
+	return 0;
+}
+
+int mpp_extrainfo_get(struct astribank_device *astribank, struct extrainfo *info)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_EXTRAINFO_GET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	assert(reply->header.op == MPP_EXTRAINFO_GET_REPLY);
+	if(info) {
+		memcpy(info, (void *)&CMD_FIELD(reply, MPP, EXTRAINFO_GET_REPLY, info), sizeof(*info));
+	}
+	free_command(reply);
+	return 0;
+}
+
+int mpp_extrainfo_set(struct astribank_device *astribank, const struct extrainfo *info)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_EXTRAINFO_SET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	memcpy(&CMD_FIELD(cmd, MPP, EXTRAINFO_SET, info), info, sizeof(*info));
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	free_command(reply);
+	return 0;
+}
+
+int mpp_eeprom_blk_rd(struct astribank_device *astribank, uint8_t *buf, uint16_t offset, uint16_t len)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+	int			size;
+
+	DBG("len = %d, offset = %d\n", len, offset);
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_EEPROM_BLK_RD, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	CMD_FIELD(cmd, MPP, EEPROM_BLK_RD, len) = len;
+	CMD_FIELD(cmd, MPP, EEPROM_BLK_RD, offset) = offset;
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		size = ret;
+		goto out;
+	}
+	size = reply->header.len - sizeof(struct mpp_header) - sizeof(XTALK_STRUCT(MPP, EEPROM_BLK_RD_REPLY));
+	INFO("size=%d offset=0x%X\n", size, CMD_FIELD(reply, MPP, EEPROM_BLK_RD_REPLY, offset));
+	dump_packet(LOG_DEBUG, DBG_MASK, "BLK_RD", (char *)reply, ret);
+	if(size > len) {
+		ERR("Truncating reply (was %d, now %d)\n", size, len);
+		size = len;
+	}
+	memcpy(buf, CMD_FIELD(reply, MPP, EEPROM_BLK_RD_REPLY, data), size);
+out:
+	free_command(reply);
+	return size;
+}
+
+int mpp_send_start(struct astribank_device *astribank, int dest, const char *ihex_version)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply = NULL;
+	struct xtalk_device	*xtalk_dev;
+	int			ret = 0;
+
+	DBG("dest = %s ihex_version = '%s'\n", dev_dest2str(dest), ihex_version);
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_DEV_SEND_START, 0)) == NULL) {
+		ERR("new_command failed\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	CMD_FIELD(cmd, MPP, DEV_SEND_START, dest) = dest;
+	set_ihex_version(CMD_FIELD(cmd, MPP, DEV_SEND_START, ihex_version), ihex_version);
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		goto out;
+	}
+out:
+	if(reply)
+		free_command(reply);
+	astribank->burn_state = (ret == 0)
+		? BURN_STATE_STARTED
+		: BURN_STATE_FAILED;
+	return ret;
+}
+
+int mpp_send_end(struct astribank_device *astribank)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply = NULL;
+	struct xtalk_device	*xtalk_dev;
+	int			ret = 0;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_DEV_SEND_END, 0)) == NULL) {
+		ERR("new_command failed\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		goto out;
+	}
+out:
+	if(reply)
+		free_command(reply);
+	astribank->burn_state = (ret == 0)
+		? BURN_STATE_ENDED
+		: BURN_STATE_FAILED;
+	return ret;
+}
+
+int mpp_send_seg(struct astribank_device *astribank, const uint8_t *data, uint16_t offset, uint16_t len)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if(!astribank->burn_state == BURN_STATE_STARTED) {
+		ERR("Tried to send a segment while burn_state=%d\n",
+				astribank->burn_state);
+		return -EINVAL;
+	}
+	DBG("len = %d, offset = %d (0x%02X, 0x%02X)\n", len, offset, *data, *(data + 1));
+	if((cmd = new_command(xtalk_dev, MPP_DEV_SEND_SEG, len)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	CMD_FIELD(cmd, MPP, DEV_SEND_SEG, offset) = offset;
+	memcpy(CMD_FIELD(cmd, MPP, DEV_SEND_SEG, data), data, len);
+#if 0
+	{
+		FILE			*fp;
+		if((fp = fopen("seg_data.bin", "a")) == NULL) {
+			perror("seg_data.bin");
+			exit(1);
+		}
+		if(fwrite(CMD_FIELD(cmd, MPP, DEV_SEND_SEG, data), len, 1, fp) != 1) {
+			perror("fwrite");
+			exit(1);
+		}
+		fclose(fp);
+	}
+#endif
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	free_command(reply);
+	return 0;
+}
+
+int mpp_reset(struct astribank_device *astribank, int full_reset)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+	int			op = (full_reset) ? MPP_RESET: MPP_HALF_RESET;
+
+	DBG("full = %s\n", (full_reset) ? "YES" : "NO");
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, op, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(xtalk_dev, cmd, NULL);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+int mpp_serial_cmd(struct astribank_device *astribank, const uint8_t *in, uint8_t *out, uint16_t len)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+	uint8_t			*data;
+
+	DBG("len=%d\n", len);
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_SER_SEND, len)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	data = CMD_FIELD(cmd, MPP, SER_SEND, data);
+	memcpy(data, in, len);
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	assert(reply->header.op == MPP_SER_RECV);
+	data = CMD_FIELD(reply, MPP, SER_RECV, data);
+	memcpy(out, data, len);
+	free_command(reply);
+	return 0;
+}
+
+int mpps_card_info(struct astribank_device *astribank, int unit, uint8_t *card_type, uint8_t *card_status)
+{
+	struct card_info_send {
+		uint8_t	ser_op;
+		uint8_t	addr;
+	} *card_info_send;
+	struct card_info_recv {
+		uint8_t	ser_op_undef;	/* invalid data */
+		uint8_t	addr;
+		uint8_t	card_full_type;	/* (type << 4 | subtype) */
+		uint8_t	card_status;	/* BIT(0) - PIC burned */
+	} *card_info_recv;
+	uint8_t	in[sizeof(struct card_info_recv)];
+	uint8_t	out[sizeof(struct card_info_recv)];
+	int	len;
+	int	ret;
+
+	len = sizeof(struct card_info_recv);
+	memset(in, 0, len);
+	memset(out, 0, len);
+	card_info_send = (struct card_info_send *)∈
+	card_info_recv = (struct card_info_recv *)&out;
+	card_info_send->ser_op = SER_CARD_INFO_GET;
+	card_info_send->addr = (unit << 4);	/* low nibble is subunit */
+	ret = mpp_serial_cmd(astribank, in, out, len);
+	if(ret < 0)
+		return ret;
+	*card_type = card_info_recv->card_full_type;
+	*card_status = card_info_recv->card_status;
+	return 0;
+}
+
+int mpp_tws_watchdog(struct astribank_device *astribank)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_TWS_WD_MODE_GET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	ret = CMD_FIELD(reply, MPP, TWS_WD_MODE_GET_REPLY, wd_active);
+	DBG("wd_active=0x%X\n", ret);
+	free_command(reply);
+	return ret == 1;
+}
+
+int mpp_tws_setwatchdog(struct astribank_device *astribank, int yes)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+
+	DBG("%s\n", (yes) ? "YES" : "NO");
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_TWS_WD_MODE_SET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	CMD_FIELD(cmd, MPP, TWS_WD_MODE_SET, wd_active) = (yes) ? 1 : 0;
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	free_command(reply);
+	return 0;
+}
+
+int mpp_tws_powerstate(struct astribank_device *astribank)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_TWS_PWR_GET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	ret = CMD_FIELD(reply, MPP, TWS_PWR_GET_REPLY, power);
+	DBG("power=0x%X\n", ret);
+	free_command(reply);
+	return ret;
+}
+
+int mpp_tws_portnum(struct astribank_device *astribank)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_command	*reply;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if((cmd = new_command(xtalk_dev, MPP_TWS_PORT_GET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	ret = CMD_FIELD(reply, MPP, TWS_PORT_GET_REPLY, portnum);
+	DBG("portnum=0x%X\n", ret);
+	free_command(reply);
+	return ret;
+}
+
+int mpp_tws_setportnum(struct astribank_device *astribank, uint8_t portnum)
+{
+	struct xtalk_command	*cmd;
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	xtalk_dev = astribank->xtalk_dev;
+	if(portnum >= 2) {
+		ERR("Invalid portnum (%d)\n", portnum);
+		return -EINVAL;
+	}
+	if((cmd = new_command(xtalk_dev, MPP_TWS_PORT_SET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	CMD_FIELD(cmd, MPP, TWS_PORT_SET, portnum) = portnum;
+	ret = process_command(xtalk_dev, cmd, NULL);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+/* Adapters for xusb ops */
+static inline int xusb_close_func(void *priv)
+{
+	return xusb_close((struct xusb *)priv);
+}
+
+static inline int xusb_send_func(void *priv, void *data, size_t len, int timeout)
+{
+	return xusb_send((struct xusb *)priv, data, len, timeout);
+}
+
+static inline int xusb_recv_func(void *priv, void *data, size_t maxlen, int timeout)
+{
+	return xusb_recv((struct xusb *)priv, data, maxlen, timeout);
+}
+
+
+static struct xtalk_ops	xusb_ops = {
+	.send_func	= xusb_send_func,
+	.recv_func	= xusb_recv_func,
+	.close_func	= xusb_close_func,
+};
+
+/*
+ * Wrappers
+ */
+
+struct astribank_device *mpp_init(const char devpath[], int iface_num)
+{
+	struct astribank_device *astribank = NULL;
+	struct xtalk_device	*xtalk_dev = NULL;
+	struct xusb		*xusb = NULL;
+	int			packet_size;
+	int			ret;
+
+	DBG("devpath='%s' iface_num=%d\n", devpath, iface_num);
+	if((astribank = astribank_open(devpath, iface_num)) == NULL) {
+		ERR("Opening astribank failed\n");
+		goto err;
+	}
+	xusb = astribank->xusb;
+	packet_size = xusb_packet_size(xusb);
+	if((xtalk_dev = xtalk_new(&xusb_ops, packet_size, xusb)) == NULL) {
+		ERR("Allocating new XTALK device failed\n");
+		goto err;
+	}
+	astribank->xtalk_dev = xtalk_dev;
+	ret = xtalk_set_protocol(xtalk_dev, &astribank_proto);
+	if(ret < 0) {
+		ERR("MPP Protocol registration failed: %d\n", ret);
+		goto err;
+	}
+	ret = xtalk_proto_query(xtalk_dev);
+	if(ret < 0) {
+		ERR("Protocol handshake failed: %d\n", ret);
+		goto err;
+	}
+	ret = mpp_status_query(astribank);
+	if(ret < 0) {
+		ERR("Status query failed: %d\n", ret);
+		goto err;
+	}
+	return astribank;
+
+err:
+	if (astribank) {
+		astribank_close(astribank, 0);
+		astribank = NULL;
+	}
+	if(xtalk_dev) {
+		xtalk_delete(xtalk_dev);
+		xtalk_dev = NULL;
+	}
+	return NULL;
+}
+
+void mpp_exit(struct astribank_device *astribank)
+{
+	DBG("\n");
+	astribank_close(astribank, 0);
+}
+
+/*
+ * data structures
+ */
+
+void show_eeprom(const struct eeprom_table *eprm, FILE *fp)
+{
+	int	rmajor = (eprm->release >> 8) & 0xFF;
+	int	rminor = eprm->release & 0xFF;;
+	char	buf[BUFSIZ];
+
+	memset(buf, 0, LABEL_SIZE + 1);
+	memcpy(buf, eprm->label, LABEL_SIZE);
+	fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Source", eprm->source);
+	fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Vendor", eprm->vendor);
+	fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Product", eprm->product);
+	fprintf(fp, "EEPROM: %-15s: %d.%d\n", "Release", rmajor, rminor);
+	fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Config", eprm->config_byte);
+	fprintf(fp, "EEPROM: %-15s: '%s'\n", "Label", buf);
+}
+
+void show_capabilities(const struct capabilities *capabilities, FILE *fp)
+{
+	fprintf(fp, "Capabilities: FXS ports: %2d\n", capabilities->ports_fxs);
+	fprintf(fp, "Capabilities: FXO ports: %2d\n", capabilities->ports_fxo);
+	fprintf(fp, "Capabilities: BRI ports: %2d\n", capabilities->ports_bri);
+	fprintf(fp, "Capabilities: PRI ports: %2d\n", capabilities->ports_pri);
+	fprintf(fp, "Capabilities: ECHO ports: %2d\n", capabilities->ports_echo);
+	fprintf(fp, "Capabilities: TwinStar : %s\n",
+		(CAP_EXTRA_TWINSTAR(capabilities)) ? "Yes" : "No");
+}
+
+void show_astribank_status(struct astribank_device *astribank, FILE *fp)
+{
+	char	version_buf[BUFSIZ];
+	int	is_loaded = STATUS_FPGA_LOADED(astribank->status);
+
+	fprintf(fp, "Astribank: EEPROM      : %s\n",
+		eeprom_type2str(astribank->eeprom_type));
+	fprintf(fp, "Astribank: FPGA status : %s\n",
+		is_loaded ? "Loaded" : "Empty");
+	if(is_loaded) {
+		memset(version_buf, 0, sizeof(version_buf));
+		memcpy(version_buf, astribank->fw_versions.fpga, VERSION_LEN);
+		fprintf(fp, "Astribank: FPGA version: %s\n",
+			version_buf);
+	}
+}
+
+void show_extrainfo(const struct extrainfo *extrainfo, FILE *fp)
+{
+	fprintf(fp, "Extrainfo:             : %s\n", (const char *)(extrainfo->text));
+}
+
+int twinstar_show(struct astribank_device *astribank, FILE *fp)
+{
+	int	watchdog;
+	int	powerstate;
+	int	portnum;
+	int	i;
+
+	if(!astribank_has_twinstar(astribank)) {
+		fprintf(fp, "TwinStar: NO\n");
+		return 0;
+	}
+	if((watchdog = mpp_tws_watchdog(astribank)) < 0) {
+		ERR("Failed getting TwinStar information\n");
+		return watchdog;
+	}
+	if((powerstate = mpp_tws_powerstate(astribank)) < 0) {
+		ERR("Failed getting TwinStar powerstate\n");
+		return powerstate;
+	}
+	if((portnum = mpp_tws_portnum(astribank)) < 0) {
+		ERR("Failed getting TwinStar portnum\n");
+		return portnum;
+	}
+	fprintf(fp, "TwinStar: Connected to : USB-%1d\n", portnum);
+	fprintf(fp, "TwinStar: Watchdog     : %s\n",
+		(watchdog) ? "on-guard" : "off-guard");
+	for(i = 0; i < 2; i++) {
+		int	pw = (1 << i) & powerstate;
+
+		fprintf(fp, "TwinStar: USB-%1d POWER  : %s\n",
+			i, (pw) ? "ON" : "OFF");
+	}
+	return 0;
+}
diff --git a/xpp/mpp_funcs.h b/xpp/mpptalk.h
similarity index 85%
rename from xpp/mpp_funcs.h
rename to xpp/mpptalk.h
index 59bbc7d..ca3e0f9 100644
--- a/xpp/mpp_funcs.h
+++ b/xpp/mpptalk.h
@@ -22,13 +22,22 @@
  *
  */
 
+#include <stdint.h>
+#include <stdio.h>
+
 #include "mpp.h"
 #include "astribank_usb.h"
 
-#define	TIMEOUT	2000
+struct astribank_device;
+struct eeprom_table;
+struct extrainfo;
+struct capabilities;
+struct capkey;
+
+#define	TIMEOUT	6000
 
 /* high-level */
-struct astribank_device *mpp_init(const char devpath[]);
+struct astribank_device *mpp_init(const char devpath[], int iface_num);
 void mpp_exit(struct astribank_device *astribank);
 int mpp_proto_query(struct astribank_device *astribank);
 int mpp_status_query(struct astribank_device *astribank);
@@ -45,7 +54,7 @@ int mpp_caps_set(struct astribank_device *astribank,
 int mpp_extrainfo_get(struct astribank_device *astribank, struct extrainfo *info);
 int mpp_extrainfo_set(struct astribank_device *astribank, const struct extrainfo *info);
 int mpp_eeprom_blk_rd(struct astribank_device *astribank, uint8_t *buf, uint16_t offset, uint16_t len);
-int mpp_send_start(struct astribank_device *astribank, enum dev_dest dest, const char *ihex_version);
+int mpp_send_start(struct astribank_device *astribank, int dest, const char *ihex_version);
 int mpp_send_end(struct astribank_device *astribank);
 int mpp_send_seg(struct astribank_device *astribank, const uint8_t *data, uint16_t offset, uint16_t len);
 int mpp_reset(struct astribank_device *astribank, int full_reset);
@@ -70,11 +79,6 @@ int mpp_tws_powerstate(struct astribank_device *astribank);
 int mpp_tws_portnum(struct astribank_device *astribank);
 int mpp_tws_setportnum(struct astribank_device *astribank, uint8_t portnum);
 
-/* low-level */
-int process_command(struct astribank_device *astribank, struct mpp_command *cmd, struct mpp_command **reply_ref);
-struct mpp_command *new_command(uint8_t protocol_version, uint8_t op, uint16_t extra_data);
-void free_command(struct mpp_command *cmd);
-
-const char *dev_dest2str(enum dev_dest dest);
+const char *dev_dest2str(int dest);
 
 #endif	/* MPP_FUNCS_H */
diff --git a/xpp/mpptalk_defs.h b/xpp/mpptalk_defs.h
new file mode 100644
index 0000000..e38f381
--- /dev/null
+++ b/xpp/mpptalk_defs.h
@@ -0,0 +1,111 @@
+#ifndef	MPPTALK_DEFS_H
+#define	MPPTALK_DEFS_H
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008,2009,2010 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 <xtalk_defs.h>
+/*
+ * MPP - Managment Processor Protocol definitions
+ */
+
+/*
+ * OP Codes:
+ * MSB of op signifies a reply from device
+ */
+#define	MPP_RENUM			0x0B	/* Trigger USB renumeration */
+#define	MPP_EEPROM_SET			0x0D
+
+/* AB capabilities	*/
+#define	MPP_CAPS_GET			0x0E
+#define	MPP_CAPS_GET_REPLY		0x8E
+#define	MPP_CAPS_SET			0x0F
+
+#define	MPP_DEV_SEND_START		0x05
+#define	MPP_DEV_SEND_SEG		0x07
+#define	MPP_DEV_SEND_END		0x09
+
+/* Astribank Status	*/
+#define	MPP_STATUS_GET			0x11
+#define	MPP_STATUS_GET_REPLY		0x91
+#define	MPP_STATUS_GET_REPLY_V13	0x91	/* backward compat */
+
+/* Get extra vendor information	*/
+#define	MPP_EXTRAINFO_GET		0x13
+#define	MPP_EXTRAINFO_GET_REPLY		0x93
+#define	MPP_EXTRAINFO_SET		0x15	/* Set extra vendor information	*/
+
+#define	MPP_EEPROM_BLK_RD		0x27
+#define	MPP_EEPROM_BLK_RD_REPLY		0xA7
+
+#define	MPP_SER_SEND			0x37
+#define	MPP_SER_RECV			0xB7
+
+#define	MPP_RESET			0x45	/* Reset both FPGA and USB firmwares */
+#define	MPP_HALF_RESET			0x47	/* Reset only FPGA firmware */
+
+/* Twinstar */
+#define	MPP_TWS_WD_MODE_SET		0x31	/* Set watchdog off/on guard	*/
+#define	MPP_TWS_WD_MODE_GET		0x32	/* Current watchdog mode 	*/
+#define	MPP_TWS_WD_MODE_GET_REPLY	0xB2	/* Current watchdog mode 	*/
+#define	MPP_TWS_PORT_SET		0x34	/* USB-[0/1]			*/
+#define	MPP_TWS_PORT_GET		0x35	/* USB-[0/1]			*/
+#define	MPP_TWS_PORT_GET_REPLY		0xB5	/* USB-[0/1]			*/
+#define	MPP_TWS_PWR_GET			0x36	/* Power: bits -> USB ports	*/
+#define	MPP_TWS_PWR_GET_REPLY		0xB6	/* Power: bits -> USB ports	*/
+
+/*
+ * Statuses
+ */
+#define	STAT_OK		0x00	/* acknowledges previous command	*/
+#define	STAT_FAIL	0x01	/* Last command failed		*/
+#define	STAT_RESET_FAIL	0x02	/* reset failed				*/
+#define	STAT_NODEST	0x03	/* No destination is selected		*/
+#define	STAT_MISMATCH	0x04	/* Data mismatch			*/
+#define	STAT_NOACCESS	0x05	/* No access				*/
+#define	STAT_BAD_CMD	0x06	/* Bad command				*/
+#define	STAT_TOO_SHORT	0x07	/* Packet is too short			*/
+#define	STAT_ERROFFS	0x08	/* Offset error				*/
+#define	STAT_NOCODE	0x09	/* Source was not burned before		*/
+#define	STAT_NO_LEEPROM	0x0A	/* Large EEPROM was not found		*/
+#define	STAT_NO_EEPROM	0x0B	/* No EEPROM was found			*/
+#define	STAT_WRITE_FAIL	0x0C	/* Writing to device failed		*/
+#define	STAT_FPGA_ERR	0x0D	/* FPGA error				*/
+#define	STAT_KEY_ERR	0x0E	/* Bad Capabilities Key			*/
+#define	STAT_NOCAPS_ERR	0x0F	/* No matching capability		*/
+#define	STAT_NOPWR_ERR	0x10	/* No power on USB connector		*/
+#define	STAT_CAPS_FPGA_ERR	0x11	/* Setting of the capabilities while FPGA is loaded */
+
+/* EEPROM_QUERY: i2cs(ID1, ID0) */
+enum eeprom_type {
+	EEPROM_TYPE_NONE	= 0,
+	EEPROM_TYPE_SMALL	= 1,
+	EEPROM_TYPE_LARGE	= 2,
+	EEPROM_TYPE_UNUSED	= 3,
+};
+
+enum dev_dest {
+	DEST_NONE	= 0x00,
+	DEST_FPGA	= 0x01,
+	DEST_EEPROM	= 0x02,
+};
+
+#endif	/* MPPTALK_DEFS_H */
diff --git a/xpp/pic_loader.c b/xpp/pic_loader.c
index ed80f22..c6ed3f1 100644
--- a/xpp/pic_loader.c
+++ b/xpp/pic_loader.c
@@ -27,7 +27,8 @@
 #include <regex.h>
 #include "hexfile.h"
 #include "pic_loader.h"
-#include "debug.h"
+#include <debug.h>
+#include <xusb.h>
 
 #define	DBG_MASK	0x03
 #define	MAX_HEX_LINES	10000
@@ -87,16 +88,16 @@ int send_picline(struct astribank_device *astribank, uint8_t card_type, enum pic
 	}
 
 	DBG("PICLINE: pack_len=%d pcmd=%d\n", pack_len, pcmd);
-	dump_packet(LOG_DEBUG, "dump:picline[W]", (char *)phead, pack_len);
+	dump_packet(LOG_DEBUG, DBG_MASK, "dump:picline[W]", (char *)phead, pack_len);
 
-	ret = send_usb(astribank, buf, pack_len, TIMEOUT);
+	ret = xusb_send(astribank->xusb, buf, pack_len, TIMEOUT);
 	if(ret < 0) {
-		ERR("send_usb failed: %d\n", ret);
+		ERR("xusb_send failed: %d\n", ret);
 		return ret;
 	}
-	DBG("send_usb: Written %d bytes\n", ret);
+	DBG("xusb_send: Written %d bytes\n", ret);
 	if (recv_answer) {
-		ret = recv_usb(astribank, buf, sizeof(buf), TIMEOUT);
+		ret = xusb_recv(astribank->xusb, buf, sizeof(buf), TIMEOUT);
 		if(ret <= 0) {
 			ERR("No USB packs to read\n");
 			return ret;
@@ -104,7 +105,7 @@ int send_picline(struct astribank_device *astribank, uint8_t card_type, enum pic
 			phead = (struct xpp_packet_header *)buf;
 			if(phead->header.op != PIC_REP_XOP) {
 				ERR("Got unexpected reply OP=0x%02X\n", phead->header.op);
-				dump_packet(LOG_ERR, "hexline[ERR]", buf, ret);
+				dump_packet(LOG_ERR, DBG_MASK, "hexline[ERR]", buf, ret);
 				return -EINVAL;
 			}
 			DBG("received OP=0x%02X, checksum=%02X\n", phead->header.op, phead->d.pic_packet.data[0]);
@@ -180,18 +181,24 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he
 	uint8_t			card_type;
 	int			ret;
 	unsigned int		i;
+	const char		*devstr;
 
 	v = (v[0]) ? v : "Unknown";
 	assert(astribank != NULL);
 	assert(hexdata != NULL);
+	devstr = xusb_devpath(astribank->xusb);
 	if(!astribank->is_usb2) {
-		ERR("Skip PIC burning (not USB2)\n");
+		ERR("%s: Skip PIC burning (not USB2)\n", devstr);
 		return 0;
 	}
-	INFO("Load PIC: %s (version %s)\n", hexdata->fname, hexdata->version_info);
+	INFO("%s [%s]: Loading PIC Firmware: %s (version %s)\n",
+		devstr,
+		xusb_serial(astribank->xusb),
+		hexdata->fname,
+		hexdata->version_info);
 	basename = pic_basename(hexdata->fname, &card_type);
 	if(!basename) {
-		ERR("Bad PIC filename '%s'. Abort.\n", hexdata->fname);
+		ERR("%s: Bad PIC filename '%s'. Abort.\n", devstr, hexdata->fname);
 		return 0;
 	}
 	DBG("basename=%s card_type=%d maxlines=%d\n",
@@ -200,9 +207,9 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he
 	 * Try to read extra left-overs from USB controller
 	 */
 	for(i = 2; i; i--) {
-		char	buf[PACKET_SIZE];
+		char    buf[PACKET_SIZE];
 
-		if(usb_bulk_read(astribank->handle, astribank->my_ep_in, buf, sizeof(buf), 1) <= 0)
+		if(xusb_recv(astribank->xusb, buf, sizeof(buf), 1) <= 0)
 			break;
 	}
 	if((ret = send_picline(astribank, card_type, PIC_START_FLAG, 0, NULL, 0)) != 0) {
@@ -215,13 +222,13 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he
 
 		hexline = hexdata->lines[i];
 		if(!hexline) {
-			ERR("hexdata finished early (line %d)", i);
+			ERR("%s: hexdata finished early (line %d)", devstr, i);
 			return 0;
 		}
 		if(hexline->d.content.header.tt == TT_DATA) {
 			len = hexline->d.content.header.ll;	/* don't send checksum */
 			if(len != 3) {
-				ERR("Bad line len %d\n", len);
+				ERR("%s: Bad line len %d\n", devstr, len);
 				return 0;
 			}
 			data = hexline->d.content.tt_data.data;
@@ -235,8 +242,8 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he
 		} else if(hexline->d.content.header.tt == TT_EOF) {
 			break;
 		} else {
-			ERR("Unexpected TT = %d in line %d\n",
-					hexline->d.content.header.tt, i);
+			ERR("%s: Unexpected TT = %d in line %d\n",
+					devstr, hexline->d.content.header.tt, i);
 			return 0;
 		}
 	}
@@ -250,9 +257,11 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he
 
 int load_pic(struct astribank_device *astribank, int numfiles, char *filelist[])
 {
-	int	i;
+	int		i;
+	const char	*devstr;
 
-	DBG("Loading %d PIC files...\n", numfiles);
+	devstr = xusb_devpath(astribank->xusb);
+	DBG("%s: Loading %d PIC files...\n", devstr, numfiles);
 	for(i = 0; i < numfiles; i++) {
 		struct hexdata	*picdata;
 		const char	*curr = filelist[i];
@@ -263,13 +272,13 @@ int load_pic(struct astribank_device *astribank, int numfiles, char *filelist[])
 			return -errno;
 		}
 		if(!pic_burn(astribank, picdata)) {
-			ERR("PIC %s burning failed\n", curr);
+			ERR("%s: PIC %s burning failed\n", devstr, curr);
 			return -ENODEV;
 		}
 		free_hexdata(picdata);
 	}
 	if((i = send_picline(astribank, 0, PIC_ENDS_FLAG, 0, NULL, 0)) != 0) {
-		ERR("PIC end burning failed\n");
+		ERR("%s: PIC end burning failed\n", devstr);
 		return -ENODEV;
 	}
 	return 0;
diff --git a/xpp/xpp_fxloader b/xpp/xpp_fxloader
index 73a6c6e..e316d0e 100644
--- a/xpp/xpp_fxloader
+++ b/xpp/xpp_fxloader
@@ -146,15 +146,19 @@ load_usb_fw() {
 }
 
 load_fw_device() {
-	dev=$1
-	fw=$2
+	dev="$1"
+	fw="$2"
 	debug "FPGA loading $fw into $dev"
 	run_astribank_hexload -D "$dev" -F "$FIRMWARE_DIR/$fw"
-	pic_files=`echo "$FIRMWARE_DIR"/PIC_TYPE_[1-4].hex`
-	debug "PIC burning into $dev: $pic_files"
-	run_astribank_hexload -D "$dev" -p $pic_files
-	run_astribank_tool -D "$dev" -n		# Do renumeration!
-	debug "PIC burning finished $pic_files"
+	if [ "$fw" = "FPGA_1161.hex" ]; then
+		pic_files=`echo "$FIRMWARE_DIR"/PIC_TYPE_[1-4].hex`
+		debug "PIC burning into $dev: $pic_files"
+		run_astribank_hexload -D "$dev" -p $pic_files
+		debug "PIC burning finished $pic_files"
+	fi
+	# Do renumeration!
+	run_astribank_tool -D "$dev" -n > /dev/null
+	debug "Reenumeration done."
 }
 
 #
diff --git a/xpp/debug.c b/xpp/xtalk/debug.c
similarity index 65%
rename from xpp/debug.c
rename to xpp/xtalk/debug.c
index b8d3a70..eea2d82 100644
--- a/xpp/debug.c
+++ b/xpp/xtalk/debug.c
@@ -20,11 +20,14 @@
  *
  */
 
+
 #include <stdio.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <stdarg.h>
 #include <syslog.h>
-#include "debug.h"
+#include <execinfo.h>
+#include <debug.h>
 
 int	verbose = LOG_INFO;
 int	debug_mask = 0;
@@ -41,13 +44,29 @@ void log_function(int level, int mask, const char *msg, ...)
 	va_end(ap);
 }
 
-void dump_packet(int loglevel, const char *msg, const char *buf, int len)
+void dump_packet(int loglevel, int mask, const char *msg, const char *buf, int len)
 {
 	int	i;
 
-	log_function(loglevel, ~0, "%-15s:", msg);
-	for(i = 0; i < len; i++)
-		log_function(loglevel, ~0, " %02X", (uint8_t)buf[i]);
-	log_function(loglevel, ~0, "\n");
+	if(mask & debug_mask) {
+		log_function(loglevel, ~0, "%-15s:", msg);
+		for(i = 0; i < len; i++)
+			log_function(loglevel, ~0, " %02X", (uint8_t)buf[i]);
+		log_function(loglevel, ~0, "\n");
+	}
 }
 
+/* from glibc info(1) */
+void print_backtrace (FILE *fp)
+{
+	void	*array[10];
+	size_t	size;
+	char	**strings;
+	size_t	i;
+
+	size = backtrace (array, 10);
+	strings = backtrace_symbols (array, size);
+	for (i = 0; i < size; i++)
+		fprintf (fp, "%s\n", strings[i]);
+	free (strings);
+}
diff --git a/xpp/debug.h b/xpp/xtalk/debug.h
similarity index 86%
rename from xpp/debug.h
rename to xpp/xtalk/debug.h
index 185848a..2d018d2 100644
--- a/xpp/debug.h
+++ b/xpp/xtalk/debug.h
@@ -23,6 +23,7 @@
  */
 
 #include <syslog.h>
+#include <stdio.h>
 
 /*
  * Each module should define a unique DBG_MASK
@@ -37,10 +38,12 @@ extern	int	debug_mask;
 void log_function(int level, int mask, const char *msg, ...) __attribute__(( format(printf, 3, 4) ));
 
 #define	ERR(fmt, arg...) log_function(LOG_ERR, 0, "%s:%d: ERROR(%s): " fmt, __FILE__, __LINE__, __FUNCTION__, ## arg)
+#define	WARN(fmt, arg...) log_function(LOG_WARNING, 0, "WARNING: " fmt, ## arg)
 #define	INFO(fmt, arg...) log_function(LOG_INFO, 0, "INFO: " fmt, ## arg)
 #define	DBG(fmt, arg...) log_function(LOG_DEBUG, DBG_MASK,	\
 		"%s:%d: DBG(%s): " fmt, __FILE__, __LINE__, __FUNCTION__, ## arg)
 
-void dump_packet(int loglevel, const char *msg, const char *buf, int len);
+void dump_packet(int loglevel, int mask, const char *msg, const char *buf, int len);
+void print_backtrace (FILE *fp);
 
 #endif	/* DEBUG_H */
diff --git a/xpp/xtalk/xlist.c b/xpp/xtalk/xlist.c
new file mode 100644
index 0000000..d28debd
--- /dev/null
+++ b/xpp/xtalk/xlist.c
@@ -0,0 +1,93 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <xlist.h>
+
+struct xlist_node *xlist_new(void *data)
+{
+	struct xlist_node	*list;
+
+	if((list = malloc(sizeof(*list))) == NULL)
+		return NULL;
+	list->next = list;
+	list->prev = list;
+	list->data = data;
+	return list;
+}
+
+void xlist_destroy(struct xlist_node *list, xlist_destructor_t destructor)
+{
+	struct xlist_node	*curr;
+	struct xlist_node	*next;
+
+	if (! list)
+		return;
+	curr = list->next;
+	while(curr != list) {
+		next = curr->next;
+		if(destructor)
+			destructor(curr->data);
+		memset(curr, 0, sizeof(*curr));
+		free(curr);
+		curr = next;
+	}
+	memset(list, 0, sizeof(*list));
+	free(list);
+}
+
+void xlist_append_item(struct xlist_node *list, struct xlist_node *item)
+{
+	assert(list);
+	assert(xlist_empty(item));
+	item->next = list;
+	item->prev = list->prev;
+	list->prev->next = item;
+	list->prev = item;
+}
+
+void xlist_prepend_item(struct xlist_node *list, struct xlist_node *item)
+{
+	assert(list);
+	assert(xlist_empty(item));
+	item->prev = list;
+	item->next = list->next;
+	list->next->prev = item;
+	list->next = item;
+}
+
+void xlist_remove_item(struct xlist_node *item)
+{
+	assert(item);
+	item->prev->next = item->next;
+	item->next->prev = item->prev;
+	item->next = item->prev = item;
+}
+
+struct xlist_node *xlist_shift(struct xlist_node *list)
+{
+	struct xlist_node	*item;
+
+	if(!list)
+		return NULL;
+	if(xlist_empty(list))
+		return NULL;
+	item = list->next;
+	xlist_remove_item(item);
+	return item;
+}
+
+int xlist_empty(const struct xlist_node *list)
+{
+	assert(list);
+	return list->next == list && list->prev == list;
+}
+
+size_t xlist_length(const struct xlist_node *list)
+{
+	struct xlist_node	*curr;
+	size_t			count = 0;
+
+	for(curr = list->next; curr != list; curr = curr->next)
+		count++;
+	return count;
+}
diff --git a/xpp/xtalk/xlist.h b/xpp/xtalk/xlist.h
new file mode 100644
index 0000000..4f7f818
--- /dev/null
+++ b/xpp/xtalk/xlist.h
@@ -0,0 +1,29 @@
+#ifndef	XLIST_H
+#define	XLIST_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+struct xlist_node {
+	void			*data;
+	struct xlist_node	*next;
+	struct xlist_node	*prev;
+};
+
+typedef void (*xlist_destructor_t)(void *data);
+
+struct xlist_node *xlist_new(void *data);
+void xlist_destroy(struct xlist_node *list, xlist_destructor_t destructor);
+void xlist_append_item(struct xlist_node *list, struct xlist_node *item);
+void xlist_remove_item(struct xlist_node *item);
+struct xlist_node *xlist_shift(struct xlist_node *list);
+int xlist_empty(const struct xlist_node *list);
+size_t xlist_length(const struct xlist_node *list);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif	/* XLIST_H */
diff --git a/xpp/xtalk/xtalk.c b/xpp/xtalk/xtalk.c
new file mode 100644
index 0000000..d3da5e0
--- /dev/null
+++ b/xpp/xtalk/xtalk.c
@@ -0,0 +1,497 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2009, 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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <xtalk.h>
+#include <debug.h>
+
+static const char rcsid[] = "$Id$";
+
+#define	DBG_MASK	0x02
+
+#define	TIMEOUT		6000
+
+/*
+ * Base XTALK device. A pointer to this struct
+ * should be included in the struct representing
+ * the dialect.
+ */
+struct xtalk_device {
+	void			*transport_priv;	/* e.g: struct xusb */
+	struct xtalk_ops	ops;
+	struct xtalk_protocol	xproto;
+	uint8_t			xtalk_proto_version;
+	uint8_t                 status;
+	size_t			packet_size;
+	uint16_t                tx_sequenceno;
+};
+
+CMD_DEF(XTALK, ACK,
+	uint8_t stat;
+	);
+
+CMD_DEF(XTALK, PROTO_GET,
+	uint8_t proto_version;
+	uint8_t reserved;
+	);
+
+CMD_DEF(XTALK, PROTO_GET_REPLY,
+	uint8_t proto_version;
+	uint8_t reserved;
+	);
+
+union XTALK_PDATA(XTALK) {
+	MEMBER(XTALK, ACK);
+	MEMBER(XTALK, PROTO_GET);
+	MEMBER(XTALK, PROTO_GET_REPLY);
+} PACKED members;
+
+struct xtalk_protocol	xtalk_base = {
+	.name	= "XTALK",
+	.proto_version = 0,
+	.commands = {
+		CMD_RECV(XTALK, ACK, NULL),
+		CMD_SEND(XTALK, PROTO_GET),
+		CMD_RECV(XTALK, PROTO_GET_REPLY, NULL),
+	},
+	.ack_statuses = {
+		ACK_STAT(OK, "Acknowledges previous command"),
+		ACK_STAT(FAIL, "Last command failed"),
+		ACK_STAT(RESET_FAIL, "reset failed"),
+		ACK_STAT(NODEST, "No destination is selected"),
+		ACK_STAT(MISMATCH, "Data mismatch"),
+		ACK_STAT(NOACCESS, "No access"),
+		ACK_STAT(BAD_CMD, "Bad command"),
+		ACK_STAT(TOO_SHORT, "Packet is too short"),
+		ACK_STAT(ERROFFS, "Offset error (not used)"),
+		ACK_STAT(NO_LEEPROM, "Large EEPROM was not found"),
+		ACK_STAT(NO_EEPROM, "No EEPROM was found"),
+		ACK_STAT(WRITE_FAIL, "Writing to device failed"),
+		ACK_STAT(NOPWR_ERR, "No power on USB connector"),
+	}
+};
+
+void free_command(struct xtalk_command *cmd)
+{
+	if(!cmd)
+		return;
+	memset(cmd, 0, cmd->header.len);
+	free(cmd);
+}
+
+static const struct xtalk_command_desc *get_command_desc(const struct xtalk_protocol *xproto, uint8_t op)
+{
+	const struct xtalk_command_desc	*desc;
+
+	if(!xproto)
+		return NULL;
+	desc = &xproto->commands[op];
+	if(!desc->name)
+		return NULL;
+#if 0
+	DBG("%s version=%d, op=0x%X (%s)\n",
+		xproto->name, xproto->proto_version,
+		op, desc->name);
+#endif
+	return desc;
+}
+
+static const char *ack_status_msg(const struct xtalk_protocol *xproto, uint8_t status)
+{
+	const char	*ack_status;
+
+	if(!xproto)
+		return NULL;
+	ack_status = xproto->ack_statuses[status];
+	DBG("%s status=0x%X (%s)\n", xproto->name, status, ack_status);
+	return ack_status;
+}
+
+int xtalk_set_protocol(struct xtalk_device *xtalk_dev, const struct xtalk_protocol *xproto)
+{
+	const char	*protoname = (xproto) ? xproto->name : "GLOBAL";
+	int		i;
+
+	DBG("%s\n", protoname);
+	memset(&xtalk_dev->xproto, 0, sizeof(xtalk_dev->xproto));
+	for(i = 0; i < MAX_OPS; i++) {
+		const struct xtalk_command_desc	*desc;
+
+		desc = get_command_desc(xproto, i);
+		if(desc) {
+			if(!IS_PRIVATE_OP(i)) {
+				ERR("Bad op=0x%X (should be in the range [0x%X-0x%X]\n",
+					i, PRIVATE_OP_FIRST, PRIVATE_OP_LAST);
+				return -EINVAL;
+			}
+			xtalk_dev->xproto.commands[i] = *desc;
+			DBG("private: op=0x%X (%s)\n", i, desc->name);
+		} else {
+			if(!IS_PRIVATE_OP(i)) {
+				const char	*name;
+
+				xtalk_dev->xproto.commands[i] = xtalk_base.commands[i];
+				name = xtalk_dev->xproto.commands[i].name;
+				if(name)
+					DBG("global: op=0x%X (%s)\n", i, name);
+			}
+		}
+	}
+	for(i = 0; i < MAX_STATUS; i++) {
+		const char	*stat_msg;
+
+		stat_msg = (xproto) ? xproto->ack_statuses[i] : NULL;
+		if(stat_msg) {
+			if(!IS_PRIVATE_OP(i)) {
+				ERR("Bad status=0x%X (should be in the range [0x%X-0x%X]\n",
+					i, PRIVATE_OP_FIRST, PRIVATE_OP_LAST);
+				return -EINVAL;
+			}
+			xtalk_dev->xproto.ack_statuses[i] = stat_msg;
+			DBG("private: status=0x%X (%s)\n", i, stat_msg);
+		} else {
+			if(!IS_PRIVATE_OP(i)) {
+				const char	*stat_msg;
+
+				xtalk_dev->xproto.ack_statuses[i] = xtalk_base.ack_statuses[i];
+				stat_msg = xtalk_dev->xproto.ack_statuses[i];
+				if(stat_msg)
+					DBG("global: status=0x%X (%s)\n", i, stat_msg);
+			}
+		}
+	}
+	xtalk_dev->xproto.name = protoname;
+	xtalk_dev->xproto.proto_version = (xproto) ? xproto->proto_version : 0;
+	return 0;
+}
+
+struct xtalk_command *new_command(
+	const struct xtalk_device *xtalk_dev,
+	uint8_t op, uint16_t extra_data)
+{
+	const struct xtalk_protocol	*xproto;
+	struct xtalk_command		*cmd;
+	const struct xtalk_command_desc	*desc;
+	uint16_t			len;
+
+	xproto = &xtalk_dev->xproto;
+	desc = get_command_desc(xproto, op);
+	if(!desc) {
+		ERR("Unknown op=0x%X.\n", op);
+		return NULL;
+	}
+	DBG("OP=0x%X [%s] (extra_data %d)\n", op, desc->name, extra_data);
+	len = desc->len + extra_data;
+	if((cmd = malloc(len)) == NULL) {
+		ERR("Out of memory\n");
+		return NULL;
+	}
+	if(extra_data) {
+		uint8_t	*ptr = (uint8_t *)cmd;
+
+		DBG("clear extra_data (%d bytes)\n", extra_data);
+		memset(ptr + desc->len, 0, extra_data);
+	}
+	cmd->header.op = op;
+	cmd->header.len = len;
+	cmd->header.seq = 0;	/* Overwritten in send_usb() */
+	return cmd;
+}
+
+void xtalk_dump_command(struct xtalk_command *cmd)
+{
+	uint16_t	len;
+	int		i;
+
+	len = cmd->header.len;
+	if(len < sizeof(struct xtalk_header)) {
+		ERR("Command too short (%d)\n", len);
+		return;
+	}
+	INFO("DUMP: OP=0x%X len=%d seq=%d\n",
+		cmd->header.op, cmd->header.len, cmd->header.seq);
+	for(i = 0; i < len - sizeof(struct xtalk_header); i++) {
+		INFO("  %2d. 0x%X\n", i, cmd->alt.raw_data[i]);
+	}
+}
+
+static int send_command(struct xtalk_device *xtalk_dev, struct xtalk_command *cmd, int timeout)
+{
+	int		ret;
+	int		len;
+	char		*buf;
+	void		*priv = xtalk_dev->transport_priv;
+
+	len = cmd->header.len;
+	cmd->header.seq = xtalk_dev->tx_sequenceno;
+
+	buf = (char *)cmd;
+	//printf("%s: len=%d\n", __FUNCTION__, len);
+#if 0
+	extern	FILE	*fp;
+	if(fp) {
+		int	i;
+
+		fprintf(fp, "%05d:", cmd->header.seq);
+		for(i = 0; i < len; i++)
+			fprintf(fp, " %02X", (uint8_t)buf[i]);
+		fprintf(fp, "\n");
+	}
+#endif
+	ret = xtalk_dev->ops.send_func(priv, (char *)cmd, len, timeout);
+	if(ret < 0) {
+		DBG("send_func failed ret=%d\n", ret);
+	}
+	xtalk_dev->tx_sequenceno++;
+	return ret;
+}
+
+static struct xtalk_command *recv_command(struct xtalk_device *xtalk_dev, int timeout)
+{
+	struct xtalk_command	*reply;
+	void			*priv = xtalk_dev->transport_priv;
+	int			ret;
+
+	if((reply = malloc(xtalk_dev->packet_size)) == NULL) {
+		ERR("Out of memory\n");
+		goto err;
+	}
+	reply->header.len = 0;
+	ret = xtalk_dev->ops.recv_func(priv, (char *)reply, xtalk_dev->packet_size, timeout);
+	if(ret < 0) {
+		ERR("Receive from usb failed.\n");
+		goto err;
+	} else if(ret == 0) {
+		goto err;	/* No reply */
+	}
+	if(ret != reply->header.len) {
+		ERR("Wrong length received: got %d bytes, but length field says %d bytes%s\n",
+				ret, reply->header.len,
+				(ret == 1)? ". Old USB firmware?": "");
+		goto err;
+	}
+	//dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, (char *)reply, ret);
+	return reply;
+err:
+	if(reply) {
+		memset(reply, 0, xtalk_dev->packet_size);
+		free_command(reply);
+	}
+	return NULL;
+}
+
+
+__attribute__((warn_unused_result))
+int process_command(
+	struct xtalk_device *xtalk_dev,
+	struct xtalk_command *cmd,
+	struct xtalk_command **reply_ref)
+{
+	const struct xtalk_protocol	*xproto;
+	struct xtalk_command		*reply = NULL;
+	const struct xtalk_command_desc	*reply_desc;
+	const struct xtalk_command_desc	*expected;
+	const struct xtalk_command_desc	*cmd_desc;
+	uint8_t				reply_op;
+	const char			*protoname;
+	int				ret;
+
+	xproto = &xtalk_dev->xproto;
+	protoname = (xproto) ? xproto->name : "GLOBAL";
+	if(reply_ref)
+		*reply_ref = NULL;	/* So the caller knows if a reply was received */
+	reply_op = cmd->header.op | XTALK_REPLY_MASK;
+	cmd_desc = get_command_desc(xproto, cmd->header.op);
+	expected = get_command_desc(xproto, reply_op);
+	//printf("%s: len=%d\n", __FUNCTION__, cmd->header.len);
+	ret = send_command(xtalk_dev, cmd, TIMEOUT);
+	if(!reply_ref) {
+		DBG("No reply requested\n");
+		goto out;
+	}
+	if(ret < 0) {
+		ERR("send_command failed: %d\n", ret);
+		goto out;
+	}
+	reply = recv_command(xtalk_dev, TIMEOUT);
+	if(!reply) {
+		ERR("recv_command failed\n");
+		ret = -EPROTO;
+		goto out;
+	}
+	*reply_ref = reply;
+	if((reply->header.op & 0x80) != 0x80) {
+		ERR("Unexpected reply op=0x%02X, should have MSB set.\n", reply->header.op);
+		ret = -EPROTO;
+		goto out;
+	}
+	DBG("REPLY OP: 0x%X\n", reply->header.op);
+	reply_desc = get_command_desc(xproto, reply->header.op);
+	if(!reply_desc) {
+		ERR("Unknown reply (proto=%s) op=0x%02X\n", protoname, reply->header.op);
+		ret = -EPROTO;
+		goto out;
+	}
+	DBG("REPLY NAME: %s\n", reply_desc->name);
+	if(reply->header.op == XTALK_ACK) {
+		int	status = CMD_FIELD(reply, XTALK, ACK, stat);
+
+		if(expected) {
+			ERR("Expected OP=0x%02X: Got ACK(%d): %s\n",
+				reply_op, status, ack_status_msg(xproto, status));
+			ret = -EPROTO;
+			goto out;
+		} else if(status != STAT_OK) {
+
+			ERR("Got ACK (for OP=0x%X [%s]): %d %s\n",
+				cmd->header.op,
+				cmd_desc->name,
+				status, ack_status_msg(xproto, status));
+#if 0
+			extern	FILE	*fp;
+			if(fp) {
+				fprintf(fp, "Got ACK(%d)\n", status);
+			}
+#endif
+			ret = -EPROTO;
+			goto out;
+		}
+		/* Good expected ACK ... */
+	} else if(reply->header.op != reply_op) {
+			ERR("Expected OP=0x%02X: Got OP=0x%02X\n",
+				reply_op, reply->header.op);
+			ret = -EPROTO;
+			goto out;
+	}
+	if(expected && expected->len > reply->header.len) {
+			ERR("Expected len=%d: Got len=%d\n",
+				expected->len, reply->header.len);
+			ret = -EPROTO;
+			goto out;
+	}
+	if(cmd->header.seq != reply->header.seq) {
+			ERR("Expected seq=%d: Got seq=%d\n",
+				cmd->header.seq, reply->header.seq);
+			ret = -EPROTO;
+			goto out;
+	}
+	ret = reply->header.len;	/* All good, return the length */
+	DBG("returning reply op 0x%X (%d bytes)\n", reply->header.op, ret);
+out:
+	free_command(cmd);
+	if(!reply_ref && reply)
+		free_command(reply);
+	return ret;
+}
+
+/*
+ * Protocol Commands
+ */
+
+int xtalk_proto_query(struct xtalk_device *xtalk_dev)
+{
+	struct xtalk_command		*cmd;
+	struct xtalk_command		*reply;
+	uint8_t				proto_version;
+	int				ret;
+
+	DBG("\n");
+	assert(xtalk_dev != NULL);
+	proto_version = xtalk_dev->xproto.proto_version;
+	if((cmd = new_command(xtalk_dev, XTALK_PROTO_GET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	CMD_FIELD(cmd, XTALK, PROTO_GET, proto_version) = proto_version;	/* Protocol Version */
+	ret = process_command(xtalk_dev, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		goto out;
+	}
+	xtalk_dev->xtalk_proto_version = CMD_FIELD(reply, XTALK, PROTO_GET_REPLY, proto_version);
+	if(xtalk_dev->xtalk_proto_version != proto_version) {
+		ERR("Got %s protocol version: 0x%02x (expected 0x%02x)\n",
+			xtalk_dev->xproto.name,
+			xtalk_dev->xtalk_proto_version,
+			proto_version);
+		ret = xtalk_dev->xtalk_proto_version;
+		goto out;
+	}
+	DBG("Protocol version: %02x\n", xtalk_dev->xtalk_proto_version);
+	ret = xtalk_dev->xtalk_proto_version;
+out:
+	free_command(reply);
+	return ret;
+}
+
+/*
+ * Wrappers
+ */
+
+struct xtalk_device *xtalk_new(const struct xtalk_ops *ops, size_t packet_size, void *priv)
+{
+	struct xtalk_device	*xtalk_dev;
+	int			ret;
+
+	DBG("\n");
+	assert(ops != NULL);
+	if((xtalk_dev = malloc(sizeof(*xtalk_dev))) == NULL) {
+		ERR("Allocating XTALK device memory failed\n");
+		return NULL;
+	}
+	memset(xtalk_dev, 0, sizeof(*xtalk_dev));
+	memcpy((void *)&xtalk_dev->ops, (const void *)ops, sizeof(xtalk_dev->ops));
+	xtalk_dev->transport_priv = priv;
+	xtalk_dev->packet_size = packet_size;
+	xtalk_dev->tx_sequenceno = 1;
+	ret = xtalk_set_protocol(xtalk_dev, NULL);
+	if(ret < 0) {
+		ERR("GLOBAL Protocol registration failed: %d\n", ret);
+		goto err;
+	}
+	return xtalk_dev;
+
+err:
+	if (xtalk_dev)
+		xtalk_delete(xtalk_dev);
+	return NULL;
+}
+
+void xtalk_delete(struct xtalk_device *xtalk_dev)
+{
+	void	*priv;
+
+	if(!xtalk_dev)
+		return;
+	DBG("\n");
+	priv = xtalk_dev->transport_priv;
+	assert(priv);
+	xtalk_dev->tx_sequenceno = 0;
+	assert(&xtalk_dev->ops != NULL);
+	assert(&xtalk_dev->ops.close_func != NULL);
+	xtalk_dev->ops.close_func(priv);
+}
diff --git a/xpp/xtalk/xtalk.h b/xpp/xtalk/xtalk.h
new file mode 100644
index 0000000..4243b64
--- /dev/null
+++ b/xpp/xtalk/xtalk.h
@@ -0,0 +1,172 @@
+#ifndef	XTALK_H
+#define	XTALK_H
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2009, 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.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * XTALK - Base protocol for our USB devices
+ *         It is meant to provide a common base for layered
+ *         protocols (dialects)
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+/* Definitions common to the firmware (in include/ directory) */
+#include <xtalk_defs.h>
+
+#ifdef	__GNUC__
+#define	PACKED	__attribute__((packed))
+#else
+#error "We do not know how your compiler packs structures"
+#endif
+
+struct xtalk_device;
+struct xtalk_command_desc;
+
+typedef int (*xtalk_cmd_callback_t)(
+	struct xtalk_device *xtalk_dev,
+	struct xtalk_command_desc *xtalk_cmd);
+
+/* Describe a single xtalk command */
+struct xtalk_command_desc {
+	uint8_t			op;
+	const char		*name;
+	xtalk_cmd_callback_t	callback;
+	uint16_t		len;	/* Minimal length */
+};
+
+/* Define a complete protocol */
+struct xtalk_protocol {
+	const char			*name;
+	uint8_t				proto_version;
+	struct xtalk_command_desc	commands[MAX_OPS];
+	const char			*ack_statuses[MAX_STATUS];
+};
+
+/*
+ * The common header of every xtalk command
+ * in every xtalk dialect.
+ */
+struct xtalk_header {
+	uint16_t	len;
+	uint16_t	seq;
+	uint8_t		op;	/* MSB: 0 - to device, 1 - from device */
+} PACKED;
+
+struct xtalk_command {
+	/* Common part */
+	struct xtalk_header	header;
+	/* Each dialect has its own data members */
+	union private_data {
+		uint8_t	raw_data[0];
+	} PACKED alt;
+} PACKED;
+
+/*
+ * Macros to unify access to protocol packets and fields:
+ *   p		- signify the dialect prefix (XTALK for base protocol)
+ *   o		- signify command op (e.g: ACK)
+ *   cmd	- A pointer to struct xtalk_command
+ *   field	- field name (e.g: raw_data)
+ */
+#define XTALK_STRUCT(p,o)	p ## _struct_ ## o
+#define XTALK_PDATA(o)		xtalk_privdata_ ## o
+#define	CMD_FIELD(cmd, p, o, field)	(((union XTALK_PDATA(p) *)&((cmd)->alt))->XTALK_STRUCT(p, o).field)
+#define CMD_DEF(p, o, ...)	struct XTALK_STRUCT(p, o) {	\
+					__VA_ARGS__		\
+				} PACKED XTALK_STRUCT(p, o)
+#define	MEMBER(p, o)	struct XTALK_STRUCT(p, o) XTALK_STRUCT(p, o)
+
+/* Wrappers for transport (xusb) functions */
+struct xtalk_ops {
+	int	(*send_func)(void *transport_priv, void *data, size_t len, int timeout);
+	int	(*recv_func)(void *transport_priv, void *data, size_t maxlen, int timeout);
+	int	(*close_func)(void *transport_priv);
+};
+
+/*
+ * Base XTALK device. A pointer to this struct
+ * should be included in the struct representing
+ * the dialect.
+ */
+struct xtalk_device;
+
+/* high-level */
+struct xtalk_device *xtalk_new(const struct xtalk_ops *ops, size_t packet_size, void *transport_priv);
+void xtalk_delete(struct xtalk_device *dev);
+int xtalk_set_protocol(struct xtalk_device *xtalk_dev, const struct xtalk_protocol *xproto);
+int xtalk_proto_query(struct xtalk_device *dev);
+void xtalk_dump_command(struct xtalk_command *cmd);
+
+/* low-level */
+int process_command(
+	struct xtalk_device *dev,
+	struct xtalk_command *cmd,
+	struct xtalk_command **reply_ref);
+struct xtalk_command *new_command(
+	const struct xtalk_device *xtalk_dev,
+	uint8_t op, uint16_t extra_data);
+void free_command(struct xtalk_command *cmd);
+
+/*
+ * Convenience macros to define entries in a protocol command table:
+ *   p		- signify the dialect prefix (XTALK for base protocol)
+ *   o		- signify command op (e.g: ACK)
+ *   cb		- A callback function (type xtalk_cmd_callback_t)
+ */
+#define	CMD_RECV(p,o,cb)	\
+	[p ## _ ## o | XTALK_REPLY_MASK] {		\
+		.op = p ## _ ## o | XTALK_REPLY_MASK,	\
+		.name = #o "_reply",			\
+		.callback = (cb), 			\
+		.len =					\
+			sizeof(struct xtalk_header) +	\
+			sizeof(struct XTALK_STRUCT(p,o)),	\
+	}
+
+#define	CMD_SEND(p,o)	\
+	[p ## _ ## o] {		\
+		.op = p ## _ ## o,	\
+		.name = #o,		\
+		.callback = NULL, 	\
+		.len =					\
+			sizeof(struct xtalk_header) +	\
+			sizeof(struct XTALK_STRUCT(p,o)),	\
+	}
+
+/*
+ * Convenience macro to define statuses:
+ *   x		- status code (e.g: OK)
+ *   m		- status message (const char *)
+ */
+#define	ACK_STAT(x,m)	[ STAT_ ## x ] = (m)
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif	/* XTALK_H */
diff --git a/xpp/xtalk/xtalk_defs.h b/xpp/xtalk/xtalk_defs.h
new file mode 100644
index 0000000..d9c590b
--- /dev/null
+++ b/xpp/xtalk/xtalk_defs.h
@@ -0,0 +1,40 @@
+#ifndef	XTALK_DEFS_H
+#define	XTALK_DEFS_H
+
+#define	MAX_OPS			256	/* single byte */
+#define	MAX_STATUS		256	/* single byte */
+
+#define	XTALK_REPLY_MASK	0x80	/* Every reply has this bit */
+
+#define	PRIVATE_OP_FIRST	0x05
+#define	PRIVATE_OP_LAST		0x7F
+#define	IS_PRIVATE_OP(x)	(	\
+					(((x) & ~(XTALK_REPLY_MASK)) >= PRIVATE_OP_FIRST) &&	\
+					(((x) & ~(XTALK_REPLY_MASK)) <= PRIVATE_OP_LAST)	\
+				)
+
+#define	XTALK_ACK		0x80
+#define	XTALK_PROTO_GET		0x01
+#define	XTALK_PROTO_GET_REPLY	(XTALK_PROTO_GET | XTALK_REPLY_MASK)
+#define	XTALK_FWVERS_GET	0x11
+#define	XTALK_FWVERS_GET_REPLY	(XTALK_FWVERS_GET | XTALK_REPLY_MASK)
+#define XTALK_CAPS_GET		0x0E	/* Get EEPROM table contents Product/Vendor Id ... */
+#define XTALK_CAPS_GET_REPLY	(XTALK_CAPS_GET | XTALK_REPLY_MASK)
+
+/*------------- XTALK: statuses in ACK ---------------------------------------*/
+#define	STAT_OK			0x00	/* OK                         */
+#define	STAT_FAIL		0x01	/* last command failed        */
+#define	STAT_RESET_FAIL		0x02	/* reset  failed              */
+#define	STAT_NODEST		0x03	/* No destination is selected */
+#define	STAT_MISMATCH		0x04	/* Data mismatch              */
+#define	STAT_NOACCESS		0x05	/* No access                  */
+#define	STAT_BAD_CMD		0x06	/* Bad command                */
+#define	STAT_TOO_SHORT		0x07	/* Packet is too short        */
+#define	STAT_ERROFFS		0x08	/* Offset error (not used)    */
+#define	STAT_NO_LEEPROM		0x0A	/* Large EEPROM was not found */
+#define	STAT_NO_EEPROM		0x0B	/* No EEPROM was found        */
+#define	STAT_WRITE_FAIL		0x0C	/* Writing to device failed   */
+#define	STAT_NOPWR_ERR		0x10	/* No power on USB connector  */
+
+
+#endif	/* XTALK_DEFS_H */
diff --git a/xpp/xtalk/xusb.c b/xpp/xtalk/xusb.c
new file mode 100644
index 0000000..ebec5a9
--- /dev/null
+++ b/xpp/xtalk/xusb.c
@@ -0,0 +1,726 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008, 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.
+ *
+ */
+
+#define	_GNU_SOURCE	/* for memrchr() */
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <arpa/inet.h>
+#include <debug.h>
+#include <xusb.h>
+
+static const char rcsid[] = "$Id$";
+
+#define	DBG_MASK	0x01
+#define	TIMEOUT	500
+
+struct xusb {
+	struct usb_device	*dev;
+	usb_dev_handle		*handle;
+	const struct xusb_spec	*spec;
+	char			iManufacturer[BUFSIZ];
+	char			iProduct[BUFSIZ];
+	char			iSerialNumber[BUFSIZ];
+	char			iInterface[BUFSIZ];
+	char			devpath_tail[PATH_MAX + 1];
+	int			bus_num;
+	int			device_num;
+	int			interface_num;
+	int			ep_out;
+	int			ep_in;
+	int			is_usb2;
+	int			is_claimed;
+	int			is_open;
+	size_t			packet_size;
+};
+
+void xusb_init_spec(struct xusb_spec *spec, char *name,
+		uint16_t vendor_id, uint16_t product_id,
+		int nifaces, int iface, int nep, int ep_out, int ep_in)
+{
+	DBG("Initialize %s: interfaces=%d using interface num=%d endpoints=%d (OUT=0x%2X, IN=0x%2X)\n",
+			name, nifaces, iface, nep, ep_out, ep_in);
+	memset(spec, 0, sizeof(*spec));
+	spec->name = name;
+	spec->num_interfaces = nifaces;
+	spec->my_interface_num = iface;
+	spec->num_endpoints = nep;
+	spec->my_vendor_id = vendor_id;
+	spec->my_product_id = product_id;
+	spec->my_ep_in = ep_in;
+	spec->my_ep_out = ep_out;
+}
+
+#define	EP_OUT(xusb)	((xusb)->spec->my_ep_out)
+#define	EP_IN(xusb)	((xusb)->spec->my_ep_in)
+
+/*
+ * USB handling
+ */
+
+static int get_usb_string(struct xusb *xusb, uint8_t item, char *buf, unsigned int len)
+{
+	char	tmp[BUFSIZ];
+	int	ret;
+
+	assert(xusb->handle);
+	if (!item)
+		return 0;
+	ret = usb_get_string_simple(xusb->handle, item, tmp, BUFSIZ);
+	if (ret <= 0)
+		return ret;
+	return snprintf(buf, len, "%s", tmp);
+}
+
+static const struct usb_interface_descriptor *get_interface(const struct usb_device *dev, int my_interface_num, int num_interfaces)
+{
+	const struct usb_interface		*interface;
+	const struct usb_interface_descriptor	*iface_desc;
+	const struct usb_config_descriptor	*config_desc;
+	int					num_altsetting;
+
+	config_desc = dev->config;
+	if (!config_desc) {
+		ERR("No configuration descriptor: strange USB1 controller?\n");
+		return NULL;
+	}
+	if(num_interfaces && config_desc->bNumInterfaces != num_interfaces) {
+		DBG("Wrong number of interfaces: have %d need %d\n",
+			config_desc->bNumInterfaces, num_interfaces);
+		return NULL;
+	}
+	interface = &config_desc->interface[my_interface_num];
+	assert(interface != NULL);
+	iface_desc = interface->altsetting;
+	num_altsetting = interface->num_altsetting;
+	assert(num_altsetting != 0);
+	assert(iface_desc != NULL);
+	return iface_desc;
+}
+
+static int match_interface(const struct usb_device *dev, const struct xusb_spec *spec)
+{
+	const struct usb_device_descriptor	*dev_desc;
+	const struct usb_interface_descriptor	*iface_desc;
+
+	//debug_mask = 0xFF;
+	//verbose = 1;
+	dev_desc = &dev->descriptor;
+	assert(dev_desc);
+	DBG("Checking: %04X:%04X interfaces=%d interface num=%d endpoints=%d: \"%s\"\n",
+			spec->my_vendor_id,
+			spec->my_product_id,
+			spec->num_interfaces,
+			spec->my_interface_num,
+			spec->num_endpoints,
+			spec->name);
+	if(dev_desc->idVendor != spec->my_vendor_id) {
+		DBG("Wrong vendor id 0x%X\n", dev_desc->idVendor);
+		return 0;
+	}
+	if(dev_desc->idProduct != spec->my_product_id) {
+		DBG("Wrong product id 0x%X\n", dev_desc->idProduct);
+		return 0;
+	}
+	if((iface_desc = get_interface(dev, spec->my_interface_num, spec->num_interfaces)) == NULL) {
+		ERR("Could not get interface descriptor of device: %s\n", usb_strerror());
+		return 0;
+	}
+	if(iface_desc->bInterfaceClass != 0xFF) {
+		DBG("Wrong interface class 0x%X\n", iface_desc->bInterfaceClass);
+		return 0;
+	}
+	if(iface_desc->bInterfaceNumber != spec->my_interface_num) {
+		DBG("Wrong interface number %d (expected %d)\n",
+			iface_desc->bInterfaceNumber, spec->my_interface_num);
+		return 0;
+	}
+	if(iface_desc->bNumEndpoints != spec->num_endpoints) {
+		DBG("Wrong number of endpoints %d\n", iface_desc->bNumEndpoints);
+		return 0;
+	}
+	return	1;
+}
+
+static int xusb_fill_strings(struct xusb *xusb)
+{
+	const struct usb_device_descriptor	*dev_desc;
+	const struct usb_interface_descriptor	*iface_desc;
+
+
+	dev_desc = &xusb->dev->descriptor;
+	assert(dev_desc);
+	if(get_usb_string(xusb, dev_desc->iManufacturer, xusb->iManufacturer, BUFSIZ) < 0) {
+		ERR("Failed reading iManufacturer string: %s\n", usb_strerror());
+		return 0;
+	}
+	if(get_usb_string(xusb, dev_desc->iProduct, xusb->iProduct, BUFSIZ) < 0) {
+		ERR("Failed reading iProduct string: %s\n", usb_strerror());
+		return 0;
+	}
+	if(get_usb_string(xusb, dev_desc->iSerialNumber, xusb->iSerialNumber, BUFSIZ) < 0) {
+		ERR("Failed reading iSerialNumber string: %s\n", usb_strerror());
+		return 0;
+	}
+	if((iface_desc = get_interface(xusb->dev, xusb->interface_num, 0)) == NULL) {
+		ERR("Could not get interface descriptor of device: %s\n", usb_strerror());
+		return 0;
+	}
+	if(get_usb_string(xusb, iface_desc->iInterface, xusb->iInterface, BUFSIZ) < 0) {
+		ERR("Failed reading iInterface string: %s\n", usb_strerror());
+		return 0;
+	}
+	return 1;
+}
+
+static int xusb_open(struct xusb *xusb)
+{
+	assert(xusb);
+	if (xusb->is_open)
+		return 1;
+	if((xusb->handle = usb_open(xusb->dev)) == NULL) {
+		ERR("Failed to open usb device '%s': %s\n",
+			xusb->devpath_tail, usb_strerror());
+		return 0;
+	}
+	xusb->is_open = 1;
+	return 1;
+}
+
+int xusb_claim_interface(struct xusb *xusb)
+{
+	const struct usb_device_descriptor	*dev_desc;
+	int					ret;
+
+	assert(xusb);
+	xusb_open(xusb);	/* If it's not open yet... */
+	if(usb_claim_interface(xusb->handle, xusb->interface_num) != 0) {
+		ERR("usb_claim_interface %d in '%s': %s\n",
+			xusb->interface_num, xusb->devpath_tail, usb_strerror());
+		return 0;
+	}
+	xusb->is_claimed = 1;
+	xusb_fill_strings(xusb);
+	dev_desc = &xusb->dev->descriptor;
+	DBG("ID=%04X:%04X Manufacturer=[%s] Product=[%s] SerialNumber=[%s] Interface=[%s]\n",
+		dev_desc->idVendor,
+		dev_desc->idProduct,
+		xusb->iManufacturer,
+		xusb->iProduct,
+		xusb->iSerialNumber,
+		xusb->iInterface);
+	if(usb_clear_halt(xusb->handle, EP_OUT(xusb)) != 0) {
+		ERR("Clearing output endpoint: %s\n", usb_strerror());
+		return 0;
+	}
+	if(usb_clear_halt(xusb->handle, EP_IN(xusb)) != 0) {
+		ERR("Clearing input endpoint: %s\n", usb_strerror());
+		return 0;
+	}
+	if((ret = xusb_flushread(xusb)) < 0) {
+		ERR("xusb_flushread failed: %d\n", ret);
+		return 0;
+	}
+	return 1;
+}
+
+static void xusb_list_dump(struct xlist_node *xusb_list)
+{
+	struct xlist_node	*curr;
+	struct xusb		*xusb;
+
+	for(curr = xusb_list->next; curr != xusb_list; curr = curr->next) {
+		struct usb_device		*dev;
+		struct usb_bus			*bus;
+		struct usb_device_descriptor	*dev_desc;
+
+		xusb = curr->data;
+		assert(xusb);
+		dev = xusb->dev;
+		assert(dev);
+		bus = dev->bus;
+		assert(bus);
+		dev_desc = &dev->descriptor;
+		assert(dev_desc);
+		DBG("usb:ID=%04X:%04X [%s / %s / %s], (%s/%s)\n",
+			dev_desc->idVendor,
+			dev_desc->idProduct,
+			xusb->iManufacturer,
+			xusb->iProduct,
+			xusb->iSerialNumber,
+			bus->dirname,
+			dev->filename
+			);
+	}
+}
+
+void xusb_destroy(struct xusb *xusb)
+{
+	if(xusb) {
+		xusb_close(xusb);
+		memset(xusb, 0, sizeof(*xusb));
+		free(xusb);
+	}
+}
+
+static struct xusb *xusb_new(struct usb_device *dev, const struct xusb_spec *spec)
+{
+	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;
+	size_t				max_packet_size;
+	int				i;
+	struct xusb			*xusb = NULL;
+
+	/*
+	 * Get information from the usb_device
+	 */
+	if((dev_desc = &dev->descriptor) == NULL) {
+		ERR("usb device without a device descriptor\n");
+		goto fail;
+	}
+	if((config_desc = dev->config) == NULL) {
+		ERR("usb device without a configuration descriptor\n");
+		goto fail;
+	}
+	interface = &config_desc->interface[spec->my_interface_num];
+	iface_desc = interface->altsetting;
+	endpoint = iface_desc->endpoint;
+	/* Calculate max packet size */
+	max_packet_size = PACKET_SIZE;
+	for(i = 0; i < iface_desc->bNumEndpoints; i++, endpoint++) {
+		DBG("Validating endpoint @ %d (interface %d)\n", i, spec->my_interface_num);
+		if(endpoint->bEndpointAddress == spec->my_ep_out || endpoint->bEndpointAddress == spec->my_ep_in) {
+			if(endpoint->wMaxPacketSize > PACKET_SIZE) {
+				ERR("Endpoint #%d wMaxPacketSize too large (%d)\n", i, endpoint->wMaxPacketSize);
+				goto fail;
+			}
+			if(endpoint->wMaxPacketSize < max_packet_size) {
+				max_packet_size = endpoint->wMaxPacketSize;
+			}
+		}
+	}
+	/* Fill xusb */
+	if((xusb = malloc(sizeof(*xusb))) == NULL) {
+		ERR("Out of memory");
+		goto fail;
+	}
+	memset(xusb, 0, sizeof(*xusb));
+	xusb->dev = dev;
+	xusb->spec = spec;
+	sscanf(dev->bus->dirname, "%d", &xusb->bus_num);
+	sscanf(dev->filename, "%d", &xusb->device_num);
+	snprintf(xusb->devpath_tail, PATH_MAX, "%03d/%03d",
+		xusb->bus_num, xusb->device_num);
+	xusb->interface_num = spec->my_interface_num;
+	xusb->ep_out = spec->my_ep_out;
+	xusb->ep_in = spec->my_ep_in;
+	xusb->packet_size = max_packet_size;
+	xusb->is_usb2 = (max_packet_size == 512);
+	if (! xusb_open(xusb)) {
+		ERR("Failed opening device: %04X:%04X - %s\n",
+			dev_desc->idVendor,
+			dev_desc->idProduct,
+			xusb->devpath_tail);
+		goto fail;
+	}
+	DBG("%04X:%04X - %s\n",
+		dev_desc->idVendor,
+		dev_desc->idProduct,
+		xusb->devpath_tail);
+	return xusb;
+fail:
+	xusb_destroy(xusb);
+	return NULL;
+}
+
+struct xusb *xusb_find_iface(const char *devpath, int iface_num, int ep_out, int ep_in)
+{
+	struct usb_bus		*bus;
+
+	DBG("\n");
+	usb_init();
+	usb_find_busses();
+	usb_find_devices();
+	for (bus = usb_get_busses(); bus; bus = bus->next) {
+		int			bus_num;
+		char			tmppath[PATH_MAX + 1];
+		struct usb_device	*dev;
+
+		tmppath[0] = '\0';
+		sscanf(bus->dirname, "%d", &bus_num);
+		snprintf(tmppath, sizeof(tmppath), "%03d", bus_num);
+		DBG("Check bus %d: %s ? %s\n", bus_num, tmppath, devpath);
+		if (strncmp(tmppath, devpath, strlen(tmppath)) != 0)
+			continue;
+		DBG("Matched bus %d\n", bus_num);
+		for (dev = bus->devices; dev; dev = dev->next) {
+			struct usb_device_descriptor	*dev_desc;
+			struct usb_config_descriptor	*config_desc;
+			struct usb_interface		*interface;
+			struct xusb_spec		spec;
+			struct xusb			*xusb;
+			int				device_num;
+
+			sscanf(dev->filename, "%d", &device_num);
+			DBG("Check device %d\n", device_num);
+			snprintf(tmppath, sizeof(tmppath), "%03d/%03d", bus_num, device_num);
+			if (strncmp(tmppath, devpath, strlen(tmppath)) != 0)
+				continue;
+			dev_desc = &dev->descriptor;
+			assert(dev_desc);
+			config_desc = dev->config;
+			assert(config_desc);
+			interface = config_desc->interface;
+			assert(interface);
+			INFO("Matched device %s: %X:%X\n", tmppath, dev_desc->idVendor, dev_desc->idProduct);
+			xusb_init_spec(&spec, "Astribank",
+				dev_desc->idVendor, dev_desc->idProduct,
+				config_desc->bNumInterfaces,
+				iface_num,
+				interface->altsetting->bNumEndpoints,
+				ep_out, ep_in);
+			if((xusb = xusb_new(dev, &spec)) == NULL) {
+				ERR("xusb allocation failed\n");
+			}
+			return xusb;
+		}
+	}
+	return NULL;
+}
+
+static const char *path_tail(const char *path)
+{
+	const	char	*p;
+
+	assert(path != NULL);
+	/* Find last '/' */
+	if((p = memrchr(path, '/', strlen(path))) == NULL) {
+		ERR("Missing a '/' in %s\n", path);
+		return NULL;
+	}
+	/* Search for a '/' before that */
+	if((p = memrchr(path, '/', p - path)) == NULL) {
+		p = path;		/* No more '/' */
+	} else {
+		p++;			/* skip '/' */
+	}
+	return p;
+}
+
+int xusb_filter_bypath(const struct xusb *xusb, void *data)
+{
+	const char	*p;
+	const char	*path = data;
+
+	DBG("%s\n", path);
+	assert(path != NULL);
+	p = path_tail(path);
+	if(strcmp(xusb->devpath_tail, p) != 0) {
+		DBG("device path missmatch: '%s' != '%s'\n", xusb->devpath_tail, p);
+		return 0;
+	}
+	return 1;
+}
+
+struct xusb *xusb_find_bypath(const struct xusb_spec *specs, int numspecs, const char *path)
+{
+	struct xlist_node	*xlist;
+	struct xlist_node	*head;
+	struct xusb		*xusb;
+
+	xlist = xusb_find_byproduct(specs, numspecs, xusb_filter_bypath, (void *)path);
+	head = xlist_shift(xlist);
+	if (!head)
+		return NULL;
+	if (! xlist_empty(xlist)) {
+		ERR("Too many matches (extra %zd) to '%s'\n", xlist_length(xlist), path);
+		return NULL;
+	}
+	xusb = head->data;
+	xlist_destroy(xlist, NULL);
+	return xusb;
+}
+
+struct xlist_node *xusb_find_byproduct(const struct xusb_spec *specs, int numspecs, xusb_filter_t filterfunc, void *data)
+{
+	struct xlist_node	*xlist;
+	struct usb_bus		*bus;
+	struct usb_device	*dev;
+
+	DBG("specs(%d)\n", numspecs);
+	if((xlist = xlist_new(NULL)) == NULL) {
+		ERR("Failed allocation new xlist");
+		goto fail_xlist;
+	}
+	usb_init();
+	usb_find_busses();
+	usb_find_devices();
+	for (bus = usb_get_busses(); bus; bus = bus->next) {
+		for (dev = bus->devices; dev; dev = dev->next) {
+			struct usb_device_descriptor	*dev_desc;
+			struct xlist_node		*item;
+			int				i;
+
+			dev_desc = &dev->descriptor;
+			assert(dev_desc);
+			DBG("usb:%s/%s: ID=%04X:%04X\n",
+				dev->bus->dirname,
+				dev->filename,
+				dev_desc->idVendor,
+				dev_desc->idProduct);
+			for(i = 0; i < numspecs; i++) {
+				struct xusb		*xusb;
+				const struct xusb_spec	*sp = &specs[i];
+
+				if(!match_interface(dev, sp))
+					continue;
+				if((xusb = xusb_new(dev, sp)) == NULL) {
+					ERR("xusb allocation failed\n");
+					goto fail_malloc;
+				}
+				if(filterfunc && !filterfunc(xusb, data)) {
+					xusb_destroy(xusb);
+					continue;
+				}
+				item = xlist_new(xusb);
+				xlist_append_item(xlist, item);
+				break;
+			}
+		}
+	}
+	xusb_list_dump(xlist);
+	return xlist;
+fail_malloc:
+	xlist_destroy(xlist, NULL);
+fail_xlist:
+	return NULL;
+}
+
+struct xusb *xusb_open_one(const struct xusb_spec *specs, int numspecs, xusb_filter_t filterfunc, void *data)
+{
+	struct xlist_node	*xusb_list;
+	struct xlist_node	*curr;
+	int			num;
+	struct xusb		*xusb = NULL;
+
+	xusb_list = xusb_find_byproduct(specs, numspecs, filterfunc, data);
+	num = xlist_length(xusb_list);
+	DBG("total %d devices\n", num);
+	switch(num) {
+	case 0:
+		ERR("No matching device.\n");
+		break;
+	case 1:
+		curr = xlist_shift(xusb_list);
+		xusb = curr->data;
+		xlist_destroy(curr, NULL);
+		xlist_destroy(xusb_list, NULL);
+		xusb_claim_interface(xusb);
+		xusb_showinfo(xusb);
+		break;
+	default:
+		ERR("Too many devices (%d). Aborting.\n", num);
+		break;
+	}
+	return xusb;
+}
+
+int xusb_interface(struct xusb *xusb)
+{
+	return xusb->interface_num;
+}
+
+size_t xusb_packet_size(const struct xusb *xusb)
+{
+	return xusb->packet_size;
+}
+
+/*
+ * MP device handling
+ */
+void xusb_showinfo(const struct xusb *xusb)
+{
+	struct usb_device_descriptor	*dev_desc;
+	struct usb_device		*dev;
+
+	assert(xusb != NULL);
+	dev = xusb->dev;
+	dev_desc = &dev->descriptor;
+	if(verbose <= LOG_INFO) {
+		INFO("usb:%s/%s: ID=%04X:%04X [%s / %s / %s]\n",
+			dev->bus->dirname,
+			dev->filename,
+			dev_desc->idVendor,
+			dev_desc->idProduct,
+			xusb->iManufacturer,
+			xusb->iProduct,
+			xusb->iSerialNumber);
+	} else {
+		printf("USB    Bus/Device:    [%s/%s] (%s,%s)\n",
+			dev->bus->dirname,
+			dev->filename,
+			(xusb->is_open) ? "open" : "closed",
+			(xusb->is_claimed) ? "claimed" : "unused");
+		printf("USB    Spec name:     [%s]\n", xusb->spec->name);
+		printf("USB    iManufacturer: [%s]\n", xusb->iManufacturer);
+		printf("USB    iProduct:      [%s]\n", xusb->iProduct);
+		printf("USB    iSerialNumber: [%s]\n", xusb->iSerialNumber);
+	}
+}
+
+const char *xusb_serial(const struct xusb *xusb)
+{
+	return xusb->iSerialNumber;
+}
+
+const char *xusb_devpath(const struct xusb *xusb)
+{
+	return xusb->devpath_tail;
+}
+
+const char *xusb_manufacturer(const struct xusb *xusb)
+{
+	return xusb->iManufacturer;
+}
+
+const char *xusb_product(const struct xusb *xusb)
+{
+	return xusb->iProduct;
+}
+
+uint16_t xusb_vendor_id(const struct xusb *xusb)
+{
+	return  xusb->dev->descriptor.idVendor;
+}
+
+uint16_t xusb_product_id(const struct xusb *xusb)
+{
+	return  xusb->dev->descriptor.idProduct;
+}
+
+const struct xusb_spec *xusb_spec(const struct xusb *xusb)
+{
+	return xusb->spec;
+}
+
+int xusb_close(struct xusb *xusb)
+{
+	if(xusb) {
+		if(xusb->handle) {
+			assert(xusb->spec);
+			assert(xusb->spec->name);
+			DBG("Closing interface \"%s\"\n", xusb->spec->name);
+			if(xusb->is_claimed) {
+				if(usb_release_interface(xusb->handle, xusb->spec->my_interface_num) != 0) {
+					ERR("Releasing interface: usb: %s\n", usb_strerror());
+				}
+				xusb->is_claimed = 0;
+			}
+			if(xusb->is_open) {
+				if(usb_close(xusb->handle) != 0) {
+					ERR("Closing device: usb: %s\n", usb_strerror());
+				}
+				xusb->is_open = 0;
+			}
+			xusb->handle = NULL;
+		}
+		xusb = NULL;
+	}
+	return 0;
+}
+
+int xusb_send(struct xusb *xusb, char *buf, int len, int timeout)
+{
+	int		ret;
+
+	dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, buf, len);
+	if(EP_OUT(xusb) & USB_ENDPOINT_IN) {
+		ERR("%s called with an input endpoint 0x%x\n", __FUNCTION__, EP_OUT(xusb));
+		return -EINVAL;
+	}
+	ret = usb_bulk_write(xusb->handle, EP_OUT(xusb), buf, len, timeout);
+	if(ret < 0) {
+		/*
+		 * If the device was gone, it may be the
+		 * result of renumeration. Ignore it.
+		 */
+		if(ret != -ENODEV) {
+			ERR("bulk_write to endpoint 0x%x failed: (%d) %s\n",
+				EP_OUT(xusb), ret, usb_strerror());
+			dump_packet(LOG_ERR, DBG_MASK, "xbus_send[ERR]", buf, len);
+			//exit(2);
+		} else {
+			DBG("bulk_write to endpoint 0x%x got ENODEV\n", EP_OUT(xusb));
+			xusb_close(xusb);
+		}
+		return ret;
+	} else if(ret != len) {
+		ERR("bulk_write to endpoint 0x%x short write: (%d) %s\n",
+			EP_OUT(xusb), ret, usb_strerror());
+		dump_packet(LOG_ERR, DBG_MASK, "xbus_send[ERR]", buf, len);
+		return -EFAULT;
+	}
+	return ret;
+}
+
+int xusb_recv(struct xusb *xusb, char *buf, size_t len, int timeout)
+{
+	int	ret;
+
+	if(EP_IN(xusb) & USB_ENDPOINT_OUT) {
+		ERR("%s called with an output endpoint 0x%x\n", __FUNCTION__, EP_IN(xusb));
+		return -EINVAL;
+	}
+	ret = usb_bulk_read(xusb->handle, EP_IN(xusb), buf, len, timeout);
+	if(ret < 0) {
+		DBG("bulk_read from endpoint 0x%x failed: (%d) %s\n",
+			EP_IN(xusb), ret, usb_strerror());
+		memset(buf, 0, len);
+		return ret;
+	}
+	dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, buf, ret);
+	return ret;
+}
+
+int xusb_flushread(struct xusb *xusb)
+{
+	char		tmpbuf[BUFSIZ];
+	int		ret;
+
+	DBG("starting...\n");
+	memset(tmpbuf, 0, BUFSIZ);
+	ret = xusb_recv(xusb, tmpbuf, BUFSIZ, 1);
+	if(ret < 0 && ret != -ETIMEDOUT) {
+		ERR("ret=%d\n", ret);
+		return ret;
+	} else if(ret > 0) {
+		DBG("Got %d bytes:\n", ret);
+		dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, tmpbuf, ret);
+	}
+	return 0;
+}
diff --git a/xpp/xtalk/xusb.h b/xpp/xtalk/xusb.h
new file mode 100644
index 0000000..65da029
--- /dev/null
+++ b/xpp/xtalk/xusb.h
@@ -0,0 +1,98 @@
+#ifndef	XUSB_H
+#define	XUSB_H
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008, 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 <stdint.h>
+#include <usb.h>
+#include <xlist.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * Xorcom usb handling
+ */
+
+#define	PACKET_SIZE	512
+
+/*
+ * Specify the wanted interface
+ */
+struct xusb_spec {
+	/* Sanity checks so we know it is our device indeed */
+	int	num_interfaces;
+	int	num_endpoints;
+	char	*name;	/* For debug/output purpose */
+	/* What we will actually use */
+	uint16_t	my_vendor_id;
+	uint16_t	my_product_id;
+	int		my_interface_num;
+	int		my_ep_out;
+	int		my_ep_in;
+};
+
+void xusb_init_spec(struct xusb_spec *xusb_spec, char *name,
+		uint16_t vendor_id, uint16_t product_id,
+		int nifaces, int iface, int nep, int ep_out, int ep_in);
+
+struct xusb;
+
+/*
+ * Prototypes
+ */
+typedef int (*xusb_filter_t)(const struct xusb *xusb, void *data);
+struct xlist_node *xusb_find_byproduct(const struct xusb_spec *specs, int numspecs, xusb_filter_t filterfunc, void *data);
+struct xusb *xusb_find_bypath(const struct xusb_spec *specs, int numspecs, const char *path);
+struct xusb *xusb_open_one(const struct xusb_spec *specs, int numspecs, xusb_filter_t filterfunc, void *data);
+struct xusb *xusb_find_iface(const char *devpath, int iface_num, int ep_out, int ep_in);
+
+/*
+ * A convenience filter
+ */
+int xusb_filter_bypath(const struct xusb *xusb, void *data);
+
+int xusb_interface(struct xusb *xusb);
+int xusb_claim_interface(struct xusb *xusb);
+void xusb_destroy(struct xusb *xusb);
+int xusb_close(struct xusb *xusb);
+size_t xusb_packet_size(const struct xusb *xusb);
+void xusb_showinfo(const struct xusb *xusb);
+const char *xusb_serial(const struct xusb *xusb);
+const char *xusb_manufacturer(const struct xusb *xusb);
+const char *xusb_product(const struct xusb *xusb);
+uint16_t xusb_vendor_id(const struct xusb *xusb);
+uint16_t xusb_product_id(const struct xusb *xusb);
+const char *xusb_devpath(const struct xusb *xusb);
+const struct xusb_spec *xusb_spec(const struct xusb *xusb);
+int xusb_send(struct xusb *xusb, char *buf, int len, int timeout);
+int xusb_recv(struct xusb *xusb, char *buf, size_t len, int timeout);
+int xusb_flushread(struct xusb *xusb);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif	/* XUSB_H */

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-voip/dahdi-tools.git



More information about the Pkg-voip-commits mailing list