/***************************************************************************** * * PidRd.c * * Copyright (c) 1999 Microsoft Corporation. All Rights Reserved. * * * * Abstract: * * Read input data from PID device . * *****************************************************************************/ #include "pidpr.h" #define sqfl (sqflRead) BOOL INTERNAL PID_IssueRead(PCPidDrv this); BOOL INTERNAL PID_IssueWrite(PCPidDrv this); /***************************************************************************** * * @doc INTERNAL * * @func PCHID | pchidFromPo | * * Given an interior pointer to an , retrieve * a pointer to the parent . * * @parm LPOVERLAPPED | po | * * The pointer to convert. * *****************************************************************************/ PCPidDrv INLINE pCPidDrvFromPo(LPOVERLAPPED po) { return (CPidDrv*) pvSubPvCb(po, FIELD_OFFSET(CPidDrv, o)); } void CALLBACK PID_ReadComplete(DWORD dwError, DWORD cbRead, LPOVERLAPPED po) { PCPidDrv this = pCPidDrvFromPo(po); //EnterProc( PID_ReadComplete, (_"xxx", dwError, cbRead, po )); if( !IsBadReadPtr(this, cbX(this)) &&this->cThreadRef && dwError == 0 //&&( this->o.InternalHigh == this->cbReport[HidP_Input] ) &&( this->hdevOvrlp != INVALID_HANDLE_VALUE ) ) { HRESULT hres; PUCHAR pReport; UINT cbReport; USHORT LinkCollection = 0x0; USAGE rgUsages[MAX_BUTTONS] ; USAGE UsagePage = HID_USAGE_PAGE_PID; ULONG cAUsages = MAX_BUTTONS; BOOL fEffectPlaying = FALSE; LONG lEffectIndex; pReport = this->pReport[HidP_Input]; cbReport = this->cbReport[HidP_Input]; // If the report does not belong to the PID usage page // we should be out of here really quick. hres = HidP_GetUsages (HidP_Input, UsagePage, LinkCollection, rgUsages, &cAUsages, this->ppd, pReport, cbReport ); if( SUCCEEDED(hres ) ) { UINT indx; DWORD dwState = DIGFFS_ACTUATORSOFF | DIGFFS_USERFFSWITCHOFF | DIGFFS_POWEROFF | DIGFFS_SAFETYSWITCHOFF; for(indx = 0x0; indx < cAUsages; indx++ ) { USAGE Usage = rgUsages[indx]; switch(Usage) { case HID_USAGE_PID_EFFECT_PLAYING: fEffectPlaying = TRUE; break; case HID_USAGE_PID_DEVICE_PAUSED: dwState |= DIGFFS_PAUSED; break; case HID_USAGE_PID_ACTUATORS_ENABLED: dwState |= DIGFFS_ACTUATORSON; dwState &= ~(DIGFFS_ACTUATORSOFF); break; case HID_USAGE_PID_ACTUATOR_OVERRIDE_SWITCH: dwState |= DIGFFS_USERFFSWITCHON; dwState &= ~(DIGFFS_USERFFSWITCHOFF); break; case HID_USAGE_PID_SAFETY_SWITCH: dwState |= DIGFFS_SAFETYSWITCHON; dwState &= ~(DIGFFS_SAFETYSWITCHOFF); break; case HID_USAGE_PID_ACTUATOR_POWER: dwState |= DIGFFS_POWERON; dwState &= ~(DIGFFS_POWEROFF); break; default: SquirtSqflPtszV(sqfl | sqflVerbose, TEXT("%s: Unsupported input status usage (%x,%x:%s) "), TEXT("PID_ReadComplete"), UsagePage, Usage, PIDUSAGETXT(UsagePage,Usage) ); break; } this->dwState = dwState; } hres = PID_ParseReport( &this->ed, &g_BlockIndexIN, LinkCollection, &lEffectIndex, cbX(lEffectIndex), pReport, cbReport ); if( SUCCEEDED(hres) ) { PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this,lEffectIndex); if(fEffectPlaying) { pEffectState->lEfState |= DIEGES_PLAYING; } else { pEffectState->lEfState &= ~(DIEGES_PLAYING); } } } // Issue another read PID_IssueRead(this); } else { // Boo! } //ExitProc(); } BOOL INTERNAL PID_IssueRead(PCPidDrv this) { BOOL fRc = FALSE; if( !IsBadReadPtr(this, cbX(this)) && this->cThreadRef ) { fRc = ReadFileEx(this->hdevOvrlp, this->pReport[HidP_Input], this->cbReport[HidP_Input], &this->o, PID_ReadComplete); if (fRc == FALSE) { SquirtSqflPtszV(sqfl | sqflError, TEXT("FAIL ReadFileEx")); } } else { RPF(TEXT("Bad this pointer or thread ref count!")); } return fRc; } void CALLBACK PID_WriteComplete(DWORD dwError, DWORD cbWritten, LPOVERLAPPED po) { PCPidDrv this = pCPidDrvFromPo(po); //EnterProc( PID_ReadComplete, (_"xxx", dwError, cbRead, po )); if( !IsBadReadPtr(this, cbX(this)) &&(this->cThreadRef) //&&( this->o.InternalHigh == this->cbWriteReport[this->blockNr] ) &&(this->hWriteComplete) &&(this->hWrite) &&( this->hdevOvrlp != INVALID_HANDLE_VALUE ) ) { //if we didn't get an error & wrote everything -- or if we already tried //twice -- we move on if ( ((dwError == 0) && (cbWritten == this->cbWriteReport [this->blockNr])) || (this->dwWriteAttempt != 0) ) { //print a message if couldn't write a particular block if ((dwError != 0) || (cbWritten != this->cbWriteReport [this->blockNr])) { SquirtSqflPtszV(sqfl | sqflError, TEXT("Couldn't write block %u after two tries, giving up on this block."), this->blockNr); } //move on this->dwWriteAttempt = 0; this->blockNr++; if (this->blockNr < this->totalBlocks) { //write the next block if (PID_IssueWrite(this) == FALSE) { //in case of failure, the callback will never be called and the completion event never set, //so need to set it here. SetEvent(this->hWriteComplete); } } else { //we are done w/ this update AssertF(this->blockNr == this->totalBlocks); SetEvent(this->hWriteComplete); } } else { //this is the first time we tried to write a particular block, and we failed; //we will try once more SquirtSqflPtszV(sqfl | sqflBenign, TEXT("Couldn't write block %u on first attempt, retrying."), this->blockNr); this->dwWriteAttempt = 1; if (PID_IssueWrite(this) == FALSE) { //in case of failure, the callback will never be called and the completion event never set, //so need to set it here. this->dwWriteAttempt = 0; SetEvent(this->hWriteComplete); } } } else { //need to set the completion event, otherwise we will keep waiting... RPF(TEXT("Bad this pointer or thread ref count or handle!")); this->dwWriteAttempt = 0; SetEvent(this->hWriteComplete); } //ExitProc(); } BOOL INTERNAL PID_IssueWrite(PCPidDrv this) { BOOL fRc = FALSE; if( !IsBadReadPtr(this, cbX(this)) && this->cThreadRef ) { fRc = WriteFileEx(this->hdevOvrlp, this->pWriteReport[this->blockNr], this->cbWriteReport[this->blockNr], &this->o, PID_WriteComplete); if (fRc == FALSE) { SquirtSqflPtszV(sqfl | sqflError, TEXT("FAIL WriteFileEx")); } } else { RPF(TEXT("Bad this pointer or thread ref count!")); } return fRc; } VOID INTERNAL PID_ThreadProc(CPidDrv* this) { MSG msg; EnterProc( PID_ThreadProc, (_"x", this )); AssertF(this->hdevOvrlp == INVALID_HANDLE_VALUE ); this->hdevOvrlp = CreateFile(this->tszDeviceInterface, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, /* no SECURITY_ATTRIBUTES */ OPEN_EXISTING, FILE_FLAG_OVERLAPPED, /* attributes */ 0); /* template */ if( this->hdevOvrlp == INVALID_HANDLE_VALUE ) { SquirtSqflPtszV(sqfl | sqflError, TEXT("%s:FAIL CreateFile(OverLapped)"), s_tszProc ); } else //fix for mb 35282 -- no use calling PID_IssueRead() w/ an INVALID_HANDLE_VALUE for a file handle { if( PID_IssueRead(this) ) { do { DWORD dwRc; do { AssertF(this->hWrite != 0x0); AssertF(this->hWriteComplete != 0x0); dwRc = MsgWaitForMultipleObjectsEx(1, &this->hWrite, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE); if (dwRc == WAIT_OBJECT_0) { if (PID_IssueWrite(this) == FALSE) { //in case of failure, the callback will never be called and the completion event never set, //so need to set it here. SetEvent(this->hWriteComplete); } } } while ((dwRc == WAIT_IO_COMPLETION) || (dwRc == WAIT_OBJECT_0)); while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } while(this->cThreadRef); if( this->hdevOvrlp != INVALID_HANDLE_VALUE ) { HANDLE hdev; hdev = this->hdevOvrlp; this->hdevOvrlp = INVALID_HANDLE_VALUE; CancelIo_(hdev); Sleep(0); CloseHandle(hdev); } } } //close the event handles as well if (this->hWrite != 0x0) { CloseHandle(this->hWrite); this->hWrite = 0x0; } if (this->hWriteComplete != 0x0) { CloseHandle(this->hWriteComplete); this->hWriteComplete = 0x0; } if(this->hThread) { HANDLE hdev = this->hThread; this->hThread = NULL; CloseHandle(hdev); } FreeLibraryAndExitThread(g_hinst, 0); ExitProc(); }