WIP: Introduce USB DFU code from my at91lib DFU port
diff --git a/firmware/Makefile b/firmware/Makefile
index e500bea..6092e8c 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -72,6 +72,7 @@
 
 AT91LIB_USB_COMMON_CORE_PATH = atmel_softpack_libraries/usb/common/core
 AT91LIB_USB_CORE_PATH = atmel_softpack_libraries/usb/device/core
+AT91LIB_USB_DFU_PATH = atmel_softpack_libraries/usb/device/dfu
 
 # Tool suffix when cross-compiling
 CROSS_COMPILE = arm-none-eabi-
@@ -91,7 +92,7 @@
 GIT_VERSION=$(shell $(TOP)/git-version-gen $(TOP)/.tarvers)
 
 # Flags
-INCLUDES_USB = -Iatmel_softpack_libraries/usb/include
+INCLUDES_USB = -Iatmel_softpack_libraries/usb/include -Iatmel_softpack_libraries
 
 INCLUDES  = -Iinclude_board -Iinclude_sam3s -Iinclude -Isrc_simtrace -Iinclude_libosmocore
 
@@ -139,13 +140,13 @@
 
 # Directories where source files can be found
 
-USB_PATHS = $(AT91LIB_USB_CORE_PATH) $(AT91LIB_USB_COMMON_CORE_PATH)
+USB_PATHS = $(AT91LIB_USB_CORE_PATH) $(AT91LIB_USB_DFU_PATH) $(AT91LIB_USB_COMMON_CORE_PATH)
 VPATH += src_board src_sam3s cmsis $(USB_PATHS) src_simtrace src_libosmocore
 
 # Objects built from C source files
 C_CMSIS    = core_cm3.o
 C_LOWLEVEL = board_cstartup_gnu.o board_lowlevel.o syscalls.o exceptions.o
-C_LIBLEVEL = spi.o pio.o pmc.o usart.o pio_it.o pio_capture.o uart_console.o iso7816_4.o wdt.o efc.o flashd.o led.o tc.o unique_id.o boardver_adc.o
+C_LIBLEVEL = spi.o pio.o pmc.o usart.o pio_it.o pio_capture.o uart_console.o iso7816_4.o wdt.o efc.o flashd.o led.o tc.o unique_id.o boardver_adc.o dfu_desc.o dfu_runtime.o
 C_CCID = cciddriver.o USBD.o USBDDriver.o USBD_HAL.o USBRequests.o USBDCallbacks.o USBDescriptors.o USBDDriverCallbacks.o
 C_SIMTRACE = simtrace_iso7816.o usb.o ccid.o sniffer.o mitm.o ringbuffer.o host_communication.o iso7816_fidi.o tc_etu.o req_ctx.o card_emu.o mode_cardemu.o i2c.o wwan_led.o wwan_perst.o
 C_OSMOCORE = timer.o rbtree.o
diff --git a/firmware/atmel_softpack_libraries/usb/common/dfu/usb_dfu.h b/firmware/atmel_softpack_libraries/usb/common/dfu/usb_dfu.h
new file mode 100644
index 0000000..d3acb09
--- /dev/null
+++ b/firmware/atmel_softpack_libraries/usb/common/dfu/usb_dfu.h
@@ -0,0 +1,81 @@
+#ifndef _USB_DFU_H
+#define _USB_DFU_H
+/* USB Device Firmware Update Implementation for OpenPCD
+ * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * Protocol definitions for USB DFU
+ *
+ * This ought to be compliant to the USB DFU Spec 1.0 as available from
+ * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf
+ *
+ */
+
+#include <stdint.h>
+
+#include <usb/include/USBRequests.h>
+
+#define USB_DT_DFU			0x21
+
+struct usb_dfu_func_descriptor {
+	uint8_t		bLength;
+	uint8_t		bDescriptorType;
+	uint8_t		bmAttributes;
+#define USB_DFU_CAN_DOWNLOAD	(1 << 0)
+#define USB_DFU_CAN_UPLOAD	(1 << 1)
+#define USB_DFU_MANIFEST_TOL	(1 << 2)
+#define USB_DFU_WILL_DETACH	(1 << 3)
+	uint16_t		wDetachTimeOut;
+	uint16_t		wTransferSize;
+	uint16_t		bcdDFUVersion;
+} __attribute__ ((packed));
+
+#define USB_DT_DFU_SIZE			9
+
+/* DFU class-specific requests (Section 3, DFU Rev 1.1) */
+#define USB_REQ_DFU_DETACH	0x00
+#define USB_REQ_DFU_DNLOAD	0x01
+#define USB_REQ_DFU_UPLOAD	0x02
+#define USB_REQ_DFU_GETSTATUS	0x03
+#define USB_REQ_DFU_CLRSTATUS	0x04
+#define USB_REQ_DFU_GETSTATE	0x05
+#define USB_REQ_DFU_ABORT	0x06
+
+struct dfu_status {
+	uint8_t bStatus;
+	uint8_t bwPollTimeout[3];
+	uint8_t bState;
+	uint8_t iString;
+} __attribute__((packed));
+
+#define DFU_STATUS_OK			0x00
+#define DFU_STATUS_errTARGET		0x01
+#define DFU_STATUS_errFILE		0x02
+#define DFU_STATUS_errWRITE		0x03
+#define DFU_STATUS_errERASE		0x04
+#define DFU_STATUS_errCHECK_ERASED	0x05
+#define DFU_STATUS_errPROG		0x06
+#define DFU_STATUS_errVERIFY		0x07
+#define DFU_STATUS_errADDRESS		0x08
+#define DFU_STATUS_errNOTDONE		0x09
+#define DFU_STATUS_errFIRMWARE		0x0a
+#define DFU_STATUS_errVENDOR		0x0b
+#define DFU_STATUS_errUSBR		0x0c
+#define DFU_STATUS_errPOR		0x0d
+#define DFU_STATUS_errUNKNOWN		0x0e
+#define DFU_STATUS_errSTALLEDPKT	0x0f
+
+enum dfu_state {
+	DFU_STATE_appIDLE		= 0,
+	DFU_STATE_appDETACH		= 1,
+	DFU_STATE_dfuIDLE		= 2,
+	DFU_STATE_dfuDNLOAD_SYNC	= 3,
+	DFU_STATE_dfuDNBUSY		= 4,
+	DFU_STATE_dfuDNLOAD_IDLE	= 5,
+	DFU_STATE_dfuMANIFEST_SYNC	= 6,
+	DFU_STATE_dfuMANIFEST		= 7,
+	DFU_STATE_dfuMANIFEST_WAIT_RST	= 8,
+	DFU_STATE_dfuUPLOAD_IDLE	= 9,
+	DFU_STATE_dfuERROR		= 10,
+};
+
+#endif /* _USB_DFU_H */
diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.c b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.c
new file mode 100644
index 0000000..bc6b29c
--- /dev/null
+++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.c
@@ -0,0 +1,49 @@
+
+#include <usb/include/USBDescriptors.h>
+#include <usb/device/dfu/dfu.h>
+
+
+/* String 1 "SimTrace DFU Interface - Application Partition" */
+const struct USBStringDescriptor USBDFU_string1 = {
+	.hdr = {
+		.bLength = sizeof(USBGenericDescriptor) + 46 * sizeof(unsigned short),
+		.bDescriptorType = USBGenericDescriptor_STRING,
+	},
+	.wData = {	0x0053, 0x0069, 0x006d, 0x0054, 0x0072, 0x0061,
+			0x0063, 0x0065, 0x0020, 0x0044, 0x0046, 0x0055,
+			0x0020, 0x0049, 0x006e, 0x0074, 0x0065, 0x0072,
+			0x0066, 0x0061, 0x0063, 0x0065, 0x0020, 0x002d,
+			0x0020, 0x0041, 0x0070, 0x0070, 0x006c, 0x0069,
+			0x0063, 0x0061, 0x0074, 0x0069, 0x006f, 0x006e,
+			0x0020, 0x0050, 0x0061, 0x0072, 0x0074, 0x0069,
+			0x0074, 0x0069, 0x006f, 0x006e, },
+};
+
+/* String 2 "SimTrace DFU Interface - Bootloader Partition" */
+const struct USBStringDescriptor USBDFU_string2 = {
+	.hdr = {
+		.bLength = sizeof(USBGenericDescriptor) + 45 * sizeof(unsigned short),
+		.bDescriptorType = USBGenericDescriptor_STRING,
+	},
+	.wData = {	0x0053, 0x0069, 0x006d, 0x0054, 0x0072, 0x0061,
+			0x0063, 0x0065, 0x0020, 0x0044, 0x0046, 0x0055,
+			0x0020, 0x0049, 0x006e, 0x0074, 0x0065, 0x0072,
+			0x0066, 0x0061, 0x0063, 0x0065, 0x0020, 0x002d,
+			0x0020, 0x0042, 0x006f, 0x006f, 0x0074, 0x006c,
+			0x006f, 0x0061, 0x0064, 0x0065, 0x0072, 0x0020,
+			0x0050, 0x0061, 0x0072, 0x0074, 0x0069, 0x0074,
+			0x0069, 0x006f, 0x006e, },
+};
+
+/* String 3 "SimTrace DFU Interface - RAM" */
+const struct USBStringDescriptor USBDFU_string3 = {
+	.hdr = {
+		.bLength = sizeof(USBGenericDescriptor) + 28 * sizeof(unsigned short),
+		.bDescriptorType = USBGenericDescriptor_STRING,
+	},
+	.wData = {	0x0053, 0x0069, 0x006d, 0x0054, 0x0072, 0x0061,
+			0x0063, 0x0065, 0x0020, 0x0044, 0x0046, 0x0055,
+			0x0020, 0x0049, 0x006e, 0x0074, 0x0065, 0x0072,
+			0x0066, 0x0061, 0x0063, 0x0065, 0x0020, 0x002d,
+			0x0020, 0x0052, 0x0041, 0x004d, },
+};
diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h
new file mode 100644
index 0000000..9033de6
--- /dev/null
+++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h
@@ -0,0 +1,130 @@
+#ifndef _USB_DEV_DFU_H
+#define _USB_DEV_DFU_H
+
+#include <stdint.h>
+#include <board.h>
+#include <usb/include/USBDescriptors.h>
+#include <usb/include/USBDDriver.h>
+
+#if 0
+/* This is valid for CCID */
+#define CONFIG_DFU_NUM_APP_IF	1
+#define CONFIG_DFU_NUM_APP_STR	4
+#else
+/* This is valid for CDC-Serial */
+#define CONFIG_DFU_NUM_APP_IF	2
+#define CONFIG_DFU_NUM_APP_STR	2
+#endif
+
+struct USBStringDescriptor {
+	USBGenericDescriptor hdr;
+	unsigned short wData[];
+} __attribute__((packed));
+
+
+#ifdef BOARD_USB_DFU
+
+#include <usb/common/dfu/usb_dfu.h>
+
+/* for board-specific config */
+#include <board.h>
+
+struct dfu_desc {
+	USBConfigurationDescriptor ucfg;
+	USBInterfaceDescriptor uif[BOARD_DFU_NUM_IF];
+	struct usb_dfu_func_descriptor func_dfu;
+} __attribute__ ((packed));
+
+/* USB DFU functional descriptor */
+#define DFU_FUNC_DESC  {						\
+	.bLength		= USB_DT_DFU_SIZE,			\
+	.bDescriptorType	= USB_DT_DFU,				\
+	.bmAttributes		= USB_DFU_CAN_UPLOAD | USB_DFU_CAN_DOWNLOAD, \
+	.wDetachTimeOut		= 0xff00,				\
+	.wTransferSize		= BOARD_DFU_PAGE_SIZE,			\
+	.bcdDFUVersion		= 0x0100,				\
+}
+
+/* Number of DFU interface during runtime mode */
+#define DFURT_NUM_IF		1
+
+/* to be used by the runtime as part of its USB descriptor structure
+ * declaration */
+#define DFURT_IF_DESCRIPTOR_STRUCT		\
+	USBInterfaceDescriptor	dfu_rt;		\
+	struct usb_dfu_func_descriptor func_dfu;
+
+/* to be used by the runtime as part of its USB Dsecriptor structure
+ * definition */
+#define DFURT_IF_DESCRIPTOR(dfuIF, dfuSTR)					\
+	.dfu_rt = {								\
+		.bLength 		= sizeof(USBInterfaceDescriptor),	\
+		.bDescriptorType	= USBGenericDescriptor_INTERFACE,	\
+		.bInterfaceNumber	= dfuIF,				\
+		.bAlternateSetting	= 0,					\
+		.bNumEndpoints		= 0,					\
+		.bInterfaceClass	= 0xFE,					\
+		.bInterfaceSubClass	= 0x01,					\
+		.bInterfaceProtocol	= 0x01,					\
+		.iInterface		= dfuSTR,				\
+	},									\
+	.func_dfu = DFU_FUNC_DESC						\
+
+/* provided by dfu_desc.c */
+extern const struct dfu_desc dfu_cfg_descriptor;
+extern const USBDDriverDescriptors dfu_descriptors;
+
+#else /* BOARD_USB_DFU */
+
+/* no DFU bootloader is being used */
+#define DFURT_NUM_IF	0
+#define DFURT_IF_DESCRIPTOR_STRUCT(a, b)
+#define DFURT_IF_DESCRIPTOR
+
+#endif /* BOARD_USB_DFU */
+
+/* magic value we use during boot to detect if we should start in DFU
+ * mode or runtime mode */
+#define USB_DFU_MAGIC	0xDFDFDFDF
+/* RAM address for this magic value above */
+#define USB_DFU_MAGIC_ADDR	IRAM_ADDR
+
+/* The API between the core DFU handler and the board/soc specific code */
+
+struct dfudata {
+	uint8_t status;
+	uint32_t state;
+	int past_manifest;
+	unsigned int total_bytes;
+};
+
+extern struct dfudata g_dfu;
+
+void set_usb_serial_str(const uint8_t *serial_usbstr);
+
+void DFURT_SwitchToDFU(void);
+
+/* call-backs from DFU USB function driver to the board/SOC */
+extern int USBDFU_handle_dnload(uint8_t altif, unsigned int offset,
+				uint8_t *data, unsigned int len);
+extern int USBDFU_handle_upload(uint8_t altif, unsigned int offset,
+				uint8_t *data, unsigned int req_len);
+
+/* function to be called at end of EP0 handler during runtime */
+void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request);
+
+/* function to be called at end of EP0 handler during DFU mode */
+void USBDFU_DFU_RequestHandler(const USBGenericRequest *request);
+
+/* initialization of USB DFU driver (in DFU mode */
+void USBDFU_Initialize(const USBDDriverDescriptors *pDescriptors);
+
+/* USBD tells us to switch from DFU mode to application mode */
+void USBDFU_SwitchToApp(void);
+
+/* Return values to be used by USBDFU_handle_{dn,up}load */
+#define DFU_RET_NOTHING	0
+#define DFU_RET_ZLP	1
+#define DFU_RET_STALL	2
+
+#endif
diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c
new file mode 100644
index 0000000..c325606
--- /dev/null
+++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c
@@ -0,0 +1,124 @@
+/* DFU related USB Descriptors */
+/* (C) 2006-2017 Harald Welte <hwelte@hmw-consulting.de> */
+
+#include <unistd.h>
+
+#include "board.h"
+
+#include <usb/include/USBDescriptors.h>
+
+#include <usb/include/USBDDriver.h>
+
+#include <usb/common/dfu/usb_dfu.h>
+#include <usb/device/dfu/dfu.h>
+
+enum {
+	STR_MANUF	= 1,
+	STR_PROD,
+	STR_CONFIG,
+	_STR_FIRST_ALT,
+	STR_SERIAL 	= (_STR_FIRST_ALT+BOARD_DFU_NUM_IF),
+};
+
+static const USBDeviceDescriptor fsDevice = {
+	.bLength = 		sizeof(USBDeviceDescriptor),
+	.bDescriptorType = 	USBGenericDescriptor_DEVICE,
+	.bcdUSB = 		USBDeviceDescriptor_USB2_00,
+	.bDeviceClass =		0,
+	.bDeviceSubClass = 	0,
+	.bDeviceProtocol = 	0,
+	.bMaxPacketSize0 =	BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0),
+	.idVendor =		BOARD_USB_VENDOR,
+	.idProduct = 		BOARD_USB_PRODUCT,
+	.bcdDevice = 		BOARD_USB_RELEASE,
+	.iManufacturer =	STR_MANUF,
+	.iProduct =		STR_PROD,
+#ifdef BOARD_USB_SERIAL
+	.iSerialNumber =	STR_SERIAL,
+#else
+	.iSerialNumber =	0,
+#endif
+	.bNumConfigurations =	1,
+};
+
+/* Alternate Interface Descriptor, we use one per partition/memory type */
+#define DFU_IF(ALT)								\
+	{									\
+		.bLength =		sizeof(USBInterfaceDescriptor),		\
+		.bDescriptorType = 	USBGenericDescriptor_INTERFACE,		\
+		.bInterfaceNumber =	0,					\
+		.bAlternateSetting =	ALT,					\
+		.bNumEndpoints =	0,					\
+		.bInterfaceClass =	0xfe,					\
+		.bInterfaceSubClass =	1,					\
+		.iInterface =		(_STR_FIRST_ALT+ALT),			\
+		.bInterfaceProtocol =	2,					\
+	}
+
+/* overall descriptor for the DFU configuration, including all
+ * descriptors for alternate interfaces */
+const struct dfu_desc dfu_cfg_descriptor = {
+	.ucfg = {
+		.bLength =	   sizeof(USBConfigurationDescriptor),
+		.bDescriptorType = USBGenericDescriptor_CONFIGURATION,
+		.wTotalLength =	   sizeof(USBConfigurationDescriptor) +
+				   BOARD_DFU_NUM_IF * sizeof(USBInterfaceDescriptor) +
+				   sizeof(struct usb_dfu_func_descriptor),
+		.bNumInterfaces =  1,
+		.bConfigurationValue = 1,
+		.iConfiguration =  STR_CONFIG,
+		.bmAttributes =	   BOARD_USB_BMATTRIBUTES,
+		.bMaxPower =	   100,
+	},
+	.uif[0] = DFU_IF(0),
+#if BOARD_DFU_NUM_IF > 1
+	.uif[1] = DFU_IF(1),
+#endif
+#if BOARD_DFU_NUM_IF > 2
+	.uif[2] = DFU_IF(2),
+#endif
+#if BOARD_DFU_NUM_IF > 3
+	.uif[3] = DFU_IF(3),
+#endif
+#if BOARD_DFU_NUM_IF > 4
+	.uif[4] = DFU_IF(4),
+#endif
+	.func_dfu = DFU_FUNC_DESC
+};
+
+#if 0
+#include "usb_strings.h"
+
+
+static const unsigned char *usb_strings[] = {
+	USB_STRINGS_GENERATED
+#ifdef BOARD_USB_SERIAL
+	NULL
+#endif
+};
+
+void set_usb_serial_str(const uint8_t *serial_usbstr)
+{
+	usb_strings[STR_SERIAL] = serial_usbstr;
+}
+#endif
+
+const USBDDriverDescriptors dfu_descriptors = {
+	.pFsDevice = &fsDevice,
+	.pFsConfiguration = &dfu_cfg_descriptor.ucfg,
+//#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS)
+#if 0 // DFU only supports FS for now
+	.pFsQualifier = ,
+	.pFsOtherSpeed = ,
+	.pHsDevice = ,
+	.pHsConfiguration = ,
+	.pHsQualifier = ,
+	.pHsOtherSpeed = ,
+#else
+	0, 0, 0, 0, 0, 0,
+#endif
+#if 0
+	.pStrings = usb_strings,
+	.numStrings = ARRAY_SIZE(usb_strings),
+#endif
+};
diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c
new file mode 100644
index 0000000..94bfc02
--- /dev/null
+++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c
@@ -0,0 +1,466 @@
+/* USB Device Firmware Update Implementation for OpenPCD, OpenPICC SIMtrace
+ * (C) 2006-2017 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * This ought to be compliant to the USB DFU Spec 1.0 as available from
+ * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf
+ *
+ *  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
+ *
+ */
+
+#include <unistd.h>
+
+#include <board.h>
+#include <core_cm3.h>
+
+#include "trace.h"
+
+#include <usb/include/USBDescriptors.h>
+#include <usb/include/USBRequests.h>
+#include <usb/include/USBD.h>
+#include <usb/common/dfu/usb_dfu.h>
+#include <usb/device/dfu/dfu.h>
+
+/* FIXME: this was used for a special ELF section which then got called
+ * by DFU code and Application code, across flash partitions */
+#define __dfudata
+#define __dfufunc
+
+/// Standard device driver instance.
+static USBDDriver usbdDriver;
+static unsigned char if_altsettings[1];
+
+__dfudata struct dfudata g_dfu = {
+  	.state = DFU_STATE_appIDLE,
+	.past_manifest = 0,
+	.total_bytes = 0,
+};
+
+WEAK void dfu_drv_updatatus(void)
+{
+	TRACE_INFO("DFU: updstatus()\n\r");
+
+	/* we transition immediately from MANIFEST_SYNC to MANIFEST,
+	 * as the flash-writing is not asynchronous in this
+	 * implementation */
+	if (g_dfu.state == DFU_STATE_dfuMANIFEST_SYNC)
+		g_dfu.state = DFU_STATE_dfuMANIFEST;
+}
+
+static __dfufunc void handle_getstatus(void)
+{
+	/* has to be static as USBD_Write is async ? */
+	static struct dfu_status dstat;
+
+	dfu_drv_updstatus();
+
+	/* send status response */
+	dstat.bStatus = g_dfu.status;
+	dstat.bState = g_dfu.state;
+	dstat.iString = 0;
+	/* FIXME: set dstat.bwPollTimeout */
+
+	TRACE_DEBUG("handle_getstatus(%u, %u)\n\r", dstat.bStatus, dstat.bState);
+
+	USBD_Write(0, (char *)&dstat, sizeof(dstat), NULL, 0);
+}
+
+static void __dfufunc handle_getstate(void)
+{
+	uint8_t u8 = g_dfu.state;
+
+	TRACE_DEBUG("handle_getstate(%u)\n\r", g_dfu.state);
+
+	USBD_Write(0, (char *)&u8, sizeof(u8), NULL, 0);
+}
+
+static void TerminateCtrlInWithNull(void *pArg,
+                                    unsigned char status,
+                                    unsigned long int transferred,
+                                    unsigned long int remaining)
+{
+    USBD_Write(0, // Endpoint #0
+               0, // No data buffer
+               0, // No data buffer
+               (TransferCallback) 0,
+               (void *)  0);
+}
+
+static uint8_t dfu_buf[BOARD_DFU_PAGE_SIZE];
+
+/* download of a single page has completed */
+static void dnload_cb(void *arg, unsigned char status, unsigned long int transferred,
+		      unsigned long int remaining)
+{
+	int rc;
+
+	TRACE_DEBUG("COMPLETE\n\r");
+
+	if (status != USBD_STATUS_SUCCESS) {
+		TRACE_ERROR("USBD download callback status %d\n\r", status);
+		USBD_Stall(0);
+		return;
+	}
+
+	rc = USBDFU_handle_dnload(if_altsettings[0], g_dfu.total_bytes, dfu_buf, transferred);
+	switch (rc) {
+	case DFU_RET_ZLP:
+		g_dfu.total_bytes += transferred;
+		g_dfu.state = DFU_STATE_dfuDNLOAD_IDLE;
+		TerminateCtrlInWithNull(0,0,0,0);
+		break;
+	case DFU_RET_STALL:
+		g_dfu.state = DFU_STATE_dfuERROR;
+		USBD_Stall(0);
+		break;
+	case DFU_RET_NOTHING:
+		break;
+	}
+
+}
+
+static int handle_dnload(uint16_t val, uint16_t len, int first)
+{
+	int rc;
+
+	if (len > BOARD_DFU_PAGE_SIZE) {
+		TRACE_ERROR("DFU length exceeds flash page size\n\r");
+		g_dfu.state = DFU_STATE_dfuERROR;
+		g_dfu.status = DFU_STATUS_errADDRESS;
+		return DFU_RET_STALL;
+	}
+
+	if (len & 0x03) {
+		TRACE_ERROR("DFU length not four-byte-aligned\n\r");
+		g_dfu.state = DFU_STATE_dfuERROR;
+		g_dfu.status = DFU_STATUS_errADDRESS;
+		return DFU_RET_STALL;
+	}
+
+	if (first)
+		g_dfu.total_bytes = 0;
+
+	if (len == 0) {
+		TRACE_DEBUG("zero-size write -> MANIFEST_SYNC\n\r");
+		g_dfu.state = DFU_STATE_dfuMANIFEST_SYNC;
+		return DFU_RET_ZLP;
+	}
+
+	/* else: actually read data */
+	rc = USBD_Read(0, dfu_buf, len, &dnload_cb, 0);
+	if (rc == USBD_STATUS_SUCCESS)
+		return DFU_RET_NOTHING;
+	else
+		return DFU_RET_STALL;
+}
+
+/* upload of a single page has completed */
+static void upload_cb(void *arg, unsigned char status, unsigned long int transferred,
+		      unsigned long int remaining)
+{
+	int rc;
+
+	TRACE_DEBUG("COMPLETE\n\r");
+
+	if (status != USBD_STATUS_SUCCESS) {
+		TRACE_ERROR("USBD upload callback status %d\n\r", status);
+		USBD_Stall(0);
+		return;
+	}
+
+	g_dfu.total_bytes += transferred;
+}
+
+static int handle_upload(uint16_t val, uint16_t len, int first)
+{
+	int rc;
+
+	if (first)
+		g_dfu.total_bytes = 0;
+
+	if (len > BOARD_DFU_PAGE_SIZE) {
+		TRACE_ERROR("DFU length exceeds flash page size\n\r");
+		g_dfu.state = DFU_STATE_dfuERROR;
+		g_dfu.status = DFU_STATUS_errADDRESS;
+		return DFU_RET_STALL;
+	}
+
+	rc = USBDFU_handle_upload(if_altsettings[0], g_dfu.total_bytes, dfu_buf, len);
+	if (rc < 0) {
+		TRACE_ERROR("application handle_upload() returned %d\n\r", rc);
+		return DFU_RET_STALL;
+	}
+
+	if (USBD_Write(0, dfu_buf, rc, &upload_cb, 0) == USBD_STATUS_SUCCESS)
+		return rc;
+
+	return DFU_RET_STALL;
+}
+
+/* this function gets daisy-chained into processing EP0 requests */
+void USBDFU_DFU_RequestHandler(const USBGenericRequest *request)
+{
+	uint8_t req = USBGenericRequest_GetRequest(request);
+	uint16_t len = USBGenericRequest_GetLength(request);
+	uint16_t val = USBGenericRequest_GetValue(request);
+	int rc, ret;
+
+	TRACE_DEBUG("type=0x%x, recipient=0x%x val=0x%x len=%u\n\r",
+			USBGenericRequest_GetType(request),
+			USBGenericRequest_GetRecipient(request),
+			val, len);
+
+	/* check for GET_DESCRIPTOR on DFU */
+	if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD &&
+	    USBGenericRequest_GetRecipient(request) == USBGenericRequest_DEVICE &&
+	    USBGenericRequest_GetRequest(request) == USBGenericRequest_GETDESCRIPTOR &&
+	    USBGetDescriptorRequest_GetDescriptorType(request) == USB_DT_DFU) {
+		uint16_t length = sizeof(struct usb_dfu_func_descriptor);
+		const USBDeviceDescriptor *pDevice;
+		int terminateWithNull;
+
+		if (USBD_IsHighSpeed())
+			pDevice = usbdDriver.pDescriptors->pHsDevice;
+		else
+			pDevice = usbdDriver.pDescriptors->pFsDevice;
+
+		terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0);
+		USBD_Write(0, &dfu_cfg_descriptor.func_dfu, length,
+			   terminateWithNull ? TerminateCtrlInWithNull : 0, 0);
+		return;
+	}
+
+	/* forward all non-DFU specific messages to core handler*/
+	if (USBGenericRequest_GetType(request) != USBGenericRequest_CLASS ||
+	    USBGenericRequest_GetRecipient(request) != USBGenericRequest_INTERFACE) {
+		TRACE_DEBUG("std_ho_usbd ");
+		USBDDriver_RequestHandler(&usbdDriver, request);
+	}
+
+	switch (g_dfu.state) {
+	case DFU_STATE_appIDLE:
+	case DFU_STATE_appDETACH:
+		TRACE_ERROR("Invalid DFU State reached in DFU mode\r\n");
+		ret = DFU_RET_STALL;
+		break;
+	case DFU_STATE_dfuIDLE:
+		switch (req) {
+		case USB_REQ_DFU_DNLOAD:
+			if (len == 0) {
+				g_dfu.state = DFU_STATE_dfuERROR;
+				ret = DFU_RET_STALL;
+				goto out;
+			}
+			g_dfu.state = DFU_STATE_dfuDNLOAD_SYNC;
+			ret = handle_dnload(val, len, 1);
+			break;
+		case USB_REQ_DFU_UPLOAD:
+			g_dfu.state = DFU_STATE_dfuUPLOAD_IDLE;
+			handle_upload(val, len, 1);
+			break;
+		case USB_REQ_DFU_ABORT:
+			/* no zlp? */
+			ret = DFU_RET_ZLP;
+			break;
+		case USB_REQ_DFU_GETSTATUS:
+			handle_getstatus();
+			break;
+		case USB_REQ_DFU_GETSTATE:
+			handle_getstate();
+			break;
+		default:
+			g_dfu.state = DFU_STATE_dfuERROR;
+			ret = DFU_RET_STALL;
+			goto out;
+			break;
+		}
+		break;
+	case DFU_STATE_dfuDNLOAD_SYNC:
+		switch (req) {
+		case USB_REQ_DFU_GETSTATUS:
+			handle_getstatus();
+			/* FIXME: state transition depending on block completeness */
+			break;
+		case USB_REQ_DFU_GETSTATE:
+			handle_getstate();
+			break;
+		default:
+			g_dfu.state = DFU_STATE_dfuERROR;
+			ret = DFU_RET_STALL;
+			goto out;
+		}
+		break;
+	case DFU_STATE_dfuDNBUSY:
+		switch (req) {
+		case USB_REQ_DFU_GETSTATUS:
+			/* FIXME: only accept getstatus if bwPollTimeout
+			 * has elapsed */
+			handle_getstatus();
+			break;
+		default:
+			g_dfu.state = DFU_STATE_dfuERROR;
+			ret = DFU_RET_STALL;
+			goto out;
+		}
+		break;
+	case DFU_STATE_dfuDNLOAD_IDLE:
+		switch (req) {
+		case USB_REQ_DFU_DNLOAD:
+			g_dfu.state = DFU_STATE_dfuDNLOAD_SYNC;
+			ret = handle_dnload(val, len, 0);
+			break;
+		case USB_REQ_DFU_ABORT:
+			g_dfu.state = DFU_STATE_dfuIDLE;
+			ret = DFU_RET_ZLP;
+			break;
+		case USB_REQ_DFU_GETSTATUS:
+			handle_getstatus();
+			break;
+		case USB_REQ_DFU_GETSTATE:
+			handle_getstate();
+			break;
+		default:
+			g_dfu.state = DFU_STATE_dfuERROR;
+			ret = DFU_RET_STALL;
+			break;
+		}
+		break;
+	case DFU_STATE_dfuMANIFEST_SYNC:
+		switch (req) {
+		case USB_REQ_DFU_GETSTATUS:
+			handle_getstatus();
+			break;
+		case USB_REQ_DFU_GETSTATE:
+			handle_getstate();
+			break;
+		default:
+			g_dfu.state = DFU_STATE_dfuERROR;
+			ret = DFU_RET_STALL;
+			break;
+		}
+		break;
+	case DFU_STATE_dfuMANIFEST:
+		switch (req) {
+		case USB_REQ_DFU_GETSTATUS:
+			/* we don't want to change to WAIT_RST, as it
+			 * would mean that we can not support another
+			 * DFU transaction before doing the actual
+			 * reset.  Instead, we switch to idle and note
+			 * that we've already been through MANIFST in
+			 * the global variable 'past_manifest'.
+			 */
+			//g_dfu.state = DFU_STATE_dfuMANIFEST_WAIT_RST;
+			g_dfu.state = DFU_STATE_dfuIDLE;
+			g_dfu.past_manifest = 1;
+			handle_getstatus();
+			break;
+		case USB_REQ_DFU_GETSTATE:
+			handle_getstate();
+			break;
+		default:
+			g_dfu.state = DFU_STATE_dfuERROR;
+			ret = DFU_RET_STALL;
+			break;
+		}
+		break;
+	case DFU_STATE_dfuMANIFEST_WAIT_RST:
+		/* we should never go here */
+		break;
+	case DFU_STATE_dfuUPLOAD_IDLE:
+		switch (req) {
+		case USB_REQ_DFU_UPLOAD:
+			/* state transition if less data then requested */
+			rc = handle_upload(val, len, 0);
+			if (rc >= 0 && rc < len)
+				g_dfu.state = DFU_STATE_dfuIDLE;
+			break;
+		case USB_REQ_DFU_ABORT:
+			g_dfu.state = DFU_STATE_dfuIDLE;
+			/* no zlp? */
+			ret = DFU_RET_ZLP;
+			break;
+		case USB_REQ_DFU_GETSTATUS:
+			handle_getstatus();
+			break;
+		case USB_REQ_DFU_GETSTATE:
+			handle_getstate();
+			break;
+		default:
+			g_dfu.state = DFU_STATE_dfuERROR;
+			ret = DFU_RET_STALL;
+			break;
+		}
+		break;
+	case DFU_STATE_dfuERROR:
+		switch (req) {
+		case USB_REQ_DFU_GETSTATUS:
+			handle_getstatus();
+			break;
+		case USB_REQ_DFU_GETSTATE:
+			handle_getstate();
+			break;
+		case USB_REQ_DFU_CLRSTATUS:
+			g_dfu.state = DFU_STATE_dfuIDLE;
+			g_dfu.status = DFU_STATUS_OK;
+			/* no zlp? */
+			ret = DFU_RET_ZLP;
+			break;
+		default:
+			g_dfu.state = DFU_STATE_dfuERROR;
+			ret = DFU_RET_STALL;
+			break;
+		}
+		break;
+	}
+
+out:
+	switch (ret) {
+	case DFU_RET_NOTHING:
+		break;
+	case DFU_RET_ZLP:
+		USBD_Write(0, 0, 0, 0, 0);
+		break;
+	case DFU_RET_STALL:
+		USBD_Stall(0);
+		break;
+	}
+}
+
+void USBDFU_Initialize(const USBDDriverDescriptors *pDescriptors)
+{
+	/* We already start in DFU idle mode */
+	g_dfu.state = DFU_STATE_dfuIDLE;
+
+	USBDDriver_Initialize(&usbdDriver, pDescriptors, if_altsettings);
+
+	USBD_Init();
+	USBD_ConfigureSpeed(1);
+}
+
+void USBDFU_SwitchToApp(void)
+{
+	/* make sure the MAGIC is not set to enter DFU again */
+	*(unsigned int *)USB_DFU_MAGIC_ADDR = 0;
+
+	/* disconnect from USB to ensure re-enumeration */
+	USBD_Disconnect();
+
+	/* disable any interrupts during transition */
+	__disable_irq();
+
+	/* Tell the hybrid to execute FTL JUMP! */
+	//BootIntoApp();
+	NVIC_SystemReset();
+}
diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c
new file mode 100644
index 0000000..0102650
--- /dev/null
+++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c
@@ -0,0 +1,189 @@
+/* DFU related functions that are active at runtime, i.e. during the
+ * normal operation of the device firmware, *not* during DFU update mode
+ * (C) 2006 Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * This ought to be compliant to the USB DFU Spec 1.0 as available from
+ * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf
+ *
+ *  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
+ *
+ */
+
+#include <board.h>
+#include <core_cm3.h>
+
+#include <usb/include/USBD.h>
+#include <usb/device/dfu/dfu.h>
+
+#include "trace.h"
+
+#include <usb/include/USBDescriptors.h>
+#include <usb/include/USBRequests.h>
+#include <usb/include/USBD.h>
+#include <usb/common/dfu/usb_dfu.h>
+#include <usb/device/dfu/dfu.h>
+
+/* FIXME: this was used for a special ELF section which then got called
+ * by DFU code and Application code, across flash partitions */
+#define __dfudata
+#define __dfufunc
+
+static __dfufunc void handle_getstatus(void)
+{
+	/* has to be static as USBD_Write is async ? */
+	static struct dfu_status dstat;
+
+	/* send status response */
+	dstat.bStatus = g_dfu.status;
+	dstat.bState = g_dfu.state;
+	dstat.iString = 0;
+	/* FIXME: set dstat.bwPollTimeout */
+
+	TRACE_DEBUG("handle_getstatus(%u, %u)\n\r", dstat.bStatus, dstat.bState);
+
+	USBD_Write(0, (char *)&dstat, sizeof(dstat), NULL, 0);
+}
+
+static void __dfufunc handle_getstate(void)
+{
+	uint8_t u8 = g_dfu.state;
+
+	TRACE_DEBUG("handle_getstate(%u)\n\r", g_dfu.state);
+
+	USBD_Write(0, (char *)&u8, sizeof(u8), NULL, 0);
+}
+
+static void TerminateCtrlInWithNull(void *pArg,
+                                    unsigned char status,
+                                    unsigned long int transferred,
+                                    unsigned long int remaining)
+{
+    USBD_Write(0, // Endpoint #0
+               0, // No data buffer
+               0, // No data buffer
+               (TransferCallback) 0,
+               (void *)  0);
+}
+
+/* this function gets daisy-chained into processing EP0 requests */
+void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request)
+{
+	USBDDriver *usbdDriver = USBD_GetDriver();
+	uint8_t req = USBGenericRequest_GetRequest(request);
+	uint16_t len = USBGenericRequest_GetLength(request);
+	uint16_t val = USBGenericRequest_GetValue(request);
+	int rc, ret;
+
+	TRACE_DEBUG("type=0x%x, recipient=0x%x val=0x%x len=%u\n\r",
+			USBGenericRequest_GetType(request),
+			USBGenericRequest_GetRecipient(request),
+			val, len);
+
+	/* check for GET_DESCRIPTOR on DFU */
+	if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD &&
+	    USBGenericRequest_GetRecipient(request) == USBGenericRequest_DEVICE &&
+	    USBGenericRequest_GetRequest(request) == USBGenericRequest_GETDESCRIPTOR &&
+	    USBGetDescriptorRequest_GetDescriptorType(request) == USB_DT_DFU) {
+		uint16_t length = sizeof(struct usb_dfu_func_descriptor);
+		const USBDeviceDescriptor *pDevice;
+		int terminateWithNull;
+
+		if (USBD_IsHighSpeed())
+			pDevice = usbdDriver->pDescriptors->pHsDevice;
+		else
+			pDevice = usbdDriver->pDescriptors->pFsDevice;
+
+		terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0);
+		USBD_Write(0, &dfu_cfg_descriptor.func_dfu, length,
+			   terminateWithNull ? TerminateCtrlInWithNull : 0, 0);
+		return;
+	}
+
+	/* forward all non-DFU specific messages to core handler*/
+	if (USBGenericRequest_GetType(request) != USBGenericRequest_CLASS ||
+	    USBGenericRequest_GetRecipient(request) != USBGenericRequest_INTERFACE) {
+		TRACE_DEBUG("std_ho_usbd ");
+		USBDDriver_RequestHandler(usbdDriver, request);
+	}
+
+	switch (g_dfu.state) {
+	case DFU_STATE_appIDLE:
+		switch (req) {
+		case USB_REQ_DFU_GETSTATUS:
+			handle_getstatus();
+			break;
+		case USB_REQ_DFU_GETSTATE:
+			handle_getstate();
+			break;
+		case USB_REQ_DFU_DETACH:
+			/* we switch it DETACH state, send a ZLP and
+			 * return.  The next USB reset in this state
+			 * will then trigger DFURT_SwitchToDFU() below */
+			TRACE_DEBUG("\r\n====dfu_detach\n\r");
+			g_dfu.state = DFU_STATE_appDETACH;
+			ret = DFU_RET_ZLP;
+			goto out;
+			break;
+		default:
+			ret = DFU_RET_STALL;
+		}
+		break;
+	case DFU_STATE_appDETACH:
+		switch (req) {
+		case USB_REQ_DFU_GETSTATUS:
+			handle_getstatus();
+			break;
+		case USB_REQ_DFU_GETSTATE:
+			handle_getstate();
+			break;
+		default:
+			g_dfu.state = DFU_STATE_appIDLE;
+			ret = DFU_RET_STALL;
+			goto out;
+			break;
+		}
+		/* FIXME: implement timer to return to appIDLE */
+		break;
+	default:
+		TRACE_ERROR("Invalid DFU State reached in Runtime Mode\r\n");
+		ret = DFU_RET_STALL;
+		break;
+	}
+
+out:
+	switch (ret) {
+	case DFU_RET_NOTHING:
+		break;
+	case DFU_RET_ZLP:
+		USBD_Write(0, 0, 0, 0, 0);
+		break;
+	case DFU_RET_STALL:
+		USBD_Stall(0);
+		break;
+	}
+}
+
+void DFURT_SwitchToDFU(void)
+{
+	unsigned int *dfu_except_tbl = (unsigned int *)IFLASH_ADDR;
+	void (*toDFU)(void) = (void *)dfu_except_tbl[1];
+
+	*(unsigned int *)USB_DFU_MAGIC_ADDR = USB_DFU_MAGIC;
+
+	USBD_Disconnect();
+	__disable_irq();
+
+	toDFU();
+}
diff --git a/firmware/include_board/board_common.h b/firmware/include_board/board_common.h
index 6a46d67..9943ae1 100644
--- a/firmware/include_board/board_common.h
+++ b/firmware/include_board/board_common.h
@@ -107,6 +107,14 @@
 #define BOARD_USB_BMATTRIBUTES                  USBConfigurationDescriptor_BUSPOWERED_NORWAKEUP
 //#define BOARD_USB_BMATTRIBUTES                  USBConfigurationDescriptor_SELFPOWERED_RWAKEUP
 
+#define BOARD_USB_VENDOR	SIMTRACE_VENDOR_ID
+#define BOARD_USB_PRODUCT	SIMTRACE_PRODUCT_ID
+#define BOARD_USB_RELEASE	0
+
+#define BOARD_USB_DFU
+#define BOARD_DFU_BOOT_SIZE	(16 * 1024)
+#define BOARD_DFU_PAGE_SIZE	512
+#define BOARD_DFU_NUM_IF	2
 
 extern void board_exec_dbg_cmd(int ch);
 extern void board_main_top(void);
diff --git a/firmware/src_board/board_cstartup_gnu.c b/firmware/src_board/board_cstartup_gnu.c
index 3647d5e..4255646 100644
--- a/firmware/src_board/board_cstartup_gnu.c
+++ b/firmware/src_board/board_cstartup_gnu.c
@@ -125,6 +125,19 @@
     IrqHandlerNotUsed   /* 35 not used */

 };

 

+#if defined (BOARD_USB_DFU) && !defined(dfu)

+static void BootIntoApp(void)

+{

+	unsigned int *pSrc;

+	void (*appReset)(void);

+

+	pSrc = (unsigned int *) ((unsigned char *)IFLASH_ADDR + BOARD_DFU_BOOT_SIZE);

+	SCB->VTOR = ((unsigned int)(pSrc)) | (0x0 << 7);

+	appReset = pSrc[1];

+	appReset();

+}

+#endif

+

 /**

  * \brief This is the code that gets called on processor reset.

  * To initialize the device, and call the main() routine.

@@ -136,6 +149,11 @@
     /* Low level Initialize */

     LowLevelInit() ;

 

+#if defined (BOARD_USB_DFU) && !defined(dfu)

+    if (*(unsigned long *)IRAM_ADDR != 0xDFDFDFDF)

+        BootIntoApp();

+#endif

+

     /* Initialize the relocate segment */

     pSrc = &_etext ;

     pDest = &_srelocate ;

@@ -169,6 +187,9 @@
     /* Branch to main function */

     main() ;

 

+    /* App should have disabled interrupts during the transition */

+    __enable_irq();

+

     /* Infinite loop */

     while ( 1 ) ;

 }

diff --git a/firmware/src_sam3s/USBD_HAL.c b/firmware/src_sam3s/USBD_HAL.c
index 8a2645b..7776004 100644
--- a/firmware/src_sam3s/USBD_HAL.c
+++ b/firmware/src_sam3s/USBD_HAL.c
@@ -52,6 +52,7 @@
 

 #include "chip.h"

 #include "USBD_HAL.h"

+#include <usb/device/dfu/dfu.h>

 

 #include <stdbool.h>

 #include <stdint.h>

@@ -1161,6 +1162,12 @@
     else if ((status & UDP_ISR_ENDBUSRES) != 0) {

 

         TRACE_INFO_WP("EoBRes ");

+

+#if defined(BOARD_USB_DFU) && defined(dfu)

+	if (g_dfu.past_manifest)

+		USBDFU_SwitchToApp();

+#endif

+

         /* Flush and enable the Suspend interrupt */

         UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP;

         UDP->UDP_IER = UDP_IER_RXSUSP;

diff --git a/firmware/src_simtrace/usb.c b/firmware/src_simtrace/usb.c
index f24ee05..66f1de8 100644
--- a/firmware/src_simtrace/usb.c
+++ b/firmware/src_simtrace/usb.c
@@ -36,6 +36,8 @@
 #include "utils.h"
 
 #include <cciddriverdescriptors.h>
+#include <usb/common/dfu/usb_dfu.h>
+#include <usb/device/dfu/dfu.h>
 
 /*------------------------------------------------------------------------------
  *       USB String descriptors 
@@ -260,7 +262,7 @@
 	USBEndpointDescriptor sniffer_dataOut;
 	USBEndpointDescriptor sniffer_dataIn;
 	USBEndpointDescriptor sniffer_interruptIn;
-
+	DFURT_IF_DESCRIPTOR_STRUCT;
 } __attribute__ ((packed)) SIMTraceDriverConfigurationDescriptorSniffer;
 
 static const SIMTraceDriverConfigurationDescriptorSniffer
@@ -270,7 +272,7 @@
 		.bLength 		= sizeof(USBConfigurationDescriptor),
 		.bDescriptorType	= USBGenericDescriptor_CONFIGURATION,
 		.wTotalLength		= sizeof(SIMTraceDriverConfigurationDescriptorSniffer),
-		.bNumInterfaces		= 1,
+		.bNumInterfaces		= 1+DFURT_NUM_IF,
 		.bConfigurationValue	= CFG_NUM_SNIFF,
 		.iConfiguration		= SNIFFER_CONF_STR,
 		.bmAttributes		= USBD_BMATTRIBUTES,
@@ -326,7 +328,8 @@
 								PHONE_INT),
 				      USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
 		.bInterval = 0x10,
-	}
+	},
+	DFURT_IF_DESCRIPTOR(1, 0),
 };
 #endif /* HAVE_SNIFFER */
 
@@ -337,7 +340,7 @@
 		.bLength		= sizeof(USBConfigurationDescriptor),
 		.bDescriptorType	= USBGenericDescriptor_CONFIGURATION,
 		.wTotalLength		= sizeof(CCIDDriverConfigurationDescriptors),
-		.bNumInterfaces		= 1,
+		.bNumInterfaces		= 1+DFURT_NUM_IF,
 		.bConfigurationValue	= CFG_NUM_CCID,
 		.iConfiguration		= CCID_CONF_STR,
 		.bmAttributes		= BOARD_USB_BMATTRIBUTES,
@@ -424,6 +427,7 @@
 					USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
 		.bInterval = 0x10,
 	},
+	DFURT_IF_DESCRIPTOR(1, 0),
 };
 #endif /* HAVE_CCID */
 
@@ -442,6 +446,7 @@
 	USBEndpointDescriptor usim2_dataIn;
 	USBEndpointDescriptor usim2_interruptIn;
 #endif
+	DFURT_IF_DESCRIPTOR_STRUCT;
 } __attribute__ ((packed)) SIMTraceDriverConfigurationDescriptorPhone;
 
 static const SIMTraceDriverConfigurationDescriptorPhone
@@ -452,9 +457,9 @@
 		USBGenericDescriptor_CONFIGURATION,
 		sizeof(SIMTraceDriverConfigurationDescriptorPhone),
 #ifdef CARDEMU_SECOND_UART
-		2,
+		2+DFURT_NUM_IF,
 #else
-		1,	/* There is one interface in this configuration */
+		1+DFURT_NUM_IF,	/* There is one interface in this configuration */
 #endif
 		CFG_NUM_PHONE,		/* configuration number */
 		PHONE_CONF_STR,	/* string descriptor for this configuration */
@@ -553,6 +558,9 @@
 		    USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
 		0x10
 	},
+	DFURT_IF_DESCRIPTOR(2, 0),
+#else
+	DFURT_IF_DESCRIPTOR(1, 0),
 #endif
 };
 #endif /* HAVE_CARDEM */
@@ -576,6 +584,8 @@
 	USBEndpointDescriptor phone_dataIn;
 	USBEndpointDescriptor phone_interruptIn;
 
+	DFURT_IF_DESCRIPTOR_STRUCT;
+
 } __attribute__ ((packed)) SIMTraceDriverConfigurationDescriptorMITM;
 
 static const SIMTraceDriverConfigurationDescriptorMITM
@@ -585,7 +595,7 @@
 		sizeof(USBConfigurationDescriptor),
 		USBGenericDescriptor_CONFIGURATION,
 		sizeof(SIMTraceDriverConfigurationDescriptorMITM),
-		2,		/* There are two interfaces in this configuration */
+		2+DFURT_NUM_IF,	/* There are two interfaces in this configuration */
 		CFG_NUM_MITM,	/* configuration number */
 		MITM_CONF_STR,	/* string descriptor for this configuration */
 		USBD_BMATTRIBUTES,
@@ -718,7 +728,8 @@
 	 USBEndpointDescriptor_INTERRUPT,
 	 MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(PHONE_INT),
 	     USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
-	 0x10}
+	 0x10},
+	DFURT_IF_DESCRIPTOR(2, 0),
 };
 #endif /* HAVE_CARDEM */
 
@@ -810,3 +821,9 @@
 
 	NVIC_EnableIRQ(UDP_IRQn);
 }
+
+void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
+{
+	/* FIXME: integration with CCID control point reqeusts */
+	USBDFU_Runtime_RequestHandler(request);
+}