ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/obm/Common/Download/ProtocolManager.c b/marvell/obm/Common/Download/ProtocolManager.c
new file mode 100644
index 0000000..fac7f0a
--- /dev/null
+++ b/marvell/obm/Common/Download/ProtocolManager.c
@@ -0,0 +1,1382 @@
+/******************************************************************************
+**
+** INTEL CONFIDENTIAL
+** Copyright 2003-2004 Intel Corporation All Rights Reserved.
+**
+** The source code contained or described herein and all documents
+** related to the source code (Material) are owned by Intel Corporation
+** or its suppliers or licensors.  Title to the Material remains with
+** Intel Corporation or its suppliers and licensors. The Material contains
+** trade secrets and proprietary and confidential information of Intel
+** or its suppliers and licensors. The Material is protected by worldwide
+** copyright and trade secret laws and treaty provisions. No part of the
+** Material may be used, copied, reproduced, modified, published, uploaded,
+** posted, transmitted, distributed, or disclosed in any way without Intel's
+** prior express written permission.
+**
+** No license under any patent, copyright, trade secret or other intellectual
+** property right is granted to or conferred upon you by disclosure or
+** delivery of the Materials, either expressly, by implication, inducement,
+** estoppel or otherwise. Any license under such intellectual property rights
+** must be express and approved by Intel in writing.
+**
+**	 ProtocolManager.c
+******************************************************************************/
+
+/******************************************************************************
+ *
+ *  (C)Copyright 2005 - 2011 Marvell. All Rights Reserved.
+ *
+ *  THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL.
+ *  The copyright notice above does not evidence any actual or intended
+ *  publication of such source code.
+ *  This Module contains Proprietary Information of Marvell and should be
+ *  treated as Confidential.
+ *  The information in this file is provided for the exclusive use of the
+ *  licensees of Marvell.
+ *  Such users have the right to use, modify, and incorporate this code into
+ *  products for purposes authorized by the license agreement provided they
+ *  include this notice and the associated copyright notice with any such
+ *  product.
+ *  The information in this file is provided "AS IS" without warranty.
+
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	The boot ROM protocol is documented in the boot ROM specification.  This
+ * implements the protocol over the USB or UART port.  It is expected that
+ * the driver for the port has a minimal set of routines to handle receiving
+ * and responding to commands.  This file will interpret the data and prepare
+ * the response data for a particular command.  The driver is resonsible for
+ * sending and receiving the data over the port.
+ *
+ *	Basic process:
+ *	 - Interrupt is received from one of the ports
+ *	 - The HandleRequest routine is called to get the command from the port
+ *	 - Based on the request type either a download request or a JTAG request
+ *		 is started.  At this point the other ports are disabled until the
+ *		 request is completed.
+ *
+ *
+ ******************************************************************************/
+
+#include "ProtocolManager.h"
+#include "Errors.h"
+#include "misc.h"
+#include "Flash.h"
+#include "FM.h"
+#include "ICU.h"
+#include "tim.h"
+#include "PlatformConfig.h"
+#include "loadoffsets.h"
+#include "nand.h"
+#include "downloader.h"
+#include "TIMDownload.h"
+
+
+#define MAX_RECV_FIFO_LEN	  (8192)
+__attribute__((aligned(8)))UINT8 receiveBuff[MAX_RECV_FIFO_LEN];
+UCHAR *pRXbuff = receiveBuff;
+
+__attribute__((aligned(8)))UINT8 transmitBuff[MAX_RECV_FIFO_LEN];
+// Here's how to interprit the version
+// MAJOR
+// A (stepping) = 1
+// B (stepping) = 2
+// C (stepping) = 3
+// D (stepping) = 4
+// MINOR
+// This is basically the stepping number, 0=0, 1=1, 2=2 etc
+// For example:
+// A0 = 1000
+// A1 = 1001
+// B2 = 2002
+// C0 = 3000
+// C2 = 3002
+
+
+__attribute__((aligned(4))) UINT8_T preambleString[] = { 0x00, 0xD3, 0x02, 0x2B };
+UINT8_T upload_config_flash_flag = 0;
+UINT8_T upload_get_times_flag = 0;
+UINT8_T upload_times = 1;
+UINT8_T ResetUE = 0;
+UINT8_T ResetDelay = 0;
+extern UINT8_T FlashInitDone;
+
+#if NAND_CODE
+extern UINT_T NandID;
+#endif
+
+#if REPORT_DDR_INFO
+extern UINT_T swd_ddr_vendor_id, swd_ddr_size, swd_flash_id;
+#endif
+
+static ProtocolISR GProtocolISR;
+static pProtocolCmd pGProtocolCmd;
+static __attribute__((aligned(4))) ProtocolRsp GProtocolRsp;
+static ProtocolMsg GProtocolMsg;
+static UINT8_T sProtocolError = NoError;
+
+//Protocol Manager helper routines - should all be 'inline' routines
+pProtocolISR getProtocolISR(void) 		{ return &GProtocolISR; }
+pProtocolCmd getProtocolCmd(void) 		{ return pGProtocolCmd; }
+pProtocolCmd setProtocolCmd(void *addr)	{ return pGProtocolCmd = (pProtocolCmd) addr; }
+pProtocolRsp getProtocolRsp(void) 		{ return &GProtocolRsp; }
+pProtocolMsg getProtocolMsg(void) 		{ return &GProtocolMsg; }
+void setProtocolError(UINT8_T Error) 	{ sProtocolError = Error; }
+UINT8_T getProtocolError(void) 			{ return sProtocolError; }
+UCHAR * getProtoBuff() 			{ return pRXbuff; }
+void setProtoBuff(UCHAR* pAddr) { pRXbuff = pAddr; }
+void resetProtoBuff() 					{ pRXbuff = receiveBuff; }
+
+
+//Protocol Manager reply routines.  Will call into USB API to do the actual send
+UINT_T SendResponse(UINT8_T *pAckBuff, UINT_T size)
+{
+	P_USBAPI_T pUsbApi = getProtocolISR()->plinkedUSB;
+
+	//pointer to the current USB Handle
+	pUsbApi->USB_Send((UINT *)pAckBuff, size, pUsbApi);
+
+	return NoError;
+}
+
+UINT_T SendAck(void)
+{
+	UINT_T Retval = NoError;
+	pProtocolCmd pCmd = getProtocolCmd();
+	pProtocolRsp pRsp = getProtocolRsp();
+
+	pRsp->Command = pCmd->Command;
+	pRsp->Sequence = pCmd->Sequence;
+	pRsp->CID = pCmd->CID;
+	pRsp->Status = Ack;
+	pRsp->Flags = pRsp->Flags & ~(MESSAGE_FLAG);
+	pRsp->Flags = pRsp->Flags | getProtocolMsg()->MessageFlag;
+
+	Retval = SendResponse(&pRsp->Command, pRsp->Length + 6);
+
+	return Retval;
+}
+
+UINT_T SendError(UINT_T ErrorCode){
+
+	UINT_T Retval = NoError;
+	UINT_T RspSize;
+	//UINT_T i;
+	pProtocolCmd pCmd = getProtocolCmd();
+	pProtocolRsp pRsp = getProtocolRsp();
+
+	pRsp->Command = pCmd->Command;
+	pRsp->Sequence = pCmd->Sequence;
+	pRsp->CID = pCmd->CID;
+	pRsp->Status = Nack;
+	pRsp->Flags = getProtocolMsg()->MessageFlag;
+	if(ErrorCode)
+	{
+		pRsp->Length = 4;
+		*(UINT16_T*)&pRsp->Data[0] = ErrorCode & 0x0000FFFF;
+		*(UINT16_T*)&pRsp->Data[2] = (ErrorCode & 0xFFFF0000) >> 16;
+	}
+	else
+		pRsp->Length = 0;
+
+	RspSize = ErrorCode ? 6 + pRsp->Length : 6;
+	Retval = SendResponse(&pRsp->Command, RspSize);
+
+	return Retval;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//	Functions to handle specific commands
+////////////////////////////////////////////////////////////////////////
+
+UINT_T HandleGetVersionCmd()
+{
+	UINT_T	Retval= 0, i;
+	pProtocolRsp pRsp;
+
+//	UINT8_T  *Version = (UINT8_T *)(VERSION_OFFSET + BOOTROMBASEADDR);	// legacy way to get version info...
+//	Version used to come from BootROM's version info.
+//	But now the BootROM's memory space is unavailable to BootLoader.
+//	Furthermore, it is probably more appropriate to return the version
+//	info of whichever executable is running: BootROM or BootLoader.
+	extern UINT8_T	ExecutableVersionInfo[];	// defined in [TBR|BL]_startup.s
+	UINT8_T  *pVersion = ExecutableVersionInfo;	// new way to get version info.
+
+	pRsp = getProtocolRsp();
+
+	pRsp->Length = 12;
+	memcpy( (void *)&(pRsp->Data[0]), pVersion, 12);
+
+#if REPORT_DDR_INFO
+	pRsp->Length += 8;
+
+	for (i = 0; i < 4; i++)
+		pRsp->Data[12+i] = (swd_ddr_vendor_id >> (8 * i)) & 0xff;
+
+	for (i = 0; i < 4; i++)
+		pRsp->Data[16+i] = (swd_ddr_size >> (8 * i)) & 0xff;
+
+	pRsp->Length += 4;
+
+	for (i = 0; i < 4; i++)
+		pRsp->Data[20+i] = (swd_flash_id >> (8 * i)) & 0xff;
+#endif
+
+	Retval = SendAck();
+
+	return Retval;
+}
+
+UINT_T HandleSelectImageCmd(UINT_T imageType)
+{
+	UINT_T Retval;
+	pProtocolRsp pRsp = getProtocolRsp();
+
+	pRsp->Length = 4;
+
+	*(UINT16_T *)&pRsp->Data[0] = imageType & 0x0000FFFF;
+	*(UINT16_T *)&pRsp->Data[2] = (imageType & 0xFFFF0000) >> 16;
+
+	Retval = SendAck();
+
+	return Retval;
+}
+
+UINT_T HandleVerifyImageCmd()
+{
+	UINT_T	Retval= 0;
+
+	getProtocolRsp()->Length = 0;
+
+	if(getProtocolCmd()->Data[0] == Nack)
+		getProtocolISR()->ErrorCode = UnknownImageError;
+
+	Retval = SendAck();
+	return Retval;
+
+}
+
+UINT_T HandleDataHeaderCmd()
+{
+	UINT_T	RemainingLen = 0;
+	UINT_T  BufferSize = 0;
+	UINT_T  NextSize = 0;
+
+	pProtocolRsp pRsp = getProtocolRsp();
+	pProtocolISR pISR = getProtocolISR();
+	pProtocolCmd pCmd = getProtocolCmd();
+
+	pRsp->Length = 4;
+	RemainingLen = *(UINT32_T *)&pCmd->Data[0];
+
+	//check to make sure the data will fit
+	if(RemainingLen > pISR->MaxImageSize)
+	{
+		AddMessageError(REPORT_NOTIFICATION, DownloadImageTooBigError);
+		SendError(DownloadImageTooBigError);
+		pISR->ErrorCode = DownloadImageTooBigError;
+		return NULL;
+	}
+
+	pISR->DataLeft = RemainingLen;	//DataLeft indicates how much of the total image remains
+
+	if (pCmd->Flags & FAST_DOWNLOAD)
+	{
+		pRsp->Flags = pRsp->Flags | FAST_DOWNLOAD;
+		pISR->FastDLInProgress = 1;
+		//setup next read for 2KB
+		NextSize = BufferSize = (RemainingLen > FD_BLOCK_SIZE) ? FD_BLOCK_SIZE : RemainingLen;
+	}
+	else
+	{
+		pRsp->Flags = pRsp->Flags & ~FAST_DOWNLOAD;
+		pISR->FastDLInProgress = 0;
+		//setup next read for 2KB
+		BufferSize = (RemainingLen > DATA_BLOCK_SIZE) ? DATA_BLOCK_SIZE : RemainingLen;
+		NextSize = BufferSize + COMMAND_SIZE;
+	}
+
+
+	*(UINT16_T*)&pRsp->Data[0] = BufferSize & 0x0000FFFF;
+	*(UINT16_T*)&pRsp->Data[2] = (BufferSize & 0xFFFF0000) >> 16;
+
+	SendAck();
+
+
+	return NextSize;
+}
+
+UINT_T HandleDataCmd()
+{
+	UINT_T	Retval = 0;
+
+	getProtocolCmd()->Command = DownloadDataCmd;
+	getProtocolRsp()->Length = 0;
+
+	SendAck();
+	return Retval;
+}
+
+UINT_T HandleDoneCmd()
+{
+	UINT_T	Retval= 0;
+	pProtocolISR pISR = getProtocolISR();
+
+	getProtocolRsp()->Length = 0;
+
+	//reset the status flags
+	pISR->PreambleReceived = FALSE;
+
+	SendAck();
+	return Retval;
+
+}
+
+UINT_T HandleMessageCmd(void){
+	UINT_T Retval= 0;
+
+#if VERBOSE_MODE
+
+	UINT_T mIndex;
+	UINT_T size;
+	UINT_T i;
+	//UINT8_T Buff[LENGTHOFMESSAGES + 6];
+	UINT8_T *Buff = transmitBuff;
+	pProtocolCmd pCmd = getProtocolCmd();
+	pProtocolMsg pMsg = getProtocolMsg();
+
+	//tool sending extra message commands to catch messages
+	//if we don't have any messages, just NACK the message and continue
+	if(pMsg->NumMessagesQueued == 0){
+		SendError(0);
+		return NoError;
+	}
+
+	//must use Buff instead of GProtocolRsp
+	Buff[0] = pCmd->Command;
+	Buff[1] = pCmd->Sequence;
+	Buff[2] = pCmd->CID;
+	Buff[3] = Ack;
+
+	mIndex = pMsg->CurrentMessageIndex;
+	size = pMsg->Lengths[mIndex];
+
+	Buff[5] = size;
+	for(i = 0; i < size; i++)
+		Buff[6+i] = pMsg->Messages[mIndex][i];
+
+	//increment the pointer to the new current message
+	pMsg->CurrentMessageIndex++;
+	pMsg->CurrentMessageIndex %= MAXNUMOFMESSAGES;
+
+	pMsg->NumMessagesQueued--;
+
+	if(pMsg->NumMessagesQueued == 0)
+		pMsg->MessageFlag = 0;
+	else
+		pMsg->MessageFlag = 1;
+
+	//mark flags (message flag	  message type flag   )
+	Buff[4] = (pMsg->MessageFlag | (pMsg->MessageType[mIndex] << 1));
+
+	SendResponse(&Buff[0], 6+size);
+
+#else // end if VERBOSE_MODE
+
+	SendError(0);
+#endif
+	return Retval;
+}
+
+UINT_T HandleDisconnect()
+{
+	UINT start_time;
+	pProtocolISR pISR = getProtocolISR();
+
+	//if there is no linked USB Device, then there was never any protocol transaction
+	if(pISR->plinkedUSB == NULL)
+		return NoError;
+
+	//check to see if there are queued up messages.
+	if( (pISR->DisconnectReceived == TRUE) && getProtocolMsg()->MessageFlag)
+	{	//clear disconnect received flag as we now need to wait for a new one
+		pISR->DisconnectReceived = FALSE;
+		//reply with a NAK to allow messages to get sent
+		SendError(0);
+	}
+
+	//give the tool a short time to get all the messages and then reply with a disconnect
+	start_time = GetOSCR0();
+	while(pISR->DisconnectReceived == FALSE)
+	{
+		//if a download is waiting, terminate it and break out of loop: wtptp tool quits on a NACK
+		if(pISR->DLWaiting == TRUE)
+		{
+			SendError(UnknownImageError);
+			break;
+		}
+
+		if(OSCR0IntervalInSec(start_time, GetOSCR0()) > PM_DISCONNET_MS)
+			break;
+	}
+
+	//lastly, reply with an ACK
+	if(pISR->DisconnectReceived == TRUE)
+		SendAck();
+
+	//need to release PM semaphore and reset all flags!
+	//Semaphore_Release(PROTOCOL_semaphore);
+	memset(pISR, 0, sizeof(ProtocolISR));
+
+	return NoError;
+}
+
+/*	InitPort()
+ *
+ *	Call into the driver to setup the ports and enable interrupts
+ *
+ */
+UINT_T InitPort(UINT_T port)
+{
+	return USBAPI_InitializeDevice(port);
+}
+
+UINT ImageDownloadWaiting(UINT_T media_num)
+{
+	pProtocolISR pISR = getProtocolISR();
+
+	//check to see if a USB is linked and said linked USB is the matching one
+	// if so, return whether a GetVersion request was made (i.e. a download is waiting)
+	if( (pISR->plinkedUSB != NULL) &&
+		(pISR->plinkedUSB->bootNum == media_num) )
+		return pISR->DLWaiting;
+	else
+		return FALSE;
+}
+
+
+UINT PreambleReceived()
+{
+	return getProtocolISR()->PreambleReceived;
+}
+
+void ClearPreambleReceived()
+{
+	getProtocolISR()->PreambleReceived = FALSE;
+}
+
+// ShutdownPorts: shutdown all ports
+void ShutdownPorts ()
+{
+	//call into USB API to shutdown all enabled USB devices
+	USBAPI_ShutdownAll();
+}
+
+//Protocol Manager ISR
+//	There are three possible scenarios when this routine is called:
+//	1. PM is already used by another USB device (unusual scenario)
+//	2. PM is being used by the calling device (most likely scenario)
+//	3. PM is free (starting scenario)
+//	The numbered comments in this routine will match up to the three mentioned scenarios
+void PM_ISR(P_USBAPI_T this, UINT bytes, UINT * buffer)
+{
+	UINT next_size, dummy = NULL;
+	pProtocolISR pISR = getProtocolISR();
+
+	//1.  Is someone else using the protocol?
+	if( (pISR->plinkedUSB != this) && (pISR->plinkedUSB != NULL) )
+	{	//Yes. Another USB is using protocol.  Transmit a NAK
+		this->USB_Send(&dummy, PREAMBLE_SIZE, this);
+		//reprime so it will try again later
+		this->USB_Receive(buffer, PREAMBLE_SIZE, this);
+		//time to leave
+		return;
+	}
+
+	//2. We're already good friends
+	if(pISR->plinkedUSB == this)
+	{
+		if((bytes == PREAMBLE_SIZE ) && (pISR->PreambleReceived == FALSE))
+		{	//check the validity of the preamble
+			if( PM_VerifyPreamble((UCHAR *)buffer) )
+			{	//good Preamble!
+				pISR->PreambleReceived = TRUE;
+				// clear out any errors, as a new Preamble mean a new Image DL
+				pISR->ErrorCode = 0;
+				//respond with the preamble
+				SendResponse(preambleString, PREAMBLE_SIZE);
+				//set the pRXBuff to protocol area
+				resetProtoBuff();
+				//Setup for a new CMD
+				this->USB_Receive((UINT *)getProtoBuff(), this->maxpacketsize, this);
+			}
+			else
+			{	//bad Preamble!
+				//Transmit a NAK
+				this->USB_Send(&dummy, PREAMBLE_SIZE, this);
+				//Reset USB control to download again
+				this->USB_Receive(buffer, PREAMBLE_SIZE, this);
+			}
+		}
+		else
+		{
+			//4.  call into PM handler
+			next_size = PM_Handler(bytes);
+
+			//5.  call into USBAPI to set up next RECEIVE
+			this->USB_Receive((UINT *)getProtoBuff(), next_size, this);
+		}
+		//all done, exit now
+		return;
+	}
+
+	//3. Newbie!  Must receive a preamble or else we can't be friends.
+	if(pISR->plinkedUSB == NULL)
+	{	//check the validity of the preamble
+		if( (bytes == PREAMBLE_SIZE) && PM_VerifyPreamble((UCHAR *)buffer) )
+		{	//good Preamble!
+			pISR->PreambleReceived = TRUE;
+			// clear out any errors, as a new Preamble mean a new Image DL
+			pISR->ErrorCode = 0;
+			//Check out using semaphore and store the USB API pointer
+			pISR->plinkedUSB = this;
+			//Semaphore_Acquire(PROTOCOL_semaphore);
+			//respond with the preamble
+			SendResponse(preambleString, PREAMBLE_SIZE);
+			//set the pRXBuff to protocol area
+			resetProtoBuff();
+			//Setup for a new CMD
+			this->USB_Receive((UINT *)getProtoBuff(), this->maxpacketsize, this);
+		}
+		else
+		{	//Premable was not valid
+			//Transmit a NAK
+			this->USB_Send(&dummy, PREAMBLE_SIZE, this);
+			//Reset USB control to download again
+			this->USB_Receive(buffer, PREAMBLE_SIZE, this);
+		}
+		return;
+	}
+}
+
+
+// PROTOCOL HANDLER
+//  This routine is the singular handler for protocol commands
+//  - JTAG over USB (CMD 36)
+//  - Image Downloading
+//
+//  Inputs:
+//	- pUSBhandle: pointer the calling USB handler
+//	- packetlength: length of the packet that triggered this call
+//	Outputs:
+//	  - PrimeSize: the size to prime the next input packet for
+UINT PM_Handler(UINT packetLength)
+{
+	pProtocolCmd pCmd;
+	pProtocolISR pISR = getProtocolISR();
+	UINT next_size = pISR->plinkedUSB->maxpacketsize;	//defualt is a full packet
+
+	//1st check if a fast download command is in progress
+	if(pISR->FastDLInProgress)
+	{
+		//Update counters
+		pISR->CurrentTransferAddress += packetLength;
+		pISR->DataLeft -= packetLength;
+		pISR->MaxImageSize = (packetLength > pISR->MaxImageSize) ? 0 : (pISR->MaxImageSize - packetLength);
+
+		//When DataLeft = 0, then the command is finally finished.  respond back
+		if(pISR->DataLeft == 0)
+		{
+			pISR->FastDLInProgress = 0;
+			HandleDataCmd();	//send the response
+			resetProtoBuff();	//restore the location back to protocol area
+		}
+		else
+		{	// Fast Download continues... set up info for next descriprots
+			//security check: can only download "MaxImageSize" per image DL.  If malicious software tries to download more,
+			//this line of code will restrict the size dTD and force USB NACKs for any additional data
+			next_size = (pISR->DataLeft > pISR->MaxImageSize) ? pISR->MaxImageSize : pISR->DataLeft;
+			next_size = (next_size < FD_BLOCK_SIZE ) ? next_size : FD_BLOCK_SIZE;
+			setProtoBuff((UINT8 *)pISR->CurrentTransferAddress);	//set location for USB to put data
+		}
+		return next_size;
+	}
+
+	//normal commands
+	//Overlay the Command structure over the buffer
+	pCmd = setProtocolCmd(getProtoBuff());
+
+	//All normal commands will load the data to the protocol buffer
+	resetProtoBuff();
+
+	//Sanity check - make sure the size read in matches the size defined in the ProtocolCmd packet
+	//if ( packetLength != (8+pCmd->Length) )
+	//{
+	//	pISR->ErrorCode = UnknownProtocolCmd;
+	//	SendError(UnknownProtocolCmd);
+	//	return next_size;
+	//}
+
+	// update Interrupt Status Flags
+	//pISR->CurrentCommand = pCmd->Command;
+
+	switch( pCmd->Command )
+	{
+	case MessageCmd:
+		//try and send a message
+		// clear the upload command flag for upload
+		pISR->CommandReceived = FALSE;
+		HandleMessageCmd();
+		break;
+	#if !BOOTROM
+	case ProtocolVersionCmd:
+		// Send the major and minor protocol version bacl
+		HandleProtocolVersionCmd();
+		break;
+	case GetParametersCmd:
+		// Send Protocol Parameters to host.
+		HandleGetParametersCmd();
+		break;
+	case GetImageCrcCmd:
+		HandleGetCrcCmd();
+		break;
+	case GetBadBlockCmd:
+		HandleGetBadBlock();
+		break;
+	#endif
+	#if JTAG_OVER_JTAG_SUPPORTED
+	case JtagOverMediaCmd:
+		//copy the JTAG data into the JTAG structure
+		memcpy(	(void *)pJTAG_CPCData->CommandFromHost, (void*)&pCmd->Data[0], pCmd->Length);
+		Jtag_Media_Handler();
+		break;
+	#endif
+	case GetVersionCmd:
+		//Indicate that a download is pending, but do NOT respond yet
+		pISR->DLWaiting = TRUE;
+		pISR->CommandReceived = TRUE; // mark it as download command
+		break;
+	case UploadDataHeaderCmd:
+		pISR->DLWaiting = TRUE; // indicate that a upload is pending
+		pISR->CommandReceived = TRUE; // mark it as upload command
+		break;
+	case UploadDataCmd:
+		pISR->CommandReceived = TRUE; // mark it as upload command
+		break;
+	case SelectImageCmd:
+		HandleSelectImageCmd(pISR->CurrentImageID);
+		next_size = 9;	//the next command will be larger than normal
+		break;
+	case VerifyImageCmd:
+		HandleVerifyImageCmd();
+		next_size = 12;	//the next command will be larger than normal
+		break;
+	case DataHeaderCmd:
+		next_size = HandleDataHeaderCmd();
+		if (pISR->FastDLInProgress)	//override the download address for fast download
+			setProtoBuff((UINT8 *)pISR->CurrentTransferAddress);	//set location for USB to put data
+		break;
+	case DownloadDataCmd:
+		//Note: this will only be triggered for "slow" download.
+		//move data from the buffer to boot address
+		memcpy((void *)(pISR->CurrentTransferAddress), (void*)&pCmd->Data[0], pCmd->Length);
+		//Update counters
+		pISR->CurrentTransferAddress += pCmd->Length;
+		pISR->MaxImageSize -= (pCmd->Length > pISR->MaxImageSize) ? pISR->MaxImageSize : pCmd->Length;
+		HandleDataCmd();
+		break;
+	case DoneCmd:
+		//Indicate that a download has finished, but do NOT respond yet
+		pISR->DLWaiting = FALSE;
+		pISR->CommandReceived = TRUE; // exit for upload while loop
+		break;
+	case DisconnectCmd:
+		pISR->DisconnectReceived = TRUE;
+		break;
+	default:
+		break;
+	}
+
+
+
+
+
+	return next_size;
+}
+
+
+
+
+
+
+// PM_ReceiveImage()
+//
+//  This is the Protocol Recieve image routine.  It does the following:
+//	1. Set the parameters for the download:
+//		-- destination address
+//		-- max size
+//		-- image ID
+//  2. Check and wait for a pending image download request (GetVersion command from host)
+//  3. Download will be kicked off by sending the GetVersion response.
+//	4. Wait until the download has finished (DoneCommand will indicate that)
+//
+UINT_T PM_ReceiveImage(UINT_T dummy, UINT_T address, UINT_T size, UINT_T image_id)
+{
+	UINT retval = NoError, start_time, wait_time = 0;
+	//pProtocolCmd pCmd = getProtocolCmd();
+	pProtocolISR pISR = getProtocolISR();
+
+	//1. set up initial DL perameters:
+	pISR->CurrentTransferAddress = address;
+	pISR->MaxImageSize = size;
+	pISR->CurrentImageID = image_id;
+
+	//AddMessageCompound((UINT8_T*) ("*** PM_ReceiveImage pISR->CurrentTransferAddress...\0"), pISR->CurrentTransferAddress);
+
+	do
+	{
+		//2. wait for the download request
+		start_time = GetOSCR0();
+		do
+		{	//Check for timeout
+			if( OSCR0IntervalInMilli(start_time, GetOSCR0()) > PM_DL_STARTTIME_MS )
+			{
+				retval = PM_ReceiveTimeOutError_1;
+				break;
+			}
+		}
+		while(pISR->DLWaiting == FALSE);
+
+		//check for an error
+		if(retval != NoError)
+			break;
+
+		//3. send the Get Version response to kick off the download
+		retval = HandleGetVersionCmd();
+
+		//check for an error
+		if(retval != NoError)
+			break;
+
+		/*
+		* Suppose the worst USB transfer speed is 0.5MB/s(in fact, it's about 12MB/s
+		* for HS mode but should also consider FS mode)
+		* Then, the wait time should not exceed (size / 1024 /4) milli seconds.
+		* The extra 2000 ms is to ensure the wait time is none-zero
+		*/
+		wait_time = (size >> 9) + 2000;
+
+		//4. Wait for the Image DL to complete or an error
+		start_time = GetOSCR0();
+		do
+		{	//Check for timeout
+			if( OSCR0IntervalInMilli(start_time, GetOSCR0()) > wait_time )
+			{
+				retval = PM_ReceiveTimeOutError_2;
+				break;
+			}
+		}
+		while( (pISR->DLWaiting == TRUE) && (pISR->ErrorCode == NoError) );
+
+	}while(FALSE);
+
+	//If there is an protocol error, override local error status
+	if(pISR->ErrorCode)
+		retval = pISR->ErrorCode;
+
+	//clear the flags to indicate an image dl is done
+	pISR->ErrorCode = NoError;
+	pISR->PreambleReceived = FALSE;
+	pISR->DLWaiting = FALSE;
+
+	//finish off the download by sending either the DONE cmd on success or NAK on failure
+	if(retval == PM_ReceiveTimeOutError_1 || retval == PM_ReceiveTimeOutError_2)
+		SendError(retval);
+	else
+		HandleDoneCmd();
+
+	//returns 0 if complete or an error code
+	return retval;
+}
+
+UINT_T GetUploadCommand(void)
+{
+	UINT_T Retval = NoError;
+	UINT_T StartTime;
+
+	pProtocolISR pISR = getProtocolISR();
+
+	StartTime = GetOSCR0(); //Dummy read to flush potentially bad data
+	StartTime = GetOSCR0();
+
+	while(pISR->CommandReceived == FALSE)
+	{
+		Retval = CheckProtocolTimeOut(StartTime);
+		if(Retval != NoError)
+			return Retval;
+	}
+	pISR->CommandReceived = FALSE;
+
+	return Retval;
+}
+
+/*
+ * HandleDownloadFlow()
+ *
+ *	This function will handle a upload request unitl it completes or fails
+ *	and return the status
+ */
+
+UINT_T HandleUploadFlow(UINT_T address)
+{
+	UINT_T Retval = NoError;
+	pProtocolCmd pCmd = getProtocolCmd();
+	pProtocolISR pISR = getProtocolISR();
+
+	pISR->CurrentTransferAddress = address;
+
+	do{
+		switch(pCmd->Command)
+		{
+		case UploadDataHeaderCmd:
+			Retval = HandleUploadDataHeaderCmd();
+			break;
+		case UploadDataCmd:
+			Retval = HandleUploadDataCmd();
+			break;
+		default:
+			if(pISR->CommandReceived == TRUE)
+			{
+				Retval = SendError(0);
+				Retval = UnknownProtocolCmd;
+			}else
+				Retval = NoError;
+			break;
+		}
+		if(Retval != NoError){
+			break;
+		}
+
+		GetUploadCommand();
+
+	}while (pCmd->Command != DoneCmd);
+
+	return Retval;
+}
+
+/**
+ * Debug Commands
+ **/
+UINT_T HandleUploadDataHeaderCmd(void)
+{
+	UINT_T Retval = NoError;
+	pProtocolCmd pCommand;
+	pProtocolISR pISR;
+	UploadDataParameters uploadParams, *pUploadParams;
+
+#if NAND_CODE || QSPINAND_CODE || SPINAND_CODE
+	UINT_T spare_size, page_size;
+	UINT_T numbers, total_spare_size;
+#endif
+
+
+	pUploadParams = &uploadParams;
+	pCommand = getProtocolCmd();
+	pISR = getProtocolISR();
+	memcpy((void*)pUploadParams,(void*)&pCommand->Data[0],sizeof(UploadDataParameters));
+
+	if (!upload_get_times_flag)
+	{
+		upload_times = pUploadParams->Times; // upload_times >= 1
+
+#if USE_SERIAL_DEBUG
+		obm_printf("upload_times: %d\n\r", upload_times);
+#endif
+
+		ResetUE = pUploadParams->ResetUE;
+		ResetDelay = pUploadParams->ResetTimeDelay;
+
+		obm_printf("ResetUE: %d, ResetDelay: %d\n\r", ResetUE, ResetDelay);
+
+		upload_get_times_flag = 1;
+	}
+
+	// Are the upload parameters ok?
+	Retval = VerifyUploadParameters(pUploadParams);
+	AddMessageError(REPORT_NOTIFICATION, PlatformBusy);
+
+	if(Retval != NoError)
+	{
+		AddMessageError(REPORT_NOTIFICATION, PlatformReady);
+		SendError(Retval);
+		return Retval;
+	}
+	else
+	{
+		getProtocolRsp()->Length = 0;
+		SendAck();
+	}
+
+	// Copy data requested into upload buffer
+
+	//AddMessageError(PlatformBusy);
+	//This could take a while
+
+	if(pUploadParams->Type == UPLOAD_DDR)
+		pISR->CurrentTransferAddress = pUploadParams->Offset;
+	else
+		Retval = CopyUploadDataIntoBuffer(pISR->CurrentTransferAddress, pUploadParams);
+
+	AddMessageError(REPORT_NOTIFICATION, PlatformReady);
+	// data should in buffer now
+
+	if(Retval != NoError)
+	{
+		setProtocolError(Retval);
+		// This was probably an error reading from source as UploadParams checked out ok.
+		// Set to No Error so that error can be sent to Host in HandleUploadDataCmd.
+		Retval =  NoError;
+	}
+	else
+	{
+#if NAND_CODE || QSPINAND_CODE || SPINAND_CODE
+		if (upload_nand_spare == TRUE)
+		{
+			spare_size = GetSpareAreaSize(BOOT_FLASH); // get nand spare areas size
+			page_size = GetPageSize(BOOT_FLASH);
+			numbers = pUploadParams->DataSize / page_size; // calculate spare areas number
+			total_spare_size = numbers * spare_size; // total spare size
+
+			pISR->DataLeft = pUploadParams->DataSize + total_spare_size; // data length + total spare length
+		}
+		else
+#endif
+		{
+			pISR->DataLeft = pUploadParams->DataSize;
+		}
+	}
+
+	return Retval;
+
+}
+
+UINT_T HandleUploadDataCmd(void)
+{
+	UINT_T Retval = NoError,txDataSize = 0;
+	pProtocolRsp pRsp = (pProtocolRsp)transmitBuff;
+	pProtocolCmd pCmd = getProtocolCmd();
+	pProtocolISR pISR = getProtocolISR();
+
+	Retval = getProtocolError();
+	if(Retval!= NoError)
+	{
+	// We had a problem reading data for Data Upload
+		SendError(Retval);
+		return Retval;
+	}
+
+	if(pISR->DataLeft <= 0)
+	{
+		Retval = SeqError;
+		SendError(Retval);
+		return Retval;
+	}
+
+	pRsp->Command = UploadDataCmd;
+	pRsp->Sequence = pCmd->Sequence;
+	pRsp->CID = pCmd->CID;
+	pRsp->Status = Ack;
+
+	// Too bad length is only a byte. Not using it.
+	pRsp->Length = 0;
+
+	txDataSize = pISR->DataLeft < UPLOAD_BLOCK_SIZE ? pISR->DataLeft : UPLOAD_BLOCK_SIZE;
+	// Not a fan but have to do this. We have 6 byte status and arbitrary data.
+	memcpy((void*)&pRsp->Data[0], (void*)pISR->CurrentTransferAddress, txDataSize);
+
+
+	// Message bit should NOT be set in flags.
+	// At this point getProtocolMsg()->MessageFlag will be 0.
+	pRsp->Flags = pRsp->Flags & ~(MESSAGE_FLAG);
+	pRsp->Flags = pRsp->Flags | getProtocolMsg()->MessageFlag;
+
+	Retval = SendResponse(&pRsp->Command, txDataSize + 6);
+
+	pISR->CurrentTransferAddress += txDataSize;
+	pISR->DataLeft -= txDataSize;
+
+	return Retval;
+}
+
+UINT_T CopyUploadDataIntoBuffer(UINT_T address, pUploadDataParameters pUploadParams)
+{
+	UINT_T Retval = NoError;
+
+	switch(pUploadParams->Type)
+	{
+		case UPLOAD_FLASH:
+			// Fix me. Need code to check if sub type of flash is supported.
+			if (!upload_config_flash_flag && !FlashInitDone)
+			{
+				/* sub type of flash is not supported  */
+				//Retval = PlatformInitFlash(pUploadParams->SubType & 0x1F);
+				Retval = Configure_Flashes(pUploadParams->SubType & 0x1F, BOOT_FLASH);
+				if( Retval != NoError)
+					FatalError(Retval, NULL, NULL);
+
+				InitializeFM(LEGACY_METHOD, BOOT_FLASH);
+
+				upload_config_flash_flag = 1; // configure flash for upload only one time
+			}
+
+		#if NAND_CODE || QSPINAND_CODE || SPINAND_CODE
+
+			#if NAND_CODE
+			if (pUploadParams->ResetUE == 1)
+			{
+				AddMessageError(REPORT_UPLOAD_NOTIFICATION, NandID);
+			}
+			#endif
+
+			upload_nand_spare = pUploadParams->IncludeOOB;
+
+			upload_disable_ecc = pUploadParams->DisableECC;
+		#endif
+
+			// Set the partition.
+		#if MMC_CODE
+			SetPartition(pUploadParams->Partition, BOOT_FLASH);
+		#endif
+
+#if defined(NEZHA701) || defined(NEZHA702)
+	if ((pUploadParams->Offset <= MEP_FALSH_START &&
+		pUploadParams->Offset + pUploadParams->DataSize > MEP_FALSH_START) ||
+		(pUploadParams->Offset >= MEP_FALSH_START &&
+		pUploadParams->Offset < MEP_FALSH_START + MEP_FLASH_LEN))
+		Retval = NotSupportedError;
+	else
+#endif
+			Retval = ReadFlash(pUploadParams->Offset, address, pUploadParams->DataSize, BOOT_FLASH);
+		break;
+		default:
+		// Not supported.
+			Retval = NotSupportedError;
+		break;
+
+	}
+	return Retval;
+}
+
+UINT_T VerifyUploadParameters(pUploadDataParameters pUploadParams)
+{
+	UINT_T Retval = NoError, flashNum;
+	pTIM pTIM_h = GetTimPointer();
+	switch(pUploadParams->Type)
+	{
+		case UPLOAD_FLASH:
+			// Is flash subtype supported. Looking in Tim.
+			flashNum = pTIM_h->pConsTIM->FlashInfo.BootFlashSign & 0xFF;
+			if(flashNum != pUploadParams->SubType & 0xFF &&
+				flashNum != CI2_USB_D) //Empty board upload
+				Retval = UnsupportedFlashError;
+
+			if(pUploadParams->UploadBypassBBT) {
+				obm_printf("Upload Flash with BBT bypassed\n\r");
+				GetFlashProperties(BOOT_FLASH)->FlashSettings.UseBBM = 0;
+			}
+			break;
+		case UPLOAD_DDR:
+			break;
+		default:
+		// Not supported.
+			Retval = NotSupportedError;
+		break;
+
+	}
+	return Retval;
+}
+
+UINT_T HandleProtocolVersionCmd()
+{
+	UINT_T Retval = 0;
+	pProtocolRsp pRsp;
+	pProtocolCmd pCmd;
+
+	pCmd = getProtocolCmd();
+	pRsp = getProtocolRsp();
+
+	pRsp->Command = pCmd->Command;
+	pRsp->Sequence = pCmd->Sequence;
+	pRsp->CID = pCmd->CID;
+	pRsp->Status = Ack;
+	pRsp->Length = 4;
+
+	pRsp->Data[0] = COMM_PROTOCOL_MAJOR_VERSION;
+	pRsp->Data[1] = COMM_PROTOCOL_MINOR_VERSION;
+	*(UINT16_T*)&pRsp->Data[2] = COMM_PROTOCOL_REV_VERSION;
+
+	pRsp->Flags = pRsp->Flags & ~(MESSAGE_FLAG);
+	pRsp->Flags = pRsp->Flags | getProtocolMsg()->MessageFlag;
+
+	SendResponse(&pRsp->Command, 6 + pRsp->Length);
+	return Retval;
+}
+
+UINT_T HandleGetParametersCmd()
+{
+	UINT_T Retval = 0;
+	pProtocolRsp pRsp;
+	pProtocolCmd pCmd;
+
+	pCmd = getProtocolCmd();
+	pRsp = getProtocolRsp();
+
+	pRsp->Command = pCmd->Command;
+	pRsp->Sequence = pCmd->Sequence;
+	pRsp->CID = pCmd->CID;
+	pRsp->Status = Ack;
+	// Currently only sending buffer size. But we have 3 more reserved paramters.
+	// Note: Rsp structure only has space for 12 bytes of data ( 3 params). If we
+	// are going to use all 4 parameters, we need a buffer and memcpy.
+	pRsp->Length = 16;
+
+	*(UINT16_T *)&pRsp->Data[0] = COMM_PROTOCOL_BUFFER_SIZE & 0xffff;
+	*(UINT16_T *)&pRsp->Data[2] = (COMM_PROTOCOL_BUFFER_SIZE & 0xffff0000)>> 16;
+	pRsp->Flags = pRsp->Flags & ~(MESSAGE_FLAG);
+	pRsp->Flags = pRsp->Flags | getProtocolMsg()->MessageFlag;
+
+	// This should be
+	// SendResponse(&pRsp->Command, 6 + pRsp->Length);
+	// See note above
+	SendResponse(&pRsp->Command, 6 + pRsp->Length);
+	return Retval;
+}
+
+UINT_T HandleGetCrcCmd()
+{
+	UINT_T Retval = 0;
+	pProtocolRsp pRsp = (pProtocolRsp)transmitBuff;
+	pProtocolCmd pCmd;
+	UINT_T BufferAddr;
+	INT_T BufferLen = 4; //Nack
+
+	pCmd = getProtocolCmd();
+
+	pRsp->Command = pCmd->Command;
+	pRsp->Sequence = pCmd->Sequence;
+	pRsp->CID = pCmd->CID;
+	Retval = GetImageReadBackCrcBuffer(&BufferAddr, &BufferLen);
+
+	pRsp->Flags = pRsp->Flags & ~(MESSAGE_FLAG);
+	pRsp->Flags = pRsp->Flags | getProtocolMsg()->MessageFlag;
+
+	if(Retval == NoError){
+		pRsp->Status = Ack;
+		//pRsp->Length is UINT8, BufferLen exceed 255
+		pRsp->Length = BufferLen;
+		memcpy(&pRsp->Data[0], (UINT8 *)BufferAddr, BufferLen);
+	}else{
+		pRsp->Status = Nack;
+		pRsp->Length = 4;
+		*(UINT16_T *)&pRsp->Data[0] = Retval & 0xffff;
+		*(UINT16_T *)&pRsp->Data[2] = (Retval & 0xffff0000)>> 16;
+	}
+
+	//pRsp->Length is UINT8, BufferLen exceed 255, use BufferLen instead
+	SendResponse(&pRsp->Command, 6 + BufferLen);
+	return Retval;
+}
+
+UINT_T HandleGetBadBlock()
+{
+	UINT_T Retval = 0;
+	pProtocolRsp pRsp = (pProtocolRsp)transmitBuff;
+	pProtocolCmd pCmd;
+	P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
+	pBadBlockData bbData;
+
+	pCmd = getProtocolCmd();
+
+	pRsp->Command = pCmd->Command;
+	pRsp->Sequence = pCmd->Sequence;
+	pRsp->CID = pCmd->CID;
+	pRsp->Status = Ack;
+
+	bbData = (pBadBlockData)(&pRsp->Data[0]);
+	bbData->TotalBadBlocks = GetBadBlockNum();
+	bbData->TotalBlocks = pFlashProp->NumBlocks;
+	pRsp->Length = 8;
+
+	pRsp->Flags = pRsp->Flags & ~(MESSAGE_FLAG);
+	pRsp->Flags = pRsp->Flags | getProtocolMsg()->MessageFlag;
+
+	SendResponse(&pRsp->Command, 6 + pRsp->Length);
+	return Retval;
+}
+
+UINT_T AddMessageError(UINT_T ReportType, UINT_T ReportCode)
+{
+	UINT_T Retval = 0;
+
+  #if VERBOSE_MODE
+	UINT_T mIndex, i;
+	pProtocolMsg pMsg = getProtocolMsg();
+	MessageReport Report;
+
+	if(pMsg->NumMessagesQueued == MAXNUMOFMESSAGES)
+		return MessageBufferFullError; //this is when message buffer is full
+
+	//find the next open slot in the Queue
+	//It will be right after the last good message
+	//this is a circular queue, so we use the '%' operation
+	mIndex = (pMsg->CurrentMessageIndex + pMsg->NumMessagesQueued) % MAXNUMOFMESSAGES;
+
+	Report.ReportType = ReportType;
+	Report.Reserved = 0;
+
+	for (i = 0; i < 4; i++)
+	{
+		Report.ReportCode[i] = (ReportCode >> (8 * i)) & 0xff;
+	}
+
+	// copy message to buffer
+	pMsg->Lengths[mIndex] = 6;
+
+	pMsg->Messages[mIndex][0] = Report.ReportType;
+	pMsg->Messages[mIndex][1] = Report.Reserved;
+
+	for (i = 0; i < 4; i++)
+	{
+		pMsg->Messages[mIndex][i + 2] = Report.ReportCode[i];
+	}
+
+	pMsg->MessageType[mIndex] = 1; // Message type 1 indicate report code
+	//set flag
+	pMsg->MessageFlag = MESSAGE_FLAG;
+
+	pMsg->NumMessagesQueued++;
+
+  #endif //endif VERBOSE_MODE
+	return NoError;
+}
+
+void InitProtocol(void)
+{
+	pProtocolMsg pMsg = getProtocolMsg();
+	//pProtocolCmd pCMD = getProtocolCmd();
+	pProtocolRsp pRsp = getProtocolRsp();
+	pProtocolISR pISR = getProtocolISR();
+
+	memset(pMsg, 0, sizeof(ProtocolMsg));
+	//memset(pCMD, 0, sizeof(ProtocolCmd));
+	memset(pRsp, 0, sizeof(ProtocolRsp));
+	memset(pISR, 0, sizeof(ProtocolISR));
+}
+
+
+
+/*
+ *	HandleRequest()
+ *
+ *	This is the main function of the protocol manager.  It is the entry point
+ *	to start a request over a port after an interrupt is received.  The process
+ *	for handling a request is as follows:
+ *
+ *	1) Get the preamble from the port and verify it
+ *	2) Get the first command packet from the port
+ *	3) Send back and ack with proper flag settings
+ *	4) Based on the command jump to the download flow or the JTAG flow
+ *	5) Complete the download or JTAG request and when complete disconnect
+ *	6) return status to the caller
+ *
+ *
+ */
+
+UINT_T HandleRequest(UINT_T src_addr, UINT_T dest_addr, UINT_T max_size, UINT_T image_id)
+{
+	UINT_T Retval = NoError;
+	pProtocolCmd pCmd = getProtocolCmd();
+
+	do
+	{
+		switch(pCmd->Command)
+		{
+		case GetVersionCmd:
+			//Retval = HandleDownloadFlow(dest_addr, image_id, max_size);
+			break;
+
+#if!BOOTROM
+		case UploadDataHeaderCmd:
+			Retval = HandleUploadFlow(src_addr);
+			if(Retval != NoError)
+				return Retval;
+			break;
+#endif
+		case DisconnectCmd:
+			//if there was an issue with a download, then tool will try to disconnect
+			//handle the disconnect, but return an error since we couldn't do a download
+			//getProtocolISR()->CommandReceived = TRUE; // This hack is needed for optimization. Handledisconnect waits for a command again
+			Retval = HandleDisconnect();
+			return Retval;
+		default:
+			//Retval.ErrorCode = SendError(0);
+			//Retval.ErrorCode = UnknownProtocolCmd;
+			break;
+		}
+		if(Retval != NoError)
+			break;
+
+	}while(pCmd->Command != DoneCmd);
+
+	if(pCmd->Command == DoneCmd)
+		HandleDoneCmd();
+	else
+		Retval = SendError(0);
+
+	return Retval;
+}
+
+//--------------------------------------------------------
+// Utility routines
+//--------------------------------------------------------
+
+
+
+/*
+ *  Verify that the Preamble matches
+ */
+UINT8_T PM_VerifyPreamble( UINT8_T *candidateString )
+{
+	//Compare the candidate preamble to the defined string
+	if( 0 == memcmp(candidateString, preambleString, sizeof(preambleString)) )
+	{	//MATCH
+		//return that all is good
+		return TRUE;
+	}
+	else
+	{	//Bad String
+		return FALSE;
+	}
+}
+
+/*
+ *  Check to see if routine has timed out
+ */
+UINT8_T CheckProtocolTimeOut(UINT_T StartTime)
+{
+	UINT_T WaitTime = 0;
+	UINT_T CurrentTime;
+
+	CurrentTime = GetOSCR0();
+
+	WaitTime = OSCR0IntervalInSec(StartTime, CurrentTime);  // measure wait time in sec
+
+	if (WaitTime >= PROTOCOL_WAITTIME)
+		return (CheckProtocolTimeOutError);
+	else return NoError;
+}
+