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.

741 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. PAGED_CODE();
  359. HGM_DBGPRINT(FILE_PNP | HGM_FENTRY,\
  360. ("HGM_InitDevice(DeviceObject=0x%x,Irp=0x%x)", \
  361. DeviceObject,Irp));
  362. /*
  363. * Get a pointer to the device extension
  364. */
  365. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  366. /*
  367. * Get resource information from GameEnum and store it in the device extension
  368. */
  369. ntStatus = HGM_GetResources(DeviceObject,Irp);
  370. if( NT_SUCCESS(ntStatus) )
  371. {
  372. ntStatus = HGM_InitAnalog(DeviceObject);
  373. }
  374. else
  375. {
  376. HGM_DBGPRINT(FILE_PNP | HGM_ERROR,\
  377. ("HGM_InitDevice: HGM_GetResources Failed"));
  378. }
  379. if( !NT_SUCCESS(ntStatus) )
  380. {
  381. /*
  382. * Acquire mutex before modifying the Global Linked list of devices
  383. */
  384. ExAcquireFastMutex (&Global.Mutex);
  385. /*
  386. * Remove this device from the linked list of devices
  387. */
  388. RemoveEntryList(&DeviceExtension->Link);
  389. /*
  390. * Release the mutex
  391. */
  392. ExReleaseFastMutex (&Global.Mutex);
  393. }
  394. HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT_STATUSOK, "HGM_InitDevice", ntStatus);
  395. return ntStatus;
  396. } /* HGM_InitDevice */
  397. /*****************************************************************************
  398. *
  399. * @doc EXTERNAL
  400. *
  401. * @func NTSTATUS | HGM_GetResources |
  402. *
  403. * Gets gameport resource information from the GameEnum driver
  404. *
  405. * @parm IN PDEVICE_OBJECT | DeviceObject |
  406. *
  407. * Pointer to the device object.
  408. *
  409. * @parm IN PIRP | Irp |
  410. *
  411. * Pointer to an I/O request packet.
  412. *
  413. * @rvalue STATUS_SUCCESS | success
  414. * @rvalue ??? | Return from IoCallDriver()
  415. *
  416. *****************************************************************************/
  417. NTSTATUS INTERNAL
  418. HGM_GetResources
  419. (
  420. IN PDEVICE_OBJECT DeviceObject,
  421. IN PIRP Irp
  422. )
  423. {
  424. NTSTATUS ntStatus = STATUS_SUCCESS;
  425. GAMEENUM_PORT_PARAMETERS PortInfo;
  426. PDEVICE_EXTENSION DeviceExtension;
  427. KEVENT IoctlCompleteEvent;
  428. PIO_STACK_LOCATION irpStack, nextStack;
  429. int i;
  430. PAGED_CODE ();
  431. HGM_DBGPRINT(FILE_PNP | HGM_FENTRY,\
  432. ("HGM_GetResources(DeviceObject=0x%x,Irp=0x%x)",\
  433. DeviceObject, Irp));
  434. /*
  435. * Get a pointer to the device extension
  436. */
  437. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  438. /*
  439. * issue a synchronous request to get the resources info from GameEnum
  440. */
  441. KeInitializeEvent(&IoctlCompleteEvent, NotificationEvent, FALSE);
  442. irpStack = IoGetCurrentIrpStackLocation(Irp);
  443. nextStack = IoGetNextIrpStackLocation(Irp);
  444. ASSERTMSG("HGM_GetResources:",nextStack != NULL);
  445. /*
  446. * pass the Portinfo buffer of the DeviceExtension
  447. */
  448. nextStack->MajorFunction =
  449. IRP_MJ_INTERNAL_DEVICE_CONTROL;
  450. nextStack->Parameters.DeviceIoControl.IoControlCode =
  451. IOCTL_GAMEENUM_PORT_PARAMETERS;
  452. PortInfo.Size =
  453. nextStack->Parameters.DeviceIoControl.InputBufferLength =
  454. nextStack->Parameters.DeviceIoControl.OutputBufferLength =
  455. sizeof (PortInfo);
  456. Irp->UserBuffer = &PortInfo;
  457. IoSetCompletionRoutine (Irp, HGM_PnPComplete,
  458. &IoctlCompleteEvent, TRUE, TRUE, TRUE);
  459. HGM_DBGPRINT(FILE_PNP | HGM_BABBLE,\
  460. ("calling GameEnum"));
  461. ntStatus = IoCallDriver(GET_NEXT_DEVICE_OBJECT (DeviceObject), Irp);
  462. if( NT_SUCCESS(ntStatus) )
  463. {
  464. ntStatus = KeWaitForSingleObject(
  465. &IoctlCompleteEvent,
  466. Executive,
  467. KernelMode,
  468. FALSE,
  469. NULL);
  470. }
  471. if( NT_SUCCESS(ntStatus) )
  472. {
  473. ntStatus = Irp->IoStatus.Status;
  474. }
  475. DeviceExtension->GameContext = PortInfo.GameContext;
  476. DeviceExtension->ReadAccessor = PortInfo.ReadAccessor;
  477. DeviceExtension->WriteAccessor = PortInfo.WriteAccessor;
  478. DeviceExtension->ReadAccessorDigital= PortInfo.ReadAccessorDigital;
  479. DeviceExtension->AcquirePort = PortInfo.AcquirePort;
  480. DeviceExtension->ReleasePort = PortInfo.ReleasePort;
  481. DeviceExtension->PortContext = PortInfo.PortContext;
  482. DeviceExtension->nAxes = PortInfo.NumberAxis;
  483. DeviceExtension->nButtons = PortInfo.NumberButtons;
  484. #ifdef CHANGE_DEVICE
  485. /*
  486. * Stash the NextDeviceObject in the device extension so that we can
  487. * call GameEnum IRPs when we're not responding to an IRP
  488. */
  489. DeviceExtension->NextDeviceObject = GET_NEXT_DEVICE_OBJECT(DeviceObject);
  490. #endif /* CHANGE_DEVICE */
  491. RtlCopyMemory(DeviceExtension->HidGameOemData.Game_Oem_Data, PortInfo.OemData, sizeof(PortInfo.OemData));
  492. for(i=0x0;
  493. i < sizeof(PortInfo.OemData)/sizeof(PortInfo.OemData[0]);
  494. i++)
  495. {
  496. HGM_DBGPRINT( FILE_PNP | HGM_BABBLE2,\
  497. ("JoystickConfig: PortInfo.OemData[%d]=0x%x",\
  498. i, PortInfo.OemData[i]) );
  499. }
  500. HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT_STATUSOK, "HGM_GetResources", Irp->IoStatus.Status);
  501. return Irp->IoStatus.Status;
  502. } /* HGM_GetResources */
  503. /*****************************************************************************
  504. *
  505. * @doc EXTERNAL
  506. *
  507. * @func NTSTATUS | HGM_PnPComplete |
  508. *
  509. * Completion routine for PnP IRPs.
  510. * Not pageable because it is a completion routine.
  511. *
  512. * @parm IN PDEVICE_OBJECT | DeviceObject |
  513. *
  514. * Pointer to the device object.
  515. *
  516. * @parm IN PIRP | Irp |
  517. *
  518. * Pointer to an I/O request packet.
  519. *
  520. * @rvalue STATUS_MORE_PROCESSING_REQUIRED | We want the IRP back
  521. *
  522. *****************************************************************************/
  523. NTSTATUS INTERNAL
  524. HGM_PnPComplete
  525. (
  526. IN PDEVICE_OBJECT DeviceObject,
  527. IN PIRP Irp,
  528. IN PVOID Context
  529. )
  530. {
  531. NTSTATUS ntStatus = STATUS_MORE_PROCESSING_REQUIRED;
  532. HGM_DBGPRINT(FILE_PNP | HGM_FENTRY,\
  533. ("HGM_PnPComplete(DeviceObject=0x%x,Irp=0x%x,Context=0x%x)", \
  534. DeviceObject, Irp, Context));
  535. UNREFERENCED_PARAMETER (DeviceObject);
  536. KeSetEvent ((PKEVENT) Context, 0, FALSE);
  537. HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT, "HGM_PnpComplete", ntStatus);
  538. return ntStatus;
  539. }
  540. /*****************************************************************************
  541. *
  542. * @doc EXTERNAL
  543. *
  544. * @func NTSTATUS | HGM_Power |
  545. *
  546. * The power dispatch routine.
  547. * <nl>This driver does not recognize power IRPS. It merely sends them down,
  548. * unmodified to the next device on the attachment stack.
  549. * As this is a POWER irp, and therefore a special irp, special power irp
  550. * handling is required. No completion routine is required.
  551. *
  552. * @parm IN PDEVICE_OBJECT | DeviceObject |
  553. *
  554. * Pointer to the device object.
  555. *
  556. * @parm IN PIRP | Irp |
  557. *
  558. * Pointer to an I/O request packet.
  559. *
  560. *
  561. * @rvalue STATUS_SUCCESS | success
  562. * @rvalue ??? | Return from PoCallDriver()
  563. *
  564. *****************************************************************************/
  565. NTSTATUS INTERNAL
  566. HGM_Power
  567. (
  568. IN PDEVICE_OBJECT DeviceObject,
  569. IN PIRP Irp
  570. )
  571. {
  572. PDEVICE_EXTENSION DeviceExtension;
  573. NTSTATUS ntStatus;
  574. PAGED_CODE ();
  575. HGM_DBGPRINT(FILE_PNP | HGM_FENTRY,\
  576. ("Enter HGM_Power(DeviceObject=0x%x,Irp=0x%x)",DeviceObject, Irp));
  577. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject);
  578. /*
  579. * Since we do not know what to do with the IRP, we should pass
  580. * it on along down the stack.
  581. */
  582. ntStatus = HGM_IncRequestCount( DeviceExtension );
  583. if (!NT_SUCCESS (ntStatus))
  584. {
  585. /*
  586. * Someone sent us another plug and play IRP after removed
  587. */
  588. HGM_DBGPRINT(FILE_PNP | HGM_ERROR,\
  589. ("HGM_Power: PnP IRP after device was removed\n"));
  590. Irp->IoStatus.Information = 0;
  591. Irp->IoStatus.Status = ntStatus;
  592. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  593. } else
  594. {
  595. IoSkipCurrentIrpStackLocation (Irp);
  596. /*
  597. * Power IRPS come synchronously; drivers must call
  598. * PoStartNextPowerIrp, when they are ready for the next power irp.
  599. * This can be called here, or in the completetion routine.
  600. */
  601. PoStartNextPowerIrp (Irp);
  602. /*
  603. * NOTE!!! PoCallDriver NOT IoCallDriver.
  604. */
  605. ntStatus = PoCallDriver (GET_NEXT_DEVICE_OBJECT (DeviceObject), Irp);
  606. HGM_DecRequestCount( DeviceExtension );
  607. }
  608. HGM_EXITPROC(FILE_IOCTL | HGM_FEXIT, "HGM_Power", ntStatus);
  609. return ntStatus;
  610. } /* HGM_Power */