Message ID | 1422618891-15613-1-git-send-email-dileep.katta@linaro.org |
---|---|
State | New |
Headers | show |
On 30 January 2015 at 22:27, Lukasz Majewski <l.majewski@samsung.com> wrote: > Hi Dileep, > > > This is the Modified version of > > http://patchwork.ozlabs.org/patch/388084/ > > - As flash support is already in mainline, it is removed > > - 'oem' command support is present > > - 'oem format' command is implemented > > - Handled review comments of the original patch > > > > Signed-off-by: Dileep Katta <dileep.katta@linaro.org> > > --- > > common/cmd_fastboot.c | 4 + > > common/cmd_mmc.c | 2 +- > > disk/Makefile | 1 + > > disk/part_fastboot.c | 363 > > ++++++++++++++++++++++++++++++++++++++++ > > doc/README.android-fastboot | 5 +- > > drivers/usb/gadget/f_fastboot.c | 85 ++++++++++ > > include/usb/fastboot.h | 108 ++++++++++++ 7 files changed, > > 564 insertions(+), 4 deletions(-) create mode 100644 > > disk/part_fastboot.c create mode 100644 include/usb/fastboot.h > > > > diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c > > index b72f4f3..efdf461 100644 > > --- a/common/cmd_fastboot.c > > +++ b/common/cmd_fastboot.c > > @@ -10,12 +10,16 @@ > > #include <common.h> > > #include <command.h> > > #include <g_dnl.h> > > +#include <usb/fastboot.h> > > > > static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char > > *const argv[]) { > > int ret; > > > > g_dnl_clear_detach(); > > +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV > > + board_partition_init(); > > +#endif > > ret = g_dnl_register("usb_dnl_fastboot"); > > if (ret) > > return ret; > > diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c > > index 4e28c9d..0ce747b 100644 > > --- a/common/cmd_mmc.c > > +++ b/common/cmd_mmc.c > > @@ -809,7 +809,7 @@ static cmd_tbl_t cmd_mmc[] = { > > U_BOOT_CMD_MKENT(setdsr, 2, 0, do_mmc_setdsr, "", ""), > > }; > > > > -static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * > > const argv[]) +int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, > > char * const argv[]) { > > cmd_tbl_t *cp; > > > > diff --git a/disk/Makefile b/disk/Makefile > > index 6970cec..4969656 100644 > > --- a/disk/Makefile > > +++ b/disk/Makefile > > @@ -13,3 +13,4 @@ obj-$(CONFIG_DOS_PARTITION) += part_dos.o > > obj-$(CONFIG_ISO_PARTITION) += part_iso.o > > obj-$(CONFIG_AMIGA_PARTITION) += part_amiga.o > > obj-$(CONFIG_EFI_PARTITION) += part_efi.o > > +obj-$(CONFIG_FASTBOOT_FLASH_MMC_DEV) +=part_fastboot.o > > diff --git a/disk/part_fastboot.c b/disk/part_fastboot.c > > new file mode 100644 > > index 0000000..adf37af > > --- /dev/null > > +++ b/disk/part_fastboot.c > > @@ -0,0 +1,363 @@ > > +/* > > + * Copyright (C) 2013 Texas Instruments > > + * > > + * Author : Pankaj Bharadiya <pankaj.bharadiya@ti.com> > > + * > > + * Tom Rix <Tom.Rix@windriver.com> and Sitara 2011 u-boot by > > + * Mohammed Afzal M A <afzal@ti.com> > > + * > > + * Copyright (C) 2008 The Android Open Source Project > > + * All rights reserved. > > + * > > + * Copyright 2014 Linaro, Ltd. > > + * Dileep Katta <dileep.katta@linaro.org> > > + * > > + * SPDX-License-Identifier: GPL-2.0+ > > + */ > > + > > +#include <common.h> > > +#include <command.h> > > +#include <usb/fastboot.h> > > +#include <linux/usb/ch9.h> > > +#include <linux/usb/gadget.h> > > +#include <environment.h> > > +#include <mmc.h> > > +#include <dfu.h> > > +#include <asm/arch/mmc_host_def.h> > > + > > +#define EFI_VERSION 0x00010000 > > +#define EFI_ENTRIES 128 > > +#define EFI_NAMELEN 36 > > + > > +struct partition_emmc { > > + const char *name; > > + unsigned size_kb; > > +}; > > + > > +/* eMMC partition layout (All sizes are in kB) > > + * Modify the below partition table to change the GPT configuration. > > + * The entry for each partition can be modified as per the > > requirement. > > + */ > > +static struct partition_emmc partitions[] = { > > Defining mmc partitions as a static struct in the code IMHO is not > flexible. > > > + { "-", 128 }, /* Master Boot Record and GUID > > Partition Table */ > > + { "spl", 128 }, /* First stage bootloader */ > > + { "bootloader", 512 }, /* Second stage bootloader */ > > + { "misc", 128 }, /* Rserved for internal > > purpose */ > > + { "-", 128 }, /* Reserved */ > > + { "recovery", 8*1024 }, /* Recovery partition */ > > + { "boot", 8*1024 }, /* Partition contains kernel + > > ramdisk images */ > > + { "system", 256*1024 }, /* Android file > > system */ > > + { "cache", 256*1024 }, /* Store Application > > Cache */ > > + { "userdata", 256*1024 }, /* User data */ > > + { "media", 0 }, /* Media files */ > > + { 0, 0 }, > > +}; > > Maybe it would be better if we could reuse $partitions ? > With above code we introduce another (not compatible and flexible) way > to specify eMMC partitions for the board. > > > + > > + > > +static const u8 partition_type[16] = { > > + 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44, > > + 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7, > > +}; > > + > > Please look into ./include/part_efi.h [1] > > > +static const u8 random_uuid[16] = { > > + 0xff, 0x1f, 0xf2, 0xf9, 0xd4, 0xa8, 0x0e, 0x5f, > > + 0x97, 0x46, 0x59, 0x48, 0x69, 0xae, 0xc3, 0x4e, > > +}; > > I'm not sure if specifying "random" uuids via static const table is > what you wanted. > > For more flexible solution please refer to Trats2 automatic generation > of UUIDs (either from HW or in SW). > > > + > > +struct efi_entry { > > + u8 type_uuid[16]; > > + u8 uniq_uuid[16]; > > + u64 first_lba; > > + u64 last_lba; > > + u64 attr; > > + u16 name[EFI_NAMELEN]; > > +}; > > + > > +struct efi_header { > > + u8 magic[8]; > > + > > + u32 version; > > + u32 header_sz; > > + > > + u32 crc32; > > + u32 reserved; > > + > > + u64 header_lba; > > + u64 backup_lba; > > + u64 first_lba; > > + u64 last_lba; > > + > > + u8 volume_uuid[16]; > > + > > + u64 entries_lba; > > + > > + u32 entries_count; > > + u32 entries_size; > > + u32 entries_crc32; > > +} __packed; > > + > > +struct ptable { > > + u8 mbr[512]; > > + union { > > + struct efi_header header; > > + u8 block[512]; > > + }; > > + struct efi_entry entry[EFI_ENTRIES]; > > +}; > > + > > Already defined at [1]. > > > +static void init_mbr(u8 *mbr, u32 blocks) > > +{ > > + mbr[0x1be] = 0x00; /* nonbootable */ > > + mbr[0x1bf] = 0xFF; /* bogus CHS */ > > + mbr[0x1c0] = 0xFF; > > + mbr[0x1c1] = 0xFF; > > + > > + mbr[0x1c2] = 0xEE; /* GPT partition */ > > + mbr[0x1c3] = 0xFF; /* bogus CHS */ > > + mbr[0x1c4] = 0xFF; > > + mbr[0x1c5] = 0xFF; > > + > > + mbr[0x1c6] = 0x01; /* start */ > > + mbr[0x1c7] = 0x00; > > + mbr[0x1c8] = 0x00; > > + mbr[0x1c9] = 0x00; > > + > > + memcpy(mbr + 0x1ca, &blocks, sizeof(u32)); > > + > > + mbr[0x1fe] = 0x55; > > + mbr[0x1ff] = 0xaa; > > +} > > + > > Please refer to part_efi.c - code for mbr initialization is already > there. > > > + > > +static void start_ptbl(struct ptable *ptbl, unsigned blocks) > > +{ > > + struct efi_header *hdr = &ptbl->header; > > + > > + memset(ptbl, 0, sizeof(*ptbl)); > > + > > + init_mbr(ptbl->mbr, blocks - 1); > > + > > + memcpy(hdr->magic, "EFI PART", 8); > > + hdr->version = EFI_VERSION; > > + hdr->header_sz = sizeof(struct efi_header); > > + hdr->header_lba = 1; > > + hdr->backup_lba = blocks - 1; > > + hdr->first_lba = 34; > > + hdr->last_lba = blocks - 1; > > + memcpy(hdr->volume_uuid, random_uuid, 16); > > + hdr->entries_lba = 2; > > + hdr->entries_count = EFI_ENTRIES; > > + hdr->entries_size = sizeof(struct efi_entry); > > +} > > + > > +static void end_ptbl(struct ptable *ptbl) > > +{ > > + struct efi_header *hdr = &ptbl->header; > > + u32 n; > > + > > + /* Get the initial checksum by passing buf as NULL */ > > + n = crc32(0, NULL, 0); > > + n = crc32(n, (void *)ptbl->entry, sizeof(ptbl->entry)); > > + hdr->entries_crc32 = n; > > + > > + n = crc32(0, (void *)&ptbl->header, sizeof(ptbl->header)); > > + hdr->crc32 = n; > > +} > > + > > +int add_ptn(struct ptable *ptbl, u64 first, u64 last, const char > > *name) +{ > > + struct efi_header *hdr = &ptbl->header; > > + struct efi_entry *entry = ptbl->entry; > > + unsigned n; > > + > > + if (first < 34) { > > + printf("partition '%s' overlaps partition table\n", > > name); > > + return -1; > > + } > > + > > + if (last > hdr->last_lba) { > > + printf("partition '%s' does not fit\n", name); > > + return -1; > > + } > > + for (n = 0; n < EFI_ENTRIES; n++, entry++) { > > + if (entry->last_lba) > > + continue; > > + memcpy(entry->type_uuid, partition_type, 16); > > + memcpy(entry->uniq_uuid, random_uuid, 16); > > + entry->uniq_uuid[0] = n; > > + entry->first_lba = first; > > + entry->last_lba = last; > > + for (n = 0; (n < EFI_NAMELEN) && *name; n++) > > + entry->name[n] = *name++; > > + return 0; > > + } > > + printf("out of partition table entries\n"); > > + return -1; > > +} > > The same as above. > > BTW - please use proper error values instead of -1. > > > + > > +void import_efi_partition(struct efi_entry *entry) > > +{ > > + struct fastboot_ptentry e; > > + int n; > > + if (memcmp(entry->type_uuid, partition_type, > > sizeof(partition_type))) > > + return; > > + for (n = 0; n < (sizeof(e.name)-1); n++) > > + e.name[n] = entry->name[n]; > > + e.name[n] = 0; > > + e.start = entry->first_lba; > > + e.length = (entry->last_lba - entry->first_lba + 1) * 512; > > + e.flags = 0; > > + > > + if (!strcmp(e.name, "environment")) > > + e.flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_ENV; > > + fastboot_flash_add_ptn(&e); > > + > > + if (e.length > 0x100000) > > + printf("%8d %7dM %s\n", e.start, e.length/0x100000, > > e.name); > > + else > > + printf("%8d %7dK %s\n", e.start, e.length/0x400, > > e.name); +} > > The above condition looks like a hard codded one. Please add rationale > for this (#defines would help there) > > > + > > +static int load_ptbl(void) > > +{ > > + u64 ptbl_sectors = 0; > > + int i = 0, r = 0; > > + > > + struct ptable gpt[sizeof(struct ptable)]; > > + struct mmc *mmc = NULL; > > + > > + mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV); > > + if (mmc == NULL) { > > + printf("No MMC in slot 1\n"); > > + return -1; > > + } > > + > > + int gpt_size = sizeof(struct ptable); > > + > > + ptbl_sectors = (u64)(gpt_size / MMCSD_SECTOR_SIZE); > > + > > + r = mmc->block_dev.block_read(1, 0, ptbl_sectors, (void > > *)gpt); > > + if (r == -1) { > > + printf("error reading GPT\n"); > > ^^^^^ error() > > > + goto fail; > > + } > > + > > + if (memcmp(gpt->header.magic, "EFI PART", 8)) { > > + printf("efi partition table not found\n"); > > + r = -1; > > ^^^ more often ret is used than r. > > > + goto fail; > > + } > > + > > + for (i = 0; i < EFI_ENTRIES; i++) > > + import_efi_partition(&gpt->entry[i]); > > + > > +fail: > > + return r; > > +} > > + > > +int board_mmc_fbtptn_init(void) > > +{ > > + char *mmc_init[2] = {"mmc", "rescan",}; > > + char dev[2]; > > + char *mmc_dev[3] = {"mmc", "dev", dev}; > > + unsigned fb_mmcdev = CONFIG_FASTOOT_FLASH_MMC_DEV; > > Is your code working with either eMMC or SD > card? > > + > > + sprintf(dev, "0x%x", fb_mmcdev); > > + > > + if (do_mmcops(NULL, 0, 3, mmc_dev)) { > > + printf("MMC DEV: %d selection FAILED!\n", fb_mmcdev); > > + return -1; > > + } > > + > > + if (do_mmcops(NULL, 0, 2, mmc_init)) { > > + printf("FAIL:Init of MMC card\n"); > > + return -1; > > + } > > + > > + return load_ptbl(); > > +} > > + > > + > > +static struct ptable the_ptable; > > + > > +int do_format(void) > > +{ > > + struct ptable *ptbl = &the_ptable; > > + struct mmc *mmc = NULL; > > + unsigned blocks; > > + unsigned next; > > + unsigned sz; > > + int n; > > + unsigned fb_mmcdev = CONFIG_FASTBOOT_FLASH_MMC_DEV; > > + > > + /* get mmc info */ > > + mmc = find_mmc_device(fb_mmcdev); > > + if (mmc == 0) { > > + printf("no mmc device at slot %d", fb_mmcdev); > > + return -1; > > + } > > + > > + mmc->has_init = 0; > > + if (mmc_init(mmc)) { > > + printf("\n mmc init FAILED"); > > + return -1; > > + } > > + > > + printf("\nmmc capacity is: %llu", mmc->capacity); > > + printf("\nmmc: number of blocks:0x%lx", mmc->block_dev.lba); > > + printf("\nmmc: block size:0x%lx", mmc->block_dev.blksz); > > + > > + blocks = mmc->block_dev.lba; > > + > > + start_ptbl(ptbl, blocks); > > + n = 0; > > + next = 0; > > + for (n = 0, next = 0; partitions[n].name; n++) { > > + /* below line change size from KB to no of blocks */ > > + sz = partitions[n].size_kb*2; > > + if (!strcmp(partitions[n].name, "-")) { > > + next += sz; > > + continue; > > + } > > + if (sz == 0) > > + sz = blocks - next; > > + if (add_ptn(ptbl, next, next + sz - 1, > > partitions[n].name)) > > + return -1; > > + next += sz; > > + } > > + end_ptbl(ptbl); > > + > > + fastboot_flash_reset_ptn(); > > + > > + char *mmc_write[5] = {"mmc", "write", NULL, NULL, NULL}; > > + char source[32], dest[32], length[32]; > > + > > + char dev[2]; > > + char *mmc_dev[3] = {"mmc", "dev", NULL}; > > + > > + mmc_dev[2] = dev; > > + sprintf(dev, "0x%x", fb_mmcdev); > > + > > + if (do_mmcops(NULL, 0, 3, mmc_dev)) { > > + printf("MMC DEV: %d selection FAILED!\n", fb_mmcdev); > > + return -1; > > + } > > + > > + mmc_write[2] = source; > > + mmc_write[3] = dest; > > + mmc_write[4] = length; > > + > > + sprintf(source, "%p", (void *)ptbl); > > + sprintf(dest, "0x%x", 0x00); > > + sprintf(length, "0x%x", (sizeof(struct ptable)/512)+1); > > + > > + if (do_mmcops(NULL, 0, 5, mmc_write)) { > > + printf("mbr write FAILED!\n"); > > + return -1; > > + } > > + > > + printf("\nnew partition table:\n"); > > + load_ptbl(); > > + > > + return 0; > > +} > > diff --git a/doc/README.android-fastboot b/doc/README.android-fastboot > > index 1677609..77cce8e 100644 > > --- a/doc/README.android-fastboot > > +++ b/doc/README.android-fastboot > > @@ -6,9 +6,8 @@ Overview > > The protocol that is used over USB is described in > > README.android-fastboot-protocol in same directory. > > > > -The current implementation does not yet support the erase command or > > the -"oem format" command, and there is minimal support for the flash > > command; -it only supports eMMC devices. > > +The current implementation does not yet support the erase command, > > and +there is minimal support for the flash command;it only supports > > eMMC devices. > > Client installation > > =================== > > diff --git a/drivers/usb/gadget/f_fastboot.c > > b/drivers/usb/gadget/f_fastboot.c index 310175a..76ccc55 100644 > > --- a/drivers/usb/gadget/f_fastboot.c > > +++ b/drivers/usb/gadget/f_fastboot.c > > @@ -23,6 +23,8 @@ > > #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV > > #include <fb_mmc.h> > > #endif > > +#include <usb/fastboot.h> > > +#include <command.h> > > > > #define FASTBOOT_VERSION "0.4" > > > > @@ -39,6 +41,12 @@ > > > > #define EP_BUFFER_SIZE 4096 > > > > +/* To support the Android-style naming of flash */ > > +#define MAX_PTN 16 > > +static struct fastboot_ptentry ptable[MAX_PTN]; > > +static unsigned int pcount; > > +/* static int static_pcount = -1; */ > > + > > struct f_fastboot { > > struct usb_function usb_function; > > > > @@ -123,6 +131,33 @@ static struct usb_gadget_strings > > *fastboot_strings[] = { > > static void rx_handler_command(struct usb_ep *ep, struct usb_request > > *req); > > +/* Android style flash utilties */ > > +void fastboot_flash_reset_ptn(void) > > +{ > > +#ifdef DEBUG > > + printf("fastboot flash reset partition..!!"); > > +#endif > > Please use debug(). > > > + pcount = 0; > > +} > > + > > +void fastboot_flash_add_ptn(struct 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++) { > > + struct fastboot_ptentry *ptn = ptable + n; > > + printf("ptn %d name='%s'", n, ptn->name); > > + printf(" start=%d len=%d\n", ptn->start, > > ptn->length); > > + } > > +} > > + > > static void fastboot_complete(struct usb_ep *ep, struct usb_request > > *req) { > > int status = req->status; > > @@ -312,6 +347,21 @@ static int fastboot_tx_write_str(const char > > *buffer) return fastboot_tx_write(buffer, strlen(buffer)); > > } > > > > +struct 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; > > +} > > + > > + > > static void compl_do_reset(struct usb_ep *ep, struct usb_request > > *req) { > > do_reset(NULL, 0, 0, NULL); > > @@ -513,6 +563,27 @@ static void cb_flash(struct usb_ep *ep, struct > > usb_request *req) } > > #endif > > > > +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV > > +int fastboot_oem(const char *cmd) > > +{ > > + if (!strcmp(cmd, "format")) > > + return do_format(); > > + return -1; > > +} > > + > > +static void cb_oem(struct usb_ep *ep, struct usb_request *req) > > +{ > > + char *cmd = req->buf; > > + > > + int r = fastboot_oem(cmd + 4); > > + if (r < 0) { > > + fastboot_tx_write_str("FAIL"); > > + } else { > > + fastboot_tx_write_str("OKAY"); > > + } > > Braces could be removed. > > > +} > > +#endif > > + > > struct cmd_dispatch_info { > > char *cmd; > > void (*cb)(struct usb_ep *ep, struct usb_request *req); > > @@ -541,6 +612,12 @@ static const struct cmd_dispatch_info > > cmd_dispatch_info[] = { .cb = cb_flash, > > }, > > #endif > > +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV > > + { > > + .cmd = "oem", > > + .cb = cb_oem, > > + }, > > +#endif > > }; > > > > static void rx_handler_command(struct usb_ep *ep, struct usb_request > > *req) @@ -576,3 +653,11 @@ static void rx_handler_command(struct > > usb_ep *ep, struct usb_request *req) usb_ep_queue(ep, req, 0); > > } > > } > > + > > +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV > > +int board_partition_init(void) > > +{ > > + board_mmc_fbtptn_init(); > > + return 1; > > +} > > +#endif > > diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h > > new file mode 100644 > > index 0000000..8fee6fc > > --- /dev/null > > +++ b/include/usb/fastboot.h > > @@ -0,0 +1,108 @@ > > +/* > > + * (C) Copyright 2008 - 2009 > > + * Windriver, <www.windriver.com> > > + * Tom Rix <Tom.Rix@windriver.com> > > + * > > + * Copyright (c) 2011 Sebastian Andrzej Siewior > > <bigeasy@linutronix.de> > > + * > > + * > > + * Copyright (C) 2008 The Android Open Source Project > > + * All rights reserved. > > + * > > + * Copyright 2014 Linaro, Ltd. > > + * Dileep Katta <dileep.katta@linaro.org> > > + * > > + * SPDX-License-Identifier: GPL-2.0+ > > + */ > > + > > +#ifndef FASTBOOT_H > > +#define FASTBOOT_H > > + > > +#include <common.h> > > +#include <command.h> > > +#include <environment.h> > > +#include <linux/usb/ch9.h> > > +#include <linux/usb/gadget.h> > > + > > +#ifdef CONFIG_CMD_FASTBOOT > > + > > +/* Android-style flash naming */ > > + > > +/* flash partitions are defined in blocks (flash erase units) */ > > +struct fastboot_ptentry { > > + /* The logical name for this partition, null terminated */ > > + char name[16]; > > + /* start wrt the nand part, must be multiple of nand block > > size */ > > + unsigned int start; > > + /* 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 is repeated. > > + * The base address is incremented. Either 0 or 1 is ok for a default > > + */ > > + > > +#define FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK(n) (n & 0x0f) > > +#define FASTBOOT_PTENTRY_FLAGS_REPEAT_4 0x00000004 > > + > > +/* > > + * 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 > > + > > +/* > > + * Following definitions are to set the ECC to software/Hardware > > + * before writing. HW and SW ECC should not both be set. > > + */ > > + > > + > > +#define FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC 0x00000040 > > +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC 0x00000080 > > +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH4_ECC 0x00000100 > > +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH8_ECC 0x00000200 > > +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH16_ECC 0x00000400 > > + > > +/* Write the file with write.i */ > > +#define FASTBOOT_PTENTRY_FLAGS_WRITE_I 0x00000800 > > + > > +/* Write the file with write.jffs2 */ > > +#define FASTBOOT_PTENTRY_FLAGS_WRITE_JFFS2 0x00001000 > > + > > +/* > > + * Write the file as a series of variable/value pairs > > + * using the setenv and saveenv commands > > + */ > > +#define FASTBOOT_PTENTRY_FLAGS_WRITE_ENV 0x00002000 > > + > > + > > +/* The Android-style flash handling */ > > + > > +/* tools to populate and query the partition table */ > > +void fastboot_flash_add_ptn(struct fastboot_ptentry *ptn); > > +struct fastboot_ptentry *fastboot_flash_find_ptn(const char *name); > > +struct fastboot_ptentry *fastboot_flash_get_ptn(unsigned n); > > +unsigned int fastboot_flash_get_ptn_count(void); > > +void fastboot_flash_dump_ptn(void); > > +int fastboot_oem(const char *cmd); > > +int do_format(void); > > +int board_mmc_fbtptn_init(void); > > +void fastboot_flash_reset_ptn(void); > > +int board_partition_init(void); > > + > > +int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const > > argv[]); + > > +#endif > > +#endif > > To sum up: > > A lot of duplicated code - already present in part_efi.[ch] - is in > this patch. Please rewrite it > > Moreover, please consider using $partitions env variable with gpt write > command to create eMMC partitions. This code is already tested and > validated in u-boot. > > > -- > Best regards, > > Lukasz Majewski > > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group > Thanks for the review. As an abstract patch for "oem format" by Rob Herring is in place, stopping this submission. Regards, Dileep
diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c index b72f4f3..efdf461 100644 --- a/common/cmd_fastboot.c +++ b/common/cmd_fastboot.c @@ -10,12 +10,16 @@ #include <common.h> #include <command.h> #include <g_dnl.h> +#include <usb/fastboot.h> static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { int ret; g_dnl_clear_detach(); +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV + board_partition_init(); +#endif ret = g_dnl_register("usb_dnl_fastboot"); if (ret) return ret; diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index 4e28c9d..0ce747b 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -809,7 +809,7 @@ static cmd_tbl_t cmd_mmc[] = { U_BOOT_CMD_MKENT(setdsr, 2, 0, do_mmc_setdsr, "", ""), }; -static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { cmd_tbl_t *cp; diff --git a/disk/Makefile b/disk/Makefile index 6970cec..4969656 100644 --- a/disk/Makefile +++ b/disk/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_DOS_PARTITION) += part_dos.o obj-$(CONFIG_ISO_PARTITION) += part_iso.o obj-$(CONFIG_AMIGA_PARTITION) += part_amiga.o obj-$(CONFIG_EFI_PARTITION) += part_efi.o +obj-$(CONFIG_FASTBOOT_FLASH_MMC_DEV) +=part_fastboot.o diff --git a/disk/part_fastboot.c b/disk/part_fastboot.c new file mode 100644 index 0000000..adf37af --- /dev/null +++ b/disk/part_fastboot.c @@ -0,0 +1,363 @@ +/* + * Copyright (C) 2013 Texas Instruments + * + * Author : Pankaj Bharadiya <pankaj.bharadiya@ti.com> + * + * Tom Rix <Tom.Rix@windriver.com> and Sitara 2011 u-boot by + * Mohammed Afzal M A <afzal@ti.com> + * + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Copyright 2014 Linaro, Ltd. + * Dileep Katta <dileep.katta@linaro.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <command.h> +#include <usb/fastboot.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <environment.h> +#include <mmc.h> +#include <dfu.h> +#include <asm/arch/mmc_host_def.h> + +#define EFI_VERSION 0x00010000 +#define EFI_ENTRIES 128 +#define EFI_NAMELEN 36 + +struct partition_emmc { + const char *name; + unsigned size_kb; +}; + +/* eMMC partition layout (All sizes are in kB) + * Modify the below partition table to change the GPT configuration. + * The entry for each partition can be modified as per the requirement. + */ +static struct partition_emmc partitions[] = { + { "-", 128 }, /* Master Boot Record and GUID Partition Table */ + { "spl", 128 }, /* First stage bootloader */ + { "bootloader", 512 }, /* Second stage bootloader */ + { "misc", 128 }, /* Rserved for internal purpose */ + { "-", 128 }, /* Reserved */ + { "recovery", 8*1024 }, /* Recovery partition */ + { "boot", 8*1024 }, /* Partition contains kernel + ramdisk images */ + { "system", 256*1024 }, /* Android file system */ + { "cache", 256*1024 }, /* Store Application Cache */ + { "userdata", 256*1024 }, /* User data */ + { "media", 0 }, /* Media files */ + { 0, 0 }, +}; + + +static const u8 partition_type[16] = { + 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44, + 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7, +}; + +static const u8 random_uuid[16] = { + 0xff, 0x1f, 0xf2, 0xf9, 0xd4, 0xa8, 0x0e, 0x5f, + 0x97, 0x46, 0x59, 0x48, 0x69, 0xae, 0xc3, 0x4e, +}; + +struct efi_entry { + u8 type_uuid[16]; + u8 uniq_uuid[16]; + u64 first_lba; + u64 last_lba; + u64 attr; + u16 name[EFI_NAMELEN]; +}; + +struct efi_header { + u8 magic[8]; + + u32 version; + u32 header_sz; + + u32 crc32; + u32 reserved; + + u64 header_lba; + u64 backup_lba; + u64 first_lba; + u64 last_lba; + + u8 volume_uuid[16]; + + u64 entries_lba; + + u32 entries_count; + u32 entries_size; + u32 entries_crc32; +} __packed; + +struct ptable { + u8 mbr[512]; + union { + struct efi_header header; + u8 block[512]; + }; + struct efi_entry entry[EFI_ENTRIES]; +}; + +static void init_mbr(u8 *mbr, u32 blocks) +{ + mbr[0x1be] = 0x00; /* nonbootable */ + mbr[0x1bf] = 0xFF; /* bogus CHS */ + mbr[0x1c0] = 0xFF; + mbr[0x1c1] = 0xFF; + + mbr[0x1c2] = 0xEE; /* GPT partition */ + mbr[0x1c3] = 0xFF; /* bogus CHS */ + mbr[0x1c4] = 0xFF; + mbr[0x1c5] = 0xFF; + + mbr[0x1c6] = 0x01; /* start */ + mbr[0x1c7] = 0x00; + mbr[0x1c8] = 0x00; + mbr[0x1c9] = 0x00; + + memcpy(mbr + 0x1ca, &blocks, sizeof(u32)); + + mbr[0x1fe] = 0x55; + mbr[0x1ff] = 0xaa; +} + + +static void start_ptbl(struct ptable *ptbl, unsigned blocks) +{ + struct efi_header *hdr = &ptbl->header; + + memset(ptbl, 0, sizeof(*ptbl)); + + init_mbr(ptbl->mbr, blocks - 1); + + memcpy(hdr->magic, "EFI PART", 8); + hdr->version = EFI_VERSION; + hdr->header_sz = sizeof(struct efi_header); + hdr->header_lba = 1; + hdr->backup_lba = blocks - 1; + hdr->first_lba = 34; + hdr->last_lba = blocks - 1; + memcpy(hdr->volume_uuid, random_uuid, 16); + hdr->entries_lba = 2; + hdr->entries_count = EFI_ENTRIES; + hdr->entries_size = sizeof(struct efi_entry); +} + +static void end_ptbl(struct ptable *ptbl) +{ + struct efi_header *hdr = &ptbl->header; + u32 n; + + /* Get the initial checksum by passing buf as NULL */ + n = crc32(0, NULL, 0); + n = crc32(n, (void *)ptbl->entry, sizeof(ptbl->entry)); + hdr->entries_crc32 = n; + + n = crc32(0, (void *)&ptbl->header, sizeof(ptbl->header)); + hdr->crc32 = n; +} + +int add_ptn(struct ptable *ptbl, u64 first, u64 last, const char *name) +{ + struct efi_header *hdr = &ptbl->header; + struct efi_entry *entry = ptbl->entry; + unsigned n; + + if (first < 34) { + printf("partition '%s' overlaps partition table\n", name); + return -1; + } + + if (last > hdr->last_lba) { + printf("partition '%s' does not fit\n", name); + return -1; + } + for (n = 0; n < EFI_ENTRIES; n++, entry++) { + if (entry->last_lba) + continue; + memcpy(entry->type_uuid, partition_type, 16); + memcpy(entry->uniq_uuid, random_uuid, 16); + entry->uniq_uuid[0] = n; + entry->first_lba = first; + entry->last_lba = last; + for (n = 0; (n < EFI_NAMELEN) && *name; n++) + entry->name[n] = *name++; + return 0; + } + printf("out of partition table entries\n"); + return -1; +} + +void import_efi_partition(struct efi_entry *entry) +{ + struct fastboot_ptentry e; + int n; + if (memcmp(entry->type_uuid, partition_type, sizeof(partition_type))) + return; + for (n = 0; n < (sizeof(e.name)-1); n++) + e.name[n] = entry->name[n]; + e.name[n] = 0; + e.start = entry->first_lba; + e.length = (entry->last_lba - entry->first_lba + 1) * 512; + e.flags = 0; + + if (!strcmp(e.name, "environment")) + e.flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_ENV; + fastboot_flash_add_ptn(&e); + + if (e.length > 0x100000) + printf("%8d %7dM %s\n", e.start, e.length/0x100000, e.name); + else + printf("%8d %7dK %s\n", e.start, e.length/0x400, e.name); +} + +static int load_ptbl(void) +{ + u64 ptbl_sectors = 0; + int i = 0, r = 0; + + struct ptable gpt[sizeof(struct ptable)]; + struct mmc *mmc = NULL; + + mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV); + if (mmc == NULL) { + printf("No MMC in slot 1\n"); + return -1; + } + + int gpt_size = sizeof(struct ptable); + + ptbl_sectors = (u64)(gpt_size / MMCSD_SECTOR_SIZE); + + r = mmc->block_dev.block_read(1, 0, ptbl_sectors, (void *)gpt); + if (r == -1) { + printf("error reading GPT\n"); + goto fail; + } + + if (memcmp(gpt->header.magic, "EFI PART", 8)) { + printf("efi partition table not found\n"); + r = -1; + goto fail; + } + + for (i = 0; i < EFI_ENTRIES; i++) + import_efi_partition(&gpt->entry[i]); + +fail: + return r; +} + +int board_mmc_fbtptn_init(void) +{ + char *mmc_init[2] = {"mmc", "rescan",}; + char dev[2]; + char *mmc_dev[3] = {"mmc", "dev", dev}; + unsigned fb_mmcdev = CONFIG_FASTBOOT_FLASH_MMC_DEV; + + sprintf(dev, "0x%x", fb_mmcdev); + + if (do_mmcops(NULL, 0, 3, mmc_dev)) { + printf("MMC DEV: %d selection FAILED!\n", fb_mmcdev); + return -1; + } + + if (do_mmcops(NULL, 0, 2, mmc_init)) { + printf("FAIL:Init of MMC card\n"); + return -1; + } + + return load_ptbl(); +} + + +static struct ptable the_ptable; + +int do_format(void) +{ + struct ptable *ptbl = &the_ptable; + struct mmc *mmc = NULL; + unsigned blocks; + unsigned next; + unsigned sz; + int n; + unsigned fb_mmcdev = CONFIG_FASTBOOT_FLASH_MMC_DEV; + + /* get mmc info */ + mmc = find_mmc_device(fb_mmcdev); + if (mmc == 0) { + printf("no mmc device at slot %d", fb_mmcdev); + return -1; + } + + mmc->has_init = 0; + if (mmc_init(mmc)) { + printf("\n mmc init FAILED"); + return -1; + } + + printf("\nmmc capacity is: %llu", mmc->capacity); + printf("\nmmc: number of blocks:0x%lx", mmc->block_dev.lba); + printf("\nmmc: block size:0x%lx", mmc->block_dev.blksz); + + blocks = mmc->block_dev.lba; + + start_ptbl(ptbl, blocks); + n = 0; + next = 0; + for (n = 0, next = 0; partitions[n].name; n++) { + /* below line change size from KB to no of blocks */ + sz = partitions[n].size_kb*2; + if (!strcmp(partitions[n].name, "-")) { + next += sz; + continue; + } + if (sz == 0) + sz = blocks - next; + if (add_ptn(ptbl, next, next + sz - 1, partitions[n].name)) + return -1; + next += sz; + } + end_ptbl(ptbl); + + fastboot_flash_reset_ptn(); + + char *mmc_write[5] = {"mmc", "write", NULL, NULL, NULL}; + char source[32], dest[32], length[32]; + + char dev[2]; + char *mmc_dev[3] = {"mmc", "dev", NULL}; + + mmc_dev[2] = dev; + sprintf(dev, "0x%x", fb_mmcdev); + + if (do_mmcops(NULL, 0, 3, mmc_dev)) { + printf("MMC DEV: %d selection FAILED!\n", fb_mmcdev); + return -1; + } + + mmc_write[2] = source; + mmc_write[3] = dest; + mmc_write[4] = length; + + sprintf(source, "%p", (void *)ptbl); + sprintf(dest, "0x%x", 0x00); + sprintf(length, "0x%x", (sizeof(struct ptable)/512)+1); + + if (do_mmcops(NULL, 0, 5, mmc_write)) { + printf("mbr write FAILED!\n"); + return -1; + } + + printf("\nnew partition table:\n"); + load_ptbl(); + + return 0; +} diff --git a/doc/README.android-fastboot b/doc/README.android-fastboot index 1677609..77cce8e 100644 --- a/doc/README.android-fastboot +++ b/doc/README.android-fastboot @@ -6,9 +6,8 @@ Overview The protocol that is used over USB is described in README.android-fastboot-protocol in same directory. -The current implementation does not yet support the erase command or the -"oem format" command, and there is minimal support for the flash command; -it only supports eMMC devices. +The current implementation does not yet support the erase command, and +there is minimal support for the flash command;it only supports eMMC devices. Client installation =================== diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 310175a..76ccc55 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -23,6 +23,8 @@ #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV #include <fb_mmc.h> #endif +#include <usb/fastboot.h> +#include <command.h> #define FASTBOOT_VERSION "0.4" @@ -39,6 +41,12 @@ #define EP_BUFFER_SIZE 4096 +/* To support the Android-style naming of flash */ +#define MAX_PTN 16 +static struct fastboot_ptentry ptable[MAX_PTN]; +static unsigned int pcount; +/* static int static_pcount = -1; */ + struct f_fastboot { struct usb_function usb_function; @@ -123,6 +131,33 @@ static struct usb_gadget_strings *fastboot_strings[] = { static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); +/* Android style flash utilties */ +void fastboot_flash_reset_ptn(void) +{ +#ifdef DEBUG + printf("fastboot flash reset partition..!!"); +#endif + pcount = 0; +} + +void fastboot_flash_add_ptn(struct 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++) { + struct fastboot_ptentry *ptn = ptable + n; + printf("ptn %d name='%s'", n, ptn->name); + printf(" start=%d len=%d\n", ptn->start, ptn->length); + } +} + static void fastboot_complete(struct usb_ep *ep, struct usb_request *req) { int status = req->status; @@ -312,6 +347,21 @@ static int fastboot_tx_write_str(const char *buffer) return fastboot_tx_write(buffer, strlen(buffer)); } +struct 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; +} + + static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) { do_reset(NULL, 0, 0, NULL); @@ -513,6 +563,27 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req) } #endif +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV +int fastboot_oem(const char *cmd) +{ + if (!strcmp(cmd, "format")) + return do_format(); + return -1; +} + +static void cb_oem(struct usb_ep *ep, struct usb_request *req) +{ + char *cmd = req->buf; + + int r = fastboot_oem(cmd + 4); + if (r < 0) { + fastboot_tx_write_str("FAIL"); + } else { + fastboot_tx_write_str("OKAY"); + } +} +#endif + struct cmd_dispatch_info { char *cmd; void (*cb)(struct usb_ep *ep, struct usb_request *req); @@ -541,6 +612,12 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = { .cb = cb_flash, }, #endif +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV + { + .cmd = "oem", + .cb = cb_oem, + }, +#endif }; static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) @@ -576,3 +653,11 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) usb_ep_queue(ep, req, 0); } } + +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV +int board_partition_init(void) +{ + board_mmc_fbtptn_init(); + return 1; +} +#endif diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h new file mode 100644 index 0000000..8fee6fc --- /dev/null +++ b/include/usb/fastboot.h @@ -0,0 +1,108 @@ +/* + * (C) Copyright 2008 - 2009 + * Windriver, <www.windriver.com> + * Tom Rix <Tom.Rix@windriver.com> + * + * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de> + * + * + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Copyright 2014 Linaro, Ltd. + * Dileep Katta <dileep.katta@linaro.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef FASTBOOT_H +#define FASTBOOT_H + +#include <common.h> +#include <command.h> +#include <environment.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> + +#ifdef CONFIG_CMD_FASTBOOT + +/* Android-style flash naming */ + +/* flash partitions are defined in blocks (flash erase units) */ +struct fastboot_ptentry { + /* The logical name for this partition, null terminated */ + char name[16]; + /* start wrt the nand part, must be multiple of nand block size */ + unsigned int start; + /* 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 is repeated. + * The base address is incremented. Either 0 or 1 is ok for a default + */ + +#define FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK(n) (n & 0x0f) +#define FASTBOOT_PTENTRY_FLAGS_REPEAT_4 0x00000004 + +/* + * 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 + +/* + * Following definitions are to set the ECC to software/Hardware + * before writing. HW and SW ECC should not both be set. + */ + + +#define FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC 0x00000040 +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC 0x00000080 +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH4_ECC 0x00000100 +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH8_ECC 0x00000200 +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH16_ECC 0x00000400 + +/* Write the file with write.i */ +#define FASTBOOT_PTENTRY_FLAGS_WRITE_I 0x00000800 + +/* Write the file with write.jffs2 */ +#define FASTBOOT_PTENTRY_FLAGS_WRITE_JFFS2 0x00001000 + +/* + * Write the file as a series of variable/value pairs + * using the setenv and saveenv commands + */ +#define FASTBOOT_PTENTRY_FLAGS_WRITE_ENV 0x00002000 + + +/* The Android-style flash handling */ + +/* tools to populate and query the partition table */ +void fastboot_flash_add_ptn(struct fastboot_ptentry *ptn); +struct fastboot_ptentry *fastboot_flash_find_ptn(const char *name); +struct fastboot_ptentry *fastboot_flash_get_ptn(unsigned n); +unsigned int fastboot_flash_get_ptn_count(void); +void fastboot_flash_dump_ptn(void); +int fastboot_oem(const char *cmd); +int do_format(void); +int board_mmc_fbtptn_init(void); +void fastboot_flash_reset_ptn(void); +int board_partition_init(void); + +int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); + +#endif +#endif
This is the Modified version of http://patchwork.ozlabs.org/patch/388084/ - As flash support is already in mainline, it is removed - 'oem' command support is present - 'oem format' command is implemented - Handled review comments of the original patch Signed-off-by: Dileep Katta <dileep.katta@linaro.org> --- common/cmd_fastboot.c | 4 + common/cmd_mmc.c | 2 +- disk/Makefile | 1 + disk/part_fastboot.c | 363 ++++++++++++++++++++++++++++++++++++++++ doc/README.android-fastboot | 5 +- drivers/usb/gadget/f_fastboot.c | 85 ++++++++++ include/usb/fastboot.h | 108 ++++++++++++ 7 files changed, 564 insertions(+), 4 deletions(-) create mode 100644 disk/part_fastboot.c create mode 100644 include/usb/fastboot.h