[U-Boot] [RFC] fastboot gadget support

Sebastian Andrzej Siewior bigeasy at linutronix.de
Wed Aug 10 20:07:43 CEST 2011


This is the faastboot gadget code based on
git://git.omapzoom.org/repo/u-boot.git as of commit 601ff71c8 including
a few changes. Some of them are:
- generic mmc framework
- "new" gadget framework
- different / easier command parsing
- booti command is missing

It was tested before it has been re-written. It is possible that it is
broken. It is posted for reference only not for merging.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy at linutronix.de>
---
 common/Makefile                 |    2 +
 common/cmd_fastboot.c           | 1334 +++++++++++++++++++++++++++++++++++++++
 drivers/usb/dwc3/fastboot_oem.c |    7 +
 drivers/usb/dwc3/misc.c         |   19 +
 drivers/usb/dwc3/sparse.c       |    8 +
 drivers/usb/gadget/Makefile     |    5 +
 drivers/usb/gadget/g_fastboot.c |  608 ++++++++++++++++++
 drivers/usb/gadget/misc.h       |   14 +
 include/linux/usb/ch9.h         |    1 +
 include/linux/usb/gadget.h      |    4 +
 include/usb/fastboot.h          |  340 ++++++++++
 include/usb/sparse.h            |   33 +
 include/usb/sparse_format.h     |   47 ++
 13 files changed, 2422 insertions(+), 0 deletions(-)
 create mode 100644 common/cmd_fastboot.c
 create mode 100644 drivers/usb/dwc3/fastboot_oem.c
 create mode 100644 drivers/usb/dwc3/misc.c
 create mode 100644 drivers/usb/dwc3/sparse.c
 create mode 100644 drivers/usb/gadget/g_fastboot.c
 create mode 100644 drivers/usb/gadget/misc.h
 create mode 100644 include/usb/fastboot.h
 create mode 100644 include/usb/sparse.h
 create mode 100644 include/usb/sparse_format.h

diff --git a/common/Makefile b/common/Makefile
index d662468..da40d64 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -157,6 +157,8 @@ COBJS-y += cmd_usb.o
 COBJS-y += usb.o
 COBJS-$(CONFIG_USB_STORAGE) += usb_storage.o
 endif
+COBJS-$(CONFIG_CMD_FASTBOOT) += cmd_fastboot.o
+
 COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o
 COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o
 
diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
new file mode 100644
index 0000000..263dd52
--- /dev/null
+++ b/common/cmd_fastboot.c
@@ -0,0 +1,1334 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix at windriver.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Part of the rx_handler were copied from the Android project.
+ * Specifically rx command parsing in the  usb_rx_data_complete
+ * function of the file bootable/bootloader/legacy/usbloader/usbloader.c
+ *
+ * The logical naming of flash comes from the Android project
+ * Thse structures and functions that look like fastboot_flash_*
+ * They come from bootable/bootloader/legacy/libboot/flash.c
+ *
+ * This is their Copyright:
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <common.h>
+#include <command.h>
+#include <nand.h>
+#include <usb/fastboot.h>
+#include <usb/sparse.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <environment.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Use do_reset for fastboot's 'reboot' command */
+#ifndef CONFIG_GENERIC_MMC
+#error Generic MMC support is required
+#endif
+
+/* Forward decl */
+static void reset_handler (void);
+
+static struct cmd_fastboot_interface interface =
+{
+	.reset_handler         = reset_handler,
+	.product_name          = NULL,
+	.serial_no             = NULL,
+	.storage_medium        = 0,
+	.nand_block_size       = 0,
+	.transfer_buffer       = (unsigned char *)0xffffffff,
+	.transfer_buffer_size  = 0,
+};
+
+static unsigned int download_size;
+static unsigned int download_bytes;
+static unsigned int download_bytes_unpadded;
+static unsigned int download_error;
+static unsigned int current_mmc_controller_no = -1;
+
+extern cmd_tbl_t __u_boot_cmd_mmc;
+int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+static void set_mmc_controller(unsigned int num)
+{
+	char str_num[20];
+	char *argv[] = {
+		NULL,
+		"dev",
+		str_num,
+	};
+	int ret;
+
+	if (current_mmc_controller_no == num)
+		return;
+	sprintf(str_num, "%u\n", num);
+	ret = do_mmcops(&__u_boot_cmd_mmc, 0, 3, argv);
+	if (ret)
+		return;
+	current_mmc_controller_no = num;
+}
+
+static int do_mmc_read(u32 block, u32 count, void *addr)
+{
+	char str_block[20];
+	char str_count[20];
+	char str_addr[20];
+	char *argv[] = {
+		NULL,
+		"read",
+		str_block,
+		str_count,
+		str_addr,
+	};
+
+	sprintf(str_block, "%x", block);
+	sprintf(str_count, "%x", count);
+	sprintf(str_addr, "%p", addr);
+	return do_mmcops(&__u_boot_cmd_mmc, 0, 5, argv);
+}
+
+static int do_mmc_write(u32 block, u32 count, void *addr)
+{
+	char str_block[20];
+	char str_count[20];
+	char str_addr[20];
+	char *argv[] = {
+		NULL,
+		"write",
+		str_block,
+		str_count,
+		str_addr,
+	};
+
+	sprintf(str_block, "%x", block);
+	sprintf(str_count, "%x", count);
+	sprintf(str_addr, "%p", addr);
+	return do_mmcops(&__u_boot_cmd_mmc, 0, 5, argv);
+}
+
+static int do_mmc_erase(u32 block, u32 count)
+{
+	char str_block[20];
+	char str_count[20];
+	char *argv[] = {
+		NULL,
+		"erase",
+		str_block,
+		str_count,
+	};
+
+	sprintf(str_block, "%x", block);
+	sprintf(str_count, "%x", count);
+	return do_mmcops(&__u_boot_cmd_mmc, 0, 4, argv);
+}
+
+static void save_env(struct fastboot_ptentry *ptn,
+		     char *var, char *val)
+{
+	setenv(var, val);
+	saveenv();
+}
+int fastboot_tx_write(const char *buffer, unsigned int buffer_size);
+
+static int fastboot_tx_write_str(const char *buffer)
+{
+	return fastboot_tx_write(buffer, strlen(buffer));
+}
+
+static void save_block_values(struct fastboot_ptentry *ptn,
+			      unsigned int offset,
+			      unsigned int size)
+{
+	char var[64], val[32];
+
+	printf ("saving it..\n");
+	if (size == 0) {
+		/* The error case, where the variables are being unset */
+
+		sprintf (var, "%s_nand_offset", ptn->name);
+		val[0] = '\0';
+		setenv(var, val);
+
+		sprintf (var, "%s_nand_size", ptn->name);
+		val[0] = '\0';
+		setenv(var, val);
+	} else {
+		/* Normal case */
+
+		sprintf (var, "%s_nand_offset", ptn->name);
+		sprintf (val, "0x%x", offset);
+		printf ("setenv %s %s\n", var, val);
+		setenv(var, val);
+
+		sprintf (var, "%s_nand_size", ptn->name);
+		sprintf (val, "0x%x", size);
+		printf ("setenv %s %s\n", var, val);
+		setenv(var, val);
+	}
+	saveenv();
+}
+
+static void reset_handler ()
+{
+	/* If there was a download going on, bail */
+	download_size = 0;
+	download_bytes = 0;
+	download_bytes_unpadded = 0;
+	download_error = 0;
+}
+
+/* When save = 0, just parse.  The input is unchanged
+   When save = 1, parse and do the save.  The input is changed */
+static int parse_env(void *ptn, char *err_string, int save, int debug)
+{
+	int ret = 1;
+	unsigned int sets = 0;
+	char *var = NULL;
+	char *var_end = NULL;
+	char *val = NULL;
+	char *val_end = NULL;
+	unsigned int i;
+
+	char *buff = (char *)interface.transfer_buffer;
+	unsigned int size = download_bytes_unpadded;
+
+	/* The input does not have to be null terminated.
+	   This will cause a problem in the corner case
+	   where the last line does not have a new line.
+	   Put a null after the end of the input.
+
+	   WARNING : Input buffer is assumed to be bigger
+	   than the size of the input */
+	if (save)
+		buff[size] = 0;
+
+	for (i = 0; i < size; i++) {
+		if (NULL == var) {
+			if (!((buff[i] == ' ') ||
+			      (buff[i] == '\t') ||
+			      (buff[i] == '\r') ||
+			      (buff[i] == '\n')))
+				var = &buff[i];
+		} else if (((NULL == var_end) || (NULL == val)) &&
+			   ((buff[i] == '\r') || (buff[i] == '\n'))) {
+
+			/* This is the case when a variable
+			   is unset. */
+
+			if (save) {
+				/* Set the var end to null so the
+				   normal string routines will work
+
+				   WARNING : This changes the input */
+				buff[i] = '\0';
+
+				save_env(ptn, var, val);
+
+				if (debug)
+					printf("Unsetting %s\n", var);
+			}
+
+			/* Clear the variable so state is parse is back
+			   to initial. */
+			var = NULL;
+			var_end = NULL;
+			sets++;
+		} else if (NULL == var_end) {
+			if ((buff[i] == ' ') ||
+			    (buff[i] == '\t'))
+				var_end = &buff[i];
+		} else if (NULL == val) {
+			if (!((buff[i] == ' ') ||
+			      (buff[i] == '\t')))
+				val = &buff[i];
+		} else if (NULL == val_end) {
+			if ((buff[i] == '\r') ||
+			    (buff[i] == '\n')) {
+				/* look for escaped cr or ln */
+				if ('\\' == buff[i - 1]) {
+					/* check for dos */
+					if ((buff[i] == '\r') &&
+					    (buff[i+1] == '\n'))
+						buff[i + 1] = ' ';
+					buff[i - 1] = buff[i] = ' ';
+				} else {
+					val_end = &buff[i];
+				}
+			}
+		} else {
+			sprintf(err_string, "Internal Error");
+
+			if (debug)
+				printf("Internal error at %s %d\n",
+				       __FILE__, __LINE__);
+			return 1;
+		}
+		/* Check if a var / val pair is ready */
+		if (NULL != val_end) {
+			if (save) {
+				/* Set the end's with nulls so
+				   normal string routines will
+				   work.
+
+				   WARNING : This changes the input */
+				*var_end = '\0';
+				*val_end = '\0';
+
+				save_env(ptn, var, val);
+
+				if (debug)
+					printf("Setting %s %s\n", var, val);
+			}
+
+			/* Clear the variable so state is parse is back
+			   to initial. */
+			var = NULL;
+			var_end = NULL;
+			val = NULL;
+			val_end = NULL;
+
+			sets++;
+		}
+	}
+
+	/* Corner case
+	   Check for the case that no newline at end of the input */
+	if ((NULL != var) &&
+	    (NULL == val_end)) {
+		if (save) {
+			/* case of val / val pair */
+			if (var_end)
+				*var_end = '\0';
+			/* else case handled by setting 0 past
+			   the end of buffer.
+			   Similar for val_end being null */
+			save_env(ptn, var, val);
+
+			if (debug) {
+				if (var_end)
+					printf("Trailing Setting %s %s\n", var, val);
+				else
+					printf("Trailing Unsetting %s\n", var);
+			}
+		}
+		sets++;
+	}
+	/* Did we set anything ? */
+	if (0 == sets)
+		sprintf(err_string, "No variables set");
+	else
+		ret = 0;
+
+	return ret;
+}
+
+static int saveenv_to_ptn(struct fastboot_ptentry *ptn, char *err_string)
+{
+	int ret = 1;
+	int save = 0;
+	int debug = 0;
+
+	/* err_string is only 32 bytes
+	   Initialize with a generic error message. */
+	sprintf(err_string, "%s", "Unknown Error");
+
+	/* Parse the input twice.
+	   Only save to the enviroment if the entire input if correct */
+	save = 0;
+	if (0 == parse_env(ptn, err_string, save, debug)) {
+		save = 1;
+		ret = parse_env(ptn, err_string, save, debug);
+	}
+	return ret;
+}
+
+static int write_to_ptn(struct fastboot_ptentry *ptn)
+{
+	int ret = 1;
+	char start[32], length[32];
+	char wstart[32], wlength[32], addr[32];
+	char ecc_type[32], write_type[32];
+	int repeat, repeat_max;
+
+	char *lock[5]   = { "nand", "lock",   NULL, NULL, NULL, };
+	char *unlock[5] = { "nand", "unlock", NULL, NULL, NULL,	};
+	char *write[6]  = { "nand", "write",  NULL, NULL, NULL, NULL, };
+	char *ecc[4]    = { "nand", "ecc",    NULL, NULL, };
+	char *erase[5]  = { "nand", "erase",  NULL, NULL, NULL, };
+
+	lock[2] = unlock[2] = erase[2] = start;
+	lock[3] = unlock[3] = erase[3] = length;
+
+	write[1] = write_type;
+	write[2] = addr;
+	write[3] = wstart;
+	write[4] = wlength;
+
+	printf("flashing '%s'\n", ptn->name);
+
+	/* Which flavor of write to use */
+	if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_I)
+		sprintf(write_type, "write.i");
+#ifdef CFG_NAND_YAFFS_WRITE
+	else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_YAFFS)
+		sprintf(write_type, "write.yaffs");
+#endif
+	else
+		sprintf(write_type, "write");
+
+
+	/* Some flashing requires the nand's ecc to be set */
+	ecc[2] = ecc_type;
+	if ((ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) &&
+	    (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC)) {
+		/* Both can not be true */
+		printf("Warning can not do hw and sw ecc for partition '%s'\n",
+		       ptn->name);
+		printf("Ignoring these flags\n");
+	} else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) {
+		sprintf(ecc_type, "hw");
+	} else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) {
+		sprintf(ecc_type, "sw");
+	}
+
+	/* Some flashing requires writing the same data in multiple,
+	   consecutive flash partitions */
+	repeat_max = 1;
+	if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK) {
+		if (ptn->flags &
+		    FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK) {
+			printf("Warning can not do both 'contiguous block' and 'repeat' writes for for partition '%s'\n", ptn->name);
+			printf("Ignoring repeat flag\n");
+		} else {
+			repeat_max = ptn->flags &
+				FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK;
+		}
+	}
+
+	/* Unlock the whole partition instead of trying to
+	   manage special cases */
+	sprintf(length, "0x%x", ptn->length * repeat_max);
+
+	for (repeat = 0; repeat < repeat_max; repeat++) {
+		sprintf(start, "0x%x", ptn->start + (repeat * ptn->length));
+
+		if ((ptn->flags &
+		     FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK) &&
+		    (ptn->flags &
+		     FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK)) {
+			/* Both can not be true */
+			printf("Warning can not do 'next good block' and 'contiguous block' for partition '%s'\n", ptn->name);
+			printf("Ignoring these flags\n");
+		} else if (ptn->flags &
+			   FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK) {
+			/* Keep writing until you get a good block
+			   transfer_buffer should already be aligned */
+			if (interface.nand_block_size) {
+				unsigned int blocks = download_bytes /
+					interface.nand_block_size;
+				unsigned int i = 0;
+				unsigned int offset = 0;
+
+				sprintf(wlength, "0x%x",
+					interface.nand_block_size);
+				while (i < blocks) {
+					/* Check for overflow */
+					if (offset >= ptn->length)
+						break;
+
+					/* download's address only advance
+					   if last write was successful */
+					sprintf(addr, "0x%p",
+						interface.transfer_buffer +
+						(i * interface.nand_block_size));
+
+					/* nand's address always advances */
+					sprintf(wstart, "0x%x",
+						ptn->start + (repeat * ptn->length) + offset);
+					if (ret)
+						break;
+					else
+						i++;
+
+					/* Go to next nand block */
+					offset += interface.nand_block_size;
+				}
+			} else {
+				printf("Warning nand block size can not be 0 when using 'next good block' for partition '%s'\n", ptn->name);
+				printf("Ignoring write request\n");
+			}
+		} else if (ptn->flags &
+			 FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK) {
+		} else {
+			/* Normal case */
+			sprintf(addr,    "0x%p", interface.transfer_buffer);
+			sprintf(wstart,  "0x%x", ptn->start +
+				(repeat * ptn->length));
+			sprintf(wlength, "0x%x", download_bytes);
+#ifdef CFG_NAND_YAFFS_WRITE
+			if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_YAFFS)
+				sprintf(wlength, "0x%x",
+					download_bytes_unpadded);
+#endif
+
+
+			if (0 == repeat) {
+				if (ret) /* failed */
+					save_block_values(ptn, 0, 0);
+				else     /* success */
+					save_block_values(ptn, ptn->start,
+							  download_bytes);
+			}
+		}
+
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+static unsigned int rx_bytes_expected(void)
+{
+	int rx_remain = download_size - download_bytes;
+	if (rx_remain < 0)
+		return 0;
+	if (rx_remain > EP_OUT_BUFFER_SIZE)
+		return EP_OUT_BUFFER_SIZE;
+	return rx_remain;
+}
+
+static char boot_addr_start[32];
+static char *booti_args[4] = { "booti", NULL, "boot", NULL };
+
+static inline int do_booti (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	return do_bootm(cmdtp, flag, argc, argv);
+}
+
+static void do_booti_on_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	req->complete = NULL;
+	fastboot_shutdown();
+	printf("Booting kernel..\n");
+
+	/* boot the boot.img */
+	do_booti(NULL, 0, 3, booti_args);
+	/*
+	 * the alternative would be to re-init fastboot and start from the
+	 * beginning
+	 */
+	do_reset(NULL, 0, 0, NULL);
+}
+
+void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
+{
+	char response[65];
+	unsigned int transfer_size = download_size - download_bytes;
+	const unsigned char *buffer = req->buf;
+	unsigned int buffer_size = req->actual;
+
+	if (!buffer_size) {
+		/* Ignore empty buffers */
+		printf ("Warning empty download buffer\n");
+		printf ("Ignoring\n");
+		return;
+	}
+	/* Handle possible overflow */
+
+	if (buffer_size < transfer_size)
+		transfer_size = buffer_size;
+
+	/* Save the data to the transfer buffer */
+	memcpy(interface.transfer_buffer + 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_OUT_BUFFER_SIZE;
+
+		if (download_error) {
+			/* There was an earlier error */
+			sprintf(response, "ERROR");
+		} else {
+			/* Everything has transferred,
+			   send the OK response */
+			sprintf(response, "OKAY");
+		}
+		fastboot_tx_write_str(response);
+
+		printf ("\ndownloading of %d bytes finished\n",
+				download_bytes);
+
+		/* Padding is required only if storage medium is NAND */
+		if (interface.storage_medium == NAND) {
+			/* Pad to block length
+			   In most cases, padding the download to be
+			   block aligned is correct. The exception is
+			   when the following flash writes to the oob
+			   area.  This happens when the image is a
+			   YAFFS image.  Since we do not know what
+			   the download is until it is flashed,
+			   go ahead and pad it, but save the true
+			   size in case if should have
+			   been unpadded */
+			download_bytes_unpadded = download_bytes;
+			if (interface.nand_block_size)
+			{
+				if (download_bytes %
+						interface.nand_block_size)
+				{
+					unsigned int pad = interface.nand_block_size - (download_bytes % interface.nand_block_size);
+					unsigned int i;
+
+					for (i = 0; i < pad; i++)
+					{
+						if (download_bytes >= interface.transfer_buffer_size)
+							break;
+
+						interface.transfer_buffer[download_bytes] = 0;
+						download_bytes++;
+					}
+				}
+			}
+		}
+	} else
+		req->length = rx_bytes_expected();
+
+	/* Provide some feedback */
+	if (download_bytes &&
+			0 == (download_bytes %
+				(16 * interface.nand_block_size)))
+	{
+		/* Some feeback that the
+		   download is happening */
+		if (download_error)
+			printf("X");
+		else
+			printf(".");
+		if (0 == (download_bytes %
+					(80 * 16 *
+					 interface.nand_block_size)))
+			printf("\n");
+
+	}
+	req->actual = 0;
+	usb_ep_queue(ep, req, 0);
+}
+
+static void compl_reboot_bootloader(struct usb_ep *ep, struct usb_request *req)
+{
+	/* Clear all reset reasons */
+	//__raw_writel(0xfff, PRM_RSTST);
+
+	//strcpy(PUBLIC_SAR_RAM_1_FREE, "reboot-bootloader");
+
+	/* now warm reset the silicon */
+	//__raw_writel(PRM_RSTCTRL_RESET_WARM_BIT, PRM_RSTCTRL);
+	printf("bootloader reset\n");
+	reset_cpu(0);
+}
+
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
+{
+	do_reset(NULL, 0, 0, NULL);
+}
+
+static void compl_do_recovery(struct usb_ep *ep, struct usb_request *req)
+{
+	printf("%s()\n", __func__);
+	/* Clear all reset reasons */
+	//__raw_writel(0xfff, PRM_RSTST);
+	//strcpy(PUBLIC_SAR_RAM_1_FREE, "recovery");
+	/* now warm reset the silicon */
+	//__raw_writel(PRM_RSTCTRL_RESET_WARM_BIT,
+	//	PRM_RSTCTRL);
+	/* Never returns */
+	while (1)
+		;
+}
+
+static void cb_reboot_bootloader(struct usb_ep *ep, struct usb_request *req)
+{
+	req_in->complete = compl_reboot_bootloader;
+	fastboot_tx_write_str("OKAY");
+}
+
+static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
+{
+	req_in->complete = compl_do_reset;
+	fastboot_tx_write_str("OKAY");
+}
+
+static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
+{
+	/* getvar
+	   Get common fastboot variables
+	   Board has a chance to handle other variables */
+	char *cmd = req->buf;
+	char response[65];
+
+	strcpy(response,"OKAY");
+	strsep(&cmd, ":");
+	if (!cmd) {
+		fastboot_tx_write_str("FAILmissing var");
+		return;
+	}
+
+	if(!strcmp(cmd, "version")) {
+		strncat(response, FASTBOOT_VERSION, sizeof(response));
+
+	} else if(!strcmp(cmd, "product")) {
+		if (interface.product_name)
+			strncat(response, interface.product_name, sizeof(response));
+		else
+			strcpy(response, "FAILproduct not set");
+
+	} else if(!strcmp(cmd, "serialno")) {
+		if (interface.serial_no)
+			strncat(response, interface.serial_no, sizeof(response));
+		else
+			strcpy(response, "FAILserialno not set");
+
+	} else if(!strcmp(cmd, "downloadsize")) {
+		char str_num[12];
+
+		sprintf(str_num, "%08x", interface.transfer_buffer_size);
+		strncat(response, str_num, sizeof(response));
+
+	} else if(!strcmp(cmd, "cpurev")) {
+		if (interface.proc_rev)
+			strncat(response, interface.proc_rev, sizeof(response));
+		else
+			strcpy(response, "FAILcpurev not set");
+	} else if(!strcmp(cmd, "secure")) {
+		if (interface.proc_type)
+			strncat(response, interface.proc_type, sizeof(response));
+		else
+			strcpy(response, "FAILsecure not set");
+	} else {
+		fastboot_getvar(cmd, response);
+	}
+	fastboot_tx_write_str(response);
+}
+
+static void cb_oem(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmd = req->buf;
+	char response[65];
+
+	strcpy(response,"OKAY");
+	strsep(&cmd, " ");
+
+	/* fastboot oem format */
+	if(memcmp(cmd, "format", 6) == 0){
+		int ret;
+
+		ret = fastboot_oem(cmd);
+		if (ret < 0) {
+			strcpy(response,"FAIL");
+		} else {
+			strcpy(response,"OKAY");
+		}
+
+	} else if(memcmp(cmd, "recovery", 8) == 0){
+		/* fastboot oem recovery */
+
+		sprintf(response,"OKAY");
+		req_in->complete = compl_do_recovery;
+
+	} else if(memcmp(cmd, "unlock", 6) == 0) {
+		/* fastboot oem unlock */
+
+		sprintf(response,"FAILnot implemented");
+		printf("\nfastboot: oem unlock not implemented yet!!\n");
+	} else {
+		printf("\nfastboot: do not understand oem %s\n", cmd);
+		strcpy(response,"FAILunknown command");
+	}
+	fastboot_tx_write_str(response);
+}
+
+static void cb_erase(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmd = req->buf;
+	char response[65];
+
+	/* erase
+	 * Erase a register flash partition
+	 * Board has to set up flash partitions
+	 */
+	strsep(&cmd, ":");
+
+	if (interface.storage_medium == NAND) {
+		/* storage medium is NAND */
+
+		struct fastboot_ptentry *ptn;
+
+		ptn = fastboot_flash_find_ptn(cmd);
+		if (ptn == 0)
+		{
+			sprintf(response, "FAILpartition does not exist");
+		}
+		else
+		{
+			char start[32], length[32];
+			int status = 0, repeat, repeat_max;
+
+			printf("erasing '%s'\n", ptn->name);
+
+			char *lock[5]   = { "nand", "lock",   NULL, NULL, NULL, };
+			char *unlock[5] = { "nand", "unlock", NULL, NULL, NULL,	};
+			char *erase[5]  = { "nand", "erase",  NULL, NULL, NULL, };
+
+			lock[2] = unlock[2] = erase[2] = start;
+			lock[3] = unlock[3] = erase[3] = length;
+
+			repeat_max = 1;
+			if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK)
+				repeat_max = ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK;
+
+			sprintf (length, "0x%x", ptn->length);
+			for (repeat = 0; repeat < repeat_max; repeat++)
+			{
+				sprintf (start, "0x%x", ptn->start + (repeat * ptn->length));
+
+				if (status)
+					break;
+			}
+
+			if (status)
+			{
+				sprintf(response, "FAILfailed to erase partition");
+			}
+			else
+			{
+				printf("partition '%s' erased\n", ptn->name);
+				sprintf(response, "OKAY");
+			}
+		}
+	} else if (interface.storage_medium == EMMC) {
+		/* storage medium is EMMC */
+
+		struct fastboot_ptentry *ptn;
+
+		/* Save the MMC controller number */
+#if  defined(CONFIG_4430PANDA)
+		/* panda board does not have eMMC on mmc1 */
+		set_mmc_controller(0);
+#else
+		/* blaze has emmc on mmc1 */
+		set_mmc_controller(1);
+#endif
+
+		/* Find the partition and erase it */
+		ptn = fastboot_flash_find_ptn(cmd);
+
+		if (ptn == 0) {
+			sprintf(response,
+					"FAIL: partition doesn't exist");
+		} else {
+			printf("Erasing '%s'\n", ptn->name);
+			if (do_mmc_erase(ptn->start, ptn->length)) {
+				printf("Erasing '%s' FAILED!\n", ptn->name);
+				sprintf(response, "FAIL: Erase partition");
+			} else {
+				printf("Erasing '%s' DONE!\n", ptn->name);
+				sprintf(response, "OKAY");
+			}
+		}
+	}
+	fastboot_tx_write_str(response);
+}
+
+static void cb_mmcerase(struct usb_ep *ep, struct usb_request *req)
+{
+	struct fastboot_ptentry *ptn;
+	char *cmd = req->buf;
+	char response[65];
+	int mmc_no;
+
+	/* EMMC Erase
+	 * Erase a register flash partition on MMC
+	 * Board has to set up flash partitions
+	 */
+	strsep(&cmd, ":");
+
+	/* Save the MMC controller number */
+	mmc_no = simple_strtoul(cmd, NULL, 10);
+	set_mmc_controller(mmc_no);
+	/* Find the partition and erase it */
+	strsep(&cmd, " ");
+	ptn = fastboot_flash_find_ptn(cmd);
+
+	if (ptn == 0) {
+		sprintf(response,
+				"FAIL: partition doesn't exist");
+	} else {
+		/* Call MMC erase function here */
+		/* This is not complete */
+
+		printf("Erasing '%s'\n", ptn->name);
+		if (do_mmc_erase(ptn->start, ptn->length)) {
+			sprintf(response, "FAIL: Erase partition");
+		} else {
+			sprintf(response, "OKAY");
+		}
+	}
+	fastboot_tx_write_str(response);
+}
+
+static void cb_download(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmd = req->buf;
+	char response[65];
+	/*
+	 * download something ..
+	 * What happens to it depends on the next command after data
+	 */
+
+	strsep(&cmd, ":");
+	/* save the size */
+	download_size = simple_strtoul(cmd, NULL, 16);
+	/* Reset the bytes count, now it is safe */
+	download_bytes = 0;
+	/* Reset error */
+	download_error = 0;
+
+	printf("Starting download of %d bytes\n",
+			download_size);
+
+	if (0 == download_size) {
+		/* bad user input */
+		sprintf(response, "FAILdata invalid size");
+	} else if (download_size >
+			interface.transfer_buffer_size)
+	{
+		/* set download_size to 0
+		 * because this is an error */
+		download_size = 0;
+		sprintf(response, "FAILdata too large");
+	} else {
+		/* The default case, the transfer fits
+		   completely in the interface buffer */
+		sprintf(response, "DATA%08x", download_size);
+		req->complete = rx_handler_dl_image;
+		req->length = rx_bytes_expected();
+	}
+	fastboot_tx_write_str(response);
+}
+
+static void cb_boot(struct usb_ep *ep, struct usb_request *req)
+{
+	/* boot
+	   boot what was downloaded
+	 **
+	 ** +-----------------+
+	 ** | boot header     | 1 page
+	 ** +-----------------+
+	 ** | kernel          | n pages
+	 ** +-----------------+
+	 ** | ramdisk         | m pages
+	 ** +-----------------+
+	 ** | second stage    | o pages
+	 ** +-----------------+
+	 **
+	 Pagesize has default value of
+	 CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE
+	 */
+
+	if ((download_bytes) &&
+			(CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE < download_bytes))
+	{
+
+		/* Skip the mkbootimage header */
+		//boot_img_hdr*hdr =
+		//	(boot_img_hdr *)
+		//	&interface.transfer_buffer[CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE];
+
+		booti_args[1] = boot_addr_start;
+		sprintf(boot_addr_start, "0x%p", interface.transfer_buffer);
+
+		req_in->complete = do_booti_on_complete;
+		/* Execution should jump to kernel so send the response
+		   now and wait a bit.  */
+		fastboot_tx_write_str("OKAY");
+		return;
+	}
+	fastboot_tx_write_str("FAILinvalid boot image");
+}
+
+static void cb_mmcwrite(struct usb_ep *ep, struct usb_request *req)
+{
+	struct fastboot_ptentry *ptn;
+	char *cmd = req->buf;
+	u32 mmc_no;
+
+	/* mmcwrite
+	   write what was downloaded on MMC*/
+	/* Write to MMC whatever was downloaded */
+
+	if (!download_bytes) {
+		fastboot_tx_write_str("FAILno image downloaded");
+		return;
+	}
+
+	/* Save the MMC controller number */
+	strsep(&cmd, ":");
+	mmc_no = simple_strtoul(cmd, NULL, 10);
+	set_mmc_controller(mmc_no);
+
+	/* Next is the partition name */
+	strsep(&cmd, " ");
+	ptn = fastboot_flash_find_ptn(cmd);
+
+	if (ptn == 0) {
+		fastboot_tx_write_str("FAILpartition does not exist");
+		return;
+	}
+
+	printf("writing to partition '%s'\n", ptn->name);
+	if (do_mmc_write(ptn->start, download_bytes, interface.transfer_buffer))
+		fastboot_tx_write_str("FAIL: Write partition");
+	else
+		fastboot_tx_write_str("OKAY");
+}
+
+static void cb_flash(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmd = req->buf;
+	char response[64];
+
+	/* flash
+	   Flash what was downloaded */
+	strsep(&cmd, ":");
+
+	if (interface.storage_medium == NAND) {
+		/* storage medium is NAND */
+
+		if (download_bytes)
+		{
+			struct fastboot_ptentry *ptn;
+
+			ptn = fastboot_flash_find_ptn(cmd);
+			if (ptn == 0) {
+				sprintf(response, "FAILpartition does not exist");
+			} else if ((download_bytes > ptn->length) &&
+					!(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
+				sprintf(response, "FAILimage too large for partition");
+				/* TODO : Improve check for yaffs write */
+			} else {
+				/* Check if this is not really a flash write
+				   but rather a saveenv */
+				if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
+					/* Since the response can only be 64 bytes,
+					   there is no point in having a large error message. */
+					char err_string[32];
+					if (saveenv_to_ptn(ptn, &err_string[0])) {
+						printf("savenv '%s' failed : %s\n", ptn->name, err_string);
+						sprintf(response, "FAIL%s", err_string);
+					} else {
+						printf("partition '%s' saveenv-ed\n", ptn->name);
+						sprintf(response, "OKAY");
+					}
+				} else {
+					/* Normal case */
+					if (write_to_ptn(ptn)) {
+						printf("flashing '%s' failed\n", ptn->name);
+						sprintf(response, "FAILfailed to flash partition");
+					} else {
+						printf("partition '%s' flashed\n", ptn->name);
+						sprintf(response, "OKAY");
+					}
+				}
+			}
+		}
+		else
+		{
+			sprintf(response, "FAILno image downloaded");
+		}
+	} else if (interface.storage_medium == EMMC) {
+		/* storage medium is EMMC */
+
+		if (download_bytes) {
+
+			struct fastboot_ptentry *ptn;
+
+			/* Save the MMC controller number */
+#if  defined(CONFIG_4430PANDA)
+			/* panda board does not have eMMC on mmc1 */
+			set_mmc_controller(0);
+#else
+			/* blaze has emmc on mmc1 */
+			set_mmc_controller(1);
+#endif
+
+			/* Next is the partition name */
+			ptn = fastboot_flash_find_ptn(cmd);
+
+			if (ptn == 0) {
+				printf("Partition:'%s' does not exist\n", ptn->name);
+				sprintf(response, "FAILpartition does not exist");
+			} else if ((download_bytes > ptn->length) &&
+					!(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
+				printf("Image too large for the partition\n");
+				sprintf(response, "FAILimage too large for partition");
+
+			} else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
+
+				if (himport_r(&env_htab, (char *)interface.transfer_buffer, ENV_SIZE, '\0', 0)) {
+					gd->flags |= GD_FLG_ENV_READY;
+					saveenv();
+					printf("saveenv to '%s' DONE!\n", ptn->name);
+					sprintf(response, "OKAY");
+				}
+			} else {
+				/* Normal case */
+
+				printf("writing to partition '%s'\n", ptn->name);
+
+				/* Check if we have sparse compressed image */
+				if ( ((sparse_header_t *)interface.transfer_buffer)->magic
+						== SPARSE_HEADER_MAGIC) {
+					printf("fastboot: %s is in sparse format\n", ptn->name);
+					if (!do_unsparse(interface.transfer_buffer,
+								ptn->start,
+								ptn->length,
+								current_mmc_controller_no)) {
+						printf("Writing sparsed: '%s' DONE!\n", ptn->name);
+					} else {
+						printf("Writing sparsed '%s' FAILED!\n", ptn->name);
+						sprintf(response, "FAIL: Sparsed Write");
+					}
+				} else {
+					/* Normal image: no sparse */
+					printf("Writing '%s'\n", ptn->name);
+					if (do_mmc_write(ptn->start, download_bytes, interface.transfer_buffer)) {
+						printf("Writing '%s' FAILED!\n", ptn->name);
+						sprintf(response, "FAIL: Write partition");
+					} else {
+						printf("Writing '%s' DONE!\n", ptn->name);
+					}
+				}
+			} /* Normal Case */
+
+		} else {
+			sprintf(response, "FAILno image downloaded");
+		}
+	} /* EMMC */
+	fastboot_tx_write_str(response);
+}
+
+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-bootloader",
+		.cb = cb_reboot_bootloader,
+	}, {
+		.cmd = "reboot",
+		.cb = cb_reboot,
+	}, {
+		.cmd = "getvar:",
+		.cb = cb_getvar,
+	}, {
+		.cmd = "oem ",
+		.cb = cb_oem,
+	}, {
+		.cmd = "erase:",
+		.cb = cb_erase,
+	}, {
+		.cmd = "mmcerase:",
+		.cb = cb_mmcerase,
+	}, {
+		.cmd = "download:",
+		.cb = cb_download,
+	}, {
+		.cmd = "boot",
+		.cb = cb_boot,
+	}, {
+		.cmd = "mmcwrite:",
+		.cb = cb_mmcwrite,
+	}, {
+		.cmd = "flash:",
+		.cb = cb_flash,
+	},
+};
+
+void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
+{
+	/* Use 65 instead of 64
+	   null gets dropped
+	   strcpy's need the extra byte */
+	char response[65];
+	/* A command */
+	const char *cmdbuf = req->buf;
+	void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
+	int i;
+
+	/* Generic failed response */
+	sprintf(response, "FAIL");
+
+	for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
+		if (!memcmp(cmdbuf, cmd_dispatch_info[i].cmd, strlen(cmd_dispatch_info[i].cmd))) {
+			func_cb = cmd_dispatch_info[i].cb;
+			break;
+		}
+	}
+
+	if (!func_cb) {
+		fastboot_tx_write_str("FAIL: unknown command");
+	} else {
+		func_cb(ep, req);
+	}
+	req->actual = 0;
+	usb_ep_queue(ep, req, 0);
+}
+
+int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	int ret = 1;
+
+	/* Initialize the board specific support */
+	if (!fastboot_init(&interface))
+	{
+		printf ("Fastboot entered...\n");
+
+		/* If we got this far, we are a success */
+		ret = 0;
+
+		/* On disconnect or error, polling returns non zero */
+		while (1)
+		{
+			if (fastboot_poll())
+				break;
+		}
+	}
+
+	/* Reset the board specific support */
+	fastboot_shutdown();
+
+	return ret;
+}
+
+U_BOOT_CMD(
+	fastboot,	1,	1,	do_fastboot,
+	"fastboot- use USB Fastboot protocol\n",
+	""
+);
+
+/* To support the Android-style naming of flash */
+#define MAX_PTN 16
+
+static fastboot_ptentry ptable[MAX_PTN];
+static unsigned int pcount = 0;
+
+void fastboot_flash_reset_ptn(void)
+{
+	pcount = 0;
+}
+
+void fastboot_flash_add_ptn(fastboot_ptentry *ptn)
+{
+    if(pcount < MAX_PTN){
+        memcpy(ptable + pcount, ptn, sizeof(*ptn));
+        pcount++;
+    }
+}
+
+void fastboot_flash_dump_ptn(void)
+{
+    unsigned int n;
+    for(n = 0; n < pcount; n++) {
+        fastboot_ptentry *ptn = ptable + n;
+        printf("ptn %d name='%s' start=%d len=%d\n",
+                n, ptn->name, ptn->start, ptn->length);
+    }
+}
+
+
+fastboot_ptentry *fastboot_flash_find_ptn(const char *name)
+{
+    unsigned int n;
+
+    for(n = 0; n < pcount; n++) {
+	    /* Make sure a substring is not accepted */
+	    if (strlen(name) == strlen(ptable[n].name))
+	    {
+		    if(0 == strcmp(ptable[n].name, name))
+			    return ptable + n;
+	    }
+    }
+    return 0;
+}
+
+fastboot_ptentry *fastboot_flash_get_ptn(unsigned int n)
+{
+    if(n < pcount) {
+        return ptable + n;
+    } else {
+        return 0;
+    }
+}
+
+unsigned int fastboot_flash_get_ptn_count(void)
+{
+    return pcount;
+}
diff --git a/drivers/usb/dwc3/fastboot_oem.c b/drivers/usb/dwc3/fastboot_oem.c
new file mode 100644
index 0000000..4974b7d
--- /dev/null
+++ b/drivers/usb/dwc3/fastboot_oem.c
@@ -0,0 +1,7 @@
+#include <common.h>
+#include <usb/fastboot.h>
+
+int fastboot_oem(const char *cmd)
+{
+	return -1;
+}
diff --git a/drivers/usb/dwc3/misc.c b/drivers/usb/dwc3/misc.c
new file mode 100644
index 0000000..346e42d
--- /dev/null
+++ b/drivers/usb/dwc3/misc.c
@@ -0,0 +1,19 @@
+#include <common.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "misc.h"
+
+int snprintf(char *buf, size_t size, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i = vsprintf(buf, fmt, args);
+	va_end(args);
+	if (i > size)
+		printf("*** Wrote too much bytes into the buffer ***\n");
+	return i;
+}
diff --git a/drivers/usb/dwc3/sparse.c b/drivers/usb/dwc3/sparse.c
new file mode 100644
index 0000000..387f8ce
--- /dev/null
+++ b/drivers/usb/dwc3/sparse.c
@@ -0,0 +1,8 @@
+#include <common.h>
+#include <usb/fastboot.h>
+
+u8 do_unsparse(unsigned char *source, u32 sector, u32 section_size, int slot_no)
+{
+	printf("%s() unsupported\n", __func__);
+	return 1;
+}
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 7d5b504..80e5e5b 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -42,6 +42,11 @@ COBJS-$(CONFIG_SPEARUDC) += spr_udc.o
 endif
 endif
 
+ifdef CONFIG_CMD_FASTBOOT
+COBJS-$(CONFIG_CMD_FASTBOOT) += g_fastboot.o
+COBJS-y += epautoconf.o
+endif
+
 COBJS	:= $(COBJS-y)
 SRCS	:= $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(COBJS))
diff --git a/drivers/usb/gadget/g_fastboot.c b/drivers/usb/gadget/g_fastboot.c
new file mode 100644
index 0000000..ea60cc2
--- /dev/null
+++ b/drivers/usb/gadget/g_fastboot.c
@@ -0,0 +1,608 @@
+#include <common.h>
+#include <errno.h>
+#include <usb/fastboot.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "misc.h"
+
+#ifdef USB_EP_DESC_USE_AUDIO
+#error Can not deal with the two extra bytes right now
+#endif
+
+#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)
+/* upgrade to HS? */
+#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE      (0x0040)
+
+#define DEVICE_STRING_PRODUCT_INDEX		1
+#define DEVICE_STRING_SERIAL_NUMBER_INDEX	2
+#define DEVICE_STRING_CONFIG_INDEX		3
+#define DEVICE_STRING_INTERFACE_INDEX		4
+#define DEVICE_STRING_MANUFACTURER_INDEX	5
+#define DEVICE_STRING_PROC_REVISION		6
+#define DEVICE_STRING_PROC_TYPE			7
+#define DEVICE_STRING_MAX_INDEX			DEVICE_STRING_PROC_TYPE
+#define DEVICE_STRING_LANGUAGE_ID		0x0409 /* English (United States) */
+
+unsigned int dwc3_cable_connected = 1;
+
+static u8 ep0_buffer[4096] __aligned(16);
+static u8 ep_out_buffer[EP_OUT_BUFFER_SIZE] __aligned(16);
+static u8 ep_in_buffer[4096] __aligned(16);
+static char *device_strings[DEVICE_STRING_MAX_INDEX + 1];
+static struct cmd_fastboot_interface *fastboot_interface;
+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,
+};
+
+int fastboot_preboot(void)
+{
+	printf("\n%s() is always off\n", __func__);
+	return 0;
+}
+
+static struct usb_gadget *g;
+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("%s() ep %s status %d\n", __func__, ep->name, status);
+}
+
+static int fastboot_bind(struct usb_gadget *gadget)
+{
+
+	g = gadget;
+	ep0_req = usb_ep_alloc_request(g->ep0, GFP_KERNEL);
+	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;
+	return 0;
+err:
+	return -1;
+}
+
+static void fastboot_unbind(struct usb_gadget *gadget)
+{
+	printf("%s\n", __func__);
+	usb_ep_free_request(g->ep0, ep0_req);
+	ep_in->driver_data = NULL;
+	ep_out->driver_data = NULL;
+}
+
+/* This is the TI USB vendor id */
+#define DEVICE_VENDOR_ID  0x0451
+/* This is just made up.. */
+#define DEVICE_PRODUCT_ID 0xd022
+/* This is just made up.. */
+#define DEVICE_BCD        0x0100
+
+struct usb_device_descriptor fb_descriptor = {
+	.bDescriptorType    = USB_DT_DEVICE,
+#ifdef CONFIG_USB_1_1_DEVICE
+	.bcdUSB             = 0x110,
+#else
+	.bcdUSB             = 0x200,
+#endif
+	.bDeviceClass       = 0x00,
+	.bDeviceSubClass    = 0x00,
+	.bDeviceProtocol    = 0x00,
+	.bMaxPacketSize0    = 0x40,
+	.idVendor           = DEVICE_VENDOR_ID,
+	.idProduct          = DEVICE_PRODUCT_ID,
+	.bcdDevice          = DEVICE_BCD,
+	.iManufacturer      = DEVICE_STRING_MANUFACTURER_INDEX,
+	.iProduct           = DEVICE_STRING_PRODUCT_INDEX,
+	.iSerialNumber      = DEVICE_STRING_SERIAL_NUMBER_INDEX,
+	.bNumConfigurations = 1,
+};
+
+struct fast_boot_config {
+	struct usb_config_descriptor c;
+	struct usb_interface_descriptor i;
+	struct usb_endpoint_descriptor e1;
+	struct usb_endpoint_descriptor e2;
+} __attribute__((packed));
+
+static struct fast_boot_config g_config;
+static int fastboot_setup_get_descr(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+	struct usb_qualifier_descriptor d;
+	u16 w_value	= le16_to_cpu(ctrl->wValue);
+	u16 w_length	= le16_to_cpu(ctrl->wLength);
+	u16 val;
+	int ret;
+	unsigned char bytes_remaining;
+	unsigned char bytes_total;
+	unsigned char bLength;
+	unsigned char string_index;
+	u8 this_inc;
+
+	val = w_value >> 8;
+
+	switch (val) {
+		case USB_DT_DEVICE:
+
+			fb_descriptor.bLength = sizeof(fb_descriptor);
+			memcpy(ep0_buffer, &fb_descriptor, fb_descriptor.bLength);
+			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 = w_length;
+			bytes_total = 0;
+
+			g_config.c.bLength             = sizeof(struct usb_config_descriptor);
+			g_config.c.bDescriptorType     = USB_DT_CONFIG;
+			/* Set this to the total we want */
+			g_config.c.wTotalLength	= cpu_to_le16(sizeof(g_config));
+			g_config.c.bNumInterfaces	= 1;
+			g_config.c.bConfigurationValue	= CONFIGURATION_NORMAL;
+			g_config.c.iConfiguration	= DEVICE_STRING_CONFIG_INDEX;
+			g_config.c.bmAttributes		= 0xc0;
+			g_config.c.bMaxPower		= 0x32;
+
+			this_inc = min(bytes_remaining, sizeof(struct usb_config_descriptor));
+			bytes_remaining -= this_inc;
+			bytes_total += this_inc;
+
+			g_config.i.bLength		= sizeof(struct usb_interface_descriptor);
+			g_config.i.bDescriptorType	= USB_DT_INTERFACE;
+			g_config.i.bInterfaceNumber	= 0x00;
+			g_config.i.bAlternateSetting	= 0x00;
+			g_config.i.bNumEndpoints	= 0x02;
+			g_config.i.bInterfaceClass	= FASTBOOT_INTERFACE_CLASS;
+			g_config.i.bInterfaceSubClass	= FASTBOOT_INTERFACE_SUB_CLASS;
+			g_config.i.bInterfaceProtocol	= FASTBOOT_INTERFACE_PROTOCOL;
+			g_config.i.iInterface		= DEVICE_STRING_INTERFACE_INDEX;
+
+			this_inc = min(bytes_remaining, sizeof(struct usb_interface_descriptor));
+			bytes_remaining -= this_inc;
+			bytes_total += this_inc;
+
+			g_config.e1 = fs_ep_in;
+
+			this_inc = min(bytes_remaining, USB_DT_ENDPOINT_SIZE);
+			bytes_remaining -= this_inc;
+			bytes_total += this_inc;
+
+			if (gadget->speed == USB_SPEED_HIGH)
+				g_config.e2 = hs_ep_out;
+			else
+				g_config.e2 = fs_ep_out;
+
+			this_inc = min(bytes_remaining, USB_DT_ENDPOINT_SIZE);
+			bytes_remaining -= this_inc;
+			bytes_total += this_inc;
+
+			memcpy(ep0_buffer, &g_config, bytes_total);
+
+			ep0_req->length = bytes_total;
+			ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+			break;
+
+		case USB_DT_STRING:
+
+			string_index = w_value & 0xff;
+
+                         if (string_index > DEVICE_STRING_MAX_INDEX) {
+
+				 printf("%s(%d)\n", __func__, __LINE__);
+
+			 } else if (string_index == 0) {
+
+                                 /* Language ID */
+				 bLength = min(4, w_length);
+
+                                 ep0_buffer[0] = 4;        /* length */
+                                 ep0_buffer[1] = USB_DT_STRING;  /* descriptor = string */
+                                 ep0_buffer[2] = DEVICE_STRING_LANGUAGE_ID & 0xff;
+                                 ep0_buffer[3] = DEVICE_STRING_LANGUAGE_ID >> 8;
+
+				 ep0_req->length = bLength;
+				 ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+			 } else {
+				 unsigned char s;
+				 unsigned char sl = strlen(&device_strings[string_index][0]);
+
+                                 /* Size of string in chars */
+                                 /* Size of descriptor
+                                    1    : header
+                                    2    : type
+                                    2*sl : string */
+                                 unsigned char sLength = 2 + (2 * sl);
+                                 unsigned char bLength;
+                                 bLength = min(sLength, w_length);
+
+                                 ep0_buffer[0] = sLength;        /* length */
+                                 ep0_buffer[1] = USB_DT_STRING;  /* descriptor = string */
+
+                                 /* Copy device string to fifo, expand to simple unicode */
+                                 for (s = 0; s < sl; s++)
+                                 {
+                                         ep0_buffer[2+ 2*s + 0] = device_strings[string_index][s];
+                                         ep0_buffer[2+ 2*s + 1] = 0;
+                                 }
+
+				 ep0_req->length = bLength;
+				 ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+			 }
+			 break;
+
+		case USB_DT_DEVICE_QUALIFIER:
+#ifdef CONFIG_USB_1_1_DEVICE
+			 /* This is an invalid request for usb 1.1, nak it */
+			 NAK_REQ();
+#else
+			 d.bLength = min(w_length, sizeof(d));
+			 d.bDescriptorType	= USB_DT_DEVICE_QUALIFIER;
+			 d.bcdUSB		= 0x200;
+			 d.bDeviceClass		= 0xff;
+			 d.bDeviceSubClass	= 0xff;
+			 d.bDeviceProtocol	= 0xff;
+			 d.bMaxPacketSize0	= 0x40;
+			 d.bNumConfigurations	= 1;
+			 d.bRESERVED		= 0;
+
+			 memcpy(ep0_buffer, &d, d.bLength);
+			 ep0_req->length = d.bLength;
+			 ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+#endif
+			 break;
+		default:
+			ret = -EINVAL;
+	}
+	return ret;
+}
+
+#define USB_STATUS_SELFPOWERED	0x01
+#define USB_REQ_TYPE_MASK		0x60
+#define USB_REQ_TYPE_STANDARD		0x00
+#define USB_REQ_DIRECTION_MASK		0x80
+#define USB_REQ_RECIPIENT_MASK		0x1f
+
+static int fastbot_setup_get_status(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+	u16 w_length	= le16_to_cpu(ctrl->wLength);
+
+	if (w_length == 0) {
+		ep0_req->length = 0;
+		return usb_ep_queue(gadget->ep0, ep0_req, 0);
+	}
+	ep0_buffer[0] = USB_STATUS_SELFPOWERED;
+	ep0_buffer[1] = 0;
+	ep0_req->length = 2;
+	return usb_ep_queue(gadget->ep0, ep0_req, 0);
+}
+
+static int fastboot_setup_get_configuration(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);
+	req->actual = 0;
+	if (fastboot_interface && fastboot_interface->tx_complete)
+		fastboot_interface->tx_complete();
+}
+
+void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+
+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("%s(%d): %d\n", __func__, __LINE__, ret);
+		goto err;
+	}
+
+	req_out = usb_ep_alloc_request(ep_out, 0);
+	if (!req_out) {
+		printf("%s(%d): %d\n", __func__, __LINE__, ret);
+		goto err;
+	}
+
+	ret = usb_ep_enable(ep_in, &fs_ep_in);
+	if (ret) {
+		printf("%s(%d): %d\n", __func__, __LINE__, ret);
+		goto err;
+	}
+	req_in = usb_ep_alloc_request(ep_in, 0);
+	if (!req_in) {
+		printf("%s(%d): %d\n", __func__, __LINE__, ret);
+		goto err;
+	}
+
+	req_out->complete = rx_handler_command;
+	req_out->buf = ep_out_buffer;
+	req_out->length = sizeof(ep_out_buffer);
+
+	req_in->complete = fastboot_complete_in;
+	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(struct usb_gadget *gadget, const struct usb_ctrlrequest *req)
+{
+	if ((req->bRequestType & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD) {
+		if ((req->bRequestType & USB_REQ_DIRECTION_MASK) == 0) {
+			/* host-to-device */
+			if ((req->bRequestType & USB_REQ_RECIPIENT_MASK) == 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;
+				};
+			}
+			if (USB_RECIP_INTERFACE == (req->bRequestType & USB_REQ_RECIPIENT_MASK)) {
+				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;
+				}
+			}
+
+			if ((req->bRequestType & USB_REQ_RECIPIENT_MASK) == USB_RECIP_ENDPOINT) {
+				switch (req->bRequest) {
+					case USB_REQ_CLEAR_FEATURE:
+						return usb_ep_queue(gadget->ep0, ep0_req, 0);
+						break;
+					default:
+						return -1;
+				}
+			}
+		}
+		/* device-to-host */
+		if ((req->bRequestType & USB_REQ_RECIPIENT_MASK) == USB_RECIP_DEVICE) {
+			switch(req->bRequest) {
+			case USB_REQ_GET_DESCRIPTOR:
+				return fastboot_setup_get_descr(gadget, req);
+				break;
+			case USB_REQ_GET_STATUS:
+				/* should be handled by dwc3 anyway */
+				return fastbot_setup_get_status(gadget, req);
+
+			case USB_REQ_GET_CONFIGURATION:
+				return fastboot_setup_get_configuration(gadget, req);
+				break;
+			default:
+				return -1;
+			}
+		} else {
+			return -1;
+		}
+	} else
+		return -1;
+}
+
+static void fastboot_disconnect(struct usb_gadget *gadget)
+{
+	fastboot_disable_ep(gadget);
+}
+
+struct usb_gadget_driver fast_gadget = {
+	.bind		= fastboot_bind,
+	.unbind		= fastboot_unbind,
+	.setup		= fastboot_setup,
+	.disconnect	= fastboot_disconnect,
+};
+
+static int dwc3_is_up;
+#define CFG_FASTBOOT_TRANSFER_BUFFER_SIZE (1024)
+static unsigned char CFG_FASTBOOT_TRANSFER_BUFFER[CFG_FASTBOOT_TRANSFER_BUFFER_SIZE];
+
+int fastboot_init(struct cmd_fastboot_interface *interface)
+{
+	int ret;
+
+	device_strings[DEVICE_STRING_MANUFACTURER_INDEX]	= "Manucacturer";
+	device_strings[DEVICE_STRING_PRODUCT_INDEX]		= "Product";
+	device_strings[DEVICE_STRING_SERIAL_NUMBER_INDEX]	= "00123";
+	device_strings[DEVICE_STRING_CONFIG_INDEX]		= "Android Fastboot";
+	device_strings[DEVICE_STRING_INTERFACE_INDEX]		= "Android Fastboot";
+	device_strings[DEVICE_STRING_PROC_REVISION]		= "ES1.0";
+	device_strings[DEVICE_STRING_PROC_TYPE]			= "Type";
+
+	fastboot_interface = interface;
+	fastboot_interface->product_name	= device_strings[DEVICE_STRING_PRODUCT_INDEX];
+	fastboot_interface->serial_no		= device_strings[DEVICE_STRING_SERIAL_NUMBER_INDEX];
+	fastboot_interface->proc_rev		= device_strings[DEVICE_STRING_PROC_REVISION];
+	fastboot_interface->proc_type		= device_strings[DEVICE_STRING_PROC_TYPE];
+
+	fastboot_interface->storage_medium		= NAND;
+	fastboot_interface->nand_block_size		= 2048;
+	fastboot_interface->transfer_buffer		= (unsigned char *) CFG_FASTBOOT_TRANSFER_BUFFER;
+	fastboot_interface->transfer_buffer_size	= CFG_FASTBOOT_TRANSFER_BUFFER_SIZE;
+
+	ret = usb_gadget_init_udc();
+	if (ret) {
+		printf("%s() Probe failed.\n", __func__);
+		return 1;
+	}
+	dwc3_is_up = 1;
+
+	ret = usb_gadget_probe_driver(&fast_gadget, fastboot_bind);
+	if (ret) {
+		printf("Add gadget failed\n");
+		goto err;
+	}
+
+	usb_gadget_handle_interrupts();
+	return 0;
+
+err:
+	fastboot_shutdown();
+	return 1;
+}
+
+int fastboot_poll(void)
+{
+	usb_gadget_handle_interrupts();
+
+	if (dwc3_cable_connected)
+		return 0;
+	else
+		return 1;
+}
+
+void fastboot_shutdown(void)
+{
+	if (!dwc3_is_up)
+		return;
+	dwc3_is_up = 0;
+	fastboot_interface = NULL;
+	usb_gadget_exit_udc();
+}
+
+void (*complete)(struct usb_ep *ep, struct usb_request *req);
+
+int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
+{
+	int ret;
+
+	memcpy(req_in->buf, buffer, buffer_size);
+	req_in->length = buffer_size;
+	ret = usb_ep_queue(ep_in, req_in, 0);
+	if (ret)
+		printf("%s() error %d on queue\n", __func__, ret);
+	return 0;
+}
+
+int fastboot_getvar(const char *rx_buffer, char *tx_buffer)
+{
+	printf("%s() missing\n", __func__);
+	return 0;
+}
diff --git a/drivers/usb/gadget/misc.h b/drivers/usb/gadget/misc.h
new file mode 100644
index 0000000..acd23c8
--- /dev/null
+++ b/drivers/usb/gadget/misc.h
@@ -0,0 +1,14 @@
+#ifndef dwc3_misc_h
+#define dwc3_misc_h
+
+#include <linux/compiler.h>
+#include <malloc.h>
+#include <asm/io.h>
+
+#define GFP_KERNEL	0
+
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
+
+#endif
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 49b7483..70cea71 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -559,6 +559,7 @@ enum usb_device_speed {
 	USB_SPEED_LOW, USB_SPEED_FULL,		/* usb 1.1 */
 	USB_SPEED_HIGH,				/* usb 2.0 */
 	USB_SPEED_VARIABLE,			/* wireless (usb 2.5) */
+	USB_SPEED_SUPER,			/* usb 3.0 */
 };
 
 enum usb_device_state {
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 275cb5f..4de6ca8 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -19,6 +19,7 @@
 #define __LINUX_USB_GADGET_H
 
 #include <linux/list.h>
+#include <errno.h>
 
 struct usb_ep;
 
@@ -854,4 +855,7 @@ extern void usb_ep_autoconfig_reset(struct usb_gadget *);
 
 extern int usb_gadget_handle_interrupts(void);
 
+extern int usb_gadget_init_udc(void);
+extern void usb_gadget_exit_udc(void);
+
 #endif	/* __LINUX_USB_GADGET_H */
diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h
new file mode 100644
index 0000000..1d67d94
--- /dev/null
+++ b/include/usb/fastboot.h
@@ -0,0 +1,340 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix at windriver.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * The logical naming of flash comes from the Android project
+ * Thse structures and functions that look like fastboot_flash_*
+ * They come from bootloader/legacy/include/boot/flash.h
+ *
+ * The boot_img_hdr structure and associated magic numbers also
+ * come from the Android project.  They are from
+ * system/core/mkbootimg/bootimg.h
+ *
+ * Here are their copyrights
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef FASTBOOT_H
+#define FASTBOOT_H
+
+#include <common.h>
+#include <command.h>
+
+/* From fastboot client.. */
+#define FASTBOOT_INTERFACE_CLASS     0xff
+#define FASTBOOT_INTERFACE_SUB_CLASS 0x42
+#define FASTBOOT_INTERFACE_PROTOCOL  0x03
+
+#define FASTBOOT_VERSION "0.5"
+
+/* The fastboot client uses a value of 2048 for the 
+   page size of it boot.img file format. 
+   Reset this in your board config file as needed. */
+#ifndef CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE
+#define CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE 2048
+#endif
+
+typedef enum { NAND, EMMC } storage_medium_type;
+
+struct cmd_fastboot_interface
+{
+	/* This function is called when a buffer has been 
+	   recieved from the client app.
+	   The buffer is a supplied by the board layer and must be unmodified. 
+	   The buffer_size is how much data is passed in. 
+	   Returns 0 on success
+	   Returns 1 on failure	
+
+	   Set by cmd_fastboot	*/
+	int (*rx_handler)(const unsigned char *buffer,
+			  unsigned int buffer_size);
+
+	/*
+	 * Returns the number of bytes which are expected in the next RX.
+	 * Returns 0 if unknown or the exact amount. This is required during
+	 * the transfer of an image where size may be a multiple of
+	 * MacPacketSize and the host is not sending a ZeroSizePacket to
+	 * terminate the tranfer. Thank you google.
+	 */
+	unsigned int (*rx_bytes_expected)(void);
+	/*
+	 * notify fastboot that a given tx-transfer completed. Used by the
+	 * "boot" command which should be executed after the transfer of
+	 * the "OKAY" message has been delived to the USB host.
+	 */
+	void (*tx_complete)(void);
+	/* This function is called when an exception has
+	   occurred in the device code and the state
+	   off fastboot needs to be reset
+
+	   Set by cmd_fastboot */
+	void (*reset_handler)(void);
+
+	/* A getvar string for the product name
+	   It can have a maximum of 60 characters
+
+	   Set by board	*/
+	char *product_name;
+
+	/* A getvar string for the serial number
+	   It can have a maximum of 60 characters
+
+	   Set by board */
+	char *serial_no;
+
+	/* A getvar string for the processor revision
+	   It can have a maximum of 60 characters
+
+	   Set by board */
+	char *proc_rev;
+
+	/* A getvar string for the processor type
+	   this can be GP, EMU or HS
+	   It can have a maximum of 60 characters
+
+	   Set by board */
+	char *proc_type;
+
+	/* To determine the storage type NAND or EMMC */
+	storage_medium_type storage_medium;
+
+	/* Nand block size
+	   Supports the write option WRITE_NEXT_GOOD_BLOCK
+
+	   Set by board */
+	unsigned int nand_block_size;
+
+	/* Transfer buffer, for handling flash updates
+	   Should be multiple of the nand_block_size
+	   Care should be take so it does not overrun bootloader memory
+	   Controlled by the configure variable CFG_FASTBOOT_TRANSFER_BUFFER
+
+	   Set by board */
+	unsigned char *transfer_buffer;
+
+	/* How big is the transfer buffer
+	   Controlled by the configure variable
+	   CFG_FASTBOOT_TRANSFER_BUFFER_SIZE
+
+	   Set by board	*/
+	unsigned int transfer_buffer_size;
+
+};
+
+/* Android-style flash naming */
+typedef struct fastboot_ptentry fastboot_ptentry;
+
+/* flash partitions are defined in terms of blocks
+** (flash erase units)
+*/
+struct fastboot_ptentry
+{
+	/* The logical name for this partition, null terminated */
+	char name[16];
+	/* The start wrt the nand part, must be multiple of nand block size */
+	unsigned int start;
+	/* The length of the partition, must be multiple of nand block size */
+	unsigned int length;
+	/* Controls the details of how operations are done on the partition
+	   See the FASTBOOT_PTENTRY_FLAGS_*'s defined below */
+	unsigned int flags;
+};
+
+/* Lower byte shows if the read/write/erase operation in
+   repeated.  The base address is incremented.
+   Either 0 or 1 is ok for a default */
+
+#define FASTBOOT_PTENTRY_FLAGS_REPEAT(n)              (n & 0x0f)
+#define FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK            0x0000000F
+
+/* Writes happen a block at a time.
+   If the write fails, go to next block
+   NEXT_GOOD_BLOCK and CONTIGOUS_BLOCK can not both be set */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK  0x00000010
+
+/* Find a contiguous block big enough for a the whole file
+   NEXT_GOOD_BLOCK and CONTIGOUS_BLOCK can not both be set */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK 0x00000020
+
+/* Sets the ECC to hardware before writing
+   HW and SW ECC should not both be set. */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC           0x00000040
+
+/* Sets the ECC to software before writing
+   HW and SW ECC should not both be set. */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC           0x00000080
+
+/* Write the file with write.i */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_I                0x00000100
+
+/* Write the file with write.yaffs */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_YAFFS            0x00000200
+
+/* Write the file as a series of variable/value pairs
+   using the setenv and saveenv commands */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_ENV              0x00000400
+
+/* Android bootimage file format */
+#define FASTBOOT_BOOT_MAGIC "ANDROID!"
+#define FASTBOOT_BOOT_MAGIC_SIZE 8
+#define FASTBOOT_BOOT_NAME_SIZE 16
+#define FASTBOOT_BOOT_ARGS_SIZE 512
+
+struct fastboot_boot_img_hdr {
+	unsigned char magic[FASTBOOT_BOOT_MAGIC_SIZE];
+
+	unsigned kernel_size;  /* size in bytes */
+	unsigned kernel_addr;  /* physical load addr */
+
+	unsigned ramdisk_size; /* size in bytes */
+	unsigned ramdisk_addr; /* physical load addr */
+
+	unsigned second_size;  /* size in bytes */
+	unsigned second_addr;  /* physical load addr */
+
+	unsigned tags_addr;    /* physical addr for kernel tags */
+	unsigned page_size;    /* flash page size we assume */
+	unsigned unused[2];    /* future expansion: should be 0 */
+
+	unsigned char name[FASTBOOT_BOOT_NAME_SIZE]; /* asciiz product name */
+
+	unsigned char cmdline[FASTBOOT_BOOT_ARGS_SIZE];
+
+	unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+};
+
+#if (CONFIG_CMD_FASTBOOT)
+/* A board specific test if u-boot should go into the fastboot command
+   ahead of the bootcmd
+   Returns 0 to continue with normal u-boot flow
+   Returns 1 to execute fastboot */
+extern int fastboot_preboot(void);
+
+/* Initizes the board specific fastboot 
+   Returns 0 on success
+   Returns 1 on failure */
+extern int fastboot_init(struct cmd_fastboot_interface *interface);
+
+/* Cleans up the board specific fastboot */
+extern void fastboot_shutdown(void);
+
+/* Handles board specific usb protocol exchanges
+   Returns 0 on success
+   Returns 1 on disconnects, break out of loop
+   Returns -1 on failure, unhandled usb requests and other error conditions */
+extern int fastboot_poll(void);
+
+/* Is this high speed (2.0) or full speed (1.1) ? 
+   Returns 0 on full speed
+   Returns 1 on high speed */
+extern int fastboot_is_highspeed(void);
+
+/* Return the size of the fifo */
+extern int fastboot_fifo_size(void);
+
+/* A board specific variable handler. 
+   The size of the buffers is governed by the fastboot spec. 
+   rx_buffer is at most 57 bytes 
+   tx_buffer is at most 60 bytes
+   Returns 0 on success
+   Returns 1 on failure */
+extern int fastboot_getvar(const char *rx_buffer, char *tx_buffer);
+/* board-specific fastboot commands */
+extern int fastboot_oem(const char *command);
+
+/* The Android-style flash handling */
+
+/* tools to populate and query the partition table */
+extern void fastboot_flash_add_ptn(fastboot_ptentry *ptn);
+extern fastboot_ptentry *fastboot_flash_find_ptn(const char *name);
+extern fastboot_ptentry *fastboot_flash_get_ptn(unsigned n);
+extern unsigned int fastboot_flash_get_ptn_count(void);
+extern void fastboot_flash_dump_ptn(void);
+
+extern int fastboot_flash_init(void);
+extern int fastboot_flash_erase(fastboot_ptentry *ptn);
+extern int fastboot_flash_read_ext(fastboot_ptentry *ptn, 
+				   unsigned extra_per_page, unsigned offset, 
+				   void *data, unsigned bytes);
+#define fastboot_flash_read(ptn, offset, data, bytes) \
+  flash_read_ext(ptn, 0, offset, data, bytes)
+extern int fastboot_flash_write(fastboot_ptentry *ptn, unsigned extra_per_page,
+				const void *data, unsigned bytes);
+
+
+#else
+
+static inline int fastboot_preboot(void) { return 0; }
+static inline int fastboot_init(struct cmd_fastboot_interface *interface) { return 1; }
+static inline void fastboot_shutdown(void) { }
+static inline int fastboot_poll(void) { return 1; }
+static inline int fastboot_is_highspeed(void) { return 0; }
+static inline int fastboot_fifo_size(void) { return 0; }
+static inline int fastboot_tx_write(const char *buffer, unsigned int buffer_size) { return 1; }
+static inline int fastboot_getvar(const char *rx_buffer, char *tx_buffer) { return 1; }
+static inline int fastboot_oem(const char *command);
+static inline void fastboot_flash_add_ptn(fastboot_ptentry *ptn) { }
+static inline fastboot_ptentry *fastboot_flash_find_ptn(const char *name) { return NULL; }
+static inline fastboot_ptentry *fastboot_flash_get_ptn(unsigned n) { return NULL; }
+static inline unsigned int fastboot_flash_get_ptn_count(void) { return 0; }
+static inline void fastboot_flash_dump_ptn(void) { }
+static inline int fastboot_flash_init(void) { }
+static inline int fastboot_flash_erase(fastboot_ptentry *ptn) { return 1; }
+static inline int fastboot_flash_read_ext(fastboot_ptentry *ptn,
+				   unsigned extra_per_page, unsigned offset,
+				   void *data, unsigned bytes) { return 0; }
+static inline int fastboot_flash_write(fastboot_ptentry *ptn, unsigned extra_per_page,
+				const void *data, unsigned bytes) { return 0; }
+
+#endif /* CONFIG_FASTBOOT */
+
+extern struct usb_ep *ep_in;
+extern struct usb_request *req_in;
+extern struct usb_ep *ep_out;
+extern struct usb_request *req_out;
+
+#define EP_OUT_BUFFER_SIZE      4096
+
+#endif /* FASTBOOT_H */
diff --git a/include/usb/sparse.h b/include/usb/sparse.h
new file mode 100644
index 0000000..6249e68
--- /dev/null
+++ b/include/usb/sparse.h
@@ -0,0 +1,33 @@
+/*
+ * (C) Copyright 2011
+ * Texas Instruments, <www.ti.com>
+ * Author: Vikram Pandita <vikram.pandita at ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __SPARSE_H
+#define __SPARSE_H
+
+/* This file is taken as such from Android repo */
+#include <usb/sparse_format.h>
+
+u8
+do_unsparse(unsigned char *source,
+                u32 sector,
+                u32 section_size,
+                int slot_no);
+#endif /* __SPARSE_H */
diff --git a/include/usb/sparse_format.h b/include/usb/sparse_format.h
new file mode 100644
index 0000000..ba13214
--- /dev/null
+++ b/include/usb/sparse_format.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+typedef struct sparse_header {
+  __le32	magic;		/* 0xed26ff3a */
+  __le16	major_version;	/* (0x1) - reject images with higher major versions */
+  __le16	minor_version;	/* (0x0) - allow images with higer minor versions */
+  __le16	file_hdr_sz;	/* 28 bytes for first revision of the file format */
+  __le16	chunk_hdr_sz;	/* 12 bytes for first revision of the file format */
+  __le32	blk_sz;		/* block size in bytes, must be a multiple of 4 (4096) */
+  __le32	total_blks;	/* total blocks in the non-sparse output image */
+  __le32	total_chunks;	/* total chunks in the sparse input image */
+  __le32	image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
+				/* as 0. Standard 802.3 polynomial, use a Public Domain */
+				/* table implementation */
+} sparse_header_t;
+
+#define SPARSE_HEADER_MAGIC	0xed26ff3a
+
+#define CHUNK_TYPE_RAW		0xCAC1
+#define CHUNK_TYPE_FILL		0xCAC2
+#define CHUNK_TYPE_DONT_CARE	0xCAC3
+
+typedef struct chunk_header {
+  __le16	chunk_type;	/* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
+  __le16	reserved1;
+  __le32	chunk_sz;	/* in blocks in output image */
+  __le32	total_sz;	/* in bytes of chunk input file including chunk header and data */
+} chunk_header_t;
+
+/* Following a Raw or Fill chunk is data.  For a Raw chunk, it's the data in chunk_sz * blk_sz.
+ *  For a Fill chunk, it's 4 bytes of the fill data.
+ */
+
-- 
1.7.4.4



More information about the U-Boot mailing list