[U-Boot] [PATCH 2/4] dfu: generic backend parts
Andrzej Pietrasiewicz
andrzej.p at samsung.com
Wed Nov 9 10:52:21 CET 2011
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p at samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park at 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 <andrzej.p at 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
More information about the U-Boot
mailing list