windows-nt/Source/XPSP1/NT/base/mvdm/wow16/user/comdev.c
2020-09-26 16:20:57 +08:00

1135 lines
33 KiB
C

/****************************************************************************/
/* */
/* COMDEV.C - */
/* */
/* Windows Communication Routines */
/* */
/****************************************************************************/
/*************************************************************************
**
** Windows Communication Layer
**
** This is the library interface layer for the Communications Device Driver.
** The driver presents an interface between windows based applications and the
** communications hardware.
**
** /-----------------------------\
** / Windows \
** \ Application Program /
** \-----------------------------/
** | Windows Interface |
** +-----------------------------+
** | OEM Dependant LowLevel Code |
** /-----------------------------\
** / Machine Layer \
** \ Communications Hardware /
** \-----------------------------/
**
*************************************************************************/
#define USECOMM
#include "user.h"
#include "comdev.h" /* Device driver structure defs */
#include "comdevi.h" /* Device driver internal defs */
HANDLE FAR GlobalDOSAlloc(LONG h);
void FAR GlobalDOSFree(HANDLE h);
#define length(string) lstrlen((char FAR *)string)
#define UPPERCASE(x) MyToUpper(x)
LPSTR NEAR PASCAL field(LPSTR, LPSTR);
short getid(LPSTR);
char FAR *GetMem(WORD);
cinfo *cinfoPtr(int);
void FreeMem(LPSTR);
char _fastcall NEAR MyToUpper(char);
/* Array of information for each communications device that we support. */
cinfo rgcinfo[DEVMAX] = {0}; /* Device additional info table */
/* Strings used for determining device characteristics. */
static char CODESEG COMbuf[] = "COM1:9600,E,7,1";
static char CODESEG LPTbuf[] = "LPT1";
static char CODESEG AUXbuf[] = "AUX1"; /* AUX will map to COM1 */
static char CODESEG PRNbuf[] = "PRN1"; /* PRN will map to LPT1 */
#define CONFIGINDEX 5 /* Index to 9600,... in COMbuf */
/*************************************************************************
** OpenComm - open a communication device
**
** Synopsis:
** short OpenComm(pszComName, cbInQue, cbOutQue)
** FAR char *pszComName;
** ushort cbInQue;
** ushort cbOutQue;
**
** Description:
** OpenComm opens a comunication device an associates a com handle with it. The
** communication device is initialized to a default configuration. The csetcom
** function call, below, should be used to initialized the device to alternate
** values.
**
** OpenComm returns an id which is used in subsequent calls to reference the
** communication device, or a negative error initialization error code.
**
** pszComName points to a string which contains "COMn" where "n" is allowed to
** range from 1 to the number of COMM devices supported by the OEM. cbInQue
** and cbOutQue reflect the receive and transmit queue sizes, respectively.
** These queues are allocated at open time, deallocated at close time, and are
** used by the interrupt driven transmit/receive software.
**
** pszComName may also point to a string which contains "LPTn" where "n" is
** allowed to range from 1 to the number of LPT devices supported by the OEM.
** cbInQue and cbOutQue are ignored for LPT devices. LPT devices are not
** interrupt driven.
**
*************************************************************************/
int API IOpenComm(LPSTR pszComName, WORD cbInQue, WORD cbOutQue)
{
short cidCur; /* ID of device */
DCB dcbNew; /* Temp DCB */
short ierr; /* Return code from inicom */
register cinfo *pcinfo; /* pointer to information block */
register qdb *pqdbNew; /* pointer to queue information */
if ((cidCur = getid(pszComName)) == -1) /* if not recognized, return */
return(IE_BADID); /* error to caller */
pcinfo = cinfoPtr(cidCur); /* form pointer to info block */
if (pcinfo->fOpen) /* if device already open */
return(IE_OPEN); /* return error to caller */
if (pcinfo->fReservedHardware)
/* if device locked for some reason return error to caller ex locked for
* use by mouse.
*/
return(IE_HARDWARE);
/* do nothing if device is LPTn. */
if (!(cidCur & LPTx))
{
if( (cbInQue == 0) && (cbOutQue == 0) ) /* if Queue length's zero, */
return(IE_MEMORY); /* return memory error right away, */
/* so a buildDCB isn't done...
this is a common method of
finding if the comm port is
already opened or not...
wanted to make it fast */
if (lstrlen(pszComName) < 4 || BuildCommDCB(pszComName, &dcbNew) == -1)
{
if (BuildCommDCB(COMbuf, &dcbNew) == -1)
return(IE_DEFAULT);
}
pqdbNew = &pcinfo->qdbCur; /* form pointer to qdb */
if ((pqdbNew->pqRx = GetMem(cbInQue)) == (char FAR *)NULL)
return(IE_MEMORY); /* no room for Rx queue */
if ((pqdbNew->pqTx = GetMem(cbOutQue)) == (char FAR *)NULL)
{
FreeMem(pqdbNew->pqRx); /* no room for Tx queue */
return(IE_MEMORY);
}
pqdbNew->cbqRx = cbInQue;
pqdbNew->cbqTx = cbOutQue;
setque(cidCur,(qdb FAR *)pqdbNew); /* init the queue's as well */
}
dcbNew.Id = (char)cidCur; /* set device ID in dcb */
ierr = inicom((DCB FAR *)&dcbNew); /* attempt to init */
if (ierr)
{
if (!(cidCur & LPTx)) /* if a comm device */
{
FreeMem(pqdbNew->pqRx); /* free Tx queue */
FreeMem(pqdbNew->pqTx); /* free Rx queue */
}
return(ierr); /* return error code */
}
pcinfo->fOpen = TRUE; /* indicate device open */
pcinfo->hTask = GetCurrentTask();
return(cidCur); /* all's well, return dev id */
}
#ifdef DISABLE
int FAR PASCAL OpenCommFromDCB(LPDCB pdcb, WORD cbInQue, WORD cbOutQue)
{
short cidCur; /* ID of device */
short ierr; /* Return code from inicom */
register cinfo *pcinfo; /* pointer to information block */
register qdb *pqdbNew; /* pointer to queue information */
cidCur = (WORD)pdcb->Id & 0x00FF;
if ((cidCur & LPTxMask) > ((cidCur & LPTx) ? (PIOMAX - 1) : (CDEVMAX - 1)))
return(IE_BADID); /* check cid for validity */
pcinfo = cinfoPtr(cidCur); /* form pointer to info block */
if (pcinfo->fOpen) /* if device already open */
return(IE_OPEN); /* return error to caller */
if (!(cidCur & LPTx)) /* device is LPTn */
{
if( (cbInQue == 0) && (cbOutQue == 0) ) /* if Queue length's zero, */
return(IE_MEMORY); /* return memory error right away, */
/* so a buildDCB isn't done... this
* is a common method of finding if
* the comm port is already opened
* or not... wanted to make it fast
*/
pqdbNew = &pcinfo->qdbCur; /* form pointer to qdb */
if ((pqdbNew->pqRx = GetMem(cbInQue)) == (char FAR *)NULL)
return(IE_MEMORY); /* no room for Rx queue */
if ((pqdbNew->pqTx = GetMem(cbOutQue)) == (char FAR *)NULL)
{
FreeMem(pqdbNew->pqRx); /* no room for Tx queue */
return(IE_MEMORY);
}
pqdbNew->cbqRx = cbInQue;
pqdbNew->cbqTx = cbOutQue;
setque(cidCur,(qdb FAR *)pqdbNew); /* init the queue's as well */
}
ierr = inicom(pdcb); /* attempt to init */
if (ierr)
{
if (!(cidCur & LPTx)) /* if a comm device */
{
FreeMem(pqdbNew->pqRx); /* free Tx queue */
FreeMem(pqdbNew->pqTx); /* free Rx queue */
}
return(ierr); /* return error code */
}
pcinfo->fOpen = TRUE; /* indicate device open */
pcinfo->hTask = GetCurrentTask();
return(cidCur); /* all's well, return dev id */
}
#endif
/*************************************************************************
** SetCommState - set communciation device configuration
**
** Synopsis:
** int SetCommState(pdcb)
** LPDCB pdcb;
**
** Description:
** pdcb points to an initialized Device Control Block for a device which
** has been openned. The referenced device, as defined by the dcb's id field,
** is set to the state as defined by the dcb. SetCommState returns 0 on
** success, or a negative initialization error code if an error occurred. Note
** that this will reinitialize all hardware and control as defined in the dcb,
** but will not empty transmit or receive queues.
**
*************************************************************************/
int API ISetCommState(LPDCB pdcb)
{
if (cinfoPtr(pdcb->Id)->fOpen == 0)
return(IE_NOPEN); /* File must be open first */
return(setcom(pdcb));
}
/*************************************************************************
** GetCommState - return current dcb values
**
** Synopsis:
** int GetCommState(cid,pdcb)
** WORD cid;
** LPDCB *pdcb;
**
** Description:
** The dcb pointed to by pdcb is updated to reflect the current dcb in use
** for the device referenced by cid. Returns 0 on success, -1 on illegal
** handle or IE_OPEN if port has not been opened yet.
**
*************************************************************************/
int API IGetCommState(register int cid, LPDCB pdcb)
{
LPDCB pdcbSrc;
register int i;
if (cinfoPtr(cid)->fOpen == 0) /* File must be open first */
return(IE_NOPEN);
if ( (pdcbSrc = getdcb(cid)) ) /* pointer to dcb for device */
{
i = sizeof(DCB);
while (i--)
*((char FAR *)pdcb)++ = *((char FAR *)pdcbSrc)++;
return(0);
}
else
return(-1);
}
/*************************************************************************
** ReadComm - read characters from communication device
**
** Synopsis:
** int ReadComm(cid, pbuf, size)
** WORD cid;
** LPSTR *pbuf;
** int size;
**
** Description:
** ReadComm reads size characters into pbuf and returns the number of characters
** actually read. If the return value equals size bytes there may exist
** additional characters to read. The return count will be less if the number
** of characters present in the receive queue is less. If the return value is
** 0 then no characters were present.
**
** If the return value is negative, then an error was also detected, and an
** error code can be retrieved from GetCommError. The absolute value of the return
** value is the number of characters read. Note that this implies that if
** there are no characters to be read, then no error status can be returned,
** and GetCommError should be used to read the status.
**
*************************************************************************/
int API IReadComm(int cid, LPSTR pbuf, int size)
{
register int cbT;
int ch;
cid &= 0xff; /* get "pure" device ID */
if (size == 0) /* Empty read */
return(0);
if ((cid & LPTxMask) > ((cid & LPTx) ? (PIOMAX - 1) : (CDEVMAX - 1)))
return(0); /* check cid for validity */
if (cinfoPtr(cid)->fOpen == 0)
return(0); /* can't assume valid dcb... */
cbT = 0;
if (cinfoPtr(cid)->fchUnget) /* if there's a backed-up char */
{
cinfoPtr(cid)->fchUnget = FALSE; /* return backed up char */
*pbuf++ = cinfoPtr(cid)->chUnget; /* and update transfer count */
cbT++;
}
/*note. reccom returns -2 if no */
/*data available, - 1 if error */
ch = 0;
if (SELECTOROF(lpCommReadString) == NULL)
{
while (cbT < size) /* up to size characters */
{
if ((ch = reccom(cid)) < 0) /* stop when no char available */
break; /* or error */
*pbuf++ = (char)ch; /* place character in users buf */
cbT++; /* and update transfer count */
}
}
else
{
ch = 0;
cbT = lpCommReadString(cid, pbuf, size);
}
return(ch == -1 ? -cbT : cbT);
}
/*************************************************************************
** UngetCommChar - push a character back onto receive queue.
**
** Synopsis:
** int UngetCommChar(cid,ch)
** WORD cid;
** char ch;
**
** Description:
** Allows an application to "back-up" one character in the receive character
** stream by placing a character back into the receive stream. This character
** is then the first character returned by the next call to ReadComm. UngetCommChar may
** only be called once between calls to ReadComm. Returns 0 on success, -1 if
** illegal id, or unable to back-up.
**
*************************************************************************/
int API IUngetCommChar(int cid, char ch)
{
cid &= 0xFF; /* get "pure" device ID */
if ((cid & LPTxMask) > ((cid & LPTx) ? (PIOMAX - 1) : (CDEVMAX - 1)))
return(0); /* check cid for validity */
if (cinfoPtr(cid)->fchUnget) /* have we already backed up 1 */
return(-1);
if (cinfoPtr(cid)->fOpen == 0) /* can't assume valid dcb... */
return(-1);
cinfoPtr(cid)->fchUnget = TRUE; /* set flag indicating backed-up*/
cinfoPtr(cid)->chUnget = ch; /* and save the character */
return(0);
}
/*************************************************************************
** WriteComm - write characters to communication device
**
** Synopsis:
** int WriteComm(cid, pbuf, size)
** int cid;
** LPSTR *pbuf;
** int size;
**
** Description:
** WriteComm will write size character to the communication device. The byte
** count written is returned on success, negative byte count on error. GetCommError
** can be used to retrieve any error code.
**
*************************************************************************/
int API IWriteComm(int cid, LPSTR pbuf, int size)
{
int cbT;
cid &= 0xFF; /* get "pure" device ID */
if ((cid & LPTxMask) > ((cid & LPTx) ? (PIOMAX - 1) : (CDEVMAX - 1)))
return(0); /* check cid for validity */
/*return zero if not valid */
if (cinfoPtr(cid)->fOpen == 0) /* verify port has been opened */
return(-1);
cbT = 0;
if (SELECTOROF(lpCommWriteString) == NULL)
{
while (size--)
{
if (sndcom(cid,*pbuf++)) /* transmit character */
return(-cbT); /* return if error */
cbT++;
}
}
else
{
cbT = lpCommWriteString(cid, pbuf, size);
if (cbT < size)
{
/* For consistency, if we couldn't transmit all the characters we
* were asked to, return the negative of the number actually
* transmitted.
*/
cbT = -cbT;
}
}
return(cbT);
}
/*************************************************************************
** CloseComm - close communication device
**
** Synopsis:
** int CloseComm(cid)
** ushort cid;
**
** Description:
** closes the communication device and dealloctes any buffers. Returns 0 on
** success, -1 on error.
**
*************************************************************************/
int API ICloseComm(int cid)
{
register cinfo *pcinfo;
WORD retval;
cid &= 0xFF; /* get "pure" device ID */
if ((cid & LPTxMask) > ((cid & LPTx) ? (PIOMAX - 1) : (CDEVMAX - 1)))
return(-1); /* return error, cid not valid */
if ((pcinfo = cinfoPtr(cid))->fOpen==0) /* verify port opened ... */
return(-1); /* return error, port not open */
retval = trmcom(cid); /* terminate the device */
if (retval == 0x8000) /* if invalid ID */
return(-1); /* return error code */
pcinfo->fOpen = FALSE; /* indicate not open */
if (!(cid & LPTx))
{
FreeMem(pcinfo->qdbCur.pqRx); /* Free Rx buffer */
FreeMem(pcinfo->qdbCur.pqTx); /* Free Rx buffer */
}
return(retval); /* 0 if OK, -2 if queue trashed */
}
/*************************************************************************
** GetCommError - return device status
**
** Synopsis:
** short GetCommError(cid,pstat)
** ushort cid;
** stat FAR *pstat;
**
** Description:
** GetCommError returns the most recent error code for the referenced device, or -1
** for an illegal handle. In addition, if pstat is non-zero, GetCommError also
** updates the status record it points to.
**
*************************************************************************/
int API IGetCommError(int cid, COMSTAT FAR *pstat)
{
register WORD st;
cid &= 0xFF;
st = stacom(cid,pstat);
if ((st != 0x8000) && pstat && (cinfoPtr(cid)->fchUnget))
pstat->cbInQue++;
return(st);
}
void FAR PASCAL SP_GPFaultCommCleanup(HANDLE hTask)
/* effects: When the given task gp faults, we check if it had any comm ports
* opened and we close them.
*/
{
register int i;
for (i=0; i<DEVMAX; i++) /* check all devices */
if (rgcinfo[i].fOpen && rgcinfo[i].hTask == hTask)
/* if device is open */
CloseComm(i); /* close it */
}
/*************************************************************************
** BuildCommDCB - Parse a string into a dcb.
**
** Synopsis:
** short BuildCommDCB(pszDef,pdcb)
** char FAR *pszDef;
** DCB FAR *pdcb;
**
** Description:
** Parses a passed string and fills appropriate fields in a dcb, the address
** off which is also passed. The string conforms to that of a DOS MODE
** command for COMn. For example: "COM1:9600,N,7,1". Returns 0 on success,
** -1 on error.
**
*************************************************************************/
int API IBuildCommDCB(LPSTR pszDef, LPDCB pdcb)
{
register int i;
register int tempid;
char c;
char szT[80]; /* buffer in which to put things*/
LFillStruct((LPSTR)pdcb, sizeof(DCB), 0);/* zero the dcb since probably on
* app's stack
*/
pszDef = field(pszDef,(char FAR *)szT); /* Get first token */
if ((tempid=getid((char FAR *)szT))==-1)/* Get ID of device */
return(-1); /* Unknown device */
pdcb->Id = (char)tempid; /* we have a device id */
if (tempid & LPTx) /* if a LPTx port, then let the */
return(0); /* rest default to whatever */
pszDef = field(pszDef,(char FAR *)szT); /* next field */
if (length(szT) < 2)
return(-1); /* must be at least two chars */
i = (szT[0] << 8) | szT[1]; /* cheap and sleazy mapping */
switch (i) /* based on first 2 chars */
{
case 0x3131:
i = 110;
break;
case 0x3135:
i = 150;
break;
case 0x3330:
i = 300;
break;
case 0x3630:
i = 600;
break;
case 0x3132:
i = 1200;
break;
case 0x3234:
i = 2400;
break;
case 0x3438:
i = 4800;
break;
case 0x3936:
i = 9600;
break;
case 0x3139:
i = 19200;
break;
case 0x3338: /* handle 38400 baud in BuildCommDCB() */
i = 38400;
break;
default:
return(-1);
}
pdcb->BaudRate = i;
pdcb->XonLim = 10; /* Set these up always. */
pdcb->XoffLim = 10; /* Set these up always. */
pdcb->fBinary = 1; /* Set these up always. */
pdcb->XonChar = 0x11; /* Ctrl-Q */
pdcb->XoffChar = 0x13; /* Ctrl-S */
if ((pszDef = field(pszDef,(char FAR *)szT)) == 0)
return(0);
switch (szT[0])
{
case 0:
case 'E':
c = EVENPARITY;
break;
case 'O':
c = ODDPARITY;
break;
case 'N':
c = NOPARITY;
break;
case 'M':
c = MARKPARITY;
break;
case 'S':
c = SPACEPARITY;
break;
default:
return(-1);
}
pdcb->Parity = c;
if ((pszDef = field(pszDef,(char FAR *)szT)) == 0)
return(0);
switch (szT[0])
{
case 0:
case '7':
c = 7;
break;
case '8':
c = 8;
break;
default:
return(-1);
}
pdcb->ByteSize = c;
if ((pszDef = field(pszDef,(char FAR *)szT)) == 0)
return(0);
switch (szT[0])
{
case 0:
if (pdcb->BaudRate == 110)
{
c = TWOSTOPBITS;
break;
}
/*** FALL THRU ***/
case '1':
c = ONESTOPBIT;
break;
case '2':
c = TWOSTOPBITS;
break;
default:
return(-1);
}
pdcb->StopBits = c;
if ((pszDef = field(pszDef,(char FAR *)szT)) == 0)
return(0);
if (szT[0] != 'P')
return(-1);
pdcb->RlsTimeout = INFINITE;
pdcb->CtsTimeout = INFINITE;
pdcb->DsrTimeout = INFINITE;
return(0);
}
/*--------------------------------------------------------------------------*/
/* */
/* field() - */
/* */
/*--------------------------------------------------------------------------*/
LPSTR NEAR PASCAL field(LPSTR pszSrc, LPSTR lpszDst)
{
register char c;
if (!(pszSrc))
return(char FAR *)0;
if (!(*pszSrc))
return(char FAR *)0;
/* While not the end of the string. */
while (c = *pszSrc)
{
pszSrc++;
/* Look for end of string. */
if ((c == ' ') || (c == ':') || (c == ','))
{
*lpszDst = 0;
while (*pszSrc == ' ')
pszSrc++;
if (*pszSrc)
return(pszSrc);
return(char FAR *)0;
}
*lpszDst++ = UPPERCASE(c);
}
*lpszDst = 0;
return(pszSrc);
}
/*************************************************************************
**
** U T I L I T Y R O U T I N E S
**
**************************************************************************
**
** getid
** Given a (far) pointer to a string, returns the comm ID of that device,
** or -1 indicating error. This routine accepts all device references of
** the form "COMn", where n is any number from 0 to 9, or "LPTn" where
** n is any number from 1 to 9
**
*************************************************************************/
short getid(LPSTR pszComName)
{
int id;
register int base;
ushort isLPTorCOM;
LPSTR pszName;
#ifdef JAPAN
/* Brought from WIN2 */
/* ------------- support 'oemgetid' (Jul,29,1987 SatoN) ----------- */
typedef int (far *FARPROC)();
extern void far int3();
static FARPROC lpOEMgetid = (FARPROC)(-1L);
/* If lpOEMgetid has not been initialized yet, initialize it.
This assumes 'GetProcAddress' does not cause FatalExit. */
if (lpOEMgetid==(FARPROC)(-1L))
{
unsigned hComm;
if ((hComm = GetModuleHandle( (char far *)"COMM" ))==NULL)
lpOEMgetid = NULL;
else
lpOEMgetid = GetProcAddress( hComm,(char far *)"oemgetid" );
}
/* If COMM driver has the routine 'oemgetid', then call it. */
if (lpOEMgetid && (id=(*lpOEMgetid)(pszComName))!=-1)
return id;
/* ------------- end of support 'oemgetid' ---------------------- */
#endif /* JAPAN */
isLPTorCOM = TRUE; /* assume LPTx or COMx */
base = 0; /* assume serial */
id = 0; /* assume LPT1 or COM1 9/25/86 */
switch (UPPERCASE(*pszComName))
{
case 'A': /* AUX possibility */
pszName = AUXbuf; /* Search string to match */
isLPTorCOM = FALSE; /* Show AUX or PRN */
break;
case 'C': /* COMx possibility */
pszName = COMbuf; /* Search string to match */
break; /* cid base */
case 'L': /* LPTx possibility */
pszName = LPTbuf; /* Search string to match */
base = LPTx; /* cid base */
break;
case 'P': /* PRN possibility */
pszName = PRNbuf; /* Search string to match */
base = LPTx; /* cid base */
isLPTorCOM = FALSE; /* Show AUX or PRN */
break;
default:
return(-1);
}
while(*pszName != '1') /* make sure strings match */
{
if (*pszName++ != UPPERCASE(*pszComName++))
return(-1);
}
if (isLPTorCOM || /* then get device number */
(*pszComName && *pszComName != ':'))/* accept PRN or AUX */
id = (*pszComName++) - '1';
if (*pszComName == ':') /* skip ':' if present */
pszComName++;
if ((id < 0) || (*pszComName != '\0'))
return(-1);
if (id > (base ? (PIOMAX - 1) : (CDEVMAX - 1)))
return(-1);
return(base + id);
}
/*--------------------------------------------------------------------------*/
/* */
/* cinfoPtr() - */
/* */
/*--------------------------------------------------------------------------*/
cinfo *cinfoPtr(int cid)
{
if (cid & LPTx)
return(&rgcinfo[((cid & LPTxMask)+CDEVMAX)]);
return(&rgcinfo[(cid & 0xFF)]);
}
/*************************************************************************
**
** GetMem
** Uses windows memory allocator to get far, global memory. We fudge here,
** in that GlobalAlloc returns a handle, which happens to be the segment
** of the fixed memory we've asked for. Hence we need to fudge it to get
** an address.
**
*************************************************************************/
LPSTR GetMem(WORD size)
{
/* See if the 286 DOS extender is installed, and if so, we must allocate
memory from conventional memory, so the queue can be used in both
protect and real modes (segment/selector ablility)
*/
if( (WinFlags & (WF_PMODE|WF_WIN286)) == (WF_PMODE|WF_WIN286) )
{
return(MAKELP(GlobalDOSAlloc((LONG)size), NULL));
}
else
{
return(MAKELP(GlobalAlloc(
GMEM_LOWER | GMEM_SHARE | GMEM_ZEROINIT | GMEM_FIXED,
(LONG)size), NULL));
}
}
/*--------------------------------------------------------------------------*/
/* */
/* FreeMem() - */
/* */
/*--------------------------------------------------------------------------*/
void FreeMem(LPSTR pMem)
{
/* See if the 286 DOS extender is installed, and if so, we must deallocate
memory from conventional memory, so the queue can be used in both
protect and real modes (segment/selector ablility)
*/
if( (WinFlags & (WF_PMODE|WF_WIN286)) == (WF_PMODE|WF_WIN286) )
{
GlobalDOSFree((HANDLE)(((LONG)pMem) >> 16));
}
else
{
GlobalFree((HANDLE)(((LONG)pMem) >> 16));
}
}
/*--------------------------------------------------------------------------*/
/* */
/* TransmitCommChar() - */
/* */
/*--------------------------------------------------------------------------*/
int API ITransmitCommChar(int cid, char character)
{
cid &= 0xFF;
return(ctx(cid, character));
}
/*--------------------------------------------------------------------------*/
/* */
/* SetCommEventMask() - */
/* */
/*--------------------------------------------------------------------------*/
WORD FAR * API ISetCommEventMask(int cid, WORD evtmask)
{
cid &= 0xFF;
return(cevt(cid, evtmask));
}
/*--------------------------------------------------------------------------*/
/* */
/* GetCommEventMask() - */
/* */
/*--------------------------------------------------------------------------*/
WORD API IGetCommEventMask(int cid, int evtmask)
{
cid &= 0xFF;
return(cevtGet(cid, evtmask));
}
/*--------------------------------------------------------------------------*/
/* */
/* SetCommBreak() - */
/* */
/*--------------------------------------------------------------------------*/
int API ISetCommBreak(int cid)
{
cid &= 0xFF;
return(csetbrk(cid));
}
/*--------------------------------------------------------------------------*/
/* */
/* ClearCommBreak() - */
/* */
/*--------------------------------------------------------------------------*/
int API IClearCommBreak(int cid)
{
cid &= 0xFF;
return(cclrbrk(cid));
}
/*--------------------------------------------------------------------------*/
/* */
/* FlushComm() - */
/* */
/*--------------------------------------------------------------------------*/
/* Parameters:
* ushort cid -- 0=com1 1=com2
* ushort queue -- 0 = clear transmit 1 = receive
*/
int API IFlushComm(int cid, int queue)
{
cid &= 0xFF;
return(cflush(cid, queue));
}
/*--------------------------------------------------------------------------*/
/* */
/* EscapeCommFunction() - */
/* */
/*--------------------------------------------------------------------------*/
LONG API IEscapeCommFunction(int cid, int fcn)
{
LONG ret;
cid &= 0xFF;
ret = cextfcn(cid, fcn);
if (SELECTOROF(lpCommWriteString) == NULL)
{
#if 0
if (fcn == GETMAXBAUD)
/* For 3.0 drivers, fake the maxbaud rate escape.
*/
ret = (LONG)CBR_19200;
else
#endif
if (fcn == GETMAXLPT)
ret = (LONG)LPTx+2; /* 3 lpt ports */
else
if (fcn == GETMAXCOM)
ret = (LONG)9;
else
if ((WORD)fcn <= RESETDEV)
/* New for 3.1, we need to return a long from this function. So fix
* things up for old 3.0 drivers who used the defined escape range
* (we had 7 escapes for 3.0 drivers).
*/
ret = (LONG)(int)(LOWORD(ret));
}
return(ret);
}
/*--------------------------------------------------------------------------*/
/* */
/* EnableCommNotification() - */
/* */
/*--------------------------------------------------------------------------*/
BOOL API IEnableCommNotification(int cid, HWND hwnd,
int recvth, int sendth)
{
cid &= 0xFF;
if (SELECTOROF(lpCommEnableNotification) == NULL)
return(FALSE);
return(lpCommEnableNotification(cid, hwnd, recvth, sendth));
}
/*--------------------------------------------------------------------------*/
/* */
/* MyToUpper() - */
/* */
/*--------------------------------------------------------------------------*/
char _fastcall NEAR MyToUpper(char c)
{
return((c < (char)'a') ? c : c - (char)32);
}
/*--------------------------------------------------------------------------*/
/* */
/* LW_DriversInit() - */
/* */
/*--------------------------------------------------------------------------*/
void LW_DriversInit(void)
{
HMODULE hModule;
char szString[128];
/*------------------------------------------------------------------------*/
/* Comm Initialization */
/*------------------------------------------------------------------------*/
/* Find out if the poor user is running with a 3.0 comm driver. Do this by
* checking for the 3.1 function WriteCommString. Also, save off the
* addresses of these functions so we don't rip had we imported them
* directly.
*/
LoadString(hInstanceWin, STR_COMMMODULENAME, szString, sizeof(szString));
hModule = GetModuleHandle(szString);
LoadString(hInstanceWin, STR_COMMWRITESTRING, szString, sizeof(szString));
(FARPROC)lpCommWriteString = GetProcAddress((HINSTANCE)hModule, szString);
LoadString(hInstanceWin, STR_COMMREADSTRING, szString, sizeof(szString));
(FARPROC)lpCommReadString = GetProcAddress((HINSTANCE)hModule, szString);
LoadString(hInstanceWin, STR_COMMENABLENOTIFICATION, szString, sizeof(szString));
(FARPROC)lpCommEnableNotification = GetProcAddress((HINSTANCE)hModule, szString);
}