From mboxrd@z Thu Jan 1 00:00:00 1970 From: Andrzej Pietrasiewicz Date: Wed, 09 Nov 2011 10:52:21 +0100 Subject: [U-Boot] [PATCH 2/4] dfu: generic backend parts In-Reply-To: <1320832343-21369-1-git-send-email-andrzej.p@samsung.com> References: <1320832343-21369-1-git-send-email-andrzej.p@samsung.com> Message-ID: <1320832343-21369-3-git-send-email-andrzej.p@samsung.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park --- Makefile | 1 + drivers/usb/dfu/Makefile | 33 ++++++++++++ drivers/usb/dfu/dfu.c | 109 ++++++++++++++++++++++++++++++++++++++++ drivers/usb/dfu/fat.c | 77 ++++++++++++++++++++++++++++ drivers/usb/dfu/mmc.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++ include/dfu_backend.h | 71 ++++++++++++++++++++++++++ include/mbr.h | 49 ++++++++++++++++++ 7 files changed, 464 insertions(+), 0 deletions(-) create mode 100644 drivers/usb/dfu/Makefile create mode 100644 drivers/usb/dfu/dfu.c create mode 100644 drivers/usb/dfu/fat.c create mode 100644 drivers/usb/dfu/mmc.c create mode 100644 include/dfu_backend.h create mode 100644 include/mbr.h diff --git a/Makefile b/Makefile index bd72286..83ea3d0 100644 --- a/Makefile +++ b/Makefile @@ -283,6 +283,7 @@ LIBS += drivers/usb/gadget/libusb_gadget.o LIBS += drivers/usb/host/libusb_host.o LIBS += drivers/usb/musb/libusb_musb.o LIBS += drivers/usb/phy/libusb_phy.o +LIBS += drivers/usb/dfu/libusb_dfu.o LIBS += drivers/video/libvideo.o LIBS += drivers/watchdog/libwatchdog.o LIBS += common/libcommon.o diff --git a/drivers/usb/dfu/Makefile b/drivers/usb/dfu/Makefile new file mode 100644 index 0000000..c2fe049 --- /dev/null +++ b/drivers/usb/dfu/Makefile @@ -0,0 +1,33 @@ +include $(TOPDIR)/config.mk + +LIB := $(obj)libusb_dfu.o + +# new USB gadget layer dependencies +COBJS-y += dfu.o + +ifdef CONFIG_MMC +COBJS-y += mmc.o +endif + +ifdef CONFIG_CMD_FAT +COBJS-y += fat.o +endif + +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### + diff --git a/drivers/usb/dfu/dfu.c b/drivers/usb/dfu/dfu.c new file mode 100644 index 0000000..2f5492d --- /dev/null +++ b/drivers/usb/dfu/dfu.c @@ -0,0 +1,109 @@ +#include +#include +#include + +/* + * Adapt transport layer buffer size to storage chunk size + * + * return < n to indicate no more data to read + */ +int read_block(void *ctx, unsigned int n, void *buf) +{ + struct flash_entity_ctx *ct = ctx; + unsigned int nread = 0; + + if (n == 0) + return n; + + while (nread < n) { + unsigned int copy; + + if (ct->num_done >= ct->length) + break; + if (ct->buffered == 0) { + ct->read(ct->buf, ct->buf_len, + ct->offset + ct->num_done); + ct->buffered = ct->buf_len; + } + copy = min(n - nread, ct->buffered); + + memcpy(buf + nread, ct->buf + ct->buf_len - ct->buffered, copy); + nread += copy; + ct->buffered -= copy; + ct->num_done += copy; + } + + return nread; +} + +/* + * Adapt transport layer buffer size to storage chunk size + */ +int write_block(void *ctx, unsigned int n, void *buf) +{ + struct flash_entity_ctx *ct = ctx; + unsigned int nwritten = 0; + + if (n == 0) + return n; + + while (nwritten < n) { + unsigned int copy; + + if (ct->num_done >= ct->length) + break; + if (ct->buffered >= ct->buf_len) { + ct->write(ct->buf, ct->buf_len, + ct->offset + ct->num_done); + ct->buffered = 0; + ct->num_done += ct->buf_len; + if (ct->num_done >= ct->length) + break; + } + copy = min(n - nwritten, ct->buf_len - ct->buffered); + + memcpy(ct->buf + ct->buffered, buf + nwritten, copy); + nwritten += copy; + ct->buffered += copy; + } + + return nwritten; +} + +/* + * Entity-specific prepare and finish + */ +static void reset_ctx(struct flash_entity_ctx *ctx) +{ + ctx->buffered = 0; + ctx->num_done = 0; +} + +int generic_prepare(void *ctx, u8 mode) +{ + struct flash_entity_ctx *ct = ctx; + + reset_ctx(ct); + memset(ct->buf, 0, ct->buf_len); + if (mode == FLASH_WRITE) { + if (ct->erase) { + printf("Erase entity: %s ", ct->this_entity->name); + ct->erase(ct->length, ct->offset); + } + printf("Write entity: %s ", ct->this_entity->name); + } else if (mode == FLASH_READ) { + printf("Read entity: %s ", ct->this_entity->name); + } + return 0; +} + +int generic_finish(void *ctx, u8 mode) +{ + struct flash_entity_ctx *ct = ctx; + + if (mode == FLASH_WRITE && ct->buffered > 0) + ct->write(ct->buf, ct->buffered, ct->offset + ct->num_done); + + return 0; +} + diff --git a/drivers/usb/dfu/fat.c b/drivers/usb/dfu/fat.c new file mode 100644 index 0000000..6f0125f --- /dev/null +++ b/drivers/usb/dfu/fat.c @@ -0,0 +1,77 @@ +#include +#include +#include + +static const char *fat_filename; +static int fat_part_num; +static block_dev_desc_t *fat_dev; + +inline int set_fat_part_num(int pnum) +{ + fat_part_num = pnum; + + return pnum; +} + +inline const char *set_fat_filename(const char *fn) +{ + fat_filename = fn; + + return fn; +} + +inline block_dev_desc_t *set_fat_dev(block_dev_desc_t *d) +{ + fat_dev = d; + + return d; +} + +int read_fat(void *buf, unsigned int len, unsigned long from) +{ + int ret; + + ret = fat_register_device(fat_dev, fat_part_num); + if (ret < 0) { + printf("error : fat_register_device\n"); + return 0; + } + printf("read up to %d B ", MMC_FAT_BLOCK_SZ); + return file_fat_read(fat_filename, buf, len); +} + +int write_fat(void *buf, unsigned int len, unsigned long from) +{ +#ifdef CONFIG_FAT_WRITE + int ret; + + ret = fat_register_device(fat_dev, fat_part_num); + if (ret < 0) { + printf("error : fat_register_divce\n"); + return 0; + } + + printf("write up to %d B ", MMC_FAT_BLOCK_SZ); + ret = file_fat_write(fat_filename, buf, len); + + /* format and write again */ + if (ret == 1) { + printf("formatting\n"); + if (mkfs_vfat(fat_dev, fat_part_num)) { + printf("error formatting device\n"); + return 0; + } + ret = file_fat_write(fat_filename, buf, len); + } + + if (ret < 0) { + printf("error : writing %s\n", fat_filename); + return 0; + } +#else + printf("error : FAT write not supported\n"); + return 0; +#endif + return len; +} + diff --git a/drivers/usb/dfu/mmc.c b/drivers/usb/dfu/mmc.c new file mode 100644 index 0000000..221d6ff --- /dev/null +++ b/drivers/usb/dfu/mmc.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include + +#define SIGNATURE ((unsigned short) 0xAA55) +#define PARAM_LEN 12 + +static int read_ebr(struct mmc *mmc, struct mbr_partition *mp, + int ebr_next, struct mbr_part_data *pd, int parts, + int *extended_lba, int mmc_mbr_dev) +{ + struct mbr *ebr; + struct mbr_partition *p; + char buf[512]; + int ret, i; + int lba = 0; + + if (ebr_next) + lba = *extended_lba; + + lba += mp->lba; + ret = mmc->block_dev.block_read(mmc_mbr_dev, lba, 1, buf); + if (ret != 1) + return 0; + + ebr = (struct mbr *) buf; + + if (ebr->signature != SIGNATURE) { + printf("Signature error 0x%x\n", ebr->signature); + return 0; + } + + for (i = 0; i < 2; i++) { + p = (struct mbr_partition *) &ebr->parts[i]; + + if (i == 0) { + lba += p->lba; + if (p->partition_type == 0x83) { + if (pd) { + pd[parts].offset = lba; + pd[parts].length = p->nsectors; + pd[parts].primary = 0; + } + parts++; + } + } + } + + if (p->lba && p->partition_type == 0x5) + parts = read_ebr(mmc, p, 1, pd, parts, extended_lba, mmc_mbr_dev); + + return parts; +} + +int read_mbr(struct mmc *mmc, struct mbr_part_data *pd, int *extended_lba, + int mmc_mbr_dev) +{ + struct mbr_partition *mp; + struct mbr *mbr; + char buf[512]; + int ret, i; + int parts = 0; + + ret = mmc->block_dev.block_read(mmc_mbr_dev, 0, 1, buf); + if (ret != 1) + return 0; + + mbr = (struct mbr *) buf; + + if (mbr->signature != SIGNATURE) { + printf("Signature error 0x%x\n", mbr->signature); + return 0; + } + + for (i = 0; i < 4; i++) { + mp = (struct mbr_partition *) &mbr->parts[i]; + + if (!mp->partition_type) + continue; + + if (mp->partition_type == 0x83) { + if (pd) { + pd[parts].offset = mp->lba; + pd[parts].length = mp->nsectors; + pd[parts].primary = 1; + } + parts++; + } + + if (mp->lba && mp->partition_type == 0x5) { + *extended_lba = mp->lba; + parts = read_ebr(mmc, mp, 0, pd, parts, extended_lba, mmc_mbr_dev); + } + } + + return parts; +} + +static int rw_mmc(void *buf, char *op, unsigned int len, unsigned long from) +{ + char ram_addr[PARAM_LEN]; + char offset[PARAM_LEN]; + char length[PARAM_LEN]; + char *argv[] = {"mmc", op, ram_addr, offset, length}; + + sprintf(ram_addr, "0x%lx", (unsigned long)buf); + sprintf(offset, "0x%lx", from / MMC_SECTOR_SZ); /* guaranteed integer */ + sprintf(length, "0x%x", (len + MMC_SECTOR_SZ - 1) / MMC_SECTOR_SZ); + + return do_mmcops(NULL, 0, 6, argv); +} + +inline int read_mmc(void *buf, unsigned int len, unsigned long from) +{ + return rw_mmc(buf, "read", len, from); +} + +inline int write_mmc(void *buf, unsigned int len, unsigned long from) +{ + return rw_mmc(buf, "write", len, from); +} + diff --git a/include/dfu_backend.h b/include/dfu_backend.h new file mode 100644 index 0000000..8c608d1 --- /dev/null +++ b/include/dfu_backend.h @@ -0,0 +1,71 @@ +/* + * dfu.h - Device Firmware Upgrade + * + * copyright (c) 2011 samsung electronics + * author: andrzej pietrasiewicz + * + * 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 + */ + +#ifndef __DFU_BACKEND_H__ +#define __DFU_BACKEND_H__ + +struct mbr_part_data { + unsigned long offset; /* #sectors from mmc begin */ + unsigned long length; /* #sectors in this partition*/ + u8 primary; /* != 0 if primary, 0 if extended */ +}; + +typedef int (*rw_op)(void *buf, unsigned int len, unsigned long from); +typedef int (*erase_op)(unsigned int len, unsigned long from); + +struct flash_entity_ctx { + unsigned long offset; /* offset into the device */ + unsigned long length; /* size of the entity */ + u8 *buf; /* buffer for one chunk */ + unsigned long buf_len; /* one chunk length */ + unsigned int buffered; /* # available bytes in buf */ + unsigned int num_done; /* total bytes handled */ + rw_op read; /* chunk read op for this medium */ + rw_op write; /* chunk write op for this medium */ + erase_op erase; /* erase op for this medium or NULL */ + struct flash_entity *this_entity; /* the containing entity */ + void *associated; /* related entity, if any */ +}; + +extern void board_dfu_init(void); +extern int board_dfu_cleanup(void); +extern int usb_gadget_handle_interrupts(void); + +extern int read_mmc(void *buf, unsigned int len, unsigned long from); +extern int write_mmc(void *buf, unsigned int len, unsigned long from); + +extern block_dev_desc_t *set_fat_dev(block_dev_desc_t *d); +extern int set_fat_part_num(int pnum); +extern const char *set_fat_filename(const char *fn); +extern int read_fat(void *buf, unsigned int len, unsigned long from); +extern int write_fat(void *buf, unsigned int len, unsigned long from); + +extern int read_mbr(struct mmc *mmc, struct mbr_part_data *pd, int *extended_lba, int mmc_mbr_dev); + +extern int read_block(void *ctx, unsigned int n, void *buf); +extern int write_block(void *ctx, unsigned int n, void *buf); +extern int generic_prepare(void *ctx, u8 mode); +extern int generic_finish(void *ctx, u8 mode); + +#define MMC_SECTOR_SZ 512 +#define MMC_FAT_BLOCK_SZ (4 * 1024 * 1024) + +#endif diff --git a/include/mbr.h b/include/mbr.h new file mode 100644 index 0000000..9cbeb2e --- /dev/null +++ b/include/mbr.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 Samsung Electrnoics + * + * 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 + +#define MBR_RESERVED_SIZE 0x8000 +#define MBR_START_OFS_BLK (0x500000 / 512) + +struct mbr_partition { + char status; + char f_chs[3]; + char partition_type; + char l_chs[3]; + int lba; + int nsectors; +} __packed; + +struct mbr { + char code_area[440]; + char disk_signature[4]; + char nulls[2]; + struct mbr_partition parts[4]; + unsigned short signature; +}; + +extern unsigned int mbr_offset[16]; +extern unsigned int mbr_parts; + +void set_mbr_dev(int dev); +void set_mbr_info(char *ramaddr, unsigned int len, unsigned int reserved); +void set_mbr_table(unsigned int start_addr, int parts, + unsigned int *blocks, unsigned int *part_offset); +int get_mbr_table(unsigned int *part_offset); -- 1.7.0.4