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.

1317 lines
32 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. fdo.c
  5. Abstract:
  6. This module provides the functions which answer IRPs to functional devices.
  7. Author:
  8. Andy Thornton (andrewth) 20-Oct-97
  9. Revision History:
  10. --*/
  11. #include "mfp.h"
  12. /*++
  13. The majority of functions in this file are called based on their presence
  14. in Pnp and Po dispatch tables. In the interests of brevity the arguments
  15. to all those functions will be described below:
  16. NTSTATUS
  17. MfXxxFdo(
  18. IN PIRP Irp,
  19. IN PMF_PARENT_EXTENSION Parent,
  20. IN PIO_STACK_LOCATION IrpStack
  21. )
  22. Routine Description:
  23. This function handles the Xxx requests for multifunction FDO's
  24. Arguments:
  25. Irp - Points to the IRP associated with this request.
  26. Parent - Points to the parent FDO's device extension.
  27. IrpStack - Points to the current stack location for this request.
  28. Return Value:
  29. Status code that indicates whether or not the function was successful.
  30. STATUS_NOT_SUPPORTED indicates that the IRP should be passed down without
  31. changing the Irp->IoStatus.Status field otherwise it is updated with this
  32. status.
  33. --*/
  34. NTSTATUS
  35. MfDeferProcessingFdo(
  36. IN PMF_PARENT_EXTENSION Parent,
  37. IN OUT PIRP Irp
  38. );
  39. NTSTATUS
  40. MfStartFdo(
  41. IN PIRP Irp,
  42. IN PMF_PARENT_EXTENSION Parent,
  43. IN PIO_STACK_LOCATION IrpStack
  44. );
  45. NTSTATUS
  46. MfStartFdoCompletion(
  47. IN PDEVICE_OBJECT DeviceObject,
  48. IN PIRP Irp,
  49. IN PVOID Context
  50. );
  51. NTSTATUS
  52. MfStartFdoInitializeArbiters(
  53. IN PMF_PARENT_EXTENSION Parent,
  54. IN PCM_RESOURCE_LIST ResList,
  55. IN PCM_RESOURCE_LIST TranslatedResList
  56. );
  57. NTSTATUS
  58. MfQueryStopFdo(
  59. IN PIRP Irp,
  60. IN PMF_PARENT_EXTENSION Parent,
  61. IN PIO_STACK_LOCATION IrpStack
  62. );
  63. NTSTATUS
  64. MfCancelStopFdo(
  65. IN PIRP Irp,
  66. IN PMF_PARENT_EXTENSION Parent,
  67. IN PIO_STACK_LOCATION IrpStack
  68. );
  69. NTSTATUS
  70. MfQueryRemoveFdo(
  71. IN PIRP Irp,
  72. IN PMF_PARENT_EXTENSION Parent,
  73. IN PIO_STACK_LOCATION IrpStack
  74. );
  75. NTSTATUS
  76. MfRemoveFdo(
  77. IN PIRP Irp,
  78. IN PMF_PARENT_EXTENSION Parent,
  79. IN PIO_STACK_LOCATION IrpStack
  80. );
  81. NTSTATUS
  82. MfSurpriseRemoveFdo(
  83. IN PIRP Irp,
  84. IN PMF_PARENT_EXTENSION Parent,
  85. IN PIO_STACK_LOCATION IrpStack
  86. );
  87. NTSTATUS
  88. MfCancelRemoveFdo(
  89. IN PIRP Irp,
  90. IN PMF_PARENT_EXTENSION Parent,
  91. IN PIO_STACK_LOCATION IrpStack
  92. );
  93. NTSTATUS
  94. MfQueryDeviceRelationsFdo(
  95. IN PIRP Irp,
  96. IN PMF_PARENT_EXTENSION Parent,
  97. IN PIO_STACK_LOCATION IrpStack
  98. );
  99. NTSTATUS
  100. MfQueryInterfaceFdo(
  101. IN PIRP Irp,
  102. IN PMF_PARENT_EXTENSION Parent,
  103. IN PIO_STACK_LOCATION IrpStack
  104. );
  105. NTSTATUS
  106. MfQueryCapabilitiesFdo(
  107. IN PIRP Irp,
  108. IN PMF_PARENT_EXTENSION Parent,
  109. IN PIO_STACK_LOCATION IrpStack
  110. );
  111. NTSTATUS
  112. MfQueryPowerFdo(
  113. IN PIRP Irp,
  114. IN PMF_PARENT_EXTENSION Parent,
  115. IN PIO_STACK_LOCATION IrpStack
  116. );
  117. NTSTATUS
  118. MfSetPowerFdo(
  119. IN PIRP Irp,
  120. IN PMF_PARENT_EXTENSION Parent,
  121. IN PIO_STACK_LOCATION IrpStack
  122. );
  123. NTSTATUS
  124. MfPassIrp(
  125. IN PIRP Irp,
  126. IN PMF_PARENT_EXTENSION Parent,
  127. IN PIO_STACK_LOCATION IrpStack
  128. );
  129. #ifdef ALLOC_PRAGMA
  130. #pragma alloc_text(PAGE, MfCancelRemoveFdo)
  131. #pragma alloc_text(PAGE, MfCancelStopFdo)
  132. #pragma alloc_text(PAGE, MfCreateFdo)
  133. #pragma alloc_text(PAGE, MfDeferProcessingFdo)
  134. #pragma alloc_text(PAGE, MfDispatchPnpFdo)
  135. #pragma alloc_text(PAGE, MfPassIrp)
  136. #pragma alloc_text(PAGE, MfQueryCapabilitiesFdo)
  137. #pragma alloc_text(PAGE, MfQueryDeviceRelationsFdo)
  138. #pragma alloc_text(PAGE, MfQueryInterfaceFdo)
  139. #pragma alloc_text(PAGE, MfQueryRemoveFdo)
  140. #pragma alloc_text(PAGE, MfQueryStopFdo)
  141. #pragma alloc_text(PAGE, MfRemoveFdo)
  142. #pragma alloc_text(PAGE, MfStartFdo)
  143. #pragma alloc_text(PAGE, MfStartFdoInitializeArbiters)
  144. #pragma alloc_text(PAGE, MfSurpriseRemoveFdo)
  145. #endif
  146. PMF_DISPATCH MfPnpDispatchTableFdo[] = {
  147. MfStartFdo, // IRP_MN_START_DEVICE
  148. MfQueryRemoveFdo, // IRP_MN_QUERY_REMOVE_DEVICE
  149. MfRemoveFdo, // IRP_MN_REMOVE_DEVICE
  150. MfCancelRemoveFdo, // IRP_MN_CANCEL_REMOVE_DEVICE
  151. MfPassIrp, // IRP_MN_STOP_DEVICE
  152. MfQueryStopFdo, // IRP_MN_QUERY_STOP_DEVICE
  153. MfCancelStopFdo, // IRP_MN_CANCEL_STOP_DEVICE
  154. MfQueryDeviceRelationsFdo, // IRP_MN_QUERY_DEVICE_RELATIONS
  155. MfQueryInterfaceFdo, // IRP_MN_QUERY_INTERFACE
  156. MfQueryCapabilitiesFdo, // IRP_MN_QUERY_CAPABILITIES
  157. MfPassIrp, // IRP_MN_QUERY_RESOURCES
  158. MfPassIrp, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS
  159. MfPassIrp, // IRP_MN_QUERY_DEVICE_TEXT
  160. MfPassIrp, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
  161. MfPassIrp, // Unused
  162. MfPassIrp, // IRP_MN_READ_CONFIG
  163. MfPassIrp, // IRP_MN_WRITE_CONFIG
  164. MfPassIrp, // IRP_MN_EJECT
  165. MfPassIrp, // IRP_MN_SET_LOCK
  166. MfPassIrp, // IRP_MN_QUERY_ID
  167. MfPassIrp, // IRP_MN_QUERY_PNP_DEVICE_STATE
  168. MfPassIrp, // IRP_MN_QUERY_BUS_INFORMATION
  169. MfDeviceUsageNotificationCommon,// IRP_MN_DEVICE_USAGE_NOTIFICATION
  170. MfSurpriseRemoveFdo, // IRP_MN_SURPRISE_REMOVAL
  171. MfPassIrp // IRP_MN_QUERY_LEGACY_BUS_INFORMATION
  172. };
  173. PMF_DISPATCH MfPoDispatchTableFdo[] = {
  174. NULL, // IRP_MN_WAIT_WAKE
  175. NULL, // IRP_MN_POWER_SEQUENCE
  176. MfSetPowerFdo, // IRP_MN_SET_POWER
  177. MfQueryPowerFdo // IRP_MN_QUERY_POWER
  178. };
  179. NTSTATUS
  180. MfCreateFdo(
  181. OUT PDEVICE_OBJECT *Fdo
  182. )
  183. /*++
  184. Routine Description:
  185. This function creates a new FDO and initializes it.
  186. Arguments:
  187. Fdo - Pointer to where the FDO should be returned
  188. Return Value:
  189. Status code that indicates whether or not the function was successful.
  190. --*/
  191. {
  192. NTSTATUS status;
  193. PMF_PARENT_EXTENSION extension;
  194. PAGED_CODE();
  195. ASSERT((sizeof(MfPnpDispatchTableFdo) / sizeof(PMF_DISPATCH)) - 1
  196. == IRP_MN_PNP_MAXIMUM_FUNCTION);
  197. ASSERT((sizeof(MfPoDispatchTableFdo) / sizeof(PMF_DISPATCH)) -1
  198. == IRP_MN_PO_MAXIMUM_FUNCTION);
  199. *Fdo = NULL;
  200. status = IoCreateDevice(MfDriverObject,
  201. sizeof(MF_PARENT_EXTENSION),
  202. NULL,
  203. FILE_DEVICE_BUS_EXTENDER,
  204. 0,
  205. FALSE,
  206. Fdo
  207. );
  208. if (!NT_SUCCESS(status)) {
  209. goto cleanup;
  210. }
  211. //
  212. // Initialize the extension
  213. //
  214. extension = (PMF_PARENT_EXTENSION) (*Fdo)->DeviceExtension;
  215. MfInitCommonExtension(&extension->Common, MfFunctionalDeviceObject);
  216. extension->Self = *Fdo;
  217. InitializeListHead(&extension->Arbiters);
  218. InitializeListHead(&extension->Children);
  219. KeInitializeEvent(&extension->ChildrenLock, SynchronizationEvent, TRUE);
  220. KeInitializeSpinLock(&extension->PowerLock);
  221. IoInitializeRemoveLock(&extension->RemoveLock, MF_POOL_TAG, 1, 20);
  222. extension->Common.PowerState = PowerDeviceD3;
  223. DEBUG_MSG(1, ("Created FDO @ 0x%08x\n", *Fdo));
  224. return status;
  225. cleanup:
  226. if (*Fdo) {
  227. IoDeleteDevice(*Fdo);
  228. }
  229. return status;
  230. }
  231. VOID
  232. MfAcquireChildrenLock(
  233. IN PMF_PARENT_EXTENSION Parent
  234. )
  235. {
  236. KeWaitForSingleObject(&Parent->ChildrenLock,
  237. Executive,
  238. KernelMode,
  239. FALSE,
  240. NULL);
  241. }
  242. VOID
  243. MfReleaseChildrenLock(
  244. IN PMF_PARENT_EXTENSION Parent
  245. )
  246. {
  247. KeSetEvent(&Parent->ChildrenLock, 0, FALSE);
  248. }
  249. VOID
  250. MfDeleteFdo(
  251. IN PDEVICE_OBJECT Fdo
  252. )
  253. {
  254. PMF_PARENT_EXTENSION parent = Fdo->DeviceExtension;
  255. PMF_ARBITER current, next;
  256. if (parent->Common.DeviceState & MF_DEVICE_DELETED) {
  257. //
  258. // Trying to delete twice
  259. //
  260. ASSERT(!(parent->Common.DeviceState & MF_DEVICE_DELETED));
  261. return;
  262. }
  263. parent->Common.DeviceState = MF_DEVICE_DELETED;
  264. //
  265. // Free up any memory we have allocated
  266. //
  267. if (parent->ResourceList) {
  268. ExFreePool(parent->ResourceList);
  269. }
  270. if (parent->TranslatedResourceList) {
  271. ExFreePool(parent->TranslatedResourceList);
  272. }
  273. if (parent->DeviceID.Buffer) {
  274. ExFreePool(parent->DeviceID.Buffer);
  275. }
  276. if (parent->InstanceID.Buffer) {
  277. ExFreePool(parent->InstanceID.Buffer);
  278. }
  279. FOR_ALL_IN_LIST_SAFE(MF_ARBITER, &parent->Arbiters, current, next) {
  280. ArbDeleteArbiterInstance(&current->Instance);
  281. ExFreePool(current);
  282. }
  283. ASSERT(IsListEmpty(&parent->Children));
  284. IoDeleteDevice(Fdo);
  285. DEBUG_MSG(1, ("Deleted FDO @ 0x%08x\n", Fdo));
  286. }
  287. NTSTATUS
  288. MfPassIrp(
  289. IN PIRP Irp,
  290. IN PMF_PARENT_EXTENSION Parent,
  291. IN PIO_STACK_LOCATION IrpStack
  292. )
  293. {
  294. PAGED_CODE();
  295. IoSkipCurrentIrpStackLocation(Irp);
  296. return IoCallDriver(Parent->AttachedDevice, Irp);
  297. }
  298. NTSTATUS
  299. MfDispatchPnpFdo(
  300. IN PDEVICE_OBJECT DeviceObject,
  301. IN PMF_PARENT_EXTENSION Parent,
  302. IN PIO_STACK_LOCATION IrpStack,
  303. IN OUT PIRP Irp
  304. )
  305. /*++
  306. Routine Description:
  307. This routine handles IRP_MJ_PNP IRPs for FDOs.
  308. Arguments:
  309. DeviceObject - Pointer to the FDO for which this IRP applies.
  310. Parent - FDO extension
  311. IrpStack - Current stack location
  312. Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.
  313. Return Value:
  314. NT status.
  315. --*/
  316. {
  317. NTSTATUS status;
  318. BOOLEAN isRemoveDevice;
  319. PAGED_CODE();
  320. //
  321. // Get a pointer to our stack location and take appropriate action based
  322. // on the minor function.
  323. //
  324. IoAcquireRemoveLock(&Parent->RemoveLock, (PVOID) Irp);
  325. isRemoveDevice = IrpStack->MinorFunction == IRP_MN_REMOVE_DEVICE;
  326. if (IrpStack->MinorFunction > IRP_MN_PNP_MAXIMUM_FUNCTION) {
  327. status = MfPassIrp(Irp, Parent, IrpStack);
  328. } else {
  329. status =
  330. MfPnpDispatchTableFdo[IrpStack->MinorFunction](Irp,
  331. Parent,
  332. IrpStack
  333. );
  334. }
  335. if (!isRemoveDevice) {
  336. IoReleaseRemoveLock(&Parent->RemoveLock, (PVOID) Irp);
  337. }
  338. return status;
  339. }
  340. NTSTATUS
  341. MfPnPFdoCompletion(
  342. IN PDEVICE_OBJECT DeviceObject,
  343. IN PIRP Irp,
  344. IN PVOID Context
  345. )
  346. /*++
  347. Routine Description:
  348. This routine is used to defer processing of an IRP until drivers
  349. lower in the stack including the bus driver have done their
  350. processing.
  351. This routine triggers the event to indicate that processing of the
  352. irp can now continue.
  353. Arguments:
  354. DeviceObject - Pointer to the FDO for which this IRP applies.
  355. Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.
  356. Return Value:
  357. NT status.
  358. --*/
  359. {
  360. KeSetEvent((PKEVENT) Context, EVENT_INCREMENT, FALSE);
  361. return STATUS_MORE_PROCESSING_REQUIRED;
  362. }
  363. NTSTATUS
  364. MfDeferProcessingFdo(
  365. IN PMF_PARENT_EXTENSION Parent,
  366. IN OUT PIRP Irp
  367. )
  368. /*++
  369. Routine Description:
  370. This routine is used to defer processing of an IRP until drivers
  371. lower in the stack including the bus driver have done their
  372. processing.
  373. This routine uses an IoCompletion routine along with an event to
  374. wait until the lower level drivers have completed processing of
  375. the irp.
  376. Arguments:
  377. Parent - FDO extension for the FDO devobj in question
  378. Irp - Pointer to the IRP_MJ_PNP IRP to defer
  379. Return Value:
  380. NT status.
  381. --*/
  382. {
  383. KEVENT event;
  384. NTSTATUS status;
  385. PAGED_CODE();
  386. KeInitializeEvent(&event, NotificationEvent, FALSE);
  387. //
  388. // Set our completion routine
  389. //
  390. IoCopyCurrentIrpStackLocationToNext(Irp);
  391. IoSetCompletionRoutine(Irp,
  392. MfPnPFdoCompletion,
  393. &event,
  394. TRUE,
  395. TRUE,
  396. TRUE
  397. );
  398. status = IoCallDriver(Parent->AttachedDevice, Irp);
  399. if (status == STATUS_PENDING) {
  400. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  401. status = Irp->IoStatus.Status;
  402. }
  403. return status;
  404. }
  405. NTSTATUS
  406. MfStartFdoInitializeArbiters(
  407. IN PMF_PARENT_EXTENSION Parent,
  408. IN PCM_RESOURCE_LIST ResList,
  409. IN PCM_RESOURCE_LIST TranslatedResList
  410. )
  411. {
  412. NTSTATUS status;
  413. ULONG size;
  414. ULONG count;
  415. PAGED_CODE();
  416. DEBUG_MSG(1, ("Start Fdo arbiters intiialization\n"));
  417. //
  418. // If we were started with any resources then remember them
  419. //
  420. if (ResList && TranslatedResList) {
  421. #if DBG
  422. MfDbgPrintCmResList(1, ResList);
  423. #endif
  424. //
  425. // We only deal with resources on a single bus - which is all we
  426. // should see in a start irp.
  427. //
  428. ASSERT(ResList->Count == 1);
  429. ASSERT(TranslatedResList->Count == 1);
  430. //
  431. // Both lists should have the same number of descriptors
  432. //
  433. ASSERT(ResList->List[0].PartialResourceList.Count == TranslatedResList->List[0].PartialResourceList.Count);
  434. //
  435. // Calculate the size of the resouceList
  436. //
  437. size = sizeof(CM_RESOURCE_LIST) +
  438. ((ResList->List[0].PartialResourceList.Count - 1) *
  439. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
  440. //
  441. // Allocate a buffer and copy the data
  442. //
  443. Parent->ResourceList = ExAllocatePoolWithTag(NonPagedPool,
  444. size,
  445. MF_PARENTS_RESOURCE_TAG
  446. );
  447. if (!Parent->ResourceList) {
  448. status = STATUS_INSUFFICIENT_RESOURCES;
  449. goto cleanup;
  450. }
  451. RtlCopyMemory(Parent->ResourceList, ResList, size);
  452. //
  453. // do the same for the TranslatedResList.
  454. //
  455. Parent->TranslatedResourceList = ExAllocatePoolWithTag(NonPagedPool,
  456. size,
  457. MF_PARENTS_RESOURCE_TAG
  458. );
  459. if (!Parent->TranslatedResourceList) {
  460. status = STATUS_INSUFFICIENT_RESOURCES;
  461. goto cleanup;
  462. }
  463. RtlCopyMemory(Parent->TranslatedResourceList, TranslatedResList, size);
  464. //
  465. // As we have resources we are going to need some arbiters
  466. //
  467. status = MfInitializeArbiters(Parent);
  468. if (!NT_SUCCESS(status)) {
  469. goto cleanup;
  470. }
  471. } else {
  472. DEBUG_MSG(1, ("Parent started with no resources\n"));
  473. }
  474. return STATUS_SUCCESS;
  475. cleanup:
  476. if (Parent->ResourceList) {
  477. ExFreePool(Parent->ResourceList);
  478. Parent->ResourceList = NULL;
  479. }
  480. if (Parent->TranslatedResourceList) {
  481. ExFreePool(Parent->TranslatedResourceList);
  482. Parent->TranslatedResourceList = NULL;
  483. }
  484. return status;
  485. }
  486. // REBALANCE
  487. //
  488. // FUTURE DESIGN NOTE:
  489. // If rebalance was actually supported by this component i.e arbiters
  490. // become stoppable, then there are various issues raised by the start
  491. // code. It performs a number of operations assuming that the device
  492. // has never been started before including the query ids, resource
  493. // list storage, etc. There are also issues in redistributing these
  494. // new resources to the children. The current requirements given to
  495. // the children are absolute. Relative requirements have some other
  496. // issues.
  497. //
  498. NTSTATUS
  499. MfStartFdo(
  500. IN PIRP Irp,
  501. IN PMF_PARENT_EXTENSION Parent,
  502. IN PIO_STACK_LOCATION IrpStack
  503. )
  504. {
  505. NTSTATUS status;
  506. IO_STACK_LOCATION location;
  507. PWSTR string;
  508. PAGED_CODE();
  509. status = MfDeferProcessingFdo(Parent, Irp);
  510. if (!NT_SUCCESS(status)) {
  511. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  512. return status;
  513. }
  514. Parent->Common.PowerState = PowerDeviceD0;
  515. //
  516. // We need to find out some information about our parent
  517. //
  518. Parent->DeviceID.Buffer = NULL;
  519. Parent->InstanceID.Buffer = NULL;
  520. RtlZeroMemory(&location, sizeof(IO_STACK_LOCATION));
  521. location.MajorFunction = IRP_MJ_PNP;
  522. location.MinorFunction = IRP_MN_QUERY_ID;
  523. //
  524. // ...DeviceID...
  525. //
  526. location.Parameters.QueryId.IdType = BusQueryDeviceID;
  527. status = MfSendPnpIrp(Parent->PhysicalDeviceObject,
  528. &location,
  529. (PULONG_PTR)&string
  530. );
  531. if (!NT_SUCCESS(status)) {
  532. goto cleanup;
  533. }
  534. RtlInitUnicodeString(&Parent->DeviceID, string);
  535. DEBUG_MSG(1, ("Parent DeviceID: %wZ\n", &Parent->DeviceID));
  536. //
  537. // ...InstanceID
  538. //
  539. location.Parameters.QueryId.IdType = BusQueryInstanceID;
  540. status = MfSendPnpIrp(Parent->PhysicalDeviceObject,
  541. &location,
  542. (PULONG_PTR)&string
  543. );
  544. if (!NT_SUCCESS(status)) {
  545. goto cleanup;
  546. }
  547. RtlInitUnicodeString(&Parent->InstanceID, string);
  548. DEBUG_MSG(1, ("Parent InstanceID: %wZ\n", &Parent->InstanceID));
  549. status = MfStartFdoInitializeArbiters(
  550. Parent,
  551. IrpStack->Parameters.StartDevice.AllocatedResources,
  552. IrpStack->Parameters.StartDevice.AllocatedResourcesTranslated
  553. );
  554. cleanup:
  555. Irp->IoStatus.Status = status;
  556. if (!NT_SUCCESS(status)) {
  557. if (Parent->DeviceID.Buffer) {
  558. ExFreePool(Parent->DeviceID.Buffer);
  559. Parent->DeviceID.Buffer = NULL;
  560. }
  561. if (Parent->InstanceID.Buffer) {
  562. ExFreePool(Parent->InstanceID.Buffer);
  563. Parent->InstanceID.Buffer = NULL;
  564. }
  565. } else {
  566. //
  567. // We are now started!
  568. //
  569. }
  570. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  571. return status;
  572. }
  573. NTSTATUS
  574. MfQueryStopFdo(
  575. IN PIRP Irp,
  576. IN PMF_PARENT_EXTENSION Parent,
  577. IN PIO_STACK_LOCATION IrpStack
  578. )
  579. {
  580. PAGED_CODE();
  581. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  582. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  583. return STATUS_UNSUCCESSFUL;
  584. }
  585. NTSTATUS
  586. MfCancelStopFdo(
  587. IN PIRP Irp,
  588. IN PMF_PARENT_EXTENSION Parent,
  589. IN PIO_STACK_LOCATION IrpStack
  590. )
  591. {
  592. NTSTATUS status;
  593. PAGED_CODE();
  594. status = MfDeferProcessingFdo(Parent, Irp);
  595. // NTRAID#53498
  596. // ASSERT(status == STATUS_SUCCESS);
  597. // Uncomment after PCI state machine is fixed to not fail bogus stops
  598. Irp->IoStatus.Status = STATUS_SUCCESS;
  599. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  600. return STATUS_SUCCESS;
  601. }
  602. NTSTATUS
  603. MfQueryRemoveFdo(
  604. IN PIRP Irp,
  605. IN PMF_PARENT_EXTENSION Parent,
  606. IN PIO_STACK_LOCATION IrpStack
  607. )
  608. {
  609. PAGED_CODE();
  610. Irp->IoStatus.Status = STATUS_SUCCESS;
  611. return MfPassIrp(Irp, Parent, IrpStack);
  612. }
  613. NTSTATUS
  614. MfRemoveFdo(
  615. IN PIRP Irp,
  616. IN PMF_PARENT_EXTENSION Parent,
  617. IN PIO_STACK_LOCATION IrpStack
  618. )
  619. {
  620. PMF_CHILD_EXTENSION current;
  621. PLIST_ENTRY currentEntry;
  622. NTSTATUS status;
  623. //
  624. // If we have any children then make sure they are removed and
  625. // delete them.
  626. //
  627. MfAcquireChildrenLock(Parent);
  628. while (!IsListEmpty(&Parent->Children)) {
  629. currentEntry = RemoveHeadList(&Parent->Children);
  630. ASSERT(currentEntry);
  631. current = CONTAINING_RECORD(currentEntry, MF_CHILD_EXTENSION,
  632. ListEntry);
  633. //
  634. // * If this child has been surprise removed, and hasn't
  635. // received the subsequent remove, then leave
  636. // the PDO intact but mark it 'missing'.
  637. //
  638. // * If this child has handled a previous remove (this is
  639. // fundamentally the case if we've gotten to the point of
  640. // removing the parent) and hasn't subsequently received a
  641. // surprise remove, then delete the pdo.
  642. //
  643. if (current->Common.DeviceState & MF_DEVICE_SURPRISE_REMOVED) {
  644. //
  645. // Mark as 'missing' and unlink dangerous reference to parent
  646. //
  647. current->Parent = NULL;
  648. current->Common.DeviceState &= ~MF_DEVICE_ENUMERATED;
  649. } else {
  650. MfDeletePdo(current);
  651. }
  652. }
  653. MfReleaseChildrenLock(Parent);
  654. Parent->Common.PowerState = PowerDeviceD3;
  655. Irp->IoStatus.Status = STATUS_SUCCESS;
  656. status = MfPassIrp(Irp, Parent, IrpStack);
  657. ASSERT(NT_SUCCESS(status));
  658. IoReleaseRemoveLockAndWait(&Parent->RemoveLock, (PVOID) Irp);
  659. //
  660. // Detach and delete myself
  661. //
  662. IoDetachDevice(Parent->AttachedDevice);
  663. Parent->AttachedDevice = NULL;
  664. MfDeleteFdo(Parent->Self);
  665. return status;
  666. }
  667. NTSTATUS
  668. MfSurpriseRemoveFdo(
  669. IN PIRP Irp,
  670. IN PMF_PARENT_EXTENSION Parent,
  671. IN PIO_STACK_LOCATION IrpStack
  672. )
  673. {
  674. PLIST_ENTRY currentEntry;
  675. PMF_CHILD_EXTENSION current;
  676. PAGED_CODE();
  677. Parent->Common.DeviceState |= MF_DEVICE_SURPRISE_REMOVED;
  678. MfAcquireChildrenLock(Parent);
  679. for (currentEntry = Parent->Children.Flink;
  680. currentEntry != &Parent->Children;
  681. currentEntry = currentEntry->Flink) {
  682. current = CONTAINING_RECORD(currentEntry,
  683. MF_CHILD_EXTENSION,
  684. ListEntry);
  685. current->Common.DeviceState &= ~MF_DEVICE_ENUMERATED;
  686. }
  687. MfReleaseChildrenLock(Parent);
  688. Irp->IoStatus.Status = STATUS_SUCCESS;
  689. return MfPassIrp(Irp, Parent, IrpStack);
  690. }
  691. NTSTATUS
  692. MfCancelRemoveFdo(
  693. IN PIRP Irp,
  694. IN PMF_PARENT_EXTENSION Parent,
  695. IN PIO_STACK_LOCATION IrpStack
  696. )
  697. {
  698. NTSTATUS status;
  699. PAGED_CODE();
  700. status = MfDeferProcessingFdo(Parent, Irp);
  701. // NTRAID#53498
  702. // ASSERT(status == STATUS_SUCCESS);
  703. // Uncomment after PCI state machine is fixed to not fail bogus stops
  704. Irp->IoStatus.Status = STATUS_SUCCESS;
  705. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  706. return STATUS_SUCCESS;
  707. }
  708. NTSTATUS
  709. MfQueryDeviceRelationsFdo(
  710. IN PIRP Irp,
  711. IN PMF_PARENT_EXTENSION Parent,
  712. IN PIO_STACK_LOCATION IrpStack
  713. )
  714. {
  715. NTSTATUS status;
  716. PDEVICE_RELATIONS relations = NULL;
  717. ULONG relationsSize, childrenCount, i;
  718. PDEVICE_OBJECT *currentRelation;
  719. PMF_CHILD_EXTENSION currentChild;
  720. PLIST_ENTRY currentEntry;
  721. PAGED_CODE();
  722. DEBUG_MSG(1,
  723. ("%s\n",
  724. RELATION_STRING(IrpStack->Parameters.QueryDeviceRelations.Type)
  725. ));
  726. switch (IrpStack->Parameters.QueryDeviceRelations.Type) {
  727. case BusRelations:
  728. MfAcquireChildrenLock(Parent);
  729. status = MfEnumerate(Parent);
  730. if (!NT_SUCCESS(status)) {
  731. MfReleaseChildrenLock(Parent);
  732. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  733. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  734. return STATUS_UNSUCCESSFUL;
  735. }
  736. childrenCount = 0;
  737. for (currentEntry = Parent->Children.Flink;
  738. currentEntry != &Parent->Children;
  739. currentEntry = currentEntry->Flink) {
  740. childrenCount++;
  741. }
  742. if (childrenCount == 0) {
  743. relationsSize = sizeof(DEVICE_RELATIONS);
  744. } else {
  745. relationsSize = sizeof(DEVICE_RELATIONS) +
  746. (childrenCount-1) * sizeof(PDEVICE_OBJECT);
  747. }
  748. relations = ExAllocatePoolWithTag(PagedPool,
  749. relationsSize,
  750. MF_BUS_RELATIONS_TAG
  751. );
  752. if (!relations) {
  753. MfReleaseChildrenLock(Parent);
  754. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  755. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  756. return STATUS_INSUFFICIENT_RESOURCES;
  757. }
  758. RtlZeroMemory(relations, relationsSize);
  759. //
  760. // Iterate through the list of children in the parent and build the
  761. // relations structure
  762. //
  763. currentRelation = relations->Objects;
  764. relations->Count = childrenCount;
  765. for (currentEntry = Parent->Children.Flink;
  766. currentEntry != &Parent->Children;
  767. currentEntry = currentEntry->Flink) {
  768. currentChild = CONTAINING_RECORD(currentEntry,
  769. MF_CHILD_EXTENSION,
  770. ListEntry);
  771. currentChild->Common.DeviceState |= MF_DEVICE_ENUMERATED;
  772. ObReferenceObject(currentChild->Self);
  773. *currentRelation = currentChild->Self;
  774. #if DBG
  775. DEBUG_MSG(1, ("\tPDO Enumerated @ 0x%08x\n", currentChild));
  776. DEBUG_MSG(1, ("\tName: %wZ\n", &currentChild->Info.Name));
  777. DEBUG_MSG(1, ("\tHardwareID: "));
  778. MfDbgPrintMultiSz(1, currentChild->Info.HardwareID.Buffer);
  779. DEBUG_MSG(1, ("\tCompatibleID: "));
  780. MfDbgPrintMultiSz(1, currentChild->Info.CompatibleID.Buffer);
  781. DEBUG_MSG(1, ("\tResourceMap: "));
  782. MfDbgPrintResourceMap(1, currentChild->Info.ResourceMap);
  783. DEBUG_MSG(1, ("\tVaryingMap: "));
  784. MfDbgPrintVaryingResourceMap(1, currentChild->Info.VaryingResourceMap);
  785. DEBUG_MSG(1, ("\tFlags: 0x%08x\n", currentChild->Info.MfFlags));
  786. #endif
  787. currentRelation++;
  788. }
  789. MfReleaseChildrenLock(Parent);
  790. //
  791. // Hand back the relations
  792. //
  793. Irp->IoStatus.Information = (ULONG_PTR) relations;
  794. Irp->IoStatus.Status = STATUS_SUCCESS;
  795. break;
  796. //
  797. // For the rest of the relations just pass down the irp untouched.
  798. //
  799. default:
  800. break;
  801. }
  802. return MfPassIrp(Irp, Parent, IrpStack);
  803. }
  804. VOID
  805. MfArbiterReference(
  806. PVOID Context
  807. )
  808. {
  809. }
  810. VOID
  811. MfArbiterDereference(
  812. PVOID Context
  813. )
  814. {
  815. }
  816. NTSTATUS
  817. MfQueryInterfaceFdo(
  818. IN PIRP Irp,
  819. IN PMF_PARENT_EXTENSION Parent,
  820. IN PIO_STACK_LOCATION IrpStack
  821. )
  822. {
  823. PMF_ARBITER current;
  824. PARBITER_INTERFACE interface = (PARBITER_INTERFACE) IrpStack->Parameters.QueryInterface.Interface;
  825. PAGED_CODE();
  826. //
  827. // We only provide arbiters
  828. //
  829. if (MfCompareGuid(&GUID_ARBITER_INTERFACE_STANDARD,
  830. IrpStack->Parameters.QueryInterface.InterfaceType)) {
  831. //
  832. // We only support version 1 of the ARBITER_INTERFACE so we
  833. // don't need to bother checking version numbers, just that the
  834. // return buffer is big enough
  835. //
  836. if (IrpStack->Parameters.QueryInterface.Size < sizeof(ARBITER_INTERFACE)) {
  837. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  838. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  839. return STATUS_BUFFER_TOO_SMALL;
  840. }
  841. FOR_ALL_IN_LIST(MF_ARBITER, &Parent->Arbiters, current) {
  842. if (current->Type == (CM_RESOURCE_TYPE)((ULONG_PTR)
  843. IrpStack->Parameters.QueryInterface.InterfaceSpecificData)) {
  844. DEBUG_MSG(1,(" Returning Arbiter interface\n"));
  845. //
  846. // Fill in the interface
  847. //
  848. interface->Size = sizeof(ARBITER_INTERFACE);
  849. interface->Version = MF_ARBITER_INTERFACE_VERSION;
  850. interface->Context = &current->Instance;
  851. interface->InterfaceReference = MfArbiterReference;
  852. interface->InterfaceDereference = MfArbiterDereference;
  853. interface->ArbiterHandler = ArbArbiterHandler;
  854. interface->Flags = 0;
  855. Irp->IoStatus.Status = STATUS_SUCCESS;
  856. break;
  857. }
  858. }
  859. }
  860. return MfPassIrp(Irp, Parent, IrpStack);
  861. }
  862. NTSTATUS
  863. MfQueryCapabilitiesFdo(
  864. IN PIRP Irp,
  865. IN PMF_PARENT_EXTENSION Parent,
  866. IN PIO_STACK_LOCATION IrpStack
  867. )
  868. {
  869. NTSTATUS status;
  870. PAGED_CODE();
  871. status = MfDeferProcessingFdo(Parent, Irp);
  872. if (!NT_SUCCESS(status)) {
  873. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  874. return status;
  875. }
  876. if (IrpStack->Parameters.DeviceCapabilities.Capabilities->Version != 1) {
  877. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  878. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  879. return STATUS_INVALID_PARAMETER;
  880. }
  881. IrpStack->Parameters.DeviceCapabilities.Capabilities->WakeFromD0 =
  882. IrpStack->Parameters.DeviceCapabilities.Capabilities->WakeFromD1 =
  883. IrpStack->Parameters.DeviceCapabilities.Capabilities->WakeFromD2 =
  884. IrpStack->Parameters.DeviceCapabilities.Capabilities->WakeFromD3 = 0;
  885. IrpStack->Parameters.DeviceCapabilities.Capabilities->DeviceWake =
  886. PowerSystemUnspecified;
  887. IrpStack->Parameters.DeviceCapabilities.Capabilities->SystemWake =
  888. PowerSystemUnspecified;
  889. Irp->IoStatus.Status = STATUS_SUCCESS;
  890. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  891. return STATUS_SUCCESS;
  892. }
  893. NTSTATUS
  894. MfDispatchPowerFdo(
  895. IN PDEVICE_OBJECT DeviceObject,
  896. PMF_PARENT_EXTENSION Parent,
  897. PIO_STACK_LOCATION IrpStack,
  898. IN PIRP Irp
  899. )
  900. /*++
  901. Routine Description:
  902. This routine handles all IRP_MJ_POWER IRPs for the FDO. It dispatches
  903. to the routines described in the PoDispatchTable entry in the device object
  904. extension.
  905. This routine is NOT pageable as it can be called at DISPATCH_LEVEL
  906. Arguments:
  907. DeviceObject - Pointer to the device object for which this IRP applies.
  908. Parent - FDO Extension
  909. Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.
  910. Return Value:
  911. NT status.
  912. --*/
  913. {
  914. NTSTATUS status;
  915. PMF_COMMON_EXTENSION common = (PMF_COMMON_EXTENSION) Parent;
  916. IoAcquireRemoveLock(&Parent->RemoveLock, (PVOID) Irp);
  917. //
  918. // Call the appropriate function
  919. //
  920. if ((IrpStack->MinorFunction <= IRP_MN_PO_MAXIMUM_FUNCTION) &&
  921. (MfPoDispatchTableFdo[IrpStack->MinorFunction])) {
  922. status =
  923. MfPoDispatchTableFdo[IrpStack->MinorFunction](Irp,
  924. (PVOID) common,
  925. IrpStack
  926. );
  927. } else {
  928. //
  929. // We don't know about this irp
  930. //
  931. DEBUG_MSG(0,
  932. ("Unknown POWER IRP 0x%x for FDO 0x%08x\n",
  933. IrpStack->MinorFunction,
  934. DeviceObject
  935. ));
  936. PoStartNextPowerIrp(Irp);
  937. IoSkipCurrentIrpStackLocation(Irp);
  938. status = PoCallDriver(Parent->AttachedDevice, Irp);
  939. }
  940. IoReleaseRemoveLock(&Parent->RemoveLock, (PVOID) Irp);
  941. return status;
  942. }
  943. NTSTATUS
  944. MfQueryPowerFdo(
  945. IN PIRP Irp,
  946. IN PMF_PARENT_EXTENSION Parent,
  947. IN PIO_STACK_LOCATION IrpStack
  948. )
  949. {
  950. PoStartNextPowerIrp(Irp);
  951. IoSkipCurrentIrpStackLocation(Irp);
  952. Irp->IoStatus.Status = STATUS_SUCCESS;
  953. return PoCallDriver(Parent->AttachedDevice, Irp);
  954. }
  955. NTSTATUS
  956. MfSetPowerFdoCompletion(
  957. IN PDEVICE_OBJECT DeviceObject,
  958. IN PIRP Irp,
  959. IN PVOID Context
  960. )
  961. {
  962. PMF_PARENT_EXTENSION parent = DeviceObject->DeviceExtension;
  963. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  964. //
  965. // Remember the parent's power state
  966. //
  967. if (irpStack->Parameters.Power.Type == DevicePowerState) {
  968. parent->Common.PowerState =
  969. irpStack->Parameters.Power.State.DeviceState;
  970. }
  971. return STATUS_SUCCESS;
  972. }
  973. NTSTATUS
  974. MfSetPowerFdo(
  975. IN PIRP Irp,
  976. IN PMF_PARENT_EXTENSION Parent,
  977. IN PIO_STACK_LOCATION IrpStack
  978. )
  979. {
  980. PoStartNextPowerIrp(Irp);
  981. IoCopyCurrentIrpStackLocationToNext(Irp);
  982. IoSetCompletionRoutine(Irp,
  983. MfSetPowerFdoCompletion,
  984. NULL, //Context
  985. TRUE, //InvokeOnSuccess
  986. FALSE, //InvokeOnError
  987. FALSE //InvokeOnCancel
  988. );
  989. Irp->IoStatus.Status = STATUS_SUCCESS;
  990. return PoCallDriver(Parent->AttachedDevice, Irp);
  991. }