Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1997 lines
70 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. fdoExt->openCount--;
  297. openCount = fdoExt->openCount;
  298. if (fileExtension){
  299. PHIDCLASS_COLLECTION classCollection;
  300. ASSERT(fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG);
  301. /*
  302. * Get a pointer to the collection that our file extension is queued on.
  303. */
  304. classCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  305. if (classCollection){
  306. DBGVERBOSE((" HidpIrpMajorClose: closing collection w/ usagePage=%xh, usage=%xh.", fdoExt->deviceDesc.CollectionDesc[pdoExt->collectionIndex].UsagePage, fdoExt->deviceDesc.CollectionDesc[pdoExt->collectionIndex].Usage))
  307. if (fdoExt->state == DEVICE_STATE_REMOVED){
  308. KeAcquireSpinLock( &classCollection->FileExtensionListSpinLock, &oldIrql );
  309. RemoveEntryList(&fileExtension->FileList);
  310. KeReleaseSpinLock( &classCollection->FileExtensionListSpinLock, oldIrql );
  311. if (fileExtension->isSecureOpen) {
  312. KeAcquireSpinLock(&classCollection->secureReadLock,
  313. &oldIrql);
  314. while(fileExtension->SecureReadMode--) {
  315. classCollection->secureReadMode--;
  316. }
  317. KeReleaseSpinLock(&classCollection->secureReadLock,
  318. oldIrql);
  319. }
  320. HidpDestroyFileExtension(classCollection, fileExtension);
  321. classCollection = BAD_POINTER;
  322. /*
  323. * Delete the device-FDO and all collection-PDOs
  324. * Don't touch fdoExt after this.
  325. */
  326. HidpCleanUpFdo(fdoExt);
  327. result = STATUS_SUCCESS;
  328. }
  329. else {
  330. //
  331. // Destroy the file object and everything on it
  332. //
  333. KeAcquireSpinLock(&classCollection->FileExtensionListSpinLock, &oldIrql);
  334. /*
  335. * Update sharing information:
  336. * Decrement open counts and clear any exclusive holds of this file extension
  337. * on the device extension.
  338. */
  339. ASSERT(pdoExt->openCount > 0);
  340. pdoExt->openCount--;
  341. if (fileExtension->accessMask & FILE_READ_DATA){
  342. ASSERT(pdoExt->opensForRead > 0);
  343. pdoExt->opensForRead--;
  344. }
  345. if (fileExtension->accessMask & FILE_WRITE_DATA){
  346. ASSERT(pdoExt->opensForWrite > 0);
  347. pdoExt->opensForWrite--;
  348. }
  349. if (!(fileExtension->shareMask & FILE_SHARE_READ)){
  350. ASSERT(pdoExt->restrictionsForRead > 0);
  351. pdoExt->restrictionsForRead--;
  352. }
  353. if (!(fileExtension->shareMask & FILE_SHARE_WRITE)){
  354. ASSERT(pdoExt->restrictionsForWrite > 0);
  355. pdoExt->restrictionsForWrite--;
  356. }
  357. if (fileExtension->shareMask == 0){
  358. ASSERT(pdoExt->restrictionsForAnyOpen > 0);
  359. pdoExt->restrictionsForAnyOpen--;
  360. }
  361. RemoveEntryList(&fileExtension->FileList);
  362. KeReleaseSpinLock(&classCollection->FileExtensionListSpinLock, oldIrql);
  363. if (fileExtension->isSecureOpen) {
  364. KeAcquireSpinLock(&classCollection->secureReadLock,
  365. &oldIrql);
  366. while(fileExtension->SecureReadMode--) {
  367. classCollection->secureReadMode--;
  368. }
  369. KeReleaseSpinLock(&classCollection->secureReadLock,
  370. oldIrql);
  371. }
  372. HidpDestroyFileExtension(classCollection, fileExtension);
  373. result = STATUS_SUCCESS;
  374. }
  375. }
  376. else {
  377. result = STATUS_DATA_ERROR;
  378. }
  379. }
  380. else {
  381. TRAP;
  382. result = STATUS_DEVICE_NOT_CONNECTED;
  383. }
  384. DBGVERBOSE((" HidpIrpMajorClose: openCount decremented to %xh/%xh (pdo/fdo).", openCount, fdoExt->openCount))
  385. }
  386. else {
  387. 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'."))
  388. result = STATUS_INVALID_PARAMETER_1;
  389. }
  390. Irp->IoStatus.Status = result;
  391. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  392. DBGSUCCESS(result, FALSE)
  393. return result;
  394. }
  395. /*
  396. ********************************************************************************
  397. * HidpIrpMajorCreate
  398. ********************************************************************************
  399. *
  400. *
  401. * Routine Description:
  402. *
  403. * We connect up to the interrupt for the create/open and initialize
  404. * the structures needed to maintain an open for a device.
  405. *
  406. * Arguments:
  407. *
  408. * DeviceObject - Pointer to the device object for this device
  409. *
  410. * Irp - Pointer to the IRP for the current request
  411. *
  412. * Return Value:
  413. *
  414. * The function value is the final status of the call
  415. *
  416. */
  417. NTSTATUS HidpIrpMajorCreate(IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension, IN OUT PIRP Irp)
  418. {
  419. NTSTATUS status = STATUS_SUCCESS;
  420. ASSERT(HidDeviceExtension->Signature == HID_DEVICE_EXTENSION_SIG);
  421. if (HidDeviceExtension->isClientPdo){
  422. PDO_EXTENSION *pdoExt = &HidDeviceExtension->pdoExt;
  423. FDO_EXTENSION *fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  424. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  425. PHIDCLASS_COLLECTION classCollection;
  426. BOOLEAN secureOpen = FALSE;
  427. secureOpen = MyPrivilegeCheck(Irp);
  428. Irp->IoStatus.Information = 0;
  429. classCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  430. if (classCollection){
  431. BOOLEAN sharingOk = TRUE, allowReadPrivilege = TRUE;
  432. KIRQL oldIrql;
  433. // This is now taken care of by the fact that we don't
  434. // enumerate mouse and keyboard collections as RAW.
  435. #if 0
  436. /*
  437. * Do security check
  438. * (must be at passive level, so don't hold any spinlocks during this call)
  439. */
  440. if (pdoExt->MouseOrKeyboard &&
  441. !MyPrivilegeCheck(Irp)){
  442. /*
  443. * This is a user-level open on a keyboard or mouse.
  444. * Disallow reads even if we do allow the open.
  445. */
  446. allowReadPrivilege = FALSE;
  447. }
  448. #endif
  449. KeAcquireSpinLock(&classCollection->FileExtensionListSpinLock, &oldIrql);
  450. /*
  451. * Enforce exclusive-open independently for exclusive-read and exclusive-write.
  452. */
  453. ASSERT(irpSp->Parameters.Create.SecurityContext);
  454. DBGVERBOSE((" HidpIrpMajorCreate: DesiredAccess = %xh, ShareAccess = %xh.", (ULONG)irpSp->Parameters.Create.SecurityContext->DesiredAccess, (ULONG)irpSp->Parameters.Create.ShareAccess))
  455. DBGASSERT((irpSp->Parameters.Create.SecurityContext->DesiredAccess & (FILE_READ_DATA|FILE_WRITE_DATA)),
  456. ("Neither FILE_READ_DATA|FILE_WRITE_DATA requested in HidpIrpMajorCreate. DesiredAccess = %xh.", (ULONG)irpSp->Parameters.Create.SecurityContext->DesiredAccess),
  457. FALSE)
  458. if (pdoExt->restrictionsForAnyOpen){
  459. /*
  460. * Oops. A previous open requested exclusive access.
  461. * Not even a client that requests only ioctl access
  462. * (does not request read nor write acess) is
  463. * allowed.
  464. */
  465. DBGWARN(("HidpIrpMajorCreate failing open: previous open is non-shared (ShareAccess==0)."))
  466. sharingOk = FALSE;
  467. }
  468. else if (pdoExt->openCount &&
  469. (irpSp->Parameters.Create.ShareAccess == 0)){
  470. /*
  471. * Oops. This open does not allow any sharing
  472. * (not even with a client that has neither read nor write access),
  473. * but there exists a previous open.
  474. */
  475. DBGWARN(("HidpIrpMajorCreate failing open: requesting non-shared (ShareAccess==0) while previous open exists."))
  476. sharingOk = FALSE;
  477. }
  478. else if ((irpSp->Parameters.Create.SecurityContext->DesiredAccess & FILE_READ_DATA) &&
  479. pdoExt->restrictionsForRead){
  480. /*
  481. * Oops. A previous open requested exclusive-read access.
  482. */
  483. DBGWARN(("HidpIrpMajorCreate failing open: requesting read access while previous open does not share read access."))
  484. sharingOk = FALSE;
  485. }
  486. else if ((irpSp->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA) &&
  487. pdoExt->restrictionsForWrite){
  488. /*
  489. * Oops. A previous open requested exclusive-write access.
  490. */
  491. DBGWARN(("HidpIrpMajorCreate failing open: requesting write access while previous open does not share write access."))
  492. sharingOk = FALSE;
  493. }
  494. else if ((pdoExt->opensForRead > 0) &&
  495. !(irpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ)){
  496. /*
  497. * Oops. The caller is requesting exclusive read access, but the device
  498. * is already open for read.
  499. */
  500. DBGWARN(("HidpIrpMajorCreate failing open: this open request does not share read access; but collection already open for read."))
  501. sharingOk = FALSE;
  502. }
  503. else if ((pdoExt->opensForWrite > 0) &&
  504. !(irpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)){
  505. /*
  506. * Oops. The caller is requesting exclusive write access, but the device
  507. * is already open for write.
  508. */
  509. DBGWARN(("HidpIrpMajorCreate failing open: this open request does not share write access; but collection already open for write."))
  510. sharingOk = FALSE;
  511. }
  512. if (!sharingOk){
  513. DBGWARN(("HidpIrpMajorCreate failing IRP_MJ_CREATE with STATUS_SHARING_VIOLATION."))
  514. status = STATUS_SHARING_VIOLATION;
  515. }
  516. else if (!allowReadPrivilege &&
  517. (irpSp->Parameters.Create.SecurityContext->DesiredAccess & FILE_READ_DATA)){
  518. DBGWARN(("HidpIrpMajorCreate failing open: user-mode client requesting read privilege on kb/mouse."))
  519. status = STATUS_ACCESS_DENIED;
  520. }
  521. else {
  522. if (irpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE){
  523. /*
  524. * Attempt to open this device as a directory
  525. */
  526. status = STATUS_NOT_A_DIRECTORY;
  527. } else {
  528. /*
  529. * Make sure the device is started.
  530. * If it is temporarily stopped, we also succeed because a stop
  531. * is supposed to be transparent to the client.
  532. */
  533. if (((fdoExt->state == DEVICE_STATE_START_SUCCESS) ||
  534. (fdoExt->state == DEVICE_STATE_STOPPING) ||
  535. (fdoExt->state == DEVICE_STATE_STOPPED))
  536. &&
  537. ((pdoExt->state == COLLECTION_STATE_RUNNING) ||
  538. (pdoExt->state == COLLECTION_STATE_STOPPING) ||
  539. (pdoExt->state == COLLECTION_STATE_STOPPED))){
  540. PHIDCLASS_FILE_EXTENSION fileExtension;
  541. /*
  542. * We have a valid collection.
  543. * Allocate a file object extension (which encapsulates an 'open' on the device).
  544. */
  545. fileExtension = ALLOCATEPOOL(NonPagedPool, sizeof(HIDCLASS_FILE_EXTENSION));
  546. if (fileExtension){
  547. PHIDP_COLLECTION_DESC hidCollectionDesc;
  548. RtlZeroMemory(fileExtension, sizeof(HIDCLASS_FILE_EXTENSION));
  549. fileExtension->CollectionNumber = pdoExt->collectionNum;
  550. fileExtension->fdoExt = fdoExt;
  551. fileExtension->FileObject = irpSp->FileObject;
  552. fileExtension->isOpportunisticPolledDeviceReader = FALSE;
  553. fileExtension->nowCompletingIrpForOpportunisticReader = 0;
  554. fileExtension->BlueScreenData.BluescreenFunction = NULL;
  555. InitializeListHead( &fileExtension->ReportList );
  556. InitializeListHead( &fileExtension->PendingIrpList );
  557. KeInitializeSpinLock( &fileExtension->ListSpinLock );
  558. fileExtension->Closing = FALSE;
  559. //
  560. // Right now we'll set a default maximum input report queue size.
  561. // This can be changed later with an IOCTL.
  562. //
  563. fileExtension->CurrentInputReportQueueSize = 0;
  564. fileExtension->MaximumInputReportQueueSize = DEFAULT_INPUT_REPORT_QUEUE_SIZE;
  565. fileExtension->insideReadCompleteCount = 0;
  566. //
  567. // Add this file extension to the list of file extensions for this
  568. // collection.
  569. //
  570. InsertHeadList(&classCollection->FileExtensionList, &fileExtension->FileList);
  571. #if DBG
  572. fileExtension->Signature = HIDCLASS_FILE_EXTENSION_SIG;
  573. #endif
  574. /*
  575. * Store the file-open attribute flags.
  576. */
  577. fileExtension->FileAttributes = irpSp->Parameters.Create.FileAttributes;
  578. fileExtension->accessMask = irpSp->Parameters.Create.SecurityContext->DesiredAccess;
  579. fileExtension->shareMask = irpSp->Parameters.Create.ShareAccess;
  580. //
  581. // Set up secure read mode
  582. //
  583. fileExtension->SecureReadMode = 0;
  584. fileExtension->isSecureOpen = secureOpen;
  585. /*
  586. * Store a pointer to our file extension in the file object.
  587. */
  588. irpSp->FileObject->FsContext = fileExtension;
  589. //
  590. // KENRAY
  591. // Only drivers can set the FsContext of file
  592. // objects so this is not a security problem.
  593. // However, there is only one file object for the entire
  594. // PDO stack. This means we have to share. You cannot
  595. // have both context pointers. I need one for the
  596. // keyboard and mouse class drivers.
  597. //
  598. // This information need go into the fileExtension.
  599. //
  600. fileExtension->SecurityCheck = TRUE;
  601. //
  602. // If this is a user-level open on a keyboard or
  603. // mouse, then we will let the client do anything
  604. // except read the device.
  605. //
  606. DBGASSERT(allowReadPrivilege,
  607. ("User-level open on keyboard or mouse. Reads will be disallowed."),
  608. FALSE)
  609. fileExtension->haveReadPrivilege = allowReadPrivilege;
  610. /*
  611. * Increment the device extension's open counts,
  612. * and set the exclusive-access fields.
  613. */
  614. fdoExt->openCount++;
  615. pdoExt->openCount++;
  616. if (irpSp->Parameters.Create.SecurityContext->DesiredAccess & FILE_READ_DATA){
  617. pdoExt->opensForRead++;
  618. }
  619. if (irpSp->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA){
  620. pdoExt->opensForWrite++;
  621. }
  622. /*
  623. * NOTE: Restrictions are independent of desired access.
  624. * For example, a client can do an open-for-read-only
  625. * AND prevent other clients from doing an open-for-write
  626. * (by not setting the FILE_SHARE_WRITE flag).
  627. */
  628. if (!(irpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ)){
  629. pdoExt->restrictionsForRead++;
  630. }
  631. if (!(irpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)){
  632. pdoExt->restrictionsForWrite++;
  633. }
  634. if (irpSp->Parameters.Create.ShareAccess == 0){
  635. /*
  636. * ShareAccess==0 means that no other opens of any kind
  637. * are allowed.
  638. */
  639. pdoExt->restrictionsForAnyOpen++;
  640. }
  641. 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))
  642. } else {
  643. status = STATUS_INSUFFICIENT_RESOURCES;
  644. }
  645. } else {
  646. status = STATUS_DEVICE_NOT_CONNECTED;
  647. }
  648. }
  649. }
  650. KeReleaseSpinLock(&classCollection->FileExtensionListSpinLock, oldIrql);
  651. }
  652. else {
  653. DBGERR(("HidpIrpMajorCreate failing -- couldn't find collection"))
  654. status = STATUS_DEVICE_NOT_CONNECTED;
  655. }
  656. }
  657. else {
  658. /*
  659. * We don't support opens on the device itself,
  660. * only on the collections.
  661. */
  662. DBGWARN(("HidpIrpMajorCreate failing -- we don't support opens on the device itself; only on collections."))
  663. status = STATUS_UNSUCCESSFUL;
  664. }
  665. Irp->IoStatus.Status = status;
  666. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  667. DBGSUCCESS(status, FALSE)
  668. return status;
  669. }
  670. /*
  671. ********************************************************************************
  672. * HidpIrpMajorDeviceControl
  673. ********************************************************************************
  674. *
  675. * Note: This function cannot be pageable because IOCTLs
  676. * can get sent at DISPATCH_LEVEL.
  677. *
  678. */
  679. NTSTATUS HidpIrpMajorDeviceControl(IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension, IN OUT PIRP Irp)
  680. {
  681. NTSTATUS status;
  682. BOOLEAN completeIrpHere = TRUE;
  683. PDO_EXTENSION *pdoExt;
  684. FDO_EXTENSION *fdoExt;
  685. ULONG ioControlCode;
  686. PIO_STACK_LOCATION irpSp;
  687. PHIDCLASS_COLLECTION hidCollection;
  688. PHIDCLASS_FILE_EXTENSION fileExtension;
  689. PFILE_OBJECT fileObject;
  690. KIRQL irql;
  691. if (!HidDeviceExtension->isClientPdo){
  692. ASSERT(HidDeviceExtension->isClientPdo);
  693. status = STATUS_INVALID_PARAMETER_1;
  694. goto HidpIrpMajorDeviceControlDone;
  695. }
  696. pdoExt = &HidDeviceExtension->pdoExt;
  697. fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  698. if (fdoExt->state != DEVICE_STATE_START_SUCCESS ||
  699. pdoExt->state != COLLECTION_STATE_RUNNING) {
  700. DBGSTATE (pdoExt->state, COLLECTION_STATE_RUNNING, FALSE)
  701. status = STATUS_DEVICE_NOT_CONNECTED;
  702. goto HidpIrpMajorDeviceControlDone;
  703. }
  704. irpSp = IoGetCurrentIrpStackLocation(Irp);
  705. // Keep this privately so we still have it after the IRP is completed.
  706. ioControlCode = irpSp->Parameters.DeviceIoControl.IoControlCode;
  707. Irp->IoStatus.Information = 0;
  708. status = HidpCheckIdleState(HidDeviceExtension, Irp);
  709. if (status != STATUS_SUCCESS) {
  710. completeIrpHere = (status != STATUS_PENDING);
  711. goto HidpIrpMajorDeviceControlDone;
  712. }
  713. switch (ioControlCode){
  714. case IOCTL_HID_GET_DRIVER_CONFIG:
  715. TRAP;
  716. status = STATUS_NOT_IMPLEMENTED;
  717. break;
  718. case IOCTL_HID_SET_DRIVER_CONFIG:
  719. TRAP;
  720. status = STATUS_NOT_IMPLEMENTED;
  721. break;
  722. case IOCTL_HID_GET_COLLECTION_INFORMATION:
  723. /*
  724. * This IRP is METHOD_BUFFERED, so the buffer
  725. * is in the AssociatedIrp.
  726. */
  727. DBGASSERT((Irp->Flags & IRP_BUFFERED_IO),
  728. ("Irp->Flags & IRP_BUFFERED_IO Irp->Type != IO_TYPE_IRP, Irp->Type == %x", Irp->Type),
  729. FALSE)
  730. if (Irp->AssociatedIrp.SystemBuffer){
  731. ULONG bufLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  732. status = HidpGetCollectionInformation(
  733. fdoExt,
  734. pdoExt->collectionNum,
  735. Irp->AssociatedIrp.SystemBuffer,
  736. &bufLen);
  737. Irp->IoStatus.Information = bufLen;
  738. }
  739. else {
  740. ASSERT(Irp->AssociatedIrp.SystemBuffer);
  741. status = STATUS_INVALID_PARAMETER;
  742. }
  743. break;
  744. case IOCTL_HID_GET_COLLECTION_DESCRIPTOR:
  745. /*
  746. * This IOCTL is METHOD_NEITHER, so the buffer is in UserBuffer.
  747. */
  748. if (Irp->UserBuffer){
  749. __try {
  750. ULONG bufLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  751. if (Irp->RequestorMode != KernelMode){
  752. /*
  753. * Ensure user-mode buffer is legal.
  754. */
  755. ProbeForWrite(Irp->UserBuffer, bufLen, sizeof(UCHAR));
  756. }
  757. status = HidpGetCollectionDescriptor(
  758. fdoExt,
  759. pdoExt->collectionNum,
  760. Irp->UserBuffer,
  761. &bufLen);
  762. Irp->IoStatus.Information = bufLen;
  763. }
  764. __except(EXCEPTION_EXECUTE_HANDLER) {
  765. TRAP;
  766. status = GetExceptionCode();
  767. }
  768. }
  769. else {
  770. ASSERT(Irp->UserBuffer);
  771. status = STATUS_INVALID_BUFFER_SIZE;
  772. }
  773. break;
  774. case IOCTL_HID_FLUSH_QUEUE:
  775. //
  776. // Run the list of report descriptors hanging off of this
  777. // file object and free them all.
  778. //
  779. fileObject = irpSp->FileObject;
  780. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  781. if(!fileExtension) {
  782. DBGWARN(("Attempted to flush queue with no file extension"))
  783. status = STATUS_PRIVILEGE_NOT_HELD;
  784. break;
  785. }
  786. ASSERT(fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG);
  787. HidpFlushReportQueue(fileExtension);
  788. status = STATUS_SUCCESS;
  789. break;
  790. case IOCTL_HID_GET_POLL_FREQUENCY_MSEC:
  791. hidCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  792. if (hidCollection && hidCollection->hidCollectionInfo.Polled){
  793. /*
  794. * Get the current poll frequency.
  795. * This IOCTL is METHOD_BUFFERED, so the result goes in the AssociatedIrp.
  796. */
  797. DBGASSERT((Irp->Flags & IRP_BUFFERED_IO),
  798. ("Irp->Flags & IRP_BUFFERED_IO Irp->Type != IO_TYPE_IRP, Irp->Type == %x", Irp->Type),
  799. FALSE)
  800. if (Irp->AssociatedIrp.SystemBuffer &&
  801. (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ULONG))){
  802. *(ULONG *)Irp->AssociatedIrp.SystemBuffer = hidCollection->PollInterval_msec;
  803. Irp->IoStatus.Information = sizeof (ULONG);
  804. status = STATUS_SUCCESS;
  805. }
  806. else {
  807. ASSERT(!"Bad SystemBuffer for IOCTL_HID_GET_POLL_FREQUENCY_MSEC.");
  808. status = STATUS_INVALID_BUFFER_SIZE;
  809. }
  810. }
  811. else {
  812. status = STATUS_INVALID_DEVICE_REQUEST;
  813. }
  814. break;
  815. case IOCTL_HID_SET_POLL_FREQUENCY_MSEC:
  816. hidCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  817. if (hidCollection && hidCollection->hidCollectionInfo.Polled){
  818. if (Irp->AssociatedIrp.SystemBuffer &&
  819. (irpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(ULONG))){
  820. ULONG newPollInterval = *(ULONG *)Irp->AssociatedIrp.SystemBuffer;
  821. fileObject = irpSp->FileObject;
  822. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  823. if(!fileExtension) {
  824. DBGWARN(("Attempted to set poll frequency with no file extension"))
  825. status = STATUS_PRIVILEGE_NOT_HELD;
  826. break;
  827. }
  828. ASSERT(fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG);
  829. if (newPollInterval == 0){
  830. /*
  831. * Poll interval zero means that this client will
  832. * be doing irregular, opportunistic reads on the
  833. * polled device. We will not change the polling
  834. * frequency of the device. But when this client
  835. * does a read, we will immediately complete that read
  836. * with either the last report for this collection
  837. * (if the data is not stale) or by immediately issuing
  838. * a new read.
  839. */
  840. fileExtension->isOpportunisticPolledDeviceReader = TRUE;
  841. }
  842. else {
  843. /*
  844. * Set the poll frequency AND tell the user what we really set it to
  845. * in case it's out of range.
  846. */
  847. if (newPollInterval < MIN_POLL_INTERVAL_MSEC){
  848. newPollInterval = MIN_POLL_INTERVAL_MSEC;
  849. }
  850. else if (newPollInterval > MAX_POLL_INTERVAL_MSEC){
  851. newPollInterval = MAX_POLL_INTERVAL_MSEC;
  852. }
  853. hidCollection->PollInterval_msec = newPollInterval;
  854. /*
  855. * If this client was an 'opportunistic' reader before,
  856. * he's not anymore.
  857. */
  858. fileExtension->isOpportunisticPolledDeviceReader = FALSE;
  859. /*
  860. * Stop and re-start the polling loop so that
  861. * the new polling interval takes effect right away.
  862. */
  863. StopPollingLoop(hidCollection, FALSE);
  864. StartPollingLoop(fdoExt, hidCollection, FALSE);
  865. }
  866. status = STATUS_SUCCESS;
  867. }
  868. else {
  869. ASSERT(!"Bad SystemBuffer for IOCTL_HID_SET_POLL_FREQUENCY_MSEC.");
  870. status = STATUS_INVALID_BUFFER_SIZE;
  871. }
  872. }
  873. else {
  874. status = STATUS_INVALID_DEVICE_REQUEST;
  875. }
  876. break;
  877. case IOCTL_HID_GET_FEATURE:
  878. case IOCTL_HID_SET_FEATURE:
  879. #if 0
  880. {
  881. BOOLEAN sentIrpToMinidriver;
  882. status = HidpGetSetFeature( HidDeviceExtension,
  883. Irp,
  884. irpSp->Parameters.DeviceIoControl.IoControlCode,
  885. &sentIrpToMinidriver);
  886. /*
  887. * If we just passed this Irp to the minidriver, we don't want to
  888. * complete the Irp; we're not even allowed to touch it since it may
  889. * have already completed.
  890. */
  891. completeIrpHere = !sentIrpToMinidriver;
  892. }
  893. break;
  894. #endif
  895. case IOCTL_HID_GET_INPUT_REPORT:
  896. case IOCTL_HID_SET_OUTPUT_REPORT:
  897. {
  898. BOOLEAN sentIrpToMinidriver;
  899. status = HidpGetSetReport ( HidDeviceExtension,
  900. Irp,
  901. irpSp->Parameters.DeviceIoControl.IoControlCode,
  902. &sentIrpToMinidriver);
  903. /*
  904. * If we just passed this Irp to the minidriver, we don't want to
  905. * complete the Irp; we're not even allowed to touch it since it may
  906. * have already completed.
  907. */
  908. completeIrpHere = !sentIrpToMinidriver;
  909. }
  910. break;
  911. // NOTE - we currently only support English (langId=0x0409).
  912. // route all collection-PDO string requests to device-FDO.
  913. case IOCTL_HID_GET_MANUFACTURER_STRING:
  914. status = HidpGetDeviceString(fdoExt, Irp, HID_STRING_ID_IMANUFACTURER, 0x0409);
  915. completeIrpHere = FALSE;
  916. break;
  917. case IOCTL_HID_GET_PRODUCT_STRING:
  918. status = HidpGetDeviceString(fdoExt, Irp, HID_STRING_ID_IPRODUCT, 0x0409);
  919. completeIrpHere = FALSE;
  920. break;
  921. case IOCTL_HID_GET_SERIALNUMBER_STRING:
  922. status = HidpGetDeviceString(fdoExt, Irp, HID_STRING_ID_ISERIALNUMBER, 0x0409);
  923. completeIrpHere = FALSE;
  924. break;
  925. case IOCTL_HID_GET_INDEXED_STRING:
  926. /*
  927. * This IRP is METHOD_OUT_DIRECT, so the buffer is in the MDL.
  928. * The second argument (string index) is in the AssociatedIrp;
  929. * the InputBufferLength is the length of this second buffer.
  930. */
  931. if (Irp->AssociatedIrp.SystemBuffer &&
  932. (irpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(ULONG))){
  933. ULONG stringIndex = *(ULONG *)Irp->AssociatedIrp.SystemBuffer;
  934. status = HidpGetIndexedString(fdoExt, Irp, stringIndex, 0x409);
  935. completeIrpHere = FALSE;
  936. }
  937. else {
  938. ASSERT(Irp->AssociatedIrp.SystemBuffer);
  939. status = STATUS_INVALID_PARAMETER;
  940. }
  941. break;
  942. case IOCTL_HID_GET_MS_GENRE_DESCRIPTOR:
  943. /*
  944. * This IRP is METHOD_OUT_DIRECT, so the buffer is in the MDL.
  945. */
  946. status = HidpGetMsGenreDescriptor(fdoExt, Irp);
  947. completeIrpHere = FALSE;
  948. break;
  949. case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS:
  950. /*
  951. * This IRP is METHOD_BUFFERED, so the buffer
  952. * is in the AssociatedIrp.SystemBuffer field.
  953. */
  954. DBGASSERT((Irp->Flags & IRP_BUFFERED_IO),
  955. ("Irp->Flags & IRP_BUFFERED_IO Irp->Type != IO_TYPE_IRP, Irp->Type == %x", Irp->Type),
  956. FALSE)
  957. if (Irp->AssociatedIrp.SystemBuffer &&
  958. (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ULONG))){
  959. fileObject = irpSp->FileObject;
  960. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  961. if(!fileExtension) {
  962. DBGWARN(("Attempted to get number of input buffers with no file extension"))
  963. status = STATUS_PRIVILEGE_NOT_HELD;
  964. break;
  965. }
  966. ASSERT( fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG );
  967. *(ULONG *)Irp->AssociatedIrp.SystemBuffer =
  968. fileExtension->MaximumInputReportQueueSize;
  969. Irp->IoStatus.Information = sizeof(ULONG);
  970. status = STATUS_SUCCESS;
  971. }
  972. else {
  973. ASSERT(Irp->AssociatedIrp.SystemBuffer);
  974. status = STATUS_INVALID_PARAMETER;
  975. }
  976. break;
  977. case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS:
  978. /*
  979. * This IRP is METHOD_BUFFERED, so the buffer
  980. * is in the AssociatedIrp.SystemBuffer field.
  981. */
  982. DBGASSERT((Irp->Flags & IRP_BUFFERED_IO),
  983. ("Irp->Flags & IRP_BUFFERED_IO Irp->Type != IO_TYPE_IRP, Irp->Type == %x", Irp->Type),
  984. FALSE)
  985. if (Irp->AssociatedIrp.SystemBuffer &&
  986. (irpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(ULONG))){
  987. ULONG newValue = *(ULONG *)Irp->AssociatedIrp.SystemBuffer;
  988. fileObject = irpSp->FileObject;
  989. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  990. if(!fileExtension) {
  991. DBGWARN(("Attempted to set number of input buffers with no file extension"))
  992. status = STATUS_PRIVILEGE_NOT_HELD;
  993. break;
  994. }
  995. ASSERT( fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG );
  996. if ((newValue >= MIN_INPUT_REPORT_QUEUE_SIZE) &&
  997. (newValue <= MAX_INPUT_REPORT_QUEUE_SIZE)){
  998. fileExtension->MaximumInputReportQueueSize = newValue;
  999. status = STATUS_SUCCESS;
  1000. }
  1001. else {
  1002. status = STATUS_INVALID_PARAMETER;
  1003. }
  1004. }
  1005. else {
  1006. ASSERT(Irp->AssociatedIrp.SystemBuffer);
  1007. status = STATUS_INVALID_PARAMETER;
  1008. }
  1009. break;
  1010. case IOCTL_GET_PHYSICAL_DESCRIPTOR:
  1011. status = HidpGetPhysicalDescriptor(HidDeviceExtension, Irp);
  1012. completeIrpHere = FALSE;
  1013. break;
  1014. case IOCTL_HID_GET_HARDWARE_ID:
  1015. {
  1016. PDEVICE_OBJECT pdo = pdoExt->deviceFdoExt->hidExt.PhysicalDeviceObject;
  1017. ULONG bufLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  1018. PWSTR hwIdBuf;
  1019. hwIdBuf = HidpGetSystemAddressForMdlSafe(Irp->MdlAddress);
  1020. if (hwIdBuf && bufLen){
  1021. ULONG actualLen;
  1022. status = IoGetDeviceProperty( pdo,
  1023. DevicePropertyHardwareID,
  1024. bufLen,
  1025. hwIdBuf,
  1026. &actualLen);
  1027. if (NT_SUCCESS(status)){
  1028. Irp->IoStatus.Information = (ULONG)actualLen;
  1029. }
  1030. }
  1031. else {
  1032. status = STATUS_INVALID_USER_BUFFER;
  1033. }
  1034. }
  1035. break;
  1036. case IOCTL_GET_SYS_BUTTON_CAPS:
  1037. hidCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  1038. if (hidCollection){
  1039. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ULONG)){
  1040. ULONG buttonCaps;
  1041. status = HidP_SysPowerCaps(hidCollection->phidDescriptor, &buttonCaps);
  1042. if (NT_SUCCESS(status)){
  1043. *(PULONG)Irp->AssociatedIrp.SystemBuffer = buttonCaps;
  1044. Irp->IoStatus.Information = sizeof(ULONG);
  1045. }
  1046. }
  1047. else {
  1048. status = STATUS_INVALID_BUFFER_SIZE;
  1049. Irp->IoStatus.Information = sizeof(ULONG);
  1050. }
  1051. }
  1052. else {
  1053. status = STATUS_DEVICE_NOT_CONNECTED;
  1054. }
  1055. break;
  1056. case IOCTL_GET_SYS_BUTTON_EVENT:
  1057. /*
  1058. * Hold onto this IRP and complete it when a power event occurs.
  1059. */
  1060. hidCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  1061. if (hidCollection){
  1062. status = QueuePowerEventIrp(hidCollection, Irp);
  1063. if (status == STATUS_PENDING){
  1064. completeIrpHere = FALSE;
  1065. }
  1066. }
  1067. else {
  1068. status = STATUS_DEVICE_NOT_CONNECTED;
  1069. }
  1070. break;
  1071. case IOCTL_HID_ENABLE_SECURE_READ:
  1072. fileObject = irpSp->FileObject;
  1073. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  1074. if(!fileExtension) {
  1075. DBGWARN(("Attempted to get number of input buffers with no file extension"))
  1076. status = STATUS_PRIVILEGE_NOT_HELD;
  1077. break;
  1078. }
  1079. ASSERT( fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG );
  1080. hidCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  1081. if (!fileExtension->isSecureOpen) {
  1082. status = STATUS_PRIVILEGE_NOT_HELD;
  1083. break;
  1084. }
  1085. KeAcquireSpinLock(&hidCollection->secureReadLock,
  1086. &irql);
  1087. fileExtension->SecureReadMode++;
  1088. hidCollection->secureReadMode++;
  1089. KeReleaseSpinLock(&hidCollection->secureReadLock,
  1090. irql);
  1091. break;
  1092. case IOCTL_HID_DISABLE_SECURE_READ:
  1093. fileObject = irpSp->FileObject;
  1094. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  1095. if(!fileExtension) {
  1096. DBGWARN(("Attempted to get number of input buffers with no file extension"))
  1097. status = STATUS_PRIVILEGE_NOT_HELD;
  1098. break;
  1099. }
  1100. ASSERT( fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG );
  1101. hidCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  1102. if (!fileExtension->isSecureOpen) {
  1103. status = STATUS_PRIVILEGE_NOT_HELD;
  1104. break;
  1105. }
  1106. KeAcquireSpinLock(&hidCollection->secureReadLock,
  1107. &irql);
  1108. if (fileExtension->SecureReadMode > 0) {
  1109. fileExtension->SecureReadMode--;
  1110. hidCollection->secureReadMode--;
  1111. }
  1112. KeReleaseSpinLock(&hidCollection->secureReadLock,
  1113. irql);
  1114. break;
  1115. default:
  1116. /*
  1117. * 'Fail' the Irp by returning the default status.
  1118. */
  1119. TRAP;
  1120. status = Irp->IoStatus.Status;
  1121. break;
  1122. }
  1123. DBG_LOG_IOCTL(fdoExt->fdo, ioControlCode, status)
  1124. HidpIrpMajorDeviceControlDone:
  1125. /*
  1126. * If we did not pass the Irp down to a lower driver, complete it here.
  1127. */
  1128. if (completeIrpHere){
  1129. Irp->IoStatus.Status = status;
  1130. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1131. }
  1132. DBGSUCCESS(status, FALSE)
  1133. return status;
  1134. }
  1135. /*
  1136. ********************************************************************************
  1137. * HidpIrpMajorINTERNALDeviceControl
  1138. ********************************************************************************
  1139. *
  1140. * Note: This function cannot be pageable because IOCTLs
  1141. * can get sent at DISPATCH_LEVEL.
  1142. *
  1143. */
  1144. NTSTATUS HidpIrpMajorINTERNALDeviceControl(IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension, IN OUT PIRP Irp)
  1145. {
  1146. NTSTATUS status;
  1147. if (HidDeviceExtension->isClientPdo){
  1148. PDO_EXTENSION *pdoExt = &HidDeviceExtension->pdoExt;
  1149. FDO_EXTENSION *fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  1150. Irp->IoStatus.Information = 0;
  1151. //
  1152. // If we ever support any other internal IOCTLs that are real and
  1153. // require touching the hardware, then we need to break out the check
  1154. // for fdoExt->devicePowerState and enqueue the irp until we get to full
  1155. // power
  1156. //
  1157. if (fdoExt->state == DEVICE_STATE_START_SUCCESS) {
  1158. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  1159. switch (irpSp->Parameters.DeviceIoControl.IoControlCode){
  1160. case IOCTL_INTERNAL_HID_SET_BLUESCREEN:
  1161. /*
  1162. * Memphis code to handle keyboards during blue screen event
  1163. */
  1164. if (Irp->AssociatedIrp.SystemBuffer){
  1165. PFILE_OBJECT fileObject = irpSp->FileObject;
  1166. PHIDCLASS_FILE_EXTENSION fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  1167. if(!fileExtension) {
  1168. DBGWARN(("Attempted to set blue screen data with no file extension"))
  1169. status = STATUS_PRIVILEGE_NOT_HELD;
  1170. } else {
  1171. ASSERT( fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG );
  1172. ASSERT(irpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof(BLUESCREEN));
  1173. fileExtension->BlueScreenData = *((PBLUESCREEN)Irp->AssociatedIrp.SystemBuffer);
  1174. status = STATUS_SUCCESS;
  1175. }
  1176. }
  1177. else {
  1178. ASSERT(Irp->AssociatedIrp.SystemBuffer);
  1179. status = STATUS_INVALID_PARAMETER;
  1180. }
  1181. break;
  1182. default:
  1183. /*
  1184. * 'Fail' the Irp by returning the default status.
  1185. */
  1186. DBGWARN(("HidpIrpMajorINTERNALDeviceControl - unsupported IOCTL %xh ", (ULONG)irpSp->Parameters.DeviceIoControl.IoControlCode))
  1187. status = Irp->IoStatus.Status;
  1188. break;
  1189. }
  1190. }
  1191. else {
  1192. status = STATUS_DEVICE_NOT_CONNECTED;
  1193. }
  1194. }
  1195. else {
  1196. ASSERT(HidDeviceExtension->isClientPdo);
  1197. status = STATUS_INVALID_PARAMETER_1;
  1198. }
  1199. Irp->IoStatus.Status = status;
  1200. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1201. DBGSUCCESS(status, FALSE)
  1202. return status;
  1203. }
  1204. /*
  1205. ********************************************************************************
  1206. * HidpIrpMajorPnp
  1207. ********************************************************************************
  1208. *
  1209. *
  1210. */
  1211. NTSTATUS HidpIrpMajorPnp(IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension, IN OUT PIRP Irp)
  1212. {
  1213. NTSTATUS status;
  1214. PIO_STACK_LOCATION irpSp;
  1215. BOOLEAN completeIrpHere;
  1216. BOOLEAN isClientPdo;
  1217. UCHAR minorFunction;
  1218. PAGED_CODE();
  1219. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1220. /*
  1221. * Keep these fields privately so that we have them
  1222. * after the IRP is completed and in case we delete
  1223. * the device extension on a REMOVE_DEVICE.
  1224. */
  1225. isClientPdo = HidDeviceExtension->isClientPdo;
  1226. minorFunction = irpSp->MinorFunction;
  1227. DBG_LOG_PNP_IRP(Irp, minorFunction, isClientPdo, FALSE, 0)
  1228. if (isClientPdo) {
  1229. status = HidpPdoPnp(HidDeviceExtension, Irp);
  1230. } else {
  1231. status = HidpFdoPnp(HidDeviceExtension, Irp);
  1232. }
  1233. DBG_LOG_PNP_IRP(Irp, minorFunction, isClientPdo, TRUE, status)
  1234. return status;
  1235. }
  1236. NTSTATUS HidpPdoPnp(
  1237. IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension,
  1238. IN OUT PIRP Irp
  1239. )
  1240. {
  1241. NTSTATUS status = NO_STATUS;
  1242. PIO_STACK_LOCATION irpSp;
  1243. FDO_EXTENSION *fdoExt;
  1244. PDO_EXTENSION *pdoExt;
  1245. UCHAR minorFunction;
  1246. PAGED_CODE();
  1247. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1248. /*
  1249. * Keep these fields privately so that we have them
  1250. * after the IRP is completed and in case we delete
  1251. * the device extension on a REMOVE_DEVICE.
  1252. */
  1253. minorFunction = irpSp->MinorFunction;
  1254. DBG_LOG_PNP_IRP(Irp, minorFunction, TRUE, FALSE, 0)
  1255. pdoExt = &HidDeviceExtension->pdoExt;
  1256. fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  1257. switch (minorFunction){
  1258. case IRP_MN_START_DEVICE:
  1259. status = HidpStartCollectionPDO(fdoExt, pdoExt, Irp);
  1260. if (NT_SUCCESS(status) &&
  1261. ISPTR(pdoExt->StatusChangeFn)) {
  1262. pdoExt->StatusChangeFn(pdoExt->StatusChangeContext,
  1263. DeviceObjectStarted);
  1264. }
  1265. break;
  1266. case IRP_MN_QUERY_STOP_DEVICE:
  1267. DBGSTATE(pdoExt->state, COLLECTION_STATE_RUNNING, FALSE)
  1268. pdoExt->prevState = pdoExt->state;
  1269. pdoExt->state = COLLECTION_STATE_STOPPING;
  1270. status = STATUS_SUCCESS;
  1271. break;
  1272. case IRP_MN_CANCEL_STOP_DEVICE:
  1273. DBGSTATE(pdoExt->state, COLLECTION_STATE_STOPPING, TRUE)
  1274. pdoExt->state = pdoExt->prevState;
  1275. status = STATUS_SUCCESS;
  1276. break;
  1277. case IRP_MN_STOP_DEVICE:
  1278. DBGSTATE(pdoExt->state, COLLECTION_STATE_STOPPING, TRUE)
  1279. if (pdoExt->prevState != COLLECTION_STATE_UNINITIALIZED){
  1280. /*
  1281. * Destroy the symbolic link for this collection.
  1282. */
  1283. HidpCreateSymbolicLink(pdoExt, pdoExt->collectionNum, FALSE, pdoExt->pdo);
  1284. HidpFreePowerEventIrp(&fdoExt->classCollectionArray[pdoExt->collectionIndex]);
  1285. pdoExt->state = COLLECTION_STATE_STOPPED;
  1286. if (ISPTR(pdoExt->StatusChangeFn)) {
  1287. pdoExt->StatusChangeFn(pdoExt->StatusChangeContext,
  1288. DeviceObjectStopped);
  1289. }
  1290. }
  1291. status = STATUS_SUCCESS;
  1292. break;
  1293. case IRP_MN_SURPRISE_REMOVAL:
  1294. case IRP_MN_QUERY_REMOVE_DEVICE:
  1295. DBGASSERT(((pdoExt->state == COLLECTION_STATE_RUNNING) ||
  1296. (pdoExt->state == COLLECTION_STATE_STOPPED)),
  1297. ("Pdo is neither stopped nor started, but is getting removed, state=%d",pdoExt->state),
  1298. FALSE)
  1299. pdoExt->prevState = pdoExt->state;
  1300. pdoExt->state = COLLECTION_STATE_REMOVING;
  1301. if ((pdoExt->prevState == COLLECTION_STATE_RUNNING)) {
  1302. /*
  1303. * Remove the symbolic link for this collection-PDO.
  1304. *
  1305. * NOTE: Do this BEFORE destroying the collection, because
  1306. * HidpDestroyCollection() may cause a client driver,
  1307. * whose pending read IRPs get cancelled when the collection
  1308. * is destroyed, to try to re-open the device.
  1309. * Deleting the symbolic link first eliminates this possibility.
  1310. */
  1311. HidpCreateSymbolicLink(pdoExt, pdoExt->collectionNum, FALSE, pdoExt->pdo);
  1312. }
  1313. if ((pdoExt->prevState == COLLECTION_STATE_RUNNING) ||
  1314. (pdoExt->prevState == COLLECTION_STATE_STOPPED)){
  1315. /*
  1316. * Flush all pending IO and deny any future io by setting
  1317. * the collection state to removing.
  1318. * Note: on NT, clients will receive the query remove
  1319. * first, but surprise removal must deny access to the
  1320. * device.
  1321. *
  1322. * NOTE: There is a hole here that results in a read being
  1323. * queued even though we've blocked everything.
  1324. * 1) Get read, check to see that our state is running
  1325. * or stopped in HidpIrpMajorRead.
  1326. * 2) Set state to COLLECTION_STATE_REMOVING and complete
  1327. * all reads here.
  1328. * 3) Enqueue read in HidpIrpMajorRead.
  1329. *
  1330. */
  1331. ULONG ctnIndx = pdoExt->collectionIndex;
  1332. PHIDCLASS_COLLECTION collection = &fdoExt->classCollectionArray[ctnIndx];
  1333. LIST_ENTRY dequeue, *entry;
  1334. PIRP irp;
  1335. DBGVERBOSE(("Got QUERY/SURPRISE REMOVE for collection; completing all pending reads. openCount=%d, pendingReads=%d.", pdoExt->openCount, collection->numPendingReads))
  1336. CompleteAllPendingReadsForCollection(collection);
  1337. DequeueAllPdoPowerDelayedIrps(pdoExt, &dequeue);
  1338. while (!IsListEmpty(&dequeue)) {
  1339. entry = RemoveHeadList(&dequeue);
  1340. irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  1341. irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  1342. IoCompleteRequest(irp, IO_NO_INCREMENT);
  1343. }
  1344. }
  1345. status = STATUS_SUCCESS;
  1346. break;
  1347. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1348. status = STATUS_SUCCESS;
  1349. DBGSTATE(pdoExt->state, COLLECTION_STATE_REMOVING, TRUE)
  1350. pdoExt->state = pdoExt->prevState;
  1351. if (pdoExt->state == COLLECTION_STATE_RUNNING) {
  1352. // Re-create the symbolic link, since we're no longer
  1353. // deleting the device.
  1354. HidpCreateSymbolicLink(pdoExt, pdoExt->collectionNum, TRUE, pdoExt->pdo);
  1355. }
  1356. break;
  1357. case IRP_MN_REMOVE_DEVICE:
  1358. /*
  1359. * REMOVE_DEVICE for the device-FDO should come after REMOVE_DEVICE for each
  1360. * of the collection-PDOs.
  1361. */
  1362. DBGASSERT((pdoExt->state == COLLECTION_STATE_UNINITIALIZED ||
  1363. pdoExt->state == COLLECTION_STATE_REMOVING),
  1364. ("On pnp remove, collection state is incorrect. Actual: %x", pdoExt->state),
  1365. TRUE)
  1366. HidpRemoveCollection(fdoExt, pdoExt, Irp);
  1367. if (ISPTR(pdoExt->StatusChangeFn)) {
  1368. pdoExt->StatusChangeFn(pdoExt->StatusChangeContext,
  1369. DeviceObjectRemoved);
  1370. }
  1371. status = STATUS_SUCCESS; // Can't fail IRP_MN_REMOVE
  1372. break;
  1373. case IRP_MN_QUERY_CAPABILITIES:
  1374. status = HidpQueryCollectionCapabilities(pdoExt, Irp);
  1375. break;
  1376. case IRP_MN_QUERY_DEVICE_RELATIONS:
  1377. if (irpSp->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation){
  1378. /*
  1379. * Return a reference to this PDO
  1380. */
  1381. PDEVICE_RELATIONS devRel = ALLOCATEPOOL(PagedPool, sizeof(DEVICE_RELATIONS));
  1382. if (devRel){
  1383. /*
  1384. * Add a reference to the PDO, since CONFIGMG will free it.
  1385. */
  1386. ObReferenceObject(pdoExt->pdo);
  1387. devRel->Objects[0] = pdoExt->pdo;
  1388. devRel->Count = 1;
  1389. Irp->IoStatus.Information = (ULONG_PTR)devRel;
  1390. status = STATUS_SUCCESS;
  1391. }
  1392. else {
  1393. status = STATUS_INSUFFICIENT_RESOURCES;
  1394. }
  1395. }
  1396. else {
  1397. /*
  1398. * Fail this Irp by returning the default
  1399. * status (typically STATUS_NOT_SUPPORTED).
  1400. */
  1401. status = Irp->IoStatus.Status;
  1402. }
  1403. break;
  1404. case IRP_MN_QUERY_ID:
  1405. status = HidpQueryIdForClientPdo(HidDeviceExtension, Irp);
  1406. break;
  1407. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  1408. //
  1409. // Do not clear any flags that may have been set by drivers above
  1410. // the PDO
  1411. //
  1412. // Irp->IoStatus.Information = 0;
  1413. switch (pdoExt->state){
  1414. case DEVICE_STATE_START_FAILURE:
  1415. Irp->IoStatus.Information |= PNP_DEVICE_FAILED;
  1416. break;
  1417. case DEVICE_STATE_STOPPED:
  1418. Irp->IoStatus.Information |= PNP_DEVICE_DISABLED;
  1419. break;
  1420. case DEVICE_STATE_REMOVING:
  1421. case DEVICE_STATE_REMOVED:
  1422. Irp->IoStatus.Information |= PNP_DEVICE_REMOVED;
  1423. break;
  1424. }
  1425. status = STATUS_SUCCESS;
  1426. break;
  1427. case IRP_MN_QUERY_INTERFACE:
  1428. status = HidpQueryInterface(HidDeviceExtension, Irp);
  1429. break;
  1430. case IRP_MN_QUERY_BUS_INFORMATION:
  1431. {
  1432. PPNP_BUS_INFORMATION busInfo = (PPNP_BUS_INFORMATION) ALLOCATEPOOL(NonPagedPool, sizeof(PNP_BUS_INFORMATION));
  1433. if (busInfo) {
  1434. busInfo->BusTypeGuid = GUID_BUS_TYPE_HID;
  1435. busInfo->LegacyBusType = PNPBus;
  1436. busInfo->BusNumber = fdoExt->BusNumber;
  1437. Irp->IoStatus.Information = (ULONG_PTR) busInfo;
  1438. status = STATUS_SUCCESS;
  1439. } else {
  1440. status = STATUS_INSUFFICIENT_RESOURCES;
  1441. Irp->IoStatus.Information = 0;
  1442. }
  1443. }
  1444. break;
  1445. default:
  1446. /*
  1447. * In the default case for the collection-PDOs we complete the IRP
  1448. * without changing IoStatus.Status; we also return the preset IoStatus.Status.
  1449. * This allows an upper filter driver to set IoStatus.Status
  1450. * on the way down. In the absence of a filter driver,
  1451. * IoStatus.Status will be STATUS_NOT_SUPPORTED.
  1452. *
  1453. * In the default case for the FDO we send the Irp on and let
  1454. * the other drivers in the stack do their thing.
  1455. */
  1456. status = Irp->IoStatus.Status;
  1457. break;
  1458. }
  1459. /*
  1460. * If this is a call for a collection-PDO, we complete it ourselves here.
  1461. * Otherwise, we pass it to the minidriver stack for more processing.
  1462. */
  1463. ASSERT(status != NO_STATUS);
  1464. Irp->IoStatus.Status = status;
  1465. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1466. DBG_LOG_PNP_IRP(Irp, minorFunction, TRUE, TRUE, status)
  1467. return status;
  1468. }
  1469. NTSTATUS HidpFdoPnp(
  1470. IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension,
  1471. IN OUT PIRP Irp
  1472. )
  1473. {
  1474. NTSTATUS status = NO_STATUS;
  1475. PIO_STACK_LOCATION irpSp;
  1476. FDO_EXTENSION *fdoExt;
  1477. BOOLEAN completeIrpHere = FALSE; // general rule
  1478. UCHAR minorFunction;
  1479. PAGED_CODE();
  1480. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1481. /*
  1482. * Keep these fields privately so that we have them
  1483. * after the IRP is completed and in case we delete
  1484. * the device extension on a REMOVE_DEVICE.
  1485. */
  1486. minorFunction = irpSp->MinorFunction;
  1487. DBG_LOG_PNP_IRP(Irp, minorFunction, FALSE, FALSE, 0)
  1488. fdoExt = &HidDeviceExtension->fdoExt;
  1489. switch (minorFunction){
  1490. case IRP_MN_START_DEVICE:
  1491. status = HidpStartDevice(HidDeviceExtension, Irp);
  1492. completeIrpHere = TRUE;
  1493. break;
  1494. case IRP_MN_QUERY_STOP_DEVICE:
  1495. /*
  1496. * We will pass this IRP down the driver stack.
  1497. * However, we need to change the default status
  1498. * from STATUS_NOT_SUPPORTED to STATUS_SUCCESS.
  1499. */
  1500. Irp->IoStatus.Status = STATUS_SUCCESS;
  1501. DBGSTATE(fdoExt->state, DEVICE_STATE_START_SUCCESS, FALSE)
  1502. fdoExt->prevState = fdoExt->state;
  1503. fdoExt->state = DEVICE_STATE_STOPPING;
  1504. break;
  1505. case IRP_MN_CANCEL_STOP_DEVICE:
  1506. /*
  1507. * We will pass this IRP down the driver stack.
  1508. * However, we need to change the default status
  1509. * from STATUS_NOT_SUPPORTED to STATUS_SUCCESS.
  1510. */
  1511. Irp->IoStatus.Status = STATUS_SUCCESS;
  1512. DBGSTATE(fdoExt->state, DEVICE_STATE_STOPPING, TRUE)
  1513. fdoExt->state = fdoExt->prevState;
  1514. break;
  1515. case IRP_MN_STOP_DEVICE:
  1516. DBGSTATE(fdoExt->state, DEVICE_STATE_STOPPING, TRUE)
  1517. if (fdoExt->prevState == DEVICE_STATE_START_SUCCESS){
  1518. /*
  1519. * While it is stopped, the host controller may not be able
  1520. * to complete IRPs. So cancel them before sending down the stop.
  1521. */
  1522. CancelAllPingPongIrps(fdoExt);
  1523. }
  1524. fdoExt->state = DEVICE_STATE_STOPPED;
  1525. IoCopyCurrentIrpStackLocationToNext(Irp);
  1526. status = HidpCallDriverSynchronous(fdoExt->fdo, Irp);
  1527. completeIrpHere = TRUE;
  1528. break;
  1529. case IRP_MN_SURPRISE_REMOVAL:
  1530. //
  1531. // On surprise removal, we should stop accessing the device.
  1532. // We do the same steps on IRP_MN_REMOVE_DEVICE for the query
  1533. // removal case. Don't bother doing it during query remove,
  1534. // itself, because we don't want to have to handle the
  1535. // cancel case. NOTE: We only get away with this because all
  1536. // of these steps can be repeated without dire consequences.
  1537. //
  1538. if (ISPTR(fdoExt->waitWakeIrp)){
  1539. IoCancelIrp(fdoExt->waitWakeIrp);
  1540. fdoExt->waitWakeIrp = BAD_POINTER;
  1541. }
  1542. HidpCancelIdleNotification(fdoExt, TRUE);
  1543. if (ISPTR(fdoExt->idleNotificationRequest)) {
  1544. IoFreeIrp(fdoExt->idleNotificationRequest);
  1545. fdoExt->idleNotificationRequest = BAD_POINTER;
  1546. }
  1547. DestroyPingPongs(fdoExt);
  1548. // fall thru to IRP_MN_QUERY_REMOVE_DEVICE
  1549. case IRP_MN_QUERY_REMOVE_DEVICE:
  1550. {
  1551. PIRP idleIrp;
  1552. while (idleIrp = DequeuePowerDelayedIrp(fdoExt)) {
  1553. idleIrp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  1554. IoCompleteRequest(idleIrp, IO_NO_INCREMENT);
  1555. }
  1556. }
  1557. /*
  1558. * We will pass this IRP down the driver stack.
  1559. * However, we need to change the default status
  1560. * from STATUS_NOT_SUPPORTED to STATUS_SUCCESS.
  1561. */
  1562. Irp->IoStatus.Status = STATUS_SUCCESS;
  1563. DBGSTATE(fdoExt->state, DEVICE_STATE_START_SUCCESS, FALSE)
  1564. DBGASSERT((fdoExt->state == DEVICE_STATE_START_SUCCESS ||
  1565. fdoExt->state == DEVICE_STATE_STOPPED),
  1566. ("Fdo is neither stopped nor started, but is getting removed, state=%d",fdoExt->state),
  1567. FALSE)
  1568. fdoExt->prevState = fdoExt->state;
  1569. fdoExt->state = DEVICE_STATE_REMOVING;
  1570. break;
  1571. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1572. /*
  1573. * We will pass this IRP down the driver stack.
  1574. * However, we need to change the default status
  1575. * from STATUS_NOT_SUPPORTED to STATUS_SUCCESS.
  1576. */
  1577. Irp->IoStatus.Status = STATUS_SUCCESS;
  1578. DBGSTATE(fdoExt->state, DEVICE_STATE_REMOVING, TRUE)
  1579. fdoExt->state = fdoExt->prevState;
  1580. break;
  1581. case IRP_MN_REMOVE_DEVICE:
  1582. /*
  1583. * REMOVE_DEVICE for the device-FDO should come after REMOVE_DEVICE
  1584. * for each of the collection-PDOs.
  1585. * Don't touch the device extension after this call.
  1586. */
  1587. DBGASSERT((fdoExt->state == DEVICE_STATE_REMOVING ||
  1588. fdoExt->state == DEVICE_STATE_START_FAILURE ||
  1589. fdoExt->state == DEVICE_STATE_INITIALIZED),
  1590. ("Incorrect device state: %x", fdoExt->state),
  1591. TRUE)
  1592. status = HidpRemoveDevice(fdoExt, Irp);
  1593. goto HidpFdoPnpDone;
  1594. break;
  1595. case IRP_MN_QUERY_DEVICE_RELATIONS:
  1596. if (irpSp->Parameters.QueryDeviceRelations.Type == BusRelations){
  1597. status = HidpQueryDeviceRelations(HidDeviceExtension, Irp);
  1598. if (NT_SUCCESS(status)){
  1599. /*
  1600. * Although we have satisfied this PnP IRP,
  1601. * we will still pass it down the stack.
  1602. * First change the default status to our status.
  1603. */
  1604. Irp->IoStatus.Status = status;
  1605. }
  1606. else {
  1607. completeIrpHere = TRUE;
  1608. }
  1609. }
  1610. break;
  1611. default:
  1612. /*
  1613. * In the default case for the collection-PDOs we complete the IRP
  1614. * without changing IoStatus.Status; we also return the preset IoStatus.Status.
  1615. * This allows an upper filter driver to set IoStatus.Status
  1616. * on the way down. In the absence of a filter driver,
  1617. * IoStatus.Status will be STATUS_NOT_SUPPORTED.
  1618. *
  1619. * In the default case for the FDO we send the Irp on and let
  1620. * the other drivers in the stack do their thing.
  1621. */
  1622. if (completeIrpHere){
  1623. status = Irp->IoStatus.Status;
  1624. }
  1625. break;
  1626. }
  1627. /*
  1628. * If this is a call for a collection-PDO, we complete it ourselves here.
  1629. * Otherwise, we pass it to the minidriver stack for more processing.
  1630. */
  1631. if (completeIrpHere){
  1632. ASSERT(status != NO_STATUS);
  1633. Irp->IoStatus.Status = status;
  1634. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1635. }
  1636. else {
  1637. /*
  1638. * Call the minidriver with this Irp.
  1639. * The rest of our processing will be done in our completion routine.
  1640. *
  1641. * Note: Don't touch the Irp after sending it down, since it may
  1642. * be completed immediately.
  1643. */
  1644. IoCopyCurrentIrpStackLocationToNext(Irp);
  1645. status = HidpCallDriver(fdoExt->fdo, Irp);
  1646. }
  1647. HidpFdoPnpDone:
  1648. DBG_LOG_PNP_IRP(Irp, minorFunction, FALSE, TRUE, status)
  1649. return status;
  1650. }