/*++ Copyright (c) 1990-2000 Microsoft Corporation Module Name: fdopnp.c Abstract: This file contains the PNP IRP dispatch code for FDOs Environment: Kernel Mode Driver. Revision History: --*/ #include "busp.h" #include "pnpisa.h" #include #include "halpnpp.h" // // Function Prototypes // NTSTATUS PiDeferProcessingFdo( IN PPI_BUS_EXTENSION BusExtension, IN OUT PIRP Irp ); NTSTATUS PiStartFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ); NTSTATUS PiQueryRemoveStopFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ); NTSTATUS PiCancelRemoveStopFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ); NTSTATUS PiStopFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ); NTSTATUS PiQueryDeviceRelationsFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ); NTSTATUS PiRemoveFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ); NTSTATUS PiQueryLegacyBusInformationFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ); NTSTATUS PiQueryInterfaceFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ); NTSTATUS PiQueryPnpDeviceState( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ); NTSTATUS PiSurpriseRemoveFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE,PiDispatchPnpFdo) #pragma alloc_text(PAGE,PiDeferProcessingFdo) #pragma alloc_text(PAGE,PiStartFdo) #pragma alloc_text(PAGE,PiQueryRemoveStopFdo) #pragma alloc_text(PAGE,PiRemoveFdo) #pragma alloc_text(PAGE,PiCancelRemoveStopFdo) #pragma alloc_text(PAGE,PiStopFdo) #pragma alloc_text(PAGE,PiQueryRemoveStopFdo) #pragma alloc_text(PAGE,PiCancelRemoveStopFdo) #pragma alloc_text(PAGE,PiQueryDeviceRelationsFdo) #pragma alloc_text(PAGE,PiQueryInterfaceFdo) #pragma alloc_text(PAGE,PipPassIrp) #pragma alloc_text(PAGE,PiQueryLegacyBusInformationFdo) #pragma alloc_text(PAGE,PiQueryPnpDeviceState) #pragma alloc_text(PAGE,PiSurpriseRemoveFdo) #endif // // PNP IRP Dispatch table for FDOs // PPI_DISPATCH PiPnpDispatchTableFdo[] = { PiStartFdo, // IRP_MN_START_DEVICE PiQueryRemoveStopFdo, // IRP_MN_QUERY_REMOVE_DEVICE PiRemoveFdo, // IRP_MN_REMOVE_DEVICE PiCancelRemoveStopFdo, // IRP_MN_CANCEL_REMOVE_DEVICE PiStopFdo, // IRP_MN_STOP_DEVICE PiQueryRemoveStopFdo, // IRP_MN_QUERY_STOP_DEVICE PiCancelRemoveStopFdo, // IRP_MN_CANCEL_STOP_DEVICE PiQueryDeviceRelationsFdo, // IRP_MN_QUERY_DEVICE_RELATIONS PiQueryInterfaceFdo, // IRP_MN_QUERY_INTERFACE PipPassIrp, // IRP_MN_QUERY_CAPABILITIES PipPassIrp, // IRP_MN_QUERY_RESOURCES PipPassIrp, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS PipPassIrp, // IRP_MN_QUERY_DEVICE_TEXT PipPassIrp, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS PipPassIrp, // Unused PipPassIrp, // IRP_MN_READ_CONFIG PipPassIrp, // IRP_MN_WRITE_CONFIG PipPassIrp, // IRP_MN_EJECT PipPassIrp, // IRP_MN_SET_LOCK PipPassIrp, // IRP_MN_QUERY_ID PiQueryPnpDeviceState, // IRP_MN_QUERY_PNP_DEVICE_STATE PipPassIrp, // IRP_MN_QUERY_BUS_INFORMATION PipPassIrp, // IRP_MN_DEVICE_USAGE_NOTIFICATION PiSurpriseRemoveFdo, // IRP_MN_SURPRISE_REMOVAL PiQueryLegacyBusInformationFdo // IRP_MN_QUERY_LEGACY_BUS_INFORMATION }; // // Function declarations // NTSTATUS PiDispatchPnpFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) /*++ Routine Description: This routine handles IRP_MJ_PNP IRPs for FDOs. Arguments: DeviceObject - Pointer to the FDO for which this IRP applies. Irp - Pointer to the IRP_MJ_PNP IRP to dispatch. Return Value: NT status. --*/ { PIO_STACK_LOCATION irpSp; NTSTATUS status; PPI_BUS_EXTENSION busExtension; PAGED_CODE(); // // Get a pointer to our stack location and take appropriate action based // on the minor function. // irpSp = IoGetCurrentIrpStackLocation(Irp); busExtension = DeviceObject->DeviceExtension; if (irpSp->MinorFunction > IRP_MN_PNP_MAXIMUM_FUNCTION) { return PipPassIrp(DeviceObject, Irp); } else { status = PiPnpDispatchTableFdo[irpSp->MinorFunction](DeviceObject, Irp); } return status; } //PipDispatchPnpFdo NTSTATUS PiPnPFdoCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++ Routine Description: This routine is used to defer processing of an IRP until drivers lower in the stack including the bus driver have done their processing. This routine triggers the event to indicate that processing of the irp can now continue. Arguments: DeviceObject - Pointer to the FDO for which this IRP applies. Irp - Pointer to the IRP_MJ_PNP IRP to dispatch. Return Value: NT status. --*/ { KeSetEvent((PKEVENT) Context, EVENT_INCREMENT, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } NTSTATUS PiDeferProcessingFdo( IN PPI_BUS_EXTENSION BusExtension, IN OUT PIRP Irp ) /*++ Routine Description: This routine is used to defer processing of an IRP until drivers lower in the stack including the bus driver have done their processing. This routine uses an IoCompletion routine along with an event to wait until the lower level drivers have completed processing of the irp. Arguments: BusExtension - FDO extension for the FDO devobj in question Irp - Pointer to the IRP_MJ_PNP IRP to defer Return Value: NT status. --*/ { KEVENT event; NTSTATUS status; KeInitializeEvent(&event, NotificationEvent, FALSE); // // Set our completion routine // IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, PiPnPFdoCompletion, &event, TRUE, TRUE, TRUE ); status = IoCallDriver(BusExtension->AttachedDevice, Irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); status = Irp->IoStatus.Status; } return status; } NTSTATUS PiStartFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PPI_BUS_EXTENSION busExtension; NTSTATUS status; DebugPrint((DEBUG_PNP, "*** StartDevice irp received FDO: %x\n",DeviceObject)); busExtension = DeviceObject->DeviceExtension; // // Postpones start operations until all lower drivers have // finished with the IRP. // status = PiDeferProcessingFdo(busExtension, Irp); if (NT_SUCCESS(status)) { busExtension->SystemPowerState = PowerSystemWorking; busExtension->DevicePowerState = PowerDeviceD0; } IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } // PiStartFdo NTSTATUS PiQueryRemoveStopFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { NTSTATUS status; PPI_BUS_EXTENSION busExtension; DebugPrint((DEBUG_PNP, "*** QR/R/StopDevice irp received FDO: %x\n",DeviceObject)); busExtension = DeviceObject->DeviceExtension; KeWaitForSingleObject( &IsaBusNumberLock, Executive, KernelMode, FALSE, NULL ); if (busExtension->BusNumber != 0) { status = PipReleaseInterfaces(busExtension); if (!NT_SUCCESS(status)) { PipCompleteRequest(Irp,status,NULL); return status; } ActiveIsaCount--; busExtension->Flags |= DF_QUERY_STOPPED; } else { Irp->IoStatus.Status = status = STATUS_UNSUCCESSFUL; IoCompleteRequest (Irp,IO_NO_INCREMENT); } KeSetEvent( &IsaBusNumberLock, 0, FALSE ); if (NT_SUCCESS(status)) { Irp->IoStatus.Status = STATUS_SUCCESS; status = PipPassIrp(DeviceObject, Irp); } DebugPrint((DEBUG_PNP, "QR/R/Stop Device returning: %x\n",status)); return status; } // PiQueryRemoveStopFdo NTSTATUS PiCancelRemoveStopFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { NTSTATUS status; PPI_BUS_EXTENSION busExtension; DebugPrint((DEBUG_PNP, "*** Cancel R/Stop Device irp received FDO: %x\n",DeviceObject)); busExtension = DeviceObject->DeviceExtension; status = PiDeferProcessingFdo(busExtension, Irp); // NTRAID#53498 // ASSERT(status == STATUS_SUCCESS); // Uncomment after PCI state machine is fixed to not fail bogus stops // // Add back to active count // KeWaitForSingleObject( &IsaBusNumberLock, Executive, KernelMode, FALSE, NULL ); if (busExtension->Flags & DF_QUERY_STOPPED) { ActiveIsaCount++; } busExtension->Flags &= ~DF_QUERY_STOPPED; KeSetEvent( &IsaBusNumberLock, 0, FALSE ); status = PipRebuildInterfaces (busExtension); ASSERT(status == STATUS_SUCCESS); PipCompleteRequest(Irp, STATUS_SUCCESS, NULL); DebugPrint((DEBUG_PNP, "Cancel R/Stop Device returning: %x\n",status)); return STATUS_SUCCESS; } // PiCancelRemoveStopFdo NTSTATUS PiStopFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PPI_BUS_EXTENSION busExtension; NTSTATUS status; DebugPrint((DEBUG_PNP, "*** Stop Device irp received FDO: %x\n",DeviceObject)); busExtension = DeviceObject->DeviceExtension; KeWaitForSingleObject( &IsaBusNumberLock, Executive, KernelMode, FALSE, NULL ); // //Actually clear the bitmap // ASSERT (RtlAreBitsSet (BusNumBM,busExtension->BusNumber,1)); RtlClearBits (BusNumBM,busExtension->BusNumber,1); KeSetEvent( &IsaBusNumberLock, 0, FALSE ); busExtension->DevicePowerState = PowerDeviceD3; // // Handled in QueryStop, pass it down. // Irp->IoStatus.Status = STATUS_SUCCESS; status = PipPassIrp (DeviceObject,Irp); DebugPrint((DEBUG_PNP, "Stop Device returning: %x\n",status)); return status; } // PiStopFdo NTSTATUS PiQueryDeviceRelationsFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PPI_BUS_EXTENSION busExtension; PIO_STACK_LOCATION irpSp; PDEVICE_RELATIONS deviceRelations; PDEVICE_INFORMATION deviceInfo; PSINGLE_LIST_ENTRY deviceLink; BOOLEAN creatingRDP=FALSE,accessHW; NTSTATUS status; DebugPrint((DEBUG_PNP, "QueryDeviceRelations FDO %x\n", DeviceObject)); busExtension = DeviceObject->DeviceExtension; irpSp = IoGetCurrentIrpStackLocation(Irp); #if ISOLATE_CARDS // // Only support BusRelations on PnpIsa bus PDO. // switch (irpSp->Parameters.QueryDeviceRelations.Type) { case BusRelations: { // // Isolation may have been disabled via registry key. In // that case, never enumerate an RDP. // // Note: Must return success and empty relations list // *RATHER* than just passing the irp down to accomplish // the same task due because of assumptions in the pnpres // code. // if (PipIsolationDisabled) { deviceRelations = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS)); if (deviceRelations) { deviceRelations->Count = 0; Irp->IoStatus.Information = (ULONG_PTR) deviceRelations; Irp->IoStatus.Status = STATUS_SUCCESS; } else { PipCompleteRequest(Irp,STATUS_INSUFFICIENT_RESOURCES,NULL); return STATUS_INSUFFICIENT_RESOURCES; } break; } // // All relations exist on the 'root' isa bus. (don't ask) // if (busExtension->BusNumber != 0) { break; } if (PipRDPNode) { // // overload the notion of "creating" for multi-bridge systems // if (PipRDPNode->Flags & (DF_PROCESSING_RDP|DF_ACTIVATED)) { creatingRDP=TRUE; } } if (PipReadDataPort == NULL && !creatingRDP && !PipRDPNode ) { status = PipCreateReadDataPort(busExtension); if (!NT_SUCCESS(status)) { PipCompleteRequest(Irp, status, NULL); return status; } creatingRDP=TRUE; } if ((PipRDPNode && (creatingRDP) && !(PipRDPNode->Flags & DF_ACTIVATED)) || (PipRDPNode && (PipRDPNode->Flags & DF_REMOVED))) { deviceRelations = (PDEVICE_RELATIONS) ExAllocatePool( PagedPool, sizeof(DEVICE_RELATIONS) ); if (deviceRelations) { // // If a device exists, mark it as disappeared so // it's not reported again // PipLockDeviceDatabase(); deviceLink = busExtension->DeviceList.Next; while (deviceLink) { deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList); if (!(deviceInfo->Flags & DF_READ_DATA_PORT)) { deviceInfo->Flags &= ~DF_ENUMERATED; } deviceLink = deviceInfo->DeviceList.Next; } PipUnlockDeviceDatabase(); deviceRelations->Count = 1; DebugPrint((DEBUG_PNP, "QueryDeviceRelations handing back the FDO\n")); ObReferenceObject(PipRDPNode->PhysicalDeviceObject); deviceRelations->Objects[0] = PipRDPNode->PhysicalDeviceObject; (PDEVICE_RELATIONS)Irp->IoStatus.Information = deviceRelations; Irp->IoStatus.Status = STATUS_SUCCESS; break; } else { PipCompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES,NULL); return STATUS_INSUFFICIENT_RESOURCES; } } // // Perform bus check to enumerate all the device under pnpisa bus. // PipLockDeviceDatabase(); if ((PipRDPNode->Flags & (DF_ACTIVATED|DF_QUERY_STOPPED)) == DF_ACTIVATED) { accessHW = TRUE; deviceLink = busExtension->DeviceList.Next; while (deviceLink) { deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList); if (!(deviceInfo->Flags & DF_READ_DATA_PORT)) { accessHW = FALSE; DebugPrint((DEBUG_PNP, "QueryDeviceRelations: Found 1 card, no more isolation\n")); break; } deviceLink = deviceInfo->DeviceList.Next; } } else { accessHW = FALSE; } if (PipRDPNode->Flags & DF_NEEDS_RESCAN) { DebugPrint((DEBUG_PNP, "QueryDeviceRelations: Force rescan\n")); PipRDPNode->Flags &= ~DF_NEEDS_RESCAN; accessHW = TRUE; } if (accessHW) { PipCheckBus(busExtension); } else { DebugPrint((DEBUG_PNP, "QueryDeviceRelations: Using cached data\n")); } status = PipQueryDeviceRelations( busExtension, (PDEVICE_RELATIONS *)&Irp->IoStatus.Information, FALSE ); PipUnlockDeviceDatabase(); Irp->IoStatus.Status = status; if (!NT_SUCCESS(status)) { PipCompleteRequest(Irp, status, NULL); return status; } } break; case EjectionRelations: { if (PipRDPNode) { deviceRelations = (PDEVICE_RELATIONS) ExAllocatePool( PagedPool, sizeof(DEVICE_RELATIONS) ); if (deviceRelations) { deviceRelations->Count = 1; ObReferenceObject(PipRDPNode->PhysicalDeviceObject); deviceRelations->Objects[0] = PipRDPNode->PhysicalDeviceObject; (PDEVICE_RELATIONS)Irp->IoStatus.Information = deviceRelations; Irp->IoStatus.Status = STATUS_SUCCESS; } else { PipCompleteRequest(Irp,STATUS_INSUFFICIENT_RESOURCES,NULL); return STATUS_INSUFFICIENT_RESOURCES; } } } break; } #else if (irpSp->Parameters.QueryDeviceRelations.Type == BusRelations && busExtension->BusNumber == 0) { deviceRelations = (PDEVICE_RELATIONS) ExAllocatePool( PagedPool, sizeof(DEVICE_RELATIONS) ); if (deviceRelations) { deviceRelations->Count = 0; (PDEVICE_RELATIONS)Irp->IoStatus.Information = deviceRelations; Irp->IoStatus.Status = STATUS_SUCCESS; } else { PipCompleteRequest(Irp,STATUS_INSUFFICIENT_RESOURCES,NULL); return STATUS_INSUFFICIENT_RESOURCES; } } #endif return PipPassIrp(DeviceObject, Irp); } // PiQueryDeviceRelationsFdo NTSTATUS PiRemoveFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { NTSTATUS status; PPI_BUS_EXTENSION busExtension; PSINGLE_LIST_ENTRY child; PBUS_EXTENSION_LIST busList,prevBus; USHORT count=0; DebugPrint((DEBUG_PNP, "*** Remove Device irp received FDO: %x\n",DeviceObject)); busExtension = DeviceObject->DeviceExtension; // // Clear the entry in the BM. Count dropped in // Query Remove. // KeWaitForSingleObject( &IsaBusNumberLock, Executive, KernelMode, FALSE, NULL ); if (!(busExtension->Flags & DF_SURPRISE_REMOVED)) { #ifdef DBG ASSERT (RtlAreBitsSet (BusNumBM,busExtension->BusNumber,1)); #endif RtlClearBits (BusNumBM,busExtension->BusNumber,1); } #if ISOLATE_CARDS PipLockDeviceDatabase(); // // Walk the list of children and delete them // child=PopEntryList (&busExtension->DeviceList); while (child) { ASSERT (CONTAINING_RECORD (child, DEVICE_INFORMATION,DeviceList)->PhysicalDeviceObject); // // This pulls them from the list! // count ++; if (CONTAINING_RECORD (child, DEVICE_INFORMATION,DeviceList)->Flags & DF_READ_DATA_PORT) { // // Force the recreate of the RDP // PipCleanupAcquiredResources (busExtension); PipReadDataPort = NULL; PipRDPNode = NULL; } else { PipReleaseDeviceResources ((PDEVICE_INFORMATION)child); } IoDeleteDevice (CONTAINING_RECORD (child, DEVICE_INFORMATION,DeviceList)->PhysicalDeviceObject); child=PopEntryList (&busExtension->DeviceList); } PipUnlockDeviceDatabase(); #endif // // Delete this extension. // prevBus= busList = PipBusExtension; ASSERT (busList != NULL); while (busList->BusExtension != busExtension) { prevBus= busList; busList = busList->Next; ASSERT (busList != NULL); } // // Remove the node // if (prevBus == busList) { // // First Node. // PipBusExtension=busList->Next; }else { prevBus->Next = busList->Next; } ExFreePool (busList); KeSetEvent( &IsaBusNumberLock, 0, FALSE ); if (count > 0 ) { // // If we STILL have an ISA bus. Do this. // if (ActiveIsaCount > 0 ) { ASSERT (PipBusExtension->BusExtension); IoInvalidateDeviceRelations (PipBusExtension->BusExtension->PhysicalBusDevice,BusRelations); } } #if ISOLATE_CARDS // // Cleanup all the resources on the last remove. // if (!(busExtension->Flags & DF_SURPRISE_REMOVED)) { PipCleanupAcquiredResources (busExtension); } #endif // // The PnpISa bus PDO is being removed... // IoDetachDevice(busExtension->AttachedDevice); Irp->IoStatus.Status=STATUS_SUCCESS; status = PipPassIrp(DeviceObject, Irp); busExtension->AttachedDevice = NULL; busExtension->Flags |= DF_DELETED; busExtension->DevicePowerState = PowerDeviceD3; IoDeleteDevice(busExtension->FunctionalBusDevice); return status; } // PiRemoveFdo NTSTATUS PiQueryLegacyBusInformationFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PLEGACY_BUS_INFORMATION legacyBusInfo; PVOID information = NULL; PPI_BUS_EXTENSION busExtension; NTSTATUS status; busExtension = DeviceObject->DeviceExtension; legacyBusInfo = (PLEGACY_BUS_INFORMATION) ExAllocatePool(PagedPool, sizeof(LEGACY_BUS_INFORMATION)); if (legacyBusInfo) { legacyBusInfo->BusTypeGuid = GUID_BUS_TYPE_ISAPNP; legacyBusInfo->LegacyBusType = Isa; legacyBusInfo->BusNumber = busExtension->BusNumber; information = legacyBusInfo; status = STATUS_SUCCESS; } else { status = STATUS_INSUFFICIENT_RESOURCES; } if (NT_SUCCESS(status)) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = (ULONG_PTR) information; return PipPassIrp(DeviceObject, Irp); } else { PipCompleteRequest (Irp,status,NULL); return status; } } NTSTATUS PiQueryInterfaceFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { NTSTATUS status; PPI_BUS_EXTENSION busExtension; busExtension = DeviceObject->DeviceExtension; // // We are a FDO - check if we are being asked for an interface we // support // status = PiQueryInterface(busExtension, Irp); if (NT_SUCCESS(status)) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; return PipPassIrp(DeviceObject, Irp); } else if (status == STATUS_NOT_SUPPORTED) { return PipPassIrp(DeviceObject, Irp); } else { PipCompleteRequest (Irp,status,NULL); return status; } } // PiQueryInterfaceFdo NTSTATUS PiQueryPnpDeviceState( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PPI_BUS_EXTENSION busExtension; busExtension = DeviceObject->DeviceExtension; // // We are a FDO // (PNP_DEVICE_STATE) Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE; Irp->IoStatus.Status = STATUS_SUCCESS; return PipPassIrp(DeviceObject, Irp); } // PiQueryPnpDeviceState NTSTATUS PiSurpriseRemoveFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { NTSTATUS status; PPI_BUS_EXTENSION busExtension; DebugPrint((DEBUG_PNP, "*** Surprise Remove Device irp received FDO: %x\n",DeviceObject)); busExtension = DeviceObject->DeviceExtension; // // Clear the entry in the BM. Count dropped in // Query Remove. // KeWaitForSingleObject( &IsaBusNumberLock, Executive, KernelMode, FALSE, NULL ); #ifdef DBG ASSERT (RtlAreBitsSet (BusNumBM,busExtension->BusNumber,1)); #endif RtlClearBits (BusNumBM,busExtension->BusNumber,1); KeSetEvent( &IsaBusNumberLock, 0, FALSE ); #if ISOLATE_CARDS PipCleanupAcquiredResources (busExtension); #endif // // The PnpISa bus PDO is being removed... // Irp->IoStatus.Status=STATUS_SUCCESS; status = PipPassIrp(DeviceObject, Irp); busExtension->AttachedDevice = NULL; busExtension->Flags |= DF_SURPRISE_REMOVED; busExtension->DevicePowerState = PowerDeviceD3; return status; } // PiSurpriseRemoveFdo