[Pkg-voip-commits] [dahdi-tools] 257/285: xpp: add all base libxtalk files

tzafrir at debian.org tzafrir at debian.org
Thu Jul 7 19:19:08 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 9c61e40187a6ad8a7d76432dd479336435cc388b
Author: Oron Peled <oron.peled at xorcom.com>
Date:   Sun Dec 21 10:39:19 2014 -0500

    xpp: add all base libxtalk files
    
    * Do not remove yet the old ones.
    * So new files are built, but not used yet.
    * Build as a "noinst_" convenience library.
    * Also, compile with '-Wno-unknown-pragmas' because we use some pragmas.
    
    Signed-off-by: Oron Peled <oron.peled at xorcom.com>
    Signed-off-by: Tzafrir Cohen <tzafrir.cohen at xorcom.com>
---
 .gitignore                              |   6 +
 configure.ac                            |   1 +
 xpp/Makefile.am                         |   2 +-
 xpp/xtalk/Makefile.am                   |  84 ++++
 xpp/xtalk/debug.c                       |   3 +-
 xpp/xtalk/include/xtalk/api_defs.h      |  38 ++
 xpp/xtalk/include/xtalk/debug.h         |  53 ++
 xpp/xtalk/include/xtalk/firmware_defs.h |  40 ++
 xpp/xtalk/include/xtalk/proto.h         | 186 +++++++
 xpp/xtalk/include/xtalk/proto_raw.h     |  76 +++
 xpp/xtalk/include/xtalk/proto_sync.h    |  75 +++
 xpp/xtalk/include/xtalk/xlist.h         |  32 ++
 xpp/xtalk/include/xtalk/xtalk_iface.h   |  19 +
 xpp/xtalk/include/xtalk/xusb.h          | 115 +++++
 xpp/xtalk/include/xtalk/xusb_iface.h    |  43 ++
 xpp/xtalk/xlist.c                       |  14 +-
 xpp/xtalk/xlist_test.c                  |  73 +++
 xpp/xtalk/xtalk-xusb.c                  |  70 +++
 xpp/xtalk/xtalk_base.c                  | 353 +++++++++++++
 xpp/xtalk/xtalk_base.h                  |  73 +++
 xpp/xtalk/xtalk_raw.c                   | 221 +++++++++
 xpp/xtalk/xtalk_raw_test.c              | 207 ++++++++
 xpp/xtalk/xtalk_send.8                  |  49 ++
 xpp/xtalk/xtalk_send.c                  | 220 +++++++++
 xpp/xtalk/xtalk_sync.c                  | 290 +++++++++++
 xpp/xtalk/xtalk_test.c                  | 199 ++++++++
 xpp/xtalk/xusb_common.c                 | 381 +++++++++++++++
 xpp/xtalk/xusb_common.h                 | 104 ++++
 xpp/xtalk/xusb_libusb.c                 | 843 ++++++++++++++++++++++++++++++++
 xpp/xtalk/xusb_libusbx.c                | 826 +++++++++++++++++++++++++++++++
 xpp/xtalk/xusb_test.c                   | 124 +++++
 xpp/xtalk/xusb_test_bypath.c            |  76 +++
 32 files changed, 4893 insertions(+), 3 deletions(-)

diff --git a/.gitignore b/.gitignore
index 3e9d0cc..87e8496 100644
--- a/.gitignore
+++ b/.gitignore
@@ -69,4 +69,10 @@ xpp/test_parse
 xpp/twinstar.8
 xpp/xpp_blink.8
 xpp/xpp_sync.8
+xpp/xtalk/xlist_test
+xpp/xtalk/xtalk_raw_test
+xpp/xtalk/xtalk_send
+xpp/xtalk/xtalk_test
+xpp/xtalk/xusb_test
+xpp/xtalk/xusb_test_bypath
 zonedata.lo
diff --git a/configure.ac b/configure.ac
index 38a1d12..74f1f0b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -372,6 +372,7 @@ AC_CONFIG_FILES([
 	hotplug/Makefile
 	ppp/Makefile
 	xpp/Makefile
+	xpp/xtalk/Makefile
 	xpp/oct612x/Makefile
 	xpp/perl_modules/Makefile
 	])
diff --git a/xpp/Makefile.am b/xpp/Makefile.am
index 0168036..e6fb290 100644
--- a/xpp/Makefile.am
+++ b/xpp/Makefile.am
@@ -64,7 +64,7 @@ CLEANFILES		= $(perl_checks) $(perl_mans)
 
 if	PBX_USB
 
-SUBDIRS		+= oct612x
+SUBDIRS		+= oct612x xtalk
 
 if	LIBUSBX
 USB_CFLAGS		= $(LIBUSBX_CFLAGS)
diff --git a/xpp/xtalk/Makefile.am b/xpp/xtalk/Makefile.am
new file mode 100644
index 0000000..e26e6b1
--- /dev/null
+++ b/xpp/xtalk/Makefile.am
@@ -0,0 +1,84 @@
+VISIBILITY_DEFS		= -DXTALK_DLL -DXTALK_DLL_EXPORTS
+COMMON_CFLAGS		= -Wall -Wno-unknown-pragmas -Werror $(VISIBILITY_DEFS) $(CFLAG_VISIBILITY)
+AM_CFLAGS		= $(COMMON_CFLAGS)
+
+
+if	LIBUSBX
+USB_CFLAGS		= $(LIBUSBX_CFLAGS)
+USB_LIBS		= $(LIBUSBX_LIBS)
+USB_NAME		= libusbx
+else
+if	LIBUSB
+USB_CFLAGS		= $(LIBUSB_CFLAGS)
+USB_LIBS		= $(LIBUSB_LIBS)
+USB_NAME		= libusb
+endif
+endif
+
+noinst_PROGRAMS		= xlist_test xusb_test xusb_test_bypath xtalk_test xtalk_raw_test
+sbin_PROGRAMS		= xtalk_send
+noinst_LTLIBRARIES	= libxtalk.la
+dist_noinst_HEADERS	= \
+	debug.h	\
+	xlist.h	\
+	xtalk.h	\
+	xtalk_base.h	\
+	xtalk_defs.h	\
+	xusb.h	\
+	xusb_common.h	\
+	include/xtalk/proto_raw.h	\
+	include/xtalk/api_defs.h	\
+	include/xtalk/xlist.h	\
+	include/xtalk/proto_sync.h	\
+	include/xtalk/xusb_iface.h	\
+	include/xtalk/proto.h	\
+	include/xtalk/debug.h	\
+	include/xtalk/xusb.h	\
+	include/xtalk/firmware_defs.h	\
+	include/xtalk/xtalk_iface.h	\
+	#
+
+man_MANS		= xtalk_send.8
+
+libxtalk_la_CFLAGS	= $(COMMON_CFLAGS) -I$(srcdir)/include -I$(srcdir) $(USB_CFLAGS)
+libxtalk_la_LDFLAGS	= #
+libxtalk_la_LIBADD	= $(USB_LIBS)
+libxtalk_la_SOURCES	= \
+			$(dist_noinst_HEADERS) \
+			xtalk_sync.c \
+			xtalk_raw.c \
+			xtalk_base.c \
+			xlist.c \
+			debug.c \
+			xtalk-xusb.c	\
+			xusb_common.c
+if	LIBUSBX
+libxtalk_la_SOURCES	+= xusb_libusbx.c
+else
+if	LIBUSB
+libxtalk_la_SOURCES	+= xusb_libusb.c
+endif
+endif
+libxtalk_la_DEPENDENCIES	= $(libxtalk_la_SOURCES)
+
+xtalk_send_CFLAGS	= $(COMMON_CFLAGS) -I$(srcdir)/include -I$(srcdir)
+xtalk_send_LDADD	= libxtalk.la $(USB_LIBS)
+
+xtalk_test_CFLAGS	= $(COMMON_CFLAGS) -I$(srcdir)/include -I$(srcdir)
+xtalk_test_LDADD	= libxtalk.la $(USB_LIBS)
+
+xtalk_raw_test_CFLAGS	= $(COMMON_CFLAGS) -I$(srcdir)/include -I$(srcdir)
+xtalk_raw_test_LDADD	= libxtalk.la $(USB_LIBS)
+
+xusb_test_CFLAGS	= $(COMMON_CFLAGS) -I$(srcdir)/include -I$(srcdir)
+xusb_test_LDADD		= libxtalk.la $(USB_LIBS)
+
+xusb_test_bypath_CFLAGS	= $(COMMON_CFLAGS) -I$(srcdir)/include -I$(srcdir)
+xusb_test_bypath_LDADD		= libxtalk.la $(USB_LIBS)
+
+xlist_test_CFLAGS	= $(COMMON_CFLAGS) -I$(srcdir)/include -I$(srcdir)
+xlist_test_LDADD	= libxtalk.la $(USB_LIBS)
+
+DISTCLEANFILES		= xtalk.pc xtalk-uninstalled.pc
+
+EXTRA_DIST	= $(man_MANS)
diff --git a/xpp/xtalk/debug.c b/xpp/xtalk/debug.c
index d2d4e15..88eace4 100644
--- a/xpp/xtalk/debug.c
+++ b/xpp/xtalk/debug.c
@@ -27,7 +27,8 @@
 #include <stdarg.h>
 #include <syslog.h>
 #include <execinfo.h>
-#include <debug.h>
+#include <xtalk/debug.h>
+#include <autoconfig.h>
 
 int	verbose = LOG_INFO;
 int	debug_mask;
diff --git a/xpp/xtalk/include/xtalk/api_defs.h b/xpp/xtalk/include/xtalk/api_defs.h
new file mode 100644
index 0000000..4188754
--- /dev/null
+++ b/xpp/xtalk/include/xtalk/api_defs.h
@@ -0,0 +1,38 @@
+#ifndef	XTALK_API_DEFS_H
+#define	XTALK_API_DEFS_H
+
+/*
+ * Visibility settings: taken from:
+ *     http://gcc.gnu.org/wiki/Visibility
+ */
+
+/* Generic helper definitions for shared library support */
+#if __GNUC__ >= 4
+	#define XTALK_HELPER_DLL_IMPORT __attribute__ ((visibility ("default")))
+	#define XTALK_HELPER_DLL_EXPORT __attribute__ ((visibility ("default")))
+	#define XTALK_HELPER_DLL_LOCAL  __attribute__ ((visibility ("hidden")))
+#else
+	#define XTALK_HELPER_DLL_IMPORT
+	#define XTALK_HELPER_DLL_EXPORT
+	#define XTALK_HELPER_DLL_LOCAL
+#endif
+
+/*
+ * Now we use the generic helper definitions above to define XTALK_API and XTALK_LOCAL.
+ * XTALK_API is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build)
+ * XTALK_LOCAL is used for non-api symbols.
+ */
+
+#ifdef XTALK_DLL /* defined if XTALK is compiled as a DLL */
+	#ifdef XTALK_DLL_EXPORTS /* defined if we are building the XTALK DLL (instead of using it) */
+		#define XTALK_API XTALK_HELPER_DLL_EXPORT
+	#else
+		#define XTALK_API XTALK_HELPER_DLL_IMPORT
+	#endif /* XTALK_DLL_EXPORTS */
+	#define XTALK_LOCAL XTALK_HELPER_DLL_LOCAL
+#else /* XTALK_DLL is not defined: this means XTALK is a static lib. */
+	#define XTALK_API
+	#define XTALK_LOCAL
+#endif /* XTALK_DLL */
+
+#endif	/* XTALK_API_DEFS_H */
diff --git a/xpp/xtalk/include/xtalk/debug.h b/xpp/xtalk/include/xtalk/debug.h
new file mode 100644
index 0000000..b7f3226
--- /dev/null
+++ b/xpp/xtalk/include/xtalk/debug.h
@@ -0,0 +1,53 @@
+#ifndef	DEBUG_H
+#define	DEBUG_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 <syslog.h>
+#include <stdio.h>
+#include <xtalk/api_defs.h>
+
+/*
+ * Each module should define a unique DBG_MASK
+ */
+
+XTALK_API extern	int	verbose;
+XTALK_API extern	int	debug_mask;
+
+/*
+ * Logging
+ */
+XTALK_API 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__, __func__, ## 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__, __func__, ## arg)
+
+XTALK_API void dump_packet(int loglevel, int mask, const char *msg,
+		const char *buf, int len);
+XTALK_API void print_backtrace(FILE *fp);
+
+#endif	/* DEBUG_H */
diff --git a/xpp/xtalk/include/xtalk/firmware_defs.h b/xpp/xtalk/include/xtalk/firmware_defs.h
new file mode 100644
index 0000000..af2072e
--- /dev/null
+++ b/xpp/xtalk/include/xtalk/firmware_defs.h
@@ -0,0 +1,40 @@
+#ifndef	XTALK_FIRMWARE_DEFS_H
+#define	XTALK_FIRMWARE_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_FIRMWARE_DEFS_H */
diff --git a/xpp/xtalk/include/xtalk/proto.h b/xpp/xtalk/include/xtalk/proto.h
new file mode 100644
index 0000000..946ad6a
--- /dev/null
+++ b/xpp/xtalk/include/xtalk/proto.h
@@ -0,0 +1,186 @@
+#ifndef	XTALK_PROTO_H
+#define	XTALK_PROTO_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>
+#include <xtalk/api_defs.h>
+#include <xtalk/firmware_defs.h>
+
+#ifdef	__GNUC__
+#define	PACKED	__attribute__((packed))
+#else
+#error "We do not know how your compiler packs structures"
+#endif
+
+struct xtalk_base;
+struct xtalk_command_desc;
+struct xtalk_command;
+
+/*
+ * Callbacks should return negative errno's
+ * in case of errors.
+ * They are called from process_command() and their
+ * return values are propagated back.
+ */
+typedef int (*xtalk_cmd_callback_t)(
+	const struct xtalk_base *xtalk_base,
+	const struct xtalk_command_desc *cmd_desc,
+	struct xtalk_command *cmd);
+
+/* Describe a single xtalk command */
+struct xtalk_command_desc {
+	uint8_t			op;
+	const char		*name;
+	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	XTALK_CMD_PTR(cmd, p)	((union XTALK_PDATA(p)*)&((cmd)->alt))
+#define	CMD_FIELD(cmd, p, o, field) \
+		(XTALK_CMD_PTR(cmd, p)->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)
+#define	XTALK_OP(p, o)		(p ## _ ## o)
+
+/* Wrappers for transport (xusb) functions */
+struct xtalk_ops {
+	int	(*send_func)(void *transport_priv, const char *data, size_t len,
+			int timeout);
+	int	(*recv_func)(void *transport_priv, char *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_base;
+struct xusb_iface;
+
+/* high-level */
+XTALK_API struct xtalk_base *xtalk_base_new_on_xusb(struct xusb_iface *xusb_iface);
+XTALK_API struct xtalk_base *xtalk_base_new(const struct xtalk_ops *ops,
+	size_t packet_size, void *priv);
+XTALK_API void xtalk_base_delete(struct xtalk_base *xtalk_base);
+XTALK_API struct xusb_iface *xusb_iface_of_xtalk_base(const struct xtalk_base *xtalk_base);
+XTALK_API const char *xtalk_protocol_name(const struct xtalk_base *dev);
+XTALK_API int xtalk_cmd_callback(struct xtalk_base *xtalk_base, int op,
+		xtalk_cmd_callback_t callback,
+		xtalk_cmd_callback_t *old_callback);
+XTALK_API void xtalk_dump_command(struct xtalk_command *cmd);
+XTALK_API int xtalk_set_timeout(struct xtalk_base *dev, int new_timeout);
+
+/* low-level */
+XTALK_API const char *ack_status_msg(const struct xtalk_protocol *xproto,
+		uint8_t status);
+XTALK_API struct xtalk_command *new_command(
+	const struct xtalk_base *xtalk_base,
+	uint8_t op, uint16_t extra_data);
+XTALK_API 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)
+ */
+#define	CMD_RECV(p, o)	\
+	[p ## _ ## o | XTALK_REPLY_MASK] = {		\
+		.op = (p ## _ ## o) | XTALK_REPLY_MASK,	\
+		.name = (#o "_reply"),			\
+		.len =					\
+			sizeof(struct xtalk_header) +	\
+			sizeof(struct XTALK_STRUCT(p, o)),	\
+	}
+
+#define	CMD_SEND(p, o)	\
+	[p ## _ ## o] = {		\
+		.op = (p ## _ ## o),	\
+		.name = (#o),		\
+		.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_PROTO_H */
diff --git a/xpp/xtalk/include/xtalk/proto_raw.h b/xpp/xtalk/include/xtalk/proto_raw.h
new file mode 100644
index 0000000..c9a9bb6
--- /dev/null
+++ b/xpp/xtalk/include/xtalk/proto_raw.h
@@ -0,0 +1,76 @@
+#ifndef	XTALK_PROTO_RAW_H
+#define	XTALK_PROTO_RAW_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 */
+
+/*
+ * XTALKSYNC - Base synchronous protocol for our USB devices
+ *             It is meant to provide a common base for layered
+ *             protocols (dialects)
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <xtalk/api_defs.h>
+#include <xtalk/proto.h>
+#include <xtalk/firmware_defs.h>
+
+#ifdef	__GNUC__
+#define	PACKED	__attribute__((packed))
+#else
+#error "We do not know how your compiler packs structures"
+#endif
+
+/*
+ * Base XTALK device. A pointer to this struct
+ * should be included in the struct representing
+ * the dialect.
+ */
+struct xtalk_raw;
+struct xusb;
+
+XTALK_API struct xtalk_raw *xtalk_raw_new(struct xtalk_base *xtalk_base);
+XTALK_API void xtalk_raw_delete(struct xtalk_raw *xraw);
+XTALK_API int xtalk_raw_set_protocol(struct xtalk_raw *xtalk_base,
+		const struct xtalk_protocol *xproto);
+XTALK_API int xtalk_raw_cmd_recv(struct xtalk_raw *xraw,
+	struct xtalk_command **reply_ref);
+XTALK_API int xtalk_raw_cmd_send(struct xtalk_raw *xraw, const char *buf, int len,
+       uint16_t *tx_seq);
+
+/*
+ * These are low-level interfaces that receive/send arbitrary buffers
+ * Be carefull, as that allow to send illegal Xtalk packets
+ */
+XTALK_API int xtalk_raw_buffer_recv(struct xtalk_raw *xraw, char *buf, int len);
+XTALK_API int xtalk_raw_buffer_send(struct xtalk_raw *xraw, const char *buf, int len);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif	/* XTALK_PROTO_RAW_H */
diff --git a/xpp/xtalk/include/xtalk/proto_sync.h b/xpp/xtalk/include/xtalk/proto_sync.h
new file mode 100644
index 0000000..b8895a7
--- /dev/null
+++ b/xpp/xtalk/include/xtalk/proto_sync.h
@@ -0,0 +1,75 @@
+#ifndef	XTALK_PROTO_SYNC_H
+#define	XTALK_PROTO_SYNC_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.
+ *
+ */
+
+#include <xtalk/api_defs.h>
+#include <xtalk/proto.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * XTALKSYNC - Base synchronous protocol for our USB devices
+ *             It is meant to provide a common base for layered
+ *             protocols (dialects)
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <xtalk/firmware_defs.h>
+
+#ifdef	__GNUC__
+#define	PACKED	__attribute__((packed))
+#else
+#error "We do not know how your compiler packs structures"
+#endif
+
+/*
+ * Base XTALK device. A pointer to this struct
+ * should be included in the struct representing
+ * the dialect.
+ */
+struct xtalk_sync;
+struct xusb;
+
+/* high-level */
+XTALK_API struct xtalk_sync *xtalk_sync_new(struct xtalk_base *xtalk_base);
+XTALK_API void xtalk_sync_delete(struct xtalk_sync *xtalk_sync);
+XTALK_API int xtalk_sync_set_protocol(struct xtalk_sync *xtalk_base,
+		const struct xtalk_protocol *xproto);
+XTALK_API int xtalk_proto_query(struct xtalk_sync *dev);
+
+/* low-level */
+XTALK_API int process_command(
+	struct xtalk_sync *dev,
+	struct xtalk_command *cmd,
+	struct xtalk_command **reply_ref,
+	uint16_t *sequence_number);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif	/* XTALK_PROTO_SYNC_H */
diff --git a/xpp/xtalk/include/xtalk/xlist.h b/xpp/xtalk/include/xtalk/xlist.h
new file mode 100644
index 0000000..3b1bae4
--- /dev/null
+++ b/xpp/xtalk/include/xtalk/xlist.h
@@ -0,0 +1,32 @@
+#ifndef	XLIST_H
+#define	XLIST_H
+
+#include <xtalk/api_defs.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);
+
+XTALK_API struct xlist_node *xlist_new(void *data);
+XTALK_API void xlist_destroy(struct xlist_node *list, xlist_destructor_t destructor);
+XTALK_API void xlist_append_list(struct xlist_node *list1, struct xlist_node *list2);
+XTALK_API void xlist_append_item(struct xlist_node *list, struct xlist_node *item);
+XTALK_API void xlist_remove_item(struct xlist_node *item);
+XTALK_API struct xlist_node *xlist_shift(struct xlist_node *list);
+XTALK_API int xlist_empty(const struct xlist_node *list);
+XTALK_API size_t xlist_length(const struct xlist_node *list);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif	/* XLIST_H */
diff --git a/xpp/xtalk/include/xtalk/xtalk_iface.h b/xpp/xtalk/include/xtalk/xtalk_iface.h
new file mode 100644
index 0000000..4b08713
--- /dev/null
+++ b/xpp/xtalk/include/xtalk/xtalk_iface.h
@@ -0,0 +1,19 @@
+/*
+ * Wrappers for swig/python integration
+ */
+
+struct Command {
+	struct xtalk_command	*command;
+};
+
+struct Xtalksync {
+	struct xtalk_base	*xtalk_base;
+	struct xtalk_sync	*xtalk_sync;
+	struct XusbIface	*py_xusb_iface;
+};
+
+struct Xtalkraw {
+	struct xtalk_base	*xtalk_base;
+	struct xtalk_raw	*xtalk_raw;
+	struct XusbIface	*py_xusb_iface;
+};
diff --git a/xpp/xtalk/include/xtalk/xusb.h b/xpp/xtalk/include/xtalk/xusb.h
new file mode 100644
index 0000000..2544985
--- /dev/null
+++ b/xpp/xtalk/include/xtalk/xusb.h
@@ -0,0 +1,115 @@
+#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 <xtalk/api_defs.h>
+#include <xtalk/xlist.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * Xorcom usb handling
+ */
+
+#define	PACKET_SIZE	512
+
+/*
+ * Specify the wanted device
+ */
+struct xusb_spec {
+	char	*name;	/* For debug/output purpose */
+	/* What we will actually use */
+	uint16_t	vendor_id;
+	uint16_t	product_id;
+};
+
+#define	SPEC_HEAD(vendor_id_, product_id_, name_) \
+	{ \
+		.name = (name_), \
+		.vendor_id = (vendor_id_), \
+		.product_id = (product_id_), \
+	}
+
+XTALK_API void xusb_init_spec(struct xusb_spec *xusb_spec,
+	char *name, uint16_t vendor_id, uint16_t product_id);
+
+struct xusb_device;
+struct xusb_iface;
+
+/*
+ * Prototypes
+ */
+typedef int (*xusb_filter_t)(const struct xusb_device *xusb_device, void *data);
+XTALK_API struct xlist_node *xusb_find_byproduct(const struct xusb_spec *specs,
+		int numspecs, xusb_filter_t filterfunc, void *data);
+XTALK_API struct xusb_device *xusb_find_bypath(const char *path);
+XTALK_API struct xusb_iface *xusb_open_one(const struct xusb_spec *specs, int numspecs,
+		int interface_num,
+		xusb_filter_t filterfunc, void *data);
+
+/*
+ * A convenience filter
+ */
+XTALK_API int xusb_filter_bypath(const struct xusb_device *xusb_device, void *data);
+
+/* Device management */
+XTALK_API const struct xusb_spec *xusb_spec(const struct xusb_device *xusb_device);
+XTALK_API void xusb_destroy(struct xusb_device *xusb_device);
+XTALK_API size_t xusb_packet_size(const struct xusb_device *xusb_device);
+XTALK_API void xusb_showinfo(const struct xusb_device *xusb_device);
+XTALK_API const char *xusb_serial(const struct xusb_device *xusb_device);
+XTALK_API const char *xusb_manufacturer(const struct xusb_device *xusb_device);
+XTALK_API const char *xusb_product(const struct xusb_device *xusb_device);
+XTALK_API uint16_t xusb_bus_num(const struct xusb_device *xusb_device);
+XTALK_API uint16_t xusb_device_num(const struct xusb_device *xusb_device);
+XTALK_API uint16_t xusb_vendor_id(const struct xusb_device *xusb_device);
+XTALK_API uint16_t xusb_product_id(const struct xusb_device *xusb_device);
+XTALK_API const char *xusb_devpath(const struct xusb_device *xusb_device);
+XTALK_API const struct xusb_spec *xusb_device_spec(const struct xusb_device *xusb_device);
+XTALK_API struct xusb_iface *xusb_find_iface(const char *devpath,
+	int iface_num,
+	int ep_out,
+	int ep_in,
+	struct xusb_spec *dummy_spec);
+XTALK_API int xusb_claim(struct xusb_device *xusb_device, unsigned int interface_num,
+	struct xusb_iface **iface);
+XTALK_API void xusb_release(struct xusb_iface *iface);
+XTALK_API int xusb_is_claimed(struct xusb_iface *iface);
+XTALK_API struct xusb_iface *xusb_interface_of(const struct xusb_device *dev, int num);
+XTALK_API struct xusb_device *xusb_deviceof(struct xusb_iface *iface);
+XTALK_API const char *xusb_interface_name(const struct xusb_iface *iface);
+XTALK_API int xusb_interface_num(const struct xusb_iface *iface);
+XTALK_API int xusb_send(struct xusb_iface *iface, const char *buf, int len, int timeout);
+XTALK_API int xusb_recv(struct xusb_iface *iface, char *buf, size_t len, int timeout);
+XTALK_API int xusb_flushread(struct xusb_iface *iface);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif	/* XUSB_H */
diff --git a/xpp/xtalk/include/xtalk/xusb_iface.h b/xpp/xtalk/include/xtalk/xusb_iface.h
new file mode 100644
index 0000000..407f04a
--- /dev/null
+++ b/xpp/xtalk/include/xtalk/xusb_iface.h
@@ -0,0 +1,43 @@
+/*
+ * Wrappers for swig/python integration
+ */
+
+#ifdef	SWIG
+%feature("docstring", "Represents the specification of wanted USB device") Spec;
+#endif
+struct Spec {
+#ifdef	SWIG
+	%immutable spec;
+	%immutable ref_count;
+#endif
+	struct xusb_spec	*spec;
+	int			ref_count;
+};
+
+#ifdef	SWIG
+%feature("docstring", "Represents a single USB device") XusbDev;
+#endif
+struct XusbDev {
+#ifdef	SWIG
+	%immutable spec;
+	%immutable xusb_device;
+	%immutable ref_count;
+#endif
+	struct Spec		*spec_wrapper;
+	struct xusb_device	*xusb_device;
+	int			ref_count;
+};
+
+#ifdef	SWIG
+%feature("docstring", "Represents a single USB interface") XusbIface;
+#endif
+struct XusbIface {
+#ifdef	SWIG
+	%immutable dev_wrapper;
+	%immutable iface;
+#endif
+	struct XusbDev		*dev_wrapper;	/* for ref-counting */
+	struct xusb_iface	*iface;
+};
+
+
diff --git a/xpp/xtalk/xlist.c b/xpp/xtalk/xlist.c
index d8cd3df..bc2f1c6 100644
--- a/xpp/xtalk/xlist.c
+++ b/xpp/xtalk/xlist.c
@@ -1,7 +1,8 @@
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
-#include <xlist.h>
+#include <xtalk/xlist.h>
+#include <autoconfig.h>
 
 struct xlist_node *xlist_new(void *data)
 {
@@ -36,6 +37,17 @@ void xlist_destroy(struct xlist_node *list, xlist_destructor_t destructor)
 	free(list);
 }
 
+void xlist_append_list(struct xlist_node *list1, struct xlist_node *list2)
+{
+	struct xlist_node *curr;
+
+	assert(list1);
+	assert(list2);
+
+	while ((curr = xlist_shift(list2)) != NULL)
+		xlist_append_item(list1, curr);
+}
+
 void xlist_append_item(struct xlist_node *list, struct xlist_node *item)
 {
 	assert(list);
diff --git a/xpp/xtalk/xlist_test.c b/xpp/xtalk/xlist_test.c
new file mode 100644
index 0000000..d5e7180
--- /dev/null
+++ b/xpp/xtalk/xlist_test.c
@@ -0,0 +1,73 @@
+#include <assert.h>
+#include <stdio.h>
+#include <xtalk/xlist.h>
+#include <autoconfig.h>
+
+void dump_list(const struct xlist_node *list)
+{
+	struct xlist_node *curr;
+	const char *p;
+	int len;
+
+	len = xlist_length(list);
+	p = list->data;
+	printf("dumping list: %s[%d]\n", p, len);
+	for (curr = list->next; curr != list; curr = curr->next) {
+		p = curr->data;
+		printf("> %s\n", p);
+	}
+}
+
+void string_destructor(void *data)
+{
+	const char	*p = data;
+
+	printf("destroy: '%s'\n", p);
+}
+
+int main()
+{
+	struct xlist_node	*list1;
+	struct xlist_node	*list2;
+	struct xlist_node	*list3;
+	struct xlist_node	*item1;
+	struct xlist_node	*item2;
+	struct xlist_node	*item3;
+
+	list1 = xlist_new("list1");
+	list2 = xlist_new("list2");
+	list3 = xlist_new("list3");
+	item1 = xlist_new("item1");
+	item2 = xlist_new("item2");
+	item3 = xlist_new("item3");
+	assert(xlist_empty(list1));
+	assert(xlist_empty(list2));
+	assert(xlist_empty(list3));
+	assert(xlist_empty(item1));
+	assert(xlist_empty(item2));
+	assert(xlist_empty(item3));
+	dump_list(list1);
+	dump_list(list2);
+	xlist_append_item(list1, item1);
+	assert(!xlist_empty(list1));
+	xlist_append_item(list1, item2);
+	xlist_append_item(list1, item3);
+	dump_list(list1);
+	xlist_remove_item(item2);
+	assert(!xlist_empty(list1));
+	xlist_append_item(list2, item2);
+	assert(!xlist_empty(list2));
+	dump_list(list1);
+	dump_list(list2);
+	xlist_shift(list1);
+	dump_list(list1);
+	xlist_append_list(list1, list2);
+	dump_list(list1);
+	xlist_append_item(list3, item1);
+	xlist_append_list(list1, list3);
+	dump_list(list1);
+	xlist_destroy(list1, string_destructor);
+	xlist_destroy(list2, string_destructor);
+	xlist_destroy(list3, string_destructor);
+	return 0;
+}
diff --git a/xpp/xtalk/xtalk-xusb.c b/xpp/xtalk/xtalk-xusb.c
new file mode 100644
index 0000000..1ac9bf4
--- /dev/null
+++ b/xpp/xtalk/xtalk-xusb.c
@@ -0,0 +1,70 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2012, 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.
+ *
+ */
+
+/*
+ * Convenience wrappers for xtalk_base over xusb
+ */
+#include <assert.h>
+#include <xtalk/debug.h>
+#include <xtalk/xusb.h>
+#include <autoconfig.h>
+#include "xtalk_base.h"
+
+static inline int close_func(void *priv)
+{
+	struct xusb_iface *iface = (struct xusb_iface *)priv;
+	xusb_release(iface);
+        return 0;
+}
+
+static inline int send_func(void *priv, const char *data, size_t len, int timeout)
+{
+	return xusb_send((struct xusb_iface *)priv, data, len, timeout);
+}
+
+static inline int recv_func(void *priv, char *data, size_t maxlen, int timeout)
+{
+	return xusb_recv((struct xusb_iface *)priv, data, maxlen, timeout);
+}
+
+
+static struct xtalk_ops	xtalk_ops = {
+	.send_func	= send_func,
+	.recv_func	= recv_func,
+	.close_func	= close_func,
+};
+
+struct xtalk_base *xtalk_base_new_on_xusb(struct xusb_iface *xusb_iface)
+{
+	struct xtalk_base	*xtalk_base;
+	int packet_size;
+
+	assert(xusb_iface);
+	packet_size = xusb_packet_size(xusb_deviceof(xusb_iface));
+
+	xtalk_base = xtalk_base_new(&xtalk_ops, packet_size, xusb_iface);
+	if (!xtalk_base) {
+		ERR("Failed creating the xtalk device abstraction\n");
+		return NULL;
+	}
+	return xtalk_base;
+}
diff --git a/xpp/xtalk/xtalk_base.c b/xpp/xtalk/xtalk_base.c
new file mode 100644
index 0000000..4dbb5ec
--- /dev/null
+++ b/xpp/xtalk/xtalk_base.c
@@ -0,0 +1,353 @@
+/*
+ * 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/debug.h>
+#include <autoconfig.h>
+#include "xtalk_base.h"
+
+#define	DBG_MASK	0x02
+
+void free_command(struct xtalk_command *cmd)
+{
+	if (!cmd)
+		return;
+	memset(cmd, 0, cmd->header.len);
+	free(cmd);
+}
+
+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;
+}
+
+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;
+}
+
+const char *xtalk_protocol_name(const struct xtalk_base *xtalk_base)
+{
+	const struct xtalk_protocol	*xproto;
+
+	xproto = &xtalk_base->xproto;
+        return (xproto) ? xproto->name : "";
+}
+
+int xtalk_set_protocol(struct xtalk_base *xtalk_base,
+		const struct xtalk_protocol *xproto_base,
+		const struct xtalk_protocol *xproto)
+{
+	const char	*protoname = (xproto) ? xproto->name : "GLOBAL";
+	int		i;
+
+	DBG("%s\n", protoname);
+	memset(&xtalk_base->xproto, 0, sizeof(xtalk_base->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_base->xproto.commands[i] = *desc;
+			DBG("private: op=0x%X (%s)\n", i, desc->name);
+		} else {
+			if (!IS_PRIVATE_OP(i)) {
+				const char	*name;
+
+				xtalk_base->xproto.commands[i] =
+					xproto_base->commands[i];
+				name = xtalk_base->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_base->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_base->xproto.ack_statuses[i] =
+					xproto_base->ack_statuses[i];
+				stat_msg = xtalk_base->xproto.ack_statuses[i];
+				if (stat_msg)
+					DBG("global: status=0x%X (%s)\n",
+						i, stat_msg);
+			}
+		}
+	}
+	xtalk_base->xproto.name = protoname;
+	xtalk_base->xproto.proto_version = (xproto) ? xproto->proto_version : 0;
+	return 0;
+}
+
+int xtalk_cmd_callback(struct xtalk_base *xtalk_base, int op,
+	xtalk_cmd_callback_t callback,
+	xtalk_cmd_callback_t *old_callback)
+{
+	const struct xtalk_protocol	*xproto;
+	const struct xtalk_command_desc	*desc;
+
+	xproto = &xtalk_base->xproto;
+	desc = get_command_desc(xproto, op);
+	if (!desc)
+		DBG("Unknown op=0x%X.\n", op);
+	if (old_callback)
+		*old_callback = xtalk_base->callbacks[op];
+	if (callback) {
+		xtalk_base->callbacks[op] = callback;
+		DBG("OP=0x%X [%s] -- set callback to %p\n",
+			op,
+			(desc) ? desc->name : "",
+			callback);
+	}
+	return 0;
+}
+
+struct xtalk_command *new_command(
+	const struct xtalk_base *xtalk_base,
+	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_base->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;
+	cmd = malloc(len);
+	if (!cmd) {
+		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]);
+}
+
+int xtalk_set_timeout(struct xtalk_base *dev, int new_timeout)
+{
+	int old_timeout = dev->default_timeout;
+	dev->default_timeout = new_timeout;
+	return old_timeout;
+}
+
+int send_buffer(struct xtalk_base *xtalk_base, const char *buf, int len)
+{
+	int		ret;
+	void		*priv = xtalk_base->transport_priv;
+	int		timeout = xtalk_base->default_timeout;
+
+	ret = xtalk_base->ops.send_func(priv, buf, len, timeout);
+	if (ret < 0)
+		DBG("%s: failed ret=%d\n", __func__, ret);
+	return ret;
+}
+
+int recv_buffer(struct xtalk_base *xtalk_base, char *buf, int len)
+{
+	void			*priv = xtalk_base->transport_priv;
+	int			timeout = xtalk_base->default_timeout;
+	int			ret;
+
+	ret = xtalk_base->ops.recv_func(priv, buf, len, timeout);
+	if (ret < 0) {
+		DBG("Receive from usb failed (ret=%d)\n", ret);
+		goto out;
+	} else if (ret == 0) {
+		DBG("No reply\n");
+		goto out;	/* No reply */
+	}
+        DBG("Received %d bytes\n", ret);
+out:
+	return ret;
+}
+
+int send_command(struct xtalk_base *xtalk_base,
+		struct xtalk_command *cmd, uint16_t *tx_seq)
+{
+	int		ret;
+	int		len;
+
+	len = cmd->header.len;
+	cmd->header.seq = xtalk_base->tx_sequenceno;
+	ret = send_buffer(xtalk_base, (const char *)cmd, len);
+	if (ret < 0)
+		DBG("%s: failed ret=%d\n", __func__, ret);
+	else if (tx_seq)
+		*tx_seq = xtalk_base->tx_sequenceno++;
+	return ret;
+}
+
+int recv_command(struct xtalk_base *xtalk_base,
+		struct xtalk_command **reply_ref)
+{
+	struct xtalk_command	*reply;
+	size_t			psize = xtalk_base->packet_size;
+	int			ret;
+
+	reply = malloc(psize);
+	if (!reply) {
+		ERR("Out of memory\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	reply->header.len = 0;
+	ret = recv_buffer(xtalk_base, (char *)reply, psize);
+	if (ret < 0) {
+		DBG("%s: calling recv_buffer() failed (ret=%d)\n", __func__, ret);
+		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, __func__, (char *)reply, ret); */
+	*reply_ref = reply;
+	return ret;
+err:
+	if (reply) {
+		memset(reply, 0, psize);
+		free_command(reply);
+		*reply_ref = NULL;
+	}
+	return ret;
+}
+
+/*
+ * Wrappers
+ */
+
+struct xtalk_base *xtalk_base_new(const struct xtalk_ops *ops,
+	size_t packet_size, void *priv)
+{
+	struct xtalk_base *xtalk_base;
+
+	DBG("\n");
+	assert(ops != NULL);
+	xtalk_base = calloc(1, sizeof(*xtalk_base));
+	if (!xtalk_base) {
+		ERR("Allocating XTALK device memory failed\n");
+		return NULL;
+	}
+	memcpy((void *)&xtalk_base->ops, (const void *)ops,
+		sizeof(xtalk_base->ops));
+	xtalk_base->packet_size = packet_size;
+	xtalk_base->transport_priv = priv;
+	xtalk_base->tx_sequenceno = 1;
+	xtalk_base->default_timeout = 2000;	/* millies */
+	return xtalk_base;
+}
+
+void xtalk_base_delete(struct xtalk_base *xtalk_base)
+{
+	void	*priv;
+
+	if (!xtalk_base)
+		return;
+	DBG("\n");
+	priv = xtalk_base->transport_priv;
+	assert(priv);
+	xtalk_base->tx_sequenceno = 0;
+	assert(&xtalk_base->ops != NULL);
+	assert(&xtalk_base->ops.close_func != NULL);
+	xtalk_base->ops.close_func(priv);
+	memset(xtalk_base, 0, sizeof(*xtalk_base));
+	free(xtalk_base);
+}
diff --git a/xpp/xtalk/xtalk_base.h b/xpp/xtalk/xtalk_base.h
new file mode 100644
index 0000000..6923675
--- /dev/null
+++ b/xpp/xtalk/xtalk_base.h
@@ -0,0 +1,73 @@
+#ifndef	XTALK_BASE_H
+#define	XTALK_BASE_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.
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <xtalk/proto.h>
+#include <xtalk/firmware_defs.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * Base XTALK device. A pointer to this struct
+ * should be included in the struct representing
+ * the dialect.
+ */
+struct xtalk_base {
+	void			*transport_priv;	/* e.g: struct xusb */
+	struct xtalk_ops	ops;
+	struct xtalk_protocol	xproto;
+	xtalk_cmd_callback_t	callbacks[MAX_OPS];
+	uint8_t			xtalk_proto_version;
+	uint8_t                 status;
+	size_t			packet_size;
+	uint16_t                tx_sequenceno;
+	int			default_timeout;	/* in millies */
+};
+
+int xtalk_set_protocol(struct xtalk_base *xtalk_base,
+		const struct xtalk_protocol *xproto_base,
+		const struct xtalk_protocol *xproto);
+const struct xtalk_command_desc *get_command_desc(
+		const struct xtalk_protocol *xproto, uint8_t op);
+int send_command(struct xtalk_base *xtalk_base,
+		struct xtalk_command *cmd, uint16_t *tx_seq);
+int recv_command(struct xtalk_base *xtalk_base,
+		struct xtalk_command **reply_ref);
+
+/*
+ * These are low-level interfaces that receive/send arbitrary buffers
+ * Be carefull, as that allow to send illegal Xtalk packets
+ */
+int send_buffer(struct xtalk_base *xtalk_base, const char *buf, int len);
+int recv_buffer(struct xtalk_base *xtalk_base, char *buf, int len);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif	/* XTALK_BASE_H */
diff --git a/xpp/xtalk/xtalk_raw.c b/xpp/xtalk/xtalk_raw.c
new file mode 100644
index 0000000..49e47d5
--- /dev/null
+++ b/xpp/xtalk/xtalk_raw.c
@@ -0,0 +1,221 @@
+/*
+ * 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/debug.h>
+#include <xtalk/proto_raw.h>
+#include <autoconfig.h>
+#include "xtalk_base.h"
+
+#define	DBG_MASK	0x02
+
+/*
+ * Base XTALK device. A pointer to this struct
+ * should be included in the struct representing
+ * the dialect.
+ */
+struct xtalk_raw {
+	struct xtalk_base	*xtalk_base;
+};
+
+CMD_DEF(XTALK, ACK,
+	uint8_t stat;
+	);
+
+union XTALK_PDATA(XTALK) {
+	MEMBER(XTALK, ACK);
+} PACKED members;
+
+const struct xtalk_protocol	xtalk_raw_proto = {
+	.name	= "XTALK-RAW",
+	.proto_version = 0,
+	.commands = {
+		CMD_RECV(XTALK, ACK),
+	},
+	.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"),
+	}
+};
+
+struct xtalk_raw *xtalk_raw_new(struct xtalk_base *xtalk_base)
+{
+	struct xtalk_raw *xtalk_raw;
+	int ret;
+
+	assert(xtalk_base);
+	xtalk_raw = calloc(1, sizeof(*xtalk_raw));
+	if (!xtalk_raw) {
+		ERR("Allocating XTALK device memory failed\n");
+		return NULL;
+	}
+	xtalk_raw->xtalk_base = xtalk_base;
+	ret = xtalk_set_protocol(xtalk_raw->xtalk_base, &xtalk_raw_proto, NULL);
+	if (ret < 0) {
+		ERR("GLOBAL Protocol registration failed: %d\n", ret);
+		goto err;
+	}
+	DBG("%s: xtalk_raw=%p\n", __func__, xtalk_raw);
+	return xtalk_raw;
+err:
+	xtalk_raw_delete(xtalk_raw);
+	return NULL;
+}
+
+void xtalk_raw_delete(struct xtalk_raw *xtalk_raw)
+{
+	if (xtalk_raw) {
+		memset(xtalk_raw, 0, sizeof(*xtalk_raw));
+		free(xtalk_raw);
+	}
+}
+
+int xtalk_raw_set_protocol(struct xtalk_raw *xtalk_raw,
+		const struct xtalk_protocol *xproto)
+{
+	return xtalk_set_protocol(xtalk_raw->xtalk_base, &xtalk_raw_proto, xproto);
+}
+
+int xtalk_raw_cmd_send(struct xtalk_raw *xtalk_raw, const char *buf, int len,
+	uint16_t *tx_seq)
+{
+	struct xtalk_command *cmd;
+	char *p;
+	int ret;
+
+	p = malloc(len);
+	if (!p) {
+		ERR("allocation failed (%d bytes)\n", len);
+		return -ENOMEM;
+	}
+	cmd = (struct xtalk_command *)p;
+	memcpy(p, buf, len);
+	cmd->header.len = len;
+
+	ret = send_command(xtalk_raw->xtalk_base, cmd, tx_seq);
+	if (ret < 0) {
+		DBG("%s: send_command(%d bytes) failed ret=%d\n",
+			__func__, len, ret);
+		goto out;
+	}
+	DBG("%s(%d bytes, tx_seq=%d)\n", __func__, len, *tx_seq);
+out:
+	free(p);
+	return ret;
+}
+
+__attribute__((warn_unused_result))
+int xtalk_raw_cmd_recv(struct xtalk_raw *xtalk_raw,
+	struct xtalk_command **reply_ref)
+{
+	struct xtalk_base *xtalk_base;
+	const struct xtalk_protocol	*xproto;
+	struct xtalk_command		*reply = NULL;
+	const struct xtalk_command_desc	*reply_desc;
+	const char			*protoname;
+	int				ret;
+	xtalk_cmd_callback_t		callback;
+
+	xtalk_base = xtalk_raw->xtalk_base;
+	xproto = &xtalk_base->xproto;
+	protoname = (xproto) ? xproto->name : "GLOBAL";
+	/* So the caller knows if a reply was received */
+	if (reply_ref)
+		*reply_ref = NULL;
+	ret = recv_command(xtalk_base, &reply);
+	if (ret <= 0) {
+		DBG("%s: failed (xproto = %s, ret = %d)\n",
+			__func__, protoname, ret);
+		goto err;
+	}
+	DBG("REPLY OP: 0x%X\n", reply->header.op);
+        if (debug_mask & DBG_MASK)
+                xtalk_dump_command(reply);
+	/* reply_desc may be NULL (raw reply to application) */
+	reply_desc = get_command_desc(xproto, reply->header.op);
+	if (reply->header.op == XTALK_ACK) {
+		int	status = CMD_FIELD(reply, XTALK, ACK, stat);
+
+		if (status != STAT_OK) {
+			ERR("Got NACK(seq=%d): %d %s\n",
+				reply->header.seq,
+				status,
+				ack_status_msg(xproto, status));
+		}
+		/* Good expected ACK ... */
+	}
+	DBG("got reply seq=%d op=0x%X (%d bytes)\n",
+		reply->header.seq,
+		reply->header.op,
+		ret);
+	/* Find if there is associated callback */
+	ret = xtalk_cmd_callback(xtalk_base, reply->header.op, NULL, &callback);
+	if (ret < 0) {
+		ERR("Failed getting callback for op=0x%X\n", reply->header.op);
+		goto err;
+	}
+	if (callback) {
+		/* Override return value with callback return value */
+		ret = callback(xtalk_base, reply_desc, reply);
+		DBG("%s: callback for 0x%X returned %d\n", __func__,
+			reply->header.op, ret);
+	}
+	if (reply_ref)
+		*reply_ref = reply;
+	return 0;
+err:
+	if (reply)
+		free_command(reply);
+	return ret;
+}
+
+int xtalk_raw_buffer_send(struct xtalk_raw *xraw, const char *buf, int len)
+{
+	dump_packet(LOG_DEBUG, DBG_MASK, __func__, buf, len);
+	return send_buffer(xraw->xtalk_base, buf, len);
+}
+
+int xtalk_raw_buffer_recv(struct xtalk_raw *xraw, char *buf, int len)
+{
+	int ret;
+
+	ret = recv_buffer(xraw->xtalk_base, buf, len);
+	if (ret >= 0)
+		dump_packet(LOG_DEBUG, DBG_MASK, __func__, buf, ret);
+	return ret;
+}
diff --git a/xpp/xtalk/xtalk_raw_test.c b/xpp/xtalk/xtalk_raw_test.c
new file mode 100644
index 0000000..e693cf9
--- /dev/null
+++ b/xpp/xtalk/xtalk_raw_test.c
@@ -0,0 +1,207 @@
+#include <assert.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <xtalk/debug.h>
+#include <xtalk/xusb.h>
+#include <xtalk/proto_raw.h>
+#include <autoconfig.h>
+
+static char	*progname;
+
+#define	DBG_MASK	0x10
+
+static void usage()
+{
+	fprintf(stderr, "Usage: %s [options...] -D <device> [hexnum ....]\n",
+		progname);
+	fprintf(stderr, "\tOptions:\n");
+	fprintf(stderr, "\t\t[-v]               # Increase verbosity\n");
+	fprintf(stderr,
+		"\t\t[-d mask]          # Debug mask (0xFF for everything)\n");
+	fprintf(stderr, "\tDevice:\n");
+	fprintf(stderr, "\t\t/proc/bus/usb/<bus>/<dev>\n");
+	fprintf(stderr, "\t\t/dev/bus/usb/<bus>/<dev>\n");
+	exit(1);
+}
+
+static void xusb_destructor(void *data)
+{
+	struct xusb_device *xusb_device = data;
+	xusb_destroy(xusb_device);
+}
+
+static const struct test_struct {
+	struct xusb_spec	spec;
+	int			interface_num;
+} known_devices[] = {
+	{ SPEC_HEAD(0xe4e4, 0x1162, "astribank2-FPGA"), 0 },
+	{{}, 0 },
+};
+
+int proto_ack_cb(
+	const struct xtalk_base *xtalk_base,
+	const struct xtalk_command_desc *cmd_desc,
+	struct xtalk_command *cmd)
+{
+	const char *name = (cmd_desc->name) ? cmd_desc->name : "RAW";
+
+	printf("%s: op=0x%X (%s): len=%d\n", __func__,
+		cmd_desc->op, name, cmd->header.len);
+	return 0;
+}
+
+/*
+ * Not const, because we override proto_version for testing
+ */
+static struct xtalk_protocol   xtalk_raw_test_base = {
+	.name   = "XTALK_TEST",
+	.proto_version = 0,	/* Modified in test_device() */
+	.commands = {
+	},
+	.ack_statuses = {
+	}
+};
+
+static int test_device(struct xusb_iface *xusb_iface, int timeout)
+{
+	struct xtalk_base *xtalk_base = NULL;
+	struct xtalk_raw *xtalk_raw = NULL;
+	struct xtalk_command *reply;
+	uint16_t tx_seq;
+	int ret;
+
+	xtalk_base = xtalk_base_new_on_xusb(xusb_iface);
+	if (!xtalk_base) {
+		ERR("Failed creating the xtalk device abstraction\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	xtalk_raw = xtalk_raw_new(xtalk_base);
+	if (!xtalk_raw) {
+		ERR("Failed creating the xtalk sync device abstraction\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	ret = xtalk_set_timeout(xtalk_base, timeout);
+	INFO("Original timeout=%d, now set to %d\n", ret, timeout);
+	/* override constness for testing */
+	ret = xtalk_raw_set_protocol(xtalk_raw, &xtalk_raw_test_base);
+	if (ret < 0) {
+		ERR("%s Protocol registration failed: %d\n",
+			xtalk_raw_test_base.name, ret);
+		ret = -EPROTO;
+		goto err;
+	}
+	ret = xtalk_cmd_callback(xtalk_base, XTALK_OP(XTALK, ACK), proto_ack_cb, NULL);
+	if (ret < 0) {
+		ERR("%s Callback registration failed: %d\n",
+			xtalk_raw_test_base.name, ret);
+		ret = -EPROTO;
+		goto err;
+	}
+	INFO("Device and Protocol are ready\n");
+	ret = xtalk_raw_cmd_send(xtalk_raw, "abcdef", 6, &tx_seq);
+	if (ret < 0) {
+		ERR("Failed sending raw command: %d\n", ret);
+		ret = -EPROTO;
+		goto err;
+	}
+	do {
+		ret = xtalk_raw_cmd_recv(xtalk_raw, &reply);
+		if (ret < 0) {
+			if (ret == -ETIMEDOUT) {
+				printf("timeout\n");
+				continue;
+			}
+			ERR("Read error (ret=%d)\n", ret);
+			goto err;
+		}
+		assert(reply);
+		printf("Got %d (len=%d)\n", reply->header.op, reply->header.len);
+	} while (1);
+err:
+	if (xtalk_raw)
+		xtalk_raw_delete(xtalk_raw);
+	if (xtalk_base)
+		xtalk_base_delete(xtalk_base);
+	return ret;
+}
+
+static int run_spec(int i, xusb_filter_t filter, char *devpath, int timeout)
+{
+	const struct xusb_spec	*s = &known_devices[i].spec;
+	int			interface_num = known_devices[i].interface_num;
+	struct xlist_node	*xlist;
+	struct xlist_node	*curr;
+	struct xusb_device	*xusb_device;
+	int			success = 1;
+
+	if (!s->name)
+		return 0;
+	xlist = xusb_find_byproduct(s, 1, filter, devpath);
+	if (!xlist_length(xlist))
+		return 1;
+	INFO("total %zd devices of type %s\n", xlist_length(xlist), s->name);
+	for (curr = xlist_shift(xlist); curr; curr = xlist_shift(xlist)) {
+		struct xusb_iface *xusb_iface;
+		int ret;
+
+		xusb_device = curr->data;
+		xusb_showinfo(xusb_device);
+		INFO("Testing interface %d\n", interface_num);
+		ret = xusb_claim(xusb_device, interface_num, &xusb_iface);
+		if (ret == 0) {
+			ret = test_device(xusb_iface, timeout);
+			if (ret < 0)
+				success = 0;
+		}
+		xusb_destroy(xusb_device);
+	}
+	xlist_destroy(xlist, xusb_destructor);
+	return success;
+}
+
+int main(int argc, char *argv[])
+{
+	char			*devpath = NULL;
+	const char		options[] = "vd:D:EFpt:";
+	xusb_filter_t		filter = NULL;
+	int			timeout = 500;	/* millies */
+	int			i;
+
+	progname = argv[0];
+	while (1) {
+		int	c;
+
+		c = getopt(argc, argv, options);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'D':
+			devpath = optarg;
+			filter = xusb_filter_bypath;
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case 't':
+			timeout = strtoul(optarg, NULL, 0);
+			break;
+		case 'd':
+			debug_mask = strtoul(optarg, NULL, 0);
+			break;
+		case 'h':
+		default:
+			ERR("Unknown option '%c'\n", c);
+			usage();
+		}
+	}
+	i = 0;
+	while (run_spec(i, filter, devpath, timeout))
+		i++;
+	return 0;
+}
diff --git a/xpp/xtalk/xtalk_send.8 b/xpp/xtalk/xtalk_send.8
new file mode 100644
index 0000000..bef62e4
--- /dev/null
+++ b/xpp/xtalk/xtalk_send.8
@@ -0,0 +1,49 @@
+.\"                                      Hey, EMACS: -*- nroff -*-
+.\" (C) Copyright 2013 Oron Peled <oron at actcom.co.il>,
+.\"
+.TH XTALK_SEND 8 "March 14, 2013"
+.\"
+.\" Some roff macros, for reference:
+.\" .nh        disable hyphenation
+.\" .hy        enable hyphenation
+.\" .ad l      left justify
+.\" .ad b      justify to both left and right margins
+.\" .nf        disable filling
+.\" .fi        enable filling
+.\" .br        insert line break
+.\" .sp <n>    insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+xtalk_send \- send arbitrary packets to XTALK devices
+.SH SYNOPSIS
+.B xtalk_send
+.RI [ options ] " hexnum" ...
+.br
+.SH DESCRIPTION
+This manual page documents briefly the \fBxtalk_send\fP command.
+.PP
+\fBxtalk_send\fP is a program that send arbitrary packets to Xorcom devices
+that use the XTALK protocol.
+.SH OPTIONS
+A summary of options is included below:
+.TP
+.B \-I <iface_num>
+Specify USB interface number (default 1).
+.TP
+.B \-t <timeout>
+Timeout from send until an answer is received (default 500).
+.TP
+.B \-Q
+Query protocol version. This is only valid for synchronous XTALK protocols.
+Usually, these protocols are bound to USB interface 1.
+.TP
+.B \-h
+Show summary of options.
+.TP
+.B \-v
+Increase output verbosity.
+.TP
+.B \-d <mask>
+Debug mask. Use 0xFF for everything.
+.SH AUTHOR
+Oron Peled <oron at actcom.co.il>
diff --git a/xpp/xtalk/xtalk_send.c b/xpp/xtalk/xtalk_send.c
new file mode 100644
index 0000000..8f3424b
--- /dev/null
+++ b/xpp/xtalk/xtalk_send.c
@@ -0,0 +1,220 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008-2011, 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 <getopt.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <arpa/inet.h>
+#include <xtalk/debug.h>
+#include <xtalk/xusb.h>
+#include <xtalk/proto_sync.h>
+#include <autoconfig.h>
+
+#define	DBG_MASK	0x80
+
+static char	*progname;
+static int	timeout		= 500;	/* msec */
+static int	iface_num	= 1;
+
+static void usage()
+{
+	fprintf(stderr, "Usage: %s [options...] -D <busnum>/<devnum> [hexnum ....]\n",
+		progname);
+	fprintf(stderr, "\tOptions:\n");
+	fprintf(stderr,
+		"\t\t[-I<iface_num>]    # Interface number (default %d)\n",
+		iface_num);
+	fprintf(stderr,
+		"\t\t[-t<timeout>]      # Timeout (default %d)\n",
+		timeout);
+	fprintf(stderr, "\t\t[-Q]               # Query protocol version\n");
+	fprintf(stderr, "\t\t[-v]               # Increase verbosity\n");
+	fprintf(stderr,
+		"\t\t[-d mask]          # Debug mask (0xFF for everything)\n");
+	fprintf(stderr, "\t\t[-h]               # This help\n");
+	exit(1);
+}
+
+/***** XTALK Interface *****************************************************/
+static const struct xtalk_protocol   xtalk_protocol = {
+	.name   = "XTALK-DERIVED",
+	.proto_version = 0,
+	.commands = {
+	},
+	.ack_statuses = {
+	}
+};
+
+
+/***** XUSB Interface ******************************************************/
+
+static int sendto_device(struct xusb_iface *iface, int nargs, char *args[])
+{
+	char *reply = NULL;
+	char *buf = NULL;
+	int ret = 0;
+	int i;
+
+	assert(nargs >= 0);
+	if (!nargs)
+		goto out;
+	buf = malloc(nargs);
+	if (!buf) {
+		ERR("Out of memory for %d command bytes\n", nargs);
+		ret = -ENOMEM;
+		goto out;
+	}
+	for (i = 0; i < nargs; i++) {
+		int	val = strtoul(args[i], NULL, 16);
+		printf("%d> 0x%02X\n", i, val);
+		buf[i] = val;
+	}
+	ret = xusb_send(iface, buf, nargs, timeout);
+	if (ret < 0) {
+		ERR("xusb_send failed ret=%d\n", ret);
+		goto out;
+	}
+	reply = malloc(PACKET_SIZE);
+	if (!reply) {
+		ERR("Out of memory\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	ret = xusb_recv(iface, reply, PACKET_SIZE, timeout);
+	if (ret < 0) {
+		ERR("Receive from usb failed.\n");
+		goto out;
+	}
+	dump_packet(LOG_INFO, 0, "REPLY", reply, ret);
+	ret = 0;
+out:
+	if (reply)
+		free(reply);
+	if (buf)
+		free(buf);
+	return ret;
+}
+
+static int show_protocol(struct xtalk_sync *xtalk_sync, struct xusb_iface *iface)
+{
+	int	ret;
+
+	ret = xtalk_sync_set_protocol(xtalk_sync, &xtalk_protocol);
+	if (ret < 0) {
+		ERR("%s Protocol registration failed: %s\n",
+			xtalk_protocol.name, strerror(-ret));
+		return ret;
+	}
+	ret = xtalk_proto_query(xtalk_sync);
+	if (ret < 0) {
+		ERR("Protocol query error: %s\n", strerror(-ret));
+		return ret;
+	}
+	INFO("usb:%s: Protocol version 0x%X\n", xusb_devpath(xusb_deviceof(iface)), ret);
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	char			*devpath = NULL;
+	struct xusb_device	*xusb_device;
+	struct xtalk_base	*xtalk_base;
+	struct xtalk_sync	*xtalk_sync;
+	struct xusb_iface	*iface;
+	const char		options[] = "vd:D:t:I:i:o:Q";
+	int			query = 0;
+	int			ret;
+
+	progname = argv[0];
+	while (1) {
+		int	c;
+
+		c = getopt(argc, argv, options);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'D':
+			devpath = optarg;
+			break;
+		case 'I':
+			iface_num = strtoul(optarg, NULL, 0);
+			break;
+		case 't':
+			timeout = strtoul(optarg, NULL, 0);
+			break;
+		case 'Q':
+			query++;
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case 'd':
+			debug_mask = strtoul(optarg, NULL, 0);
+			break;
+		case 'h':
+		default:
+			ERR("Unknown option '%c'\n", c);
+			usage();
+		}
+	}
+	if (!devpath) {
+		ERR("Missing device path\n");
+		usage();
+	}
+	xusb_device = xusb_find_bypath(devpath);
+	if (!xusb_device) {
+		ERR("No XUSB device found\n");
+		return 1;
+	}
+	ret = xusb_claim(xusb_device, iface_num, &iface);
+	if (ret < 0) {
+		ERR("Claiming interface #%d failed (ret = %d)\n", iface_num, ret);
+		return 1;
+	}
+	xusb_showinfo(xusb_deviceof(iface));
+	xtalk_base = xtalk_base_new_on_xusb(iface);
+	if (!xtalk_base) {
+		ERR("Failed creating the xtalk device abstraction\n");
+		return 1;
+	}
+	xtalk_sync = xtalk_sync_new(xtalk_base);
+	if (!xtalk_sync) {
+		ERR("Failed creating the xtalk device abstraction\n");
+		return 1;
+	}
+	if (query) {
+		ret = show_protocol(xtalk_sync, iface);
+		if (ret < 0)
+			return 1;
+	}
+	ret = sendto_device(iface, argc - optind, argv + optind);
+	if (ret < 0)
+		ERR("Command failed: %d\n", ret);
+	xtalk_sync_delete(xtalk_sync);
+	xtalk_base_delete(xtalk_base);
+	xusb_destroy(xusb_deviceof(iface));
+	return 0;
+}
diff --git a/xpp/xtalk/xtalk_sync.c b/xpp/xtalk/xtalk_sync.c
new file mode 100644
index 0000000..c0be8fd
--- /dev/null
+++ b/xpp/xtalk/xtalk_sync.c
@@ -0,0 +1,290 @@
+/*
+ * 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/debug.h>
+#include <xtalk/proto_sync.h>
+#include <autoconfig.h>
+#include "xtalk_base.h"
+
+#define	DBG_MASK	0x02
+
+/*
+ * Base XTALK device. A pointer to this struct
+ * should be included in the struct representing
+ * the dialect.
+ */
+struct xtalk_sync {
+	struct xtalk_base	*xtalk_base;
+};
+
+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;
+
+const struct xtalk_protocol	xtalk_sync_proto = {
+	.name	= "XTALK-SYNC",
+	.proto_version = 0,
+	.commands = {
+		CMD_RECV(XTALK, ACK),
+		CMD_SEND(XTALK, PROTO_GET),
+		CMD_RECV(XTALK, PROTO_GET_REPLY),
+	},
+	.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"),
+	}
+};
+
+struct xtalk_sync *xtalk_sync_new(struct xtalk_base *xtalk_base)
+{
+	struct xtalk_sync *xtalk_sync;
+	int ret;
+
+	assert(xtalk_base);
+	xtalk_sync = calloc(1, sizeof(*xtalk_sync));
+	if (!xtalk_sync) {
+		ERR("Allocating XTALK device memory failed\n");
+		return NULL;
+	}
+	xtalk_sync->xtalk_base = xtalk_base;
+	ret = xtalk_set_protocol(xtalk_sync->xtalk_base, &xtalk_sync_proto, NULL);
+	if (ret < 0) {
+		ERR("GLOBAL Protocol registration failed: %d\n", ret);
+		goto err;
+	}
+        DBG("%s: xtalk_sync=%p\n", __func__, xtalk_sync);
+	return xtalk_sync;
+err:
+	xtalk_sync_delete(xtalk_sync);
+	return NULL;
+}
+
+void xtalk_sync_delete(struct xtalk_sync *xtalk_sync)
+{
+	if (xtalk_sync) {
+		memset(xtalk_sync, 0, sizeof(*xtalk_sync));
+		free(xtalk_sync);
+	}
+}
+
+int xtalk_sync_set_protocol(struct xtalk_sync *xtalk_sync,
+		const struct xtalk_protocol *xproto)
+{
+	return xtalk_set_protocol(xtalk_sync->xtalk_base, &xtalk_sync_proto, xproto);
+}
+
+__attribute__((warn_unused_result))
+int process_command(
+	struct xtalk_sync *xtalk_sync,
+	struct xtalk_command *cmd,
+	struct xtalk_command **reply_ref,
+	uint16_t *tx_seq)
+{
+	struct xtalk_base *xtalk_base;
+	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;
+	xtalk_cmd_callback_t		callback;
+
+	xtalk_base = xtalk_sync->xtalk_base;
+	xproto = &xtalk_base->xproto;
+	protoname = (xproto) ? xproto->name : "GLOBAL";
+	/* So the caller knows if a reply was received */
+	if (reply_ref)
+		*reply_ref = NULL;
+	reply_op = cmd->header.op | XTALK_REPLY_MASK;
+	cmd_desc = get_command_desc(xproto, cmd->header.op);
+	expected = get_command_desc(xproto, reply_op);
+	ret = send_command(xtalk_base, cmd, tx_seq);
+	if (ret < 0) {
+		ERR("send_command failed: %d\n", ret);
+		goto out;
+	}
+	if (!reply_ref) {
+		DBG("No reply requested\n");
+		goto out;
+	}
+	ret = recv_command(xtalk_base, &reply);
+	if (ret <= 0) {
+		DBG("recv_command failed (ret = %d)\n", ret);
+		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;
+	}
+	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);
+		dump_packet(LOG_ERR, 0, __func__, (const char *)reply, ret);
+		ret = -EPROTO;
+		goto out;
+	}
+	DBG("REPLY OP: 0x%X [%s]\n", reply->header.op, 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));
+			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;
+	}
+	/* Find if there is associated callback */
+	ret = xtalk_cmd_callback(xtalk_base, reply->header.op, NULL, &callback);
+	if (ret < 0) {
+		ERR("Failed getting callback for op=0x%X\n", reply->header.op);
+		goto out;
+	}
+	ret = reply->header.len;	/* All good, return the length */
+	DBG("got reply op 0x%X (%d bytes)\n", reply->header.op, ret);
+	if (callback) {
+		/* Override return value with callback return value */
+		ret = callback(xtalk_base, reply_desc, reply);
+		DBG("%s: callback for 0x%X returned %d\n", __func__,
+			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_sync *xtalk_sync)
+{
+	struct xtalk_base *xtalk_base;
+	struct xtalk_command		*cmd;
+	struct xtalk_command		*reply;
+	uint8_t				proto_version;
+	int				ret;
+	uint16_t			tx_seq;
+
+	DBG("\n");
+	assert(xtalk_sync != NULL);
+	xtalk_base = xtalk_sync->xtalk_base;
+	proto_version = xtalk_base->xproto.proto_version;
+	cmd = new_command(xtalk_base, XTALK_OP(XTALK, PROTO_GET), 0);
+	if (!cmd) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	/* Protocol Version */
+	CMD_FIELD(cmd, XTALK, PROTO_GET, proto_version) = proto_version;
+	CMD_FIELD(cmd, XTALK, PROTO_GET, reserved) = 0;	/* RESERVED */
+	ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
+	if (ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		goto out;
+	}
+	xtalk_base->xtalk_proto_version =
+		CMD_FIELD(reply, XTALK, PROTO_GET_REPLY, proto_version);
+	if (xtalk_base->xtalk_proto_version != proto_version) {
+		DBG("Got %s protocol version: 0x%02x (expected 0x%02x)\n",
+			xtalk_base->xproto.name,
+			xtalk_base->xtalk_proto_version,
+			proto_version);
+		ret = xtalk_base->xtalk_proto_version;
+		goto out;
+	}
+	DBG("Protocol version: %02x (tx_seq = %d)\n",
+		xtalk_base->xtalk_proto_version, tx_seq);
+	ret = xtalk_base->xtalk_proto_version;
+out:
+	free_command(reply);
+	return ret;
+}
diff --git a/xpp/xtalk/xtalk_test.c b/xpp/xtalk/xtalk_test.c
new file mode 100644
index 0000000..a77e061
--- /dev/null
+++ b/xpp/xtalk/xtalk_test.c
@@ -0,0 +1,199 @@
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <xtalk/debug.h>
+#include <xtalk/xusb.h>
+#include <xtalk/proto_sync.h>
+#include <autoconfig.h>
+
+static char	*progname;
+
+#define	DBG_MASK	0x10
+
+static void usage()
+{
+	fprintf(stderr, "Usage: %s [options...] -D <device> [hexnum ....]\n",
+		progname);
+	fprintf(stderr, "\tOptions:\n");
+	fprintf(stderr, "\t\t[-v]               # Increase verbosity\n");
+	fprintf(stderr,
+		"\t\t[-d mask]          # Debug mask (0xFF for everything)\n");
+	fprintf(stderr, "\tDevice:\n");
+	fprintf(stderr, "\t\t/proc/bus/usb/<bus>/<dev>\n");
+	fprintf(stderr, "\t\t/dev/bus/usb/<bus>/<dev>\n");
+	exit(1);
+}
+
+static void xusb_destructor(void *data)
+{
+	struct xusb_device	*xusb_device = data;
+	xusb_destroy(xusb_device);
+}
+
+#define	KNOWN_DEV(p, i, v, d) \
+		{ SPEC_HEAD(0xe4e4, (p), (d)), (i), (v) }
+
+static const struct test_struct {
+	struct xusb_spec	spec;
+	int			interface_num;
+	uint8_t			proto_version;
+} known_devices[] = {
+	/*        PROD    I  V     NAME */
+	KNOWN_DEV(0x1161, 1, 0x14, "astribank2-USB"),
+	KNOWN_DEV(0x1162, 1, 0x14, "astribank2-FPGA"),
+	KNOWN_DEV(0x1191, 1, 0x10, "xpanel"),
+	KNOWN_DEV(0x1183, 1, 0x11, "multi-ps"),
+	KNOWN_DEV(0x11a3, 0, 0x01, "auth-dongle"),
+	KNOWN_DEV(0xbb01, 1, 0x10, "iwc"),
+	KNOWN_DEV(0,      0, 0,    NULL),
+};
+
+int proto_get_reply_cb(
+	const struct xtalk_base *xtalk_base,
+	const struct xtalk_command_desc *cmd_desc,
+	struct xtalk_command *cmd)
+{
+	INFO("CALLBACK: op=0x%X (%s): len=%d\n",
+		cmd_desc->op, cmd_desc->name, cmd->header.len);
+	return 0;
+}
+
+/*
+ * Not const, because we override proto_version for testing
+ */
+static struct xtalk_protocol   xtalk_test_base = {
+	.name   = "XTALK_TEST",
+	.proto_version = 0,	/* Modified in test_device() */
+	.commands = {
+	},
+	.ack_statuses = {
+	}
+};
+
+static int test_device(struct xusb_iface *xusb_iface, uint8_t wanted_version, int timeout)
+{
+	struct xtalk_base *xtalk_base;
+	struct xtalk_sync *xtalk_sync;
+	int proto_version;
+	int ret;
+
+	xtalk_base = xtalk_base_new_on_xusb(xusb_iface);
+	if (!xtalk_base) {
+		ERR("Failed creating the xtalk device abstraction\n");
+		return -ENOMEM;
+	}
+	xtalk_sync = xtalk_sync_new(xtalk_base);
+	if (!xtalk_sync) {
+		ERR("Failed creating the xtalk sync device abstraction\n");
+		return -ENOMEM;
+	}
+	ret = xtalk_set_timeout(xtalk_base, timeout);
+	INFO("Original timeout=%d, now set to %d\n", ret, timeout);
+	/* override constness for testing */
+	xtalk_test_base.proto_version = wanted_version;
+	ret = xtalk_sync_set_protocol(xtalk_sync, &xtalk_test_base);
+	if (ret < 0) {
+		ERR("%s Protocol registration failed: %d\n",
+			xtalk_test_base.name, ret);
+		return -EPROTO;
+	}
+	ret = xtalk_cmd_callback(xtalk_base, XTALK_OP(XTALK, PROTO_GET_REPLY), proto_get_reply_cb, NULL);
+	if (ret < 0) {
+		ERR("%s Callback registration failed: %d\n",
+			xtalk_test_base.name, ret);
+		return -EPROTO;
+	}
+	proto_version = xtalk_proto_query(xtalk_sync);
+	if (proto_version < 0) {
+		ERR("Protocol query error: %s\n", strerror(-proto_version));
+		return proto_version;
+	}
+	if (proto_version != xtalk_test_base.proto_version) {
+		ERR("Bad protocol version: 0x%02x\n", proto_version);
+		return -EPROTO;
+	}
+	INFO("Device and Protocol are ready (proto_version=0x%X)\n",
+		proto_version);
+	xtalk_sync_delete(xtalk_sync);
+	xtalk_base_delete(xtalk_base);
+	return 0;
+}
+
+static int run_spec(int i, xusb_filter_t filter, char *devpath, int timeout)
+{
+	const struct xusb_spec	*s = &known_devices[i].spec;
+	int			interface_num = known_devices[i].interface_num;
+	uint8_t			proto_version = known_devices[i].proto_version;
+	struct xlist_node	*xlist;
+	struct xlist_node	*curr;
+	struct xusb_device	*xusb_device;
+	int			success = 1;
+
+	if (!s->name)
+		return 0;
+	xlist = xusb_find_byproduct(s, 1, filter, devpath);
+	if (!xlist_length(xlist))
+		return 1;
+	INFO("total %zd devices of type %s\n", xlist_length(xlist), s->name);
+	for (curr = xlist_shift(xlist); curr; curr = xlist_shift(xlist)) {
+		struct xusb_iface *xusb_iface;
+		int ret;
+
+		xusb_device = curr->data;
+		xusb_showinfo(xusb_device);
+		INFO("Testing interface %d\n", interface_num);
+		ret = xusb_claim(xusb_device, interface_num, &xusb_iface);
+		if (ret == 0) {
+			ret = test_device(xusb_iface, proto_version, timeout);
+			if (ret < 0)
+				success = 0;
+		}
+		xusb_destroy(xusb_device);
+	}
+	xlist_destroy(xlist, xusb_destructor);
+	return success;
+}
+
+int main(int argc, char *argv[])
+{
+	char			*devpath = NULL;
+	const char		options[] = "vd:D:EFpt:";
+	xusb_filter_t		filter = NULL;
+	int			timeout = 500;	/* millies */
+	int			i;
+
+	progname = argv[0];
+	while (1) {
+		int	c;
+
+		c = getopt(argc, argv, options);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'D':
+			devpath = optarg;
+			filter = xusb_filter_bypath;
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case 't':
+			timeout = strtoul(optarg, NULL, 0);
+			break;
+		case 'd':
+			debug_mask = strtoul(optarg, NULL, 0);
+			break;
+		case 'h':
+		default:
+			ERR("Unknown option '%c'\n", c);
+			usage();
+		}
+	}
+	i = 0;
+	while (run_spec(i, filter, devpath, timeout))
+		i++;
+	return 0;
+}
diff --git a/xpp/xtalk/xusb_common.c b/xpp/xtalk/xusb_common.c
new file mode 100644
index 0000000..bccfd39
--- /dev/null
+++ b/xpp/xtalk/xusb_common.c
@@ -0,0 +1,381 @@
+#define	_GNU_SOURCE	/* for memrchr() */
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <xtalk/debug.h>
+#include <autoconfig.h>
+#include "xusb_common.h"
+
+#define	DBG_MASK	0x01
+
+const char *xusb_tt_name(enum xusb_transfer_type tt)
+{
+	switch (tt) {
+	case XUSB_TT_BULK: return "BULK";
+	case XUSB_TT_INTERRUPT: return "INTERRUPT";
+	case XUSB_TT_ILLEGAL:
+		break;
+	}
+	return "ILLEGAL";
+}
+
+/* GCC versions before 4.6 did not support neither push and pop on
+ * the diagnostic pragma nor applying it inside a function.
+ */
+#ifndef HAVE_GCC_PRAGMA_DIAG_STACK
+#pragma GCC diagnostic ignored "-Wformat-security"
+#endif
+int xusb_printf(const struct xusb_iface *iface, int level, int debug_mask,
+	const char *prefix, const char *fmt, ...)
+{
+	int n;
+	va_list ap;
+	char fmtbuf[BUFSIZ];
+	char tmpbuf[BUFSIZ];
+
+	snprintf(fmtbuf, sizeof(fmtbuf), "%s%03d/%03d[%d] %s",
+		prefix,
+		xusb_bus_num(iface->xusb_device),
+		xusb_device_num(iface->xusb_device),
+		xusb_interface_num(iface),
+		fmt);
+	va_start(ap, fmt);
+	n = vsnprintf(tmpbuf, sizeof(tmpbuf), fmtbuf, ap);
+	va_end(ap);
+#ifdef HAVE_GCC_PRAGMA_DIAG_STACK
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-security"
+#endif
+	log_function(level, debug_mask, tmpbuf);
+#ifdef HAVE_GCC_PRAGMA_DIAG_STACK
+#pragma GCC diagnostic pop
+#endif
+	return n;
+}
+#ifndef HAVE_GCC_PRAGMA_DIAG_STACK
+#pragma GCC diagnostic error "-Wformat-security"
+#endif
+
+int xusb_printf_details(const struct xusb_iface *iface, int level, int debug_mask,
+	const char *file, int line, const char *severity, const char *func,
+	const char *fmt, ...)
+{
+	int n;
+	va_list ap;
+	char prefix[BUFSIZ];
+	char tmpbuf[BUFSIZ];
+
+	va_start(ap, fmt);
+	vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap);
+	va_end(ap);
+	snprintf(prefix, sizeof(prefix), "%s:%d: %s(%s): ",
+		file, line, severity, func);
+	va_start(ap, fmt);
+	n = xusb_printf(iface, level, DBG_MASK, prefix, tmpbuf);
+	va_end(ap);
+	return n;
+}
+
+void xusb_init_spec(struct xusb_spec *spec, char *name,
+	uint16_t vendor_id, uint16_t product_id)
+{
+	DBG("Initialize [%02X:%02X] - %s\n", vendor_id, product_id, name);
+	memset(spec, 0, sizeof(*spec));
+	spec->name = name;
+	spec->vendor_id = vendor_id;
+	spec->product_id = product_id;
+}
+
+const struct xusb_spec *xusb_device_spec(const struct xusb_device *xusb_device)
+{
+	return xusb_device->spec;
+}
+
+/*
+ * Match the string "tail" as the tail of string "path"
+ * Returns 1 in case they match, 0 otherwise
+ */
+int match_devpath(const char *path, const char *tail)
+{
+	int len_path = strlen(path);
+	int len_tail = strlen(tail);
+	int path_offset = len_path - len_tail;
+
+	if (path_offset < 0)
+		return 0;
+	return strstr(path + path_offset, tail) != NULL;
+}
+
+int match_device(const struct xusb_device *xusb_device,
+		const struct xusb_spec *spec)
+{
+	assert(xusb_device);
+	DBG("Checking: %04X:%04X: "
+			"\"%s\"\n",
+			spec->vendor_id,
+			spec->product_id,
+			spec->name);
+	if (xusb_device->idVendor != spec->vendor_id) {
+		DBG("Wrong vendor id 0x%X\n", xusb_device->idVendor);
+		return 0;
+	}
+	if (xusb_device->idProduct != spec->product_id) {
+		DBG("Wrong product id 0x%X\n", xusb_device->idProduct);
+		return 0;
+	}
+	return	1;
+}
+
+struct xusb_device *xusb_deviceof(struct xusb_iface *iface)
+{
+	return iface->xusb_device;
+}
+
+int xusb_is_claimed(struct xusb_iface *iface)
+{
+	return iface->is_claimed != 0;
+}
+
+struct xusb_iface *xusb_interface_of(const struct xusb_device *dev, int num)
+{
+	return dev->interfaces[num];
+}
+
+#define	XUSB_IFACE_DUMP(prefix, level, iface) \
+	XUSB_PRINT((iface), level, "%s%d\tep_out=0x%2X ep_in=0x%02X [%s]\n", \
+			(prefix), \
+			(iface)->interface_num, \
+			(iface)->ep_out, \
+			(iface)->ep_in, \
+			(iface)->iInterface)
+
+void xusb_list_dump(struct xlist_node *xusb_list)
+{
+	struct xlist_node	*curr;
+	struct xusb_device	*xusb_device;
+
+	for (curr = xusb_list->next; curr != xusb_list; curr = curr->next) {
+		struct xusb_iface **piface;
+
+		xusb_device = curr->data;
+		assert(xusb_device);
+		DBG("%s: usb:ID=%04X:%04X [%s / %s / %s]\n",
+			xusb_device->devpath_tail,
+			xusb_device->idVendor,
+			xusb_device->idProduct,
+			xusb_device->iManufacturer,
+			xusb_device->iProduct,
+			xusb_device->iSerialNumber
+			);
+		for (piface = xusb_device->interfaces; *piface; piface++)
+			XUSB_IFACE_DUMP("\t", DEBUG, *piface);
+	}
+}
+
+void xusb_destroy_interface(struct xusb_iface *iface)
+{
+	if (iface) {
+		xusb_release(iface);
+		XUSB_DBG(iface, "MEM: FREE interface\n");
+		memset(iface, 0, sizeof(*iface));
+		free(iface);
+		iface = NULL;
+	}
+}
+
+static const char *path_tail(const char *path)
+{
+	const char	*p;
+
+	assert(path != NULL);
+	/* Find last '/' */
+	p = memrchr(path, '/', strlen(path));
+	if (!p) {
+		ERR("Missing a '/' in %s\n", path);
+		return NULL;
+	}
+	/* Search for a '/' before that */
+	p = memrchr(path, '/', p - path);
+	if (!p)
+		p = path;		/* No more '/' */
+	else
+		p++;			/* skip '/' */
+	return p;
+}
+
+int xusb_filter_bypath(const struct xusb_device *xusb_device, void *data)
+{
+	const char	*p;
+	const char	*path = data;
+
+	DBG("%s\n", path);
+	assert(path != NULL);
+	p = path_tail(path);
+	if (strcmp(xusb_device->devpath_tail, p) != 0) {
+		DBG("%s: device path missmatch (!= '%s')\n",
+			xusb_device->devpath_tail, p);
+		return 0;
+	}
+	return 1;
+}
+
+struct xusb_iface *xusb_open_one(const struct xusb_spec *specs, int numspecs,
+		int interface_num,
+		xusb_filter_t filterfunc, void *data)
+{
+	struct xlist_node	*xusb_list;
+	struct xlist_node	*curr;
+	int			num;
+	struct xusb_device	*xusb_device = NULL;
+	struct xusb_iface	*iface = NULL;
+	int ret;
+
+	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_device = curr->data;
+		xlist_destroy(curr, NULL);
+		xlist_destroy(xusb_list, NULL);
+		ret = xusb_claim(xusb_device, interface_num, &iface);
+		if (ret < 0) {
+			ERR("%s: Failed claiming interface %d (ret = %d)\n",
+				xusb_device->devpath_tail,
+				interface_num,
+				ret);
+			xusb_destroy(xusb_device);
+			return NULL;
+		}
+		break;
+	default:
+		ERR("Too many devices (%d). Aborting.\n", num);
+		break;
+	}
+	return iface;
+}
+
+int xusb_interface_num(const struct xusb_iface *iface)
+{
+	return iface->interface_num;
+}
+
+uint16_t xusb_vendor_id(const struct xusb_device *xusb_device)
+{
+	return xusb_device->idVendor;
+}
+
+uint16_t xusb_product_id(const struct xusb_device *xusb_device)
+{
+	return  xusb_device->idProduct;
+}
+
+size_t xusb_packet_size(const struct xusb_device *xusb_device)
+{
+	return xusb_device->packet_size;
+}
+
+const char *xusb_serial(const struct xusb_device *xusb_device)
+{
+	return xusb_device->iSerialNumber;
+}
+
+const char *xusb_devpath(const struct xusb_device *xusb_device)
+{
+	return xusb_device->devpath_tail;
+}
+
+uint16_t xusb_bus_num(const struct xusb_device *xusb_device)
+{
+	return xusb_device->bus_num;
+}
+
+uint16_t xusb_device_num(const struct xusb_device *xusb_device)
+{
+	return xusb_device->device_num;
+}
+
+const char *xusb_interface_name(const struct xusb_iface *iface)
+{
+	return iface->iInterface;
+}
+
+const char *xusb_manufacturer(const struct xusb_device *xusb_device)
+{
+	return xusb_device->iManufacturer;
+}
+
+const char *xusb_product(const struct xusb_device *xusb_device)
+{
+	return xusb_device->iProduct;
+}
+
+const struct xusb_spec *xusb_spec(const struct xusb_device *xusb_device)
+{
+	return xusb_device->spec;
+}
+
+int xusb_flushread(struct xusb_iface *iface)
+{
+	char tmpbuf[BUFSIZ];
+	int ret;
+
+	XUSB_DBG(iface, "starting...\n");
+	memset(tmpbuf, 0, BUFSIZ);
+	ret = xusb_recv(iface, tmpbuf, BUFSIZ, 1);
+	if (ret < 0 && ret != -ETIMEDOUT) {
+		XUSB_ERR(iface, "ret=%d\n", ret);
+		return ret;
+	} else if (ret > 0) {
+		XUSB_DBG(iface, "Got %d bytes:\n", ret);
+		dump_packet(LOG_DEBUG, DBG_MASK, __func__, tmpbuf, ret);
+	}
+	return 0;
+}
+
+static int use_clear_halt = 1;
+
+static int xtalk_one_option(const char *option_string)
+{
+	if (strcmp(option_string, "use-clear-halt") == 0) {
+		use_clear_halt = 1;
+		return 0;
+	}
+	if (strcmp(option_string, "no-use-clear-halt") == 0) {
+		use_clear_halt = 0;
+		return 0;
+	}
+	ERR("Unknown XTALK_OPTIONS content: '%s'\n", option_string);
+	return -EINVAL;
+}
+
+int xtalk_option_use_clear_halt(void)
+{
+	return use_clear_halt;
+}
+
+int xtalk_parse_options(void)
+{
+	char *xtalk_options;
+	char *saveptr;
+	char *token;
+	int ret;
+
+	xtalk_options = getenv("XTALK_OPTIONS");
+	if (!xtalk_options)
+		return 0;
+	token = strtok_r(xtalk_options, " \t", &saveptr);
+	while (token) {
+		ret = xtalk_one_option(token);
+		if (ret < 0)
+			return ret;
+		token = strtok_r(NULL, " \t", &saveptr);
+	}
+	return 0;
+}
diff --git a/xpp/xtalk/xusb_common.h b/xpp/xtalk/xusb_common.h
new file mode 100644
index 0000000..ed411ed
--- /dev/null
+++ b/xpp/xtalk/xusb_common.h
@@ -0,0 +1,104 @@
+#ifndef	XUSB_COMMON_H
+#define	XUSB_COMMON_H
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2012, 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 <limits.h>
+#include <xtalk/xusb.h>
+
+/*
+ * XTALK_OPTIONS:
+ *     - "use-clear-halt"
+ *     - "no-use-clear-halt"
+ */
+int xtalk_parse_options(void);
+int xtalk_option_use_clear_halt(void);
+
+enum xusb_transfer_type {
+	XUSB_TT_ILLEGAL = 0,
+	XUSB_TT_BULK,
+	XUSB_TT_INTERRUPT,
+};
+
+struct xusb_iface {
+	struct xusb_device	*xusb_device;
+	int		interface_num;
+	int		ep_out;
+	int		ep_in;
+	enum xusb_transfer_type transfer_type;
+	int		is_claimed;
+	char		iInterface[BUFSIZ];
+};
+struct libusb_implementation;
+
+#define	XUSB_MAX_INTERFACES	32
+
+struct xusb_device {
+	struct libusb_implementation *impl;
+	const struct xusb_spec	*spec;
+	int			idVendor;
+	int			idProduct;
+	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			is_usb2;
+	size_t			packet_size;
+	struct xusb_iface	*interfaces[XUSB_MAX_INTERFACES];
+};
+
+#define	EP_OUT(iface)	((iface)->ep_out)
+#define	EP_IN(iface)	((iface)->ep_in)
+
+int match_devpath(const char *path, const char *tail);
+int match_device(const struct xusb_device *xusb_device,
+		const struct xusb_spec *spec);
+void xusb_list_dump(struct xlist_node *xusb_list);
+void xusb_destroy_interface(struct xusb_iface *iface);
+int xusb_close(struct xusb_device *xusb_device);
+
+enum xusb_transfer_type xusb_transfer_type(const struct xusb_iface *iface);
+const char *xusb_tt_name(enum xusb_transfer_type tt);
+
+
+int xusb_printf(const struct xusb_iface *iface, int level, int debug_mask,
+	const char *prefix, const char *fmt, ...);
+
+int xusb_printf_details(const struct xusb_iface *iface, int level, int debug_mask,
+	const char *file, int line, const char *severity, const char *func,
+	const char *fmt, ...);
+
+#define XUSB_PRINT(iface, level, fmt, arg...) \
+		xusb_printf(iface, LOG_ ## level, 0, #level ": ", fmt, ## arg)
+
+#define XUSB_PRINT_DETAILS(iface, level, debug_mask, fmt, arg...) \
+		xusb_printf_details(iface, LOG_ ## level, debug_mask, \
+			__FILE__, __LINE__, #level, __func__, fmt, ## arg)
+
+#define XUSB_INFO(iface, fmt, arg...) XUSB_PRINT(iface, INFO, fmt, ## arg)
+#define XUSB_ERR(iface, fmt, arg...) XUSB_PRINT_DETAILS(iface, ERR, 0, fmt, ## arg)
+#define XUSB_DBG(iface, fmt, arg...) XUSB_PRINT_DETAILS(iface, DEBUG, DBG_MASK, fmt, ## arg)
+
+#endif	/* XUSB_COMMON_H */
diff --git a/xpp/xtalk/xusb_libusb.c b/xpp/xtalk/xusb_libusb.c
new file mode 100644
index 0000000..0edbb98
--- /dev/null
+++ b/xpp/xtalk/xusb_libusb.c
@@ -0,0 +1,843 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <usb.h>
+#include <xtalk/debug.h>
+#include <xtalk/xusb.h>
+#include <autoconfig.h>
+#include "xusb_common.h"
+
+#define	DBG_MASK	0x01
+#define	TIMEOUT	500
+#define	MAX_RETRIES	10
+
+#define	EP_IS_IN(ep)	(((ep) & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN)
+#define	EP_IS_OUT(ep)	(((ep) & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT)
+
+struct libusb_implementation {
+	struct usb_device	*dev;
+	usb_dev_handle		*handle;
+	struct usb_config_descriptor	*config_desc;
+};
+
+static void xusb_init();
+
+/*
+ * USB handling
+ */
+
+static int get_usb_string(struct xusb_device *xusb_device, uint8_t item, char *buf)
+{
+	char	tmp[BUFSIZ];
+	int	ret;
+
+	if (!xusb_device->impl->handle) {
+		ERR("%s: device closed\n", xusb_device->devpath_tail);
+		return -ENXIO;
+	}
+	if (!item)
+		return 0;
+	ret = usb_get_string_simple(xusb_device->impl->handle, item, tmp, BUFSIZ);
+	if (ret <= 0)
+		return ret;
+	return snprintf(buf, BUFSIZ, "%s", tmp);
+}
+
+static const struct usb_interface_descriptor *get_iface_descriptor(
+	const struct xusb_device *xusb_device, int i)
+{
+	const struct usb_config_descriptor	*config_desc;
+	const struct usb_interface		*interface;
+	const struct usb_interface_descriptor	*iface_desc;
+	int					num_altsetting;
+
+	assert(xusb_device);
+	assert(xusb_device->impl);
+	config_desc = xusb_device->impl->config_desc;
+	assert(config_desc);
+	assert(config_desc->bNumInterfaces < XUSB_MAX_INTERFACES);
+	if (i >= XUSB_MAX_INTERFACES)
+		return NULL;
+	interface = &config_desc->interface[i];
+	assert(interface != NULL);
+	iface_desc = interface->altsetting;
+	num_altsetting = interface->num_altsetting;
+	assert(num_altsetting != 0);
+	assert(iface_desc != NULL);
+	return iface_desc;
+}
+
+#define	GET_USB_STRING(xusb_device, from, item) \
+		get_usb_string((xusb_device), (from)->item, (xusb_device)->item)
+
+static int xusb_fill_strings(struct xusb_device *xusb_device, int interface_num)
+{
+	const struct usb_device_descriptor *dev_desc;
+	const struct usb_interface_descriptor *iface_desc;
+	struct xusb_iface *iface = xusb_device->interfaces[interface_num];
+	int ret;
+
+	dev_desc = &xusb_device->impl->dev->descriptor;
+	assert(dev_desc);
+	ret = GET_USB_STRING(xusb_device, dev_desc, iManufacturer);
+	if (ret < 0) {
+		XUSB_ERR(iface, "Failed reading iManufacturer string: %s\n",
+			usb_strerror());
+		return 0;
+	}
+	ret = GET_USB_STRING(xusb_device, dev_desc, iProduct);
+	if (ret < 0) {
+		XUSB_ERR(iface, "Failed reading iProduct string: %s\n",
+			usb_strerror());
+		return 0;
+	}
+	ret = GET_USB_STRING(xusb_device, dev_desc, iSerialNumber);
+	if (ret < 0) {
+		XUSB_ERR(iface, "Failed reading iSerialNumber string: %s\n",
+			usb_strerror());
+		return 0;
+	}
+	iface_desc = get_iface_descriptor(xusb_device, interface_num);
+	if (!iface_desc) {
+		XUSB_ERR(iface, "Could not get interface descriptor of device\n");
+		return 0;
+	}
+	ret = GET_USB_STRING(xusb_device, iface_desc, iInterface);
+	if (ret < 0) {
+		XUSB_ERR(iface, "Failed reading iInterface string: %s\n",
+			usb_strerror());
+		return 0;
+	}
+	return 1;
+}
+
+static int xusb_open(struct xusb_device *xusb_device)
+{
+	int ret = 0;
+
+	assert(xusb_device);
+	DBG("%s\n", xusb_device->devpath_tail);
+	if (xusb_device->impl->handle) {
+		ERR("%s: already open\n", xusb_device->devpath_tail);
+		ret = -EBUSY;
+		goto out;
+	}
+	xusb_device->impl->handle = usb_open(xusb_device->impl->dev);
+	if (!xusb_device->impl->handle) {
+		ERR("%s: Failed to open usb device: %s\n",
+			xusb_device->devpath_tail,
+			usb_strerror());
+		xusb_device->impl->handle = NULL;
+		goto out;
+	}
+	return 1;
+out:
+	return ret;
+}
+
+void xusb_release(struct xusb_iface *iface)
+{
+	if (iface && iface->is_claimed) {
+		usb_dev_handle *handle;
+		int ret;
+
+		assert(iface->xusb_device);
+		handle = iface->xusb_device->impl->handle;
+		XUSB_DBG(iface, "Releasing interface\n");
+		if (!handle) {
+			XUSB_ERR(iface, "device closed\n");
+			iface->is_claimed = 0;
+			return;
+		}
+		ret = usb_release_interface(handle, iface->interface_num);
+		if (ret < 0)
+			XUSB_ERR(iface, "Releasing interface: %s\n",
+					usb_strerror());
+		iface->is_claimed = 0;
+	}
+}
+
+static int xusb_clear_halt(struct xusb_iface *xusb_iface)
+{
+	struct xusb_device *xusb_device;
+	int ret = 0;
+	int ep;
+
+	xusb_device = xusb_iface->xusb_device;
+	/*
+	 * WE DO NOT CALL HALT for problematic devices:
+	 * - It cause problem with our usb-dongle (cypress CY7C63803, interrupt driven)
+	 */
+	if (xusb_device->idVendor == 0xe4e4 && xusb_device->idProduct == 0x11a3) {
+		XUSB_DBG(xusb_iface, "Skipping clear_halt()\n");
+		goto out;
+	}
+	if (!xtalk_option_use_clear_halt()) {
+		XUSB_DBG(xusb_iface, "Don't use clear_halt()\n");
+		goto out;
+	}
+	ep = EP_OUT(xusb_iface);
+	ret = usb_clear_halt(xusb_device->impl->handle, ep);
+	if (ret < 0) {
+		XUSB_ERR(xusb_iface, "Clearing output endpoint 0x%02X: %s\n",
+			ep, usb_strerror());
+		goto out;
+	}
+	ep = EP_IN(xusb_iface);
+	ret = usb_clear_halt(xusb_device->impl->handle, ep);
+	if (ret < 0) {
+		XUSB_ERR(xusb_iface, "Clearing input endpoint 0x%02X: %s\n",
+			ep, usb_strerror());
+		goto out;
+	}
+out:
+	return ret;
+}
+
+int xusb_claim(struct xusb_device *xusb_device, unsigned int interface_num,
+	struct xusb_iface **xusb_iface)
+{
+	struct xusb_iface *iface = NULL;
+	enum xusb_transfer_type	iface_tt = XUSB_TT_ILLEGAL;
+	int ret = 0;
+
+	*xusb_iface = NULL;
+	assert(xusb_device);
+	if (!xusb_device->impl->handle) {
+		XUSB_ERR(iface, "device closed\n");
+		ret = -ENXIO;
+		goto failed;
+	}
+	if (interface_num >= XUSB_MAX_INTERFACES) {
+		ERR("%s: interface number %d is too big\n",
+			xusb_device->devpath_tail, interface_num);
+		ret = -EINVAL;
+		goto failed;
+	}
+	iface = xusb_device->interfaces[interface_num];
+	if (!iface) {
+		ERR("%s: No interface number %d\n",
+			xusb_device->devpath_tail, interface_num);
+		ret = -EINVAL;
+		goto failed;
+	}
+	if (iface->is_claimed) {
+		XUSB_ERR(iface, "Already claimed\n");
+		ret = -EBUSY;
+		goto failed;
+	}
+	ret = usb_claim_interface(xusb_device->impl->handle, iface->interface_num);
+	if (ret < 0) {
+		XUSB_ERR(iface, "usb_claim_interface: %s\n", usb_strerror());
+		goto failed;
+	}
+	iface->is_claimed = 1;
+	iface_tt = xusb_transfer_type(iface);
+	if (iface_tt == XUSB_TT_ILLEGAL) {
+		ret = -ENOTSUP;
+		goto failed;
+	}
+	iface->transfer_type = iface_tt;
+	ret = xusb_clear_halt(iface);
+	if (ret < 0)
+		goto failed;
+	ret = xusb_flushread(iface);
+	if (ret < 0) {
+		XUSB_ERR(iface, "xusb_flushread failed: %s\n", usb_strerror());
+		goto failed;
+	}
+	xusb_fill_strings(xusb_device, interface_num);
+	XUSB_DBG(iface, "ID=%04X:%04X Manufacturer=[%s] Product=[%s] "
+		"SerialNumber=[%s] Interface=[%s] TT=%s\n",
+		xusb_device->idVendor,
+		xusb_device->idProduct,
+		xusb_device->iManufacturer,
+		xusb_device->iProduct,
+		xusb_device->iSerialNumber,
+		iface->iInterface,
+		xusb_tt_name(iface->transfer_type));
+	*xusb_iface = iface;
+	return 0;
+failed:
+	xusb_release(iface);
+	return ret;
+}
+
+void xusb_destroy(struct xusb_device *xusb_device)
+{
+	if (xusb_device) {
+		struct xusb_iface **piface;
+		struct libusb_implementation *impl;
+
+		for (piface = xusb_device->interfaces; *piface; piface++) {
+			xusb_destroy_interface(*piface);
+			*piface = NULL;
+		}
+		impl = xusb_device->impl;
+		if (impl) {
+			if (impl->handle) {
+				xusb_close(xusb_device);
+				impl->handle = NULL;
+			}
+		}
+		DBG("%s: MEM: FREE device\n", xusb_device->devpath_tail);
+		memset(xusb_device, 0, sizeof(*xusb_device));
+		free(xusb_device);
+		xusb_device = NULL;
+	}
+}
+
+static int init_interfaces(struct xusb_device *xusb_device)
+{
+	const struct usb_config_descriptor *config_desc;
+	const struct usb_interface_descriptor *iface_desc;
+	struct xusb_iface *iface;
+	int max_packet_size = 0;
+	int packet_size;
+	int if_idx;
+
+	assert(xusb_device);
+	assert(xusb_device->impl);
+	config_desc = xusb_device->impl->config_desc;
+	assert(config_desc);
+	assert(config_desc->bNumInterfaces < XUSB_MAX_INTERFACES);
+	for (if_idx = 0; if_idx < config_desc->bNumInterfaces; if_idx++) {
+		int ep_idx;
+
+		iface_desc = get_iface_descriptor(xusb_device, if_idx);
+		if (iface_desc->bInterfaceNumber != if_idx) {
+			ERR("%s: interface %d is number %d\n",
+				xusb_device->devpath_tail,
+				if_idx, iface_desc->bInterfaceNumber);
+			return -EINVAL;
+		}
+		if (iface_desc->bNumEndpoints != 2) {
+			ERR("%s: interface %d has %d endpoints\n",
+				xusb_device->devpath_tail,
+				if_idx, iface_desc->bNumEndpoints);
+			return -EINVAL;
+		}
+		iface = calloc(sizeof(*iface), 1);
+		if (!iface) {
+			ERR("%s: interface %d -- out of memory\n",
+				xusb_device->devpath_tail, if_idx);
+			return -ENOMEM;
+		}
+		DBG("MEM: ALLOC interface: %p\n", iface);
+		xusb_device->interfaces[if_idx] = iface;
+		iface->xusb_device = xusb_device;
+		iface->interface_num = iface_desc->bInterfaceNumber;
+
+		/* Search Endpoints */
+		iface->ep_in = 0;
+		iface->ep_out = 0;
+		for (ep_idx = 0; ep_idx < iface_desc->bNumEndpoints; ep_idx++) {
+			int ep_num;
+
+			ep_num = iface_desc->endpoint[ep_idx].bEndpointAddress;
+			packet_size = iface_desc->endpoint[ep_idx].wMaxPacketSize;
+			if (!max_packet_size || packet_size < max_packet_size)
+				max_packet_size = packet_size;
+			if (EP_IS_OUT(ep_num))
+				iface->ep_out = ep_num;
+			if (EP_IS_IN(ep_num))
+				iface->ep_in = ep_num;
+		}
+		/* Validation */
+		if (!iface->ep_out) {
+			ERR("%s[%d]: Missing output endpoint\n",
+				xusb_device->devpath_tail, if_idx);
+			return -EINVAL;
+		}
+		if (!iface->ep_in) {
+			ERR("%s[%d]: Missing input endpoint\n",
+				xusb_device->devpath_tail, if_idx);
+			return -EINVAL;
+		}
+
+		iface->is_claimed = 0;
+		XUSB_DBG(iface, "ep_out=0x%X ep_in=0x%X packet_size=%d\n",
+			iface->ep_out, iface->ep_in, max_packet_size);
+	}
+	if (xusb_device->packet_size < max_packet_size)
+		xusb_device->packet_size = max_packet_size;
+	xusb_device->is_usb2 = (xusb_device->packet_size == 512);
+	return 0;
+}
+
+static struct xusb_device *xusb_new(struct usb_device *dev,
+	const struct xusb_spec *spec,
+	xusb_filter_t filterfunc,
+	void *data)
+{
+	struct usb_device_descriptor	*dev_desc;
+	int				ret;
+	struct xusb_device		*xusb_device = NULL;
+
+	xusb_device = calloc(sizeof(*xusb_device) + sizeof(struct libusb_implementation), 1);
+	if (!xusb_device) {
+		ERR("Out of memory");
+		goto fail;
+	}
+	DBG("MEM: ALLOC device: %p\n", xusb_device);
+	/* Fill xusb_device */
+	xusb_device->impl = (void *)xusb_device + sizeof(*xusb_device);
+	xusb_device->impl->dev = dev;
+	xusb_device->spec = spec;
+	/*
+	 * Get information from the usb_device
+	 */
+	dev_desc = &dev->descriptor;
+	if (!dev_desc) {
+		ERR("usb device without a device descriptor\n");
+		goto fail;
+	}
+	xusb_device->idVendor = dev_desc->idVendor;
+	xusb_device->idProduct = dev_desc->idProduct;
+	sscanf(dev->bus->dirname, "%d", &xusb_device->bus_num);
+	sscanf(dev->filename, "%d", &xusb_device->device_num);
+	snprintf(xusb_device->devpath_tail, PATH_MAX, "%03d/%03d",
+		xusb_device->bus_num, xusb_device->device_num);
+	if (!match_device(xusb_device, spec)) {
+		DBG("[%04X:%04X] did not match\n",
+			xusb_device->idVendor, xusb_device->idProduct);
+		goto fail;
+	}
+	xusb_device->impl->config_desc = dev->config;
+	if (!xusb_device->impl->config_desc) {
+		ERR("usb device without a configuration descriptor\n");
+		goto fail;
+	}
+	ret = init_interfaces(xusb_device);
+	if (ret < 0) {
+		ERR("%s: init_interfaces() failed (ret = %d)\n",
+			xusb_device->devpath_tail, ret);
+		goto fail;
+	}
+	if (!xusb_open(xusb_device)) {
+		ERR("%s: Failed opening device: %04X:%04X\n",
+			xusb_device->devpath_tail,
+			xusb_device->idVendor,
+			xusb_device->idProduct);
+		goto fail;
+	}
+	DBG("%s: %04X:%04X\n",
+		xusb_device->devpath_tail,
+		xusb_device->idVendor,
+		xusb_device->idProduct);
+	return xusb_device;
+fail:
+	xusb_destroy(xusb_device);
+	return NULL;
+}
+
+struct xusb_iface *xusb_find_iface(const char *devpath,
+	int iface_num,
+	int ep_out,
+	int ep_in,
+	struct xusb_spec *dummy_spec)
+{
+	return NULL;
+}
+
+struct xusb_device *xusb_find_bypath(const char *path)
+{
+	struct usb_bus *bus;
+	struct usb_device *dev;
+	char devpath_tail[PATH_MAX];
+	struct xusb_spec *spec;
+
+	DBG("path='%s'\n", path);
+	spec = calloc(sizeof(*spec), 1);
+	if (!spec) {
+		ERR("Failed allocating spec\n");
+		goto failed;
+	}
+	xusb_init();
+	for (bus = usb_get_busses(); bus; bus = bus->next) {
+		for (dev = bus->devices; dev; dev = dev->next) {
+			struct usb_device_descriptor *dev_desc;
+			struct xusb_device *xusb_device = NULL;
+
+			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);
+			snprintf(devpath_tail, PATH_MAX, "%3s/%3s",
+				dev->bus->dirname, dev->filename);
+			if (!match_devpath(path, devpath_tail))
+				continue;
+			DBG("Found: usb:%s/%s: ID=%04X:%04X\n",
+				dev->bus->dirname,
+				dev->filename,
+				dev_desc->idVendor,
+				dev_desc->idProduct);
+			xusb_init_spec(spec, "<BYPATH>",
+				dev_desc->idVendor, dev_desc->idProduct);
+			xusb_device = xusb_new(dev, spec, NULL, NULL);
+			if (!xusb_device) {
+				ERR("Failed creating xusb for %s\n",
+					devpath_tail);
+				xusb_init_spec(spec, "<EMPTY>", 0, 0);
+				continue;
+			}
+			return xusb_device;
+		}
+	}
+failed:
+	if (spec)
+		free(spec);
+	return NULL;
+}
+
+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);
+	xlist = xlist_new(NULL);
+	if (!xlist) {
+		ERR("Failed allocation new xlist");
+		goto failed;
+	}
+	xusb_init();
+	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_device	*xusb_device;
+				const struct xusb_spec	*sp = &specs[i];
+
+				xusb_device = xusb_new(dev, sp, filterfunc, data);
+				if (!xusb_device)
+					continue;
+				if (filterfunc && !filterfunc(xusb_device, data)) {
+					DBG("%s: %04X:%04X filtered out\n",
+						xusb_device->devpath_tail,
+						dev_desc->idVendor,
+						dev_desc->idProduct);
+					xusb_destroy(xusb_device);
+					continue;
+				}
+				item = xlist_new(xusb_device);
+				xlist_append_item(xlist, item);
+				break;
+			}
+		}
+	}
+	xusb_list_dump(xlist);
+	return xlist;
+failed:
+	if (xlist)
+		xlist_destroy(xlist, NULL);
+	return NULL;
+}
+
+void xusb_showinfo(const struct xusb_device *xusb_device)
+{
+	struct usb_device_descriptor	*dev_desc;
+	struct usb_device		*dev;
+	const struct xusb_iface **piface;
+
+	assert(xusb_device);
+	dev = xusb_device->impl->dev;
+	assert(dev);
+	dev_desc = &dev->descriptor;
+	assert(dev_desc);
+	if (verbose <= LOG_INFO) {
+		INFO("%s: [%04X:%04X] [%s / %s / %s]\n",
+			xusb_device->devpath_tail,
+			dev_desc->idVendor,
+			dev_desc->idProduct,
+			xusb_device->iManufacturer,
+			xusb_device->iProduct,
+			xusb_device->iSerialNumber);
+	} else {
+		printf("USB    Bus/Device:    [%s/%s] (%s)\n",
+			dev->bus->dirname,
+			dev->filename,
+			(xusb_device->impl->handle) ? "open" : "closed");
+		printf("USB    Spec name:     [%s]\n", xusb_device->spec->name);
+		printf("USB    iManufacturer: [%s]\n", xusb_device->iManufacturer);
+		printf("USB    iProduct:      [%s]\n", xusb_device->iProduct);
+		printf("USB    iSerialNumber: [%s]\n", xusb_device->iSerialNumber);
+		piface = (const struct xusb_iface **)xusb_device->interfaces;
+		for (; *piface; piface++) {
+			printf("USB    Interface[%d]:  ep_out=0x%02X ep_in=0x%02X claimed=%d [%s]\n",
+				(*piface)->interface_num,
+				(*piface)->ep_out,
+				(*piface)->ep_in,
+				(*piface)->is_claimed,
+				(*piface)->iInterface);
+		}
+	}
+}
+
+int xusb_close(struct xusb_device *xusb_device)
+{
+	if (xusb_device && xusb_device->impl && xusb_device->impl->handle) {
+		assert(xusb_device->spec);
+		assert(xusb_device->spec->name);
+		DBG("%s: Closing device \"%s\"\n",
+			xusb_device->devpath_tail,
+			xusb_device->spec->name);
+		usb_close(xusb_device->impl->handle);
+		xusb_device->impl->handle = NULL;
+	}
+	return 0;
+}
+
+enum xusb_transfer_type xusb_transfer_type(const struct xusb_iface *iface)
+{
+	const struct xusb_device *xusb_device;
+	const struct usb_interface_descriptor *iface_desc;
+	const struct usb_endpoint_descriptor *ep;
+	enum xusb_transfer_type ret = XUSB_TT_ILLEGAL;
+
+	assert(iface);
+	xusb_device = iface->xusb_device;
+	assert(xusb_device);
+	iface_desc = get_iface_descriptor(xusb_device, iface->interface_num);
+	assert(iface_desc);
+	ep = iface_desc->endpoint;
+	assert(ep);
+	switch (ep->bmAttributes) {
+        case USB_ENDPOINT_TYPE_CONTROL:
+        case USB_ENDPOINT_TYPE_ISOCHRONOUS:
+		break;
+        case USB_ENDPOINT_TYPE_BULK:
+		ret = XUSB_TT_BULK;
+		break;
+        case USB_ENDPOINT_TYPE_INTERRUPT:
+		ret = XUSB_TT_INTERRUPT;
+		break;
+	}
+	return ret;
+}
+
+int xusb_send(struct xusb_iface *iface, const char *buf, int len, int timeout)
+{
+	struct xusb_device *xusb_device = iface->xusb_device;
+	int ep_out = EP_OUT(iface);
+	int retries = 0;
+	int ret;
+
+	dump_packet(LOG_DEBUG, DBG_MASK, __func__, buf, len);
+	if (!xusb_device->impl->handle) {
+		XUSB_ERR(iface, "device closed\n");
+		return -ENXIO;
+	}
+	if (!EP_IS_OUT(ep_out)) {
+		XUSB_ERR(iface, "%s called with an input endpoint 0x%x\n",
+			__func__, ep_out);
+		return -EINVAL;
+	}
+retry_write:
+	switch (iface->transfer_type) {
+	case XUSB_TT_BULK:
+		ret = usb_bulk_write(xusb_device->impl->handle, ep_out, (char *)buf, len, timeout);
+		break;
+	case XUSB_TT_INTERRUPT:
+		ret = usb_interrupt_write(xusb_device->impl->handle, ep_out, (char *)buf, len, timeout);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (ret < 0) {
+		/*
+		 * If the device was gone, it may be the
+		 * result of renumeration. Ignore it.
+		 */
+		if (ret != -ENODEV) {
+			XUSB_ERR(iface, "write to endpoint 0x%x failed: (%d) %s\n",
+				ep_out, ret, usb_strerror());
+			dump_packet(LOG_ERR, DBG_MASK, "xusb_send[ERR]",
+				buf, len);
+			/*exit(2);*/
+		} else {
+			XUSB_DBG(iface, "write to endpoint 0x%x got ENODEV\n",
+				ep_out);
+			xusb_close(xusb_device);
+		}
+		return ret;
+	}
+	if (!ret) {
+
+		XUSB_ERR(iface, "write to endpoint 0x%x short write[%d]: (%d)\n",
+			ep_out, retries, ret);
+		if (retries++ > MAX_RETRIES)
+			return -EFAULT;
+		usleep(100);
+		goto retry_write;
+	}
+	if (ret != len) {
+		XUSB_ERR(iface, "write to endpoint 0x%x short write: (%d) %s\n",
+			ep_out, ret, usb_strerror());
+		dump_packet(LOG_ERR, DBG_MASK, "xusb_send[ERR]", buf, len);
+		return -EFAULT;
+	}
+	return ret;
+}
+
+int xusb_recv(struct xusb_iface *iface, char *buf, size_t len, int timeout)
+{
+	struct xusb_device *xusb_device = iface->xusb_device;
+	int ep_in = EP_IN(iface);
+	int retries = 0;
+	int ret;
+
+	if (!xusb_device->impl->handle) {
+		XUSB_ERR(iface, "device closed\n");
+		return -ENXIO;
+	}
+	if (!EP_IS_IN(ep_in)) {
+		XUSB_ERR(iface, "called with an output endpoint 0x%x\n", ep_in);
+		return -EINVAL;
+	}
+retry_read:
+	switch (iface->transfer_type) {
+	case XUSB_TT_BULK:
+		ret = usb_bulk_read(xusb_device->impl->handle, ep_in, buf, len, timeout);
+		break;
+	case XUSB_TT_INTERRUPT:
+		ret = usb_interrupt_read(xusb_device->impl->handle, ep_in, buf, len, timeout);
+		break;
+	default:
+		ret = -EAFNOSUPPORT;
+		break;
+	}
+	if (ret < 0) {
+		XUSB_DBG(iface, "read from endpoint 0x%x failed: (%d) %s\n",
+			ep_in, ret, usb_strerror());
+		memset(buf, 0, len);
+		return ret;
+	}
+	if (!ret) {
+		XUSB_ERR(iface, "read to endpoint 0x%x short read[%d]: (%d)\n",
+			ep_in, retries, ret);
+		if (retries++ > MAX_RETRIES)
+			return -EFAULT;
+		usleep(100);
+		goto retry_read;
+	}
+	dump_packet(LOG_DEBUG, DBG_MASK, __func__, buf, ret);
+	return ret;
+}
+
+/*
+ * Serialize calls to usb_find_busses()/usb_find_devices()
+ */
+
+static const key_t	SEM_KEY = 0x1a2b3c4d;
+static int semid = -1;	/* Failure */
+
+static void xusb_lock_usb()
+{
+	struct sembuf	sembuf;
+
+	while (semid < 0) {
+		/* Maybe it was already created? */
+		semid = semget(SEM_KEY, 1, 0);
+		if (semid < 0) {
+			/* No, let's create ourselves */
+			semid = semget(SEM_KEY, 1, IPC_CREAT | IPC_EXCL | 0644);
+			if (semid < 0) {
+				/* Someone else won the race to create it */
+				if (errno != ENOENT)
+					ERR("%s: semget() failed: %s\n",
+						__func__, strerror(errno));
+				/* Retry */
+				continue;
+			}
+			/* Initialize */
+			if (semctl(semid, 0, SETVAL, 1) < 0)
+				ERR("%s: SETVAL() failed: %s\n",
+					__func__, strerror(errno));
+		}
+	}
+	DBG("%d: LOCKING\n", getpid());
+	sembuf.sem_num = 0;
+	sembuf.sem_op = -1;
+	sembuf.sem_flg = SEM_UNDO;
+	if (semop(semid, &sembuf, 1) < 0)
+		ERR("%s: semop() failed: %s\n", __func__, strerror(errno));
+	DBG("%d: LOCKED\n", getpid());
+}
+
+static void xusb_unlock_usb()
+{
+	struct sembuf	sembuf;
+
+	DBG("%d: UNLOCKING\n", getpid());
+	sembuf.sem_num = 0;
+	sembuf.sem_op = 1;
+	sembuf.sem_flg = SEM_UNDO;
+	if (semop(semid, &sembuf, 1) < 0)
+		ERR("%s: semop() failed: %s\n", __func__, strerror(errno));
+	DBG("%d: UNLOCKED\n", getpid());
+}
+
+static int		initizalized;
+
+void __attribute__((constructor)) xusb_init(void)
+{
+	xtalk_parse_options();
+	if (!getenv("XUSB_NOLOCK"))
+		xusb_lock_usb();
+	if (!initizalized) {
+		usb_init();
+		initizalized = 1;
+	}
+	usb_find_busses();
+	usb_find_devices();
+	if (!getenv("XUSB_NOLOCK"))
+		xusb_unlock_usb();
+}
diff --git a/xpp/xtalk/xusb_libusbx.c b/xpp/xtalk/xusb_libusbx.c
new file mode 100644
index 0000000..69670df
--- /dev/null
+++ b/xpp/xtalk/xusb_libusbx.c
@@ -0,0 +1,826 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2012, 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 <stdarg.h>
+#include <syslog.h>
+#include <arpa/inet.h>
+#include <libusb.h>
+#include <xtalk/debug.h>
+#include <xtalk/xusb.h>
+#include <autoconfig.h>
+#include "xusb_common.h"
+
+#define	DBG_MASK	0x01
+#define	TIMEOUT	500
+
+#define	EP_IS_IN(ep)	(((ep) & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
+#define	EP_IS_OUT(ep)	(((ep) & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT)
+
+struct libusb_implementation {
+	struct libusb_device	*dev;
+	struct libusb_device_handle *handle;
+	struct libusb_config_descriptor	*config_desc;
+};
+
+void __attribute__((constructor)) xusb_init(void)
+{
+	int ret;
+
+	xtalk_parse_options();
+	ret = libusb_init(NULL);
+	if (ret < 0) {
+		ERR("libusb_init() failed: ret=%d\n", ret);
+		abort();
+	}
+}
+
+void __attribute__((destructor)) xusb_fini(void)
+{
+	libusb_exit(NULL);
+}
+
+/*
+ * Translate libusbx error codes to regular errno
+ */
+static int errno_map(int libusb_err)
+{
+	int ret = -libusb_err;
+#define	ERRNO_MAP(libusb, errno)	[-(libusb)] = errno
+	static const int error_codes[] = {
+		ERRNO_MAP(LIBUSB_SUCCESS,		0),
+		ERRNO_MAP(LIBUSB_ERROR_IO,		EIO),
+		ERRNO_MAP(LIBUSB_ERROR_INVALID_PARAM,	EINVAL),
+		ERRNO_MAP(LIBUSB_ERROR_ACCESS,		EACCES),
+		ERRNO_MAP(LIBUSB_ERROR_NO_DEVICE,	ENODEV),
+		ERRNO_MAP(LIBUSB_ERROR_NOT_FOUND,	ENOENT),
+		ERRNO_MAP(LIBUSB_ERROR_BUSY,		EBUSY),
+		ERRNO_MAP(LIBUSB_ERROR_TIMEOUT,		ETIMEDOUT),
+		ERRNO_MAP(LIBUSB_ERROR_OVERFLOW,	EOVERFLOW),
+		ERRNO_MAP(LIBUSB_ERROR_PIPE,		EPIPE),
+		ERRNO_MAP(LIBUSB_ERROR_INTERRUPTED,	EINTR),
+		ERRNO_MAP(LIBUSB_ERROR_NO_MEM,		ENOMSG),
+		ERRNO_MAP(LIBUSB_ERROR_NOT_SUPPORTED,	ENOTSUP),
+		ERRNO_MAP(LIBUSB_ERROR_OTHER,		EPROTO),
+	};
+#undef	ERRNO_MAP
+	if (ret < 0 || ret > sizeof(error_codes)/sizeof(error_codes[0])) {
+		ERR("%s: Bad return code %d\n", __func__, -ret);
+		return -EPROTO;
+	}
+	return -(error_codes[ret]);
+}
+
+
+/*
+ * USB handling
+ */
+
+static int get_usb_string(struct xusb_device *xusb_device, uint8_t item, char *buf)
+{
+	unsigned char tmp[BUFSIZ];
+	int ret;
+
+	if (!xusb_device->impl->handle) {
+		ERR("%s: device closed\n", xusb_device->devpath_tail);
+		return -ENXIO;
+	}
+	if (!item)
+		return 0;
+	ret = libusb_get_string_descriptor_ascii(xusb_device->impl->handle, item,
+		tmp, BUFSIZ);
+	if (ret <= 0)
+		return errno_map(ret);
+	return snprintf(buf, BUFSIZ, "%s", tmp);
+}
+
+static const struct libusb_interface_descriptor *get_iface_descriptor(
+	const struct xusb_device *xusb_device, int i)
+{
+	const struct libusb_config_descriptor *config_desc;
+	const struct libusb_interface *interface;
+	const struct libusb_interface_descriptor *iface_desc;
+
+	assert(xusb_device);
+	assert(xusb_device->impl);
+	config_desc = xusb_device->impl->config_desc;
+	assert(config_desc);
+	assert(config_desc->bNumInterfaces < XUSB_MAX_INTERFACES);
+	if (i >= XUSB_MAX_INTERFACES)
+		return NULL;
+	interface = &config_desc->interface[i];
+	iface_desc = interface->altsetting;
+	return iface_desc;
+}
+
+#define	GET_USB_STRING(xusb_device, from, item) \
+		get_usb_string((xusb_device), (from)->item, (xusb_device)->item)
+
+static int xusb_fill_strings(struct xusb_device *xusb_device, int interface_num)
+{
+	struct libusb_device_descriptor	dev_desc;
+	const struct libusb_interface_descriptor *iface_desc;
+	struct xusb_iface *iface = xusb_device->interfaces[interface_num];
+	int ret;
+
+	assert(xusb_device);
+	assert(xusb_device->impl);
+	ret = libusb_get_device_descriptor(xusb_device->impl->dev, &dev_desc);
+	if (ret) {
+		XUSB_ERR(iface, "libusb_get_device_descriptor() failed: %s\n",
+			libusb_error_name(ret));
+		return errno_map(ret);
+	}
+	ret = GET_USB_STRING(xusb_device, &dev_desc, iManufacturer);
+	if (ret < 0) {
+		XUSB_ERR(iface, "Failed reading iManufacturer string: %s\n",
+			libusb_error_name(ret));
+		return 0;
+	}
+	ret = GET_USB_STRING(xusb_device, &dev_desc, iProduct);
+	if (ret < 0) {
+		XUSB_ERR(iface, "Failed reading iProduct string: %s\n",
+			libusb_error_name(ret));
+		return 0;
+	}
+	ret = GET_USB_STRING(xusb_device, &dev_desc, iSerialNumber);
+	if (ret < 0) {
+		XUSB_ERR(iface, "Failed reading iSerialNumber string: %s\n",
+			libusb_error_name(ret));
+		return 0;
+	}
+	iface_desc = get_iface_descriptor(xusb_device, interface_num);
+	if (!iface_desc) {
+		XUSB_ERR(iface, "Could not get interface descriptor of device\n");
+		return 0;
+	}
+	ret = get_usb_string(xusb_device, iface_desc->iInterface, iface->iInterface);
+	if (ret < 0) {
+		XUSB_ERR(iface, "Failed reading iInterface string: %s\n",
+			libusb_error_name(ret));
+		return 0;
+	}
+	return 1;
+}
+
+static int xusb_open(struct xusb_device *xusb_device)
+{
+	int ret = 0;
+
+	DBG("%s\n", xusb_device->devpath_tail);
+	if (xusb_device->impl->handle) {
+		ERR("%s: already open\n", xusb_device->devpath_tail);
+		ret = -EBUSY;
+		goto out;
+	}
+	ret = libusb_open(xusb_device->impl->dev, &(xusb_device->impl->handle));
+	if (ret < 0) {
+		ERR("%s: Failed to open usb device: %s\n",
+			xusb_device->devpath_tail,
+			libusb_error_name(ret));
+		ret = errno_map(ret);
+		xusb_device->impl->handle = NULL;
+		goto out;
+	}
+out:
+	return ret;
+}
+
+void xusb_release(struct xusb_iface *iface)
+{
+	if (iface && iface->is_claimed) {
+		struct libusb_device_handle *handle;
+
+		assert(iface->xusb_device);
+		handle = iface->xusb_device->impl->handle;
+		XUSB_DBG(iface, "Releasing interface\n");
+		if (!handle) {
+			XUSB_ERR(iface, "device closed\n");
+			iface->is_claimed = 0;
+			return;
+		}
+		int ret = libusb_release_interface(handle, iface->interface_num);
+		if (ret < 0)
+			XUSB_ERR(iface, "Releasing interface: %s\n",
+					libusb_error_name(ret));
+		iface->is_claimed = 0;
+	}
+}
+
+static int xusb_clear_halt(struct xusb_iface *xusb_iface)
+{
+	struct xusb_device *xusb_device;
+	int ret = 0;
+	int ep;
+
+	xusb_device = xusb_iface->xusb_device;
+	/*
+	 * WE DO NOT CALL HALT for problematic devices:
+	 * - It cause problem with our usb-dongle (cypress CY7C63803, interrupt driven)
+	 */
+	if (xusb_device->idVendor == 0xe4e4 && xusb_device->idProduct == 0x11a3) {
+		XUSB_DBG(xusb_iface, "Skipping clear_halt()\n");
+		goto out;
+	}
+	if (!xtalk_option_use_clear_halt()) {
+		XUSB_DBG(xusb_iface, "Don't use clear_halt()\n");
+		goto out;
+	}
+	ep = EP_OUT(xusb_iface);
+	ret = libusb_clear_halt(xusb_device->impl->handle, ep);
+	if (ret < 0) {
+		XUSB_ERR(xusb_iface, "Clearing output endpoint 0x%02X: %s\n",
+			ep, libusb_error_name(ret));
+		ret = errno_map(ret);
+		goto out;
+	}
+	ep = EP_IN(xusb_iface);
+	ret = libusb_clear_halt(xusb_device->impl->handle, ep);
+	if (ret < 0) {
+		XUSB_ERR(xusb_iface, "Clearing input endpoint 0x%02X: %s\n",
+			ep, libusb_error_name(ret));
+		ret = errno_map(ret);
+		goto out;
+	}
+out:
+	return ret;
+}
+
+int xusb_claim(struct xusb_device *xusb_device, unsigned int interface_num,
+	struct xusb_iface **xusb_iface)
+{
+	struct xusb_iface *iface = NULL;
+	enum xusb_transfer_type	iface_tt = XUSB_TT_ILLEGAL;
+	int ret = 0;
+
+	*xusb_iface = NULL;
+	assert(xusb_device);
+	if (!xusb_device->impl->handle) {
+		ERR("%s: device closed\n", xusb_device->devpath_tail);
+		return -ENXIO;
+	}
+	if (interface_num >= XUSB_MAX_INTERFACES) {
+		ERR("%s: interface number %d is too big\n",
+			xusb_device->devpath_tail, interface_num);
+		ret = -EINVAL;
+		goto failed;
+	}
+	iface = xusb_device->interfaces[interface_num];
+	if (!iface) {
+		ERR("%s: No interface number %d\n",
+			xusb_device->devpath_tail, interface_num);
+		ret = -EINVAL;
+		goto failed;
+	}
+	if (iface->is_claimed) {
+		XUSB_ERR(iface, "Already claimed\n");
+		ret = -EBUSY;
+		goto failed;
+	}
+	ret = libusb_claim_interface(xusb_device->impl->handle, iface->interface_num);
+	if (ret < 0) {
+		XUSB_ERR(iface, "libusb_claim_interface: %s\n",
+			libusb_error_name(ret));
+		ret = errno_map(ret);
+		goto failed;
+	}
+	iface->is_claimed = 1;
+	iface_tt = xusb_transfer_type(iface);
+	if (iface_tt == XUSB_TT_ILLEGAL) {
+		ret = -ENOTSUP;
+		goto failed;
+	}
+	iface->transfer_type = iface_tt;
+	xusb_fill_strings(xusb_device, interface_num);
+	XUSB_DBG(iface, "ID=%04X:%04X Manufacturer=[%s] Product=[%s] "
+		"SerialNumber=[%s] Interface=[%s] TT=%s\n",
+		xusb_device->idVendor,
+		xusb_device->idProduct,
+		xusb_device->iManufacturer,
+		xusb_device->iProduct,
+		xusb_device->iSerialNumber,
+		iface->iInterface,
+		xusb_tt_name(iface->transfer_type));
+	ret = xusb_clear_halt(iface);
+	if (ret < 0)
+		goto failed;
+	ret = xusb_flushread(iface);
+	if (ret < 0) {
+		XUSB_ERR(iface, "xusb_flushread failed: %d\n", ret);
+		goto failed;
+	}
+	*xusb_iface = iface;
+	return 0;
+failed:
+	if (iface)
+		xusb_release(iface);
+	return ret;
+}
+
+void xusb_destroy(struct xusb_device *xusb_device)
+{
+	if (xusb_device) {
+		struct xusb_iface **piface;
+		struct libusb_implementation *impl;
+
+		for (piface = xusb_device->interfaces; *piface; piface++) {
+			xusb_destroy_interface(*piface);
+			*piface = NULL;
+		}
+		impl = xusb_device->impl;
+		if (impl) {
+			if (impl->handle) {
+				xusb_close(xusb_device);
+				impl->handle = NULL;
+			}
+			if (impl->config_desc)
+				libusb_free_config_descriptor(impl->config_desc);
+		}
+		DBG("%s: MEM: FREE device\n", xusb_device->devpath_tail);
+		memset(xusb_device, 0, sizeof(*xusb_device));
+		free(xusb_device);
+		xusb_device = NULL;
+	}
+}
+
+static int init_interfaces(struct xusb_device *xusb_device)
+{
+	const struct libusb_config_descriptor *config_desc;
+	const struct libusb_interface_descriptor *iface_desc;
+	struct xusb_iface *iface;
+	int max_packet_size = 0;
+	int packet_size;
+	int if_idx;
+
+	assert(xusb_device);
+	assert(xusb_device->impl);
+	config_desc = xusb_device->impl->config_desc;
+	assert(config_desc->bNumInterfaces < XUSB_MAX_INTERFACES);
+	for (if_idx = 0; if_idx < config_desc->bNumInterfaces; if_idx++) {
+		int ep_idx;
+
+		iface_desc = get_iface_descriptor(xusb_device, if_idx);
+		if (iface_desc->bInterfaceNumber != if_idx) {
+			ERR("%s: interface %d is number %d\n",
+				xusb_device->devpath_tail,
+				if_idx, iface_desc->bInterfaceNumber);
+			return -EINVAL;
+		}
+		if (iface_desc->bNumEndpoints != 2) {
+			ERR("%s: interface %d has %d endpoints\n",
+				xusb_device->devpath_tail,
+				if_idx, iface_desc->bNumEndpoints);
+			return -EINVAL;
+		}
+		iface = calloc(sizeof(*iface), 1);
+		if (!iface) {
+			ERR("%s: interface %d -- out of memory\n",
+				xusb_device->devpath_tail, if_idx);
+			return -ENOMEM;
+		}
+		DBG("MEM: ALLOC interface: %p\n", iface);
+		xusb_device->interfaces[if_idx] = iface;
+		iface->xusb_device = xusb_device;
+		iface->interface_num = iface_desc->bInterfaceNumber;
+
+		/* Search Endpoints */
+		iface->ep_in = 0;
+		iface->ep_out = 0;
+		for (ep_idx = 0; ep_idx < iface_desc->bNumEndpoints; ep_idx++) {
+			int ep_num;
+
+			ep_num = iface_desc->endpoint[ep_idx].bEndpointAddress;
+			packet_size = libusb_get_max_packet_size(xusb_device->impl->dev, ep_num);
+			if (!max_packet_size || packet_size < max_packet_size)
+				max_packet_size = packet_size;
+			if (EP_IS_OUT(ep_num))
+				iface->ep_out = ep_num;
+			if (EP_IS_IN(ep_num))
+				iface->ep_in = ep_num;
+		}
+		/* Validation */
+		if (!iface->ep_out) {
+			ERR("%s[%d]: Missing output endpoint\n",
+				xusb_device->devpath_tail, if_idx);
+			return -EINVAL;
+		}
+		if (!iface->ep_in) {
+			ERR("%s[%d]: Missing input endpoint\n",
+				xusb_device->devpath_tail, if_idx);
+			return -EINVAL;
+		}
+
+		iface->is_claimed = 0;
+		XUSB_DBG(iface, "ep_out=0x%X ep_in=0x%X packet_size=%d\n",
+			iface->ep_out, iface->ep_in, max_packet_size);
+	}
+	if (xusb_device->packet_size < max_packet_size)
+		xusb_device->packet_size = max_packet_size;
+	xusb_device->is_usb2 = (xusb_device->packet_size == 512);
+	return 0;
+}
+
+static struct xusb_device *xusb_new(struct libusb_device *dev,
+	const struct xusb_spec *spec)
+{
+	struct libusb_device_descriptor	dev_desc;
+	int				ret;
+	struct xusb_device		*xusb_device = NULL;
+
+	xusb_device = calloc(sizeof(*xusb_device) + sizeof(struct libusb_implementation), 1);
+	if (!xusb_device) {
+		ERR("Out of memory");
+		goto fail;
+	}
+	DBG("MEM: ALLOC device: %p\n", xusb_device);
+	/* Fill xusb_device */
+	xusb_device->impl = (void *)xusb_device + sizeof(*xusb_device);
+	xusb_device->impl->dev = dev;
+	xusb_device->spec = spec;
+	xusb_device->bus_num = libusb_get_bus_number(dev);
+	xusb_device->device_num = libusb_get_device_address(dev);
+	snprintf(xusb_device->devpath_tail, PATH_MAX, "%03d/%03d",
+		xusb_device->bus_num, xusb_device->device_num);
+	/*
+	 * Opening the device
+	 */
+	ret = xusb_open(xusb_device);
+	if (ret < 0) {
+		ERR("%s: Failed to open usb device: %s\n",
+				xusb_device->devpath_tail,
+				strerror(-ret));
+		goto fail;
+	}
+	/*
+	 * Get information from the usb_device
+	 */
+	ret = libusb_get_device_descriptor(dev, &dev_desc);
+	if (ret) {
+		ERR("%s: libusb_get_device_descriptor() failed: %s\n",
+			xusb_device->devpath_tail,
+			libusb_error_name(ret));
+		goto fail;
+	}
+	xusb_device->idVendor = dev_desc.idVendor;
+	xusb_device->idProduct = dev_desc.idProduct;
+	if (!match_device(xusb_device, spec)) {
+		DBG("[%04X:%04X] did not match\n",
+			xusb_device->idVendor, xusb_device->idProduct);
+		goto fail;
+	}
+	DBG("%s: process [%X:%X]\n",
+		xusb_device->devpath_tail,
+		xusb_device->idVendor,
+		xusb_device->idProduct);
+	ret = libusb_get_config_descriptor(dev, 0, &xusb_device->impl->config_desc);
+	if (ret) {
+		ERR("%s: libusb_get_config_descriptor() failed: %s\n",
+			xusb_device->devpath_tail,
+			libusb_error_name(ret));
+		goto fail;
+	}
+	ret = init_interfaces(xusb_device);
+	if (ret < 0) {
+		ERR("%s: init_interfaces() failed (ret = %d)\n",
+			xusb_device->devpath_tail, ret);
+		goto fail;
+	}
+	DBG("%s: Created %04X:%04X\n",
+		xusb_device->devpath_tail,
+		xusb_device->idVendor,
+		xusb_device->idProduct);
+	return xusb_device;
+fail:
+	xusb_destroy(xusb_device);
+	return NULL;
+}
+
+struct xusb_iface *xusb_find_iface(const char *devpath,
+	int iface_num,
+	int ep_out,
+	int ep_in,
+	struct xusb_spec *dummy_spec)
+{
+	ERR("FIXME: Unimplemented yet\n");
+	return NULL;
+}
+
+struct xusb_device *xusb_find_bypath(const char *path)
+{
+	struct xusb_spec *spec;
+	libusb_device **list;
+	ssize_t cnt;
+	int i;
+
+	DBG("path='%s'\n", path);
+	spec = calloc(sizeof(*spec), 1);
+	if (!spec) {
+		ERR("Failed allocating spec\n");
+		goto failed;
+	}
+	cnt = libusb_get_device_list(NULL, &list);
+	if (cnt < 0) {
+		ERR("libusb_get_device_list() failed");
+		goto failed;
+	}
+	for (i = 0; i < cnt; i++) {
+		struct libusb_device_descriptor	dev_desc;
+		libusb_device *dev = list[i];
+		struct xusb_device *xusb_device;
+		char devpath_tail[PATH_MAX];
+		int bus_num;
+		int device_num;
+		int ret;
+
+		bus_num = libusb_get_bus_number(dev);
+		device_num = libusb_get_device_address(dev);
+		snprintf(devpath_tail, PATH_MAX, "%03d/%03d",
+			bus_num, device_num);
+		if (!match_devpath(path, devpath_tail))
+			continue;
+		ret = libusb_get_device_descriptor(dev, &dev_desc);
+		if (ret < 0) {
+			ERR("usb device without a device descriptor\n");
+			continue;
+		}
+		INFO("Found: %04x:%04x %s\n",
+			dev_desc.idVendor, dev_desc.idProduct, devpath_tail);
+		xusb_init_spec(spec, "<BYPATH>",
+			dev_desc.idVendor, dev_desc.idProduct);
+		xusb_device = xusb_new(dev, spec);
+		if (!xusb_device) {
+			ERR("Failed creating xusb for %s\n",
+				devpath_tail);
+			xusb_init_spec(spec, "<EMPTY>", 0, 0);
+			continue;
+		}
+		return xusb_device;
+	}
+failed:
+	if (spec)
+		free(spec);
+	return NULL;
+}
+
+struct xlist_node *xusb_find_byproduct(const struct xusb_spec *specs,
+		int numspecs, xusb_filter_t filterfunc, void *data)
+{
+	struct xlist_node	*xlist;
+	libusb_device **list;
+	ssize_t cnt;
+	int i;
+
+	DBG("specs(%d)\n", numspecs);
+	xlist = xlist_new(NULL);
+	if (!xlist) {
+		ERR("Failed allocation new xlist");
+		goto cleanup;
+	}
+	cnt = libusb_get_device_list(NULL, &list);
+	if (cnt < 0) {
+		ERR("libusb_get_device_list() failed");
+		goto cleanup;
+	}
+	for (i = 0; i < cnt; i++) {
+		struct libusb_device_descriptor	dev_desc;
+		libusb_device *dev = list[i];
+		struct xlist_node *item;
+		int ret;
+		int j;
+
+		ret = libusb_get_device_descriptor(dev, &dev_desc);
+		if (ret < 0) {
+			ERR("usb device without a device descriptor\n");
+			continue;
+		}
+		for (j = 0; j < numspecs; j++) {
+			struct xusb_device	*xusb_device;
+			const struct xusb_spec	*sp = &specs[j];
+
+			xusb_device = xusb_new(dev, sp);
+			if (!xusb_device)
+				continue;
+			if (filterfunc && !filterfunc(xusb_device, data)) {
+				DBG("%s: %04X:%04X filtered out\n",
+					xusb_device->devpath_tail,
+					dev_desc.idVendor,
+					dev_desc.idProduct);
+				xusb_destroy(xusb_device);
+				continue;
+			}
+			item = xlist_new(xusb_device);
+			xlist_append_item(xlist, item);
+			break;
+		}
+	}
+	xusb_list_dump(xlist);
+	return xlist;
+cleanup:
+	if (xlist)
+		xlist_destroy(xlist, NULL);
+	return NULL;
+}
+
+void xusb_showinfo(const struct xusb_device *xusb_device)
+{
+	struct libusb_device_descriptor	dev_desc;
+	struct libusb_device	*dev;
+	const struct xusb_iface **piface;
+	int ret;
+
+	assert(xusb_device);
+	dev = xusb_device->impl->dev;
+	ret = libusb_get_device_descriptor(dev, &dev_desc);
+	if (ret < 0) {
+		ERR("%s: usb device without a device descriptor\n",
+			xusb_device->devpath_tail);
+		return;
+	}
+	if (verbose <= LOG_INFO) {
+		INFO("%s: [%04X:%04X] [%s / %s / %s]\n",
+			xusb_device->devpath_tail,
+			dev_desc.idVendor,
+			dev_desc.idProduct,
+			xusb_device->iManufacturer,
+			xusb_device->iProduct,
+			xusb_device->iSerialNumber);
+	} else {
+		printf("USB    Bus/Device:    [%03d/%03d] (%s)\n",
+			xusb_device->bus_num,
+			xusb_device->device_num,
+			(xusb_device->impl->handle) ? "open" : "closed");
+		printf("USB    Spec name:     [%s]\n", xusb_device->spec->name);
+		printf("USB    iManufacturer: [%s]\n", xusb_device->iManufacturer);
+		printf("USB    iProduct:      [%s]\n", xusb_device->iProduct);
+		printf("USB    iSerialNumber: [%s]\n", xusb_device->iSerialNumber);
+		piface = (const struct xusb_iface **)xusb_device->interfaces;
+		for (; *piface; piface++) {
+			printf("USB    Interface[%d]:  ep_out=0x%02X ep_in=0x%02X claimed=%d [%s]\n",
+				(*piface)->interface_num,
+				(*piface)->ep_out,
+				(*piface)->ep_in,
+				(*piface)->is_claimed,
+				(*piface)->iInterface);
+		}
+	}
+}
+
+int xusb_close(struct xusb_device *xusb_device)
+{
+	if (xusb_device && xusb_device->impl && xusb_device->impl->handle) {
+		assert(xusb_device->spec);
+		assert(xusb_device->spec->name);
+		DBG("%s: Closing device \"%s\"\n",
+			xusb_device->devpath_tail,
+			xusb_device->spec->name);
+		libusb_close(xusb_device->impl->handle);
+		xusb_device->impl->handle = NULL;
+	}
+	return 0;
+}
+
+enum xusb_transfer_type xusb_transfer_type(const struct xusb_iface *iface)
+{
+	const struct xusb_device *xusb_device;
+	const struct libusb_interface_descriptor *iface_desc;
+	const struct libusb_endpoint_descriptor *ep;
+	enum xusb_transfer_type ret = XUSB_TT_ILLEGAL;
+
+	assert(iface);
+	xusb_device = iface->xusb_device;
+	assert(xusb_device);
+	iface_desc = get_iface_descriptor(xusb_device, iface->interface_num);
+	assert(iface_desc);
+	ep = iface_desc->endpoint;
+	assert(ep);
+	switch (ep->bmAttributes) {
+        case LIBUSB_TRANSFER_TYPE_CONTROL:
+        case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+		break;
+        case LIBUSB_TRANSFER_TYPE_BULK:
+		ret = XUSB_TT_BULK;
+		break;
+        case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+		ret = XUSB_TT_INTERRUPT;
+		break;
+	}
+	return ret;
+}
+
+int xusb_send(struct xusb_iface *iface, const char *buf, int len, int timeout)
+{
+	struct xusb_device *xusb_device = iface->xusb_device;
+	int actual_len;
+	int ep_out = EP_OUT(iface);
+	int ret;
+
+	if (!xusb_device->impl->handle) {
+		ERR("%s: device closed\n", xusb_device->devpath_tail);
+		return -ENXIO;
+	}
+	dump_packet(LOG_DEBUG, DBG_MASK, __func__, buf, len);
+	if (!EP_IS_OUT(ep_out)) {
+		XUSB_ERR(iface, "%s called with an input endpoint 0x%x\n",
+			__func__, ep_out);
+		return -EINVAL;
+	}
+	switch (iface->transfer_type) {
+	case XUSB_TT_BULK:
+		ret = libusb_bulk_transfer(xusb_device->impl->handle, ep_out,
+			(unsigned char *)buf, len, &actual_len, timeout);
+		break;
+	case XUSB_TT_INTERRUPT:
+		ret = libusb_interrupt_transfer(xusb_device->impl->handle, ep_out,
+			(unsigned char *)buf, len, &actual_len, timeout);
+		break;
+	default:
+		ret = -EAFNOSUPPORT;
+		break;
+	}
+	if (ret) {
+		/*
+		 * If the device was gone, it may be the
+		 * result of renumeration. Ignore it.
+		 */
+		if (ret != LIBUSB_ERROR_NO_DEVICE) {
+			XUSB_ERR(iface, "write to endpoint 0x%x failed: (%d) %s\n",
+				ep_out, ret, libusb_error_name(ret));
+			dump_packet(LOG_ERR, DBG_MASK, "xbus_send[ERR]",
+				buf, len);
+			/*exit(2);*/
+		} else {
+			XUSB_DBG(iface, "write to endpoint 0x%x got ENODEV\n",
+				ep_out);
+			xusb_close(xusb_device);
+		}
+		return errno_map(ret);
+	} else if (actual_len != len) {
+		XUSB_ERR(iface, "write to endpoint 0x%x short write: (%d) %s\n",
+			ep_out, ret, libusb_error_name(ret));
+		dump_packet(LOG_ERR, DBG_MASK, "xbus_send[ERR]", buf, len);
+		return -EFAULT;
+	}
+	return actual_len;
+}
+
+int xusb_recv(struct xusb_iface *iface, char *buf, size_t len, int timeout)
+{
+	struct xusb_device *xusb_device = iface->xusb_device;
+	int actual_len;
+	int ep_in = EP_IN(iface);
+	int ret;
+
+	if (!xusb_device->impl->handle) {
+		ERR("%s: device closed\n", xusb_device->devpath_tail);
+		return -ENXIO;
+	}
+	if (!EP_IS_IN(ep_in)) {
+		XUSB_ERR(iface, "%s called with an output endpoint 0x%x\n",
+			__func__, ep_in);
+		return -EINVAL;
+	}
+	switch (iface->transfer_type) {
+	case XUSB_TT_BULK:
+		ret = libusb_bulk_transfer(xusb_device->impl->handle, ep_in,
+			(unsigned char *)buf, len, &actual_len, timeout);
+		break;
+	case XUSB_TT_INTERRUPT:
+		ret = libusb_interrupt_transfer(xusb_device->impl->handle, ep_in,
+			(unsigned char *)buf, len, &actual_len, timeout);
+		break;
+	default:
+		ret = -EAFNOSUPPORT;
+		break;
+	}
+	if (ret < 0) {
+		XUSB_DBG(iface, "read from endpoint 0x%x failed: (%d) %s\n",
+			ep_in, ret, libusb_error_name(ret));
+		memset(buf, 0, len);
+		return errno_map(ret);
+	}
+	dump_packet(LOG_DEBUG, DBG_MASK, __func__, buf, actual_len);
+	return actual_len;
+}
diff --git a/xpp/xtalk/xusb_test.c b/xpp/xtalk/xusb_test.c
new file mode 100644
index 0000000..8f0b37b
--- /dev/null
+++ b/xpp/xtalk/xusb_test.c
@@ -0,0 +1,124 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <xtalk/debug.h>
+#include <xtalk/xusb.h>
+#include <autoconfig.h>
+
+static char	*progname;
+
+static void usage()
+{
+	fprintf(stderr, "Usage: %s [options...] -D <device> [hexnum ....]\n",
+		progname);
+	fprintf(stderr, "\tOptions:\n");
+	fprintf(stderr, "\t\t[-v]               # Increase verbosity\n");
+	fprintf(stderr,
+		"\t\t[-d mask]          # Debug mask (0xFF for everything)\n");
+	fprintf(stderr, "\tDevice:\n");
+	fprintf(stderr, "\t\t/proc/bus/usb/<bus>/<dev>\n");
+	fprintf(stderr, "\t\t/dev/bus/usb/<bus>/<dev>\n");
+	exit(1);
+}
+
+static void xusb_destructor(void *data)
+{
+	struct xusb_device	*xusb_device = data;
+	xusb_destroy(xusb_device);
+}
+
+#define	XUSB_IFACE_DESC(p, i, d) \
+		{ SPEC_HEAD(0xe4e4, (p), (d)), (i) }
+
+static struct xusb_iface_description {
+	struct xusb_spec	spec;
+	int interface_num;
+} test_specs[] = {
+	/* 115x */
+	XUSB_IFACE_DESC(0x1150, 1, "old-astribank-NOFW"),
+	XUSB_IFACE_DESC(0x1151, 1, "old-astribank-USB"),
+	XUSB_IFACE_DESC(0x1152, 1, "old-astribank-FPGA"),
+
+	/* 116x */
+	XUSB_IFACE_DESC(0x1160, 1, "astribank2-NOFW"),
+	XUSB_IFACE_DESC(0x1161, 1, "astribank2-USB"),
+	XUSB_IFACE_DESC(0x1162, 1, "astribank2-FPGA"),
+	XUSB_IFACE_DESC(0x1163, 1, "astribank2-TWINSTAR"),
+	XUSB_IFACE_DESC(0x1191, 1, "xpanel"),
+	XUSB_IFACE_DESC(0x1183, 1, "multi-ps"),
+	XUSB_IFACE_DESC(0x11a3, 0, "auth-dongle"),
+	XUSB_IFACE_DESC(0xbb01, 0, "iwc"),
+	{},
+};
+
+static int run_spec(int i, xusb_filter_t filter, char *devpath)
+{
+	struct xusb_iface_description *desc = &test_specs[i];
+	struct xusb_spec	*s = &desc->spec;
+	struct xlist_node	*xlist;
+	struct xlist_node	*curr;
+	int interface_num = desc->interface_num;
+	int num_devs;
+
+	if (!s->name)
+		return 0;
+	xlist = xusb_find_byproduct(s, 1, filter, devpath);
+	num_devs = (xlist) ? xlist_length(xlist) : 0;
+	INFO("total %d devices of type %s (interface=%d)\n",
+		num_devs, s->name, interface_num);
+	for (curr = xlist_shift(xlist); curr; curr = xlist_shift(xlist)) {
+		struct xusb_device	*xusb_device;
+		struct xusb_iface	*iface;
+                int ret;
+
+		xusb_device = curr->data;
+                ret = xusb_claim(xusb_device, interface_num, &iface);
+                if (ret < 0) {
+                        ERR("%s: xusb_claim() failed (ret = %d)\n",
+                                xusb_devpath(xusb_device), ret);
+                        continue;
+                }
+		xusb_showinfo(xusb_device);
+                xusb_release(iface);
+	}
+	xlist_destroy(xlist, xusb_destructor);
+	return 1;
+}
+
+int main(int argc, char *argv[])
+{
+	char			*devpath = NULL;
+	const char		options[] = "vd:D:EFp";
+	xusb_filter_t		filter = NULL;
+	int			i;
+
+	progname = argv[0];
+	while (1) {
+		int	c;
+
+		c = getopt(argc, argv, options);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'D':
+			devpath = optarg;
+			filter = xusb_filter_bypath;
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case 'd':
+			debug_mask = strtoul(optarg, NULL, 0);
+			break;
+		case 'h':
+		default:
+			ERR("Unknown option '%c'\n", c);
+			usage();
+		}
+	}
+	i = 0;
+	while (run_spec(i, filter, devpath))
+		i++;
+	return 0;
+}
diff --git a/xpp/xtalk/xusb_test_bypath.c b/xpp/xtalk/xusb_test_bypath.c
new file mode 100644
index 0000000..8cd4792
--- /dev/null
+++ b/xpp/xtalk/xusb_test_bypath.c
@@ -0,0 +1,76 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <xtalk/debug.h>
+#include <xtalk/xusb.h>
+#include <autoconfig.h>
+
+static char	*progname;
+
+static void usage()
+{
+	fprintf(stderr, "Usage: %s [options...] <busnum>/<devnum> ...\n", progname);
+	fprintf(stderr, "\tOptions:\n");
+	fprintf(stderr, "\t\t[-v]               # Increase verbosity\n");
+	fprintf(stderr,
+		"\t\t[-d mask]          # Debug mask (0xFF for everything)\n");
+	exit(1);
+}
+
+static int check_devpath(const char *devpath)
+{
+	const struct xusb_spec *spec;
+	struct xusb_device *xusb_dev;
+	struct xusb_iface *iface;
+	int ret;
+
+	printf("Checking %s: ", devpath);
+	fflush(stdout);
+	xusb_dev = xusb_find_bypath(devpath);
+	if (!xusb_dev) {
+		ERR("missing %s\n", devpath);
+		return 1;
+	}
+	spec = xusb_device_spec(xusb_dev);
+	printf("Found: %04x:%04x\n", spec->vendor_id, spec->product_id);
+	ret = xusb_claim(xusb_dev, 1, &iface);
+	if (ret < 0) {
+		ERR("%s: xusb_claim() failed (ret = %d)\n",
+			xusb_devpath(xusb_dev), ret);
+		return 1;
+	}
+	xusb_showinfo(xusb_dev);
+	xusb_release(iface);
+	return 1;
+}
+
+int main(int argc, char *argv[])
+{
+	const char		options[] = "vd:";
+	int			i;
+
+	progname = argv[0];
+	while (1) {
+		int	c;
+
+		c = getopt(argc, argv, options);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'v':
+			verbose++;
+			break;
+		case 'd':
+			debug_mask = strtoul(optarg, NULL, 0);
+			break;
+		case 'h':
+		default:
+			ERR("Unknown option '%c'\n", c);
+			usage();
+		}
+	}
+	for (i = optind; i < argc; i++)
+		check_devpath(argv[i]);
+	return 0;
+}

-- 
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