/****************************************************************************
**
**  Name:  rdwr.c
**
**  Description:
**     Confidence test driver read, write, ramtst support functions
**
**  $Log:   S:/tbird/mt2_186/pvtest/rdwr.c_v  $
** 
**    Rev 1.1   27 Mar 1998 15:15:12   Eric
** No change.
** 
**    Rev 1.0   16 Dec 1996 16:45:26   Judy
** Initial revision.
** 
**    Rev 1.1   10 Oct 1994 13:32:56   ernie
** Added SPACE_JTAG
** 
**    Rev 1.0   10 May 1994 09:53:08   ernie
** Initial revision.
** 
**  $Header:   S:/tbird/mt2_186/pvtest/rdwr.c_v   1.1   27 Mar 1998 15:15:12   Eric  $
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef _ADDR_
#include "addr.h"
#endif
#ifndef _BASEWIND_
#include "basewind.h"
#endif
#ifndef _HEAP_
#include "heap.h"
#endif
#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif
#ifndef _LOCAL_
#include "local.h"
#endif
#ifndef _PVTASK_
#include "pvtask.h"
#endif
#ifndef _PVTEST_
#include "pvtest.h"
#endif
#ifndef _SDPROBE_
#include "sdprobe.h"
#endif
#ifndef _SSHARED_
#include "sshared.h"
#endif
#ifndef _TBIRDMEM_
#include "tbirdmem.h"
#endif

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
#define MAX_SPACES       64

typedef struct {
   char name[MAX_MAPPED_NAME];
   U16  value;
   BOOLEAN bigEndian;
} SPACE_MAPPING;

static HANDLE hLib;
static SPACE_MAPPING spaceTable[MAX_SPACES];
static U16 numSpaces;

                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/
RETCODE PRIVATE CacheNames(VOID);
RETCODE EXPORT ConfigSpaceCallback(LPSTR key, LPSTR value, BOOLEAN *abort,
   VOID *data);

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/

#pragma argsused
int FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg, WORD cbHeapSize,
      LPSTR lpszCmdLine) {
   if (cbHeapSize != 0) /* the DLL Data segment is MOVEABLE */
      UnlockData(0);
   /*
   ** Read and cache memory space names
   */
   CacheNames();
   hLib = hInstance;
   return(TRUE);
}

/****************************************************************************
**
** CacheNames
**
** Read the config file and fill in the tables of test and space names and
** the list of tests for the installed processor.
**
*****************************************************************************/
RETCODE PRIVATE CacheNames(VOID) {
   numSpaces = 0;
   return(ConfigFileEnumerate("[spaces]",ConfigSpaceCallback,
      NULL, NULL));
}

#pragma argsused
RETCODE EXPORT ConfigSpaceCallback(LPSTR key, LPSTR value, BOOLEAN *abort,
      VOID *data) {
   LPSTR space, endian;
   if ((space = strtok(value,",")) == NULL) return(GOOD);
   if ((endian = strtok(NULL,"\n")) == NULL) return(GOOD);
   strcpy(spaceTable[numSpaces].name, key);
   spaceTable[numSpaces].value = (U16)strtoul(space,NULL,0);
   spaceTable[numSpaces].bigEndian = (toupper(*endian) == 'B');
   numSpaces++;
   return(GOOD);
}

/****************************************************************************
**
** ConfigFileRead
**
** Extract one item from the test config file.
*****************************************************************************/
RETCODE EXPORT ConfigFileRead(LPSTR section, LPSTR key,
                              LPSTR value) {
   FILE *ifp;
   S8 line[MAX_LINE];
   LPSTR token,white;
   size_t len;
   *value = '\0';
   if ((ifp = fopen(CONFIG_FILE, "r")) == NULL) return(GOOD);
   len = strlen(section);
   do {
      if (fgets(line, MAX_LINE, ifp) == NULL) goto DONE;
   } while (strnicmp(line,section,len));
   len = strlen(key);
   do {
      if (fgets(line, MAX_LINE, ifp) == NULL) goto DONE;
      if (strstr(line,"//")) continue;   /* comment line */
      if (strstr(line,"/*")) continue;   /* comment line */
      if (strstr(line,"[")) goto DONE;
      token = strtok(line,"=");
      if (!token) break;
      if ((white = strpbrk(token," \t")) != NULL) *white='\0';
   } while (stricmp(token,key));
   if (token) {
      token = strtok(NULL,"\n");
      if (token) strcpy(value, token);
   }
DONE:
   fclose(ifp);
   return(GOOD);
}

/****************************************************************************
**
** ConfigFileEnumerate
**
** Enumerate all items under a given section name and call function for each.
*****************************************************************************/
RETCODE EXPORT ConfigFileEnumerate(LPSTR section,
      CONFIG_CALLBACK callback, BOOLEAN *abort, VOID *data) {
   RETCODE err=GOOD;
   FILE *ifp;
   S8 line[MAX_LINE];
   size_t len;
   LPSTR key,value,white;
   if ((ifp = fopen(CONFIG_FILE, "r")) == NULL) return(GOOD);
   len = strlen(section);
   do {
      if (fgets(line, MAX_LINE, ifp) == NULL) goto DONE;
   } while (strnicmp(line,section,len));
   while(1) {
      if (fgets(line, MAX_LINE, ifp) == NULL) break;
      if (strstr(line,"//")) continue;   /* comment line */
      if (strstr(line,"/*")) continue;   /* comment line */
      if (strstr(line,"[")) break;       /* done */
      if ((key = strtok(line,"=")) == NULL) continue;
      if ((value = strtok(NULL,"\n")) == NULL) continue;
      if ((white = strpbrk(key," \t")) != NULL) *white='\0'; //strip whitespace
      if ((err = (*callback)(key, value, abort, data)) != GOOD) goto DONE;
      if (abort && *abort) break;
   }
DONE:
   fclose(ifp);
   return(err);
}

/****************************************************************************
**
** TestIsExtendedSpace
**
*****************************************************************************/
BOOLEAN EXPORT TestIsExtendedSpace(LPSTR str, ADDR_SPACE *space) {
   /* Search space table for name */
   U16 entry;
   for (entry=0; entry<numSpaces; entry++) {
      if (stricmp(str, spaceTable[entry].name) == 0) {
         *space = spaceTable[entry].value;
         return(TRUE);
      }
   }
   return(FALSE);
}

/****************************************************************************
**
** TestIsSastBitName
**
*****************************************************************************/
BOOLEAN EXPORT TestIsSastBitName(LPSTR str, ADDR_SPACE space, U32 *addr) {
   S8 section[32];
   S8 valString[32];
   LPSTR token;
   switch (space) {
      case SPACE_SAST:
         if (ProcInsertSystemName("[sast %s]",section) != GOOD) return(FALSE);
         if (ConfigFileRead(section, str, valString) != GOOD) return(FALSE);
         if (*valString == '\0') return(FALSE);   /* not in sast signal list */
         *addr = strtoul(valString,NULL,0);
         return(TRUE);
      case SPACE_JTAG:
         if (ProcInsertSystemName("[jtaginput %s]",section) != GOOD)
            return(FALSE);
         if (ConfigFileRead(section, str, valString) != GOOD) return(FALSE);
         if (*valString == '\0') return(FALSE);   /* not in jtag signal list */
         if ((token = strtok(valString, ",")) == NULL) return(FALSE);
         if ((token = strtok(valString, ",\n")) == NULL) return(FALSE);
         if ((token = strtok(valString, ",\n")) == NULL) return(FALSE);
         *addr = strtoul(token,NULL,0);
         return(TRUE);
      default:
         break;
   }
   return(FALSE);
}

/****************************************************************************
**
** TestSwapBytesInWord
** TestSwapBytesInLong
**
*****************************************************************************/
U16 EXPORT TestSwapBytesInWord(U16 input, ADDR_SPACE space) {
   /* Search space table for value */
   U16 entry;
   for (entry=0; entry<numSpaces; entry++) {
      if (spaceTable[entry].value == space) {
         if (spaceTable[entry].bigEndian) {
            U16 result;
            ((U8*)&result)[0] = ((U8*)&input)[1];
            ((U8*)&result)[1] = ((U8*)&input)[0];
            return(result);
         }
         return(input);
      }
   }
   return(input);   // not found...assume little endian
}

U32 EXPORT TestSwapBytesInLong(U32 input, ADDR_SPACE space) {
   /* Search space table for value */
   U16 entry;
   for (entry=0; entry<numSpaces; entry++) {
      if (spaceTable[entry].value == space) {
         if (spaceTable[entry].bigEndian) {
            U32 result;
            ((U8*)&result)[0] = ((U8*)&input)[3];
            ((U8*)&result)[1] = ((U8*)&input)[2];
            ((U8*)&result)[2] = ((U8*)&input)[1];
            ((U8*)&result)[3] = ((U8*)&input)[0];
            return(result);
         }
         return(input);
      }
   }
   return(input);   // not found...assume little endian
}

/****************************************************************************
**
** TestRead
**
*****************************************************************************/
RETCODE EXPORT TestRead(DESCRIPTOR addr, ADDR_SPACE space, U32 length,
                        U8 **data, BOOLEAN loop) {
   RETCODE err;
   U32 physical;
   if ((*data = (U8*)TMalloc(length)) == 0) return(ER_OUT_OF_MEMORY);
   /*!!! This should be AdrToPhysical() when implemented */
   if ((err = AdrGetAddrOffset(addr, &physical)) != GOOD) return(err);
   return(TestReadPhysical(physical, space, length, *data, loop));
}

RETCODE EXPORT TestReadPhysical(U32 offset, ADDR_SPACE space, U32 length,
                        U8 *data, BOOLEAN loop) {
   RETCODE err;
   RDWR_COMMAND cmd = RDWR_READ;
   BOOLEAN timedOut;
   BOOLEAN abort = TRUE, abortFromEsc;
   ACCESS_SIZE access;
   if (length == 0) return(GOOD);
   if ((err = TskCheckAbort(&abortFromEsc)) != GOOD) return(err);
   if ((err = MemGetAccessSize(&access)) != GOOD) return(err);
   if ((err = SdnWriteMember(SDN_RDWR_ACCESS, (U8*)&access, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteMember(SDN_RDWR_ADDR, (U8*)&offset, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteMember(SDN_RDWR_SPACE, (U8*)&space, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteMember(SDN_RDWR_LENGTH, (U8*)&length, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteMember(SDN_RDWR_LOOP, (U8*)&loop, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteCmdChkAbortReadResponse(SDN_RDWR_COMMAND, (U8*)&cmd,GOOD,
      SDN_RDWR_ABORT, &abort, GOOD,
      SDN_RDWR_RESULT, (loop)?0x7ffffffful:0, &timedOut)) != GOOD) return(err);
   if ((err = SdnReadPartialMember(SDN_RDWR_BUFFER, 0, 
      ((space == SPACE_SAST) || (space == SPACE_JTAG)) ? (length+7)/8 : length,
      data)) != GOOD) return(err);
   return(GOOD);
}

/****************************************************************************
**
** TestWrite
**
*****************************************************************************/
RETCODE EXPORT TestWrite(DESCRIPTOR addr, ADDR_SPACE space, U32 length,
                        U8 *data, BOOLEAN loop) {
   RETCODE err,err2;
   U32 physical;
   /*!!! xlt */
   err = AdrGetAddrOffset(addr, &physical);
   if (!err) err = TestWritePhysical(physical, space, length, data, loop);
   err2 = TFree((LPSTR)data);
   return(err?err:err2);
}

RETCODE EXPORT TestWritePhysical(U32 offset, ADDR_SPACE space, U32 length,
                        U8 *data, BOOLEAN loop) {
   RETCODE err;
   RDWR_COMMAND cmd = RDWR_WRITE;
   BOOLEAN timedOut,abortFromEsc;
   BOOLEAN abort = TRUE;
   ACCESS_SIZE access;
   if (length == 0) return(GOOD);
   if (length>SIZE_RDWR) err = ER_MEMORY_BUFF_LEN;
   if ((err = SdnWritePartialMember(SDN_RDWR_BUFFER,0,
      ((space == SPACE_SAST) || (space == SPACE_JTAG)) ? (length+7)/8 : length,
      data, GOOD)) != GOOD) return(err);
   if ((err = TskCheckAbort(&abortFromEsc)) != GOOD) return(err);
   if ((err = MemGetAccessSize(&access)) != GOOD) return(err);
   if ((err = SdnWriteMember(SDN_RDWR_ACCESS, (U8*)&access, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteMember(SDN_RDWR_ADDR, (U8*)&offset, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteMember(SDN_RDWR_SPACE, (U8*)&space, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteMember(SDN_RDWR_LENGTH, (U8*)&length, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteMember(SDN_RDWR_LOOP, (U8*)&loop, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteCmdChkAbortReadResponse(SDN_RDWR_COMMAND, (U8*)&cmd,GOOD,
      SDN_RDWR_ABORT, &abort, GOOD,
      SDN_RDWR_RESULT, (loop)?0x7ffffffful:0, &timedOut)) != GOOD) return(err);
   return(GOOD);
}

/****************************************************************************
**
** TestRamtst
**
*****************************************************************************/
RETCODE EXPORT TestRamtst(DESCRIPTOR addr, ADDR_SPACE space, U32 length,
                         BOOLEAN loop, RAMTST_INFO *info) {
   RETCODE err;
   U32 physical;
   ACCESS_SIZE access;
   /*!!! xlt */
   if ((err = AdrGetAddrOffset(addr, &physical)) != GOOD) return(err);
   if ((err = MemGetAccessSize(&access)) != GOOD) return(err);
   return(TestRamtstPhysical(physical,0ul,space,length,access,loop,info));
}

RETCODE EXPORT TestRamtstPhysical(U32 offset, U32 skip, ADDR_SPACE space,
      U32 length, ACCESS_SIZE access,  BOOLEAN loop, RAMTST_INFO *info) {
   RETCODE err=GOOD,err2;
   RDWR_COMMAND cmd = RDWR_RAMTST;
   BOOLEAN timedOut, abortFromEsc;
   BOOLEAN abort = TRUE;
   if (length == 0) return(GOOD);
   if ((err = TskCheckAbort(&abortFromEsc)) != GOOD) return(err);
   if ((err = SdnWriteMember(SDN_RDWR_ACCESS, (U8*)&access, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteMember(SDN_RDWR_ADDR, (U8*)&offset, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteMember(SDN_RDWR_MASK, (U8*)&skip, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteMember(SDN_RDWR_SPACE, (U8*)&space, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteMember(SDN_RDWR_LENGTH, (U8*)&length, GOOD)) != GOOD)
      return(err);
   if ((err = SdnWriteMember(SDN_RDWR_LOOP, (U8*)&loop, GOOD)) != GOOD)
      return(err);
   err = SdnWriteCmdChkAbortReadResponse(SDN_RDWR_COMMAND, (U8*)&cmd,GOOD,
      SDN_RDWR_ABORT, &abort, GOOD,
      SDN_RDWR_RESULT, 0x7ffffffful, &timedOut);
   if (err == ER_MEMORY_VERIFY) {
      err2=SdnReadPartialMember(SDN_RDWR_BUFFER,0,sizeof(*info),(U8*)info);
      if (err2) err=err2;
   }
   return(err);
}

/******************************** E O F ***********************************/
