Signed-off-by: Andrzej Pietrasiewicz <andrze...@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.p...@samsung.com>
---
 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 <common.h>
+#include <dfu_backend.h>
+#include <flash_entity.h>
+
+/*
+ * 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 <common.h>
+#include <fat.h>
+#include <dfu_backend.h>
+
+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 <common.h>
+#include <mbr.h>
+#include <mmc.h>
+#include <dfu_backend.h>
+#include <flash_entity.h>
+
+#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 <andrze...@samsung.com>
+ *
+ * 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 <linux/compiler.h>
+
+#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

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to