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.
415 lines
11 KiB
415 lines
11 KiB
//============================================================================
|
|
// 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 "kmddsp.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;
|
|
}
|