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.

380 lines
9.4 KiB

  1. /*****************************************************************************
  2. *
  3. * PidRd.c
  4. *
  5. * Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
  6. *
  7. *
  8. *
  9. * Abstract:
  10. *
  11. * Read input data from PID device .
  12. *
  13. *****************************************************************************/
  14. #include "pidpr.h"
  15. #define sqfl (sqflRead)
  16. BOOL INTERNAL
  17. PID_IssueRead(PCPidDrv this);
  18. BOOL INTERNAL
  19. PID_IssueWrite(PCPidDrv this);
  20. /*****************************************************************************
  21. *
  22. * @doc INTERNAL
  23. *
  24. * @func PCHID | pchidFromPo |
  25. *
  26. * Given an interior pointer to an <t OVERLAPPED>, retrieve
  27. * a pointer to the parent <t CHid>.
  28. *
  29. * @parm LPOVERLAPPED | po |
  30. *
  31. * The pointer to convert.
  32. *
  33. *****************************************************************************/
  34. PCPidDrv INLINE
  35. pCPidDrvFromPo(LPOVERLAPPED po)
  36. {
  37. return (CPidDrv*) pvSubPvCb(po, FIELD_OFFSET(CPidDrv, o));
  38. }
  39. void CALLBACK
  40. PID_ReadComplete(DWORD dwError, DWORD cbRead, LPOVERLAPPED po)
  41. {
  42. PCPidDrv this = pCPidDrvFromPo(po);
  43. //EnterProc( PID_ReadComplete, (_"xxx", dwError, cbRead, po ));
  44. if( !IsBadReadPtr(this, cbX(this))
  45. &&this->cThreadRef
  46. && dwError == 0
  47. //&&( this->o.InternalHigh == this->cbReport[HidP_Input] )
  48. &&( this->hdevOvrlp != INVALID_HANDLE_VALUE ) )
  49. {
  50. HRESULT hres;
  51. PUCHAR pReport;
  52. UINT cbReport;
  53. USHORT LinkCollection = 0x0;
  54. USAGE rgUsages[MAX_BUTTONS] ;
  55. USAGE UsagePage = HID_USAGE_PAGE_PID;
  56. ULONG cAUsages = MAX_BUTTONS;
  57. BOOL fEffectPlaying = FALSE;
  58. LONG lEffectIndex;
  59. pReport = this->pReport[HidP_Input];
  60. cbReport = this->cbReport[HidP_Input];
  61. // If the report does not belong to the PID usage page
  62. // we should be out of here really quick.
  63. hres = HidP_GetUsages
  64. (HidP_Input,
  65. UsagePage,
  66. LinkCollection,
  67. rgUsages,
  68. &cAUsages,
  69. this->ppd,
  70. pReport,
  71. cbReport
  72. );
  73. if( SUCCEEDED(hres ) )
  74. {
  75. UINT indx;
  76. DWORD dwState = DIGFFS_ACTUATORSOFF | DIGFFS_USERFFSWITCHOFF | DIGFFS_POWEROFF | DIGFFS_SAFETYSWITCHOFF;
  77. for(indx = 0x0; indx < cAUsages; indx++ )
  78. {
  79. USAGE Usage = rgUsages[indx];
  80. switch(Usage)
  81. {
  82. case HID_USAGE_PID_EFFECT_PLAYING:
  83. fEffectPlaying = TRUE;
  84. break;
  85. case HID_USAGE_PID_DEVICE_PAUSED:
  86. dwState |= DIGFFS_PAUSED;
  87. break;
  88. case HID_USAGE_PID_ACTUATORS_ENABLED:
  89. dwState |= DIGFFS_ACTUATORSON;
  90. dwState &= ~(DIGFFS_ACTUATORSOFF);
  91. break;
  92. case HID_USAGE_PID_ACTUATOR_OVERRIDE_SWITCH:
  93. dwState |= DIGFFS_USERFFSWITCHON;
  94. dwState &= ~(DIGFFS_USERFFSWITCHOFF);
  95. break;
  96. case HID_USAGE_PID_SAFETY_SWITCH:
  97. dwState |= DIGFFS_SAFETYSWITCHON;
  98. dwState &= ~(DIGFFS_SAFETYSWITCHOFF);
  99. break;
  100. case HID_USAGE_PID_ACTUATOR_POWER:
  101. dwState |= DIGFFS_POWERON;
  102. dwState &= ~(DIGFFS_POWEROFF);
  103. break;
  104. default:
  105. SquirtSqflPtszV(sqfl | sqflVerbose,
  106. TEXT("%s: Unsupported input status usage (%x,%x:%s) "),
  107. TEXT("PID_ReadComplete"),
  108. UsagePage, Usage,
  109. PIDUSAGETXT(UsagePage,Usage) );
  110. break;
  111. }
  112. this->dwState = dwState;
  113. }
  114. hres = PID_ParseReport(
  115. &this->ed,
  116. &g_BlockIndexIN,
  117. LinkCollection,
  118. &lEffectIndex,
  119. cbX(lEffectIndex),
  120. pReport,
  121. cbReport
  122. );
  123. if( SUCCEEDED(hres) )
  124. {
  125. PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this,lEffectIndex);
  126. if(fEffectPlaying)
  127. {
  128. pEffectState->lEfState |= DIEGES_PLAYING;
  129. } else
  130. {
  131. pEffectState->lEfState &= ~(DIEGES_PLAYING);
  132. }
  133. }
  134. }
  135. // Issue another read
  136. PID_IssueRead(this);
  137. } else
  138. {
  139. // Boo!
  140. }
  141. //ExitProc();
  142. }
  143. BOOL INTERNAL
  144. PID_IssueRead(PCPidDrv this)
  145. {
  146. BOOL fRc = FALSE;
  147. if( !IsBadReadPtr(this, cbX(this))
  148. && this->cThreadRef )
  149. {
  150. fRc = ReadFileEx(this->hdevOvrlp, this->pReport[HidP_Input],
  151. this->cbReport[HidP_Input], &this->o,
  152. PID_ReadComplete);
  153. if (fRc == FALSE)
  154. {
  155. SquirtSqflPtszV(sqfl | sqflError,
  156. TEXT("FAIL ReadFileEx"));
  157. }
  158. }
  159. else
  160. {
  161. RPF(TEXT("Bad this pointer or thread ref count!"));
  162. }
  163. return fRc;
  164. }
  165. void CALLBACK
  166. PID_WriteComplete(DWORD dwError, DWORD cbWritten, LPOVERLAPPED po)
  167. {
  168. PCPidDrv this = pCPidDrvFromPo(po);
  169. //EnterProc( PID_ReadComplete, (_"xxx", dwError, cbRead, po ));
  170. if( !IsBadReadPtr(this, cbX(this))
  171. &&(this->cThreadRef)
  172. //&&( this->o.InternalHigh == this->cbWriteReport[this->blockNr] )
  173. &&(this->hWriteComplete)
  174. &&(this->hWrite)
  175. &&( this->hdevOvrlp != INVALID_HANDLE_VALUE ) )
  176. {
  177. //if we didn't get an error & wrote everything -- or if we already tried
  178. //twice -- we move on
  179. if ( ((dwError == 0) && (cbWritten == this->cbWriteReport [this->blockNr]))
  180. || (this->dwWriteAttempt != 0)
  181. )
  182. {
  183. //print a message if couldn't write a particular block
  184. if ((dwError != 0) || (cbWritten != this->cbWriteReport [this->blockNr]))
  185. {
  186. SquirtSqflPtszV(sqfl | sqflError,
  187. TEXT("Couldn't write block %u after two tries, giving up on this block."),
  188. this->blockNr);
  189. }
  190. //move on
  191. this->dwWriteAttempt = 0;
  192. this->blockNr++;
  193. if (this->blockNr < this->totalBlocks)
  194. {
  195. //write the next block
  196. if (PID_IssueWrite(this) == FALSE)
  197. {
  198. //in case of failure, the callback will never be called and the completion event never set,
  199. //so need to set it here.
  200. SetEvent(this->hWriteComplete);
  201. }
  202. }
  203. else
  204. {
  205. //we are done w/ this update
  206. AssertF(this->blockNr == this->totalBlocks);
  207. SetEvent(this->hWriteComplete);
  208. }
  209. }
  210. else
  211. {
  212. //this is the first time we tried to write a particular block, and we failed;
  213. //we will try once more
  214. SquirtSqflPtszV(sqfl | sqflBenign,
  215. TEXT("Couldn't write block %u on first attempt, retrying."),
  216. this->blockNr);
  217. this->dwWriteAttempt = 1;
  218. if (PID_IssueWrite(this) == FALSE)
  219. {
  220. //in case of failure, the callback will never be called and the completion event never set,
  221. //so need to set it here.
  222. this->dwWriteAttempt = 0;
  223. SetEvent(this->hWriteComplete);
  224. }
  225. }
  226. } else
  227. {
  228. //need to set the completion event, otherwise we will keep waiting...
  229. RPF(TEXT("Bad this pointer or thread ref count or handle!"));
  230. this->dwWriteAttempt = 0;
  231. SetEvent(this->hWriteComplete);
  232. }
  233. //ExitProc();
  234. }
  235. BOOL INTERNAL
  236. PID_IssueWrite(PCPidDrv this)
  237. {
  238. BOOL fRc = FALSE;
  239. if( !IsBadReadPtr(this, cbX(this))
  240. && this->cThreadRef )
  241. {
  242. fRc = WriteFileEx(this->hdevOvrlp, this->pWriteReport[this->blockNr],
  243. this->cbWriteReport[this->blockNr], &this->o,
  244. PID_WriteComplete);
  245. if (fRc == FALSE)
  246. {
  247. SquirtSqflPtszV(sqfl | sqflError,
  248. TEXT("FAIL WriteFileEx"));
  249. }
  250. }
  251. else
  252. {
  253. RPF(TEXT("Bad this pointer or thread ref count!"));
  254. }
  255. return fRc;
  256. }
  257. VOID INTERNAL
  258. PID_ThreadProc(CPidDrv* this)
  259. {
  260. MSG msg;
  261. EnterProc( PID_ThreadProc, (_"x", this ));
  262. AssertF(this->hdevOvrlp == INVALID_HANDLE_VALUE );
  263. this->hdevOvrlp = CreateFile(this->tszDeviceInterface,
  264. GENERIC_READ | GENERIC_WRITE,
  265. FILE_SHARE_READ | FILE_SHARE_WRITE,
  266. 0, /* no SECURITY_ATTRIBUTES */
  267. OPEN_EXISTING,
  268. FILE_FLAG_OVERLAPPED, /* attributes */
  269. 0); /* template */
  270. if( this->hdevOvrlp == INVALID_HANDLE_VALUE )
  271. {
  272. SquirtSqflPtszV(sqfl | sqflError,
  273. TEXT("%s:FAIL CreateFile(OverLapped)"),
  274. s_tszProc );
  275. }
  276. else
  277. //fix for mb 35282 -- no use calling PID_IssueRead() w/ an INVALID_HANDLE_VALUE for a file handle
  278. {
  279. if( PID_IssueRead(this) )
  280. {
  281. do
  282. {
  283. DWORD dwRc;
  284. do
  285. {
  286. AssertF(this->hWrite != 0x0);
  287. AssertF(this->hWriteComplete != 0x0);
  288. dwRc = MsgWaitForMultipleObjectsEx(1, &this->hWrite, INFINITE, QS_ALLINPUT,
  289. MWMO_ALERTABLE);
  290. if (dwRc == WAIT_OBJECT_0)
  291. {
  292. if (PID_IssueWrite(this) == FALSE)
  293. {
  294. //in case of failure, the callback will never be called and the completion event never set,
  295. //so need to set it here.
  296. SetEvent(this->hWriteComplete);
  297. }
  298. }
  299. } while ((dwRc == WAIT_IO_COMPLETION) || (dwRc == WAIT_OBJECT_0));
  300. while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  301. {
  302. TranslateMessage(&msg);
  303. DispatchMessage(&msg);
  304. }
  305. } while(this->cThreadRef);
  306. if( this->hdevOvrlp != INVALID_HANDLE_VALUE )
  307. {
  308. HANDLE hdev;
  309. hdev = this->hdevOvrlp;
  310. this->hdevOvrlp = INVALID_HANDLE_VALUE;
  311. CancelIo_(hdev);
  312. Sleep(0);
  313. CloseHandle(hdev);
  314. }
  315. }
  316. }
  317. //close the event handles as well
  318. if (this->hWrite != 0x0)
  319. {
  320. CloseHandle(this->hWrite);
  321. this->hWrite = 0x0;
  322. }
  323. if (this->hWriteComplete != 0x0)
  324. {
  325. CloseHandle(this->hWriteComplete);
  326. this->hWriteComplete = 0x0;
  327. }
  328. if(this->hThread)
  329. {
  330. HANDLE hdev = this->hThread;
  331. this->hThread = NULL;
  332. CloseHandle(hdev);
  333. }
  334. FreeLibraryAndExitThread(g_hinst, 0);
  335. ExitProc();
  336. }