summaryrefslogtreecommitdiff
path: root/usb-dfu-experiment/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'usb-dfu-experiment/main.c')
-rw-r--r--usb-dfu-experiment/main.c99
1 files changed, 93 insertions, 6 deletions
diff --git a/usb-dfu-experiment/main.c b/usb-dfu-experiment/main.c
index a939799..81f7e89 100644
--- a/usb-dfu-experiment/main.c
+++ b/usb-dfu-experiment/main.c
@@ -52,12 +52,16 @@
#include <utility/trace.h>
#include <utility/led.h>
+#include <memories/flash/flashd.h>
+
#include <usb/device/core/USBD.h>
#include <usb/device/core/USBDDriver.h>
#include <usb/device/dfu/dfu.h>
#include "dfu_desc.h"
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
/*----------------------------------------------------------------------------
* Definitions
*----------------------------------------------------------------------------*/
@@ -105,6 +109,14 @@ static volatile uint8_t isRecActive = 0;
/** VBus pin instance. */
static const Pin pinVbus = PIN_USB_VBUS;
+/* this needs to be in sync with usb-strings.txt !! */
+enum dfu_altif {
+ ALTIF_APP,
+ ALTIF_BOOT,
+ ALTIF_RAM,
+ ALTIF_FPGA
+};
+
/**
* Handles interrupts coming from PIO controllers.
*/
@@ -272,27 +284,99 @@ void USBDDriverCallbacks_InterfaceSettingChanged(unsigned char interface,
TRACE_INFO("DFU: IfSettingChgd(if=%u, alt=%u)\n\r", interface, setting);
}
-static int upl_first = 1;
+#define BOOT_FLASH_SIZE (16 * 1024)
+
+struct flash_part {
+ void *base_addr;
+ uint32_t size;
+};
+
+static const struct flash_part flash_parts[] = {
+ [ALTIF_BOOT] = {
+ .base_addr = AT91C_IFLASH0,
+ .size = BOOT_FLASH_SIZE,
+ },
+ [ALTIF_APP] = {
+ .base_addr = (AT91C_IFLASH + BOOT_FLASH_SIZE),
+ .size = (AT91C_IFLASH0_SIZE - BOOT_FLASH_SIZE),
+ },
+ [ALTIF_RAM] = {
+ .base_addr = AT91C_IRAM,
+ .size = AT91C_IRAM_SIZE,
+ },
+ [ALTIF_FPGA] = {
+ .base_addr = AT91C_IFLASH1,
+ .size = AT91C_IFLASH1_SIZE,
+ },
+};
/* DFU callback */
int USBDFU_handle_upload(uint8_t altif, unsigned int offset,
uint8_t *buf, unsigned int req_len)
{
+ struct flash_part *part;
+ void *end, *addr;
+ uint32_t real_len;
+
TRACE_INFO("DFU: handle_upload(%u, %u, %u)\n\r", altif, offset, req_len);
- if (upl_first) {
- upl_first = 0;
- return req_len;
- }
- return 4;
+ if (altif > ARRAY_SIZE(flash_parts))
+ return -EINVAL;
+
+ part = &flash_parts[altif];
+
+ addr = part->base_addr + offset;
+ end = part->base_addr + part->size;
+
+ real_len = end - addr;
+ if (req_len < real_len)
+ real_len = req_len;
+
+ memcpy(buf, addr, real_len);
+
+ return real_len;
}
/* DFU callback */
int USBDFU_handle_dnload(uint8_t altif, unsigned int offset,
uint8_t *buf, unsigned int len)
{
+ struct flash_part *part;
+ void *end, *addr;
+ int rc;
+
TRACE_INFO("DFU: handle_dnload(%u, %u, %u)\n\r", altif, offset, len);
+ if (altif > ARRAY_SIZE(flash_parts))
+ return -EINVAL;
+
+ part = &flash_parts[altif];
+
+ addr = part->base_addr + offset;
+ end = part->base_addr + part->size;
+
+ if (addr + len > end) {
+ TRACE_ERROR("Cannot write beyond end of DFU partition %u\n\r", altif);
+ dfu.status = DFU_STATUS_errADDRESS;
+ return DFU_RET_STALL;
+ }
+
+ switch (altif) {
+ case ALTIF_APP:
+ case ALTIF_FPGA:
+ rc = FLASHD_Write(addr, buf, len);
+ if (rc != 0) {
+ TRACE_ERROR("Error during write of DFU partition %u\n\r", altif);
+ dfu.status = DFU_STATUS_errPROG;
+ return DFU_RET_STALL;
+ }
+ break;
+ default:
+ TRACE_WARNING("Write to DFU partition %u not implemented\n\r", altif);
+ dfu.status = DFU_STATUS_errTARGET;
+ break;
+ }
+
return DFU_RET_ZLP;
}
@@ -300,6 +384,9 @@ int USBDFU_handle_dnload(uint8_t altif, unsigned int offset,
void dfu_drv_updstatus(void)
{
TRACE_INFO("DFU: updstatus()\n\r");
+
+ if (dfu.state == DFU_STATE_dfuMANIFEST_SYNC)
+ dfu.state = DFU_STATE_dfuMANIFEST;
}
/*----------------------------------------------------------------------------
personal git repositories of Harald Welte. Your mileage may vary