diff options
Diffstat (limited to 'drivers/dfu/dfu_mmc.c')
-rw-r--r-- | drivers/dfu/dfu_mmc.c | 108 |
1 files changed, 72 insertions, 36 deletions
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index 083d745..e2f3978 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -22,6 +22,7 @@ #include <common.h> #include <malloc.h> #include <errno.h> +#include <div64.h> #include <dfu.h> enum dfu_mmc_op { @@ -29,32 +30,51 @@ enum dfu_mmc_op { DFU_OP_WRITE, }; +static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE) + dfu_file_buf[CONFIG_SYS_DFU_MAX_FILE_SIZE]; +static long dfu_file_buf_len; + static int mmc_block_op(enum dfu_mmc_op op, struct dfu_entity *dfu, - void *buf, long *len) + u64 offset, void *buf, long *len) { char cmd_buf[DFU_CMD_BUF_SIZE]; + u32 blk_start, blk_count; + + /* + * We must ensure that we work in lba_blk_size chunks, so ALIGN + * this value. + */ + *len = ALIGN(*len, dfu->data.mmc.lba_blk_size); + + blk_start = dfu->data.mmc.lba_start + + (u32)lldiv(offset, dfu->data.mmc.lba_blk_size); + blk_count = *len / dfu->data.mmc.lba_blk_size; + if (blk_start + blk_count > + dfu->data.mmc.lba_start + dfu->data.mmc.lba_size) { + puts("Request would exceed designated area!\n"); + return -EINVAL; + } - sprintf(cmd_buf, "mmc %s 0x%x %x %x", + sprintf(cmd_buf, "mmc %s %p %x %x", op == DFU_OP_READ ? "read" : "write", - (unsigned int) buf, - dfu->data.mmc.lba_start, - dfu->data.mmc.lba_size); - - if (op == DFU_OP_READ) - *len = dfu->data.mmc.lba_blk_size * dfu->data.mmc.lba_size; + buf, blk_start, blk_count); debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf); return run_command(cmd_buf, 0); } -static inline int mmc_block_write(struct dfu_entity *dfu, void *buf, long *len) +static int mmc_file_buffer(struct dfu_entity *dfu, void *buf, long *len) { - return mmc_block_op(DFU_OP_WRITE, dfu, buf, len); -} + if (dfu_file_buf_len + *len > CONFIG_SYS_DFU_MAX_FILE_SIZE) { + dfu_file_buf_len = 0; + return -EINVAL; + } -static inline int mmc_block_read(struct dfu_entity *dfu, void *buf, long *len) -{ - return mmc_block_op(DFU_OP_READ, dfu, buf, len); + /* Add to the current buffer. */ + memcpy(dfu_file_buf + dfu_file_buf_len, buf, *len); + dfu_file_buf_len += *len; + + return 0; } static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu, @@ -66,20 +86,23 @@ static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu, switch (dfu->layout) { case DFU_FS_FAT: - sprintf(cmd_buf, "fat%s mmc %d:%d 0x%x %s %lx", + sprintf(cmd_buf, "fat%s mmc %d:%d 0x%x %s", op == DFU_OP_READ ? "load" : "write", dfu->data.mmc.dev, dfu->data.mmc.part, - (unsigned int) buf, dfu->name, *len); + (unsigned int) buf, dfu->name); + if (op == DFU_OP_WRITE) + sprintf(cmd_buf + strlen(cmd_buf), " %lx", *len); break; case DFU_FS_EXT4: - sprintf(cmd_buf, "ext4%s mmc %d:%d /%s 0x%x %ld", + sprintf(cmd_buf, "ext4%s mmc %d:%d 0x%x /%s", op == DFU_OP_READ ? "load" : "write", dfu->data.mmc.dev, dfu->data.mmc.part, - dfu->name, (unsigned int) buf, *len); + (unsigned int) buf, dfu->name); break; default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, dfu_get_layout(dfu->layout)); + return -1; } debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf); @@ -102,27 +125,18 @@ static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu, return ret; } -static inline int mmc_file_write(struct dfu_entity *dfu, void *buf, long *len) -{ - return mmc_file_op(DFU_OP_WRITE, dfu, buf, len); -} - -static inline int mmc_file_read(struct dfu_entity *dfu, void *buf, long *len) -{ - return mmc_file_op(DFU_OP_READ, dfu, buf, len); -} - -int dfu_write_medium_mmc(struct dfu_entity *dfu, void *buf, long *len) +int dfu_write_medium_mmc(struct dfu_entity *dfu, + u64 offset, void *buf, long *len) { int ret = -1; switch (dfu->layout) { case DFU_RAW_ADDR: - ret = mmc_block_write(dfu, buf, len); + ret = mmc_block_op(DFU_OP_WRITE, dfu, offset, buf, len); break; case DFU_FS_FAT: case DFU_FS_EXT4: - ret = mmc_file_write(dfu, buf, len); + ret = mmc_file_buffer(dfu, buf, len); break; default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, @@ -132,17 +146,34 @@ int dfu_write_medium_mmc(struct dfu_entity *dfu, void *buf, long *len) return ret; } -int dfu_read_medium_mmc(struct dfu_entity *dfu, void *buf, long *len) +int dfu_flush_medium_mmc(struct dfu_entity *dfu) +{ + int ret = 0; + + if (dfu->layout != DFU_RAW_ADDR) { + /* Do stuff here. */ + ret = mmc_file_op(DFU_OP_WRITE, dfu, &dfu_file_buf, + &dfu_file_buf_len); + + /* Now that we're done */ + dfu_file_buf_len = 0; + } + + return ret; +} + +int dfu_read_medium_mmc(struct dfu_entity *dfu, u64 offset, void *buf, + long *len) { int ret = -1; switch (dfu->layout) { case DFU_RAW_ADDR: - ret = mmc_block_read(dfu, buf, len); + ret = mmc_block_op(DFU_OP_READ, dfu, offset, buf, len); break; case DFU_FS_FAT: case DFU_FS_EXT4: - ret = mmc_file_read(dfu, buf, len); + ret = mmc_file_op(DFU_OP_READ, dfu, buf, len); break; default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, @@ -181,14 +212,15 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s) mmc = find_mmc_device(dev); if (mmc == NULL || mmc_init(mmc)) { - printf("%s: could not find mmc device #%d!\n", __func__, dev); + printf("%s: could not find mmc device #%d!\n", + __func__, dev); return -ENODEV; } blk_dev = &mmc->block_dev; if (get_partition_info(blk_dev, part, &partinfo) != 0) { printf("%s: could not find partition #%d on mmc device #%d!\n", - __func__, part, dev); + __func__, part, dev); return -ENODEV; } @@ -208,6 +240,10 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s) dfu->read_medium = dfu_read_medium_mmc; dfu->write_medium = dfu_write_medium_mmc; + dfu->flush_medium = dfu_flush_medium_mmc; + + /* initial state */ + dfu->inited = 0; return 0; } |