Leaked source code of windows server 2003
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.

620 lines
17 KiB

  1. /*****************************************************************************
  2. *
  3. * DIEmH.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Emulation module for HID. HID is always run at ring 3,
  10. * so "emulation" is a bit of a misnomer.
  11. *
  12. * Contents:
  13. *
  14. * CEm_HID_CreateInstance
  15. *
  16. *****************************************************************************/
  17. #include "dinputpr.h"
  18. #ifdef HID_SUPPORT
  19. /*****************************************************************************
  20. *
  21. * The sqiffle for this file.
  22. *
  23. *****************************************************************************/
  24. #define sqfl sqflEm
  25. /*****************************************************************************
  26. *
  27. * Forward declarations
  28. *
  29. * CEm_HID_ReadComplete and CEm_HID_IssueRead schedule each other
  30. * back and forth.
  31. *
  32. *****************************************************************************/
  33. void CALLBACK
  34. CEm_HID_ReadComplete(DWORD dwError, DWORD cbRead, LPOVERLAPPED po);
  35. /*****************************************************************************
  36. *
  37. * HID "emulation"
  38. *
  39. *****************************************************************************/
  40. STDMETHODIMP CEm_HID_Acquire(PEM this, BOOL fAcquire);
  41. /*****************************************************************************
  42. *
  43. * @doc INTERNAL
  44. *
  45. * @func BOOL | FakeCancelIO |
  46. *
  47. * Stub function which doesn't do anything but
  48. * keeps us from crashing.
  49. *
  50. * @parm HANDLE | h |
  51. *
  52. * The handle whose I/O is supposed to be cancelled.
  53. *
  54. *****************************************************************************/
  55. BOOL WINAPI
  56. FakeCancelIO(HANDLE h)
  57. {
  58. AssertF(0);
  59. return FALSE;
  60. }
  61. /*****************************************************************************
  62. *
  63. * @doc INTERNAL
  64. *
  65. * @func BOOL | FakeTryEnterCriticalSection |
  66. *
  67. * We use TryEnterCriticalSection in DEBUG to detect deadlock
  68. * If the function does not exist, just enter CritSection and report
  69. * true. This compromises some debug functionality.
  70. *
  71. * @parm LPCRITICAL_SECTION | lpCriticalSection |
  72. *
  73. * Address of Critical Section to be entered.
  74. *
  75. *****************************************************************************/
  76. #ifdef XDEBUG
  77. BOOL WINAPI
  78. FakeTryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
  79. {
  80. EnterCriticalSection(lpCriticalSection);
  81. return TRUE;
  82. }
  83. #endif
  84. /*****************************************************************************
  85. *
  86. * @doc INTERNAL
  87. *
  88. * @func void | CEm_HID_Hold |
  89. *
  90. * Place a hold on both the parent device and the
  91. * emulation structure, so neither will go away while
  92. * we aren't paying attention.
  93. *
  94. * @parm PCHID | this |
  95. *
  96. * The item to be held.
  97. *
  98. *****************************************************************************/
  99. void INTERNAL
  100. CEm_Hid_Hold(PCHID this)
  101. {
  102. CEm_AddRef(pemFromPvi(this->pvi));
  103. Common_Hold(this);
  104. }
  105. /*****************************************************************************
  106. *
  107. * @doc INTERNAL
  108. *
  109. * @func void | CEm_HID_Unhold |
  110. *
  111. * Release the holds we placed via <f CEm_HID_Hold>.
  112. *
  113. * @parm PCHID | this |
  114. *
  115. * The item to be unheld.
  116. *
  117. *****************************************************************************/
  118. void INTERNAL
  119. CEm_Hid_Unhold(PCHID this)
  120. {
  121. CEm_Release(pemFromPvi(this->pvi));
  122. Common_Unhold(this);
  123. }
  124. /*****************************************************************************
  125. *
  126. * @doc EXTERNAL
  127. *
  128. * @func BOOL | CEm_HID_IssueRead |
  129. *
  130. * Issue another read request.
  131. *
  132. * @parm PCHID | this |
  133. *
  134. * The device on which the read is to be issued.
  135. *
  136. * @returns
  137. *
  138. * Returns nonzero if the read was successfully issued.
  139. *
  140. *****************************************************************************/
  141. BOOL EXTERNAL
  142. CEm_HID_IssueRead(PCHID this)
  143. {
  144. BOOL fRc;
  145. fRc = ReadFileEx(this->hdevEm, this->hriIn.pvReport,
  146. this->hriIn.cbReport, &this->o,
  147. CEm_HID_ReadComplete);
  148. if(!fRc)
  149. {
  150. /*
  151. * Couldn't issue read; force an unacquire.
  152. *
  153. * Unhold the device once, since the read loop is gone.
  154. */
  155. // 7/18/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  156. SquirtSqflPtszV(sqfl | sqflError,
  157. TEXT("IssueRead: Access to HID device(%p, handle=0x%p) lost le=0x%x!"),
  158. this, this->hdevEm, GetLastError() );
  159. DllEnterCrit();
  160. ConfirmF(SUCCEEDED(GPA_DeletePtr(&g_plts->gpaHid, pemFromPvi(this->pvi))));
  161. DllLeaveCrit();
  162. CEm_ForceDeviceUnacquire(&this->ed,
  163. (!(this->pvi->fl & VIFL_ACQUIRED)) ? FDUFL_UNPLUGGED : 0);
  164. CEm_Hid_Unhold(this);
  165. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  166. SquirtSqflPtszV(sqfl | sqflVerbose,
  167. TEXT("Removed HID device(%p) from GPA "), this);
  168. }
  169. return fRc;
  170. }
  171. /*****************************************************************************
  172. *
  173. * @doc INTERNAL
  174. *
  175. * @func void | CEm_HID_PrepareState |
  176. *
  177. * Prepare the staging area for a new device state
  178. * by assuming that nothing has changed.
  179. *
  180. * @parm PCHID | this |
  181. *
  182. * The device on which a read has just completed.
  183. *
  184. *****************************************************************************/
  185. void INLINE
  186. CEm_HID_PrepareState(PCHID this)
  187. {
  188. /*
  189. * Copy over everything...
  190. */
  191. CopyMemory(this->pvStage, this->pvPhys, this->cbPhys);
  192. }
  193. /*****************************************************************************
  194. *
  195. * @doc INTERNAL
  196. *
  197. * @func void | CEm_HID_ReadComplete |
  198. *
  199. * APC function which is called when an I/O has completed.
  200. *
  201. * @parm DWORD | dwError |
  202. *
  203. * Error code, or zero on success.
  204. *
  205. * @parm DWORD | cbRead |
  206. *
  207. * Number of bytes actually read.
  208. *
  209. * @parm LPOVERLAPPED | po |
  210. *
  211. * I/O packet that completed.
  212. *
  213. *****************************************************************************/
  214. void CALLBACK
  215. CEm_HID_ReadComplete(DWORD dwError, DWORD cbRead, LPOVERLAPPED po)
  216. {
  217. PCHID this = pchidFromPo(po);
  218. //EnterProc(Cem_HID_ReadComplete, (_"ddp", dwError, cbRead, po ));
  219. /*
  220. * Cannot own any critical sections because CEm_ForceDeviceUnacquire
  221. * assumes that no critical sections are taken.
  222. */
  223. AssertF(!CDIDev_InCrit(this->pvi->pdd));
  224. AssertF(!DllInCrit());
  225. /*
  226. * Process the data.
  227. *
  228. * Note: We can get error STATUS_DEVICE_NOT_CONNECTED
  229. * or ERROR_READ_FAULT if the device is unplugged.
  230. */
  231. if(dwError == 0 &&
  232. this->o.InternalHigh == this->caps.InputReportByteLength)
  233. {
  234. NTSTATUS stat;
  235. CEm_HID_PrepareState(this);
  236. stat = CHid_ParseData(this, HidP_Input, &this->hriIn);
  237. if(SUCCEEDED(stat))
  238. {
  239. CEm_AddState(&this->ed, this->pvStage, GetTickCount());
  240. }
  241. CEm_HID_IssueRead(this);
  242. } else
  243. {
  244. if(!dwError)
  245. {
  246. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  247. SquirtSqflPtszV(sqflError | sqfl,
  248. TEXT("ReadComplete HID(%p) short read! Got %d wanted %d"),
  249. this,
  250. this->o.InternalHigh,
  251. this->caps.InputReportByteLength);
  252. } else
  253. {
  254. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  255. SquirtSqflPtszV(sqflError | sqfl,
  256. TEXT("ReadComplete HID(%p) read failed! error=0x%08x "),
  257. this, dwError);
  258. }
  259. DllEnterCrit();
  260. ConfirmF(SUCCEEDED(GPA_DeletePtr(&g_plts->gpaHid, pemFromPvi(this->pvi))));
  261. DllLeaveCrit();
  262. CEm_ForceDeviceUnacquire(&this->ed,
  263. (!(this->pvi->fl & VIFL_ACQUIRED)) ? FDUFL_UNPLUGGED : 0);
  264. CEm_Hid_Unhold(this);
  265. }
  266. /*
  267. * And wait for more data.
  268. * If the read failed, then CEm_HID_IssueRead() will its Reference
  269. */
  270. // CEm_HID_IssueRead(this);
  271. //ExitProc();
  272. }
  273. /*****************************************************************************
  274. *
  275. * @doc INTERNAL
  276. *
  277. * @func void | CEm_HID_Sync |
  278. *
  279. * Kick off a read or kill the existing one.
  280. *
  281. * @parm PLLTHREADSTATE | plts |
  282. *
  283. * Thread hook state containing hook information to synchronize.
  284. *
  285. * @parm PEM | pem |
  286. *
  287. * Who is the poor victim?
  288. *
  289. *****************************************************************************/
  290. void EXTERNAL
  291. CEm_HID_Sync(PLLTHREADSTATE plts, PEM pem)
  292. {
  293. PCHID this;
  294. EnterProc(CEm_HID_Sync, (_ "pp", plts, pem ));
  295. this = pchidFromPem(pem);
  296. AssertF(GPA_FindPtr(&plts->gpaHid, pem));
  297. AssertF(this->pvi == &pem->vi);
  298. AssertF(pem->ped == &this->ed);
  299. /*
  300. * Cannot own any critical sections because CEm_HID_IssueRead
  301. * may result in a call to CEm_ForceDeviceUnacquire, which
  302. * in turn assumes that no critical sections are taken.
  303. */
  304. AssertF(!CDIDev_InCrit(this->pvi->pdd));
  305. AssertF(!DllInCrit());
  306. if( pem->vi.fl & VIFL_ACQUIRED )
  307. {
  308. AssertF(this->hdevEm == INVALID_HANDLE_VALUE);
  309. /*
  310. * Start reading.
  311. *
  312. * While underneath the device critical section, duplicate
  313. * the handle so we can avoid race conditions with the
  314. * main thread (when the main thread closes the handle,
  315. * we need to keep our private version alive so we can
  316. * clean it up nicely).
  317. */
  318. /*
  319. * Need to look again, in case the device has already
  320. * been unacquired before we get a chance to synchronize
  321. * with the main thread. This can happen, for example,
  322. * if the app quickly does an Acquire/Unacquire without
  323. * an intervening thread switch.
  324. */
  325. AssertF(!CDIDev_InCrit(this->pvi->pdd));
  326. //CDIDev_EnterCrit(this->pvi->pdd);
  327. if(this->hdev != INVALID_HANDLE_VALUE)
  328. {
  329. HANDLE hProcessMe = GetCurrentProcess();
  330. HANDLE hdevEm;
  331. if(DuplicateHandle(hProcessMe, this->hdev,
  332. hProcessMe, &hdevEm, GENERIC_READ,
  333. 0, 0))
  334. {
  335. this->hdevEm = hdevEm;
  336. }
  337. }
  338. //CDIDev_LeaveCrit(this->pvi->pdd);
  339. if(this->hdevEm != INVALID_HANDLE_VALUE)
  340. {
  341. /*
  342. * On Win98, HidD_FlushQueue will fail if the underlying
  343. * device is dead. Whereas on NT, it blindly succeeds.
  344. * Therefore, we cannot trust the return value.
  345. */
  346. HidD_FlushQueue(this->hdevEm);
  347. }
  348. /*
  349. * Even if we have failed to duplicate the handle
  350. * we still want to issue the read. A error in read
  351. * will force the device to be unacquired
  352. */
  353. CEm_HID_IssueRead(this);
  354. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  355. SquirtSqflPtszV(sqfl | sqflVerbose,
  356. TEXT(" StartReading(%p) "),
  357. this);
  358. } else
  359. {
  360. HANDLE hdev;
  361. /*
  362. * Stop reading. There is still another outstanding
  363. * hold by the read loop, which will be cleaned up when
  364. * the the I/O cancel is received.
  365. */
  366. AssertF(this->hdevEm != INVALID_HANDLE_VALUE);
  367. hdev = this->hdevEm;
  368. this->hdevEm = INVALID_HANDLE_VALUE;
  369. if(hdev != INVALID_HANDLE_VALUE)
  370. {
  371. /*
  372. * We don't need to call CancelIo because we're closing
  373. * the handle soon anyway. Which is good, because Memphis
  374. * B#55771 prevents CancelIo from working on read-only
  375. * handles (which we are).
  376. *
  377. */
  378. /* Need CancelIo on NT otherwise HID devices appear only on every
  379. * consecutive plug in
  380. */
  381. _CancelIO(hdev);
  382. CloseHandle(hdev);
  383. }
  384. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  385. SquirtSqflPtszV(sqfl | sqflVerbose,
  386. TEXT(" StopReading(%p) "),
  387. this);
  388. }
  389. ExitProc();
  390. }
  391. /*****************************************************************************
  392. *
  393. * @doc INTERNAL
  394. *
  395. * @func HRESULT | CEm_HID_Acquire |
  396. *
  397. * Acquire/unacquire a HID device.
  398. *
  399. * @parm PEM | pem |
  400. *
  401. * Device being acquired.
  402. *
  403. * @parm BOOL | fAcquire |
  404. *
  405. * Whether the device is being acquired or unacquired.
  406. *
  407. *****************************************************************************/
  408. STDMETHODIMP
  409. CEm_HID_Acquire(PEM pem, BOOL fAcquire)
  410. {
  411. HRESULT hres;
  412. PLLTHREADSTATE plts;
  413. PCHID pchid;
  414. EnterProc(CEm_HID_Acquire, (_ "pu", pem, fAcquire));
  415. AssertF(pem->dwSignature == CEM_SIGNATURE);
  416. pchid = pchidFromPem(pem);
  417. if( fAcquire )
  418. {
  419. pchid->hdev = CHid_OpenDevicePath(pchid, FILE_FLAG_OVERLAPPED);
  420. if(pchid->hdev != INVALID_HANDLE_VALUE )
  421. {
  422. hres = S_OK;
  423. } else
  424. {
  425. hres = DIERR_UNPLUGGED;
  426. }
  427. } else
  428. {
  429. HANDLE hdev;
  430. AssertF(pchid->hdev != INVALID_HANDLE_VALUE);
  431. hdev = pchid->hdev;
  432. pchid->hdev = INVALID_HANDLE_VALUE;
  433. _CancelIO(hdev);
  434. CloseHandle(hdev);
  435. hres = S_OK;
  436. }
  437. if( pchid->IsPolledInput )
  438. {
  439. hres = S_OK;
  440. AssertF(pchid->hdevEm == INVALID_HANDLE_VALUE);
  441. } else if( SUCCEEDED(hres) )
  442. {
  443. #ifdef USE_WM_INPUT
  444. ResetEvent( g_hEventHid );
  445. #endif
  446. hres = CEm_GetWorkerThread(pem, &plts);
  447. if(SUCCEEDED(hres) )
  448. {
  449. if(fAcquire )
  450. {
  451. /* Begin the I/O */
  452. /*
  453. * Must apply the hold before adding to the list
  454. * to avoid a race condition where the worker thread
  455. * unholds the pchid before we can hold it.
  456. *
  457. * The rule is that there is a hold to track each copy
  458. * of the device on the gpaHid.
  459. */
  460. CEm_Hid_Hold(pchid);
  461. /*
  462. * Add ourselves to the busy list, and wake up
  463. * the worker thread to tell him to start paying attention.
  464. */
  465. DllEnterCrit();
  466. hres = GPA_Append(&plts->gpaHid, pem);
  467. DllLeaveCrit();
  468. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  469. SquirtSqflPtszV(sqfl | sqflVerbose,
  470. TEXT("Added HID device(%p) to GPA "), pchid );
  471. if(FAILED(hres))
  472. {
  473. CEm_Hid_Unhold(pchid);
  474. }
  475. NudgeWorkerThreadPem(plts, pem);
  476. #ifdef USE_WM_INPUT
  477. if( g_fRawInput) {
  478. DWORD dwRc;
  479. dwRc = WaitForSingleObject( g_hEventHid, INFINITE );
  480. }
  481. #endif
  482. } else
  483. {
  484. HANDLE hdev;
  485. hdev = pchid->hdevEm;
  486. pchid->hdevEm = INVALID_HANDLE_VALUE;
  487. if(hdev != INVALID_HANDLE_VALUE)
  488. {
  489. _CancelIO(hdev);
  490. CloseHandle(hdev);
  491. }
  492. }
  493. }
  494. }
  495. ExitOleProc();
  496. return hres;
  497. }
  498. /*****************************************************************************
  499. *
  500. * @doc INTERNAL
  501. *
  502. * @func HRESULT | CEm_HID_CreateInstance |
  503. *
  504. * Create a HID thing.
  505. *
  506. * @parm PVXDDEVICEFORMAT | pdevf |
  507. *
  508. * What the object should look like.
  509. *
  510. * @parm PVXDINSTANCE * | ppviOut |
  511. *
  512. * The answer goes here.
  513. *
  514. *****************************************************************************/
  515. HRESULT EXTERNAL
  516. CEm_HID_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut)
  517. {
  518. PCHID pchid = (PCHID)pdevf->dwExtra;
  519. PED ped = &pchid->ed;
  520. AssertF(ped->pState == 0);
  521. AssertF(ped->pDevType == 0);
  522. *(PPV)&ped->pState = pchid->pvPhys; /* De-const */
  523. ped->Acquire = CEm_HID_Acquire;
  524. ped->cAcquire = -1;
  525. ped->cbData = pdevf->cbData;
  526. ped->cRef = 0x0;
  527. return CEm_CreateInstance(pdevf, ppviOut, &pchid->ed);
  528. }
  529. #endif /* HID_SUPPORT */