| ..back |
/***********************************************************************/
/**Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved**/
/***********************************************************************/
//
// tapi.c The Telephony Service Provider Interface
//
// @doc EX_TSPI
//
// @topic TSPI |
//
// Tspi Stuff
//
//
#include "windows.h"
#include "types.h"
#include "memory.h"
#include "mcx.h"
#include "tspi.h"
#include "linklist.h"
#include "tspip.h"
#include "tapicomn.h"
#include "config.h"
#include "resource.h"
TSPIGLOBALS TspiGlobals;
const GETIDINFO aGetID[] ={{TEXT("tapi/line"), STRINGFORMAT_BINARY},
{TEXT("comm"), STRINGFORMAT_UNICODE},
{TEXT("comm/datamodem"),STRINGFORMAT_BINARY},
{TEXT("ndis"), STRINGFORMAT_BINARY}};
const WCHAR g_szzClassList[] = {TEXT("tapi/line")TEXT("\0")
TEXT("comm")TEXT("\0")
TEXT("comm/datamodem")TEXT("\0")
TEXT("ndis")TEXT("\0\0")};
const WCHAR g_szDeviceClass[] = TEXT("com");
extern const WCHAR szSettings[];
extern const WCHAR szDialSuffix[];
HANDLE g_hCoreDLL;
// Debug Zones.
#ifdef DEBUG
DBGPARAM dpCurSettings = {
TEXT("Unimodem"), {
TEXT("Init"), TEXT("Temp"), TEXT("Async"), TEXT(""),
TEXT(""), TEXT(""), TEXT(""), TEXT("Dial"),
TEXT("Thread"), TEXT("Lists"), TEXT("Call State"), TEXT("Misc"),
TEXT("Alloc"), TEXT("Function"), TEXT("Warning"), TEXT("Error") },
0xC000
};
#endif
extern BOOL IsAPIReady(DWORD dwAPISet);
// **********************************************************************
// First, we have the TSPI_provider functions
// **********************************************************************
LONG TSPIAPI
TSPI_providerInit(
DWORD dwTSPIVersion, // @parm TSPI Version - in
DWORD dwPermanentProviderID, // @parm Permanent Provider ID - in
DWORD dwLineDeviceIDBase, // @parm Line Base ID - in
DWORD dwPhoneDeviceIDBase, // @parm phone Base ID - in
DWORD dwNumLines, // @parm Number of lines - in
DWORD dwNumPhones, // @parm Number of phones - in
ASYNC_COMPLETION lpfnCompletionProc, // @parm Pointer to callback - in
LPDWORD lpdwTSPIOptions // @parm Optional Behaviour Flags - out
)
{
DEBUGMSG(ZONE_FUNC|ZONE_INIT,
(TEXT("UNIMODEM:+TSPI_providerInit, dwPPID 0x%X, dwDeviceIDBase 0x%X, dwNumLines 0x%X\n"),
dwPermanentProviderID,
dwLineDeviceIDBase,
dwNumLines));
TspiGlobals.fnCompletionCallback = lpfnCompletionProc;
DEBUGMSG(ZONE_FUNC|ZONE_INIT, (TEXT("UNIMODEM:-TSPI_providerInit\n")));
return SUCCESS;
}
LONG TSPIAPI
TSPI_providerInstall(
HWND hwndOwner,
DWORD dwPermanentProviderID
)
{
DEBUGMSG(ZONE_FUNC|ZONE_INIT,
(TEXT("UNIMODEM:+TSPI_providerInstall, dwPPID 0x%X\n"),
dwPermanentProviderID ));
// Unimodem doesn't really need an install. Just say OK.
DEBUGMSG(ZONE_FUNC|ZONE_INIT, (TEXT("UNIMODEM:-TSPI_providerInstall\n")));
return SUCCESS;
}
LONG TSPIAPI
TSPI_providerShutdown(
DWORD dwTSPIVersion
)
{
DEBUGMSG(ZONE_FUNC|ZONE_INIT, (TEXT("UNIMODEM:+TSPI_providerShutdown\n")));
DEBUGMSG(ZONE_FUNC|ZONE_INIT, (TEXT("UNIMODEM:-TSPI_providerShutdown\n")));
return SUCCESS;
}
LONG TSPIAPI TSPI_providerEnumDevices(
DWORD dwPermanentProviderID,
LPDWORD lpdwNumLines,
LPDWORD lpdwNumPhones,
HPROVIDER hProvider,
LINEEVENT lpfnLineCreateProc,
PHONEEVENT lpfnPhoneCreateProc
)
{
DEBUGMSG(ZONE_FUNC|ZONE_INIT, (TEXT("UNIMODEM:+TSPI_providerEnumDevices\n")));
*lpdwNumLines = 0;
// This should be the same event proc that gets passed in to
// lineOpen. but I need it here and now so that I can notify
// TAPI about devices coming and going. I'll probably go ahead
// and store the per device copy just in case TAPI decides that
// the two funcs should be different for some reason.
TspiGlobals.fnLineEventProc = lpfnLineCreateProc;
TspiGlobals.dwProviderID = dwPermanentProviderID;
TspiGlobals.hProvider = hProvider;
// Note that the only devices that we actually enumerate are
// the external modems. All other entries are created when the
// device loader loads the physical device and notifies us about
// it.
EnumExternModems();
DEBUGMSG(ZONE_FUNC|ZONE_INIT, (TEXT("UNIMODEM:-TSPI_providerEnumDevices\n")));
return SUCCESS;
}
// **********************************************************************
// Then, we have the TSPI_line functions
// **********************************************************************
//
// This function serves as a stub in the vtbl for any of the TSPI
// functions which we choose not to support
//
LONG
TSPIAPI
TSPI_Unsupported( void )
{
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_Unsupported\n")));
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_Unsupported\n")));
return LINEERR_OPERATIONUNAVAIL;
}
LONG
TSPIAPI
TSPI_lineAccept(
DRV_REQUESTID dwRequestID,
HDRVCALL hdCall,
LPCSTR lpsUserUserInfo,
DWORD dwSize
)
{
PTLINEDEV pLineDev;
LONG rc;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineAccept\n")));
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdCall)) == NULL) {
DEBUGMSG(ZONE_ERROR|ZONE_CALLS, (TEXT("UNIMODEM:TSPI_lineAccept ** Invalid Call Handle\n")));
rc = LINEERR_INVALCALLHANDLE;
goto exitPoint;
}
if (LINECALLSTATE_OFFERING == pLineDev->dwCallState) {
SetAsyncOp(pLineDev, PENDING_LINEACCEPT);
SetAsyncStatus(pLineDev, 0);
NewCallState(pLineDev, LINECALLSTATE_ACCEPTED, 0);
rc = SetAsyncID(pLineDev, dwRequestID);
} else {
DEBUGMSG(ZONE_ERROR|ZONE_CALLS, (TEXT("UNIMODEM:TSPI_lineAccept ** Invalid Call State\n")));
rc = LINEERR_INVALCALLSTATE;
}
exitPoint:
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineAccept %x\n"), rc));
return rc;
}
LONG
TSPIAPI
TSPI_lineAnswer(
DRV_REQUESTID dwRequestID,
HDRVCALL hdCall,
LPCSTR lpsUserUserInfo,
DWORD dwSize
)
{
LONG rc;
PTLINEDEV pLineDev;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineAnswer\n")));
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdCall)) == NULL) {
DEBUGMSG(ZONE_ERROR|ZONE_CALLS, (TEXT("UNIMODEM:TSPI_lineAnswer ** Invalid Call Handle\n")));
rc = LINEERR_INVALCALLHANDLE;
goto exitPoint;
}
if ((pLineDev->dwCallState != LINECALLSTATE_OFFERING) &&
(pLineDev->dwCallState != LINECALLSTATE_ACCEPTED)) {
DEBUGMSG(ZONE_ERROR|ZONE_CALLS, (TEXT("UNIMODEM:TSPI_lineAnswer ** Invalid Call State\n")));
rc = LINEERR_INVALCALLSTATE;
goto exitPoint;
}
rc = ControlThreadCmd(pLineDev, PENDING_LINEANSWER, dwRequestID);
if (!(rc & 0x80000000)) {
rc = SetAsyncID(pLineDev, dwRequestID);
}
exitPoint:
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineAnswer %x\n"), rc));
return rc;
} // TSPI_lineAnswer
//
// Close a specified open line device
//
LONG TSPIAPI
TSPI_lineClose(
HDRVLINE hdLine
)
{
PTLINEDEV pLineDev;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineClose\n")));
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdLine)) == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:-TSPI_lineClose ** Invalid Line Handle\n")));
return LINEERR_OPERATIONFAILED;
}
EnterCriticalSection(&pLineDev->OpenCS);
pLineDev->dwDetMediaModes = 0;
pLineDev->htLine = NULL;
LeaveCriticalSection(&pLineDev->OpenCS);
if (ControlThreadCmd(pLineDev, PENDING_EXIT, INVALID_PENDINGID)) {
// Make sure that we do not leave anything open
DevlineClose(pLineDev, TRUE);
}
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineClose\n")));
return SUCCESS;
}
LONG TSPIAPI
TSPI_lineCloseCall(
HDRVCALL hdCall
)
{
LONG rc;
PTLINEDEV pLineDev;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineCloseCall\n")));
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdCall)) == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineCloseCall ** Invalid Call Handle\n")));
rc = LINEERR_OPERATIONFAILED;
goto exitPoint;
}
// Mark call as unused
pLineDev->dwCallFlags &= ~(CALL_ALLOCATED|CALL_ACTIVE);
pLineDev->htCall = NULL;
rc = 0;
exitPoint:
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineCloseCall\n")));
return rc;
}
LONG TSPIAPI
TSPI_lineConditionalMediaDetection(
HDRVLINE hdLine,
DWORD dwMediaModes,
LPLINECALLPARAMS const lpCallParams
)
{
LONG rc;
PTLINEDEV pLineDev;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineConditionalMediaDetection\n")));
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdLine)) == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineConditionalMediaDetection ** Invalid Line Handle\n")));
rc = LINEERR_OPERATIONFAILED;
goto exitPoint;
}
// Check the requested modes. There must be only our media modes.
//
if (dwMediaModes & ~pLineDev->dwMediaModes) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineConditionalMediaDetection ** Invalid Media Mode\n")));
rc = LINEERR_INVALMEDIAMODE;
goto exitPoint;
}
// Check the call paramaters
//
if ((lpCallParams->dwBearerMode & (~pLineDev->dwBearerModes)) ||
(lpCallParams->dwMediaMode & (~pLineDev->dwMediaModes)) ||
(lpCallParams->dwAddressMode & (~LINEADDRESSMODE_ADDRESSID))) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineConditionalMediaDetection ** Invalid Call Params\n")));
rc = LINEERR_INVALCALLPARAMS;
goto exitPoint;
}
if ((lpCallParams->dwAddressType) && (lpCallParams->dwAddressType != LINEADDRESSTYPE_PHONENUMBER)) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineConditionalMediaDetection ** Invalid Call Params Address Type\n")));
rc = LINEERR_INVALCALLPARAMS;
goto exitPoint;
}
rc = 0;
exitPoint:
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineConditionalMediaDetection\n")));
return rc;
} // TSPI_lineConditionalMediaDetection
LONG TSPIAPI
TSPI_lineConfigDialogEdit(
DWORD dwDeviceID,
HWND hwndOwner,
LPCWSTR lpszDeviceClass,
LPVOID const lpDeviceConfigIn,
DWORD dwSize,
LPVARSTRING lpDeviceConfigOut
)
{
PTLINEDEV pLineDev;
BYTE cbSize;
DWORD dwRet = SUCCESS;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineConfigDialogEdit\n")));
// Validate the input/output buffer
//
if (lpDeviceConfigOut == NULL) {
DEBUGMSG(ZONE_FUNC|ZONE_ERROR, (TEXT("UNIMODEM:-TSPI_lineConfigDialogEdit Invalid lpDeviceConfigOut\n")));
return LINEERR_INVALPOINTER;
}
if (lpDeviceConfigIn == NULL) {
DEBUGMSG(ZONE_FUNC|ZONE_ERROR, (TEXT("UNIMODEM:-TSPI_lineConfigDialogEdit Invalid lpDeviceConfigIn\n")));
return LINEERR_INVALPOINTER;
}
if (lpDeviceConfigOut->dwTotalSize < sizeof(VARSTRING)) {
DEBUGMSG(ZONE_FUNC|ZONE_ERROR, (TEXT("UNIMODEM:-TSPI_lineConfigDialogEdit lpDeviceConfigOut too small\n")));
return LINEERR_STRUCTURETOOSMALL;
}
// Validate the requested device class
//
if (lpszDeviceClass != NULL)
{
if (!ValidateDevCfgClass(lpszDeviceClass))
return LINEERR_INVALDEVICECLASS;
};
// Validate the device ID
//
if ((pLineDev = GetLineDevfromID(dwDeviceID)) == NULL)
return LINEERR_NODEVICE;
// Validate the device configuration structure
//
if (pLineDev->DevMiniCfg.wVersion != ((PDEVMINICFG)lpDeviceConfigIn)->wVersion)
return LINEERR_INVALPARAM;
// Set the output buffer size
//
cbSize = sizeof( DEVMINICFG );
lpDeviceConfigOut->dwUsedSize = sizeof(VARSTRING);
lpDeviceConfigOut->dwNeededSize = sizeof(VARSTRING) + cbSize;
// Validate the output buffer size
//
if (lpDeviceConfigOut->dwTotalSize >= lpDeviceConfigOut->dwNeededSize)
{
PDEVMINICFG pDevMiniConfig;
// Initialize the buffer
//
lpDeviceConfigOut->dwStringFormat = STRINGFORMAT_BINARY;
lpDeviceConfigOut->dwStringSize = cbSize;
lpDeviceConfigOut->dwStringOffset = sizeof(VARSTRING);
lpDeviceConfigOut->dwUsedSize += cbSize;
pDevMiniConfig = (PDEVMINICFG)(lpDeviceConfigOut+1);
// Bring up property sheets for modems and get the updated commconfig
//
if (!TSPI_EditMiniConfig(hwndOwner, pLineDev, (PDEVMINICFG)lpDeviceConfigIn, pDevMiniConfig))
{
DEBUGMSG(ZONE_MISC,(TEXT("UNIMODEM:TSPI_lineConfigDialogEdit User canceled in line config dialog\n")));
}
DEBUGMSG(ZONE_DIAL,
(TEXT("UNIMODEM:TSPI_lineConfigDialogEdit After config dialog edit, Dial Modifier %s\n"), pDevMiniConfig->szDialModifier));
}
else
{
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:TSPI_lineConfigDialogEdit Insufficient space in output buffer (passed %d, needed %d)\n"),
lpDeviceConfigOut->dwTotalSize, lpDeviceConfigOut->dwNeededSize));
}
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:-TSPI_lineConfigDialogEdit x%X (Used %d, Need %d)\n"),
dwRet, lpDeviceConfigOut->dwUsedSize, lpDeviceConfigOut->dwNeededSize));
return dwRet;
}
//
// Unimodem specific extensions - see common\oak\inc\unimodem.h for more details. Currently only setting properties of
// a DEVMINCONFIG is supported.
//
LONG TSPIAPI
TSPI_lineDevSpecific(
DRV_REQUESTID dwRequestID,
HDRVLINE hdLine,
DWORD dwAddressID,
HDRVCALL hdCall,
LPVOID lpParams,
DWORD dwSize
)
{
DWORD rc;
LPDWORD lpdwCmd;
PTLINEDEV pLineDev;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineDevSpecific\n")));
lpdwCmd = (LPDWORD)lpParams; // The first 4 bytes is the command code
switch (*lpdwCmd) {
case UNIMDM_CMD_CHG_DEVCFG:
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdLine)) == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineDevSpecific ** Invalid Line Handle\n")));
rc = LINEERR_OPERATIONFAILED;
goto exitPoint;
}
SetAsyncOp(pLineDev, PENDING_LINEDEVSPECIFIC);
if (rc = DevSpecificLineConfigEdit(pLineDev,(PUNIMDM_CHG_DEVCFG)lpParams)) {
goto exitPoint;
}
SetAsyncStatus(pLineDev, 0);
break;
default:
rc = LINEERR_OPERATIONUNAVAIL;
goto exitPoint;
}
rc = SetAsyncID(pLineDev, dwRequestID);
exitPoint:
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineDevSpecific, rc x%X\n"), rc));
return rc;
} // TSPI_lineDevSpecific
LONG TSPIAPI
TSPI_lineDial(
DRV_REQUESTID dwRequestID,
HDRVCALL hdCall,
LPCWSTR lpszDestAddress,
DWORD dwCountryCode
)
{
PTLINEDEV pLineDev;
LONG rc;
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:+TSPI_lineDial\n")));
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdCall)) == NULL) {
DEBUGMSG(ZONE_ERROR|ZONE_CALLS, (TEXT("UNIMODEM:TSPI_lineDial ** Invalid Call Handle\n")));
rc = LINEERR_INVALLINEHANDLE;
goto exitPoint;
}
if (pLineDev->DevState != DEVST_PORTCONNECTWAITFORLINEDIAL) {
DEBUGMSG(ZONE_ERROR|ZONE_CALLS, (TEXT("UNIMODEM:TSPI_lineDial ** DevState != DEVST_PORTCONNECTWAITFORLINEDIAL\n")));
rc = LINEERR_INVALCALLSTATE;
goto exitPoint;
}
// Validate lpszDestAddress and get the processed form of it.
DEBUGMSG(ZONE_MISC|ZONE_CALLS, (TEXT("UNIMODEM:TSPI_lineDial - validating destination address\n")));
rc = ValidateAddress(pLineDev, lpszDestAddress, pLineDev->szAddress);
if (SUCCESS != rc){
DEBUGMSG(ZONE_FUNC|ZONE_ERROR|ZONE_CALLS, (TEXT("UNIMODEM:TSPI_lineDial ** Invalid Address\n")));
goto exitPoint;
}
rc = ControlThreadCmd(pLineDev, PENDING_LINEDIAL, dwRequestID);
if (!(rc & 0x80000000)) {
rc = SetAsyncID(pLineDev, dwRequestID);
}
exitPoint:
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:-TSPI_lineDial, rc x%X\n"), rc));
return rc;
} // TSPI_lineDial
//
// Terminate a call or abandon a call attempt in progress
//
LONG TSPIAPI
TSPI_lineDrop(DRV_REQUESTID dwRequestID,
HDRVCALL hdCall,
LPCSTR lpsUserUserInfo,
DWORD dwSize
)
{
PTLINEDEV pLineDev;
LONG rc;
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:+TSPI_lineDrop\n")));
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdCall)) == NULL) {
DEBUGMSG(ZONE_ERROR|ZONE_CALLS, (TEXT("UNIMODEM:TSPI_lineDrop ** Invalid Call Handle\n")));
return LINEERR_INVALCALLHANDLE;
}
if (pLineDev->dwCallState == LINECALLSTATE_IDLE) {
DEBUGMSG(ZONE_ERROR|ZONE_CALLS, (TEXT("UNIMODEM:TSPI_lineDrop ** Invalid Call State\n")));
return LINEERR_INVALCALLSTATE;
}
EnterCriticalSection(&pLineDev->OpenCS);
pLineDev->dwCallFlags |= CALL_DROPPING; // Flag that this call is going away
pLineDev->dwCallFlags &= ~CALL_ACTIVE;
LeaveCriticalSection(&pLineDev->OpenCS);
if (pLineDev->fTakeoverMode) {
pLineDev->fTakeoverMode = FALSE;
pLineDev->DevState = DEVST_DISCONNECTED;
NewCallState(pLineDev, LINECALLSTATE_DISCONNECTED, LINEDISCONNECTMODE_NORMAL);
NewCallState(pLineDev, LINECALLSTATE_IDLE, 0);
SetAsyncOp(pLineDev, PENDING_LINEDROP);
SetAsyncStatus(pLineDev, 0);
rc = 0;
} else {
rc = ControlThreadCmd(pLineDev, PENDING_LINEDROP, dwRequestID);
}
if (!(rc & 0x80000000)) {
rc = SetAsyncID(pLineDev, dwRequestID);
}
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:-TSPI_lineDrop, rc x%X\n"), rc));
return rc;
} // TSPI_lineDrop
LONG
TSPIAPI
TSPI_lineGetAddressCaps(
DWORD dwDeviceID,
DWORD dwAddressID,
DWORD dwTSPIVersion,
DWORD dwExtVersion,
LPLINEADDRESSCAPS lpAddressCaps
)
{
LONG rc;
PTLINEDEV pLineDev;
int cbDevClassLen;
int cbAvailMem;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineGetAddressCaps\n")));
rc = 0;
InitVarData((LPVOID)lpAddressCaps, sizeof(LINEADDRESSCAPS));
// Validate the device ID
if ((pLineDev = GetLineDevfromID(dwDeviceID)) == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineGetAddressCaps ** Invalid DeviceID\n")));
rc = LINEERR_NODEVICE;
goto exitPoint;
}
// Validate the address ID
if(dwAddressID != 0) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineGetAddressCaps ** Invalid AddressID\n")));
rc = LINEERR_INVALADDRESSID;
goto exitPoint;
}
lpAddressCaps->dwLineDeviceID = dwDeviceID;
lpAddressCaps->dwAddressSharing = LINEADDRESSSHARING_PRIVATE;
lpAddressCaps->dwCallInfoStates = LINECALLINFOSTATE_APPSPECIFIC | LINECALLINFOSTATE_MEDIAMODE;
lpAddressCaps->dwCallerIDFlags = LINECALLPARTYID_UNAVAIL;
lpAddressCaps->dwCalledIDFlags = LINECALLPARTYID_UNAVAIL;
lpAddressCaps->dwConnectedIDFlags = LINECALLPARTYID_UNAVAIL;
lpAddressCaps->dwRedirectionIDFlags = LINECALLPARTYID_UNAVAIL;
lpAddressCaps->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
lpAddressCaps->dwCallStates = LINECALLSTATE_IDLE |
LINECALLSTATE_OFFERING |
LINECALLSTATE_ACCEPTED |
LINECALLSTATE_DIALTONE |
LINECALLSTATE_DIALING |
LINECALLSTATE_CONNECTED |
LINECALLSTATE_PROCEEDING |
LINECALLSTATE_DISCONNECTED |
LINECALLSTATE_UNKNOWN;
lpAddressCaps->dwDialToneModes = LINEDIALTONEMODE_UNAVAIL;
lpAddressCaps->dwBusyModes = LINEBUSYMODE_UNAVAIL;
lpAddressCaps->dwSpecialInfo = LINESPECIALINFO_UNAVAIL;
lpAddressCaps->dwDisconnectModes = LINEDISCONNECTMODE_UNAVAIL |
LINEDISCONNECTMODE_NORMAL |
LINEDISCONNECTMODE_BUSY |
LINEDISCONNECTMODE_NODIALTONE |
LINEDISCONNECTMODE_NOANSWER;
lpAddressCaps->dwMaxNumActiveCalls = 1;
lpAddressCaps->dwAddrCapFlags = LINEADDRCAPFLAGS_PARTIALDIAL;
if (!IS_NULL_MODEM(pLineDev)) {
lpAddressCaps->dwAddrCapFlags |= LINEADDRCAPFLAGS_DIALED;
}
lpAddressCaps->dwCallFeatures = LINECALLFEATURE_ANSWER |
LINECALLFEATURE_ACCEPT |
LINECALLFEATURE_SETCALLPARAMS |
LINECALLFEATURE_DIAL |
LINECALLFEATURE_DROP;
cbAvailMem = (int) (lpAddressCaps->dwTotalSize - lpAddressCaps->dwUsedSize);
cbDevClassLen = sizeof(g_szzClassList);
// Copy device classes if it fits
if (cbAvailMem >= cbDevClassLen) {
memcpy((LPBYTE)lpAddressCaps + lpAddressCaps->dwUsedSize, g_szzClassList, cbDevClassLen);
lpAddressCaps->dwDeviceClassesSize = cbDevClassLen;
lpAddressCaps->dwDeviceClassesOffset= lpAddressCaps->dwUsedSize;
lpAddressCaps->dwUsedSize += cbDevClassLen;
cbAvailMem -= cbDevClassLen;
} else {
lpAddressCaps->dwDeviceClassesSize = 0;
lpAddressCaps->dwDeviceClassesOffset = 0;
}
lpAddressCaps->dwNeededSize += cbDevClassLen;
exitPoint:
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineGetAddressCaps 0x%x\n"), rc));
return rc;
} // TSPI_lineGetAddressCaps
LONG
TSPIAPI
TSPI_lineGetAddressStatus(
HDRVLINE hdLine,
DWORD dwAddressID,
LPLINEADDRESSSTATUS lpAddressStatus
)
{
LONG rc;
PTLINEDEV pLineDev;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineGetAddressStatus\n")));
rc = 0;
InitVarData((LPVOID)lpAddressStatus, sizeof(LINEADDRESSSTATUS));
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdLine)) == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineGetAddressStatus ** Invalid hdLine\n")));
rc = LINEERR_INVALLINEHANDLE;
goto exitPoint;
}
if(dwAddressID != 0) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineGetAddressStatus ** Invalid AddressID\n")));
rc = LINEERR_INVALADDRESSID;
goto exitPoint;
}
if (pLineDev->dwCallFlags & CALL_ACTIVE) {
lpAddressStatus->dwNumInUse = 1;
lpAddressStatus->dwNumActiveCalls = (pLineDev->dwCallState != LINECALLSTATE_IDLE) ? 1 : 0;
} else {
lpAddressStatus->dwNumInUse = 0;
lpAddressStatus->dwNumActiveCalls = 0;
};
lpAddressStatus->dwAddressFeatures = (pLineDev->dwCallFlags & CALL_ALLOCATED) ? 0 : LINEADDRFEATURE_MAKECALL;
exitPoint:
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineGetAddressStatus 0x%x\n"), rc));
return rc;
} // TSPI_lineGetAddressStatus
LONG
TSPIAPI
TSPI_lineGetCallInfo(
HDRVCALL hdCall,
LPLINECALLINFO lpCallInfo
)
{
PTLINEDEV pLineDev;
LONG rc;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineGetCallInfo\n")));
InitVarData((LPVOID)lpCallInfo, sizeof(LINECALLINFO));
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdCall)) == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineGetCallInfo Invalid hdCall\n")));
rc = LINEERR_INVALCALLHANDLE;
goto exitPoint;
}
rc = 0;
lpCallInfo->dwLineDeviceID = pLineDev->dwDeviceID;
lpCallInfo->dwAddressID = 0;
lpCallInfo->dwBearerMode = pLineDev->dwCurBearerModes;
lpCallInfo->dwRate = pLineDev->dwCurrentBaudRate;
lpCallInfo->dwMediaMode = pLineDev->dwCurMediaModes;
lpCallInfo->dwAppSpecific = 0;
lpCallInfo->dwCallStates = pLineDev->dwCallFlags & CALL_INBOUND ?
(LINECALLSTATE_IDLE |
LINECALLSTATE_OFFERING |
LINECALLSTATE_ACCEPTED |
LINECALLSTATE_CONNECTED |
LINECALLSTATE_DISCONNECTED |
LINECALLSTATE_UNKNOWN) :
(LINECALLSTATE_IDLE |
LINECALLSTATE_DIALTONE |
LINECALLSTATE_DIALING |
LINECALLSTATE_PROCEEDING |
LINECALLSTATE_CONNECTED |
LINECALLSTATE_DISCONNECTED |
LINECALLSTATE_UNKNOWN);
lpCallInfo->dwOrigin = pLineDev->dwCallFlags & CALL_INBOUND ?
LINECALLORIGIN_INBOUND : LINECALLORIGIN_OUTBOUND;
lpCallInfo->dwReason = pLineDev->dwCallFlags & CALL_INBOUND ?
LINECALLREASON_UNAVAIL : LINECALLREASON_DIRECT;
lpCallInfo->dwCallerIDFlags = LINECALLPARTYID_UNAVAIL;
lpCallInfo->dwCalledIDFlags = LINECALLPARTYID_UNAVAIL;
lpCallInfo->dwConnectedIDFlags = LINECALLPARTYID_UNAVAIL;
lpCallInfo->dwRedirectionIDFlags = LINECALLPARTYID_UNAVAIL;
lpCallInfo->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
lpCallInfo->dwAddressType = LINEADDRESSTYPE_PHONENUMBER;
exitPoint:
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineGetCallInfo %x\n"), rc));
return rc;
} // TSPI_lineGetCallInfo
LONG
TSPIAPI
TSPI_lineGetCallStatus(
HDRVCALL hdCall,
LPLINECALLSTATUS lpCallStatus
)
{
PTLINEDEV pLineDev;
LONG rc;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineGetCallStatus\n")));
InitVarData((LPVOID)lpCallStatus, sizeof(LINECALLSTATUS));
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdCall)) == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineGetCallStatus Invalid hdCall\n")));
rc = LINEERR_INVALCALLHANDLE;
goto exitPoint;
}
rc = 0;
//
// Current call information
//
lpCallStatus->dwCallState = pLineDev->dwCallState;
lpCallStatus->dwCallStateMode = pLineDev->dwCallStateMode;
// if we are in takeover mode, disallow all dwCallFeatures
if (!pLineDev->fTakeoverMode) {
switch(lpCallStatus->dwCallState) {
case LINECALLSTATE_OFFERING:
lpCallStatus->dwCallFeatures = LINECALLFEATURE_ACCEPT |
LINECALLFEATURE_SETCALLPARAMS |
LINECALLFEATURE_DROP;
// We can only answer if a possible media mode is DATAMODEM.
if (pLineDev->dwCurMediaModes & LINEMEDIAMODE_DATAMODEM) {
lpCallStatus->dwCallFeatures |= LINECALLFEATURE_ANSWER;
}
break;
case LINECALLSTATE_DIALTONE:
lpCallStatus->dwCallFeatures = LINECALLFEATURE_DROP;
break;
case LINECALLSTATE_DIALING:
lpCallStatus->dwCallFeatures = LINECALLFEATURE_DROP;
if (DEVST_PORTCONNECTWAITFORLINEDIAL == pLineDev->DevState) {
lpCallStatus->dwCallFeatures |= LINECALLFEATURE_DIAL;
}
break;
case LINECALLSTATE_ACCEPTED:
lpCallStatus->dwCallFeatures = LINECALLFEATURE_SETCALLPARAMS|LINECALLFEATURE_DROP;
// We can only answer if a possible media mode is DATAMODEM.
if (pLineDev->dwCurMediaModes & LINEMEDIAMODE_DATAMODEM) {
lpCallStatus->dwCallFeatures |= LINECALLFEATURE_ANSWER;
}
break;
case LINECALLSTATE_CONNECTED:
lpCallStatus->dwCallFeatures = LINECALLFEATURE_SETCALLPARAMS |
LINECALLFEATURE_DROP;
break;
case LINECALLSTATE_UNKNOWN:
case LINECALLSTATE_PROCEEDING:
case LINECALLSTATE_DISCONNECTED:
lpCallStatus->dwCallFeatures = LINECALLFEATURE_DROP;
break;
case LINECALLSTATE_IDLE:
default:
lpCallStatus->dwCallFeatures = 0;
break;
}
}
exitPoint:
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineGetCallStatus %x\n"), rc));
return rc;
} // TSPI_lineGetCallStatus
static const WCHAR szProviderName[] = TEXT("UNIMODEM");
//
// Determine Telephony capabilites for the specified device.
//
// NOTES:
// WinCE UNIMODEM uses a DWORD of DevSpecific information (denoted by
// LINEDEVCAPS.dwDevSpecificSize and LINEDEVCAPS.dwDevSpecificOffset).
// The format of of these 4 bytes is that the first WORD is a device type
// and the second WORD is an "active" indicator (0 for PC card modems that
// have been removed).
//
// The provider name is stored in the ProviderInfo section (denoted by
// LINEDEVCAPS.dwProviderInfoSize and LINEDEVCAPS.dwProviderInfoOffset).
//
LONG TSPIAPI
TSPI_lineGetDevCaps(
DWORD dwDeviceID,
DWORD dwTSPIVersion,
DWORD dwExtVersion,
LPLINEDEVCAPS lpLineDevCaps
)
{
PTLINEDEV pLineDev;
int cbLineNameLen = 0;
int cbProviderNameLen = 0;
int cbDevClassLen = 0;
int cbAvailMem = 0;
DWORD dwRet = SUCCESS;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineGetDevCaps\n")));
InitVarData((LPVOID)lpLineDevCaps, sizeof(LINEDEVCAPS));
// We need to fill in a device caps struct specific to
// the device.
if ((pLineDev = GetLineDevfromID ((DWORD)dwDeviceID)) == NULL)
return LINEERR_NODEVICE;
// Check to see how much memory we'll need.
cbLineNameLen = (wcslen(pLineDev->szFriendlyName) + 1) * sizeof(WCHAR);
cbProviderNameLen = (wcslen(szProviderName) + 1) * sizeof(WCHAR);
cbDevClassLen = sizeof(g_szzClassList);
cbAvailMem = (int) (lpLineDevCaps->dwTotalSize - lpLineDevCaps->dwUsedSize);
// Enter the size we ideally need.
lpLineDevCaps->dwNeededSize = lpLineDevCaps->dwUsedSize +
cbLineNameLen + // room for linename
cbProviderNameLen + // room for provider name
cbDevClassLen + // room for device class list
(2*sizeof(WORD)); // and room for DevSpecific info
if (cbAvailMem >= sizeof(DWORD) )
{
*(LPWORD)((LPSTR)lpLineDevCaps + lpLineDevCaps->dwUsedSize) = pLineDev->wDeviceType;
*((LPWORD)((LPSTR)lpLineDevCaps + lpLineDevCaps->dwUsedSize) + 1) = pLineDev->wDeviceAvail;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:TSPI_lineGetDevCaps Storing Device Type x%X, available x%X\n"),
pLineDev->wDeviceType,
pLineDev->wDeviceAvail));
lpLineDevCaps->dwDevSpecificSize = sizeof( DWORD );
lpLineDevCaps->dwDevSpecificOffset = lpLineDevCaps->dwUsedSize;
lpLineDevCaps->dwUsedSize += lpLineDevCaps->dwDevSpecificSize;
cbAvailMem -= lpLineDevCaps->dwDevSpecificSize;
}
else
{
lpLineDevCaps->dwDevSpecificSize = 0;
lpLineDevCaps->dwDevSpecificOffset = 0;
lpLineDevCaps->dwNeededSize += sizeof(WORD);
}
// If the provider info fits, then also append the line name
if (cbAvailMem >= cbLineNameLen)
{
wcscpy((LPWSTR)((LPSTR)lpLineDevCaps + lpLineDevCaps->dwUsedSize),
pLineDev->szFriendlyName);
lpLineDevCaps->dwLineNameSize = cbLineNameLen;
lpLineDevCaps->dwLineNameOffset = lpLineDevCaps->dwUsedSize;
lpLineDevCaps->dwUsedSize += cbLineNameLen;
cbAvailMem -= cbLineNameLen;
}
else
{
lpLineDevCaps->dwLineNameSize = 0;
lpLineDevCaps->dwLineNameOffset = 0;
}
if (cbAvailMem >= cbProviderNameLen)
{
wcscpy((LPWSTR)((LPSTR)lpLineDevCaps + lpLineDevCaps->dwUsedSize), szProviderName);
lpLineDevCaps->dwProviderInfoSize = cbProviderNameLen;
lpLineDevCaps->dwProviderInfoOffset = lpLineDevCaps->dwUsedSize;
lpLineDevCaps->dwUsedSize += cbProviderNameLen;
cbAvailMem -= cbProviderNameLen;
}
else
{
lpLineDevCaps->dwProviderInfoSize = 0;
lpLineDevCaps->dwProviderInfoOffset = 0;
}
// TODO - We don't have permanent ID's yet.
lpLineDevCaps->dwPermanentLineID = 0;
lpLineDevCaps->dwStringFormat = STRINGFORMAT_UNICODE;
lpLineDevCaps->dwAddressModes = LINEADDRESSMODE_ADDRESSID;
lpLineDevCaps->dwNumAddresses = 1;
// Bearer mode & information
lpLineDevCaps->dwMaxRate = pLineDev->dwMaxDCERate;
lpLineDevCaps->dwBearerModes = pLineDev->dwBearerModes;
// Media mode
lpLineDevCaps->dwMediaModes = pLineDev->dwMediaModes;
// We can simulate wait-for-bong if the modem isn't capable of
// supporting it.
lpLineDevCaps->dwDevCapFlags = pLineDev->dwDevCapFlags |
LINEDEVCAPFLAGS_DIALBILLING |
LINEDEVCAPFLAGS_CLOSEDROP;
lpLineDevCaps->dwRingModes = 1;
lpLineDevCaps->dwMaxNumActiveCalls = 1;
// Line device state to be notified
lpLineDevCaps->dwLineStates = LINEDEVSTATE_CONNECTED |
LINEDEVSTATE_DISCONNECTED |
LINEDEVSTATE_OPEN |
LINEDEVSTATE_CLOSE |
LINEDEVSTATE_INSERVICE |
LINEDEVSTATE_OUTOFSERVICE |
LINEDEVSTATE_REMOVED |
LINEDEVSTATE_RINGING |
LINEDEVSTATE_REINIT;
lpLineDevCaps->dwLineFeatures = LINEFEATURE_MAKECALL;
//
// Don't go beyond older version app's buffer
//
if (lpLineDevCaps->dwTotalSize >= sizeof(LINEDEVCAPS)) {
lpLineDevCaps->dwSettableDevStatus = 0;
// Copy device classes if it fits
if (cbAvailMem >= cbDevClassLen) {
memcpy((LPBYTE)lpLineDevCaps + lpLineDevCaps->dwUsedSize, g_szzClassList, cbDevClassLen);
lpLineDevCaps->dwDeviceClassesSize = cbDevClassLen;
lpLineDevCaps->dwDeviceClassesOffset= lpLineDevCaps->dwUsedSize;
lpLineDevCaps->dwUsedSize += cbDevClassLen;
cbAvailMem -= cbDevClassLen;
} else {
lpLineDevCaps->dwDeviceClassesSize = 0;
lpLineDevCaps->dwDeviceClassesOffset = 0;
}
lpLineDevCaps->dwAddressTypes = LINEADDRESSTYPE_PHONENUMBER;
lpLineDevCaps->dwAvailableTracking = 0;
}
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineGetDevCaps x%X\n"), dwRet));
return dwRet;
}
//
// WINCE NOTE:
// TSPI_lineGetDevConfig returns the default device configuration for the specified device.
// This is done so applications can avoid storing the devcfg when the user wants the default
// settings. If the settings are different than the default, then the application needs to store
// them and set them via lineSetDevConfig whether lineGetDevConfig returns defaults or not.
//
LONG TSPIAPI
TSPI_lineGetDevConfig(
DWORD dwDeviceID,
LPVARSTRING lpDeviceConfig,
LPCWSTR lpszDeviceClass
)
{
PTLINEDEV pLineDev;
DWORD dwRet = SUCCESS;
BYTE cbSize;
PDEVMINICFG pDevMiniCfg;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineGetDevConfig\n")));
// Validate the requested device class
//
if (lpszDeviceClass != NULL)
{
if (!ValidateDevCfgClass(lpszDeviceClass))
return LINEERR_INVALDEVICECLASS;
}
// Validate the buffer
//
if (lpDeviceConfig == NULL)
return LINEERR_INVALPOINTER;
if (lpDeviceConfig->dwTotalSize < sizeof(VARSTRING))
return LINEERR_STRUCTURETOOSMALL;
// Validate the device ID
//
if ((pLineDev = GetLineDevfromID (dwDeviceID)) == NULL)
return LINEERR_NODEVICE;
// Validate the buffer size
//
cbSize = sizeof(DEVMINICFG);
lpDeviceConfig->dwUsedSize = sizeof(VARSTRING);
lpDeviceConfig->dwNeededSize = sizeof(VARSTRING) + cbSize;
if (lpDeviceConfig->dwTotalSize >= lpDeviceConfig->dwNeededSize)
{
pDevMiniCfg = (PDEVMINICFG)(((LPBYTE)lpDeviceConfig) + sizeof(VARSTRING));
// If someone does a SetDevCfg for some provider who needs a post-dial-terminal
// and they then want to create a new connection via GetDevCfg/CfgDialogEdit,
// they will end up with the default connection lookin like the original.
// To work around this, I will always return the default config here. If the app
// needs to remember a specific config for later edit, they must store it themselves.
// LAM
getDefaultDevConfig( pLineDev, pDevMiniCfg );
lpDeviceConfig->dwStringFormat = STRINGFORMAT_BINARY;
lpDeviceConfig->dwStringSize = cbSize;
lpDeviceConfig->dwStringOffset = sizeof(VARSTRING);
lpDeviceConfig->dwUsedSize += cbSize;
DEBUGMSG(ZONE_FUNC|ZONE_CALLS,
(TEXT("UNIMODEM:TSPI_lineGetDevConfig (DevID %d): dwModemOptions x%X, fwOptions x%X, dwCallSetupFail x%X\n"),
dwDeviceID, pDevMiniCfg->dwModemOptions, pDevMiniCfg->fwOptions, pDevMiniCfg->dwCallSetupFailTimer));
}
else
{
// Not enough room
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:TSPI_lineGetDevConfig needed %d bytes, had %d\n"),
lpDeviceConfig->dwNeededSize, lpDeviceConfig->dwTotalSize));
};
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:-TSPI_lineGetDevConfig x%X (Used %d, Need %d)\n"),
dwRet, lpDeviceConfig->dwUsedSize, lpDeviceConfig->dwNeededSize));
return dwRet;
}
typedef HICON (WINAPI * PFN_LOADICON)(HINSTANCE, LPCWSTR);
LONG
TSPIAPI
TSPI_lineGetIcon(
DWORD dwDeviceID,
LPCWSTR lpszDeviceClass,
LPHICON lphIcon
)
{
LONG rc;
PFN_LOADICON pfnLoadIcon;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineGetIcon\n")));
rc = LINEERR_RESOURCEUNAVAIL;
//
// TODO: First check that the device class corresponds to the icon
//
if (TspiGlobals.hIconLine == NULL) {
if (IsAPIReady(SH_WMGR)) {
if (pfnLoadIcon = (PFN_LOADICON)GetProcAddress(g_hCoreDLL, L"LoadIconW")) {
TspiGlobals.hIconLine = pfnLoadIcon(
TspiGlobals.hInstance,
(LPCWSTR)MAKEINTRESOURCE(LINE_ICON)
);
rc = 0;
}
}
} else {
rc = 0;
}
*lphIcon = TspiGlobals.hIconLine;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineGetIcon returning %x\n"), rc));
return rc;
} // TSPI_lineGetIcon
//
// Get the device ID for the specified device. The caller
// can use the returned ID with the corresponding media (i.e. for
// serial lines the ID can be passed to ReadFile(), WriteFile(),
// etc).
//
LONG TSPIAPI
TSPI_lineGetID(
HDRVLINE hdLine,
DWORD dwAddressID,
HDRVCALL hdCall,
DWORD dwSelect,
LPVARSTRING lpDeviceID,
LPCWSTR lpszDeviceClass
)
{
PTLINEDEV pLineDev;
UINT cbPort;
UINT idClass;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineGetID - ProcPerm=0x%X\n"),
GetCurrentPermissions()));
switch (dwSelect)
{
case LINECALLSELECT_ADDRESS:
if (dwAddressID != 0)
{
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineGetID - INVALADDRESSID\n")));
return LINEERR_INVALADDRESSID;
}
// FALLTHROUGH
case LINECALLSELECT_LINE:
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdLine)) == NULL)
{
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineGetID - INVALLINEHANDLE\n")));
return LINEERR_INVALLINEHANDLE;
}
break;
case LINECALLSELECT_CALL:
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdCall)) == NULL)
{
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineGetID - INVALCALLHANDLE\n")));
return LINEERR_INVALCALLHANDLE;
}
break;
default:
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:-TSPI_lineGetID - Invalid dwSelect x%X\n"),
dwSelect));
return LINEERR_OPERATIONFAILED;
}
// Determine the device class
//
for (idClass = 0; idClass < MAX_SUPPORT_CLASS; idClass++)
{
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:TSPI_lineGetID Comparing strings %s to %s\n"),
lpszDeviceClass, aGetID[idClass].szClassName));
if (wcsicmp(lpszDeviceClass, aGetID[idClass].szClassName) == 0)
break;
};
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:TSPI_lineGetID Class ID = %d (%s)\n"), idClass,
aGetID[idClass].szClassName));
// Determine the required size
//
switch (idClass)
{
case TAPILINE:
cbPort = sizeof(DWORD);
break;
case COMM:
cbPort = (wcslen(pLineDev->szFriendlyName) + 1) * sizeof(WCHAR);
break;
case COMMMODEM:
cbPort = (wcslen(pLineDev->szFriendlyName) + 1) * sizeof(WCHAR) + sizeof(DWORD);
break;
case NDIS:
cbPort = sizeof(g_szDeviceClass) + sizeof(DWORD);
break;
default:
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:-TSPI_lineGetID - Invalid ID Class x%X\n"),
idClass ));
return LINEERR_OPERATIONFAILED;
};
// Calculate the required size
//
//lpDeviceID->dwUsedSize = sizeof(VARSTRING); // TAPI fills it in.
lpDeviceID->dwNeededSize = sizeof(VARSTRING) + cbPort;
lpDeviceID->dwStringFormat = aGetID[idClass].dwFormat;
ASSERT(lpDeviceID->dwUsedSize == sizeof(VARSTRING));
if ((lpDeviceID->dwTotalSize - lpDeviceID->dwUsedSize) <
cbPort)
{
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineGetID - Inusufficient space\n")));
return SUCCESS;
}
// We have enough space to return valid information
//
lpDeviceID->dwStringSize = cbPort;
lpDeviceID->dwStringOffset = sizeof(VARSTRING);
lpDeviceID->dwUsedSize += cbPort;
// Return the useful information
switch (idClass)
{
case TAPILINE:
{
LPDWORD lpdwDeviceID;
lpdwDeviceID = (LPDWORD)(((LPBYTE)lpDeviceID) + sizeof(VARSTRING));
*lpdwDeviceID = (DWORD) pLineDev->dwDeviceID;
DEBUGMSG(ZONE_MISC,
(TEXT("UNIMODEM:-TSPI_lineGetID TAPILINE - Device ID x%X\n"),
pLineDev->dwDeviceID));
break;
}
case COMM:
{
wcsncpy( (LPWSTR)((LPBYTE)lpDeviceID + sizeof(VARSTRING)),
pLineDev->szFriendlyName, (cbPort/sizeof(WCHAR)) );
DEBUGMSG(ZONE_MISC,
(TEXT("UNIMODEM:-TSPI_lineGetID COMM - Device name \"%s\" (len %d)\n"),
pLineDev->szFriendlyName, (cbPort/sizeof(WCHAR))));
break;
}
case COMMMODEM:
{
LPDWORD lpdwDeviceHandle;
lpdwDeviceHandle = (LPDWORD)(((LPBYTE)lpDeviceID) + sizeof(VARSTRING));
if (pLineDev->hDevice != (HANDLE)INVALID_DEVICE)
{
*lpdwDeviceHandle = (DWORD)pLineDev->hDevice;
SetHandleOwner((HANDLE)*lpdwDeviceHandle, GetCallerProcess());
}
else
{
*lpdwDeviceHandle = (DWORD)NULL;
};
wcscpy((LPWSTR)(lpdwDeviceHandle+1), pLineDev->szFriendlyName );
DEBUGMSG(ZONE_MISC,
(TEXT("UNIMODEM:-TSPI_lineGetID COMMMODEM - Device Handle x%X, Device name %s\n"),
*lpdwDeviceHandle, pLineDev->szFriendlyName));
break;
}
case NDIS:
{
LPDWORD lpdwDeviceID;
lpdwDeviceID = (LPDWORD)(((LPBYTE)lpDeviceID) + sizeof(VARSTRING));
*lpdwDeviceID = (pLineDev->hDevice != (HANDLE)INVALID_DEVICE ?
(DWORD)pLineDev->hDevice_r0 : (DWORD)NULL);
wcscpy((LPWSTR)(lpdwDeviceID+1), g_szDeviceClass);
DEBUGMSG(ZONE_MISC,
(TEXT("UNIMODEM:-TSPI_lineGetID NDIS - Device Handle x%X, Device name %s\n"),
*lpdwDeviceID, g_szDeviceClass));
break;
}
};
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineGetID\n")));
return SUCCESS;
}
LONG
TSPIAPI
TSPI_lineGetLineDevStatus(
HDRVLINE hdLine,
LPLINEDEVSTATUS lpLineDevStatus
)
{
LONG rc;
PTLINEDEV pLineDev;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineGetLineDevStatus\n")));
InitVarData((LPVOID)lpLineDevStatus, sizeof(LINEDEVSTATUS));
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdLine)) == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineGetLineDevStatus ** Invalid Handle\n")));
rc = LINEERR_INVALLINEHANDLE;
goto exitPoint;
}
rc = 0;
if (pLineDev->dwCallFlags & CALL_ACTIVE) {
lpLineDevStatus->dwNumActiveCalls = 1;
lpLineDevStatus->dwLineFeatures = 0;
} else {
lpLineDevStatus->dwNumActiveCalls = 0;
lpLineDevStatus->dwLineFeatures = (pLineDev->dwCallFlags & CALL_ALLOCATED) ?
0 : LINEFEATURE_MAKECALL;
}
// Line hardware information
//
lpLineDevStatus->dwSignalLevel = 0x0000FFFF;
lpLineDevStatus->dwBatteryLevel = 0x0000FFFF;
lpLineDevStatus->dwRoamMode = LINEROAMMODE_UNAVAIL;
// Always allow TAPI calls
//
lpLineDevStatus->dwDevStatusFlags = LINEDEVSTATUSFLAGS_CONNECTED;
/* TODO
if (!(pLineDev->fdwResources & LINEDEVFLAGS_OUTOFSERVICE)) {
lpLineDevStatus->dwDevStatusFlags |= LINEDEVSTATUSFLAGS_INSERVICE;
} */
exitPoint:
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineGetLineDevStatus 0x%x\n"), rc));
return rc;
} // TSPI_lineGetLineDevStatus
LONG
TSPIAPI
TSPI_lineGetNumAddressIDs(
HDRVLINE hdLine,
LPDWORD lpdwNumAddressIDs
)
{
LONG rc;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineGetNumAddressIDs\n")));
if (GetLineDevfromHandle ((DWORD)hdLine) == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineGetNumAddressIDs ** Invalid Handle\n")));
rc = LINEERR_INVALLINEHANDLE;
} else {
rc = 0;
*lpdwNumAddressIDs = 1;
}
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineGetNumAddressIDs 0x%x\n"), rc));
return rc;
} // TSPI_lineGetNumAddressIDs
LONG TSPIAPI
TSPI_lineMakeCall(
DRV_REQUESTID dwRequestID,
HDRVLINE hdLine,
HTAPICALL htCall,
LPHDRVCALL lphdCall,
LPCWSTR lpszDestAddress,
DWORD dwCountryCode,
LPLINECALLPARAMS const lpCallParams
)
{
PTLINEDEV pLineDev;
DWORD dwRet;
BOOL fDoTakeover = FALSE;
WCHAR szSuffix[16];
DWORD dwSize;
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:+TSPI_lineMakeCall\n")));
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdLine)) == NULL) {
DEBUGMSG(ZONE_FUNC|ZONE_ERROR|ZONE_CALLS,
(TEXT("UNIMODEM:-TSPI_lineMakeCall ** Invalid Handle\n")));
return LINEERR_INVALLINEHANDLE;
}
// See if we have a free call struct.
if (pLineDev->dwCallFlags & CALL_ALLOCATED) {
DEBUGMSG(ZONE_FUNC|ZONE_ERROR|ZONE_CALLS,
(TEXT("UNIMODEM:-TSPI_lineMakeCall ** Call already allocated\n")));
return LINEERR_CALLUNAVAIL;
}
// By default, don't do blind dialing.
pLineDev->dwDialOptions &= ~MDM_BLIND_DIAL;
// Examine LINECALLPARAMS, if present
if (lpCallParams) {
DEBUGMSG(ZONE_FUNC|ZONE_ERROR|ZONE_CALLS,
(TEXT("UNIMODEM:TSPI_lineMakeCall - Check CallParams\n")));
// verify media mode
if (lpCallParams->dwMediaMode & ~pLineDev->dwMediaModes) {
DEBUGMSG(ZONE_FUNC|ZONE_ERROR|ZONE_CALLS,
(TEXT("UNIMODEM:-TSPI_lineMakeCall ** Invalid Media Mode\n")));
return LINEERR_INVALMEDIAMODE;
}
DEBUGMSG(ZONE_MISC,
(TEXT("UNIMODEM:TSPI_lineMakeCall - verified media modes\n")));
// verify bearer mode
if ((~pLineDev->dwBearerModes) & lpCallParams->dwBearerMode) {
DEBUGMSG(ZONE_FUNC|ZONE_ERROR|ZONE_CALLS,
(TEXT("UNIMODEM:-TSPI_lineMakeCall ** Invalid Bearer Mode 0x%x vs 0x%x\n"),
pLineDev->dwBearerModes, lpCallParams->dwBearerMode));
return LINEERR_INVALBEARERMODE;
}
if (lpCallParams->dwBearerMode & LINEBEARERMODE_PASSTHROUGH) {
fDoTakeover = TRUE;
} else {
// We're not requested to do passthrough. Can we actually
// dial the media modes without passthrough? This is to
// prevent G3FAX from being used without passthrough...
// (We can only dial with DATAMODEM)
if ((lpCallParams->dwMediaMode &
(LINEMEDIAMODE_DATAMODEM)) == 0) {
DEBUGMSG(ZONE_FUNC|ZONE_ERROR|ZONE_CALLS,
(TEXT("UNIMODEM:-TSPI_lineMakeCall ** Invalid Media Mode\n")));
return LINEERR_INVALMEDIAMODE;
}
}
pLineDev->dwCurBearerModes = lpCallParams->dwBearerMode;
pLineDev->dwCurMediaModes = lpCallParams->dwMediaMode;
DEBUGMSG(ZONE_MISC,
(TEXT("UNIMODEM:TSPI_lineMakeCall - got media & bearer modes\n")));
if (!(lpCallParams->dwCallParamFlags & LINECALLPARAMFLAGS_IDLE)) {
DEBUGMSG(ZONE_FUNC|ZONE_CALLS,
(TEXT("UNIMODEM:TSPI_lineMakeCall LINECALLPARAMFLAGS_IDLE: not set, no dialtone detect\n") ));
// Turn on blind dialing
pLineDev->dwDialOptions |= MDM_BLIND_DIAL;
}
if ((lpCallParams->dwAddressType) && (lpCallParams->dwAddressType != LINEADDRESSTYPE_PHONENUMBER)) {
DEBUGMSG(ZONE_FUNC|ZONE_ERROR|ZONE_CALLS,
(TEXT("UNIMODEM:-TSPI_lineMakeCall ** Invalid Address Type\n")));
return LINEERR_INVALADDRESS;
}
} else {
// set the standard defaults - for peg tapi it is DATAMODEM
ASSERT(pLineDev->dwMediaModes & LINEMEDIAMODE_DATAMODEM);
pLineDev->dwCurMediaModes = LINEMEDIAMODE_DATAMODEM;
pLineDev->dwCurBearerModes = pLineDev->dwBearerModes & ~LINEBEARERMODE_PASSTHROUGH;
}
// Do we have a phone number?
//
if (!fDoTakeover)
{
if (IS_NULL_MODEM(pLineDev) ||
pLineDev->DevMiniCfg.fwOptions & MANUAL_DIAL)
{
*pLineDev->szAddress = '\0';
DEBUGMSG(ZONE_MISC|ZONE_CALLS,
(TEXT("UNIMODEM:TSPI_lineMakeCall - Manual dial, zeroing dial string\n")));
// Turn on blind dialing if this is MANUAL_DIAL.
if (pLineDev->DevMiniCfg.fwOptions & MANUAL_DIAL)
{
pLineDev->dwDialOptions |= MDM_BLIND_DIAL;
}
}
else
{
// Validate lpszDestAddress and get the processed form of it.
DEBUGMSG(ZONE_MISC|ZONE_CALLS,
(TEXT("UNIMODEM:TSPI_lineMakeCall - validating destination address\n")));
dwRet = ValidateAddress(pLineDev, lpszDestAddress, pLineDev->szAddress);
if (SUCCESS != dwRet)
{
DEBUGMSG(ZONE_FUNC|ZONE_ERROR|ZONE_CALLS,
(TEXT("UNIMODEM:-TSPI_lineMakeCall ** Invalid Address\n")));
return dwRet;
}
// if the lpszDestAddress was NULL or "", then we just want to do a
// dialtone detection. We expect that lineDial will be called.
// Setting the szAddress to ";" will do this.
if ('\0' == pLineDev->szAddress[0])
{
dwSize = sizeof(szSuffix);
if (ERROR_SUCCESS != MdmRegGetValue( pLineDev,
szSettings,
szDialSuffix,
REG_SZ,
(PUCHAR)szSuffix,
&dwSize) )
{
wcscpy(szSuffix, TEXT(";"));
}
wcscpy(pLineDev->szAddress, szSuffix);
}
}
}
// Record the call attributes
pLineDev->htCall = htCall;
pLineDev->dwCallFlags = CALL_ALLOCATED;
*lphdCall = (HDRVCALL)pLineDev;
// We allow making a call to an already-opened line if the line is monitoring
// a call. Therefore, if the line is in use, try making a call. The make-call
// routine will return error if the state is not appropriate.
//
dwRet = DevlineOpen(pLineDev);
if ((dwRet == SUCCESS) || (dwRet == LINEERR_ALLOCATED)) {
if (fDoTakeover) {
DEBUGMSG(ZONE_MISC|ZONE_CALLS ,(TEXT("UNIMODEM:TSPI_lineMakeCall - Takeover\n")));
// For takeover, we don't actually do any calling. Just open the
// port so that the application can get the device handle from
// lineGetID.
if ((pLineDev->DevState == DEVST_DISCONNECTED) ||
(pLineDev->DevState == DEVST_PORTLISTENING)) {
// We can only go into passthrough if device is not in use
// OK, the device was opened above, so now we just need to
// let the apps know that the callstate has changed.
pLineDev->dwCallState = LINECALLSTATE_UNKNOWN;
pLineDev->DevState = DEVST_CONNECTED;
pLineDev->fTakeoverMode = TRUE;
SetAsyncOp(pLineDev, PENDING_LINEMAKECALL);
SetAsyncStatus(pLineDev, 0);
NewCallState(pLineDev, LINECALLSTATE_CONNECTED, LINECONNECTEDMODE_ACTIVE);
dwRet = 0;
} else {
dwRet = LINEERR_OPERATIONFAILED;
}
} else {
pLineDev->DevState = DEVST_PORTCONNECTDIAL;
dwRet = ControlThreadCmd(pLineDev, PENDING_LINEMAKECALL, dwRequestID);
}
}
// Check if an error occurs
//
if (IS_TAPI_ERROR(dwRet))
{
DEBUGMSG(ZONE_CALLS,
(TEXT("UNIMODEM:TSPI_lineMakeCall Ret Code x%X, invalidating pending ID.\n"),
dwRet ));
// Deallocate the call from this line
pLineDev->htCall = NULL;
pLineDev->dwCallFlags = 0;
*lphdCall = NULL;
} else {
dwRet = SetAsyncID(pLineDev, dwRequestID);
}
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:-TSPI_lineMakeCall, dwRet x%X\n"), dwRet));
return dwRet;
} // TSPI_lineMakeCall
LONG TSPIAPI
TSPI_lineNegotiateTSPIVersion(
DWORD dwDeviceID,
DWORD dwLowVersion,
DWORD dwHighVersion,
LPDWORD lpdwTSPIVersion
)
{
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineNegotiateTSPIVersion\n")));
// Check the range of the device ID
//
if ((dwDeviceID == INITIALIZE_NEGOTIATION) || (GetLineDevfromID(dwDeviceID) != NULL))
{
// Check the version range
//
if((dwLowVersion > SPI_VERSION) || (dwHighVersion < SPI_VERSION))
{
*lpdwTSPIVersion = 0;
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:-TSPI_lineNegotiateTSPIVersion - SPI Ver x%X out of TAPI range x%X..x%X\n"),
SPI_VERSION, dwLowVersion, dwHighVersion));
return LINEERR_INCOMPATIBLEAPIVERSION;
}
else
{
*lpdwTSPIVersion = SPI_VERSION;
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:-TSPI_lineNegotiateTSPIVersion - Ver x%X\n"),
SPI_VERSION));
return SUCCESS;
};
};
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineNegotiateTSPIVersion - No Device\n")));
// The requested device doesn't exist.
return LINEERR_NODEVICE;
}
LONG TSPIAPI
TSPI_lineOpen(
DWORD dwDeviceID,
HTAPILINE htLine,
LPHDRVLINE lphdLine,
DWORD dwTSPIVersion,
LINEEVENT lineEventProc)
{
PTLINEDEV pLineDev;
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:+TSPI_lineOpen DevID x%X, HTapiLine x%X, SPI Ver x%X\n"),
dwDeviceID, htLine, dwTSPIVersion));
// Validate the device ID
if ((pLineDev = GetLineDevfromID(dwDeviceID)) == NULL) {
DEBUGMSG(ZONE_ERROR,
(TEXT("TSPI_lineOpen, could not find device for dwId x%X\n"),
dwDeviceID));
return LINEERR_NODEVICE;
}
EnterCriticalSection(&pLineDev->OpenCS);
// Update the line device
*lphdLine = (HDRVLINE)pLineDev;
pLineDev->lpfnEvent = lineEventProc;
DEBUGMSG((lineEventProc != TspiGlobals.fnLineEventProc) & ZONE_WARN,
(TEXT("UNIMODEM:TSPI_lineOpen lineEventProc != TspiGlobals.fnLineEventProc\n")));
pLineDev->htLine = htLine;
LeaveCriticalSection(&pLineDev->OpenCS);
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineOpen\n")));
return SUCCESS;
}
LONG TSPIAPI
TSPI_lineSetDevConfig(
DWORD dwDeviceID,
LPVOID const lpDeviceConfig,
DWORD dwSize,
LPCWSTR lpszDeviceClass
)
{
PTLINEDEV pLineDev;
PDEVMINICFG pDevMiniCfg;
#ifdef DEBUG
DWORD dwTemp;
#endif
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineSetDevConfig\n")));
// Validate the requested device class
//
if (!ValidateDevCfgClass(lpszDeviceClass))
{
DEBUGMSG(ZONE_FUNC|ZONE_ERROR,
(TEXT("UNIMODEM:-TSPI_lineSetDevConfig : LINEERR_INVALDEVICECLASS\n")));
return LINEERR_INVALDEVICECLASS;
}
// Validate the buffer
//
if (lpDeviceConfig == NULL)
{
DEBUGMSG(ZONE_FUNC|ZONE_ERROR,
(TEXT("UNIMODEM:-TSPI_lineSetDevConfig : LINEERR_INVALPOINTER\n")));
return LINEERR_INVALPOINTER;
}
// Validate the device ID
//
if ((pLineDev = GetLineDevfromID(dwDeviceID)) == NULL)
{
DEBUGMSG(ZONE_FUNC|ZONE_ERROR,
(TEXT("UNIMODEM:-TSPI_lineSetDevConfig : LINEERR_NODEVICE\n")));
return LINEERR_NODEVICE;
}
// verify the structure size and version
//
pDevMiniCfg = (PDEVMINICFG)lpDeviceConfig;
if ( (dwSize != sizeof(DEVMINICFG)) ||
(pLineDev->DevMiniCfg.wVersion != (pDevMiniCfg->wVersion)) )
{
DEBUGMSG(ZONE_FUNC|ZONE_ERROR,
(TEXT("UNIMODEM:-TSPI_lineSetDevConfig : LINEERR_INVALPARAM\n")));
return LINEERR_INVALPARAM;
}
// Get the new settings
pLineDev->DevMiniCfg = *pDevMiniCfg;
#ifdef DEBUG
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:DevConfig set :\n")));
if( MDM_FLOWCONTROL_HARD & pLineDev->DevMiniCfg.dwModemOptions )
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:\tHardware Flow Control\n")));
else if( MDM_FLOWCONTROL_SOFT & pLineDev->DevMiniCfg.dwModemOptions )
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:\tSoftware Flow Control\n")));
else
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:\tNo Flow Control\n")));
if (MANUAL_DIAL & pLineDev->DevMiniCfg.fwOptions )
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:\tManual Dialing\n")));
if (TERMINAL_PRE & pLineDev->DevMiniCfg.fwOptions )
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:\tPredial Terminal\n")));
if (TERMINAL_POST & pLineDev->DevMiniCfg.fwOptions )
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:\tPostdial Terminal\n")));
if ( MDM_BLIND_DIAL & pLineDev->DevMiniCfg.dwModemOptions )
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:\tBlind Dialing\n")));
dwTemp = wcslen(pLineDev->DevMiniCfg.szDialModifier);
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM: Dial Modifier len %d\n"),
dwTemp));
if( dwTemp )
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM: Dial Modifier string %s\n"),
pLineDev->DevMiniCfg.szDialModifier));
#endif
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineSetDevConfig\n")));
return SUCCESS;
}
//
// Enable the opened line to detect an inbound call.
//
LONG TSPIAPI
TSPI_lineSetDefaultMediaDetection(
HDRVLINE hdLine,
DWORD dwMediaModes
)
{
PTLINEDEV pLineDev;
LONG rc = LINEERR_OPERATIONFAILED; // assume failure
DWORD dwOrigMediaModes;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineSetDefaultMediaDetection\n")));
pLineDev = GetLineDevfromHandle((DWORD)hdLine);
if (!pLineDev) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineSetDefaultMediaDetection: invalid hdLine 0x%x\n"), hdLine));
rc = LINEERR_INVALLINEHANDLE;
goto exitPoint;
}
// Check the requested modes. There must be only our media modes.
// In addition, don't allow INTERACTIVEVOICE to be used for listening.
//
if (dwMediaModes & ~(pLineDev->dwMediaModes & ~LINEMEDIAMODE_INTERACTIVEVOICE)) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineSetDefaultMediaDetection: invalid dwMediaModes 0x%x\n"), dwMediaModes));
rc = LINEERR_INVALMEDIAMODE;
goto exitPoint;
}
EnterCriticalSection(&pLineDev->OpenCS);
LeaveCriticalSection(&pLineDev->OpenCS);
//
// If no detection and a detection is requested
//
dwOrigMediaModes = pLineDev->dwDetMediaModes;
if ((dwOrigMediaModes == 0) && (dwMediaModes)) {
pLineDev->dwDetMediaModes = dwMediaModes;
rc = ControlThreadCmd(pLineDev, PENDING_LISTEN, INVALID_PENDINGID);
if (rc) {
pLineDev->dwDetMediaModes = dwOrigMediaModes;
}
} else {
//
// we are stopping detection OR adjusting the detection media modes
//
//
// If we are detecting and requested not to, then stop the control thread
//
if (dwOrigMediaModes && (dwMediaModes == 0) &&
(DEVST_PORTLISTENING == pLineDev->DevState ||
DEVST_PORTLISTENINIT == pLineDev->DevState)) {
pLineDev->dwDetMediaModes = 0;
ControlThreadCmd(pLineDev, PENDING_EXIT, INVALID_PENDINGID);
}
pLineDev->dwDetMediaModes = dwMediaModes;
rc = ERROR_SUCCESS;
}
exitPoint:
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineSetDefaultMediaDetection 0x%x\n"), rc));
return rc;
} // TSPI_lineSetDefaultMediaDetection
LONG
TSPIAPI
TSPI_lineSetMediaMode(
HDRVCALL hdCall,
DWORD dwMediaMode
)
{
LONG rc;
PTLINEDEV pLineDev;
if ((pLineDev = GetLineDevfromHandle ((DWORD)hdCall)) == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineSetMediaMode ** Invalid Handle\n")));
rc = LINEERR_INVALCALLHANDLE;
goto exitPoint;
}
// Check the requested modes. There must be only our media modes
//
if (dwMediaMode & ~pLineDev->dwMediaModes) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineSetMediaMode ** Invalid dwMediaMode\n")));
rc = LINEERR_INVALMEDIAMODE;
goto exitPoint;
}
rc = 0;
if (pLineDev->dwCurMediaModes != dwMediaMode) {
pLineDev->dwCurMediaModes = dwMediaMode;
CallLineEventProc(
pLineDev,
pLineDev->htCall,
LINE_CALLINFO,
LINECALLINFOSTATE_MEDIAMODE,
0,
0
);
}
exitPoint:
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineSetMediaMode 0x%x\n"), rc));
return rc;
}
LONG TSPIAPI
TSPI_lineSetStatusMessages(
HDRVLINE hdLine,
DWORD dwLineStates,
DWORD dwAddressStates
)
{
PTLINEDEV pLineDev;
LONG rc;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineSetStatusMessages\n")));
if (pLineDev = GetLineDevfromHandle((DWORD)hdLine)) {
rc = 0;
pLineDev->dwLineStatesMask = dwLineStates;
// We don't send LINE_ADDRESSSTATE msgs so no need to filter them.
} else {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:TSPI_lineSetStatusMessages ** Invalid Handle\n")));
rc = LINEERR_INVALLINEHANDLE;
}
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineSetStatusMessages 0x%x\n"), rc));
return rc;
}
//
// LONG TSPIAPI TSPI_providerCreateLineDevice()
//
// Dynamically creates a new device. This entry point will be
// called by devloader whenver he adds a new device which lists
// unimodem.dll as the service provider.
//
LONG TSPIAPI
TSPI_providerCreateLineDevice(
HKEY hActiveKey, // @parm Registry key for this active device
LPCWSTR lpszDevPath, // @parm Registry path for this device
LPCWSTR lpszDeviceName // @parm Device Name
)
{
PTLINEDEV ptLineDev;
DWORD dwRet;
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:+TSPI_providerCreateLineDevice %s.\n"),
lpszDeviceName));
dwRet = (DWORD) -1; // Assume failure
// It is possible that this device already exists (for example
// if it is a PCMCIA card that was removed and re-inserted.)
// So scan the current device list looking for it, and use
// the existing entry if it is found. Otherwise, go ahead and
// create a device.
ptLineDev = createLineDev( hActiveKey, lpszDevPath, lpszDeviceName );
if( NULL != ptLineDev )
{
dwRet = ptLineDev->dwDeviceID;
}
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:-TSPI_providerCreateLineDevice, return x%X.\n"),
dwRet));
return dwRet;
}
//
// LONG TSPIAPI TSPI_providerDeleteLineDevice()
//
// Removes a device from the system.
//
// NOTE : Devload doesn't actually know which devices we added,
// so it is possible that this device is not one for which we
// have created a lineDevice entry. Note that we never really remove
// a device. We simply mark it as disconnected. It may later get
// re-added to the system.
//
LONG TSPIAPI TSPI_providerDeleteLineDevice(
DWORD Identifier // @parm dwDeviceID associated with this device
)
{
DWORD dwRet;
PTLINEDEV ptLineDev;
DEBUGMSG(ZONE_FUNC|ZONE_INIT,
(TEXT("UNIMODEM:+TSPI_providerDeleteLineDevice, x%X.\n"),
Identifier));
// Get the name of the device and check its validity
if ( (DWORD)-1 == Identifier )
return LINEERR_BADDEVICEID;
dwRet = LINEERR_OPERATIONFAILED; // Assume failure
// See if we actually have such a device in our system
if( ptLineDev = GetLineDevfromID(Identifier) )
{
if (ptLineDev->wDeviceAvail) {
EnterCriticalSection(&ptLineDev->OpenCS);
ptLineDev->DevState = DEVST_DISCONNECTED;
ptLineDev->dwDetMediaModes = 0;
LeaveCriticalSection(&ptLineDev->OpenCS);
// OK, send a DEVSTATE_DISCONNECTED to TAPI.
DEBUGMSG(ZONE_FUNC|ZONE_INIT,
(TEXT("UNIMODEM:TSPI_providerDeleteLineDevice Send disconnected for ptLine x%X, htLine x%X\n"),
ptLineDev, ptLineDev->htLine));
CallLineEventProc(
ptLineDev,
0,
LINE_LINEDEVSTATE,
LINEDEVSTATE_DISCONNECTED|LINEDEVSTATE_OUTOFSERVICE|LINEDEVSTATE_REMOVED,
0,
0
);
// And this Setting Key is no longer valid.
RegCloseKey( ptLineDev->hSettingsKey );
// And mark this as disconnected so that GetDevCaps can return this info.
ptLineDev->wDeviceAvail = 0;
dwRet = 0;
}
} else {
DEBUGMSG(ZONE_FUNC|ZONE_INIT,
(TEXT("UNIMODEM:-TSPI_providerDeleteLineDevice, invalid device id x%X.\n"),
Identifier));
}
DEBUGMSG(ZONE_FUNC|ZONE_INIT,
(TEXT("UNIMODEM:-TSPI_providerDeleteLineDevice.\n")));
return dwRet;
}
LONG
TSPIAPI
TSPI_providerRemoveDevice(
LPCWSTR lpszDeviceName
)
{
PTLINEDEV ptLineDev;
LONG rc = LINEERR_OPERATIONFAILED;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_providerRemoveDevice\n")));
// See if we actually have such a device in our system
if (ptLineDev = GetLineDevfromName(lpszDeviceName, NULL)) {
rc = TSPI_providerDeleteLineDevice(ptLineDev->dwDeviceID);
}
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_providerRemoveDevice returning %x\n"), rc));
return rc;
} // TSPI_providerRemoveDevice
BOOL
DllEntry (HANDLE hinstDLL,
DWORD Op,
LPVOID lpvReserved)
{
switch (Op) {
case DLL_PROCESS_ATTACH :
DEBUGREGISTER(hinstDLL);
DEBUGMSG (ZONE_FUNC, (TEXT("UNIMODEM:DllEntry(ProcessAttach)\n")));
// Now lets init TSPIGlobals, etc.
TSPIDLL_Load( );
TspiGlobals.hInstance = hinstDLL; // Instance handle needed to
// load dialog resources
break;
case DLL_PROCESS_DETACH :
case DLL_THREAD_DETACH :
case DLL_THREAD_ATTACH :
default :
break;
}
return TRUE;
}
// **********************************************************************
// Now we need to provide a vtbl that can be used to access our functions
// **********************************************************************
TSPI_PROCS tspi_procs;
LONG TSPIAPI TSPI_lineGetProcTable(
LPTSPI_PROCS *lplpTspiProcs
)
{
PDWORD pdw;
LONG i;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+TSPI_lineGetProcTable, ptr = x%X\n"), &tspi_procs));
if (tspi_procs.TSPI_lineClose != TSPI_lineClose) {
for (pdw = (PDWORD)&tspi_procs, i = 0;
i < sizeof(TSPI_PROCS)/sizeof(DWORD);
pdw++,i++) {
*pdw = (DWORD)TSPI_Unsupported;
}
tspi_procs.TSPI_lineAccept = TSPI_lineAccept;
tspi_procs.TSPI_lineAnswer = TSPI_lineAnswer;
tspi_procs.TSPI_lineClose = TSPI_lineClose;
tspi_procs.TSPI_lineCloseCall = TSPI_lineCloseCall;
tspi_procs.TSPI_lineConditionalMediaDetection = TSPI_lineConditionalMediaDetection;
tspi_procs.TSPI_lineDevSpecific = TSPI_lineDevSpecific;
tspi_procs.TSPI_lineDial = TSPI_lineDial;
tspi_procs.TSPI_lineDrop = TSPI_lineDrop;
tspi_procs.TSPI_lineGetAddressCaps = TSPI_lineGetAddressCaps;
tspi_procs.TSPI_lineGetAddressStatus = TSPI_lineGetAddressStatus;
tspi_procs.TSPI_lineGetCallInfo = TSPI_lineGetCallInfo;
tspi_procs.TSPI_lineGetCallStatus = TSPI_lineGetCallStatus;
tspi_procs.TSPI_lineGetDevCaps = TSPI_lineGetDevCaps;
tspi_procs.TSPI_lineGetDevConfig = TSPI_lineGetDevConfig;
tspi_procs.TSPI_lineGetIcon = TSPI_lineGetIcon;
tspi_procs.TSPI_lineGetID = TSPI_lineGetID;
tspi_procs.TSPI_lineGetLineDevStatus = TSPI_lineGetLineDevStatus;
tspi_procs.TSPI_lineGetNumAddressIDs = TSPI_lineGetNumAddressIDs;
tspi_procs.TSPI_lineMakeCall = TSPI_lineMakeCall;
tspi_procs.TSPI_lineNegotiateTSPIVersion = TSPI_lineNegotiateTSPIVersion;
tspi_procs.TSPI_lineOpen = TSPI_lineOpen;
tspi_procs.TSPI_lineSetDevConfig = TSPI_lineSetDevConfig;
tspi_procs.TSPI_lineSetMediaMode = TSPI_lineSetMediaMode;
tspi_procs.TSPI_lineSetStatusMessages = TSPI_lineSetStatusMessages;
tspi_procs.TSPI_providerInit = TSPI_providerInit;
tspi_procs.TSPI_providerInstall = TSPI_providerInstall;
tspi_procs.TSPI_providerShutdown = TSPI_providerShutdown;
tspi_procs.TSPI_providerEnumDevices = TSPI_providerEnumDevices;
tspi_procs.TSPI_providerCreateLineDevice = TSPI_providerCreateLineDevice;
tspi_procs.TSPI_providerDeleteLineDevice = TSPI_providerDeleteLineDevice;
tspi_procs.TSPI_lineConfigDialogEdit = TSPI_lineConfigDialogEdit;
tspi_procs.TSPI_providerRemoveDevice = TSPI_providerRemoveDevice;
tspi_procs.TSPI_lineSetDefaultMediaDetection = TSPI_lineSetDefaultMediaDetection;
}
*lplpTspiProcs = &tspi_procs;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-TSPI_lineGetProcTable, ptr = x%X\n"), &tspi_procs));
return SUCCESS;
}
Legal Declaration: it is for studying wince(MicroSoft Windows CE) only! : http://www.vxworks6.com