/*--------------------------------------------------------------------------*/ /* */ /* */ /* ------------ Bit-Bucket Software, Co. */ /* \ 10001101 / Writers and Distributors of */ /* \ 011110 / Freely Available Software. */ /* \ 1011 / */ /* ------ */ /* */ /* (C) Copyright 1987-96, Bit Bucket Software Co. */ /* */ /* */ /* */ /* BinkleyTerm Windows NT Async Comm I/O Routines */ /* */ /* */ /* For complete details of the licensing restrictions, please refer */ /* to the License agreement, which is published in its entirety in */ /* the MAKEFILE and BT.C, and also contained in the file LICENSE.260. */ /* */ /* USE OF THIS FILE IS SUBJECT TO THE RESTRICTIONS CONTAINED IN THE */ /* BINKLEYTERM LICENSING AGREEMENT. IF YOU DO NOT FIND THE TEXT OF */ /* THIS AGREEMENT IN ANY OF THE AFOREMENTIONED FILES, OR IF YOU DO */ /* NOT HAVE THESE FILES, YOU SHOULD IMMEDIATELY CONTACT BIT BUCKET */ /* SOFTWARE CO. AT ONE OF THE ADDRESSES LISTED BELOW. IN NO EVENT */ /* SHOULD YOU PROCEED TO USE THIS FILE WITHOUT HAVING ACCEPTED THE */ /* TERMS OF THE BINKLEYTERM LICENSING AGREEMENT, OR SUCH OTHER */ /* AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO. */ /* */ /* */ /* You can contact Bit Bucket Software Co. at any one of the following */ /* addresses: */ /* */ /* Bit Bucket Software Co. FidoNet 1:104/501, 1:343/491 */ /* P.O. Box 460398 AlterNet 7:42/1491 */ /* Aurora, CO 80046 BBS-Net 86:2030/1 */ /* Internet f491.n343.z1.fidonet.org */ /* */ /* Please feel free to contact us at any time to share your comments about */ /* our software and/or licensing policies. */ /* */ /*--------------------------------------------------------------------------*/ /* Include this file before any other includes or defines! */ /* #include "includes.h" */ #ifndef _WIN32 #pragma message("This Module For Windows NT") #else #include #include #include #include #include #include #include #include "com_nt.h" #include "wnfossil.h" typedef unsigned char byte; extern unsigned int comm_bits; extern unsigned int parity; extern unsigned int stop_bits; extern void _cdecl status_line (char *,...); extern long timerset (int); extern int timeup (long); extern void time_release (void); #define FOSSIL_BUFFER_SIZE 128 extern char fossil_buffer[]; extern char *fossil_fetch_pointer; extern int fossil_count; extern char out_buffer[]; extern char *out_send_pointer; extern int out_count; #define INBUF_SIZE 3072L #define OUTBUF_SIZE 10240L HANDLE hcModem = 0; /* comm handle */ HANDLE hRead = 0; /* Read event handle */ HANDLE hWrite = 0; /* Write event handle */ OVERLAPPED ovRead; /* Read overlapped stuct */ OVERLAPPED ovWrite; /* Write overlapped stuct */ DWORD FailSafeTimer = 0; BOOL fWriteWait = FALSE; /* Now waiting for write */ static short fDCD; /* Current carrier detect */ static HANDLE hDCD; /* Associated event */ static short fRXAvailable; /* We think there's a character */ static HANDLE hRXAvailable; /* Associated event */ static short fTXEmpty; /* We think transmitter's silent */ static ULONG SavedRate = 0; /* Last set baud rate */ DWORD FAR PASCAL stdComWatchProc (LPVOID nothing); HANDLE hWatchThread = 0; /* Watch comm events */ DWORD dwWatchThread = 0; /* Thread identifier */ CRITICAL_SECTION csWatchThread; /* Critical section for watched events */ unsigned short baseCominit (int port, int failsafe); extern int use_winfossil; PFNU_II Cominit = baseCominit; PFNS_HU ComSetParms ; PFNV_H ComDeInit ; PFNS_H ComCarrier ; PFNS_H ComInCount ; PFNS_H ComOutCount ; PFNS_H ComOutSpace ; PFNV_H ComDTROff ; PFNV_H ComDTROn ; PFNV_H ComTXPurge ; PFNV_H ComRXPurge ; PFNV_H ComXONEnable ; PFNV_H ComXONDisable ; PFNS_HB ComPutc ; PFNS_HB ComBufferByte ; PFNV_HU ComTxWait ; PFNI_HU ComRxWait ; PFNU_H ComGetc ; PFNS_H ComPeek ; PFNV_HI ComBreak ; PFNV_HPVUS ComWrite ; PFNI_H ComGetFH ; PFNI_H ComPause ; PFNI_H ComResume ; PFNI_I com_getc ; void stdComWriteEx (HANDLE hcModem, void *buf, USHORT count, short dcdcheck); int stdComRxWaitEx (HANDLE hcModem, ULONG interval, BOOL fWatchDCD); int stdComTxFinish (DWORD dwInterval, short sDCDCheck); unsigned short stdComGetc (HANDLE hcModem); unsigned short baseCominit (int port, int failsafe) { /* This only gets called if ComSelect hasn't been called yet */ ComSelect (!use_winfossil); return Cominit (port, failsafe); } void ComSelect (int fStandard) { if (fStandard) { Cominit = stdCominit; ComSetParms = stdComSetParms; ComDeInit = stdComDeInit; ComCarrier = stdComCarrier; ComInCount = stdComInCount; ComOutCount = stdComOutCount; ComOutSpace = stdComOutSpace; ComDTROff = stdComDTROff; ComDTROn = stdComDTROn; ComTXPurge = stdComTXPurge; ComRXPurge = stdComRXPurge; ComXONEnable = stdComXONEnable; ComXONDisable = stdComXONDisable; ComPutc = stdComPutc; ComBufferByte = stdComBufferByte; ComTxWait = stdComTxWait; ComRxWait = stdComRxWait; ComGetc = stdComGetc; ComPeek = stdComPeek; ComBreak = stdComBreak; ComWrite = stdComWrite; ComGetFH = stdComGetFH; ComPause = stdComPause; ComResume = stdComResume; com_getc = stdcom_getc; } else { Cominit = wfCominit; ComSetParms = wfComSetParms; ComDeInit = wfComDeInit; ComCarrier = wfComCarrier; ComInCount = wfComInCount; ComOutCount = wfComOutCount; ComOutSpace = wfComOutSpace; ComDTROff = wfComDTROff; ComDTROn = wfComDTROn; ComTXPurge = wfComTXPurge; ComRXPurge = wfComRXPurge; ComXONEnable = wfComXONEnable; ComXONDisable = wfComXONDisable; ComPutc = wfComPutc; ComBufferByte = wfComBufferByte; ComTxWait = wfComTxWait; ComRxWait = wfComRxWait; ComGetc = wfComGetc; ComPeek = wfComPeek; ComBreak = wfComBreak; ComWrite = wfComWrite; ComGetFH = wfComGetFH; ComPause = wfComPause; ComResume = wfComResume; com_getc = wfcom_getc; } } void stdComDTROn (HANDLE hcModem) { DWORD dwIgnore; ClearCommError (hcModem, &dwIgnore, NULL); if (!EscapeCommFunction (hcModem, SETDTR)) { status_line ("!SYS%08u: EscapeCommFunction(SETDTR)", GetLastError ()); exit (3); } } void stdComDTROff (HANDLE hcModem) { DWORD dwIgnore; ClearCommError (hcModem, &dwIgnore, NULL); if (!EscapeCommFunction (hcModem, CLRDTR)) { status_line ("!SYS%08u: EscapeCommFunction(CLRDTR)", GetLastError ()); exit (3); } } void stdComXONDisable (HANDLE hcModem) { DCB dcb; BOOL rc; DWORD dwIgnore; ClearCommError (hcModem, &dwIgnore, NULL); if (rc = GetCommState (hcModem, &dcb)) { dcb.fOutX = dcb.fInX = 0; SetCommState (hcModem, &dcb); ClearCommError (hcModem, &dwIgnore, NULL); } else { status_line ("!SYS%08u: GetCommState()", GetLastError ()); exit (3); } } void stdComXONEnable (HANDLE hcModem) { DCB dcb; BOOL rc; DWORD dwIgnore; ClearCommError (hcModem, &dwIgnore, NULL); if (rc = GetCommState (hcModem, &dcb)) { dcb.fOutX = dcb.fInX = 1; SetCommState (hcModem, &dcb); ClearCommError (hcModem, &dwIgnore, NULL); } else { status_line ("!SYS%08u: GetCommState()", GetLastError ()); exit (3); } } void stdComBreak (HANDLE hcModem, int on) { DWORD dwIgnore; if (on) SetCommBreak (hcModem); else ClearCommBreak (hcModem); ClearCommError (hcModem, &dwIgnore, NULL); } short stdComSetParms (HANDLE hcModem, ULONG rate) { DCB dcb; BOOL rc; DWORD dwIgnore; ClearCommError (hcModem, &dwIgnore, NULL); if (rc = GetCommState (hcModem, &dcb)) { dcb.ByteSize = (comm_bits == 3 /* BITS_8 */ )? 8 : 7; dcb.StopBits = (stop_bits == 4 /* STOP_2 */ )? TWOSTOPBITS : ONESTOPBIT; switch (parity) { case 0x08: /* ODD_PARITY */ dcb.Parity = ODDPARITY; break; case 0x18: /* EVEN_PARITY */ dcb.Parity = EVENPARITY; break; default: dcb.Parity = NOPARITY; break; } dcb.BaudRate = rate; SetCommState (hcModem, &dcb); SavedRate = rate; } else { status_line ("!SYS%08u: GetCommState()", GetLastError ()); exit (3); } return 1; } void stdComDeInit (HANDLE hcModem) { DWORD dwEventMask = 0; if (hcModem) { TerminateThread (hWatchThread, 1); DeleteCriticalSection (&csWatchThread); CloseHandle (hDCD); CloseHandle (hRXAvailable); stdComTXPurge (hcModem); stdComRXPurge (hcModem); CloseHandle (hcModem); CloseHandle (hRead); CloseHandle (hWrite); hcModem = 0; } } int stdcom_getc (int t) { long t1 = 0; if (fossil_count == 0) (void) stdComRxWaitEx (hcModem, (ULONG)(t * 1000), TRUE); return (fossil_count == 0 ? -1 : stdComGetc (hcModem)); } short stdComCarrier (HANDLE hcModem) { return fDCD; } int stdComGetFH (HANDLE hcModem) { return (int) hcModem; } unsigned short stdComGetc (HANDLE hcModem) { unsigned char c; if (fossil_count == 0) (void) stdComRxWait (hcModem, INFINITE); --fossil_count; c = (unsigned char) *fossil_fetch_pointer++; return ((unsigned short)c); } short stdComInCount (HANDLE hcModem) { (void) stdComRxWait (hcModem, 0L); return fossil_count; } short stdComOutCount (HANDLE hcModem) { /* Special case of stdComTxWait ... it's OK to return 0 if nothing is pending and 1 if anything is... */ if (fWriteWait) { DWORD dwWait = 0; dwWait = WaitForSingleObject (hWrite, 0L); if (dwWait == 0) { ResetEvent (hWrite); memset (&ovWrite, 0, sizeof (OVERLAPPED)); ovWrite.hEvent = hWrite; fWriteWait = FALSE; } else return 1; } if (out_count == 0) return 0; stdComWrite (hcModem, NULL, 0, 1); return stdComOutCount (hcModem); } short stdComOutSpace (HANDLE hcModem) { /* For now always say there is room. */ return 1; } int stdComPause (HANDLE hcModem) { DCB dcb; BOOL rc; FlushFileBuffers (hcModem); stdComRXPurge (hcModem); TerminateThread (hWatchThread, 1); hWatchThread = NULL; CloseHandle (hDCD); hDCD = NULL; CloseHandle (hRXAvailable); hRXAvailable = NULL; DeleteCriticalSection (&csWatchThread); if (rc = GetCommState (hcModem, &dcb)) { dcb.fBinary = 1; dcb.fParity = 0; dcb.fOutxCtsFlow = 1; dcb.fOutxDsrFlow = 0; dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fDsrSensitivity = 0; dcb.fTXContinueOnXoff = 0; dcb.fOutX = dcb.fInX = 0; dcb.fErrorChar = 0; dcb.fNull = 0; dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; dcb.fAbortOnError = 0; SetCommState (hcModem, &dcb); } return 0; } short stdComPeek (HANDLE hcModem) { unsigned char c; if (fossil_count == 0) { if (!stdComRxWait (hcModem, 0L)) return (unsigned short) -1; } c = (unsigned char) *fossil_fetch_pointer; return ((unsigned short) c); } void stdComTXPurge (HANDLE hcModem) { DWORD dwIgnore; PurgeComm (hcModem, PURGE_TXABORT | PURGE_TXCLEAR); ClearCommError (hcModem, &dwIgnore, NULL); out_send_pointer = out_buffer; out_count = 0; } void stdComRXPurge (HANDLE hcModem) { DWORD dwIgnore; PurgeComm (hcModem, PURGE_RXABORT | PURGE_RXCLEAR); ClearCommError (hcModem, &dwIgnore, NULL); fossil_fetch_pointer = fossil_buffer; fossil_count = 0; } int stdComResume (HANDLE hcModem) { DCB dcb; BOOL rc; SetupComm (hcModem, INBUF_SIZE, OUTBUF_SIZE); if (rc = GetCommState (hcModem, &dcb)) { dcb.fBinary = 1; dcb.fParity = 0; dcb.fOutxCtsFlow = 1; dcb.fOutxDsrFlow = 0; dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fDsrSensitivity = 0; dcb.fTXContinueOnXoff = 0; dcb.fOutX = dcb.fInX = 0; dcb.fErrorChar = 0; dcb.fNull = 0; dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; dcb.fAbortOnError = 0; dcb.XoffLim = INBUF_SIZE - 512; dcb.XonLim = 512; SetCommState (hcModem, &dcb); if (SavedRate) stdComSetParms (hcModem, SavedRate); EscapeCommFunction (hcModem, SETDTR); } else { status_line ("!SYS%08u: GetCommState()", GetLastError ()); exit (3); } if (hDCD == NULL) { hDCD = CreateEvent (NULL, TRUE, FALSE, NULL); if (hDCD == NULL) { status_line ("!SYS%08u: CreateEvent() (DCD)", GetLastError ()); exit (3); } } fRXAvailable = 1; if (hRXAvailable == NULL) { hRXAvailable = CreateEvent (NULL, TRUE, FALSE, NULL); if (hRXAvailable == NULL) { status_line ("!SYS%08u: CreateEvent() (receive)", GetLastError ()); exit (3); } } fTXEmpty = 1; if (hWatchThread == NULL) { InitializeCriticalSection (&csWatchThread); hWatchThread = CreateThread (NULL, 2048, stdComWatchProc, NULL, 0, &dwWatchThread); if (hWatchThread == NULL) { status_line ("!SYS%08u: CreateThread() (watch)", GetLastError ()); exit (3); } } return 1; } void stdComTxWait (HANDLE hcModem, ULONG interval) { if (fWriteWait) { DWORD dwWait; int iResult; if (out_count) dwWait = (FailSafeTimer ? FailSafeTimer : INFINITE); else dwWait = (FailSafeTimer ? min (FailSafeTimer, (interval * 10)) : interval * 10); iResult = stdComTxFinish (dwWait, 1); if (!iResult) return; } if (out_count == 0) return; stdComWrite (hcModem, NULL, 0, 1); } int stdComTxFinish (DWORD dwInterval, short sDCDCheck) { DWORD dwResult = 0; DWORD dwcWait; HANDLE rghWait[2]; rghWait[0] = hWrite; if (sDCDCheck) { rghWait[1] = hDCD; dwcWait = 2; } else dwcWait = 1; dwResult = WaitForMultipleObjects (dwcWait, rghWait, FALSE, dwInterval); /* Only "success" value is WAIT_OBJECT_0 */ if (dwResult == WAIT_OBJECT_0) { ResetEvent (hWrite); memset (&ovWrite, 0, sizeof (OVERLAPPED)); ovWrite.hEvent = hWrite; fWriteWait = FALSE; return 1; } /* For example, WAIT_TIMEOUT, WAIT_OBJECT_1 (DCD down) */ stdComTXPurge (hcModem); ResetEvent (hWrite); memset (&ovWrite, 0, sizeof (OVERLAPPED)); ovWrite.hEvent = hWrite; fWriteWait = FALSE; return 0; } int stdComRxWait (HANDLE hcModem, ULONG interval) { return stdComRxWaitEx (hcModem, interval, FALSE); } int stdComRxWaitEx (HANDLE hcModem, ULONG interval, BOOL fWatchDCD) { COMSTAT cst; DWORD dwCharsToRead; DWORD dwCharsRead; DWORD dwIgnore; DWORD dwcWait; HANDLE rghWait[2]; if (fossil_count != 0) return fossil_count; EnterCriticalSection (&csWatchThread); memset (&cst, 0, sizeof (COMSTAT)); ClearCommError (hcModem, &dwIgnore, &cst); dwCharsToRead = (cst.cbInQue > FOSSIL_BUFFER_SIZE ? FOSSIL_BUFFER_SIZE : cst.cbInQue); fRXAvailable = !!dwCharsToRead; if (!fRXAvailable) ResetEvent (hRXAvailable); LeaveCriticalSection (&csWatchThread); if (!fRXAvailable && interval) { rghWait[0] = hRXAvailable; if (fWatchDCD) { rghWait[1] = hDCD; dwcWait = 2; } else dwcWait = 1; (void) WaitForMultipleObjects (dwcWait, rghWait, FALSE, (DWORD)interval); if (fRXAvailable) { memset (&cst, 0, sizeof (COMSTAT)); ClearCommError (hcModem, &dwIgnore, &cst); dwCharsToRead = (cst.cbInQue > FOSSIL_BUFFER_SIZE ? FOSSIL_BUFFER_SIZE : cst.cbInQue); } } if (!dwCharsToRead) return 0; while (!ReadFile (hcModem, fossil_buffer, dwCharsToRead, &dwCharsRead, &ovRead)) { if (GetLastError () == ERROR_IO_PENDING) { dwIgnore = 0; dwIgnore = WaitForSingleObject (hRead, INFINITE); if (dwIgnore != 0) return 0; if (!GetOverlappedResult (hcModem, &ovRead, &dwCharsRead, FALSE)) return 0; break; } else { status_line ("!SYS%08u: ReadFile", GetLastError ()); ClearCommError (hcModem, &dwIgnore, NULL); } } ResetEvent (hRead); memset (&ovRead, 0, sizeof (OVERLAPPED)); ovRead.hEvent = hRead; fossil_fetch_pointer = fossil_buffer; fossil_count = dwCharsRead; return fossil_count; } short stdComPutc (HANDLE hcModem, byte c) { byte b = c; (void) stdComWrite (hcModem, &b, 1, 0); return 1; } short stdComBufferByte (HANDLE hcModem, byte c) { if (out_count == FOSSIL_BUFFER_SIZE) stdComWrite (hcModem, NULL, 0, 1); out_count++; *out_send_pointer++ = c; return 1; } void stdComWrite (HANDLE hcModem, void *buf, USHORT count, short dcdcheck) { /* Empty the fossil buffer before we proceed */ if (out_count) { (void) stdComWriteEx (hcModem, out_buffer, (USHORT)out_count, dcdcheck); out_send_pointer = out_buffer; out_count = 0; } /* Special case for code that's calling just to empty fossil buffer */ if (count == 0) return; stdComWriteEx (hcModem, buf, count, dcdcheck); return; } void stdComWriteEx (HANDLE hcModem, void *buf, USHORT count, short dcdcheck) { unsigned long cb; BOOL fResult; if (fWriteWait) { DWORD dwWait = (FailSafeTimer ? FailSafeTimer : INFINITE); int iResult; iResult = stdComTxFinish (dwWait, dcdcheck); if (!iResult) return; } fResult = WriteFile (hcModem, buf, count, &cb, &ovWrite); if (fResult == FALSE && GetLastError () == ERROR_IO_PENDING) fWriteWait = TRUE; return; } unsigned short stdCominit (int port, int failsafe) { DCB dcb; BOOL rc; SECURITY_ATTRIBUTES sa; COMMTIMEOUTS pct; /* Common to read stuff */ char tmp[5]; FailSafeTimer = failsafe; if (!hcModem) { sprintf (tmp, "com%1u", port + 1); sa.nLength = sizeof (sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; hcModem = CreateFile (tmp, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (hcModem == (HANDLE) 0xFFFFFFFF) { status_line ("!SYS%08u: CreateFile (%s)", GetLastError (), tmp); exit (3); } SetupComm (hcModem, INBUF_SIZE, OUTBUF_SIZE); if (rc = GetCommState (hcModem, &dcb)) { dcb.fBinary = 1; dcb.fParity = 0; dcb.fOutxCtsFlow = 1; dcb.fOutxDsrFlow = 0; dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fDsrSensitivity = 0; dcb.fTXContinueOnXoff = 0; dcb.fOutX = dcb.fInX = 0; dcb.fErrorChar = 0; dcb.fNull = 0; dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; dcb.fAbortOnError = 0; dcb.XoffLim = INBUF_SIZE - 512; dcb.XonLim = 512; SetCommState (hcModem, &dcb); EscapeCommFunction (hcModem, SETDTR); } else { status_line ("!SYS%08u: GetCommState()", GetLastError ()); exit (3); } hRead = CreateEvent (NULL, TRUE, TRUE, NULL); if (hRead == NULL) { status_line ("!SYS%08u: CreateEvent() (read)", GetLastError ()); exit (3); } memset (&ovRead, 0, sizeof (OVERLAPPED)); ovRead.hEvent = hRead; hWrite = CreateEvent (NULL, TRUE, TRUE, NULL); if (hWrite == NULL) { status_line ("!SYS%08u: CreateEvent() (write)", GetLastError ()); exit (3); } memset (&ovWrite, 0, sizeof (OVERLAPPED)); ovWrite.hEvent = hWrite; fWriteWait = FALSE; GetCommTimeouts (hcModem, &pct); pct.ReadIntervalTimeout = 10; pct.ReadTotalTimeoutMultiplier = 0; pct.ReadTotalTimeoutConstant = 500; pct.WriteTotalTimeoutMultiplier = 0; pct.WriteTotalTimeoutConstant = 60000; SetCommTimeouts (hcModem, &pct); fDCD = 0; hDCD = CreateEvent (NULL, TRUE, FALSE, NULL); if (hDCD == NULL) { status_line ("!SYS%08u: CreateEvent() (DCD)", GetLastError ()); exit (3); } fRXAvailable = 1; hRXAvailable = CreateEvent (NULL, TRUE, FALSE, NULL); if (hRXAvailable == NULL) { status_line ("!SYS%08u: CreateEvent() (receive)", GetLastError ()); exit (3); } fTXEmpty = 1; InitializeCriticalSection (&csWatchThread); hWatchThread = CreateThread (NULL, 2048, stdComWatchProc, NULL, 0, &dwWatchThread); if (hWatchThread == NULL) { status_line ("!SYS%08u: CreateThread() (watch)", GetLastError ()); exit (3); } } else stdComResume (hcModem); fossil_fetch_pointer = fossil_buffer; fossil_count = 0; out_send_pointer = out_buffer; out_count = 0; return (0x1954); } /* force transmitter to go */ void com_kick (void) { } DWORD FAR PASCAL stdComWatchProc (LPVOID nothing) { BOOL fResult; DWORD dwEventMask; DWORD dwModemStats; dwEventMask = (EV_RLSD | EV_RXCHAR | EV_TXEMPTY); SetCommMask (hcModem, dwEventMask); for (;;) { fResult = WaitCommEvent (hcModem, &dwEventMask, NULL); if (fResult == FALSE || dwEventMask == 0) break; if (dwEventMask & (EV_RLSD | EV_RXCHAR | EV_TXEMPTY)) { EnterCriticalSection (&csWatchThread); if (dwEventMask & EV_RLSD) { GetCommModemStatus (hcModem, &dwModemStats); fDCD = dwModemStats & MS_RLSD_ON ? 1 : 0; /* This is backwards for a reason */ if (fDCD) ResetEvent (hDCD); else SetEvent (hDCD); } if (dwEventMask & EV_RXCHAR) { fRXAvailable = 1; SetEvent (hRXAvailable); } if (dwEventMask & EV_TXEMPTY) fTXEmpty = 1; LeaveCriticalSection (&csWatchThread); } dwEventMask = 0; } return (FALSE); } /* ======================================================================== */ /* ======================================================================== */ /* == == */ /* == The following code was added by Bryan Woodruff to permit BT32 to == */ /* == use communications services provided by his WinFOSSIL driver, and == */ /* == to thereby allow BT32 to be the frontend for a DOS FOSSIL-based == */ /* == BBS system. == */ /* == == */ /* == Please contact Bryan at 1:343/294@fidonet for details. == */ /* == == */ /* ======================================================================== */ /* ======================================================================== */ BOOL WfControlWait ( HANDLE hFOSSIL, DWORD dwIoControlCode, PVOID pvIn, ULONG cbIn, PVOID pvOut, ULONG cbOut, PULONG pcbReturned ) { BOOL fResult ; fResult = DeviceIoControl( ((PFOSSIL_PORTINFO) hFOSSIL) -> hDevice, dwIoControlCode, pvIn, cbIn, pvOut, cbOut, pcbReturned, &((PFOSSIL_PORTINFO) hFOSSIL) -> ov ) ; if (!fResult) { if (ERROR_IO_PENDING == GetLastError()) { WaitForSingleObject( ((PFOSSIL_PORTINFO) hFOSSIL) -> ov.hEvent, INFINITE ) ; fResult = TRUE ; } else fResult = FALSE ; ResetEvent( ((PFOSSIL_PORTINFO) hFOSSIL) -> ov.hEvent ) ; } return fResult ; } void wfComDTROn ( HANDLE hFOSSIL ) { FOSSIL_CONTROL DeviceControl ; ULONG cbReturned ; DeviceControl.ulControl = FOSSIL_CONTROL_DTR ; DeviceControl.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ; DeviceControl.ulParam = 1 ; if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_CONTROL, &DeviceControl, sizeof( DeviceControl ), NULL, 0, &cbReturned )) { status_line ("!SYS%08u: WfControl(DTR-ON)", GetLastError()) ; exit (3) ; } } void wfComDTROff ( HANDLE hFOSSIL ) { FOSSIL_CONTROL DeviceControl ; ULONG cbReturned ; DeviceControl.ulControl = FOSSIL_CONTROL_DTR ; DeviceControl.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ; DeviceControl.ulParam = 0 ; if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_CONTROL, &DeviceControl, sizeof( DeviceControl ), NULL, 0, &cbReturned )) { status_line ("!SYS%08u: WfControl(DTR-OFF)", GetLastError()) ; exit (3) ; } } void wfComXONDisable ( HANDLE hFOSSIL ) { FOSSIL_CONTROL DeviceControl ; ULONG cbReturned ; DeviceControl.ulControl = FOSSIL_CONTROL_FLOWCTL ; DeviceControl.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ; DeviceControl.ulParam = FOSSIL_FLOWCTLF_RTSCTS ; if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_CONTROL, &DeviceControl, sizeof( DeviceControl ), NULL, 0, &cbReturned )) { status_line ("!SYS%08u: WfControl(DISABLEXON)", GetLastError()) ; exit (3) ; } } void wfComXONEnable ( HANDLE hFOSSIL ) { FOSSIL_CONTROL DeviceControl ; ULONG cbReturned ; DeviceControl.ulControl = FOSSIL_CONTROL_FLOWCTL ; DeviceControl.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ; DeviceControl.ulParam = FOSSIL_FLOWCTLF_RTSCTS | FOSSIL_FLOWCTLF_INX | FOSSIL_FLOWCTLF_OUTX ; if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_CONTROL, &DeviceControl, sizeof( DeviceControl ), NULL, 0, &cbReturned )) { status_line ("!SYS%08u: WfControl(ENABLEXON)", GetLastError()) ; exit (3) ; } } void wfComBreak( HANDLE hFOSSIL, int on ) { FOSSIL_CONTROL DeviceControl ; ULONG cbReturned ; DeviceControl.ulControl = FOSSIL_CONTROL_BREAK ; DeviceControl.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ; DeviceControl.ulParam = on ; if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_CONTROL, &DeviceControl, sizeof( DeviceControl ), NULL, 0, &cbReturned )) { status_line ("!SYS%08u: WfControl(BREAK)", GetLastError()) ; exit (3) ; } } short wfComSetParms ( HANDLE hFOSSIL, ULONG rate ) { FOSSIL_SETPARAMS SetParams ; ULONG cbReturned ; SetParams.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ; SetParams.ByteSize = (comm_bits == 3)? 8 : 7 ; SetParams.StopBits = (stop_bits == 4)? TWOSTOPBITS : ONESTOPBIT ; switch (parity) { case 0x08: SetParams.Parity = ODDPARITY ; break ; case 0x18: SetParams.Parity = EVENPARITY ; break ; default: SetParams.Parity = NOPARITY ; break ; } SetParams.BaudRate = rate; if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_SETPARAMS, &SetParams, sizeof( SetParams ), NULL, 0, &cbReturned )) { status_line ("!SYS%08u: WfControl(SETPARAMS)", GetLastError()) ; exit (3) ; } else SavedRate = rate ; return 1 ; } void wfComDeInit ( HANDLE hFOSSIL ) { ULONG cbReturned ; if (hFOSSIL) { wfComTXPurge( hFOSSIL ) ; wfComRXPurge( hFOSSIL ) ; if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_DEACTIVATE_PORT, &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId, sizeof( ULONG ), NULL, 0, &cbReturned )) { status_line ("!SYS%08u: WfControl(DEACTIVATEPORT)", GetLastError()) ; exit (3) ; } CloseHandle( ((PFOSSIL_PORTINFO) hFOSSIL) -> hDevice ) ; CloseHandle( ((PFOSSIL_PORTINFO) hFOSSIL) -> ov.hEvent ) ; HeapFree( GetProcessHeap(), 0, hFOSSIL ) ; hcModem = 0; } } int wfcom_getc ( int t ) { long t1 = 0 ; if (fossil_count == 0) { (void) wfComRxWait( hcModem, 0 ) ; while (fossil_count == 0) { if (!t1) t1 = timerset ((unsigned int) (t * 1000)); else if (timeup (t1)) { return (-1); } /* * This should work because we only do TIMED_READ when we have * carrier */ if (!wfComCarrier( hcModem )) { return (-1); } time_release (); (void) wfComRxWait( hcModem, 0 ) ; } } return wfComGetc( hcModem ) ; } int wfComGetFH( HANDLE hFOSSIL ) { return ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId + 1 ; } short wfComCarrier( HANDLE hFOSSIL ) { ULONG cbReturned, ulStatus ; if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_GETPORTSTATUS, &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId, sizeof( ULONG ), &ulStatus, sizeof( ULONG ), &cbReturned )) { status_line ("!SYS%08u: WfControl(SETDTR)", GetLastError()) ; exit (3) ; } return (SHORT)(ulStatus & FOSSIL_STATUSF_MS_RLSD_ON) ; } unsigned short wfComGetc ( HANDLE hFOSSIL ) { unsigned char c ; while (fossil_count == 0) { time_release() ; (void) wfComRxWait( hFOSSIL, 0 ) ; } --fossil_count ; c = (unsigned char) *fossil_fetch_pointer++ ; return ((unsigned short) c) ; } short wfComInCount ( HANDLE hFOSSIL ) { (void) wfComRxWait (hFOSSIL, 0L) ; return fossil_count ; } short wfComOutCount( HANDLE hFOSSIL ) { FOSSIL_INFORMATION Information ; ULONG cbReturned ; /* Special case of wfComTxWait ... it's OK to return 0 if nothing is pending and 1 if anything is... */ if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_GETPORTINFO, &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId, sizeof( ULONG ), &Information, sizeof( FOSSIL_INFORMATION ), &cbReturned )) { status_line ("!SYS%08u: WfControl(GETPORTINFO) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ) ; exit( 3 ) ; } if (Information.cbTransmitFree != Information.cbTransmitBuffer) return 1 ; if (out_count == 0) return 0 ; wfComWrite( hFOSSIL, NULL, 0, 1 ) ; return wfComOutCount (hFOSSIL); } short wfComOutSpace( HANDLE hFOSSIL ) { FOSSIL_INFORMATION Information ; ULONG cbReturned ; if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_GETPORTINFO, &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId, sizeof( ULONG ), &Information, sizeof( FOSSIL_INFORMATION ), &cbReturned )) { status_line ("!SYS%08u: WfControl(GETPORTINFO) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ) ; exit( 3 ) ; } return (short) Information.cbTransmitFree ; } int wfComPause ( HANDLE hFOSSIL ) { wfComRXPurge( hFOSSIL ) ; return 0 ; } short wfComPeek ( HANDLE hFOSSIL ) { unsigned char c ; if (fossil_count == 0) { if (!wfComRxWait( hFOSSIL, 0L )) return (unsigned short) -1 ; } c = (unsigned char) *fossil_fetch_pointer ; return ((unsigned short) c) ; } void wfComTXPurge ( HANDLE hFOSSIL ) { FOSSIL_CONTROL DeviceControl ; ULONG cbReturned ; DeviceControl.ulControl = FOSSIL_CONTROL_PURGE ; DeviceControl.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ; DeviceControl.ulParam = FOSSIL_PURGE_TRANSMIT ; if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_CONTROL, &DeviceControl, sizeof( DeviceControl ), NULL, 0, &cbReturned )) { status_line ("!SYS%08u: WfControl(PURGERX)", GetLastError()) ; exit (3) ; } out_send_pointer = out_buffer; out_count = 0; } void wfComRXPurge ( HANDLE hFOSSIL ) { FOSSIL_CONTROL DeviceControl ; ULONG cbReturned ; DeviceControl.ulControl = FOSSIL_CONTROL_PURGE ; DeviceControl.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ; DeviceControl.ulParam = FOSSIL_PURGE_RECEIVE ; if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_CONTROL, &DeviceControl, sizeof( DeviceControl ), NULL, 0, &cbReturned )) { status_line ("!SYS%08u: WfControl(PURGERX)", GetLastError()) ; exit (3) ; } fossil_fetch_pointer = fossil_buffer; fossil_count = 0; } int wfComResume ( HANDLE hFOSSIL ) { FOSSIL_INFORMATION Information ; ULONG cbReturned ; if (!hFOSSIL || !WfControlWait( hFOSSIL, IOCTL_FOSSIL_ACTIVATE_PORT, &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId, sizeof( ULONG ), &Information, sizeof( FOSSIL_INFORMATION ), &cbReturned ) || !cbReturned) { status_line ("!SYS%08u: WfControl(REACTIVATE) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ) ; exit( 3 ) ; } return 1 ; } void wfComTxWait ( HANDLE hFOSSIL, ULONG interval ) { DWORD dwWait, dwStarted ; FOSSIL_INFORMATION Information ; ULONG cbReturned ; /* // BryanW: // // This loop is TOTALLY inefficient... but WinFOSSIL doesn't // have the ability to signal threads yet. I'll fix this // in the next release. */ if (out_count) dwWait = (FailSafeTimer ? FailSafeTimer : 30000); else dwWait = (FailSafeTimer ? min (FailSafeTimer, (interval * 10)) : interval * 10); dwStarted = GetCurrentTime() ; do { if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_GETPORTINFO, &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId, sizeof( ULONG ), &Information, sizeof( FOSSIL_INFORMATION ), &cbReturned )) { status_line ("!SYS%08u: WfControl(GETPORTINFO) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ); exit( 3 ) ; } if (Information.cbTransmitFree >= (ULONG) out_count) break ; Sleep( 0 ) ; } while (GetCurrentTime() < (dwStarted + dwWait)) ; if (!out_count || (Information.cbTransmitFree < (ULONG) out_count)) return ; wfComWrite (hFOSSIL, NULL, 0, 1 ) ; } int wfComRxWait ( HANDLE hFOSSIL, ULONG interval ) { FOSSIL_INFORMATION Information ; FOSSIL_BUFFER Buffer ; ULONG cbRead, cbReturned ; if (fossil_count) return fossil_count ; if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_GETPORTINFO, &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId, sizeof( ULONG ), &Information, sizeof( FOSSIL_INFORMATION ), &cbReturned )) { status_line ("!SYS%08u: WfControl(GETPORTINFO) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ) ; exit( 3 ) ; } cbRead = Information.cbReceiveBuffer - Information.cbReceiveFree ; if (!cbRead) return 0 ; Buffer.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ; Buffer.pchBuffer = fossil_buffer ; Buffer.cbBuffer = min( cbRead, FOSSIL_BUFFER_SIZE ) ; if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_BLOCKRECV, &Buffer, sizeof( Buffer ), &cbRead, sizeof( ULONG ), &cbReturned )) { status_line ("!SYS%08u: WfControl(BLOCKRECV) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ) ; exit( 3 ) ; } fossil_fetch_pointer = fossil_buffer; fossil_count = cbRead ; return fossil_count ; } short wfComPutc ( HANDLE hFOSSIL, byte c ) { byte b = c ; wfComWrite( hFOSSIL, &b, 1, 0 ) ; return 1; } short wfComBufferByte ( HANDLE hFOSSIL, byte c ) { if (out_count == FOSSIL_BUFFER_SIZE) wfComWrite( hFOSSIL, NULL, 0, 1 ) ; out_count++ ; *out_send_pointer++ = c ; return 1 ; } void wfComWriteEx ( HANDLE hFOSSIL, void *pvBuffer, USHORT cbBuffer, short fWatchCD ) { DWORD dwStarted ; FOSSIL_BUFFER Buffer ; FOSSIL_INFORMATION Information ; ULONG cbReturned, cbWrote, ulWait ; /* // This loop is TOTALLY inefficient... but WinFOSSIL doesn't // have the ability to signal threads yet. I'll fix this // in the next release. */ ulWait = (FailSafeTimer ? FailSafeTimer : 30000); dwStarted = GetCurrentTime() ; do { if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_GETPORTINFO, &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId, sizeof( ULONG ), &Information, sizeof( FOSSIL_INFORMATION ), &cbReturned )) { status_line ("!SYS%08u: WfControl(GETPORTINFO) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ) ; exit( 3 ) ; } if (Information.cbTransmitFree >= (ULONG) cbBuffer) break ; Sleep( 0 ) ; } while (GetCurrentTime() < (dwStarted + ulWait)) ; if (!cbBuffer || (Information.cbTransmitFree < (ULONG) cbBuffer)) return ; while (cbBuffer) { Buffer.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ; Buffer.pchBuffer = pvBuffer ; Buffer.cbBuffer = cbBuffer ; if (!WfControlWait( hFOSSIL, IOCTL_FOSSIL_BLOCKXMIT, &Buffer, sizeof( Buffer ), &cbWrote, sizeof( ULONG ), &cbReturned )) { status_line( "!SYS%08u: WfControl(BLOCKXMIT) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ) ; exit( 3 ) ; } cbBuffer -= (USHORT) cbWrote ; } } void wfComWrite ( HANDLE hFOSSIL, void *pvBuffer, USHORT cbBuffer, short fWatchCD ) { if (out_count) { wfComWriteEx( hFOSSIL, out_buffer, (USHORT) out_count, fWatchCD ) ; out_send_pointer = out_buffer; out_count = 0; } if (!cbBuffer) return ; wfComWriteEx( hFOSSIL, pvBuffer, cbBuffer, fWatchCD ) ; return ; } unsigned short wfCominit ( int port, int failsafe ) { FOSSIL_INFORMATION Information ; ULONG cbReturned, ulId = port ; FailSafeTimer = failsafe; hcModem = (HANDLE) HeapAlloc( GetProcessHeap(), 0, sizeof( FOSSIL_PORTINFO ) ) ; ((PFOSSIL_PORTINFO) hcModem) -> hDevice = CreateFile( "\\\\.\\FOSSIL", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL ) ; if (((PFOSSIL_PORTINFO) hcModem) -> hDevice == (HANDLE) -1) { status_line ("!SYS%08u: CreateFile 'FOSSIL'", GetLastError() ) ; exit( 3 ) ; } RtlZeroMemory( &((PFOSSIL_PORTINFO) hcModem) -> ov, sizeof( OVERLAPPED ) ) ; if (NULL == ( ((PFOSSIL_PORTINFO) hcModem) -> ov.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ))) { status_line ("!SYS%08u: CreateEvent", GetLastError() ) ; exit( 3 ) ; } ((PFOSSIL_PORTINFO) hcModem) -> ulPortId = ulId ; if (!WfControlWait( hcModem, IOCTL_FOSSIL_ACTIVATE_PORT, &ulId, sizeof( ULONG ), &Information, sizeof( FOSSIL_INFORMATION ), &cbReturned )) { status_line ("!SYS%08u: WfControl(ACTIVATEPORT) (%d)", GetLastError(), ulId ) ; exit( 3 ) ; } fossil_fetch_pointer = fossil_buffer; fossil_count = 0; out_send_pointer = out_buffer; out_count = 0; return( (Information.wSignature == 0x4257) ? 0x1954 : 0 ) ; } #endif /* _WIN32 */