You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2088 lines
55 KiB
2088 lines
55 KiB
//****************************************************************************
|
|
//
|
|
// Microsoft NT Remote Access Service
|
|
//
|
|
// Copyright (C) 1992-93 Microsft Corporation. All rights reserved.
|
|
//
|
|
// Filename: serial.c
|
|
//
|
|
// Revision History
|
|
//
|
|
// Sep 3, 1992 J. Perry Hannah Created
|
|
//
|
|
//
|
|
// Description: This file contains all entry points for SERIAL.DLL
|
|
// which is the media DLL for serial ports.
|
|
//
|
|
//****************************************************************************
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#include <rasman.h>
|
|
#include <raserror.h>
|
|
#include <rasfile.h>
|
|
#include <mprlog.h>
|
|
#include <rtutils.h>
|
|
#include <rasmxs.h>
|
|
|
|
#include <wanpub.h>
|
|
#include <asyncpub.h>
|
|
|
|
#include <media.h>
|
|
#include <serial.h>
|
|
#include <serialpr.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <malloc.h>
|
|
#include <string.h>
|
|
|
|
|
|
|
|
//* Global Variables *******************************************************
|
|
//
|
|
|
|
SERIALPCB *gpSerialPCB; // Points to Serial PCB linked list
|
|
HANDLE ghRasfileMutex; // Mutex used to protect access to Rasfile
|
|
|
|
HRASFILE ghIniFile; // Handle to Serial.ini memory image
|
|
HANDLE ghAsyMac; // Handle to AsyncMac driver
|
|
DWORD gLastError;
|
|
|
|
|
|
//* Prototypes For APIs That Are Called Internally *************************
|
|
//
|
|
|
|
DWORD PortClearStatistics(HANDLE hIOPort);
|
|
|
|
OVERLAPPED overlapped ;
|
|
|
|
|
|
//* Initialization Routine *************************************************
|
|
//
|
|
|
|
//* SerialDllEntryPoint
|
|
//
|
|
// Function: Initializes Serial DLL when the DLL is loaded into memory,
|
|
// and cleans up when the last process detaches from the DLL.
|
|
//
|
|
// Returns: TRUE if successful, else FALSE.
|
|
//
|
|
//*
|
|
|
|
BOOL APIENTRY
|
|
SerialDllEntryPoint(HANDLE hDll, DWORD dwReason, LPVOID pReserved)
|
|
{
|
|
static BOOL bFirstCall = TRUE;
|
|
|
|
char szIniFilePath[MAX_PATH];
|
|
WCHAR szDriverName[] = ASYNCMAC_FILENAME;
|
|
|
|
|
|
DebugPrintf(("SerialDllEntryPoint\n"));
|
|
//DbgPrint("SerialDllEntryPoint\n");
|
|
|
|
switch(dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
|
|
if (bFirstCall)
|
|
{
|
|
DebugPrintf(("\tProcess Attach.\n"));
|
|
|
|
|
|
// Open Serial.ini file
|
|
*szIniFilePath = '\0';
|
|
GetIniFileName(szIniFilePath, sizeof(szIniFilePath));
|
|
ghIniFile = RasfileLoad(szIniFilePath, RFM_READONLY, NULL, NULL);
|
|
|
|
DebugPrintf(("INI: %s, ghIniFile: 0x%08x\n", szIniFilePath, ghIniFile));
|
|
|
|
/*
|
|
if (ghIniFile == INVALID_HRASFILE)
|
|
{
|
|
LogError(ROUTERLOG_CANNOT_OPEN_SERIAL_INI, 0, NULL, 0xffffffff);
|
|
return(FALSE);
|
|
} */
|
|
|
|
if ((ghRasfileMutex = CreateMutex (NULL,FALSE,NULL)) == NULL)
|
|
return FALSE ;
|
|
|
|
|
|
|
|
// Get handle to Asyncmac driver
|
|
/*
|
|
ghAsyMac = CreateFileW(szDriverName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, //No security attribs
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
|
NULL); //No template file
|
|
|
|
DebugPrintf(("ghAsyMac: 0x%08x\n", ghAsyMac));
|
|
|
|
if (ghAsyMac == INVALID_HANDLE_VALUE)
|
|
{
|
|
DebugPrintf(("CreateFileError: %d\n", GetLastError()));
|
|
|
|
LogError(ROUTERLOG_CANNOT_GET_ASYNCMAC_HANDLE, 0, NULL, 0xffffffff);
|
|
return(FALSE);
|
|
} */
|
|
|
|
bFirstCall = FALSE;
|
|
}
|
|
break;
|
|
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
DebugPrintf(("\tProcess Detach.\n"));
|
|
if(INVALID_HANDLE_VALUE != ghRasfileMutex
|
|
&& NULL != ghRasfileMutex)
|
|
{
|
|
CloseHandle(ghRasfileMutex);
|
|
ghRasfileMutex = INVALID_HANDLE_VALUE;
|
|
}
|
|
break;
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
DebugPrintf(("\tThread Attach.\n"));
|
|
break;
|
|
|
|
case DLL_THREAD_DETACH:
|
|
DebugPrintf(("\tThread Detach.\n"));
|
|
break;
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
UNREFERENCED_PARAMETER(hDll);
|
|
UNREFERENCED_PARAMETER(pReserved);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//* Serial APIs ************************************************************
|
|
//
|
|
|
|
|
|
//* PortEnum ---------------------------------------------------------------
|
|
//
|
|
// Function: This API returns a buffer containing a PortMediaInfo struct.
|
|
//
|
|
// Returns: SUCCESS
|
|
// ERROR_BUFFER_TOO_SMALL
|
|
// ERROR_READING_SECTIONNAME
|
|
// ERROR_READING_DEVICETYPE
|
|
// ERROR_READING_DEVICENAME
|
|
// ERROR_READING_USAGE
|
|
// ERROR_BAD_USAGE_IN_INI_FILE
|
|
//
|
|
//*
|
|
|
|
DWORD APIENTRY
|
|
PortEnum(BYTE *pBuffer, DWORD *pdwSize, DWORD *pdwNumPorts)
|
|
{
|
|
DWORD dwAvailable;
|
|
TCHAR szUsage[RAS_MAXLINEBUFLEN];
|
|
CHAR szMacName[MAC_NAME_SIZE] ;
|
|
PortMediaInfo *pPMI;
|
|
BYTE buffer [1000] ;
|
|
DWORD dwBytesReturned;
|
|
TCHAR *pszBuffer = NULL;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
memset (&overlapped, 0, sizeof (OVERLAPPED)) ;
|
|
|
|
DebugPrintf(("PortEnum\n"));
|
|
|
|
|
|
// Count number of sections in serial.ini
|
|
|
|
*pdwNumPorts = 0;
|
|
|
|
// Begin Exclusion
|
|
|
|
WaitForSingleObject(ghRasfileMutex, INFINITE);
|
|
|
|
if ( INVALID_HRASFILE != ghIniFile
|
|
&& RasfileFindFirstLine(ghIniFile, RFL_SECTION, RFS_FILE))
|
|
(*pdwNumPorts)++;
|
|
else
|
|
{
|
|
*pdwSize = 0;
|
|
|
|
// End Exclusion
|
|
|
|
ReleaseMutex(ghRasfileMutex);
|
|
return(SUCCESS);
|
|
}
|
|
|
|
while(RasfileFindNextLine(ghIniFile, RFL_SECTION, RFS_FILE))
|
|
(*pdwNumPorts)++;
|
|
|
|
// End Exclusion
|
|
|
|
ReleaseMutex(ghRasfileMutex);
|
|
|
|
|
|
// Calculate size of buffer needed
|
|
|
|
dwAvailable = *pdwSize;
|
|
*pdwSize = sizeof(PortMediaInfo) * (*pdwNumPorts);
|
|
if (*pdwSize > dwAvailable)
|
|
return(ERROR_BUFFER_TOO_SMALL);
|
|
|
|
|
|
// Translate serial.ini file section by section into pBuffer
|
|
|
|
pPMI = (PortMediaInfo *) pBuffer;
|
|
|
|
// Begin Exclusion
|
|
|
|
WaitForSingleObject(ghRasfileMutex, INFINITE);
|
|
|
|
RasfileFindFirstLine(ghIniFile, RFL_SECTION, RFS_FILE);
|
|
|
|
#if 0
|
|
// Need to get the MAC name
|
|
|
|
if (!DeviceIoControl(ghAsyMac,
|
|
IOCTL_ASYMAC_ENUM,
|
|
buffer,
|
|
sizeof(buffer),
|
|
buffer,
|
|
sizeof(buffer),
|
|
&dwBytesReturned,
|
|
&overlapped))
|
|
{
|
|
// End Exclusion
|
|
|
|
ReleaseMutex(ghRasfileMutex);
|
|
return(GetLastError());
|
|
}
|
|
|
|
wcstombs(szMacName, ((PASYMAC_ENUM)buffer)->AdapterInfo[0].MacName,
|
|
wcslen(((PASYMAC_ENUM)buffer)->AdapterInfo[0].MacName)+1) ;
|
|
|
|
#else
|
|
szMacName[0] = '\0' ;
|
|
#endif
|
|
|
|
pszBuffer = LocalAlloc(LPTR, RAS_MAXLINEBUFLEN);
|
|
if(NULL == pszBuffer)
|
|
{
|
|
ReleaseMutex(ghRasfileMutex);
|
|
return GetLastError();
|
|
}
|
|
|
|
|
|
|
|
do
|
|
{
|
|
// Get Section Name (same as Port Name)
|
|
|
|
if (!RasfileGetSectionName(ghIniFile, pPMI->PMI_Name))
|
|
{
|
|
// End Exclusion
|
|
|
|
ReleaseMutex(ghRasfileMutex);
|
|
dwErr = ERROR_READING_SECTIONNAME;
|
|
break;
|
|
}
|
|
|
|
|
|
// Set Binding Name
|
|
|
|
strcpy (pPMI->PMI_MacBindingName, szMacName) ;
|
|
|
|
|
|
// Get Device Type
|
|
|
|
if(!(RasfileFindNextKeyLine(ghIniFile, SER_DEVICETYPE_KEY, RFS_SECTION) &&
|
|
RasfileGetKeyValueFields(ghIniFile, NULL, pszBuffer/* pPMI->PMI_DeviceType*/)))
|
|
{
|
|
// End Exclusion
|
|
CopyMemory(pPMI->PMI_DeviceType, pszBuffer, MAX_DEVICETYPE_NAME);
|
|
ReleaseMutex(ghRasfileMutex);
|
|
dwErr = ERROR_READING_DEVICETYPE;
|
|
break;
|
|
}
|
|
|
|
CopyMemory(pPMI->PMI_DeviceType, pszBuffer, MAX_DEVICETYPE_NAME);
|
|
ZeroMemory(pszBuffer, sizeof(RAS_MAXLINEBUFLEN));
|
|
|
|
// Get Device Name
|
|
|
|
if (!(RasfileFindFirstLine(ghIniFile, RFL_SECTION, RFS_SECTION) &&
|
|
RasfileFindNextKeyLine(ghIniFile, SER_DEVICENAME_KEY, RFS_SECTION) &&
|
|
RasfileGetKeyValueFields(ghIniFile, NULL, pszBuffer /*pPMI->PMI_DeviceName*/)))
|
|
{
|
|
// End Exclusion
|
|
CopyMemory(pPMI->PMI_DeviceName, pszBuffer, MAX_DEVICE_NAME);
|
|
ReleaseMutex(ghRasfileMutex);
|
|
dwErr = ERROR_READING_DEVICENAME;
|
|
break;
|
|
}
|
|
|
|
CopyMemory(pPMI->PMI_DeviceName, pszBuffer, MAX_DEVICE_NAME);
|
|
ZeroMemory(pszBuffer, RAS_MAXLINEBUFLEN);
|
|
|
|
// Get Usage
|
|
|
|
if (!(RasfileFindFirstLine(ghIniFile, RFL_SECTION, RFS_SECTION) &&
|
|
RasfileFindNextKeyLine(ghIniFile, SER_USAGE_KEY, RFS_SECTION) &&
|
|
RasfileGetKeyValueFields(ghIniFile, NULL, pszBuffer /*szUsage*/)))
|
|
{
|
|
// End Exclusion
|
|
CopyMemory(szUsage, pszBuffer, RAS_MAXLINEBUFLEN);
|
|
ReleaseMutex(ghRasfileMutex);
|
|
dwErr = ERROR_READING_USAGE;
|
|
break;
|
|
}
|
|
|
|
CopyMemory(szUsage, pszBuffer, RAS_MAXLINEBUFLEN);
|
|
|
|
if (!StrToUsage(szUsage, &(pPMI->PMI_Usage)))
|
|
{
|
|
// End Exclusion
|
|
|
|
ReleaseMutex(ghRasfileMutex);
|
|
dwErr = ERROR_BAD_USAGE_IN_INI_FILE;
|
|
break;
|
|
}
|
|
|
|
pPMI->PMI_LineDeviceId = INVALID_TAPI_ID;
|
|
pPMI->PMI_AddressId = INVALID_TAPI_ID;
|
|
|
|
pPMI++;
|
|
|
|
}while(RasfileFindNextLine(ghIniFile, RFL_SECTION, RFS_FILE));
|
|
|
|
|
|
if(NULL != pszBuffer)
|
|
{
|
|
LocalFree(pszBuffer);
|
|
}
|
|
|
|
// End Exclusion
|
|
|
|
ReleaseMutex(ghRasfileMutex);
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//* PortOpen ---------------------------------------------------------------
|
|
//
|
|
// Function: This API opens a COM port. It takes the port name in ASCIIZ
|
|
// form and supplies a handle to the open port. hNotify is use
|
|
// to notify the caller if the device on the port shuts down.
|
|
//
|
|
// PortOpen allocates a SerialPCB and places it at the head of
|
|
// the linked list of Serial Port Control Blocks.
|
|
//
|
|
// Returns: SUCCESS
|
|
// ERROR_PORT_NOT_CONFIGURED
|
|
// ERROR_DEVICE_NOT_READY
|
|
//
|
|
//*
|
|
|
|
DWORD APIENTRY
|
|
PortOpen(
|
|
char *pszPortName,
|
|
HANDLE *phIOPort,
|
|
HANDLE hIoCompletionPort,
|
|
DWORD dwCompletionKey)
|
|
{
|
|
SERIALPCB *pSPCB ;
|
|
DWORD dwRC, dwStatus = 0;
|
|
TCHAR szPort[MAX_PATH];
|
|
WCHAR szDriverName[] = ASYNCMAC_FILENAME;
|
|
|
|
|
|
try
|
|
{
|
|
DebugPrintf(("PortOpen: %s\n", pszPortName));
|
|
|
|
|
|
// Check serial.ini to see that pszPortName is configured for RAS
|
|
|
|
// Begin Exclusion
|
|
|
|
if(INVALID_HRASFILE == ghIniFile)
|
|
{
|
|
return ERROR_PORT_NOT_CONFIGURED;
|
|
}
|
|
|
|
WaitForSingleObject(ghRasfileMutex, INFINITE);
|
|
|
|
#if DBG
|
|
ASSERT(INVALID_HRASFILE != ghIniFile );
|
|
#endif
|
|
|
|
if (!RasfileFindSectionLine(ghIniFile, pszPortName, FROM_TOP_OF_FILE))
|
|
{
|
|
// End Exclusion
|
|
|
|
ReleaseMutex(ghRasfileMutex);
|
|
return(ERROR_PORT_NOT_CONFIGURED);
|
|
}
|
|
// End Exclusion
|
|
|
|
ReleaseMutex(ghRasfileMutex);
|
|
|
|
|
|
|
|
// Prepend \\.\ to COMx
|
|
|
|
strcpy(szPort, "\\\\.\\");
|
|
strcat(szPort, pszPortName);
|
|
|
|
|
|
// Open Port
|
|
|
|
*phIOPort = CreateFile(szPort,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_EXCLUSIVE_MODE,
|
|
NULL, //No Security Attributes
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
|
NULL); //No Template File
|
|
|
|
|
|
DebugPrintf(("hioport: 0x%08x\n", *phIOPort));
|
|
//DbgPrint("hioport: 0x%08x\n", *phIOPort);
|
|
|
|
if (*phIOPort == INVALID_HANDLE_VALUE)
|
|
{
|
|
dwRC = GetLastError();
|
|
if (dwRC == ERROR_ACCESS_DENIED)
|
|
return (ERROR_PORT_ALREADY_OPEN);
|
|
else if (dwRC == ERROR_FILE_NOT_FOUND)
|
|
return (ERROR_PORT_NOT_FOUND) ;
|
|
else
|
|
return(dwRC);
|
|
}
|
|
|
|
//
|
|
// Associate an I/O completion port with
|
|
// the file handle.
|
|
//
|
|
if (CreateIoCompletionPort(
|
|
*phIOPort,
|
|
hIoCompletionPort,
|
|
dwCompletionKey,
|
|
0) == NULL)
|
|
{
|
|
CloseHandle(*phIOPort);
|
|
*phIOPort = NULL;
|
|
return GetLastError();
|
|
}
|
|
|
|
|
|
|
|
#ifdef notdef
|
|
{
|
|
DWORD dwBytesReturned ;
|
|
|
|
#define FILE_DEVICE_SERIAL_PORT 0x0000001b
|
|
#define _SERIAL_CONTROL_CODE(request,method) \
|
|
((FILE_DEVICE_SERIAL_PORT)<<16 | (request<<2) | method)
|
|
#define IOCTL_SERIAL_PRIVATE_RAS _SERIAL_CONTROL_CODE(4000, METHOD_BUFFERED)
|
|
|
|
DeviceIoControl(*phIOPort,
|
|
IOCTL_SERIAL_PRIVATE_RAS,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&dwBytesReturned,
|
|
NULL) ;
|
|
}
|
|
#endif
|
|
|
|
// Set Queue sizes and default values for Comm Port
|
|
|
|
if (!SetupComm(*phIOPort, INPUT_QUEUE_SIZE, OUTPUT_QUEUE_SIZE))
|
|
{
|
|
LogError(ROUTERLOG_SERIAL_QUEUE_SIZE_SMALL, 0, NULL, 0xffffffff);
|
|
}
|
|
|
|
SetCommDefaults(*phIOPort, pszPortName);
|
|
|
|
|
|
// Add a Serial PCB to head of list and set eDeviceType
|
|
|
|
AddPortToList(*phIOPort, pszPortName);
|
|
|
|
pSPCB = FindPortInList(*phIOPort, NULL) ; //Find port just added
|
|
|
|
if(NULL == pSPCB)
|
|
{
|
|
CloseHandle(*phIOPort);
|
|
*phIOPort = NULL;
|
|
return ERROR_PORT_NOT_FOUND;
|
|
}
|
|
|
|
// Get handle to Asyncmac driver
|
|
|
|
pSPCB->hAsyMac = CreateFileW(szDriverName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, //No security attribs
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
|
NULL); //No template file
|
|
|
|
DebugPrintf(("pSPCB->hAsyMac: 0x%08x\n", pSPCB->hAsyMac));
|
|
|
|
//DbgPrint("pSPCB->hAsyMac: 0x%08x\n", pSPCB->hAsyMac);
|
|
|
|
if (pSPCB->hAsyMac == INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD dwErr;
|
|
dwErr = GetLastError();
|
|
DebugPrintf(("CreateFileError: %d\n", dwErr));
|
|
//DbgPrint("CreateFileError: %d\n", dwErr);
|
|
|
|
LogError(ROUTERLOG_CANNOT_GET_ASYNCMAC_HANDLE, 0, NULL, 0xffffffff);
|
|
CloseHandle(*phIOPort);
|
|
*phIOPort = NULL;
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
//
|
|
// Associate the I/O completion port with
|
|
// the asyncmac file handle
|
|
//
|
|
if (CreateIoCompletionPort(pSPCB->hAsyMac,
|
|
hIoCompletionPort,
|
|
dwCompletionKey,
|
|
0) == NULL)
|
|
{
|
|
DWORD dwErr;
|
|
dwErr = GetLastError();
|
|
//DbgPrint("PortOpen: Failed to create IoCompletionPort %d\n", dwErr);
|
|
CloseHandle(*phIOPort);
|
|
*phIOPort = NULL;
|
|
return dwErr;
|
|
}
|
|
|
|
dwRC = InitCarrierBps(pszPortName, pSPCB->szCarrierBPS);
|
|
if (dwRC != SUCCESS)
|
|
{
|
|
gLastError = dwRC;
|
|
RaiseException(EXCEPT_RAS_MEDIA, EXCEPTION_NONCONTINUABLE, 0, NULL);
|
|
}
|
|
|
|
|
|
// Check that device is powered on and ready (DSR is up) If it is then
|
|
// we monitor DSR - else - we do not monitor DSR until we are connected.
|
|
//
|
|
GetCommModemStatus(*phIOPort, &dwStatus);
|
|
|
|
pSPCB->dwPreviousModemStatus = 0;
|
|
|
|
if ( ! (dwStatus & MS_DSR_ON))
|
|
// DSR is not raised by the device = assume that it will not raise
|
|
// it until its connected.
|
|
//
|
|
pSPCB->dwActiveDSRMask = pSPCB->dwMonitorDSRMask = 0 ;
|
|
else {
|
|
// Tell system to signal rasman if DSR drops
|
|
|
|
pSPCB->dwActiveDSRMask = pSPCB->dwMonitorDSRMask = EV_DSR ;
|
|
//DbgPrint("PortOpen: Setting mask 0x%x\n", EV_DSR);
|
|
SetCommMask(*phIOPort, EV_DSR);
|
|
|
|
|
|
if (!WaitCommEvent(*phIOPort,
|
|
&(pSPCB->dwEventMask),
|
|
(LPOVERLAPPED)&(pSPCB->MonitorDevice)))
|
|
{
|
|
|
|
//DbgPrint("PortOpen: WaitCommEvent. %d\n", GetLastError());
|
|
}
|
|
|
|
}
|
|
|
|
// Set values in Serial Port Control Block
|
|
|
|
GetDefaultOffStr(*phIOPort, pszPortName);
|
|
|
|
}
|
|
except(exception_code()==EXCEPT_RAS_MEDIA ? HANDLE_EXCEPTION:CONTINUE_SEARCH)
|
|
{
|
|
return(gLastError);
|
|
}
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//* PortClose --------------------------------------------------------------
|
|
//
|
|
// Function: This API closes the COM port for the input handle. It also
|
|
// finds the SerialPCB for the input handle, removes it from
|
|
// the linked list, and frees the memory for it
|
|
//
|
|
// Returns: SUCCESS
|
|
// Values returned by GetLastError()
|
|
//
|
|
//*
|
|
|
|
DWORD APIENTRY
|
|
PortClose (HANDLE hIOPort)
|
|
{
|
|
SERIALPCB *pPrev, *pSPCB = gpSerialPCB;
|
|
|
|
|
|
DebugPrintf(("PortClose\n"));
|
|
|
|
|
|
// Find the SerialPCB which contains hIOPOrt
|
|
|
|
pSPCB = FindPortInList(hIOPort, &pPrev);
|
|
|
|
if (pSPCB == NULL)
|
|
return(ERROR_PORT_NOT_OPEN);
|
|
|
|
|
|
// Remove the found SerialPCB
|
|
|
|
if (pSPCB == gpSerialPCB)
|
|
gpSerialPCB = pSPCB->pNextSPCB;
|
|
else
|
|
pPrev->pNextSPCB = pSPCB->pNextSPCB;
|
|
|
|
// Cancel wait on this port (WaitCommEvent)
|
|
//
|
|
//DbgPrint("PortClose: Setting mask to 0\n");
|
|
SetCommMask(hIOPort, 0);
|
|
|
|
// Drop DTR
|
|
//
|
|
EscapeCommFunction(hIOPort, CLRDTR);
|
|
|
|
// Close COM Port
|
|
//
|
|
if (!CloseHandle(hIOPort))
|
|
return(GetLastError());
|
|
|
|
// close the asymac file we associated with this com port
|
|
if (!CloseHandle(pSPCB->hAsyMac))
|
|
return GetLastError();
|
|
|
|
// Free portcontrolblock: note this must be done after CloseHandle since the struct
|
|
// contains an overlapped struct used for i/o on the port. this overlapped struct
|
|
// is freed when the handle to the port is closed.
|
|
//
|
|
free(pSPCB);
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//* PortGetInfo ------------------------------------------------------------
|
|
//
|
|
// Function: This API returns a block of information to the caller about
|
|
// the port state. This API may be called before the port is
|
|
// open in which case it will return inital default values
|
|
// instead of actual port values.
|
|
//
|
|
// If the API is to be called before the port is open, set hIOPort
|
|
// to INVALID_HANDLE_VALUE and pszPortName to the port name. If
|
|
// hIOPort is valid (the port is open), pszPortName may be set
|
|
// to NULL.
|
|
//
|
|
// hIOPort pSPCB := FindPortNameInList() Port
|
|
// ------- ----------------------------- ------
|
|
// valid x open
|
|
// invalid non_null open
|
|
// invalid null closed
|
|
//
|
|
// Returns: SUCCESS
|
|
// ERROR_BUFFER_TOO_SMALL
|
|
//*
|
|
|
|
DWORD APIENTRY
|
|
PortGetInfo(HANDLE hIOPort, TCHAR *pszPortName, BYTE *pBuffer, DWORD *pdwSize)
|
|
{
|
|
SERIALPCB *pSPCB;
|
|
DCB DCB;
|
|
RAS_PARAMS *pParam;
|
|
TCHAR *pValue;
|
|
TCHAR szDefaultOff[RAS_MAXLINEBUFLEN];
|
|
TCHAR szClientDefaultOff[RAS_MAXLINEBUFLEN];
|
|
TCHAR szDeviceType[MAX_DEVICETYPE_NAME + 1];
|
|
TCHAR szDeviceName[MAX_DEVICE_NAME + 1];
|
|
TCHAR szPortName[MAX_PORT_NAME + 1];
|
|
TCHAR szConnectBPS[MAX_BPS_STR_LEN], szCarrierBPS[MAX_BPS_STR_LEN];
|
|
DWORD dwConnectBPSLen, dwCarrierBPSLen, dwDefaultOffLen;
|
|
DWORD dwDeviceTypeLen, dwDeviceNameLen, dwPortNameLen;
|
|
DWORD dwClientDefaultOffLen;
|
|
DWORD dwStructSize;
|
|
DWORD dwAvailable, dwNumOfParams = 12;
|
|
|
|
try
|
|
{
|
|
|
|
DebugPrintf(("PortGetInfo\n"));
|
|
|
|
if (hIOPort == INVALID_HANDLE_VALUE &&
|
|
(pSPCB = FindPortNameInList(pszPortName)) == NULL)
|
|
{
|
|
// Port is not yet open
|
|
|
|
// Read from Serial.ini
|
|
|
|
GetValueFromFile(pszPortName, SER_DEFAULTOFF_KEY, szDefaultOff, RAS_MAXLINEBUFLEN);
|
|
GetValueFromFile(pszPortName, SER_MAXCONNECTBPS_KEY, szConnectBPS, MAX_BPS_STR_LEN);
|
|
GetValueFromFile(pszPortName, SER_MAXCARRIERBPS_KEY, szCarrierBPS, MAX_BPS_STR_LEN);
|
|
GetValueFromFile(pszPortName, SER_DEVICETYPE_KEY, szDeviceType, MAX_DEVICETYPE_NAME + 1);
|
|
GetValueFromFile(pszPortName, SER_DEVICENAME_KEY, szDeviceName, MAX_DEVICE_NAME + 1);
|
|
strcpy(szPortName, pszPortName);
|
|
|
|
|
|
// Set RAS default values in the DCB
|
|
|
|
SetDcbDefaults(&DCB);
|
|
}
|
|
else
|
|
{
|
|
// Port is open; Get a Device Control Block with current port values
|
|
|
|
if (hIOPort != INVALID_HANDLE_VALUE)
|
|
{
|
|
pSPCB = FindPortInList(hIOPort, NULL);
|
|
if (pSPCB == NULL)
|
|
{
|
|
gLastError = ERROR_PORT_NOT_OPEN;
|
|
RaiseException(EXCEPT_RAS_MEDIA, EXCEPTION_NONCONTINUABLE, 0, NULL);
|
|
}
|
|
}
|
|
|
|
if (!GetCommState(pSPCB->hIOPort, &DCB))
|
|
{
|
|
gLastError = GetLastError();
|
|
RaiseException(EXCEPT_RAS_MEDIA, EXCEPTION_NONCONTINUABLE, 0, NULL);
|
|
}
|
|
|
|
_itoa(DCB.BaudRate, szConnectBPS, 10);
|
|
strcpy(szCarrierBPS, pSPCB->szCarrierBPS);
|
|
strcpy(szDefaultOff, pSPCB->szDefaultOff);
|
|
strcpy(szDeviceType, pSPCB->szDeviceType);
|
|
strcpy(szDeviceName, pSPCB->szDeviceName);
|
|
strcpy(szPortName, pSPCB->szPortName);
|
|
}
|
|
|
|
|
|
|
|
// Read from Serial.ini even if port is open
|
|
|
|
GetValueFromFile(szPortName, SER_C_DEFAULTOFFSTR_KEY, szClientDefaultOff, RAS_MAXLINEBUFLEN);
|
|
|
|
|
|
// Calculate Buffer size needed
|
|
|
|
dwStructSize = sizeof(RASMAN_PORTINFO)
|
|
+ sizeof(RAS_PARAMS) * (dwNumOfParams - 1);
|
|
|
|
dwConnectBPSLen = strlen(szConnectBPS);
|
|
dwCarrierBPSLen = strlen(szCarrierBPS);
|
|
dwDeviceTypeLen = strlen(szDeviceType);
|
|
dwDeviceNameLen = strlen(szDeviceName);
|
|
dwDefaultOffLen = strlen(szDefaultOff);
|
|
dwPortNameLen = strlen(szPortName);
|
|
dwClientDefaultOffLen = strlen(szClientDefaultOff);
|
|
|
|
dwAvailable = *pdwSize;
|
|
*pdwSize = (dwStructSize + dwConnectBPSLen + dwCarrierBPSLen
|
|
+ dwDeviceTypeLen + dwDeviceNameLen
|
|
+ dwDefaultOffLen + dwPortNameLen
|
|
+ dwClientDefaultOffLen +
|
|
+ 7L); //Zero bytes
|
|
if (*pdwSize > dwAvailable)
|
|
return(ERROR_BUFFER_TOO_SMALL);
|
|
|
|
|
|
|
|
// Fill in Buffer
|
|
|
|
((RASMAN_PORTINFO *)pBuffer)->PI_NumOfParams = ( WORD ) dwNumOfParams;
|
|
|
|
pParam = ((RASMAN_PORTINFO *)pBuffer)->PI_Params;
|
|
pValue = pBuffer + dwStructSize;
|
|
|
|
strcpy(pParam->P_Key, SER_CONNECTBPS_KEY);
|
|
pParam->P_Type = String;
|
|
pParam->P_Attributes = 0;
|
|
pParam->P_Value.String.Length = dwConnectBPSLen;
|
|
pParam->P_Value.String.Data = pValue;
|
|
strcpy(pParam->P_Value.String.Data, szConnectBPS);
|
|
pValue += dwConnectBPSLen + 1;
|
|
|
|
pParam++;
|
|
strcpy(pParam->P_Key, SER_DATABITS_KEY);
|
|
pParam->P_Type = Number;
|
|
pParam->P_Attributes = 0;
|
|
pParam->P_Value.Number = DCB.ByteSize;
|
|
|
|
pParam++;
|
|
strcpy(pParam->P_Key, SER_PARITY_KEY);
|
|
pParam->P_Type = Number;
|
|
pParam->P_Attributes = 0;
|
|
pParam->P_Value.Number = DCB.Parity;
|
|
|
|
pParam++;
|
|
strcpy(pParam->P_Key, SER_STOPBITS_KEY);
|
|
pParam->P_Type = Number;
|
|
pParam->P_Attributes = 0;
|
|
pParam->P_Value.Number = DCB.StopBits;
|
|
|
|
pParam++;
|
|
strcpy(pParam->P_Key, SER_HDWFLOWCTRLON_KEY);
|
|
pParam->P_Type = Number;
|
|
pParam->P_Attributes = 0;
|
|
pParam->P_Value.Number = DCB.fOutxCtsFlow;
|
|
|
|
pParam++;
|
|
strcpy(pParam->P_Key, SER_CARRIERBPS_KEY);
|
|
pParam->P_Type = String;
|
|
pParam->P_Attributes = 0;
|
|
pParam->P_Value.String.Length = dwCarrierBPSLen;
|
|
pParam->P_Value.String.Data = pValue;
|
|
strcpy(pParam->P_Value.String.Data, szCarrierBPS);
|
|
pValue += dwCarrierBPSLen + 1;
|
|
|
|
pParam++;
|
|
strcpy(pParam->P_Key, SER_ERRORCONTROLON_KEY);
|
|
pParam->P_Type = Number;
|
|
pParam->P_Attributes = 0;
|
|
if (pSPCB == NULL)
|
|
pParam->P_Value.Number = FALSE;
|
|
else
|
|
pParam->P_Value.Number = pSPCB->bErrorControlOn;
|
|
|
|
pParam++;
|
|
strcpy(pParam->P_Key, SER_DEFAULTOFFSTR_KEY);
|
|
pParam->P_Type = String;
|
|
pParam->P_Attributes = 0;
|
|
pParam->P_Value.String.Length = dwDefaultOffLen;
|
|
pParam->P_Value.String.Data = pValue;
|
|
strcpy(pParam->P_Value.String.Data, szDefaultOff);
|
|
pValue += dwDefaultOffLen + 1;
|
|
|
|
pParam++;
|
|
strcpy(pParam->P_Key, SER_DEVICETYPE_KEY);
|
|
pParam->P_Type = String;
|
|
pParam->P_Attributes = 0;
|
|
pParam->P_Value.String.Length = dwDeviceTypeLen;
|
|
pParam->P_Value.String.Data = pValue;
|
|
strcpy(pParam->P_Value.String.Data, szDeviceType);
|
|
pValue += dwDeviceTypeLen + 1;
|
|
|
|
pParam++;
|
|
strcpy(pParam->P_Key, SER_DEVICENAME_KEY);
|
|
pParam->P_Type = String;
|
|
pParam->P_Attributes = 0;
|
|
pParam->P_Value.String.Length = dwDeviceNameLen;
|
|
pParam->P_Value.String.Data = pValue;
|
|
strcpy(pParam->P_Value.String.Data, szDeviceName);
|
|
pValue += dwDeviceNameLen + 1;
|
|
|
|
pParam++;
|
|
strcpy(pParam->P_Key, SER_PORTNAME_KEY);
|
|
pParam->P_Type = String;
|
|
pParam->P_Attributes = 0;
|
|
pParam->P_Value.String.Length = dwPortNameLen;
|
|
pParam->P_Value.String.Data = pValue;
|
|
strcpy(pParam->P_Value.String.Data, szPortName);
|
|
pValue += dwPortNameLen + 1;
|
|
|
|
pParam++;
|
|
strcpy(pParam->P_Key, SER_C_DEFAULTOFFSTR_KEY);
|
|
pParam->P_Type = String;
|
|
pParam->P_Attributes = 0;
|
|
pParam->P_Value.String.Length = dwClientDefaultOffLen;
|
|
pParam->P_Value.String.Data = pValue;
|
|
strcpy(pParam->P_Value.String.Data, szClientDefaultOff);
|
|
//pValue += dwClientDefaultOffLen + 1;
|
|
|
|
|
|
return(SUCCESS);
|
|
|
|
}
|
|
except(exception_code()==EXCEPT_RAS_MEDIA ? HANDLE_EXCEPTION:CONTINUE_SEARCH)
|
|
{
|
|
return(gLastError);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//* PortSetInfo ------------------------------------------------------------
|
|
//
|
|
// Function: The values for most input keys are used to set the port
|
|
// parameters directly. However, the carrier BPS and the
|
|
// error conrol on flag set fields in the Serial Port Control
|
|
// Block only, and not the port.
|
|
//
|
|
// Returns: SUCCESS
|
|
// ERROR_WRONG_INFO_SPECIFIED
|
|
// Values returned by GetLastError()
|
|
//*
|
|
|
|
DWORD APIENTRY
|
|
PortSetInfo(HANDLE hIOPort, RASMAN_PORTINFO *pInfo)
|
|
{
|
|
RAS_PARAMS *p;
|
|
SERIALPCB *pSPCB;
|
|
DCB DCB;
|
|
WORD i;
|
|
BOOL bTypeError = FALSE;
|
|
|
|
|
|
try
|
|
{
|
|
|
|
DebugPrintf(("PortSetInfo\n\thPort = %d\n", hIOPort));
|
|
|
|
|
|
// Find the SerialPCB which contains hIOPOrt
|
|
|
|
pSPCB = FindPortInList(hIOPort, NULL);
|
|
|
|
if (pSPCB == NULL)
|
|
{
|
|
gLastError = ERROR_PORT_NOT_OPEN;
|
|
RaiseException(EXCEPT_RAS_MEDIA, EXCEPTION_NONCONTINUABLE, 0, NULL);
|
|
}
|
|
|
|
|
|
// Get a Device Control Block with current port values
|
|
|
|
if (!GetCommState(hIOPort, &DCB))
|
|
return(GetLastError());
|
|
|
|
|
|
// Set DCB and PCB values
|
|
|
|
for (i=0, p=pInfo->PI_Params; i<pInfo->PI_NumOfParams; i++, p++)
|
|
{
|
|
// Set DCB values
|
|
|
|
if (_stricmp(p->P_Key, SER_CONNECTBPS_KEY) == 0)
|
|
|
|
DCB.BaudRate = ValueToNum(p);
|
|
|
|
else if (_stricmp(p->P_Key, SER_DATABITS_KEY) == 0)
|
|
|
|
DCB.ByteSize = (BYTE) ValueToNum(p);
|
|
|
|
else if (_stricmp(p->P_Key, SER_PARITY_KEY) == 0)
|
|
|
|
DCB.Parity = (BYTE) ValueToNum(p);
|
|
|
|
else if (_stricmp(p->P_Key, SER_STOPBITS_KEY) == 0)
|
|
|
|
DCB.StopBits = (BYTE) ValueToNum(p);
|
|
|
|
else if (_stricmp(p->P_Key, SER_HDWFLOWCTRLON_KEY) == 0)
|
|
|
|
DCB.fOutxCtsFlow = ValueToBool(p);
|
|
|
|
|
|
// Set PCB values
|
|
|
|
else if (_stricmp(p->P_Key, SER_CARRIERBPS_KEY) == 0)
|
|
|
|
if (p->P_Type == String)
|
|
{
|
|
strncpy(pSPCB->szCarrierBPS,
|
|
p->P_Value.String.Data,
|
|
p->P_Value.String.Length);
|
|
|
|
pSPCB->szCarrierBPS[p->P_Value.String.Length] = '\0';
|
|
}
|
|
else
|
|
_itoa(p->P_Value.Number, pSPCB->szCarrierBPS, 10);
|
|
|
|
else if (_stricmp(p->P_Key, SER_ERRORCONTROLON_KEY) == 0)
|
|
|
|
pSPCB->bErrorControlOn = ValueToBool(p);
|
|
|
|
else if (_stricmp(p->P_Key, SER_DEFAULTOFF_KEY) == 0)
|
|
|
|
if (p->P_Type == String)
|
|
{
|
|
strncpy(pSPCB->szDefaultOff,
|
|
p->P_Value.String.Data,
|
|
p->P_Value.String.Length);
|
|
|
|
pSPCB->szDefaultOff[p->P_Value.String.Length] = '\0';
|
|
}
|
|
else
|
|
pSPCB->szDefaultOff[0] = USE_DEVICE_INI_DEFAULT;
|
|
|
|
|
|
else
|
|
return(ERROR_WRONG_INFO_SPECIFIED);
|
|
|
|
} // for
|
|
|
|
|
|
// Send DCB to Port
|
|
|
|
if (!SetCommState(hIOPort, &DCB))
|
|
return(GetLastError());
|
|
|
|
|
|
return(SUCCESS);
|
|
|
|
}
|
|
except(exception_code()==EXCEPT_RAS_MEDIA ? HANDLE_EXCEPTION:CONTINUE_SEARCH)
|
|
{
|
|
return(gLastError);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//* PortTestSignalState ----------------------------------------------------
|
|
//
|
|
// Function: This API indicates the state of the DSR and DTR lines.
|
|
// DSR - Data Set Ready
|
|
// DCD - Data Carrier Detect (RLSD - Received Line Signal Detect)
|
|
//
|
|
// Returns: SUCCESS
|
|
// Values returned by GetLastError()
|
|
//
|
|
//*
|
|
|
|
DWORD APIENTRY
|
|
PortTestSignalState(HANDLE hIOPort, DWORD *pdwDeviceState)
|
|
{
|
|
DWORD dwModemStatus;
|
|
SERIALPCB *pSPCB;
|
|
DWORD dwSetMask = 0 ;
|
|
|
|
DebugPrintf(("PortTestSignalState\n"));
|
|
|
|
*pdwDeviceState = 0;
|
|
|
|
|
|
if ((pSPCB = FindPortInList (hIOPort, NULL)) == NULL)
|
|
return ERROR_PORT_NOT_OPEN ;
|
|
|
|
if (!GetCommModemStatus(hIOPort, &dwModemStatus))
|
|
{
|
|
*pdwDeviceState = 0xffffffff;
|
|
return(GetLastError());
|
|
}
|
|
|
|
// If DSR is down AND it was up before then mark it as a hw failure.
|
|
//
|
|
if ((!(dwModemStatus & MS_DSR_ON)) && (pSPCB->dwMonitorDSRMask))
|
|
*pdwDeviceState |= SS_HARDWAREFAILURE;
|
|
|
|
// Similarly, if DCD is down and it was up before then link has dropped.
|
|
//
|
|
if (!(dwModemStatus & MS_RLSD_ON))
|
|
*pdwDeviceState |= SS_LINKDROPPED;
|
|
else
|
|
dwSetMask = EV_RLSD ;
|
|
|
|
if (pSPCB->uRasEndpoint != INVALID_HANDLE_VALUE) {
|
|
ASYMAC_DCDCHANGE A ;
|
|
DWORD dwBytesReturned;
|
|
|
|
A.MacAdapter = NULL ;
|
|
A.hNdisEndpoint = (HANDLE) pSPCB->uRasEndpoint ;
|
|
DeviceIoControl(pSPCB->hAsyMac,
|
|
IOCTL_ASYMAC_DCDCHANGE,
|
|
&A,
|
|
sizeof(A),
|
|
&A,sizeof(A),
|
|
&dwBytesReturned,
|
|
(LPOVERLAPPED)&(pSPCB->MonitorDevice)) ;
|
|
|
|
} else {
|
|
|
|
dwSetMask |= (pSPCB->dwMonitorDSRMask) ; // Only monitor DSR if it is used.
|
|
|
|
if (dwSetMask == 0)
|
|
return (SUCCESS) ; // do not set wait mask.
|
|
|
|
if (dwModemStatus == pSPCB->dwPreviousModemStatus)
|
|
{
|
|
//DbgPrint("PortTestSignalState: Modemstatus hasn't changed\n");
|
|
return SUCCESS;
|
|
}
|
|
else
|
|
pSPCB->dwPreviousModemStatus = dwModemStatus;
|
|
|
|
//DbgPrint("PortTestSignalState: Setting mask ox%x\n", dwSetMask);
|
|
SetCommMask(hIOPort, dwSetMask);
|
|
|
|
// Start a new wait on signal lines (DSR and/or DCD)
|
|
|
|
if (!WaitCommEvent(hIOPort,
|
|
&(pSPCB->dwEventMask),
|
|
(LPOVERLAPPED)&(pSPCB->MonitorDevice)))
|
|
{
|
|
//DbgPrint("PortTestSignalState: WaitCommEvent. %d\n", GetLastError());
|
|
}
|
|
}
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//* PortConnect ------------------------------------------------------------
|
|
//
|
|
// Function: This API is called when a connection has been completed and some
|
|
// steps need to be taken, If bWaitForDevice is set then we monitor DCD only
|
|
// else,
|
|
// It in turn calls the asyncmac device driver in order to
|
|
// indicate to asyncmac that the port and the connection
|
|
// over it are ready for commumication.
|
|
//
|
|
// pdwCompressionInfo is an output only parameter which
|
|
// indicates the type(s) of compression supported by the MAC.
|
|
//
|
|
// bWaitForDevice is set to TRUE when we just want to start monitoring DCD
|
|
//
|
|
// Returns: SUCCESS
|
|
// ERROR_PORT_NOT_OPEN
|
|
// ERROR_NO_CONNECTION
|
|
// Values returned by GetLastError()
|
|
//
|
|
//*
|
|
|
|
DWORD APIENTRY
|
|
PortConnect(HANDLE hIOPort,
|
|
BOOL bWaitForDevice,
|
|
HANDLE *pRasEndpoint)
|
|
{
|
|
ASYMAC_OPEN AsyMacOpen;
|
|
ASYMAC_DCDCHANGE A ;
|
|
SERIALPCB *pSPCB;
|
|
BOOL bPadDevice;
|
|
DWORD dwModemStatus, dwBytesReturned;
|
|
TCHAR szDeviceType[RAS_MAXLINEBUFLEN];
|
|
|
|
|
|
// This is a special mode of PortConnect where all we do is start monitoring DCD
|
|
// Hand off to asyncmac does not happen till the next call to port connect where the
|
|
// bWaitForDevice flag is false
|
|
//
|
|
|
|
if (bWaitForDevice) {
|
|
|
|
pSPCB = FindPortInList(hIOPort, NULL);
|
|
|
|
if (pSPCB == NULL)
|
|
{
|
|
gLastError = ERROR_PORT_NOT_OPEN;
|
|
return ERROR_NO_CONNECTION ;
|
|
}
|
|
|
|
if (!GetCommModemStatus(hIOPort, &dwModemStatus))
|
|
return(GetLastError());
|
|
|
|
|
|
// UPDATE the DSR monitoring
|
|
//
|
|
if (!(dwModemStatus & MS_DSR_ON))
|
|
pSPCB->dwMonitorDSRMask = 0 ;
|
|
else
|
|
pSPCB->dwMonitorDSRMask = EV_DSR ;
|
|
|
|
// Tell serial driver to signal rasman if DCD, (and DSR, if it was used) drop
|
|
//
|
|
//DbgPrint("PortConnect: Setting mask to 0x%x\n",EV_RLSD | (pSPCB->dwMonitorDSRMask));
|
|
if (!SetCommMask(hIOPort, EV_RLSD | (pSPCB->dwMonitorDSRMask)))
|
|
return(GetLastError());
|
|
|
|
WaitCommEvent(hIOPort,
|
|
&(pSPCB->dwEventMask),
|
|
(LPOVERLAPPED) &(pSPCB->MonitorDevice)) ;
|
|
|
|
return SUCCESS ;
|
|
}
|
|
|
|
|
|
// Else we do both - change DCD monitoring and handing off context to asyncmac
|
|
//
|
|
memset (&overlapped, 0, sizeof (OVERLAPPED)) ;
|
|
|
|
try
|
|
{
|
|
|
|
DebugPrintf(("PortConnect\n"));
|
|
|
|
|
|
// Find port in list
|
|
|
|
pSPCB = FindPortInList(hIOPort, NULL);
|
|
|
|
if (pSPCB == NULL)
|
|
{
|
|
gLastError = ERROR_PORT_NOT_OPEN;
|
|
RaiseException(EXCEPT_RAS_MEDIA, EXCEPTION_NONCONTINUABLE, 0, NULL);
|
|
}
|
|
|
|
|
|
//Make sure connection is still up
|
|
|
|
if (!GetCommModemStatus(hIOPort, &dwModemStatus))
|
|
return(GetLastError());
|
|
|
|
|
|
// Make sure that DSR is still up (if it ever was up!)
|
|
|
|
if ((!(dwModemStatus & MS_DSR_ON)) && (pSPCB->dwMonitorDSRMask)) {
|
|
OutputDebugString ("DSR down!!!\r\n") ;
|
|
return(ERROR_NO_CONNECTION); //Device is down
|
|
}
|
|
|
|
if (!(dwModemStatus & MS_RLSD_ON) ) {
|
|
OutputDebugString ("DCD down!!!\r\n") ;
|
|
return(ERROR_NO_CONNECTION); //DCD is down
|
|
}
|
|
|
|
// // UPDATE the DSR monitoring
|
|
// //
|
|
// if ( ! (dwModemStatus & MS_DSR_ON)) {
|
|
// pSPCB->dwMonitorDSRMask = 0 ;
|
|
// } else {
|
|
// pSPCB->dwMonitorDSRMask = EV_DSR ;
|
|
// }
|
|
//
|
|
// // Tell system to signal rasman if DCD, (and DSR, if it was used) drop
|
|
//
|
|
// if (!SetCommMask(hIOPort, EV_RLSD | (pSPCB->dwMonitorDSRMask)))
|
|
// return(GetLastError());
|
|
//
|
|
// WaitCommEvent(hIOPort,
|
|
// &(pSPCB->dwEventMask),
|
|
// &(pSPCB->MonitorDevice)) ;
|
|
|
|
//Put endpoint in Serial PCB for later use by PortDisconnect
|
|
|
|
|
|
//Find if device type is Pad
|
|
|
|
GetValueFromFile(pSPCB->szPortName, SER_DEVICETYPE_KEY, szDeviceType, RAS_MAXLINEBUFLEN);
|
|
|
|
bPadDevice = (_stricmp(szDeviceType, MXS_PAD_TXT) == 0);
|
|
|
|
|
|
// Let the ASYMAC notify us of DCD and DSR change
|
|
//
|
|
//DbgPrint("PortConnect: Setting mask to 0\n");
|
|
if (!SetCommMask(hIOPort, 0)) // Set mask to stop monitoring DCD
|
|
return(GetLastError());
|
|
|
|
|
|
//Open AsyncMac (Hand off port to AsyncMac)
|
|
|
|
AsyMacOpen.hNdisEndpoint = INVALID_HANDLE_VALUE ;
|
|
AsyMacOpen.LinkSpeed = (atoi(pSPCB->szCarrierBPS) == 0) ?
|
|
14400 :
|
|
atoi(pSPCB->szCarrierBPS) ;
|
|
AsyMacOpen.FileHandle = hIOPort;
|
|
|
|
if (bPadDevice || pSPCB->bErrorControlOn)
|
|
AsyMacOpen.QualOfConnect = (UINT)NdisWanErrorControl;
|
|
else
|
|
AsyMacOpen.QualOfConnect = (UINT)NdisWanRaw;
|
|
|
|
if (!DeviceIoControl(pSPCB->hAsyMac,
|
|
IOCTL_ASYMAC_OPEN,
|
|
&AsyMacOpen,
|
|
sizeof(AsyMacOpen),
|
|
&AsyMacOpen,
|
|
sizeof(AsyMacOpen),
|
|
&dwBytesReturned,
|
|
&overlapped))
|
|
{
|
|
// Clear the stored end point, so that if it failed to open
|
|
// no attempt will be made to close it.
|
|
|
|
pSPCB->uRasEndpoint = INVALID_HANDLE_VALUE;
|
|
return(GetLastError());
|
|
} else
|
|
pSPCB->uRasEndpoint = AsyMacOpen.hNdisEndpoint;
|
|
|
|
*pRasEndpoint = AsyMacOpen.hNdisEndpoint ;
|
|
|
|
//DbgPrint("PortConnect: RasEndpoint = 0x%x\n", *pRasEndpoint);
|
|
|
|
A.hNdisEndpoint = (HANDLE) *pRasEndpoint ;
|
|
A.MacAdapter = NULL ;
|
|
if (!DeviceIoControl(pSPCB->hAsyMac,
|
|
IOCTL_ASYMAC_DCDCHANGE,
|
|
&A,
|
|
sizeof(A),
|
|
&A,
|
|
sizeof(A),
|
|
&dwBytesReturned,
|
|
(LPOVERLAPPED)&(pSPCB->MonitorDevice)))
|
|
{
|
|
;//DbgPrint("PortConnect: DeviceIoControl (IOCTL_ASYMAC_DCDCHANGE) failed. %d\n",
|
|
// GetLastError());
|
|
}
|
|
|
|
PortClearStatistics(hIOPort);
|
|
|
|
|
|
// if (!(dwModemStatus & MS_RLSD_ON))
|
|
// return(PENDING); //DCD is down
|
|
// else
|
|
|
|
return(SUCCESS);
|
|
|
|
}
|
|
except(exception_code()==EXCEPT_RAS_MEDIA ? HANDLE_EXCEPTION:CONTINUE_SEARCH)
|
|
{
|
|
return(gLastError);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//* PortDisconnect ---------------------------------------------------------
|
|
//
|
|
// Function: This API is called to drop a connection and close AsyncMac.
|
|
//
|
|
// Returns: SUCCESS
|
|
// PENDING
|
|
// ERROR_PORT_NOT_OPEN
|
|
//
|
|
//*
|
|
|
|
DWORD APIENTRY
|
|
PortDisconnect(HANDLE hIOPort)
|
|
{
|
|
ASYMAC_CLOSE AsyMacClose;
|
|
SERIALPCB *pSPCB;
|
|
DWORD dwModemStatus, dwBytesReturned;
|
|
DWORD retcode ;
|
|
DWORD dwSetMask = 0;
|
|
DWORD fdwAction = PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR;
|
|
|
|
memset (&overlapped, 0, sizeof (OVERLAPPED)) ;
|
|
|
|
try
|
|
{
|
|
|
|
DebugPrintf(("PortDisconnect\n"));
|
|
|
|
|
|
//Signal other end of link that connection is being dropped
|
|
|
|
if (!EscapeCommFunction(hIOPort, CLRDTR))
|
|
{
|
|
;//DbgPrint("PortDisconnect: EscapeCommFunction Failed. %d\n", GetLastError());
|
|
}
|
|
|
|
//
|
|
// Apparently, DTR isn't really down
|
|
// yet, even though this call is supposed
|
|
// to be synchronous to the serial driver.
|
|
// We sleep here for a while to make sure
|
|
// DTR drops.
|
|
//
|
|
Sleep(100);
|
|
|
|
//Find port in list
|
|
|
|
if ((pSPCB = FindPortInList(hIOPort, NULL)) == NULL)
|
|
{
|
|
gLastError = ERROR_PORT_NOT_OPEN;
|
|
RaiseException(EXCEPT_RAS_MEDIA, EXCEPTION_NONCONTINUABLE, 0, NULL);
|
|
}
|
|
|
|
|
|
if (pSPCB->uRasEndpoint != INVALID_HANDLE_VALUE)
|
|
{
|
|
// Update statistics before closing Asyncmac
|
|
|
|
if ((retcode = UpdateStatistics(pSPCB)) != SUCCESS)
|
|
{
|
|
gLastError = retcode;
|
|
RaiseException(EXCEPT_RAS_MEDIA, EXCEPTION_NONCONTINUABLE, 0, NULL);
|
|
}
|
|
|
|
//Close AsynacMac
|
|
|
|
AsyMacClose.MacAdapter = NULL;
|
|
AsyMacClose.hNdisEndpoint = (HANDLE) pSPCB->uRasEndpoint;
|
|
|
|
DeviceIoControl(pSPCB->hAsyMac,
|
|
IOCTL_ASYMAC_CLOSE,
|
|
&AsyMacClose,
|
|
sizeof(AsyMacClose),
|
|
&AsyMacClose,
|
|
sizeof(AsyMacClose),
|
|
&dwBytesReturned,
|
|
&overlapped);
|
|
|
|
pSPCB->uRasEndpoint = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
PurgeComm(hIOPort, fdwAction) ; // flush the ports
|
|
|
|
//Check whether DCD has dropped yet
|
|
|
|
GetCommModemStatus(hIOPort, &dwModemStatus);
|
|
|
|
if (dwModemStatus & MS_RLSD_ON) {
|
|
|
|
//DbgPrint("PortDisconnect: DCD hasn't dropped yet!\n");
|
|
dwSetMask = EV_RLSD ;
|
|
retcode = PENDING ; // not yet dropped.
|
|
} else
|
|
retcode = SUCCESS ;
|
|
|
|
|
|
// UPDATE the DSR monitoring: this restores the DCR to what it was when
|
|
// the port was opened.
|
|
//
|
|
pSPCB->dwMonitorDSRMask = pSPCB->dwActiveDSRMask ;
|
|
|
|
dwSetMask |= (pSPCB->dwMonitorDSRMask) ;
|
|
|
|
if (dwSetMask != 0) { // set only if mask is not 0
|
|
//DbgPrint("PortDisconnect: Setting mask to 0x%x\n", dwSetMask);
|
|
SetCommMask (hIOPort, dwSetMask);
|
|
if (!WaitCommEvent(hIOPort,
|
|
&(pSPCB->dwEventMask),
|
|
(LPOVERLAPPED)&(pSPCB->MonitorDevice)))
|
|
{
|
|
//DbgPrint("PortDisconnect: WaitCommEvent. %d\n", GetLastError());
|
|
}
|
|
}
|
|
|
|
//Since DCD may have dropped after GetCommModemStatus and
|
|
// before WaitCommEvent, check it again.
|
|
|
|
if (retcode != SUCCESS)
|
|
{
|
|
GetCommModemStatus(hIOPort, &dwModemStatus);
|
|
|
|
if (dwModemStatus & MS_RLSD_ON)
|
|
{
|
|
//DbgPrint("PortDisconnect: DCD hasn't dropped yet. 2\n");
|
|
retcode = PENDING ; // not yet dropped.
|
|
}
|
|
else
|
|
retcode = SUCCESS ;
|
|
}
|
|
|
|
|
|
// Set the default connect baud
|
|
//
|
|
SetCommDefaults(pSPCB->hIOPort, pSPCB->szPortName);
|
|
|
|
}
|
|
except(exception_code()==EXCEPT_RAS_MEDIA ? HANDLE_EXCEPTION:CONTINUE_SEARCH)
|
|
{
|
|
return(gLastError);
|
|
}
|
|
|
|
return retcode ;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//* PortInit ---------------------------------------------------------------
|
|
//
|
|
// Function: This API re-initializes the com port after use.
|
|
//
|
|
// Returns: SUCCESS
|
|
// ERROR_PORT_NOT_CONFIGURED
|
|
// ERROR_DEVICE_NOT_READY
|
|
//
|
|
//*
|
|
|
|
DWORD APIENTRY
|
|
PortInit(HANDLE hIOPort)
|
|
{
|
|
DWORD fdwAction = PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR;
|
|
DWORD dwErrors;
|
|
SERIALPCB *pSPCB;
|
|
|
|
|
|
DebugPrintf(("PortInit\n"));
|
|
|
|
|
|
pSPCB = FindPortInList(hIOPort, NULL) ;
|
|
|
|
// Raise DTR
|
|
|
|
if (!EscapeCommFunction(hIOPort, SETDTR))
|
|
return(GetLastError());
|
|
|
|
if (!PurgeComm(hIOPort, fdwAction))
|
|
return(GetLastError());
|
|
|
|
if (!ClearCommError(hIOPort, &dwErrors, NULL))
|
|
return(GetLastError());
|
|
|
|
// Reset szCarrierBPS to MAXCARRIERBPS from ini file
|
|
//
|
|
InitCarrierBps(pSPCB->szPortName, pSPCB->szCarrierBPS);
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//* PortSend ---------------------------------------------------------------
|
|
//
|
|
// Function: This API sends a buffer to the port. This API is
|
|
// asynchronous and normally returns PENDING; however, if
|
|
// WriteFile returns synchronously, the API will return
|
|
// SUCCESS.
|
|
//
|
|
// Returns: SUCCESS
|
|
// PENDING
|
|
// Return code from GetLastError
|
|
//
|
|
//*
|
|
|
|
DWORD
|
|
PortSend(HANDLE hIOPort, BYTE *pBuffer, DWORD dwSize)
|
|
{
|
|
SERIALPCB *pSPCB;
|
|
DWORD dwRC, pdwBytesWritten;
|
|
BOOL bIODone;
|
|
|
|
|
|
DebugPrintf(("PortSend\n"));
|
|
|
|
|
|
// Find the SerialPCB which contains hIOPOrt
|
|
|
|
pSPCB = FindPortInList(hIOPort, NULL);
|
|
|
|
if (pSPCB == NULL)
|
|
return(ERROR_PORT_NOT_OPEN);
|
|
|
|
// Send Buffer to Port
|
|
|
|
bIODone = WriteFile(hIOPort,
|
|
pBuffer,
|
|
dwSize,
|
|
&pdwBytesWritten, //pdwBytesWritten is not used
|
|
(LPOVERLAPPED)&(pSPCB->SendReceive));
|
|
|
|
if (bIODone)
|
|
return(PENDING);
|
|
|
|
else if ((dwRC = GetLastError()) == ERROR_IO_PENDING)
|
|
return(PENDING);
|
|
|
|
else
|
|
return(dwRC);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//* PortReceive ------------------------------------------------------------
|
|
//
|
|
// Function: This API reads from the port. This API is
|
|
// asynchronous and normally returns PENDING; however, if
|
|
// ReadFile returns synchronously, the API will return
|
|
// SUCCESS.
|
|
//
|
|
// Returns: SUCCESS
|
|
// PENDING
|
|
// Return code from GetLastError
|
|
//
|
|
//*
|
|
|
|
DWORD
|
|
PortReceive(HANDLE hIOPort,
|
|
BYTE *pBuffer,
|
|
DWORD dwSize,
|
|
DWORD dwTimeOut)
|
|
{
|
|
COMMTIMEOUTS CT;
|
|
SERIALPCB *pSPCB;
|
|
DWORD dwRC, pdwBytesRead;
|
|
BOOL bIODone;
|
|
|
|
|
|
DebugPrintf(("PortReceive\n"));
|
|
|
|
|
|
// Find the SerialPCB which contains hIOPOrt
|
|
|
|
pSPCB = FindPortInList(hIOPort, NULL);
|
|
|
|
if (pSPCB == NULL)
|
|
return(ERROR_PORT_NOT_OPEN);
|
|
|
|
|
|
// Set Read Timeouts
|
|
|
|
CT.ReadIntervalTimeout = 0;
|
|
CT.ReadTotalTimeoutMultiplier = 0;
|
|
CT.ReadTotalTimeoutConstant = dwTimeOut;
|
|
|
|
if ( ! SetCommTimeouts(hIOPort, &CT))
|
|
return(GetLastError());
|
|
|
|
// Read from Port
|
|
|
|
bIODone = ReadFile(hIOPort,
|
|
pBuffer,
|
|
dwSize,
|
|
&pdwBytesRead, //pdwBytesRead is not used
|
|
(LPOVERLAPPED)&(pSPCB->SendReceive));
|
|
|
|
if (bIODone) {
|
|
return(PENDING);
|
|
}
|
|
|
|
else if ((dwRC = GetLastError()) == ERROR_IO_PENDING)
|
|
return(PENDING);
|
|
|
|
else
|
|
return(dwRC);
|
|
}
|
|
|
|
|
|
//* PortReceiveComplete ------------------------------------------------------
|
|
//
|
|
// Function: Completes a read - if still PENDING it cancels it - else it returns the bytes read.
|
|
// PortClearStatistics.
|
|
//
|
|
// Returns: SUCCESS
|
|
// ERROR_PORT_NOT_OPEN
|
|
//*
|
|
|
|
DWORD
|
|
PortReceiveComplete (HANDLE hIOPort, PDWORD bytesread)
|
|
{
|
|
SERIALPCB *pSPCB;
|
|
|
|
// Find the SerialPCB which contains hIOPOrt
|
|
|
|
pSPCB = FindPortInList(hIOPort, NULL);
|
|
|
|
if (pSPCB == NULL)
|
|
return(ERROR_PORT_NOT_OPEN);
|
|
|
|
if (!GetOverlappedResult(hIOPort,
|
|
(LPOVERLAPPED)&(pSPCB->SendReceive),
|
|
bytesread,
|
|
FALSE))
|
|
{
|
|
#if DBG
|
|
DbgPrint("PortReceiveComplete: GetOverlappedResult failed. %d", GetLastError());
|
|
#endif
|
|
PurgeComm (hIOPort, PURGE_RXABORT) ;
|
|
*bytesread = 0 ;
|
|
}
|
|
|
|
return SUCCESS ;
|
|
}
|
|
|
|
|
|
|
|
//* PortCompressionSetInfo -------------------------------------------------
|
|
//
|
|
// Function: This API selects Asyncmac compression mode by setting
|
|
// Asyncmac's compression bits.
|
|
//
|
|
// Returns: SUCCESS
|
|
// Return code from GetLastError
|
|
//
|
|
//*
|
|
|
|
DWORD
|
|
PortCompressionSetInfo(HANDLE hIOPort)
|
|
{
|
|
|
|
// Not supported anymore -
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//* PortClearStatistics ----------------------------------------------------
|
|
//
|
|
// Function: This API is used to mark the beginning of the period for which
|
|
// statistics will be reported. The current numbers are copied
|
|
// from the MAC and stored in the Serial Port Control Block. At
|
|
// the end of the period PortGetStatistics will be called to
|
|
// compute the difference.
|
|
//
|
|
// Returns: SUCCESS
|
|
// ERROR_PORT_NOT_OPEN
|
|
//*
|
|
|
|
DWORD
|
|
PortClearStatistics(HANDLE hIOPort)
|
|
{
|
|
#if 0
|
|
ASYMAC_GETSTATS A;
|
|
int i;
|
|
DWORD dwBytesReturned;
|
|
SERIALPCB *pSPCB;
|
|
|
|
memset (&overlapped, 0, sizeof (OVERLAPPED)) ;
|
|
|
|
DebugPrintf(("PortClearStatistics\n"));
|
|
|
|
|
|
// Find port in list
|
|
|
|
if ((pSPCB = FindPortInList(hIOPort, NULL)) == NULL)
|
|
return(ERROR_PORT_NOT_OPEN);
|
|
|
|
|
|
// Check whether Asyncmac is open
|
|
|
|
if (pSPCB->uRasEndpoint == INVALID_RASENDPOINT)
|
|
|
|
for (i=0; i<NUM_RAS_SERIAL_STATS; i++) // Asymac is closed
|
|
pSPCB->Stats[i] = 0;
|
|
|
|
else // Asyncmac is open
|
|
{
|
|
// Fill in GetStats struct
|
|
|
|
A.MacAdapter = NULL;
|
|
A.hNdisEndpoint = pSPCB->uRasEndpoint;
|
|
|
|
|
|
// Call Asymac
|
|
|
|
if (!DeviceIoControl(pSPCB->hAsyMac,
|
|
IOCTL_ASYMAC_GETSTATS,
|
|
&A,
|
|
sizeof(A),
|
|
&A,
|
|
sizeof(A),
|
|
&dwBytesReturned,
|
|
&overlapped))
|
|
return(GetLastError());
|
|
|
|
|
|
// Update Stats in Serial Port Control Block
|
|
|
|
pSPCB->Stats[BYTES_XMITED] = A.AsyMacStats.GenericStats.BytesTransmitted;
|
|
pSPCB->Stats[BYTES_RCVED] = A.AsyMacStats.GenericStats.BytesReceived;
|
|
pSPCB->Stats[FRAMES_XMITED] = A.AsyMacStats.GenericStats.FramesTransmitted;
|
|
pSPCB->Stats[FRAMES_RCVED] = A.AsyMacStats.GenericStats.FramesReceived;
|
|
|
|
pSPCB->Stats[CRC_ERR] = A.AsyMacStats.SerialStats.CRCErrors;
|
|
pSPCB->Stats[TIMEOUT_ERR] = A.AsyMacStats.SerialStats.TimeoutErrors;
|
|
pSPCB->Stats[ALIGNMENT_ERR] = A.AsyMacStats.SerialStats.AlignmentErrors;
|
|
pSPCB->Stats[SERIAL_OVERRUN_ERR]
|
|
= A.AsyMacStats.SerialStats.SerialOverrunErrors;
|
|
pSPCB->Stats[FRAMING_ERR] = A.AsyMacStats.SerialStats.FramingErrors;
|
|
pSPCB->Stats[BUFFER_OVERRUN_ERR]
|
|
= A.AsyMacStats.SerialStats.BufferOverrunErrors;
|
|
|
|
pSPCB->Stats[BYTES_XMITED_UNCOMP]
|
|
= A.AsyMacStats.CompressionStats.BytesTransmittedUncompressed;
|
|
|
|
pSPCB->Stats[BYTES_RCVED_UNCOMP]
|
|
= A.AsyMacStats.CompressionStats.BytesReceivedUncompressed;
|
|
|
|
pSPCB->Stats[BYTES_XMITED_COMP]
|
|
= A.AsyMacStats.CompressionStats.BytesTransmittedCompressed;
|
|
|
|
pSPCB->Stats[BYTES_RCVED_COMP]
|
|
= A.AsyMacStats.CompressionStats.BytesReceivedCompressed;
|
|
}
|
|
#endif
|
|
return(SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//* PortGetStatistics ------------------------------------------------------
|
|
//
|
|
// Function: This API reports MAC statistics since the last call to
|
|
// PortClearStatistics.
|
|
//
|
|
// Returns: SUCCESS
|
|
// ERROR_PORT_NOT_OPEN
|
|
//*
|
|
|
|
DWORD
|
|
PortGetStatistics(HANDLE hIOPort, RAS_STATISTICS *pStat)
|
|
{
|
|
#if 0
|
|
ASYMAC_GETSTATS A;
|
|
DWORD dwBytesReturned;
|
|
SERIALPCB *pSPCB;
|
|
|
|
memset (&overlapped, 0, sizeof (OVERLAPPED)) ;
|
|
|
|
DebugPrintf(("PortGetStatistics\n"));
|
|
|
|
|
|
// Find port in list
|
|
|
|
if ((pSPCB = FindPortInList(hIOPort, NULL)) == NULL)
|
|
return(ERROR_PORT_NOT_OPEN);
|
|
|
|
|
|
// Check whether Asyncmac is open
|
|
|
|
if (pSPCB->uRasEndpoint == INVALID_RASENDPOINT)
|
|
{
|
|
// Asyncmac is closed
|
|
// Report current counts
|
|
|
|
pStat->S_NumOfStatistics = NUM_RAS_SERIAL_STATS;
|
|
|
|
pStat->S_Statistics[BYTES_XMITED] = pSPCB->Stats[BYTES_XMITED];
|
|
pStat->S_Statistics[BYTES_RCVED] = pSPCB->Stats[BYTES_RCVED];
|
|
pStat->S_Statistics[FRAMES_XMITED] = pSPCB->Stats[FRAMES_XMITED];
|
|
pStat->S_Statistics[FRAMES_RCVED] = pSPCB->Stats[FRAMES_RCVED];
|
|
|
|
pStat->S_Statistics[CRC_ERR] = pSPCB->Stats[CRC_ERR];
|
|
pStat->S_Statistics[TIMEOUT_ERR] = pSPCB->Stats[TIMEOUT_ERR];
|
|
pStat->S_Statistics[ALIGNMENT_ERR] = pSPCB->Stats[ALIGNMENT_ERR];
|
|
pStat->S_Statistics[SERIAL_OVERRUN_ERR] = pSPCB->Stats[SERIAL_OVERRUN_ERR];
|
|
pStat->S_Statistics[FRAMING_ERR] = pSPCB->Stats[FRAMING_ERR];
|
|
pStat->S_Statistics[BUFFER_OVERRUN_ERR] = pSPCB->Stats[BUFFER_OVERRUN_ERR];
|
|
|
|
pStat->S_Statistics[BYTES_XMITED_UNCOMP]= pSPCB->Stats[BYTES_XMITED_UNCOMP];
|
|
pStat->S_Statistics[BYTES_RCVED_UNCOMP] = pSPCB->Stats[BYTES_RCVED_UNCOMP];
|
|
pStat->S_Statistics[BYTES_XMITED_COMP] = pSPCB->Stats[BYTES_XMITED_COMP];
|
|
pStat->S_Statistics[BYTES_RCVED_COMP] = pSPCB->Stats[BYTES_RCVED_COMP];
|
|
}
|
|
else
|
|
{
|
|
// Asyncmac is open
|
|
// Fill in GetStats struct
|
|
|
|
A.MacAdapter = NULL;
|
|
A.hNdisEndpoint = pSPCB->uRasEndpoint;
|
|
|
|
|
|
// Call Asymac to get current MAC statistics counts
|
|
|
|
if (!DeviceIoControl(pSPCB->hAsyMac,
|
|
IOCTL_ASYMAC_GETSTATS,
|
|
&A,
|
|
sizeof(A),
|
|
&A,
|
|
sizeof(A),
|
|
&dwBytesReturned,
|
|
&overlapped))
|
|
return(GetLastError());
|
|
|
|
|
|
// Find difference between last PortClearStatistics and current counts
|
|
|
|
pStat->S_NumOfStatistics = NUM_RAS_SERIAL_STATS;
|
|
|
|
pStat->S_Statistics[BYTES_XMITED]
|
|
= A.AsyMacStats.GenericStats.BytesTransmitted
|
|
- pSPCB->Stats[BYTES_XMITED];
|
|
|
|
pStat->S_Statistics[BYTES_RCVED]
|
|
= A.AsyMacStats.GenericStats.BytesReceived
|
|
- pSPCB->Stats[BYTES_RCVED];
|
|
|
|
pStat->S_Statistics[FRAMES_XMITED]
|
|
= A.AsyMacStats.GenericStats.FramesTransmitted
|
|
- pSPCB->Stats[FRAMES_XMITED];
|
|
|
|
pStat->S_Statistics[FRAMES_RCVED]
|
|
= A.AsyMacStats.GenericStats.FramesReceived
|
|
- pSPCB->Stats[FRAMES_RCVED];
|
|
|
|
pStat->S_Statistics[CRC_ERR]
|
|
= A.AsyMacStats.SerialStats.CRCErrors
|
|
- pSPCB->Stats[CRC_ERR];
|
|
|
|
pStat->S_Statistics[TIMEOUT_ERR]
|
|
= A.AsyMacStats.SerialStats.TimeoutErrors
|
|
- pSPCB->Stats[TIMEOUT_ERR];
|
|
|
|
pStat->S_Statistics[ALIGNMENT_ERR]
|
|
= A.AsyMacStats.SerialStats.AlignmentErrors
|
|
- pSPCB->Stats[ALIGNMENT_ERR];
|
|
|
|
pStat->S_Statistics[SERIAL_OVERRUN_ERR]
|
|
= A.AsyMacStats.SerialStats.SerialOverrunErrors
|
|
- pSPCB->Stats[SERIAL_OVERRUN_ERR];
|
|
|
|
pStat->S_Statistics[FRAMING_ERR]
|
|
= A.AsyMacStats.SerialStats.FramingErrors
|
|
- pSPCB->Stats[FRAMING_ERR];
|
|
|
|
pStat->S_Statistics[BUFFER_OVERRUN_ERR]
|
|
= A.AsyMacStats.SerialStats.BufferOverrunErrors
|
|
- pSPCB->Stats[BUFFER_OVERRUN_ERR];
|
|
|
|
pStat->S_Statistics[BYTES_XMITED_UNCOMP]
|
|
= A.AsyMacStats.CompressionStats.BytesTransmittedUncompressed
|
|
- pSPCB->Stats[BYTES_XMITED_UNCOMP];
|
|
|
|
pStat->S_Statistics[BYTES_RCVED_UNCOMP]
|
|
= A.AsyMacStats.CompressionStats.BytesReceivedUncompressed
|
|
- pSPCB->Stats[BYTES_RCVED_UNCOMP];
|
|
|
|
pStat->S_Statistics[BYTES_XMITED_COMP]
|
|
= A.AsyMacStats.CompressionStats.BytesTransmittedCompressed
|
|
- pSPCB->Stats[BYTES_XMITED_COMP];
|
|
|
|
pStat->S_Statistics[BYTES_RCVED_COMP]
|
|
= A.AsyMacStats.CompressionStats.BytesReceivedCompressed
|
|
- pSPCB->Stats[BYTES_RCVED_COMP];
|
|
}
|
|
#endif
|
|
return(SUCCESS);
|
|
}
|
|
|
|
|
|
//* PortSetFraming -------------------------------------------------------
|
|
//
|
|
// Function: Sets the framing type with the mac
|
|
//
|
|
// Returns: SUCCESS
|
|
//
|
|
//*
|
|
DWORD APIENTRY
|
|
PortSetFraming(HANDLE hIOPort, DWORD SendFeatureBits, DWORD RecvFeatureBits,
|
|
DWORD SendBitMask, DWORD RecvBitMask)
|
|
{
|
|
#if 0
|
|
ASYMAC_STARTFRAMING A;
|
|
DWORD dwBytesReturned;
|
|
SERIALPCB *pSPCB;
|
|
|
|
memset (&overlapped, 0, sizeof (OVERLAPPED)) ;
|
|
|
|
// Find port in list
|
|
|
|
if ((pSPCB = FindPortInList(hIOPort, NULL)) == NULL)
|
|
return(ERROR_PORT_NOT_OPEN);
|
|
|
|
A.MacAdapter = NULL ;
|
|
A.hNdisEndpoint = pSPCB->uRasEndpoint;
|
|
A.SendFeatureBits = SendFeatureBits;
|
|
A.RecvFeatureBits = RecvFeatureBits;
|
|
A.SendBitMask = SendBitMask;
|
|
A.RecvBitMask = RecvBitMask;
|
|
|
|
if (!DeviceIoControl(pSPCB->hAsyMac,
|
|
IOCTL_ASYMAC_STARTFRAMING,
|
|
&A,
|
|
sizeof(A),
|
|
&A,
|
|
sizeof(A),
|
|
&dwBytesReturned,
|
|
&overlapped))
|
|
return(GetLastError());
|
|
#endif
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
//* PortGetPortState -------------------------------------------------------
|
|
//
|
|
// Function: This API is used in MS-DOS only.
|
|
//
|
|
// Returns: SUCCESS
|
|
//
|
|
//*
|
|
|
|
DWORD APIENTRY
|
|
PortGetPortState(char *pszPortName, DWORD *pdwUsage)
|
|
{
|
|
DebugPrintf(("PortGetPortState\n"));
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//* PortChangeCallback -----------------------------------------------------
|
|
//
|
|
// Function: This API is used in MS-DOS only.
|
|
//
|
|
// Returns: SUCCESS
|
|
//
|
|
//*
|
|
|
|
DWORD APIENTRY
|
|
PortChangeCallback(HANDLE hIOPort)
|
|
{
|
|
DebugPrintf(("PortChangeCallback\n"));
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
DWORD APIENTRY
|
|
PortSetINetCfg(PVOID pvINetCfg)
|
|
{
|
|
((void) pvINetCfg);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
DWORD APIENTRY
|
|
PortSetIoCompletionPort ( HANDLE hIoCompletionPort)
|
|
{
|
|
((void) hIoCompletionPort);
|
|
|
|
return SUCCESS;
|
|
}
|