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