windows-nt/Source/XPSP1/NT/shell/osshell/accesory/terminal/serial.c
2020-09-26 16:20:57 +08:00

497 lines
15 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*===========================================================================*/
/* Copyright (c) 1987 - 1988, Future Soft Engineering, Inc. */
/* Houston, Texas */
/*===========================================================================*/
#define NOGDICAPMASKS TRUE
#define NOVIRTUALKEYCODES TRUE
#define NOICONS TRUE
#define NOKEYSTATES TRUE
#define NOSYSCOMMANDS TRUE
#define NOATOM TRUE
#define NOCLIPBOARD TRUE
#define NODRAWTEXT TRUE
#define NOMINMAX TRUE
#define NOOPENFILE TRUE
#define NOSCROLL TRUE
#define NOHELP TRUE
#define NOPROFILER TRUE
#define NODEFERWINDOWPOS TRUE
#define NOPEN TRUE
#define NO_TASK_DEFINES TRUE
#define NOLSTRING TRUE
#define WIN31
#define USECOMM
#include <windows.h>
#include <port1632.h>
#include "dcrc.h"
#include "dynacomm.h"
#include "connect.h"
/*---------------------------------------------------------------------------*/
/* exitSerial() - [mbb/rkh] */
/*---------------------------------------------------------------------------*/
VOID NEAR WIN_exitSerial() /* mbbx 2.00: network... */
{
DCB dcb;
if(GetCommState(sPort, (DCB FAR *) &dcb) == 0) /* mbbx 1.04: RTS/DTR disable... */
{
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
EscapeCommFunction(sPort,CLRRTS);
EscapeCommFunction(sPort,CLRDTR);
DEBOUT("SetCommState from Win_exitSerial for comport=%lx\n",sPort);
if(!SetCommState(sPort,(DCB FAR *) &dcb))
{
DEBOUT("FAIL: SetCommState from Win_exitSerial for comport=%lx\n",sPort);
}
}
#ifdef ORGCODE
FlushComm(sPort, 1);
FlushComm(sPort, 0);
#else
DEBOUT("FlushFileBuffers from Win_exitSerial: comport %lx\n",sPort);
#ifndef BUGBYPASS
DEBOUT("FlushFileBuffers from Win_exitSerial: BYPASSING FLUSH DUE TO BUG %lx\n",sPort);
#else
if (!FlushFileBuffers(sPort))
{
DEBOUT("FAIL: FlushFileBuffers comport %lx\n",sPort);
}
#endif
DEBOUT("PurgeComm from Win_exitSerial:comport %lx\n",sPort);
if (!PurgeComm(sPort,0))
{
DEBOUT("FAIL: PurgeComm comport %lx\n",sPort);
}
#endif
SetCommMask(sPort, EV_RXCHAR);
//WaitForSingleObject(hMutex, 500);
bPortIsGood = FALSE;
/**********
{
// Make suer sPort gets closed, bug#9671
// Actually a bug in serial driver, The fix is a
// quick hack, should be removed once the driver
// is fixed.
int cnt=20;
while (cnt-- && CloseHandle(sPort)) Sleep (200);
}
**********/
//
// We can't close the handle twice now.
// So, just close it and wait a little.
//
Sleep (200);
CloseHandle (sPort);
Sleep (200);
sPort = NULL;
//ReleaseMutex(hMutex);
}
VOID exitSerial() /* mbbx 2.00: network... */
{
switch(trmParams.comDevRef)
{
case ITMWINCOM:
WIN_exitSerial();
break;
case ITMDLLCONNECT: /* slc nova 012 bjw nova 02 */
DLL_ExitConnector(ghCCB, &trmParams); /* slc nova 031 */
break;
}
trmParams.comDevRef = ITMNOCOM;
}
/*---------------------------------------------------------------------------*/
/* resetSerial() - [mbb/rkh] */
/*---------------------------------------------------------------------------*/
VOID NEAR WIN_resetSerial(recTrmParams *trmParams, BOOL bLoad, NEARPROC errProc)
{
INT attempts;
// sdj: this is replaced by global szCurrentPortName ;BYTE tmp1[TMPNSTR+1];
BYTE tmp1[TMPNSTR+1],tmp2[TMPNSTR+1];
DCB dcb;
DCB PrevDcb;
COMMTIMEOUTS CommTimeOuts;
BOOL bRc;
DWORD dwError;
COMMPROP CommProp; // -sdj sep92 on low mem rx buffer can be < 1024
modemReset(); /* mbbx 0.72: avoid hang if XOFF-ed */
if(bLoad)
{
for(attempts = 0; trmParams->comDevRef == ITMNOCOM; attempts += 1)
{
if(trmParams->comPortRef > MaxComPortNumberInMenu)
strcpy(szCurrentPortName, "\\\\.\\TELNET");
else
{
// LoadString(hInst, STR_COM, (LPSTR) tmp2, MINRESSTR);
// sprintf(szCurrentPortName, tmp2, trmParams->comPortRef);
strcpy(szCurrentPortName,arComNumAndName[trmParams->comPortRef].PortName);
}
if( (sPort != NULL) && (sPort != (HANDLE)-1) )
{
SetCommMask(sPort, 0); // so that waitcommevent comes out; -sdj
sPort = NULL;
}
sPort = CreateFile(szCurrentPortName, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (sPort == (HANDLE)-1)
{
dwError = GetLastError();
bPortIsGood = FALSE;
if(!(*errProc)(trmParams, attempts))
return;
}
else
{
SetCommMask(sPort, EV_RXCHAR); // -sdj 27apr92 telnet deadlock
dwWriteFileTimeout = 5000; // -sdj 28apr92 telnet debug
trmParams->comDevRef = ITMWINCOM;
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
if (trmParams->flowControl == ITMHARDFLOW)
{
CommTimeOuts.WriteTotalTimeoutConstant = 5000; // 5msecs
}
else
{
CommTimeOuts.WriteTotalTimeoutConstant = 10000; //10secs
}
if (!(bRc = SetCommTimeouts(sPort,&CommTimeOuts) ) )
{
if(!(*errProc)(trmParams, attempts))
return;
}
// There may be data already waiting to be read - i.e. data
// that arrived before we set comm mask. This data will not
// be uncovered by wait mask, so we must try to read it.
gotCommEvent = TRUE;
}
} // endof for
} // endof if bload
/* This would work on both win30 and win32 -sdj*/
/* if(GetCommState(sPort, (DCB FAR *) &dcb) == 0) -sdj*/
DEBOUT("HACK : %s\n","rc of GetCommState: not checked for now");
{
GetCommState(sPort, (DCB FAR *) &dcb);
GetCommState(sPort, (DCB FAR *) &PrevDcb);
// -sdj sep92 on low mem rx buffer can be < 1024
// -sdj set rx buffer to nice 4096 bytes size
// -sdj driver will do its best and set the Rx buffer to this size
// -sdj if it fails then dwCurrentRxQueue will be the one we have
// -sdj so do getcommprop again to fetch this value, which can
// -sdj be used to set xoff and xon lims
GetCommProperties(sPort,&CommProp);
SetupComm(sPort,4096,4096);
CommProp.dwCurrentRxQueue = 0; // -sdj dirty it so that we
// -sdj can use this only if !=0
GetCommProperties(sPort,&CommProp);
// sdj: added this code to take care of extra baud rates support
if (trmParams->speed <= 57600)
{
dcb.BaudRate = trmParams->speed; /* mbbx 2.00: allow any baud... */
}
else
{
if (trmParams->speed == 57601)
{
// sdj: this means 115.2K baud rate which cannot fit into BYTE!
dcb.BaudRate = 115200;
}
else{
if (trmParams->speed == 57602)
{
dcb.BaudRate = 128000;
}
else
{
// sdj: something wrong! default to 1200
dcb.BaudRate = 1200;
}
}
}
dcb.ByteSize = 8 + (trmParams->dataBits - ITMDATA8);
dcb.Parity = NOPARITY + (trmParams->parity - ITMNOPARITY);
dcb.StopBits = ONESTOPBIT + (trmParams->stopBits - ITMSTOP1);
// dcb.RlsTimeout = 0;
// dcb.CtsTimeout = (trmParams->flowControl == ITMHARDFLOW) ? 5 : 0; /* mbbx 1.10: CUA */
// dcb.DsrTimeout = 0;
dcb.fBinary = TRUE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fParity = trmParams->fParity; /* mbbx 1.10: CUA */
dcb.fOutxCtsFlow = (trmParams->flowControl == ITMHARDFLOW); /* mbbx 1.10: CUA... */
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fOutX =
dcb.fInX = (trmParams->flowControl == ITMXONFLOW);
dcb.fErrorChar = trmParams->fParity; /* mbbx 1.10: CUA */
dcb.fNull = FALSE;
// dcb.fChEvt = FALSE;
// dcb.fDtrFlow = FALSE;
if (trmParams->flowControl == ITMHARDFLOW)
{
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; /* mbbx 1.10: CUA... */
}
dcb.XonChar = XON;
dcb.XoffChar = XOFF;
/* -sdj sep92, this is 1k/4=256, 9M system can have RXQ=256
-sdj in that case SetCommState can fail due to invalid
-sdj parameters of xoff xon limits
dcb.XonLim = NINQUEUE / 4;
dcb.XoffLim = NINQUEUE / 4;
*/
// -sdj if for some wierd reason dwCurrentRxQueue is not
// -sdj filled in by the driver, then let xon xoff lims
// -sdj be the default which the driver has.
// -sdj (dwCurrentRxQueue was set to 0 before calling Get again)
if (CommProp.dwCurrentRxQueue != 0)
{
dcb.XonLim = (WORD)(CommProp.dwCurrentRxQueue / 4);
dcb.XoffLim = (WORD)(CommProp.dwCurrentRxQueue / 4);
}
dcb.ErrorChar = '?';
dcb.EofChar = CNTRLZ;
dcb.EvtChar = 0;
dcb.wReserved = 0;
#ifdef ORGCODE
if(SetCommState((DCB FAR *) &dcb) == 0)
{
#else
if(SetCommState(sPort, (DCB FAR *) &dcb) == 0)
{
DEBOUT("FAIL: SetCommState for comport=%lx\n",sPort);
#endif
mdmOnLine = FALSE; /* mbbx 1.10: carrier... */
mdmConnect();
LoadString(hInst, STR_SETCOMFAIL, (LPSTR) tmp1, TMPNSTR);
LoadString(hInst, STR_ERRCAPTION, (LPSTR) tmp2, TMPNSTR);
MessageBox(hItWnd, (LPSTR) tmp1, (LPSTR)tmp2, MB_OK | MB_APPLMODAL);
SetCommState(sPort,&PrevDcb);
return;
}
#ifdef ORGCODE
#else
/*DWORD ReadIntervalTimeout; Maximum time between read chars. */
/*DWORD ReadTotalTimeoutMultiplier; Multiplier of characters. */
/*DWORD ReadTotalTimeoutConstant; Constant in milliseconds. */
/*DWORD WriteTotalTimeoutMultiplier; Multiplier of characters. */
/*DWORD WriteTotalTimeoutConstant; Constant in milliseconds. */
DEBOUT("Win_resetSerial: %s\n","Setting Comm timeouts");
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
if (trmParams->flowControl == ITMHARDFLOW)
{
CommTimeOuts.WriteTotalTimeoutConstant = 5000; //5 msecs
}
else
{
CommTimeOuts.WriteTotalTimeoutConstant = 10000; //10secs
}
if (!(bRc = SetCommTimeouts(sPort,&CommTimeOuts) ) )
{
DEBOUT("FAIL: SetCommTimeouts failed rc: %lx\n",bRc);
mdmOnLine = FALSE; /* mbbx 1.10: carrier... */
mdmConnect();
return;
}
#endif
}
bPortIsGood = TRUE; /* now the port is properly initialized -sdj 05/21/92*/
//-sdj for telnet-quit processing
bPortDisconnected = FALSE; /* there is no problem of port_was_opened_but_not_working */
}
VOID resetSerial(recTrmParams *trmParams, BOOL bLoad,BOOL bInit,BYTE byFlowFlag) /* slc swat */
{
/* LPCONNECTOR_CONTROL_BLOCK lpCCB; -sdj no unref variables please ; slc nova 031 */
if(bLoad)
{
if(!trmParams->fResetDevice)
trmParams->newDevRef = trmParams->comDevRef;
exitSerial();
}
switch(bLoad ? trmParams->newDevRef : trmParams->comDevRef)
{
case ITMNOCOM:
break;
default: // case ITMWINCOM:
WIN_resetSerial(trmParams, bLoad, bInit ? (NEARPROC)resetSerialError0 : (NEARPROC)resetSerialError1 /*, byFlowFlag*/); /* slc swat */
break;
#ifdef OLDCODE
case ITMWINCOM:
WIN_resetSerial(trmParams, bLoad, bInit ? (NEARPROC)resetSerialError0 : (NEARPROC)resetSerialError1 /*, byFlowFlag*/); /* slc swat */
break;
case ITMDLLCONNECT: /* slc nova 012 bjw nova 002 */
if((lpCCB = (LPCONNECTOR_CONTROL_BLOCK)GlobalLock(ghCCB)) != NULL) /* slc nova 031 */
{
if(lpCCB->hConnectorInst == NULL) /* first time? */
if(!loadConnector(NULL, ghCCB, (LPSTR)trmParams->szConnectorName, FALSE))
return;
GlobalUnlock(ghCCB);
trmParams->comDevRef = ITMDLLCONNECT;
DLL_SetupConnector(ghCCB, FALSE); /* slc nova 031 */
}
break;
#endif
}
trmParams->fResetDevice = FALSE;
}
/*---------------------------------------------------------------------------*/
/* resetSerialError0 - called during initialization; [mbb] */
/* auto attempt other COM port, then fail */
/*---------------------------------------------------------------------------*/
BOOL PASCAL NEAR resetSerialError0(recTrmParams *trmParams, WORD count)
{
BYTE tmp1[TMPNSTR+1];
BYTE tmp2[TMPNSTR+1];
//sdj: if this is a telnet port then advice the user to go to
//sdj: the control panel and see if telnet service is started
//sdj: else stick with the original msg of selected com port not
//sdj: available, select other port.
if (!strcmp(szCurrentPortName,"\\\\.\\TELNET"))
{
LoadString(hInst, STR_TELNETFAIL, (LPSTR) tmp1, TMPNSTR);
}
else
{
LoadString(hInst, STR_OTHERCOM, (LPSTR) tmp1, TMPNSTR);
}
LoadString(hInst, STR_ERRCAPTION, (LPSTR) tmp2, TMPNSTR);
MessageBox(hItWnd, (LPSTR) tmp1, (LPSTR)tmp2, MB_OK | MB_APPLMODAL);
doSettings(IDDBCOMM, dbComm);
return(FALSE);
}
/*---------------------------------------------------------------------------*/
/* resetSerialError1 - default case (e.g., after loading settings) [mbb] */
/* prompt to attempt other COM port, then fail */
/*---------------------------------------------------------------------------*/
BOOL PASCAL NEAR resetSerialError1(recTrmParams *trmParams, WORD count)
{
BYTE tmp1[TMPNSTR+1];
BYTE tmp2[TMPNSTR+1];
if(count > 0)
{
LoadString(hInst, STR_NOCOMMPORTS, (LPSTR) tmp1, TMPNSTR); /* mbbx 1.00 */
testMsg(tmp1,NULL,NULL);
}
else
{
//sdj: if this is a telnet port then advice the user to go to
//sdj: the control panel and see if telnet service is started
//sdj: else stick with the original msg of selected com port not
//sdj: available, select other port.
if (!strcmp(szCurrentPortName,"\\\\.\\TELNET"))
{
LoadString(hInst, STR_TELNETFAIL, (LPSTR) tmp1, TMPNSTR);
}
else
{
LoadString(hInst, STR_OTHERCOM, (LPSTR) tmp1, TMPNSTR);
}
LoadString(hInst, STR_ERRCAPTION, (LPSTR) tmp2, TMPNSTR);
MessageBox(hItWnd, (LPSTR) tmp1, (LPSTR)tmp2, MB_OK | MB_APPLMODAL);
trmParams->comPortRef = ITMNOCOM; /* mbbx 1.10: CUA */
}
return(FALSE);
}