📄 misc.c
字号:
/**************************************************************************/
/** Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved. **/
/**************************************************************************/
//
// misc.c Support files for Telephony Service Provider Interface
//
// @doc EX_TSPI
//
// @topic TSPI |
//
// Tspi utilities
//
//
#include "windows.h"
#include "types.h"
#include "memory.h"
#include "mcx.h"
#include "tspi.h"
#include "tspip.h"
#include "linklist.h"
extern const WCHAR szSettings[];
extern const WCHAR szDialSuffix[];
const WCHAR szDefaultsName[] = TEXT("Drivers\\Unimodem");
// Unimodem thread priority
#define DEFAULT_THREAD_PRIORITY 150
#define REGISTRY_PRIORITY_VALUE TEXT("Priority256")
DWORD g_dwUnimodemThreadPriority;
const DEVMINICFG DefaultDevCfg =
{
DEVMINCFG_VERSION, // Version
0x00, // WaitBong
90, // CallSetupFail
0, // ModemOptions
19200, // Baud Rate
0, // Options
8, // Byte Size
0, // Stop Bits
0 // Parity
};
extern HANDLE g_hCoreDLL;
//
// Function to complete an outstanding async operation
// (unimodem can only handle one outstanding async operation per linedev)
//
// NOTE: Must be called holding the OpenCS
//
void
CompleteAsyncOp(
PTLINEDEV pLineDev
)
{
DWORD dwID;
DWORD dwStatus;
DEBUGMSG(ZONE_FUNC|ZONE_ASYNC, (TEXT("UNIMODEM:+CompleteAsyncOp\n")));
dwID = pLineDev->dwPendingID;
dwStatus = pLineDev->dwPendingStatus;
switch (pLineDev->dwPendingType) {
case PENDING_LINEACCEPT:
case PENDING_LINEANSWER:
case PENDING_LINEDEVSPECIFIC:
case PENDING_LINEDIAL:
case PENDING_LINEDROP:
case PENDING_LINEMAKECALL:
LeaveCriticalSection(&pLineDev->OpenCS);
DEBUGMSG(ZONE_ASYNC, (TEXT("UNIMODEM:CompleteAsyncOp completing Op %s(0x%x)\n"),
GetPendingName(pLineDev->dwPendingType), dwID));
TspiGlobals.fnCompletionCallback(dwID, dwStatus);
EnterCriticalSection(&pLineDev->OpenCS);
break;
}
pLineDev->dwPendingID = INVALID_PENDINGID;
pLineDev->dwPendingType = INVALID_PENDINGOP;
pLineDev->dwPendingStatus = 0;
DEBUGMSG(ZONE_FUNC|ZONE_ASYNC, (TEXT("UNIMODEM:-CompleteAsyncOp\n")));
} // CompleteAsyncOp
//
// NOTE on async operations:
// The function that invokes an async operation (TSPI_lineMakeCall, TSPI_lineAnswer, etc)
// first calls ControlThreadCmd which calls SetAsyncOp. Just before returning it calls
// SetAsyncID in order to avoid calling the TAPI completion callback before the user
// knows the async ID. The UnimodemControlThread will call SetAsyncStatus when the
// async operation has completed. If the ID has been set, then SetAsyncStatus will perform
// the callback.
//
//
// Set the async ID for a pending operation. This signals that the function which
// invoked the async operation has completed so any subsequent SetAsyncStatus call
// will cause a completion callback to TAPI. If the invoked async operation has
// already completed (SetAsyncStatus already called), then we need to kick off a
// thread to make the callback for this completed async operation.
//
// Return LINEERR_OPERATIONFAILED if this async operation has been aborted, else
// return async ID.
//
DWORD
SetAsyncID(
PTLINEDEV pLineDev,
DWORD dwID
)
{
DWORD dwRet = LINEERR_OPERATIONFAILED;
DEBUGMSG(ZONE_FUNC|ZONE_ASYNC, (TEXT("UNIMODEM:+SetAsyncID\n")));
EnterCriticalSection(&pLineDev->OpenCS);
if (pLineDev->dwPendingID != INVALID_PENDINGID) {
LeaveCriticalSection(&pLineDev->OpenCS);
} else {
pLineDev->dwPendingID = dwID;
dwRet = dwID;
//
// If the operation has completed then we need to do the callback on another thread
//
if (pLineDev->dwPendingStatus != LINEERR_ALLOCATED) {
LeaveCriticalSection(&pLineDev->OpenCS);
if (!StartCompleteAsyncOp(pLineDev)) {
dwRet = LINEERR_OPERATIONFAILED;
}
} else {
LeaveCriticalSection(&pLineDev->OpenCS);
}
}
DEBUGMSG(ZONE_FUNC|ZONE_ASYNC, (TEXT("UNIMODEM:-SetAsyncID 0x%x\n"), dwRet));
return dwRet;
} // SetAsyncID
//
// Set the status for a pending async operation and complete it if possible.
//
void
SetAsyncStatus(
PTLINEDEV pLineDev,
DWORD dwNewStatus
)
{
DEBUGMSG(ZONE_FUNC|ZONE_ASYNC, (TEXT("UNIMODEM:+SetAsyncStatus\n")));
EnterCriticalSection(&pLineDev->OpenCS);
//
// Is there a pending operation to complete?
//
if (pLineDev->dwPendingType != INVALID_PENDINGOP) {
pLineDev->dwPendingStatus = dwNewStatus;
if (pLineDev->dwPendingID != INVALID_PENDINGID) {
CompleteAsyncOp(pLineDev);
}
}
LeaveCriticalSection(&pLineDev->OpenCS);
DEBUGMSG(ZONE_FUNC|ZONE_ASYNC, (TEXT("UNIMODEM:-SetAsyncStatus\n")));
} // SetAsyncStatus
//
// Abort any previously pending operation and record new pending operation
// (called by async TSPI_line* functions)
//
void
SetAsyncOp(
PTLINEDEV pLineDev,
DWORD dwNewOp
)
{
DEBUGMSG(ZONE_FUNC|ZONE_ASYNC, (TEXT("UNIMODEM:+SetAsyncOp\n")));
EnterCriticalSection(&pLineDev->OpenCS);
//
// Is there a pending operation that we need to abort?
//
if (pLineDev->dwPendingType != INVALID_PENDINGOP) {
LeaveCriticalSection(&pLineDev->OpenCS);
SetAsyncStatus(pLineDev, LINEERR_OPERATIONFAILED);
EnterCriticalSection(&pLineDev->OpenCS);
}
pLineDev->dwPendingType = dwNewOp;
pLineDev->dwPendingStatus = LINEERR_ALLOCATED;
pLineDev->dwPendingID = INVALID_PENDINGID;
LeaveCriticalSection(&pLineDev->OpenCS);
DEBUGMSG(ZONE_FUNC|ZONE_ASYNC, (TEXT("UNIMODEM:-SetAsyncOp\n")));
} // SetAsyncOp
typedef struct _ASYNCCMD {
DWORD dwRequestID;
DWORD dwResult;
} ASYNCCMD, * PASYNCCMD;
DWORD
AsyncCompleteThread(
PVOID lpvIn
)
{
PASYNCCMD pCmd = (PASYNCCMD)lpvIn;
DEBUGMSG(ZONE_ASYNC, (TEXT("UNIMODEM:AsyncCompleteThread completing ID(0x%x) result 0x%x\n"),
pCmd->dwRequestID, pCmd->dwResult));
TspiGlobals.fnCompletionCallback(pCmd->dwRequestID, pCmd->dwResult);
TSPIFree(pCmd);
return 0;
} // AsyncCompleteThread
BOOL
StartCompleteAsyncOp(
PTLINEDEV pLineDev
)
{
HANDLE hThd;
PASYNCCMD pCmd;
if (NULL == (pCmd = TSPIAlloc(sizeof(ASYNCCMD)))) {
DEBUGMSG(1, (TEXT("UNIMODEM:StartCompleteAsyncOp Unable to allocate ASYNCCMD!!!\n")));
return FALSE;
}
EnterCriticalSection(&pLineDev->OpenCS);
pCmd->dwRequestID = pLineDev->dwPendingID;
pCmd->dwResult = pLineDev->dwPendingStatus;
pLineDev->dwPendingID = INVALID_PENDINGID;
pLineDev->dwPendingType = INVALID_PENDINGOP;
pLineDev->dwPendingStatus = 0;
LeaveCriticalSection(&pLineDev->OpenCS);
hThd = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)AsyncCompleteThread,
pCmd, 0, NULL );
if (!hThd) {
DEBUGMSG(1, (TEXT("UNIMODEM:StartCompleteAsyncOp Unable to Create AsyncCompleteThread!!!\n")));
TSPIFree(pCmd);
return FALSE;
}
CloseHandle(hThd);
return TRUE;
} // StartCompleteAsyncOp
//
// Read the default devconfig for this device from the registry
//
VOID
getDefaultDevConfig(
PTLINEDEV ptLineDev,
PDEVMINICFG pDevMiniCfg
)
{
static const WCHAR szDevConfig[] = TEXT("DevConfig");
DWORD dwSize, dwRetCode;
DEBUGMSG(ZONE_FUNC | ZONE_INIT,
(TEXT("UNIMODEM:+getDefaultDevConfig\r\n")));
// Get the default device config from the registry
dwSize = sizeof( DEVMINICFG );
dwRetCode = MdmRegGetValue(ptLineDev, NULL, szDevConfig, REG_BINARY,
(LPBYTE)pDevMiniCfg, &dwSize);
if( (dwRetCode != ERROR_SUCCESS) ||
(pDevMiniCfg->wVersion != DEVMINCFG_VERSION) ||
(dwSize < (sizeof(DEVMINICFG) - (DIAL_MODIFIER_LEN*sizeof(WCHAR)) )))
{
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(TEXT("UNIMODEM:Device Config error, retcode x%X, version x%X (x%X), Size x%X (x%X)\r\n"),
dwRetCode,
pDevMiniCfg->wVersion, DEVMINCFG_VERSION,
dwSize, (sizeof(DEVMINICFG) - (DIAL_MODIFIER_LEN*sizeof(WCHAR)) )) );
// Either the registry value is missing, or it is invalid.
// We need some default, use the one in ROM
*pDevMiniCfg = DefaultDevCfg;
}
pDevMiniCfg->szDialModifier[DIAL_MODIFIER_LEN] = 0; // make sure it is null terminated
DEBUGMSG(ZONE_INIT,
(TEXT("UNIMODEM:Done reading Device Config, retcode x%X\r\n"),
dwRetCode));
DEBUGMSG(ZONE_INIT,
(TEXT("UNIMODEM:Version x%X\tWait Bong x%X\tCall Setup Fail x%X\r\n"),
ptLineDev->DevMiniCfg.wVersion,
ptLineDev->DevMiniCfg.wWaitBong,
ptLineDev->DevMiniCfg.dwCallSetupFailTimer));
DEBUGMSG(ZONE_INIT,
(TEXT("UNIMODEM:Baud %d\tByte Size %d\tStop Bits %d\tParity %d\r\n"),
ptLineDev->DevMiniCfg.dwBaudRate,
ptLineDev->DevMiniCfg.ByteSize,
ptLineDev->DevMiniCfg.StopBits,
ptLineDev->DevMiniCfg.Parity));
DEBUGMSG(ZONE_FUNC | ZONE_INIT,
(TEXT("UNIMODEM:-getDefaultDevConfig\r\n")));
}
//
// Create a LineDev
//
PTLINEDEV
createLineDev(
HKEY hActiveKey,
LPCWSTR lpszDevPath,
LPCWSTR lpszDeviceName
)
{
PTLINEDEV ptLineDev;
PTLINEDEV ptExistingDev;
static const WCHAR szDeviceType[] = TEXT("DeviceType");
static const WCHAR szPortName[] = TEXT("Port");
static const WCHAR szFriendlyName[] = TEXT("FriendlyName");
static const WCHAR szPnpIdName[] = TEXT("PnpId");
static const WCHAR szMaxCmd[] = TEXT("MaxCmd");
static const WCHAR szDialBilling[] = TEXT("DialBilling");
DWORD dwSize, dwRetCode, dwTemp;
WCHAR szContinuation[16];
DEBUGMSG(ZONE_FUNC|ZONE_INIT,
(TEXT("UNIMODEM:+createLineDev\r\n")));
// We are being asked to create a new linedev - do it
if (!(ptLineDev = (PTLINEDEV) TSPIAlloc(sizeof(TLINEDEV)) )) {
return NULL;
}
// Initialize all of the fields
ptLineDev->dwPendingID = INVALID_PENDINGID;
ptLineDev->dwDefaultMediaModes = LINEMEDIAMODE_DATAMODEM; // Do this early, NullifyLine uses it
ptLineDev->bControlThreadRunning = FALSE;
NullifyLineDevice( ptLineDev, TRUE ); // also calls getDefaultDevConfig
// Get the device registry handle for later use.
dwRetCode = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
lpszDevPath,
0,
KEY_READ,
&ptLineDev->hSettingsKey);
if (ERROR_SUCCESS != dwRetCode) {
// We can't very well continue if the registry values aren't there.
DEBUGMSG(ZONE_ERROR|ZONE_INIT,
(TEXT("UNIMODEM:createLineDev - RegOpenKeyEx %s returned %d.\r\n"),
lpszDevPath, dwRetCode));
goto abort_buffer_allocated;
} else {
DEBUGMSG(ZONE_MISC|ZONE_INIT,
(TEXT("UNIMODEM:createLineDev - RegOpenKeyEx %s handle x%X.\r\n"),
lpszDevPath, ptLineDev->hSettingsKey));
}
// Record the port name, or read it ourselves if NULL
if( NULL == lpszDeviceName ) {
// Get the port name from registry
dwSize = MAXDEVICENAME;
dwRetCode = MdmRegGetValue(ptLineDev, NULL, szPortName, REG_SZ,
(LPBYTE)ptLineDev->szDeviceName, &dwSize);
if( dwRetCode != ERROR_SUCCESS ) {
// We can't do much without a port, abort now.
goto abort_registry_opened;
}
} else {
wcscpy( ptLineDev->szDeviceName, lpszDeviceName );
}
// Get the device type from registry
dwSize = sizeof( DWORD );
dwRetCode = MdmRegGetValue(ptLineDev, NULL, szDeviceType, REG_DWORD,
(LPBYTE)&dwTemp, &dwSize);
if( dwRetCode == ERROR_SUCCESS ) {
DEBUGMSG(ZONE_MISC|ZONE_INIT,
(TEXT("UNIMODEM:createLineDev - Device type x%X.\r\n"), dwTemp));
ptLineDev->wDeviceType = (WORD)dwTemp;
} else {
DEBUGMSG(ZONE_MISC|ZONE_INIT,
(TEXT("UNIMODEM:createLineDev - Device type defaulting to NULL_MODEM.\r\n")));
ptLineDev->wDeviceType = DT_NULL_MODEM; // default type is null
}
// Get the maximum command length from registry
dwSize = sizeof( DWORD );
dwRetCode = MdmRegGetValue(ptLineDev, szSettings, szMaxCmd, REG_DWORD,
(LPBYTE)&dwTemp, &dwSize);
if( dwRetCode == ERROR_SUCCESS ) {
DEBUGMSG(ZONE_MISC|ZONE_INIT,
(TEXT("UNIMODEM:createLineDev - Max command length x%X.\r\n"), dwTemp));
ptLineDev->dwMaxCmd = (WORD)dwTemp;
} else {
DEBUGMSG(ZONE_MISC|ZONE_INIT,
(TEXT("UNIMODEM:createLineDev - Max command length defaulting to x%X.\r\n"), MAX_CMD_LENGTH));
ptLineDev->dwMaxCmd = MAX_CMD_LENGTH;
}
// Get modem command continuation character - assume it is the first character of the dial suffix
dwSize = sizeof( szContinuation );
if (ERROR_SUCCESS != MdmRegGetValue(ptLineDev, szSettings, szDialSuffix,
REG_SZ, (PUCHAR)szContinuation, &dwSize) ) {
ptLineDev->chContinuation = ';';
} else {
ptLineDev->chContinuation = szContinuation[0];
}
//
// Get modem dial capabilities
//
ptLineDev->dwDevCapFlags = LINEDEVCAPFLAGS_DIALQUIET |
LINEDEVCAPFLAGS_DIALDIALTONE |
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -