add simtrace2 host libraries

these are copies of files from simtrace2
diff --git a/src/apdu_dispatch.c b/src/apdu_dispatch.c
new file mode 100644
index 0000000..7c7ed01
--- /dev/null
+++ b/src/apdu_dispatch.c
@@ -0,0 +1,173 @@
+/* apdu_dispatch - State machine to determine Rx/Tx phases of APDU
+ *
+ * (C) 2016 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/sim/sim.h>
+#include <osmocom/sim/class_tables.h>
+
+#include "apdu_dispatch.h"
+
+/*! \brief Has the command-data phase been completed yet? */
+static inline bool is_dc_complete(struct apdu_context *ac)
+{
+	return (ac->lc.tot == ac->lc.cur);
+}
+
+/*! \brief Has the expected-data phase been completed yet? */
+static inline bool is_de_complete(struct apdu_context *ac)
+{
+	return (ac->le.tot == ac->le.cur);
+}
+
+static const char *dump_apdu_hdr(const struct osim_apdu_cmd_hdr *h)
+{
+	static char buf[256];
+	sprintf(buf, "CLA=%02x INS=%02x P1=%02x P2=%02x P3=%02x",
+		h->cla, h->ins, h->p1, h->p2, h->p3);
+
+	return buf;
+}
+
+static void dump_apdu_ctx(const struct apdu_context *ac)
+{
+	printf("%s; case=%d, lc=%d(%d), le=%d(%d)\n",
+		dump_apdu_hdr(&ac->hdr), ac->apdu_case,
+		ac->lc.tot, ac->lc.cur,
+		ac->le.tot, ac->le.cur);
+}
+
+/*! \brief input function for APDU segmentation
+ *  \param ac APDU context accross successive calls
+ *  \param[in] apdu_buf APDU inpud data buffer
+ *  \param[in] apdu_len Length of apdu_buf
+ *  \param[in] new_apdu Is this the beginning of a new APDU?
+ *
+ *  The function returns APDU_ACT_TX_CAPDU_TO_CARD once there is
+ *  sufficient data of the APDU received to transmit the command-APDU to
+ *  the actual card.
+ *
+ *  The function retunrs APDU_ACT_RX_MORE_CAPDU_FROM_READER when there
+ *  is more data to be received from the card reader (GSM Phone).
+ */
+int apdu_segment_in(struct apdu_context *ac, const uint8_t *apdu_buf,
+		    unsigned int apdu_len, bool new_apdu)
+{
+	int rc = 0;
+
+	if (new_apdu) {
+		/* initialize the apdu context structure */
+		memset(ac, 0, sizeof(*ac));
+		/* copy APDU header over */
+		memcpy(&ac->hdr, apdu_buf, sizeof(ac->hdr));
+		ac->apdu_case = osim_determine_apdu_case(&osim_uicc_sim_cic_profile, apdu_buf);
+		switch (ac->apdu_case) {
+		case 1: /* P3 == 0, No Lc/Le */
+			ac->le.tot = ac->lc.tot = 0;
+			break;
+		case 2: /* P3 == Le */
+			ac->le.tot = ac->hdr.p3;
+			break;
+		case 3: /* P3 = Lc */
+			ac->lc.tot = ac->hdr.p3;
+			/* copy Dc */
+			ac->lc.cur = apdu_len - sizeof(ac->hdr);
+			memcpy(ac->dc, apdu_buf + sizeof(ac->hdr),
+				ac->lc.cur);
+			break;
+		case 4: /* P3 = Lc; SW with Le */
+			ac->lc.tot = ac->hdr.p3;
+			/* copy Dc */
+			ac->lc.cur = apdu_len - sizeof(ac->hdr);
+			memcpy(ac->dc, apdu_buf + sizeof(ac->hdr),
+				ac->lc.cur);
+			break;
+		case 0:
+		default:
+			fprintf(stderr, "Unknown APDU case %d\n", ac->apdu_case);
+			return -1;
+		}
+	} else {
+		/* copy more data, if available */
+		int cpy_len;
+		switch (ac->apdu_case) {
+		case 1:
+		case 2:
+			break;
+		case 3:
+		case 4:
+			cpy_len = ac->lc.tot - ac->lc.cur;
+			if (cpy_len > apdu_len)
+				cpy_len = apdu_len;
+			memcpy(ac->dc+ac->lc.cur, apdu_buf, cpy_len);
+			ac->lc.cur += cpy_len;
+			break;
+		default:
+			fprintf(stderr, "Unknown APDU case %d\n", ac->apdu_case);
+			break;
+		}
+	}
+
+	/* take some decisions... */
+	switch (ac->apdu_case) {
+	case 1: /* P3 == 0, No Lc/Le */
+		/* send C-APDU to card */
+		/* receive SW from card, forward to reader */
+		rc |= APDU_ACT_TX_CAPDU_TO_CARD;
+		break;
+	case 2: /* P3 == Le */
+		/* send C-APDU to card */
+		/* receive Le bytes + SW from card, forward to reader */
+		rc |= APDU_ACT_TX_CAPDU_TO_CARD;
+		break;
+	case 3: /* P3 = Lc */
+		if (!is_dc_complete(ac)) {
+			/* send PB + read further Lc bytes from reader */
+			rc |= APDU_ACT_RX_MORE_CAPDU_FROM_READER;
+		} else {
+			/* send C-APDU to card */
+			/* receive SW from card, forward to reader */
+			rc |= APDU_ACT_TX_CAPDU_TO_CARD;
+		}
+		break;
+	case 4: /* P3 = Lc; SW with Le */
+		if (!is_dc_complete(ac)) {
+			/* send PB + read further Lc bytes from reader */
+			rc |= APDU_ACT_RX_MORE_CAPDU_FROM_READER;
+		} else {
+			/* send C-APDU to card */
+			/* receive SW from card, forward to reader */
+			rc |= APDU_ACT_TX_CAPDU_TO_CARD;
+		}
+		break;
+	case 0:
+	default:
+		fprintf(stderr, "Unknown APDU case %d\n", ac->apdu_case);
+		break;
+	}
+
+	dump_apdu_ctx(ac);
+
+	return rc;
+}
diff --git a/src/apdu_dispatch.h b/src/apdu_dispatch.h
new file mode 100644
index 0000000..2c99858
--- /dev/null
+++ b/src/apdu_dispatch.h
@@ -0,0 +1,49 @@
+/* apdu_dispatch - State machine to determine Rx/Tx phases of APDU
+ *
+ * (C) 2016 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <osmocom/sim/sim.h>
+
+struct apdu_context {
+	struct osim_apdu_cmd_hdr hdr;
+	uint8_t dc[256];
+	uint8_t de[256];
+	uint8_t sw[2];
+	uint8_t apdu_case;
+	struct {
+		uint8_t tot;
+		uint8_t cur;
+	} lc;
+	struct {
+		uint8_t tot;
+		uint8_t cur;
+	} le;
+};
+
+enum apdu_action {
+	APDU_ACT_TX_CAPDU_TO_CARD		= 0x0001,
+	APDU_ACT_RX_MORE_CAPDU_FROM_READER	= 0x0002,
+};
+
+
+int apdu_segment_in(struct apdu_context *ac, const uint8_t *apdu_buf,
+		    unsigned int apdu_len, bool new_apdu);
diff --git a/src/libusb_util.c b/src/libusb_util.c
new file mode 100644
index 0000000..cb435e2
--- /dev/null
+++ b/src/libusb_util.c
@@ -0,0 +1,297 @@
+/* libisb utilities
+ * 
+ * (C) 2010-2016 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <libusb.h>
+
+#include "libusb_util.h"
+
+static char path_buf[USB_MAX_PATH_LEN];
+
+static char *get_path(libusb_device *dev)
+{
+#if (defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102) || (defined(LIBUSBX_API_VERSION) && LIBUSBX_API_VERSION >= 0x01000102)
+	uint8_t path[8];
+	int r,j;
+	r = libusb_get_port_numbers(dev, path, sizeof(path));
+	if (r > 0) {
+		sprintf(path_buf,"%d-%d",libusb_get_bus_number(dev),path[0]);
+		for (j = 1; j < r; j++){
+			sprintf(path_buf+strlen(path_buf),".%d",path[j]);
+		};
+	}
+	return path_buf;
+#else
+# warning "libusb too old - building without USB path support!"
+	return NULL;
+#endif
+}
+
+static int match_dev_id(const struct libusb_device_descriptor *desc, const struct dev_id *id)
+{
+	if ((desc->idVendor == id->vendor_id) && (desc->idProduct == id->product_id))
+		return 1;
+	return 0;
+}
+
+
+static int match_dev_ids(const struct libusb_device_descriptor *desc, const struct dev_id *ids)
+{
+	const struct dev_id *id;
+
+	for (id = ids; id->vendor_id || id->product_id; id++) {
+		if (match_dev_id(desc, id))
+			return 1;
+	}
+	return 0;
+}
+
+libusb_device **find_matching_usb_devs(const struct dev_id *dev_ids)
+{
+	libusb_device **list;
+	libusb_device **out = calloc(256, sizeof(libusb_device *));
+	libusb_device **cur = out;
+	unsigned int i;
+	int rc;
+
+	if (!out)
+		return NULL;
+
+	rc = libusb_get_device_list(NULL, &list);
+	if (rc <= 0) {
+		perror("No USB devices found");
+		free(out);
+		return NULL;
+	}
+
+	for (i = 0; list[i] != NULL; i++) {
+		struct libusb_device_descriptor dev_desc;
+		libusb_device *dev = list[i];
+
+		rc = libusb_get_device_descriptor(dev, &dev_desc);
+		if (rc < 0) {
+			perror("Couldn't get device descriptor\n");
+			libusb_unref_device(dev);
+			continue;
+		}
+
+		if (match_dev_ids(&dev_desc, dev_ids)) {
+			*cur = dev;
+			cur++;
+			/* FIXME: overflow check */
+		} else
+			libusb_unref_device(dev);
+	}
+	if (cur == out) {
+		libusb_free_device_list(list, 1);
+		free(out);
+		return NULL;
+	}
+
+	libusb_free_device_list(list, 0);
+	return out;
+}
+
+int dev_find_matching_interfaces(libusb_device *dev, int class, int sub_class, int protocol,
+				 struct usb_interface_match *out, unsigned int out_len)
+{
+	struct libusb_device_descriptor dev_desc;
+	int rc, i, out_idx = 0;
+	uint8_t addr;
+	char *path;
+
+	rc = libusb_get_device_descriptor(dev, &dev_desc);
+	if (rc < 0) {
+		perror("Couldn't get device descriptor\n");
+		return -EIO;
+	}
+
+	addr = libusb_get_device_address(dev);
+	path = get_path(dev);
+
+	/* iterate over all configurations */
+	for (i = 0; i < dev_desc.bNumConfigurations; i++) {
+		struct libusb_config_descriptor *conf_desc;
+		int j;
+
+		rc = libusb_get_config_descriptor(dev, i, &conf_desc);
+		if (rc < 0) {
+			fprintf(stderr, "Couldn't get config descriptor %u\n", i);
+			continue;
+		}
+		/* iterate over all interfaces */
+		for (j = 0; j < conf_desc->bNumInterfaces; j++) {
+			const struct libusb_interface *intf = &conf_desc->interface[j];
+			int k;
+			/* iterate over all alternate settings */
+			for (k = 0; k < intf->num_altsetting; k++) {
+				const struct libusb_interface_descriptor *if_desc;
+				if_desc = &intf->altsetting[k];
+				if (class >= 0 && if_desc->bInterfaceClass != class)
+					continue;
+				if (sub_class >= 0 && if_desc->bInterfaceSubClass != sub_class)
+					continue;
+				if (protocol >= 0 && if_desc->bInterfaceProtocol != protocol)
+					continue;
+				/* MATCH! */
+				out[out_idx].usb_dev = dev;
+				out[out_idx].vendor = dev_desc.idVendor;
+				out[out_idx].product = dev_desc.idProduct;
+				out[out_idx].addr = addr;
+				strncpy(out[out_idx].path, path, sizeof(out[out_idx].path));
+				out[out_idx].path[sizeof(out[out_idx].path)-1] = '\0';
+				out[out_idx].configuration = conf_desc->bConfigurationValue;
+				out[out_idx].interface = if_desc->bInterfaceNumber;
+				out[out_idx].altsetting = if_desc->bAlternateSetting;
+				out[out_idx].class = if_desc->bInterfaceClass;
+				out[out_idx].sub_class = if_desc->bInterfaceSubClass;
+				out[out_idx].protocol = if_desc->bInterfaceProtocol;
+				out[out_idx].string_idx = if_desc->iInterface;
+				out_idx++;
+				if (out_idx >= out_len)
+					return out_idx;
+			}
+		}
+	}
+	return out_idx;
+}
+
+int usb_match_interfaces(libusb_context *ctx, const struct dev_id *dev_ids,
+			 int class, int sub_class, int protocol,
+			 struct usb_interface_match *out, unsigned int out_len)
+{
+	struct usb_interface_match *out_cur = out;
+	unsigned int out_len_remain = out_len;
+	libusb_device **list;
+	libusb_device **dev;
+
+	list = find_matching_usb_devs(dev_ids);
+	if (!list)
+		return 0;
+
+	for (dev = list; *dev; dev++) {
+		int rc;
+
+#if 0
+		struct libusb_device_descriptor dev_desc;
+		uint8_t ports[8];
+		uint8_t addr;
+		rc = libusb_get_device_descriptor(*dev, &dev_desc);
+		if (rc < 0) {
+			perror("Cannot get device descriptor");
+			continue;
+		}
+
+		addr = libusb_get_device_address(*dev);
+
+		rc = libusb_get_port_numbers(*dev, ports, sizeof(ports));
+		if (rc < 0) {
+			perror("Cannot get device path");
+			continue;
+		}
+
+		printf("Found USB Device %04x:%04x at address %d\n",
+			dev_desc.idVendor, dev_desc.idProduct, addr);
+#endif
+
+		rc = dev_find_matching_interfaces(*dev, class, sub_class, protocol, out_cur, out_len_remain);
+		if (rc < 0)
+			continue;
+		out_cur += rc;
+		out_len_remain -= rc;
+
+	}
+	return out_len - out_len_remain;
+}
+
+libusb_device_handle *usb_open_claim_interface(libusb_context *ctx,
+					       const struct usb_interface_match *ifm)
+{
+	int rc, config;
+	struct dev_id dev_ids[] = { { ifm->vendor, ifm->product }, { 0, 0 } };
+	libusb_device **list;
+	libusb_device **dev;
+	libusb_device_handle *usb_devh = NULL;
+
+	list = find_matching_usb_devs(dev_ids);
+	if (!list) {
+		perror("No USB device with matching VID/PID");
+		return NULL;
+	}
+
+	for (dev = list; *dev; dev++) {
+		int addr;
+		char *path;
+
+		addr = libusb_get_device_address(*dev);
+		path = get_path(*dev);
+		if ((ifm->addr && addr == ifm->addr) ||
+		    (strlen(ifm->path) && !strcmp(path, ifm->path))) {
+			rc = libusb_open(*dev, &usb_devh);
+			if (rc < 0) {
+				fprintf(stderr, "Cannot open device: %s\n", libusb_error_name(rc));
+				usb_devh = NULL;
+				break;
+			}
+			rc = libusb_get_configuration(usb_devh, &config);
+			if (rc < 0) {
+				fprintf(stderr, "Cannot get current configuration: %s\n", libusb_error_name(rc));
+				libusb_close(usb_devh);
+				usb_devh = NULL;
+				break;
+			}
+			if (config != ifm->configuration) {
+				rc = libusb_set_configuration(usb_devh, ifm->configuration);
+				if (rc < 0) {
+					fprintf(stderr, "Cannot set configuration: %s\n", libusb_error_name(rc));
+					libusb_close(usb_devh);
+					usb_devh = NULL;
+					break;
+				}
+			}
+			rc = libusb_claim_interface(usb_devh, ifm->interface);
+			if (rc < 0) {
+				fprintf(stderr, "Cannot claim interface: %s\n", libusb_error_name(rc));
+				libusb_close(usb_devh);
+				usb_devh = NULL;
+				break;
+			}
+			rc = libusb_set_interface_alt_setting(usb_devh, ifm->interface, ifm->altsetting);
+			if (rc < 0) {
+				fprintf(stderr, "Cannot set interface altsetting: %s\n", libusb_error_name(rc));
+				libusb_release_interface(usb_devh, ifm->interface);
+				libusb_close(usb_devh);
+				usb_devh = NULL;
+				break;
+			}
+		}
+	}
+
+	/* unref / free list */
+	for (dev = list; *dev; dev++)
+		libusb_unref_device(*dev);
+	free(list);
+
+	return usb_devh;
+}
diff --git a/src/libusb_util.h b/src/libusb_util.h
new file mode 100644
index 0000000..2b2d92e
--- /dev/null
+++ b/src/libusb_util.h
@@ -0,0 +1,70 @@
+/* libisb utilities
+ * 
+ * (C) 2010-2016 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#pragma once
+
+#include <libusb.h>
+
+#define USB_MAX_PATH_LEN 20
+
+struct dev_id {
+	uint16_t vendor_id;
+	uint16_t product_id;
+};
+
+/* Find any USB devices in the system matching the given Vendor and
+ * Product ID */
+libusb_device **find_matching_usb_devs(const struct dev_id *dev_ids);
+
+/* structure describing a single matching interface found */
+struct usb_interface_match {
+	/* libusb device E*/
+	libusb_device *usb_dev;
+	/* Vendor ID of the device running matching interface */
+	uint16_t vendor;
+	/* Product ID of the device running matching interface */
+	uint16_t product;
+	/* USB Bus Address */
+	uint8_t addr;
+	/* physical path */
+	char path[USB_MAX_PATH_LEN];
+	/* configuration of matching interface */
+	uint8_t configuration;
+	/* interface number of matching interface */
+	uint8_t interface;
+	/* altsetting of matching interface */
+	uint8_t altsetting;
+	/* bInterfaceClass of matching interface */
+	uint8_t class;
+	/* bInterfaceSubClass of matching interface */
+	uint8_t sub_class;
+	/* bInterfaceProtocol of matching interface */
+	uint8_t protocol;
+	/* index of string descriptor of matching interface */
+	uint8_t string_idx;
+};
+
+int dev_find_matching_interfaces(libusb_device *dev, int class, int sub_class, int protocol,
+				 struct usb_interface_match *out, unsigned int out_len);
+
+int usb_match_interfaces(libusb_context *ctx, const struct dev_id *dev_ids,
+			 int class, int sub_class, int protocol,
+			 struct usb_interface_match *out, unsigned int out_len);
+
+libusb_device_handle *usb_open_claim_interface(libusb_context *ctx,
+					       const struct usb_interface_match *ifm);
diff --git a/src/simtrace.h b/src/simtrace.h
new file mode 100644
index 0000000..c4a20da
--- /dev/null
+++ b/src/simtrace.h
@@ -0,0 +1,7 @@
+#ifndef _SIMTRACE_H
+#define _SIMTRACE_H
+
+#define SIMTRACE_USB_VENDOR	0x1d50
+#define SIMTRACE_USB_PRODUCT	0x60e3
+
+#endif
diff --git a/src/simtrace2-discovery.c b/src/simtrace2-discovery.c
new file mode 100644
index 0000000..a7306ce
--- /dev/null
+++ b/src/simtrace2-discovery.c
@@ -0,0 +1,94 @@
+/* simtrace2-discovery - host PC library to scan for matching USB
+ * devices
+ *
+ * (C) 2016 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#include <stdint.h>
+
+#include <libusb.h>
+
+/*! \brief obtain the endpoint addresses for a given USB interface */
+int get_usb_ep_addrs(libusb_device_handle *devh, unsigned int if_num,
+		     uint8_t *out, uint8_t *in, uint8_t *irq)
+{
+	libusb_device *dev = libusb_get_device(devh);
+	struct libusb_config_descriptor *cdesc;
+	const struct libusb_interface_descriptor *idesc;
+	const struct libusb_interface *iface;
+	int rc, l;
+
+	rc = libusb_get_active_config_descriptor(dev, &cdesc);
+	if (rc < 0)
+		return rc;
+
+	iface = &cdesc->interface[if_num];
+	/* FIXME: we assume there's no altsetting */
+	idesc = &iface->altsetting[0];
+
+	for (l = 0; l < idesc->bNumEndpoints; l++) {
+		const struct libusb_endpoint_descriptor *edesc = &idesc->endpoint[l];
+		switch (edesc->bmAttributes & 3) {
+		case LIBUSB_TRANSFER_TYPE_BULK:
+			if (edesc->bEndpointAddress & 0x80) {
+				if (in)
+					*in = edesc->bEndpointAddress;
+			} else {
+				if (out)
+					*out = edesc->bEndpointAddress;
+			}
+			break;
+		case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+			if (irq)
+				*irq = edesc->bEndpointAddress;
+			break;
+		default:
+			break;
+		}
+	}
+	return 0;
+}
+
+#if 0
+	struct libusb_device_descriptor ddesc;
+	int rc, i, j, k;
+
+	rc = libusb_get_device_descriptor(devh, &ddesc);
+	if (rc < 0)
+		return;
+
+	for (i = 0; i < ddesc.bNumConfigurations; i++) {
+		struct libusb_config_descriptor *cdesc;
+		rc = libusb_get_config_descriptor(devh, i, &cdesc);
+		if (rc < 0)
+			return;
+
+		for (j = 0; j < cdesc->bNumInterfaces; j++) {
+			const struct libusb_interface *iface = cdesc->interface[j];
+			for (k = 0; k < iface->num_altsetting; k++) {
+				const struct libusb_interface_descriptor *idesc = iface->altsetting[k];
+				/* make sure this is the interface we're looking for */
+				if (idesc->bInterfaceClass != 0xFF ||
+				    idesc->bInterfaceSubClass != if_class ||
+				    idsec->bInterfaceProtocol != if_proto)
+					continue;
+				/* FIXME */
+			}
+		}
+
+		libusb_free_config_descriptor(cdesc);
+	}
+#endif
diff --git a/src/simtrace2-discovery.h b/src/simtrace2-discovery.h
new file mode 100644
index 0000000..cfba956
--- /dev/null
+++ b/src/simtrace2-discovery.h
@@ -0,0 +1,26 @@
+/* simtrace2-discovery - host PC library to scan for matching USB
+ * devices
+ * 
+ * (C) 2016 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#pragma once
+
+#include <stdint.h>
+#include <libusb.h>
+
+int get_usb_ep_addrs(libusb_device_handle *devh, unsigned int if_num,
+		     uint8_t *out, uint8_t *in, uint8_t *irq);
diff --git a/src/simtrace_prot.h b/src/simtrace_prot.h
new file mode 100644
index 0000000..878bc34
--- /dev/null
+++ b/src/simtrace_prot.h
@@ -0,0 +1,322 @@
+/* SIMtrace2 USB protocol
+ *
+ * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
+ * (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA
+ */
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/***********************************************************************
+ * COMMON HEADER
+ ***********************************************************************/
+
+enum simtrace_msg_class {
+	SIMTRACE_MSGC_GENERIC = 0,
+	/* Card Emulation / Forwarding */
+	SIMTRACE_MSGC_CARDEM,
+	/* Modem Control (if modem is attached next to device) */
+	SIMTRACE_MSGC_MODEM,
+	/* Reader/phone-car/SIM communication sniff */
+	SIMTRACE_MSGC_SNIFF,
+
+	/* first vendor-specific request */
+	_SIMTRACE_MGSC_VENDOR_FIRST = 127,
+};
+
+enum simtrace_msg_type_generic {
+	/* Generic Error Message */
+	SIMTRACE_CMD_DO_ERROR	= 0,
+	/* Request/Response for simtrace_board_info */
+	SIMTRACE_CMD_BD_BOARD_INFO,
+};
+
+/* SIMTRACE_MSGC_CARDEM */
+enum simtrace_msg_type_cardem {
+	/* TPDU Data to be transmitted to phone */
+	SIMTRACE_MSGT_DT_CEMU_TX_DATA = 1,
+	/* Set the ATR to be returned at phone-SIM reset */
+	SIMTRACE_MSGT_DT_CEMU_SET_ATR,
+	/* Get Statistics Request / Response */
+	SIMTRACE_MSGT_BD_CEMU_STATS,
+	/* Get Status Request / Response */
+	SIMTRACE_MSGT_BD_CEMU_STATUS,
+	/* Request / Confirm emulated card insert */
+	SIMTRACE_MSGT_DT_CEMU_CARDINSERT,
+	/* TPDU Data received from phomne */
+	SIMTRACE_MSGT_DO_CEMU_RX_DATA,
+	/* Indicate PTS request from phone */
+	SIMTRACE_MSGT_DO_CEMU_PTS,
+};
+
+/* SIMTRACE_MSGC_MODEM */
+enum simtrace_msg_type_modem {
+	/* Modem Control: Reset an attached modem */
+	SIMTRACE_MSGT_DT_MODEM_RESET = 1,
+	/* Modem Control: Select local / remote SIM */
+	SIMTRACE_MSGT_DT_MODEM_SIM_SELECT,
+	/* Modem Control: Status (WWAN LED, SIM Presence) */
+	SIMTRACE_MSGT_BD_MODEM_STATUS,
+};
+
+/* SIMTRACE_MSGC_SNIFF */
+enum simtrace_msg_type_sniff {
+	/* Status change (card inserted, reset, ...) */
+	SIMTRACE_MSGT_SNIFF_CHANGE = 0,
+	/* Fi/Di baudrate change */
+	SIMTRACE_MSGT_SNIFF_FIDI,
+	/* ATR data */
+	SIMTRACE_MSGT_SNIFF_ATR,
+	/* PPS (request or response) data */
+	SIMTRACE_MSGT_SNIFF_PPS,
+	/* TPDU data */
+	SIMTRACE_MSGT_SNIFF_TPDU,
+};
+
+/* common message header */
+struct simtrace_msg_hdr {
+	uint8_t msg_class;	/* simtrace_msg_class */
+	uint8_t msg_type;	/* simtrace_msg_type_xxx */
+	uint8_t seq_nr;
+	uint8_t slot_nr;	/* SIM slot number */
+	uint16_t _reserved;
+	uint16_t msg_len;	/* length including header */
+	uint8_t payload[0];
+} __attribute__ ((packed));
+
+/***********************************************************************
+ * Capabilities
+ ***********************************************************************/
+
+/* generic capabilities */
+enum simtrace_capability_generic {
+	/* compatible with 5V SIM card interface */
+	SIMTRACE_CAP_VOLT_5V,
+	/* compatible with 3.3V SIM card interface */
+	SIMTRACE_CAP_VOLT_3V3,
+	/* compatible with 1.8V SIM card interface */
+	SIMTRACE_CAP_VOLT_1V8,
+	/* Has LED1 */
+	SIMTRACE_CAP_LED_1,
+	/* Has LED2 */
+	SIMTRACE_CAP_LED_2,
+	/* Has Single-Pole Dual-Throw (local/remote SIM) */
+	SIMTRACE_CAP_SPDT,
+	/* Has Bus-Switch (trace / MITM) */
+	SIMTRACE_CAP_BUS_SWITCH,
+	/* Can read VSIM via ADC */
+	SIMTRACE_CAP_VSIM_ADC,
+	/* Can read temperature via ADC */
+	SIMTRACE_CAP_TEMP_ADC,
+	/* Supports DFU for firmware update */
+	SIMTRACE_CAP_DFU,
+	/* Supports Ctrl EP command for erasing flash / return to SAM-BA */
+	SIMTRACE_CAP_ERASE_FLASH,
+	/* Can read the status of card insert contact */
+	SIMTRACE_CAP_READ_CARD_DET,
+	/* Can control the status of a simulated card insert */
+	SIMTRACE_CAP_ASSERT_CARD_DET,
+	/* Can toggle the hardware reset of an attached modem */
+	SIMTRACE_CAP_ASSERT_MODEM_RST,
+};
+
+/* vendor-specific capabilities of sysmocom devices */
+enum simtrace_capability_vendor {
+	/* Can erase a peer SAM3 controller */
+	SIMTRACE_CAP_SYSMO_QMOD_ERASE_PEER,
+	/* Can read/write an attached EEPROM */
+	SIMTRACE_CAP_SYSMO_QMOD_RW_EEPROM,
+	/* can reset an attached USB hub */
+	SIMTRACE_CAP_SYSMO_QMOD_RESET_HUB,
+};
+
+/* SIMTRACE_CMD_BD_BOARD_INFO */
+struct simtrace_board_info {
+	struct {
+		char manufacturer[32];
+		char model[32];
+		char version[32];
+	} hardware;
+	struct {
+		/* who provided this software? */
+		char provider[32];
+		/* name of software image */
+		char name[32];
+		/* (git) version at build time */
+		char version[32];
+		/* built on which machine? */
+		char buildhost[32];
+		/* CRC-32 over software image */
+		uint32_t crc;
+	} software;
+	struct {
+		/* Maximum baud rate supported */
+		uint32_t max_baud_rate;
+	} speed;
+	/* number of bytes of generic capability bit-mask */
+	uint8_t cap_generic_bytes;
+	/* number of bytes of vendor capability bit-mask */
+	uint8_t cap_vendor_bytes;
+	uint8_t data[0];
+	/* cap_generic + cap_vendor */
+} __attribute__ ((packed));
+
+/***********************************************************************
+ * CARD EMULATOR / FORWARDER
+ ***********************************************************************/
+
+/* indicates a TPDU header is present in this message */
+#define CEMU_DATA_F_TPDU_HDR	0x00000001
+/* indicates last part of transmission in this direction */
+#define CEMU_DATA_F_FINAL	0x00000002
+/* incdicates a PB is present and we should continue with TX */
+#define CEMU_DATA_F_PB_AND_TX	0x00000004
+/* incdicates a PB is present and we should continue with RX */
+#define CEMU_DATA_F_PB_AND_RX	0x00000008
+
+/* CEMU_USB_MSGT_DT_CARDINSERT */
+struct cardemu_usb_msg_cardinsert {
+	uint8_t card_insert;
+} __attribute__ ((packed));
+
+/* CEMU_USB_MSGT_DT_SET_ATR */
+struct cardemu_usb_msg_set_atr {
+	uint8_t atr_len;
+	/* variable-length ATR data */
+	uint8_t atr[0];
+} __attribute__ ((packed));
+
+/* CEMU_USB_MSGT_DT_TX_DATA */
+struct cardemu_usb_msg_tx_data {
+	uint32_t flags;
+	uint16_t data_len;
+	/* variable-length TPDU data */
+	uint8_t data[0];
+} __attribute__ ((packed));
+
+/* CEMU_USB_MSGT_DO_RX_DATA */
+struct cardemu_usb_msg_rx_data {
+	uint32_t flags;
+	uint16_t data_len;
+	/* variable-length TPDU data */
+	uint8_t data[0];
+} __attribute__ ((packed));
+
+#define CEMU_STATUS_F_VCC_PRESENT	0x00000001
+#define CEMU_STATUS_F_CLK_ACTIVE	0x00000002
+#define CEMU_STATUS_F_RCEMU_ACTIVE	0x00000004
+#define CEMU_STATUS_F_CARD_INSERT	0x00000008
+#define CEMU_STATUS_F_RESET_ACTIVE	0x00000010
+
+/* CEMU_USB_MSGT_DO_STATUS */
+struct cardemu_usb_msg_status {
+	uint32_t flags;
+	/* phone-applied target voltage in mV */
+	uint16_t voltage_mv;
+	/* Fi/Di related information */
+	uint8_t fi;
+	uint8_t di;
+	uint8_t wi;
+	uint32_t waiting_time;
+} __attribute__ ((packed));
+
+/* CEMU_USB_MSGT_DO_PTS */
+struct cardemu_usb_msg_pts_info {
+	uint8_t pts_len;
+	/* PTS request as sent from reader */
+	uint8_t req[6];
+	/* PTS response as sent by card */
+	uint8_t resp[6];
+} __attribute__ ((packed));
+
+/* CEMU_USB_MSGT_DO_ERROR */
+struct cardemu_usb_msg_error {
+	uint8_t severity;
+	uint8_t subsystem;
+	uint16_t code;
+	uint8_t msg_len;
+	/* human-readable error message */
+	uint8_t msg[0];
+} __attribute__ ((packed));
+
+/***********************************************************************
+ * MODEM CONTROL
+ ***********************************************************************/
+
+/* SIMTRACE_MSGT_DT_MODEM_RESET */
+struct st_modem_reset {
+	/* 0: de-assert reset, 1: assert reset, 2: pulse reset */
+	uint8_t asserted;
+	/* if above is '2', duration of pulse in ms */
+	uint16_t pulse_duration_msec;
+} __attribute__((packed));
+
+/* SIMTRACE_MSGT_DT_MODEM_SIM_SELECT */
+struct st_modem_sim_select {
+	/* remote (1), local (0) */
+	uint8_t remote_sim;
+} __attribute__((packed));
+
+/* SIMTRACE_MSGT_BD_MODEM_STATUS */
+#define ST_MDM_STS_BIT_WWAN_LED		(1 << 0)
+#define ST_MDM_STS_BIT_CARD_INSERTED	(1 << 1)
+struct st_modem_status {
+	/* bit-field of supported status bits */
+	uint8_t supported_mask;
+	/* bit-field of current status bits */
+	uint8_t status_mask;
+	/* bit-field of changed status bits */
+	uint8_t changed_mask;
+} __attribute__((packed));
+
+/***********************************************************************
+ * SNIFF
+ ***********************************************************************/
+
+/* SIMTRACE_MSGT_SNIFF_CHANGE flags */
+#define SNIFF_CHANGE_FLAG_CARD_INSERT (1<<0)
+#define SNIFF_CHANGE_FLAG_CARD_EJECT (1<<1)
+#define SNIFF_CHANGE_FLAG_RESET_ASSERT (1<<2)
+#define SNIFF_CHANGE_FLAG_RESET_DEASSERT (1<<3)
+#define SNIFF_CHANGE_FLAG_TIMEOUT_WT (1<<4)
+/* SIMTRACE_MSGT_SNIFF_ATR, SIMTRACE_MSGT_SNIFF_PPS, SIMTRACE_MSGT_SNIFF_TPDU flags */
+#define SNIFF_DATA_FLAG_ERROR_INCOMPLETE (1<<5)
+#define SNIFF_DATA_FLAG_ERROR_MALFORMED (1<<6)
+#define SNIFF_DATA_FLAG_ERROR_CHECKSUM (1<<7)
+
+/* SIMTRACE_MSGT_SNIFF_CHANGE */
+struct sniff_change {
+	/* SIMTRACE_MSGT_SNIFF_CHANGE flags */
+	uint32_t flags;
+} __attribute__ ((packed));
+
+/* SIMTRACE_MSGT_SNIFF_FIDI */
+struct sniff_fidi {
+	/* Fi/Di values as encoded in TA1 */
+	uint8_t fidi;
+} __attribute__ ((packed));
+
+/* SIMTRACE_MSGT_SNIFF_ATR, SIMTRACE_MSGT_SNIFF_PPS, SIMTRACE_MSGT_SNIFF_TPDU */
+struct sniff_data {
+	/* data flags */
+	uint32_t flags;
+	/* data length */
+	uint16_t length;
+	/* data */
+	uint8_t data[0];
+} __attribute__ ((packed));
diff --git a/src/simtrace_usb.h b/src/simtrace_usb.h
new file mode 100644
index 0000000..c0da9c5
--- /dev/null
+++ b/src/simtrace_usb.h
@@ -0,0 +1,67 @@
+/* SIMtrace 2 USB definitions
+ *
+ * (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA
+ */
+/* SIMtrace USB IDs */
+#define USB_VENDOR_OPENMOKO			0x1d50
+#define USB_PRODUCT_OWHW_SAM3_DFU	0x4001	/* was 0x4000 */
+#define USB_PRODUCT_OWHW_SAM3		0x4001
+#define USB_PRODUCT_QMOD_HUB		0x4002
+#define USB_PRODUCT_QMOD_SAM3_DFU	0x4004	/* was 0x4003 */
+#define USB_PRODUCT_QMOD_SAM3		0x4004
+#define USB_PRODUCT_SIMTRACE2_DFU	0x60e3	/* was 0x60e2 */
+#define USB_PRODUCT_SIMTRACE2		0x60e3
+
+/* USB proprietary class */
+#define USB_CLASS_PROPRIETARY			0xff
+
+/* SIMtrace USB sub-classes */
+/*! Sniffer USB sub-class */
+#define SIMTRACE_SNIFFER_USB_SUBCLASS	1
+/*! Card-emulation USB sub-class */
+#define SIMTRACE_CARDEM_USB_SUBCLASS	2
+
+/* Generic USB endpoint numbers */
+/*! Card-side USB data out (host to device) endpoint number */
+#define SIMTRACE_USB_EP_CARD_DATAOUT	1
+/*! Card-side USB data in (device to host) endpoint number */
+#define SIMTRACE_USB_EP_CARD_DATAIN		2
+/*! Card-side USB interrupt endpoint number */
+#define SIMTRACE_USB_EP_CARD_INT		3
+/*! Phone-side USB data out (host to device) endpoint number */
+#define SIMTRACE_USB_EP_PHONE_DATAOUT	4
+/*! Phone-side USB data in (device to host) endpoint number */
+#define SIMTRACE_USB_EP_PHONE_DATAIN	5
+/*! Phone-side USB interrupt endpoint number */
+#define SIMTRACE_USB_EP_PHONE_INT		6
+
+/* Card-emulation USB endpoint numbers */
+/*! USIM1 USB data out (host to device) endpoint number */
+#define SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT	4
+/*! USIM1 USB data in (device to host) endpoint number */
+#define SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN		5
+/*! USIM1 USB interrupt endpoint number */
+#define SIMTRACE_CARDEM_USB_EP_USIM1_INT		6
+/*! USIM2 USB data out (host to device) endpoint number */
+#define SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT	1
+/*! USIM2 USB data in (device to host) endpoint number */
+#define SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN		2
+/*! USIM2 USB interrupt endpoint number */
+#define SIMTRACE_CARDEM_USB_EP_USIM2_INT		3
+
+/*! Maximum number of endpoints */
+#define BOARD_USB_NUMENDPOINTS		6