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.

744 lines
22 KiB

  1. /*++
  2. Copyright (c) 1998 - 1999 Microsoft Corporation
  3. Module Name:
  4. pnp.c
  5. Abstract: This module contains PnP Start, Stop, Remove,
  6. Power dispatch routines and IRP cancel routine.
  7. Environment:
  8. Kernel mode
  9. @@BEGIN_DDKSPLIT
  10. Author:
  11. Eliyas Yakub (Mar, 11, 1997)
  12. Revision History:
  13. Updated by Eliyas on Feb 5 1998
  14. Om Sharma ( April 15, 1998)
  15. MarcAnd 02-Jul-98 Quick tidy for DDK
  16. @@END_DDKSPLIT
  17. --*/
  18. #include "hidgame.h"
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text (PAGE, HGM_RemoveDevice)
  21. #pragma alloc_text (PAGE, HGM_PnP)
  22. #pragma alloc_text (PAGE, HGM_InitDevice)
  23. #pragma alloc_text (PAGE, HGM_GetResources)
  24. #pragma alloc_text (PAGE, HGM_Power)
  25. #endif
  26. /*****************************************************************************
  27. *
  28. * @doc INTERNAL
  29. *
  30. * @func NTSTATUS | HGM_IncRequestCount |
  31. *
  32. * Try to increment the request count but fail if the device is
  33. * being removed.
  34. *
  35. * @parm IN PDEVICE_EXTENSION | DeviceExtension |
  36. *
  37. * Pointer to the device extension.
  38. *
  39. * @rvalue STATUS_SUCCESS | success
  40. * @rvalue STATUS_DELETE_PENDING | PnP IRP received after device was removed
  41. *
  42. *****************************************************************************/
  43. NTSTATUS EXTERNAL
  44. HGM_IncRequestCount
  45. (
  46. IN PDEVICE_EXTENSION DeviceExtension
  47. )
  48. {
  49. NTSTATUS ntStatus;
  50. InterlockedIncrement( &DeviceExtension->RequestCount );
  51. ASSERT( DeviceExtension->RequestCount > 0 );
  52. if( DeviceExtension->fRemoved )
  53. {
  54. /*
  55. * PnP has already told us to remove the device so fail and make
  56. * sure that the event has been set.
  57. */
  58. if( 0 == InterlockedDecrement( &DeviceExtension->RequestCount ) )
  59. {
  60. KeSetEvent( &DeviceExtension->RemoveEvent, IO_NO_INCREMENT, FALSE );
  61. }
  62. ntStatus = STATUS_DELETE_PENDING;
  63. }
  64. else
  65. {
  66. ntStatus = STATUS_SUCCESS;
  67. }
  68. return ntStatus;
  69. }
  70. /*****************************************************************************
  71. *
  72. * @doc INTERNAL
  73. *
  74. * @func VOID | HGM_DecRequestCount |
  75. *
  76. * Decrement the request count and set event if this is the last.
  77. *
  78. * @parm IN PDEVICE_EXTENSION | DeviceExtension |
  79. *
  80. * Pointer to the device extension.
  81. *
  82. *****************************************************************************/
  83. VOID EXTERNAL
  84. HGM_DecRequestCount
  85. (
  86. IN PDEVICE_EXTENSION DeviceExtension
  87. )
  88. {
  89. LONG LocalCount;
  90. LocalCount = InterlockedDecrement( &DeviceExtension->RequestCount );
  91. ASSERT( DeviceExtension->RequestCount >= 0 );
  92. if( LocalCount == 0 )
  93. {
  94. /*
  95. * PnP has already told us to remove the device so the PnP remove
  96. * code should have set device as removed and should be waiting on
  97. * the event.
  98. */
  99. ASSERT( DeviceExtension->fRemoved );
  100. KeSetEvent( &DeviceExtension->RemoveEvent, IO_NO_INCREMENT, FALSE );
  101. }
  102. return;
  103. }
  104. /*****************************************************************************
  105. *
  106. * @doc EXTERNAL
  107. *
  108. * @func VOID | HGM_RemoveDevice |
  109. *
  110. * FDO Remove routine
  111. *
  112. * @parm IN PDEVICE_EXTENSION | DeviceExtension |
  113. *
  114. * Pointer to the device extension.
  115. *
  116. *****************************************************************************/
  117. VOID INTERNAL
  118. HGM_RemoveDevice
  119. (
  120. PDEVICE_EXTENSION DeviceExtension
  121. )
  122. {
  123. if (DeviceExtension->fSurpriseRemoved) {
  124. return;
  125. }
  126. DeviceExtension->fSurpriseRemoved = TRUE;
  127. /*
  128. * Acquire mutex before modifying the Global Linked list of devices
  129. */
  130. ExAcquireFastMutex (&Global.Mutex);
  131. /*
  132. * Remove this device from the linked list of devices
  133. */
  134. RemoveEntryList(&DeviceExtension->Link);
  135. /*
  136. * Release the mutex
  137. */
  138. ExReleaseFastMutex (&Global.Mutex);
  139. } /* HGM_RemoveDevice */
  140. /*****************************************************************************
  141. *
  142. * @doc EXTERNAL
  143. *
  144. * @func NTSTATUS | HGM_PnP |
  145. *
  146. * Plug and Play dispatch routine for this driver.
  147. *
  148. * @parm IN PDEVICE_OBJECT | DeviceObject |
  149. *
  150. * Pointer to the device object.
  151. *
  152. * @parm IN PIRP | Irp |
  153. *
  154. * Pointer to an I/O request packet.
  155. *
  156. * @rvalue STATUS_SUCCESS | success
  157. * @rvalue STATUS_DELETE_PENDING | PnP IRP received after device was removed
  158. * @rvalue ??? | Return from IoCallDriver() or HGM_InitDevice()
  159. *
  160. *****************************************************************************/
  161. NTSTATUS EXTERNAL
  162. HGM_PnP
  163. (
  164. IN PDEVICE_OBJECT DeviceObject,
  165. IN PIRP Irp
  166. )
  167. {
  168. NTSTATUS ntStatus;
  169. PDEVICE_EXTENSION DeviceExtension;
  170. KEVENT StartEvent;
  171. PAGED_CODE();
  172. HGM_DBGPRINT(FILE_PNP | HGM_FENTRY,\
  173. ("HGM_PnP(DeviceObject=0x%x,Irp=0x%x)",\
  174. DeviceObject, Irp ));
  175. /*
  176. * Get a pointer to the device extension
  177. */
  178. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  179. ntStatus = HGM_IncRequestCount( DeviceExtension );
  180. if (!NT_SUCCESS (ntStatus))
  181. {
  182. /*
  183. * Someone sent us another plug and play IRP after removed
  184. */
  185. HGM_DBGPRINT(FILE_PNP | HGM_ERROR,\
  186. ("HGM_PnP: PnP IRP after device was removed\n"));
  187. Irp->IoStatus.Information = 0;
  188. Irp->IoStatus.Status = ntStatus;
  189. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  190. } else
  191. {
  192. PIO_STACK_LOCATION IrpStack;
  193. /*
  194. * Get a pointer to the current location in the Irp
  195. */
  196. IrpStack = IoGetCurrentIrpStackLocation (Irp);
  197. switch(IrpStack->MinorFunction)
  198. {
  199. case IRP_MN_START_DEVICE:
  200. HGM_DBGPRINT(FILE_PNP | HGM_BABBLE,\
  201. ("HGM_Pnp: IRP_MN_START_DEVICE"));
  202. /*
  203. * We cannot touch the device (send it any non pnp irps) until a
  204. * start device has been passed down to the lower drivers.
  205. */
  206. KeInitializeEvent(&StartEvent, NotificationEvent, FALSE);
  207. IoCopyCurrentIrpStackLocationToNext (Irp);
  208. IoSetCompletionRoutine (Irp, HGM_PnPComplete, &StartEvent, TRUE, TRUE, TRUE);
  209. ntStatus = IoCallDriver (GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
  210. if( NT_SUCCESS(ntStatus ) )
  211. {
  212. ntStatus = KeWaitForSingleObject
  213. (
  214. &StartEvent,
  215. Executive, /* Waiting for reason of a driver */
  216. KernelMode, /* Waiting in kernel mode */
  217. FALSE, /* No allert */
  218. NULL /* No timeout */
  219. );
  220. }
  221. if(NT_SUCCESS(ntStatus))
  222. {
  223. ntStatus = Irp->IoStatus.Status;
  224. }
  225. if(NT_SUCCESS (ntStatus))
  226. {
  227. /*
  228. * As we are now back from our start device we can do work.
  229. */
  230. ntStatus = HGM_InitDevice (DeviceObject, Irp);
  231. } else
  232. {
  233. HGM_DBGPRINT(FILE_PNP | HGM_ERROR,\
  234. ("HGM_Pnp: IRP_MN_START_DEVICE ntStatus =0x%x",\
  235. ntStatus));
  236. }
  237. DeviceExtension->fStarted = TRUE;
  238. /*
  239. * Return Status
  240. */
  241. Irp->IoStatus.Information = 0;
  242. Irp->IoStatus.Status = ntStatus;
  243. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  244. break;
  245. case IRP_MN_STOP_DEVICE:
  246. HGM_DBGPRINT(FILE_PNP | HGM_BABBLE,\
  247. ("HGM_Pnp: IRP_MN_STOP_DEVICE"));
  248. /*
  249. * After the start IRP has been sent to the lower driver object, the bus may
  250. * NOT send any more IRPS down ``touch'' until another START has occured.
  251. * Whatever access is required must be done before Irp passed on.
  252. */
  253. DeviceExtension->fStarted = FALSE;
  254. /*
  255. * We don't need a completion routine so fire and forget.
  256. * Set the current stack location to the next stack location and
  257. * call the next device object.
  258. */
  259. IoSkipCurrentIrpStackLocation (Irp);
  260. ntStatus = IoCallDriver (GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
  261. break;
  262. case IRP_MN_SURPRISE_REMOVAL:
  263. HGM_DBGPRINT(FILE_PNP | HGM_BABBLE,\
  264. ("HGM_Pnp: IRP_MN_SURPRISE_REMOVAL"));
  265. HGM_RemoveDevice(DeviceExtension);
  266. Irp->IoStatus.Status = STATUS_SUCCESS;
  267. IoSkipCurrentIrpStackLocation(Irp);
  268. ntStatus = IoCallDriver (GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
  269. break;
  270. case IRP_MN_REMOVE_DEVICE:
  271. HGM_DBGPRINT(FILE_PNP | HGM_BABBLE,\
  272. ("HGM_Pnp: IRP_MN_REMOVE_DEVICE"));
  273. /*
  274. * The PlugPlay system has dictacted the removal of this device. We
  275. * have no choice but to detach and delete the device object.
  276. * (If we wanted to express an interest in preventing this removal,
  277. * we should have filtered the query remove and query stop routines.)
  278. * Note: we might receive a remove WITHOUT first receiving a stop.
  279. */
  280. /*
  281. * Make sure we do not allow more IRPs to start touching the device
  282. */
  283. DeviceExtension->fRemoved = TRUE;
  284. /*
  285. * Stop the device without touching the hardware.
  286. */
  287. HGM_RemoveDevice(DeviceExtension);
  288. /*
  289. * Send on the remove IRP
  290. */
  291. IoSkipCurrentIrpStackLocation (Irp);
  292. ntStatus = IoCallDriver (GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
  293. /*
  294. * Remove this IRPs hold which should leave the initial 1 plus
  295. * any other IRP holds.
  296. */
  297. {
  298. LONG RequestCount = InterlockedDecrement( &DeviceExtension->RequestCount );
  299. ASSERT( RequestCount > 0 );
  300. }
  301. /*
  302. * If someone has already started, wait for them to finish
  303. */
  304. if( InterlockedDecrement( &DeviceExtension->RequestCount ) > 0 )
  305. {
  306. KeWaitForSingleObject( &DeviceExtension->RemoveEvent,
  307. Executive, KernelMode, FALSE, NULL );
  308. }
  309. ntStatus = STATUS_SUCCESS;
  310. HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT_STATUSOK, "HGM_PnP Exit 1", ntStatus);
  311. return ntStatus;
  312. default:
  313. HGM_DBGPRINT(FILE_PNP | HGM_WARN,\
  314. ("HGM_PnP: IrpStack->MinorFunction Not handled 0x%x", \
  315. IrpStack->MinorFunction));
  316. IoSkipCurrentIrpStackLocation (Irp);
  317. ntStatus = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
  318. break;
  319. }
  320. HGM_DecRequestCount( DeviceExtension );
  321. }
  322. HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT, "HGM_PnP", ntStatus);
  323. return ntStatus;
  324. } /* HGM_PnP */
  325. /*****************************************************************************
  326. *
  327. * @doc EXTERNAL
  328. *
  329. * @func NTSTATUS | HGM_InitDevice |
  330. *
  331. * Get the device information and attempt to initialize a configuration
  332. * for a device. If we cannot identify this as a valid HID device or
  333. * configure the device, our start device function is failed.
  334. *
  335. * @parm IN PDEVICE_OBJECT | DeviceObject |
  336. *
  337. * Pointer to the device object.
  338. *
  339. * @parm IN PIRP | Irp |
  340. *
  341. * Pointer to an I/O request packet.
  342. *
  343. * @rvalue STATUS_SUCCESS | success
  344. * @rvalue STATUS_DEVICE_CONFIGURATION_ERROR | Resources overlap
  345. * @rvalue ??? | Return from HGM_GetResources() or HGM_JoystickConfig()
  346. *
  347. *
  348. *****************************************************************************/
  349. NTSTATUS INTERNAL
  350. HGM_InitDevice
  351. (
  352. IN PDEVICE_OBJECT DeviceObject,
  353. IN PIRP Irp
  354. )
  355. {
  356. NTSTATUS ntStatus;
  357. PDEVICE_EXTENSION DeviceExtension;
  358. ULONG DescriptorLength;
  359. PAGED_CODE();
  360. HGM_DBGPRINT(FILE_PNP | HGM_FENTRY,\
  361. ("HGM_InitDevice(DeviceObject=0x%x,Irp=0x%x)", \
  362. DeviceObject,Irp));
  363. /*
  364. * Get a pointer to the device extension
  365. */
  366. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  367. /*
  368. * Get resource information from GameEnum and store it in the device extension
  369. */
  370. ntStatus = HGM_GetResources(DeviceObject,Irp);
  371. if( NT_SUCCESS(ntStatus) )
  372. {
  373. ntStatus = HGM_InitAnalog(DeviceObject);
  374. }
  375. else
  376. {
  377. HGM_DBGPRINT(FILE_PNP | HGM_ERROR,\
  378. ("HGM_InitDevice: HGM_GetResources Failed"));
  379. }
  380. if( !NT_SUCCESS(ntStatus) )
  381. {
  382. /*
  383. * Acquire mutex before modifying the Global Linked list of devices
  384. */
  385. ExAcquireFastMutex (&Global.Mutex);
  386. /*
  387. * Remove this device from the linked list of devices
  388. */
  389. RemoveEntryList(&DeviceExtension->Link);
  390. /*
  391. * Release the mutex
  392. */
  393. ExReleaseFastMutex (&Global.Mutex);
  394. }
  395. HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT_STATUSOK, "HGM_InitDevice", ntStatus);
  396. return ntStatus;
  397. } /* HGM_InitDevice */
  398. /*****************************************************************************
  399. *
  400. * @doc EXTERNAL
  401. *
  402. * @func NTSTATUS | HGM_GetResources |
  403. *
  404. * Gets gameport resource information from the GameEnum driver
  405. *
  406. * @parm IN PDEVICE_OBJECT | DeviceObject |
  407. *
  408. * Pointer to the device object.
  409. *
  410. * @parm IN PIRP | Irp |
  411. *
  412. * Pointer to an I/O request packet.
  413. *
  414. * @rvalue STATUS_SUCCESS | success
  415. * @rvalue ??? | Return from IoCallDriver()
  416. *
  417. *****************************************************************************/
  418. NTSTATUS INTERNAL
  419. HGM_GetResources
  420. (
  421. IN PDEVICE_OBJECT DeviceObject,
  422. IN PIRP Irp
  423. )
  424. {
  425. NTSTATUS ntStatus = STATUS_SUCCESS;
  426. GAMEENUM_PORT_PARAMETERS PortInfo;
  427. POEMDATA OemData;
  428. PDEVICE_EXTENSION DeviceExtension;
  429. KEVENT IoctlCompleteEvent;
  430. IO_STATUS_BLOCK IoStatus;
  431. PIO_STACK_LOCATION irpStack, nextStack;
  432. int i;
  433. PAGED_CODE ();
  434. HGM_DBGPRINT(FILE_PNP | HGM_FENTRY,\
  435. ("HGM_GetResources(DeviceObject=0x%x,Irp=0x%x)",\
  436. DeviceObject, Irp));
  437. /*
  438. * Get a pointer to the device extension
  439. */
  440. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  441. /*
  442. * issue a synchronous request to get the resources info from GameEnum
  443. */
  444. KeInitializeEvent(&IoctlCompleteEvent, NotificationEvent, FALSE);
  445. irpStack = IoGetCurrentIrpStackLocation(Irp);
  446. nextStack = IoGetNextIrpStackLocation(Irp);
  447. ASSERTMSG("HGM_GetResources:",nextStack != NULL);
  448. /*
  449. * pass the Portinfo buffer of the DeviceExtension
  450. */
  451. nextStack->MajorFunction =
  452. IRP_MJ_INTERNAL_DEVICE_CONTROL;
  453. nextStack->Parameters.DeviceIoControl.IoControlCode =
  454. IOCTL_GAMEENUM_PORT_PARAMETERS;
  455. PortInfo.Size =
  456. nextStack->Parameters.DeviceIoControl.InputBufferLength =
  457. nextStack->Parameters.DeviceIoControl.OutputBufferLength =
  458. sizeof (PortInfo);
  459. Irp->UserBuffer = &PortInfo;
  460. IoSetCompletionRoutine (Irp, HGM_PnPComplete,
  461. &IoctlCompleteEvent, TRUE, TRUE, TRUE);
  462. HGM_DBGPRINT(FILE_PNP | HGM_BABBLE,\
  463. ("calling GameEnum"));
  464. ntStatus = IoCallDriver(GET_NEXT_DEVICE_OBJECT (DeviceObject), Irp);
  465. if( NT_SUCCESS(ntStatus) )
  466. {
  467. ntStatus = KeWaitForSingleObject(
  468. &IoctlCompleteEvent,
  469. Executive,
  470. KernelMode,
  471. FALSE,
  472. NULL);
  473. }
  474. if( NT_SUCCESS(ntStatus) )
  475. {
  476. ntStatus = Irp->IoStatus.Status;
  477. }
  478. DeviceExtension->GameContext = PortInfo.GameContext;
  479. DeviceExtension->ReadAccessor = PortInfo.ReadAccessor;
  480. DeviceExtension->WriteAccessor = PortInfo.WriteAccessor;
  481. DeviceExtension->ReadAccessorDigital= PortInfo.ReadAccessorDigital;
  482. DeviceExtension->AcquirePort = PortInfo.AcquirePort;
  483. DeviceExtension->ReleasePort = PortInfo.ReleasePort;
  484. DeviceExtension->PortContext = PortInfo.PortContext;
  485. DeviceExtension->nAxes = PortInfo.NumberAxis;
  486. DeviceExtension->nButtons = PortInfo.NumberButtons;
  487. #ifdef CHANGE_DEVICE
  488. /*
  489. * Stash the NextDeviceObject in the device extension so that we can
  490. * call GameEnum IRPs when we're not responding to an IRP
  491. */
  492. DeviceExtension->NextDeviceObject = GET_NEXT_DEVICE_OBJECT(DeviceObject);
  493. #endif /* CHANGE_DEVICE */
  494. RtlCopyMemory(DeviceExtension->HidGameOemData.Game_Oem_Data, PortInfo.OemData, sizeof(PortInfo.OemData));
  495. for(i=0x0;
  496. i < sizeof(PortInfo.OemData)/sizeof(PortInfo.OemData[0]);
  497. i++)
  498. {
  499. HGM_DBGPRINT( FILE_HIDJOY | HGM_BABBLE2,\
  500. ("JoystickConfig: PortInfo.OemData[%d]=0x%x",\
  501. i, PortInfo.OemData[i]) );
  502. }
  503. HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT_STATUSOK, "HGM_GetResources", Irp->IoStatus.Status);
  504. return Irp->IoStatus.Status;
  505. } /* HGM_GetResources */
  506. /*****************************************************************************
  507. *
  508. * @doc EXTERNAL
  509. *
  510. * @func NTSTATUS | HGM_PnPComplete |
  511. *
  512. * Completion routine for PnP IRPs.
  513. * Not pageable because it is a completion routine.
  514. *
  515. * @parm IN PDEVICE_OBJECT | DeviceObject |
  516. *
  517. * Pointer to the device object.
  518. *
  519. * @parm IN PIRP | Irp |
  520. *
  521. * Pointer to an I/O request packet.
  522. *
  523. * @rvalue STATUS_MORE_PROCESSING_REQUIRED | We want the IRP back
  524. *
  525. *****************************************************************************/
  526. NTSTATUS INTERNAL
  527. HGM_PnPComplete
  528. (
  529. IN PDEVICE_OBJECT DeviceObject,
  530. IN PIRP Irp,
  531. IN PVOID Context
  532. )
  533. {
  534. NTSTATUS ntStatus = STATUS_MORE_PROCESSING_REQUIRED;
  535. HGM_DBGPRINT(FILE_PNP | HGM_FENTRY,\
  536. ("HGM_PnPComplete(DeviceObject=0x%x,Irp=0x%x,Context=0x%x)", \
  537. DeviceObject, Irp, Context));
  538. UNREFERENCED_PARAMETER (DeviceObject);
  539. KeSetEvent ((PKEVENT) Context, 0, FALSE);
  540. HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT, "HGM_PnpComplete", ntStatus);
  541. return ntStatus;
  542. }
  543. /*****************************************************************************
  544. *
  545. * @doc EXTERNAL
  546. *
  547. * @func NTSTATUS | HGM_Power |
  548. *
  549. * The power dispatch routine.
  550. * <nl>This driver does not recognize power IRPS. It merely sends them down,
  551. * unmodified to the next device on the attachment stack.
  552. * As this is a POWER irp, and therefore a special irp, special power irp
  553. * handling is required. No completion routine is required.
  554. *
  555. * @parm IN PDEVICE_OBJECT | DeviceObject |
  556. *
  557. * Pointer to the device object.
  558. *
  559. * @parm IN PIRP | Irp |
  560. *
  561. * Pointer to an I/O request packet.
  562. *
  563. *
  564. * @rvalue STATUS_SUCCESS | success
  565. * @rvalue ??? | Return from PoCallDriver()
  566. *
  567. *****************************************************************************/
  568. NTSTATUS INTERNAL
  569. HGM_Power
  570. (
  571. IN PDEVICE_OBJECT DeviceObject,
  572. IN PIRP Irp
  573. )
  574. {
  575. PDEVICE_EXTENSION DeviceExtension;
  576. NTSTATUS ntStatus;
  577. PAGED_CODE ();
  578. HGM_DBGPRINT(FILE_PNP | HGM_FENTRY,\
  579. ("Enter HGM_Power(DeviceObject=0x%x,Irp=0x%x)",DeviceObject, Irp));
  580. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject);
  581. /*
  582. * Since we do not know what to do with the IRP, we should pass
  583. * it on along down the stack.
  584. */
  585. ntStatus = HGM_IncRequestCount( DeviceExtension );
  586. if (!NT_SUCCESS (ntStatus))
  587. {
  588. /*
  589. * Someone sent us another plug and play IRP after removed
  590. */
  591. HGM_DBGPRINT(FILE_PNP | HGM_ERROR,\
  592. ("HGM_Power: PnP IRP after device was removed\n"));
  593. Irp->IoStatus.Information = 0;
  594. Irp->IoStatus.Status = ntStatus;
  595. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  596. } else
  597. {
  598. IoSkipCurrentIrpStackLocation (Irp);
  599. /*
  600. * Power IRPS come synchronously; drivers must call
  601. * PoStartNextPowerIrp, when they are ready for the next power irp.
  602. * This can be called here, or in the completetion routine.
  603. */
  604. PoStartNextPowerIrp (Irp);
  605. /*
  606. * NOTE!!! PoCallDriver NOT IoCallDriver.
  607. */
  608. ntStatus = PoCallDriver (GET_NEXT_DEVICE_OBJECT (DeviceObject), Irp);
  609. HGM_DecRequestCount( DeviceExtension );
  610. }
  611. HGM_EXITPROC(FILE_IOCTL | HGM_FEXIT, "HGM_Power", ntStatus);
  612. return ntStatus;
  613. } /* HGM_Power */