/*****************************************************************************
**  Name: mapdlg.c
**
**  $Log:   S:/tbird/mt2_68k/map_lc/csdlg.c_v  $
** 
**    Rev 1.0   25 Aug 1997 15:08:18   gene
** Initial revision.
**
**  $Header:   S:/tbird/mt2_68k/map_lc/csdlg.c_v   1.0   25 Aug 1997 15:08:18   gene  $
**
**  Copyright (C) 1997 Microtek International.  All rights reserved.
**
****************************************************************************/
                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef _MAPRC_
#include "maprc.h"
#endif

#ifndef _MAPDEF_
#include "mapdef.h"
#endif

#ifndef _MAPDLG_
#include "mapdlg.h"
#endif

#ifndef _MAP_
#include "map.h"
#endif

#ifndef _SDS2ABI_
#include "sds2abi.h"
#endif

#ifndef _HEAP_
#include "heap.h"
#endif

#ifndef __COMMDLG_H
#include <commdlg.h>
#endif

#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <dir.h>

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/

CS_FIELD_INFO gCSTable[4];

FARPROC lpfnOldEdit,lpfnNewEdit;
                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
extern MAP_REGISTERS table302[];

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/
RETCODE bDialog(HWND, U16, FARPROC, DWORD);
RETCODE ResAddStrings(HWND, U16, U16, LPSTR, ...);
RETCODE ResSetDefault(HWND, U16, U16, U16);
RETCODE GetItemVal(HWND, U16, DWORD *);
RETCODE SetItemVal(HWND, U16, LPSTR, DWORD);
RETCODE GetSpaceStr(U16, LPSTR);
RETCODE SaveCSFile(OPENFILENAME *);
RETCODE OpenCSFile(OPENFILENAME *);
RETCODE InitFileStruct(HWND, OPENFILENAME *);
RETCODE CSSaveCS(LPSTR,CS_FIELD_INFO *);
RETCODE CSRestoreCS(LPSTR fileName,CS_FIELD_INFO *csInfo);
RETCODE MapGetCSInfo(CS_FIELD_INFO*);
RETCODE CSToStr(CS_FIELD_INFO*, LPSTR);
RETCODE MapSetCSInfo(CS_FIELD_INFO *csInfo,U8 idx);


BOOL FAR PASCAL DlgCSProc(HWND , UINT , WPARAM, LPARAM);
BOOL FAR PASCAL DlgCSEditProc(HWND , UINT, WPARAM, LPARAM);
long FAR PASCAL DlgCSEditAddrProc(HWND hWnd, UINT message,
                         UINT wParam, LONG lParam);
                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/
/******************************************************
**
** MapDlgChipSelect   setup chip-select using a dialog
**
**   Execute the dialog
**
**  called from ACTOR toolbar menu item...
**
*********************************************************/
#pragma argsused
RETCODE EXPORT MapDlgChipSelect(HWND hWnd) {

   MapGetCSInfo(gCSTable);
   return(bDialog(hWnd,IDD_CHIPSELECT,(FARPROC) DlgCSProc,NULL));
}

VOID PRIVATE UpdateCSList(HWND hDlg,CS_FIELD_INFO *csInfo) {
   U8 i;
   CHAR strBuf[80];
   HANDLE hList;

   hList = GetDlgItem(hDlg,IDC_CSLIST);
   SendMessage(hList,LB_RESETCONTENT,NULL,NULL);
   for (i=0; i<4; i++) {
      CSToStr(&(csInfo[i]),strBuf);
      SendMessage(hList,LB_ADDSTRING, NULL, (LPARAM)(LPSTR) strBuf);
   }
}

/**************************************************************************
**
**  DlgCSProc
**  Description: the main function for ChipSelect to deal with messages
**
**  hDlg    (in): handle of the dialog box
**  message (in): window message
**  wParam  (in): depends on window message
**  lParam  (in): depends on window message
**
***************************************************************************/
BOOL FAR PASCAL DlgCSProc(HWND hDlg, UINT message,
                           WPARAM wParam, LPARAM lParam)
{  char strBuf[100];
   U8 i,sel;
   DWORD rc;
   OPENFILENAME m_ofn;
   HANDLE hTemp, hFont;

   switch (message) {
      case WM_INITDIALOG:
         hTemp = GetDlgItem(hDlg,IDC_CSLIST);
         hFont = GetStockObject(SYSTEM_FIXED_FONT);
         SendMessage(hTemp,WM_SETFONT,hFont,NULL);
         UpdateCSList(hDlg,gCSTable);
         SendDlgItemMessage(hDlg,IDC_CSLIST,LB_SETCURSEL,0,NULL);
         SendMessage(hDlg,WM_SETFOCUS,NULL,NULL);
         break;

      case WM_ACTIVATE:
         if (wParam != 0) { // To use WA_INACTIVE(==0), the WIN 3.1 header
                            // file should be included.
            MapGetCSInfo(gCSTable);
            UpdateCSList(hDlg,gCSTable);
            SendDlgItemMessage(hDlg,IDC_CSLIST,LB_SETCURSEL,0,NULL);
         }
         break;

      case WM_CLOSE:
         EndDialog (hDlg, FALSE);
         return TRUE;

      case WM_COMMAND:
         switch (wParam) {
         case IDC_CSLIST:
            if (HIWORD(lParam) == LBN_DBLCLK)
               // invoke edit dialog box
               SendMessage(hDlg, WM_COMMAND, IDC_CSEDIT, NULL);
            break;
         case IDC_CSSAVE:
            InitFileStruct(hDlg,&m_ofn);
            m_ofn.lpstrFilter = "CS files (*.cs)\0*.cs\0";
            if (SaveCSFile(&m_ofn) == GOOD)
               CSSaveCS(m_ofn.lpstrFile,gCSTable);
            TFree(m_ofn.lpstrInitialDir);
            FreeProcInstance((FARPROC)m_ofn.lpfnHook);
            return TRUE;
         case IDC_CSRESTORE:
            InitFileStruct(hDlg,&m_ofn);
            m_ofn.lpstrFilter = "CS files (*.cs)\0*.cs\0";
            if (OpenCSFile(&m_ofn) == GOOD)
               CSRestoreCS(m_ofn.lpstrFile,gCSTable);
            TFree(m_ofn.lpstrInitialDir);
            FreeProcInstance((FARPROC)m_ofn.lpfnHook);
            UpdateCSList(hDlg,gCSTable);
            return TRUE;
         case IDC_CSHELP:
            return TRUE;
         case IDC_CSCLOSE:
            EndDialog (hDlg, TRUE);
            return TRUE;
         case IDC_CSEDIT:
            sel = SendDlgItemMessage(hDlg,IDC_CSLIST,LB_GETCURSEL,NULL,NULL);
            if (sel > 3) sel = 0;
            if (bDialog(hDlg,IDD_CSEDIT,(FARPROC) DlgCSEditProc,(LPARAM) sel)
                      == GOOD) {
               MapSetCSInfo(&(gCSTable[sel]),sel);
               SendDlgItemMessage(hDlg,IDC_CSLIST,LB_DELETESTRING,
                           sel, (LPARAM)(LPSTR) strBuf);
               CSToStr(&(gCSTable[sel]),strBuf);
               SendDlgItemMessage(hDlg,IDC_CSLIST,LB_INSERTSTRING,
                           sel, (LPARAM)(LPSTR) strBuf);
            }
            SendDlgItemMessage(hDlg,IDC_CSLIST,LB_SETCURSEL,sel,NULL);
            return TRUE;
         };
      break;
   }
   return FALSE;
}

/**************************************************************************
**
**  DlgCSEditProc
**  Description: the major function for editing ChipSelect
**
**  hDlg    (in): handle of the dialog box
**  message (in): window message
**  wParam  (in): depends on window message
**  lParam  (in): depends on window message
**
***************************************************************************/
CS_FIELD_INFO *p_dlgCS;
HANDLE hCSEditAddr,hCSEditMask,hCSEditAddrText,hCSEditMaskText;
HANDLE hFont;

BOOL FAR PASCAL DlgCSEditProc(HWND hDlg, UINT message,
                           WPARAM wParam, LPARAM lParam)
{  CHAR szStrBuf[80],szTitle[10] = "Edit CS0",*endPtr;
   U8 sel, idx;

   switch (message) {
      case WM_INITDIALOG:
         hCSEditAddr = GetDlgItem(hDlg,IDC_CSEADDR);
         hCSEditMask = GetDlgItem(hDlg,IDC_CSEMASK);
         hCSEditAddrText = GetDlgItem(hDlg,IDC_CSEADDRTEXT);
         hCSEditMaskText = GetDlgItem(hDlg,IDC_CSEMASKTEXT);
         //change edit message procedure
         lpfnOldEdit = (FARPROC)GetWindowLong(
            hCSEditAddr,GWL_WNDPROC);
         lpfnNewEdit = MakeProcInstance((FARPROC)DlgCSEditAddrProc,
                            GetWindowWord(hDlg,GWW_HINSTANCE));
         SetWindowLong(hCSEditAddr,GWL_WNDPROC,(LONG)lpfnNewEdit);
         SetWindowLong(hCSEditMask,GWL_WNDPROC,(LONG)lpfnNewEdit);

         szTitle[7] = '0' + lParam;
         SendMessage(hDlg,WM_SETTEXT,NULL,(LPARAM)(LPSTR)szTitle);
         p_dlgCS = &(gCSTable[lParam]);
         ResAddStrings(hDlg,CB_ADDSTRING,IDC_CSEFC,
                       "000","001 (UD)","010 (UP)","011","100","101 (SD)",
                       "110 (SP)","COMMON");
         ResAddStrings(hDlg,CB_ADDSTRING,IDC_CSEDTACK,
                       "0 Wait State","1 Wait State","2 Wait States",
                       "3 Wait States","4 Wait States","5 Wait States",
                       "6 Wait States","External");

         SendDlgItemMessage(hDlg,IDC_CSEENABLE,BM_SETCHECK,
                               p_dlgCS->en,NULL);

         wsprintf(szStrBuf,"%03X",p_dlgCS->baseAddr);
         SendDlgItemMessage(hDlg,IDC_CSEADDR,WM_SETTEXT,NULL,(LPARAM)(LPSTR)szStrBuf);
         wsprintf(szStrBuf,"%03X",p_dlgCS->maskAddr);
         SendDlgItemMessage(hDlg,IDC_CSEMASK,WM_SETTEXT,NULL,(LPARAM)(LPSTR)szStrBuf);
         wsprintf(szStrBuf,"0x%06lX",((U32)p_dlgCS->baseAddr) << 11);
         SendDlgItemMessage(hDlg,IDC_CSEADDRTEXT,WM_SETTEXT,NULL,(LPARAM)(LPSTR)szStrBuf);
         wsprintf(szStrBuf,"0x%06lX",((U32)p_dlgCS->maskAddr) << 11);
         SendDlgItemMessage(hDlg,IDC_CSEMASKTEXT,WM_SETTEXT,NULL,(LPARAM)(LPSTR)szStrBuf);

         sel = p_dlgCS->cfc?p_dlgCS->fc:7; /* 7 ==> COMMON */
         SendDlgItemMessage(hDlg,IDC_CSEFC,CB_SETCURSEL,sel,NULL);
         SendDlgItemMessage(hDlg,IDC_CSEDTACK,CB_SETCURSEL,p_dlgCS->dtack,NULL);

         sel = p_dlgCS->mrw?(p_dlgCS->rw?1:0):2;
         CheckRadioButton(hDlg, IDC_CSEREADONLY, IDC_CSEREADWRITE, IDC_CSEREADONLY+sel);
         return TRUE;

      case WM_ACTIVATE:
         if (wParam != 0) { // To use WA_INACTIVE(==0), the WIN 3.1 header
                            // file should be included.
            MapGetCSInfo(gCSTable);
            SendMessage(hDlg,WM_GETTEXT,12,(LPARAM)(LPSTR)szStrBuf);
            sel = szStrBuf[7] - '0';
            p_dlgCS = &(gCSTable[sel]);

            SendDlgItemMessage(hDlg,IDC_CSEENABLE,BM_SETCHECK,
                                  p_dlgCS->en,NULL);

            wsprintf(szStrBuf,"%03X",p_dlgCS->baseAddr);
            SendDlgItemMessage(hDlg,IDC_CSEADDR,WM_SETTEXT,NULL,(LPARAM)(LPSTR)szStrBuf);
            wsprintf(szStrBuf,"%03X",p_dlgCS->maskAddr);
            SendDlgItemMessage(hDlg,IDC_CSEMASK,WM_SETTEXT,NULL,(LPARAM)(LPSTR)szStrBuf);
            wsprintf(szStrBuf,"0x%06lX",((U32)p_dlgCS->baseAddr) << 11);
            SendDlgItemMessage(hDlg,IDC_CSEADDRTEXT,WM_SETTEXT,NULL,(LPARAM)(LPSTR)szStrBuf);
            wsprintf(szStrBuf,"0x%06lX",((U32)p_dlgCS->maskAddr) << 11);
            SendDlgItemMessage(hDlg,IDC_CSEMASKTEXT,WM_SETTEXT,NULL,(LPARAM)(LPSTR)szStrBuf);

            sel = p_dlgCS->cfc?p_dlgCS->fc:7; /* 7 ==> COMMON */
            SendDlgItemMessage(hDlg,IDC_CSEFC,CB_SETCURSEL,sel,NULL);
            SendDlgItemMessage(hDlg,IDC_CSEDTACK,CB_SETCURSEL,p_dlgCS->dtack,NULL);

            sel = p_dlgCS->mrw?(p_dlgCS->rw?1:0):2;
            CheckRadioButton(hDlg, IDC_CSEREADONLY, IDC_CSEREADWRITE, IDC_CSEREADONLY+sel);
         }
         break;

      case WM_CLOSE:
         EndDialog (hDlg, FALSE);
         return TRUE;

      case WM_COMMAND:
         switch (wParam) {
         case IDC_CSECANCEL:
            EndDialog (hDlg, FALSE);
            FreeProcInstance(lpfnNewEdit);
            return TRUE;
         case IDC_CSEHELP:
            break;
         case IDC_CSEOK:
            SendDlgItemMessage(hDlg,IDC_CSEADDRTEXT,WM_GETTEXT,12,
                                    (LPARAM)(LPSTR)szStrBuf);
            if (strcmp(szStrBuf,"Invalid") == 0) {
               MessageBox(NULL,"Invalid address value.","Error",MB_OK|MB_ICONASTERISK);
               return TRUE;
            }
            SendDlgItemMessage(hDlg,IDC_CSEMASKTEXT,WM_GETTEXT,12,
                                    (LPARAM)(LPSTR)szStrBuf);
            if (strcmp(szStrBuf,"Invalid") == 0) {
               MessageBox(NULL,"Invalid address value.","Error",MB_OK|MB_ICONASTERISK);
               return TRUE;
            }

            SendMessage(hDlg,WM_GETTEXT,10,(LPARAM)(LPSTR)szTitle);
            idx = szTitle[7] - '0';

            if (SendDlgItemMessage(hDlg,IDC_CSEENABLE,BM_GETCHECK,NULL,NULL))
               gCSTable[idx].en = 1;
            else
               gCSTable[idx].en = 0;

            SendDlgItemMessage(hDlg,IDC_CSEADDR,WM_GETTEXT,12,(LPARAM)(LPSTR)szStrBuf);
            gCSTable[idx].baseAddr = (U16)strtoul(szStrBuf,&endPtr,16);
            SendDlgItemMessage(hDlg,IDC_CSEMASK,WM_GETTEXT,12,(LPARAM)(LPSTR)szStrBuf);
            gCSTable[idx].maskAddr = (U16)strtoul(szStrBuf,&endPtr,16);

            sel = SendDlgItemMessage(hDlg,IDC_CSEFC,CB_GETCURSEL,NULL,NULL);
            if (sel == 7)
               gCSTable[idx].cfc = 0;
            else {
               gCSTable[idx].fc = sel;
               gCSTable[idx].cfc = 1;
            }
            sel = SendDlgItemMessage(hDlg,IDC_CSEDTACK,CB_GETCURSEL,NULL,NULL);
            gCSTable[idx].dtack = sel;
            if (SendDlgItemMessage(hDlg,IDC_CSEREADONLY,BM_GETCHECK,NULL,NULL)) {
               gCSTable[idx].mrw = 1;
               gCSTable[idx].rw = 0;
            } else if (SendDlgItemMessage(hDlg,IDC_CSEWRITEONLY,BM_GETCHECK,NULL,NULL)) {
               gCSTable[idx].mrw = 1;
               gCSTable[idx].rw = 1;
            } else {
               gCSTable[idx].mrw = 0;
               gCSTable[idx].rw = 0;
            }
            EndDialog (hDlg, TRUE);
            FreeProcInstance(lpfnNewEdit);
            return TRUE;
         case IDC_CSEREADONLY:
         case IDC_CSEWRITEONLY:
         case IDC_CSEREADWRITE:
            CheckRadioButton(hDlg,IDC_CSEREADONLY,IDC_CSEREADWRITE,wParam);
            return TRUE;
         };
      break;
   }
   return FALSE;
}

/**************************************************************************
**
**  DlgCSEditAddrProc
**  Description: the major function for edit control of CS dialog
**
**  hDlg    (in): handle of the dialog box
**  message (in): window message
**  wParam  (in): depends on window message
**  lParam  (in): depends on window message
**
***************************************************************************/
long FAR PASCAL DlgCSEditAddrProc(HWND hWnd, UINT message,
                         UINT wParam, LONG lParam) {
short n;
CHAR szStrBuf[10], *endPtr;
U32 value32;
BOOL update=FALSE;

   n=GetWindowWord(hWnd,GWW_ID);
   switch(message) {
   case WM_KEYUP:
      switch(wParam) {
      case VK_RETURN:
         return TRUE;
      case VK_DELETE:
      case VK_BACK:
         update = TRUE;
         break;
      }
      SendMessage(hWnd,WM_GETTEXT,10,(LPARAM)(LPSTR)szStrBuf);
      if (isxdigit(wParam) || update) {
         value32 = strtoul(szStrBuf,&endPtr,16);
         if (value32 > 0x7FF)
            strcpy(szStrBuf,"Invalid");
         else
            wsprintf(szStrBuf,"0x%06lX",value32 << 11);

         if (n == IDC_CSEADDR)
            SendMessage(hCSEditAddrText,WM_SETTEXT,NULL,
                                        (LPARAM)(LPSTR)szStrBuf);
         else
            SendMessage(hCSEditMaskText,WM_SETTEXT,NULL,
                                        (LPARAM)(LPSTR)szStrBuf);
      } else {
         switch(wParam) {
         case VK_RETURN:
         case VK_HOME:
         case VK_END:
         case VK_DELETE:
         case VK_BACK:
         case VK_LEFT:
         case VK_RIGHT:
         case VK_TAB:
            break;
         default:
            if (n == IDC_CSEADDR)
               SendMessage(hCSEditAddrText,WM_SETTEXT,NULL,
                                           (LPARAM)(LPSTR)"Invalid");
            else
               SendMessage(hCSEditMaskText,WM_SETTEXT,NULL,
                                           (LPARAM)(LPSTR)"Invalid");
         }
      }
      break;
   case WM_KEYDOWN:
      if (!isxdigit(wParam)) {
         switch(wParam) {
         case VK_RETURN:
         case VK_HOME:
         case VK_END:
         case VK_DELETE:
         case VK_BACK:
         case VK_LEFT:
         case VK_RIGHT:
         case VK_TAB:
            break;
         default:
            MessageBeep(2);
            return TRUE;
         }
      }
      break;
   case WM_SYSKEYDOWN:
      SendMessage(GetParent(hWnd),WM_SYSKEYDOWN,wParam,lParam);
      break;
   }
   return CallWindowProc(lpfnOldEdit,hWnd,message,wParam,lParam);        
}       

/****************************************************************************
**
** MapGetCSInfo
**
*****************************************************************************/
RETCODE MapGetCSInfo(CS_FIELD_INFO *csInfo) {
   MAP_REGISTERS *tblPtr;
   U32 reg;
   U8 i=0;
   RETCODE err;

   tblPtr = table302;
   while( lstrlen(tblPtr->regName) != 0 ) {
      /* read CS base register */
      if ((err=Sds2AbiGetIntReg(tblPtr->offset, tblPtr->size, &reg, TRUE))
           != GOOD) return(err);
      (csInfo[i]).fc = (reg >> 13) & 0x7;
      (csInfo[i]).baseAddr = (reg >> 2) & 0x7FF;
      (csInfo[i]).rw = (reg >> 1) & 0x1;
      (csInfo[i]).en = reg & 0x1;
      tblPtr++;
      /* read CS option register */
      if ((err=Sds2AbiGetIntReg(tblPtr->offset, tblPtr->size, &reg, TRUE))
           != GOOD) return(err);
      (csInfo[i]).dtack =(reg >> 13) & 0x7;
      (csInfo[i]).maskAddr = (reg >> 2) & 0x7FF;
      (csInfo[i]).mrw = (reg >> 1) & 0x1;
      (csInfo[i]).cfc = reg & 0x1;
      tblPtr++;
      i++;
   }
   return GOOD;
}

/****************************************************************************
**
** MapSetCSInfo
**
*****************************************************************************/
RETCODE MapSetCSInfo(CS_FIELD_INFO *csInfo,U8 idx) {
   MAP_REGISTERS *tblPtr;
   U32 reg;
   RETCODE err;

   tblPtr = &(table302[idx*2]);
   /* write CS base register */
   reg = csInfo->fc << 13;
   reg |= csInfo->baseAddr << 2;
   reg |= csInfo->rw << 1;
   reg |= csInfo->en;
   if ((err=Sds2AbiSetIntReg(tblPtr->offset, tblPtr->size, reg, TRUE))
        != GOOD) return(err);
   tblPtr++;
   /* write CS option register */
   reg = csInfo->dtack << 13;
   reg |= csInfo->maskAddr << 2;
   reg |= csInfo->mrw << 1;
   reg |= csInfo->cfc;
   if ((err=Sds2AbiSetIntReg(tblPtr->offset, tblPtr->size, reg, TRUE))
        != GOOD) return(err);

   return GOOD;
}

/**************************************************************************
**
**  CSToStr
**
**  Purpose: convert map information into a string
**
**  hDlg   (in): handle of the dialog box
**  Map    (in): map information
**  lpszMap(out): result
**
***************************************************************************/
CHAR szSpaceStr[8][4] = {"sp0", "UD ", "UP ", "sp3",
                         "sp4", "SD ", "SP ", "com"};
char szEnStr[2][9] = {"Disable", "Enable "};
char szRWStr[3][13] = {"Read-Only ", "Write-Only", "Read/Write"};
char szDTACK[8][14] = {"0 wait", "1 wait", "2 wait",
                       "3 wait", "4 wait", "5 wait",
                       "6 wait", "External"};
RETCODE CSToStr(CS_FIELD_INFO *cs, LPSTR lpszCS)
{
   wsprintf(lpszCS," %s 0x%06lX   0x%06lX    %s  %s   %s",
              cs->en?szEnStr[1]:szEnStr[0],
              ((U32)cs->baseAddr) << 11,
              ((U32)cs->maskAddr) << 11,
              cs->cfc?szSpaceStr[cs->fc]:szSpaceStr[7],
              cs->mrw?(cs->rw?szRWStr[1]:szRWStr[0]):szRWStr[2],
              szDTACK[cs->dtack]);
   return GOOD;
}

/**************************************************************************
**
**  SaveCSFile
**
**  Purpose: invoke a standard common dialog box to get a save filename
**
**  ofn  (in/out): with OPENFILENAME data structure
**
***************************************************************************/
RETCODE SaveCSFile(OPENFILENAME *ofn)
{
   OFSTRUCT ofs;
   int hFile;

   ofn->Flags = OFN_OVERWRITEPROMPT|OFN_SHOWHELP|OFN_HIDEREADONLY|OFN_ENABLEHOOK;
   ofn->lpstrTitle = "Save CS File";
   if (GetSaveFileName(ofn)) {
      hFile = OpenFile(ofn->lpstrFile, &ofs, OF_CREATE|OF_WRITE);
      // if (hFile == HFILE_ERROR)  <== should include windows.h v3.1
      if (hFile == (int)-1)
         return (ER_MAP_CANNOT_OPEN_FILE);
      _lclose(hFile);
      chdir(ofn->lpstrInitialDir);
   }
   else
      return (ER_MAP_CANNOT_OPEN_FILE);
   return (GOOD);
}

/**************************************************************************
**
**  OpenCSFile
**
**  Purpose: invoke a standard open-file dialog box to get a filename
**
**  ofn  (in/out): with OPENFILENAME data structure
**
***************************************************************************/
RETCODE OpenCSFile(OPENFILENAME *ofn)
{
   int hFile;

   ofn->lpstrTitle = "Restore CS File";
   ofn->Flags = OFN_FILEMUSTEXIST|OFN_SHOWHELP|OFN_HIDEREADONLY|OFN_ENABLEHOOK;
   if (GetOpenFileName(ofn)) {
      hFile = _lopen(ofn->lpstrFile, READ);
      // if (hFile == HFILE_ERROR)  <== should include windows.h v3.1
      if (hFile == (int)-1)
         return (ER_MAP_CANNOT_OPEN_FILE);
      _lclose(hFile);
      chdir(ofn->lpstrInitialDir);
   }
   else
      return (ER_MAP_CANNOT_OPEN_FILE);
   return(GOOD);
}

/****************************************************************************
**
** CSSaveCS
**
*****************************************************************************/
RETCODE CSSaveCS(LPSTR fileName,CS_FIELD_INFO *csInfo) {
   RETCODE err=GOOD;
   FILE    *outFile;
   U16      reg;
   MAP_REGISTERS *tblPtr;
   U8 i=0;
   
   tblPtr = table302;
   if (NULL == (outFile = fopen(fileName, "wt"))) {
      return ER_MAP_CANNOT_OPEN_FILE;
   }

   while( lstrlen(tblPtr->regName) != 0 ) {

      fprintf(outFile, "%8s    ",tblPtr->regName);
      reg = csInfo[i].fc << 13;
      reg |= csInfo[i].baseAddr << 2;
      reg |= csInfo[i].rw << 1;
      reg |= csInfo[i].en;
      fprintf(outFile,"0x%04X\n", reg);
      tblPtr++;

      fprintf(outFile, "%8s    ",tblPtr->regName);
      reg = csInfo[i].dtack << 13;
      reg |= csInfo[i].maskAddr << 2;
      reg |= csInfo[i].mrw << 1;
      reg |= csInfo[i].cfc;
      fprintf(outFile,"0x%04X\n", reg);
      tblPtr++;
      i++;
   }

   fclose(outFile);
   return(err);
}  /* end of CSSaveCS */

/*---------------------------------------------------------------------------
** CSRestoreCS
**
** Purpose: Reads file and converts ascii entries into values to be programmed
**    into internal chip select registers.
**
** Design:
**    Open file, return error if error
**    Get base address of registers
**    loop
**       read line
**       parse into register name and value; if error output error and linenum
**    until eof reached
**    write only registers that were found to hardware
----------------------------------------------------------------------------*/
#define LINE_LEN 80
#define TOKSTR " \n\r"
RETCODE CSRestoreCS(LPSTR fileName,CS_FIELD_INFO *csInfo) {
   FILE    *inputFile;
   RETCODE err1, err2, firstErr = GOOD;
   MAP_REGISTERS *tblPtr, *posPtr, *savPosPtr;
   S8      inputStr[81];
   U8 idx;

   tblPtr = table302;
   for( posPtr = tblPtr; lstrlen(posPtr->regName) != 0; posPtr++ )
      posPtr->restoreFound = FALSE;
   posPtr = tblPtr;
   if (NULL == (inputFile = fopen((LPSTR)fileName, "rt"))) {
      return ER_MAP_CANNOT_OPEN_FILE;
   }
   while( fgets(inputStr, LINE_LEN - 2, inputFile) != NULL ) {
      S8 *regPtr, *valPtr;
      char *endPtr;
      BOOLEAN matched;
      if( (regPtr=strtok(inputStr,TOKSTR)) == NULL) {
         err1 = ER_MAP_VALUE_MISSING;
         goto CLEANUP3;
      }
      if( (valPtr=strtok(NULL,TOKSTR)) == NULL) {
         err1 = ER_MAP_VALUE_MISSING;
         goto CLEANUP3;
      }
      if( strtok(NULL,TOKSTR) != NULL) {
         err1 = ER_MAP_TOO_MANY_INPUT_LINES;
         goto CLEANUP3;
      }
      matched = FALSE;
      savPosPtr = posPtr;
      while( lstrlen(posPtr->regName) != 0 ) {
         if( strcmpi(regPtr,posPtr->regName) == 0 ) {
             matched = TRUE;
             break;
         }
         posPtr++;
      }
      if( !matched ) {
         // if not found start from beginning of table and search to
         // where we started.
         posPtr = tblPtr;
         while( posPtr != savPosPtr ) {
            if( strcmpi(regPtr,posPtr->regName) == 0 ) {
               matched = TRUE;
               break;
            }
            posPtr++;
         }
      }
      if( !matched ) {
         err1 = ER_MAP_INVALID_REGNAME;
         goto CLEANUP3;
      }
      posPtr->restoreValue = strtoul((valPtr), &endPtr, 16);
      if (*endPtr != 0) {
         err1 = ER_MAP_INVALID_VALUE_INPUT;
         goto CLEANUP3;
      }
      if( ((posPtr->size == 1) && (posPtr->restoreValue > 0xffL))
          || ((posPtr->size == 2) && (posPtr->restoreValue > 0xffffL)) ) {
         err1 = ER_MAP_VALUE_TOO_BIG;
         goto CLEANUP3;
      }
      posPtr->restoreFound = TRUE;

      // save time for next search by assuming next entry is below
      // the previous in the table
      posPtr++;
   }
   
   for( posPtr = tblPtr,idx = 0; strlen(posPtr->regName) != 0; idx++ ) {
      U8 i;
      U16 reg[2];
      for (i=0; i<2; i++,posPtr++) {
         if( !posPtr->restoreFound ) {
            // if(posPtr->VIR) {
               // Currently MBAR is the only VIR - if not defined we don't
               // know where to put the other sim registers so error out.
               err2 = ER_MAP_VALUE_MISSING;
               goto CLEANUP2;
            //}
            //continue;
         }
         //if (posPtr->VIR) {
            if ((err2 = Sds2AbiSetIntReg(posPtr->offset, posPtr->size,
                  posPtr->restoreValue, TRUE)) != GOOD) goto CLEANUP2;
            reg[i] = posPtr->restoreValue;
         //}
      }
      csInfo[idx].fc = reg[0] >> 13;
      csInfo[idx].baseAddr = (reg[0] >> 2) & 0x7FF;
      csInfo[idx].rw = (reg[0] >> 1) & 1;
      csInfo[idx].en = (reg[0] & 1);
      csInfo[idx].dtack = reg[1] >> 13;
      csInfo[idx].maskAddr = (reg[1] >> 2) & 0x7FF;
      csInfo[idx].mrw = (reg[1] >> 1) & 1;
      csInfo[idx].cfc = (reg[1] & 1);
   }

CLEANUP2:
   if(GOOD == firstErr) firstErr = err2;

CLEANUP3:
   if (GOOD == firstErr) firstErr = err1;
   fclose(inputFile);
   return firstErr;
}  /* end of CSRestoreCS */

