/* flashDrv.c - Flash memory device driver */
#ifdef USE_VXWORKS /* IXDP425 */
#include "copyright_wrs.h"

#include "vxWorks.h"
#include "config.h"
#include "ioLib.h"
#include "iosLib.h"
#include "memLib.h"
#include "errnoLib.h"
#endif
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
#ifdef USE_VXWORKS
#include "bootlib.h"
#include "ftplib.h"
#include "fiolib.h"
#include "remlib.h"
#include "taskLib.h"
#else
#define EOS '\0'
#include <linux/param.h>
#include <unistd.h>
typedef int		(*FUNCPTR)();
#endif


#include "flash.h"
#include "flashMem.h"
#include "apidef.h"
#ifdef MPC_855 /* this is Vxworks related not needed in IXDP425 */

typedef struct		/* FLASH_DEV - memory device descriptor */
    {
    DEV_HDR devHdr;
    int base;		/* start of memory */
    int length;		/* how much */
    int offset;		/* current position */
    int mode;		/* O_RDONLY, O_WRONLY, O_RDWR */
    int fileLen;        /* Length of existing file    */
    int firstSector;    /* First sector assigned to this driver  */
    int numSector;      /* Number of sectors allocated for this driver */
    int currentSector;  /* Current sector being accessed   */
    int sectorOffset;   /* Current offset for the currect sector  */
    } FLASH_DEV;
#endif

extern void flashEraseImage( int imageNum);
extern UINT initFlash( void ); 
extern STATUS	inflate (char *, char *, int);
extern STATUS memDrv (void);
extern STATUS memDevCreate (char *, char *, int);
extern STATUS 	bootLoadModule ();
extern STATUS 	memDevDelete ();
extern int	logMsg (char *fmt, int arg1, int arg2,
			int arg3, int arg4, int arg5, int arg6);
extern STATUS 	tftpXfer (char * pHost, int port, char * pFilename,
			  char * pCommand, char * pMode, int * pDataDesc,
    			  int * pErrorDesc);

//extern int intLock(void); /* IXDP425 */
//extern void intUnlock(int);
extern int inflate(char * src, char * dest, int nBytes);
extern char tmpBuf[];
extern int FlashEraseSectorVW(volatile char *pSector);

/*
**  For debugging, we can enable trace messages by setting flashDebug to non zero.
*/
extern int flashDebug;
char 	tmpBuf[0x400000];
int		tmpFileSize;
/******************************************************************************/

int bootNum;

int flashDebug = 0;                           


/******************************************************************************/

#define  UNCMP_BUF_SIZE   0x00800000

#ifdef MPC_855 /* IXDP425 */
STATUS flashLoad( int vxWorksImage, FUNCPTR *pEntry)
{

    int      fd;
    char    *flashPtr;
    STATUS   flashStatus;

    flashPtr = ( UCHAR * ) RAM_LOW_ADRS;

    flashStatus = flashReadImage( vxWorksImage, flashPtr);
    if( flashStatus != OK ) return flashStatus;
    /*
    **  Now open the file for reading and load it into 
    **  system RAM so we can start the system
    */

    fd = open ("/mem/Image/", O_RDONLY, 0);

#ifdef FLASH_SUPPORT_INCLUDE  

    if (bootLoadModule (fd, pEntry) != OK)
    { 
       if (flashDebug)
          logMsg("error in downloading Image from flash error %D\n", errno,0,0,0,0,0);
    }
    
    *pEntry = (FUNCPTR)0x100000;
#endif

    close(fd);   

    /*
    **  Clean up file system and return allocated memory.
    */
    return OK;

}
#endif

/* the programming of downLoadImageOnly is specific to vxWorks ... */

STATUS downLoadImageOnly( int vxWorksImage, char *hostName, char *fileName,
                                    char *usr, char *passwd, FUNCPTR *pEntry )
{
    int fd;
    int errFd;		/* for receiving standard error messages from Unix */
    char command [100];
    BOOL bootFtp = (passwd[0] != EOS);
    BOOL bootRsh = FALSE;
    int rc;
    int fileSize = 0;
    int numOfReads = 0;    
    unsigned char *bPtr;
    unsigned char temp[512];
    unsigned char *currentPtr;
    int errorReportCount = 0;
    STATUS retval = OK;
    
    bPtr = tmpBuf;

    currentPtr = bPtr;

/*	if (tftpXfer (hostName, 0, fileName, "get", "binary", &fd,
		      &errFd) == ERROR)*/
/*Above line is commented for IXDP425 as tftpXfer is VxWorks call */
	    return (ERROR);
    
    /*
    **  Now store the file into our cache buffer.
    */
    while( ( rc = read( fd, temp, 512 ) ) > 0 )
    {

        bcopy( temp, currentPtr, rc );
        numOfReads++;
        currentPtr += rc;
        fileSize   += rc;
        
    }                                                   

/* reuse temp - contents have been copied to tmpBuf .. */
/* vxWorks manual suggests up to 512 bytes may be available */

    errorReportCount = read( errFd, temp, 512 );
    if (errorReportCount > 0)
    {
	temp[ errorReportCount ] = '\0';

  	/*printf( "\nImage download failed, error message is %s\n", temp );*/
	/* error message from VxWorks is not very helpful without parsing */
	/* testing shows tftpLib itself displays a useful error message on failure */

  	printf( "\nImage download failed.\n" );
	tmpFileSize=0;
        retval = ERROR;
    }
    else
    {

    /*
    **  On successful transfer, image stays in tmpBuf,
    **  presumably to be sent to the CPE modems(s)
    */

	tmpFileSize=fileSize;

	if (fileSize > 0)
	  printf( "\nImage %s size=%d (bytes) downloaded successful\n",  fileName, fileSize);
	else
        {
	  printf( "\nImage %s downloaded failed, no data transferred\n",  fileName );
          retval = ERROR;
	}
    }

    /* program both images for new unit */
    
/*   free the temporary buffer   */
/*    if( bPtr ) free(bPtr);*/

    if( bootRsh == FALSE )
    {

        /* Empty the Data Socket before close. PC FTP server hangs otherwise */

        while( ( rc = read( fd, command, sizeof( command ) ) ) > 0 )
        {
            fileSize += rc;
        }

        if( bootFtp ) (void) ftpCommand ( errFd, "QUIT", 0, 0, 0, 0, 0, 0 );
    }

    close( fd );
    close( errFd );
    return retval;
}


STATUS flashDownLoadImage( int vxWorksImage, char *hostName, char *fileName,
                                    char *usr, char *passwd, FUNCPTR *pEntry )
{
#ifdef MPC_855 /* IXDP425 */
    int fd;
    int errFd;		/* for receiving standard error messages from Unix */
    char command [100];
    BOOL bootFtp = (passwd[0] != EOS);
    BOOL bootRsh = FALSE;
    int rc;
    int fileSize = 0;
    int numOfReads = 0;    
    unsigned char *bPtr;
    unsigned char temp[512];
    unsigned char *currentPtr;
    int errorReportCount = 0;
    STATUS retval = OK;
    
    bPtr = tmpBuf;

    currentPtr = bPtr;

/*	if (tftpXfer (hostName, 0, fileName, "get", "binary", &fd,
		      &errFd) == ERROR)*/
/*Above line is commented for IXDP425 as tftpXfer is VxWorks call */
	    return (ERROR);
    
    /*
    **  Now store the file into our cache buffer.
    */
    while( ( rc = read( fd, temp, 512 ) ) > 0 )
    {

        bcopy( temp, currentPtr, rc );
        numOfReads++;
        currentPtr += rc;
        fileSize   += rc;
        
    }


/* reuse temp - contents have been copied to tmpBuf .. */
/* vxWorks manual suggests up to 512 bytes may be available */

    errorReportCount = read( errFd, temp, 512 );
    if (errorReportCount > 0)
    {
	temp[ errorReportCount ] = '\0';

  	/*printf( "\nImage download failed, error message is %s\n", temp );*/
	/* error message from VxWorks is not very helpful without parsing */
	/* testing shows tftpLib itself displays a useful error message on failure */

  	printf( "\nImage download failed.\n" );
	tmpFileSize=0;
        retval = ERROR;
    }
    else

    /*
    **  Write the image to flash.
    */
    if (fileSize > IMAGE_LEN && vxWorksImage == 2) {                   
        printf("\nERROR. Not enough space for image 2.\n");
    }
    else if (fileSize < 1) {
	  printf( "\nImage %s downloaded failed, no data transferred\n",  fileName );
	  retval = ERROR;
    }
    else {
        printf( "\nWriting vxWorks image %x, size %x to flash...\n",  vxWorksImage, fileSize);

        /* program both images for new unit */
        
        flashWriteImage( vxWorksImage, bPtr, fileSize );
        printf("\nEnd flashWriteImage.\n");

        imageLengthSave(vxWorksImage, fileSize);
    }
    
    if( bootRsh == FALSE )
    {

        /* Empty the Data Socket before close. PC FTP server hangs otherwise */

        while( ( rc = read( fd, command, sizeof( command ) ) ) > 0 )
        {
            fileSize += rc;
        }

        if( bootFtp ) (void) ftpCommand ( errFd, "QUIT", 0, 0, 0, 0, 0, 0 );
    }

    close( fd );
    close( errFd );
    return retval;
#endif 
    return 0;
}


STATUS uploadImageOnly( int len, char *hostName, char *fileName,
                                    char *usr, char *passwd, FUNCPTR *pEntry )
{
#ifdef MPC_855 /* IXDP425 */
    int fd;
    int errFd;		/* for receiving standard error messages from Unix */
    int rc;
    int fileSize = 0;
    unsigned char *bPtr;
    unsigned char temp[512];
    unsigned char *currentPtr;
    STATUS retval = OK;
    
    bPtr = tmpBuf;

    currentPtr = bPtr;

/*	if (tftpXfer (hostName, 0, fileName, "put", "binary", &fd,
		      &errFd) == ERROR) */
/*Above line is commented for IXDP425 as tftpXfer is VxWorks call */
	    return (ERROR);
#ifdef USE_VXWORKS    /*IXDP425*/
    taskDelay(60);
#else
    usleep(60);
#endif
    
    printf( "\nStart uploading file...\n" );
    /*
    **  Now store the file into our cache buffer.
    */
    bcopy(currentPtr, temp, 512 );
    while( fileSize < len )
    {
        if (( rc = write( fd, temp, 512 ) ) > 0) {
            currentPtr += rc;
            fileSize   += rc;
            bcopy(currentPtr, temp, rc );
        }
        
    }                                                   

    printf( "\nEnd uploading file.\n" );
/* reuse temp - contents have been copied to tmpBuf .. */
/* vxWorks manual suggests up to 512 bytes may be available */
#if 0
    errorReportCount = write( errFd, temp, 512 );
    if (errorReportCount > 0)
    {
	    temp[ errorReportCount ] = '\0';

  	/*printf( "\nImage download failed, error message is %s\n", temp );*/
	/* error message from VxWorks is not very helpful without parsing */
	/* testing shows tftpLib itself displays a useful error message on failure */

  	    printf( "\nImage download failed.\n" );
	    tmpFileSize=0;
        retval = ERROR;
    }
    else
    {

    /*
    **  On successful transfer, image stays in tmpBuf,
    **  presumably to be sent to the CPE modems(s)
    */

	    tmpFileSize=fileSize;

	    if (fileSize > 0)
	        printf( "\nImage %s size=%d (bytes) uploaded successful\n",  fileName, fileSize);
	    else
        {
	        printf( "\nImage %s uploaded failed, no data transferred\n",  fileName );
            retval = ERROR;
	    }
    }
    /* program both images for new unit */
    
/*   free the temporary buffer   */
/*    if( bPtr ) free(bPtr);*/

    if( bootRsh == FALSE )
    {

        /* Empty the Data Socket before close. PC FTP server hangs otherwise */

        while( ( rc = read( fd, command, sizeof( command ) ) ) > 0 )
        {
            fileSize += rc;
        }

        if( bootFtp ) (void) ftpCommand ( errFd, "QUIT", 0, 0, 0, 0, 0, 0 );
    }
#endif
    close( fd );
    return retval;
#endif 
    return 0;
}

STATUS remoteDownLoadImage( int vxWorksImage, char *hostName, char *fileName)
{
    downLoadImageOnly (vxWorksImage, hostName, fileName, "anonymous", "user", 0);
    return OK;
}


STATUS remoteFlashImage( int vxWorksImage, char *hostName, char *fileName)
{
    flashDownLoadImage (vxWorksImage, hostName, fileName, "anonymous", "user", 0);
    return OK;

}


STATUS remoteUpLoadImage( int len, char *hostName, char *fileName)
{
    uploadImageOnly (len, hostName, fileName, "anonymous", "user", 0);
    return OK;
}

/***********************************************************************/

STATUS flashReadImage( int imageNum, char *buf)
{

    char     *ptr=0;
    int      len=0, imageLen=0;      
 
    if (imageNum == 1) {
        ptr = VXWORKS_IMAGE1_ADRS;
        imageLen = *IMAGE_1_LEN ;
    }
    else if (imageNum == 2) {
        ptr = VXWORKS_IMAGE2_ADRS;
        imageLen = *IMAGE_2_LEN ;
    }
    if (*(ptr+1) == 'E' && *(ptr+2) == 'L' && *(ptr+3) == 'F') {
        ptr += 0x10000;
        while (len < imageLen) {
            *buf = *ptr;
            buf++;
            ptr++;
            len++;
        }
    }
    else {
        //inflate(ptr, buf-0x10000, imageLen); /* IXDP425 */
    }
    
    return OK;

}

/***********************************************************************/

int flashWriteImage( int imageNum, char *buf, int bufLen )
{

    char     *ptr = VXWORKS_IMAGE1_ADRS;
    int      len=0;
    //int lock; /* IXDP425 */                                
 
    if (imageNum == 1) {
        ptr = VXWORKS_IMAGE1_ADRS;
    }                                     
    else if (imageNum == 2) {
        ptr = VXWORKS_IMAGE2_ADRS;
    }
    if ((ptr + bufLen) < (VXWORKS_IMAGE1_ADRS + IMAGE_LEN * 2)) {
        //lock = intLock(); /* IXDP425 */
        while (len < bufLen) {
            FlashEraseSectorVW(ptr);
            FlashWriteVW (ptr, buf, FLASH_SECT_SIZE);
            ptr += FLASH_SECT_SIZE;
            buf += FLASH_SECT_SIZE;
            len += FLASH_SECT_SIZE;
            printf(".");
        }
        //intUnlock(lock); /* IXDP425 */
		return (IPOS_SUCCESS);
    }
    else
	{
        printf("\nERROR. Not enough space for image %d.\n", imageNum);
		return (IPOS_RFM_SPACE_ERR);
	}
    
    printf(" Done.");

}

/***********************************************************************/

void flashEraseImage( int imageNum)
{

    char     *ptr = VXWORKS_IMAGE1_ADRS;
    int      len=0;
    //int lock; /* IXDP425 */
 
    if (imageNum == 1) {
        ptr = VXWORKS_IMAGE1_ADRS;
    }
    else if (imageNum == 2) {
        ptr = VXWORKS_IMAGE2_ADRS;
    }

    //lock = intLock(); /* IXDP425 */
    while (len < IMAGE_LEN) {
        FlashEraseSectorVW(ptr);
        ptr += FLASH_SECT_SIZE;
        len += FLASH_SECT_SIZE;
        printf(".");
    }
    //intUnlock(lock); /* IXDP425 */

    printf(" Done.");

}

/***********************************************************************/
char imageStringSave(char index, char *addr)
{
    char *ptr;

    ptr = tmpBuf;
    memcpy(ptr, START_MAC_IP_ADRS, FLASH_SECT_SIZE); 
    if (index == 1) {
        memcpy(ptr+STRING_1_OFFSET, addr, IMAGE_STR_SIZE); 
    }
    else if (index == 2) {
        memcpy(ptr+STRING_2_OFFSET, addr, IMAGE_STR_SIZE); 
    }
    wtSect(START_MAC_IP_ADRS, (char *)ptr, FLASH_SECT_SIZE); 
    return OK;
}


/***********************************************************************/
char imageStringGet(char index, char *addr)
{
    char *ptr;

    if (index == 1) {
        ptr = START_MAC_IP_ADRS+STRING_1_OFFSET;
        memcpy(addr, ptr,  IMAGE_STR_SIZE); 
    }
    else if (index == 2) {
        ptr = START_MAC_IP_ADRS+STRING_2_OFFSET;
        memcpy(addr, ptr,  IMAGE_STR_SIZE); 
    }
    return OK;
}

/***********************************************************************/
char imageFlagSet(char index)
{
    char *ptr;

    ptr = tmpBuf;
    memcpy(ptr, START_MAC_IP_ADRS, FLASH_SECT_SIZE); 
    if (index == 1) {
        *(ptr + DOWNLOAD_1_OFFSET) = 1; 
    }
    else if (index == 2) {
        *(ptr + DOWNLOAD_2_OFFSET) = 1; 
    }
    wtSect(START_MAC_IP_ADRS, (char *)ptr, FLASH_SECT_SIZE); 
    return OK;
}


/***********************************************************************/
char imageFlagReset(char index)
{
    char *ptr;

    ptr = tmpBuf;
    memcpy(ptr, START_MAC_IP_ADRS, FLASH_SECT_SIZE); 
    if (index == 1) {
        *(ptr + DOWNLOAD_1_OFFSET) = 0; 
    }
    else if (index == 2) {
        *(ptr + DOWNLOAD_2_OFFSET) = 0; 
    }
    wtSect(START_MAC_IP_ADRS, (char *)ptr, FLASH_SECT_SIZE); 
    return OK;

}

/***********************************************************************/
char indexFlagGet(void)
{
    return (*DOWNLOAD_I_ADRS);
}

/***********************************************************************/
char indexFlagSet(char index)
{
    char *ptr;

    ptr = tmpBuf;
    memcpy(ptr, START_MAC_IP_ADRS, FLASH_SECT_SIZE); 
    *(ptr + DOWNLOAD_I_OFFSET) = index; 
    wtSect(START_MAC_IP_ADRS, (char *)ptr, FLASH_SECT_SIZE);
    return OK; 
}
/***********************************************************************/
char imageNumSet(char index)
{
    char *ptr, *ptr1;

    ptr = tmpBuf;                  
    memcpy(ptr, START_MAC_IP_ADRS, FLASH_SECT_SIZE); 
    ptr1 = ptr + 0x3e000;                  
    while (ptr1++) {
        if (*ptr1 == 'o' && *(ptr1+1) == '=') {
            if (index == 1) {
                *(ptr1+4) = '1';
            }
            else if (index == 2) {
                *(ptr1+4) = '2';
            }
           break;
        }
        if (ptr1 > (tmpBuf + FLASH_SECT_SIZE)) {
            break;
        }
    }
    *(ptr + DOWNLOAD_I_OFFSET) = index; 
    wtSect(START_MAC_IP_ADRS, (char *)ptr, FLASH_SECT_SIZE); 
    return OK;
}

/***********************************************************************/
char imageLengthSave(char index, int size)
{
    int *ptr;

    ptr = (int *)tmpBuf;
    memcpy(ptr, START_MAC_IP_ADRS, FLASH_SECT_SIZE); 
    if (index == 1) {
        *(ptr + IMAGE_1_OFFSET/4) = size; 
    }
    else if (index == 2) {
        *(ptr + IMAGE_2_OFFSET/4) = size; 
    }
    wtSect(START_MAC_IP_ADRS, (char *)ptr, FLASH_SECT_SIZE); 
    return OK;

}

/***********************************************************************/
char bootloadInfo(void)
{
    char *ptr;

    ptr = (char *)BOOTLOADER_INFO_ADRS;
    return (strcmp(ptr, "Copyright 1988-2000 Wind River HSI Corporation"));

}


/***********************************************************************/
char saveImageVer(char *verString)
{
	char *ptr, index;

    ptr = tmpBuf;

	if(bootloadInfo() == 0) {		/* bootloader is compatiable */
        index = indexFlagGet();
        memcpy(ptr, START_MAC_IP_ADRS, 0x40000); 
        if (strcmp(ptr+(STRING_1_OFFSET*index),verString)) {
            if (indexFlagGet() == 1) {
                strcpy (ptr+STRING_1_OFFSET,verString);
            }
            else if (indexFlagGet() == 2) {
                strcpy (ptr+STRING_2_OFFSET,verString);
            }

            wtSect(START_MAC_IP_ADRS, (char *)ptr, 0x40000); 
        }
    }
	return	OK;
}



void	saveSysInfo(char	*sysInfo)
{

	//int	 lock; /* IXDP425 */
	char *ptr;
    ptr = tmpBuf;

	//lock=intLock(); /* IXDP425 */
    memcpy(ptr, START_MAC_IP_ADRS, 0x40000); 

    if (memcmp(ptr+SYSINFO_OFFSET, sysInfo, SYSINFO_LEN)) {
                memcpy (ptr+SYSINFO_OFFSET,sysInfo, SYSINFO_LEN);
	            wtSect(START_MAC_IP_ADRS, (char *)ptr, 0x40000); 
        }

	//intUnlock(lock); /* IXDP425 */

}


char getSysInfo (char	*sysInfo)
{

	memcpy(sysInfo, START_MAC_IP_ADRS+SYSINFO_OFFSET, SYSINFO_LEN);
	return	OK;

}


void tstSave()
{

	char	sysInfo[64]="16 bit SDRAM", sysInfo2[64];
	saveSysInfo(sysInfo);
	getSysInfo(sysInfo2);
	printf("%s", sysInfo2);

}


void saveDiagFlashInfo(char	*info, int offset, int len)
{

	//int	 lock; /* IXDP425 */
	char *ptr;
    ptr = tmpBuf;

	//lock=intLock(); /* IXDP425 */
    memcpy(ptr, START_MAC_IP_ADRS, 0x40000); 

    if (memcmp(ptr+offset, info, len)) {
                memcpy (ptr+offset,info, len);
	            wtSect(START_MAC_IP_ADRS, (char *)ptr, 0x40000); 
        }

	//intUnlock(lock); /* IXDP425 */
}

void getDiagFlashInfo(char	*info, int offset, int len)
{

	memcpy(info, START_MAC_IP_ADRS+offset, len);

}
	
/***********************************************************************/
/* return address of boot loader version string
   two possibilities
   1)  .cdx compatible boot loader.  bootloadInfo() returns 0.
       This routine returns CDX_BOOTLOADER_INFO_ADRS
   2)  .bdx compatible boot loader.  bootloadInfo() returns non-zero value
       This routine returns BDX_BOOTLOADER_INFO_ADRS

   This routine is required to either return an address of a NUL-terminated
   string of length <= 100 or NULL.  The calling program shall be able to
   pass the return value from this routine to strlen() without risking a
   bus trap or machine check, provided the return value is not NULL.   */
/***********************************************************************/

char *
getBootloadInfo(void)
{
	if (bootloadInfo() == 0)
	  return( CDX_BOOTLOADER_INFO_ADRS );
	else
	  return( BDX_BOOTLOADER_INFO_ADRS );
}
