[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