Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

980 lines
29 KiB

/*****************************************************************************
*
* PidInit.c
* Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
* Abstract:
*
* Initialization code .
*
*****************************************************************************/
#include "pidpr.h"
#define sqfl ( sqflInit )
#define NudgeWorkerThread(thid) \
PostThreadMessage(thid, WM_NULL, 0x0, (LPARAM)NULL)
#pragma BEGIN_CONST_DATA
static PIDUSAGE c_rgUsgPool[] =
{
MAKE_PIDUSAGE(SIMULTANEOUS_EFFECTS_MAX, FIELD_OFFSET(REPORTPOOL,uSimulEfMax)),
MAKE_PIDUSAGE(RAM_POOL_SIZE, FIELD_OFFSET(REPORTPOOL,uRamPoolSz)),
MAKE_PIDUSAGE(ROM_POOL_SIZE, FIELD_OFFSET(REPORTPOOL,uRomPoolSz)),
MAKE_PIDUSAGE(ROM_EFFECT_BLOCK_COUNT, FIELD_OFFSET(REPORTPOOL,uRomETCount)),
MAKE_PIDUSAGE(POOL_ALIGNMENT, FIELD_OFFSET(REPORTPOOL,uPoolAlign)),
};
static PIDUSAGE c_rgUsgPoolSz[] =
{
MAKE_PIDUSAGE(SET_CONSTANT_FORCE_REPORT, FIELD_OFFSET(SZPOOL, uSzConstant)),
MAKE_PIDUSAGE(SET_ENVELOPE_REPORT, FIELD_OFFSET(SZPOOL, uSzEnvelope)),
MAKE_PIDUSAGE(SET_CONDITION_REPORT, FIELD_OFFSET(SZPOOL, uSzCondition)),
MAKE_PIDUSAGE(SET_CUSTOM_FORCE_REPORT, FIELD_OFFSET(SZPOOL, uSzCustom)),
MAKE_PIDUSAGE(SET_PERIODIC_REPORT, FIELD_OFFSET(SZPOOL, uSzPeriodic)),
MAKE_PIDUSAGE(SET_RAMP_FORCE_REPORT, FIELD_OFFSET(SZPOOL, uSzRamp)),
MAKE_PIDUSAGE(SET_EFFECT_REPORT, FIELD_OFFSET(SZPOOL, uSzEffect)),
MAKE_PIDUSAGE(CUSTOM_FORCE_DATA_REPORT, FIELD_OFFSET(SZPOOL, uSzCustomData)),
};
static PIDREPORT PoolSz =
{
HidP_Feature,
HID_USAGE_PAGE_PID,
HID_USAGE_PID_PARAMETER_BLOCK_SIZE,
cbX(SZPOOL),
cA(c_rgUsgPoolSz),
c_rgUsgPoolSz
};
PIDREPORT g_PoolReport =
{
HidP_Feature,
HID_USAGE_PAGE_PID,
HID_USAGE_PID_POOL_REPORT,
cbX(REPORTPOOL),
cA(c_rgUsgPool),
c_rgUsgPool
};
static PIDSUPPORT g_PoolSupport[] =
{
{PID_DEVICEMANAGED, PIDMAKEUSAGEDWORD(DEVICE_MANAGED_POOL), HID_BUTTON, HidP_Feature},
{PID_SHAREDPARAM, PIDMAKEUSAGEDWORD(SHARED_PARAMETER_BLOCKS), HID_BUTTON, HidP_Feature},
};
#pragma END_CONST_DATA
/*****************************************************************************
*
* PID_InitSharedMem
*
* Inits our Shared Memory
*
*****************************************************************************/
HRESULT INTERNAL
PID_InitSharedMem
(
IDirectInputEffectDriver *ped
)
{
HRESULT hres = S_OK;
CPidDrv *this = (CPidDrv *)ped;
EnterProcI( PID_InitSharedMem, (_"x", ped));
// Get hold of global memory to keep the EffectState
if( SUCCEEDED(hres) )
{
UINT unitID;
hres = DIERR_PID_NOTINITIALIZED;
WaitForSingleObject(g_hmtxShared, INFINITE);
for(unitID = 0; unitID < MAX_UNITS; unitID++)
{
GUID* pGuid = &g_pshmem->rgus[unitID].GuidInstance;
#ifdef DEBUG
TCHAR lpName[MAX_PATH];
NameFromGUID(lpName, pGuid);
SquirtSqflPtszV(sqfl | sqflVerbose,
TEXT("%s:UnitId(%d): GUID %s"),
s_tszProc, unitID, lpName );
#endif
if( IsEqualGUID(pGuid, &this->GuidInstance) )
{
this->iUnitStateOffset = (&g_pshmem->rgus[unitID] - (PUNITSTATE)g_pshmem);
hres = S_OK;
} else if( IsEqualGUID(pGuid, &GUID_NULL ) )
{
PUNITSTATE pUnitState;
this->iUnitStateOffset = (&g_pshmem->rgus[unitID] - (PUNITSTATE)g_pshmem);
pUnitState = (PUNITSTATE)(g_pshmem + this->iUnitStateOffset);
pUnitState->GuidInstance = this->GuidInstance;
pUnitState->nAlloc = 0x0;
ZeroBuf(pUnitState->State,GLOBAL_EFFECT_MEMSZ );
hres = S_OK;
}
if( SUCCEEDED(hres) )
{
break;
}
}
if(SUCCEEDED(hres) )
{
PUNITSTATE pUnitState = (PUNITSTATE)(g_pshmem + this->iUnitStateOffset);
PPIDMEM pGuard = pUnitState->Guard;
INT_PTR iGuard1 = (PUCHAR)&pUnitState->Guard[0] - (PUCHAR)pUnitState, iGuard2 = (PUCHAR)&pUnitState->Guard[1] - (PUCHAR)pUnitState;
pGuard->uOfSz = PIDMEM_OFSZ(0x0, 0x0 );
pGuard->iNext = iGuard2;
pGuard++;
pGuard->uOfSz = PIDMEM_OFSZ(this->ReportPool.uRamPoolSz, 0x0);
pGuard->iNext = iGuard1;
pUnitState->nAlloc = 0x2;
pUnitState->cEfDownloaded = (USHORT)this->ReportPool.uRomETCount;
}
ReleaseMutex(g_hmtxShared);
if( FAILED(hres) )
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%s:FAIL Could not find free unitID"),
s_tszProc );
}
}
ExitOleProc();
return hres;
}
/*****************************************************************************
*
* PID_InitScaling
*
* Inits Scaling Coefficients
*
*****************************************************************************/
PID_InitScaling
(
IDirectInputEffectDriver *ped
)
{
HRESULT hres = S_OK;
CPidDrv *this = (CPidDrv *)ped;
USHORT LinkCollection;
UINT indx;
EnterProc( PID_InitScaling, (_"x", ped));
// Scaling Exponents and Offsets
this->DiSEffectScale.dwSize = this->DiSEffectOffset.dwSize = sizeof(DIEFFECT); /* sizeof(DIEFFECT) */
//this->DiSEffect.dwFlags /* DiEffect* */
this->DiSEffectScale.dwDuration = DI_SECONDS ;/* Microseconds */
this->DiSEffectScale.dwSamplePeriod = DI_SECONDS ;/* Microseconds */
this->DiSEffectScale.dwGain = DI_FFNOMINALMAX;
this->DiSEffectScale.dwTriggerButton = 0x0; /* or DIEB_NOTRIGGER */
this->DiSEffectScale.dwTriggerRepeatInterval = DI_SECONDS; /* Microseconds */
//this->DiSEffect.cAxes; /* Number of axes */
//this->DiSEffect.rgdwAxes; /* Array of axes */
//this->DiSEffect.rglDirection; /* Array of directions */
//this->DiSEffect.lpEnvelope; /* Optional */
//this->DiSEffect.cbTypeSpecificParams; /* Size of params */
//this->DiSEffect.lpvTypeSpecificParams; /* Pointer to params */
#if DIRECTINPUT_VERSION >= 0x600
this->DiSEffectScale.dwStartDelay = DI_SECONDS; // Start delay
#endif
if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Effect.UsagePage, g_Effect.Collection, 0x0, &LinkCollection )))
{
PID_ComputeScalingFactors(ped, &g_Effect, LinkCollection, &this->DiSEffectScale, this->DiSEffectScale.dwSize, &this->DiSEffectOffset, this->DiSEffectOffset.dwSize);
}
this->DiSEnvScale.dwSize = this->DiSEnvOffset.dwSize = sizeof(DIENVELOPE); /* sizeof(DIENVELOPE) */
this->DiSEnvScale.dwAttackLevel = DI_FFNOMINALMAX;
this->DiSEnvScale.dwAttackTime = DI_SECONDS; /* Microseconds */
this->DiSEnvScale.dwFadeLevel = DI_FFNOMINALMAX;
this->DiSEnvScale.dwFadeTime = DI_SECONDS; /* Microseconds */
if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Envelope.UsagePage, g_Envelope.Collection, 0x0, &LinkCollection)))
{
PID_ComputeScalingFactors(ped, &g_Envelope, LinkCollection, &this->DiSEnvScale, this->DiSEnvScale.dwSize, &this->DiSEnvOffset, this->DiSEnvOffset.dwSize);
}
this->DiSPeriodicScale.dwMagnitude = DI_FFNOMINALMAX;
this->DiSPeriodicScale.lOffset = DI_FFNOMINALMAX;
this->DiSPeriodicScale.dwPhase = 360 * DI_DEGREES;
this->DiSPeriodicScale.dwPeriod = DI_SECONDS;
if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Periodic.UsagePage, g_Periodic.Collection, 0x0, &LinkCollection)))
{
PID_ComputeScalingFactors(ped, &g_Periodic, LinkCollection, &this->DiSPeriodicScale, cbX(this->DiSPeriodicScale), &this->DiSPeriodicOffset, cbX(this->DiSPeriodicOffset));
}
this->DiSRampScale.lStart =
this->DiSRampScale.lEnd = DI_FFNOMINALMAX;
if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Ramp.UsagePage, g_Ramp.Collection, 0x0, &LinkCollection)))
{
PID_ComputeScalingFactors(ped, &g_Ramp, LinkCollection, &this->DiSRampScale, cbX(this->DiSRampScale), &this->DiSRampOffset, cbX(this->DiSRampOffset));
}
this->DiSCondScale.lOffset =
this->DiSCondScale.lPositiveCoefficient =
this->DiSCondScale.lNegativeCoefficient =
this->DiSCondScale.dwPositiveSaturation =
this->DiSCondScale.dwNegativeSaturation =
this->DiSCondScale.lDeadBand = DI_FFNOMINALMAX;
if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Condition.UsagePage,g_Condition.Collection,0x0, &LinkCollection)))
{
PID_ComputeScalingFactors(ped, &g_Condition, LinkCollection, &this->DiSCondScale, cbX(this->DiSCondScale), &this->DiSCondOffset, cbX(this->DiSCondOffset));
}
this->DiSConstScale.lMagnitude = DI_FFNOMINALMAX;
if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Constant.UsagePage, g_Constant.Collection, 0x0, &LinkCollection)))
{
PID_ComputeScalingFactors(ped, &g_Constant, LinkCollection, &this->DiSConstScale,cbX(this->DiSConstScale), &this->DiSConstOffset,cbX(this->DiSConstOffset));
}
this->DiSCustomScale.dwSamplePeriod = DI_SECONDS;
if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Custom.UsagePage, g_Custom.Collection, 0x0, &LinkCollection)))
{
PID_ComputeScalingFactors(ped, &g_Custom, LinkCollection, &this->DiSCustomScale, cbX(this->DiSCustomScale), &this->DiSCustomOffset, cbX(this->DiSCustomOffset));
}
// Direction could be ordinals
g_Direction.cbXData = cA(c_rgUsgOrdinals)*cbX(DWORD);
g_Direction.cAPidUsage = cA(c_rgUsgOrdinals);
g_Direction.rgPidUsage = c_rgUsgOrdinals;
if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Direction.UsagePage, g_Direction.Collection, 0x0, &LinkCollection)))
{
HRESULT hres1;
for(indx = 0x0; indx < MAX_ORDINALS; indx++)
{
this->DiSEffectAngleScale[indx] = 360 * DI_DEGREES;
}
hres1 = PID_ComputeScalingFactors(ped, &g_Direction, LinkCollection, &this->DiSEffectAngleScale[0], cbX(this->DiSEffectAngleScale), &this->DiSEffectAngleOffset[0], cbX(this->DiSEffectAngleOffset));
// Direction could be angles
if(hres1 == E_NOTIMPL )
{
g_Direction.cbXData = cA(c_rgUsgDirection)*cbX(DWORD);
g_Direction.cAPidUsage = cA(c_rgUsgDirection);
g_Direction.rgPidUsage = c_rgUsgDirection;
// Reset the nominal values
for(indx = 0x0; indx < MAX_ORDINALS; indx++)
{
this->DiSEffectAngleScale[indx] = 360 * DI_DEGREES;
}
hres1 = PID_ComputeScalingFactors(ped, &g_Direction, LinkCollection, &this->DiSEffectAngleScale[0], cbX(this->DiSEffectAngleScale), &this->DiSEffectAngleOffset[0], cbX(this->DiSEffectAngleOffset));
if( hres1 == E_NOTIMPL )
{
// Could be direction Vectors
// Not sure how vectors are implemented in PID
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%s:FAIL Cannot understand the direction collection\n")
TEXT("\t\t Supported usages are {Rx, Ry, Rz} or {Ordinals} \n"),
s_tszProc );
}
}
}
for(indx = 0x0; indx < MAX_ORDINALS; indx++)
{
this->DiSCustomSample[indx] = DI_FFNOMINALMAX;
}
if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_CustomSample.UsagePage, g_CustomSample.Collection, 0x0, &LinkCollection)) )
{
//get the custom data for each axis
USHORT cAValCaps = 0x1;
USAGE UsagePage;
USAGE Usage[3] = {HID_USAGE_GENERIC_X, HID_USAGE_GENERIC_Y, HID_USAGE_GENERIC_Z};
NTSTATUS ntSt[3];
int nAxis = 0;
UsagePage = HID_USAGE_PAGE_GENERIC;
for (nAxis = 0; nAxis < 3; nAxis ++)
{
cAValCaps = 0x1;
ntSt[nAxis] = HidP_GetSpecificValueCaps
(
g_CustomSample.HidP_Type,
UsagePage,
LinkCollection,
Usage[nAxis],
&this->customCaps[nAxis],
&cAValCaps,
this->ppd
);
if (FAILED(ntSt[nAxis]))
{
this->customCaps[nAxis].BitSize = 0;
this->customCaps[nAxis].LogicalMin = this->customCaps[nAxis].LogicalMax = 0;
}
}
if ((FAILED(ntSt[0])) && (FAILED(ntSt[1])) && (FAILED(ntSt[2])))
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%s:FAIL Cannot understand the download force sample collection\n")
TEXT("\t\t Supported usages are {X, Y, Z} \n"),
s_tszProc );
}
//get how many bytes of custom data can send at a time
if (SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_CustomData.UsagePage, g_CustomData.Collection, 0x0, &LinkCollection )))
{
USAGE UsageData = HID_USAGE_PID_CUSTOM_FORCE_DATA;
NTSTATUS ntst;
cAValCaps = 0x1;
UsagePage = HID_USAGE_PAGE_PID;
ntst = HidP_GetSpecificValueCaps
(
g_CustomData.HidP_Type,
UsagePage,
LinkCollection,
UsageData,
&this->customDataCaps,
&cAValCaps,
this->ppd
);
if (FAILED(ntst))
{
this->customDataCaps.BitSize = 0;
}
}
}
ExitOleProc();
return hres;
}
/*****************************************************************************
*
* DIEnumProc
*
* Enum and cache FF device objects
*
*****************************************************************************/
BOOL CALLBACK
DIEnumProc(LPCDIDEVICEOBJECTINSTANCE pinst, LPVOID pv)
{
BOOL frc = DIENUM_CONTINUE;
HRESULT hres = S_OK;
CPidDrv* this = (CPidDrv*) pv;
EnterProc( DIEnumProc, (_"xx", pinst, pv ));
if( (pinst->dwFlags & DIDOI_FFACTUATOR )
||(pinst->dwFlags & DIDOI_FFEFFECTTRIGGER ))
{
AssertF(this->cFFObj <= this->cFFObjMax);
if( this->cFFObj == this->cFFObjMax )
{
/* Grow by doubling */
this->cFFObjMax = max(PIDALLOC_INIT, 2*this->cFFObjMax);
hres = ReallocCbPpv(this->cFFObjMax * cbX(DIUSAGEANDINST), &this->rgFFUsageInst);
}
if( SUCCEEDED(hres) )
{
PDIUSAGEANDINST pdiUI = this->rgFFUsageInst + this->cFFObj;
pdiUI->dwUsage = DIMAKEUSAGEDWORD(pinst->wUsagePage, pinst->wUsage);
pdiUI->dwType = pinst->dwType ;
}
this->cFFObj++;
}
if( FAILED(hres) )
{
frc = DIENUM_STOP;
}
ExitProcF(frc);
return frc;
}
STDMETHODIMP
PID_InitFFAttributes
(
IDirectInputEffectDriver *ped
)
{
HRESULT hres = S_OK;
CPidDrv *this = (CPidDrv *)ped;
EnterProcI( PID_Init, (_"x", ped));
// We cannot call this function at init, because DInput call us before the device
// has been completely initialized.
if( this->cFFObj )
{
hres = S_FALSE; // Already initialized
} else
{
// We need to get the Usage & UsagePage
// for device objects marked as
// FF Triggers and FF Actuators
//If we are called with DInput version not larger than 7, load dinput.dll w/ IID_DirectInput7
//else load dinput8.dll.
if (this->dwDirectInputVersion <= 0x0700)
{
HINSTANCE hinst = LoadLibrary(TEXT("dinput.dll"));
if (hinst)
{
typedef HRESULT ( WINAPI * DIRECTINPUTCREATEEX) ( HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter);
DIRECTINPUTCREATEEX _DirectInputCreateEx;
LPDIRECTINPUT lpDI;
_DirectInputCreateEx = (DIRECTINPUTCREATEEX)GetProcAddress(hinst, "DirectInputCreateEx");
if (_DirectInputCreateEx)
{
hres = _DirectInputCreateEx(g_hinst, this->dwDirectInputVersion, &IID_IDirectInput7, &lpDI, NULL );
if( SUCCEEDED(hres) )
{
LPDIRECTINPUTDEVICE pdid;
hres = IDirectInput_CreateDevice(lpDI, &this->GuidInstance, &pdid, NULL);
/* Create the device object */
if( SUCCEEDED(hres) )
{
hres = IDirectInputDevice2_EnumObjects
(
pdid,
DIEnumProc,
ped,
DIDFT_ALL //DIDFT_FFEFFECTTRIGGER | DIDFT_FFACTUATOR
);
IDirectInput_Release(pdid);
}
IDirectInput_Release(lpDI);
}
}
else //!DirectInputCreateEx
{
//Something is horribly wrong here if we can't find the Create fn!
//Return the same error code that CDIDev_CreateEffectDriver() returns if there was an error loading FF driver
hres = DIERR_UNSUPPORTED;
}
FreeLibrary(hinst);
}
else // !hinst
{
//Something is horribly wrong here if we came through Dinput but can't load it!
//Return the same error code that CDIDev_CreateEffectDriver() returns if there was an error loading FF driver
hres = DIERR_UNSUPPORTED;
}
}
else
{
HINSTANCE hinst = LoadLibrary(TEXT("dinput8.dll"));
if (hinst)
{
typedef HRESULT ( WINAPI * DIRECTINPUT8CREATE) ( HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter);
DIRECTINPUT8CREATE _DirectInput8Create;
LPDIRECTINPUT8 lpDI;
_DirectInput8Create = (DIRECTINPUT8CREATE)GetProcAddress(hinst, "DirectInput8Create");
if (_DirectInput8Create)
{
hres = _DirectInput8Create(g_hinst, this->dwDirectInputVersion, &IID_IDirectInput8, &lpDI, NULL );
if( SUCCEEDED(hres) )
{
LPDIRECTINPUTDEVICE8 pdid;
hres = IDirectInput8_CreateDevice(lpDI, &this->GuidInstance, &pdid, NULL);
/* Create the device object */
if( SUCCEEDED(hres) )
{
hres = IDirectInputDevice8_EnumObjects
(
pdid,
DIEnumProc,
ped,
DIDFT_ALL //DIDFT_FFEFFECTTRIGGER | DIDFT_FFACTUATOR
);
IDirectInput_Release(pdid);
}
IDirectInput_Release(lpDI);
}
}
else //!DirectInput8Create
{
//Something is horribly wrong here if we can't find the Create fn!
//Return the same error code that CDIDev_CreateEffectDriver() returns if there was an error loading FF driver
hres = DIERR_UNSUPPORTED;
}
FreeLibrary(hinst);
}
else // !hinst
{
//Something is horribly wrong here if we came through Dinput but can't load it!
//Return the same error code that CDIDev_CreateEffectDriver() returns if there was an error loading FF driver
hres = DIERR_UNSUPPORTED;
}
}
}
ExitOleProc();
return hres;
}
/*****************************************************************************
*
* PID_Init
*
* Inits PID device
*
*****************************************************************************/
STDMETHODIMP
PID_Init
(
IDirectInputEffectDriver *ped
)
{
HRESULT hres = S_OK;
CPidDrv *this = (CPidDrv *)ped;
USHORT LinkCollection;
EnterProcI( PID_Init, (_"x", ped));
PID_CreateUsgTxt();
AssertF( this->hdev == INVALID_HANDLE_VALUE );
if( SUCCEEDED(hres) )
{
this->hdev = CreateFile(this->tszDeviceInterface,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0, /* no SECURITY_ATTRIBUTES */
OPEN_EXISTING,
0x0, /* attributes */
0); /* template */
if( this->hdev == INVALID_HANDLE_VALUE )
{
hres = E_HANDLE;
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%s:FAIL CreateFile"),
s_tszProc );
}
}
if( SUCCEEDED(hres) )
{
// Get all the HID goo
if( HidD_GetAttributes(this->hdev, &this->attr) &&
HidD_GetPreparsedData(this->hdev, &this->ppd) &&
SUCCEEDED(HidP_GetCaps(this->ppd, &this->caps)) )
{
// Success
} else
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%s: FAIL HID init "),
s_tszProc );
hres = DIERR_PID_NOTINITIALIZED;
}
}
if( SUCCEEDED(hres) )
{
// Get collection info
hres = AllocCbPpv(cbX(*this->pLinkCollection) * this->caps.NumberLinkCollectionNodes,
&this->pLinkCollection);
if( SUCCEEDED(hres) && (this->pLinkCollection != NULL) )
{
ULONG cALinkCollection=this->caps.NumberLinkCollectionNodes;
hres = HidP_GetLinkCollectionNodes
(
this->pLinkCollection,
&cALinkCollection,
this->ppd
);
}
}
if(SUCCEEDED(hres) )
{
UINT indx;
this->cbReport[HidP_Input] = this->caps.InputReportByteLength;
this->cbReport[HidP_Output] = this->caps.OutputReportByteLength;
this->cbReport[HidP_Feature] = this->caps.FeatureReportByteLength;
//write reports are output reports
for( indx = 0x0; indx < MAX_BLOCKS; indx++ )
{
this->cbWriteReport[indx] = this->caps.OutputReportByteLength;
}
for( indx = 0x0; indx < HidP_Max; indx++ )
{
hres = AllocCbPpv(this->cbReport[indx], &this->pReport[indx]);
if( FAILED(hres) )
{
break;
}
}
for( indx = 0x0; indx < MAX_BLOCKS; indx++ )
{
hres = AllocCbPpv(this->cbWriteReport[indx], &this->pWriteReport[indx]);
if( FAILED(hres) )
{
break;
}
}
}
if( SUCCEEDED(hres) )
{
hres = PID_InitRegistry(ped);
}
if(SUCCEEDED(PID_GetLinkCollectionIndex(ped,g_PoolReport.UsagePage,g_PoolReport.Collection,0x0,&LinkCollection)))
{
PUCHAR pReport = this->pReport[g_PoolReport.HidP_Type];
UINT cbReport = this->cbReport[g_PoolReport.HidP_Type];
PID_GetReport
(ped,
&g_PoolReport,
LinkCollection,
pReport,
cbReport
);
PID_ParseReport
(
ped,
&g_PoolReport,
LinkCollection,
&this->ReportPool,
cbX(this->ReportPool),
pReport,
cbReport
);
}
SquirtSqflPtszV(sqfl | sqflVerbose,
TEXT("%s:RamPoolSz:0x%x"),
s_tszProc, this->ReportPool.uRamPoolSz );
if(SUCCEEDED(PID_GetLinkCollectionIndex(ped,PoolSz.UsagePage,PoolSz.Collection,0x0,&LinkCollection)) )
{
PUCHAR pReport = this->pReport[PoolSz.HidP_Type];
UINT cbReport = this->cbReport[PoolSz.HidP_Type];
PID_GetReport
(ped,
&PoolSz,
LinkCollection,
pReport,
cbReport
);
PID_ParseReport
(
ped,
&PoolSz,
LinkCollection,
&this->SzPool,
cbX(this->SzPool),
pReport,
cbReport
);
}
PID_Support(ped, cA(g_PoolSupport), g_PoolSupport, &this->uDeviceManaged);
// Determine max number of parameter blocks per effect ?
if( SUCCEEDED(hres) )
{
USHORT LinkCollection;
hres = PID_GetLinkCollectionIndex(ped, HID_USAGE_PAGE_PID, HID_USAGE_PID_TYPE_SPECIFIC_BLOCK_OFFSET, 0x0, &LinkCollection );
if( SUCCEEDED(hres) )
{
USHORT cAValCaps;
cAValCaps = 0x0;
HidP_GetSpecificValueCaps
(
HidP_Output,
HID_USAGE_PAGE_ORDINALS,
LinkCollection,
0x0,
NULL,
&cAValCaps,
this->ppd
);
this->cMaxParameters = cAValCaps;
} else
{
this->cMaxParameters = 0x2;
hres = S_OK;
}
}
if( SUCCEEDED(hres))
{
hres = PID_InitSharedMem(ped);
}
if( SUCCEEDED(hres ) )
{
hres = PID_InitScaling(ped);
}
if( SUCCEEDED(hres) )
{
// Determine Max effects that can be downloaded to the device
HIDP_VALUE_CAPS ValCaps;
USHORT cAValCaps = 0x1;
USAGE UsagePage = DIGETUSAGEPAGE(g_BlockIndex.rgPidUsage[0].dwUsage);
USAGE Usage = DIGETUSAGE(g_BlockIndex.rgPidUsage[0].dwUsage);
hres = HidP_GetSpecificValueCaps
(
g_BlockIndex.HidP_Type,
UsagePage,
0x0,
Usage,
&ValCaps,
&cAValCaps,
this->ppd
);
if( SUCCEEDED(hres) || ( hres == HIDP_STATUS_BUFFER_TOO_SMALL ) )
{
hres = S_OK;
this->cMaxEffects = (USHORT) ( ValCaps.PhysicalMax - ValCaps.PhysicalMin );
} else
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%s: FAIL HidP_GetValCaps for (%x %x:%s) "),
s_tszProc , UsagePage, Usage, PIDUSAGETXT(UsagePage,Usage) );
}
}
this->cMaxEffects = (USHORT)min(this->cMaxEffects,
GLOBAL_EFFECT_MEMSZ / ((FIELD_OFFSET(EFFECTSTATE,PidMem)) + this->cMaxParameters*cbX(PIDMEM)) );
if( this->ReportPool.uSimulEfMax == 0x0 )
{
this->ReportPool.uSimulEfMax = 0xff;
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%s: FAIL HID dwSimulEfMax == 0x0 defaults to %d "),
s_tszProc, this->cMaxEffects );
}
if( SUCCEEDED(hres) )
{
TCHAR tsz[MAX_PATH];
AssertF(this->hThread == 0x0 );
AssertF(this->hWrite == 0x0);
AssertF(this->hWriteComplete == 0x0);
if( GetModuleFileName(g_hinst, tsz, cA(tsz))
&&LoadLibrary(tsz) == g_hinst)
{
InterlockedIncrement(&this->cThreadRef);
AssertF(this->cThreadRef == 0x1 );
AssertF(this->hThread == 0x0 );
this->hWrite = CreateEvent(NULL, FALSE, FALSE, NULL);
if (this->hWrite == 0x0)
{
goto event_thread_error;
}
this->hWriteComplete = CreateEvent(NULL, TRUE, TRUE, NULL);
if (this->hWriteComplete == 0x0)
{
goto event_thread_error;
}
this->hThread= CreateThread(0, 0, (LPTHREAD_START_ROUTINE)PID_ThreadProc, this,
0, &this->idThread);
if (this->hThread == 0x0)
{
event_thread_error:;
//close the event handles
if (this->hWrite != 0x0)
{
CloseHandle(this->hWrite);
this->hWrite = 0x0;
}
if (this->hWriteComplete != 0x0)
{
CloseHandle(this->hWriteComplete);
this->hWriteComplete = 0x0;
}
hres = DIERR_PID_NOTINITIALIZED;
FreeLibrary(g_hinst);
InterlockedDecrement(&this->cThreadRef);
}
}
}
ExitOleProc();
return hres;
}
/*****************************************************************************
*
* PID_Finalize
*
* Destroys PID device specific memory
*
*****************************************************************************/
STDMETHODIMP
PID_Finalize
(
IDirectInputEffectDriver *ped
)
{
HRESULT hres = S_OK;
CPidDrv *this = (CPidDrv *)ped;
HANDLE hdev;
UINT indx;
EnterProc( PID_Finalize, (_"x", ped));
DllEnterCrit();
// Assasinate the thread
InterlockedDecrement(&this->cThreadRef);
AssertF(this->cThreadRef == 0x0 );
// Wait for the thread to die before we go about releasing
// memory
do
{
DWORD dwWait;
NudgeWorkerThread(this->idThread);
Sleep(0);
dwWait = WaitForSingleObject(this->hThread, 500 ) ;
if( WAIT_TIMEOUT == dwWait)
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%s: Waiting for worker Thread %d to die"),
s_tszProc,this->idThread );
}
//if didn't timeout, and thread didn't die, then we can get into an infinite loop.
//so close the handle.
if ((WAIT_ABANDONED == dwWait) || (WAIT_FAILED == dwWait))
{
if( this->hdevOvrlp != INVALID_HANDLE_VALUE )
{
HANDLE hdevOvr;
hdevOvr = this->hdevOvrlp;
this->hdevOvrlp = INVALID_HANDLE_VALUE;
CancelIo_(hdevOvr);
Sleep(0);
CloseHandle(hdevOvr);
}
AssertF(this->hdevOvrlp == INVALID_HANDLE_VALUE);
}
}while( this->hdevOvrlp != INVALID_HANDLE_VALUE );
// Close the handle
if( this->hdev != INVALID_HANDLE_VALUE)
{
hdev = this->hdev;
this->hdev = INVALID_HANDLE_VALUE;
CloseHandle(hdev);
}
// Free PreParseData
if( this->ppd )
{
HidD_FreePreparsedData(this->ppd);
this->ppd = NULL;
}
// Free HIDP_VALUE_CAPS data
FreePpv(&this->rgFFUsageInst);
FreePpv(&this->pLinkCollection);
for(indx = 0x0; indx < HidP_Max; indx++ )
{
FreePpv(&this->pReport[indx]);
}
for(indx = 0x0; indx < MAX_BLOCKS; indx++ )
{
FreePpv(&this->pWriteReport[indx]);
}
DllLeaveCrit();
ExitOleProc();
return hres;
}