[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