Patchwork [U-Boot,3/7] dfu: DFU backend implementation

login
register
mail settings
Submitter Łukasz Majewski
Date July 3, 2012, 9:38 a.m.
Message ID <1341308291-14663-4-git-send-email-l.majewski@samsung.com>
Download mbox | patch
Permalink /patch/168750/
State Changes Requested
Headers show

Comments

Łukasz Majewski - July 3, 2012, 9:38 a.m.
New, separate driver at ./drivers/dfu has been added. It allows platform
and storage independent operation of DFU.

Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Vasut <marex@denx.de>
---
 Makefile             |    1 +
 drivers/dfu/Makefile |   43 ++++++++
 drivers/dfu/dfu.c    |  259 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/dfu.h        |   99 +++++++++++++++++++
 4 files changed, 402 insertions(+), 0 deletions(-)
 create mode 100644 drivers/dfu/Makefile
 create mode 100644 drivers/dfu/dfu.c
 create mode 100644 include/dfu.h
Marek Vasut - July 3, 2012, 9:28 p.m.
Dear Lukasz Majewski,

> New, separate driver at ./drivers/dfu has been added. It allows platform
> and storage independent operation of DFU.
> 
> Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Marek Vasut <marex@denx.de>
> ---

[...]

> +#include <common.h>
> +#include <malloc.h>
> +#include <mmc.h>
> +#include <fat.h>
> +#include <dfu.h>
> +#include <linux/list.h>
> +#include <linux/compiler.h>
> +
> +static LIST_HEAD(dfu_list);
> +static int dfu_alt_num;
> +
> +static int dfu_find_alt_num(char *s)
> +{
> +	int i = 0;
> +
> +	for (; *s; s++)
> +		if (*s == ';')
> +			i++;
> +
> +	return ++i;
> +}
> +
> +static char *dfu_extract_entity(char** env)
> +{
> +	char *s = *env;
> +
> +	strsep(env, ";");
> +	return s;
> +}

Shall we not make these all generic? They seem to be quite helpful components.

> +
> +char *dfu_extract_token(char** e, int *n)
> +{
> +	char *st = *e;
> +
> +	debug("%s: %s\n", __func__, st);
> +
> +	strsep(e, " ");
> +	*n = *e - st;
> +
> +	return st;
> +}
> +
> +static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE)
> +				     dfu_buf[DFU_DATA_BUF_SIZE];

Can we not stack-allocate it with ALLOC_CACHE_ALIGN_BUFFER()?

[...]

> diff --git a/include/dfu.h b/include/dfu.h
> new file mode 100644
> index 0000000..f7d823b
> --- /dev/null
> +++ b/include/dfu.h

[...]

> +struct dfu_entity {
> +	char			name[DFU_NAME_SIZE];
> +	int                     alt;
> +	void                    *dev_private;
> +	int                     dev_num;
> +	enum dfu_device_type    dev_type;
> +	enum dfu_layout         layout;
> +
> +	union {
> +		struct mmc_internal_data mmc;

This union seems redundant ;-)

[...]
Łukasz Majewski - July 4, 2012, 8:56 a.m.
Hi Marek,

> Dear Lukasz Majewski,
> 
> > New, separate driver at ./drivers/dfu has been added. It allows
> > platform and storage independent operation of DFU.
> > 
> > Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > Cc: Marek Vasut <marex@denx.de>
> > ---
> 
> [...]
> 
> > +#include <common.h>
> > +#include <malloc.h>
> > +#include <mmc.h>
> > +#include <fat.h>
> > +#include <dfu.h>
> > +#include <linux/list.h>
> > +#include <linux/compiler.h>
> > +
> > +static LIST_HEAD(dfu_list);
> > +static int dfu_alt_num;
> > +
> > +static int dfu_find_alt_num(char *s)
> > +{
> > +	int i = 0;
> > +
> > +	for (; *s; s++)
> > +		if (*s == ';')
> > +			i++;
> > +
> > +	return ++i;
> > +}
> > +
> > +static char *dfu_extract_entity(char** env)
> > +{
> > +	char *s = *env;
> > +
> > +	strsep(env, ";");
> > +	return s;
> > +}
> 
> Shall we not make these all generic? They seem to be quite helpful
> components.

It is a good topic for a discussion if those functions shall be moved
to ./lib/string.c. 
I regarded them as a "little" helper functions for parsing DFU alt
setting env variable. Those are very short and build with methods
exported from string.c

> 
> > +
> > +char *dfu_extract_token(char** e, int *n)
> > +{
> > +	char *st = *e;
> > +
> > +	debug("%s: %s\n", __func__, st);
> > +
> > +	strsep(e, " ");
> > +	*n = *e - st;
> > +
> > +	return st;
> > +}
> > +
> > +static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE)
> > +				     dfu_buf[DFU_DATA_BUF_SIZE];
> 
> Can we not stack-allocate it with ALLOC_CACHE_ALIGN_BUFFER()?

The dfu_buf is 4 MiB (this is the size of DFU_DATA_BUF_SIZE). I don't
think, that allocating it on the stack (for stack allocation the
ALLOC_CACHE_ALIGN_BUFFER() is designed) is a good idea.

> 
> [...]
> 
> > diff --git a/include/dfu.h b/include/dfu.h
> > new file mode 100644
> > index 0000000..f7d823b
> > --- /dev/null
> > +++ b/include/dfu.h
> 
> [...]
> 
> > +struct dfu_entity {
> > +	char			name[DFU_NAME_SIZE];
> > +	int                     alt;
> > +	void                    *dev_private;
> > +	int                     dev_num;
> > +	enum dfu_device_type    dev_type;
> > +	enum dfu_layout         layout;
> > +
> > +	union {
> > +		struct mmc_internal_data mmc;
> 
> This union seems redundant ;-)

Good point :-), but I predict, that DFU will be used to program other
memory types (OneNAND, or NAND). To support those, one needs to extend
the union with e.g struct onenand_internal_data onenand.

Since we don't have so many memory types, I think that union usage is
acceptable. 

> 
> [...]
Marek Vasut - July 4, 2012, 2:36 p.m.
Dear Lukasz Majewski,

> Hi Marek,
> 
> > Dear Lukasz Majewski,
> > 
> > > New, separate driver at ./drivers/dfu has been added. It allows
> > > platform and storage independent operation of DFU.
> > > 
> > > Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
> > > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > > Cc: Marek Vasut <marex@denx.de>
> > > ---
> > 
> > [...]
> > 
> > > +#include <common.h>
> > > +#include <malloc.h>
> > > +#include <mmc.h>
> > > +#include <fat.h>
> > > +#include <dfu.h>
> > > +#include <linux/list.h>
> > > +#include <linux/compiler.h>
> > > +
> > > +static LIST_HEAD(dfu_list);
> > > +static int dfu_alt_num;
> > > +
> > > +static int dfu_find_alt_num(char *s)
> > > +{
> > > +	int i = 0;
> > > +
> > > +	for (; *s; s++)
> > > +		if (*s == ';')
> > > +			i++;
> > > +
> > > +	return ++i;
> > > +}
> > > +
> > > +static char *dfu_extract_entity(char** env)
> > > +{
> > > +	char *s = *env;
> > > +
> > > +	strsep(env, ";");
> > > +	return s;
> > > +}
> > 
> > Shall we not make these all generic? They seem to be quite helpful
> > components.
> 
> It is a good topic for a discussion if those functions shall be moved
> to ./lib/string.c.
> I regarded them as a "little" helper functions for parsing DFU alt
> setting env variable. Those are very short and build with methods
> exported from string.c

Good point

> > > +
> > > +char *dfu_extract_token(char** e, int *n)
> > > +{
> > > +	char *st = *e;
> > > +
> > > +	debug("%s: %s\n", __func__, st);
> > > +
> > > +	strsep(e, " ");
> > > +	*n = *e - st;
> > > +
> > > +	return st;
> > > +}
> > > +
> > > +static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE)
> > > +				     dfu_buf[DFU_DATA_BUF_SIZE];
> > 
> > Can we not stack-allocate it with ALLOC_CACHE_ALIGN_BUFFER()?
> 
> The dfu_buf is 4 MiB (this is the size of DFU_DATA_BUF_SIZE). I don't
> think, that allocating it on the stack (for stack allocation the
> ALLOC_CACHE_ALIGN_BUFFER() is designed) is a good idea.

Heh, agreed :-)

> > [...]
> > 
> > > diff --git a/include/dfu.h b/include/dfu.h
> > > new file mode 100644
> > > index 0000000..f7d823b
> > > --- /dev/null
> > > +++ b/include/dfu.h
> > 
> > [...]
> > 
> > > +struct dfu_entity {
> > > +	char			name[DFU_NAME_SIZE];
> > > +	int                     alt;
> > > +	void                    *dev_private;
> > > +	int                     dev_num;
> > > +	enum dfu_device_type    dev_type;
> > > +	enum dfu_layout         layout;
> > > +
> > > +	union {
> > > +		struct mmc_internal_data mmc;
> > 
> > This union seems redundant ;-)
> 
> Good point :-), but I predict, that DFU will be used to program other
> memory types (OneNAND, or NAND). To support those, one needs to extend
> the union with e.g struct onenand_internal_data onenand.
> 
> Since we don't have so many memory types, I think that union usage is
> acceptable.

And will those pieces be implemented any soon ? :)

> > [...]

Best regards,
Marek Vasut
Łukasz Majewski - July 4, 2012, 3:07 p.m.
Hi Marek,

> Dear Lukasz Majewski,
> 
> > Hi Marek,
> > 
> > > Dear Lukasz Majewski,
> > > 
> > > > New, separate driver at ./drivers/dfu has been added. It allows
> > > > platform and storage independent operation of DFU.
> > > > 
> > > > Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
> > > > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > > > Cc: Marek Vasut <marex@denx.de>
> > > > ---
> > > 
> > > [...]
> > > 
> > > > +#include <common.h>
> > > > +#include <malloc.h>
> > > > +#include <mmc.h>
> > > > +#include <fat.h>
> > > > +#include <dfu.h>
> > > > +#include <linux/list.h>
> > > > +#include <linux/compiler.h>
> > > > +
> > > > +static LIST_HEAD(dfu_list);
> > > > +static int dfu_alt_num;
> > > > +
> > > > +static int dfu_find_alt_num(char *s)
> > > > +{
> > > > +	int i = 0;
> > > > +
> > > > +	for (; *s; s++)
> > > > +		if (*s == ';')
> > > > +			i++;
> > > > +
> > > > +	return ++i;
> > > > +}
> > > > +
> > > > +static char *dfu_extract_entity(char** env)
> > > > +{
> > > > +	char *s = *env;
> > > > +
> > > > +	strsep(env, ";");
> > > > +	return s;
> > > > +}
> > > 
> > > Shall we not make these all generic? They seem to be quite helpful
> > > components.
> > 
> > It is a good topic for a discussion if those functions shall be
> > moved to ./lib/string.c.
> > I regarded them as a "little" helper functions for parsing DFU alt
> > setting env variable. Those are very short and build with methods
> > exported from string.c
> 
> Good point
> 
> > > > +
> > > > +char *dfu_extract_token(char** e, int *n)
> > > > +{
> > > > +	char *st = *e;
> > > > +
> > > > +	debug("%s: %s\n", __func__, st);
> > > > +
> > > > +	strsep(e, " ");
> > > > +	*n = *e - st;
> > > > +
> > > > +	return st;
> > > > +}
> > > > +
> > > > +static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE)
> > > > +
> > > > dfu_buf[DFU_DATA_BUF_SIZE];
> > > 
> > > Can we not stack-allocate it with ALLOC_CACHE_ALIGN_BUFFER()?
> > 
> > The dfu_buf is 4 MiB (this is the size of DFU_DATA_BUF_SIZE). I
> > don't think, that allocating it on the stack (for stack allocation
> > the ALLOC_CACHE_ALIGN_BUFFER() is designed) is a good idea.
> 
> Heh, agreed :-)
> 
> > > [...]
> > > 
> > > > diff --git a/include/dfu.h b/include/dfu.h
> > > > new file mode 100644
> > > > index 0000000..f7d823b
> > > > --- /dev/null
> > > > +++ b/include/dfu.h
> > > 
> > > [...]
> > > 
> > > > +struct dfu_entity {
> > > > +	char			name[DFU_NAME_SIZE];
> > > > +	int                     alt;
> > > > +	void                    *dev_private;
> > > > +	int                     dev_num;
> > > > +	enum dfu_device_type    dev_type;
> > > > +	enum dfu_layout         layout;
> > > > +
> > > > +	union {
> > > > +		struct mmc_internal_data mmc;
> > > 
> > > This union seems redundant ;-)
> > 
> > Good point :-), but I predict, that DFU will be used to program
> > other memory types (OneNAND, or NAND). To support those, one needs
> > to extend the union with e.g struct onenand_internal_data onenand.
> > 
> > Since we don't have so many memory types, I think that union usage
> > is acceptable.
> 
> And will those pieces be implemented any soon ? :)

:-). Since I'm the OneNAND custodian I shall keep in the back of my
head, that support for this memory is important :-)

> 
> > > [...]
> 
> Best regards,
> Marek Vasut
Marek Vasut - July 4, 2012, 4:22 p.m.
Dear Lukasz Majewski,

[...]

> > 
> > And will those pieces be implemented any soon ? :)
> :
> :-). Since I'm the OneNAND custodian I shall keep in the back of my
> 
> head, that support for this memory is important :-)

Good, will look forward to it :)


Best regards,
Marek Vasut
Mike Frysinger - July 20, 2012, 4:32 a.m.
On Tuesday 03 July 2012 05:38:07 Lukasz Majewski wrote:
> +		puts("UPLOAD ... done\n");
> +		puts("Ctrl+C to exit ...\n");

combine into a single puts() ?

> +static int dfu_fill_entity(struct dfu_entity *dfu, char* s, int alt,
> +			    char *interface, int num)
> +{
> +	char *st = NULL;
> +	int n = 0;
> +
> +	debug("%s: %s interface: %s num: %d\n", __func__, s, interface, num);
> +
> +	st = dfu_extract_token(&s, &n);
> +	strncpy((char *) &dfu->name, st, n);

what's with the pointless cast ?  just do:
	strncpy(dfu->name, st, n);

also, "n" here is wrong.  it should be sizeof(dfu->name), not (presumably) the 
length of st.  considering this is the 2nd time i noticed this bug in the dfu 
patchset, you might want to do a grep on your patches to see if your other 
string related usage is wrong.

> +void dfu_free_entities(void)
> +{
> +	struct dfu_entity *dfu = NULL, *p = NULL;

no point in assigning to NULL here

> +static char *dfu_get_dev_type(enum dfu_device_type t)

static const char *...

> +{
> +	static char *dev_t[] = {NULL, "MMC", "ONENAND", "NAND" };

static const char * const dev_t[] = {...}

> +static char *dfu_get_layout(enum dfu_device_type l)

static const char *...

> +{
> +	static char *dfu_layout[] = {NULL, "RAW_ADDR", "FAT", "EXT" };

static const char * const dfu_layout[] = {...}

> +void dfu_show_entities(void)
> +{
> +	struct dfu_entity *dfu = NULL;

no point in assigning to NULL

> +struct dfu_entity *dfu_get_entity(int alt)
> +{
> +	struct dfu_entity *dfu = NULL;

no point in assigning to NULL
-mike
Łukasz Majewski - July 23, 2012, 4:11 p.m.
Dear Mike Frysinger,

> On Tuesday 03 July 2012 05:38:07 Lukasz Majewski wrote:
> > +		puts("UPLOAD ... done\n");
> > +		puts("Ctrl+C to exit ...\n");
> 
> combine into a single puts() ?
Ok, will be done
> 
> > +static int dfu_fill_entity(struct dfu_entity *dfu, char* s, int
> > alt,
> > +			    char *interface, int num)
> > +{
> > +	char *st = NULL;
> > +	int n = 0;
> > +
> > +	debug("%s: %s interface: %s num: %d\n", __func__, s,
> > interface, num); +
> > +	st = dfu_extract_token(&s, &n);
> > +	strncpy((char *) &dfu->name, st, n);
> 
> what's with the pointless cast ?  just do:
> 	strncpy(dfu->name, st, n);
Yes, you are right.

> 
> also, "n" here is wrong.  it should be sizeof(dfu->name), not
> (presumably) the length of st.  considering this is the 2nd time i
> noticed this bug in the dfu patchset, you might want to do a grep on
> your patches to see if your other string related usage is wrong.

I will double-check the string operations.

> 
> > +void dfu_free_entities(void)
> > +{
> > +	struct dfu_entity *dfu = NULL, *p = NULL;
> 
> no point in assigning to NULL here

Will remove.
> 
> > +static char *dfu_get_dev_type(enum dfu_device_type t)
> 
> static const char *...
Will correct.
> 
> > +{
> > +	static char *dev_t[] = {NULL, "MMC", "ONENAND", "NAND" };
> 
> static const char * const dev_t[] = {...}
Ok
> 
> > +static char *dfu_get_layout(enum dfu_device_type l)
> 
> static const char *...
> 
Ok
> > +{
> > +	static char *dfu_layout[] = {NULL, "RAW_ADDR", "FAT",
> > "EXT" };
> 
> static const char * const dfu_layout[] = {...}
> 
OK
> > +void dfu_show_entities(void)
> > +{
> > +	struct dfu_entity *dfu = NULL;
> 
> no point in assigning to NULL
OK
> 
> > +struct dfu_entity *dfu_get_entity(int alt)
> > +{
> > +	struct dfu_entity *dfu = NULL;
> 
> no point in assigning to NULL
OK
> -mike

Patch

diff --git a/Makefile b/Makefile
index 0197239..c37dcf3 100644
--- a/Makefile
+++ b/Makefile
@@ -271,6 +271,7 @@  LIBS += drivers/pci/libpci.o
 LIBS += drivers/pcmcia/libpcmcia.o
 LIBS += drivers/power/libpower.o
 LIBS += drivers/spi/libspi.o
+LIBS += drivers/dfu/libdfu.o
 ifeq ($(CPU),mpc83xx)
 LIBS += drivers/qe/libqe.o
 LIBS += arch/powerpc/cpu/mpc8xxx/ddr/libddr.o
diff --git a/drivers/dfu/Makefile b/drivers/dfu/Makefile
new file mode 100644
index 0000000..7736485
--- /dev/null
+++ b/drivers/dfu/Makefile
@@ -0,0 +1,43 @@ 
+#
+# Copyright (C) 2012 Samsung Electronics
+# Lukasz Majewski <l.majewski@samsung.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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 $(TOPDIR)/config.mk
+
+LIB	= $(obj)libdfu.o
+
+COBJS-$(CONFIG_DFU_FUNCTION) += dfu.o
+
+SRCS    := $(COBJS-y:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS-y))
+
+$(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/dfu/dfu.c b/drivers/dfu/dfu.c
new file mode 100644
index 0000000..63733fb
--- /dev/null
+++ b/drivers/dfu/dfu.c
@@ -0,0 +1,259 @@ 
+/*
+ * dfu.c -- DFU back-end routines
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * authors: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *	    Lukasz Majewski <l.majewski@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
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <fat.h>
+#include <dfu.h>
+#include <linux/list.h>
+#include <linux/compiler.h>
+
+static LIST_HEAD(dfu_list);
+static int dfu_alt_num;
+
+static int dfu_find_alt_num(char *s)
+{
+	int i = 0;
+
+	for (; *s; s++)
+		if (*s == ';')
+			i++;
+
+	return ++i;
+}
+
+static char *dfu_extract_entity(char** env)
+{
+	char *s = *env;
+
+	strsep(env, ";");
+	return s;
+}
+
+char *dfu_extract_token(char** e, int *n)
+{
+	char *st = *e;
+
+	debug("%s: %s\n", __func__, st);
+
+	strsep(e, " ");
+	*n = *e - st;
+
+	return st;
+}
+
+static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE)
+				     dfu_buf[DFU_DATA_BUF_SIZE];
+
+int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num)
+{
+	static unsigned char *i_buf;
+	static int i_blk_seq_num;
+	long w_size = 0;
+	int ret = 0;
+
+	debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x i_buf: 0x%p\n",
+	       __func__, dfu->name, buf, size, blk_seq_num, i_buf);
+
+	if (blk_seq_num == 0) {
+		memset(dfu_buf, '\0', sizeof(dfu_buf));
+		i_buf = dfu_buf;
+		i_blk_seq_num = 0;
+	}
+
+	if (i_blk_seq_num++ != blk_seq_num) {
+		printf("%s: Wrong sequence number! [%d] [%d]\n",
+		       __func__, i_blk_seq_num, blk_seq_num);
+		return -1;
+	}
+
+	memcpy(i_buf, buf, size);
+	i_buf += size;
+
+	if (size == 0) {
+		/* Integrity check (if needed) */
+		debug("%s: %s %d [B] CRC32: 0x%x\n", __func__, dfu->name,
+		       i_buf - dfu_buf, crc32(0, dfu_buf, i_buf - dfu_buf));
+
+		w_size = i_buf - dfu_buf;
+		ret = dfu->write_medium(dfu, dfu_buf, &w_size);
+		if (ret)
+			debug("%s: Write error!\n", __func__);
+
+		i_blk_seq_num = 0;
+		i_buf = NULL;
+		return ret;
+	}
+
+	return ret;
+}
+
+int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num)
+{
+	static unsigned char *i_buf;
+	static int i_blk_seq_num;
+	static long r_size;
+	static u32 crc;
+	int ret = 0;
+
+	debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x i_buf: 0x%p\n",
+	       __func__, dfu->name, buf, size, blk_seq_num, i_buf);
+
+	if (blk_seq_num == 0) {
+		i_buf = dfu_buf;
+		memset(dfu_buf, '\0', sizeof(dfu_buf));
+		ret = dfu->read_medium(dfu, i_buf, &r_size);
+		debug("%s: %s %ld [B]\n", __func__, dfu->name, r_size);
+		i_blk_seq_num = 0;
+		/* Integrity check (if needed) */
+		crc = crc32(0, dfu_buf, r_size);
+	}
+
+	if (i_blk_seq_num++ != blk_seq_num) {
+		printf("%s: Wrong sequence number! [%d] [%d]\n",
+		       __func__, i_blk_seq_num, blk_seq_num);
+		return -1;
+	}
+
+	if (r_size >= size) {
+		memcpy(buf, i_buf, size);
+		i_buf += size;
+		r_size -= size;
+		return size;
+	} else {
+		memcpy(buf, i_buf, r_size);
+		i_buf += r_size;
+		debug("%s: %s CRC32: 0x%x\n", __func__, dfu->name, crc);
+		puts("UPLOAD ... done\n");
+		puts("Ctrl+C to exit ...\n");
+
+		i_buf = NULL;
+		i_blk_seq_num = 0;
+		crc = 0;
+		return r_size;
+	}
+	return ret;
+}
+
+static int dfu_fill_entity(struct dfu_entity *dfu, char* s, int alt,
+			    char *interface, int num)
+{
+	char *st = NULL;
+	int n = 0;
+
+	debug("%s: %s interface: %s num: %d\n", __func__, s, interface, num);
+
+	st = dfu_extract_token(&s, &n);
+	strncpy((char *) &dfu->name, st, n);
+
+	dfu->dev_num = num;
+	dfu->alt = alt;
+
+	/* Specific for mmc device */
+	if (strcmp(interface, "mmc") == 0) {
+		if (dfu_fill_entity_mmc(dfu, s))
+			return -1;
+	} else {
+		printf("dfu: Device %s not supported\n", interface);
+		return -1;
+	}
+
+	return 0;
+}
+
+int dfu_config_entities(char *env, char *interface, int num)
+{
+	struct dfu_entity *dfu;
+	int i, ret;
+	char *s;
+
+	dfu_alt_num = dfu_find_alt_num(env);
+	debug("%s: dfu_alt_num=%d\n", __func__, dfu_alt_num);
+
+	for (i = 0; i < dfu_alt_num; i++) {
+		dfu = calloc(sizeof(struct dfu_entity), 1);
+
+		s = dfu_extract_entity(&env);
+		ret = dfu_fill_entity(dfu, s, i, interface, num);
+		if (ret)
+			return -1;
+
+		list_add_tail(&dfu->list, &dfu_list);
+	}
+
+	return 0;
+}
+
+void dfu_free_entities(void)
+{
+	struct dfu_entity *dfu = NULL, *p = NULL;
+
+	list_for_each_entry_safe_reverse(dfu, p, &dfu_list, list) {
+		list_del(&dfu->list);
+		free(dfu);
+	}
+
+	INIT_LIST_HEAD(&dfu_list);
+}
+
+static char *dfu_get_dev_type(enum dfu_device_type t)
+{
+	static char *dev_t[] = {NULL, "MMC", "ONENAND", "NAND" };
+	return dev_t[t];
+}
+
+static char *dfu_get_layout(enum dfu_device_type l)
+{
+	static char *dfu_layout[] = {NULL, "RAW_ADDR", "FAT", "EXT" };
+	return dfu_layout[l];
+}
+
+void dfu_show_entities(void)
+{
+	struct dfu_entity *dfu = NULL;
+
+	puts("DFU alt settings list:\n");
+
+	list_for_each_entry(dfu, &dfu_list, list) {
+		printf("dev: %s alt: %d name: %s layout: %s\n",
+		       dfu_get_dev_type(dfu->dev_type), dfu->alt,
+		       dfu->name, dfu_get_layout(dfu->layout));
+	}
+}
+
+int dfu_get_alt_number(void)
+{
+	return dfu_alt_num;
+}
+
+struct dfu_entity *dfu_get_entity(int alt)
+{
+	struct dfu_entity *dfu = NULL;
+
+	list_for_each_entry(dfu, &dfu_list, list) {
+		if (dfu->alt == alt)
+			return dfu;
+	}
+
+	return NULL;
+}
diff --git a/include/dfu.h b/include/dfu.h
new file mode 100644
index 0000000..f7d823b
--- /dev/null
+++ b/include/dfu.h
@@ -0,0 +1,99 @@ 
+/*
+ * dfu.h - DFU flashable area description
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * authors: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *	    Lukasz Majewski <l.majewski@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_ENTITY_H_
+#define __DFU_ENTITY_H_
+
+#include <common.h>
+#include <linux/list.h>
+#include <mmc.h>
+
+enum dfu_device_type {
+	MMC = 1,
+	ONENAND,
+	NAND
+};
+
+enum dfu_layout {
+	RAW_ADDR = 1,
+	FAT,
+	EXT,
+};
+
+struct mmc_internal_data {
+	/* RAW programming */
+	unsigned int lba_start;
+	unsigned int lba_size;
+	unsigned int lba_blk_size;
+
+	/* FAT/EXT */
+	unsigned int dev;
+	unsigned int part;
+};
+
+static inline unsigned int get_mmc_blk_size(int dev)
+{
+	return find_mmc_device(dev)->read_bl_len;
+}
+
+#define DFU_NAME_SIZE 32
+#define DFU_CMD_BUF_SIZE 128
+#define DFU_DATA_BUF_SIZE (1024*1024*4) /* 4 MiB */
+
+struct dfu_entity {
+	char			name[DFU_NAME_SIZE];
+	int                     alt;
+	void                    *dev_private;
+	int                     dev_num;
+	enum dfu_device_type    dev_type;
+	enum dfu_layout         layout;
+
+	union {
+		struct mmc_internal_data mmc;
+	} data;
+
+	int (*read_medium)(struct dfu_entity *dfu, void *buf, long *len);
+	int (*write_medium)(struct dfu_entity *dfu, void *buf, long *len);
+
+	struct list_head list;
+};
+
+int dfu_config_entities(char *s, char *interface, int num);
+void dfu_free_entities(void);
+void dfu_show_entities(void);
+int dfu_get_alt_number(void);
+struct dfu_entity *dfu_get_entity(int alt);
+char *dfu_extract_token(char** e, int *n);
+
+int dfu_read(struct dfu_entity *de, void *buf, int size, int blk_seq_num);
+int dfu_write(struct dfu_entity *de, void *buf, int size, int blk_seq_num);
+/* Device specific */
+#ifdef CONFIG_DFU_MMC
+extern int dfu_fill_entity_mmc(struct dfu_entity *dfu, char* s);
+#else
+static inline int dfu_fill_entity_mmc(struct dfu_entity *dfu, char* s)
+{
+	puts("MMC support not available!\n");
+	return -1;
+}
+#endif
+#endif /* __DFU_ENTITY_H_ */