Leaked source code of windows server 2003
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

//============================================================================
// 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;
}