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.

720 lines
16 KiB

  1. /*++
  2. Copyright (c) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. pnp.c
  5. Abstract:
  6. This module implements the IRP_MJ_PNP IRP processing routines for the
  7. Plug and Play Memory driver. Dispatch routines are invoked through
  8. tables located at the bottom of the module.
  9. Author:
  10. Dave Richards (daveri) 16-Aug-1999
  11. Environment:
  12. Kernel mode only.
  13. Revision History:
  14. --*/
  15. #include "pnpmem.h"
  16. NTSTATUS
  17. PmPassIrp(
  18. IN PDEVICE_OBJECT DeviceObject,
  19. IN PIRP Irp
  20. );
  21. NTSTATUS
  22. PmPnpDispatch(
  23. IN PDEVICE_OBJECT DeviceObject,
  24. IN PIRP Irp
  25. );
  26. NTSTATUS
  27. PmDeferProcessing(
  28. IN PDEVICE_OBJECT DeviceObject,
  29. IN OUT PIRP Irp
  30. );
  31. NTSTATUS
  32. PmStartDevice(
  33. IN PDEVICE_OBJECT DeviceObject,
  34. IN PIRP Irp
  35. );
  36. NTSTATUS
  37. PmQueryRemoveDevice(
  38. IN PDEVICE_OBJECT DeviceObject,
  39. IN PIRP Irp
  40. );
  41. NTSTATUS
  42. PmRemoveDevice(
  43. IN PDEVICE_OBJECT DeviceObject,
  44. IN PIRP Irp
  45. );
  46. NTSTATUS
  47. PmCancelRemoveDevice(
  48. IN PDEVICE_OBJECT DeviceObject,
  49. IN PIRP Irp
  50. );
  51. NTSTATUS
  52. PmQueryStopDevice(
  53. IN PDEVICE_OBJECT DeviceObject,
  54. IN PIRP Irp
  55. );
  56. NTSTATUS
  57. PmCancelStopDevice(
  58. IN PDEVICE_OBJECT DeviceObject,
  59. IN PIRP Irp
  60. );
  61. NTSTATUS
  62. PmQueryCapabilities(
  63. IN PDEVICE_OBJECT DeviceObject,
  64. IN PIRP Irp
  65. );
  66. NTSTATUS
  67. PmSurpriseRemoveDevice(
  68. IN PDEVICE_OBJECT DeviceObject,
  69. IN PIRP Irp
  70. );
  71. #ifdef ALLOC_PRAGMA
  72. #pragma alloc_text(PAGE, PmPassIrp)
  73. #pragma alloc_text(PAGE, PmPnpDispatch)
  74. #pragma alloc_text(PAGE, PmDeferProcessing)
  75. #pragma alloc_text(PAGE, PmStartDevice)
  76. #pragma alloc_text(PAGE, PmQueryRemoveDevice)
  77. #pragma alloc_text(PAGE, PmRemoveDevice)
  78. #pragma alloc_text(PAGE, PmCancelRemoveDevice)
  79. #pragma alloc_text(PAGE, PmQueryStopDevice)
  80. #pragma alloc_text(PAGE, PmCancelStopDevice)
  81. #pragma alloc_text(PAGE, PmSurpriseRemoveDevice)
  82. #pragma alloc_text(PAGE, PmQueryCapabilities)
  83. #endif
  84. PDRIVER_DISPATCH PmPnpDispatchTable[];
  85. extern ULONG PmPnpDispatchTableSize;
  86. NTSTATUS
  87. PmPassIrp(
  88. IN PDEVICE_OBJECT DeviceObject,
  89. IN PIRP Irp
  90. )
  91. {
  92. PPM_DEVICE_EXTENSION deviceExtension;
  93. PAGED_CODE();
  94. deviceExtension = DeviceObject->DeviceExtension;
  95. IoSkipCurrentIrpStackLocation(Irp);
  96. return IoCallDriver(deviceExtension->AttachedDevice, Irp);
  97. }
  98. NTSTATUS
  99. PmPnpDispatch(
  100. IN PDEVICE_OBJECT DeviceObject,
  101. IN PIRP Irp
  102. )
  103. /*++
  104. Routine Description:
  105. This routine handles IRP_MJ_PNP IRPs for FDOs.
  106. Arguments:
  107. DeviceObject - Pointer to the FDO for which this IRP applies.
  108. Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.
  109. Return Value:
  110. NT status.
  111. --*/
  112. {
  113. NTSTATUS status;
  114. BOOLEAN isRemoveDevice;
  115. PIO_STACK_LOCATION irpSp;
  116. PPM_DEVICE_EXTENSION deviceExtension;
  117. PAGED_CODE();
  118. //
  119. // Get a pointer to our stack location and take appropriate action based
  120. // on the minor function.
  121. //
  122. irpSp = IoGetCurrentIrpStackLocation(Irp);
  123. deviceExtension = DeviceObject->DeviceExtension;
  124. IoAcquireRemoveLock(&deviceExtension->RemoveLock, (PVOID) Irp);
  125. isRemoveDevice = irpSp->MinorFunction == IRP_MN_REMOVE_DEVICE;
  126. if ((irpSp->MinorFunction < PmPnpDispatchTableSize) &&
  127. PmPnpDispatchTable[irpSp->MinorFunction]) {
  128. status =
  129. PmPnpDispatchTable[irpSp->MinorFunction](DeviceObject,
  130. Irp
  131. );
  132. } else {
  133. status = PmPassIrp(DeviceObject, Irp);
  134. }
  135. if (!isRemoveDevice) {
  136. IoReleaseRemoveLock(&deviceExtension->RemoveLock, (PVOID) Irp);
  137. }
  138. return status;
  139. }
  140. NTSTATUS
  141. PmPnpCompletion(
  142. IN PDEVICE_OBJECT DeviceObject,
  143. IN PIRP Irp,
  144. IN PVOID Context
  145. )
  146. /*++
  147. Routine Description:
  148. This routine is used to defer processing of an IRP until drivers
  149. lower in the stack including the bus driver have done their
  150. processing.
  151. This routine triggers the event to indicate that processing of the
  152. irp can now continue.
  153. Arguments:
  154. DeviceObject - Pointer to the FDO for which this IRP applies.
  155. Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.
  156. Return Value:
  157. NT status.
  158. --*/
  159. {
  160. KeSetEvent((PKEVENT) Context, EVENT_INCREMENT, FALSE);
  161. return STATUS_MORE_PROCESSING_REQUIRED;
  162. }
  163. NTSTATUS
  164. PmDeferProcessing(
  165. IN PDEVICE_OBJECT DeviceObject,
  166. IN OUT PIRP Irp
  167. )
  168. /*++
  169. Routine Description:
  170. This routine is used to defer processing of an IRP until drivers
  171. lower in the stack including the bus driver have done their
  172. processing.
  173. This routine uses an IoCompletion routine along with an event to
  174. wait until the lower level drivers have completed processing of
  175. the irp.
  176. Arguments:
  177. Parent - FDO extension for the FDO devobj in question
  178. Irp - Pointer to the IRP_MJ_PNP IRP to defer
  179. Return Value:
  180. NT status.
  181. --*/
  182. {
  183. PPM_DEVICE_EXTENSION deviceExtension;
  184. KEVENT event;
  185. NTSTATUS status;
  186. PAGED_CODE();
  187. deviceExtension = DeviceObject->DeviceExtension;
  188. KeInitializeEvent(&event, NotificationEvent, FALSE);
  189. //
  190. // Set our completion routine
  191. //
  192. IoCopyCurrentIrpStackLocationToNext(Irp);
  193. IoSetCompletionRoutine(Irp,
  194. PmPnpCompletion,
  195. &event,
  196. TRUE,
  197. TRUE,
  198. TRUE
  199. );
  200. status = IoCallDriver(deviceExtension->AttachedDevice, Irp);
  201. if (status == STATUS_PENDING) {
  202. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  203. status = Irp->IoStatus.Status;
  204. }
  205. return status;
  206. }
  207. NTSTATUS
  208. PmStartDevice(
  209. IN PDEVICE_OBJECT DeviceObject,
  210. IN PIRP Irp
  211. )
  212. /*++
  213. Routine Description:
  214. This function handles IRP_MN_START_DEVICE IRPs.
  215. Arguments:
  216. DeviceObject - The functional device object.
  217. Irp - The I/O request packet.
  218. Return Value:
  219. NTSTATUS
  220. --*/
  221. {
  222. PIO_STACK_LOCATION irpSp;
  223. PPM_RANGE_LIST RangeList;
  224. PPM_DEVICE_EXTENSION deviceExtension;
  225. POWER_STATE power;
  226. NTSTATUS status;
  227. PAGED_CODE();
  228. status = PmDeferProcessing(DeviceObject, Irp);
  229. if (!NT_SUCCESS(status)) {
  230. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  231. return status;
  232. }
  233. PmDumpOsMemoryRanges(L"Before Start");
  234. irpSp = IoGetCurrentIrpStackLocation(Irp);
  235. deviceExtension = DeviceObject->DeviceExtension;
  236. ASSERT(deviceExtension->RangeList == NULL);
  237. if (irpSp->Parameters.StartDevice.AllocatedResources) {
  238. RangeList = PmCreateRangeListFromCmResourceList(
  239. irpSp->Parameters.StartDevice.AllocatedResources
  240. );
  241. if (RangeList == NULL) {
  242. //
  243. // The memory allocation failure here is more serious than
  244. // is intially obvious. If we fail this allocation, we're
  245. // going to get removed from the stack before we find out
  246. // if the OS knows about this memory. If the OS knows
  247. // about this memory already, then ejecting the PDO would
  248. // cause the memory underneath the OS to disappear.
  249. // Better to be on the stack, but not have added any
  250. // memory then to be off the stack and leave a dangerous
  251. // situation.
  252. //
  253. // Only solution is to arbitrarily fail
  254. // IRP_MN_QUERY_REMOVE.
  255. //
  256. deviceExtension->FailQueryRemoves = TRUE;
  257. }
  258. } else {
  259. RangeList = NULL;
  260. }
  261. PmTrimReservedMemory(deviceExtension, &RangeList);
  262. PmDebugDumpRangeList(PNPMEM_MEMORY, "Memory Ranges to be added:\n",
  263. RangeList);
  264. if (deviceExtension->FailQueryRemoves) {
  265. PmPrint((DPFLTR_WARNING_LEVEL | PNPMEM_MEMORY, "PNPMEM device can't be removed\n"));
  266. }
  267. if (RangeList != NULL) {
  268. (VOID) PmAddPhysicalMemory(DeviceObject, RangeList);
  269. deviceExtension->RangeList = RangeList;
  270. }
  271. power.DeviceState = PowerDeviceD0;
  272. PoSetPowerState(DeviceObject, DevicePowerState, power);
  273. deviceExtension->PowerState = PowerDeviceD0;
  274. PmDumpOsMemoryRanges(L"After Start ");
  275. Irp->IoStatus.Status = STATUS_SUCCESS;
  276. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  277. return STATUS_SUCCESS;
  278. }
  279. NTSTATUS
  280. PmQueryRemoveDevice(
  281. IN PDEVICE_OBJECT DeviceObject,
  282. IN PIRP Irp
  283. )
  284. /*++
  285. Routine Description:
  286. This function handles IRP_MN_QUERY_REMOVE_DEVICE IRPs.
  287. Arguments:
  288. DeviceObject - The functional device object.
  289. Irp - The I/O request packet.
  290. Return Value:
  291. NTSTATUS
  292. --*/
  293. {
  294. PPM_DEVICE_EXTENSION deviceExtension;
  295. NTSTATUS status;
  296. PAGED_CODE();
  297. deviceExtension = DeviceObject->DeviceExtension;
  298. if (!MemoryRemovalSupported) {
  299. PmPrint((DPFLTR_WARNING_LEVEL | PNPMEM_MEMORY,
  300. "QueryRemove vetoed because memory removal is not supported\n"));
  301. status = STATUS_UNSUCCESSFUL;
  302. } else if (deviceExtension->FailQueryRemoves) {
  303. PmPrint((DPFLTR_WARNING_LEVEL | PNPMEM_MEMORY,
  304. "QueryRemove vetoed because removing this memory device may contain special memory\n"));
  305. status = STATUS_UNSUCCESSFUL;
  306. } else if (deviceExtension->RangeList != NULL) {
  307. status = PmRemovePhysicalMemory(deviceExtension->RangeList);
  308. if (!NT_SUCCESS(status)) {
  309. //
  310. // Some ranges may have been removed, before failure. Add
  311. // them back. Should be low-cost due to optimizations in
  312. // PmAddPhysicalMemory.
  313. //
  314. (VOID) PmAddPhysicalMemory(DeviceObject, deviceExtension->RangeList);
  315. }
  316. } else {
  317. status = STATUS_SUCCESS;
  318. }
  319. Irp->IoStatus.Status = status;
  320. if (NT_SUCCESS(status)) {
  321. return PmPassIrp(DeviceObject, Irp);
  322. } else {
  323. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  324. return status;
  325. }
  326. }
  327. NTSTATUS
  328. PmRemoveDevice(
  329. IN PDEVICE_OBJECT DeviceObject,
  330. IN PIRP Irp
  331. )
  332. /*++
  333. Routine Description:
  334. This function handles IRP_MN_REMOVE_DEVICE IRPs.
  335. Arguments:
  336. DeviceObject - The functional device object.
  337. Irp - The I/O request packet.
  338. Return Value:
  339. NTSTATUS
  340. --*/
  341. {
  342. PPM_DEVICE_EXTENSION deviceExtension;
  343. PPM_RANGE_LIST RangeList;
  344. POWER_STATE power;
  345. NTSTATUS status;
  346. PAGED_CODE();
  347. deviceExtension = DeviceObject->DeviceExtension;
  348. if ((deviceExtension->Flags & DF_SURPRISE_REMOVED) == 0) {
  349. power.DeviceState = PowerDeviceD3;
  350. PoSetPowerState(DeviceObject, DevicePowerState, power);
  351. deviceExtension->PowerState = PowerDeviceD0;
  352. if (deviceExtension->RangeList != NULL) {
  353. status = PmRemovePhysicalMemory(deviceExtension->RangeList);
  354. ASSERT(status == STATUS_SUCCESS);
  355. DbgBreakPoint();
  356. }
  357. }
  358. Irp->IoStatus.Status = STATUS_SUCCESS;
  359. status = PmPassIrp(DeviceObject, Irp);
  360. IoReleaseRemoveLockAndWait(&deviceExtension->RemoveLock, (PVOID) Irp);
  361. IoDetachDevice(deviceExtension->AttachedDevice);
  362. deviceExtension->AttachedDevice = NULL;
  363. if (deviceExtension->RangeList != NULL) {
  364. PmFreeRangeList(deviceExtension->RangeList);
  365. deviceExtension->RangeList = NULL;
  366. }
  367. IoDeleteDevice(DeviceObject);
  368. return status;
  369. }
  370. NTSTATUS
  371. PmCancelRemoveDevice(
  372. IN PDEVICE_OBJECT DeviceObject,
  373. IN PIRP Irp
  374. )
  375. /*++
  376. Routine Description:
  377. This function handles IRP_MN_CANCEL_REMOVE_DEVICE IRPs.
  378. Arguments:
  379. DeviceObject - The functional device object.
  380. Irp - The I/O request packet.
  381. Return Value:
  382. NTSTATUS
  383. --*/
  384. {
  385. PPM_DEVICE_EXTENSION deviceExtension;
  386. PAGED_CODE();
  387. (VOID) PmDeferProcessing(DeviceObject, Irp);
  388. deviceExtension = DeviceObject->DeviceExtension;
  389. if (deviceExtension->RangeList != NULL) {
  390. (VOID) PmAddPhysicalMemory(DeviceObject, deviceExtension->RangeList);
  391. }
  392. Irp->IoStatus.Status = STATUS_SUCCESS;
  393. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  394. return STATUS_SUCCESS;
  395. }
  396. NTSTATUS
  397. PmQueryStopDevice(
  398. IN PDEVICE_OBJECT DeviceObject,
  399. IN PIRP Irp
  400. )
  401. /*++
  402. Routine Description:
  403. This function handles IRP_MN_QUERY_STOP_DEVICE IRPs.
  404. Arguments:
  405. DeviceObject - The functional device object.
  406. Irp - The I/O request packet.
  407. Return Value:
  408. NTSTATUS
  409. --*/
  410. {
  411. PAGED_CODE();
  412. Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  413. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  414. return STATUS_DEVICE_BUSY;
  415. }
  416. NTSTATUS
  417. PmCancelStopDevice(
  418. IN PDEVICE_OBJECT DeviceObject,
  419. IN PIRP Irp
  420. )
  421. /*++
  422. Routine Description:
  423. This function handles IRP_MN_CANCEL_STOP_DEVICE IRPs.
  424. Arguments:
  425. DeviceObject - The functional device object.
  426. Irp - The I/O request packet.
  427. Return Value:
  428. NTSTATUS
  429. --*/
  430. {
  431. NTSTATUS status;
  432. PAGED_CODE();
  433. (VOID) PmDeferProcessing(DeviceObject, Irp);
  434. Irp->IoStatus.Status = STATUS_SUCCESS;
  435. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  436. return STATUS_SUCCESS;
  437. }
  438. NTSTATUS
  439. PmQueryCapabilities(
  440. IN PDEVICE_OBJECT DeviceObject,
  441. IN PIRP Irp
  442. )
  443. {
  444. PPM_DEVICE_EXTENSION deviceExtension;
  445. PIO_STACK_LOCATION irpSp;
  446. NTSTATUS status;
  447. ULONG i;
  448. PAGED_CODE();
  449. irpSp = IoGetCurrentIrpStackLocation(Irp);
  450. deviceExtension = DeviceObject->DeviceExtension;
  451. status = PmDeferProcessing(DeviceObject, Irp);
  452. if (!NT_SUCCESS(status)) {
  453. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  454. return status;
  455. }
  456. if (irpSp->Parameters.DeviceCapabilities.Capabilities->Version != 1) {
  457. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  458. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  459. return STATUS_INVALID_PARAMETER;
  460. }
  461. for (i = 0; i < PowerSystemMaximum; i++) {
  462. deviceExtension->DeviceStateMapping[i] =
  463. irpSp->Parameters.DeviceCapabilities.Capabilities->DeviceState[i];
  464. }
  465. //
  466. // Would *LIKE* to smash the eject supported, and removable bits
  467. // here but this isn't really supported. The hot plug applet pops
  468. // up (because the device is marked removable or ejectable) and
  469. // then goes away a few seconds later when the driver is installed
  470. // (and the capabilities requeried).
  471. //
  472. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  473. return STATUS_SUCCESS;
  474. }
  475. NTSTATUS
  476. PmSurpriseRemoveDevice(
  477. IN PDEVICE_OBJECT DeviceObject,
  478. IN PIRP Irp
  479. )
  480. {
  481. PPM_DEVICE_EXTENSION deviceExtension;
  482. PAGED_CODE();
  483. deviceExtension = DeviceObject->DeviceExtension;
  484. if (deviceExtension->RangeList != NULL) {
  485. // XXX
  486. // KeBugCheckEx(MEMORY_FATAL_ERROR,
  487. // ....
  488. }
  489. deviceExtension->Flags |= DF_SURPRISE_REMOVED;
  490. if (deviceExtension->RangeList != NULL) {
  491. PmFreeRangeList(deviceExtension->RangeList);
  492. deviceExtension->RangeList = NULL;
  493. }
  494. Irp->IoStatus.Status = STATUS_SUCCESS;
  495. return PmPassIrp(DeviceObject, Irp);
  496. }
  497. PDRIVER_DISPATCH PmPnpDispatchTable[] = {
  498. PmStartDevice, // IRP_MN_START_DEVICE
  499. PmQueryRemoveDevice, // IRP_MN_QUERY_REMOVE_DEVICE
  500. PmRemoveDevice, // IRP_MN_REMOVE_DEVICE
  501. PmCancelRemoveDevice, // IRP_MN_CANCEL_REMOVE_DEVICE
  502. NULL, // IRP_MN_STOP_DEVICE (never get, fails query-stop)
  503. PmQueryStopDevice, // IRP_MN_QUERY_STOP_DEVICE
  504. PmCancelStopDevice, // IRP_MN_CANCEL_STOP_DEVICE
  505. NULL, // IRP_MN_QUERY_DEVICE_RELATIONS
  506. NULL, // IRP_MN_QUERY_INTERFACE
  507. PmQueryCapabilities, // IRP_MN_QUERY_CAPABILITIES
  508. NULL, // IRP_MN_QUERY_RESOURCES
  509. NULL, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS
  510. NULL, // IRP_MN_QUERY_DEVICE_TEXT
  511. NULL, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
  512. NULL, // unused
  513. NULL, // IRP_MN_READ_CONFIG
  514. NULL, // IRP_MN_WRITE_CONFIG
  515. NULL, // IRP_MN_EJECT
  516. NULL, // IRP_MN_SET_LOCK
  517. NULL, // IRP_MN_QUERY_ID
  518. NULL, // IRP_MN_QUERY_PNP_DEVICE_STATE
  519. NULL, // IRP_MN_QUERY_BUS_INFORMATION
  520. NULL, // IRP_MN_DEVICE_USAGE_NOTIFICATION
  521. PmSurpriseRemoveDevice, // IRP_MN_SURPRISE_REMOVAL
  522. };
  523. ULONG PmPnpDispatchTableSize =
  524. sizeof (PmPnpDispatchTable) / sizeof (PmPnpDispatchTable[0]);