//께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께
//께
//께   C Source code for BIOS.DLC
//께
//께    There are 3 groups of functions:
//께
//께      1. DLL entry and exit routines
//께      2. PROCOMM PLUS for WINDOWS entry points
//께      3. Internal worker routines
//께
//께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께
//께        
//께                Copyright (C) 1999 Symantec Corp.
//께                         All Rights Reserved
//께
//께    Information in this file is proprietary and confidential, and
//께      may not be copied, reproduced or distributed in any manner
//께   without the express written permission of Symantec Corp.
//께
//께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께

#define STRICT
#include <windows.h>
#include <string.h>
#include "bios.h"

// Prototypes for local worker functions
static int ClearComm( int , NETWORK *);
static int CommStatus( int, NETWORK * );
static BYTE GetBaud( int, NETWORK * );

// Global variables
COMM int14[4];
HANDLE hInst;

//께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께
//께
//께 1. DLL entry and exit routines
//께
//께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께

//--------------------------------------------------------------------------
//
// DllMain() - DLL entry/exit function
//
// Note that since multiple instances are implemented as threads in
// Procomm Plus 4.xx, one may wish to do some specific processing for
// instances in the DLL_THREAD_ATTACH and DLL_THREAD_DETACH sections.
//--------------------------------------------------------------------------
BOOL WINAPI DllMain (HANDLE hInstance, DWORD dwFunction, LPVOID lpNot)
{
   switch (dwFunction)
   {
      case DLL_PROCESS_ATTACH:
         hInst=hInstance;
         break;

      case DLL_THREAD_ATTACH:
         break;

      case DLL_THREAD_DETACH:
         break;

      case DLL_PROCESS_DETACH:
         break;

      default:
         break;
   }

   return TRUE;
}


//께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께
//께
//께 2. PROCOMM PLUS for WINDOWS entry points
//께
//께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께

////////////////////////////////////////////////////////////////////////////
// C_AddNewConnection() -
// This is called to allow the DLC to add available connections to
// Procomm Plus' parameter file.  The function should return TRUE for
// each connection that is added.  Procomm Plus will continue to call
// this function, incrementing i, until FALSE is returned.  For example,
// this DLC supports "ports" 1 through 4.  The code below will return
// true for each call 0 through 3, and FALSE thereafter.  Therefore,
// Procomm Plus will add 4 new connections via this DLC.
////////////////////////////////////////////////////////////////////////////
EXPORTED DWORD CALLBACK C_AddNewConnection(LPSTR line, int i)
{
   BOOL  fRC=FALSE;

   if (i<4)                            // ebios supports only 4 connections
   {
      LoadString(hInst, IDS_CONNECT+i, line, 63 );
      fRC=TRUE;
   }

   return(fRC);
}


//--------------------------------------------------------------------------
// C_SetForDial() - Called before OpenComm() to let us know dialing dir entry
//--------------------------------------------------------------------------
EXPORTED void CALLBACK C_SetForDial( HWND hWnd, int indialentry, LPSTR szManualNumber, void * inDid)
{
}


//--------------------------------------------------------------------------
// C_XferStatus() - Called before file transfer && after file xfer
//--------------------------------------------------------------------------
EXPORTED void CALLBACK C_XferStatus( int hCid, int xferactive)
{
}


//--------------------------------------------------------------------------
//
// C_GetCaps() - Used to get dlc capabilities
//               for PW2.0 must return >= 200
//               Since this sample is 32 bit only, it is safe to return 400
//               indicating that this is for 4.xx only.
//
//--------------------------------------------------------------------------
EXPORTED DWORD CALLBACK C_GetCaps()
{
   return(400);
}


//--------------------------------------------------------------------------
//
// C_Setup() - Setup the port type and number
//
// Called after a connection is selected, This allows the dlc to setup any
// initialization necessary. The full connection "name" is passed to the dlc.
//             ie. "Int14h - port1".
// For each dlc connection, PW.EXE will pass a pointer to 128 bytes which the
//      dlc can use for any purpose necessary.
//
//    Notes:   1. Assumes that the last character in the name is the ASCII
//                port number ('1', '2', etc.).
//
//--------------------------------------------------------------------------
EXPORTED BOOL CALLBACK C_Setup(HWND hWnd, LPSTR name, NETWORK *nt )
{
   DialogBox( hInst, "ABOUT", hWnd, AboutDlgProc );
   return TRUE;
}


//--------------------------------------------------------------------------
//
// C_OpenComm() - Initialize the port
//
// For each dlc connection, PW.EXE will pass a pointer to 128 bytes "nt"
//          which the  dlc can use for any purpose necessary.
// "from_install" is a flag set if a new modem is being installed, or
// reconfigured, and can be used if a dlc is to query the user with a dialog
// box at each opencomm call.  If "from_install" is set the dlc will not what
// to query the user at that time.  Not needed in this bios implementation.
//
//--------------------------------------------------------------------------
EXPORTED HANDLE CALLBACK C_OpenComm(   HWND hWnd, LPSTR lptr, WORD txsize, WORD rxsize,
                              NETWORK *nt, BYTE from_install)
{
int i;

   i = lstrlen(lptr);
   nt->port = ((int)*(lptr+i-1)-'1');          // for this connection save the connection index for later
   if(int14[nt->port].instance) // if previous int14[nt->port].instance return false
      return((HANDLE)IE_OPEN);

   if ( !(int14[nt->port].hTxBuff=GlobalAlloc( GMEM_MOVEABLE|GMEM_ZEROINIT, (DWORD)(txsize+10) )))
      return((HANDLE)IE_MEMORY);
   if ( !(int14[nt->port].hRxBuff=GlobalAlloc( GMEM_MOVEABLE|GMEM_ZEROINIT, (DWORD)(rxsize+10) )))
   {
      GlobalFree(int14[nt->port].hTxBuff);
      return((HANDLE)IE_MEMORY);
   }
   int14[nt->port].btxptr = int14[nt->port].txptr = int14[nt->port].stxptr = GlobalLock(int14[nt->port].hTxBuff);
   int14[nt->port].brxptr = int14[nt->port].rxptr = int14[nt->port].srxptr = GlobalLock(int14[nt->port].hRxBuff);
   int14[nt->port].txmax=txsize;
   int14[nt->port].rxmax=rxsize;
   int14[nt->port].xoffed=int14[nt->port].xoffsent=0;
   int14[nt->port].rxcnt=int14[nt->port].txcnt=0;
   int14[nt->port].instance++;
   return((HANDLE)nt->port);
}


//--------------------------------------------------------------------------
//
// C_CloseComm() - Shutdown the port
//
//--------------------------------------------------------------------------
EXPORTED int CALLBACK C_CloseComm(int hCid, NETWORK *nt)
{
   int14[hCid].instance--;
   GlobalUnlock(int14[hCid].hTxBuff);
   GlobalUnlock(int14[hCid].hRxBuff);
   GlobalFree(int14[hCid].hTxBuff);
   GlobalFree(int14[hCid].hRxBuff);
   return(TRUE);
}


//--------------------------------------------------------------------------
//
// C_FlushComm() - Remove pending rx/tx characters from port queues
//
//--------------------------------------------------------------------------
EXPORTED int CALLBACK C_FlushComm(int hCid, int rcv, NETWORK *nt)
{
   if(hCid==-1)
      return(1);
   if(rcv==1)
   {
      int14[hCid].rxcnt=0;
      int14[hCid].rxptr=int14[hCid].srxptr=int14[hCid].brxptr;
   }
   else
   {
      int14[hCid].txcnt=0;
      int14[hCid].txptr=int14[hCid].stxptr=int14[hCid].btxptr;
   }
   return(0);
}


//--------------------------------------------------------------------------
//
// C_ReadComm() - Read characters from port
//
//--------------------------------------------------------------------------
EXPORTED int CALLBACK C_ReadComm(int hCid, LPSTR lptr, int cnt, NETWORK *nt)
{
int i,j,k;

   if(hCid==-1)
      return(0);
   i=ClearComm(hCid,nt);              // returns comm status send any outstanding recieves any
   if(!(k=min(cnt,int14[hCid].rxcnt)))// if we are to read 0 or there are 0 to read, leave
      return(0);
   for(j=0;j<k;j++)
   {
      *lptr++ = *int14[hCid].srxptr;
      if(int14[hCid].srxptr==(int14[hCid].brxptr+int14[hCid].rxmax))
         int14[hCid].srxptr = int14[hCid].brxptr;
      else
         int14[hCid].srxptr++;
      int14[hCid].rxcnt -=1;
   }

   if(i)                               // if error in ClearComm,
      j = -j;                          //   then negate the count

   return(j);
}


//--------------------------------------------------------------------------
//
// C_WriteComm() - Write characters to port
//
//--------------------------------------------------------------------------
EXPORTED int CALLBACK C_WriteComm(int hCid, LPSTR lptr, int cnt, NETWORK *nt)
{
int j,k;

   k = min(cnt,(int14[hCid].txmax-int14[hCid].txcnt));
   for(j=0;j<k;j++)
   {
      *int14[hCid].txptr = *lptr++;
      if(int14[hCid].txptr==(int14[hCid].btxptr+int14[hCid].txmax))
         int14[hCid].txptr=int14[hCid].btxptr;
      else
         int14[hCid].txptr++;
      int14[hCid].txcnt +=1;
   }
   if(ClearComm(hCid,nt))              // if error in ClearComm,
      j = -j;                          //   then negate the count

   return(j);
}


//--------------------------------------------------------------------------
//
// C_GetCommError() - read status of comm port, returns negative if error
//
//--------------------------------------------------------------------------
EXPORTED int CALLBACK C_GetCommError(int hCid, COMSTAT *cstat, NETWORK *nt)
{
int i;

   i=ClearComm(hCid,nt);
   cstat->fCtsHold = FALSE;

   if(int14[hCid].xoffed)                       /* Received handshake */
      cstat->fXoffHold=TRUE;
   if(int14[hCid].xoffsent)                       /* Received handshake */
      cstat->fXoffSent=TRUE;
   cstat->cbInQue = int14[hCid].rxcnt;          /* count of characters in Rx Queue */
   cstat->cbOutQue = int14[hCid].txcnt;         /* count of characters in Tx Queue */
   return(i);
}


//--------------------------------------------------------------------------
//
// C_UngetCommChar() - Add a char. to recieve queues as if it were received
//
//--------------------------------------------------------------------------
EXPORTED int CALLBACK C_UngetCommChar(int hCid, char c, NETWORK *nt)
{
   if(int14[hCid].srxptr==int14[hCid].brxptr)
      int14[hCid].srxptr=(int14[hCid].brxptr+int14[hCid].rxmax);
   else
      int14[hCid].srxptr--;
   *int14[hCid].srxptr = c; int14[hCid].rxcnt +=1;
   return(0);
}


//--------------------------------------------------------------------------
//
// C_SetCommBreak() - Initiate a BREAK (long space)
//
//--------------------------------------------------------------------------
EXPORTED int CALLBACK C_SetCommBreak( int hCid, NETWORK *nt)
{
   return(1);                                   // not supported in int14H
}


//--------------------------------------------------------------------------
//
// C_ClearCommBreak() - Terminate a BREAK (long space)
//
//--------------------------------------------------------------------------
EXPORTED int CALLBACK C_ClearCommBreak(int hCid, NETWORK *nt)
{
   return(1);                                   // not supported in int14H
}


//--------------------------------------------------------------------------
//
// C_SetCommState() - Set the ports line characteristics (baud, parity, etc.)
//
//--------------------------------------------------------------------------
EXPORTED int CALLBACK C_SetCommState(DCB *dcbw, NETWORK *nt)
{
   BYTE j;

   j = GetBaud(dcbw->BaudRate, nt);
   if(j==0xFFF)                                 // unsupported baud rate
      return(1);                                // fail
   if(dcbw->Parity>2)                           // only NONE ODD EVEN
      return(1);
   if (dcbw->Parity == EVENPARITY)              // Win       EVEN=1 0
      j |= 0x18;                                // INT14(0h) EVEN=1 1
   else
      j |= (dcbw->Parity<<3);
   if(dcbw->StopBits)                           // if stop bits == 2
      j |= 0x4;
   if(dcbw->ByteSize==7)                        // 7 bits = 1
      j |= 0x2;
   else
      j |= 0x3;
   myint14(_COM_INIT, nt->port, j);
   memcpy( (LPSTR)&int14[nt->port].Int14dcb, (LPSTR)dcbw, sizeof(DCB) );
   return(0);
}


//--------------------------------------------------------------------------
//
// C_GetCommState() - Get the ports line characteristics (baud, parity, etc.)
//
//--------------------------------------------------------------------------
EXPORTED int CALLBACK C_GetCommState(int hCid, DCB *dcbw, NETWORK *nt)
{
   memcpy( (LPSTR)dcbw, (LPSTR)&int14[hCid].Int14dcb, sizeof(DCB) );
   return(1);
}


//--------------------------------------------------------------------------
//
// C_EscapeCommFunction() - sets DTR or simulates XON being received
//
//--------------------------------------------------------------------------
EXPORTED int CALLBACK C_EscapeCommFunction(int hCid, int j, NETWORK *nt)
{
   switch(j)
   {
      case SETXON:                        /*  2 Simulate XON received */
         int14[hCid].xoffed = 0;
         break;
      case SETDTR:                        /*  5 Set DTR high */
         break;
      case CLRDTR:                        /*  6 Set DTR low  */
         break;
      case RESETDEV:
         break;
   }
   return(0);
}


//--------------------------------------------------------------------------
//
// C_DCD() - Return the status of DCD
//
//--------------------------------------------------------------------------
EXPORTED int CALLBACK C_DCD(unsigned port, NETWORK *nt)
{
int i;

   i=myint14( _COM_STATUS, nt->port, 0);
   return ( (i & 0x80) ? 1 : 0);
}


//--------------------------------------------------------------------------
// C_QueryBaudRate() - Ask if baud rate is supported
//--------------------------------------------------------------------------
EXPORTED int CALLBACK C_QueryBaudRate( int i, NETWORK *nt )
{
   if (i == CBR_19200 )
      return CBR_9600;           // we cant support > 9600
   else if(i == CBR_14400 )
      return CBR_9600;
   else if(i==CBR_28800)
      return CBR_9600;
   else if(i==CBR_38400)
      return CBR_9600;
   else if(i==CBR_56000)
      return CBR_9600;
   else if(i==CBR_115200)
      return CBR_9600;
   else return(i);
}


//--------------------------------------------------------------------------
//
// C_FastRate() - Set the ports baud rate if greater than 19200
//   i = 7       38400
//   i = 8       57600
//   i = 9       115200
//
//--------------------------------------------------------------------------
EXPORTED int CALLBACK C_FastRate(int i, unsigned port, NETWORK *nt)
{
   return(FALSE);                      // cannot support > 19200 so fail
}


//--------------------------------------------------------------------------
//
// C_FindPortAddress() - Called to find a port address, not required by ebios
//                       but PW.EXE will call this funcion after port is opened
//
//--------------------------------------------------------------------------
EXPORTED unsigned CALLBACK C_FindPortAddress(NETWORK *nt)
{
   return(0);
}


EXPORTED void CALLBACK C_SetNewConnection(LPSTR lpszNetwork, LPSTR lpszModem)
{
}


//께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께
//께
//께 3. Internal worker routines
//께
//께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께


//--------------------------------------------------------------------------
//
// ClearComm() - main worker routine
// transmits chars in buffer
// recieves  chars available
// calls CommStatus() at end to update global variables
//
//--------------------------------------------------------------------------
static int ClearComm(int hCid,NETWORK *nt)
{
int i;
                                                            // receive all in buffer
   while( int14[hCid].rxcnt<int14[hCid].rxmax )             // while still room in buffer
   {
      if( int14[hCid].rxcnt > ((int14[hCid].rxmax*8)/10) && !int14[hCid].xoffsent && int14[hCid].Int14dcb.fInX )  // if software flowcontrol
      {
         do
         {
            i= myint14( _COM_STATUS, hCid, 0xff);
         } while( (i&0x2000)==0 || i==0x3ff );                   // while txholding reg is not empty, sit and spin
         if ( ((i&0x10)==0  &&  int14[hCid].Int14dcb.fRtsControl) )   // if !cts and we are doing harware handshake leave
            break;
         myint14( _COM_SEND, hCid, int14[hCid].Int14dcb.XoffChar );
         int14[hCid].xoffsent=1;
      }
      i=myint14( _COM_STATUS, hCid, 0xff);
      if( i==0x3ff || (i&0x100)==0)                        // data available?
         break;
      i=myint14( _COM_RECEIVE, hCid, 0);
      if( (*int14[hCid].rxptr==int14[hCid].Int14dcb.XoffChar) && int14[hCid].Int14dcb.fInX )
      {
         int14[hCid].xoffed = TRUE;
         continue;
      }
      else if( (*int14[hCid].rxptr==int14[hCid].Int14dcb.XonChar) && int14[hCid].Int14dcb.fInX )
      {
         int14[hCid].xoffed = 0;
         continue;
      }
      *int14[hCid].rxptr = LOBYTE(i);
      if(int14[hCid].rxptr==(int14[hCid].brxptr+int14[hCid].rxmax))
         int14[hCid].rxptr=int14[hCid].brxptr;
      else
         int14[hCid].rxptr++;
      int14[hCid].rxcnt += 1;
      if(i&0x8000)
         break;
   }

   // if we are int14[hCid].xoffed and the buffer can now hold more send xon

   if(int14[hCid].rxcnt<((int14[hCid].rxmax*8)/10) && int14[hCid].xoffsent && int14[hCid].Int14dcb.fInX )
   {
      do
      {
         i= myint14( _COM_STATUS, hCid, 0);
      } while( (i&0x2000)==0 );                   // while txholding reg is not empty, sit and spin
      if ( !int14[hCid].Int14dcb.fRtsControl || ( (i&0x10) && int14[hCid].Int14dcb.fRtsControl) )   // if cts and we are doing harware flowe send it
      {
         myint14( _COM_SEND, hCid, int14[hCid].Int14dcb.XonChar );
         int14[hCid].xoffsent=0;
      }
   }

   /* send all in buffer */
   while( int14[hCid].txcnt && !int14[hCid].xoffed )                       // send all in buffer
   {
      i= myint14( _COM_STATUS, hCid, 0xff);
      if((i&0x2000)==0 && i!=0x3ff )              // if txholding reg is not empty, leave
         break;
      if ( (i&0x10)==0  &&  int14[hCid].Int14dcb.fRtsControl )   // if !cts and we are doing harware handshake leave
         break;
      myint14( _COM_SEND, hCid, *int14[hCid].stxptr );
      if(int14[hCid].stxptr==(int14[hCid].btxptr+int14[hCid].txmax))
         int14[hCid].stxptr=int14[hCid].btxptr;
      else
         int14[hCid].stxptr++;
      int14[hCid].txcnt -= 1;
   }
   return(CommStatus( hCid, nt));
}


//--------------------------------------------------------------------------
//
// CommStatus() - Return the status of the port (LSR), and sets
//  int14[hCid].com_cts && int14[hCid].com_dcd
//--------------------------------------------------------------------------
static int CommStatus(int hCid, NETWORK *nt)
{
int i;
int error=0;

   i=myint14( _COM_STATUS, hCid, 0xff);
   if(i==0x3ff)
      return(error);
   if(i&0x10)
      int14[hCid].com_cts = 1;
   else
      int14[hCid].com_cts = 0;
   if(i&0x80)
      int14[hCid].com_dcd = 1;
   else
      int14[hCid].com_dcd = 0;
   if(i&0x200)
      error |= CE_OVERRUN;      /* CE_OVERRUN          0x0002   Receive Overrun Error        */
   if(i&0x400)
      error |= CE_RXPARITY;     /* CE_RXPARITY         0x0004   Receive Parity Error         */
   if(i&0x800)
      error |= CE_FRAME;        /* CE_FRAME            0x0008   Receive Framing error        */
   if(i&0x1000)
      error |= CE_BREAK;        /* CE_BREAK            0x0010   Break Detected               */
   return(error);
}


//--------------------------------------------------------------------------
//
// GetBaud - Convert a baud rate into an INT 14h index
//
//--------------------------------------------------------------------------
static BYTE GetBaud(int i, NETWORK *nt)
{
   switch(i)
   {
      case 300:
         return(0x40);
      case 600:
         return(0x60);
      case 1200:
         return(0x80);
      case 2400:
         return(0xA0);
      case 4800:
         return(0xC0);
      case CBR_9600:
         return(0xE0);
      default:
         return(0xFF);
   }
}


void CenterDlg( HWND hDlg )
{
RECT rect;
int myX, myY;

   GetWindowRect( hDlg, &rect );
   myX = (GetSystemMetrics( SM_CXSCREEN ) - rect.right + rect.left)/2;
   if (myX < 0)
      myX = 0;
   myY = (GetSystemMetrics( SM_CYSCREEN ) - rect.bottom + rect.top)/2;
   if (myY < 0)
      myY = 0;
   SetWindowPos( hDlg, 0, myX, myY, 0, 0, SWP_NOSIZE | SWP_NOZORDER );
}


EXPORTED BOOL CALLBACK AboutDlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
   switch (message)
   {
      default:
         return( FALSE );
      case WM_INITDIALOG:
         CenterDlg( hDlg );
         break;
      case WM_COMMAND:
         if (wParam != IDOK)
            return( FALSE );
         EndDialog( hDlg, TRUE );
         break;
   }
   return( TRUE );
}
