All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v3 0/5] Android Fastboot support
@ 2014-04-10 19:18 Rob Herring
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 1/5] common: introduce maximum load size Rob Herring
                   ` (8 more replies)
  0 siblings, 9 replies; 59+ messages in thread
From: Rob Herring @ 2014-04-10 19:18 UTC (permalink / raw)
  To: u-boot

From: Rob Herring <robh@kernel.org>

I'm reviving the Android Fastboot support after 2+ years since the last 
posting[1]. The previous postings had some questions about licensing and 
source of some code. I believe I've traced the history sufficiently that 
the copyrights and source information are complete and correct.

The Android code used or referenced is BSD 2-clause license. This was 
originally raised by Wolfgang that it was not compatible with GPLv2+. I 
believe that has since been demonstrated and agreed that the BSD 
2-clause license is compatible with u-boot. 

As far as the history of the code, I have traced that back. The u-boot 
code started in 2008/2009 by Tom Rix @ Windriver. This initial support 
was then adopted and extended by TI (eMMC support primarily, not 
included here) in their OMAP u-boot tree[2]. In 2011, the TI code was 
used as a basis for upstream patches by Sebastian Siewior @ Linutronix. 
The code has been rearranged quite a bit since the original, but the 
content is pretty much the same. Some of the re-arranging left stale or 
missing copyrights in the v2 version which I have corrected.

I've reworked the previous version to make enabling board support more 
simple including re-using the existing settings for image loading 
address.

I've tested this series on a BeagleBoard.

Rob

[1] http://lists.denx.de/pipermail/u-boot/2011-November/110557.html
[2] http://git.omapzoom.org/?p=repo/u-boot.git;a=commit;h=601ff71c8d46b5e90e13613974a16d10f2006bb3

Rob Herring (3):
  common: introduce maximum load size
  usb: handle NULL table in usb_gadget_get_string
  arm: beagle: enable Android fastboot support

Sebastian Siewior (2):
  image: add support for Android's boot image format
  usb/gadget: add the fastboot gadget

 README                               |   3 +
 common/Makefile                      |   3 +
 common/board_r.c                     |   1 +
 common/cmd_bootm.c                   |  23 +-
 common/cmd_fastboot.c                |  36 +++
 common/image-android.c               |  84 ++++++
 common/image.c                       |  37 ++-
 doc/README.android-fastboot          |  86 ++++++
 doc/README.android-fastboot-protocol | 170 +++++++++++
 drivers/usb/gadget/Makefile          |   1 +
 drivers/usb/gadget/f_fastboot.c      | 535 +++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/g_fastboot.h      |  15 +
 drivers/usb/gadget/u_fastboot.c      | 260 +++++++++++++++++
 drivers/usb/gadget/usbstring.c       |   3 +
 include/android_image.h              |  69 +++++
 include/common.h                     |   1 +
 include/config_fallbacks.h           |   4 +
 include/configs/omap3_beagle.h       |   5 +
 include/image.h                      |  13 +
 include/usb/fastboot.h               |  36 +++
 20 files changed, 1379 insertions(+), 6 deletions(-)
 create mode 100644 common/cmd_fastboot.c
 create mode 100644 common/image-android.c
 create mode 100644 doc/README.android-fastboot
 create mode 100644 doc/README.android-fastboot-protocol
 create mode 100644 drivers/usb/gadget/f_fastboot.c
 create mode 100644 drivers/usb/gadget/g_fastboot.h
 create mode 100644 drivers/usb/gadget/u_fastboot.c
 create mode 100644 include/android_image.h
 create mode 100644 include/usb/fastboot.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 1/5] common: introduce maximum load size
  2014-04-10 19:18 [U-Boot] [PATCH v3 0/5] Android Fastboot support Rob Herring
@ 2014-04-10 19:18 ` Rob Herring
  2014-04-11 14:46   ` Tom Rini
                     ` (2 more replies)
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 2/5] usb: handle NULL table in usb_gadget_get_string Rob Herring
                   ` (7 subsequent siblings)
  8 siblings, 3 replies; 59+ messages in thread
From: Rob Herring @ 2014-04-10 19:18 UTC (permalink / raw)
  To: u-boot

From: Rob Herring <robh@kernel.org>

Various commands that load images have no checks that a loaded image
does not exceed the available RAM space and will happily continue
overwriting u-boot or other RAM that should not be touched. Also,
some commands such as USB DFU or fastboot need to know the maximum
buffer size, but there is no common way to define this.

Introduce a global load_size and environment variable loadsize to
specify the size. The default is ~0UL which is effectively unlimited.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 README                     |  3 +++
 common/board_r.c           |  1 +
 common/image.c             | 17 +++++++++++++++++
 include/common.h           |  1 +
 include/config_fallbacks.h |  4 ++++
 5 files changed, 26 insertions(+)

diff --git a/README b/README
index 39e05d3..45c0438 100644
--- a/README
+++ b/README
@@ -4871,6 +4871,9 @@ List of environment variables (most likely not complete):
   loadaddr	- Default load address for commands like "bootp",
 		  "rarpboot", "tftpboot", "loadb" or "diskboot"
 
+  loadsize	- Maximum load size for commands like "bootp",
+		  "rarpboot", "tftpboot", "loadb" or "diskboot"
+
   loads_echo	- see CONFIG_LOADS_ECHO
 
   serverip	- TFTP server IP address; needed for tftpboot command
diff --git a/common/board_r.c b/common/board_r.c
index 8629a65..b420f43 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -451,6 +451,7 @@ static int initr_env(void)
 
 	/* Initialize from environment */
 	load_addr = getenv_ulong("loadaddr", 16, load_addr);
+	load_size = getenv_ulong("loadsize", 16, load_size);
 #if defined(CONFIG_SYS_EXTBDINFO)
 #if defined(CONFIG_405GP) || defined(CONFIG_405EP)
 #if defined(CONFIG_I2CFAST)
diff --git a/common/image.c b/common/image.c
index 9c6bec5..afbf806 100644
--- a/common/image.c
+++ b/common/image.c
@@ -396,6 +396,7 @@ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
 /*****************************************************************************/
 #ifndef USE_HOSTCC
 ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */
+ulong load_size = CONFIG_SYS_LOAD_SIZE;	/* Default Load Size */
 ulong save_addr;			/* Default Save Address */
 ulong save_size;			/* Default Save Size (in bytes) */
 
@@ -415,6 +416,22 @@ static int on_loadaddr(const char *name, const char *value, enum env_op op,
 }
 U_BOOT_ENV_CALLBACK(loadaddr, on_loadaddr);
 
+static int on_loadsize(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		load_size = simple_strtoul(value, NULL, 16);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(loadsize, on_loadsize);
+
 ulong getenv_bootm_low(void)
 {
 	char *s = getenv("bootm_low");
diff --git a/include/common.h b/include/common.h
index cbd3c9e..80f366e 100644
--- a/include/common.h
+++ b/include/common.h
@@ -342,6 +342,7 @@ void flash_perror (int);
 int	source (ulong addr, const char *fit_uname);
 
 extern ulong load_addr;		/* Default Load Address */
+extern ulong load_size;		/* Default Load Size (maximum) */
 extern ulong save_addr;		/* Default Save Address */
 extern ulong save_size;		/* Default Save Size */
 
diff --git a/include/config_fallbacks.h b/include/config_fallbacks.h
index e6fb47b..92a36f5 100644
--- a/include/config_fallbacks.h
+++ b/include/config_fallbacks.h
@@ -79,4 +79,8 @@
 #define CONFIG_SYS_HZ		1000
 #endif
 
+#ifndef CONFIG_SYS_LOAD_SIZE
+#define CONFIG_SYS_LOAD_SIZE	(~0UL)
+#endif
+
 #endif	/* __CONFIG_FALLBACKS_H */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 2/5] usb: handle NULL table in usb_gadget_get_string
  2014-04-10 19:18 [U-Boot] [PATCH v3 0/5] Android Fastboot support Rob Herring
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 1/5] common: introduce maximum load size Rob Herring
@ 2014-04-10 19:18 ` Rob Herring
  2014-04-11 14:46   ` Tom Rini
                     ` (2 more replies)
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 3/5] image: add support for Android's boot image format Rob Herring
                   ` (6 subsequent siblings)
  8 siblings, 3 replies; 59+ messages in thread
From: Rob Herring @ 2014-04-10 19:18 UTC (permalink / raw)
  To: u-boot

From: Rob Herring <robh@kernel.org>

Allow a NULL table to be passed to usb_gadget_get_string for cases
when a string table may not be populated.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 drivers/usb/gadget/usbstring.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index de5fa3f..8c3ff64 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -108,6 +108,9 @@ usb_gadget_get_string(struct usb_gadget_strings *table, int id, u8 *buf)
 	struct usb_string	*s;
 	int			len;
 
+	if (!table)
+		return -EINVAL;
+
 	/* descriptor 0 has the language id */
 	if (id == 0) {
 		buf[0] = 4;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 3/5] image: add support for Android's boot image format
  2014-04-10 19:18 [U-Boot] [PATCH v3 0/5] Android Fastboot support Rob Herring
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 1/5] common: introduce maximum load size Rob Herring
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 2/5] usb: handle NULL table in usb_gadget_get_string Rob Herring
@ 2014-04-10 19:18 ` Rob Herring
  2014-04-11 14:46   ` Tom Rini
                     ` (2 more replies)
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget Rob Herring
                   ` (5 subsequent siblings)
  8 siblings, 3 replies; 59+ messages in thread
From: Rob Herring @ 2014-04-10 19:18 UTC (permalink / raw)
  To: u-boot

From: Sebastian Siewior <bigeasy@linutronix.de>

This patch adds support for the Android boot-image format. The header
file is from the Android project and got slightly alterted so the struct +
its defines are not generic but have something like a namespace. The
header file is from bootloader/legacy/include/boot/bootimg.h. The header
parsing has been written from scratch and I looked at
bootloader/legacy/usbloader/usbloader.c for some details.
The image contains the physical address (load address) of the kernel and
ramdisk. This address is considered only for the kernel image.
The "second image" is currently ignored. I haven't found anything that
is creating this.

v3 (Rob Herring):
This is based on http://patchwork.ozlabs.org/patch/126797/ with the
following changes:
- Rebased to current mainline
- Moved android image handling to separate functions in
  common/image-android.c
- s/u8/char/ in header to fix string function warnings
- Use SPDX identifiers for licenses
- Cleaned-up file source information:
  android_image.h is from file include/boot/bootimg.h in repository:
  https://android.googlesource.com/platform/bootable/bootloader/legacy
  The git commit hash is 4205b865141ff2e255fe1d3bd16de18e217ef06a
  usbloader.c would be from the same commit, but it does not appear
  to have been used for any actual code.

Cc: Wolfgang Denk <wd@denx.de>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Rob Herring <robh@kernel.org>
---
 common/Makefile         |  1 +
 common/cmd_bootm.c      | 23 +++++++++++++-
 common/image-android.c  | 84 +++++++++++++++++++++++++++++++++++++++++++++++++
 common/image.c          | 20 +++++++++---
 include/android_image.h | 69 ++++++++++++++++++++++++++++++++++++++++
 include/image.h         | 13 ++++++++
 6 files changed, 204 insertions(+), 6 deletions(-)
 create mode 100644 common/image-android.c
 create mode 100644 include/android_image.h

diff --git a/common/Makefile b/common/Makefile
index cecd81a..da208f3 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -236,6 +236,7 @@ obj-y += console.o
 obj-$(CONFIG_CROS_EC) += cros_ec.o
 obj-y += dlmalloc.o
 obj-y += image.o
+obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
 obj-$(CONFIG_OF_LIBFDT) += image-fdt.o
 obj-$(CONFIG_FIT) += image-fit.o
 obj-$(CONFIG_FIT_SIGNATURE) += image-sig.o
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 9751edc..b6c8288 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -223,6 +223,8 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
 {
 	const void *os_hdr;
 
+	images.ep = ~0UL;
+
 	/* get kernel image header, start address and length */
 	os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
 			&images, &images.os.image_start, &images.os.image_len);
@@ -274,6 +276,17 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
 		}
 		break;
 #endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	case IMAGE_FORMAT_ANDROID:
+		images.os.type = IH_TYPE_KERNEL;
+		images.os.comp = IH_COMP_NONE;
+		images.os.os = IH_OS_LINUX;
+		images.ep = images.os.load;
+
+		images.os.end = android_image_get_end(os_hdr);
+		images.os.load = android_image_get_kload(os_hdr);
+		break;
+#endif
 	default:
 		puts("ERROR: unknown image format type!\n");
 		return 1;
@@ -293,7 +306,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
 			return 1;
 		}
 #endif
-	} else {
+	} else if (images.ep == ~0UL) {
 		puts("Could not find kernel entry point!\n");
 		return 1;
 	}
@@ -1002,6 +1015,14 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,
 		images->fit_noffset_os = os_noffset;
 		break;
 #endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	case IMAGE_FORMAT_ANDROID:
+		printf("## Booting Android Image at 0x%08lx ...\n", img_addr);
+		if (android_image_get_kernel((void *)img_addr, images->verify,
+					     os_data, os_len))
+			return NULL;
+		break;
+#endif
 	default:
 		printf("Wrong Image Format for %s command\n", cmdtp->name);
 		bootstage_error(BOOTSTAGE_ID_FIT_KERNEL_INFO);
diff --git a/common/image-android.c b/common/image-android.c
new file mode 100644
index 0000000..ec6fb3d
--- /dev/null
+++ b/common/image-android.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <image.h>
+#include <android_image.h>
+
+static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
+
+int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
+			     ulong *os_data, ulong *os_len)
+{
+	/*
+	 * Not all Android tools use the id field for signing the image with
+	 * sha1 (or anything) so we don't check it. It is not obvious that the
+	 * string is null terminated so we take care of this.
+	 */
+	strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE);
+	andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0';
+	if (strlen(andr_tmp_str))
+		printf("Android's image name: %s\n", andr_tmp_str);
+
+	printf("Kernel load addr 0x%08x size %u KiB\n",
+	       hdr->kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024));
+	strncpy(andr_tmp_str, hdr->cmdline, ANDR_BOOT_ARGS_SIZE);
+	andr_tmp_str[ANDR_BOOT_ARGS_SIZE] = '\0';
+	if (strlen(andr_tmp_str)) {
+		printf("Kernel command line: %s\n", andr_tmp_str);
+		setenv("bootargs", andr_tmp_str);
+	}
+	if (hdr->ramdisk_size)
+		printf("RAM disk load addr 0x%08x size %u KiB\n",
+		       hdr->ramdisk_addr,
+		       DIV_ROUND_UP(hdr->ramdisk_size, 1024));
+
+	if (os_data) {
+		*os_data = (ulong)hdr;
+		*os_data += hdr->page_size;
+	}
+	if (os_len)
+		*os_len = hdr->kernel_size;
+	return 0;
+}
+
+int android_image_check_header(const struct andr_img_hdr *hdr)
+{
+	return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE);
+}
+
+ulong android_image_get_end(const struct andr_img_hdr *hdr)
+{
+	u32 size = 0;
+	/*
+	 * The header takes a full page, the remaining components are aligned
+	 * on page boundary
+	 */
+	size += hdr->page_size;
+	size += ALIGN(hdr->kernel_size, hdr->page_size);
+	size += ALIGN(hdr->ramdisk_size, hdr->page_size);
+	size += ALIGN(hdr->second_size, hdr->page_size);
+
+	return size;
+}
+
+ulong android_image_get_kload(const struct andr_img_hdr *hdr)
+{
+	return hdr->kernel_addr;
+}
+
+int andriod_image_get_ramdisk(const struct andr_img_hdr *hdr,
+			      ulong *rd_data, ulong *rd_len)
+{
+	if (!hdr->ramdisk_size)
+		return -1;
+	*rd_data = (unsigned long)hdr;
+	*rd_data += hdr->page_size;
+	*rd_data += ALIGN(hdr->kernel_size, hdr->page_size);
+
+	*rd_len = hdr->ramdisk_size;
+	return 0;
+}
diff --git a/common/image.c b/common/image.c
index afbf806..b6063f6 100644
--- a/common/image.c
+++ b/common/image.c
@@ -676,10 +676,12 @@ int genimg_get_format(const void *img_addr)
 	if (image_check_magic(hdr))
 		format = IMAGE_FORMAT_LEGACY;
 #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
-	else {
-		if (fdt_check_header(img_addr) == 0)
-			format = IMAGE_FORMAT_FIT;
-	}
+	else if (fdt_check_header(img_addr) == 0)
+		format = IMAGE_FORMAT_FIT;
+#endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	else if (android_image_check_header(img_addr) == 0)
+		format = IMAGE_FORMAT_ANDROID;
 #endif
 
 	return format;
@@ -949,7 +951,15 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
 				(ulong)images->legacy_hdr_os);
 
 		image_multi_getimg(images->legacy_hdr_os, 1, &rd_data, &rd_len);
-	} else {
+	}
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	else if ((genimg_get_format(images) == IMAGE_FORMAT_ANDROID) &&
+		 (!andriod_image_get_ramdisk((void *)images->os.start,
+		    &rd_data, &rd_len))) {
+		/* empty */
+	}
+#endif
+	else {
 		/*
 		 * no initrd image
 		 */
diff --git a/include/android_image.h b/include/android_image.h
new file mode 100644
index 0000000..094d60a
--- /dev/null
+++ b/include/android_image.h
@@ -0,0 +1,69 @@
+/*
+ * This is from the Android Project,
+ * Repository: https://android.googlesource.com/platform/bootable/bootloader/legacy
+ * File: include/boot/bootimg.h
+ * Commit: 4205b865141ff2e255fe1d3bd16de18e217ef06a
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _ANDROID_IMAGE_H_
+#define _ANDROID_IMAGE_H_
+
+#define ANDR_BOOT_MAGIC "ANDROID!"
+#define ANDR_BOOT_MAGIC_SIZE 8
+#define ANDR_BOOT_NAME_SIZE 16
+#define ANDR_BOOT_ARGS_SIZE 512
+
+struct andr_img_hdr {
+	char magic[ANDR_BOOT_MAGIC_SIZE];
+
+	u32 kernel_size;	/* size in bytes */
+	u32 kernel_addr;	/* physical load addr */
+
+	u32 ramdisk_size;	/* size in bytes */
+	u32 ramdisk_addr;	/* physical load addr */
+
+	u32 second_size;	/* size in bytes */
+	u32 second_addr;	/* physical load addr */
+
+	u32 tags_addr;		/* physical addr for kernel tags */
+	u32 page_size;		/* flash page size we assume */
+	u32 unused[2];		/* future expansion: should be 0 */
+
+	char name[ANDR_BOOT_NAME_SIZE]; /* asciiz product name */
+
+	char cmdline[ANDR_BOOT_ARGS_SIZE];
+
+	u32 id[8]; /* timestamp / checksum / sha1 / etc */
+};
+
+/*
+ * +-----------------+
+ * | boot header     | 1 page
+ * +-----------------+
+ * | kernel          | n pages
+ * +-----------------+
+ * | ramdisk         | m pages
+ * +-----------------+
+ * | second stage    | o pages
+ * +-----------------+
+ *
+ * n = (kernel_size + page_size - 1) / page_size
+ * m = (ramdisk_size + page_size - 1) / page_size
+ * o = (second_size + page_size - 1) / page_size
+ *
+ * 0. all entities are page_size aligned in flash
+ * 1. kernel and ramdisk are required (size != 0)
+ * 2. second is optional (second_size == 0 -> no second)
+ * 3. load each element (kernel, ramdisk, second) at
+ *    the specified physical address (kernel_addr, etc)
+ * 4. prepare tags at tag_addr.  kernel_args[] is
+ *    appended to the kernel commandline in the tags.
+ * 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
+ * 6. if second_size != 0: jump to second_addr
+ *    else: jump to kernel_addr
+ */
+#endif
diff --git a/include/image.h b/include/image.h
index 6afd57b..b123860 100644
--- a/include/image.h
+++ b/include/image.h
@@ -403,6 +403,7 @@ enum fit_load_op {
 #define IMAGE_FORMAT_INVALID	0x00
 #define IMAGE_FORMAT_LEGACY	0x01	/* legacy image_header based format */
 #define IMAGE_FORMAT_FIT	0x02	/* new, libfdt based format */
+#define IMAGE_FORMAT_ANDROID	0x03	/* Android boot image */
 
 int genimg_get_format(const void *img_addr);
 int genimg_has_config(bootm_headers_t *images);
@@ -996,4 +997,16 @@ static inline int fit_image_check_target_arch(const void *fdt, int node)
 #endif /* CONFIG_FIT_VERBOSE */
 #endif /* CONFIG_FIT */
 
+#if defined(CONFIG_ANDROID_BOOT_IMAGE)
+struct andr_img_hdr;
+int android_image_check_header(const struct andr_img_hdr *hdr);
+int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
+			     ulong *os_data, ulong *os_len);
+int andriod_image_get_ramdisk(const struct andr_img_hdr *hdr,
+			      ulong *rd_data, ulong *rd_len);
+ulong android_image_get_end(const struct andr_img_hdr *hdr);
+ulong android_image_get_kload(const struct andr_img_hdr *hdr);
+
+#endif /* CONFIG_ANDROID_BOOT_IMAGE */
+
 #endif	/* __IMAGE_H__ */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget
  2014-04-10 19:18 [U-Boot] [PATCH v3 0/5] Android Fastboot support Rob Herring
                   ` (2 preceding siblings ...)
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 3/5] image: add support for Android's boot image format Rob Herring
@ 2014-04-10 19:18 ` Rob Herring
  2014-04-11  7:14   ` Bo Shen
                     ` (4 more replies)
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 5/5] arm: beagle: enable Android fastboot support Rob Herring
                   ` (4 subsequent siblings)
  8 siblings, 5 replies; 59+ messages in thread
From: Rob Herring @ 2014-04-10 19:18 UTC (permalink / raw)
  To: u-boot

From: Sebastian Siewior <bigeasy@linutronix.de>

This patch contains an implementation of the fastboot protocol on the
device side and a little of documentation.
The gadget expects the new-style gadget framework.
The gadget implements the getvar, reboot, download and reboot commands.
What is missing is the flash handling i.e. writting the image to media.

v3 (Rob Herring):
This is based on http://patchwork.ozlabs.org/patch/126798/ with the
following changes:
- Rebase to current mainline and updates for current gadget API
- Use SPDX identifiers for licenses
- Traced the history and added missing copyright to cmd_fastboot.c
- Use load_addr/load_size for transfer buffer
- Allow vendor strings to be optional
- Set vendor/product ID from config defines
- Allow Ctrl-C to exit fastboot mode

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Rob Herring <robh@kernel.org>
---
 common/Makefile                      |   2 +
 common/cmd_fastboot.c                |  36 +++
 doc/README.android-fastboot          |  86 ++++++
 doc/README.android-fastboot-protocol | 170 +++++++++++
 drivers/usb/gadget/Makefile          |   1 +
 drivers/usb/gadget/f_fastboot.c      | 535 +++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/g_fastboot.h      |  15 +
 drivers/usb/gadget/u_fastboot.c      | 260 +++++++++++++++++
 include/usb/fastboot.h               |  36 +++
 9 files changed, 1141 insertions(+)
 create mode 100644 common/cmd_fastboot.c
 create mode 100644 doc/README.android-fastboot
 create mode 100644 doc/README.android-fastboot-protocol
 create mode 100644 drivers/usb/gadget/f_fastboot.c
 create mode 100644 drivers/usb/gadget/g_fastboot.h
 create mode 100644 drivers/usb/gadget/u_fastboot.c
 create mode 100644 include/usb/fastboot.h

diff --git a/common/Makefile b/common/Makefile
index da208f3..fe1d8b9 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -167,6 +167,8 @@ obj-y += cmd_usb.o
 obj-y += usb.o usb_hub.o
 obj-$(CONFIG_USB_STORAGE) += usb_storage.o
 endif
+obj-$(CONFIG_CMD_FASTBOOT) += cmd_fastboot.o
+
 obj-$(CONFIG_CMD_USB_MASS_STORAGE) += cmd_usb_mass_storage.o
 obj-$(CONFIG_CMD_THOR_DOWNLOAD) += cmd_thordown.o
 obj-$(CONFIG_CMD_XIMG) += cmd_ximg.o
diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
new file mode 100644
index 0000000..fc8d9e0
--- /dev/null
+++ b/common/cmd_fastboot.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 - 2009 Windriver, <www.windriver.com>
+ * Author: Tom Rix <Tom.Rix@windriver.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <command.h>
+#include <usb/fastboot.h>
+
+static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	int ret = 1;
+
+	if (!fastboot_init()) {
+		printf("Fastboot entered...\n");
+
+		ret = 0;
+
+		while (1) {
+			if (fastboot_poll())
+				break;
+			if (ctrlc())
+				break;
+		}
+	}
+
+	fastboot_shutdown();
+	return ret;
+}
+
+U_BOOT_CMD(
+	fastboot,	1,	1,	do_fastboot,
+	"fastboot - enter USB Fastboot protocol",
+	""
+);
diff --git a/doc/README.android-fastboot b/doc/README.android-fastboot
new file mode 100644
index 0000000..4b2a9aa
--- /dev/null
+++ b/doc/README.android-fastboot
@@ -0,0 +1,86 @@
+Android Fastboot
+~~~~~~~~~~~~~~~~
+
+Overview
+========
+The protocol that is used over USB is described in
+README.android-fastboot-protocol in same folder.
+
+The current implementation does not yet support the flash and erase
+commands.
+
+Client installation
+===================
+The counterpart to this gadget is the fastboot client which can
+be found in Android's platform/system/core repository in the fastboot
+folder. It runs on Windows, Linux and even OSx. Linux user are lucky since
+they only need libusb.
+Windows users need to bring some time until they have Android SDK (currently
+http://dl.google.com/android/installer_r12-windows.exe) installed. You
+need to install ADB package which contains the required glue libraries for
+accessing USB. Also you need "Google USB driver package" and "SDK platform
+tools". Once installed the usb driver is placed in your SDK folder under
+extras\google\usb_driver. The android_winusb.inf needs a line like
+
+   %SingleBootLoaderInterface% = USB_Install, USB\VID_0451&PID_D022
+
+either in the [Google.NTx86] section for 32bit Windows or [Google.NTamd64]
+for 64bit Windows. VID and PID should match whatever the fastboot is
+advertising.
+
+Board specific
+==============
+The gadget calls at probe time the function fastboot_board_init() which
+should be provided by the board to setup its specific configuration.
+It is possible here to overwrite specific strings like Vendor or Serial
+number. Strings which are not specified here will return a default value.
+This init function must also provide a memory area for the
+"transfer_buffer" and its size. This buffer should be large enough to hold
+whatever the download commands is willing to send or it will fail. This
+can be a kernel image for booting which could be around two MiB or a flash
+partition which could be slightly larger :)
+
+In Action
+=========
+Enter into fastboot by executing the fastboot command in u-boot and you
+should see:
+|Fastboot entered...
+
+The gadget terminates once the is unplugged. On the client side you can
+fetch the product name for instance:
+|>fastboot getvar product
+|product: Default Product
+|finished. total time: 0.016s
+
+or initiate a reboot:
+|>fastboot reboot
+
+and once the client comes back, the board should reset.
+
+You can also specify a kernel image to boot. You have to either specify
+the an image in Android format _or_ pass a binary kernel and let the
+fastboot client wrap the Android suite around it. On OMAP for instance you
+take zImage kernel and pass it to the fastboot client:
+
+|>fastboot -b 0x80000000 -c "console=ttyO2 earlyprintk root=/dev/ram0
+|	mem=128M" boot zImage
+|creating boot image...
+|creating boot image - 1847296 bytes
+|downloading 'boot.img'...
+|OKAY [  2.766s]
+|booting...
+|OKAY [ -0.000s]
+|finished. total time: 2.766s
+
+and on the gadget side you should see:
+|Starting download of 1847296 bytes
+|........................................................
+|downloading of 1847296 bytes finished
+|Booting kernel..
+|## Booting Android Image at 0x81000000 ...
+|Kernel load addr 0x80008000 size 1801 KiB
+|Kernel command line: console=ttyO2 earlyprintk root=/dev/ram0 mem=128M
+|   Loading Kernel Image ... OK
+|OK
+|
+|Starting kernel ...
diff --git a/doc/README.android-fastboot-protocol b/doc/README.android-fastboot-protocol
new file mode 100644
index 0000000..e9e7166
--- /dev/null
+++ b/doc/README.android-fastboot-protocol
@@ -0,0 +1,170 @@
+FastBoot  Version  0.4
+----------------------
+
+The fastboot protocol is a mechanism for communicating with bootloaders
+over USB.  It is designed to be very straightforward to implement, to
+allow it to be used across a wide range of devices and from hosts running
+Linux, Windows, or OSX.
+
+
+Basic Requirements
+------------------
+
+* Two bulk endpoints (in, out) are required
+* Max packet size must be 64 bytes for full-speed and 512 bytes for
+  high-speed USB
+* The protocol is entirely host-driven and synchronous (unlike the
+  multi-channel, bi-directional, asynchronous ADB protocol)
+
+
+Transport and Framing
+---------------------
+
+1. Host sends a command, which is an ascii string in a single
+   packet no greater than 64 bytes.
+
+2. Client response with a single packet no greater than 64 bytes.
+   The first four bytes of the response are "OKAY", "FAIL", "DATA",
+   or "INFO".  Additional bytes may contain an (ascii) informative
+   message.
+
+   a. INFO -> the remaining 60 bytes are an informative message
+      (providing progress or diagnostic messages).  They should
+      be displayed and then step #2 repeats
+
+   b. FAIL -> the requested command failed.  The remaining 60 bytes
+      of the response (if present) provide a textual failure message
+      to present to the user.  Stop.
+
+   c. OKAY -> the requested command completed successfully.  Go to #5
+
+   d. DATA -> the requested command is ready for the data phase.
+      A DATA response packet will be 12 bytes long, in the form of
+      DATA00000000 where the 8 digit hexidecimal number represents
+      the total data size to transfer.
+
+3. Data phase.  Depending on the command, the host or client will
+   send the indicated amount of data.  Short packets are always
+   acceptable and zero-length packets are ignored.  This phase continues
+   until the client has sent or received the number of bytes indicated
+   in the "DATA" response above.
+
+4. Client responds with a single packet no greater than 64 bytes.
+   The first four bytes of the response are "OKAY", "FAIL", or "INFO".
+   Similar to #2:
+
+   a. INFO -> display the remaining 60 bytes and return to #4
+
+   b. FAIL -> display the remaining 60 bytes (if present) as a failure
+      reason and consider the command failed.  Stop.
+
+   c. OKAY -> success.  Go to #5
+
+5. Success.  Stop.
+
+
+Example Session
+---------------
+
+Host:    "getvar:version"        request version variable
+
+Client:  "OKAY0.4"               return version "0.4"
+
+Host:    "getvar:nonexistant"    request some undefined variable
+
+Client:  "OKAY"                  return value ""
+
+Host:    "download:00001234"     request to send 0x1234 bytes of data
+
+Client:  "DATA00001234"          ready to accept data
+
+Host:    < 0x1234 bytes >        send data
+
+Client:  "OKAY"                  success
+
+Host:    "flash:bootloader"      request to flash the data to the bootloader
+
+Client:  "INFOerasing flash"     indicate status / progress
+         "INFOwriting flash"
+         "OKAY"                  indicate success
+
+Host:    "powerdown"             send a command
+
+Client:  "FAILunknown command"   indicate failure
+
+
+Command Reference
+-----------------
+
+* Command parameters are indicated by printf-style escape sequences.
+
+* Commands are ascii strings and sent without the quotes (which are
+  for illustration only here) and without a trailing 0 byte.
+
+* Commands that begin with a lowercase letter are reserved for this
+  specification.  OEM-specific commands should not begin with a
+  lowercase letter, to prevent incompatibilities with future specs.
+
+ "getvar:%s"           Read a config/version variable from the bootloader.
+                       The variable contents will be returned after the
+                       OKAY response.
+
+ "download:%08x"       Write data to memory which will be later used
+                       by "boot", "ramdisk", "flash", etc.  The client
+                       will reply with "DATA%08x" if it has enough
+                       space in RAM or "FAIL" if not.  The size of
+                       the download is remembered.
+
+  "verify:%08x"        Send a digital signature to verify the downloaded
+                       data.  Required if the bootloader is "secure"
+                       otherwise "flash" and "boot" will be ignored.
+
+  "flash:%s"           Write the previously downloaded image to the
+                       named partition (if possible).
+
+  "erase:%s"           Erase the indicated partition (clear to 0xFFs)
+
+  "boot"               The previously downloaded data is a boot.img
+                       and should be booted according to the normal
+                       procedure for a boot.img
+
+  "continue"           Continue booting as normal (if possible)
+
+  "reboot"             Reboot the device.
+
+  "reboot-bootloader"  Reboot back into the bootloader.
+                       Useful for upgrade processes that require upgrading
+                       the bootloader and then upgrading other partitions
+                       using the new bootloader.
+
+  "powerdown"          Power off the device.
+
+
+
+Client Variables
+----------------
+
+The "getvar:%s" command is used to read client variables which
+represent various information about the device and the software
+on it.
+
+The various currently defined names are:
+
+  version             Version of FastBoot protocol supported.
+                      It should be "0.3" for this document.
+
+  version-bootloader  Version string for the Bootloader.
+
+  version-baseband    Version string of the Baseband Software
+
+  product             Name of the product
+
+  serialno            Product serial number
+
+  secure              If the value is "yes", this is a secure
+                      bootloader requiring a signature before
+                      it will install or boot images.
+
+Names starting with a lowercase character are reserved by this
+specification.  OEM-specific names should not start with lowercase
+characters.
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 804a2bd..b14f60e 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_THOR_FUNCTION) += f_thor.o
 obj-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
 obj-$(CONFIG_DFU_FUNCTION) += f_dfu.o
 obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o
+obj-$(CONFIG_CMD_FASTBOOT) += f_fastboot.o u_fastboot.o
 endif
 ifdef CONFIG_USB_ETHER
 obj-y += ether.o
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
new file mode 100644
index 0000000..f74a52e
--- /dev/null
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -0,0 +1,535 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <usb/fastboot.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/compiler.h>
+
+#include "g_fastboot.h"
+
+#define FASTBOOT_INTERFACE_CLASS	0xff
+#define FASTBOOT_INTERFACE_SUB_CLASS	0x42
+#define FASTBOOT_INTERFACE_PROTOCOL	0x03
+
+#define CONFIGURATION_NORMAL      1
+#define BULK_ENDPOINT 1
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0  (0x0200)
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1  (0x0040)
+#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE      (0x0040)
+
+static struct usb_string def_usb_fb_strings[] = {
+	{ FB_STR_PRODUCT_IDX,		"Default Product" },
+	{ FB_STR_SERIAL_IDX,		"1234567890" },
+	{ FB_STR_CONFIG_IDX,		"Android Fastboot" },
+	{ FB_STR_INTERFACE_IDX,		"Android Fastboot" },
+	{ FB_STR_MANUFACTURER_IDX,	"Default Manufacturer" },
+	{ FB_STR_PROC_REV_IDX,		"Default 1.0" },
+	{ FB_STR_PROC_TYPE_IDX,		"Emulator" },
+	{  }
+};
+
+static struct usb_gadget_strings def_fb_strings = {
+	.language	= 0x0409, /* en-us */
+	.strings	= def_usb_fb_strings,
+};
+
+static struct usb_gadget_strings *vendor_fb_strings;
+
+static unsigned int gadget_is_connected;
+
+static u8 ep0_buffer[512];
+static u8 ep_out_buffer[EP_BUFFER_SIZE];
+static u8 ep_in_buffer[EP_BUFFER_SIZE];
+static int current_config;
+
+/* e1 */
+static struct usb_endpoint_descriptor fs_ep_in = {
+	.bLength            = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType    = USB_DT_ENDPOINT,
+	.bEndpointAddress   = USB_DIR_IN, /* IN */
+	.bmAttributes       = USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize     = TX_ENDPOINT_MAXIMUM_PACKET_SIZE,
+	.bInterval          = 0x00,
+};
+
+/* e2 */
+static struct usb_endpoint_descriptor fs_ep_out = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT, /* OUT */
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1,
+	.bInterval		= 0x00,
+};
+
+static struct usb_endpoint_descriptor hs_ep_out = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT, /* OUT */
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0,
+	.bInterval		= 0x00,
+};
+
+const char *fb_find_usb_string(unsigned int id)
+{
+	struct usb_string *s = NULL;
+
+	if (vendor_fb_strings) {
+		for (s = vendor_fb_strings->strings; s && s->s; s++) {
+			if (s->id == id)
+				break;
+		}
+	}
+	if (!s || !s->s) {
+		for (s = def_fb_strings.strings; s && s->s; s++) {
+			if (s->id == id)
+				break;
+		}
+	}
+	if (!s)
+		return NULL;
+	return s->s;
+}
+
+static struct usb_request *ep0_req;
+
+struct usb_ep *ep_in;
+struct usb_request *req_in;
+
+struct usb_ep *ep_out;
+struct usb_request *req_out;
+
+static void fastboot_ep0_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	int status = req->status;
+
+	if (!status)
+		return;
+	printf("ep0 status %d\n", status);
+}
+
+static int fastboot_bind(struct usb_gadget *gadget)
+{
+	ep0_req = usb_ep_alloc_request(gadget->ep0, 0);
+	if (!ep0_req)
+		goto err;
+	ep0_req->buf = ep0_buffer;
+	ep0_req->complete = fastboot_ep0_complete;
+
+	ep_in = usb_ep_autoconfig(gadget, &fs_ep_in);
+	if (!ep_in)
+		goto err;
+	ep_in->driver_data = ep_in;
+
+	ep_out = usb_ep_autoconfig(gadget, &fs_ep_out);
+	if (!ep_out)
+		goto err;
+	ep_out->driver_data = ep_out;
+
+	hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
+
+	usb_gadget_connect(gadget);
+	gadget_is_connected = 1;
+
+	return 0;
+err:
+	return -1;
+}
+
+static void fastboot_unbind(struct usb_gadget *gadget)
+{
+	usb_ep_free_request(gadget->ep0, ep0_req);
+	ep_in->driver_data = NULL;
+	ep_out->driver_data = NULL;
+
+	gadget_is_connected = 0;
+	usb_gadget_disconnect(gadget);
+}
+
+#define DEVICE_BCD        0x0100
+
+struct usb_device_descriptor fb_descriptor = {
+	.bLength            = sizeof(fb_descriptor),
+	.bDescriptorType    = USB_DT_DEVICE,
+	.bcdUSB             = 0x200,
+	.bMaxPacketSize0    = 0x40,
+	.idVendor           = cpu_to_le16(CONFIG_USB_FASTBOOT_VENDOR_ID),
+	.idProduct          = cpu_to_le16(CONFIG_USB_FASTBOOT_PRODUCT_ID),
+	.bcdDevice          = DEVICE_BCD,
+	.iManufacturer      = FB_STR_MANUFACTURER_IDX,
+	.iProduct           = FB_STR_PRODUCT_IDX,
+	.iSerialNumber      = FB_STR_SERIAL_IDX,
+	.bNumConfigurations = 1,
+};
+
+#define TOT_CFG_DESC_LEN	(USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE + \
+		USB_DT_ENDPOINT_SIZE + USB_DT_ENDPOINT_SIZE)
+
+static struct usb_config_descriptor config_desc = {
+	.bLength		= USB_DT_CONFIG_SIZE,
+	.bDescriptorType	= USB_DT_CONFIG,
+	.wTotalLength		= cpu_to_le16(TOT_CFG_DESC_LEN),
+	.bNumInterfaces		= 1,
+	.bConfigurationValue	= CONFIGURATION_NORMAL,
+	.iConfiguration		= FB_STR_CONFIG_IDX,
+	.bmAttributes		= 0xc0,
+	.bMaxPower		= 0x32,
+};
+
+static struct usb_interface_descriptor interface_desc = {
+	.bLength		= USB_DT_INTERFACE_SIZE,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	.bInterfaceNumber	= 0x00,
+	.bAlternateSetting	= 0x00,
+	.bNumEndpoints		= 0x02,
+	.bInterfaceClass	= FASTBOOT_INTERFACE_CLASS,
+	.bInterfaceSubClass	= FASTBOOT_INTERFACE_SUB_CLASS,
+	.bInterfaceProtocol	= FASTBOOT_INTERFACE_PROTOCOL,
+	.iInterface		= FB_STR_INTERFACE_IDX,
+};
+
+static struct usb_qualifier_descriptor qual_desc = {
+	.bLength		= sizeof(qual_desc),
+	.bDescriptorType	= USB_DT_DEVICE_QUALIFIER,
+	.bcdUSB			= 0x200,
+	.bMaxPacketSize0	= 0x40,
+	.bNumConfigurations	= 1,
+};
+
+static int fastboot_setup_get_descr(struct usb_gadget *gadget,
+		const struct usb_ctrlrequest *ctrl)
+{
+	u16 w_value	= le16_to_cpu(ctrl->wValue);
+	u16 w_length	= le16_to_cpu(ctrl->wLength);
+	u16 val;
+	int ret;
+	u32 bytes_remaining;
+	u32 bytes_total;
+	u32 this_inc;
+
+	val = w_value >> 8;
+
+	switch (val) {
+	case USB_DT_DEVICE:
+		memcpy(ep0_buffer, &fb_descriptor, sizeof(fb_descriptor));
+		ep0_req->length = min(w_length, sizeof(fb_descriptor));
+		ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+		break;
+	case USB_DT_CONFIG:
+		bytes_remaining = min(w_length, sizeof(ep0_buffer));
+		bytes_total = 0;
+
+		/* config */
+		this_inc = min(bytes_remaining, USB_DT_CONFIG_SIZE);
+		bytes_remaining -= this_inc;
+		memcpy(ep0_buffer + bytes_total, &config_desc, this_inc);
+		bytes_total += this_inc;
+
+		/* interface */
+		this_inc = min(bytes_remaining, USB_DT_INTERFACE_SIZE);
+		bytes_remaining -= this_inc;
+		memcpy(ep0_buffer + bytes_total, &interface_desc, this_inc);
+		bytes_total += this_inc;
+
+		/* ep in */
+		this_inc = min(bytes_remaining, USB_DT_ENDPOINT_SIZE);
+		bytes_remaining -= this_inc;
+		memcpy(ep0_buffer + bytes_total, &fs_ep_in, this_inc);
+		bytes_total += this_inc;
+
+		/* ep out */
+		this_inc = min(bytes_remaining, USB_DT_ENDPOINT_SIZE);
+
+		if (gadget->speed == USB_SPEED_HIGH)
+			memcpy(ep0_buffer + bytes_total, &hs_ep_out, this_inc);
+		else
+			memcpy(ep0_buffer + bytes_total, &fs_ep_out, this_inc);
+		bytes_total += this_inc;
+
+		ep0_req->length = bytes_total;
+		ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+		break;
+	case USB_DT_STRING:
+		ret = usb_gadget_get_string(vendor_fb_strings,
+					    w_value & 0xff, ep0_buffer);
+		if (ret < 0)
+			ret = usb_gadget_get_string(&def_fb_strings,
+						    w_value & 0xff,
+						    ep0_buffer);
+		if (ret < 0)
+			break;
+
+		ep0_req->length = ret;
+		ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+		break;
+	case USB_DT_DEVICE_QUALIFIER:
+		memcpy(ep0_buffer, &qual_desc, sizeof(qual_desc));
+		ep0_req->length = min(w_length, sizeof(qual_desc));
+		ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int fastboot_setup_get_conf(struct usb_gadget *gadget,
+		const struct usb_ctrlrequest *ctrl)
+{
+	u16 w_length	= le16_to_cpu(ctrl->wLength);
+
+	if (w_length == 0)
+		return -1;
+
+	ep0_buffer[0] = current_config;
+	ep0_req->length = 1;
+	return usb_ep_queue(gadget->ep0, ep0_req, 0);
+}
+
+static void fastboot_complete_in(struct usb_ep *ep, struct usb_request *req)
+{
+	int status = req->status;
+
+	if (status)
+		printf("status: %d ep_in trans: %d\n", status, req->actual);
+}
+
+static int fastboot_disable_ep(struct usb_gadget *gadget)
+{
+	if (req_out) {
+		usb_ep_free_request(ep_out, req_out);
+		req_out = NULL;
+	}
+	if (req_in) {
+		usb_ep_free_request(ep_in, req_in);
+		req_in = NULL;
+	}
+	usb_ep_disable(ep_out);
+	usb_ep_disable(ep_in);
+
+	return 0;
+}
+
+static int fastboot_enable_ep(struct usb_gadget *gadget)
+{
+	int ret;
+
+	/* make sure we don't enable the ep twice */
+	if (gadget->speed == USB_SPEED_HIGH)
+		ret = usb_ep_enable(ep_out, &hs_ep_out);
+	else
+		ret = usb_ep_enable(ep_out, &fs_ep_out);
+	if (ret) {
+		printf("failed to enable out ep\n");
+		goto err;
+	}
+
+	req_out = usb_ep_alloc_request(ep_out, 0);
+	if (!req_out) {
+		printf("failed to alloc out req\n");
+		goto err;
+	}
+
+	ret = usb_ep_enable(ep_in, &fs_ep_in);
+	if (ret) {
+		printf("failed to enable in ep\n");
+		goto err;
+	}
+	req_in = usb_ep_alloc_request(ep_in, 0);
+	if (!req_in) {
+		printf("failed alloc req in\n");
+		goto err;
+	}
+
+	req_out->complete = rx_handler_command;
+	req_out->buf = ep_out_buffer;
+	req_out->length = sizeof(ep_out_buffer);
+
+	req_in->buf = ep_in_buffer;
+	req_in->length = sizeof(ep_in_buffer);
+
+	ret = usb_ep_queue(ep_out, req_out, 0);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	fastboot_disable_ep(gadget);
+	return -1;
+}
+
+static int fastboot_set_interface(struct usb_gadget *gadget, u32 enable)
+{
+	if (enable && req_out)
+		return 0;
+	if (!enable && !req_out)
+		return 0;
+
+	if (enable)
+		return fastboot_enable_ep(gadget);
+	else
+		return fastboot_disable_ep(gadget);
+}
+
+static int fastboot_setup_out_req(struct usb_gadget *gadget,
+		const struct usb_ctrlrequest *req)
+{
+	switch (req->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		switch (req->bRequest) {
+		case USB_REQ_SET_CONFIGURATION:
+
+			ep0_req->length = 0;
+			if (req->wValue == CONFIGURATION_NORMAL) {
+				current_config = CONFIGURATION_NORMAL;
+				fastboot_set_interface(gadget, 1);
+				return usb_ep_queue(gadget->ep0,
+						ep0_req, 0);
+			}
+			if (req->wValue == 0) {
+				current_config = 0;
+				fastboot_set_interface(gadget, 0);
+				return usb_ep_queue(gadget->ep0,
+						ep0_req, 0);
+			}
+			return -1;
+			break;
+		default:
+			return -1;
+		};
+
+	case USB_RECIP_INTERFACE:
+		switch (req->bRequest) {
+		case USB_REQ_SET_INTERFACE:
+
+			ep0_req->length = 0;
+			if (!fastboot_set_interface(gadget, 1))
+				return usb_ep_queue(gadget->ep0,
+						ep0_req, 0);
+			return -1;
+			break;
+		default:
+			return -1;
+		}
+
+	case USB_RECIP_ENDPOINT:
+		switch (req->bRequest) {
+		case USB_REQ_CLEAR_FEATURE:
+
+			return usb_ep_queue(gadget->ep0, ep0_req, 0);
+			break;
+		default:
+			return -1;
+		}
+	}
+	return -1;
+}
+
+static int fastboot_setup(struct usb_gadget *gadget,
+		const struct usb_ctrlrequest *req)
+{
+	if ((req->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
+		return -1;
+
+	if ((req->bRequestType & USB_DIR_IN) == 0)
+		/* host-to-device */
+		return fastboot_setup_out_req(gadget, req);
+
+	/* device-to-host */
+	if ((req->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+		switch (req->bRequest) {
+		case USB_REQ_GET_DESCRIPTOR:
+			return fastboot_setup_get_descr(gadget, req);
+			break;
+
+		case USB_REQ_GET_CONFIGURATION:
+			return fastboot_setup_get_conf(gadget, req);
+			break;
+		default:
+			return -1;
+		}
+	}
+	return -1;
+}
+
+static void fastboot_disconnect(struct usb_gadget *gadget)
+{
+	fastboot_disable_ep(gadget);
+	gadget_is_connected = 0;
+}
+
+struct usb_gadget_driver fast_gadget = {
+	.speed		= USB_SPEED_HIGH,
+	.bind		= fastboot_bind,
+	.unbind		= fastboot_unbind,
+	.setup		= fastboot_setup,
+	.disconnect	= fastboot_disconnect,
+};
+
+static int udc_is_probbed;
+
+int __weak fastboot_board_init(struct usb_gadget_strings **str)
+{
+	return 0;
+}
+
+int fastboot_init(void)
+{
+	int ret;
+
+	ret = fastboot_board_init(&vendor_fb_strings);
+	if (ret)
+		return ret;
+
+	ret = usb_gadget_register_driver(&fast_gadget);
+	if (ret) {
+		printf("Add gadget failed\n");
+		return ret;
+	}
+
+	udc_is_probbed = 1;
+	return 0;
+}
+
+int fastboot_poll(void)
+{
+	usb_gadget_handle_interrupts();
+
+	if (gadget_is_connected)
+		return 0;
+	else
+		return 1;
+}
+
+void fastboot_shutdown(void)
+{
+	if (!udc_is_probbed)
+		return;
+	udc_is_probbed = 0;
+	usb_gadget_unregister_driver(&fast_gadget);
+}
+
+int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
+{
+	int ret;
+
+	if (req_in->complete == NULL)
+		req_in->complete = fastboot_complete_in;
+
+	memcpy(req_in->buf, buffer, buffer_size);
+	req_in->length = buffer_size;
+	ret = usb_ep_queue(ep_in, req_in, 0);
+	if (ret)
+		printf("Error %d on queue\n", ret);
+	return 0;
+}
diff --git a/drivers/usb/gadget/g_fastboot.h b/drivers/usb/gadget/g_fastboot.h
new file mode 100644
index 0000000..733eb38
--- /dev/null
+++ b/drivers/usb/gadget/g_fastboot.h
@@ -0,0 +1,15 @@
+#ifndef _G_FASTBOOT_H_
+#define _G_FASTBOOT_H_
+
+#define EP_BUFFER_SIZE			4096
+
+extern struct usb_ep *ep_in;
+extern struct usb_request *req_in;
+extern struct usb_ep *ep_out;
+extern struct usb_request *req_out;
+
+void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+int fastboot_tx_write(const char *buffer, unsigned int buffer_size);
+const char *fb_find_usb_string(unsigned int id);
+
+#endif
diff --git a/drivers/usb/gadget/u_fastboot.c b/drivers/usb/gadget/u_fastboot.c
new file mode 100644
index 0000000..76116c0
--- /dev/null
+++ b/drivers/usb/gadget/u_fastboot.c
@@ -0,0 +1,260 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+/*
+ * Part of the rx_handler were copied from the Android project.
+ * Specifically rx command parsing in the usb_rx_cmd_complete
+ * function of the file bootable/bootloader/legacy/usbloader/usbloader.c
+ *
+ * Repository: https://android.googlesource.com/platform/bootable/bootloader/legacy
+ * Files: usbloader/usbloader.c
+ * Commit: 4205b865141ff2e255fe1d3bd16de18e217ef06a
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <common.h>
+#include <usb/fastboot.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include "g_fastboot.h"
+
+#define FASTBOOT_VERSION		"0.4"
+
+/* The 64 defined bytes plus \0 */
+#define RESPONSE_LEN	(64 + 1)
+
+static unsigned int download_size;
+static unsigned int download_bytes;
+
+static int fastboot_tx_write_str(const char *buffer)
+{
+	return fastboot_tx_write(buffer, strlen(buffer));
+}
+
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
+{
+	do_reset(NULL, 0, 0, NULL);
+}
+
+static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
+{
+	req_in->complete = compl_do_reset;
+	fastboot_tx_write_str("OKAY");
+}
+
+static int strcmp_l1(const char *s1, const char *s2)
+{
+	return strncmp(s1, s2, strlen(s1));
+}
+
+static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmd = req->buf;
+	char response[RESPONSE_LEN];
+	const char *s;
+
+	strcpy(response, "OKAY");
+	strsep(&cmd, ":");
+	if (!cmd) {
+		fastboot_tx_write_str("FAILmissing var");
+		return;
+	}
+
+	if (!strcmp_l1("version", cmd)) {
+		strncat(response, FASTBOOT_VERSION, sizeof(response));
+	} else if (!strcmp_l1("downloadsize", cmd)) {
+		char str_num[12];
+
+		sprintf(str_num, "%08lx", load_size);
+		strncat(response, str_num, sizeof(response));
+	} else if (!strcmp_l1("product", cmd)) {
+		s = fb_find_usb_string(FB_STR_PRODUCT_IDX);
+		if (s)
+			strncat(response, s, sizeof(response));
+		else
+			strcpy(response, "FAILValue not set");
+	} else if (!strcmp_l1("serialno", cmd)) {
+		s = fb_find_usb_string(FB_STR_SERIAL_IDX);
+		if (s)
+			strncat(response, s, sizeof(response));
+		else
+			strcpy(response, "FAILValue not set");
+	} else if (!strcmp_l1("cpurev", cmd)) {
+		s = fb_find_usb_string(FB_STR_PROC_REV_IDX);
+		if (s)
+			strncat(response, s, sizeof(response));
+		else
+			strcpy(response, "FAILValue not set");
+	} else if (!strcmp_l1("secure", cmd)) {
+		s = fb_find_usb_string(FB_STR_PROC_TYPE_IDX);
+		if (s)
+			strncat(response, s, sizeof(response));
+		else
+			strcpy(response, "FAILValue not set");
+	} else {
+		strcpy(response, "FAILVariable not implemented");
+	}
+	fastboot_tx_write_str(response);
+}
+
+static unsigned int rx_bytes_expected(void)
+{
+	int rx_remain = download_size - download_bytes;
+	if (rx_remain < 0)
+		return 0;
+	if (rx_remain > EP_BUFFER_SIZE)
+		return EP_BUFFER_SIZE;
+	return rx_remain;
+}
+
+#define BYTES_PER_DOT	32768
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
+{
+	char response[RESPONSE_LEN];
+	unsigned int transfer_size = download_size - download_bytes;
+	const unsigned char *buffer = req->buf;
+	unsigned int buffer_size = req->actual;
+
+	if (req->status != 0) {
+		printf("Bad status: %d\n", req->status);
+		return;
+	}
+
+	if (buffer_size < transfer_size)
+		transfer_size = buffer_size;
+
+	memcpy((void *)load_addr + download_bytes, buffer, transfer_size);
+
+	download_bytes += transfer_size;
+
+	/* Check if transfer is done */
+	if (download_bytes >= download_size) {
+		/*
+		 * Reset global transfer variable, keep download_bytes because
+		 * it will be used in the next possible flashing command
+		 */
+		download_size = 0;
+		req->complete = rx_handler_command;
+		req->length = EP_BUFFER_SIZE;
+
+		sprintf(response, "OKAY");
+		fastboot_tx_write_str(response);
+
+		printf("\ndownloading of %d bytes finished\n", download_bytes);
+	} else {
+		req->length = rx_bytes_expected();
+	}
+
+	if (download_bytes && !(download_bytes % BYTES_PER_DOT)) {
+		printf(".");
+		if (!(download_bytes % (74 * BYTES_PER_DOT)))
+			printf("\n");
+	}
+	req->actual = 0;
+	usb_ep_queue(ep, req, 0);
+}
+
+static void cb_download(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmd = req->buf;
+	char response[RESPONSE_LEN];
+
+	strsep(&cmd, ":");
+	download_size = simple_strtoul(cmd, NULL, 16);
+	download_bytes = 0;
+
+	printf("Starting download of %d bytes\n", download_size);
+
+	if (0 == download_size) {
+		sprintf(response, "FAILdata invalid size");
+	} else if (download_size > load_size) {
+		download_size = 0;
+		sprintf(response, "FAILdata too large");
+	} else {
+		sprintf(response, "DATA%08x", download_size);
+		req->complete = rx_handler_dl_image;
+		req->length = rx_bytes_expected();
+	}
+	fastboot_tx_write_str(response);
+}
+
+static char boot_addr_start[32];
+static char *bootm_args[] = { "bootm", boot_addr_start, NULL };
+
+static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	req->complete = NULL;
+	fastboot_shutdown();
+	printf("Booting kernel..\n");
+
+	do_bootm(NULL, 0, 2, bootm_args);
+
+	/* This only happens if image is somehow faulty so we start over */
+	do_reset(NULL, 0, 0, NULL);
+}
+
+static void cb_boot(struct usb_ep *ep, struct usb_request *req)
+{
+	sprintf(boot_addr_start, "0x%lx", load_addr);
+
+	req_in->complete = do_bootm_on_complete;
+	fastboot_tx_write_str("OKAY");
+	return;
+}
+
+struct cmd_dispatch_info {
+	char *cmd;
+	void (*cb)(struct usb_ep *ep, struct usb_request *req);
+};
+
+static struct cmd_dispatch_info cmd_dispatch_info[] = {
+	{
+		.cmd = "reboot",
+		.cb = cb_reboot,
+	}, {
+		.cmd = "getvar:",
+		.cb = cb_getvar,
+	}, {
+		.cmd = "download:",
+		.cb = cb_download,
+	}, {
+		.cmd = "boot",
+		.cb = cb_boot,
+	},
+};
+
+void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
+{
+	char response[RESPONSE_LEN];
+	char *cmdbuf = req->buf;
+	void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
+	int i;
+
+	sprintf(response, "FAIL");
+
+	for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
+		if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
+			func_cb = cmd_dispatch_info[i].cb;
+			break;
+		}
+	}
+
+	if (!func_cb)
+		fastboot_tx_write_str("FAILunknown command");
+	else
+		func_cb(ep, req);
+
+	if (req->status == 0) {
+		*cmdbuf = '\0';
+		req->actual = 0;
+		usb_ep_queue(ep, req, 0);
+	}
+}
diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h
new file mode 100644
index 0000000..b348886
--- /dev/null
+++ b/include/usb/fastboot.h
@@ -0,0 +1,36 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef FASTBOOT_H
+#define FASTBOOT_H
+
+#include <common.h>
+#include <command.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#define FB_STR_PRODUCT_IDX      1
+#define FB_STR_SERIAL_IDX       2
+#define FB_STR_CONFIG_IDX       3
+#define FB_STR_INTERFACE_IDX    4
+#define FB_STR_MANUFACTURER_IDX 5
+#define FB_STR_PROC_REV_IDX     6
+#define FB_STR_PROC_TYPE_IDX    7
+
+#ifdef CONFIG_CMD_FASTBOOT
+
+int fastboot_init(void);
+void fastboot_shutdown(void);
+int fastboot_poll(void);
+
+int fastboot_board_init(struct usb_gadget_strings **str);
+
+#endif
+#endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 5/5] arm: beagle: enable Android fastboot support
  2014-04-10 19:18 [U-Boot] [PATCH v3 0/5] Android Fastboot support Rob Herring
                   ` (3 preceding siblings ...)
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget Rob Herring
@ 2014-04-10 19:18 ` Rob Herring
  2014-04-11 14:46   ` Tom Rini
  2014-04-10 19:18 ` [U-Boot] [PATCH 5/5] beagle: " Rob Herring
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 59+ messages in thread
From: Rob Herring @ 2014-04-10 19:18 UTC (permalink / raw)
  To: u-boot

From: Rob Herring <robh@kernel.org>

Enable Android Fastboot support on omap3_beagle board.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 include/configs/omap3_beagle.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/configs/omap3_beagle.h b/include/configs/omap3_beagle.h
index 0b57421..e070760 100644
--- a/include/configs/omap3_beagle.h
+++ b/include/configs/omap3_beagle.h
@@ -110,6 +110,11 @@
 #define CONFIG_TWL4030_USB		1
 #define CONFIG_USB_ETHER
 #define CONFIG_USB_ETHER_RNDIS
+#define CONFIG_USB_GADGET
+#define CONFIG_CMD_FASTBOOT
+#define CONFIG_ANDROID_BOOT_IMAGE
+#define CONFIG_USB_FASTBOOT_VENDOR_ID	0x0451
+#define CONFIG_USB_FASTBOOT_PRODUCT_ID	0xd022
 
 /* USB EHCI */
 #define CONFIG_CMD_USB
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH 5/5] beagle: fastboot support
  2014-04-10 19:18 [U-Boot] [PATCH v3 0/5] Android Fastboot support Rob Herring
                   ` (4 preceding siblings ...)
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 5/5] arm: beagle: enable Android fastboot support Rob Herring
@ 2014-04-10 19:18 ` Rob Herring
  2014-04-10 19:42   ` Rob Herring
  2014-04-11  7:04 ` [U-Boot] [PATCH v3 0/5] Android Fastboot support Sebastian Andrzej Siewior
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 59+ messages in thread
From: Rob Herring @ 2014-04-10 19:18 UTC (permalink / raw)
  To: u-boot

From: Rob Herring <robh@kernel.org>

Signed-off-by: Rob Herring <robh@kernel.org>
---
 include/configs/omap3_beagle.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/configs/omap3_beagle.h b/include/configs/omap3_beagle.h
index 0b57421..e070760 100644
--- a/include/configs/omap3_beagle.h
+++ b/include/configs/omap3_beagle.h
@@ -110,6 +110,11 @@
 #define CONFIG_TWL4030_USB		1
 #define CONFIG_USB_ETHER
 #define CONFIG_USB_ETHER_RNDIS
+#define CONFIG_USB_GADGET
+#define CONFIG_CMD_FASTBOOT
+#define CONFIG_ANDROID_BOOT_IMAGE
+#define CONFIG_USB_FASTBOOT_VENDOR_ID	0x0451
+#define CONFIG_USB_FASTBOOT_PRODUCT_ID	0xd022
 
 /* USB EHCI */
 #define CONFIG_CMD_USB
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH 5/5] beagle: fastboot support
  2014-04-10 19:18 ` [U-Boot] [PATCH 5/5] beagle: " Rob Herring
@ 2014-04-10 19:42   ` Rob Herring
  0 siblings, 0 replies; 59+ messages in thread
From: Rob Herring @ 2014-04-10 19:42 UTC (permalink / raw)
  To: u-boot

On Thu, Apr 10, 2014 at 2:18 PM, Rob Herring <robherring2@gmail.com> wrote:
> From: Rob Herring <robh@kernel.org>
>
> Signed-off-by: Rob Herring <robh@kernel.org>

Oops. Ignore this one...

Rob

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 0/5] Android Fastboot support
  2014-04-10 19:18 [U-Boot] [PATCH v3 0/5] Android Fastboot support Rob Herring
                   ` (5 preceding siblings ...)
  2014-04-10 19:18 ` [U-Boot] [PATCH 5/5] beagle: " Rob Herring
@ 2014-04-11  7:04 ` Sebastian Andrzej Siewior
  2014-04-11 14:15   ` Tom Rini
  2014-04-11 14:45 ` Tom Rini
  2014-04-18 13:54 ` [U-Boot] [PATCH v4 " Rob Herring
  8 siblings, 1 reply; 59+ messages in thread
From: Sebastian Andrzej Siewior @ 2014-04-11  7:04 UTC (permalink / raw)
  To: u-boot

On 04/10/2014 09:18 PM, Rob Herring wrote:
> From: Rob Herring <robh@kernel.org>
> 
> I'm reviving the Android Fastboot support after 2+ years since the last 
> posting[1]. The previous postings had some questions about licensing and 
> source of some code. I believe I've traced the history sufficiently that 
> the copyrights and source information are complete and correct.

Thank you for picking this up. I believe in the end Wolfgang wasn't
concerned about the copyright issue anymore but I simply didn't have
the time to re-post the thing again.

Sebastian

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget Rob Herring
@ 2014-04-11  7:14   ` Bo Shen
  2014-04-11 12:55     ` Rob Herring
  2014-04-11  7:30   ` Lukasz Majewski
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 59+ messages in thread
From: Bo Shen @ 2014-04-11  7:14 UTC (permalink / raw)
  To: u-boot

Hi Rob Herring,
   I am just do a function testing on Atmel sama5d3xek board. And a 
small comment as following.

   Btw, do you test to transfer big size file. I try a file bigger than 
100MiB, it will hang. However use DFU or RNDIS don't meet this issue.

On 04/11/2014 03:18 AM, Rob Herring wrote:
> +static void fastboot_unbind(struct usb_gadget *gadget)
> +{
> +	usb_ep_free_request(gadget->ep0, ep0_req);
> +	ep_in->driver_data = NULL;
> +	ep_out->driver_data = NULL;
> +
> +	gadget_is_connected = 0;
> +	usb_gadget_disconnect(gadget);
> +}

[snip]

> +static void fastboot_disconnect(struct usb_gadget *gadget)
> +{
> +	fastboot_disable_ep(gadget);
> +	gadget_is_connected = 0;

Do this only in unbind, as unbind is really disconnect.

> +}
> +
> +struct usb_gadget_driver fast_gadget = {
> +	.speed		= USB_SPEED_HIGH,
> +	.bind		= fastboot_bind,
> +	.unbind		= fastboot_unbind,
> +	.setup		= fastboot_setup,
> +	.disconnect	= fastboot_disconnect,
> +};

Best Regards,
Bo Shen

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget Rob Herring
  2014-04-11  7:14   ` Bo Shen
@ 2014-04-11  7:30   ` Lukasz Majewski
  2014-04-11 14:46   ` Tom Rini
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 59+ messages in thread
From: Lukasz Majewski @ 2014-04-11  7:30 UTC (permalink / raw)
  To: u-boot

Hi Rob,

Thanks for the patch. I've just glimpsed to them. I will provide a
thorough review in a near future (next week probably).

> This patch contains an implementation of the fastboot protocol on the
> device side and a little of documentation.
> The gadget expects the new-style gadget framework.

What do you mean by that? To which version of gadget framework from
linux does it correspond? The u-boot's gadget infrastructure, used by
UMS, DFU and THOR gadgets [*], is based on linux 2.6.36.

> The gadget implements the getvar, reboot, download and reboot
> commands. What is missing is the flash handling i.e. writting the
> image to media.

For the three above gadgets [*] one "flashing" backend is used. It is
done by dfu_write() function defined at ./drivers/dfu/dfu.c.

Additionally some common gadget handling code is already in the u-boot
tree. It is called g_dnl.c at drivers/usb/gadget, and is used by [*]
gadgets. Maybe fastboot gadget could reuse its code?

-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget
  2014-04-11  7:14   ` Bo Shen
@ 2014-04-11 12:55     ` Rob Herring
  2014-04-11 22:13       ` Marek Vasut
  2014-04-14  2:28       ` Bo Shen
  0 siblings, 2 replies; 59+ messages in thread
From: Rob Herring @ 2014-04-11 12:55 UTC (permalink / raw)
  To: u-boot

On Fri, Apr 11, 2014 at 2:14 AM, Bo Shen <voice.shen@atmel.com> wrote:
> Hi Rob Herring,
>   I am just do a function testing on Atmel sama5d3xek board. And a small
> comment as following.
>
>   Btw, do you test to transfer big size file. I try a file bigger than
> 100MiB, it will hang. However use DFU or RNDIS don't meet this issue.

How much RAM do you have? It will happily download into the end of RAM
overwriting u-boot if loadsize is not set. DFU at least has its own
buffer size configuration.

>
>
> On 04/11/2014 03:18 AM, Rob Herring wrote:
>>
>> +static void fastboot_unbind(struct usb_gadget *gadget)
>> +{
>> +       usb_ep_free_request(gadget->ep0, ep0_req);
>> +       ep_in->driver_data = NULL;
>> +       ep_out->driver_data = NULL;
>> +
>> +       gadget_is_connected = 0;
>> +       usb_gadget_disconnect(gadget);
>> +}
>
>
> [snip]
>
>
>> +static void fastboot_disconnect(struct usb_gadget *gadget)
>> +{
>> +       fastboot_disable_ep(gadget);
>> +       gadget_is_connected = 0;
>
>
> Do this only in unbind, as unbind is really disconnect.

So, what should disconnect function do?

Rob

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 0/5] Android Fastboot support
  2014-04-11  7:04 ` [U-Boot] [PATCH v3 0/5] Android Fastboot support Sebastian Andrzej Siewior
@ 2014-04-11 14:15   ` Tom Rini
  0 siblings, 0 replies; 59+ messages in thread
From: Tom Rini @ 2014-04-11 14:15 UTC (permalink / raw)
  To: u-boot

On Fri, Apr 11, 2014 at 09:04:36AM +0200, Sebastian Andrzej Siewior wrote:
> On 04/10/2014 09:18 PM, Rob Herring wrote:
> > From: Rob Herring <robh@kernel.org>
> > 
> > I'm reviving the Android Fastboot support after 2+ years since the last 
> > posting[1]. The previous postings had some questions about licensing and 
> > source of some code. I believe I've traced the history sufficiently that 
> > the copyrights and source information are complete and correct.
> 
> Thank you for picking this up. I believe in the end Wolfgang wasn't
> concerned about the copyright issue anymore but I simply didn't have
> the time to re-post the thing again.

Yes, for the record, Copyright issues are not a concern, so long as
nothing there changed from last time.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140411/be95f263/attachment.pgp>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 0/5] Android Fastboot support
  2014-04-10 19:18 [U-Boot] [PATCH v3 0/5] Android Fastboot support Rob Herring
                   ` (6 preceding siblings ...)
  2014-04-11  7:04 ` [U-Boot] [PATCH v3 0/5] Android Fastboot support Sebastian Andrzej Siewior
@ 2014-04-11 14:45 ` Tom Rini
  2014-04-14 12:19   ` Rob Herring
  2014-04-18 13:54 ` [U-Boot] [PATCH v4 " Rob Herring
  8 siblings, 1 reply; 59+ messages in thread
From: Tom Rini @ 2014-04-11 14:45 UTC (permalink / raw)
  To: u-boot

On Thu, Apr 10, 2014 at 02:18:02PM -0500, Rob Herring wrote:

> From: Rob Herring <robh@kernel.org>
> 
> I'm reviving the Android Fastboot support after 2+ years since the last 
> posting[1]. The previous postings had some questions about licensing and 
> source of some code. I believe I've traced the history sufficiently that 
> the copyrights and source information are complete and correct.

First, thanks for picking this up.  I've been hoping someone would get
around to this for a while now as it's an often requested thing.

> I've tested this series on a BeagleBoard.

Any other boards you can test this on as well?  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140411/33c141e1/attachment.pgp>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 1/5] common: introduce maximum load size
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 1/5] common: introduce maximum load size Rob Herring
@ 2014-04-11 14:46   ` Tom Rini
  2014-04-15 12:55   ` Lukasz Majewski
  2014-04-15 21:59   ` Wolfgang Denk
  2 siblings, 0 replies; 59+ messages in thread
From: Tom Rini @ 2014-04-11 14:46 UTC (permalink / raw)
  To: u-boot

On Thu, Apr 10, 2014 at 02:18:03PM -0500, Rob Herring wrote:

> From: Rob Herring <robh@kernel.org>
> 
> Various commands that load images have no checks that a loaded image
> does not exceed the available RAM space and will happily continue
> overwriting u-boot or other RAM that should not be touched. Also,
> some commands such as USB DFU or fastboot need to know the maximum
> buffer size, but there is no common way to define this.
> 
> Introduce a global load_size and environment variable loadsize to
> specify the size. The default is ~0UL which is effectively unlimited.
> 
> Signed-off-by: Rob Herring <robh@kernel.org>

Reviewed-by: Tom Rini <trini@ti.com>

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140411/aa6b4417/attachment.pgp>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 2/5] usb: handle NULL table in usb_gadget_get_string
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 2/5] usb: handle NULL table in usb_gadget_get_string Rob Herring
@ 2014-04-11 14:46   ` Tom Rini
  2014-04-11 21:39   ` Marek Vasut
  2014-04-15 13:00   ` Lukasz Majewski
  2 siblings, 0 replies; 59+ messages in thread
From: Tom Rini @ 2014-04-11 14:46 UTC (permalink / raw)
  To: u-boot

On Thu, Apr 10, 2014 at 02:18:04PM -0500, Rob Herring wrote:

> From: Rob Herring <robh@kernel.org>
> 
> Allow a NULL table to be passed to usb_gadget_get_string for cases
> when a string table may not be populated.
> 
> Signed-off-by: Rob Herring <robh@kernel.org>

Reviewed-by: Tom Rini <trini@ti.com>

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140411/542731ff/attachment.pgp>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 3/5] image: add support for Android's boot image format
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 3/5] image: add support for Android's boot image format Rob Herring
@ 2014-04-11 14:46   ` Tom Rini
  2014-04-11 21:44   ` Marek Vasut
  2014-04-15 13:59   ` Lukasz Majewski
  2 siblings, 0 replies; 59+ messages in thread
From: Tom Rini @ 2014-04-11 14:46 UTC (permalink / raw)
  To: u-boot

On Thu, Apr 10, 2014 at 02:18:05PM -0500, Rob Herring wrote:

> From: Sebastian Siewior <bigeasy@linutronix.de>
> 
> This patch adds support for the Android boot-image format. The header
> file is from the Android project and got slightly alterted so the struct +
> its defines are not generic but have something like a namespace. The
> header file is from bootloader/legacy/include/boot/bootimg.h. The header
> parsing has been written from scratch and I looked at
> bootloader/legacy/usbloader/usbloader.c for some details.
> The image contains the physical address (load address) of the kernel and
> ramdisk. This address is considered only for the kernel image.
> The "second image" is currently ignored. I haven't found anything that
> is creating this.

Reviewed-by: Tom Rini <trini@ti.com>

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140411/d767b882/attachment.pgp>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 5/5] arm: beagle: enable Android fastboot support
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 5/5] arm: beagle: enable Android fastboot support Rob Herring
@ 2014-04-11 14:46   ` Tom Rini
  0 siblings, 0 replies; 59+ messages in thread
From: Tom Rini @ 2014-04-11 14:46 UTC (permalink / raw)
  To: u-boot

On Thu, Apr 10, 2014 at 02:18:07PM -0500, Rob Herring wrote:

> From: Rob Herring <robh@kernel.org>
> 
> Enable Android Fastboot support on omap3_beagle board.
> 
> Signed-off-by: Rob Herring <robh@kernel.org>

Reviewed-by: Tom Rini <trini@ti.com>

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140411/b7b66a73/attachment.pgp>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget Rob Herring
  2014-04-11  7:14   ` Bo Shen
  2014-04-11  7:30   ` Lukasz Majewski
@ 2014-04-11 14:46   ` Tom Rini
  2014-04-11 22:08   ` Marek Vasut
  2014-04-15 15:41   ` Lukasz Majewski
  4 siblings, 0 replies; 59+ messages in thread
From: Tom Rini @ 2014-04-11 14:46 UTC (permalink / raw)
  To: u-boot

On Thu, Apr 10, 2014 at 02:18:06PM -0500, Rob Herring wrote:

> From: Sebastian Siewior <bigeasy@linutronix.de>
> 
> This patch contains an implementation of the fastboot protocol on the
> device side and a little of documentation.
> The gadget expects the new-style gadget framework.
> The gadget implements the getvar, reboot, download and reboot commands.
> What is missing is the flash handling i.e. writting the image to media.
> 
> v3 (Rob Herring):
> This is based on http://patchwork.ozlabs.org/patch/126798/ with the
> following changes:
> - Rebase to current mainline and updates for current gadget API
> - Use SPDX identifiers for licenses
> - Traced the history and added missing copyright to cmd_fastboot.c
> - Use load_addr/load_size for transfer buffer
> - Allow vendor strings to be optional
> - Set vendor/product ID from config defines
> - Allow Ctrl-C to exit fastboot mode
> 
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Signed-off-by: Rob Herring <robh@kernel.org>

I suspect Lukasz or Marek will have more in depth comments next week,
but please use puts rather than printf when we don't have format chars
in the string.  Things look generally speaking reasonable however.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140411/3d3ad02f/attachment.pgp>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 2/5] usb: handle NULL table in usb_gadget_get_string
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 2/5] usb: handle NULL table in usb_gadget_get_string Rob Herring
  2014-04-11 14:46   ` Tom Rini
@ 2014-04-11 21:39   ` Marek Vasut
  2014-04-15 13:00   ` Lukasz Majewski
  2 siblings, 0 replies; 59+ messages in thread
From: Marek Vasut @ 2014-04-11 21:39 UTC (permalink / raw)
  To: u-boot

On Thursday, April 10, 2014 at 09:18:04 PM, Rob Herring wrote:
> From: Rob Herring <robh@kernel.org>
> 
> Allow a NULL table to be passed to usb_gadget_get_string for cases
> when a string table may not be populated.
> 
> Signed-off-by: Rob Herring <robh@kernel.org>

Acked-by: Marek Vasut <marex@denx.de>

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 3/5] image: add support for Android's boot image format
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 3/5] image: add support for Android's boot image format Rob Herring
  2014-04-11 14:46   ` Tom Rini
@ 2014-04-11 21:44   ` Marek Vasut
  2014-04-12 21:54     ` Rob Herring
  2014-04-15 13:59   ` Lukasz Majewski
  2 siblings, 1 reply; 59+ messages in thread
From: Marek Vasut @ 2014-04-11 21:44 UTC (permalink / raw)
  To: u-boot

On Thursday, April 10, 2014 at 09:18:05 PM, Rob Herring wrote:
> From: Sebastian Siewior <bigeasy@linutronix.de>
> 
> This patch adds support for the Android boot-image format. The header
> file is from the Android project and got slightly alterted so the struct +
> its defines are not generic but have something like a namespace. The
> header file is from bootloader/legacy/include/boot/bootimg.h. The header
> parsing has been written from scratch and I looked at
> bootloader/legacy/usbloader/usbloader.c for some details.
> The image contains the physical address (load address) of the kernel and
> ramdisk. This address is considered only for the kernel image.
> The "second image" is currently ignored. I haven't found anything that
> is creating this.

Can you please elaborate on those last two sentences ?

> v3 (Rob Herring):
> This is based on http://patchwork.ozlabs.org/patch/126797/ with the
> following changes:
> - Rebased to current mainline
> - Moved android image handling to separate functions in
>   common/image-android.c
> - s/u8/char/ in header to fix string function warnings
> - Use SPDX identifiers for licenses
> - Cleaned-up file source information:
>   android_image.h is from file include/boot/bootimg.h in repository:
>   https://android.googlesource.com/platform/bootable/bootloader/legacy
>   The git commit hash is 4205b865141ff2e255fe1d3bd16de18e217ef06a
>   usbloader.c would be from the same commit, but it does not appear
>   to have been used for any actual code.

[...]

> @@ -293,7 +306,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag,
> int argc, return 1;
>  		}
>  #endif
> -	} else {
> +	} else if (images.ep == ~0UL) {


I don't find this really portable. While it's unlikely the kernel will have the 
EP here, don't we have a better solution than using special value?

[...]

> @@ -949,7 +951,15 @@ int boot_get_ramdisk(int argc, char * const argv[],
> bootm_headers_t *images, (ulong)images->legacy_hdr_os);
> 
>  		image_multi_getimg(images->legacy_hdr_os, 1, &rd_data, &rd_len);
> -	} else {
> +	}
> +#ifdef CONFIG_ANDROID_BOOT_IMAGE
> +	else if ((genimg_get_format(images) == IMAGE_FORMAT_ANDROID) &&
> +		 (!andriod_image_get_ramdisk((void *)images->os.start,

andriod_image_get_ramdisk() ? There is a typo in the function name, did you 
actually ever even compile this patchset please ?
[...]

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget Rob Herring
                     ` (2 preceding siblings ...)
  2014-04-11 14:46   ` Tom Rini
@ 2014-04-11 22:08   ` Marek Vasut
  2014-04-15 15:41   ` Lukasz Majewski
  4 siblings, 0 replies; 59+ messages in thread
From: Marek Vasut @ 2014-04-11 22:08 UTC (permalink / raw)
  To: u-boot

On Thursday, April 10, 2014 at 09:18:06 PM, Rob Herring wrote:
> From: Sebastian Siewior <bigeasy@linutronix.de>
[...]

> +++ b/doc/README.android-fastboot
> @@ -0,0 +1,86 @@
> +Android Fastboot
> +~~~~~~~~~~~~~~~~
> +
> +Overview
> +========
> +The protocol that is used over USB is described in
> +README.android-fastboot-protocol in same folder.

"directory", this is not windows, so no folders here either ...

> +The current implementation does not yet support the flash and erase
> +commands.
> +
> +Client installation
> +===================
> +The counterpart to this gadget is the fastboot client which can
> +be found in Android's platform/system/core repository in the fastboot
> +folder. It runs on Windows, Linux and even OSx. Linux user are lucky since
> +they only need libusb.

OSX is written like so, the X is also capital.

[...]

> +In Action
> +=========
> +Enter into fastboot by executing the fastboot command in u-boot and you
> +should see:
> +|Fastboot entered...
> +
> +The gadget terminates once the is unplugged.

The above sentence makes zero sense to me.

[...]

> +
> +/* e1 */

This is a fine comment, but please make it sensible.

[...]

> +
> +static struct usb_request *ep0_req;
> +
> +struct usb_ep *ep_in;
> +struct usb_request *req_in;
> +
> +struct usb_ep *ep_out;
> +struct usb_request *req_out;

Please define all global variables at the top of the file.

[...]

> diff --git a/drivers/usb/gadget/g_fastboot.h
> b/drivers/usb/gadget/g_fastboot.h new file mode 100644
> index 0000000..733eb38
> --- /dev/null
> +++ b/drivers/usb/gadget/g_fastboot.h
> @@ -0,0 +1,15 @@
> +#ifndef _G_FASTBOOT_H_
> +#define _G_FASTBOOT_H_
> +
> +#define EP_BUFFER_SIZE			4096
> +
> +extern struct usb_ep *ep_in;
> +extern struct usb_request *req_in;
> +extern struct usb_ep *ep_out;
> +extern struct usb_request *req_out;

Ick, I really dislike how you're distributing the variables across the code. Is 
this really necessary ?

> +void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
> +int fastboot_tx_write(const char *buffer, unsigned int buffer_size);
> +const char *fb_find_usb_string(unsigned int id);

Please produce a consistent naming for those function names, something that can 
also be identified that it's coming from the fastboot gadget. Otherwise, these 
function names look rather random and are hard to pair with particular part of 
U-Boot at first glance.

[...]

> +static int strcmp_l1(const char *s1, const char *s2)
> +{
> +	return strncmp(s1, s2, strlen(s1));

I suspect someone will sooner or later call this function with non-null-
terminated string as $s1 . Can't you do some boundary checking here?

I'd hate to have some fastbleed bug here (sorry, bad pun).
[...]

> +static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request
> *req) +{
> +	char response[RESPONSE_LEN];
> +	unsigned int transfer_size = download_size - download_bytes;
> +	const unsigned char *buffer = req->buf;
> +	unsigned int buffer_size = req->actual;
> +
> +	if (req->status != 0) {
> +		printf("Bad status: %d\n", req->status);
> +		return;
> +	}
> +
> +	if (buffer_size < transfer_size)
> +		transfer_size = buffer_size;
> +
> +	memcpy((void *)load_addr + download_bytes, buffer, transfer_size);
> +
> +	download_bytes += transfer_size;
> +
> +	/* Check if transfer is done */
> +	if (download_bytes >= download_size) {
> +		/*
> +		 * Reset global transfer variable, keep download_bytes because
> +		 * it will be used in the next possible flashing command
> +		 */
> +		download_size = 0;
> +		req->complete = rx_handler_command;
> +		req->length = EP_BUFFER_SIZE;
> +
> +		sprintf(response, "OKAY");
> +		fastboot_tx_write_str(response);
> +
> +		printf("\ndownloading of %d bytes finished\n", download_bytes);
> +	} else {
> +		req->length = rx_bytes_expected();
> +	}
> +
> +	if (download_bytes && !(download_bytes % BYTES_PER_DOT)) {
> +		printf(".");

putc()

> +		if (!(download_bytes % (74 * BYTES_PER_DOT)))
> +			printf("\n");

putc()

> +	}
> +	req->actual = 0;
> +	usb_ep_queue(ep, req, 0);
> +}
[...]

> +#define FB_STR_PRODUCT_IDX      1
> +#define FB_STR_SERIAL_IDX       2
> +#define FB_STR_CONFIG_IDX       3
> +#define FB_STR_INTERFACE_IDX    4
> +#define FB_STR_MANUFACTURER_IDX 5
> +#define FB_STR_PROC_REV_IDX     6
> +#define FB_STR_PROC_TYPE_IDX    7

Use enum {} for those for the sake of typechecking ?
[..]

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget
  2014-04-11 12:55     ` Rob Herring
@ 2014-04-11 22:13       ` Marek Vasut
  2014-04-14  6:51         ` Lukasz Majewski
  2014-04-14  2:28       ` Bo Shen
  1 sibling, 1 reply; 59+ messages in thread
From: Marek Vasut @ 2014-04-11 22:13 UTC (permalink / raw)
  To: u-boot

On Friday, April 11, 2014 at 02:55:31 PM, Rob Herring wrote:
> On Fri, Apr 11, 2014 at 2:14 AM, Bo Shen <voice.shen@atmel.com> wrote:
> > Hi Rob Herring,
> > 
> >   I am just do a function testing on Atmel sama5d3xek board. And a small
> > 
> > comment as following.
> > 
> >   Btw, do you test to transfer big size file. I try a file bigger than
> > 
> > 100MiB, it will hang. However use DFU or RNDIS don't meet this issue.
> 
> How much RAM do you have? It will happily download into the end of RAM
> overwriting u-boot if loadsize is not set. DFU at least has its own
> buffer size configuration.

I really have to wonder ... why does android not use DFU instead and instead 
forces us to take in yet another (fourth ? ... CDC ethernet, DFU, Thor, 
Fastboot) usb image download protocol someone invented without cooperating with 
the rest of the community on a common and functional solution? Sigh :'-(

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 3/5] image: add support for Android's boot image format
  2014-04-11 21:44   ` Marek Vasut
@ 2014-04-12 21:54     ` Rob Herring
  2014-04-13 16:55       ` Marek Vasut
  0 siblings, 1 reply; 59+ messages in thread
From: Rob Herring @ 2014-04-12 21:54 UTC (permalink / raw)
  To: u-boot

On Fri, Apr 11, 2014 at 4:44 PM, Marek Vasut <marex@denx.de> wrote:
> On Thursday, April 10, 2014 at 09:18:05 PM, Rob Herring wrote:
>> From: Sebastian Siewior <bigeasy@linutronix.de>
>>
>> This patch adds support for the Android boot-image format. The header
>> file is from the Android project and got slightly alterted so the struct +
>> its defines are not generic but have something like a namespace. The
>> header file is from bootloader/legacy/include/boot/bootimg.h. The header
>> parsing has been written from scratch and I looked at
>> bootloader/legacy/usbloader/usbloader.c for some details.
>> The image contains the physical address (load address) of the kernel and
>> ramdisk. This address is considered only for the kernel image.
>> The "second image" is currently ignored. I haven't found anything that
>> is creating this.
>
> Can you please elaborate on those last two sentences ?

The android header has 3 images: kernel, ramdisk and "second". I think
this is for secondary bootloader, but I'll have to investigate.

>
>> v3 (Rob Herring):
>> This is based on http://patchwork.ozlabs.org/patch/126797/ with the
>> following changes:
>> - Rebased to current mainline
>> - Moved android image handling to separate functions in
>>   common/image-android.c
>> - s/u8/char/ in header to fix string function warnings
>> - Use SPDX identifiers for licenses
>> - Cleaned-up file source information:
>>   android_image.h is from file include/boot/bootimg.h in repository:
>>   https://android.googlesource.com/platform/bootable/bootloader/legacy
>>   The git commit hash is 4205b865141ff2e255fe1d3bd16de18e217ef06a
>>   usbloader.c would be from the same commit, but it does not appear
>>   to have been used for any actual code.
>
> [...]
>
>> @@ -293,7 +306,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag,
>> int argc, return 1;
>>               }
>>  #endif
>> -     } else {
>> +     } else if (images.ep == ~0UL) {
>
>
> I don't find this really portable. While it's unlikely the kernel will have the
> EP here, don't we have a better solution than using special value?

This is to address Wolfgang's prior comments about moving setting of
images.ep into the switch statement above. Do you like the previous
version better?

> [...]
>
>> @@ -949,7 +951,15 @@ int boot_get_ramdisk(int argc, char * const argv[],
>> bootm_headers_t *images, (ulong)images->legacy_hdr_os);
>>
>>               image_multi_getimg(images->legacy_hdr_os, 1, &rd_data, &rd_len);
>> -     } else {
>> +     }
>> +#ifdef CONFIG_ANDROID_BOOT_IMAGE
>> +     else if ((genimg_get_format(images) == IMAGE_FORMAT_ANDROID) &&
>> +              (!andriod_image_get_ramdisk((void *)images->os.start,
>
> andriod_image_get_ramdisk() ? There is a typo in the function name, did you
> actually ever even compile this patchset please ?
> [...]

Of course it compiles as the same typo is everywhere for this
function... :) I've compiled and run this (although I have not tested
with a ramdisk).

Rob

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 3/5] image: add support for Android's boot image format
  2014-04-12 21:54     ` Rob Herring
@ 2014-04-13 16:55       ` Marek Vasut
  0 siblings, 0 replies; 59+ messages in thread
From: Marek Vasut @ 2014-04-13 16:55 UTC (permalink / raw)
  To: u-boot

On Saturday, April 12, 2014 at 11:54:10 PM, Rob Herring wrote:
> On Fri, Apr 11, 2014 at 4:44 PM, Marek Vasut <marex@denx.de> wrote:
> > On Thursday, April 10, 2014 at 09:18:05 PM, Rob Herring wrote:
> >> From: Sebastian Siewior <bigeasy@linutronix.de>
> >> 
> >> This patch adds support for the Android boot-image format. The header
> >> file is from the Android project and got slightly alterted so the struct
> >> + its defines are not generic but have something like a namespace. The
> >> header file is from bootloader/legacy/include/boot/bootimg.h. The
> >> header parsing has been written from scratch and I looked at
> >> bootloader/legacy/usbloader/usbloader.c for some details.
> >> The image contains the physical address (load address) of the kernel and
> >> ramdisk. This address is considered only for the kernel image.
> >> The "second image" is currently ignored. I haven't found anything that
> >> is creating this.
> > 
> > Can you please elaborate on those last two sentences ?
> 
> The android header has 3 images: kernel, ramdisk and "second". I think
> this is for secondary bootloader, but I'll have to investigate.

Viva hardcoded b/s :'-(

> >> v3 (Rob Herring):
> >> This is based on http://patchwork.ozlabs.org/patch/126797/ with the
> >> following changes:
> >> - Rebased to current mainline
> >> - Moved android image handling to separate functions in
> >> 
> >>   common/image-android.c
> >> 
> >> - s/u8/char/ in header to fix string function warnings
> >> - Use SPDX identifiers for licenses
> >> 
> >> - Cleaned-up file source information:
> >>   android_image.h is from file include/boot/bootimg.h in repository:
> >>   https://android.googlesource.com/platform/bootable/bootloader/legacy
> >>   The git commit hash is 4205b865141ff2e255fe1d3bd16de18e217ef06a
> >>   usbloader.c would be from the same commit, but it does not appear
> >>   to have been used for any actual code.
> > 
> > [...]
> > 
> >> @@ -293,7 +306,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag,
> >> int argc, return 1;
> >> 
> >>               }
> >>  
> >>  #endif
> >> 
> >> -     } else {
> >> +     } else if (images.ep == ~0UL) {
> > 
> > I don't find this really portable. While it's unlikely the kernel will
> > have the EP here, don't we have a better solution than using special
> > value?
> 
> This is to address Wolfgang's prior comments about moving setting of
> images.ep into the switch statement above. Do you like the previous
> version better?

I think I might be missing that part of the discussion. My point is just that 
you might rather have a separate variable to detect error instead of having a 
special value like this.

Does my rant make sense to you please ?

> > [...]
> > 
> >> @@ -949,7 +951,15 @@ int boot_get_ramdisk(int argc, char * const argv[],
> >> bootm_headers_t *images, (ulong)images->legacy_hdr_os);
> >> 
> >>               image_multi_getimg(images->legacy_hdr_os, 1, &rd_data,
> >>               &rd_len);
> >> 
> >> -     } else {
> >> +     }
> >> +#ifdef CONFIG_ANDROID_BOOT_IMAGE
> >> +     else if ((genimg_get_format(images) == IMAGE_FORMAT_ANDROID) &&
> >> +              (!andriod_image_get_ramdisk((void *)images->os.start,
> > 
> > andriod_image_get_ramdisk() ? There is a typo in the function name, did
> > you actually ever even compile this patchset please ?
> > [...]
> 
> Of course it compiles as the same typo is everywhere for this
> function... :) I've compiled and run this (although I have not tested
> with a ramdisk).

Okay, thanks for clearing this up (and fixing this in v4)!

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget
  2014-04-11 12:55     ` Rob Herring
  2014-04-11 22:13       ` Marek Vasut
@ 2014-04-14  2:28       ` Bo Shen
  1 sibling, 0 replies; 59+ messages in thread
From: Bo Shen @ 2014-04-14  2:28 UTC (permalink / raw)
  To: u-boot

Hi Rob,

On 04/11/2014 08:55 PM, Rob Herring wrote:
> On Fri, Apr 11, 2014 at 2:14 AM, Bo Shen <voice.shen@atmel.com> wrote:
>> Hi Rob Herring,
>>    I am just do a function testing on Atmel sama5d3xek board. And a small
>> comment as following.
>>
>>    Btw, do you test to transfer big size file. I try a file bigger than
>> 100MiB, it will hang. However use DFU or RNDIS don't meet this issue.
>
> How much RAM do you have? It will happily download into the end of RAM
> overwriting u-boot if loadsize is not set. DFU at least has its own
> buffer size configuration.

There are 512MiB RAM on board. So, it won't be a problem to load this 
file from the begin of the RAM (As the u-boot is relocated to top RAM).

>>
>>
>> On 04/11/2014 03:18 AM, Rob Herring wrote:
>>>
>>> +static void fastboot_unbind(struct usb_gadget *gadget)
>>> +{
>>> +       usb_ep_free_request(gadget->ep0, ep0_req);
>>> +       ep_in->driver_data = NULL;
>>> +       ep_out->driver_data = NULL;
>>> +
>>> +       gadget_is_connected = 0;
>>> +       usb_gadget_disconnect(gadget);
>>> +}
>>
>>
>> [snip]
>>
>>
>>> +static void fastboot_disconnect(struct usb_gadget *gadget)
>>> +{
>>> +       fastboot_disable_ep(gadget);
>>> +       gadget_is_connected = 0;
>>
>>
>> Do this only in unbind, as unbind is really disconnect.
>
> So, what should disconnect function do?

Maybe some misunderstanding. I mean the "gadget_is_connected" should be 
cleared in unbind function while not in disconnect function.

> Rob
>

Best Regards,
Bo Shen

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget
  2014-04-11 22:13       ` Marek Vasut
@ 2014-04-14  6:51         ` Lukasz Majewski
  0 siblings, 0 replies; 59+ messages in thread
From: Lukasz Majewski @ 2014-04-14  6:51 UTC (permalink / raw)
  To: u-boot

Hi Marek,

> On Friday, April 11, 2014 at 02:55:31 PM, Rob Herring wrote:
> > On Fri, Apr 11, 2014 at 2:14 AM, Bo Shen <voice.shen@atmel.com>
> > wrote:
> > > Hi Rob Herring,
> > > 
> > >   I am just do a function testing on Atmel sama5d3xek board. And
> > > a small
> > > 
> > > comment as following.
> > > 
> > >   Btw, do you test to transfer big size file. I try a file bigger
> > > than
> > > 
> > > 100MiB, it will hang. However use DFU or RNDIS don't meet this
> > > issue.
> > 
> > How much RAM do you have? It will happily download into the end of
> > RAM overwriting u-boot if loadsize is not set. DFU at least has its
> > own buffer size configuration.
> 
> I really have to wonder ... why does android not use DFU

Unfortunately the DFU has its own limitations. The most notable one is
using only EP0 for transmission. As a result the transmission speed is
slow when compared with other solutions, which are using other EPs.

> instead and
> instead forces us to take in yet another (fourth ? ... CDC ethernet,
> DFU, Thor, Fastboot)

A little explanation:
1. UMS (CDC Ethernet) - export the content of the whole flash. It should
be regarded as a convenient debug option. It is somewhat clumsy
to use dd if=/u-boot.bin of=/dev/sda1 .... to store u-boot.

2. DFU it is the standard - devised at 2004 - rather outdated now. It is
slow but reliable - targeted to uC flashing.

3. Thor, fastboot - protocols devised to provide faster transmission
rates (they use other EPs for transmission).

> usb image download protocol someone invented
> without cooperating with the rest of the community on a common and
> functional solution? Sigh :'-(

I think, that this problem emerged because of the lack of DFU standard
update - adding better checksumming and possibility for using other EPs
would solve the problem.

In u-boot it is not a big problem, since we are using one backend
(dfu_write()) to store data on the medium. Moreover common gadget code
- g_dnl.c is available to reduce code duplication.

To add support for other gadget one needs to implement proper function
(like f_thor.c, f_dfu.c, f_fastboot.c).

> 
> Best regards,
> Marek Vasut



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 0/5] Android Fastboot support
  2014-04-11 14:45 ` Tom Rini
@ 2014-04-14 12:19   ` Rob Herring
  0 siblings, 0 replies; 59+ messages in thread
From: Rob Herring @ 2014-04-14 12:19 UTC (permalink / raw)
  To: u-boot

On Fri, Apr 11, 2014 at 9:45 AM, Tom Rini <trini@ti.com> wrote:
> On Thu, Apr 10, 2014 at 02:18:02PM -0500, Rob Herring wrote:
>
>> From: Rob Herring <robh@kernel.org>
>>
>> I'm reviving the Android Fastboot support after 2+ years since the last
>> posting[1]. The previous postings had some questions about licensing and
>> source of some code. I believe I've traced the history sufficiently that
>> the copyrights and source information are complete and correct.
>
> First, thanks for picking this up.  I've been hoping someone would get
> around to this for a while now as it's an often requested thing.
>
>> I've tested this series on a BeagleBoard.
>
> Any other boards you can test this on as well?  Thanks!

No, that is the only one I have with USB device. Bo Shen tested on
at91, but had some issue with large files I have to look into.

Rob

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 1/5] common: introduce maximum load size
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 1/5] common: introduce maximum load size Rob Herring
  2014-04-11 14:46   ` Tom Rini
@ 2014-04-15 12:55   ` Lukasz Majewski
  2014-04-15 21:59   ` Wolfgang Denk
  2 siblings, 0 replies; 59+ messages in thread
From: Lukasz Majewski @ 2014-04-15 12:55 UTC (permalink / raw)
  To: u-boot

Hi Rob,

> From: Rob Herring <robh@kernel.org>
> 
> Various commands that load images have no checks that a loaded image
> does not exceed the available RAM space and will happily continue
> overwriting u-boot or other RAM that should not be touched. Also,
> some commands such as USB DFU or fastboot need to know the maximum
> buffer size, but there is no common way to define this.
> 
> Introduce a global load_size and environment variable loadsize to
> specify the size. The default is ~0UL which is effectively unlimited.
> 
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
>  README                     |  3 +++
>  common/board_r.c           |  1 +
>  common/image.c             | 17 +++++++++++++++++
>  include/common.h           |  1 +
>  include/config_fallbacks.h |  4 ++++
>  5 files changed, 26 insertions(+)
> 
> diff --git a/README b/README
> index 39e05d3..45c0438 100644
> --- a/README
> +++ b/README
> @@ -4871,6 +4871,9 @@ List of environment variables (most likely not
> complete): loadaddr	- Default load address for commands like
> "bootp", "rarpboot", "tftpboot", "loadb" or "diskboot"
>  
> +  loadsize	- Maximum load size for commands like "bootp",
> +		  "rarpboot", "tftpboot", "loadb" or "diskboot"
> +
>    loads_echo	- see CONFIG_LOADS_ECHO
>  
>    serverip	- TFTP server IP address; needed for tftpboot
> command diff --git a/common/board_r.c b/common/board_r.c
> index 8629a65..b420f43 100644
> --- a/common/board_r.c
> +++ b/common/board_r.c
> @@ -451,6 +451,7 @@ static int initr_env(void)
>  
>  	/* Initialize from environment */
>  	load_addr = getenv_ulong("loadaddr", 16, load_addr);
> +	load_size = getenv_ulong("loadsize", 16, load_size);
>  #if defined(CONFIG_SYS_EXTBDINFO)
>  #if defined(CONFIG_405GP) || defined(CONFIG_405EP)
>  #if defined(CONFIG_I2CFAST)
> diff --git a/common/image.c b/common/image.c
> index 9c6bec5..afbf806 100644
> --- a/common/image.c
> +++ b/common/image.c
> @@ -396,6 +396,7 @@ static const image_header_t
> *image_get_ramdisk(ulong rd_addr, uint8_t
> arch, /*****************************************************************************/
> #ifndef USE_HOSTCC ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/*
> Default Load Address */ +ulong load_size =
> CONFIG_SYS_LOAD_SIZE;	/* Default Load Size */ ulong
> save_addr;			/* Default Save Address */ ulong
> save_size;			/* Default Save Size (in bytes) */ 
> @@ -415,6 +416,22 @@ static int on_loadaddr(const char *name, const
> char *value, enum env_op op, }
>  U_BOOT_ENV_CALLBACK(loadaddr, on_loadaddr);
>  
> +static int on_loadsize(const char *name, const char *value, enum
> env_op op,
> +	int flags)
> +{
> +	switch (op) {
> +	case env_op_create:
> +	case env_op_overwrite:
> +		load_size = simple_strtoul(value, NULL, 16);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +}
> +U_BOOT_ENV_CALLBACK(loadsize, on_loadsize);
> +
>  ulong getenv_bootm_low(void)
>  {
>  	char *s = getenv("bootm_low");
> diff --git a/include/common.h b/include/common.h
> index cbd3c9e..80f366e 100644
> --- a/include/common.h
> +++ b/include/common.h
> @@ -342,6 +342,7 @@ void flash_perror (int);
>  int	source (ulong addr, const char *fit_uname);
>  
>  extern ulong load_addr;		/* Default Load Address */
> +extern ulong load_size;		/* Default Load Size
> (maximum) */ extern ulong save_addr;		/* Default Save
> Address */ extern ulong save_size;		/* Default Save
> Size */ 
> diff --git a/include/config_fallbacks.h b/include/config_fallbacks.h
> index e6fb47b..92a36f5 100644
> --- a/include/config_fallbacks.h
> +++ b/include/config_fallbacks.h
> @@ -79,4 +79,8 @@
>  #define CONFIG_SYS_HZ		1000
>  #endif
>  
> +#ifndef CONFIG_SYS_LOAD_SIZE
> +#define CONFIG_SYS_LOAD_SIZE	(~0UL)
> +#endif
> +
>  #endif	/* __CONFIG_FALLBACKS_H */

Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>

-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 2/5] usb: handle NULL table in usb_gadget_get_string
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 2/5] usb: handle NULL table in usb_gadget_get_string Rob Herring
  2014-04-11 14:46   ` Tom Rini
  2014-04-11 21:39   ` Marek Vasut
@ 2014-04-15 13:00   ` Lukasz Majewski
  2 siblings, 0 replies; 59+ messages in thread
From: Lukasz Majewski @ 2014-04-15 13:00 UTC (permalink / raw)
  To: u-boot

Hi Rob,

> From: Rob Herring <robh@kernel.org>
> 
> Allow a NULL table to be passed to usb_gadget_get_string for cases
> when a string table may not be populated.

I might be wrong, since I'm not the native speaker, but this
description is a bit misleading.

For me this patch is supposed to prevent from using uninitialized string
table in this function.

> 
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
>  drivers/usb/gadget/usbstring.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/usb/gadget/usbstring.c
> b/drivers/usb/gadget/usbstring.c index de5fa3f..8c3ff64 100644
> --- a/drivers/usb/gadget/usbstring.c
> +++ b/drivers/usb/gadget/usbstring.c
> @@ -108,6 +108,9 @@ usb_gadget_get_string(struct usb_gadget_strings
> *table, int id, u8 *buf) struct usb_string	*s;
>  	int			len;
>  
> +	if (!table)
> +		return -EINVAL;
> +
>  	/* descriptor 0 has the language id */
>  	if (id == 0) {
>  		buf[0] = 4;

Despite the problem with parsing commit message :-)

Acked-by: Lukasz Majewski <l.majewski@samsung.com>

-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 3/5] image: add support for Android's boot image format
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 3/5] image: add support for Android's boot image format Rob Herring
  2014-04-11 14:46   ` Tom Rini
  2014-04-11 21:44   ` Marek Vasut
@ 2014-04-15 13:59   ` Lukasz Majewski
  2 siblings, 0 replies; 59+ messages in thread
From: Lukasz Majewski @ 2014-04-15 13:59 UTC (permalink / raw)
  To: u-boot

Hi Rob,

> From: Sebastian Siewior <bigeasy@linutronix.de>
> 
> This patch adds support for the Android boot-image format. The header
> file is from the Android project and got slightly alterted so the
> struct + its defines are not generic but have something like a
> namespace. The header file is from
> bootloader/legacy/include/boot/bootimg.h. The header parsing has been
> written from scratch and I looked at
> bootloader/legacy/usbloader/usbloader.c for some details. The image
> contains the physical address (load address) of the kernel and
> ramdisk. This address is considered only for the kernel image. The
> "second image" is currently ignored. I haven't found anything that is
> creating this.
> 
> v3 (Rob Herring):
> This is based on http://patchwork.ozlabs.org/patch/126797/ with the
> following changes:
> - Rebased to current mainline
> - Moved android image handling to separate functions in
>   common/image-android.c
> - s/u8/char/ in header to fix string function warnings
> - Use SPDX identifiers for licenses
> - Cleaned-up file source information:
>   android_image.h is from file include/boot/bootimg.h in repository:
>   https://android.googlesource.com/platform/bootable/bootloader/legacy
>   The git commit hash is 4205b865141ff2e255fe1d3bd16de18e217ef06a
>   usbloader.c would be from the same commit, but it does not appear
>   to have been used for any actual code.
> 
> Cc: Wolfgang Denk <wd@denx.de>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
>  common/Makefile         |  1 +
>  common/cmd_bootm.c      | 23 +++++++++++++-
>  common/image-android.c  | 84
> +++++++++++++++++++++++++++++++++++++++++++++++++
> common/image.c          | 20 +++++++++--- include/android_image.h |
> 69 ++++++++++++++++++++++++++++++++++++++++ include/image.h         |
> 13 ++++++++ 6 files changed, 204 insertions(+), 6 deletions(-)
>  create mode 100644 common/image-android.c
>  create mode 100644 include/android_image.h
> 
> diff --git a/common/Makefile b/common/Makefile
> index cecd81a..da208f3 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -236,6 +236,7 @@ obj-y += console.o
>  obj-$(CONFIG_CROS_EC) += cros_ec.o
>  obj-y += dlmalloc.o
>  obj-y += image.o
> +obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
>  obj-$(CONFIG_OF_LIBFDT) += image-fdt.o
>  obj-$(CONFIG_FIT) += image-fit.o
>  obj-$(CONFIG_FIT_SIGNATURE) += image-sig.o
> diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
> index 9751edc..b6c8288 100644
> --- a/common/cmd_bootm.c
> +++ b/common/cmd_bootm.c
> @@ -223,6 +223,8 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int
> flag, int argc, {
>  	const void *os_hdr;
>  
> +	images.ep = ~0UL;
> +
>  	/* get kernel image header, start address and length */
>  	os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
>  			&images, &images.os.image_start,
> &images.os.image_len); @@ -274,6 +276,17 @@ static int
> bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc, }
>  		break;
>  #endif
> +#ifdef CONFIG_ANDROID_BOOT_IMAGE
> +	case IMAGE_FORMAT_ANDROID:
> +		images.os.type = IH_TYPE_KERNEL;
> +		images.os.comp = IH_COMP_NONE;
> +		images.os.os = IH_OS_LINUX;
> +		images.ep = images.os.load;
> +
> +		images.os.end = android_image_get_end(os_hdr);
> +		images.os.load = android_image_get_kload(os_hdr);
> +		break;
> +#endif
>  	default:
>  		puts("ERROR: unknown image format type!\n");
>  		return 1;
> @@ -293,7 +306,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int
> flag, int argc, return 1;
>  		}
>  #endif
> -	} else {
> +	} else if (images.ep == ~0UL) {
>  		puts("Could not find kernel entry point!\n");
>  		return 1;
>  	}
> @@ -1002,6 +1015,14 @@ static const void *boot_get_kernel(cmd_tbl_t
> *cmdtp, int flag, int argc, images->fit_noffset_os = os_noffset;
>  		break;
>  #endif
> +#ifdef CONFIG_ANDROID_BOOT_IMAGE
> +	case IMAGE_FORMAT_ANDROID:
> +		printf("## Booting Android Image at 0x%08lx ...\n",
> img_addr);
> +		if (android_image_get_kernel((void *)img_addr,
> images->verify,
> +					     os_data, os_len))
> +			return NULL;
> +		break;
> +#endif
>  	default:
>  		printf("Wrong Image Format for %s command\n",
> cmdtp->name); bootstage_error(BOOTSTAGE_ID_FIT_KERNEL_INFO);
> diff --git a/common/image-android.c b/common/image-android.c
> new file mode 100644
> index 0000000..ec6fb3d
> --- /dev/null
> +++ b/common/image-android.c
> @@ -0,0 +1,84 @@
> +/*
> + * Copyright (c) 2011 Sebastian Andrzej Siewior
> <bigeasy@linutronix.de>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <image.h>
> +#include <android_image.h>
> +
> +static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
> +
> +int android_image_get_kernel(const struct andr_img_hdr *hdr, int
> verify,
> +			     ulong *os_data, ulong *os_len)
> +{
> +	/*
> +	 * Not all Android tools use the id field for signing the
> image with
> +	 * sha1 (or anything) so we don't check it. It is not
> obvious that the
> +	 * string is null terminated so we take care of this.
> +	 */
> +	strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE);
> +	andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0';
> +	if (strlen(andr_tmp_str))
> +		printf("Android's image name: %s\n", andr_tmp_str);
> +
> +	printf("Kernel load addr 0x%08x size %u KiB\n",
> +	       hdr->kernel_addr, DIV_ROUND_UP(hdr->kernel_size,
> 1024));
> +	strncpy(andr_tmp_str, hdr->cmdline, ANDR_BOOT_ARGS_SIZE);
> +	andr_tmp_str[ANDR_BOOT_ARGS_SIZE] = '\0';
> +	if (strlen(andr_tmp_str)) {
> +		printf("Kernel command line: %s\n", andr_tmp_str);
> +		setenv("bootargs", andr_tmp_str);
> +	}
> +	if (hdr->ramdisk_size)
> +		printf("RAM disk load addr 0x%08x size %u KiB\n",
> +		       hdr->ramdisk_addr,
> +		       DIV_ROUND_UP(hdr->ramdisk_size, 1024));
> +
> +	if (os_data) {
> +		*os_data = (ulong)hdr;
> +		*os_data += hdr->page_size;
> +	}
> +	if (os_len)
> +		*os_len = hdr->kernel_size;
> +	return 0;
> +}
> +
> +int android_image_check_header(const struct andr_img_hdr *hdr)
> +{
> +	return memcmp(ANDR_BOOT_MAGIC, hdr->magic,
> ANDR_BOOT_MAGIC_SIZE); +}
> +
> +ulong android_image_get_end(const struct andr_img_hdr *hdr)
> +{
> +	u32 size = 0;
> +	/*
> +	 * The header takes a full page, the remaining components
> are aligned
> +	 * on page boundary
> +	 */
> +	size += hdr->page_size;
> +	size += ALIGN(hdr->kernel_size, hdr->page_size);
> +	size += ALIGN(hdr->ramdisk_size, hdr->page_size);
> +	size += ALIGN(hdr->second_size, hdr->page_size);
> +
> +	return size;
> +}
> +
> +ulong android_image_get_kload(const struct andr_img_hdr *hdr)
> +{
> +	return hdr->kernel_addr;
> +}
> +
> +int andriod_image_get_ramdisk(const struct andr_img_hdr *hdr,
> +			      ulong *rd_data, ulong *rd_len)
> +{
> +	if (!hdr->ramdisk_size)
> +		return -1;
> +	*rd_data = (unsigned long)hdr;
> +	*rd_data += hdr->page_size;
> +	*rd_data += ALIGN(hdr->kernel_size, hdr->page_size);
> +
> +	*rd_len = hdr->ramdisk_size;
> +	return 0;
> +}
> diff --git a/common/image.c b/common/image.c
> index afbf806..b6063f6 100644
> --- a/common/image.c
> +++ b/common/image.c
> @@ -676,10 +676,12 @@ int genimg_get_format(const void *img_addr)
>  	if (image_check_magic(hdr))
>  		format = IMAGE_FORMAT_LEGACY;
>  #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
> -	else {
> -		if (fdt_check_header(img_addr) == 0)
> -			format = IMAGE_FORMAT_FIT;
> -	}
> +	else if (fdt_check_header(img_addr) == 0)
> +		format = IMAGE_FORMAT_FIT;
> +#endif
> +#ifdef CONFIG_ANDROID_BOOT_IMAGE
> +	else if (android_image_check_header(img_addr) == 0)
> +		format = IMAGE_FORMAT_ANDROID;
>  #endif
>  
>  	return format;
> @@ -949,7 +951,15 @@ int boot_get_ramdisk(int argc, char * const
> argv[], bootm_headers_t *images, (ulong)images->legacy_hdr_os);
>  
>  		image_multi_getimg(images->legacy_hdr_os, 1,
> &rd_data, &rd_len);
> -	} else {
> +	}
> +#ifdef CONFIG_ANDROID_BOOT_IMAGE
> +	else if ((genimg_get_format(images) == IMAGE_FORMAT_ANDROID)
> &&
> +		 (!andriod_image_get_ramdisk((void
> *)images->os.start,
> +		    &rd_data, &rd_len))) {
> +		/* empty */
> +	}
> +#endif
> +	else {
>  		/*
>  		 * no initrd image
>  		 */
> diff --git a/include/android_image.h b/include/android_image.h
> new file mode 100644
> index 0000000..094d60a
> --- /dev/null
> +++ b/include/android_image.h
> @@ -0,0 +1,69 @@
> +/*
> + * This is from the Android Project,
> + * Repository:
> https://android.googlesource.com/platform/bootable/bootloader/legacy
> + * File: include/boot/bootimg.h
> + * Commit: 4205b865141ff2e255fe1d3bd16de18e217ef06a
> + *
> + * Copyright (C) 2008 The Android Open Source Project
> + *
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +
> +#ifndef _ANDROID_IMAGE_H_
> +#define _ANDROID_IMAGE_H_
> +
> +#define ANDR_BOOT_MAGIC "ANDROID!"
> +#define ANDR_BOOT_MAGIC_SIZE 8
> +#define ANDR_BOOT_NAME_SIZE 16
> +#define ANDR_BOOT_ARGS_SIZE 512
> +
> +struct andr_img_hdr {
> +	char magic[ANDR_BOOT_MAGIC_SIZE];
> +
> +	u32 kernel_size;	/* size in bytes */
> +	u32 kernel_addr;	/* physical load addr */
> +
> +	u32 ramdisk_size;	/* size in bytes */
> +	u32 ramdisk_addr;	/* physical load addr */
> +
> +	u32 second_size;	/* size in bytes */
> +	u32 second_addr;	/* physical load addr */
> +
> +	u32 tags_addr;		/* physical addr for kernel
> tags */
> +	u32 page_size;		/* flash page size we assume */
> +	u32 unused[2];		/* future expansion: should be
> 0 */ +
> +	char name[ANDR_BOOT_NAME_SIZE]; /* asciiz product name */
> +
> +	char cmdline[ANDR_BOOT_ARGS_SIZE];
> +
> +	u32 id[8]; /* timestamp / checksum / sha1 / etc */
> +};
> +
> +/*
> + * +-----------------+
> + * | boot header     | 1 page
> + * +-----------------+
> + * | kernel          | n pages
> + * +-----------------+
> + * | ramdisk         | m pages
> + * +-----------------+
> + * | second stage    | o pages
> + * +-----------------+
> + *
> + * n = (kernel_size + page_size - 1) / page_size
> + * m = (ramdisk_size + page_size - 1) / page_size
> + * o = (second_size + page_size - 1) / page_size
> + *
> + * 0. all entities are page_size aligned in flash
> + * 1. kernel and ramdisk are required (size != 0)
> + * 2. second is optional (second_size == 0 -> no second)
> + * 3. load each element (kernel, ramdisk, second) at
> + *    the specified physical address (kernel_addr, etc)
> + * 4. prepare tags at tag_addr.  kernel_args[] is
> + *    appended to the kernel commandline in the tags.
> + * 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
> + * 6. if second_size != 0: jump to second_addr
> + *    else: jump to kernel_addr
> + */
> +#endif
> diff --git a/include/image.h b/include/image.h
> index 6afd57b..b123860 100644
> --- a/include/image.h
> +++ b/include/image.h
> @@ -403,6 +403,7 @@ enum fit_load_op {
>  #define IMAGE_FORMAT_INVALID	0x00
>  #define IMAGE_FORMAT_LEGACY	0x01	/* legacy
> image_header based format */ #define IMAGE_FORMAT_FIT
> 0x02	/* new, libfdt based format */ +#define
> IMAGE_FORMAT_ANDROID	0x03	/* Android boot image */ 
>  int genimg_get_format(const void *img_addr);
>  int genimg_has_config(bootm_headers_t *images);
> @@ -996,4 +997,16 @@ static inline int
> fit_image_check_target_arch(const void *fdt, int node) #endif /*
> CONFIG_FIT_VERBOSE */ #endif /* CONFIG_FIT */
>  
> +#if defined(CONFIG_ANDROID_BOOT_IMAGE)
> +struct andr_img_hdr;
> +int android_image_check_header(const struct andr_img_hdr *hdr);
> +int android_image_get_kernel(const struct andr_img_hdr *hdr, int
> verify,
> +			     ulong *os_data, ulong *os_len);
> +int andriod_image_get_ramdisk(const struct andr_img_hdr *hdr,
> +			      ulong *rd_data, ulong *rd_len);
> +ulong android_image_get_end(const struct andr_img_hdr *hdr);
> +ulong android_image_get_kload(const struct andr_img_hdr *hdr);
> +
> +#endif /* CONFIG_ANDROID_BOOT_IMAGE */
> +
>  #endif	/* __IMAGE_H__ */

Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>

-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget Rob Herring
                     ` (3 preceding siblings ...)
  2014-04-11 22:08   ` Marek Vasut
@ 2014-04-15 15:41   ` Lukasz Majewski
  2014-04-15 16:01     ` Rob Herring
  4 siblings, 1 reply; 59+ messages in thread
From: Lukasz Majewski @ 2014-04-15 15:41 UTC (permalink / raw)
  To: u-boot

Hi Rob,

> From: Sebastian Siewior <bigeasy@linutronix.de>
> 
> This patch contains an implementation of the fastboot protocol on the
> device side and a little of documentation.
> The gadget expects the new-style gadget framework.
> The gadget implements the getvar, reboot, download and reboot
> commands. What is missing is the flash handling i.e. writting the
> image to media.
> 
> v3 (Rob Herring):
> This is based on http://patchwork.ozlabs.org/patch/126798/ with the
> following changes:
> - Rebase to current mainline and updates for current gadget API
> - Use SPDX identifiers for licenses
> - Traced the history and added missing copyright to cmd_fastboot.c
> - Use load_addr/load_size for transfer buffer
> - Allow vendor strings to be optional

I could only propose to use common g_dnl.c code with CONFIG_G_DNL_*
defines.

> - Set vendor/product ID from config defines
> - Allow Ctrl-C to exit fastboot mode
> 
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
>  common/Makefile                      |   2 +
>  common/cmd_fastboot.c                |  36 +++
>  doc/README.android-fastboot          |  86 ++++++
>  doc/README.android-fastboot-protocol | 170 +++++++++++
>  drivers/usb/gadget/Makefile          |   1 +
>  drivers/usb/gadget/f_fastboot.c      | 535
> +++++++++++++++++++++++++++++++++++
> drivers/usb/gadget/g_fastboot.h      |  15 +
> drivers/usb/gadget/u_fastboot.c      | 260 +++++++++++++++++
> include/usb/fastboot.h               |  36 +++ 9 files changed, 1141
> insertions(+) create mode 100644 common/cmd_fastboot.c
>  create mode 100644 doc/README.android-fastboot
>  create mode 100644 doc/README.android-fastboot-protocol
>  create mode 100644 drivers/usb/gadget/f_fastboot.c
>  create mode 100644 drivers/usb/gadget/g_fastboot.h
>  create mode 100644 drivers/usb/gadget/u_fastboot.c
>  create mode 100644 include/usb/fastboot.h
> 
> diff --git a/common/Makefile b/common/Makefile
> index da208f3..fe1d8b9 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -167,6 +167,8 @@ obj-y += cmd_usb.o
>  obj-y += usb.o usb_hub.o
>  obj-$(CONFIG_USB_STORAGE) += usb_storage.o
>  endif
> +obj-$(CONFIG_CMD_FASTBOOT) += cmd_fastboot.o
> +
>  obj-$(CONFIG_CMD_USB_MASS_STORAGE) += cmd_usb_mass_storage.o
>  obj-$(CONFIG_CMD_THOR_DOWNLOAD) += cmd_thordown.o
>  obj-$(CONFIG_CMD_XIMG) += cmd_ximg.o
> diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
> new file mode 100644
> index 0000000..fc8d9e0
> --- /dev/null
> +++ b/common/cmd_fastboot.c
> @@ -0,0 +1,36 @@
> +/*
> + * Copyright 2008 - 2009 Windriver, <www.windriver.com>
> + * Author: Tom Rix <Tom.Rix@windriver.com>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +#include <common.h>
> +#include <command.h>
> +#include <usb/fastboot.h>
> +
> +static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char
> *const argv[]) +{
> +	int ret = 1;
> +
> +	if (!fastboot_init()) {
> +		printf("Fastboot entered...\n");
		
	Please use puts();
> +
> +		ret = 0;
> +
> +		while (1) {
> +			if (fastboot_poll())
> +				break;
> +			if (ctrlc())
> +				break;
> +		}
> +	}
> +
> +	fastboot_shutdown();
> +	return ret;
> +}

For the fastboot command you could use the common gadget download code
(g_dnl.c). For reference please look into common/cmd_dfu.c 

> +
> +U_BOOT_CMD(
> +	fastboot,	1,	1,	do_fastboot,
> +	"fastboot - enter USB Fastboot protocol",
> +	""
> +);
> diff --git a/doc/README.android-fastboot b/doc/README.android-fastboot
> new file mode 100644
> index 0000000..4b2a9aa
> --- /dev/null
> +++ b/doc/README.android-fastboot
> @@ -0,0 +1,86 @@
> +Android Fastboot
> +~~~~~~~~~~~~~~~~
> +
> +Overview
> +========
> +The protocol that is used over USB is described in
> +README.android-fastboot-protocol in same folder.
> +
> +The current implementation does not yet support the flash and erase
> +commands.

Flashing of received data can be performed with common dfu_write()
method.

> +
> +Client installation
> +===================
> +The counterpart to this gadget is the fastboot client which can
> +be found in Android's platform/system/core repository in the fastboot
> +folder. It runs on Windows, Linux and even OSx. Linux user are lucky
> since +they only need libusb.
> +Windows users need to bring some time until they have Android SDK
> (currently +http://dl.google.com/android/installer_r12-windows.exe)
> installed. You +need to install ADB package which contains the
> required glue libraries for +accessing USB. Also you need "Google USB
> driver package" and "SDK platform +tools". Once installed the usb
> driver is placed in your SDK folder under +extras\google\usb_driver.
> The android_winusb.inf needs a line like +
> +   %SingleBootLoaderInterface% = USB_Install, USB\VID_0451&PID_D022
> +
> +either in the [Google.NTx86] section for 32bit Windows or
> [Google.NTamd64] +for 64bit Windows. VID and PID should match
> whatever the fastboot is +advertising.
> +
> +Board specific
> +==============
> +The gadget calls at probe time the function fastboot_board_init()
> which +should be provided by the board to setup its specific
> configuration. +It is possible here to overwrite specific strings
> like Vendor or Serial +number. Strings which are not specified here
> will return a default value. +This init function must also provide a
> memory area for the +"transfer_buffer" and its size. This buffer
> should be large enough to hold +whatever the download commands is
> willing to send or it will fail. This +can be a kernel image for
> booting which could be around two MiB or a flash +partition which
> could be slightly larger :) +

With the write backend (dfu.c) you can specify the buffer size with
dfu_bufsiz env variable.

> +In Action
> +=========
> +Enter into fastboot by executing the fastboot command in u-boot and
> you +should see:
> +|Fastboot entered...
> +
> +The gadget terminates once the is unplugged. On the client side you
> can +fetch the product name for instance:
> +|>fastboot getvar product
> +|product: Default Product
> +|finished. total time: 0.016s
> +
> +or initiate a reboot:
> +|>fastboot reboot
> +
> +and once the client comes back, the board should reset.
> +
> +You can also specify a kernel image to boot. You have to either
> specify +the an image in Android format _or_ pass a binary kernel and
> let the +fastboot client wrap the Android suite around it. On OMAP
> for instance you +take zImage kernel and pass it to the fastboot
> client: +
> +|>fastboot -b 0x80000000 -c "console=ttyO2 earlyprintk root=/dev/ram0
> +|	mem=128M" boot zImage
> +|creating boot image...
> +|creating boot image - 1847296 bytes
> +|downloading 'boot.img'...
> +|OKAY [  2.766s]
> +|booting...
> +|OKAY [ -0.000s]
> +|finished. total time: 2.766s
> +
> +and on the gadget side you should see:
> +|Starting download of 1847296 bytes
> +|........................................................
> +|downloading of 1847296 bytes finished
> +|Booting kernel..
> +|## Booting Android Image at 0x81000000 ...
> +|Kernel load addr 0x80008000 size 1801 KiB
> +|Kernel command line: console=ttyO2 earlyprintk root=/dev/ram0
> mem=128M +|   Loading Kernel Image ... OK
> +|OK
> +|
> +|Starting kernel ...
> diff --git a/doc/README.android-fastboot-protocol
> b/doc/README.android-fastboot-protocol new file mode 100644
> index 0000000..e9e7166
> --- /dev/null
> +++ b/doc/README.android-fastboot-protocol
> @@ -0,0 +1,170 @@
> +FastBoot  Version  0.4
> +----------------------
> +
> +The fastboot protocol is a mechanism for communicating with
> bootloaders +over USB.  It is designed to be very straightforward to
> implement, to +allow it to be used across a wide range of devices and
> from hosts running +Linux, Windows, or OSX.
> +
> +
> +Basic Requirements
> +------------------
> +
> +* Two bulk endpoints (in, out) are required
> +* Max packet size must be 64 bytes for full-speed and 512 bytes for
> +  high-speed USB
> +* The protocol is entirely host-driven and synchronous (unlike the
> +  multi-channel, bi-directional, asynchronous ADB protocol)
> +
> +
> +Transport and Framing
> +---------------------
> +
> +1. Host sends a command, which is an ascii string in a single
> +   packet no greater than 64 bytes.
> +
> +2. Client response with a single packet no greater than 64 bytes.
> +   The first four bytes of the response are "OKAY", "FAIL", "DATA",
> +   or "INFO".  Additional bytes may contain an (ascii) informative
> +   message.
> +
> +   a. INFO -> the remaining 60 bytes are an informative message
> +      (providing progress or diagnostic messages).  They should
> +      be displayed and then step #2 repeats
> +
> +   b. FAIL -> the requested command failed.  The remaining 60 bytes
> +      of the response (if present) provide a textual failure message
> +      to present to the user.  Stop.
> +
> +   c. OKAY -> the requested command completed successfully.  Go to #5
> +
> +   d. DATA -> the requested command is ready for the data phase.
> +      A DATA response packet will be 12 bytes long, in the form of
> +      DATA00000000 where the 8 digit hexidecimal number represents
> +      the total data size to transfer.
> +
> +3. Data phase.  Depending on the command, the host or client will
> +   send the indicated amount of data.  Short packets are always
> +   acceptable and zero-length packets are ignored.  This phase
> continues
> +   until the client has sent or received the number of bytes
> indicated
> +   in the "DATA" response above.
> +
> +4. Client responds with a single packet no greater than 64 bytes.
> +   The first four bytes of the response are "OKAY", "FAIL", or
> "INFO".
> +   Similar to #2:
> +
> +   a. INFO -> display the remaining 60 bytes and return to #4
> +
> +   b. FAIL -> display the remaining 60 bytes (if present) as a
> failure
> +      reason and consider the command failed.  Stop.
> +
> +   c. OKAY -> success.  Go to #5
> +
> +5. Success.  Stop.
> +
> +
> +Example Session
> +---------------
> +
> +Host:    "getvar:version"        request version variable
> +
> +Client:  "OKAY0.4"               return version "0.4"
> +
> +Host:    "getvar:nonexistant"    request some undefined variable
> +
> +Client:  "OKAY"                  return value ""
> +
> +Host:    "download:00001234"     request to send 0x1234 bytes of data
> +
> +Client:  "DATA00001234"          ready to accept data
> +
> +Host:    < 0x1234 bytes >        send data
> +
> +Client:  "OKAY"                  success
> +
> +Host:    "flash:bootloader"      request to flash the data to the
> bootloader +
> +Client:  "INFOerasing flash"     indicate status / progress
> +         "INFOwriting flash"
> +         "OKAY"                  indicate success
> +
> +Host:    "powerdown"             send a command
> +
> +Client:  "FAILunknown command"   indicate failure
> +
> +
> +Command Reference
> +-----------------
> +
> +* Command parameters are indicated by printf-style escape sequences.
> +
> +* Commands are ascii strings and sent without the quotes (which are
> +  for illustration only here) and without a trailing 0 byte.
> +
> +* Commands that begin with a lowercase letter are reserved for this
> +  specification.  OEM-specific commands should not begin with a
> +  lowercase letter, to prevent incompatibilities with future specs.
> +
> + "getvar:%s"           Read a config/version variable from the
> bootloader.
> +                       The variable contents will be returned after
> the
> +                       OKAY response.
> +
> + "download:%08x"       Write data to memory which will be later used
> +                       by "boot", "ramdisk", "flash", etc.  The
> client
> +                       will reply with "DATA%08x" if it has enough
> +                       space in RAM or "FAIL" if not.  The size of
> +                       the download is remembered.
> +
> +  "verify:%08x"        Send a digital signature to verify the
> downloaded
> +                       data.  Required if the bootloader is "secure"
> +                       otherwise "flash" and "boot" will be ignored.
> +
> +  "flash:%s"           Write the previously downloaded image to the
> +                       named partition (if possible).
> +
> +  "erase:%s"           Erase the indicated partition (clear to 0xFFs)
> +
> +  "boot"               The previously downloaded data is a boot.img
> +                       and should be booted according to the normal
> +                       procedure for a boot.img
> +
> +  "continue"           Continue booting as normal (if possible)
> +
> +  "reboot"             Reboot the device.
> +
> +  "reboot-bootloader"  Reboot back into the bootloader.
> +                       Useful for upgrade processes that require
> upgrading
> +                       the bootloader and then upgrading other
> partitions
> +                       using the new bootloader.
> +
> +  "powerdown"          Power off the device.
> +
> +

It is a very nice mix of commands and downloading data. Frankly, I'm
quite interested if there is support for "upload" command available (or
easily implementable)? It seems, like it is also not possible to
execute an arbitrary command from a set supported by the u-boot
bootloader. 

I'm asking because protocol with such features, would greatly facilitate
 automated testing for u-boot running on a particular HW.


> +
> +Client Variables
> +----------------
> +
> +The "getvar:%s" command is used to read client variables which
> +represent various information about the device and the software
> +on it.
> +
> +The various currently defined names are:
> +
> +  version             Version of FastBoot protocol supported.
> +                      It should be "0.3" for this document.
> +
> +  version-bootloader  Version string for the Bootloader.
> +
> +  version-baseband    Version string of the Baseband Software
> +
> +  product             Name of the product
> +
> +  serialno            Product serial number
> +
> +  secure              If the value is "yes", this is a secure
> +                      bootloader requiring a signature before
> +                      it will install or boot images.
> +
> +Names starting with a lowercase character are reserved by this
> +specification.  OEM-specific names should not start with lowercase
> +characters.
> diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
> index 804a2bd..b14f60e 100644
> --- a/drivers/usb/gadget/Makefile
> +++ b/drivers/usb/gadget/Makefile
> @@ -17,6 +17,7 @@ obj-$(CONFIG_THOR_FUNCTION) += f_thor.o
>  obj-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
>  obj-$(CONFIG_DFU_FUNCTION) += f_dfu.o
>  obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o
> +obj-$(CONFIG_CMD_FASTBOOT) += f_fastboot.o u_fastboot.o
>  endif
>  ifdef CONFIG_USB_ETHER
>  obj-y += ether.o
> diff --git a/drivers/usb/gadget/f_fastboot.c
> b/drivers/usb/gadget/f_fastboot.c new file mode 100644
> index 0000000..f74a52e
> --- /dev/null
> +++ b/drivers/usb/gadget/f_fastboot.c
> @@ -0,0 +1,535 @@
> +/*
> + * (C) Copyright 2008 - 2009
> + * Windriver, <www.windriver.com>
> + * Tom Rix <Tom.Rix@windriver.com>
> + *
> + * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +#include <common.h>
> +#include <errno.h>
> +#include <usb/fastboot.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +#include <linux/compiler.h>
> +
> +#include "g_fastboot.h"
> +
> +#define FASTBOOT_INTERFACE_CLASS	0xff
> +#define FASTBOOT_INTERFACE_SUB_CLASS	0x42
> +#define FASTBOOT_INTERFACE_PROTOCOL	0x03
> +
> +#define CONFIGURATION_NORMAL      1
> +#define BULK_ENDPOINT 1
> +#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0  (0x0200)
> +#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1  (0x0040)
> +#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE      (0x0040)
> +
> +static struct usb_string def_usb_fb_strings[] = {
> +	{ FB_STR_PRODUCT_IDX,		"Default Product" },
> +	{ FB_STR_SERIAL_IDX,		"1234567890" },
> +	{ FB_STR_CONFIG_IDX,		"Android Fastboot" },
> +	{ FB_STR_INTERFACE_IDX,		"Android Fastboot" },
> +	{ FB_STR_MANUFACTURER_IDX,	"Default Manufacturer" },
> +	{ FB_STR_PROC_REV_IDX,		"Default 1.0" },
> +	{ FB_STR_PROC_TYPE_IDX,		"Emulator" },
> +	{  }
> +};

Such structure in a more generic way is defined at g_dnl.c file.

> +
> +static struct usb_gadget_strings def_fb_strings = {
> +	.language	= 0x0409, /* en-us */
> +	.strings	= def_usb_fb_strings,
> +};
> +
> +static struct usb_gadget_strings *vendor_fb_strings;
> +
> +static unsigned int gadget_is_connected;
> +

You would probably need DEFINE_CACHE_ALIGN_BUFFER() here to avoid
problems with cache coherency. 

> +static u8 ep0_buffer[512];
> +static u8 ep_out_buffer[EP_BUFFER_SIZE];
> +static u8 ep_in_buffer[EP_BUFFER_SIZE];
> +static int current_config;
> +
> +/* e1 */
> +static struct usb_endpoint_descriptor fs_ep_in = {
> +	.bLength            = USB_DT_ENDPOINT_SIZE,
> +	.bDescriptorType    = USB_DT_ENDPOINT,
> +	.bEndpointAddress   = USB_DIR_IN, /* IN */
> +	.bmAttributes       = USB_ENDPOINT_XFER_BULK,
> +	.wMaxPacketSize     = TX_ENDPOINT_MAXIMUM_PACKET_SIZE,
> +	.bInterval          = 0x00,
> +};
> +
> +/* e2 */
> +static struct usb_endpoint_descriptor fs_ep_out = {
> +	.bLength		= USB_DT_ENDPOINT_SIZE,
> +	.bDescriptorType	= USB_DT_ENDPOINT,
> +	.bEndpointAddress	= USB_DIR_OUT, /* OUT */
> +	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
> +	.wMaxPacketSize		=
> RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1,
> +	.bInterval		= 0x00,
> +};
> +
> +static struct usb_endpoint_descriptor hs_ep_out = {
> +	.bLength		= USB_DT_ENDPOINT_SIZE,
> +	.bDescriptorType	= USB_DT_ENDPOINT,
> +	.bEndpointAddress	= USB_DIR_OUT, /* OUT */
> +	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
> +	.wMaxPacketSize		=
> RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0,
> +	.bInterval		= 0x00,
> +};
> +
> +const char *fb_find_usb_string(unsigned int id)
> +{
> +	struct usb_string *s = NULL;
> +
> +	if (vendor_fb_strings) {
> +		for (s = vendor_fb_strings->strings; s && s->s; s++)
> {
> +			if (s->id == id)
> +				break;
> +		}
> +	}
> +	if (!s || !s->s) {
> +		for (s = def_fb_strings.strings; s && s->s; s++) {
> +			if (s->id == id)
> +				break;
> +		}
> +	}
> +	if (!s)
> +		return NULL;
> +	return s->s;
> +}
> +
> +static struct usb_request *ep0_req;
> +
> +struct usb_ep *ep_in;
> +struct usb_request *req_in;
> +
> +struct usb_ep *ep_out;
> +struct usb_request *req_out;
> +
> +static void fastboot_ep0_complete(struct usb_ep *ep, struct
> usb_request *req) +{
> +	int status = req->status;
> +
> +	if (!status)
> +		return;
> +	printf("ep0 status %d\n", status);
> +}
> +
> +static int fastboot_bind(struct usb_gadget *gadget)
> +{
> +	ep0_req = usb_ep_alloc_request(gadget->ep0, 0);
> +	if (!ep0_req)
> +		goto err;
> +	ep0_req->buf = ep0_buffer;
> +	ep0_req->complete = fastboot_ep0_complete;
> +
> +	ep_in = usb_ep_autoconfig(gadget, &fs_ep_in);
> +	if (!ep_in)
> +		goto err;
> +	ep_in->driver_data = ep_in;
> +
> +	ep_out = usb_ep_autoconfig(gadget, &fs_ep_out);
> +	if (!ep_out)
> +		goto err;
> +	ep_out->driver_data = ep_out;
> +
> +	hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
> +
> +	usb_gadget_connect(gadget);
> +	gadget_is_connected = 1;
> +
> +	return 0;
> +err:
> +	return -1;
> +}
> +
> +static void fastboot_unbind(struct usb_gadget *gadget)
> +{
> +	usb_ep_free_request(gadget->ep0, ep0_req);
> +	ep_in->driver_data = NULL;
> +	ep_out->driver_data = NULL;
> +
> +	gadget_is_connected = 0;
> +	usb_gadget_disconnect(gadget);
> +}
> +
> +#define DEVICE_BCD        0x0100
> +
> +struct usb_device_descriptor fb_descriptor = {
> +	.bLength            = sizeof(fb_descriptor),
> +	.bDescriptorType    = USB_DT_DEVICE,
> +	.bcdUSB             = 0x200,
> +	.bMaxPacketSize0    = 0x40,
> +	.idVendor           =
> cpu_to_le16(CONFIG_USB_FASTBOOT_VENDOR_ID),
> +	.idProduct          =
> cpu_to_le16(CONFIG_USB_FASTBOOT_PRODUCT_ID),
> +	.bcdDevice          = DEVICE_BCD,
> +	.iManufacturer      = FB_STR_MANUFACTURER_IDX,
> +	.iProduct           = FB_STR_PRODUCT_IDX,
> +	.iSerialNumber      = FB_STR_SERIAL_IDX,
> +	.bNumConfigurations = 1,
> +};
> +
> +#define TOT_CFG_DESC_LEN	(USB_DT_CONFIG_SIZE +
> USB_DT_INTERFACE_SIZE + \
> +		USB_DT_ENDPOINT_SIZE + USB_DT_ENDPOINT_SIZE)
> +
> +static struct usb_config_descriptor config_desc = {
> +	.bLength		= USB_DT_CONFIG_SIZE,
> +	.bDescriptorType	= USB_DT_CONFIG,
> +	.wTotalLength		= cpu_to_le16(TOT_CFG_DESC_LEN),
> +	.bNumInterfaces		= 1,
> +	.bConfigurationValue	= CONFIGURATION_NORMAL,
> +	.iConfiguration		= FB_STR_CONFIG_IDX,
> +	.bmAttributes		= 0xc0,
> +	.bMaxPower		= 0x32,
> +};
> +
> +static struct usb_interface_descriptor interface_desc = {
> +	.bLength		= USB_DT_INTERFACE_SIZE,
> +	.bDescriptorType	= USB_DT_INTERFACE,
> +	.bInterfaceNumber	= 0x00,
> +	.bAlternateSetting	= 0x00,
> +	.bNumEndpoints		= 0x02,
> +	.bInterfaceClass	= FASTBOOT_INTERFACE_CLASS,
> +	.bInterfaceSubClass	= FASTBOOT_INTERFACE_SUB_CLASS,
> +	.bInterfaceProtocol	= FASTBOOT_INTERFACE_PROTOCOL,
> +	.iInterface		= FB_STR_INTERFACE_IDX,
> +};
> +
> +static struct usb_qualifier_descriptor qual_desc = {
> +	.bLength		= sizeof(qual_desc),
> +	.bDescriptorType	= USB_DT_DEVICE_QUALIFIER,
> +	.bcdUSB			= 0x200,
> +	.bMaxPacketSize0	= 0x40,
> +	.bNumConfigurations	= 1,
> +};
> +
> +static int fastboot_setup_get_descr(struct usb_gadget *gadget,
> +		const struct usb_ctrlrequest *ctrl)
> +{
> +	u16 w_value	= le16_to_cpu(ctrl->wValue);
> +	u16 w_length	= le16_to_cpu(ctrl->wLength);
> +	u16 val;
> +	int ret;
> +	u32 bytes_remaining;
> +	u32 bytes_total;
> +	u32 this_inc;
> +
> +	val = w_value >> 8;
> +
> +	switch (val) {
> +	case USB_DT_DEVICE:
> +		memcpy(ep0_buffer, &fb_descriptor,
> sizeof(fb_descriptor));
> +		ep0_req->length = min(w_length,
> sizeof(fb_descriptor));
> +		ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
> +		break;
> +	case USB_DT_CONFIG:
> +		bytes_remaining = min(w_length, sizeof(ep0_buffer));
> +		bytes_total = 0;
> +
> +		/* config */
> +		this_inc = min(bytes_remaining, USB_DT_CONFIG_SIZE);
> +		bytes_remaining -= this_inc;
> +		memcpy(ep0_buffer + bytes_total, &config_desc,
> this_inc);
> +		bytes_total += this_inc;
> +
> +		/* interface */
> +		this_inc = min(bytes_remaining,
> USB_DT_INTERFACE_SIZE);
> +		bytes_remaining -= this_inc;
> +		memcpy(ep0_buffer + bytes_total, &interface_desc,
> this_inc);
> +		bytes_total += this_inc;
> +
> +		/* ep in */
> +		this_inc = min(bytes_remaining,
> USB_DT_ENDPOINT_SIZE);
> +		bytes_remaining -= this_inc;
> +		memcpy(ep0_buffer + bytes_total, &fs_ep_in,
> this_inc);
> +		bytes_total += this_inc;
> +
> +		/* ep out */
> +		this_inc = min(bytes_remaining,
> USB_DT_ENDPOINT_SIZE); +
> +		if (gadget->speed == USB_SPEED_HIGH)
> +			memcpy(ep0_buffer + bytes_total, &hs_ep_out,
> this_inc);
> +		else
> +			memcpy(ep0_buffer + bytes_total, &fs_ep_out,
> this_inc);
> +		bytes_total += this_inc;
> +
> +		ep0_req->length = bytes_total;
> +		ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
> +		break;
> +	case USB_DT_STRING:
> +		ret = usb_gadget_get_string(vendor_fb_strings,
> +					    w_value & 0xff,
> ep0_buffer);
> +		if (ret < 0)
> +			ret = usb_gadget_get_string(&def_fb_strings,
> +						    w_value & 0xff,
> +						    ep0_buffer);
> +		if (ret < 0)
> +			break;
> +
> +		ep0_req->length = ret;
> +		ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
> +		break;
> +	case USB_DT_DEVICE_QUALIFIER:
> +		memcpy(ep0_buffer, &qual_desc, sizeof(qual_desc));
> +		ep0_req->length = min(w_length, sizeof(qual_desc));
> +		ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +	}
> +	return ret;
> +}

Here you use only the gadget API. In the THOR, UMS and DFU functions
such code is handled by the composite layer (composite.c) for all of
them. 


> +
> +static int fastboot_setup_get_conf(struct usb_gadget *gadget,
> +		const struct usb_ctrlrequest *ctrl)
> +{
> +	u16 w_length	= le16_to_cpu(ctrl->wLength);
> +
> +	if (w_length == 0)
> +		return -1;
> +
> +	ep0_buffer[0] = current_config;
> +	ep0_req->length = 1;
> +	return usb_ep_queue(gadget->ep0, ep0_req, 0);
> +}
> +
> +static void fastboot_complete_in(struct usb_ep *ep, struct
> usb_request *req) +{
> +	int status = req->status;
> +
> +	if (status)
> +		printf("status: %d ep_in trans: %d\n", status,
> req->actual); +}
> +
> +static int fastboot_disable_ep(struct usb_gadget *gadget)
> +{
> +	if (req_out) {
> +		usb_ep_free_request(ep_out, req_out);
> +		req_out = NULL;
> +	}
> +	if (req_in) {
> +		usb_ep_free_request(ep_in, req_in);
> +		req_in = NULL;
> +	}
> +	usb_ep_disable(ep_out);
> +	usb_ep_disable(ep_in);
> +
> +	return 0;
> +}
> +
> +static int fastboot_enable_ep(struct usb_gadget *gadget)
> +{
> +	int ret;
> +
> +	/* make sure we don't enable the ep twice */
> +	if (gadget->speed == USB_SPEED_HIGH)
> +		ret = usb_ep_enable(ep_out, &hs_ep_out);
> +	else
> +		ret = usb_ep_enable(ep_out, &fs_ep_out);
> +	if (ret) {
> +		printf("failed to enable out ep\n");
> +		goto err;
> +	}
> +
> +	req_out = usb_ep_alloc_request(ep_out, 0);
> +	if (!req_out) {
> +		printf("failed to alloc out req\n");
> +		goto err;
> +	}
> +
> +	ret = usb_ep_enable(ep_in, &fs_ep_in);
> +	if (ret) {
> +		printf("failed to enable in ep\n");
> +		goto err;
> +	}
> +	req_in = usb_ep_alloc_request(ep_in, 0);
> +	if (!req_in) {
> +		printf("failed alloc req in\n");
> +		goto err;
> +	}
> +
> +	req_out->complete = rx_handler_command;
> +	req_out->buf = ep_out_buffer;
> +	req_out->length = sizeof(ep_out_buffer);
> +
> +	req_in->buf = ep_in_buffer;
> +	req_in->length = sizeof(ep_in_buffer);
> +
> +	ret = usb_ep_queue(ep_out, req_out, 0);
> +	if (ret)
> +		goto err;
> +
> +	return 0;
> +err:
> +	fastboot_disable_ep(gadget);
> +	return -1;
> +}
> +
> +static int fastboot_set_interface(struct usb_gadget *gadget, u32
> enable) +{
> +	if (enable && req_out)
> +		return 0;
> +	if (!enable && !req_out)
> +		return 0;
> +

	^^^^^^^ maybe one if?

> +	if (enable)
> +		return fastboot_enable_ep(gadget);
> +	else
> +		return fastboot_disable_ep(gadget);
> +}
> +
> +static int fastboot_setup_out_req(struct usb_gadget *gadget,
> +		const struct usb_ctrlrequest *req)
> +{
> +	switch (req->bRequestType & USB_RECIP_MASK) {
> +	case USB_RECIP_DEVICE:
> +		switch (req->bRequest) {
> +		case USB_REQ_SET_CONFIGURATION:
> +
> +			ep0_req->length = 0;
> +			if (req->wValue == CONFIGURATION_NORMAL) {
> +				current_config =
> CONFIGURATION_NORMAL;
> +				fastboot_set_interface(gadget, 1);
> +				return usb_ep_queue(gadget->ep0,
> +						ep0_req, 0);
> +			}
> +			if (req->wValue == 0) {
> +				current_config = 0;
> +				fastboot_set_interface(gadget, 0);
> +				return usb_ep_queue(gadget->ep0,
> +						ep0_req, 0);
> +			}
> +			return -1;
	
			I always encourage people to return values from
			<errno.h>

> +			break;
> +		default:
> +			return -1;
> +		};
> +
> +	case USB_RECIP_INTERFACE:
> +		switch (req->bRequest) {
> +		case USB_REQ_SET_INTERFACE:
> +
> +			ep0_req->length = 0;
> +			if (!fastboot_set_interface(gadget, 1))
> +				return usb_ep_queue(gadget->ep0,
> +						ep0_req, 0);
> +			return -1;
> +			break;
> +		default:
> +			return -1;
> +		}
> +
> +	case USB_RECIP_ENDPOINT:
> +		switch (req->bRequest) {
> +		case USB_REQ_CLEAR_FEATURE:
> +
> +			return usb_ep_queue(gadget->ep0, ep0_req, 0);
> +			break;
> +		default:
> +			return -1;
> +		}
> +	}
> +	return -1;
> +}
> +
> +static int fastboot_setup(struct usb_gadget *gadget,
> +		const struct usb_ctrlrequest *req)
> +{
> +	if ((req->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
> +		return -1;
> +
> +	if ((req->bRequestType & USB_DIR_IN) == 0)
> +		/* host-to-device */
> +		return fastboot_setup_out_req(gadget, req);
> +
> +	/* device-to-host */
> +	if ((req->bRequestType & USB_RECIP_MASK) ==
> USB_RECIP_DEVICE) {
> +		switch (req->bRequest) {
> +		case USB_REQ_GET_DESCRIPTOR:
> +			return fastboot_setup_get_descr(gadget, req);
> +			break;
> +
> +		case USB_REQ_GET_CONFIGURATION:
> +			return fastboot_setup_get_conf(gadget, req);
> +			break;
> +		default:
> +			return -1;
> +		}
> +	}
> +	return -1;
> +}
> +
> +static void fastboot_disconnect(struct usb_gadget *gadget)
> +{
> +	fastboot_disable_ep(gadget);
> +	gadget_is_connected = 0;
> +}
> +
> +struct usb_gadget_driver fast_gadget = {
> +	.speed		= USB_SPEED_HIGH,
> +	.bind		= fastboot_bind,
> +	.unbind		= fastboot_unbind,
> +	.setup		= fastboot_setup,
> +	.disconnect	= fastboot_disconnect,
> +};
> +
> +static int udc_is_probbed;
> +
> +int __weak fastboot_board_init(struct usb_gadget_strings **str)
> +{
> +	return 0;
> +}
> +
> +int fastboot_init(void)
> +{
> +	int ret;
> +
> +	ret = fastboot_board_init(&vendor_fb_strings);
> +	if (ret)
> +		return ret;
> +
> +	ret = usb_gadget_register_driver(&fast_gadget);
> +	if (ret) {
> +		printf("Add gadget failed\n");
> +		return ret;
> +	}
> +
> +	udc_is_probbed = 1;
> +	return 0;
> +}
> +
> +int fastboot_poll(void)
> +{
> +	usb_gadget_handle_interrupts();
> +
> +	if (gadget_is_connected)
> +		return 0;
> +	else
> +		return 1;
> +}
> +
> +void fastboot_shutdown(void)
> +{
> +	if (!udc_is_probbed)
> +		return;
> +	udc_is_probbed = 0;
> +	usb_gadget_unregister_driver(&fast_gadget);
> +}
> +
> +int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
> +{
> +	int ret;
> +
> +	if (req_in->complete == NULL)
> +		req_in->complete = fastboot_complete_in;
> +
> +	memcpy(req_in->buf, buffer, buffer_size);
> +	req_in->length = buffer_size;
> +	ret = usb_ep_queue(ep_in, req_in, 0);
> +	if (ret)
> +		printf("Error %d on queue\n", ret);
> +	return 0;
> +}
> diff --git a/drivers/usb/gadget/g_fastboot.h
> b/drivers/usb/gadget/g_fastboot.h new file mode 100644
> index 0000000..733eb38
> --- /dev/null
> +++ b/drivers/usb/gadget/g_fastboot.h
> @@ -0,0 +1,15 @@
> +#ifndef _G_FASTBOOT_H_
> +#define _G_FASTBOOT_H_
> +
> +#define EP_BUFFER_SIZE			4096
> +
> +extern struct usb_ep *ep_in;
> +extern struct usb_request *req_in;
> +extern struct usb_ep *ep_out;
> +extern struct usb_request *req_out;
> +
> +void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
> +int fastboot_tx_write(const char *buffer, unsigned int buffer_size);
> +const char *fb_find_usb_string(unsigned int id);
> +
> +#endif
> diff --git a/drivers/usb/gadget/u_fastboot.c
> b/drivers/usb/gadget/u_fastboot.c new file mode 100644
> index 0000000..76116c0
> --- /dev/null
> +++ b/drivers/usb/gadget/u_fastboot.c
> @@ -0,0 +1,260 @@
> +/*
> + * (C) Copyright 2008 - 2009
> + * Windriver, <www.windriver.com>
> + * Tom Rix <Tom.Rix@windriver.com>
> + *
> + * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +/*
> + * Part of the rx_handler were copied from the Android project.
> + * Specifically rx command parsing in the usb_rx_cmd_complete
> + * function of the file
> bootable/bootloader/legacy/usbloader/usbloader.c
> + *
> + * Repository:
> https://android.googlesource.com/platform/bootable/bootloader/legacy
> + * Files: usbloader/usbloader.c
> + * Commit: 4205b865141ff2e255fe1d3bd16de18e217ef06a
> + *
> + * Copyright (C) 2008 The Android Open Source Project
> + *
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +#include <common.h>
> +#include <usb/fastboot.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +#include "g_fastboot.h"
> +
> +#define FASTBOOT_VERSION		"0.4"
> +
> +/* The 64 defined bytes plus \0 */
> +#define RESPONSE_LEN	(64 + 1)
> +
> +static unsigned int download_size;
> +static unsigned int download_bytes;
> +
> +static int fastboot_tx_write_str(const char *buffer)
> +{
> +	return fastboot_tx_write(buffer, strlen(buffer));
> +}
> +
> +static void compl_do_reset(struct usb_ep *ep, struct usb_request
> *req) +{
> +	do_reset(NULL, 0, 0, NULL);
> +}
> +
> +static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
> +{
> +	req_in->complete = compl_do_reset;
> +	fastboot_tx_write_str("OKAY");
> +}
> +
> +static int strcmp_l1(const char *s1, const char *s2)
> +{
> +	return strncmp(s1, s2, strlen(s1));
> +}
> +
> +static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
> +{
> +	char *cmd = req->buf;
> +	char response[RESPONSE_LEN];
> +	const char *s;
> +
> +	strcpy(response, "OKAY");
> +	strsep(&cmd, ":");
> +	if (!cmd) {
> +		fastboot_tx_write_str("FAILmissing var");
> +		return;
> +	}
> +
> +	if (!strcmp_l1("version", cmd)) {
> +		strncat(response, FASTBOOT_VERSION,
> sizeof(response));
> +	} else if (!strcmp_l1("downloadsize", cmd)) {
> +		char str_num[12];
> +
> +		sprintf(str_num, "%08lx", load_size);
> +		strncat(response, str_num, sizeof(response));
> +	} else if (!strcmp_l1("product", cmd)) {
> +		s = fb_find_usb_string(FB_STR_PRODUCT_IDX);
> +		if (s)
> +			strncat(response, s, sizeof(response));
> +		else
> +			strcpy(response, "FAILValue not set");
> +	} else if (!strcmp_l1("serialno", cmd)) {
> +		s = fb_find_usb_string(FB_STR_SERIAL_IDX);
> +		if (s)
> +			strncat(response, s, sizeof(response));
> +		else
> +			strcpy(response, "FAILValue not set");
> +	} else if (!strcmp_l1("cpurev", cmd)) {
> +		s = fb_find_usb_string(FB_STR_PROC_REV_IDX);
> +		if (s)
> +			strncat(response, s, sizeof(response));
> +		else
> +			strcpy(response, "FAILValue not set");
> +	} else if (!strcmp_l1("secure", cmd)) {
> +		s = fb_find_usb_string(FB_STR_PROC_TYPE_IDX);
> +		if (s)
> +			strncat(response, s, sizeof(response));
> +		else
> +			strcpy(response, "FAILValue not set");
> +	} else {
> +		strcpy(response, "FAILVariable not implemented");
> +	}
> +	fastboot_tx_write_str(response);
> +}
> +
> +static unsigned int rx_bytes_expected(void)
> +{
> +	int rx_remain = download_size - download_bytes;
> +	if (rx_remain < 0)
> +		return 0;
> +	if (rx_remain > EP_BUFFER_SIZE)
> +		return EP_BUFFER_SIZE;
> +	return rx_remain;
> +}
> +
> +#define BYTES_PER_DOT	32768
> +static void rx_handler_dl_image(struct usb_ep *ep, struct
> usb_request *req) +{
> +	char response[RESPONSE_LEN];
> +	unsigned int transfer_size = download_size - download_bytes;
> +	const unsigned char *buffer = req->buf;
> +	unsigned int buffer_size = req->actual;
> +
> +	if (req->status != 0) {
> +		printf("Bad status: %d\n", req->status);
> +		return;
> +	}
> +
> +	if (buffer_size < transfer_size)
> +		transfer_size = buffer_size;
> +
> +	memcpy((void *)load_addr + download_bytes, buffer,
> transfer_size); +
> +	download_bytes += transfer_size;

	The dfu backend uses zero copy approach.

> +
> +	/* Check if transfer is done */
> +	if (download_bytes >= download_size) {
> +		/*
> +		 * Reset global transfer variable, keep
> download_bytes because
> +		 * it will be used in the next possible flashing
> command
> +		 */
> +		download_size = 0;
> +		req->complete = rx_handler_command;
> +		req->length = EP_BUFFER_SIZE;
> +
> +		sprintf(response, "OKAY");
> +		fastboot_tx_write_str(response);
> +
> +		printf("\ndownloading of %d bytes finished\n",
> download_bytes);
> +	} else {
> +		req->length = rx_bytes_expected();
> +	}
> +
> +	if (download_bytes && !(download_bytes % BYTES_PER_DOT)) {
> +		printf(".");
> +		if (!(download_bytes % (74 * BYTES_PER_DOT)))
> +			printf("\n");
> +	}
> +	req->actual = 0;
> +	usb_ep_queue(ep, req, 0);
> +}
> +
> +static void cb_download(struct usb_ep *ep, struct usb_request *req)
> +{
> +	char *cmd = req->buf;
> +	char response[RESPONSE_LEN];
> +
> +	strsep(&cmd, ":");
> +	download_size = simple_strtoul(cmd, NULL, 16);
> +	download_bytes = 0;
> +
> +	printf("Starting download of %d bytes\n", download_size);
> +
> +	if (0 == download_size) {
> +		sprintf(response, "FAILdata invalid size");
> +	} else if (download_size > load_size) {
> +		download_size = 0;
> +		sprintf(response, "FAILdata too large");
> +	} else {
> +		sprintf(response, "DATA%08x", download_size);
> +		req->complete = rx_handler_dl_image;
> +		req->length = rx_bytes_expected();
> +	}
> +	fastboot_tx_write_str(response);
> +}
> +
> +static char boot_addr_start[32];
> +static char *bootm_args[] = { "bootm", boot_addr_start, NULL };
> +
> +static void do_bootm_on_complete(struct usb_ep *ep, struct
> usb_request *req) +{
> +	req->complete = NULL;
> +	fastboot_shutdown();
> +	printf("Booting kernel..\n");

	puts();

> +
> +	do_bootm(NULL, 0, 2, bootm_args);
> +
> +	/* This only happens if image is somehow faulty so we start
> over */
> +	do_reset(NULL, 0, 0, NULL);
> +}
> +
> +static void cb_boot(struct usb_ep *ep, struct usb_request *req)
> +{
> +	sprintf(boot_addr_start, "0x%lx", load_addr);
> +
> +	req_in->complete = do_bootm_on_complete;
> +	fastboot_tx_write_str("OKAY");
> +	return;
> +}
> +
> +struct cmd_dispatch_info {
> +	char *cmd;
> +	void (*cb)(struct usb_ep *ep, struct usb_request *req);
> +};
> +
> +static struct cmd_dispatch_info cmd_dispatch_info[] = {
> +	{
> +		.cmd = "reboot",
> +		.cb = cb_reboot,
> +	}, {
> +		.cmd = "getvar:",
> +		.cb = cb_getvar,
> +	}, {
> +		.cmd = "download:",
> +		.cb = cb_download,
> +	}, {
> +		.cmd = "boot",
> +		.cb = cb_boot,
> +	},
> +};
> +
> +void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
> +{
> +	char response[RESPONSE_LEN];
> +	char *cmdbuf = req->buf;
> +	void (*func_cb)(struct usb_ep *ep, struct usb_request *req)
> = NULL;
> +	int i;
> +
> +	sprintf(response, "FAIL");
> +
> +	for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
> +		if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
> +			func_cb = cmd_dispatch_info[i].cb;
> +			break;
> +		}
> +	}
> +
> +	if (!func_cb)
> +		fastboot_tx_write_str("FAILunknown command");
> +	else
> +		func_cb(ep, req);
> +
> +	if (req->status == 0) {
> +		*cmdbuf = '\0';
> +		req->actual = 0;
> +		usb_ep_queue(ep, req, 0);
> +	}
> +}
> diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h
> new file mode 100644
> index 0000000..b348886
> --- /dev/null
> +++ b/include/usb/fastboot.h
> @@ -0,0 +1,36 @@
> +/*
> + * (C) Copyright 2008 - 2009
> + * Windriver, <www.windriver.com>
> + * Tom Rix <Tom.Rix@windriver.com>
> + *
> + * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#ifndef FASTBOOT_H
> +#define FASTBOOT_H
> +
> +#include <common.h>
> +#include <command.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +
> +#define FB_STR_PRODUCT_IDX      1
> +#define FB_STR_SERIAL_IDX       2
> +#define FB_STR_CONFIG_IDX       3
> +#define FB_STR_INTERFACE_IDX    4
> +#define FB_STR_MANUFACTURER_IDX 5
> +#define FB_STR_PROC_REV_IDX     6
> +#define FB_STR_PROC_TYPE_IDX    7
> +
> +#ifdef CONFIG_CMD_FASTBOOT
> +
> +int fastboot_init(void);
> +void fastboot_shutdown(void);
> +int fastboot_poll(void);
> +
> +int fastboot_board_init(struct usb_gadget_strings **str);
> +
> +#endif
> +#endif

To sum up:

It seems that you are using UDC driver + gadget approach for fastboot. 

However, current gadgets for downloading data (DFU, UMS, THOR) use UDC +
composite gadget + function.

Also they use common download code - g_dnl.c to implement their
commands.

I would be more than happy if you were willing to port the fastboot
protocol to the existing framework. 
For overall picture of the current design please look into the following
keynote:
http://www.denx.de/wiki/pub/U-Boot/MiniSummitELCE2013/dfu_elce_u-boot.pdf

Please let me know if you have any questions.


-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget
  2014-04-15 15:41   ` Lukasz Majewski
@ 2014-04-15 16:01     ` Rob Herring
  0 siblings, 0 replies; 59+ messages in thread
From: Rob Herring @ 2014-04-15 16:01 UTC (permalink / raw)
  To: u-boot

On Tue, Apr 15, 2014 at 10:41 AM, Lukasz Majewski
<l.majewski@samsung.com> wrote:
> Hi Rob,
>
>> From: Sebastian Siewior <bigeasy@linutronix.de>
>>
>> This patch contains an implementation of the fastboot protocol on the
>> device side and a little of documentation.
>> The gadget expects the new-style gadget framework.
>> The gadget implements the getvar, reboot, download and reboot
>> commands. What is missing is the flash handling i.e. writting the
>> image to media.
>>
>> v3 (Rob Herring):
>> This is based on http://patchwork.ozlabs.org/patch/126798/ with the
>> following changes:
>> - Rebase to current mainline and updates for current gadget API
>> - Use SPDX identifiers for licenses
>> - Traced the history and added missing copyright to cmd_fastboot.c
>> - Use load_addr/load_size for transfer buffer
>> - Allow vendor strings to be optional

[snip]

> To sum up:
>
> It seems that you are using UDC driver + gadget approach for fastboot.
>
> However, current gadgets for downloading data (DFU, UMS, THOR) use UDC +
> composite gadget + function.
>
> Also they use common download code - g_dnl.c to implement their
> commands.
>
> I would be more than happy if you were willing to port the fastboot
> protocol to the existing framework.
> For overall picture of the current design please look into the following
> keynote:
> http://www.denx.de/wiki/pub/U-Boot/MiniSummitELCE2013/dfu_elce_u-boot.pdf
>
> Please let me know if you have any questions.

Thanks for your review. I have this working using the common g_dnl.c
code now. I have a bit more clean-up to do and I will post it. My
current branch is here:

git://git.linaro.org/people/rob.herring/u-boot.git fastboot-v2

Rob

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 1/5] common: introduce maximum load size
  2014-04-10 19:18 ` [U-Boot] [PATCH v3 1/5] common: introduce maximum load size Rob Herring
  2014-04-11 14:46   ` Tom Rini
  2014-04-15 12:55   ` Lukasz Majewski
@ 2014-04-15 21:59   ` Wolfgang Denk
  2014-04-15 23:54     ` Rob Herring
  2 siblings, 1 reply; 59+ messages in thread
From: Wolfgang Denk @ 2014-04-15 21:59 UTC (permalink / raw)
  To: u-boot

Dear Rob,

In message <1397157488-8695-2-git-send-email-robherring2@gmail.com> you wrote:
> 
> Various commands that load images have no checks that a loaded image
> does not exceed the available RAM space and will happily continue
> overwriting u-boot or other RAM that should not be touched. Also,
> some commands such as USB DFU or fastboot need to know the maximum
> buffer size, but there is no common way to define this.

You are mixing some pretty much unrelated things here, which is IMO
not a good idea.  Limiting the size for load operations is one thing,
but buffer size is something totally different.  These must not be
mixed up.  Please keep in mind that there is (or at least should be)
no need to load the whole file into a buffer. [Limitations of the
implementation should be fixed rather than supported.]

> Introduce a global load_size and environment variable loadsize to
> specify the size. The default is ~0UL which is effectively unlimited.

I think this feature should be made optional.  I don;t think I want to
have this on all systems.

> +  loadsize	- Maximum load size for commands like "bootp",
> +		  "rarpboot", "tftpboot", "loadb" or "diskboot"

Um... what makes these operations different from any other operations
that read images or other data to memory?  Like loading from NOR or
NAND flash, from USB, IDE or SATA storage devices, from any of the
supported file system types?

I feel we should either support this consequently everywhere, or not
at all.  My personal preference is the second option, as otherwise you
will just add a lot of code in too many places for too little benefit.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
No man knows what true happiness is until he gets married.  By  then,
of course, its too late.

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 1/5] common: introduce maximum load size
  2014-04-15 21:59   ` Wolfgang Denk
@ 2014-04-15 23:54     ` Rob Herring
  2014-04-16  7:27       ` Wolfgang Denk
  0 siblings, 1 reply; 59+ messages in thread
From: Rob Herring @ 2014-04-15 23:54 UTC (permalink / raw)
  To: u-boot

On Tue, Apr 15, 2014 at 4:59 PM, Wolfgang Denk <wd@denx.de> wrote:
> Dear Rob,
>
> In message <1397157488-8695-2-git-send-email-robherring2@gmail.com> you wrote:
>>
>> Various commands that load images have no checks that a loaded image
>> does not exceed the available RAM space and will happily continue
>> overwriting u-boot or other RAM that should not be touched. Also,
>> some commands such as USB DFU or fastboot need to know the maximum
>> buffer size, but there is no common way to define this.
>
> You are mixing some pretty much unrelated things here, which is IMO
> not a good idea.  Limiting the size for load operations is one thing,
> but buffer size is something totally different.  These must not be
> mixed up.  Please keep in mind that there is (or at least should be)
> no need to load the whole file into a buffer. [Limitations of the
> implementation should be fixed rather than supported.]

That is true if you are loading files to write to storage, but if you
are loading them to boot like tftp, diskboot, fsload, fastboot, etc.
all do, then you should have some checks in place. Otherwise you can
just load things over RAM u-boot is using.

fastboot is loading images to boot just like other commands that use
loadaddr, but has the additional need to know the max size. Rather
than add yet another custom define, I was looking at how to solve this
generically. I considered perhaps this should be based on LMB/bootmap?
But LMB is more about what the OS can use rather than what memory is
available.


>> Introduce a global load_size and environment variable loadsize to
>> specify the size. The default is ~0UL which is effectively unlimited.
>
> I think this feature should be made optional.  I don;t think I want to
> have this on all systems.
>
>> +  loadsize   - Maximum load size for commands like "bootp",
>> +               "rarpboot", "tftpboot", "loadb" or "diskboot"
>
> Um... what makes these operations different from any other operations
> that read images or other data to memory?  Like loading from NOR or
> NAND flash, from USB, IDE or SATA storage devices, from any of the
> supported file system types?

They are not. I just copied the text from loadaddr, but any command
that uses load_addr is missing any upper bounds checking.

> I feel we should either support this consequently everywhere, or not
> at all.  My personal preference is the second option, as otherwise you
> will just add a lot of code in too many places for too little benefit.

I believe the former will make things more robust and I would like to
see this for all commands that load something to memory, but we should
agree on the approach first.

Rob

>
> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
> No man knows what true happiness is until he gets married.  By  then,
> of course, its too late.

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v3 1/5] common: introduce maximum load size
  2014-04-15 23:54     ` Rob Herring
@ 2014-04-16  7:27       ` Wolfgang Denk
  0 siblings, 0 replies; 59+ messages in thread
From: Wolfgang Denk @ 2014-04-16  7:27 UTC (permalink / raw)
  To: u-boot

Dear Rob Herring,

In message <CAL_JsqJ3mDsUoqqDL93Aa6OiLVpscVs3M_ixjgF0O+yfkftgEA@mail.gmail.com> you wrote:
>
> > You are mixing some pretty much unrelated things here, which is IMO
> > not a good idea.  Limiting the size for load operations is one thing,
> > but buffer size is something totally different.  These must not be
> > mixed up.  Please keep in mind that there is (or at least should be)
> > no need to load the whole file into a buffer. [Limitations of the
> > implementation should be fixed rather than supported.]
> 
> That is true if you are loading files to write to storage, but if you
> are loading them to boot like tftp, diskboot, fsload, fastboot, etc.
> all do, then you should have some checks in place. Otherwise you can
> just load things over RAM u-boot is using.

This can always happen - like when the user sets the maximum load size
too big.  Actually the concept of a maximum load size is not working
at all, as it takes not into account _where_ you load the image to;
when loading it low in RAM the allowable size is different from when
loading to a higher address.  You cannot tell in advance how much RAM
you can actually use - the stack is growing downward, and we don't
have any hard limits on the stack size.  And even if the loading does
not collide with the stack, you don't know if the stack will not grow
urther down when you process the image, in which case it would get
overwritten _after_ loading, so your test would not catch it either.

> fastboot is loading images to boot just like other commands that use
> loadaddr, but has the additional need to know the max size. Rather

Don't you see that the max actually available size depends on
loadaddr, so you cannot set one without considering the other?

> > Um... what makes these operations different from any other operations
> > that read images or other data to memory?  Like loading from NOR or
> > NAND flash, from USB, IDE or SATA storage devices, from any of the
> > supported file system types?
> 
> They are not. I just copied the text from loadaddr, but any command
> that uses load_addr is missing any upper bounds checking.

Yes, and this is intentionally.  There is no clean, reliable way to
implement this features, so instead of providing some deceptive
security we rely on the user knowing what he is doing.

> > I feel we should either support this consequently everywhere, or not
> > at all.  My personal preference is the second option, as otherwise you
> > will just add a lot of code in too many places for too little benefit.
> 
> I believe the former will make things more robust and I would like to
> see this for all commands that load something to memory, but we should
> agree on the approach first.

Well, we need one that actually works first.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Let the programmers be many and the managers few -- then all will  be
productive.               -- Geoffrey James, "The Tao of Programming"

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 0/5] Android Fastboot support
  2014-04-10 19:18 [U-Boot] [PATCH v3 0/5] Android Fastboot support Rob Herring
                   ` (7 preceding siblings ...)
  2014-04-11 14:45 ` Tom Rini
@ 2014-04-18 13:54 ` Rob Herring
  2014-04-18 13:54   ` [U-Boot] [PATCH v4 1/5] usb: handle NULL table in usb_gadget_get_string Rob Herring
                     ` (6 more replies)
  8 siblings, 7 replies; 59+ messages in thread
From: Rob Herring @ 2014-04-18 13:54 UTC (permalink / raw)
  To: u-boot

From: Rob Herring <robh@kernel.org>

This is the 2nd version since I revived the fastboot patches Sebastian 
submitted.

I'm reviving the Android Fastboot support after 2+ years since the last 
posting[1]. The previous postings had some questions about licensing 
and source of some code. I believe I've traced the history sufficiently 
that the copyrights and source information are complete and correct.

The Android code used or referenced is BSD 2-clause license. This was 
originally raised by Wolfgang that it was not compatible with GPLv2+. I 
believe that has since been demonstrated and agreed that the BSD 
2-clause license is compatible with u-boot. 

As far as the history of the code, I have traced that back. The u-boot 
code started in 2008/2009 by Tom Rix @ Windriver. This initial support 
was then adopted and extended by TI (eMMC support primarily, not 
included here) in their OMAP u-boot tree[2]. In 2011, the TI code was 
used as a basis for upstream patches by Sebastian Siewior @ Linutronix. 
The code has been rearranged quite a bit since the original, but the 
content is pretty much the same. Some of the re-arranging left stale or 
missing copyrights in the v2 version which I have corrected.

I've redone the fastboot code significantly to use the USB download 
gadget composite driver. With this, I've consolidated the fastboot 
function into a single file. I believe I've addressed all the review 
comments, but many don't apply with the re-write.

I dropped the patch adding a loadsize env variable and added config 
uptions instead to set the fastboot buffer size.

I've tested this series on a BeagleBoard.

Rob

[1] http://lists.denx.de/pipermail/u-boot/2011-November/110557.html
[2] http://git.omapzoom.org/?p=repo/u-boot.git;a=commit;h=601ff71c8d46b5e90e13613974a16d10f2006bb3

Rob Herring (3):
  usb: handle NULL table in usb_gadget_get_string
  usb: musb: fill in usb_gadget_unregister_driver
  arm: beagle: enable Android fastboot support

Sebastian Siewior (2):
  image: add support for Android's boot image format
  usb/gadget: add the fastboot gadget

 common/Makefile                      |   3 +
 common/cmd_bootm.c                   |  23 +-
 common/cmd_fastboot.c                |  36 +++
 common/image-android.c               |  84 ++++++
 common/image.c                       |  20 +-
 doc/README.android-fastboot          |  91 ++++++
 doc/README.android-fastboot-protocol | 170 ++++++++++++
 drivers/usb/gadget/Makefile          |   1 +
 drivers/usb/gadget/f_fastboot.c      | 518 +++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/g_dnl.c           |   6 +
 drivers/usb/gadget/usbstring.c       |   3 +
 drivers/usb/musb-new/musb_uboot.c    |   5 +-
 include/android_image.h              |  69 +++++
 include/configs/omap3_beagle.h       |  10 +
 include/fastboot.h                   |  22 ++
 include/image.h                      |  13 +
 16 files changed, 1067 insertions(+), 7 deletions(-)
 create mode 100644 common/cmd_fastboot.c
 create mode 100644 common/image-android.c
 create mode 100644 doc/README.android-fastboot
 create mode 100644 doc/README.android-fastboot-protocol
 create mode 100644 drivers/usb/gadget/f_fastboot.c
 create mode 100644 include/android_image.h
 create mode 100644 include/fastboot.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 1/5] usb: handle NULL table in usb_gadget_get_string
  2014-04-18 13:54 ` [U-Boot] [PATCH v4 " Rob Herring
@ 2014-04-18 13:54   ` Rob Herring
  2014-04-18 13:54   ` [U-Boot] [PATCH v4 2/5] image: add support for Android's boot image format Rob Herring
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 59+ messages in thread
From: Rob Herring @ 2014-04-18 13:54 UTC (permalink / raw)
  To: u-boot

From: Rob Herring <robh@kernel.org>

Allow a NULL table to be passed to usb_gadget_get_string for cases
when a string table may not be populated.

Signed-off-by: Rob Herring <robh@kernel.org>
Reviewed-by: Tom Rini <trini@ti.com>
Acked-by: Marek Vasut <marex@denx.de>
Acked-by: Lukasz Majewski <l.majewski@samsung.com>
---
 drivers/usb/gadget/usbstring.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index de5fa3f..8c3ff64 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -108,6 +108,9 @@ usb_gadget_get_string(struct usb_gadget_strings *table, int id, u8 *buf)
 	struct usb_string	*s;
 	int			len;
 
+	if (!table)
+		return -EINVAL;
+
 	/* descriptor 0 has the language id */
 	if (id == 0) {
 		buf[0] = 4;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 2/5] image: add support for Android's boot image format
  2014-04-18 13:54 ` [U-Boot] [PATCH v4 " Rob Herring
  2014-04-18 13:54   ` [U-Boot] [PATCH v4 1/5] usb: handle NULL table in usb_gadget_get_string Rob Herring
@ 2014-04-18 13:54   ` Rob Herring
  2014-04-18 13:54   ` [U-Boot] [PATCH v4 3/5] usb: musb: fill in usb_gadget_unregister_driver Rob Herring
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 59+ messages in thread
From: Rob Herring @ 2014-04-18 13:54 UTC (permalink / raw)
  To: u-boot

From: Sebastian Siewior <bigeasy@linutronix.de>

This patch adds support for the Android boot-image format. The header
file is from the Android project and got slightly alterted so the struct +
its defines are not generic but have something like a namespace. The
header file is from bootloader/legacy/include/boot/bootimg.h. The header
parsing has been written from scratch and I looked at
bootloader/legacy/usbloader/usbloader.c for some details.
The image contains the physical address (load address) of the kernel and
ramdisk. This address is considered only for the kernel image.
The "second image" defined in the image header is currently not
supported. I haven't found anything that is creating this.

v3 (Rob Herring):
This is based on http://patchwork.ozlabs.org/patch/126797/ with the
following changes:
- Rebased to current mainline
- Moved android image handling to separate functions in
  common/image-android.c
- s/u8/char/ in header to fix string function warnings
- Use SPDX identifiers for licenses
- Cleaned-up file source information:
  android_image.h is from file include/boot/bootimg.h in repository:
  https://android.googlesource.com/platform/bootable/bootloader/legacy
  The git commit hash is 4205b865141ff2e255fe1d3bd16de18e217ef06a
  usbloader.c would be from the same commit, but it does not appear
  to have been used for any actual code.
v4:
- s/andriod/android/
- Use a separate flag ep_found to track if the entry point has been set
rather than using a magic value.

Cc: Wolfgang Denk <wd@denx.de>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Rob Herring <robh@kernel.org>
Reviewed-by: Tom Rini <trini@ti.com>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>
---
 common/Makefile         |  1 +
 common/cmd_bootm.c      | 23 +++++++++++++-
 common/image-android.c  | 84 +++++++++++++++++++++++++++++++++++++++++++++++++
 common/image.c          | 20 +++++++++---
 include/android_image.h | 69 ++++++++++++++++++++++++++++++++++++++++
 include/image.h         | 13 ++++++++
 6 files changed, 204 insertions(+), 6 deletions(-)
 create mode 100644 common/image-android.c
 create mode 100644 include/android_image.h

diff --git a/common/Makefile b/common/Makefile
index cecd81a..da208f3 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -236,6 +236,7 @@ obj-y += console.o
 obj-$(CONFIG_CROS_EC) += cros_ec.o
 obj-y += dlmalloc.o
 obj-y += image.o
+obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
 obj-$(CONFIG_OF_LIBFDT) += image-fdt.o
 obj-$(CONFIG_FIT) += image-fit.o
 obj-$(CONFIG_FIT_SIGNATURE) += image-sig.o
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 9751edc..3de876d 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -222,6 +222,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
 			 char * const argv[])
 {
 	const void *os_hdr;
+	bool ep_found = false;
 
 	/* get kernel image header, start address and length */
 	os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
@@ -274,6 +275,18 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
 		}
 		break;
 #endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	case IMAGE_FORMAT_ANDROID:
+		images.os.type = IH_TYPE_KERNEL;
+		images.os.comp = IH_COMP_NONE;
+		images.os.os = IH_OS_LINUX;
+		images.ep = images.os.load;
+		ep_found = true;
+
+		images.os.end = android_image_get_end(os_hdr);
+		images.os.load = android_image_get_kload(os_hdr);
+		break;
+#endif
 	default:
 		puts("ERROR: unknown image format type!\n");
 		return 1;
@@ -293,7 +306,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
 			return 1;
 		}
 #endif
-	} else {
+	} else if (!ep_found) {
 		puts("Could not find kernel entry point!\n");
 		return 1;
 	}
@@ -1002,6 +1015,14 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,
 		images->fit_noffset_os = os_noffset;
 		break;
 #endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	case IMAGE_FORMAT_ANDROID:
+		printf("## Booting Android Image at 0x%08lx ...\n", img_addr);
+		if (android_image_get_kernel((void *)img_addr, images->verify,
+					     os_data, os_len))
+			return NULL;
+		break;
+#endif
 	default:
 		printf("Wrong Image Format for %s command\n", cmdtp->name);
 		bootstage_error(BOOTSTAGE_ID_FIT_KERNEL_INFO);
diff --git a/common/image-android.c b/common/image-android.c
new file mode 100644
index 0000000..6ded7e2
--- /dev/null
+++ b/common/image-android.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <image.h>
+#include <android_image.h>
+
+static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
+
+int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
+			     ulong *os_data, ulong *os_len)
+{
+	/*
+	 * Not all Android tools use the id field for signing the image with
+	 * sha1 (or anything) so we don't check it. It is not obvious that the
+	 * string is null terminated so we take care of this.
+	 */
+	strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE);
+	andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0';
+	if (strlen(andr_tmp_str))
+		printf("Android's image name: %s\n", andr_tmp_str);
+
+	printf("Kernel load addr 0x%08x size %u KiB\n",
+	       hdr->kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024));
+	strncpy(andr_tmp_str, hdr->cmdline, ANDR_BOOT_ARGS_SIZE);
+	andr_tmp_str[ANDR_BOOT_ARGS_SIZE] = '\0';
+	if (strlen(andr_tmp_str)) {
+		printf("Kernel command line: %s\n", andr_tmp_str);
+		setenv("bootargs", andr_tmp_str);
+	}
+	if (hdr->ramdisk_size)
+		printf("RAM disk load addr 0x%08x size %u KiB\n",
+		       hdr->ramdisk_addr,
+		       DIV_ROUND_UP(hdr->ramdisk_size, 1024));
+
+	if (os_data) {
+		*os_data = (ulong)hdr;
+		*os_data += hdr->page_size;
+	}
+	if (os_len)
+		*os_len = hdr->kernel_size;
+	return 0;
+}
+
+int android_image_check_header(const struct andr_img_hdr *hdr)
+{
+	return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE);
+}
+
+ulong android_image_get_end(const struct andr_img_hdr *hdr)
+{
+	u32 size = 0;
+	/*
+	 * The header takes a full page, the remaining components are aligned
+	 * on page boundary
+	 */
+	size += hdr->page_size;
+	size += ALIGN(hdr->kernel_size, hdr->page_size);
+	size += ALIGN(hdr->ramdisk_size, hdr->page_size);
+	size += ALIGN(hdr->second_size, hdr->page_size);
+
+	return size;
+}
+
+ulong android_image_get_kload(const struct andr_img_hdr *hdr)
+{
+	return hdr->kernel_addr;
+}
+
+int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
+			      ulong *rd_data, ulong *rd_len)
+{
+	if (!hdr->ramdisk_size)
+		return -1;
+	*rd_data = (unsigned long)hdr;
+	*rd_data += hdr->page_size;
+	*rd_data += ALIGN(hdr->kernel_size, hdr->page_size);
+
+	*rd_len = hdr->ramdisk_size;
+	return 0;
+}
diff --git a/common/image.c b/common/image.c
index 9c6bec5..7ff27d7 100644
--- a/common/image.c
+++ b/common/image.c
@@ -659,10 +659,12 @@ int genimg_get_format(const void *img_addr)
 	if (image_check_magic(hdr))
 		format = IMAGE_FORMAT_LEGACY;
 #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
-	else {
-		if (fdt_check_header(img_addr) == 0)
-			format = IMAGE_FORMAT_FIT;
-	}
+	else if (fdt_check_header(img_addr) == 0)
+		format = IMAGE_FORMAT_FIT;
+#endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	else if (android_image_check_header(img_addr) == 0)
+		format = IMAGE_FORMAT_ANDROID;
 #endif
 
 	return format;
@@ -932,7 +934,15 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
 				(ulong)images->legacy_hdr_os);
 
 		image_multi_getimg(images->legacy_hdr_os, 1, &rd_data, &rd_len);
-	} else {
+	}
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	else if ((genimg_get_format(images) == IMAGE_FORMAT_ANDROID) &&
+		 (!android_image_get_ramdisk((void *)images->os.start,
+		 &rd_data, &rd_len))) {
+		/* empty */
+	}
+#endif
+	else {
 		/*
 		 * no initrd image
 		 */
diff --git a/include/android_image.h b/include/android_image.h
new file mode 100644
index 0000000..094d60a
--- /dev/null
+++ b/include/android_image.h
@@ -0,0 +1,69 @@
+/*
+ * This is from the Android Project,
+ * Repository: https://android.googlesource.com/platform/bootable/bootloader/legacy
+ * File: include/boot/bootimg.h
+ * Commit: 4205b865141ff2e255fe1d3bd16de18e217ef06a
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _ANDROID_IMAGE_H_
+#define _ANDROID_IMAGE_H_
+
+#define ANDR_BOOT_MAGIC "ANDROID!"
+#define ANDR_BOOT_MAGIC_SIZE 8
+#define ANDR_BOOT_NAME_SIZE 16
+#define ANDR_BOOT_ARGS_SIZE 512
+
+struct andr_img_hdr {
+	char magic[ANDR_BOOT_MAGIC_SIZE];
+
+	u32 kernel_size;	/* size in bytes */
+	u32 kernel_addr;	/* physical load addr */
+
+	u32 ramdisk_size;	/* size in bytes */
+	u32 ramdisk_addr;	/* physical load addr */
+
+	u32 second_size;	/* size in bytes */
+	u32 second_addr;	/* physical load addr */
+
+	u32 tags_addr;		/* physical addr for kernel tags */
+	u32 page_size;		/* flash page size we assume */
+	u32 unused[2];		/* future expansion: should be 0 */
+
+	char name[ANDR_BOOT_NAME_SIZE]; /* asciiz product name */
+
+	char cmdline[ANDR_BOOT_ARGS_SIZE];
+
+	u32 id[8]; /* timestamp / checksum / sha1 / etc */
+};
+
+/*
+ * +-----------------+
+ * | boot header     | 1 page
+ * +-----------------+
+ * | kernel          | n pages
+ * +-----------------+
+ * | ramdisk         | m pages
+ * +-----------------+
+ * | second stage    | o pages
+ * +-----------------+
+ *
+ * n = (kernel_size + page_size - 1) / page_size
+ * m = (ramdisk_size + page_size - 1) / page_size
+ * o = (second_size + page_size - 1) / page_size
+ *
+ * 0. all entities are page_size aligned in flash
+ * 1. kernel and ramdisk are required (size != 0)
+ * 2. second is optional (second_size == 0 -> no second)
+ * 3. load each element (kernel, ramdisk, second) at
+ *    the specified physical address (kernel_addr, etc)
+ * 4. prepare tags at tag_addr.  kernel_args[] is
+ *    appended to the kernel commandline in the tags.
+ * 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
+ * 6. if second_size != 0: jump to second_addr
+ *    else: jump to kernel_addr
+ */
+#endif
diff --git a/include/image.h b/include/image.h
index 6afd57b..5f85b96 100644
--- a/include/image.h
+++ b/include/image.h
@@ -403,6 +403,7 @@ enum fit_load_op {
 #define IMAGE_FORMAT_INVALID	0x00
 #define IMAGE_FORMAT_LEGACY	0x01	/* legacy image_header based format */
 #define IMAGE_FORMAT_FIT	0x02	/* new, libfdt based format */
+#define IMAGE_FORMAT_ANDROID	0x03	/* Android boot image */
 
 int genimg_get_format(const void *img_addr);
 int genimg_has_config(bootm_headers_t *images);
@@ -996,4 +997,16 @@ static inline int fit_image_check_target_arch(const void *fdt, int node)
 #endif /* CONFIG_FIT_VERBOSE */
 #endif /* CONFIG_FIT */
 
+#if defined(CONFIG_ANDROID_BOOT_IMAGE)
+struct andr_img_hdr;
+int android_image_check_header(const struct andr_img_hdr *hdr);
+int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
+			     ulong *os_data, ulong *os_len);
+int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
+			      ulong *rd_data, ulong *rd_len);
+ulong android_image_get_end(const struct andr_img_hdr *hdr);
+ulong android_image_get_kload(const struct andr_img_hdr *hdr);
+
+#endif /* CONFIG_ANDROID_BOOT_IMAGE */
+
 #endif	/* __IMAGE_H__ */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 3/5] usb: musb: fill in usb_gadget_unregister_driver
  2014-04-18 13:54 ` [U-Boot] [PATCH v4 " Rob Herring
  2014-04-18 13:54   ` [U-Boot] [PATCH v4 1/5] usb: handle NULL table in usb_gadget_get_string Rob Herring
  2014-04-18 13:54   ` [U-Boot] [PATCH v4 2/5] image: add support for Android's boot image format Rob Herring
@ 2014-04-18 13:54   ` Rob Herring
  2014-04-23  9:46     ` Lukasz Majewski
  2014-04-18 13:54   ` [U-Boot] [PATCH v4 4/5] usb/gadget: add the fastboot gadget Rob Herring
                     ` (3 subsequent siblings)
  6 siblings, 1 reply; 59+ messages in thread
From: Rob Herring @ 2014-04-18 13:54 UTC (permalink / raw)
  To: u-boot

From: Rob Herring <robh@kernel.org>

Add missing missing disconnect and unbind calls to the musb gadget driver's
usb_gadget_unregister_driver function. Otherwise, any gadget drivers fail
to uninitialize and run a 2nd time.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 drivers/usb/musb-new/musb_uboot.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c
index 0512680..0d7b89f 100644
--- a/drivers/usb/musb-new/musb_uboot.c
+++ b/drivers/usb/musb-new/musb_uboot.c
@@ -204,7 +204,10 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
 
 int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 {
-	/* TODO: implement me */
+	if (driver->disconnect)
+		driver->disconnect(&gadget->g);
+	if (driver->unbind)
+		driver->unbind(&gadget->g);
 	return 0;
 }
 #endif /* CONFIG_MUSB_GADGET */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 4/5] usb/gadget: add the fastboot gadget
  2014-04-18 13:54 ` [U-Boot] [PATCH v4 " Rob Herring
                     ` (2 preceding siblings ...)
  2014-04-18 13:54   ` [U-Boot] [PATCH v4 3/5] usb: musb: fill in usb_gadget_unregister_driver Rob Herring
@ 2014-04-18 13:54   ` Rob Herring
  2014-04-23 11:02     ` Lukasz Majewski
  2014-04-18 13:54   ` [U-Boot] [PATCH v4 5/5] arm: beagle: enable Android fastboot support Rob Herring
                     ` (2 subsequent siblings)
  6 siblings, 1 reply; 59+ messages in thread
From: Rob Herring @ 2014-04-18 13:54 UTC (permalink / raw)
  To: u-boot

From: Sebastian Siewior <bigeasy@linutronix.de>

This patch contains an implementation of the fastboot protocol on the
device side and documentation. This is based on USB download gadget
infrastructure. The fastboot function implements the getvar, reboot,
download and reboot commands. What is missing is the flash handling i.e.
writting the image to media.

v3 (Rob Herring):
This is based on http://patchwork.ozlabs.org/patch/126798/ with the
following changes:
- Rebase to current mainline and updates for current gadget API
- Use SPDX identifiers for licenses
- Traced the history and added missing copyright to cmd_fastboot.c
- Use load_addr/load_size for transfer buffer
- Allow vendor strings to be optional
- Set vendor/product ID from config defines
- Allow Ctrl-C to exit fastboot mode
v4:
- Major re-write to use the USB download gadget. Consolidated function
code to a single file.
- Moved globals into single struct.
- Use puts and putc as appropriate.
- Added CONFIG_USB_FASTBOOT_BUF_ADDR and CONFIG_USB_FASTBOOT_BUF_SIZE to
set the fastboot transfer buffer.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Rob Herring <robh@kernel.org>
---
 common/Makefile                      |   2 +
 common/cmd_fastboot.c                |  36 +++
 doc/README.android-fastboot          |  91 ++++++
 doc/README.android-fastboot-protocol | 170 ++++++++++++
 drivers/usb/gadget/Makefile          |   1 +
 drivers/usb/gadget/f_fastboot.c      | 518 +++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/g_dnl.c           |   6 +
 include/fastboot.h                   |  22 ++
 8 files changed, 846 insertions(+)
 create mode 100644 common/cmd_fastboot.c
 create mode 100644 doc/README.android-fastboot
 create mode 100644 doc/README.android-fastboot-protocol
 create mode 100644 drivers/usb/gadget/f_fastboot.c
 create mode 100644 include/fastboot.h

diff --git a/common/Makefile b/common/Makefile
index da208f3..fe1d8b9 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -167,6 +167,8 @@ obj-y += cmd_usb.o
 obj-y += usb.o usb_hub.o
 obj-$(CONFIG_USB_STORAGE) += usb_storage.o
 endif
+obj-$(CONFIG_CMD_FASTBOOT) += cmd_fastboot.o
+
 obj-$(CONFIG_CMD_USB_MASS_STORAGE) += cmd_usb_mass_storage.o
 obj-$(CONFIG_CMD_THOR_DOWNLOAD) += cmd_thordown.o
 obj-$(CONFIG_CMD_XIMG) += cmd_ximg.o
diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
new file mode 100644
index 0000000..ce7e198
--- /dev/null
+++ b/common/cmd_fastboot.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 - 2009 Windriver, <www.windriver.com>
+ * Author: Tom Rix <Tom.Rix@windriver.com>
+ *
+ * (C) Copyright 2014 Linaro, Ltd.
+ * Rob Herring <robh@kernel.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <command.h>
+#include <g_dnl.h>
+
+static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	int ret;
+
+	ret = g_dnl_register("fastboot");
+	if (ret)
+		return ret;
+
+	while (1) {
+		if (ctrlc())
+			break;
+		usb_gadget_handle_interrupts();
+	}
+
+	g_dnl_unregister();
+	return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+	fastboot,	1,	1,	do_fastboot,
+	"fastboot - enter USB Fastboot protocol",
+	""
+);
diff --git a/doc/README.android-fastboot b/doc/README.android-fastboot
new file mode 100644
index 0000000..f1d128c
--- /dev/null
+++ b/doc/README.android-fastboot
@@ -0,0 +1,91 @@
+Android Fastboot
+~~~~~~~~~~~~~~~~
+
+Overview
+========
+The protocol that is used over USB is described in
+README.android-fastboot-protocol in same directory.
+
+The current implementation does not yet support the flash and erase
+commands.
+
+Client installation
+===================
+The counterpart to this gadget is the fastboot client which can
+be found in Android's platform/system/core repository in the fastboot
+folder. It runs on Windows, Linux and even OSX. Linux user are lucky since
+they only need libusb.
+Windows users need to bring some time until they have Android SDK (currently
+http://dl.google.com/android/installer_r12-windows.exe) installed. You
+need to install ADB package which contains the required glue libraries for
+accessing USB. Also you need "Google USB driver package" and "SDK platform
+tools". Once installed the usb driver is placed in your SDK folder under
+extras\google\usb_driver. The android_winusb.inf needs a line like
+
+   %SingleBootLoaderInterface% = USB_Install, USB\VID_0451&PID_D022
+
+either in the [Google.NTx86] section for 32bit Windows or [Google.NTamd64]
+for 64bit Windows. VID and PID should match whatever the fastboot is
+advertising.
+
+Board specific
+==============
+The fastboot gadget relies on the USB download gadget, so the following
+options must be configured:
+
+CONFIG_USBDOWNLOAD_GADGET
+CONFIG_G_DNL_VENDOR_NUM
+CONFIG_G_DNL_PRODUCT_NUM
+CONFIG_G_DNL_MANUFACTURER
+
+The fastboot function is enabled by defining CONFIG_CMD_FASTBOOT and
+CONFIG_ANDROID_BOOT_IMAGE.
+
+The fastboot protocol requires a large memory buffer for downloads. This
+buffer should be as large as possible for a platform. The location of the
+buffer and size are set with CONFIG_USB_FASTBOOT_BUF_ADDR and
+CONFIG_USB_FASTBOOT_BUF_SIZE.
+
+In Action
+=========
+Enter into fastboot by executing the fastboot command in u-boot and you
+should see:
+|GADGET DRIVER: usb_dnl_fastboot
+
+On the client side you can fetch the bootloader version for instance:
+|>fastboot getvar bootloader-version
+|bootloader-version: U-Boot 2014.04-00005-gd24cabc
+|finished. total time: 0.000s
+
+or initiate a reboot:
+|>fastboot reboot
+
+and once the client comes back, the board should reset.
+
+You can also specify a kernel image to boot. You have to either specify
+the an image in Android format _or_ pass a binary kernel and let the
+fastboot client wrap the Android suite around it. On OMAP for instance you
+take zImage kernel and pass it to the fastboot client:
+
+|>fastboot -b 0x80000000 -c "console=ttyO2 earlyprintk root=/dev/ram0
+|	mem=128M" boot zImage
+|creating boot image...
+|creating boot image - 1847296 bytes
+|downloading 'boot.img'...
+|OKAY [  2.766s]
+|booting...
+|OKAY [ -0.000s]
+|finished. total time: 2.766s
+
+and on the gadget side you should see:
+|Starting download of 1847296 bytes
+|........................................................
+|downloading of 1847296 bytes finished
+|Booting kernel..
+|## Booting Android Image at 0x81000000 ...
+|Kernel load addr 0x80008000 size 1801 KiB
+|Kernel command line: console=ttyO2 earlyprintk root=/dev/ram0 mem=128M
+|   Loading Kernel Image ... OK
+|OK
+|
+|Starting kernel ...
diff --git a/doc/README.android-fastboot-protocol b/doc/README.android-fastboot-protocol
new file mode 100644
index 0000000..e9e7166
--- /dev/null
+++ b/doc/README.android-fastboot-protocol
@@ -0,0 +1,170 @@
+FastBoot  Version  0.4
+----------------------
+
+The fastboot protocol is a mechanism for communicating with bootloaders
+over USB.  It is designed to be very straightforward to implement, to
+allow it to be used across a wide range of devices and from hosts running
+Linux, Windows, or OSX.
+
+
+Basic Requirements
+------------------
+
+* Two bulk endpoints (in, out) are required
+* Max packet size must be 64 bytes for full-speed and 512 bytes for
+  high-speed USB
+* The protocol is entirely host-driven and synchronous (unlike the
+  multi-channel, bi-directional, asynchronous ADB protocol)
+
+
+Transport and Framing
+---------------------
+
+1. Host sends a command, which is an ascii string in a single
+   packet no greater than 64 bytes.
+
+2. Client response with a single packet no greater than 64 bytes.
+   The first four bytes of the response are "OKAY", "FAIL", "DATA",
+   or "INFO".  Additional bytes may contain an (ascii) informative
+   message.
+
+   a. INFO -> the remaining 60 bytes are an informative message
+      (providing progress or diagnostic messages).  They should
+      be displayed and then step #2 repeats
+
+   b. FAIL -> the requested command failed.  The remaining 60 bytes
+      of the response (if present) provide a textual failure message
+      to present to the user.  Stop.
+
+   c. OKAY -> the requested command completed successfully.  Go to #5
+
+   d. DATA -> the requested command is ready for the data phase.
+      A DATA response packet will be 12 bytes long, in the form of
+      DATA00000000 where the 8 digit hexidecimal number represents
+      the total data size to transfer.
+
+3. Data phase.  Depending on the command, the host or client will
+   send the indicated amount of data.  Short packets are always
+   acceptable and zero-length packets are ignored.  This phase continues
+   until the client has sent or received the number of bytes indicated
+   in the "DATA" response above.
+
+4. Client responds with a single packet no greater than 64 bytes.
+   The first four bytes of the response are "OKAY", "FAIL", or "INFO".
+   Similar to #2:
+
+   a. INFO -> display the remaining 60 bytes and return to #4
+
+   b. FAIL -> display the remaining 60 bytes (if present) as a failure
+      reason and consider the command failed.  Stop.
+
+   c. OKAY -> success.  Go to #5
+
+5. Success.  Stop.
+
+
+Example Session
+---------------
+
+Host:    "getvar:version"        request version variable
+
+Client:  "OKAY0.4"               return version "0.4"
+
+Host:    "getvar:nonexistant"    request some undefined variable
+
+Client:  "OKAY"                  return value ""
+
+Host:    "download:00001234"     request to send 0x1234 bytes of data
+
+Client:  "DATA00001234"          ready to accept data
+
+Host:    < 0x1234 bytes >        send data
+
+Client:  "OKAY"                  success
+
+Host:    "flash:bootloader"      request to flash the data to the bootloader
+
+Client:  "INFOerasing flash"     indicate status / progress
+         "INFOwriting flash"
+         "OKAY"                  indicate success
+
+Host:    "powerdown"             send a command
+
+Client:  "FAILunknown command"   indicate failure
+
+
+Command Reference
+-----------------
+
+* Command parameters are indicated by printf-style escape sequences.
+
+* Commands are ascii strings and sent without the quotes (which are
+  for illustration only here) and without a trailing 0 byte.
+
+* Commands that begin with a lowercase letter are reserved for this
+  specification.  OEM-specific commands should not begin with a
+  lowercase letter, to prevent incompatibilities with future specs.
+
+ "getvar:%s"           Read a config/version variable from the bootloader.
+                       The variable contents will be returned after the
+                       OKAY response.
+
+ "download:%08x"       Write data to memory which will be later used
+                       by "boot", "ramdisk", "flash", etc.  The client
+                       will reply with "DATA%08x" if it has enough
+                       space in RAM or "FAIL" if not.  The size of
+                       the download is remembered.
+
+  "verify:%08x"        Send a digital signature to verify the downloaded
+                       data.  Required if the bootloader is "secure"
+                       otherwise "flash" and "boot" will be ignored.
+
+  "flash:%s"           Write the previously downloaded image to the
+                       named partition (if possible).
+
+  "erase:%s"           Erase the indicated partition (clear to 0xFFs)
+
+  "boot"               The previously downloaded data is a boot.img
+                       and should be booted according to the normal
+                       procedure for a boot.img
+
+  "continue"           Continue booting as normal (if possible)
+
+  "reboot"             Reboot the device.
+
+  "reboot-bootloader"  Reboot back into the bootloader.
+                       Useful for upgrade processes that require upgrading
+                       the bootloader and then upgrading other partitions
+                       using the new bootloader.
+
+  "powerdown"          Power off the device.
+
+
+
+Client Variables
+----------------
+
+The "getvar:%s" command is used to read client variables which
+represent various information about the device and the software
+on it.
+
+The various currently defined names are:
+
+  version             Version of FastBoot protocol supported.
+                      It should be "0.3" for this document.
+
+  version-bootloader  Version string for the Bootloader.
+
+  version-baseband    Version string of the Baseband Software
+
+  product             Name of the product
+
+  serialno            Product serial number
+
+  secure              If the value is "yes", this is a secure
+                      bootloader requiring a signature before
+                      it will install or boot images.
+
+Names starting with a lowercase character are reserved by this
+specification.  OEM-specific names should not start with lowercase
+characters.
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 804a2bd..3375f68 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_THOR_FUNCTION) += f_thor.o
 obj-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
 obj-$(CONFIG_DFU_FUNCTION) += f_dfu.o
 obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o
+obj-$(CONFIG_CMD_FASTBOOT) += f_fastboot.o
 endif
 ifdef CONFIG_USB_ETHER
 obj-y += ether.o
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
new file mode 100644
index 0000000..514279f
--- /dev/null
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -0,0 +1,518 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Copyright 2014 Linaro, Ltd.
+ * Rob Herring <robh@kernel.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+#include <linux/compiler.h>
+#include <version.h>
+#include <g_dnl.h>
+#include <fastboot.h>
+
+#define FASTBOOT_VERSION		"0.4"
+
+#define FASTBOOT_INTERFACE_CLASS	0xff
+#define FASTBOOT_INTERFACE_SUB_CLASS	0x42
+#define FASTBOOT_INTERFACE_PROTOCOL	0x03
+
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0  (0x0200)
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1  (0x0040)
+#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE      (0x0040)
+
+/* The 64 defined bytes plus \0 */
+#define RESPONSE_LEN	(64 + 1)
+
+#define EP_BUFFER_SIZE			4096
+
+struct f_fastboot {
+	struct usb_function usb_function;
+
+	/* IN/OUT EP's and correspoinding requests */
+	struct usb_ep *in_ep, *out_ep;
+	struct usb_request *in_req, *out_req;
+};
+
+static inline struct f_fastboot *func_to_fastboot(struct usb_function *f)
+{
+	return container_of(f, struct f_fastboot, usb_function);
+}
+
+static struct f_fastboot *fastboot_func;
+static unsigned int download_size;
+static unsigned int download_bytes;
+
+static struct usb_endpoint_descriptor fs_ep_in = {
+	.bLength            = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType    = USB_DT_ENDPOINT,
+	.bEndpointAddress   = USB_DIR_IN,
+	.bmAttributes       = USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize     = TX_ENDPOINT_MAXIMUM_PACKET_SIZE,
+	.bInterval          = 0x00,
+};
+
+static struct usb_endpoint_descriptor fs_ep_out = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1,
+	.bInterval		= 0x00,
+};
+
+static struct usb_endpoint_descriptor hs_ep_out = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0,
+	.bInterval		= 0x00,
+};
+
+static struct usb_interface_descriptor interface_desc = {
+	.bLength		= USB_DT_INTERFACE_SIZE,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	.bInterfaceNumber	= 0x00,
+	.bAlternateSetting	= 0x00,
+	.bNumEndpoints		= 0x02,
+	.bInterfaceClass	= FASTBOOT_INTERFACE_CLASS,
+	.bInterfaceSubClass	= FASTBOOT_INTERFACE_SUB_CLASS,
+	.bInterfaceProtocol	= FASTBOOT_INTERFACE_PROTOCOL,
+};
+
+static struct usb_descriptor_header *fb_runtime_descs[] = {
+	(struct usb_descriptor_header *)&interface_desc,
+	(struct usb_descriptor_header *)&fs_ep_in,
+	(struct usb_descriptor_header *)&hs_ep_out,
+	NULL,
+};
+
+/*
+ * static strings, in UTF-8
+ */
+static const char fastboot_name[] = "Android Fastboot";
+
+static struct usb_string fastboot_string_defs[] = {
+	[0].s = fastboot_name,
+	{  }			/* end of list */
+};
+
+static struct usb_gadget_strings stringtab_fastboot = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= fastboot_string_defs,
+};
+
+static struct usb_gadget_strings *fastboot_strings[] = {
+	&stringtab_fastboot,
+	NULL,
+};
+
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+
+static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	int status = req->status;
+	if (!status)
+		return;
+	printf("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
+}
+
+static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	int status, id;
+	struct usb_gadget *gadget = c->cdev->gadget;
+	struct f_fastboot *f_fb = func_to_fastboot(f);
+
+	/* DYNAMIC interface numbers assignments */
+	status = usb_interface_id(c, f);
+	if (status < 0)
+		goto err;
+
+	interface_desc.bInterfaceNumber = status;
+
+	id = usb_string_id(c->cdev);
+	if (id < 0)
+		goto err;
+	fastboot_string_defs[0].id = id;
+	interface_desc.iInterface = id;
+
+	f_fb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
+	if (!f_fb->in_ep)
+		goto err;
+	f_fb->in_ep->driver_data = c->cdev;
+
+	f_fb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
+	if (!f_fb->out_ep)
+		goto err;
+	f_fb->out_ep->driver_data = c->cdev;
+
+	hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
+
+	return 0;
+err:
+	return -1;
+}
+
+static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	memset(fastboot_func, 0, sizeof(*fastboot_func));
+}
+
+static void fastboot_disable(struct usb_function *f)
+{
+	struct f_fastboot *f_fb = func_to_fastboot(f);
+
+	usb_ep_disable(f_fb->out_ep);
+	usb_ep_disable(f_fb->in_ep);
+
+	if (f_fb->out_req) {
+		free(f_fb->out_req->buf);
+		usb_ep_free_request(f_fb->out_ep, f_fb->out_req);
+		f_fb->out_req = NULL;
+	}
+	if (f_fb->in_req) {
+		free(f_fb->in_req->buf);
+		usb_ep_free_request(f_fb->in_ep, f_fb->in_req);
+		f_fb->in_req = NULL;
+	}
+}
+
+static struct usb_request *fastboot_start_ep(struct usb_ep *ep)
+{
+	struct usb_request *req;
+
+	req = usb_ep_alloc_request(ep, 0);
+	if (!req)
+		return NULL;
+
+	req->length = EP_BUFFER_SIZE;
+	req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE);
+	if (!req->buf) {
+		usb_ep_free_request(ep, req);
+		return NULL;
+	}
+
+	memset(req->buf, 0, req->length);
+	return req;
+}
+
+static int fastboot_set_alt(struct usb_function *f,
+			    unsigned interface, unsigned alt)
+{
+	int ret;
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_gadget *gadget = cdev->gadget;
+	struct f_fastboot *f_fb = func_to_fastboot(f);
+
+	debug("%s: func: %s intf: %d alt: %d\n",
+	      __func__, f->name, interface, alt);
+
+	/* make sure we don't enable the ep twice */
+	if (gadget->speed == USB_SPEED_HIGH)
+		ret = usb_ep_enable(f_fb->out_ep, &hs_ep_out);
+	else
+		ret = usb_ep_enable(f_fb->out_ep, &fs_ep_out);
+	if (ret) {
+		puts("failed to enable out ep\n");
+		goto err;
+	}
+
+	f_fb->out_req = fastboot_start_ep(f_fb->out_ep);
+	if (!f_fb->out_req) {
+		puts("failed to alloc out req\n");
+		goto err;
+	}
+
+	ret = usb_ep_enable(f_fb->in_ep, &fs_ep_in);
+	if (ret) {
+		puts("failed to enable in ep\n");
+		goto err;
+	}
+	f_fb->out_req->complete = rx_handler_command;
+
+	f_fb->in_req = fastboot_start_ep(f_fb->in_ep);
+	if (!f_fb->in_req) {
+		puts("failed alloc req in\n");
+		goto err;
+	}
+	f_fb->in_req->complete = fastboot_complete;
+
+	ret = usb_ep_queue(f_fb->out_ep, f_fb->out_req, 0);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	fastboot_disable(f);
+	return -1;
+}
+
+int fastboot_add(struct usb_configuration *c)
+{
+	struct f_fastboot *f_fb = fastboot_func;
+	int status;
+
+	debug("%s: cdev: 0x%p\n", __func__, c->cdev);
+
+	if (!f_fb) {
+		f_fb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_fb));
+		if (!f_fb)
+			return -ENOMEM;
+
+		fastboot_func = f_fb;
+		memset(f_fb, 0, sizeof(*f_fb));
+	}
+
+	f_fb->usb_function.name = "f_fastboot";
+	f_fb->usb_function.hs_descriptors = fb_runtime_descs;
+	f_fb->usb_function.bind = fastboot_bind;
+	f_fb->usb_function.unbind = fastboot_unbind;
+	f_fb->usb_function.set_alt = fastboot_set_alt;
+	f_fb->usb_function.disable = fastboot_disable;
+	f_fb->usb_function.strings = fastboot_strings;
+
+	status = usb_add_function(c, &f_fb->usb_function);
+	if (status) {
+		free(f_fb);
+		fastboot_func = f_fb;
+	}
+
+	return status;
+}
+
+int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
+{
+	struct usb_request *in_req = fastboot_func->in_req;
+	int ret;
+
+	if (in_req->complete == NULL)
+		in_req->complete = fastboot_complete;
+
+	memcpy(in_req->buf, buffer, buffer_size);
+	in_req->length = buffer_size;
+	ret = usb_ep_queue(fastboot_func->in_ep, in_req, 0);
+	if (ret)
+		printf("Error %d on queue\n", ret);
+	return 0;
+}
+
+static int fastboot_tx_write_str(const char *buffer)
+{
+	return fastboot_tx_write(buffer, strlen(buffer));
+}
+
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
+{
+	do_reset(NULL, 0, 0, NULL);
+}
+
+static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
+{
+	fastboot_func->in_req->complete = compl_do_reset;
+	fastboot_tx_write_str("OKAY");
+}
+
+static int strcmp_l1(const char *s1, const char *s2)
+{
+	if (!s1 || !s2)
+		return -1;
+	return strncmp(s1, s2, strlen(s1));
+}
+
+static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmd = req->buf;
+	char response[RESPONSE_LEN];
+	const char *s;
+
+	strcpy(response, "OKAY");
+	strsep(&cmd, ":");
+	if (!cmd) {
+		fastboot_tx_write_str("FAILmissing var");
+		return;
+	}
+
+	if (!strcmp_l1("version", cmd)) {
+		strncat(response, FASTBOOT_VERSION, sizeof(response));
+	} else if (!strcmp_l1("bootloader-version", cmd)) {
+		strncat(response, U_BOOT_VERSION, sizeof(response));
+	} else if (!strcmp_l1("downloadsize", cmd)) {
+		char str_num[12];
+
+		sprintf(str_num, "%08x", CONFIG_USB_FASTBOOT_BUF_SIZE);
+		strncat(response, str_num, sizeof(response));
+	} else if (!strcmp_l1("serialno", cmd)) {
+		s = getenv("serial#");
+		if (s)
+			strncat(response, s, sizeof(response));
+		else
+			strcpy(response, "FAILValue not set");
+	} else {
+		strcpy(response, "FAILVariable not implemented");
+	}
+	fastboot_tx_write_str(response);
+}
+
+static unsigned int rx_bytes_expected(void)
+{
+	int rx_remain = download_size - download_bytes;
+	if (rx_remain < 0)
+		return 0;
+	if (rx_remain > EP_BUFFER_SIZE)
+		return EP_BUFFER_SIZE;
+	return rx_remain;
+}
+
+#define BYTES_PER_DOT	32768
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
+{
+	char response[RESPONSE_LEN];
+	unsigned int transfer_size = download_size - download_bytes;
+	const unsigned char *buffer = req->buf;
+	unsigned int buffer_size = req->actual;
+
+	if (req->status != 0) {
+		printf("Bad status: %d\n", req->status);
+		return;
+	}
+
+	if (buffer_size < transfer_size)
+		transfer_size = buffer_size;
+
+	memcpy((void *)CONFIG_USB_FASTBOOT_BUF_ADDR + download_bytes,
+	       buffer, transfer_size);
+
+	download_bytes += transfer_size;
+
+	/* Check if transfer is done */
+	if (download_bytes >= download_size) {
+		/*
+		 * Reset global transfer variable, keep download_bytes because
+		 * it will be used in the next possible flashing command
+		 */
+		download_size = 0;
+		req->complete = rx_handler_command;
+		req->length = EP_BUFFER_SIZE;
+
+		sprintf(response, "OKAY");
+		fastboot_tx_write_str(response);
+
+		printf("\ndownloading of %d bytes finished\n", download_bytes);
+	} else {
+		req->length = rx_bytes_expected();
+	}
+
+	if (download_bytes && !(download_bytes % BYTES_PER_DOT)) {
+		putc('.');
+		if (!(download_bytes % (74 * BYTES_PER_DOT)))
+			putc('\n');
+	}
+	req->actual = 0;
+	usb_ep_queue(ep, req, 0);
+}
+
+static void cb_download(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmd = req->buf;
+	char response[RESPONSE_LEN];
+
+	strsep(&cmd, ":");
+	download_size = simple_strtoul(cmd, NULL, 16);
+	download_bytes = 0;
+
+	printf("Starting download of %d bytes\n", download_size);
+
+	if (0 == download_size) {
+		sprintf(response, "FAILdata invalid size");
+	} else if (download_size > CONFIG_USB_FASTBOOT_BUF_SIZE) {
+		download_size = 0;
+		sprintf(response, "FAILdata too large");
+	} else {
+		sprintf(response, "DATA%08x", download_size);
+		req->complete = rx_handler_dl_image;
+		req->length = rx_bytes_expected();
+	}
+	fastboot_tx_write_str(response);
+}
+
+static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	char boot_addr_start[12];
+	char *bootm_args[] = { "bootm", boot_addr_start, NULL };
+
+	req->complete = NULL;
+	g_dnl_unregister();
+	puts("Booting kernel..\n");
+
+	sprintf(boot_addr_start, "0x%lx", load_addr);
+	do_bootm(NULL, 0, 2, bootm_args);
+
+	/* This only happens if image is somehow faulty so we start over */
+	do_reset(NULL, 0, 0, NULL);
+}
+
+static void cb_boot(struct usb_ep *ep, struct usb_request *req)
+{
+	fastboot_func->in_req->complete = do_bootm_on_complete;
+	fastboot_tx_write_str("OKAY");
+}
+
+struct cmd_dispatch_info {
+	char *cmd;
+	void (*cb)(struct usb_ep *ep, struct usb_request *req);
+};
+
+static const struct cmd_dispatch_info cmd_dispatch_info[] = {
+	{
+		.cmd = "reboot",
+		.cb = cb_reboot,
+	}, {
+		.cmd = "getvar:",
+		.cb = cb_getvar,
+	}, {
+		.cmd = "download:",
+		.cb = cb_download,
+	}, {
+		.cmd = "boot",
+		.cb = cb_boot,
+	},
+};
+
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
+{
+	char response[RESPONSE_LEN];
+	char *cmdbuf = req->buf;
+	void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
+	int i;
+
+	sprintf(response, "FAIL");
+
+	for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
+		if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
+			func_cb = cmd_dispatch_info[i].cb;
+			break;
+		}
+	}
+
+	if (!func_cb)
+		fastboot_tx_write_str("FAILunknown command");
+	else
+		func_cb(ep, req);
+
+	if (req->status == 0) {
+		*cmdbuf = '\0';
+		req->actual = 0;
+		usb_ep_queue(ep, req, 0);
+	}
+}
diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c
index dd95afe..dbea322 100644
--- a/drivers/usb/gadget/g_dnl.c
+++ b/drivers/usb/gadget/g_dnl.c
@@ -17,6 +17,7 @@
 #include <usb_mass_storage.h>
 #include <dfu.h>
 #include <thor.h>
+#include <fastboot.h>
 
 #include "gadget_chips.h"
 #include "composite.c"
@@ -117,6 +118,8 @@ static int g_dnl_do_config(struct usb_configuration *c)
 		ret = fsg_add(c);
 	else if (!strcmp(s, "usb_dnl_thor"))
 		ret = thor_add(c);
+	else if (!strcmp(s, "usb_dnl_fastboot"))
+		ret = fastboot_add(c);
 
 	return ret;
 }
@@ -242,6 +245,9 @@ int g_dnl_register(const char *type)
 	} else if (!strcmp(type, "thor")) {
 		strcpy(name, shortname);
 		strcat(name, type);
+	} else if (!strcmp(type, "fastboot")) {
+		strcpy(name, shortname);
+		strcat(name, type);
 	} else {
 		printf("%s: unknown command: %s\n", __func__, type);
 		return -EINVAL;
diff --git a/include/fastboot.h b/include/fastboot.h
new file mode 100644
index 0000000..3c26bd6
--- /dev/null
+++ b/include/fastboot.h
@@ -0,0 +1,22 @@
+/*
+ * (C) Copyright 2014 Linaro, Ltd.
+ * Rob Herring <robh@kernel.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef FASTBOOT_H
+#define FASTBOOT_H
+
+#include <linux/usb/composite.h>
+
+#ifdef CONFIG_CMD_FASTBOOT
+int fastboot_add(struct usb_configuration *c);
+#else
+static int fastboot_add(struct usb_configuration *c)
+{
+	return 0;
+}
+#endif
+
+#endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 5/5] arm: beagle: enable Android fastboot support
  2014-04-18 13:54 ` [U-Boot] [PATCH v4 " Rob Herring
                     ` (3 preceding siblings ...)
  2014-04-18 13:54   ` [U-Boot] [PATCH v4 4/5] usb/gadget: add the fastboot gadget Rob Herring
@ 2014-04-18 13:54   ` Rob Herring
  2014-04-18 16:14   ` [U-Boot] [PATCH v4 0/5] Android Fastboot support Wolfgang Denk
  2014-05-05 20:08   ` [U-Boot] [PATCH v5 0/3] " Rob Herring
  6 siblings, 0 replies; 59+ messages in thread
From: Rob Herring @ 2014-04-18 13:54 UTC (permalink / raw)
  To: u-boot

From: Rob Herring <robh@kernel.org>

Enable Android Fastboot support on omap3_beagle board.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 include/configs/omap3_beagle.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/include/configs/omap3_beagle.h b/include/configs/omap3_beagle.h
index 0b57421..be39b7c 100644
--- a/include/configs/omap3_beagle.h
+++ b/include/configs/omap3_beagle.h
@@ -110,6 +110,16 @@
 #define CONFIG_TWL4030_USB		1
 #define CONFIG_USB_ETHER
 #define CONFIG_USB_ETHER_RNDIS
+#define CONFIG_USB_GADGET
+#define CONFIG_USB_GADGET_VBUS_DRAW	0
+#define CONFIG_USBDOWNLOAD_GADGET
+#define CONFIG_G_DNL_VENDOR_NUM		0x0451
+#define CONFIG_G_DNL_PRODUCT_NUM	0xd022
+#define CONFIG_G_DNL_MANUFACTURER	"TI"
+#define CONFIG_CMD_FASTBOOT
+#define CONFIG_ANDROID_BOOT_IMAGE
+#define CONFIG_USB_FASTBOOT_BUF_ADDR	CONFIG_SYS_LOAD_ADDR
+#define CONFIG_USB_FASTBOOT_BUF_SIZE	0x07000000
 
 /* USB EHCI */
 #define CONFIG_CMD_USB
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 0/5] Android Fastboot support
  2014-04-18 13:54 ` [U-Boot] [PATCH v4 " Rob Herring
                     ` (4 preceding siblings ...)
  2014-04-18 13:54   ` [U-Boot] [PATCH v4 5/5] arm: beagle: enable Android fastboot support Rob Herring
@ 2014-04-18 16:14   ` Wolfgang Denk
  2014-04-21 15:13     ` Marek Vasut
  2014-05-05 20:08   ` [U-Boot] [PATCH v5 0/3] " Rob Herring
  6 siblings, 1 reply; 59+ messages in thread
From: Wolfgang Denk @ 2014-04-18 16:14 UTC (permalink / raw)
  To: u-boot

Dear Rob,

In message <1397829272-22266-1-git-send-email-robherring2@gmail.com> you wrote:
> 
> I dropped the patch adding a loadsize env variable and added config 
> uptions instead to set the fastboot buffer size.

Thanks, but...

>  common/Makefile                      |   3 +
>  common/cmd_bootm.c                   |  23 +-
>  common/cmd_fastboot.c                |  36 +++
>  common/image-android.c               |  84 ++++++
>  common/image.c                       |  20 +-
>  doc/README.android-fastboot          |  91 ++++++
>  doc/README.android-fastboot-protocol | 170 ++++++++++++
>  drivers/usb/gadget/Makefile          |   1 +
>  drivers/usb/gadget/f_fastboot.c      | 518 +++++++++++++++++++++++++++++++++++
>  drivers/usb/gadget/g_dnl.c           |   6 +
>  drivers/usb/gadget/usbstring.c       |   3 +
>  drivers/usb/musb-new/musb_uboot.c    |   5 +-
>  include/android_image.h              |  69 +++++
>  include/configs/omap3_beagle.h       |  10 +
>  include/fastboot.h                   |  22 ++
>  include/image.h                      |  13 +
>  16 files changed, 1067 insertions(+), 7 deletions(-)

...I don't see the README in the list of modified files - but new
CONFIG options _must_ be documented there.  So please add the missing
documentation.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
A direct quote from the Boss: "We passed over a lot of good people to
get the ones we hired."

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 0/5] Android Fastboot support
  2014-04-18 16:14   ` [U-Boot] [PATCH v4 0/5] Android Fastboot support Wolfgang Denk
@ 2014-04-21 15:13     ` Marek Vasut
  2014-04-23 14:36       ` Rob Herring
  0 siblings, 1 reply; 59+ messages in thread
From: Marek Vasut @ 2014-04-21 15:13 UTC (permalink / raw)
  To: u-boot

On Friday, April 18, 2014 at 06:14:26 PM, Wolfgang Denk wrote:
> Dear Rob,
> 
> In message <1397829272-22266-1-git-send-email-robherring2@gmail.com> you 
wrote:
> > I dropped the patch adding a loadsize env variable and added config
> > uptions instead to set the fastboot buffer size.
> 
> Thanks, but...
> 
> >  common/Makefile                      |   3 +
> >  common/cmd_bootm.c                   |  23 +-
> >  common/cmd_fastboot.c                |  36 +++
> >  common/image-android.c               |  84 ++++++
> >  common/image.c                       |  20 +-
> >  doc/README.android-fastboot          |  91 ++++++
> >  doc/README.android-fastboot-protocol | 170 ++++++++++++
> >  drivers/usb/gadget/Makefile          |   1 +
> >  drivers/usb/gadget/f_fastboot.c      | 518
> >  +++++++++++++++++++++++++++++++++++ drivers/usb/gadget/g_dnl.c         
> >   |   6 +
> >  drivers/usb/gadget/usbstring.c       |   3 +
> >  drivers/usb/musb-new/musb_uboot.c    |   5 +-
> >  include/android_image.h              |  69 +++++
> >  include/configs/omap3_beagle.h       |  10 +
> >  include/fastboot.h                   |  22 ++
> >  include/image.h                      |  13 +
> >  16 files changed, 1067 insertions(+), 7 deletions(-)
> 
> ...I don't see the README in the list of modified files - but new
> CONFIG options _must_ be documented there.  So please add the missing
> documentation.

I reviewed the patches again. I am with WD on this, please add the changes to 
the README file.

Other than that, I applied 1/5 and 3/5 now as they are clearly fixes and can go 
in. Please rebase on top of u-boot-usb/master and re-submit the rest.

Thanks!

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 3/5] usb: musb: fill in usb_gadget_unregister_driver
  2014-04-18 13:54   ` [U-Boot] [PATCH v4 3/5] usb: musb: fill in usb_gadget_unregister_driver Rob Herring
@ 2014-04-23  9:46     ` Lukasz Majewski
  0 siblings, 0 replies; 59+ messages in thread
From: Lukasz Majewski @ 2014-04-23  9:46 UTC (permalink / raw)
  To: u-boot

Hi Rob,

> From: Rob Herring <robh@kernel.org>
> 
> Add missing missing disconnect and unbind calls to the musb gadget
      ^^^^^^^ I suppose that one missing is redundant.

> driver's usb_gadget_unregister_driver function. Otherwise, any gadget
> drivers fail to uninitialize and run a 2nd time.
> 
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
>  drivers/usb/musb-new/musb_uboot.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/usb/musb-new/musb_uboot.c
> b/drivers/usb/musb-new/musb_uboot.c index 0512680..0d7b89f 100644
> --- a/drivers/usb/musb-new/musb_uboot.c
> +++ b/drivers/usb/musb-new/musb_uboot.c
> @@ -204,7 +204,10 @@ int usb_gadget_register_driver(struct
> usb_gadget_driver *driver) 
>  int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
>  {
> -	/* TODO: implement me */
> +	if (driver->disconnect)
> +		driver->disconnect(&gadget->g);
> +	if (driver->unbind)
> +		driver->unbind(&gadget->g);
>  	return 0;
>  }
>  #endif /* CONFIG_MUSB_GADGET */

Despite the minor problem with commit message, the rest seems correct.

Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>

-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 4/5] usb/gadget: add the fastboot gadget
  2014-04-18 13:54   ` [U-Boot] [PATCH v4 4/5] usb/gadget: add the fastboot gadget Rob Herring
@ 2014-04-23 11:02     ` Lukasz Majewski
  2014-04-23 12:25       ` Marek Vasut
  2014-04-24 15:02       ` Rob Herring
  0 siblings, 2 replies; 59+ messages in thread
From: Lukasz Majewski @ 2014-04-23 11:02 UTC (permalink / raw)
  To: u-boot

Hi Rob,

> From: Sebastian Siewior <bigeasy@linutronix.de>
> 
> This patch contains an implementation of the fastboot protocol on the
> device side and documentation. This is based on USB download gadget
> infrastructure. The fastboot function implements the getvar, reboot,
> download and reboot commands. What is missing is the flash handling
> i.e. writting the image to media.
> 
> v3 (Rob Herring):
> This is based on http://patchwork.ozlabs.org/patch/126798/ with the
> following changes:
> - Rebase to current mainline and updates for current gadget API
> - Use SPDX identifiers for licenses
> - Traced the history and added missing copyright to cmd_fastboot.c
> - Use load_addr/load_size for transfer buffer
> - Allow vendor strings to be optional
> - Set vendor/product ID from config defines
> - Allow Ctrl-C to exit fastboot mode
> v4:
> - Major re-write to use the USB download gadget. Consolidated function
> code to a single file.
> - Moved globals into single struct.
> - Use puts and putc as appropriate.
> - Added CONFIG_USB_FASTBOOT_BUF_ADDR and CONFIG_USB_FASTBOOT_BUF_SIZE
> to set the fastboot transfer buffer.
> 
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
>  common/Makefile                      |   2 +
>  common/cmd_fastboot.c                |  36 +++
>  doc/README.android-fastboot          |  91 ++++++
>  doc/README.android-fastboot-protocol | 170 ++++++++++++
>  drivers/usb/gadget/Makefile          |   1 +
>  drivers/usb/gadget/f_fastboot.c      | 518
> +++++++++++++++++++++++++++++++++++
> drivers/usb/gadget/g_dnl.c           |   6 +
> include/fastboot.h                   |  22 ++ 8 files changed, 846
> insertions(+) create mode 100644 common/cmd_fastboot.c
>  create mode 100644 doc/README.android-fastboot
>  create mode 100644 doc/README.android-fastboot-protocol
>  create mode 100644 drivers/usb/gadget/f_fastboot.c
>  create mode 100644 include/fastboot.h
> 
> diff --git a/common/Makefile b/common/Makefile
> index da208f3..fe1d8b9 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -167,6 +167,8 @@ obj-y += cmd_usb.o
>  obj-y += usb.o usb_hub.o
>  obj-$(CONFIG_USB_STORAGE) += usb_storage.o
>  endif
> +obj-$(CONFIG_CMD_FASTBOOT) += cmd_fastboot.o
> +
>  obj-$(CONFIG_CMD_USB_MASS_STORAGE) += cmd_usb_mass_storage.o
>  obj-$(CONFIG_CMD_THOR_DOWNLOAD) += cmd_thordown.o
>  obj-$(CONFIG_CMD_XIMG) += cmd_ximg.o
> diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
> new file mode 100644
> index 0000000..ce7e198
> --- /dev/null
> +++ b/common/cmd_fastboot.c
> @@ -0,0 +1,36 @@
> +/*
> + * Copyright 2008 - 2009 Windriver, <www.windriver.com>
> + * Author: Tom Rix <Tom.Rix@windriver.com>
> + *
> + * (C) Copyright 2014 Linaro, Ltd.
> + * Rob Herring <robh@kernel.org>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +#include <common.h>
> +#include <command.h>
> +#include <g_dnl.h>
> +
> +static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char
> *const argv[]) +{
> +	int ret;
> +
> +	ret = g_dnl_register("fastboot");
> +	if (ret)
> +		return ret;
> +
> +	while (1) {
> +		if (ctrlc())
> +			break;
> +		usb_gadget_handle_interrupts();
> +	}
> +
> +	g_dnl_unregister();
> +	return CMD_RET_SUCCESS;
> +}
> +
> +U_BOOT_CMD(
> +	fastboot,	1,	1,	do_fastboot,
> +	"fastboot - enter USB Fastboot protocol",
> +	""
> +);
> diff --git a/doc/README.android-fastboot b/doc/README.android-fastboot
> new file mode 100644
> index 0000000..f1d128c
> --- /dev/null
> +++ b/doc/README.android-fastboot
> @@ -0,0 +1,91 @@
> +Android Fastboot
> +~~~~~~~~~~~~~~~~
> +
> +Overview
> +========
> +The protocol that is used over USB is described in
> +README.android-fastboot-protocol in same directory.
> +
> +The current implementation does not yet support the flash and erase
> +commands.
> +
> +Client installation
> +===================
> +The counterpart to this gadget is the fastboot client which can
> +be found in Android's platform/system/core repository in the fastboot
> +folder. It runs on Windows, Linux and even OSX. Linux user are lucky
> since +they only need libusb.
> +Windows users need to bring some time until they have Android SDK
> (currently +http://dl.google.com/android/installer_r12-windows.exe)
> installed. You +need to install ADB package which contains the
> required glue libraries for +accessing USB. Also you need "Google USB
> driver package" and "SDK platform +tools". Once installed the usb
> driver is placed in your SDK folder under +extras\google\usb_driver.
> The android_winusb.inf needs a line like +
> +   %SingleBootLoaderInterface% = USB_Install, USB\VID_0451&PID_D022
> +
> +either in the [Google.NTx86] section for 32bit Windows or
> [Google.NTamd64] +for 64bit Windows. VID and PID should match
> whatever the fastboot is +advertising.
> +
> +Board specific
> +==============
> +The fastboot gadget relies on the USB download gadget, so the
> following +options must be configured:
> +
> +CONFIG_USBDOWNLOAD_GADGET
> +CONFIG_G_DNL_VENDOR_NUM
> +CONFIG_G_DNL_PRODUCT_NUM
> +CONFIG_G_DNL_MANUFACTURER
> +
> +The fastboot function is enabled by defining CONFIG_CMD_FASTBOOT and
> +CONFIG_ANDROID_BOOT_IMAGE.
> +
> +The fastboot protocol requires a large memory buffer for downloads.
> This +buffer should be as large as possible for a platform. The
> location of the +buffer and size are set with
> CONFIG_USB_FASTBOOT_BUF_ADDR and +CONFIG_USB_FASTBOOT_BUF_SIZE.
> +
> +In Action
> +=========
> +Enter into fastboot by executing the fastboot command in u-boot and
> you +should see:
> +|GADGET DRIVER: usb_dnl_fastboot
> +
> +On the client side you can fetch the bootloader version for instance:
> +|>fastboot getvar bootloader-version
> +|bootloader-version: U-Boot 2014.04-00005-gd24cabc
> +|finished. total time: 0.000s
> +
> +or initiate a reboot:
> +|>fastboot reboot
> +
> +and once the client comes back, the board should reset.
> +
> +You can also specify a kernel image to boot. You have to either
> specify +the an image in Android format _or_ pass a binary kernel and
> let the +fastboot client wrap the Android suite around it. On OMAP
> for instance you +take zImage kernel and pass it to the fastboot
> client: +
> +|>fastboot -b 0x80000000 -c "console=ttyO2 earlyprintk root=/dev/ram0
> +|	mem=128M" boot zImage
> +|creating boot image...
> +|creating boot image - 1847296 bytes
> +|downloading 'boot.img'...
> +|OKAY [  2.766s]
> +|booting...
> +|OKAY [ -0.000s]
> +|finished. total time: 2.766s
> +
> +and on the gadget side you should see:
> +|Starting download of 1847296 bytes
> +|........................................................
> +|downloading of 1847296 bytes finished
> +|Booting kernel..
> +|## Booting Android Image at 0x81000000 ...
> +|Kernel load addr 0x80008000 size 1801 KiB
> +|Kernel command line: console=ttyO2 earlyprintk root=/dev/ram0
> mem=128M +|   Loading Kernel Image ... OK
> +|OK
> +|
> +|Starting kernel ...
> diff --git a/doc/README.android-fastboot-protocol
> b/doc/README.android-fastboot-protocol new file mode 100644
> index 0000000..e9e7166
> --- /dev/null
> +++ b/doc/README.android-fastboot-protocol
> @@ -0,0 +1,170 @@
> +FastBoot  Version  0.4
> +----------------------
> +
> +The fastboot protocol is a mechanism for communicating with
> bootloaders +over USB.  It is designed to be very straightforward to
> implement, to +allow it to be used across a wide range of devices and
> from hosts running +Linux, Windows, or OSX.
> +
> +
> +Basic Requirements
> +------------------
> +
> +* Two bulk endpoints (in, out) are required
> +* Max packet size must be 64 bytes for full-speed and 512 bytes for
> +  high-speed USB
> +* The protocol is entirely host-driven and synchronous (unlike the
> +  multi-channel, bi-directional, asynchronous ADB protocol)
> +
> +
> +Transport and Framing
> +---------------------
> +
> +1. Host sends a command, which is an ascii string in a single
> +   packet no greater than 64 bytes.
> +
> +2. Client response with a single packet no greater than 64 bytes.
> +   The first four bytes of the response are "OKAY", "FAIL", "DATA",
> +   or "INFO".  Additional bytes may contain an (ascii) informative
> +   message.
> +
> +   a. INFO -> the remaining 60 bytes are an informative message
> +      (providing progress or diagnostic messages).  They should
> +      be displayed and then step #2 repeats
> +
> +   b. FAIL -> the requested command failed.  The remaining 60 bytes
> +      of the response (if present) provide a textual failure message
> +      to present to the user.  Stop.
> +
> +   c. OKAY -> the requested command completed successfully.  Go to #5
> +
> +   d. DATA -> the requested command is ready for the data phase.
> +      A DATA response packet will be 12 bytes long, in the form of
> +      DATA00000000 where the 8 digit hexidecimal number represents
> +      the total data size to transfer.
> +
> +3. Data phase.  Depending on the command, the host or client will
> +   send the indicated amount of data.  Short packets are always
> +   acceptable and zero-length packets are ignored.  This phase
> continues
> +   until the client has sent or received the number of bytes
> indicated
> +   in the "DATA" response above.
> +
> +4. Client responds with a single packet no greater than 64 bytes.
> +   The first four bytes of the response are "OKAY", "FAIL", or
> "INFO".
> +   Similar to #2:
> +
> +   a. INFO -> display the remaining 60 bytes and return to #4
> +
> +   b. FAIL -> display the remaining 60 bytes (if present) as a
> failure
> +      reason and consider the command failed.  Stop.
> +
> +   c. OKAY -> success.  Go to #5
> +
> +5. Success.  Stop.
> +
> +
> +Example Session
> +---------------
> +
> +Host:    "getvar:version"        request version variable
> +
> +Client:  "OKAY0.4"               return version "0.4"
> +
> +Host:    "getvar:nonexistant"    request some undefined variable
> +
> +Client:  "OKAY"                  return value ""
> +
> +Host:    "download:00001234"     request to send 0x1234 bytes of data
> +
> +Client:  "DATA00001234"          ready to accept data
> +
> +Host:    < 0x1234 bytes >        send data
> +
> +Client:  "OKAY"                  success
> +
> +Host:    "flash:bootloader"      request to flash the data to the
> bootloader +
> +Client:  "INFOerasing flash"     indicate status / progress
> +         "INFOwriting flash"
> +         "OKAY"                  indicate success
> +
> +Host:    "powerdown"             send a command
> +
> +Client:  "FAILunknown command"   indicate failure
> +
> +
> +Command Reference
> +-----------------
> +
> +* Command parameters are indicated by printf-style escape sequences.
> +
> +* Commands are ascii strings and sent without the quotes (which are
> +  for illustration only here) and without a trailing 0 byte.
> +
> +* Commands that begin with a lowercase letter are reserved for this
> +  specification.  OEM-specific commands should not begin with a
> +  lowercase letter, to prevent incompatibilities with future specs.
> +
> + "getvar:%s"           Read a config/version variable from the
> bootloader.
> +                       The variable contents will be returned after
> the
> +                       OKAY response.
> +
> + "download:%08x"       Write data to memory which will be later used
> +                       by "boot", "ramdisk", "flash", etc.  The
> client
> +                       will reply with "DATA%08x" if it has enough
> +                       space in RAM or "FAIL" if not.  The size of
> +                       the download is remembered.
> +
> +  "verify:%08x"        Send a digital signature to verify the
> downloaded
> +                       data.  Required if the bootloader is "secure"
> +                       otherwise "flash" and "boot" will be ignored.
> +
> +  "flash:%s"           Write the previously downloaded image to the
> +                       named partition (if possible).
> +
> +  "erase:%s"           Erase the indicated partition (clear to 0xFFs)
> +
> +  "boot"               The previously downloaded data is a boot.img
> +                       and should be booted according to the normal
> +                       procedure for a boot.img
> +
> +  "continue"           Continue booting as normal (if possible)
> +
> +  "reboot"             Reboot the device.
> +
> +  "reboot-bootloader"  Reboot back into the bootloader.
> +                       Useful for upgrade processes that require
> upgrading
> +                       the bootloader and then upgrading other
> partitions
> +                       using the new bootloader.
> +
> +  "powerdown"          Power off the device.
> +
> +
> +
> +Client Variables
> +----------------
> +
> +The "getvar:%s" command is used to read client variables which
> +represent various information about the device and the software
> +on it.
> +
> +The various currently defined names are:
> +
> +  version             Version of FastBoot protocol supported.
> +                      It should be "0.3" for this document.
> +
> +  version-bootloader  Version string for the Bootloader.
> +
> +  version-baseband    Version string of the Baseband Software
> +
> +  product             Name of the product
> +
> +  serialno            Product serial number
> +
> +  secure              If the value is "yes", this is a secure
> +                      bootloader requiring a signature before
> +                      it will install or boot images.
> +
> +Names starting with a lowercase character are reserved by this
> +specification.  OEM-specific names should not start with lowercase
> +characters.
> diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
> index 804a2bd..3375f68 100644
> --- a/drivers/usb/gadget/Makefile
> +++ b/drivers/usb/gadget/Makefile
> @@ -17,6 +17,7 @@ obj-$(CONFIG_THOR_FUNCTION) += f_thor.o
>  obj-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
>  obj-$(CONFIG_DFU_FUNCTION) += f_dfu.o
>  obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o
> +obj-$(CONFIG_CMD_FASTBOOT) += f_fastboot.o
>  endif
>  ifdef CONFIG_USB_ETHER
>  obj-y += ether.o
> diff --git a/drivers/usb/gadget/f_fastboot.c
> b/drivers/usb/gadget/f_fastboot.c new file mode 100644
> index 0000000..514279f
> --- /dev/null
> +++ b/drivers/usb/gadget/f_fastboot.c
> @@ -0,0 +1,518 @@
> +/*
> + * (C) Copyright 2008 - 2009
> + * Windriver, <www.windriver.com>
> + * Tom Rix <Tom.Rix@windriver.com>
> + *
> + * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> + *
> + * Copyright 2014 Linaro, Ltd.
> + * Rob Herring <robh@kernel.org>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +#include <common.h>
> +#include <errno.h>
> +#include <malloc.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +#include <linux/usb/composite.h>
> +#include <linux/compiler.h>
> +#include <version.h>
> +#include <g_dnl.h>
> +#include <fastboot.h>
> +
> +#define FASTBOOT_VERSION		"0.4"
> +
> +#define FASTBOOT_INTERFACE_CLASS	0xff
> +#define FASTBOOT_INTERFACE_SUB_CLASS	0x42
> +#define FASTBOOT_INTERFACE_PROTOCOL	0x03
> +
> +#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0  (0x0200)
> +#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1  (0x0040)
> +#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE      (0x0040)
> +
> +/* The 64 defined bytes plus \0 */
> +#define RESPONSE_LEN	(64 + 1)
> +
> +#define EP_BUFFER_SIZE			4096
> +
> +struct f_fastboot {
> +	struct usb_function usb_function;
> +
> +	/* IN/OUT EP's and correspoinding requests */
> +	struct usb_ep *in_ep, *out_ep;
> +	struct usb_request *in_req, *out_req;
> +};
> +
> +static inline struct f_fastboot *func_to_fastboot(struct
> usb_function *f) +{
> +	return container_of(f, struct f_fastboot, usb_function);
> +}
> +
> +static struct f_fastboot *fastboot_func;
> +static unsigned int download_size;
> +static unsigned int download_bytes;
> +
> +static struct usb_endpoint_descriptor fs_ep_in = {
> +	.bLength            = USB_DT_ENDPOINT_SIZE,
> +	.bDescriptorType    = USB_DT_ENDPOINT,
> +	.bEndpointAddress   = USB_DIR_IN,
> +	.bmAttributes       = USB_ENDPOINT_XFER_BULK,
> +	.wMaxPacketSize     = TX_ENDPOINT_MAXIMUM_PACKET_SIZE,
> +	.bInterval          = 0x00,
> +};
> +
> +static struct usb_endpoint_descriptor fs_ep_out = {
> +	.bLength		= USB_DT_ENDPOINT_SIZE,
> +	.bDescriptorType	= USB_DT_ENDPOINT,
> +	.bEndpointAddress	= USB_DIR_OUT,
> +	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
> +	.wMaxPacketSize		=
> RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1,
> +	.bInterval		= 0x00,
> +};
> +
> +static struct usb_endpoint_descriptor hs_ep_out = {
> +	.bLength		= USB_DT_ENDPOINT_SIZE,
> +	.bDescriptorType	= USB_DT_ENDPOINT,
> +	.bEndpointAddress	= USB_DIR_OUT,
> +	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
> +	.wMaxPacketSize		=
> RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0,
> +	.bInterval		= 0x00,
> +};
> +
> +static struct usb_interface_descriptor interface_desc = {
> +	.bLength		= USB_DT_INTERFACE_SIZE,
> +	.bDescriptorType	= USB_DT_INTERFACE,
> +	.bInterfaceNumber	= 0x00,
> +	.bAlternateSetting	= 0x00,
> +	.bNumEndpoints		= 0x02,
> +	.bInterfaceClass	= FASTBOOT_INTERFACE_CLASS,
> +	.bInterfaceSubClass	= FASTBOOT_INTERFACE_SUB_CLASS,
> +	.bInterfaceProtocol	= FASTBOOT_INTERFACE_PROTOCOL,
> +};
> +
> +static struct usb_descriptor_header *fb_runtime_descs[] = {
> +	(struct usb_descriptor_header *)&interface_desc,
> +	(struct usb_descriptor_header *)&fs_ep_in,
> +	(struct usb_descriptor_header *)&hs_ep_out,
> +	NULL,
> +};
> +
> +/*
> + * static strings, in UTF-8
> + */
> +static const char fastboot_name[] = "Android Fastboot";
> +
> +static struct usb_string fastboot_string_defs[] = {
> +	[0].s = fastboot_name,
> +	{  }			/* end of list */
> +};
> +
> +static struct usb_gadget_strings stringtab_fastboot = {
> +	.language	= 0x0409,	/* en-us */
> +	.strings	= fastboot_string_defs,
> +};
> +
> +static struct usb_gadget_strings *fastboot_strings[] = {
> +	&stringtab_fastboot,
> +	NULL,
> +};
> +
> +static void rx_handler_command(struct usb_ep *ep, struct usb_request
> *req); +
> +static void fastboot_complete(struct usb_ep *ep, struct usb_request
> *req) +{
> +	int status = req->status;
> +	if (!status)
> +		return;
> +	printf("status: %d ep '%s' trans: %d\n", status, ep->name,
> req->actual); +}
> +
> +static int fastboot_bind(struct usb_configuration *c, struct
> usb_function *f) +{
> +	int status, id;
> +	struct usb_gadget *gadget = c->cdev->gadget;
> +	struct f_fastboot *f_fb = func_to_fastboot(f);
> +
> +	/* DYNAMIC interface numbers assignments */
> +	status = usb_interface_id(c, f);
> +	if (status < 0)
> +		goto err;
> +
> +	interface_desc.bInterfaceNumber = status;
> +
> +	id = usb_string_id(c->cdev);
> +	if (id < 0)
> +		goto err;
> +	fastboot_string_defs[0].id = id;
> +	interface_desc.iInterface = id;
> +
> +	f_fb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
> +	if (!f_fb->in_ep)
> +		goto err;
> +	f_fb->in_ep->driver_data = c->cdev;
> +
> +	f_fb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
> +	if (!f_fb->out_ep)
> +		goto err;
> +	f_fb->out_ep->driver_data = c->cdev;
> +
> +	hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
> +
> +	return 0;
> +err:
> +	return -1;

		Maybe -ENODEV or -EINVAL?

> +}
> +
> +static void fastboot_unbind(struct usb_configuration *c, struct
> usb_function *f) +{
> +	memset(fastboot_func, 0, sizeof(*fastboot_func));
> +}
> +
> +static void fastboot_disable(struct usb_function *f)
> +{
> +	struct f_fastboot *f_fb = func_to_fastboot(f);
> +
> +	usb_ep_disable(f_fb->out_ep);
> +	usb_ep_disable(f_fb->in_ep);
> +
> +	if (f_fb->out_req) {
> +		free(f_fb->out_req->buf);
> +		usb_ep_free_request(f_fb->out_ep, f_fb->out_req);
> +		f_fb->out_req = NULL;
> +	}
> +	if (f_fb->in_req) {
> +		free(f_fb->in_req->buf);
> +		usb_ep_free_request(f_fb->in_ep, f_fb->in_req);
> +		f_fb->in_req = NULL;
> +	}
> +}
> +
> +static struct usb_request *fastboot_start_ep(struct usb_ep *ep)
> +{
> +	struct usb_request *req;
> +
> +	req = usb_ep_alloc_request(ep, 0);
> +	if (!req)
> +		return NULL;
> +
> +	req->length = EP_BUFFER_SIZE;
> +	req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE,
> EP_BUFFER_SIZE);
> +	if (!req->buf) {
> +		usb_ep_free_request(ep, req);
> +		return NULL;
> +	}
> +
> +	memset(req->buf, 0, req->length);
> +	return req;
> +}
> +
> +static int fastboot_set_alt(struct usb_function *f,
> +			    unsigned interface, unsigned alt)
> +{
> +	int ret;
> +	struct usb_composite_dev *cdev = f->config->cdev;
> +	struct usb_gadget *gadget = cdev->gadget;
> +	struct f_fastboot *f_fb = func_to_fastboot(f);
> +
> +	debug("%s: func: %s intf: %d alt: %d\n",
> +	      __func__, f->name, interface, alt);
> +
> +	/* make sure we don't enable the ep twice */
> +	if (gadget->speed == USB_SPEED_HIGH)
> +		ret = usb_ep_enable(f_fb->out_ep, &hs_ep_out);
> +	else
> +		ret = usb_ep_enable(f_fb->out_ep, &fs_ep_out);
> +	if (ret) {
> +		puts("failed to enable out ep\n");
> +		goto err;
> +	}
> +
> +	f_fb->out_req = fastboot_start_ep(f_fb->out_ep);
> +	if (!f_fb->out_req) {
> +		puts("failed to alloc out req\n");
> +		goto err;
> +	}
> +
> +	ret = usb_ep_enable(f_fb->in_ep, &fs_ep_in);
> +	if (ret) {
> +		puts("failed to enable in ep\n");
> +		goto err;
> +	}
> +	f_fb->out_req->complete = rx_handler_command;
> +
> +	f_fb->in_req = fastboot_start_ep(f_fb->in_ep);
> +	if (!f_fb->in_req) {
> +		puts("failed alloc req in\n");
> +		goto err;
> +	}
> +	f_fb->in_req->complete = fastboot_complete;
> +
> +	ret = usb_ep_queue(f_fb->out_ep, f_fb->out_req, 0);
> +	if (ret)
> +		goto err;
> +
> +	return 0;
> +err:
> +	fastboot_disable(f);
> +	return -1;

	Here,I would also encourage to use appropriate error code from
	<errno.h>.

> +}
> +
> +int fastboot_add(struct usb_configuration *c)
> +{
> +	struct f_fastboot *f_fb = fastboot_func;
> +	int status;
> +
> +	debug("%s: cdev: 0x%p\n", __func__, c->cdev);
> +
> +	if (!f_fb) {
> +		f_fb = memalign(CONFIG_SYS_CACHELINE_SIZE,
> sizeof(*f_fb));
> +		if (!f_fb)
> +			return -ENOMEM;
> +
> +		fastboot_func = f_fb;
> +		memset(f_fb, 0, sizeof(*f_fb));
> +	}
> +
> +	f_fb->usb_function.name = "f_fastboot";
> +	f_fb->usb_function.hs_descriptors = fb_runtime_descs;
> +	f_fb->usb_function.bind = fastboot_bind;
> +	f_fb->usb_function.unbind = fastboot_unbind;
> +	f_fb->usb_function.set_alt = fastboot_set_alt;
> +	f_fb->usb_function.disable = fastboot_disable;
> +	f_fb->usb_function.strings = fastboot_strings;
> +
> +	status = usb_add_function(c, &f_fb->usb_function);
> +	if (status) {
> +		free(f_fb);
> +		fastboot_func = f_fb;
> +	}
> +
> +	return status;
> +}
> +
> +int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
> +{
> +	struct usb_request *in_req = fastboot_func->in_req;
> +	int ret;
> +
> +	if (in_req->complete == NULL)
> +		in_req->complete = fastboot_complete;
> +
> +	memcpy(in_req->buf, buffer, buffer_size);
> +	in_req->length = buffer_size;
> +	ret = usb_ep_queue(fastboot_func->in_ep, in_req, 0);
> +	if (ret)
> +		printf("Error %d on queue\n", ret);
> +	return 0;
> +}
> +
> +static int fastboot_tx_write_str(const char *buffer)
> +{
> +	return fastboot_tx_write(buffer, strlen(buffer));
> +}
> +
> +static void compl_do_reset(struct usb_ep *ep, struct usb_request
> *req) +{
> +	do_reset(NULL, 0, 0, NULL);
> +}
> +
> +static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
> +{
> +	fastboot_func->in_req->complete = compl_do_reset;
> +	fastboot_tx_write_str("OKAY");
> +}
> +
> +static int strcmp_l1(const char *s1, const char *s2)
> +{
> +	if (!s1 || !s2)
> +		return -1;
> +	return strncmp(s1, s2, strlen(s1));
> +}
> +
> +static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
> +{
> +	char *cmd = req->buf;
> +	char response[RESPONSE_LEN];
> +	const char *s;
> +
> +	strcpy(response, "OKAY");
> +	strsep(&cmd, ":");
> +	if (!cmd) {
> +		fastboot_tx_write_str("FAILmissing var");
> +		return;
> +	}
> +
> +	if (!strcmp_l1("version", cmd)) {
> +		strncat(response, FASTBOOT_VERSION,
> sizeof(response));
> +	} else if (!strcmp_l1("bootloader-version", cmd)) {
> +		strncat(response, U_BOOT_VERSION, sizeof(response));
> +	} else if (!strcmp_l1("downloadsize", cmd)) {
> +		char str_num[12];
> +
> +		sprintf(str_num, "%08x",
> CONFIG_USB_FASTBOOT_BUF_SIZE);
> +		strncat(response, str_num, sizeof(response));
> +	} else if (!strcmp_l1("serialno", cmd)) {
> +		s = getenv("serial#");
> +		if (s)
> +			strncat(response, s, sizeof(response));
> +		else
> +			strcpy(response, "FAILValue not set");
> +	} else {
> +		strcpy(response, "FAILVariable not implemented");
> +	}
> +	fastboot_tx_write_str(response);
> +}
> +
> +static unsigned int rx_bytes_expected(void)
> +{
> +	int rx_remain = download_size - download_bytes;
> +	if (rx_remain < 0)
> +		return 0;
> +	if (rx_remain > EP_BUFFER_SIZE)
> +		return EP_BUFFER_SIZE;
> +	return rx_remain;
> +}
> +
> +#define BYTES_PER_DOT	32768
> +static void rx_handler_dl_image(struct usb_ep *ep, struct
> usb_request *req) +{
> +	char response[RESPONSE_LEN];
> +	unsigned int transfer_size = download_size - download_bytes;
> +	const unsigned char *buffer = req->buf;
> +	unsigned int buffer_size = req->actual;
> +
> +	if (req->status != 0) {
> +		printf("Bad status: %d\n", req->status);
> +		return;
> +	}
> +
> +	if (buffer_size < transfer_size)
> +		transfer_size = buffer_size;
> +
> +	memcpy((void *)CONFIG_USB_FASTBOOT_BUF_ADDR + download_bytes,

	Please consider using dfu_get_buf() from dfu.c to provide
	dynamically allocated and controlled buffer instead of the
	CONFIG_USB_FASTBOOT_BUF_ADDR and _SIZE.

	Another advantage of this code is the ability to set
	"dfu_bufsiz" env variable with size of the buffer.

> +	       buffer, transfer_size);
> +
> +	download_bytes += transfer_size;
> +
> +	/* Check if transfer is done */
> +	if (download_bytes >= download_size) {
> +		/*
> +		 * Reset global transfer variable, keep
> download_bytes because
> +		 * it will be used in the next possible flashing
> command
> +		 */
> +		download_size = 0;
> +		req->complete = rx_handler_command;
> +		req->length = EP_BUFFER_SIZE;
> +
> +		sprintf(response, "OKAY");
> +		fastboot_tx_write_str(response);
> +
> +		printf("\ndownloading of %d bytes finished\n",
> download_bytes);
> +	} else {
> +		req->length = rx_bytes_expected();
> +	}
> +
> +	if (download_bytes && !(download_bytes % BYTES_PER_DOT)) {
> +		putc('.');
> +		if (!(download_bytes % (74 * BYTES_PER_DOT)))
> +			putc('\n');
> +	}
> +	req->actual = 0;
> +	usb_ep_queue(ep, req, 0);
> +}
> +
> +static void cb_download(struct usb_ep *ep, struct usb_request *req)
> +{
> +	char *cmd = req->buf;
> +	char response[RESPONSE_LEN];
> +
> +	strsep(&cmd, ":");
> +	download_size = simple_strtoul(cmd, NULL, 16);
> +	download_bytes = 0;
> +
> +	printf("Starting download of %d bytes\n", download_size);
> +
> +	if (0 == download_size) {
> +		sprintf(response, "FAILdata invalid size");
> +	} else if (download_size > CONFIG_USB_FASTBOOT_BUF_SIZE) {
> +		download_size = 0;
> +		sprintf(response, "FAILdata too large");
> +	} else {
> +		sprintf(response, "DATA%08x", download_size);
> +		req->complete = rx_handler_dl_image;
> +		req->length = rx_bytes_expected();
> +	}
> +	fastboot_tx_write_str(response);
> +}
> +
> +static void do_bootm_on_complete(struct usb_ep *ep, struct
> usb_request *req) +{
> +	char boot_addr_start[12];
> +	char *bootm_args[] = { "bootm", boot_addr_start, NULL };
> +
> +	req->complete = NULL;
> +	g_dnl_unregister();
> +	puts("Booting kernel..\n");
> +
> +	sprintf(boot_addr_start, "0x%lx", load_addr);
> +	do_bootm(NULL, 0, 2, bootm_args);
> +
> +	/* This only happens if image is somehow faulty so we start
> over */
> +	do_reset(NULL, 0, 0, NULL);
> +}
> +
> +static void cb_boot(struct usb_ep *ep, struct usb_request *req)
> +{
> +	fastboot_func->in_req->complete = do_bootm_on_complete;
> +	fastboot_tx_write_str("OKAY");
> +}
> +
> +struct cmd_dispatch_info {
> +	char *cmd;
> +	void (*cb)(struct usb_ep *ep, struct usb_request *req);
> +};
> +
> +static const struct cmd_dispatch_info cmd_dispatch_info[] = {
> +	{
> +		.cmd = "reboot",
> +		.cb = cb_reboot,
> +	}, {
> +		.cmd = "getvar:",
> +		.cb = cb_getvar,
> +	}, {
> +		.cmd = "download:",
> +		.cb = cb_download,
> +	}, {
> +		.cmd = "boot",
> +		.cb = cb_boot,
> +	},
> +};
> +
> +static void rx_handler_command(struct usb_ep *ep, struct usb_request
> *req) +{
> +	char response[RESPONSE_LEN];
> +	char *cmdbuf = req->buf;
> +	void (*func_cb)(struct usb_ep *ep, struct usb_request *req)
> = NULL;
> +	int i;
> +
> +	sprintf(response, "FAIL");
> +
> +	for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
> +		if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
> +			func_cb = cmd_dispatch_info[i].cb;
> +			break;
> +		}
> +	}
> +
> +	if (!func_cb)
> +		fastboot_tx_write_str("FAILunknown command");
> +	else
> +		func_cb(ep, req);
> +
> +	if (req->status == 0) {
> +		*cmdbuf = '\0';
> +		req->actual = 0;
> +		usb_ep_queue(ep, req, 0);
> +	}
> +}
> diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c
> index dd95afe..dbea322 100644
> --- a/drivers/usb/gadget/g_dnl.c
> +++ b/drivers/usb/gadget/g_dnl.c
> @@ -17,6 +17,7 @@
>  #include <usb_mass_storage.h>
>  #include <dfu.h>
>  #include <thor.h>
> +#include <fastboot.h>
>  
>  #include "gadget_chips.h"
>  #include "composite.c"
> @@ -117,6 +118,8 @@ static int g_dnl_do_config(struct
> usb_configuration *c) ret = fsg_add(c);
>  	else if (!strcmp(s, "usb_dnl_thor"))
>  		ret = thor_add(c);
> +	else if (!strcmp(s, "usb_dnl_fastboot"))
> +		ret = fastboot_add(c);
>  
>  	return ret;
>  }
> @@ -242,6 +245,9 @@ int g_dnl_register(const char *type)
>  	} else if (!strcmp(type, "thor")) {
>  		strcpy(name, shortname);
>  		strcat(name, type);
> +	} else if (!strcmp(type, "fastboot")) {
> +		strcpy(name, shortname);
> +		strcat(name, type);
>  	} else {
>  		printf("%s: unknown command: %s\n", __func__, type);
>  		return -EINVAL;
> diff --git a/include/fastboot.h b/include/fastboot.h
> new file mode 100644
> index 0000000..3c26bd6
> --- /dev/null
> +++ b/include/fastboot.h
> @@ -0,0 +1,22 @@
> +/*
> + * (C) Copyright 2014 Linaro, Ltd.
> + * Rob Herring <robh@kernel.org>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#ifndef FASTBOOT_H
> +#define FASTBOOT_H
> +
> +#include <linux/usb/composite.h>
> +
> +#ifdef CONFIG_CMD_FASTBOOT
> +int fastboot_add(struct usb_configuration *c);
> +#else
> +static int fastboot_add(struct usb_configuration *c)
> +{
> +	return 0;
> +}
> +#endif
> +
> +#endif

One more remark regarding your patches.

There is an ongoing work done by Mateusz Zalega (CC'ed). 

Patch series
"[PATCH v4 00/13] DFU, MMC, Gadget, Goni, misc."
embracing below patch:
http://patchwork.ozlabs.org/patch/339263/

is changing the g_dnl interface.

I'm not the USB maintainer :-) (Marek Vasut is), but for me it seems
that above patches are more likely to be earlier accepted to u-boot-usb
tree. 

Marek, is this a correct assumption? 

If Marek don't mind, I'd like to ask you to rebase yours patches on top
of Mateusz work.


-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 4/5] usb/gadget: add the fastboot gadget
  2014-04-23 11:02     ` Lukasz Majewski
@ 2014-04-23 12:25       ` Marek Vasut
  2014-04-24 15:02       ` Rob Herring
  1 sibling, 0 replies; 59+ messages in thread
From: Marek Vasut @ 2014-04-23 12:25 UTC (permalink / raw)
  To: u-boot

On Wednesday, April 23, 2014 at 01:02:13 PM, Lukasz Majewski wrote:
[...]

> > +#include <linux/usb/composite.h>
> > +
> > +#ifdef CONFIG_CMD_FASTBOOT
> > +int fastboot_add(struct usb_configuration *c);
> > +#else
> > +static int fastboot_add(struct usb_configuration *c)
> > +{
> > +	return 0;
> > +}
> > +#endif
> > +
> > +#endif
> 
> One more remark regarding your patches.
> 
> There is an ongoing work done by Mateusz Zalega (CC'ed).
> 
> Patch series
> "[PATCH v4 00/13] DFU, MMC, Gadget, Goni, misc."
> embracing below patch:
> http://patchwork.ozlabs.org/patch/339263/
> 
> is changing the g_dnl interface.
> 
> I'm not the USB maintainer :-) (Marek Vasut is), but for me it seems
> that above patches are more likely to be earlier accepted to u-boot-usb
> tree.
> 
> Marek, is this a correct assumption?

Depends on Mateusz, surely we will see V5 of his set.

> If Marek don't mind, I'd like to ask you to rebase yours patches on top
> of Mateusz work.

btw Please learn to trim the message to only the relevant bits.

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 0/5] Android Fastboot support
  2014-04-21 15:13     ` Marek Vasut
@ 2014-04-23 14:36       ` Rob Herring
  2014-04-23 16:57         ` Marek Vasut
  0 siblings, 1 reply; 59+ messages in thread
From: Rob Herring @ 2014-04-23 14:36 UTC (permalink / raw)
  To: u-boot

On Mon, Apr 21, 2014 at 10:13 AM, Marek Vasut <marex@denx.de> wrote:
> On Friday, April 18, 2014 at 06:14:26 PM, Wolfgang Denk wrote:
>> Dear Rob,
>>
>> In message <1397829272-22266-1-git-send-email-robherring2@gmail.com> you
> wrote:

[...]

>> ...I don't see the README in the list of modified files - but new
>> CONFIG options _must_ be documented there.  So please add the missing
>> documentation.
>
> I reviewed the patches again. I am with WD on this, please add the changes to
> the README file.

Okay, will do.

> Other than that, I applied 1/5 and 3/5 now as they are clearly fixes and can go
> in. Please rebase on top of u-boot-usb/master and re-submit the rest.

It does not appear you have pushed out those 2 patches to your tree.

Rob

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 0/5] Android Fastboot support
  2014-04-23 14:36       ` Rob Herring
@ 2014-04-23 16:57         ` Marek Vasut
  0 siblings, 0 replies; 59+ messages in thread
From: Marek Vasut @ 2014-04-23 16:57 UTC (permalink / raw)
  To: u-boot

On Wednesday, April 23, 2014 at 04:36:04 PM, Rob Herring wrote:
> On Mon, Apr 21, 2014 at 10:13 AM, Marek Vasut <marex@denx.de> wrote:
> > On Friday, April 18, 2014 at 06:14:26 PM, Wolfgang Denk wrote:
> >> Dear Rob,
> >> 
> >> In message <1397829272-22266-1-git-send-email-robherring2@gmail.com> you
> > 
> > wrote:
> [...]
> 
> >> ...I don't see the README in the list of modified files - but new
> >> CONFIG options _must_ be documented there.  So please add the missing
> >> documentation.
> > 
> > I reviewed the patches again. I am with WD on this, please add the
> > changes to the README file.
> 
> Okay, will do.
> 
> > Other than that, I applied 1/5 and 3/5 now as they are clearly fixes and
> > can go in. Please rebase on top of u-boot-usb/master and re-submit the
> > rest.
> 
> It does not appear you have pushed out those 2 patches to your tree.

Fixed, thanks for bringing this to my attention.

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 4/5] usb/gadget: add the fastboot gadget
  2014-04-23 11:02     ` Lukasz Majewski
  2014-04-23 12:25       ` Marek Vasut
@ 2014-04-24 15:02       ` Rob Herring
  2014-04-25  5:26         ` Lukasz Majewski
  1 sibling, 1 reply; 59+ messages in thread
From: Rob Herring @ 2014-04-24 15:02 UTC (permalink / raw)
  To: u-boot

On Wed, Apr 23, 2014 at 6:02 AM, Lukasz Majewski <l.majewski@samsung.com> wrote:
> Hi Rob,
>
>> From: Sebastian Siewior <bigeasy@linutronix.de>
>>
>> This patch contains an implementation of the fastboot protocol on the
>> device side and documentation. This is based on USB download gadget
>> infrastructure. The fastboot function implements the getvar, reboot,
>> download and reboot commands. What is missing is the flash handling
>> i.e. writting the image to media.
>>

[...]

>> +     f_fb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
>> +     if (!f_fb->out_ep)
>> +             goto err;
>> +     f_fb->out_ep->driver_data = c->cdev;
>> +
>> +     hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
>> +
>> +     return 0;
>> +err:
>> +     return -1;
>
>                 Maybe -ENODEV or -EINVAL?

Okay. Actually, we can remove the goto and just return the original error codes.


>> +     if (buffer_size < transfer_size)
>> +             transfer_size = buffer_size;
>> +
>> +     memcpy((void *)CONFIG_USB_FASTBOOT_BUF_ADDR + download_bytes,
>
>         Please consider using dfu_get_buf() from dfu.c to provide
>         dynamically allocated and controlled buffer instead of the
>         CONFIG_USB_FASTBOOT_BUF_ADDR and _SIZE.
>
>         Another advantage of this code is the ability to set
>         "dfu_bufsiz" env variable with size of the buffer.

I considered this already. I certainly don't like reinventing things
which was why I originally used loadaddr and added loadsize to provide
a defined load buffer size.

The problem is fastboot needs enough RAM to download an entire sparse
filesystem. I have no idea what size exactly is typical or required,
but it seems that we want to be able to use nearly all free RAM. We
can talk all we want about how this is a crappy design, but it is what
it is. This is how the protocol works.

The problem with the DFU buffer is it is allocated from the malloc
region. If we just increase the malloc region to be close to total RAM
size then we will start to break other commands like tftp and fsload
which typically just use the RAM u-boot is not using (i.e. all but the
end of memory). The only platforms which have more than a few MB for
malloc are the ones that enable DFU.

Rob

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 4/5] usb/gadget: add the fastboot gadget
  2014-04-24 15:02       ` Rob Herring
@ 2014-04-25  5:26         ` Lukasz Majewski
  2014-04-25 13:30           ` Rob Herring
  0 siblings, 1 reply; 59+ messages in thread
From: Lukasz Majewski @ 2014-04-25  5:26 UTC (permalink / raw)
  To: u-boot

Hi Rob,

> On Wed, Apr 23, 2014 at 6:02 AM, Lukasz Majewski
> <l.majewski@samsung.com> wrote:
> > Hi Rob,
> >
> >> From: Sebastian Siewior <bigeasy@linutronix.de>
> >>
> >> This patch contains an implementation of the fastboot protocol on
> >> the device side and documentation. This is based on USB download
> >> gadget infrastructure. The fastboot function implements the
> >> getvar, reboot, download and reboot commands. What is missing is
> >> the flash handling i.e. writting the image to media.
> >>
> 
> [...]
> 
> >> +     f_fb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
> >> +     if (!f_fb->out_ep)
> >> +             goto err;
> >> +     f_fb->out_ep->driver_data = c->cdev;
> >> +
> >> +     hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
> >> +
> >> +     return 0;
> >> +err:
> >> +     return -1;
> >
> >                 Maybe -ENODEV or -EINVAL?
> 
> Okay. Actually, we can remove the goto and just return the original
> error codes.
> 
> 
> >> +     if (buffer_size < transfer_size)
> >> +             transfer_size = buffer_size;
> >> +
> >> +     memcpy((void *)CONFIG_USB_FASTBOOT_BUF_ADDR + download_bytes,
> >
> >         Please consider using dfu_get_buf() from dfu.c to provide
> >         dynamically allocated and controlled buffer instead of the
> >         CONFIG_USB_FASTBOOT_BUF_ADDR and _SIZE.
> >
> >         Another advantage of this code is the ability to set
> >         "dfu_bufsiz" env variable with size of the buffer.
> 
> I considered this already. I certainly don't like reinventing things
> which was why I originally used loadaddr and added loadsize to provide
> a defined load buffer size.
> 
> The problem is fastboot needs enough RAM to download an entire sparse
> filesystem. I have no idea what size exactly is typical or required,
> but it seems that we want to be able to use nearly all free RAM. We
> can talk all we want about how this is a crappy design, but it is what
> it is. This is how the protocol works.

I understand you :-). The same situation was with DFU on the beginning.
Large buffer with starting address defined per board.

Then, after some discussion, we come to conclusion that it would be
better to increase malloc pool and dynamically allocate buffer. 

Am I correct, that you don't know beforehand what would be the size of
downloaded file - maybe 5 MiB or maybe 512 MiB? Also from your
descriptor it seems like fastboot protocol don't want to impose any
restrictions about the size. Is it user's responsibility to send data
smaller than RAM size?

In the DFU/THOR we store data in buffer size packets (32 MiB). It also
has some drawbacks - with large raw data images we cannot download the
whole (e.g. rootfs) image and beforehand flashing check integrity.

One question - when your board has e.g. 768 MiB of "available" RAM, then
is the size of large rootfs restricted to this size?


> 
> The problem with the DFU buffer is it is allocated from the malloc
> region. If we just increase the malloc region to be close to total RAM
> size then we will start to break other commands like tftp and fsload
> which typically just use the RAM u-boot is not using (i.e. all but the
> end of memory). The only platforms which have more than a few MB for
> malloc are the ones that enable DFU.

Correct. On the other hand when we want to allocate too large buffer
we receive error from malloc and flashing is aborted. No harm is done.

> 
> Rob


-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 4/5] usb/gadget: add the fastboot gadget
  2014-04-25  5:26         ` Lukasz Majewski
@ 2014-04-25 13:30           ` Rob Herring
  2014-04-28  7:00             ` Lukasz Majewski
  0 siblings, 1 reply; 59+ messages in thread
From: Rob Herring @ 2014-04-25 13:30 UTC (permalink / raw)
  To: u-boot

On Fri, Apr 25, 2014 at 12:26 AM, Lukasz Majewski
<l.majewski@samsung.com> wrote:
> Hi Rob,
>
>> On Wed, Apr 23, 2014 at 6:02 AM, Lukasz Majewski
>> <l.majewski@samsung.com> wrote:
>> > Hi Rob,
>> >
>> >> From: Sebastian Siewior <bigeasy@linutronix.de>
>> >>
>> >> This patch contains an implementation of the fastboot protocol on
>> >> the device side and documentation. This is based on USB download
>> >> gadget infrastructure. The fastboot function implements the
>> >> getvar, reboot, download and reboot commands. What is missing is
>> >> the flash handling i.e. writting the image to media.
>> >>
>>
>> [...]

>> >         Please consider using dfu_get_buf() from dfu.c to provide
>> >         dynamically allocated and controlled buffer instead of the
>> >         CONFIG_USB_FASTBOOT_BUF_ADDR and _SIZE.
>> >
>> >         Another advantage of this code is the ability to set
>> >         "dfu_bufsiz" env variable with size of the buffer.
>>
>> I considered this already. I certainly don't like reinventing things
>> which was why I originally used loadaddr and added loadsize to provide
>> a defined load buffer size.
>>
>> The problem is fastboot needs enough RAM to download an entire sparse
>> filesystem. I have no idea what size exactly is typical or required,
>> but it seems that we want to be able to use nearly all free RAM. We
>> can talk all we want about how this is a crappy design, but it is what
>> it is. This is how the protocol works.
>
> I understand you :-). The same situation was with DFU on the beginning.
> Large buffer with starting address defined per board.
>
> Then, after some discussion, we come to conclusion that it would be
> better to increase malloc pool and dynamically allocate buffer.
>
> Am I correct, that you don't know beforehand what would be the size of
> downloaded file - maybe 5 MiB or maybe 512 MiB? Also from your
> descriptor it seems like fastboot protocol don't want to impose any
> restrictions about the size. Is it user's responsibility to send data
> smaller than RAM size?

Correct. The client side will check the size which is one of the
variables. I searched around some to try to get an idea of what the
typical buffer size is without much luck.

> In the DFU/THOR we store data in buffer size packets (32 MiB). It also
> has some drawbacks - with large raw data images we cannot download the
> whole (e.g. rootfs) image and beforehand flashing check integrity.
>
> One question - when your board has e.g. 768 MiB of "available" RAM, then
> is the size of large rootfs restricted to this size?

Yes, but that is not the size of the rootfs partition. The downloaded
files are sparse. I would guess only the minimal filesystem is laid
down this way and most optional pieces are installed later.

>>
>> The problem with the DFU buffer is it is allocated from the malloc
>> region. If we just increase the malloc region to be close to total RAM
>> size then we will start to break other commands like tftp and fsload
>> which typically just use the RAM u-boot is not using (i.e. all but the
>> end of memory). The only platforms which have more than a few MB for
>> malloc are the ones that enable DFU.
>
> Correct. On the other hand when we want to allocate too large buffer
> we receive error from malloc and flashing is aborted. No harm is done.

If increasing your malloc region breaks various load commands, then
harm is done.

Rob

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v4 4/5] usb/gadget: add the fastboot gadget
  2014-04-25 13:30           ` Rob Herring
@ 2014-04-28  7:00             ` Lukasz Majewski
  0 siblings, 0 replies; 59+ messages in thread
From: Lukasz Majewski @ 2014-04-28  7:00 UTC (permalink / raw)
  To: u-boot

Hi Rob,

> On Fri, Apr 25, 2014 at 12:26 AM, Lukasz Majewski
> <l.majewski@samsung.com> wrote:
> > Hi Rob,
> >
> >> On Wed, Apr 23, 2014 at 6:02 AM, Lukasz Majewski
> >> <l.majewski@samsung.com> wrote:
> >> > Hi Rob,
> >> >
> >> >> From: Sebastian Siewior <bigeasy@linutronix.de>
> >> >>
> >> >> This patch contains an implementation of the fastboot protocol
> >> >> on the device side and documentation. This is based on USB
> >> >> download gadget infrastructure. The fastboot function
> >> >> implements the getvar, reboot, download and reboot commands.
> >> >> What is missing is the flash handling i.e. writting the image
> >> >> to media.
> >> >>
> >>
> >> [...]
> 
> >> >         Please consider using dfu_get_buf() from dfu.c to provide
> >> >         dynamically allocated and controlled buffer instead of
> >> > the CONFIG_USB_FASTBOOT_BUF_ADDR and _SIZE.
> >> >
> >> >         Another advantage of this code is the ability to set
> >> >         "dfu_bufsiz" env variable with size of the buffer.
> >>
> >> I considered this already. I certainly don't like reinventing
> >> things which was why I originally used loadaddr and added loadsize
> >> to provide a defined load buffer size.
> >>
> >> The problem is fastboot needs enough RAM to download an entire
> >> sparse filesystem. I have no idea what size exactly is typical or
> >> required, but it seems that we want to be able to use nearly all
> >> free RAM. We can talk all we want about how this is a crappy
> >> design, but it is what it is. This is how the protocol works.
> >
> > I understand you :-). The same situation was with DFU on the
> > beginning. Large buffer with starting address defined per board.
> >
> > Then, after some discussion, we come to conclusion that it would be
> > better to increase malloc pool and dynamically allocate buffer.
> >
> > Am I correct, that you don't know beforehand what would be the size
> > of downloaded file - maybe 5 MiB or maybe 512 MiB? Also from your
> > descriptor it seems like fastboot protocol don't want to impose any
> > restrictions about the size. Is it user's responsibility to send
> > data smaller than RAM size?
> 
> Correct. The client side will check the size which is one of the
> variables. I searched around some to try to get an idea of what the
> typical buffer size is without much luck.

Ok, I see.

> 
> > In the DFU/THOR we store data in buffer size packets (32 MiB). It
> > also has some drawbacks - with large raw data images we cannot
> > download the whole (e.g. rootfs) image and beforehand flashing
> > check integrity.
> >
> > One question - when your board has e.g. 768 MiB of "available" RAM,
> > then is the size of large rootfs restricted to this size?
> 
> Yes, but that is not the size of the rootfs partition. The downloaded
> files are sparse. I would guess only the minimal filesystem is laid
> down this way and most optional pieces are installed later.

Or it is resized when needed.

> 
> >>
> >> The problem with the DFU buffer is it is allocated from the malloc
> >> region. If we just increase the malloc region to be close to total
> >> RAM size then we will start to break other commands like tftp and
> >> fsload which typically just use the RAM u-boot is not using (i.e.
> >> all but the end of memory). The only platforms which have more
> >> than a few MB for malloc are the ones that enable DFU.
> >
> > Correct. On the other hand when we want to allocate too large buffer
> > we receive error from malloc and flashing is aborted. No harm is
> > done.
> 
> If increasing your malloc region breaks various load commands, then
> harm is done.

To be more precise - in our boards we have at least 1 GiB of RAM. The
"large" malloc'ed buffer for DFU has 32 MiB at our boards. The total
pool size is 80 MiB, which is less than 10% of total RAM. Hence I
don't have problems similar to yours.

My little request - please make those defines to be easily reusable at
other boards.

> 
> Rob


-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v5 0/3] Android Fastboot support
  2014-04-18 13:54 ` [U-Boot] [PATCH v4 " Rob Herring
                     ` (5 preceding siblings ...)
  2014-04-18 16:14   ` [U-Boot] [PATCH v4 0/5] Android Fastboot support Wolfgang Denk
@ 2014-05-05 20:08   ` Rob Herring
  2014-05-05 20:08     ` [U-Boot] [PATCH v5 1/3] image: add support for Android's boot image format Rob Herring
                       ` (4 more replies)
  6 siblings, 5 replies; 59+ messages in thread
From: Rob Herring @ 2014-05-05 20:08 UTC (permalink / raw)
  To: u-boot

From: Rob Herring <robh@kernel.org>

This is the 3nd version since I revived the fastboot patches Sebastian 
submitted.

I'm reviving the Android Fastboot support after 2+ years since the last 
posting[1]. The previous postings had some questions about licensing 
and source of some code. I believe I've traced the history sufficiently 
that the copyrights and source information are complete and correct.

The Android code used or referenced is BSD 2-clause license. This was 
originally raised by Wolfgang that it was not compatible with GPLv2+. I 
believe that has since been demonstrated and agreed that the BSD 
2-clause license is compatible with u-boot. 

As far as the history of the code, I have traced that back. The u-boot 
code started in 2008/2009 by Tom Rix @ Windriver. This initial support 
was then adopted and extended by TI (eMMC support primarily, not 
included here) in their OMAP u-boot tree[2]. In 2011, the TI code was 
used as a basis for upstream patches by Sebastian Siewior @ Linutronix. 
The code has been rearranged quite a bit since the original, but the 
content is pretty much the same. Some of the re-arranging left stale or 
missing copyrights in the v2 version which I have corrected.

This version is rebased on u-boot usb tree with the recent USB 
downloader gadget registration changes. The primary change is 
documentation added to README for new config options.

I've tested this series on a BeagleBoard.

Rob

[1] http://lists.denx.de/pipermail/u-boot/2011-November/110557.html
[2] http://git.omapzoom.org/?p=repo/u-boot.git;a=commit;h=601ff71c8d46b5e90e13613974a16d10f2006bb3


Rob Herring (1):
  arm: beagle: enable Android fastboot support

Sebastian Siewior (2):
  image: add support for Android's boot image format
  usb/gadget: add the fastboot gadget

 README                               |  22 ++
 common/Makefile                      |   3 +
 common/cmd_bootm.c                   |  23 +-
 common/cmd_fastboot.c                |  36 +++
 common/image-android.c               |  84 ++++++
 common/image.c                       |  20 +-
 doc/README.android-fastboot          |  91 +++++++
 doc/README.android-fastboot-protocol | 170 ++++++++++++
 drivers/usb/gadget/Makefile          |   1 +
 drivers/usb/gadget/f_fastboot.c      | 513 +++++++++++++++++++++++++++++++++++
 include/android_image.h              |  69 +++++
 include/configs/omap3_beagle.h       |  10 +
 include/image.h                      |  13 +
 13 files changed, 1049 insertions(+), 6 deletions(-)
 create mode 100644 common/cmd_fastboot.c
 create mode 100644 common/image-android.c
 create mode 100644 doc/README.android-fastboot
 create mode 100644 doc/README.android-fastboot-protocol
 create mode 100644 drivers/usb/gadget/f_fastboot.c
 create mode 100644 include/android_image.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v5 1/3] image: add support for Android's boot image format
  2014-05-05 20:08   ` [U-Boot] [PATCH v5 0/3] " Rob Herring
@ 2014-05-05 20:08     ` Rob Herring
  2014-05-05 20:08     ` [U-Boot] [PATCH v5 2/3] usb/gadget: add the fastboot gadget Rob Herring
                       ` (3 subsequent siblings)
  4 siblings, 0 replies; 59+ messages in thread
From: Rob Herring @ 2014-05-05 20:08 UTC (permalink / raw)
  To: u-boot

From: Sebastian Siewior <bigeasy@linutronix.de>

This patch adds support for the Android boot-image format. The header
file is from the Android project and got slightly alterted so the struct +
its defines are not generic but have something like a namespace. The
header file is from bootloader/legacy/include/boot/bootimg.h. The header
parsing has been written from scratch and I looked at
bootloader/legacy/usbloader/usbloader.c for some details.
The image contains the physical address (load address) of the kernel and
ramdisk. This address is considered only for the kernel image.
The "second image" defined in the image header is currently not
supported. I haven't found anything that is creating this.

v3 (Rob Herring):
This is based on http://patchwork.ozlabs.org/patch/126797/ with the
following changes:
- Rebased to current mainline
- Moved android image handling to separate functions in
  common/image-android.c
- s/u8/char/ in header to fix string function warnings
- Use SPDX identifiers for licenses
- Cleaned-up file source information:
  android_image.h is from file include/boot/bootimg.h in repository:
  https://android.googlesource.com/platform/bootable/bootloader/legacy
  The git commit hash is 4205b865141ff2e255fe1d3bd16de18e217ef06a
  usbloader.c would be from the same commit, but it does not appear
  to have been used for any actual code.
v4:
- s/andriod/android/
- Use a separate flag ep_found to track if the entry point has been set
rather than using a magic value.

Cc: Wolfgang Denk <wd@denx.de>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Rob Herring <robh@kernel.org>
Reviewed-by: Tom Rini <trini@ti.com>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>
---
 common/Makefile         |  1 +
 common/cmd_bootm.c      | 23 +++++++++++++-
 common/image-android.c  | 84 +++++++++++++++++++++++++++++++++++++++++++++++++
 common/image.c          | 20 +++++++++---
 include/android_image.h | 69 ++++++++++++++++++++++++++++++++++++++++
 include/image.h         | 13 ++++++++
 6 files changed, 204 insertions(+), 6 deletions(-)
 create mode 100644 common/image-android.c
 create mode 100644 include/android_image.h

diff --git a/common/Makefile b/common/Makefile
index 7c853ae..bfcb466 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -237,6 +237,7 @@ obj-y += console.o
 obj-$(CONFIG_CROS_EC) += cros_ec.o
 obj-y += dlmalloc.o
 obj-y += image.o
+obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
 obj-$(CONFIG_OF_LIBFDT) += image-fdt.o
 obj-$(CONFIG_FIT) += image-fit.o
 obj-$(CONFIG_FIT_SIGNATURE) += image-sig.o
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index c243a5b..993b906 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -222,6 +222,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
 			 char * const argv[])
 {
 	const void *os_hdr;
+	bool ep_found = false;
 
 	/* get kernel image header, start address and length */
 	os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
@@ -274,6 +275,18 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
 		}
 		break;
 #endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	case IMAGE_FORMAT_ANDROID:
+		images.os.type = IH_TYPE_KERNEL;
+		images.os.comp = IH_COMP_NONE;
+		images.os.os = IH_OS_LINUX;
+		images.ep = images.os.load;
+		ep_found = true;
+
+		images.os.end = android_image_get_end(os_hdr);
+		images.os.load = android_image_get_kload(os_hdr);
+		break;
+#endif
 	default:
 		puts("ERROR: unknown image format type!\n");
 		return 1;
@@ -293,7 +306,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
 			return 1;
 		}
 #endif
-	} else {
+	} else if (!ep_found) {
 		puts("Could not find kernel entry point!\n");
 		return 1;
 	}
@@ -1002,6 +1015,14 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,
 		images->fit_noffset_os = os_noffset;
 		break;
 #endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	case IMAGE_FORMAT_ANDROID:
+		printf("## Booting Android Image at 0x%08lx ...\n", img_addr);
+		if (android_image_get_kernel((void *)img_addr, images->verify,
+					     os_data, os_len))
+			return NULL;
+		break;
+#endif
 	default:
 		printf("Wrong Image Format for %s command\n", cmdtp->name);
 		bootstage_error(BOOTSTAGE_ID_FIT_KERNEL_INFO);
diff --git a/common/image-android.c b/common/image-android.c
new file mode 100644
index 0000000..6ded7e2
--- /dev/null
+++ b/common/image-android.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <image.h>
+#include <android_image.h>
+
+static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
+
+int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
+			     ulong *os_data, ulong *os_len)
+{
+	/*
+	 * Not all Android tools use the id field for signing the image with
+	 * sha1 (or anything) so we don't check it. It is not obvious that the
+	 * string is null terminated so we take care of this.
+	 */
+	strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE);
+	andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0';
+	if (strlen(andr_tmp_str))
+		printf("Android's image name: %s\n", andr_tmp_str);
+
+	printf("Kernel load addr 0x%08x size %u KiB\n",
+	       hdr->kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024));
+	strncpy(andr_tmp_str, hdr->cmdline, ANDR_BOOT_ARGS_SIZE);
+	andr_tmp_str[ANDR_BOOT_ARGS_SIZE] = '\0';
+	if (strlen(andr_tmp_str)) {
+		printf("Kernel command line: %s\n", andr_tmp_str);
+		setenv("bootargs", andr_tmp_str);
+	}
+	if (hdr->ramdisk_size)
+		printf("RAM disk load addr 0x%08x size %u KiB\n",
+		       hdr->ramdisk_addr,
+		       DIV_ROUND_UP(hdr->ramdisk_size, 1024));
+
+	if (os_data) {
+		*os_data = (ulong)hdr;
+		*os_data += hdr->page_size;
+	}
+	if (os_len)
+		*os_len = hdr->kernel_size;
+	return 0;
+}
+
+int android_image_check_header(const struct andr_img_hdr *hdr)
+{
+	return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE);
+}
+
+ulong android_image_get_end(const struct andr_img_hdr *hdr)
+{
+	u32 size = 0;
+	/*
+	 * The header takes a full page, the remaining components are aligned
+	 * on page boundary
+	 */
+	size += hdr->page_size;
+	size += ALIGN(hdr->kernel_size, hdr->page_size);
+	size += ALIGN(hdr->ramdisk_size, hdr->page_size);
+	size += ALIGN(hdr->second_size, hdr->page_size);
+
+	return size;
+}
+
+ulong android_image_get_kload(const struct andr_img_hdr *hdr)
+{
+	return hdr->kernel_addr;
+}
+
+int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
+			      ulong *rd_data, ulong *rd_len)
+{
+	if (!hdr->ramdisk_size)
+		return -1;
+	*rd_data = (unsigned long)hdr;
+	*rd_data += hdr->page_size;
+	*rd_data += ALIGN(hdr->kernel_size, hdr->page_size);
+
+	*rd_len = hdr->ramdisk_size;
+	return 0;
+}
diff --git a/common/image.c b/common/image.c
index 9c6bec5..7ff27d7 100644
--- a/common/image.c
+++ b/common/image.c
@@ -659,10 +659,12 @@ int genimg_get_format(const void *img_addr)
 	if (image_check_magic(hdr))
 		format = IMAGE_FORMAT_LEGACY;
 #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
-	else {
-		if (fdt_check_header(img_addr) == 0)
-			format = IMAGE_FORMAT_FIT;
-	}
+	else if (fdt_check_header(img_addr) == 0)
+		format = IMAGE_FORMAT_FIT;
+#endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	else if (android_image_check_header(img_addr) == 0)
+		format = IMAGE_FORMAT_ANDROID;
 #endif
 
 	return format;
@@ -932,7 +934,15 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
 				(ulong)images->legacy_hdr_os);
 
 		image_multi_getimg(images->legacy_hdr_os, 1, &rd_data, &rd_len);
-	} else {
+	}
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	else if ((genimg_get_format(images) == IMAGE_FORMAT_ANDROID) &&
+		 (!android_image_get_ramdisk((void *)images->os.start,
+		 &rd_data, &rd_len))) {
+		/* empty */
+	}
+#endif
+	else {
 		/*
 		 * no initrd image
 		 */
diff --git a/include/android_image.h b/include/android_image.h
new file mode 100644
index 0000000..094d60a
--- /dev/null
+++ b/include/android_image.h
@@ -0,0 +1,69 @@
+/*
+ * This is from the Android Project,
+ * Repository: https://android.googlesource.com/platform/bootable/bootloader/legacy
+ * File: include/boot/bootimg.h
+ * Commit: 4205b865141ff2e255fe1d3bd16de18e217ef06a
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _ANDROID_IMAGE_H_
+#define _ANDROID_IMAGE_H_
+
+#define ANDR_BOOT_MAGIC "ANDROID!"
+#define ANDR_BOOT_MAGIC_SIZE 8
+#define ANDR_BOOT_NAME_SIZE 16
+#define ANDR_BOOT_ARGS_SIZE 512
+
+struct andr_img_hdr {
+	char magic[ANDR_BOOT_MAGIC_SIZE];
+
+	u32 kernel_size;	/* size in bytes */
+	u32 kernel_addr;	/* physical load addr */
+
+	u32 ramdisk_size;	/* size in bytes */
+	u32 ramdisk_addr;	/* physical load addr */
+
+	u32 second_size;	/* size in bytes */
+	u32 second_addr;	/* physical load addr */
+
+	u32 tags_addr;		/* physical addr for kernel tags */
+	u32 page_size;		/* flash page size we assume */
+	u32 unused[2];		/* future expansion: should be 0 */
+
+	char name[ANDR_BOOT_NAME_SIZE]; /* asciiz product name */
+
+	char cmdline[ANDR_BOOT_ARGS_SIZE];
+
+	u32 id[8]; /* timestamp / checksum / sha1 / etc */
+};
+
+/*
+ * +-----------------+
+ * | boot header     | 1 page
+ * +-----------------+
+ * | kernel          | n pages
+ * +-----------------+
+ * | ramdisk         | m pages
+ * +-----------------+
+ * | second stage    | o pages
+ * +-----------------+
+ *
+ * n = (kernel_size + page_size - 1) / page_size
+ * m = (ramdisk_size + page_size - 1) / page_size
+ * o = (second_size + page_size - 1) / page_size
+ *
+ * 0. all entities are page_size aligned in flash
+ * 1. kernel and ramdisk are required (size != 0)
+ * 2. second is optional (second_size == 0 -> no second)
+ * 3. load each element (kernel, ramdisk, second) at
+ *    the specified physical address (kernel_addr, etc)
+ * 4. prepare tags at tag_addr.  kernel_args[] is
+ *    appended to the kernel commandline in the tags.
+ * 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
+ * 6. if second_size != 0: jump to second_addr
+ *    else: jump to kernel_addr
+ */
+#endif
diff --git a/include/image.h b/include/image.h
index 2508d7d..e1f9297 100644
--- a/include/image.h
+++ b/include/image.h
@@ -412,6 +412,7 @@ enum fit_load_op {
 #define IMAGE_FORMAT_INVALID	0x00
 #define IMAGE_FORMAT_LEGACY	0x01	/* legacy image_header based format */
 #define IMAGE_FORMAT_FIT	0x02	/* new, libfdt based format */
+#define IMAGE_FORMAT_ANDROID	0x03	/* Android boot image */
 
 int genimg_get_format(const void *img_addr);
 int genimg_has_config(bootm_headers_t *images);
@@ -1030,4 +1031,16 @@ static inline int fit_image_check_target_arch(const void *fdt, int node)
 #endif /* CONFIG_FIT_VERBOSE */
 #endif /* CONFIG_FIT */
 
+#if defined(CONFIG_ANDROID_BOOT_IMAGE)
+struct andr_img_hdr;
+int android_image_check_header(const struct andr_img_hdr *hdr);
+int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
+			     ulong *os_data, ulong *os_len);
+int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
+			      ulong *rd_data, ulong *rd_len);
+ulong android_image_get_end(const struct andr_img_hdr *hdr);
+ulong android_image_get_kload(const struct andr_img_hdr *hdr);
+
+#endif /* CONFIG_ANDROID_BOOT_IMAGE */
+
 #endif	/* __IMAGE_H__ */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v5 2/3] usb/gadget: add the fastboot gadget
  2014-05-05 20:08   ` [U-Boot] [PATCH v5 0/3] " Rob Herring
  2014-05-05 20:08     ` [U-Boot] [PATCH v5 1/3] image: add support for Android's boot image format Rob Herring
@ 2014-05-05 20:08     ` Rob Herring
  2014-05-05 20:08     ` [U-Boot] [PATCH v5 3/3] arm: beagle: enable Android fastboot support Rob Herring
                       ` (2 subsequent siblings)
  4 siblings, 0 replies; 59+ messages in thread
From: Rob Herring @ 2014-05-05 20:08 UTC (permalink / raw)
  To: u-boot

From: Sebastian Siewior <bigeasy@linutronix.de>

This patch contains an implementation of the fastboot protocol on the
device side and documentation. This is based on USB download gadget
infrastructure. The fastboot function implements the getvar, reboot,
download and reboot commands. What is missing is the flash handling i.e.
writting the image to media.

v3 (Rob Herring):
This is based on http://patchwork.ozlabs.org/patch/126798/ with the
following changes:
- Rebase to current mainline and updates for current gadget API
- Use SPDX identifiers for licenses
- Traced the history and added missing copyright to cmd_fastboot.c
- Use load_addr/load_size for transfer buffer
- Allow vendor strings to be optional
- Set vendor/product ID from config defines
- Allow Ctrl-C to exit fastboot mode
v4:
- Major re-write to use the USB download gadget. Consolidated function
code to a single file.
- Moved globals into single struct.
- Use puts and putc as appropriate.
- Added CONFIG_USB_FASTBOOT_BUF_ADDR and CONFIG_USB_FASTBOOT_BUF_SIZE to
set the fastboot transfer buffer.
v5:
- Add CONFIG option documentation to README
- Rebase using new downloader registration

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Rob Herring <robh@kernel.org>
---
 README                               |  22 ++
 common/Makefile                      |   2 +
 common/cmd_fastboot.c                |  36 +++
 doc/README.android-fastboot          |  91 +++++++
 doc/README.android-fastboot-protocol | 170 ++++++++++++
 drivers/usb/gadget/Makefile          |   1 +
 drivers/usb/gadget/f_fastboot.c      | 513 +++++++++++++++++++++++++++++++++++
 7 files changed, 835 insertions(+)
 create mode 100644 common/cmd_fastboot.c
 create mode 100644 doc/README.android-fastboot
 create mode 100644 doc/README.android-fastboot-protocol
 create mode 100644 drivers/usb/gadget/f_fastboot.c

diff --git a/README b/README
index b973344..8114f79 100644
--- a/README
+++ b/README
@@ -1558,6 +1558,28 @@ The following options need to be configured:
 		entering dfuMANIFEST state. Host waits this timeout, before
 		sending again an USB request to the device.
 
+- USB Device Android Fastboot support:
+		CONFIG_CMD_FASTBOOT
+		This enables the command "fastboot" which enables the Android
+		fastboot mode for the platform's USB device. Fastboot is a USB
+		protocol for downloading images, flashing and device control
+		used on Android devices.
+		See doc/README.android-fastboot for more information.
+
+		CONFIG_ANDROID_BOOT_IMAGE
+		This enables support for booting images which use the Android
+		image format header.
+
+		CONFIG_USB_FASTBOOT_BUF_ADDR
+		The fastboot protocol requires a large memory buffer for
+		downloads. Define this to the starting RAM address to use for
+		downloaded images.
+
+		CONFIG_USB_FASTBOOT_BUF_SIZE
+		The fastboot protocol requires a large memory buffer for
+		downloads. This buffer should be as large as possible for a
+		platform. Define this to the size available RAM for fastboot.
+
 - Journaling Flash filesystem support:
 		CONFIG_JFFS2_NAND, CONFIG_JFFS2_NAND_OFF, CONFIG_JFFS2_NAND_SIZE,
 		CONFIG_JFFS2_NAND_DEV
diff --git a/common/Makefile b/common/Makefile
index bfcb466..219cb51 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -168,6 +168,8 @@ obj-y += cmd_usb.o
 obj-y += usb.o usb_hub.o
 obj-$(CONFIG_USB_STORAGE) += usb_storage.o
 endif
+obj-$(CONFIG_CMD_FASTBOOT) += cmd_fastboot.o
+
 obj-$(CONFIG_CMD_USB_MASS_STORAGE) += cmd_usb_mass_storage.o
 obj-$(CONFIG_CMD_THOR_DOWNLOAD) += cmd_thordown.o
 obj-$(CONFIG_CMD_XIMG) += cmd_ximg.o
diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
new file mode 100644
index 0000000..83fa7bd
--- /dev/null
+++ b/common/cmd_fastboot.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 - 2009 Windriver, <www.windriver.com>
+ * Author: Tom Rix <Tom.Rix@windriver.com>
+ *
+ * (C) Copyright 2014 Linaro, Ltd.
+ * Rob Herring <robh@kernel.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <command.h>
+#include <g_dnl.h>
+
+static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	int ret;
+
+	ret = g_dnl_register("usb_dnl_fastboot");
+	if (ret)
+		return ret;
+
+	while (1) {
+		if (ctrlc())
+			break;
+		usb_gadget_handle_interrupts();
+	}
+
+	g_dnl_unregister();
+	return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+	fastboot,	1,	1,	do_fastboot,
+	"fastboot - enter USB Fastboot protocol",
+	""
+);
diff --git a/doc/README.android-fastboot b/doc/README.android-fastboot
new file mode 100644
index 0000000..f1d128c
--- /dev/null
+++ b/doc/README.android-fastboot
@@ -0,0 +1,91 @@
+Android Fastboot
+~~~~~~~~~~~~~~~~
+
+Overview
+========
+The protocol that is used over USB is described in
+README.android-fastboot-protocol in same directory.
+
+The current implementation does not yet support the flash and erase
+commands.
+
+Client installation
+===================
+The counterpart to this gadget is the fastboot client which can
+be found in Android's platform/system/core repository in the fastboot
+folder. It runs on Windows, Linux and even OSX. Linux user are lucky since
+they only need libusb.
+Windows users need to bring some time until they have Android SDK (currently
+http://dl.google.com/android/installer_r12-windows.exe) installed. You
+need to install ADB package which contains the required glue libraries for
+accessing USB. Also you need "Google USB driver package" and "SDK platform
+tools". Once installed the usb driver is placed in your SDK folder under
+extras\google\usb_driver. The android_winusb.inf needs a line like
+
+   %SingleBootLoaderInterface% = USB_Install, USB\VID_0451&PID_D022
+
+either in the [Google.NTx86] section for 32bit Windows or [Google.NTamd64]
+for 64bit Windows. VID and PID should match whatever the fastboot is
+advertising.
+
+Board specific
+==============
+The fastboot gadget relies on the USB download gadget, so the following
+options must be configured:
+
+CONFIG_USBDOWNLOAD_GADGET
+CONFIG_G_DNL_VENDOR_NUM
+CONFIG_G_DNL_PRODUCT_NUM
+CONFIG_G_DNL_MANUFACTURER
+
+The fastboot function is enabled by defining CONFIG_CMD_FASTBOOT and
+CONFIG_ANDROID_BOOT_IMAGE.
+
+The fastboot protocol requires a large memory buffer for downloads. This
+buffer should be as large as possible for a platform. The location of the
+buffer and size are set with CONFIG_USB_FASTBOOT_BUF_ADDR and
+CONFIG_USB_FASTBOOT_BUF_SIZE.
+
+In Action
+=========
+Enter into fastboot by executing the fastboot command in u-boot and you
+should see:
+|GADGET DRIVER: usb_dnl_fastboot
+
+On the client side you can fetch the bootloader version for instance:
+|>fastboot getvar bootloader-version
+|bootloader-version: U-Boot 2014.04-00005-gd24cabc
+|finished. total time: 0.000s
+
+or initiate a reboot:
+|>fastboot reboot
+
+and once the client comes back, the board should reset.
+
+You can also specify a kernel image to boot. You have to either specify
+the an image in Android format _or_ pass a binary kernel and let the
+fastboot client wrap the Android suite around it. On OMAP for instance you
+take zImage kernel and pass it to the fastboot client:
+
+|>fastboot -b 0x80000000 -c "console=ttyO2 earlyprintk root=/dev/ram0
+|	mem=128M" boot zImage
+|creating boot image...
+|creating boot image - 1847296 bytes
+|downloading 'boot.img'...
+|OKAY [  2.766s]
+|booting...
+|OKAY [ -0.000s]
+|finished. total time: 2.766s
+
+and on the gadget side you should see:
+|Starting download of 1847296 bytes
+|........................................................
+|downloading of 1847296 bytes finished
+|Booting kernel..
+|## Booting Android Image at 0x81000000 ...
+|Kernel load addr 0x80008000 size 1801 KiB
+|Kernel command line: console=ttyO2 earlyprintk root=/dev/ram0 mem=128M
+|   Loading Kernel Image ... OK
+|OK
+|
+|Starting kernel ...
diff --git a/doc/README.android-fastboot-protocol b/doc/README.android-fastboot-protocol
new file mode 100644
index 0000000..e9e7166
--- /dev/null
+++ b/doc/README.android-fastboot-protocol
@@ -0,0 +1,170 @@
+FastBoot  Version  0.4
+----------------------
+
+The fastboot protocol is a mechanism for communicating with bootloaders
+over USB.  It is designed to be very straightforward to implement, to
+allow it to be used across a wide range of devices and from hosts running
+Linux, Windows, or OSX.
+
+
+Basic Requirements
+------------------
+
+* Two bulk endpoints (in, out) are required
+* Max packet size must be 64 bytes for full-speed and 512 bytes for
+  high-speed USB
+* The protocol is entirely host-driven and synchronous (unlike the
+  multi-channel, bi-directional, asynchronous ADB protocol)
+
+
+Transport and Framing
+---------------------
+
+1. Host sends a command, which is an ascii string in a single
+   packet no greater than 64 bytes.
+
+2. Client response with a single packet no greater than 64 bytes.
+   The first four bytes of the response are "OKAY", "FAIL", "DATA",
+   or "INFO".  Additional bytes may contain an (ascii) informative
+   message.
+
+   a. INFO -> the remaining 60 bytes are an informative message
+      (providing progress or diagnostic messages).  They should
+      be displayed and then step #2 repeats
+
+   b. FAIL -> the requested command failed.  The remaining 60 bytes
+      of the response (if present) provide a textual failure message
+      to present to the user.  Stop.
+
+   c. OKAY -> the requested command completed successfully.  Go to #5
+
+   d. DATA -> the requested command is ready for the data phase.
+      A DATA response packet will be 12 bytes long, in the form of
+      DATA00000000 where the 8 digit hexidecimal number represents
+      the total data size to transfer.
+
+3. Data phase.  Depending on the command, the host or client will
+   send the indicated amount of data.  Short packets are always
+   acceptable and zero-length packets are ignored.  This phase continues
+   until the client has sent or received the number of bytes indicated
+   in the "DATA" response above.
+
+4. Client responds with a single packet no greater than 64 bytes.
+   The first four bytes of the response are "OKAY", "FAIL", or "INFO".
+   Similar to #2:
+
+   a. INFO -> display the remaining 60 bytes and return to #4
+
+   b. FAIL -> display the remaining 60 bytes (if present) as a failure
+      reason and consider the command failed.  Stop.
+
+   c. OKAY -> success.  Go to #5
+
+5. Success.  Stop.
+
+
+Example Session
+---------------
+
+Host:    "getvar:version"        request version variable
+
+Client:  "OKAY0.4"               return version "0.4"
+
+Host:    "getvar:nonexistant"    request some undefined variable
+
+Client:  "OKAY"                  return value ""
+
+Host:    "download:00001234"     request to send 0x1234 bytes of data
+
+Client:  "DATA00001234"          ready to accept data
+
+Host:    < 0x1234 bytes >        send data
+
+Client:  "OKAY"                  success
+
+Host:    "flash:bootloader"      request to flash the data to the bootloader
+
+Client:  "INFOerasing flash"     indicate status / progress
+         "INFOwriting flash"
+         "OKAY"                  indicate success
+
+Host:    "powerdown"             send a command
+
+Client:  "FAILunknown command"   indicate failure
+
+
+Command Reference
+-----------------
+
+* Command parameters are indicated by printf-style escape sequences.
+
+* Commands are ascii strings and sent without the quotes (which are
+  for illustration only here) and without a trailing 0 byte.
+
+* Commands that begin with a lowercase letter are reserved for this
+  specification.  OEM-specific commands should not begin with a
+  lowercase letter, to prevent incompatibilities with future specs.
+
+ "getvar:%s"           Read a config/version variable from the bootloader.
+                       The variable contents will be returned after the
+                       OKAY response.
+
+ "download:%08x"       Write data to memory which will be later used
+                       by "boot", "ramdisk", "flash", etc.  The client
+                       will reply with "DATA%08x" if it has enough
+                       space in RAM or "FAIL" if not.  The size of
+                       the download is remembered.
+
+  "verify:%08x"        Send a digital signature to verify the downloaded
+                       data.  Required if the bootloader is "secure"
+                       otherwise "flash" and "boot" will be ignored.
+
+  "flash:%s"           Write the previously downloaded image to the
+                       named partition (if possible).
+
+  "erase:%s"           Erase the indicated partition (clear to 0xFFs)
+
+  "boot"               The previously downloaded data is a boot.img
+                       and should be booted according to the normal
+                       procedure for a boot.img
+
+  "continue"           Continue booting as normal (if possible)
+
+  "reboot"             Reboot the device.
+
+  "reboot-bootloader"  Reboot back into the bootloader.
+                       Useful for upgrade processes that require upgrading
+                       the bootloader and then upgrading other partitions
+                       using the new bootloader.
+
+  "powerdown"          Power off the device.
+
+
+
+Client Variables
+----------------
+
+The "getvar:%s" command is used to read client variables which
+represent various information about the device and the software
+on it.
+
+The various currently defined names are:
+
+  version             Version of FastBoot protocol supported.
+                      It should be "0.3" for this document.
+
+  version-bootloader  Version string for the Bootloader.
+
+  version-baseband    Version string of the Baseband Software
+
+  product             Name of the product
+
+  serialno            Product serial number
+
+  secure              If the value is "yes", this is a secure
+                      bootloader requiring a signature before
+                      it will install or boot images.
+
+Names starting with a lowercase character are reserved by this
+specification.  OEM-specific names should not start with lowercase
+characters.
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 896c8d4..66becdc 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_THOR_FUNCTION) += f_thor.o
 obj-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
 obj-$(CONFIG_DFU_FUNCTION) += f_dfu.o
 obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o
+obj-$(CONFIG_CMD_FASTBOOT) += f_fastboot.o
 endif
 ifdef CONFIG_USB_ETHER
 obj-y += ether.o
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
new file mode 100644
index 0000000..9dd85b6
--- /dev/null
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -0,0 +1,513 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Copyright 2014 Linaro, Ltd.
+ * Rob Herring <robh@kernel.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+#include <linux/compiler.h>
+#include <version.h>
+#include <g_dnl.h>
+
+#define FASTBOOT_VERSION		"0.4"
+
+#define FASTBOOT_INTERFACE_CLASS	0xff
+#define FASTBOOT_INTERFACE_SUB_CLASS	0x42
+#define FASTBOOT_INTERFACE_PROTOCOL	0x03
+
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0  (0x0200)
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1  (0x0040)
+#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE      (0x0040)
+
+/* The 64 defined bytes plus \0 */
+#define RESPONSE_LEN	(64 + 1)
+
+#define EP_BUFFER_SIZE			4096
+
+struct f_fastboot {
+	struct usb_function usb_function;
+
+	/* IN/OUT EP's and correspoinding requests */
+	struct usb_ep *in_ep, *out_ep;
+	struct usb_request *in_req, *out_req;
+};
+
+static inline struct f_fastboot *func_to_fastboot(struct usb_function *f)
+{
+	return container_of(f, struct f_fastboot, usb_function);
+}
+
+static struct f_fastboot *fastboot_func;
+static unsigned int download_size;
+static unsigned int download_bytes;
+
+static struct usb_endpoint_descriptor fs_ep_in = {
+	.bLength            = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType    = USB_DT_ENDPOINT,
+	.bEndpointAddress   = USB_DIR_IN,
+	.bmAttributes       = USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize     = TX_ENDPOINT_MAXIMUM_PACKET_SIZE,
+	.bInterval          = 0x00,
+};
+
+static struct usb_endpoint_descriptor fs_ep_out = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1,
+	.bInterval		= 0x00,
+};
+
+static struct usb_endpoint_descriptor hs_ep_out = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0,
+	.bInterval		= 0x00,
+};
+
+static struct usb_interface_descriptor interface_desc = {
+	.bLength		= USB_DT_INTERFACE_SIZE,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	.bInterfaceNumber	= 0x00,
+	.bAlternateSetting	= 0x00,
+	.bNumEndpoints		= 0x02,
+	.bInterfaceClass	= FASTBOOT_INTERFACE_CLASS,
+	.bInterfaceSubClass	= FASTBOOT_INTERFACE_SUB_CLASS,
+	.bInterfaceProtocol	= FASTBOOT_INTERFACE_PROTOCOL,
+};
+
+static struct usb_descriptor_header *fb_runtime_descs[] = {
+	(struct usb_descriptor_header *)&interface_desc,
+	(struct usb_descriptor_header *)&fs_ep_in,
+	(struct usb_descriptor_header *)&hs_ep_out,
+	NULL,
+};
+
+/*
+ * static strings, in UTF-8
+ */
+static const char fastboot_name[] = "Android Fastboot";
+
+static struct usb_string fastboot_string_defs[] = {
+	[0].s = fastboot_name,
+	{  }			/* end of list */
+};
+
+static struct usb_gadget_strings stringtab_fastboot = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= fastboot_string_defs,
+};
+
+static struct usb_gadget_strings *fastboot_strings[] = {
+	&stringtab_fastboot,
+	NULL,
+};
+
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+
+static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	int status = req->status;
+	if (!status)
+		return;
+	printf("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
+}
+
+static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	int id;
+	struct usb_gadget *gadget = c->cdev->gadget;
+	struct f_fastboot *f_fb = func_to_fastboot(f);
+
+	/* DYNAMIC interface numbers assignments */
+	id = usb_interface_id(c, f);
+	if (id < 0)
+		return id;
+	interface_desc.bInterfaceNumber = id;
+
+	id = usb_string_id(c->cdev);
+	if (id < 0)
+		return id;
+	fastboot_string_defs[0].id = id;
+	interface_desc.iInterface = id;
+
+	f_fb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
+	if (!f_fb->in_ep)
+		return -ENODEV;
+	f_fb->in_ep->driver_data = c->cdev;
+
+	f_fb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
+	if (!f_fb->out_ep)
+		return -ENODEV;
+	f_fb->out_ep->driver_data = c->cdev;
+
+	hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
+
+	return 0;
+}
+
+static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	memset(fastboot_func, 0, sizeof(*fastboot_func));
+}
+
+static void fastboot_disable(struct usb_function *f)
+{
+	struct f_fastboot *f_fb = func_to_fastboot(f);
+
+	usb_ep_disable(f_fb->out_ep);
+	usb_ep_disable(f_fb->in_ep);
+
+	if (f_fb->out_req) {
+		free(f_fb->out_req->buf);
+		usb_ep_free_request(f_fb->out_ep, f_fb->out_req);
+		f_fb->out_req = NULL;
+	}
+	if (f_fb->in_req) {
+		free(f_fb->in_req->buf);
+		usb_ep_free_request(f_fb->in_ep, f_fb->in_req);
+		f_fb->in_req = NULL;
+	}
+}
+
+static struct usb_request *fastboot_start_ep(struct usb_ep *ep)
+{
+	struct usb_request *req;
+
+	req = usb_ep_alloc_request(ep, 0);
+	if (!req)
+		return NULL;
+
+	req->length = EP_BUFFER_SIZE;
+	req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE);
+	if (!req->buf) {
+		usb_ep_free_request(ep, req);
+		return NULL;
+	}
+
+	memset(req->buf, 0, req->length);
+	return req;
+}
+
+static int fastboot_set_alt(struct usb_function *f,
+			    unsigned interface, unsigned alt)
+{
+	int ret;
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_gadget *gadget = cdev->gadget;
+	struct f_fastboot *f_fb = func_to_fastboot(f);
+
+	debug("%s: func: %s intf: %d alt: %d\n",
+	      __func__, f->name, interface, alt);
+
+	/* make sure we don't enable the ep twice */
+	if (gadget->speed == USB_SPEED_HIGH)
+		ret = usb_ep_enable(f_fb->out_ep, &hs_ep_out);
+	else
+		ret = usb_ep_enable(f_fb->out_ep, &fs_ep_out);
+	if (ret) {
+		puts("failed to enable out ep\n");
+		return ret;
+	}
+
+	f_fb->out_req = fastboot_start_ep(f_fb->out_ep);
+	if (!f_fb->out_req) {
+		puts("failed to alloc out req\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	f_fb->out_req->complete = rx_handler_command;
+
+	ret = usb_ep_enable(f_fb->in_ep, &fs_ep_in);
+	if (ret) {
+		puts("failed to enable in ep\n");
+		goto err;
+	}
+
+	f_fb->in_req = fastboot_start_ep(f_fb->in_ep);
+	if (!f_fb->in_req) {
+		puts("failed alloc req in\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	f_fb->in_req->complete = fastboot_complete;
+
+	ret = usb_ep_queue(f_fb->out_ep, f_fb->out_req, 0);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	fastboot_disable(f);
+	return ret;
+}
+
+static int fastboot_add(struct usb_configuration *c)
+{
+	struct f_fastboot *f_fb = fastboot_func;
+	int status;
+
+	debug("%s: cdev: 0x%p\n", __func__, c->cdev);
+
+	if (!f_fb) {
+		f_fb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_fb));
+		if (!f_fb)
+			return -ENOMEM;
+
+		fastboot_func = f_fb;
+		memset(f_fb, 0, sizeof(*f_fb));
+	}
+
+	f_fb->usb_function.name = "f_fastboot";
+	f_fb->usb_function.hs_descriptors = fb_runtime_descs;
+	f_fb->usb_function.bind = fastboot_bind;
+	f_fb->usb_function.unbind = fastboot_unbind;
+	f_fb->usb_function.set_alt = fastboot_set_alt;
+	f_fb->usb_function.disable = fastboot_disable;
+	f_fb->usb_function.strings = fastboot_strings;
+
+	status = usb_add_function(c, &f_fb->usb_function);
+	if (status) {
+		free(f_fb);
+		fastboot_func = f_fb;
+	}
+
+	return status;
+}
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add);
+
+int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
+{
+	struct usb_request *in_req = fastboot_func->in_req;
+	int ret;
+
+	memcpy(in_req->buf, buffer, buffer_size);
+	in_req->length = buffer_size;
+	ret = usb_ep_queue(fastboot_func->in_ep, in_req, 0);
+	if (ret)
+		printf("Error %d on queue\n", ret);
+	return 0;
+}
+
+static int fastboot_tx_write_str(const char *buffer)
+{
+	return fastboot_tx_write(buffer, strlen(buffer));
+}
+
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
+{
+	do_reset(NULL, 0, 0, NULL);
+}
+
+static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
+{
+	fastboot_func->in_req->complete = compl_do_reset;
+	fastboot_tx_write_str("OKAY");
+}
+
+static int strcmp_l1(const char *s1, const char *s2)
+{
+	if (!s1 || !s2)
+		return -1;
+	return strncmp(s1, s2, strlen(s1));
+}
+
+static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmd = req->buf;
+	char response[RESPONSE_LEN];
+	const char *s;
+
+	strcpy(response, "OKAY");
+	strsep(&cmd, ":");
+	if (!cmd) {
+		fastboot_tx_write_str("FAILmissing var");
+		return;
+	}
+
+	if (!strcmp_l1("version", cmd)) {
+		strncat(response, FASTBOOT_VERSION, sizeof(response));
+	} else if (!strcmp_l1("bootloader-version", cmd)) {
+		strncat(response, U_BOOT_VERSION, sizeof(response));
+	} else if (!strcmp_l1("downloadsize", cmd)) {
+		char str_num[12];
+
+		sprintf(str_num, "%08x", CONFIG_USB_FASTBOOT_BUF_SIZE);
+		strncat(response, str_num, sizeof(response));
+	} else if (!strcmp_l1("serialno", cmd)) {
+		s = getenv("serial#");
+		if (s)
+			strncat(response, s, sizeof(response));
+		else
+			strcpy(response, "FAILValue not set");
+	} else {
+		strcpy(response, "FAILVariable not implemented");
+	}
+	fastboot_tx_write_str(response);
+}
+
+static unsigned int rx_bytes_expected(void)
+{
+	int rx_remain = download_size - download_bytes;
+	if (rx_remain < 0)
+		return 0;
+	if (rx_remain > EP_BUFFER_SIZE)
+		return EP_BUFFER_SIZE;
+	return rx_remain;
+}
+
+#define BYTES_PER_DOT	0x20000
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
+{
+	char response[RESPONSE_LEN];
+	unsigned int transfer_size = download_size - download_bytes;
+	const unsigned char *buffer = req->buf;
+	unsigned int buffer_size = req->actual;
+
+	if (req->status != 0) {
+		printf("Bad status: %d\n", req->status);
+		return;
+	}
+
+	if (buffer_size < transfer_size)
+		transfer_size = buffer_size;
+
+	memcpy((void *)CONFIG_USB_FASTBOOT_BUF_ADDR + download_bytes,
+	       buffer, transfer_size);
+
+	download_bytes += transfer_size;
+
+	/* Check if transfer is done */
+	if (download_bytes >= download_size) {
+		/*
+		 * Reset global transfer variable, keep download_bytes because
+		 * it will be used in the next possible flashing command
+		 */
+		download_size = 0;
+		req->complete = rx_handler_command;
+		req->length = EP_BUFFER_SIZE;
+
+		sprintf(response, "OKAY");
+		fastboot_tx_write_str(response);
+
+		printf("\ndownloading of %d bytes finished\n", download_bytes);
+	} else {
+		req->length = rx_bytes_expected();
+		if (req->length < ep->maxpacket)
+			req->length = ep->maxpacket;
+	}
+
+	if (download_bytes && !(download_bytes % BYTES_PER_DOT)) {
+		putc('.');
+		if (!(download_bytes % (74 * BYTES_PER_DOT)))
+			putc('\n');
+	}
+	req->actual = 0;
+	usb_ep_queue(ep, req, 0);
+}
+
+static void cb_download(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmd = req->buf;
+	char response[RESPONSE_LEN];
+
+	strsep(&cmd, ":");
+	download_size = simple_strtoul(cmd, NULL, 16);
+	download_bytes = 0;
+
+	printf("Starting download of %d bytes\n", download_size);
+
+	if (0 == download_size) {
+		sprintf(response, "FAILdata invalid size");
+	} else if (download_size > CONFIG_USB_FASTBOOT_BUF_SIZE) {
+		download_size = 0;
+		sprintf(response, "FAILdata too large");
+	} else {
+		sprintf(response, "DATA%08x", download_size);
+		req->complete = rx_handler_dl_image;
+		req->length = rx_bytes_expected();
+		if (req->length < ep->maxpacket)
+			req->length = ep->maxpacket;
+	}
+	fastboot_tx_write_str(response);
+}
+
+static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	char boot_addr_start[12];
+	char *bootm_args[] = { "bootm", boot_addr_start, NULL };
+
+	puts("Booting kernel..\n");
+
+	sprintf(boot_addr_start, "0x%lx", load_addr);
+	do_bootm(NULL, 0, 2, bootm_args);
+
+	/* This only happens if image is somehow faulty so we start over */
+	do_reset(NULL, 0, 0, NULL);
+}
+
+static void cb_boot(struct usb_ep *ep, struct usb_request *req)
+{
+	fastboot_func->in_req->complete = do_bootm_on_complete;
+	fastboot_tx_write_str("OKAY");
+}
+
+struct cmd_dispatch_info {
+	char *cmd;
+	void (*cb)(struct usb_ep *ep, struct usb_request *req);
+};
+
+static const struct cmd_dispatch_info cmd_dispatch_info[] = {
+	{
+		.cmd = "reboot",
+		.cb = cb_reboot,
+	}, {
+		.cmd = "getvar:",
+		.cb = cb_getvar,
+	}, {
+		.cmd = "download:",
+		.cb = cb_download,
+	}, {
+		.cmd = "boot",
+		.cb = cb_boot,
+	},
+};
+
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmdbuf = req->buf;
+	void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
+		if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
+			func_cb = cmd_dispatch_info[i].cb;
+			break;
+		}
+	}
+
+	if (!func_cb)
+		fastboot_tx_write_str("FAILunknown command");
+	else
+		func_cb(ep, req);
+
+	if (req->status == 0) {
+		*cmdbuf = '\0';
+		req->actual = 0;
+		usb_ep_queue(ep, req, 0);
+	}
+}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v5 3/3] arm: beagle: enable Android fastboot support
  2014-05-05 20:08   ` [U-Boot] [PATCH v5 0/3] " Rob Herring
  2014-05-05 20:08     ` [U-Boot] [PATCH v5 1/3] image: add support for Android's boot image format Rob Herring
  2014-05-05 20:08     ` [U-Boot] [PATCH v5 2/3] usb/gadget: add the fastboot gadget Rob Herring
@ 2014-05-05 20:08     ` Rob Herring
  2014-05-05 20:21     ` [U-Boot] [PATCH v5 0/3] Android Fastboot support Marek Vasut
  2014-05-07  6:35     ` Lukasz Majewski
  4 siblings, 0 replies; 59+ messages in thread
From: Rob Herring @ 2014-05-05 20:08 UTC (permalink / raw)
  To: u-boot

From: Rob Herring <robh@kernel.org>

Enable Android Fastboot support on omap3_beagle board.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 include/configs/omap3_beagle.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/include/configs/omap3_beagle.h b/include/configs/omap3_beagle.h
index 0b57421..be39b7c 100644
--- a/include/configs/omap3_beagle.h
+++ b/include/configs/omap3_beagle.h
@@ -110,6 +110,16 @@
 #define CONFIG_TWL4030_USB		1
 #define CONFIG_USB_ETHER
 #define CONFIG_USB_ETHER_RNDIS
+#define CONFIG_USB_GADGET
+#define CONFIG_USB_GADGET_VBUS_DRAW	0
+#define CONFIG_USBDOWNLOAD_GADGET
+#define CONFIG_G_DNL_VENDOR_NUM		0x0451
+#define CONFIG_G_DNL_PRODUCT_NUM	0xd022
+#define CONFIG_G_DNL_MANUFACTURER	"TI"
+#define CONFIG_CMD_FASTBOOT
+#define CONFIG_ANDROID_BOOT_IMAGE
+#define CONFIG_USB_FASTBOOT_BUF_ADDR	CONFIG_SYS_LOAD_ADDR
+#define CONFIG_USB_FASTBOOT_BUF_SIZE	0x07000000
 
 /* USB EHCI */
 #define CONFIG_CMD_USB
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v5 0/3] Android Fastboot support
  2014-05-05 20:08   ` [U-Boot] [PATCH v5 0/3] " Rob Herring
                       ` (2 preceding siblings ...)
  2014-05-05 20:08     ` [U-Boot] [PATCH v5 3/3] arm: beagle: enable Android fastboot support Rob Herring
@ 2014-05-05 20:21     ` Marek Vasut
  2014-05-07  6:35     ` Lukasz Majewski
  4 siblings, 0 replies; 59+ messages in thread
From: Marek Vasut @ 2014-05-05 20:21 UTC (permalink / raw)
  To: u-boot

On Monday, May 05, 2014 at 10:08:08 PM, Rob Herring wrote:
> From: Rob Herring <robh@kernel.org>
> 
> This is the 3nd version since I revived the fastboot patches Sebastian
> submitted.
> 
> I'm reviving the Android Fastboot support after 2+ years since the last
> posting[1]. The previous postings had some questions about licensing
> and source of some code. I believe I've traced the history sufficiently
> that the copyrights and source information are complete and correct.
> 
> The Android code used or referenced is BSD 2-clause license. This was
> originally raised by Wolfgang that it was not compatible with GPLv2+. I
> believe that has since been demonstrated and agreed that the BSD
> 2-clause license is compatible with u-boot.
> 
> As far as the history of the code, I have traced that back. The u-boot
> code started in 2008/2009 by Tom Rix @ Windriver. This initial support
> was then adopted and extended by TI (eMMC support primarily, not
> included here) in their OMAP u-boot tree[2]. In 2011, the TI code was
> used as a basis for upstream patches by Sebastian Siewior @ Linutronix.
> The code has been rearranged quite a bit since the original, but the
> content is pretty much the same. Some of the re-arranging left stale or
> missing copyrights in the v2 version which I have corrected.
> 
> This version is rebased on u-boot usb tree with the recent USB
> downloader gadget registration changes. The primary change is
> documentation added to README for new config options.
> 
> I've tested this series on a BeagleBoard.

Looks good.

Acked-by: Marek Vasut <marex@denx.de>

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [U-Boot] [PATCH v5 0/3] Android Fastboot support
  2014-05-05 20:08   ` [U-Boot] [PATCH v5 0/3] " Rob Herring
                       ` (3 preceding siblings ...)
  2014-05-05 20:21     ` [U-Boot] [PATCH v5 0/3] Android Fastboot support Marek Vasut
@ 2014-05-07  6:35     ` Lukasz Majewski
  4 siblings, 0 replies; 59+ messages in thread
From: Lukasz Majewski @ 2014-05-07  6:35 UTC (permalink / raw)
  To: u-boot

Hi Rob,

> From: Rob Herring <robh@kernel.org>
> 
> This is the 3nd version since I revived the fastboot patches
> Sebastian submitted.
> 
> I'm reviving the Android Fastboot support after 2+ years since the
> last posting[1]. The previous postings had some questions about
> licensing and source of some code. I believe I've traced the history
> sufficiently that the copyrights and source information are complete
> and correct.
> 
> The Android code used or referenced is BSD 2-clause license. This was 
> originally raised by Wolfgang that it was not compatible with GPLv2+.
> I believe that has since been demonstrated and agreed that the BSD 
> 2-clause license is compatible with u-boot. 
> 
> As far as the history of the code, I have traced that back. The
> u-boot code started in 2008/2009 by Tom Rix @ Windriver. This initial
> support was then adopted and extended by TI (eMMC support primarily,
> not included here) in their OMAP u-boot tree[2]. In 2011, the TI code
> was used as a basis for upstream patches by Sebastian Siewior @
> Linutronix. The code has been rearranged quite a bit since the
> original, but the content is pretty much the same. Some of the
> re-arranging left stale or missing copyrights in the v2 version which
> I have corrected.
> 
> This version is rebased on u-boot usb tree with the recent USB 
> downloader gadget registration changes. The primary change is 
> documentation added to README for new config options.
> 
> I've tested this series on a BeagleBoard.

Applied to u-boot-dfu tree. Rob, thanks for development.

-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

^ permalink raw reply	[flat|nested] 59+ messages in thread

end of thread, other threads:[~2014-05-07  6:35 UTC | newest]

Thread overview: 59+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-10 19:18 [U-Boot] [PATCH v3 0/5] Android Fastboot support Rob Herring
2014-04-10 19:18 ` [U-Boot] [PATCH v3 1/5] common: introduce maximum load size Rob Herring
2014-04-11 14:46   ` Tom Rini
2014-04-15 12:55   ` Lukasz Majewski
2014-04-15 21:59   ` Wolfgang Denk
2014-04-15 23:54     ` Rob Herring
2014-04-16  7:27       ` Wolfgang Denk
2014-04-10 19:18 ` [U-Boot] [PATCH v3 2/5] usb: handle NULL table in usb_gadget_get_string Rob Herring
2014-04-11 14:46   ` Tom Rini
2014-04-11 21:39   ` Marek Vasut
2014-04-15 13:00   ` Lukasz Majewski
2014-04-10 19:18 ` [U-Boot] [PATCH v3 3/5] image: add support for Android's boot image format Rob Herring
2014-04-11 14:46   ` Tom Rini
2014-04-11 21:44   ` Marek Vasut
2014-04-12 21:54     ` Rob Herring
2014-04-13 16:55       ` Marek Vasut
2014-04-15 13:59   ` Lukasz Majewski
2014-04-10 19:18 ` [U-Boot] [PATCH v3 4/5] usb/gadget: add the fastboot gadget Rob Herring
2014-04-11  7:14   ` Bo Shen
2014-04-11 12:55     ` Rob Herring
2014-04-11 22:13       ` Marek Vasut
2014-04-14  6:51         ` Lukasz Majewski
2014-04-14  2:28       ` Bo Shen
2014-04-11  7:30   ` Lukasz Majewski
2014-04-11 14:46   ` Tom Rini
2014-04-11 22:08   ` Marek Vasut
2014-04-15 15:41   ` Lukasz Majewski
2014-04-15 16:01     ` Rob Herring
2014-04-10 19:18 ` [U-Boot] [PATCH v3 5/5] arm: beagle: enable Android fastboot support Rob Herring
2014-04-11 14:46   ` Tom Rini
2014-04-10 19:18 ` [U-Boot] [PATCH 5/5] beagle: " Rob Herring
2014-04-10 19:42   ` Rob Herring
2014-04-11  7:04 ` [U-Boot] [PATCH v3 0/5] Android Fastboot support Sebastian Andrzej Siewior
2014-04-11 14:15   ` Tom Rini
2014-04-11 14:45 ` Tom Rini
2014-04-14 12:19   ` Rob Herring
2014-04-18 13:54 ` [U-Boot] [PATCH v4 " Rob Herring
2014-04-18 13:54   ` [U-Boot] [PATCH v4 1/5] usb: handle NULL table in usb_gadget_get_string Rob Herring
2014-04-18 13:54   ` [U-Boot] [PATCH v4 2/5] image: add support for Android's boot image format Rob Herring
2014-04-18 13:54   ` [U-Boot] [PATCH v4 3/5] usb: musb: fill in usb_gadget_unregister_driver Rob Herring
2014-04-23  9:46     ` Lukasz Majewski
2014-04-18 13:54   ` [U-Boot] [PATCH v4 4/5] usb/gadget: add the fastboot gadget Rob Herring
2014-04-23 11:02     ` Lukasz Majewski
2014-04-23 12:25       ` Marek Vasut
2014-04-24 15:02       ` Rob Herring
2014-04-25  5:26         ` Lukasz Majewski
2014-04-25 13:30           ` Rob Herring
2014-04-28  7:00             ` Lukasz Majewski
2014-04-18 13:54   ` [U-Boot] [PATCH v4 5/5] arm: beagle: enable Android fastboot support Rob Herring
2014-04-18 16:14   ` [U-Boot] [PATCH v4 0/5] Android Fastboot support Wolfgang Denk
2014-04-21 15:13     ` Marek Vasut
2014-04-23 14:36       ` Rob Herring
2014-04-23 16:57         ` Marek Vasut
2014-05-05 20:08   ` [U-Boot] [PATCH v5 0/3] " Rob Herring
2014-05-05 20:08     ` [U-Boot] [PATCH v5 1/3] image: add support for Android's boot image format Rob Herring
2014-05-05 20:08     ` [U-Boot] [PATCH v5 2/3] usb/gadget: add the fastboot gadget Rob Herring
2014-05-05 20:08     ` [U-Boot] [PATCH v5 3/3] arm: beagle: enable Android fastboot support Rob Herring
2014-05-05 20:21     ` [U-Boot] [PATCH v5 0/3] Android Fastboot support Marek Vasut
2014-05-07  6:35     ` Lukasz Majewski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.