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.

731 lines
23 KiB

  1. // @doc
  2. /**********************************************************************
  3. *
  4. * @module InternalPolling.c |
  5. *
  6. * Implementation of routines for internal polling
  7. *
  8. * History
  9. * ----------------------------------------------------------
  10. * Mitchell S. Dernis Original
  11. *
  12. * (c) 1986-1999 Microsoft Corporation. All right reserved.
  13. *
  14. * @topic Internal Polling |
  15. * All polling to get data is via this internal polling mechanism.
  16. * However, for security and access checks, the first poll from
  17. * a new file handle is sent straight down, and comes up via
  18. * different completion. To keep track of this we keep a linked
  19. * list of GCK_FILE_OPEN_ITEMs representing each of the FILE_OBJECTS
  20. * that we need.<nl>
  21. * To Poll internally we need to have a valid FILE_OBJECT otherwise
  22. * hidclass.sys will reject the poll request. This is done
  23. * via GCK_IP_CreateFileObject which internally calls IoGetDeviceObjectPointer.
  24. * Somewhat unfortunately, this takes circular path through, so is not
  25. * really distinguishable from opens done up top. (Ken Ray tells me that
  26. * this is guaranteed to be synchronous, so we can compare thread IDs and
  27. * figure out that a given open is from our driver, but this code is written
  28. * assuming that we don't really need to distinguish.)
  29. *
  30. **********************************************************************/
  31. #define __DEBUG_MODULE_IN_USE__ GCK_INTERNALPOLL_C
  32. #include <wdm.h>
  33. #include "Debug.h"
  34. #include "GckShell.h"
  35. DECLARE_MODULE_DEBUG_LEVEL((DBG_WARN|DBG_ERROR|DBG_CRITICAL));
  36. /***********************************************************************************
  37. **
  38. ** NTSTATUS GCK_IP_AddFileObject(IN PGCK_FILTER_EXT pFilterExt, IN PFILE_OBJECT pFileObject)
  39. **
  40. ** @func Called to add a GCK_FILE_OPEN_ITEM entry corresponding to pFileObject to
  41. ** our list of file handles that we know about. Allocate and initializes the structure.
  42. **
  43. ** @rdesc STATUS_SUCCESS, or STATUS_UNSUCCESSFUL if pFileObject is not found.
  44. **
  45. *************************************************************************************/
  46. NTSTATUS
  47. GCK_IP_AddFileObject
  48. (
  49. IN PGCK_FILTER_EXT pFilterExt,
  50. IN PFILE_OBJECT pFileObject,
  51. IN USHORT usDesiredShareAccess,
  52. IN ULONG ulDesiredAccess
  53. )
  54. {
  55. PGCK_FILE_OPEN_ITEM pNewFileOpenItem;
  56. KIRQL OldIrql;
  57. GCK_DBG_ENTRY_PRINT(("Entering GCK_IP_AddFileObject pFilterExt = 0x%0.8x, pFileObject = 0x%0.8x\n", pFilterExt, pFileObject));
  58. //We need a spin lock to access this list
  59. KeAcquireSpinLock(&pFilterExt->InternalPoll.InternalPollLock, &OldIrql);
  60. //Check for sharing violation
  61. if( !GCK_IP_CheckSharing(pFilterExt->InternalPoll.ShareStatus, usDesiredShareAccess, ulDesiredAccess) )
  62. {
  63. KeReleaseSpinLock(&pFilterExt->InternalPoll.InternalPollLock, OldIrql);
  64. GCK_DBG_EXIT_PRINT(("Exiting GCK_IP_AddFileObject: Sharing Violation\n"));
  65. return STATUS_SHARING_VIOLATION;
  66. }
  67. //Allocate Space for NewFileOpenItem;
  68. pNewFileOpenItem = (PGCK_FILE_OPEN_ITEM)EX_ALLOCATE_POOL(NonPagedPool, sizeof(GCK_FILE_OPEN_ITEM));
  69. if(!pNewFileOpenItem)
  70. {
  71. GCK_DBG_CRITICAL_PRINT(("Failed to allocate space for GCK_FILE_OPEN_ITEM\n"));
  72. GCK_DBG_EXIT_PRINT(("Exiting GCK_IP_AddFileObject(1) STATUS_NO_MEMORY\n"));
  73. return STATUS_NO_MEMORY;
  74. }
  75. //Initialize FileOpenItem
  76. pNewFileOpenItem->fReadPending = FALSE;
  77. pNewFileOpenItem->pFileObject = pFileObject;
  78. pNewFileOpenItem->pNextOpenItem = NULL;
  79. pNewFileOpenItem->ulAccess = ulDesiredAccess;
  80. pNewFileOpenItem->usSharing = usDesiredShareAccess;
  81. pNewFileOpenItem->fConfirmed = FALSE;
  82. //Add New Item to head of list
  83. pNewFileOpenItem->pNextOpenItem = pFilterExt->InternalPoll.pFirstOpenItem;
  84. pFilterExt->InternalPoll.pFirstOpenItem = pNewFileOpenItem;
  85. //Update SHARE_ACCESS
  86. GCK_IP_AddSharing(&pFilterExt->InternalPoll.ShareStatus, usDesiredShareAccess, ulDesiredAccess);
  87. //Release Spinlock
  88. KeReleaseSpinLock(&pFilterExt->InternalPoll.InternalPollLock, OldIrql);
  89. GCK_DBG_EXIT_PRINT(("Exiting GCK_IP_AddFileObject(2) STATUS_SUCCESS\n"));
  90. return STATUS_SUCCESS;
  91. }
  92. /***********************************************************************************
  93. **
  94. ** NTSTATUS GCK_IP_RemoveFileObject(IN PGCK_FILTER_EXT pFilterExt, IN PFILE_OBJECT pFileObject)
  95. **
  96. ** @func Called to remove a GCK_FILE_OPEN_ITEM entry corresponding to pFileObject from
  97. ** our list of file handles that we know about. Deallocates structure.
  98. **
  99. ** @rdesc STATUS_SUCCESS, or STATUS_UNSUCCESSFUL if pFileObject is not found.
  100. **
  101. *************************************************************************************/
  102. NTSTATUS
  103. GCK_IP_RemoveFileObject
  104. (
  105. IN PGCK_FILTER_EXT pFilterExt,
  106. IN PFILE_OBJECT pFileObject
  107. )
  108. {
  109. //Remove is just a negative confirmation
  110. return GCK_IP_ConfirmFileObject(pFilterExt, pFileObject, FALSE);
  111. }
  112. NTSTATUS
  113. GCK_IP_ConfirmFileObject
  114. (
  115. IN PGCK_FILTER_EXT pFilterExt,
  116. IN PFILE_OBJECT pFileObject,
  117. IN BOOLEAN fConfirm
  118. )
  119. {
  120. //Find FileOpenItem and remove it.
  121. PGCK_FILE_OPEN_ITEM pCurrentFileItem = pFilterExt->InternalPoll.pFirstOpenItem;
  122. PGCK_FILE_OPEN_ITEM pPreviousFileItem = NULL;
  123. GCK_DBG_ENTRY_PRINT(("Entering GCK_IP_ConfirmFileObject pFilterExt = 0x%0.8x, pFileObject = 0x%0.8x, fConfirm = %d\n", pFilterExt, pFileObject, fConfirm));
  124. while(pCurrentFileItem)
  125. {
  126. //Check for File Object Match
  127. if(pCurrentFileItem->pFileObject == pFileObject)
  128. {
  129. //If this is a confirmation, flag
  130. if( fConfirm )
  131. {
  132. pCurrentFileItem->fConfirmed = TRUE;
  133. }
  134. //Otherwise, it is a negative confirmation, and we must remove it
  135. else
  136. {
  137. //Remove from list
  138. if( NULL == pPreviousFileItem)
  139. {
  140. pFilterExt->InternalPoll.pFirstOpenItem = pCurrentFileItem->pNextOpenItem;
  141. }
  142. else
  143. {
  144. pPreviousFileItem->pNextOpenItem = pCurrentFileItem->pNextOpenItem;
  145. }
  146. //Decrement number of open file objects
  147. GCK_IP_RemoveSharing(&pFilterExt->InternalPoll.ShareStatus, pCurrentFileItem->usSharing, pCurrentFileItem->ulAccess);
  148. //Free memory allocate for FileOpenItem
  149. ExFreePool(pCurrentFileItem);
  150. }
  151. //Return Successfully
  152. GCK_DBG_EXIT_PRINT(("Exiting GCK_IP_RemoveFileObject(1) STATUS_SUCCESS\n"));
  153. return STATUS_SUCCESS;
  154. }
  155. pPreviousFileItem = pCurrentFileItem;
  156. pCurrentFileItem = pCurrentFileItem->pNextOpenItem;
  157. }
  158. //If we are here the file object is not in our list. Either it was never added
  159. //or is was removed
  160. ASSERT(FALSE);
  161. GCK_DBG_EXIT_PRINT(("Exiting GCK_IP_ConfirmFileObject(2) STATUS_UNSUCCESSFUL\n"));
  162. return STATUS_UNSUCCESSFUL;
  163. }
  164. BOOLEAN
  165. GCK_IP_CheckSharing
  166. (
  167. IN SHARE_STATUS ShareStatus,
  168. IN USHORT usDesiredShareAccess,
  169. IN ULONG ulDesiredAccess
  170. )
  171. {
  172. //Check that no-one has exclusive access to the desire access
  173. if(
  174. ( (ulDesiredAccess & FILE_WRITE_DATA) && (ShareStatus.SharedWrite < ShareStatus.OpenCount) ) ||
  175. ( (ulDesiredAccess & FILE_READ_DATA) && (ShareStatus.SharedRead < ShareStatus.OpenCount) )
  176. )
  177. {
  178. return FALSE;
  179. }
  180. //Check that not requesting exclusive access, if already open
  181. if(
  182. ( !(usDesiredShareAccess & FILE_SHARE_READ) && ShareStatus.Readers) ||
  183. ( !(usDesiredShareAccess & FILE_SHARE_WRITE) && ShareStatus.Writers) ||
  184. (!usDesiredShareAccess && ShareStatus.OpenCount)
  185. )
  186. {
  187. return FALSE;
  188. }
  189. //This would be approved
  190. return TRUE;
  191. }
  192. BOOLEAN
  193. GCK_IP_AddSharing
  194. (
  195. IN OUT SHARE_STATUS *pShareStatus,
  196. IN USHORT usDesiredShareAccess,
  197. IN ULONG ulDesiredAccess
  198. )
  199. {
  200. //We assume this was checked before requested
  201. ASSERT(GCK_IP_CheckSharing(*pShareStatus, usDesiredShareAccess, ulDesiredAccess));
  202. pShareStatus->OpenCount++;
  203. if(usDesiredShareAccess & FILE_SHARE_READ) pShareStatus->SharedRead++;
  204. if(usDesiredShareAccess & FILE_SHARE_WRITE) pShareStatus->SharedWrite++;
  205. if(ulDesiredAccess & FILE_WRITE_DATA) pShareStatus->Writers++;
  206. if(ulDesiredAccess & FILE_READ_DATA) pShareStatus->Readers++;
  207. return TRUE;
  208. }
  209. BOOLEAN
  210. GCK_IP_RemoveSharing
  211. (
  212. IN OUT SHARE_STATUS *pShareStatus,
  213. IN USHORT usDesiredShareAccess,
  214. IN ULONG ulDesiredAccess
  215. )
  216. {
  217. pShareStatus->OpenCount--;
  218. if(usDesiredShareAccess & FILE_SHARE_READ) pShareStatus->SharedRead--;
  219. if(usDesiredShareAccess & FILE_SHARE_WRITE) pShareStatus->SharedWrite--;
  220. if(ulDesiredAccess & FILE_WRITE_DATA) pShareStatus->Writers--;
  221. if(ulDesiredAccess & FILE_READ_DATA) pShareStatus->Readers--;
  222. return TRUE;
  223. }
  224. typedef struct _GCK_INTERNEL_WorkItemExtension
  225. {
  226. WORK_QUEUE_ITEM WorkItem;
  227. PGCK_FILTER_EXT pFilterExt;
  228. } GCK_INTERNEL_WorkItemExtension;
  229. VOID GCK_IP_WorkItem
  230. (
  231. IN PVOID pvContext
  232. )
  233. {
  234. GCK_INTERNEL_WorkItemExtension* pWIExtension = (GCK_INTERNEL_WorkItemExtension*)pvContext;
  235. if (pWIExtension != NULL)
  236. {
  237. GCKF_IncomingReadRequests(pWIExtension->pFilterExt, NULL);
  238. ExFreePool(pWIExtension);
  239. }
  240. }
  241. /***********************************************************************************
  242. **
  243. ** NTSTATUS GCK_IP_OneTimePoll(IN PGCK_FILTER_EXT pFilterExt)
  244. **
  245. ** @func If a private poll is not pending, it forces one.
  246. **
  247. ** @rdesc STATUS_SUCCESS, or various errors
  248. **
  249. *************************************************************************************/
  250. NTSTATUS
  251. GCK_IP_OneTimePoll
  252. (
  253. IN PGCK_FILTER_EXT pFilterExt
  254. )
  255. {
  256. PIO_STACK_LOCATION pPrivateIrpStack;
  257. GCK_INTERNEL_WorkItemExtension* pWIExtension;
  258. //
  259. // Create a polling FileObject if necessary
  260. //
  261. if(!pFilterExt->InternalPoll.fReady)
  262. {
  263. NTSTATUS NtStatus;
  264. if(GCK_STATE_STARTED == pFilterExt->eDeviceState)
  265. {
  266. pFilterExt->InternalPoll.InternalCreateThread=KeGetCurrentThread();
  267. NtStatus = GCK_IP_CreateFileObject( &pFilterExt->InternalPoll.pInternalFileObject, pFilterExt->pPDO);
  268. pFilterExt->InternalPoll.InternalCreateThread=NULL;
  269. if( NT_SUCCESS(NtStatus) )
  270. {
  271. pFilterExt->InternalPoll.fReady = TRUE;
  272. }
  273. else
  274. {
  275. return STATUS_DEVICE_NOT_CONNECTED;
  276. }
  277. }
  278. else
  279. {
  280. return STATUS_DEVICE_NOT_CONNECTED;
  281. }
  282. }
  283. // If an read IRP is not pending, post one
  284. /* if( pFilterExt->InternalPoll.fReadPending )
  285. {
  286. //If an IRP is pending, we're done
  287. return STATUS_SUCCESS;
  288. }
  289. // Mark a read pending
  290. pFilterExt->InternalPoll.fReadPending = TRUE;
  291. */ if (InterlockedExchange(&pFilterExt->InternalPoll.fReadPending, TRUE) == TRUE)
  292. {
  293. return STATUS_SUCCESS;
  294. }
  295. //Otherwise Post an IRP
  296. GCK_DBG_RT_WARN_PRINT(("No IRP Pending, posting one.\n"));
  297. // Give a change for the LEDs to update (we fake an incoming request)
  298. pWIExtension = (GCK_INTERNEL_WorkItemExtension*)(EX_ALLOCATE_POOL(NonPagedPool, sizeof(GCK_INTERNEL_WorkItemExtension)));
  299. if (pWIExtension != NULL)
  300. {
  301. pWIExtension->pFilterExt = pFilterExt;
  302. ExInitializeWorkItem(&pWIExtension->WorkItem, GCK_IP_WorkItem, (void*)(pWIExtension));
  303. // Need to callback at IRQL PASSIVE_LEVEL
  304. ExQueueWorkItem(&pWIExtension->WorkItem, DelayedWorkQueue);
  305. pWIExtension = NULL; // Will be deleted by the work item routine
  306. }
  307. //Setup the file object for out internal IRP
  308. GCK_DBG_RT_WARN_PRINT(("Copying File object.\n"));
  309. pPrivateIrpStack = IoGetNextIrpStackLocation(pFilterExt->InternalPoll.pPrivateIrp);
  310. pPrivateIrpStack->FileObject = pFilterExt->InternalPoll.pInternalFileObject;
  311. // Reset status
  312. pFilterExt->InternalPoll.pPrivateIrp->IoStatus.Information = 0;
  313. pFilterExt->InternalPoll.pPrivateIrp->IoStatus.Status = STATUS_SUCCESS;
  314. // Reset the ByteOffset, Length
  315. pPrivateIrpStack->Parameters.Read.ByteOffset.QuadPart = 0;
  316. pPrivateIrpStack->Parameters.Read.Key = 0;
  317. pPrivateIrpStack->Parameters.Read.Length =
  318. (ULONG)pFilterExt->HidInfo.HidPCaps.InputReportByteLength;
  319. // Set Completion routine to process poll after it is complete.
  320. GCK_DBG_RT_WARN_PRINT(("Setting completion routine.\n"));
  321. ASSERT(pFilterExt->InternalPoll.pPrivateIrp);
  322. IoSetCompletionRoutine(
  323. pFilterExt->InternalPoll.pPrivateIrp,
  324. GCK_IP_ReadComplete,
  325. (PVOID)pFilterExt,
  326. TRUE,
  327. TRUE,
  328. TRUE
  329. );
  330. // We are about to generate another IRP so increment outstanding IO count
  331. GCK_IncRemoveLock(&pFilterExt->RemoveLock);
  332. // Send IRP down to driver
  333. GCK_DBG_RT_WARN_PRINT(("Calling down to next driver.\n"));
  334. return IoCallDriver (pFilterExt->pTopOfStack, pFilterExt->InternalPoll.pPrivateIrp);
  335. }
  336. /***********************************************************************************
  337. **
  338. ** NTSTATUS GCK_IP_FullTimePoll(IN PGCK_FILTER_EXT pFilterExt, IN BOOLEAN fStart)
  339. **
  340. ** @func Turns FullTime internal polling on or off. Actually changes a refcount.
  341. ** When the refcount goes to zero, polling is off, otherwise it is on. Calls
  342. ** GCK_IP_OneTimePoll which may be necessary to get ball rolling.
  343. **
  344. ** @rdesc STATUS_SUCCESS, or various errors
  345. **
  346. *************************************************************************************/
  347. NTSTATUS
  348. GCK_IP_FullTimePoll
  349. (
  350. IN PGCK_FILTER_EXT pFilterExt,
  351. IN BOOLEAN fStart
  352. )
  353. {
  354. //Change number of requests for continuous background polling.
  355. if(fStart)
  356. {
  357. pFilterExt->InternalPoll.ulInternalPollRef++;
  358. ASSERT( 0!= pFilterExt->InternalPoll.ulInternalPollRef);
  359. //There is no thread, the completion routine recycles the IRP
  360. //and polls again if pFilterExt->InternalPoll.ulInternalPollRef > 0
  361. //we need to hit GCK_IP_OneTimePoll just to get the ball rolling though.
  362. if(GCK_STATE_STARTED == pFilterExt->eDeviceState )
  363. {
  364. return GCK_IP_OneTimePoll(pFilterExt);
  365. }
  366. return STATUS_SUCCESS;
  367. }
  368. //We need to decrment the refcount.
  369. ASSERT( 0 != pFilterExt->InternalPoll.ulInternalPollRef);
  370. if(0 != pFilterExt->InternalPoll.ulInternalPollRef)
  371. {
  372. pFilterExt->InternalPoll.ulInternalPollRef--;
  373. }
  374. return STATUS_SUCCESS;
  375. }
  376. /***********************************************************************************
  377. **
  378. ** NTSTATUS GCK_IP_ReadComplete (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID pContext)
  379. **
  380. ** @func When a Private IRP is completed handles processing the data. Also
  381. ** important is that it repolls internall if pFilterExt->InternalPoll.ulInternalPollRef
  382. ** is greater than zero.
  383. **
  384. ** @rdesc STATUS_SUCCESS, or various errors
  385. **
  386. *************************************************************************************/
  387. NTSTATUS
  388. GCK_IP_ReadComplete (
  389. IN PDEVICE_OBJECT pDeviceObject,
  390. IN PIRP pIrp,
  391. IN PVOID pContext
  392. )
  393. {
  394. PGCK_FILTER_EXT pFilterExt;
  395. PVOID pvReportBuffer;
  396. UNREFERENCED_PARAMETER(pDeviceObject);
  397. GCK_DBG_RT_ENTRY_PRINT(("Entering GCK_ReadComplete. pDO = 0x%0.8x, pIrp = 0x%0.8x, pContext = 0x%0.8x\n", pDeviceObject, pIrp, pContext));
  398. // Cast context to device extension
  399. pFilterExt = (PGCK_FILTER_EXT) pContext;
  400. // Just an extra sanity check
  401. ASSERT( GCK_DO_TYPE_FILTER == pFilterExt->ulGckDevObjType);
  402. // Get Pointer to data
  403. ASSERT(pIrp);
  404. pvReportBuffer = GCK_GetSystemAddressForMdlSafe(pIrp->MdlAddress);
  405. if(pvReportBuffer)
  406. {
  407. // Tell filter we have new data
  408. GCKF_IncomingInputReports(pFilterExt, pvReportBuffer, pIrp->IoStatus);
  409. }
  410. //**
  411. //** At this point we are done with the IRP
  412. //** Need not complete it, it will be recycled.
  413. //**
  414. // Decrement outstanding IRP count
  415. GCK_DecRemoveLock(&pFilterExt->RemoveLock);
  416. // Read is no longer pending
  417. pFilterExt->InternalPoll.fReadPending = FALSE;
  418. //If the InternalPollRef is greater than zero,
  419. //we need to be polling ourselves continuously
  420. //but don't carry on if some catestrophic failure
  421. //occured which lead to a MDL mapping failure
  422. if( pvReportBuffer
  423. && (pFilterExt->InternalPoll.ulInternalPollRef) )
  424. {
  425. GCK_IP_OneTimePoll(pFilterExt);
  426. }
  427. //We don't want any cleanup to happen
  428. return STATUS_MORE_PROCESSING_REQUIRED;
  429. }
  430. void GCK_IP_AddDevice(PGCK_FILTER_EXT pFilterExt)
  431. {
  432. KeInitializeSpinLock(&pFilterExt->InternalPoll.InternalPollLock);
  433. pFilterExt->InternalPoll.ShareStatus.OpenCount = 0;
  434. pFilterExt->InternalPoll.ShareStatus.Readers = 0;
  435. pFilterExt->InternalPoll.ShareStatus.Writers = 0;
  436. pFilterExt->InternalPoll.ShareStatus.SharedRead = 0;
  437. pFilterExt->InternalPoll.ShareStatus.SharedWrite = 0;
  438. pFilterExt->InternalPoll.fReadPending = FALSE;
  439. pFilterExt->InternalPoll.ulInternalPollRef = 0;
  440. pFilterExt->InternalPoll.pFirstOpenItem = NULL;
  441. pFilterExt->InternalPoll.fReady = FALSE;
  442. }
  443. /***********************************************************************************
  444. **
  445. ** NTSTATUS GCK_IP_Init (IN OUT PGCK_FILTER_EXT pFilterExt);
  446. **
  447. ** @func As part of the initialization that occurs at the end of Start device on
  448. ** a filtered device, the filter must be prepared for internal polling.
  449. ** All data polling is internal. (IRP_MJ_READ are sent down directly once
  450. ** so that hidclass.sys can perform its security check, but the data from
  451. ** that poll is discarded.) Initialize InternalPoll Data in Device Extension
  452. ** including creating a pInternalFileObject, a pPrivateIRP and an associtated
  453. ** Buffer.
  454. **
  455. ** @rdesc STATUS_SUCCESS, or various errors
  456. **
  457. *************************************************************************************/
  458. NTSTATUS
  459. GCK_IP_Init
  460. (
  461. IN OUT PGCK_FILTER_EXT pFilterExt
  462. )
  463. {
  464. //NTSTATUS NtStatus;
  465. LARGE_INTEGER lgiBufferOffset;
  466. //Initialize the Internal Poll Structure
  467. pFilterExt->InternalPoll.pInternalFileObject = NULL;
  468. pFilterExt->InternalPoll.pPrivateIrp = NULL;
  469. pFilterExt->InternalPoll.pucReportBuffer = NULL;
  470. // Allocate a Buffer for the private IRP_MJ_READ
  471. pFilterExt->InternalPoll.pucReportBuffer = (PUCHAR) EX_ALLOCATE_POOL
  472. ( NonPagedPool,
  473. pFilterExt->HidInfo.HidPCaps.InputReportByteLength );
  474. if(!pFilterExt->InternalPoll.pucReportBuffer)
  475. {
  476. GCK_DBG_CRITICAL_PRINT(("Failed to allocate Report Buffer for private IRPs\n"));
  477. return STATUS_INSUFFICIENT_RESOURCES;
  478. }
  479. // Allocate private recyclable IRPs for internal polling
  480. lgiBufferOffset.QuadPart = 0;
  481. pFilterExt->InternalPoll.pPrivateIrp = IoBuildAsynchronousFsdRequest
  482. (
  483. IRP_MJ_READ,
  484. pFilterExt->pTopOfStack,
  485. pFilterExt->InternalPoll.pucReportBuffer,
  486. (ULONG)pFilterExt->HidInfo.HidPCaps.InputReportByteLength,
  487. &lgiBufferOffset,
  488. NULL
  489. );
  490. if(!pFilterExt->InternalPoll.pPrivateIrp)
  491. {
  492. GCK_DBG_CRITICAL_PRINT(("Failed to allocate private Ping-Pong IRP\n"));
  493. return STATUS_INSUFFICIENT_RESOURCES;
  494. }
  495. // Initialize status for very first IRP
  496. pFilterExt->ioLastReportStatus.Information = (ULONG)pFilterExt->HidInfo.HidPCaps.InputReportByteLength;
  497. pFilterExt->ioLastReportStatus.Status = STATUS_SUCCESS;
  498. /**
  499. ** Cannot do this here since build 2006 or so,
  500. ** so defer until the first time we need it.
  501. **
  502. **
  503. ** //Open ourselves with a file object
  504. ** pFilterExt->InternalPoll.InternalCreateThread=KeGetCurrentThread();
  505. ** NtStatus = GCK_IP_CreateFileObject( &pFilterExt->InternalPoll.pInternalFileObject, pFilterExt->pTopOfStack);
  506. ** pFilterExt->InternalPoll.InternalCreateThread=NULL;
  507. ** if( NT_SUCCESS(NtStatus) )
  508. ** {
  509. ** pFilterExt->InternalPoll.fReady = TRUE;
  510. ** }
  511. **/
  512. return STATUS_SUCCESS;
  513. }
  514. /***********************************************************************************
  515. **
  516. ** NTSTATUS GCK_IP_Cleanup (IN OUT PGCK_FILTER_EXT pFilterExt);
  517. **
  518. ** @func Reverses Init, cancels outstanding internal polls, release pFileObject for
  519. ** internal polls, release private IRP and buffer. Does not release open file handles
  520. **
  521. ** @rdesc STATUS_SUCCESS, STATUS_UNSUCCESSFUL if we could not cancel a pending poll
  522. **
  523. *************************************************************************************/
  524. NTSTATUS
  525. GCK_IP_Cleanup
  526. (
  527. IN OUT PGCK_FILTER_EXT pFilterExt
  528. )
  529. {
  530. NTSTATUS NtStatus = STATUS_SUCCESS;
  531. if( pFilterExt->InternalPoll.fReady)
  532. {
  533. NtStatus = GCK_IP_CloseFileObject(pFilterExt);
  534. }
  535. if(NT_SUCCESS(NtStatus))
  536. {
  537. //Cleanup private IRP - and buffer, safely they may never had been allocated
  538. if(pFilterExt->InternalPoll.pPrivateIrp)
  539. {
  540. IoFreeIrp(pFilterExt->InternalPoll.pPrivateIrp);
  541. pFilterExt->InternalPoll.pPrivateIrp = NULL;
  542. }
  543. if(pFilterExt->InternalPoll.pucReportBuffer)
  544. {
  545. ExFreePool(pFilterExt->InternalPoll.pucReportBuffer);
  546. pFilterExt->InternalPoll.pucReportBuffer = NULL;
  547. }
  548. }
  549. return NtStatus;
  550. }
  551. /***********************************************************************************
  552. **
  553. ** NTSTATUS GCK_IP_CreateFileObject (OUT PFILE_OBJECT *ppFileObject, IN PDEVICE_OBJECT pPDO);
  554. **
  555. ** @func Calls IoGetDeviceObjectPointer, even though we already attached to the
  556. ** and have a pointer to the device object, the caller wants to create a
  557. ** new file object for internal calls down the stack that may require one.
  558. **
  559. ** @rdesc STATUS_SUCCESS, or various errors
  560. **
  561. *************************************************************************************/
  562. NTSTATUS
  563. GCK_IP_CreateFileObject
  564. (
  565. OUT PFILE_OBJECT *ppFileObject,
  566. IN PDEVICE_OBJECT pPDO
  567. )
  568. {
  569. NTSTATUS NtStatus;
  570. ULONG ulBufferLength = 0;
  571. PVOID pPDONameBuffer = NULL;
  572. UNICODE_STRING uniPDOName;
  573. PDEVICE_OBJECT pDeviceObject;
  574. //Get the size required for the PDO Name Buffer
  575. NtStatus = IoGetDeviceProperty(
  576. pPDO,
  577. DevicePropertyPhysicalDeviceObjectName,
  578. ulBufferLength,
  579. pPDONameBuffer,
  580. &ulBufferLength
  581. );
  582. ASSERT(STATUS_BUFFER_TOO_SMALL==NtStatus);
  583. //Allocate space
  584. pPDONameBuffer = EX_ALLOCATE_POOL(NonPagedPool, ulBufferLength);
  585. if(!pPDONameBuffer)
  586. {
  587. return STATUS_NO_MEMORY;
  588. }
  589. //Get PDO Name
  590. NtStatus = IoGetDeviceProperty(
  591. pPDO,
  592. DevicePropertyPhysicalDeviceObjectName,
  593. ulBufferLength,
  594. pPDONameBuffer,
  595. &ulBufferLength
  596. );
  597. ASSERT(NT_SUCCESS(NtStatus));
  598. if( NT_ERROR(NtStatus) )
  599. {
  600. return NtStatus;
  601. }
  602. //Make PDO Name into UNICODE string
  603. RtlInitUnicodeString(&uniPDOName, pPDONameBuffer);
  604. //Call IoGetDeviceObjectPointer to create a FILE_OBJECT
  605. NtStatus = IoGetDeviceObjectPointer(
  606. &uniPDOName,
  607. FILE_READ_DATA,
  608. ppFileObject,
  609. &pDeviceObject
  610. );
  611. ASSERT(NT_SUCCESS(NtStatus));
  612. //Release the space for Name
  613. ExFreePool(pPDONameBuffer);
  614. return NtStatus;
  615. }
  616. /***********************************************************************************
  617. **
  618. ** NTSTATUS GCK_IP_CloseFileObject (OUT PFILE_OBJECT *ppFileObject, IN PDEVICE_OBJECT pPDO);
  619. **
  620. ** @func Stops outstanding IO to hidclass.sys and closes handle
  621. ** @rdesc STATUS_SUCCESS, or STATUS_UNSUCCESSFUL
  622. **
  623. *************************************************************************************/
  624. NTSTATUS
  625. GCK_IP_CloseFileObject
  626. (
  627. IN OUT PGCK_FILTER_EXT pFilterExt
  628. )
  629. {
  630. NTSTATUS NtStatus;
  631. BOOLEAN fResult = TRUE;
  632. //Turn off internal polling
  633. pFilterExt->InternalPoll.fReady = FALSE;
  634. //Cancel pending internal polls
  635. if(pFilterExt->InternalPoll.fReadPending)
  636. {
  637. ASSERT(pFilterExt->InternalPoll.pPrivateIrp);
  638. fResult = IoCancelIrp(pFilterExt->InternalPoll.pPrivateIrp);
  639. }
  640. if(!fResult)
  641. {
  642. return STATUS_UNSUCCESSFUL;
  643. }
  644. //***
  645. //***If we are here, there are no pending polls, and there shall be no pending polls.
  646. //***
  647. //Release internal file object - if it had been created successfully
  648. if(pFilterExt->InternalPoll.pInternalFileObject)
  649. {
  650. ObDereferenceObject((PVOID)pFilterExt->InternalPoll.pInternalFileObject);
  651. pFilterExt->InternalPoll.pInternalFileObject=NULL;
  652. }
  653. return STATUS_SUCCESS;
  654. }