WIP: Introduce USB DFU code from my at91lib DFU port
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();
+}