|
|
//============================================================================
// Copyright (c) 2000, Microsoft Corporation
//
// File: devlist.c
//
// History:
// Yi Sun July-26-2000 Created
//
// Abstract:
// TSPI_lineGetDevCaps queries a specified line device to determine
// its telephony capabilities. The returned cap structure doesn't change
// with time. This allows us to be able to save that structure so that
// we don't have to take a user/kernel transition for every GetCaps call.
// We also save negotiated/committed TSPI version and extension version
// so that we can verify version numbers passed in with a GetCaps call.
// Since TSPI_lineGetNumAddressIDs is based on TSPI_lineGetDevCaps, by
// implementing this optimization, we also save an IOCTL call for every
// GetNumAddressIDs call.
//============================================================================
#include "nt.h"
#include "ntrtl.h"
#include "nturtl.h"
#include "windows.h"
#include "tapi.h"
#include "ndptsp.h"
typedef struct _LINE_DEV_NODE { struct _LINE_DEV_NODE *pNext; LINEDEVCAPS *pCaps; DWORD dwDeviceID; DWORD dwNegTSPIV; // negotiated TSPI version
DWORD dwComTSPIV; // committed TSPI version
DWORD dwNegExtV; // negotiated ext version
DWORD dwComExtV; // committed ext version
} LINE_DEV_NODE, *PLINE_DEV_NODE;
typedef struct _LINE_DEV_LIST { CRITICAL_SECTION critSec; PLINE_DEV_NODE pHead;
} LINE_DEV_LIST, *PLINE_DEV_LIST;
static LINE_DEV_LIST gLineDevList;
//
// call InitLineDevList() in DllMain(): DLL_PROCESS_ATTACH
// to make sure that the dev list is initialized before
// TSPI version negotiation happens
//
VOID InitLineDevList() { InitializeCriticalSection(&gLineDevList.critSec); gLineDevList.pHead = NULL; }
//
// call UninitLineDevList() in DllMain(): DLL_PROCESS_DETACH
//
VOID UninitLineDevList() { while (gLineDevList.pHead != NULL) { PLINE_DEV_NODE pNode = gLineDevList.pHead; gLineDevList.pHead = gLineDevList.pHead->pNext;
if (pNode->pCaps != NULL) { FREE(pNode->pCaps); }
FREE(pNode); }
DeleteCriticalSection(&gLineDevList.critSec); }
PLINE_DEV_NODE GetLineDevNode( IN DWORD dwDeviceID ) { PLINE_DEV_NODE pNode; EnterCriticalSection(&gLineDevList.critSec);
pNode = gLineDevList.pHead; while ((pNode != NULL) && (pNode->dwDeviceID != dwDeviceID)) { pNode = pNode->pNext; }
if (pNode != NULL) { LeaveCriticalSection(&gLineDevList.critSec); return pNode; }
// pNode == NULL
// so allocate and zeroinit a node
pNode = (PLINE_DEV_NODE)MALLOC(sizeof(LINE_DEV_NODE)); if (NULL == pNode) { TspLog(DL_ERROR, "GetLineDevNode: failed to alloc LINE_DEV_NODE"); LeaveCriticalSection(&gLineDevList.critSec); return NULL; }
ASSERT(pNode != NULL); // init pNode
pNode->dwDeviceID = dwDeviceID;
// insert pNode into the list
pNode->pNext = gLineDevList.pHead; gLineDevList.pHead = pNode;
LeaveCriticalSection(&gLineDevList.critSec); return pNode; }
//
// TSPI_lineNegotiateTSPIVersion calls this function to pass
// the negotiated TSPI version number
//
LONG SetNegotiatedTSPIVersion( IN DWORD dwDeviceID, IN DWORD dwTSPIVersion ) { PLINE_DEV_NODE pNode; TspLog(DL_TRACE, "SetNegotiatedTSPIVersion: deviceID(%x), TSPIV(%x)", dwDeviceID, dwTSPIVersion);
EnterCriticalSection(&gLineDevList.critSec);
pNode = GetLineDevNode(dwDeviceID); if (NULL == pNode) { LeaveCriticalSection(&gLineDevList.critSec); return LINEERR_NOMEM; }
pNode->dwNegTSPIV = dwTSPIVersion;
LeaveCriticalSection(&gLineDevList.critSec); return TAPI_SUCCESS; }
//
// TSPI_lineNegotiateExtVersion calls this function to pass
// the negotiated extension version number
//
LONG SetNegotiatedExtVersion( IN DWORD dwDeviceID, IN DWORD dwExtVersion ) { PLINE_DEV_NODE pNode; TspLog(DL_TRACE, "SetNegotiatedExtVersion: deviceID(%x), ExtV(%x)", dwDeviceID, dwExtVersion);
EnterCriticalSection(&gLineDevList.critSec);
pNode = GetLineDevNode(dwDeviceID); if (NULL == pNode) { LeaveCriticalSection(&gLineDevList.critSec); return LINEERR_NOMEM; }
pNode->dwNegExtV = dwExtVersion;
LeaveCriticalSection(&gLineDevList.critSec); return TAPI_SUCCESS; }
//
// TSPI_lineSelectExtVersion calls this function to commit/decommit
// extension version. The ext version is decommitted by selecting ext
// version 0
//
LONG SetSelectedExtVersion( IN DWORD dwDeviceID, IN DWORD dwExtVersion ) { PLINE_DEV_NODE pNode;
TspLog(DL_TRACE, "SetSelectedExtVersion: deviceID(%x), ExtV(%x)", dwDeviceID, dwExtVersion);
EnterCriticalSection(&gLineDevList.critSec);
pNode = GetLineDevNode(dwDeviceID); if (NULL == pNode) { LeaveCriticalSection(&gLineDevList.critSec); return LINEERR_NOMEM; }
if ((dwExtVersion != 0) && (dwExtVersion != pNode->dwNegExtV)) { TspLog(DL_ERROR, "SetSelectedExtVersion: ext version(%x) not match "\ "the negotiated one(%x)", dwExtVersion, pNode->dwNegExtV);
LeaveCriticalSection(&gLineDevList.critSec); return LINEERR_INCOMPATIBLEEXTVERSION; }
pNode->dwComExtV = dwExtVersion;
LeaveCriticalSection(&gLineDevList.critSec); return TAPI_SUCCESS; }
//
// TSPI_lineOpen calls this function to commit TSPI version
//
LONG CommitNegotiatedTSPIVersion( IN DWORD dwDeviceID ) { PLINE_DEV_NODE pNode;
TspLog(DL_TRACE, "CommitNegotiatedTSPIVersion: deviceID(%x)", dwDeviceID);
EnterCriticalSection(&gLineDevList.critSec);
pNode = GetLineDevNode(dwDeviceID); if (NULL == pNode) { LeaveCriticalSection(&gLineDevList.critSec); return LINEERR_NOMEM; }
pNode->dwComTSPIV = pNode->dwNegTSPIV;
LeaveCriticalSection(&gLineDevList.critSec); return TAPI_SUCCESS; }
//
// TSPI_lineClose calls this function to decommit TSPI version
//
LONG DecommitNegotiatedTSPIVersion( IN DWORD dwDeviceID ) { PLINE_DEV_NODE pNode;
TspLog(DL_TRACE, "DecommitNegotiatedTSPIVersion: deviceID(%x)", dwDeviceID);
EnterCriticalSection(&gLineDevList.critSec);
pNode = GetLineDevNode(dwDeviceID); if (NULL == pNode) { LeaveCriticalSection(&gLineDevList.critSec); return LINEERR_NOMEM; }
pNode->dwComTSPIV = 0;
LeaveCriticalSection(&gLineDevList.critSec); return TAPI_SUCCESS; }
//
// actual implementation of TSPI_lineGetNumAddressIDs
//
LONG GetNumAddressIDs( IN DWORD dwDeviceID, OUT DWORD *pdwNumAddressIDs ) { PLINE_DEV_NODE pNode; EnterCriticalSection(&gLineDevList.critSec);
pNode = GetLineDevNode(dwDeviceID); if (NULL == pNode) { LeaveCriticalSection(&gLineDevList.critSec); return LINEERR_NOMEM; }
ASSERT(pNode != NULL); if (NULL == pNode->pCaps) { pNode->pCaps = GetLineDevCaps(dwDeviceID, pNode->dwComExtV); if (NULL == pNode->pCaps) { LeaveCriticalSection(&gLineDevList.critSec); return LINEERR_NOMEM; } }
ASSERT(pNode->pCaps != NULL); *pdwNumAddressIDs = pNode->pCaps->dwNumAddresses;
LeaveCriticalSection(&gLineDevList.critSec); return TAPI_SUCCESS; }
//
// actual implementation of TSPI_lineGetDevCaps
//
LONG GetDevCaps( IN DWORD dwDeviceID, IN DWORD dwTSPIVersion, IN DWORD dwExtVersion, OUT LINEDEVCAPS *pLineDevCaps ) { PLINE_DEV_NODE pNode; EnterCriticalSection(&gLineDevList.critSec);
pNode = GetLineDevNode(dwDeviceID); if (NULL == pNode) { LeaveCriticalSection(&gLineDevList.critSec); return LINEERR_NOMEM; }
ASSERT(pNode != NULL); //
// check the version numbers
//
if ((pNode->dwComTSPIV != 0) && (dwTSPIVersion != pNode->dwComTSPIV)) { TspLog(DL_ERROR, "GetDevCaps: tspi version(%x) not match"\ "the committed one(%x)", dwTSPIVersion, pNode->dwComTSPIV);
LeaveCriticalSection(&gLineDevList.critSec); return LINEERR_INCOMPATIBLEAPIVERSION; } if ((pNode->dwComExtV != 0) && (dwExtVersion != pNode->dwComExtV)) { TspLog(DL_ERROR, "GetDevCaps: ext version(%x) not match "\ "the committed one(%x)", dwExtVersion, pNode->dwComExtV);
LeaveCriticalSection(&gLineDevList.critSec); return LINEERR_INCOMPATIBLEEXTVERSION; }
if (NULL == pNode->pCaps) { pNode->pCaps = GetLineDevCaps(dwDeviceID, dwExtVersion); if (NULL == pNode->pCaps) { LeaveCriticalSection(&gLineDevList.critSec); return LINEERR_NOMEM; } }
ASSERT(pNode->pCaps != NULL); //
// copy caps over
//
if (pNode->pCaps->dwNeededSize > pLineDevCaps->dwTotalSize) { pLineDevCaps->dwNeededSize = pNode->pCaps->dwNeededSize; pLineDevCaps->dwUsedSize = (pLineDevCaps->dwTotalSize < sizeof(LINEDEVCAPS) ? pLineDevCaps->dwTotalSize : sizeof(LINEDEVCAPS));
ASSERT(pLineDevCaps->dwUsedSize >= 10); // reset dwProviderInfoSize to dwLineNameOffset to 0
ZeroMemory(&pLineDevCaps->dwProviderInfoSize, 7 * sizeof(DWORD)); // copy over dwPermanentLineID
pLineDevCaps->dwPermanentLineID = pNode->pCaps->dwPermanentLineID; // copy everything from dwStringFormat
CopyMemory(&pLineDevCaps->dwStringFormat, &pNode->pCaps->dwStringFormat, pLineDevCaps->dwUsedSize - 10 * sizeof(DWORD));
// we don't need to set dwTerminalCaps(Size, Offset),
// dwTerminalText(Size, Offset), etc. to 0
// because these fields have been preset with 0
// before the service provider was called
} else { // copy over all fields except dwTotalSize
CopyMemory(&pLineDevCaps->dwNeededSize, &pNode->pCaps->dwNeededSize, pNode->pCaps->dwNeededSize - sizeof(DWORD)); }
LeaveCriticalSection(&gLineDevList.critSec); return TAPI_SUCCESS; }
|