diff options
Diffstat (limited to 'usb-dfu-experiment/main.c')
-rw-r--r-- | usb-dfu-experiment/main.c | 99 |
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; } /*---------------------------------------------------------------------------- |