aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2017-02-26 17:00:43 +0100
committerHarald Welte <laforge@gnumonks.org>2017-02-27 09:28:34 +0100
commit7ed6f3bc375f4eddecb7ccf10e837f3068cb4e42 (patch)
treecd89e0edc25a809f43cedec582384e9067738f43
parentaa3b867abb3e5887cb3b3b5a28bcb7c0c97482be (diff)
WIP: Introduce USB DFU code from my at91lib DFU port
-rw-r--r--firmware/Makefile7
-rw-r--r--firmware/atmel_softpack_libraries/usb/common/dfu/usb_dfu.h81
-rw-r--r--firmware/atmel_softpack_libraries/usb/device/dfu/dfu.c49
-rw-r--r--firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h130
-rw-r--r--firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c124
-rw-r--r--firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c466
-rw-r--r--firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c189
-rw-r--r--firmware/include_board/board_common.h8
-rw-r--r--firmware/src_board/board_cstartup_gnu.c21
-rw-r--r--firmware/src_sam3s/USBD_HAL.c7
-rw-r--r--firmware/src_simtrace/usb.c33
11 files changed, 1104 insertions, 11 deletions
diff --git a/firmware/Makefile b/firmware/Makefile
index e500bea..6092e8c 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -72,6 +72,7 @@ OBJ = obj
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 @@ TOP=..
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 @@ LDFLAGS = -mcpu=cortex-m3 -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-secti
# 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 @@ IntFunc exception_table[] = {
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 @@ void ResetException( void )
/* 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 @@ void ResetException( void )
/* 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 @@ void USBD_IrqHandler(void)
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 @@ typedef struct _SIMTraceDriverConfigurationDescriptorSniffer {
USBEndpointDescriptor sniffer_dataOut;
USBEndpointDescriptor sniffer_dataIn;
USBEndpointDescriptor sniffer_interruptIn;
-
+ DFURT_IF_DESCRIPTOR_STRUCT;
} __attribute__ ((packed)) SIMTraceDriverConfigurationDescriptorSniffer;
static const SIMTraceDriverConfigurationDescriptorSniffer
@@ -270,7 +272,7 @@ static const SIMTraceDriverConfigurationDescriptorSniffer
.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 @@ static const SIMTraceDriverConfigurationDescriptorSniffer
PHONE_INT),
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
.bInterval = 0x10,
- }
+ },
+ DFURT_IF_DESCRIPTOR(1, 0),
};
#endif /* HAVE_SNIFFER */
@@ -337,7 +340,7 @@ static const CCIDDriverConfigurationDescriptors configurationDescriptorCCID = {
.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 @@ static const CCIDDriverConfigurationDescriptors configurationDescriptorCCID = {
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
.bInterval = 0x10,
},
+ DFURT_IF_DESCRIPTOR(1, 0),
};
#endif /* HAVE_CCID */
@@ -442,6 +446,7 @@ typedef struct _SIMTraceDriverConfigurationDescriptorPhone {
USBEndpointDescriptor usim2_dataIn;
USBEndpointDescriptor usim2_interruptIn;
#endif
+ DFURT_IF_DESCRIPTOR_STRUCT;
} __attribute__ ((packed)) SIMTraceDriverConfigurationDescriptorPhone;
static const SIMTraceDriverConfigurationDescriptorPhone
@@ -452,9 +457,9 @@ static const SIMTraceDriverConfigurationDescriptorPhone
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 @@ static const SIMTraceDriverConfigurationDescriptorPhone
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
0x10
},
+ DFURT_IF_DESCRIPTOR(2, 0),
+#else
+ DFURT_IF_DESCRIPTOR(1, 0),
#endif
};
#endif /* HAVE_CARDEM */
@@ -576,6 +584,8 @@ typedef struct _SIMTraceDriverConfigurationDescriptorMITM {
USBEndpointDescriptor phone_dataIn;
USBEndpointDescriptor phone_interruptIn;
+ DFURT_IF_DESCRIPTOR_STRUCT;
+
} __attribute__ ((packed)) SIMTraceDriverConfigurationDescriptorMITM;
static const SIMTraceDriverConfigurationDescriptorMITM
@@ -585,7 +595,7 @@ static const SIMTraceDriverConfigurationDescriptorMITM
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 @@ static const SIMTraceDriverConfigurationDescriptorMITM
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 @@ void SIMtrace_USB_Initialize(void)
NVIC_EnableIRQ(UDP_IRQn);
}
+
+void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
+{
+ /* FIXME: integration with CCID control point reqeusts */
+ USBDFU_Runtime_RequestHandler(request);
+}