NT4/private/unimodem/tapisp/mcxrw.c
2020-09-30 17:12:29 +02:00

650 lines
15 KiB
C

/******************************************************************************
(C) Copyright MICROSOFT Corp., 1987-1993
Rob Williams, June 93 w/ State machine and parser plagarized from RAS
******************************************************************************/
#include "unimdm.h"
#include "mcxp.h"
#include <devioctl.h>
#include <ntddmodm.h>
BOOL WINAPI
CreateDeferedWorkItem(
MODEMINFORMATION * pModemInfo
)
{
LPOVERNODE pNode;
BOOL bResult;
pNode=(LPOVERNODE)OverPoolAlloc(++pModemInfo->mi_dwDeferedExpected, 1);
if (pNode == NULL) {
return FALSE;
}
pNode->Type=OVERNODE_TYPE_WORKITEM;
bResult=PostQueuedCompletionStatus(
ghCompletionPort,
0,
pModemInfo->mi_dwCompletionKey,
&pNode->overlapped
);
if (!bResult) {
OverPoolFree((LPOVERLAPPED)pNode);
}
return bResult;
}
//****************************************************************************
//DWORD ModemWrite (MODEMINFORMATION * pModemInfo, LPBYTE lpBuf,
// DWORD cbWrite, LPDWORD lpcbWritten, DWORD dwTimeout)
//
// Function: Write a string to the modem. Always perform asynchronously,
// even if WriteFile finishes synchronously.
//
// Returns: MODEM_PENDING if pending
// MODEM_FAILURE if fails
// (Never returns MODEM_SUCCESS)
//
// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont]
// created
//****************************************************************************
DWORD ModemWrite (MODEMINFORMATION * pModemInfo, LPBYTE lpBuf,
DWORD cbWrite, LPDWORD lpcbWritten, DWORD dwTimeout)
{
COMMTIMEOUTS commtimeout;
DWORD dwResult;
LPOVERNODE pNode;
// MCXPRINTF("ModemWrite");
ASSERT(pModemInfo->mi_lpOverlappedRW == NULL);
// Set timeout
//
commtimeout.ReadIntervalTimeout = 0;
commtimeout.ReadTotalTimeoutMultiplier = 0;
commtimeout.ReadTotalTimeoutConstant = 0;
commtimeout.WriteTotalTimeoutMultiplier= 0;
commtimeout.WriteTotalTimeoutConstant = dwTimeout;
SetCommTimeouts(pModemInfo->mi_PortHandle, &commtimeout);
pNode=(LPOVERNODE)OverPoolAlloc(++pModemInfo->mi_dwRWIOExpected, 1);
if (pNode == NULL) {
dwResult = MODEM_FAILURE;
}
else
{
SET_OVERNODE_TYPE(pNode,OVERNODE_TYPE_READWRITE);
// Make the asynchronous write call
//
if (WriteFile(pModemInfo->mi_PortHandle, lpBuf, cbWrite, lpcbWritten,
&pNode->overlapped))
{
dwResult = MODEM_PENDING; // I/O will show up on the completion port
}
else
{
// Determine the result
//
dwResult = GetLastError();
if (dwResult == ERROR_IO_PENDING)
{
dwResult = MODEM_PENDING;
}
else
{
OverPoolFree((LPOVERLAPPED)pNode);
pNode=NULL;
dwResult = MODEM_FAILURE;
};
};
}
pModemInfo->mi_lpOverlappedRW=pNode;
return dwResult;
}
//****************************************************************************
//DWORD ModemRead (MODEMINFORMATION * pModemInfo, LPBYTE lpBuf,
// DWORD cbRead, LPDWORD lpcbRead, DWORD dwTimeout)
//
// Function: Read a string from the modem Always perform asynchronously,
// even if ReadFile finishes synchronously.
//
// Returns: MODEM_PENDING if pending
// MODEM_FAILURE if fails
// (Never returns MODEM_SUCCESS)
//
// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont]
// created
//****************************************************************************
DWORD ModemRead (MODEMINFORMATION * pModemInfo, LPBYTE lpBuf,
DWORD cbRead, LPDWORD lpcbRead, DWORD dwTimeout)
{
COMMTIMEOUTS commtimeout;
DWORD dwResult;
LPOVERNODE pNode;
// MCXPRINTF("ModemRead");
ASSERT(pModemInfo->mi_lpOverlappedRW == NULL);
// Set timeout
//
commtimeout.ReadIntervalTimeout = 0;
commtimeout.ReadTotalTimeoutMultiplier = 0;
commtimeout.ReadTotalTimeoutConstant = dwTimeout;
commtimeout.WriteTotalTimeoutMultiplier= 0;
commtimeout.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(pModemInfo->mi_PortHandle, &commtimeout);
pNode=(LPOVERNODE)OverPoolAlloc(++pModemInfo->mi_dwRWIOExpected, 1);
if (pNode == NULL) {
dwResult = MODEM_FAILURE;
}
else
{
SET_OVERNODE_TYPE(pNode,OVERNODE_TYPE_READWRITE);
// Make the asynchronous write call
//
if (ReadFile(pModemInfo->mi_PortHandle, lpBuf, cbRead, lpcbRead,
&pNode->overlapped))
{
dwResult = MODEM_PENDING; // I/O will show up on the completion port
}
else
{
// Determine the result
//
dwResult = GetLastError();
if (dwResult == ERROR_IO_PENDING)
{
dwResult = MODEM_PENDING;
}
else
{
OverPoolFree((LPOVERLAPPED)pNode);
pNode=NULL;
dwResult = MODEM_FAILURE;
};
};
}
pModemInfo->mi_lpOverlappedRW=pNode;
return dwResult;
}
//****************************************************************************
// DWORD ModemRWAsyncComplete (MODEMINFORMATION * pModemInfo, LPDWORD lpcb)
//
// Function: Complete the asynchronous read/write operation
//
// Returns: MODEM_SUCCESS if success
// MODEM_PENDING if pending
// MODEM_FAILURE if fails
//
// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont]
// created
//****************************************************************************
DWORD ModemRWAsyncComplete (MODEMINFORMATION * pModemInfo, LPDWORD lpcb)
{
DWORD dwRet;
if (pModemInfo->mi_lpOverlappedRW == NULL) {
*lpcb = 0;
return MODEM_FAILURE;
}
// Has all of the write buffer been emptied?
if (GetOverlappedResult(pModemInfo->mi_PortHandle,
&pModemInfo->mi_lpOverlappedRW->overlapped,
lpcb,
FALSE))
{
// Very Funny!! sometimes GetOverlappedResult returns success but nothing
// was written nor read. In this case it should mean timeout.
//
if (*lpcb)
{
dwRet = MODEM_SUCCESS;
}
else
{
dwRet = MODEM_PENDING;
};
}
else
{
if (GetLastError() == ERROR_IO_INCOMPLETE)
{
dwRet = MODEM_PENDING;
}
else
{
dwRet = MODEM_FAILURE;
};
};
pModemInfo->mi_lpOverlappedRW=NULL;
return dwRet;
}
//****************************************************************************
//DWORD ModemWaitEvent (MODEMINFORMATION * pModemInfo, DWORD dwEvent,
// DWORD dwTimeout)
//
// Function: Monitor the modem's control signal
//
// Returns: MODEM_SUCCESS if the control is signalled
// MODEM_PENDING if the control line is being monitored
// MODEM_FAILURE if fails
//
// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont]
// created
//****************************************************************************
DWORD ModemWaitEvent (MODEMINFORMATION * pModemInfo, DWORD dwEvent,
DWORD dwTimeOut)
{
DWORD dwWaitEvent;
DWORD dwResult;
LPOVERNODE pNode;
MCXPRINTF("ModemWaitEvent");
ASSERT(dwTimeOut<GTC_MAXDELTA);
ASSERT(pModemInfo->mi_lpOverlappedEvent == NULL);
// Make the asynchronous wait call
//
SetCommMask(pModemInfo->mi_PortHandle, dwEvent);
pModemInfo->mi_waitEvent = dwEvent;
pNode=(LPOVERNODE)OverPoolAlloc(++pModemInfo->mi_dwEventIOExpected,
dwTimeOut ? 2 : 1);
if (pNode == NULL) {
dwResult = MODEM_FAILURE;
}
else
{
SET_OVERNODE_TYPE(pNode,OVERNODE_TYPE_COMMEVENT);
pNode->CommEvent=0;
if (WaitCommEvent(pModemInfo->mi_PortHandle, &pNode->CommEvent,
&pNode->overlapped))
{
MCXPRINTF1("WaitCommEvent returned TRUE! Returning PENDING anyways.%08lx",pNode->overlapped.Internal);
dwResult = MODEM_PENDING; // The event will be signaled.
}
else
{
// Determine the result
//
dwResult = GetLastError();
if (dwResult == ERROR_IO_PENDING)
{
if (dwTimeOut)
{
// Mark the timeout
//
GTC_AequalsBplusC(pModemInfo->mi_timeout, GETTICKCOUNT(),dwTimeOut);
if (SetMdmTimer(pModemInfo->mi_dwCompletionKey,
&pNode->overlapped,
dwTimeOut) == ERROR_SUCCESS)
{
MCXPRINTF2("SET_TIMEOUT (%d ms dtr droppage) @%d",
dwTimeOut, GETTICKCOUNT());
}
else
{
MCXPRINTF("SetMdmTimer did not return ERROR_SUCCESS");
pModemInfo->mi_timeout=GETTICKCOUNT();
SetCommMask(pModemInfo->mi_PortHandle, 0);
PostQueuedCompletionStatus(ghCompletionPort,
0,
pModemInfo->mi_dwCompletionKey,
&pNode->overlapped);
};
};
dwResult = MODEM_PENDING;
}
else
{
OverPoolFree((LPOVERLAPPED)pNode);
if (dwTimeOut) {
// Free it twice because the reference count was 2.
//
OverPoolFree((LPOVERLAPPED)pNode);
}
pNode=NULL;
MCXPRINTF1("GetLastError() in ModemWaitEvent returned %ld", dwResult);
dwResult = MODEM_FAILURE;
};
};
}
MCXPRINTF3("ModemWaitEvent returned %ld, id=%d, %08lx", dwResult,pNode ? pNode->dwToken : (DWORD)-1 , pNode);
pModemInfo->mi_lpOverlappedEvent=pNode;
return dwResult;
}
//****************************************************************************
// DWORD ModemWaitEventComplete (MODEMINFORMATION * pModemInfo)
//
// Function: Complete the asynchronous wait-event operation
//
// Returns: MODEM_SUCCESS if success
//
// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont]
// created
//****************************************************************************
DWORD WINAPI
ModemWaitEventComplete(
MODEMINFORMATION * pModemInfo,
LPOVERNODE pNode
)
{
// If we are not waiting for an event, return failure
//
if (pModemInfo->mi_lpOverlappedEvent != pNode) {
MCXPRINTF("ModemWaitEventComplete returning failure 1.");
return MODEM_FAILURE;
}
pModemInfo->mi_lpOverlappedEvent=NULL;
if ((pNode->CommEvent & pModemInfo->mi_waitEvent) || (pModemInfo->mi_waitEvent == 0))
{
// Disable HW detection
//
SetCommMask(pModemInfo->mi_PortHandle, 0L);
// If we have a timer pending, clear timer
//
if (pModemInfo->mi_timeout)
{
pModemInfo->mi_timeout = 0;
if (KillMdmTimer(pModemInfo->mi_dwCompletionKey,
(LPOVERLAPPED)pNode) == TRUE)
{
OverPoolFree((LPOVERLAPPED)pNode);
}
};
return MODEM_SUCCESS;
}
else
{
// We may have a timeout
//
if (pModemInfo->mi_timeout)
{
DWORD tcNow = GETTICKCOUNT();
if (GTC_AleB(pModemInfo->mi_timeout, tcNow))
{
// Timeout expired
pModemInfo->mi_timeout = 0;
MCXPRINTF1("HW timeout expired @%d.", GetTickCount());
// Disable HW detection
//
SetCommMask(pModemInfo->mi_PortHandle, 0L);
return MODEM_PENDING;
}
else
{
// We got an event that we did not want, We will just return success,
// to keep things from hanging, and hope for the best. This should no happen.
//
// Kill the timer too
//
#ifdef DEBUG
{
DWORD RealMask;
GetCommMask(
pModemInfo->mi_PortHandle,
&RealMask
);
MCXPRINTF2("ModemWaitEventComplete: got unexpected event (signalEvent = %d, mask=%d).",
pNode->CommEvent,RealMask);
// LogPrintf(pModemInfo->mi_hLogFile, pModemInfo->mi_dwID,
// "ModemWaitEventComplete: got unexpected event (signalEvent = %d, mask=%d).\n",
// pNode->CommEvent,RealMask);
// ASSERT(0);
}
#endif
SetCommMask(pModemInfo->mi_PortHandle, 0L);
// If we have a timer pending, clear timer
//
pModemInfo->mi_timeout = 0;
if (KillMdmTimer(pModemInfo->mi_dwCompletionKey,
(LPOVERLAPPED)pNode) == TRUE)
{
OverPoolFree((LPOVERLAPPED)pNode);
}
return MODEM_PENDING;
};
}
else
{
// We should not be here at all.
// Disable HW detection so we do not get a spurious event and
// get stuck in a infinite loop
//
SetCommMask(pModemInfo->mi_PortHandle, 0L);
MCXPRINTF("ModemWaitEventComplete returning failure 3.");
return MODEM_FAILURE;
};
};
}
BOOL WINAPI
CurrentlyWaitingForCommEvent(
MODEMINFORMATION * pModemInfo
)
{
return (pModemInfo->mi_lpOverlappedEvent != NULL);
}
//****************************************************************************
// VOID ModemSetPassthrough (MODEMINFORMATION * pModemInfo,
// DWORD dwMode)
//
// Function: Sets the device driver passthrough mode.
//
// Input: dwMode can be one of:
// MODEM_NOPASSTHROUGH
// MODEM_PASSTHROUGH
// MODEM_DCDSNIFF
//
// Returns: nothing. always assumed to succeed
//
// Fri 13-Oct-1995 18:11:26 -by- Chris Caputo [ccaputo]
// created
//****************************************************************************
#if 0
VOID ModemSetPassthrough (MODEMINFORMATION * pModemInfo,
DWORD dwMode)
{
DWORD dwBytesReturned;
if (FALSE == DeviceIoControl(pModemInfo->mi_PortHandle,
IOCTL_MODEM_SET_PASSTHROUGH,
&dwMode,
sizeof(dwMode),
NULL,
0,
&dwBytesReturned,
NULL))
{
MCXPRINTF1("SET_PASSTHROUGH - %s - failed.", dwMode == MODEM_NOPASSTHROUGH ?
"NOPASSTHROUGH" :
dwMode == MODEM_PASSTHROUGH ?
"PASSTHROUGH" :
dwMode == MODEM_DCDSNIFF ?
"DCDSNIFF" :
"INVALID_SETTING");
MCXPRINTF1("DevioceIoControl(IOCTL_SET_PASSTHROUGH) returned %d",
GetLastError());
MCXPRINTF1("pModemInfo->mi_PortHandle = %d", pModemInfo->mi_PortHandle);
ASSERT(0);
}
else
{
MCXPRINTF1("SET_PASSTHROUGH - %s - worked.", dwMode == MODEM_NOPASSTHROUGH ?
"NOPASSTHROUGH" :
dwMode == MODEM_PASSTHROUGH ?
"PASSTHROUGH" :
dwMode == MODEM_DCDSNIFF ?
"DCDSNIFF" :
"INVALID_SETTING");
}
}
#endif
VOID WINAPI
ModemSetPassthrough (
MODEMINFORMATION * pModemInfo,
DWORD dwMode
)
{
DWORD BytesWritten;
OVERLAPPED OverLapped;
BOOL bResult;
OverLapped.hEvent=(HANDLE)((DWORD)pModemInfo->mi_SyncReadEvent | 1);
bResult=DeviceIoControl(
pModemInfo->mi_PortHandle,
IOCTL_MODEM_SET_PASSTHROUGH,
&dwMode,
sizeof(dwMode),
NULL,
0,
&BytesWritten,
NULL
);
if (!bResult) {
if (GetLastError() == ERROR_IO_PENDING) {
//
// pending
//
bResult=GetOverlappedResult(
pModemInfo->mi_PortHandle,
&OverLapped,
&BytesWritten,
TRUE
);
}
}
if (bResult) {
MCXPRINTF1("SET_PASSTHROUGH - %s - worked.", dwMode == MODEM_NOPASSTHROUGH ?
"NOPASSTHROUGH" :
dwMode == MODEM_PASSTHROUGH ?
"PASSTHROUGH" :
dwMode == MODEM_DCDSNIFF ?
"DCDSNIFF" :
"INVALID_SETTING");
} else {
MCXPRINTF1("SET_PASSTHROUGH - %s - failed.", dwMode == MODEM_NOPASSTHROUGH ?
"NOPASSTHROUGH" :
dwMode == MODEM_PASSTHROUGH ?
"PASSTHROUGH" :
dwMode == MODEM_DCDSNIFF ?
"DCDSNIFF" :
"INVALID_SETTING");
MCXPRINTF1("DevioceIoControl(IOCTL_SET_PASSTHROUGH) returned %d",
GetLastError());
MCXPRINTF1("pModemInfo->mi_PortHandle = %d", pModemInfo->mi_PortHandle);
ASSERT(0);
}
return ;
}