+ /* calculate sector size */
+ sector_size = c->size / c->num_sectors;
+
+ /* check alignment */
+ if ((addr - c->base) % sector_size || length % sector_size)
+ return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+
+ first = (addr - c->base) / sector_size;
+ last = first + length / sector_size - 1;
+ return c->driver->erase(c, first, last);
+}
+
+int flash_write(target_t *target, image_t *image, u32 *image_size, char **error_str, u32 *failed)
+{
+ int section;
+ int retval;
+
+ *image_size = 0;
+
+ /* for each section in the image */
+ for (section = 0; section < image->num_sections; section++)
+ {
+ u32 offset = 0;
+ u32 address = image->sections[section].base_address;
+ u32 size = image->sections[section].size;
+
+ failed[section] = 0;
+
+ while (size != 0)
+ {
+ flash_bank_t *c;
+ u32 thisrun_size = size;
+ u32 size_read;
+ u8 *buffer;
+
+ /* find the corresponding flash bank */
+ if ((c = get_flash_bank_by_addr(target, address)) == NULL)
+ {
+ /* mark as failed, and skip the current section */
+ failed[section] = 1;
+ break;
+ }
+
+ /* check whether it fits, split into multiple runs if not */
+ if ((address + size) > (c->base + c->size))
+ thisrun_size = c->base + c->size - address;
+
+ buffer = malloc(thisrun_size);
+ if (((retval = image_read_section(image, section, offset, size, buffer, &size_read)) != ERROR_OK)
+ || (thisrun_size != size_read))
+ {
+ *error_str = malloc(FLASH_MAX_ERROR_STR);
+ snprintf(*error_str, FLASH_MAX_ERROR_STR, "error reading from image");
+ return ERROR_IMAGE_TEMPORARILY_UNAVAILABLE;
+ }
+
+ if ((retval = c->driver->write(c, buffer, address - c->base, thisrun_size)) != ERROR_OK)
+ {
+ /* mark the current section as failed */
+ failed[section] = 1;
+ *error_str = malloc(FLASH_MAX_ERROR_STR);
+ switch (retval)
+ {
+ case ERROR_TARGET_NOT_HALTED:
+ snprintf(*error_str, FLASH_MAX_ERROR_STR, "can't flash image while target is running");
+ break;
+ case ERROR_INVALID_ARGUMENTS:
+ snprintf(*error_str, FLASH_MAX_ERROR_STR, "flash driver can't fulfill request");
+ break;
+ case ERROR_FLASH_OPERATION_FAILED:
+ snprintf(*error_str, FLASH_MAX_ERROR_STR, "flash program error");
+ break;
+ case ERROR_FLASH_DST_BREAKS_ALIGNMENT:
+ snprintf(*error_str, FLASH_MAX_ERROR_STR, "offset breaks required alignment");
+ break;
+ case ERROR_FLASH_DST_OUT_OF_BANK:
+ snprintf(*error_str, FLASH_MAX_ERROR_STR, "no flash mapped at requested address");
+ break;
+ case ERROR_FLASH_SECTOR_NOT_ERASED:
+ snprintf(*error_str, FLASH_MAX_ERROR_STR, "destination sector(s) not erased");
+ break;
+ default:
+ snprintf(*error_str, FLASH_MAX_ERROR_STR, "unknown error: %i", retval);
+ }
+
+ free(buffer);
+
+ /* abort operation */
+ return retval;
+ }
+
+ free(buffer);
+
+ offset += thisrun_size;
+ address += thisrun_size;
+ size -= thisrun_size;
+ }
+
+ *image_size += image->sections[section].size;
+ }
+
+ return ERROR_OK;