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.

1952 lines
69 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. dispatch.c
  5. Abstract
  6. Dispatch routines for the HID class driver.
  7. Author:
  8. Ervin P.
  9. Environment:
  10. Kernel mode only
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. #include <poclass.h>
  15. #include <wdmguid.h>
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE, HidpCallDriverSynchronous)
  18. #pragma alloc_text(PAGE, HidpIrpMajorPnp)
  19. #pragma alloc_text(PAGE, HidpFdoPnp)
  20. #pragma alloc_text(PAGE, HidpPdoPnp)
  21. #endif
  22. /*
  23. ********************************************************************************
  24. * HidpCallDriver
  25. ********************************************************************************
  26. *
  27. *
  28. */
  29. NTSTATUS HidpCallDriver(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp)
  30. {
  31. PHIDCLASS_DEVICE_EXTENSION hidDeviceExtension;
  32. PHIDCLASS_DRIVER_EXTENSION hidDriverExtension;
  33. PIO_STACK_LOCATION irpSp;
  34. NTSTATUS status;
  35. #if DBG
  36. KIRQL saveIrql;
  37. #endif
  38. DBGASSERT((Irp->Type == IO_TYPE_IRP),
  39. ("Irp->Type != IO_TYPE_IRP, Irp->Type == %x", Irp->Type),
  40. TRUE)
  41. /*
  42. * Update the IRP stack to point to the next location.
  43. */
  44. Irp->CurrentLocation--;
  45. if (Irp->CurrentLocation <= 0) {
  46. KeBugCheckEx( NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR) Irp, 0, 0, 0 );
  47. }
  48. irpSp = IoGetNextIrpStackLocation( Irp );
  49. Irp->Tail.Overlay.CurrentStackLocation = irpSp;
  50. //
  51. // Save a pointer to the device object for this request so that it can
  52. // be used later in completion.
  53. //
  54. irpSp->DeviceObject = DeviceObject;
  55. //
  56. // Get a pointer to the class extension and verify it.
  57. //
  58. hidDeviceExtension = (PHIDCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
  59. ASSERT(hidDeviceExtension->Signature == HID_DEVICE_EXTENSION_SIG);
  60. ASSERT(!hidDeviceExtension->isClientPdo);
  61. //
  62. // Ditto for the driver extension
  63. //
  64. hidDriverExtension = hidDeviceExtension->fdoExt.driverExt;
  65. ASSERT( hidDriverExtension->Signature == HID_DRIVER_EXTENSION_SIG );
  66. //
  67. // Invoke the driver at its dispatch routine entry point.
  68. //
  69. #if DBG
  70. saveIrql = KeGetCurrentIrql();
  71. #endif
  72. /*
  73. * Call down to the minidriver
  74. */
  75. status = hidDriverExtension->MajorFunction[irpSp->MajorFunction](DeviceObject, Irp);
  76. #if DBG
  77. if (saveIrql != KeGetCurrentIrql()) {
  78. DbgPrint( "IO: HidpCallDriver( Driver ext: %x Device object: %x Irp: %x )\n",
  79. hidDriverExtension,
  80. DeviceObject,
  81. Irp
  82. );
  83. DbgPrint( " Irql before: %x != After: %x\n", saveIrql, KeGetCurrentIrql() );
  84. DbgBreakPoint();
  85. }
  86. #endif
  87. return status;
  88. }
  89. /*
  90. ********************************************************************************
  91. * HidpSynchronousCallCompletion
  92. ********************************************************************************
  93. *
  94. *
  95. */
  96. NTSTATUS HidpSynchronousCallCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
  97. {
  98. PKEVENT event = Context;
  99. DBG_COMMON_ENTRY()
  100. KeSetEvent(event, 0, FALSE);
  101. DBG_COMMON_EXIT()
  102. return STATUS_MORE_PROCESSING_REQUIRED;
  103. }
  104. /*
  105. ********************************************************************************
  106. * HidpCallDriverSynchronous
  107. ********************************************************************************
  108. *
  109. *
  110. */
  111. NTSTATUS HidpCallDriverSynchronous(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp)
  112. {
  113. KEVENT event;
  114. NTSTATUS status;
  115. static LARGE_INTEGER timeout = {(ULONG) -50000000, 0xFFFFFFFF };
  116. PAGED_CODE();
  117. KeInitializeEvent(&event, NotificationEvent, FALSE);
  118. IoSetCompletionRoutine(Irp, HidpSynchronousCallCompletion, &event, TRUE, TRUE, TRUE);
  119. status = HidpCallDriver(DeviceObject, Irp);
  120. if (STATUS_PENDING == status) {
  121. //
  122. // Wait for 5 seconds. If we don't get a response within said amount
  123. // of time, the device is being unresponsive (happens with some UPS').
  124. // At that point, cancel the irp and return STATUS_IO_TIMEOUT.
  125. //
  126. status = KeWaitForSingleObject(&event,
  127. Executive, // wait reason
  128. KernelMode,
  129. FALSE, // not alertable
  130. &timeout ); // 5 second timeout
  131. if (status == STATUS_TIMEOUT) {
  132. #if DBG
  133. LARGE_INTEGER li;
  134. KeQueryTickCount(&li);
  135. DBGWARN(("Could not cancel irp. Will have to wait. Time %x.",Irp,li))
  136. #endif
  137. DBGWARN(("Device didn't respond for 5 seconds. Cancelling request. Irp %x",Irp))
  138. IoCancelIrp(Irp);
  139. KeWaitForSingleObject(&event,
  140. Executive, // wait reason
  141. KernelMode,
  142. FALSE, // not alertable
  143. NULL ); // no timeout
  144. #if DBG
  145. KeQueryTickCount(&li);
  146. DBGWARN(("Irp conpleted. Time %x.",li))
  147. #endif
  148. //
  149. // If we successfully cancelled the irp, then set the status to
  150. // STATUS_IO_TIMEOUT, otherwise, leave the status alone.
  151. //
  152. status = Irp->IoStatus.Status =
  153. (Irp->IoStatus.Status == STATUS_CANCELLED) ? STATUS_IO_TIMEOUT : Irp->IoStatus.Status;
  154. } else {
  155. //
  156. // The minidriver must always return STATUS_PENDING or STATUS_SUCCESS
  157. // (depending on async or sync completion) and set the real status
  158. // in the status block. We're not expecting anything but success from
  159. // KeWaitForSingleObject, either.
  160. //
  161. status = Irp->IoStatus.Status;
  162. }
  163. }
  164. DBGSUCCESS(status, FALSE)
  165. return status;
  166. }
  167. /*
  168. ********************************************************************************
  169. * HidpMajorHandler
  170. ********************************************************************************
  171. *
  172. * Note: this function should not be pageable because
  173. * reads can come in at dispatch level.
  174. *
  175. */
  176. NTSTATUS HidpMajorHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  177. {
  178. PHIDCLASS_DEVICE_EXTENSION hidClassExtension;
  179. PIO_STACK_LOCATION irpSp;
  180. NTSTATUS result;
  181. UCHAR majorFunction;
  182. BOOLEAN isClientPdo;
  183. DBG_COMMON_ENTRY()
  184. hidClassExtension = (PHIDCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
  185. ASSERT(hidClassExtension->Signature == HID_DEVICE_EXTENSION_SIG);
  186. //
  187. // Get a pointer to the current stack location and dispatch to the
  188. // appropriate routine.
  189. //
  190. irpSp = IoGetCurrentIrpStackLocation(Irp);
  191. /*
  192. * Keep these privately so we still have it after the IRP completes
  193. * or after the device extension is freed on a REMOVE_DEVICE
  194. */
  195. majorFunction = irpSp->MajorFunction;
  196. isClientPdo = hidClassExtension->isClientPdo;
  197. DBG_LOG_IRP_MAJOR(Irp, majorFunction, isClientPdo, FALSE, 0)
  198. switch (majorFunction){
  199. case IRP_MJ_CLOSE:
  200. result = HidpIrpMajorClose( hidClassExtension, Irp );
  201. break;
  202. case IRP_MJ_CREATE:
  203. result = HidpIrpMajorCreate( hidClassExtension, Irp );
  204. break;
  205. case IRP_MJ_DEVICE_CONTROL:
  206. result = HidpIrpMajorDeviceControl( hidClassExtension, Irp );
  207. break;
  208. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  209. result = HidpIrpMajorINTERNALDeviceControl( hidClassExtension, Irp );
  210. break;
  211. case IRP_MJ_PNP:
  212. result = HidpIrpMajorPnp( hidClassExtension, Irp );
  213. break;
  214. case IRP_MJ_POWER:
  215. result = HidpIrpMajorPower( hidClassExtension, Irp );
  216. break;
  217. case IRP_MJ_READ:
  218. result = HidpIrpMajorRead( hidClassExtension, Irp );
  219. break;
  220. case IRP_MJ_WRITE:
  221. result = HidpIrpMajorWrite( hidClassExtension, Irp );
  222. break;
  223. case IRP_MJ_SYSTEM_CONTROL:
  224. result = HidpIrpMajorSystemControl( hidClassExtension, Irp );
  225. break;
  226. default:
  227. result = HidpIrpMajorDefault( hidClassExtension, Irp );
  228. break;
  229. }
  230. DBG_LOG_IRP_MAJOR(Irp, majorFunction, isClientPdo, TRUE, result)
  231. DBG_COMMON_EXIT()
  232. return result;
  233. }
  234. /*
  235. ********************************************************************************
  236. * HidpIrpMajorDefault
  237. ********************************************************************************
  238. *
  239. * Handle IRPs with un-handled MAJOR function codes
  240. *
  241. */
  242. NTSTATUS HidpIrpMajorDefault(IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension, IN OUT PIRP Irp)
  243. {
  244. NTSTATUS status;
  245. PIO_STACK_LOCATION irpSp;
  246. irpSp = IoGetCurrentIrpStackLocation(Irp);
  247. DBGVERBOSE(("Unhandled IRP, MJ function: %x", irpSp->MajorFunction))
  248. if (HidDeviceExtension->isClientPdo){
  249. /*
  250. * This IRP is bound for the collection-PDO.
  251. * Return the default status.
  252. */
  253. status = Irp->IoStatus.Status;
  254. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  255. }
  256. else {
  257. /*
  258. * This IRP is bound for the lower device.
  259. * Pass it down the stack.
  260. */
  261. FDO_EXTENSION *fdoExt = &HidDeviceExtension->fdoExt;
  262. IoCopyCurrentIrpStackLocationToNext(Irp);
  263. status = HidpCallDriver(fdoExt->fdo, Irp);
  264. }
  265. DBGSUCCESS(status, FALSE)
  266. return status;
  267. }
  268. /*
  269. ********************************************************************************
  270. * HidpIrpMajorClose
  271. ********************************************************************************
  272. *
  273. * Note: this function cannot be pageable because it
  274. * acquires a spinlock.
  275. *
  276. */
  277. NTSTATUS HidpIrpMajorClose(IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension, IN OUT PIRP Irp)
  278. {
  279. NTSTATUS result;
  280. ASSERT(HidDeviceExtension->Signature == HID_DEVICE_EXTENSION_SIG);
  281. if (HidDeviceExtension->isClientPdo){
  282. PIO_STACK_LOCATION irpSp;
  283. PHIDCLASS_FILE_EXTENSION fileExtension;
  284. PFILE_OBJECT fileObject;
  285. KIRQL oldIrql;
  286. PDO_EXTENSION *pdoExt;
  287. FDO_EXTENSION *fdoExt;
  288. ULONG openCount;
  289. pdoExt = &HidDeviceExtension->pdoExt;
  290. fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  291. ASSERT(fdoExt->openCount > 0);
  292. Irp->IoStatus.Information = 0;
  293. irpSp = IoGetCurrentIrpStackLocation( Irp );
  294. fileObject = irpSp->FileObject;
  295. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  296. openCount = InterlockedDecrement(&fdoExt->openCount);
  297. if (fileExtension){
  298. PHIDCLASS_COLLECTION classCollection;
  299. ASSERT(fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG);
  300. /*
  301. * Get a pointer to the collection that our file extension is queued on.
  302. */
  303. classCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  304. if (classCollection){
  305. DBGVERBOSE((" HidpIrpMajorClose: closing collection w/ usagePage=%xh, usage=%xh.", fdoExt->deviceDesc.CollectionDesc[pdoExt->collectionIndex].UsagePage, fdoExt->deviceDesc.CollectionDesc[pdoExt->collectionIndex].Usage))
  306. if (fdoExt->state == DEVICE_STATE_REMOVED){
  307. KeAcquireSpinLock( &classCollection->FileExtensionListSpinLock, &oldIrql );
  308. RemoveEntryList(&fileExtension->FileList);
  309. KeReleaseSpinLock( &classCollection->FileExtensionListSpinLock, oldIrql );
  310. if (fileExtension->isSecureOpen) {
  311. KeAcquireSpinLock(&classCollection->secureReadLock,
  312. &oldIrql);
  313. while(fileExtension->SecureReadMode--) {
  314. classCollection->secureReadMode--;
  315. }
  316. KeReleaseSpinLock(&classCollection->secureReadLock,
  317. oldIrql);
  318. }
  319. HidpDestroyFileExtension(classCollection, fileExtension);
  320. classCollection = BAD_POINTER;
  321. /*
  322. * Delete the device-FDO and all collection-PDOs
  323. * Don't touch fdoExt after this.
  324. */
  325. HidpCleanUpFdo(fdoExt);
  326. result = STATUS_SUCCESS;
  327. }
  328. else {
  329. //
  330. // Destroy the file object and everything on it
  331. //
  332. KeAcquireSpinLock(&classCollection->FileExtensionListSpinLock, &oldIrql);
  333. /*
  334. * Update sharing information:
  335. * Decrement open counts and clear any exclusive holds of this file extension
  336. * on the device extension.
  337. */
  338. ASSERT(pdoExt->openCount > 0);
  339. InterlockedDecrement(&pdoExt->openCount);
  340. if (fileExtension->accessMask & FILE_READ_DATA){
  341. ASSERT(pdoExt->opensForRead > 0);
  342. pdoExt->opensForRead--;
  343. }
  344. if (fileExtension->accessMask & FILE_WRITE_DATA){
  345. ASSERT(pdoExt->opensForWrite > 0);
  346. pdoExt->opensForWrite--;
  347. }
  348. if (!(fileExtension->shareMask & FILE_SHARE_READ)){
  349. ASSERT(pdoExt->restrictionsForRead > 0);
  350. pdoExt->restrictionsForRead--;
  351. }
  352. if (!(fileExtension->shareMask & FILE_SHARE_WRITE)){
  353. ASSERT(pdoExt->restrictionsForWrite > 0);
  354. pdoExt->restrictionsForWrite--;
  355. }
  356. if (fileExtension->shareMask == 0){
  357. ASSERT(pdoExt->restrictionsForAnyOpen > 0);
  358. pdoExt->restrictionsForAnyOpen--;
  359. }
  360. RemoveEntryList(&fileExtension->FileList);
  361. KeReleaseSpinLock(&classCollection->FileExtensionListSpinLock, oldIrql);
  362. if (fileExtension->isSecureOpen) {
  363. KeAcquireSpinLock(&classCollection->secureReadLock,
  364. &oldIrql);
  365. while(fileExtension->SecureReadMode--) {
  366. classCollection->secureReadMode--;
  367. }
  368. KeReleaseSpinLock(&classCollection->secureReadLock,
  369. oldIrql);
  370. }
  371. HidpDestroyFileExtension(classCollection, fileExtension);
  372. result = STATUS_SUCCESS;
  373. }
  374. }
  375. else {
  376. result = STATUS_DATA_ERROR;
  377. }
  378. }
  379. else {
  380. TRAP;
  381. result = STATUS_DEVICE_NOT_CONNECTED;
  382. }
  383. DBGVERBOSE((" HidpIrpMajorClose: openCount decremented to %xh/%xh (pdo/fdo).", openCount, fdoExt->openCount))
  384. }
  385. else {
  386. DBGERR(("IRP_MJ_CLOSE was sent with a device-FDO extension for which an open never succeeded. The OBJDIR test tool does this sometimes. Hit 'g'."))
  387. result = STATUS_INVALID_PARAMETER_1;
  388. }
  389. Irp->IoStatus.Status = result;
  390. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  391. DBGSUCCESS(result, FALSE)
  392. return result;
  393. }
  394. /*
  395. ********************************************************************************
  396. * HidpIrpMajorCreate
  397. ********************************************************************************
  398. *
  399. *
  400. * Routine Description:
  401. *
  402. * We connect up to the interrupt for the create/open and initialize
  403. * the structures needed to maintain an open for a device.
  404. *
  405. * Arguments:
  406. *
  407. * DeviceObject - Pointer to the device object for this device
  408. *
  409. * Irp - Pointer to the IRP for the current request
  410. *
  411. * Return Value:
  412. *
  413. * The function value is the final status of the call
  414. *
  415. */
  416. NTSTATUS HidpIrpMajorCreate(IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension, IN OUT PIRP Irp)
  417. {
  418. NTSTATUS status = STATUS_SUCCESS;
  419. ASSERT(HidDeviceExtension->Signature == HID_DEVICE_EXTENSION_SIG);
  420. if (HidDeviceExtension->isClientPdo){
  421. PDO_EXTENSION *pdoExt = &HidDeviceExtension->pdoExt;
  422. FDO_EXTENSION *fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  423. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  424. PHIDCLASS_COLLECTION classCollection;
  425. Irp->IoStatus.Information = 0;
  426. classCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  427. if (classCollection){
  428. BOOLEAN sharingOk = TRUE;
  429. KIRQL oldIrql;
  430. BOOLEAN secureOpen = FALSE;
  431. secureOpen = MyPrivilegeCheck(Irp);
  432. // This is now taken care of by the fact that we don't
  433. // enumerate mouse and keyboard collections as RAW.
  434. KeAcquireSpinLock(&classCollection->FileExtensionListSpinLock, &oldIrql);
  435. /*
  436. * Enforce exclusive-open independently for exclusive-read and exclusive-write.
  437. */
  438. ASSERT(irpSp->Parameters.Create.SecurityContext);
  439. DBGVERBOSE((" HidpIrpMajorCreate: DesiredAccess = %xh, ShareAccess = %xh.", (ULONG)irpSp->Parameters.Create.SecurityContext->DesiredAccess, (ULONG)irpSp->Parameters.Create.ShareAccess))
  440. DBGASSERT((irpSp->Parameters.Create.SecurityContext->DesiredAccess & (FILE_READ_DATA|FILE_WRITE_DATA)),
  441. ("Neither FILE_READ_DATA|FILE_WRITE_DATA requested in HidpIrpMajorCreate. DesiredAccess = %xh.", (ULONG)irpSp->Parameters.Create.SecurityContext->DesiredAccess),
  442. FALSE)
  443. if (pdoExt->restrictionsForAnyOpen){
  444. /*
  445. * Oops. A previous open requested exclusive access.
  446. * Not even a client that requests only ioctl access
  447. * (does not request read nor write acess) is
  448. * allowed.
  449. */
  450. DBGWARN(("HidpIrpMajorCreate failing open: previous open is non-shared (ShareAccess==0)."))
  451. sharingOk = FALSE;
  452. }
  453. else if (pdoExt->openCount &&
  454. (irpSp->Parameters.Create.ShareAccess == 0)){
  455. /*
  456. * Oops. This open does not allow any sharing
  457. * (not even with a client that has neither read nor write access),
  458. * but there exists a previous open.
  459. */
  460. DBGWARN(("HidpIrpMajorCreate failing open: requesting non-shared (ShareAccess==0) while previous open exists."))
  461. sharingOk = FALSE;
  462. }
  463. else if ((irpSp->Parameters.Create.SecurityContext->DesiredAccess & FILE_READ_DATA) &&
  464. pdoExt->restrictionsForRead){
  465. /*
  466. * Oops. A previous open requested exclusive-read access.
  467. */
  468. DBGWARN(("HidpIrpMajorCreate failing open: requesting read access while previous open does not share read access."))
  469. sharingOk = FALSE;
  470. }
  471. else if ((irpSp->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA) &&
  472. pdoExt->restrictionsForWrite){
  473. /*
  474. * Oops. A previous open requested exclusive-write access.
  475. */
  476. DBGWARN(("HidpIrpMajorCreate failing open: requesting write access while previous open does not share write access."))
  477. sharingOk = FALSE;
  478. }
  479. else if ((pdoExt->opensForRead > 0) &&
  480. !(irpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ)){
  481. /*
  482. * Oops. The caller is requesting exclusive read access, but the device
  483. * is already open for read.
  484. */
  485. DBGWARN(("HidpIrpMajorCreate failing open: this open request does not share read access; but collection already open for read."))
  486. sharingOk = FALSE;
  487. }
  488. else if ((pdoExt->opensForWrite > 0) &&
  489. !(irpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)){
  490. /*
  491. * Oops. The caller is requesting exclusive write access, but the device
  492. * is already open for write.
  493. */
  494. DBGWARN(("HidpIrpMajorCreate failing open: this open request does not share write access; but collection already open for write."))
  495. sharingOk = FALSE;
  496. }
  497. if (!sharingOk){
  498. DBGWARN(("HidpIrpMajorCreate failing IRP_MJ_CREATE with STATUS_SHARING_VIOLATION."))
  499. status = STATUS_SHARING_VIOLATION;
  500. }
  501. else {
  502. if (irpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE){
  503. /*
  504. * Attempt to open this device as a directory
  505. */
  506. status = STATUS_NOT_A_DIRECTORY;
  507. } else {
  508. /*
  509. * Make sure the device is started.
  510. * If it is temporarily stopped, we also succeed because a stop
  511. * is supposed to be transparent to the client.
  512. */
  513. if (((fdoExt->state == DEVICE_STATE_START_SUCCESS) ||
  514. (fdoExt->state == DEVICE_STATE_STOPPING) ||
  515. (fdoExt->state == DEVICE_STATE_STOPPED))
  516. &&
  517. ((pdoExt->state == COLLECTION_STATE_RUNNING) ||
  518. (pdoExt->state == COLLECTION_STATE_STOPPING) ||
  519. (pdoExt->state == COLLECTION_STATE_STOPPED))){
  520. PHIDCLASS_FILE_EXTENSION fileExtension;
  521. /*
  522. * We have a valid collection.
  523. * Allocate a file object extension (which encapsulates an 'open' on the device).
  524. */
  525. try {
  526. fileExtension = ALLOCATEQUOTAPOOL(NonPagedPool,
  527. sizeof(HIDCLASS_FILE_EXTENSION));
  528. } except (EXCEPTION_EXECUTE_HANDLER) {
  529. fileExtension = NULL;
  530. status = GetExceptionCode();
  531. }
  532. if (fileExtension){
  533. PHIDP_COLLECTION_DESC hidCollectionDesc;
  534. RtlZeroMemory(fileExtension, sizeof(HIDCLASS_FILE_EXTENSION));
  535. fileExtension->CollectionNumber = pdoExt->collectionNum;
  536. fileExtension->fdoExt = fdoExt;
  537. fileExtension->FileObject = irpSp->FileObject;
  538. fileExtension->isOpportunisticPolledDeviceReader = FALSE;
  539. InitializeListHead( &fileExtension->ReportList );
  540. InitializeListHead( &fileExtension->PendingIrpList );
  541. KeInitializeSpinLock( &fileExtension->ListSpinLock );
  542. fileExtension->Closing = FALSE;
  543. //
  544. // Right now we'll set a default maximum input report queue size.
  545. // This can be changed later with an IOCTL.
  546. //
  547. fileExtension->CurrentInputReportQueueSize = 0;
  548. fileExtension->MaximumInputReportQueueSize = DEFAULT_INPUT_REPORT_QUEUE_SIZE;
  549. fileExtension->insideReadCompleteCount = 0;
  550. //
  551. // Add this file extension to the list of file extensions for this
  552. // collection.
  553. //
  554. InsertHeadList(&classCollection->FileExtensionList, &fileExtension->FileList);
  555. #if DBG
  556. fileExtension->Signature = HIDCLASS_FILE_EXTENSION_SIG;
  557. #endif
  558. /*
  559. * Store the file-open attribute flags.
  560. */
  561. fileExtension->FileAttributes = irpSp->Parameters.Create.FileAttributes;
  562. fileExtension->accessMask = irpSp->Parameters.Create.SecurityContext->DesiredAccess;
  563. fileExtension->shareMask = irpSp->Parameters.Create.ShareAccess;
  564. //
  565. // Set up secure read mode
  566. //
  567. fileExtension->SecureReadMode = 0;
  568. fileExtension->isSecureOpen = secureOpen;
  569. /*
  570. * Store a pointer to our file extension in the file object.
  571. */
  572. irpSp->FileObject->FsContext = fileExtension;
  573. //
  574. // KENRAY
  575. // Only drivers can set the FsContext of file
  576. // objects so this is not a security problem.
  577. // However, there is only one file object for the entire
  578. // PDO stack. This means we have to share. You cannot
  579. // have both context pointers. I need one for the
  580. // keyboard and mouse class drivers.
  581. //
  582. // This information need go into the fileExtension.
  583. //
  584. /*
  585. * Increment the device extension's open counts,
  586. * and set the exclusive-access fields.
  587. */
  588. InterlockedIncrement(&fdoExt->openCount);
  589. InterlockedIncrement(&pdoExt->openCount);
  590. if (irpSp->Parameters.Create.SecurityContext->DesiredAccess & FILE_READ_DATA){
  591. pdoExt->opensForRead++;
  592. }
  593. if (irpSp->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA){
  594. pdoExt->opensForWrite++;
  595. }
  596. /*
  597. * NOTE: Restrictions are independent of desired access.
  598. * For example, a client can do an open-for-read-only
  599. * AND prevent other clients from doing an open-for-write
  600. * (by not setting the FILE_SHARE_WRITE flag).
  601. */
  602. if (!(irpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ)){
  603. pdoExt->restrictionsForRead++;
  604. }
  605. if (!(irpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)){
  606. pdoExt->restrictionsForWrite++;
  607. }
  608. if (irpSp->Parameters.Create.ShareAccess == 0){
  609. /*
  610. * ShareAccess==0 means that no other opens of any kind
  611. * are allowed.
  612. */
  613. pdoExt->restrictionsForAnyOpen++;
  614. }
  615. DBGVERBOSE((" HidpIrpMajorCreate: opened collection w/ usagePage=%xh, usage=%xh. openCount incremented to %xh/%xh (pdo/fdo).", fdoExt->deviceDesc.CollectionDesc[pdoExt->collectionIndex].UsagePage, fdoExt->deviceDesc.CollectionDesc[pdoExt->collectionIndex].Usage, pdoExt->openCount, fdoExt->openCount))
  616. } else {
  617. status = STATUS_INSUFFICIENT_RESOURCES;
  618. }
  619. } else {
  620. status = STATUS_DEVICE_NOT_CONNECTED;
  621. }
  622. }
  623. }
  624. KeReleaseSpinLock(&classCollection->FileExtensionListSpinLock, oldIrql);
  625. }
  626. else {
  627. DBGERR(("HidpIrpMajorCreate failing -- couldn't find collection"))
  628. status = STATUS_DEVICE_NOT_CONNECTED;
  629. }
  630. }
  631. else {
  632. /*
  633. * We don't support opens on the device itself,
  634. * only on the collections.
  635. */
  636. DBGWARN(("HidpIrpMajorCreate failing -- we don't support opens on the device itself; only on collections."))
  637. status = STATUS_UNSUCCESSFUL;
  638. }
  639. Irp->IoStatus.Status = status;
  640. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  641. DBGSUCCESS(status, FALSE)
  642. return status;
  643. }
  644. /*
  645. ********************************************************************************
  646. * HidpIrpMajorDeviceControl
  647. ********************************************************************************
  648. *
  649. * Note: This function cannot be pageable because IOCTLs
  650. * can get sent at DISPATCH_LEVEL.
  651. *
  652. */
  653. NTSTATUS HidpIrpMajorDeviceControl(IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension, IN OUT PIRP Irp)
  654. {
  655. NTSTATUS status;
  656. BOOLEAN completeIrpHere = TRUE;
  657. PDO_EXTENSION *pdoExt;
  658. FDO_EXTENSION *fdoExt;
  659. ULONG ioControlCode;
  660. KIRQL irql;
  661. PIO_STACK_LOCATION irpSp;
  662. PHIDCLASS_COLLECTION hidCollection;
  663. PHIDCLASS_FILE_EXTENSION fileExtension;
  664. PFILE_OBJECT fileObject;
  665. if (!HidDeviceExtension->isClientPdo){
  666. ASSERT(HidDeviceExtension->isClientPdo);
  667. status = STATUS_INVALID_PARAMETER_1;
  668. goto HidpIrpMajorDeviceControlDone;
  669. }
  670. pdoExt = &HidDeviceExtension->pdoExt;
  671. fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  672. if (fdoExt->state != DEVICE_STATE_START_SUCCESS ||
  673. pdoExt->state != COLLECTION_STATE_RUNNING) {
  674. DBGSTATE (pdoExt->state, COLLECTION_STATE_RUNNING, FALSE)
  675. status = STATUS_DEVICE_NOT_CONNECTED;
  676. goto HidpIrpMajorDeviceControlDone;
  677. }
  678. irpSp = IoGetCurrentIrpStackLocation(Irp);
  679. // Keep this privately so we still have it after the IRP is completed.
  680. ioControlCode = irpSp->Parameters.DeviceIoControl.IoControlCode;
  681. Irp->IoStatus.Information = 0;
  682. status = HidpCheckIdleState(HidDeviceExtension, Irp);
  683. if (status != STATUS_SUCCESS) {
  684. completeIrpHere = (status != STATUS_PENDING);
  685. goto HidpIrpMajorDeviceControlDone;
  686. }
  687. switch (ioControlCode){
  688. case IOCTL_HID_GET_DRIVER_CONFIG:
  689. case IOCTL_HID_SET_DRIVER_CONFIG:
  690. DBGWARN(("Unsupported ioctl received: %x", ioControlCode));
  691. status = STATUS_NOT_IMPLEMENTED;
  692. break;
  693. case IOCTL_HID_GET_COLLECTION_INFORMATION:
  694. /*
  695. * This IRP is METHOD_BUFFERED, so the buffer
  696. * is in the AssociatedIrp.
  697. */
  698. DBGASSERT((Irp->Flags & IRP_BUFFERED_IO),
  699. ("Irp->Flags & IRP_BUFFERED_IO Irp->Type != IO_TYPE_IRP, Irp->Type == %x", Irp->Type),
  700. FALSE)
  701. if (Irp->AssociatedIrp.SystemBuffer){
  702. ULONG bufLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  703. status = HidpGetCollectionInformation(
  704. fdoExt,
  705. pdoExt->collectionNum,
  706. Irp->AssociatedIrp.SystemBuffer,
  707. &bufLen);
  708. Irp->IoStatus.Information = bufLen;
  709. }
  710. else {
  711. status = STATUS_INVALID_PARAMETER;
  712. }
  713. break;
  714. case IOCTL_HID_GET_COLLECTION_DESCRIPTOR:
  715. /*
  716. * This IOCTL is METHOD_NEITHER, so the buffer is in UserBuffer.
  717. */
  718. if (Irp->UserBuffer){
  719. __try {
  720. ULONG bufLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  721. if (Irp->RequestorMode != KernelMode){
  722. /*
  723. * Ensure user-mode buffer is legal.
  724. */
  725. ProbeForWrite(Irp->UserBuffer, bufLen, sizeof(UCHAR));
  726. }
  727. status = HidpGetCollectionDescriptor(
  728. fdoExt,
  729. pdoExt->collectionNum,
  730. Irp->UserBuffer,
  731. &bufLen);
  732. Irp->IoStatus.Information = bufLen;
  733. }
  734. __except(EXCEPTION_EXECUTE_HANDLER) {
  735. DBGWARN(("Invalid user mode buffer in IOCTL_HID_DET_COLLECTION_DESCRIPTOR"));
  736. status = GetExceptionCode();
  737. }
  738. }
  739. else {
  740. status = STATUS_INVALID_BUFFER_SIZE;
  741. }
  742. break;
  743. case IOCTL_HID_FLUSH_QUEUE:
  744. //
  745. // Run the list of report descriptors hanging off of this
  746. // file object and free them all.
  747. //
  748. fileObject = irpSp->FileObject;
  749. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  750. if(!fileExtension) {
  751. DBGWARN(("Attempted to flush queue with no file extension"))
  752. status = STATUS_PRIVILEGE_NOT_HELD;
  753. break;
  754. }
  755. ASSERT(fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG);
  756. HidpFlushReportQueue(fileExtension);
  757. status = STATUS_SUCCESS;
  758. break;
  759. case IOCTL_HID_GET_POLL_FREQUENCY_MSEC:
  760. hidCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  761. if (hidCollection && hidCollection->hidCollectionInfo.Polled){
  762. /*
  763. * Get the current poll frequency.
  764. * This IOCTL is METHOD_BUFFERED, so the result goes in the AssociatedIrp.
  765. */
  766. DBGASSERT((Irp->Flags & IRP_BUFFERED_IO),
  767. ("Irp->Flags & IRP_BUFFERED_IO Irp->Type != IO_TYPE_IRP, Irp->Type == %x", Irp->Type),
  768. FALSE)
  769. if (Irp->AssociatedIrp.SystemBuffer &&
  770. (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ULONG))){
  771. *(ULONG *)Irp->AssociatedIrp.SystemBuffer = hidCollection->PollInterval_msec;
  772. Irp->IoStatus.Information = sizeof (ULONG);
  773. status = STATUS_SUCCESS;
  774. }
  775. else {
  776. status = STATUS_INVALID_BUFFER_SIZE;
  777. }
  778. }
  779. else {
  780. status = STATUS_INVALID_DEVICE_REQUEST;
  781. }
  782. break;
  783. case IOCTL_HID_SET_POLL_FREQUENCY_MSEC:
  784. hidCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  785. if (hidCollection && hidCollection->hidCollectionInfo.Polled){
  786. if (Irp->AssociatedIrp.SystemBuffer &&
  787. (irpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(ULONG))){
  788. ULONG newPollInterval = *(ULONG *)Irp->AssociatedIrp.SystemBuffer;
  789. fileObject = irpSp->FileObject;
  790. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  791. if(!fileExtension) {
  792. DBGWARN(("Attempted to set poll frequency with no file extension"))
  793. status = STATUS_PRIVILEGE_NOT_HELD;
  794. break;
  795. }
  796. ASSERT(fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG);
  797. if (newPollInterval == 0){
  798. /*
  799. * Poll interval zero means that this client will
  800. * be doing irregular, opportunistic reads on the
  801. * polled device. We will not change the polling
  802. * frequency of the device. But when this client
  803. * does a read, we will immediately complete that read
  804. * with either the last report for this collection
  805. * (if the data is not stale) or by immediately issuing
  806. * a new read.
  807. */
  808. fileExtension->isOpportunisticPolledDeviceReader = TRUE;
  809. }
  810. else {
  811. /*
  812. * Set the poll frequency AND tell the user what we really set it to
  813. * in case it's out of range.
  814. */
  815. if (newPollInterval < MIN_POLL_INTERVAL_MSEC){
  816. newPollInterval = MIN_POLL_INTERVAL_MSEC;
  817. }
  818. else if (newPollInterval > MAX_POLL_INTERVAL_MSEC){
  819. newPollInterval = MAX_POLL_INTERVAL_MSEC;
  820. }
  821. hidCollection->PollInterval_msec = newPollInterval;
  822. /*
  823. * If this client was an 'opportunistic' reader before,
  824. * he's not anymore.
  825. */
  826. fileExtension->isOpportunisticPolledDeviceReader = FALSE;
  827. /*
  828. * Stop and re-start the polling loop so that
  829. * the new polling interval takes effect right away.
  830. */
  831. StopPollingLoop(hidCollection, FALSE);
  832. StartPollingLoop(fdoExt, hidCollection, FALSE);
  833. }
  834. status = STATUS_SUCCESS;
  835. }
  836. else {
  837. status = STATUS_INVALID_BUFFER_SIZE;
  838. }
  839. }
  840. else {
  841. status = STATUS_INVALID_DEVICE_REQUEST;
  842. }
  843. break;
  844. case IOCTL_HID_GET_FEATURE:
  845. case IOCTL_HID_SET_FEATURE:
  846. case IOCTL_HID_GET_INPUT_REPORT:
  847. case IOCTL_HID_SET_OUTPUT_REPORT:
  848. {
  849. BOOLEAN sentIrpToMinidriver;
  850. status = HidpGetSetReport ( HidDeviceExtension,
  851. Irp,
  852. irpSp->Parameters.DeviceIoControl.IoControlCode,
  853. &sentIrpToMinidriver);
  854. /*
  855. * If we just passed this Irp to the minidriver, we don't want to
  856. * complete the Irp; we're not even allowed to touch it since it may
  857. * have already completed.
  858. */
  859. completeIrpHere = !sentIrpToMinidriver;
  860. }
  861. break;
  862. // NOTE - we currently only support English (langId=0x0409).
  863. // route all collection-PDO string requests to device-FDO.
  864. case IOCTL_HID_GET_MANUFACTURER_STRING:
  865. status = HidpGetDeviceString(fdoExt, Irp, HID_STRING_ID_IMANUFACTURER, 0x0409);
  866. completeIrpHere = FALSE;
  867. break;
  868. case IOCTL_HID_GET_PRODUCT_STRING:
  869. status = HidpGetDeviceString(fdoExt, Irp, HID_STRING_ID_IPRODUCT, 0x0409);
  870. completeIrpHere = FALSE;
  871. break;
  872. case IOCTL_HID_GET_SERIALNUMBER_STRING:
  873. status = HidpGetDeviceString(fdoExt, Irp, HID_STRING_ID_ISERIALNUMBER, 0x0409);
  874. completeIrpHere = FALSE;
  875. break;
  876. case IOCTL_HID_GET_INDEXED_STRING:
  877. /*
  878. * This IRP is METHOD_OUT_DIRECT, so the buffer is in the MDL.
  879. * The second argument (string index) is in the AssociatedIrp;
  880. * the InputBufferLength is the length of this second buffer.
  881. */
  882. if (Irp->AssociatedIrp.SystemBuffer &&
  883. (irpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(ULONG))){
  884. ULONG stringIndex = *(ULONG *)Irp->AssociatedIrp.SystemBuffer;
  885. status = HidpGetIndexedString(fdoExt, Irp, stringIndex, 0x409);
  886. completeIrpHere = FALSE;
  887. }
  888. else {
  889. status = STATUS_INVALID_PARAMETER;
  890. }
  891. break;
  892. case IOCTL_HID_GET_MS_GENRE_DESCRIPTOR:
  893. /*
  894. * This IRP is METHOD_OUT_DIRECT, so the buffer is in the MDL.
  895. */
  896. status = HidpGetMsGenreDescriptor(fdoExt, Irp);
  897. completeIrpHere = FALSE;
  898. break;
  899. case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS:
  900. /*
  901. * This IRP is METHOD_BUFFERED, so the buffer
  902. * is in the AssociatedIrp.SystemBuffer field.
  903. */
  904. DBGASSERT((Irp->Flags & IRP_BUFFERED_IO),
  905. ("Irp->Flags & IRP_BUFFERED_IO Irp->Type != IO_TYPE_IRP, Irp->Type == %x", Irp->Type),
  906. FALSE)
  907. if (Irp->AssociatedIrp.SystemBuffer &&
  908. (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ULONG))){
  909. fileObject = irpSp->FileObject;
  910. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  911. if(!fileExtension) {
  912. DBGWARN(("Attempted to get number of input buffers with no file extension"))
  913. status = STATUS_PRIVILEGE_NOT_HELD;
  914. break;
  915. }
  916. ASSERT( fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG );
  917. *(ULONG *)Irp->AssociatedIrp.SystemBuffer =
  918. fileExtension->MaximumInputReportQueueSize;
  919. Irp->IoStatus.Information = sizeof(ULONG);
  920. status = STATUS_SUCCESS;
  921. }
  922. else {
  923. status = STATUS_INVALID_PARAMETER;
  924. }
  925. break;
  926. case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS:
  927. /*
  928. * This IRP is METHOD_BUFFERED, so the buffer
  929. * is in the AssociatedIrp.SystemBuffer field.
  930. */
  931. DBGASSERT((Irp->Flags & IRP_BUFFERED_IO),
  932. ("Irp->Flags & IRP_BUFFERED_IO Irp->Type != IO_TYPE_IRP, Irp->Type == %x", Irp->Type),
  933. FALSE)
  934. if (Irp->AssociatedIrp.SystemBuffer &&
  935. (irpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(ULONG))){
  936. ULONG newValue = *(ULONG *)Irp->AssociatedIrp.SystemBuffer;
  937. fileObject = irpSp->FileObject;
  938. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  939. if(!fileExtension) {
  940. DBGWARN(("Attempted to set number of input buffers with no file extension"))
  941. status = STATUS_PRIVILEGE_NOT_HELD;
  942. break;
  943. }
  944. ASSERT( fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG );
  945. if ((newValue >= MIN_INPUT_REPORT_QUEUE_SIZE) &&
  946. (newValue <= MAX_INPUT_REPORT_QUEUE_SIZE)){
  947. fileExtension->MaximumInputReportQueueSize = newValue;
  948. status = STATUS_SUCCESS;
  949. }
  950. else {
  951. status = STATUS_INVALID_PARAMETER;
  952. }
  953. }
  954. else {
  955. status = STATUS_INVALID_PARAMETER;
  956. }
  957. break;
  958. case IOCTL_GET_PHYSICAL_DESCRIPTOR:
  959. status = HidpGetPhysicalDescriptor(HidDeviceExtension, Irp);
  960. completeIrpHere = FALSE;
  961. break;
  962. case IOCTL_HID_GET_HARDWARE_ID:
  963. {
  964. PDEVICE_OBJECT pdo = pdoExt->deviceFdoExt->hidExt.PhysicalDeviceObject;
  965. ULONG bufLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  966. PWSTR hwIdBuf;
  967. hwIdBuf = HidpGetSystemAddressForMdlSafe(Irp->MdlAddress);
  968. if (hwIdBuf && bufLen){
  969. ULONG actualLen;
  970. status = IoGetDeviceProperty( pdo,
  971. DevicePropertyHardwareID,
  972. bufLen,
  973. hwIdBuf,
  974. &actualLen);
  975. if (NT_SUCCESS(status)){
  976. Irp->IoStatus.Information = (ULONG)actualLen;
  977. }
  978. }
  979. else {
  980. status = STATUS_INVALID_USER_BUFFER;
  981. }
  982. }
  983. break;
  984. case IOCTL_GET_SYS_BUTTON_CAPS:
  985. hidCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  986. if (hidCollection){
  987. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ULONG)){
  988. ULONG buttonCaps;
  989. status = HidP_SysPowerCaps(hidCollection->phidDescriptor, &buttonCaps);
  990. if (NT_SUCCESS(status)){
  991. *(PULONG)Irp->AssociatedIrp.SystemBuffer = buttonCaps;
  992. Irp->IoStatus.Information = sizeof(ULONG);
  993. }
  994. }
  995. else {
  996. status = STATUS_INVALID_BUFFER_SIZE;
  997. Irp->IoStatus.Information = sizeof(ULONG);
  998. }
  999. }
  1000. else {
  1001. status = STATUS_DEVICE_NOT_CONNECTED;
  1002. }
  1003. break;
  1004. case IOCTL_GET_SYS_BUTTON_EVENT:
  1005. /*
  1006. * Hold onto this IRP and complete it when a power event occurs.
  1007. */
  1008. hidCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  1009. if (hidCollection){
  1010. status = QueuePowerEventIrp(hidCollection, Irp);
  1011. if (status == STATUS_PENDING){
  1012. completeIrpHere = FALSE;
  1013. }
  1014. }
  1015. else {
  1016. status = STATUS_DEVICE_NOT_CONNECTED;
  1017. }
  1018. break;
  1019. case IOCTL_HID_ENABLE_SECURE_READ:
  1020. fileObject = irpSp->FileObject;
  1021. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  1022. if(!fileExtension) {
  1023. DBGWARN(("Attempted to get number of input buffers with no file extension"))
  1024. status = STATUS_PRIVILEGE_NOT_HELD;
  1025. break;
  1026. }
  1027. ASSERT( fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG );
  1028. hidCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  1029. if (!fileExtension->isSecureOpen) {
  1030. status = STATUS_PRIVILEGE_NOT_HELD;
  1031. break;
  1032. }
  1033. KeAcquireSpinLock(&hidCollection->secureReadLock,
  1034. &irql);
  1035. fileExtension->SecureReadMode++;
  1036. hidCollection->secureReadMode++;
  1037. KeReleaseSpinLock(&hidCollection->secureReadLock,
  1038. irql);
  1039. break;
  1040. case IOCTL_HID_DISABLE_SECURE_READ:
  1041. fileObject = irpSp->FileObject;
  1042. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  1043. if(!fileExtension) {
  1044. DBGWARN(("Attempted to get number of input buffers with no file extension"))
  1045. status = STATUS_PRIVILEGE_NOT_HELD;
  1046. break;
  1047. }
  1048. ASSERT( fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG );
  1049. hidCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  1050. if (!fileExtension->isSecureOpen) {
  1051. status = STATUS_PRIVILEGE_NOT_HELD;
  1052. break;
  1053. }
  1054. KeAcquireSpinLock(&hidCollection->secureReadLock,
  1055. &irql);
  1056. if (fileExtension->SecureReadMode > 0) {
  1057. fileExtension->SecureReadMode--;
  1058. hidCollection->secureReadMode--;
  1059. }
  1060. KeReleaseSpinLock(&hidCollection->secureReadLock,
  1061. irql);
  1062. break;
  1063. default:
  1064. /*
  1065. * 'Fail' the Irp by returning the default status.
  1066. */
  1067. DBGWARN(("Unrecognized ioctl received: %x", ioControlCode));
  1068. status = Irp->IoStatus.Status;
  1069. break;
  1070. }
  1071. DBG_LOG_IOCTL(fdoExt->fdo, ioControlCode, status)
  1072. HidpIrpMajorDeviceControlDone:
  1073. /*
  1074. * If we did not pass the Irp down to a lower driver, complete it here.
  1075. */
  1076. if (completeIrpHere){
  1077. Irp->IoStatus.Status = status;
  1078. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1079. }
  1080. DBGSUCCESS(status, FALSE)
  1081. return status;
  1082. }
  1083. /*
  1084. ********************************************************************************
  1085. * HidpIrpMajorINTERNALDeviceControl
  1086. ********************************************************************************
  1087. *
  1088. * Note: This function cannot be pageable because IOCTLs
  1089. * can get sent at DISPATCH_LEVEL.
  1090. *
  1091. */
  1092. NTSTATUS HidpIrpMajorINTERNALDeviceControl(IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension, IN OUT PIRP Irp)
  1093. {
  1094. NTSTATUS status;
  1095. if (HidDeviceExtension->isClientPdo){
  1096. PDO_EXTENSION *pdoExt = &HidDeviceExtension->pdoExt;
  1097. FDO_EXTENSION *fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  1098. Irp->IoStatus.Information = 0;
  1099. //
  1100. // If we ever support any other internal IOCTLs that are real and
  1101. // require touching the hardware, then we need to break out the check
  1102. // for fdoExt->devicePowerState and enqueue the irp until we get to full
  1103. // power
  1104. //
  1105. if (fdoExt->state == DEVICE_STATE_START_SUCCESS) {
  1106. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  1107. switch (irpSp->Parameters.DeviceIoControl.IoControlCode){
  1108. default:
  1109. /*
  1110. * 'Fail' the Irp by returning the default status.
  1111. */
  1112. DBGWARN(("HidpIrpMajorINTERNALDeviceControl - unsupported IOCTL %xh ", (ULONG)irpSp->Parameters.DeviceIoControl.IoControlCode))
  1113. status = Irp->IoStatus.Status;
  1114. break;
  1115. }
  1116. }
  1117. else {
  1118. status = STATUS_DEVICE_NOT_CONNECTED;
  1119. }
  1120. }
  1121. else {
  1122. ASSERT(HidDeviceExtension->isClientPdo);
  1123. status = STATUS_INVALID_PARAMETER_1;
  1124. }
  1125. Irp->IoStatus.Status = status;
  1126. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1127. DBGSUCCESS(status, FALSE)
  1128. return status;
  1129. }
  1130. /*
  1131. ********************************************************************************
  1132. * HidpIrpMajorPnp
  1133. ********************************************************************************
  1134. *
  1135. *
  1136. */
  1137. NTSTATUS HidpIrpMajorPnp(IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension, IN OUT PIRP Irp)
  1138. {
  1139. NTSTATUS status;
  1140. PIO_STACK_LOCATION irpSp;
  1141. BOOLEAN completeIrpHere;
  1142. BOOLEAN isClientPdo;
  1143. UCHAR minorFunction;
  1144. PAGED_CODE();
  1145. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1146. /*
  1147. * Keep these fields privately so that we have them
  1148. * after the IRP is completed and in case we delete
  1149. * the device extension on a REMOVE_DEVICE.
  1150. */
  1151. isClientPdo = HidDeviceExtension->isClientPdo;
  1152. minorFunction = irpSp->MinorFunction;
  1153. DBG_LOG_PNP_IRP(Irp, minorFunction, isClientPdo, FALSE, 0)
  1154. if (isClientPdo) {
  1155. status = HidpPdoPnp(HidDeviceExtension, Irp);
  1156. } else {
  1157. status = HidpFdoPnp(HidDeviceExtension, Irp);
  1158. }
  1159. DBG_LOG_PNP_IRP(Irp, minorFunction, isClientPdo, TRUE, status)
  1160. return status;
  1161. }
  1162. NTSTATUS HidpPdoPnp(
  1163. IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension,
  1164. IN OUT PIRP Irp
  1165. )
  1166. {
  1167. NTSTATUS status = NO_STATUS;
  1168. PIO_STACK_LOCATION irpSp;
  1169. FDO_EXTENSION *fdoExt;
  1170. PDO_EXTENSION *pdoExt;
  1171. UCHAR minorFunction;
  1172. BOOLEAN deleteDevice = FALSE;
  1173. PAGED_CODE();
  1174. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1175. /*
  1176. * Keep these fields privately so that we have them
  1177. * after the IRP is completed and in case we delete
  1178. * the device extension on a REMOVE_DEVICE.
  1179. */
  1180. minorFunction = irpSp->MinorFunction;
  1181. DBG_LOG_PNP_IRP(Irp, minorFunction, TRUE, FALSE, 0)
  1182. pdoExt = &HidDeviceExtension->pdoExt;
  1183. fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  1184. switch (minorFunction){
  1185. case IRP_MN_START_DEVICE:
  1186. status = HidpStartCollectionPDO(fdoExt, pdoExt, Irp);
  1187. if (NT_SUCCESS(status) &&
  1188. ISPTR(pdoExt->StatusChangeFn)) {
  1189. pdoExt->StatusChangeFn(pdoExt->StatusChangeContext,
  1190. DeviceObjectStarted);
  1191. }
  1192. break;
  1193. case IRP_MN_QUERY_STOP_DEVICE:
  1194. DBGSTATE(pdoExt->state, COLLECTION_STATE_RUNNING, FALSE)
  1195. pdoExt->prevState = pdoExt->state;
  1196. pdoExt->state = COLLECTION_STATE_STOPPING;
  1197. status = STATUS_SUCCESS;
  1198. break;
  1199. case IRP_MN_CANCEL_STOP_DEVICE:
  1200. DBGSTATE(pdoExt->state, COLLECTION_STATE_STOPPING, TRUE)
  1201. pdoExt->state = pdoExt->prevState;
  1202. status = STATUS_SUCCESS;
  1203. break;
  1204. case IRP_MN_STOP_DEVICE:
  1205. DBGSTATE(pdoExt->state, COLLECTION_STATE_STOPPING, TRUE)
  1206. if (pdoExt->prevState != COLLECTION_STATE_UNINITIALIZED){
  1207. /*
  1208. * Destroy the symbolic link for this collection.
  1209. */
  1210. HidpCreateSymbolicLink(pdoExt, pdoExt->collectionNum, FALSE, pdoExt->pdo);
  1211. HidpFreePowerEventIrp(&fdoExt->classCollectionArray[pdoExt->collectionIndex]);
  1212. pdoExt->state = COLLECTION_STATE_STOPPED;
  1213. if (ISPTR(pdoExt->StatusChangeFn)) {
  1214. pdoExt->StatusChangeFn(pdoExt->StatusChangeContext,
  1215. DeviceObjectStopped);
  1216. }
  1217. }
  1218. status = STATUS_SUCCESS;
  1219. break;
  1220. case IRP_MN_SURPRISE_REMOVAL:
  1221. case IRP_MN_QUERY_REMOVE_DEVICE:
  1222. DBGASSERT(((pdoExt->state == COLLECTION_STATE_RUNNING) ||
  1223. (pdoExt->state == COLLECTION_STATE_STOPPED)),
  1224. ("Pdo is neither stopped nor started, but is getting removed, state=%d",pdoExt->state),
  1225. FALSE)
  1226. pdoExt->prevState = pdoExt->state;
  1227. pdoExt->state = COLLECTION_STATE_REMOVING;
  1228. if ((pdoExt->prevState == COLLECTION_STATE_RUNNING)) {
  1229. /*
  1230. * Remove the symbolic link for this collection-PDO.
  1231. *
  1232. * NOTE: Do this BEFORE destroying the collection, because
  1233. * HidpDestroyCollection() may cause a client driver,
  1234. * whose pending read IRPs get cancelled when the collection
  1235. * is destroyed, to try to re-open the device.
  1236. * Deleting the symbolic link first eliminates this possibility.
  1237. */
  1238. HidpCreateSymbolicLink(pdoExt, pdoExt->collectionNum, FALSE, pdoExt->pdo);
  1239. }
  1240. if ((pdoExt->prevState == COLLECTION_STATE_RUNNING) ||
  1241. (pdoExt->prevState == COLLECTION_STATE_STOPPED)){
  1242. /*
  1243. * Flush all pending IO and deny any future io by setting
  1244. * the collection state to removing.
  1245. * Note: on NT, clients will receive the query remove
  1246. * first, but surprise removal must deny access to the
  1247. * device.
  1248. *
  1249. * NOTE: There is a hole here that results in a read being
  1250. * queued even though we've blocked everything.
  1251. * 1) Get read, check to see that our state is running
  1252. * or stopped in HidpIrpMajorRead.
  1253. * 2) Set state to COLLECTION_STATE_REMOVING and complete
  1254. * all reads here.
  1255. * 3) Enqueue read in HidpIrpMajorRead.
  1256. *
  1257. */
  1258. ULONG ctnIndx = pdoExt->collectionIndex;
  1259. PHIDCLASS_COLLECTION collection = &fdoExt->classCollectionArray[ctnIndx];
  1260. LIST_ENTRY dequeue, *entry;
  1261. PIRP irp;
  1262. DBGVERBOSE(("Got QUERY/SURPRISE REMOVE for collection; completing all pending reads. openCount=%d, pendingReads=%d.", pdoExt->openCount, collection->numPendingReads))
  1263. CompleteAllPendingReadsForCollection(collection);
  1264. DequeueAllPdoPowerDelayedIrps(pdoExt, &dequeue);
  1265. while (!IsListEmpty(&dequeue)) {
  1266. entry = RemoveHeadList(&dequeue);
  1267. irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  1268. irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  1269. IoCompleteRequest(irp, IO_NO_INCREMENT);
  1270. }
  1271. }
  1272. status = STATUS_SUCCESS;
  1273. break;
  1274. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1275. status = STATUS_SUCCESS;
  1276. DBGSTATE(pdoExt->state, COLLECTION_STATE_REMOVING, TRUE)
  1277. pdoExt->state = pdoExt->prevState;
  1278. if (pdoExt->state == COLLECTION_STATE_RUNNING) {
  1279. // Re-create the symbolic link, since we're no longer
  1280. // deleting the device.
  1281. HidpCreateSymbolicLink(pdoExt, pdoExt->collectionNum, TRUE, pdoExt->pdo);
  1282. }
  1283. break;
  1284. case IRP_MN_REMOVE_DEVICE:
  1285. /*
  1286. * REMOVE_DEVICE for the device-FDO should come after REMOVE_DEVICE for each
  1287. * of the collection-PDOs.
  1288. */
  1289. DBGASSERT((pdoExt->state == COLLECTION_STATE_UNINITIALIZED ||
  1290. pdoExt->state == COLLECTION_STATE_REMOVING),
  1291. ("On pnp remove, collection state is incorrect. Actual: %x", pdoExt->state),
  1292. TRUE)
  1293. HidpRemoveCollection(fdoExt, pdoExt, Irp);
  1294. if (ISPTR(pdoExt->StatusChangeFn)) {
  1295. pdoExt->StatusChangeFn(pdoExt->StatusChangeContext,
  1296. DeviceObjectRemoved);
  1297. }
  1298. if (!fdoExt->presentReported) {
  1299. if (ISPTR(pdoExt->name)){
  1300. RtlFreeUnicodeString(pdoExt->name);
  1301. ExFreePool(pdoExt->name);
  1302. pdoExt->name = BAD_POINTER;
  1303. }
  1304. deleteDevice = TRUE;
  1305. }
  1306. status = STATUS_SUCCESS; // Can't fail IRP_MN_REMOVE
  1307. break;
  1308. case IRP_MN_QUERY_CAPABILITIES:
  1309. status = HidpQueryCollectionCapabilities(pdoExt, Irp);
  1310. break;
  1311. case IRP_MN_QUERY_DEVICE_RELATIONS:
  1312. if (irpSp->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation){
  1313. /*
  1314. * Return a reference to this PDO
  1315. */
  1316. PDEVICE_RELATIONS devRel = ALLOCATEPOOL(PagedPool, sizeof(DEVICE_RELATIONS));
  1317. if (devRel){
  1318. /*
  1319. * Add a reference to the PDO, since CONFIGMG will free it.
  1320. */
  1321. ObReferenceObject(pdoExt->pdo);
  1322. devRel->Objects[0] = pdoExt->pdo;
  1323. devRel->Count = 1;
  1324. Irp->IoStatus.Information = (ULONG_PTR)devRel;
  1325. status = STATUS_SUCCESS;
  1326. }
  1327. else {
  1328. status = STATUS_INSUFFICIENT_RESOURCES;
  1329. }
  1330. }
  1331. else {
  1332. /*
  1333. * Fail this Irp by returning the default
  1334. * status (typically STATUS_NOT_SUPPORTED).
  1335. */
  1336. status = Irp->IoStatus.Status;
  1337. }
  1338. break;
  1339. case IRP_MN_QUERY_ID:
  1340. status = HidpQueryIdForClientPdo(HidDeviceExtension, Irp);
  1341. break;
  1342. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  1343. //
  1344. // Do not clear any flags that may have been set by drivers above
  1345. // the PDO
  1346. //
  1347. // Irp->IoStatus.Information = 0;
  1348. switch (pdoExt->state){
  1349. case DEVICE_STATE_START_FAILURE:
  1350. Irp->IoStatus.Information |= PNP_DEVICE_FAILED;
  1351. break;
  1352. case DEVICE_STATE_STOPPED:
  1353. Irp->IoStatus.Information |= PNP_DEVICE_DISABLED;
  1354. break;
  1355. case DEVICE_STATE_REMOVING:
  1356. case DEVICE_STATE_REMOVED:
  1357. Irp->IoStatus.Information |= PNP_DEVICE_REMOVED;
  1358. break;
  1359. }
  1360. status = STATUS_SUCCESS;
  1361. break;
  1362. case IRP_MN_QUERY_INTERFACE:
  1363. status = HidpQueryInterface(HidDeviceExtension, Irp);
  1364. break;
  1365. case IRP_MN_QUERY_BUS_INFORMATION:
  1366. {
  1367. PPNP_BUS_INFORMATION busInfo = (PPNP_BUS_INFORMATION) ALLOCATEPOOL(NonPagedPool, sizeof(PNP_BUS_INFORMATION));
  1368. if (busInfo) {
  1369. busInfo->BusTypeGuid = GUID_BUS_TYPE_HID;
  1370. busInfo->LegacyBusType = PNPBus;
  1371. busInfo->BusNumber = fdoExt->BusNumber;
  1372. Irp->IoStatus.Information = (ULONG_PTR) busInfo;
  1373. status = STATUS_SUCCESS;
  1374. } else {
  1375. status = STATUS_INSUFFICIENT_RESOURCES;
  1376. Irp->IoStatus.Information = 0;
  1377. }
  1378. }
  1379. break;
  1380. default:
  1381. /*
  1382. * In the default case for the collection-PDOs we complete the IRP
  1383. * without changing IoStatus.Status; we also return the preset IoStatus.Status.
  1384. * This allows an upper filter driver to set IoStatus.Status
  1385. * on the way down. In the absence of a filter driver,
  1386. * IoStatus.Status will be STATUS_NOT_SUPPORTED.
  1387. *
  1388. * In the default case for the FDO we send the Irp on and let
  1389. * the other drivers in the stack do their thing.
  1390. */
  1391. status = Irp->IoStatus.Status;
  1392. break;
  1393. }
  1394. /*
  1395. * If this is a call for a collection-PDO, we complete it ourselves here.
  1396. * Otherwise, we pass it to the minidriver stack for more processing.
  1397. */
  1398. ASSERT(status != NO_STATUS);
  1399. Irp->IoStatus.Status = status;
  1400. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1401. if (deleteDevice) {
  1402. /*
  1403. * Delete the client PDO.
  1404. * Don't touch the pdoExt after doing this.
  1405. */
  1406. ObDereferenceObject(pdoExt->pdo);
  1407. IoDeleteDevice(pdoExt->pdo);
  1408. }
  1409. DBG_LOG_PNP_IRP(Irp, minorFunction, TRUE, TRUE, status)
  1410. return status;
  1411. }
  1412. NTSTATUS HidpFdoPnp(
  1413. IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension,
  1414. IN OUT PIRP Irp
  1415. )
  1416. {
  1417. NTSTATUS status = NO_STATUS;
  1418. PIO_STACK_LOCATION irpSp;
  1419. FDO_EXTENSION *fdoExt;
  1420. BOOLEAN completeIrpHere = FALSE; // general rule
  1421. UCHAR minorFunction;
  1422. PAGED_CODE();
  1423. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1424. /*
  1425. * Keep these fields privately so that we have them
  1426. * after the IRP is completed and in case we delete
  1427. * the device extension on a REMOVE_DEVICE.
  1428. */
  1429. minorFunction = irpSp->MinorFunction;
  1430. DBG_LOG_PNP_IRP(Irp, minorFunction, FALSE, FALSE, 0)
  1431. fdoExt = &HidDeviceExtension->fdoExt;
  1432. switch (minorFunction){
  1433. case IRP_MN_START_DEVICE:
  1434. status = HidpStartDevice(HidDeviceExtension, Irp);
  1435. completeIrpHere = TRUE;
  1436. break;
  1437. case IRP_MN_QUERY_STOP_DEVICE:
  1438. /*
  1439. * We will pass this IRP down the driver stack.
  1440. * However, we need to change the default status
  1441. * from STATUS_NOT_SUPPORTED to STATUS_SUCCESS.
  1442. */
  1443. Irp->IoStatus.Status = STATUS_SUCCESS;
  1444. DBGSTATE(fdoExt->state, DEVICE_STATE_START_SUCCESS, FALSE)
  1445. fdoExt->prevState = fdoExt->state;
  1446. fdoExt->state = DEVICE_STATE_STOPPING;
  1447. break;
  1448. case IRP_MN_CANCEL_STOP_DEVICE:
  1449. /*
  1450. * We will pass this IRP down the driver stack.
  1451. * However, we need to change the default status
  1452. * from STATUS_NOT_SUPPORTED to STATUS_SUCCESS.
  1453. */
  1454. Irp->IoStatus.Status = STATUS_SUCCESS;
  1455. DBGSTATE(fdoExt->state, DEVICE_STATE_STOPPING, TRUE)
  1456. fdoExt->state = fdoExt->prevState;
  1457. break;
  1458. case IRP_MN_STOP_DEVICE:
  1459. DBGSTATE(fdoExt->state, DEVICE_STATE_STOPPING, TRUE)
  1460. if (fdoExt->prevState == DEVICE_STATE_START_SUCCESS){
  1461. /*
  1462. * While it is stopped, the host controller may not be able
  1463. * to complete IRPs. So cancel them before sending down the stop.
  1464. */
  1465. CancelAllPingPongIrps(fdoExt);
  1466. }
  1467. fdoExt->state = DEVICE_STATE_STOPPED;
  1468. IoCopyCurrentIrpStackLocationToNext(Irp);
  1469. status = HidpCallDriverSynchronous(fdoExt->fdo, Irp);
  1470. completeIrpHere = TRUE;
  1471. break;
  1472. case IRP_MN_SURPRISE_REMOVAL:
  1473. //
  1474. // On surprise removal, we should stop accessing the device.
  1475. // We do the same steps on IRP_MN_REMOVE_DEVICE for the query
  1476. // removal case. Don't bother doing it during query remove,
  1477. // itself, because we don't want to have to handle the
  1478. // cancel case. NOTE: We only get away with this because all
  1479. // of these steps can be repeated without dire consequences.
  1480. //
  1481. if (ISPTR(fdoExt->waitWakeIrp)){
  1482. IoCancelIrp(fdoExt->waitWakeIrp);
  1483. fdoExt->waitWakeIrp = BAD_POINTER;
  1484. }
  1485. HidpCancelIdleNotification(fdoExt, TRUE);
  1486. if (ISPTR(fdoExt->idleNotificationRequest)) {
  1487. IoFreeIrp(fdoExt->idleNotificationRequest);
  1488. fdoExt->idleNotificationRequest = BAD_POINTER;
  1489. }
  1490. DestroyPingPongs(fdoExt);
  1491. // fall thru to IRP_MN_QUERY_REMOVE_DEVICE
  1492. case IRP_MN_QUERY_REMOVE_DEVICE:
  1493. {
  1494. PIRP idleIrp;
  1495. while (idleIrp = DequeuePowerDelayedIrp(fdoExt)) {
  1496. idleIrp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  1497. IoCompleteRequest(idleIrp, IO_NO_INCREMENT);
  1498. }
  1499. }
  1500. /*
  1501. * We will pass this IRP down the driver stack.
  1502. * However, we need to change the default status
  1503. * from STATUS_NOT_SUPPORTED to STATUS_SUCCESS.
  1504. */
  1505. Irp->IoStatus.Status = STATUS_SUCCESS;
  1506. DBGSTATE(fdoExt->state, DEVICE_STATE_START_SUCCESS, FALSE)
  1507. DBGASSERT((fdoExt->state == DEVICE_STATE_START_SUCCESS ||
  1508. fdoExt->state == DEVICE_STATE_STOPPED),
  1509. ("Fdo is neither stopped nor started, but is getting removed, state=%d",fdoExt->state),
  1510. FALSE)
  1511. fdoExt->prevState = fdoExt->state;
  1512. fdoExt->state = DEVICE_STATE_REMOVING;
  1513. break;
  1514. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1515. /*
  1516. * We will pass this IRP down the driver stack.
  1517. * However, we need to change the default status
  1518. * from STATUS_NOT_SUPPORTED to STATUS_SUCCESS.
  1519. */
  1520. Irp->IoStatus.Status = STATUS_SUCCESS;
  1521. DBGSTATE(fdoExt->state, DEVICE_STATE_REMOVING, TRUE)
  1522. fdoExt->state = fdoExt->prevState;
  1523. break;
  1524. case IRP_MN_REMOVE_DEVICE:
  1525. /*
  1526. * REMOVE_DEVICE for the device-FDO should come after REMOVE_DEVICE
  1527. * for each of the collection-PDOs.
  1528. * Don't touch the device extension after this call.
  1529. */
  1530. DBGASSERT((fdoExt->state == DEVICE_STATE_REMOVING ||
  1531. fdoExt->state == DEVICE_STATE_START_FAILURE ||
  1532. fdoExt->state == DEVICE_STATE_INITIALIZED),
  1533. ("Incorrect device state: %x", fdoExt->state),
  1534. TRUE)
  1535. status = HidpRemoveDevice(fdoExt, Irp);
  1536. goto HidpFdoPnpDone;
  1537. break;
  1538. case IRP_MN_QUERY_DEVICE_RELATIONS:
  1539. if (irpSp->Parameters.QueryDeviceRelations.Type == BusRelations){
  1540. status = HidpQueryDeviceRelations(HidDeviceExtension, Irp);
  1541. if (NT_SUCCESS(status)){
  1542. /*
  1543. * Although we have satisfied this PnP IRP,
  1544. * we will still pass it down the stack.
  1545. * First change the default status to our status.
  1546. */
  1547. Irp->IoStatus.Status = status;
  1548. }
  1549. else {
  1550. completeIrpHere = TRUE;
  1551. }
  1552. }
  1553. break;
  1554. default:
  1555. /*
  1556. * In the default case for the collection-PDOs we complete the IRP
  1557. * without changing IoStatus.Status; we also return the preset IoStatus.Status.
  1558. * This allows an upper filter driver to set IoStatus.Status
  1559. * on the way down. In the absence of a filter driver,
  1560. * IoStatus.Status will be STATUS_NOT_SUPPORTED.
  1561. *
  1562. * In the default case for the FDO we send the Irp on and let
  1563. * the other drivers in the stack do their thing.
  1564. */
  1565. if (completeIrpHere){
  1566. status = Irp->IoStatus.Status;
  1567. }
  1568. break;
  1569. }
  1570. /*
  1571. * If this is a call for a collection-PDO, we complete it ourselves here.
  1572. * Otherwise, we pass it to the minidriver stack for more processing.
  1573. */
  1574. if (completeIrpHere){
  1575. ASSERT(status != NO_STATUS);
  1576. Irp->IoStatus.Status = status;
  1577. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1578. }
  1579. else {
  1580. /*
  1581. * Call the minidriver with this Irp.
  1582. * The rest of our processing will be done in our completion routine.
  1583. *
  1584. * Note: Don't touch the Irp after sending it down, since it may
  1585. * be completed immediately.
  1586. */
  1587. IoCopyCurrentIrpStackLocationToNext(Irp);
  1588. status = HidpCallDriver(fdoExt->fdo, Irp);
  1589. }
  1590. HidpFdoPnpDone:
  1591. DBG_LOG_PNP_IRP(Irp, minorFunction, FALSE, TRUE, status)
  1592. return status;
  1593. }