12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883 |
- /*
- * Copyright 2008 - 2009 (C) Wind River Systems, Inc.
- * Tom Rix <Tom.Rix@windriver.com>
- *
- * Copyright (C) 2010-2012 Freescale Semiconductor, Inc.
- *
- * 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 <common.h>
- #include <command.h>
- #include <nand.h>
- #include <fastboot.h>
- #include <environment.h>
- #ifdef CONFIG_FASTBOOT
- /* Use do_reset for fastboot's 'reboot' command */
- extern int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
- /* Use do_nand for fastboot's flash commands */
- #if defined(CONFIG_FASTBOOT_STORAGE_NAND)
- extern int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
- #elif defined(CONFIG_FASTBOOT_STORAGE_EMMC_SATA)
- extern int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
- #if defined(CONFIG_CMD_SATA)
- extern int do_sata(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
- #endif
- extern env_t *env_ptr;
- #endif
- //extern int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
- /* Use do_setenv and do_saveenv to permenantly save data */
- //int do_saveenv(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
- int do_setenv(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
- /* Use do_bootm and do_go for fastboot's 'boot' command */
- int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
- int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
- /* Forward decl */
- static int tx_handler(void);
- static int rx_handler(const unsigned char *buffer, unsigned int buffer_size);
- static void reset_handler(void);
- static struct cmd_fastboot_interface interface = {
- .rx_handler = rx_handler,
- .reset_handler = reset_handler,
- .product_name = NULL,
- .serial_no = NULL,
- .nand_block_size = 0,
- .transfer_buffer = (unsigned char *)0xffffffff,
- .transfer_buffer_size = 0,
- };
- extern struct fastboot_device_info fastboot_devinfo;
- static unsigned int download_size;
- static unsigned int download_bytes;
- static unsigned int download_bytes_unpadded;
- static unsigned int download_error;
- static unsigned int continue_booting;
- static unsigned int upload_size;
- static unsigned int upload_bytes;
- static unsigned int upload_error;
- /* To support the Android-style naming of flash */
- #define MAX_PTN 16
- #define MMC_SATA_BLOCK_SIZE 512
- static fastboot_ptentry ptable[MAX_PTN];
- static unsigned int pcount;
- static int static_pcount = -1;
- #ifdef CONFIG_FASTBOOT_STORAGE_NAND
- static void set_env(char *var, char *val)
- {
- char *setenv[4] = { "setenv", NULL, NULL, NULL, };
- setenv[1] = var;
- setenv[2] = val;
- do_setenv(NULL, 0, 3, setenv);
- }
- static void save_env(struct fastboot_ptentry *ptn,
- char *var, char *val)
- {
- char start[32], length[32];
- char ecc_type[32];
- char *lock[5] = { "nand", "lock", NULL, NULL, NULL, };
- char *unlock[5] = { "nand", "unlock", NULL, NULL, NULL, };
- char *ecc[4] = { "nand", "ecc", NULL, NULL, };
- char *saveenv[2] = { "setenv", NULL, };
- lock[2] = unlock[2] = start;
- lock[3] = unlock[3] = length;
- set_env(var, val);
- /* 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");
- do_nand(NULL, 0, 3, ecc);
- } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) {
- sprintf(ecc_type, "sw");
- do_nand(NULL, 0, 3, ecc);
- }
- sprintf(start, "0x%x", ptn->start);
- sprintf(length, "0x%x", ptn->length);
- /* This could be a problem is there is an outstanding lock */
- do_nand(NULL, 0, 4, unlock);
- //do_saveenv(NULL, 0, 1, saveenv);
- do_nand(NULL, 0, 4, lock);
- }
- static void save_block_values(struct fastboot_ptentry *ptn,
- unsigned int offset,
- unsigned int size)
- {
- struct fastboot_ptentry *env_ptn;
- char var[64], val[32];
- char start[32], length[32];
- char ecc_type[32];
- char *lock[5] = { "nand", "lock", NULL, NULL, NULL, };
- char *unlock[5] = { "nand", "unlock", NULL, NULL, NULL, };
- char *ecc[4] = { "nand", "ecc", NULL, NULL, };
- char *setenv[4] = { "setenv", NULL, NULL, NULL, };
- char *saveenv[2] = { "setenv", NULL, };
- setenv[1] = var;
- setenv[2] = val;
- lock[2] = unlock[2] = start;
- lock[3] = unlock[3] = length;
- printf("saving it..\n");
- if (size == 0) {
- /* The error case, where the variables are being unset */
- sprintf(var, "%s_nand_offset", ptn->name);
- sprintf(val, "");
- do_setenv(NULL, 0, 3, setenv);
- sprintf(var, "%s_nand_size", ptn->name);
- sprintf(val, "");
- do_setenv(NULL, 0, 3, setenv);
- } else {
- /* Normal case */
- sprintf(var, "%s_nand_offset", ptn->name);
- sprintf(val, "0x%x", offset);
- printf("%s %s %s\n", setenv[0], setenv[1], setenv[2]);
- do_setenv(NULL, 0, 3, setenv);
- sprintf(var, "%s_nand_size", ptn->name);
- sprintf(val, "0x%x", size);
- printf("%s %s %s\n", setenv[0], setenv[1], setenv[2]);
- do_setenv(NULL, 0, 3, setenv);
- }
- /* Warning :
- The environment is assumed to be in a partition named 'enviroment'.
- It is very possible that your board stores the enviroment
- someplace else. */
- env_ptn = fastboot_flash_find_ptn("environment");
- if (env_ptn) {
- /* Some flashing requires the nand's ecc to be set */
- ecc[2] = ecc_type;
- if ((env_ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) &&
- (env_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 (env_ptn->flags &
- FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) {
- sprintf(ecc_type, "hw");
- do_nand(NULL, 0, 3, ecc);
- } else if (env_ptn->flags &
- FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) {
- sprintf(ecc_type, "sw");
- do_nand(NULL, 0, 3, ecc);
- }
- sprintf(start, "0x%x", env_ptn->start);
- sprintf(length, "0x%x", env_ptn->length);
- /* This could be a problem is there is an outstanding lock */
- do_nand(NULL, 0, 4, unlock);
- }
- //do_saveenv(NULL, 0, 1, saveenv);
- if (env_ptn)
- do_nand(NULL, 0, 4, lock);
- }
- #else
- /* will do later */
- #endif
- 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;
- continue_booting = 0;
- upload_size = 0;
- upload_bytes = 0;
- upload_error = 0;
- }
- #ifdef CONFIG_FASTBOOT_STORAGE_NAND
- /* 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;
- unsigned int comment_start = 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) {
- /*
- * Check for comments, comment ok only on
- * mostly empty lines
- */
- if (buff[i] == '#')
- comment_start = 1;
- if (comment_start) {
- if ((buff[i] == '\r') ||
- (buff[i] == '\n')) {
- comment_start = 0;
- }
- } else {
- if (!((buff[i] == ' ') ||
- (buff[i] == '\t') ||
- (buff[i] == '\r') ||
- (buff[i] == '\n'))) {
- /*
- * Normal whitespace before the
- * variable
- */
- 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 void set_ptn_ecc(struct fastboot_ptentry *ptn)
- {
- char ecc_type[32];
- char *ecc[4] = {"nand", "ecc", NULL, NULL, };
- /* 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");
- do_nand(NULL, 0, 3, ecc);
- } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) {
- sprintf(ecc_type, "sw");
- do_nand(NULL, 0, 3, ecc);
- }
- }
- 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 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 *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");
- set_ptn_ecc(ptn);
- /* 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));
- do_nand(NULL, 0, 4, unlock);
- do_nand(NULL, 0, 4, erase);
- 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);
- ret = do_nand(NULL, 0, 5, write);
- 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) {
- /* Keep writing until you get a good block
- transfer_buffer should already be aligned */
- if (interface.nand_block_size) {
- if (0 == nand_curr_device) {
- nand_info_t *nand;
- unsigned long off;
- unsigned int ok_start;
- nand = &nand_info[nand_curr_device];
- printf("\nDevice %d bad blocks:\n",
- nand_curr_device);
- /* Initialize the ok_start to the
- start of the partition
- Then try to find a block large
- enough for the download */
- ok_start = ptn->start;
- /* It is assumed that the start and
- length are multiples of block size */
- for (off = ptn->start;
- off < ptn->start + ptn->length;
- off += nand->erasesize) {
- if (nand_block_isbad(nand, off)) {
- /* Reset the ok_start
- to the next block */
- ok_start = off +
- nand->erasesize;
- }
- /* Check if we have enough
- blocks */
- if ((ok_start - off) >=
- download_bytes)
- break;
- }
- /* Check if there is enough space */
- if (ok_start + download_bytes <=
- ptn->start + ptn->length) {
- sprintf(addr, "0x%p",
- interface.transfer_buffer);
- sprintf(wstart, "0x%x", ok_start);
- sprintf(wlength, "0x%x", download_bytes);
- ret = do_nand(NULL, 0, 5, write);
- /* Save the results into an
- environment variable on the
- format
- ptn_name + 'offset'
- ptn_name + 'size' */
- if (ret) {
- /* failed */
- save_block_values(ptn, 0, 0);
- } else {
- /* success */
- save_block_values(ptn, ok_start, download_bytes);
- }
- } else {
- printf("Error could not find enough contiguous space in partition '%s' \n", ptn->name);
- printf("Ignoring write request\n");
- }
- } else {
- /* TBD : Generalize flash handling */
- printf("Error only handling 1 NAND per board");
- printf("Ignoring write request\n");
- }
- } else {
- printf("Warning nand block size can not be 0 \
- when using 'continuous block' for \
- partition '%s'\n", ptn->name);
- printf("Ignoring write request\n");
- }
- } 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
- ret = do_nand(NULL, 0, 5, write);
- if (0 == repeat) {
- if (ret) /* failed */
- save_block_values(ptn, 0, 0);
- else /* success */
- save_block_values(ptn, ptn->start,
- download_bytes);
- }
- }
- do_nand(NULL, 0, 4, lock);
- if (ret)
- break;
- }
- return ret;
- }
- #else
- /* will do environment writing/saving later */
- #endif
- static int tx_handler(void)
- {
- if (upload_size) {
- int bytes_written;
- bytes_written = fastboot_tx(interface.transfer_buffer +
- upload_bytes, upload_size -
- upload_bytes);
- if (bytes_written > 0) {
- upload_bytes += bytes_written;
- /* Check if this is the last */
- if (upload_bytes == upload_size) {
- /* Reset upload */
- upload_size = 0;
- upload_bytes = 0;
- upload_error = 0;
- }
- }
- }
- return upload_error;
- }
- static int rx_handler (const unsigned char *buffer, unsigned int buffer_size)
- {
- int ret = 1, temp_len = 0;
- /* Use 65 instead of 64
- null gets dropped
- strcpy's need the extra byte */
- char response[65];
- if (download_size) {
- /* Something to download */
- if (buffer_size) {
- /* Handle possible overflow */
- unsigned int transfer_size =
- download_size - download_bytes;
- 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;
- if (download_error) {
- /* There was an earlier error */
- sprintf(response, "ERROR");
- } else {
- /* Everything has transferred,
- send the OK response */
- sprintf(response, "OKAY");
- }
- fastboot_tx_status(response, strlen(response));
- printf("\ndownloading of %d bytes finished\n",
- download_bytes);
- #if defined(CONFIG_FASTBOOT_STORAGE_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++;
- }
- }
- }
- #endif
- }
- /* 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");
- }
- } else {
- /* Ignore empty buffers */
- printf("Warning empty download buffer\n");
- printf("Ignoring\n");
- }
- ret = 0;
- } else {
- /* A command */
- /* Cast to make compiler happy with string functions */
- const char *cmdbuf = (char *) buffer;
- printf("cmdbuf: %s\n", cmdbuf);
- /* Generic failed response */
- sprintf(response, "FAIL");
- /* reboot
- Reboot the board. */
- if (memcmp(cmdbuf, "reboot", 6) == 0) {
- sprintf(response, "OKAY");
- fastboot_tx_status(response, strlen(response));
- udelay(1000000); /* 1 sec */
- do_reset(NULL, 0, 0, NULL);
- /* This code is unreachable,
- leave it to make the compiler happy */
- return 0;
- }
- /* getvar
- Get common fastboot variables
- Board has a chance to handle other variables */
- if (memcmp(cmdbuf, "getvar:", 7) == 0) {
- strcpy(response, "OKAY");
- temp_len = strlen("getvar:");
- if (!strcmp(cmdbuf + temp_len, "version")) {
- strcpy(response + 4, FASTBOOT_VERSION);
- } else if (!strcmp(cmdbuf + temp_len,
- "product")) {
- if (interface.product_name)
- strcpy(response + 4, interface.product_name);
- } else if (!strcmp(cmdbuf + temp_len,
- "serialno")) {
- if (interface.serial_no)
- strcpy(response + 4, interface.serial_no);
- } else if (!strcmp(cmdbuf + temp_len,
- "downloadsize")) {
- if (interface.transfer_buffer_size)
- sprintf(response + 4, "0x%x",
- interface.transfer_buffer_size);
- } else {
- fastboot_getvar(cmdbuf + 7, response + 4);
- }
- ret = 0;
- }
- /* erase
- Erase a register flash partition
- Board has to set up flash partitions */
- if (memcmp(cmdbuf, "erase:", 6) == 0) {
- #if defined(CONFIG_FASTBOOT_STORAGE_NAND)
- struct fastboot_ptentry *ptn;
- ptn = fastboot_flash_find_ptn(cmdbuf + 6);
- if (ptn == 0) {
- sprintf(response, "FAILpartition does not exist");
- } else {
- char start[32], length[32];
- int status, 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));
- do_nand(NULL, 0, 4, unlock);
- status = do_nand(NULL, 0, 4, erase);
- do_nand(NULL, 0, 4, lock);
- if (status)
- break;
- }
- if (status) {
- sprintf(response,
- "FAILfailed to erase partition");
- } else {
- printf("partition '%s' erased\n", ptn->name);
- sprintf(response, "OKAY");
- }
- }
- ret = 0;
- #else
- printf("Not support erase command for EMMC\n");
- ret = -1;
- #endif
- }
- /* download
- download something ..
- What happens to it depends on the next command after data */
- if (memcmp(cmdbuf, "download:", 9) == 0) {
- /* save the size */
- download_size = simple_strtoul(cmdbuf + 9, 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);
- }
- ret = 0;
- }
- /* boot
- boot what was downloaded
- WARNING WARNING WARNING
- This is not what you expect.
- The fastboot client does its own packaging of the
- kernel. The layout is defined in the android header
- file bootimage.h. This layeout is copiedlooks like this,
- **
- ** +-----------------+
- ** | boot header | 1 page
- ** +-----------------+
- ** | kernel | n pages
- ** +-----------------+
- ** | ramdisk | m pages
- ** +-----------------+
- ** | second stage | o pages
- ** +-----------------+
- **
- We only care about the kernel.
- So we have to jump past a page.
- What is a page size ?
- The fastboot client uses 2048
- The is the default value of
- CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE
- */
- if (memcmp(cmdbuf, "boot", 4) == 0) {
- if ((download_bytes) &&
- (CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE <
- download_bytes)) {
- char start[32];
- char *booti_args[4] = {"booti", NULL, "boot", NULL};
- /*
- * Use this later to determine if a command line was passed
- * for the kernel.
- */
- /* struct fastboot_boot_img_hdr *fb_hdr = */
- /* (struct fastboot_boot_img_hdr *) interface.transfer_buffer; */
- /* Skip the mkbootimage header */
- /* image_header_t *hdr = */
- /* (image_header_t *) */
- /* &interface.transfer_buffer[CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE]; */
- booti_args[1] = start;
- sprintf(start, "0x%x", (unsigned int)interface.transfer_buffer);
- /* Execution should jump to kernel so send the response
- now and wait a bit. */
- sprintf(response, "OKAY");
- fastboot_tx_status(response, strlen(response));
- printf("Booting kernel...\n");
- /* Reserve for further use, this can
- * be more convient for developer. */
- /* if (strlen ((char *) &fb_hdr->cmdline[0])) */
- /* set_env("bootargs", (char *) &fb_hdr->cmdline[0]); */
- /* boot the boot.img */
- //do_booti(NULL, 0, 3, booti_args);
- }
- sprintf(response, "FAILinvalid boot image");
- ret = 0;
- }
- /* flash
- Flash what was downloaded */
- if (memcmp(cmdbuf, "flash:", 6) == 0) {
- #if defined(CONFIG_FASTBOOT_STORAGE_NAND)
- if (download_bytes) {
- struct fastboot_ptentry *ptn;
- ptn = fastboot_flash_find_ptn(cmdbuf + 6);
- 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");
- }
- #elif defined(CONFIG_FASTBOOT_STORAGE_EMMC_SATA)
- if (download_bytes) {
- struct fastboot_ptentry *ptn;
- /* Next is the partition name */
- ptn = fastboot_flash_find_ptn(cmdbuf + 6);
- if (ptn == 0) {
- printf("Partition:'%s' does not exist\n", ptn->name);
- sprintf(response, "FAILpartition does not exist");
- } else if ((download_bytes >
- ptn->length * MMC_SATA_BLOCK_SIZE) &&
- !(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) {
- /* Check if this is not really a flash write,
- * but instead a saveenv
- */
- unsigned int i = 0;
- /* Env file is expected with a NULL delimeter between
- * env variables So replace New line Feeds (0x0a) with
- * NULL (0x00)
- */
- printf("Goto write env, flags=0x%x\n",
- ptn->flags);
- for (i = 0; i < download_bytes; i++) {
- if (interface.transfer_buffer[i] == 0x0a)
- interface.transfer_buffer[i] = 0x00;
- }
- memset(env_ptr->data, 0, ENV_SIZE);
- memcpy(env_ptr->data, interface.transfer_buffer, download_bytes);
- //do_saveenv(NULL, 0, 1, NULL);
- printf("saveenv to '%s' DONE!\n", ptn->name);
- sprintf(response, "OKAY");
- } else {
- char source[32], dest[32];
- char length[32], slot_no[32];
- char part_no[32];
- unsigned int temp;
- /* Normal case */
- if (fastboot_devinfo.type == DEV_MMC)
- /* download to mmc */
- goto mmc_ops;
- else {
- /* downaload to sata */
- #ifdef CONFIG_CMD_SATA
- char *sata_write[5] = {"sata", "write",
- NULL, NULL, NULL};
- sata_write[2] = source;
- sata_write[3] = dest;
- sata_write[4] = length;
- sprintf(source, "0x%x",
- (unsigned int)interface.transfer_buffer);
- /* block offset */
- sprintf(dest, "0x%x", ptn->start);
- /* block count */
- temp = (download_bytes +
- MMC_SATA_BLOCK_SIZE - 1) /
- MMC_SATA_BLOCK_SIZE;
- sprintf(length, "0x%x", temp);
- if (do_sata(NULL, 0, 5, sata_write)) {
- printf("Writing '%s' FAILED!\n",
- ptn->name);
- sprintf(response,
- "FAIL: Write partition");
- } else {
- printf("Writing '%s' DONE!\n",
- ptn->name);
- sprintf(response, "OKAY");
- ret = 0;
- }
- #else
- sprintf(response, "FAIL: Not support");
- #endif
- fastboot_tx_status(response,
- strlen(response));
- return ret; /* End of sata download */
- }
- mmc_ops:
- printf("writing to partition '%s'\n", ptn->name);
- char *mmc_write[5] = {"mmc", "write",
- NULL, NULL, NULL};
- char *mmc_dev[4] = {"mmc", "dev", NULL, NULL};
- mmc_dev[2] = slot_no;
- mmc_dev[3] = part_no;
- mmc_write[2] = source;
- mmc_write[3] = dest;
- mmc_write[4] = length;
- sprintf(slot_no, "%d",
- fastboot_devinfo.dev_id);
- sprintf(source, "0x%x", (unsigned int)interface.transfer_buffer);
- /* partition no */
- sprintf(part_no, "%d",
- ptn->partition_id);
- /* block offset */
- sprintf(dest, "0x%x", ptn->start);
- /* block count */
- temp = (download_bytes +
- MMC_SATA_BLOCK_SIZE - 1) /
- MMC_SATA_BLOCK_SIZE;
- sprintf(length, "0x%x", temp);
- printf("Initializing '%s'\n", ptn->name);
- if(1)
- //if (do_mmcops(NULL, 0, 4, mmc_dev))
- sprintf(response, "FAIL:Init of MMC card");
- else
- sprintf(response, "OKAY");
- printf("Writing '%s'\n", ptn->name);
- if(1) {
- //if (do_mmcops(NULL, 0, 5, mmc_write)) {
- printf("Writing '%s' FAILED!\n", ptn->name);
- sprintf(response, "FAIL: Write partition");
- } else {
- printf("Writing '%s' DONE!\n", ptn->name);
- sprintf(response, "OKAY");
- }
- }
- } else {
- sprintf(response, "FAILno image downloaded");
- }
- #endif
- ret = 0;
- }
- /* continue
- Stop doing fastboot */
- if (memcmp(cmdbuf, "continue", 8) == 0) {
- sprintf(response, "OKAY");
- continue_booting = 1;
- ret = 0;
- }
- /* upload
- Upload just the data in a partition */
- if ((memcmp(cmdbuf, "upload:", 7) == 0) ||
- (memcmp(cmdbuf, "uploadraw:", 10) == 0)) {
- #if defined(CONFIG_FASTBOOT_STORAGE_NAND)
- unsigned int adv, delim_index, len;
- struct fastboot_ptentry *ptn;
- unsigned int is_raw = 0;
- /* Is this a raw read ? */
- if (memcmp(cmdbuf, "uploadraw:", 10) == 0) {
- is_raw = 1;
- adv = 10;
- } else {
- adv = 7;
- }
- /* Scan to the next ':' to find when the size starts */
- len = strlen(cmdbuf);
- for (delim_index = adv;
- delim_index < len; delim_index++) {
- if (cmdbuf[delim_index] == ':') {
- /* WARNING, cmdbuf is being modified. */
- *((char *) &cmdbuf[delim_index]) = 0;
- break;
- }
- }
- ptn = fastboot_flash_find_ptn(cmdbuf + adv);
- if (ptn == 0) {
- sprintf(response,
- "FAILpartition does not exist");
- } else {
- /* This is how much the user is expecting */
- unsigned int user_size;
- /*
- * This is the maximum size needed for
- * this partition
- */
- unsigned int size;
- /* This is the length of the data */
- unsigned int length;
- /*
- * Used to check previous write of
- * the parition
- */
- char env_ptn_length_var[128];
- char *env_ptn_length_val;
- user_size = 0;
- if (delim_index < len)
- user_size =
- simple_strtoul(cmdbuf + delim_index +
- 1, NULL, 16);
- /* Make sure output is padded to block size */
- length = ptn->length;
- sprintf(env_ptn_length_var,
- "%s_nand_size", ptn->name);
- env_ptn_length_val = getenv(env_ptn_length_var);
- if (env_ptn_length_val) {
- length =
- simple_strtoul(env_ptn_length_val,
- NULL, 16);
- /* Catch possible problems */
- if (!length)
- length = ptn->length;
- }
- size = length / interface.nand_block_size;
- size *= interface.nand_block_size;
- if (length % interface.nand_block_size)
- size += interface.nand_block_size;
- if (is_raw)
- size += (size /
- interface.nand_block_size) *
- interface.nand_oob_size;
- if (size > interface.transfer_buffer_size) {
- sprintf(response, "FAILdata too large");
- } else if (user_size == 0) {
- /* Send the data response */
- sprintf(response, "DATA%08x", size);
- } else if (user_size != size) {
- /* This is the wrong size */
- sprintf(response, "FAIL");
- } else {
- /*
- * This is where the transfer
- * buffer is populated
- */
- unsigned char *buf =
- interface.transfer_buffer;
- char start[32], length[32], type[32],
- addr[32];
- char *read[6] = { "nand", NULL, NULL,
- NULL, NULL, NULL, };
- /*
- * Setting upload_size causes
- * transfer to happen in main loop
- */
- upload_size = size;
- upload_bytes = 0;
- upload_error = 0;
- /*
- * Poison the transfer buffer, 0xff
- * is erase value of nand
- */
- memset(buf, 0xff, upload_size);
- /* Which flavor of read to use */
- if (is_raw)
- sprintf(type, "read.raw");
- else
- sprintf(type, "read.i");
- sprintf(addr, "0x%x",
- interface.transfer_buffer);
- sprintf(start, "0x%x", ptn->start);
- sprintf(length, "0x%x", upload_size);
- read[1] = type;
- read[2] = addr;
- read[3] = start;
- read[4] = length;
- set_ptn_ecc(ptn);
- do_nand(NULL, 0, 5, read);
- /* Send the data response */
- sprintf(response, "DATA%08x", size);
- }
- }
- #endif
- ret = 0;
- }
- fastboot_tx_status(response, strlen(response));
- } /* End of command */
- return ret;
- }
- static int check_against_static_partition(struct fastboot_ptentry *ptn)
- {
- int ret = 0;
- struct fastboot_ptentry *c;
- int i;
- for (i = 0; i < static_pcount; i++) {
- c = fastboot_flash_get_ptn((unsigned int) i);
- if (0 == ptn->length)
- break;
- if ((ptn->start >= c->start) &&
- (ptn->start < c->start + c->length))
- break;
- if ((ptn->start + ptn->length > c->start) &&
- (ptn->start + ptn->length <= c->start + c->length))
- break;
- if ((0 == strcmp(ptn->name, c->name)) &&
- (0 == strcmp(c->name, ptn->name)))
- break;
- }
- if (i >= static_pcount)
- ret = 1;
- return ret;
- }
- static unsigned long long memparse(char *ptr, char **retptr)
- {
- char *endptr; /* local pointer to end of parsed string */
- unsigned long ret = simple_strtoul(ptr, &endptr, 0);
- switch (*endptr) {
- case 'M':
- case 'm':
- ret <<= 10;
- case 'K':
- case 'k':
- ret <<= 10;
- endptr++;
- default:
- break;
- }
- if (retptr)
- *retptr = endptr;
- return ret;
- }
- static int add_partition_from_environment(char *s, char **retptr)
- {
- unsigned long size;
- unsigned long offset = 0;
- char *name;
- int name_len;
- int delim;
- unsigned int flags;
- struct fastboot_ptentry part;
- size = memparse(s, &s);
- if (0 == size) {
- printf("Error:FASTBOOT size of parition is 0\n");
- return 1;
- }
- /* fetch partition name and flags */
- flags = 0; /* this is going to be a regular partition */
- delim = 0;
- /* check for offset */
- if (*s == '@') {
- s++;
- offset = memparse(s, &s);
- } else {
- printf("Error:FASTBOOT offset of parition is not given\n");
- return 1;
- }
- /* now look for name */
- if (*s == '(')
- delim = ')';
- if (delim) {
- char *p;
- name = ++s;
- p = strchr((const char *)name, delim);
- if (!p) {
- printf("Error:FASTBOOT no closing %c found in partition name\n", delim);
- return 1;
- }
- name_len = p - name;
- s = p + 1;
- } else {
- printf("Error:FASTBOOT no partition name for \'%s\'\n", s);
- return 1;
- }
- /* test for options */
- while (1) {
- if (strncmp(s, "i", 1) == 0) {
- flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_I;
- s += 1;
- } else if (strncmp(s, "yaffs", 5) == 0) {
- /* yaffs */
- flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_YAFFS;
- s += 5;
- } else if (strncmp(s, "swecc", 5) == 0) {
- /* swecc */
- flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC;
- s += 5;
- } else if (strncmp(s, "hwecc", 5) == 0) {
- /* hwecc */
- flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC;
- s += 5;
- } else {
- break;
- }
- if (strncmp(s, "|", 1) == 0)
- s += 1;
- }
- /* enter this partition (offset will be calculated later if it is zero at this point) */
- part.length = size;
- part.start = offset;
- part.flags = flags;
- if (name) {
- if (name_len >= sizeof(part.name)) {
- printf("Error:FASTBOOT partition name is too long\n");
- return 1;
- }
- strncpy(&part.name[0], name, name_len);
- /* name is not null terminated */
- part.name[name_len] = '\0';
- } else {
- printf("Error:FASTBOOT no name\n");
- return 1;
- }
- /* Check if this overlaps a static partition */
- if (check_against_static_partition(&part)) {
- printf("Adding: %s, offset 0x%8.8x, size 0x%8.8x, flags 0x%8.8x\n",
- part.name, part.start, part.length, part.flags);
- fastboot_flash_add_ptn(&part);
- }
- /* return (updated) pointer command line string */
- *retptr = s;
- /* return partition table */
- return 0;
- }
- int do_fastboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
- {
- int ret = 1;
- char fbparts[4096], *env;
- int check_timeout = 0;
- uint64_t timeout_endtime = 0;
- uint64_t timeout_ticks = 1000;
- long timeout_seconds = -1;
- int continue_from_disconnect = 0;
- /*
- * Place the runtime partitions at the end of the
- * static paritions. First save the start off so
- * it can be saved from run to run.
- */
- if (static_pcount >= 0) {
- /* Reset */
- pcount = static_pcount;
- } else {
- /* Save */
- static_pcount = pcount;
- }
- env = getenv("fbparts");
- if (env) {
- unsigned int len;
- len = strlen(env);
- if (len && len < 4096) {
- char *s, *e;
- memcpy(&fbparts[0], env, len + 1);
- printf("Fastboot: Adding partitions from environment\n");
- s = &fbparts[0];
- e = s + len;
- while (s < e) {
- if (add_partition_from_environment(s, &s)) {
- printf("Error:Fastboot: Abort adding partitions\n");
- /* reset back to static */
- pcount = static_pcount;
- break;
- }
- /* Skip a bunch of delimiters */
- while (s < e) {
- if ((' ' == *s) ||
- ('\t' == *s) ||
- ('\n' == *s) ||
- ('\r' == *s) ||
- (',' == *s)) {
- s++;
- } else {
- break;
- }
- }
- }
- }
- }
- /* Time out */
- if (2 == argc) {
- long try_seconds;
- char *try_seconds_end;
- if (argv[1][0] == 'q') {
- if ((argv[1][1] >= '0') && (argv[1][1] <= '2'))
- fastboot_quick(argv[1][1] - '0');
- else
- fastboot_quick(0);
- }
- /* Check for timeout */
- try_seconds = simple_strtol(argv[1],
- &try_seconds_end, 10);
- if ((try_seconds_end != argv[1]) &&
- (try_seconds >= 0)) {
- check_timeout = 1;
- timeout_seconds = try_seconds;
- printf("Fastboot inactivity timeout %ld seconds\n", timeout_seconds);
- }
- }
- do {
- continue_from_disconnect = 0;
- /* Initialize the board specific support */
- if (0 == fastboot_init(&interface)) {
- int poll_status;
- /* If we got this far, we are a success */
- ret = 0;
- printf("fastboot initialized\n");
- timeout_endtime = get_timer(0);
- timeout_endtime += timeout_ticks;
- while (1) {
- uint64_t current_time = 0;
- poll_status = fastboot_poll();
- if (1 == check_timeout)
- current_time = get_timer(0);
- if (FASTBOOT_ERROR == poll_status) {
- /* Error */
- break;
- } else if (FASTBOOT_DISCONNECT == poll_status) {
- /* beak, cleanup and re-init */
- printf("Fastboot disconnect detected\n");
- continue_from_disconnect = 1;
- break;
- } else if ((1 == check_timeout) &&
- (FASTBOOT_INACTIVE == poll_status)) {
- /* No activity */
- if (current_time >= timeout_endtime) {
- printf("Fastboot inactivity detected\n");
- break;
- }
- } else {
- /* Something happened */
- if (1 == check_timeout) {
- /* Update the timeout endtime */
- timeout_endtime = current_time;
- timeout_endtime += timeout_ticks;
- }
- }
- /* Check if the user wanted to terminate with ^C */
- if ((FASTBOOT_INACTIVE == poll_status) &&
- (ctrlc())) {
- printf("Fastboot ended by user\n");
- break;
- }
- /*
- * Check if the fastboot client wanted to
- * continue booting
- */
- if (continue_booting) {
- printf("Fastboot ended by client\n");
- break;
- }
- /* Check if there is something to upload */
- tx_handler();
- }
- }
- /* Reset the board specific support */
- fastboot_shutdown();
- /* restart the loop if a disconnect was detected */
- } while (continue_from_disconnect);
- return ret;
- }
- U_BOOT_CMD(
- fastboot, 2, 1, do_fastboot,
- "fastboot- use USB Fastboot protocol\n",
- "[inactive timeout]\n"
- " - Run as a fastboot usb device.\n"
- " - The optional inactive timeout is the decimal seconds before\n"
- " - the normal console resumes\n"
- );
- /*
- * Android style flash utilties */
- void fastboot_flash_add_ptn(fastboot_ptentry *ptn)
- {
- if (pcount < MAX_PTN) {
- memcpy(ptable + pcount, ptn, sizeof(fastboot_ptentry));
- 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;
- }
- }
- printf("can't find partition: %s, dump the partition table\n", name);
- fastboot_flash_dump_ptn();
- 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;
- }
- int fastboot_write_storage(u8 *partition_name, u32 write_len)
- {
- struct fastboot_ptentry *ptn;
- u32 storage_len = 0;
- if (0 == write_len) {
- DBG_ERR("WriteMMC with 0 lenght\n");
- return -1;
- }
- ptn = fastboot_flash_find_ptn((const char *)partition_name);
- if (!ptn) {
- DBG_ERR("Partition:'%s' does not exist\n", partition_name);
- return -1;
- }
- if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
- DBG_ERR("ENV Write, None image partition, failed\n");
- return -1;
- }
- DBG_DEBUG("PTN name=%s, start=0x%x, len=0x%x, flags=0x%x, id=0x%x\n",
- ptn->name, ptn->start, ptn->length, ptn->flags, ptn->partition_id);
- #if defined(CONFIG_FASTBOOT_STORAGE_NAND)
- storage_len = ptn->length;
- #elif defined(CONFIG_FASTBOOT_STORAGE_EMMC_SATA)
- storage_len = ptn->length * MMC_SATA_BLOCK_SIZE;
- #endif
- if (write_len > storage_len) {
- DBG_ERR("Write len big than part volume. 0x%x:0x%x\n",
- write_len, storage_len);
- return -1;
- }
- #if defined(CONFIG_FASTBOOT_STORAGE_NAND)
- DBG_ALWS("Writing nand %s...", ptn->name);
- download_bytes_unpadded = download_bytes = write_len;
- 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++;
- }
- }
- }
- if (write_to_ptn(ptn)) {
- DBG_ERR("Write to nand %s failed\n", ptn->name);
- return -1;
- } else {
- DBG_ALWS("Write to nand %s done\n", ptn->name);
- return write_len;
- }
- #elif defined(CONFIG_FASTBOOT_STORAGE_EMMC_SATA)
- {
- char source[32], dest[32], length[32];
- char part_no[32], slot_no[32];
- unsigned int temp;
- char *mmc_write[5] = {"mmc", "write", source, dest, length};
- char *mmc_dev[4] = {"mmc", "dev", slot_no, part_no};
- memset(source, 0, sizeof(source));
- memset(dest, 0, sizeof(dest));
- memset(length, 0, sizeof(length));
- memset(part_no, 0, sizeof(part_no));
- memset(slot_no, 0, sizeof(slot_no));
- sprintf(slot_no, "%d", fastboot_devinfo.dev_id);
- sprintf(part_no, "%d", ptn->partition_id);
- DBG_ALWS("Init MMC%s(%s)...\n", slot_no, ptn->name);
- if(0) {
- //if (do_mmcops(NULL, 0, 4, mmc_dev)) {
- DBG_ERR("MMC%s(%s) init fail\n", slot_no, ptn->name);
- return -1;
- } else {
- DBG_ALWS("MMC%s(%s) init done\n", slot_no, ptn->name);
- }
- sprintf(source, "0x%x", CONFIG_FASTBOOT_TRANSFER_BUF);
- sprintf(dest, "0x%x", ptn->start);
- temp = (write_len + MMC_SATA_BLOCK_SIZE - 1) / MMC_SATA_BLOCK_SIZE;
- sprintf(length, "0x%x", temp);
- DBG_ALWS("Writing MMC%s(%s), %u blocks...", slot_no, ptn->name, temp);
- if(0) {
- //if (do_mmcops(NULL, 0, 5, mmc_write)) {
- DBG_ERR("MMC%s(%s) write fail\n", slot_no, ptn->name);
- return -1;
- } else {
- DBG_ALWS("MMC%s(%s) write done\n", slot_no, ptn->name);
- return write_len;
- }
- }
- #endif
- }
- #endif /* CONFIG_FASTBOOT */
|