/*++ Copyright (c) 1998-2000 Microsoft Corporation Module Name: pdo.c Abstract: This module handles IRPs for PCI PDO's. Author: Adrian J. Oney (adriao) & Andrew Thornton (andrewth) 10-20-1998 Revision History: --*/ #include "pcip.h" NTSTATUS PciPdoIrpStartDevice( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpQueryRemoveDevice( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpRemoveDevice( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpCancelRemoveDevice( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpStopDevice( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpQueryStopDevice( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpCancelStopDevice( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpQueryDeviceRelations( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpQueryCapabilities( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpQueryInterface( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpQueryResources( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpQueryResourceRequirements( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpQueryDeviceText( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpReadConfig( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpWriteConfig( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpQueryId( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpQueryBusInformation( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpDeviceUsageNotification( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpQueryLegacyBusInformation( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpSurpriseRemoval( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); NTSTATUS PciPdoIrpQueryDeviceState( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, PciPdoCreate) #pragma alloc_text(PAGE, PciPdoDestroy) #pragma alloc_text(PAGE, PciPdoIrpStartDevice) #pragma alloc_text(PAGE, PciPdoIrpQueryRemoveDevice) #pragma alloc_text(PAGE, PciPdoIrpRemoveDevice) #pragma alloc_text(PAGE, PciPdoIrpCancelRemoveDevice) #pragma alloc_text(PAGE, PciPdoIrpStopDevice) #pragma alloc_text(PAGE, PciPdoIrpQueryStopDevice) #pragma alloc_text(PAGE, PciPdoIrpCancelStopDevice) #pragma alloc_text(PAGE, PciPdoIrpQueryDeviceRelations) #pragma alloc_text(PAGE, PciPdoIrpQueryInterface) #pragma alloc_text(PAGE, PciPdoIrpQueryCapabilities) #pragma alloc_text(PAGE, PciPdoIrpQueryResources) #pragma alloc_text(PAGE, PciPdoIrpQueryResourceRequirements) #pragma alloc_text(PAGE, PciPdoIrpQueryDeviceText) #pragma alloc_text(PAGE, PciPdoIrpReadConfig) #pragma alloc_text(PAGE, PciPdoIrpWriteConfig) #pragma alloc_text(PAGE, PciPdoIrpQueryId) #pragma alloc_text(PAGE, PciPdoIrpQueryBusInformation) #pragma alloc_text(PAGE, PciPdoIrpDeviceUsageNotification) #pragma alloc_text(PAGE, PciPdoIrpQueryLegacyBusInformation) #pragma alloc_text(PAGE, PciPdoIrpSurpriseRemoval) #pragma alloc_text(PAGE, PciPdoIrpQueryDeviceState) #endif /*++ The majority of functions in this file are called based on their presence in Pnp and Po dispatch tables. In the interests of brevity the arguments to all those functions will be described below: NTSTATUS PciXxxPdo( IN PIRP Irp, IN PIO_STACK_LOCATION IrpStack, IN PPCI_EXTENSION DeviceExtension ) Routine Description: This function handles the Xxx requests for a given PCI FDO or PDO. Arguments: Irp - Points to the IRP associated with this request. IrpStack - Points to the current stack location for this request. DeviceExtension - Points to the device's extension. Return Value: Status code that indicates whether or not the function was successful. STATUS_NOT_SUPPORTED indicates that the IRP should be completed without changing the Irp->IoStatus.Status field otherwise it is updated with this status. --*/ #define PCI_MAX_MINOR_POWER_IRP 0x3 #define PCI_MAX_MINOR_PNP_IRP 0x18 PCI_MN_DISPATCH_TABLE PciPdoDispatchPowerTable[] = { { IRP_DISPATCH, PciPdoWaitWake }, // 0x00 - IRP_MN_WAIT_WAKE { IRP_COMPLETE, PciIrpNotSupported }, // 0x01 - IRP_MN_POWER_SEQUENCE { IRP_COMPLETE, PciPdoSetPowerState }, // 0x02 - IRP_MN_SET_POWER { IRP_COMPLETE, PciPdoIrpQueryPower }, // 0x03 - IRP_MN_QUERY_POWER { IRP_COMPLETE, PciIrpNotSupported }, // - UNHANDLED Power IRP }; PCI_MN_DISPATCH_TABLE PciPdoDispatchPnpTable[] = { { IRP_COMPLETE, PciPdoIrpStartDevice }, // 0x00 - IRP_MN_START_DEVICE { IRP_COMPLETE, PciPdoIrpQueryRemoveDevice }, // 0x01 - IRP_MN_QUERY_REMOVE_DEVICE { IRP_COMPLETE, PciPdoIrpRemoveDevice }, // 0x02 - IRP_MN_REMOVE_DEVICE { IRP_COMPLETE, PciPdoIrpCancelRemoveDevice }, // 0x03 - IRP_MN_CANCEL_REMOVE_DEVICE { IRP_COMPLETE, PciPdoIrpStopDevice }, // 0x04 - IRP_MN_STOP_DEVICE { IRP_COMPLETE, PciPdoIrpQueryStopDevice }, // 0x05 - IRP_MN_QUERY_STOP_DEVICE { IRP_COMPLETE, PciPdoIrpCancelStopDevice }, // 0x06 - IRP_MN_CANCEL_STOP_DEVICE { IRP_COMPLETE, PciPdoIrpQueryDeviceRelations }, // 0x07 - IRP_MN_QUERY_DEVICE_RELATIONS { IRP_COMPLETE, PciPdoIrpQueryInterface }, // 0x08 - IRP_MN_QUERY_INTERFACE { IRP_COMPLETE, PciPdoIrpQueryCapabilities }, // 0x09 - IRP_MN_QUERY_CAPABILITIES { IRP_COMPLETE, PciPdoIrpQueryResources }, // 0x0A - IRP_MN_QUERY_RESOURCES { IRP_COMPLETE, PciPdoIrpQueryResourceRequirements }, // 0x0B - IRP_MN_QUERY_RESOURCE_REQUIREMENTS { IRP_COMPLETE, PciPdoIrpQueryDeviceText }, // 0x0C - IRP_MN_QUERY_DEVICE_TEXT { IRP_COMPLETE, PciIrpNotSupported }, // 0x0D - IRP_MN_FILTER_RESOURCE_REQUIREMENTS { IRP_COMPLETE, PciIrpNotSupported }, // 0x0E - NOT USED { IRP_COMPLETE, PciPdoIrpReadConfig }, // 0x0F - IRP_MN_READ_CONFIG { IRP_COMPLETE, PciPdoIrpWriteConfig }, // 0x10 - IRP_MN_WRITE_CONFIG { IRP_COMPLETE, PciIrpNotSupported }, // 0x11 - IRP_MN_EJECT { IRP_COMPLETE, PciIrpNotSupported }, // 0x12 - IRP_MN_SET_LOCK { IRP_COMPLETE, PciPdoIrpQueryId }, // 0x13 - IRP_MN_QUERY_ID { IRP_COMPLETE, PciPdoIrpQueryDeviceState }, // 0x14 - IRP_MN_QUERY_PNP_DEVICE_STATE { IRP_COMPLETE, PciPdoIrpQueryBusInformation }, // 0x15 - IRP_MN_QUERY_BUS_INFORMATION { IRP_COMPLETE, PciPdoIrpDeviceUsageNotification }, // 0x16 - IRP_MN_DEVICE_USAGE_NOTIFICATION { IRP_COMPLETE, PciPdoIrpSurpriseRemoval }, // 0x17 - IRP_MN_SURPRISE_REMOVAL { IRP_COMPLETE, PciPdoIrpQueryLegacyBusInformation }, // 0x18 - IRP_MN_QUERY_LEGACY_BUS_INFORMATION { IRP_COMPLETE, PciIrpNotSupported } // - UNHANDLED PNP IRP }; // // This is the major function dispatch table for Pdo's // PCI_MJ_DISPATCH_TABLE PciPdoDispatchTable = { PCI_MAX_MINOR_PNP_IRP, PciPdoDispatchPnpTable, // Pnp irps PCI_MAX_MINOR_POWER_IRP, PciPdoDispatchPowerTable, // Power irps IRP_COMPLETE, PciIrpNotSupported, IRP_COMPLETE, PciIrpInvalidDeviceRequest // Other }; // // Data // BOOLEAN PciStopOnIllegalConfigAccess = FALSE; ULONG PciPdoSequenceNumber = (ULONG)-1; NTSTATUS PciPdoCreate( IN PPCI_FDO_EXTENSION FdoExtension, IN PCI_SLOT_NUMBER Slot, OUT PDEVICE_OBJECT *PhysicalDeviceObject ) { NTSTATUS status; PDRIVER_OBJECT driverObject; PDEVICE_OBJECT functionalDeviceObject; PDEVICE_OBJECT physicalDeviceObject; PPCI_PDO_EXTENSION pdoExtension; UNICODE_STRING unicodeDeviceString; WCHAR deviceString[32]; PAGED_CODE(); // // We've been asked to create a new PDO for a PCI device. First get // a pointer to our driver object. // functionalDeviceObject = FdoExtension->FunctionalDeviceObject; driverObject = functionalDeviceObject->DriverObject; // // Create the physical device object for this device. // In theory it doesn't need a name,... It must have // a name. // // But what name? For now we'll call it NTPNP_PCIxxxx, // where xxxx is the 0-based number of PCI devices we've // found. // _snwprintf(deviceString, sizeof(deviceString)/sizeof(WCHAR), L"\\Device\\NTPNP_PCI%04d", InterlockedIncrement(&PciPdoSequenceNumber)); RtlInitUnicodeString(&unicodeDeviceString, deviceString); status = IoCreateDevice( driverObject, // our driver object sizeof(PCI_PDO_EXTENSION), // size of our extension, &unicodeDeviceString, // our name FILE_DEVICE_UNKNOWN, // device type 0, // device characteristics FALSE, // not exclusive &physicalDeviceObject // store new device object here ); if (!NT_SUCCESS(status)) { ASSERT(NT_SUCCESS(status)); return status; } pdoExtension = (PPCI_PDO_EXTENSION)physicalDeviceObject->DeviceExtension; PciDebugPrint(PciDbgVerbose, "PCI: New PDO (b=0x%x, d=0x%x, f=0x%x) @ %p, ext @ %p\n", FdoExtension->BaseBus, Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber, physicalDeviceObject, pdoExtension); // // We have our physical device object, initialize it. // // And yes, I would have zeroed the extension if I didn't know // for a fact that it was zeroed by IoCreateDevice(). // pdoExtension->ExtensionType = PciPdoExtensionType; pdoExtension->IrpDispatchTable = &PciPdoDispatchTable; pdoExtension->PhysicalDeviceObject = physicalDeviceObject; pdoExtension->Slot = Slot; pdoExtension->PowerState.CurrentSystemState = PowerSystemWorking; pdoExtension->PowerState.CurrentDeviceState = PowerDeviceD0; pdoExtension->ParentFdoExtension = FdoExtension; ExInitializeFastMutex(&pdoExtension->SecondaryExtMutex); PciInitializeState((PPCI_COMMON_EXTENSION) pdoExtension); // // Insert it into the list of child PDOs hanging off of the FdoExtension. // We won't be re-entered enumerating the same bus, so we don't need to // protect the list. // pdoExtension->Next = NULL; PciInsertEntryAtTail( (PSINGLE_LIST_ENTRY)&FdoExtension->ChildPdoList, (PSINGLE_LIST_ENTRY)&pdoExtension->Next, &FdoExtension->ChildListMutex ); *PhysicalDeviceObject = physicalDeviceObject; return STATUS_SUCCESS; } VOID PciPdoDestroy( IN PDEVICE_OBJECT PhysicalDeviceObject ) { PPCI_PDO_EXTENSION pdoExtension; PPCI_PDO_EXTENSION *previousBridge; PPCI_FDO_EXTENSION fdoExtension; PAGED_CODE(); pdoExtension = (PPCI_PDO_EXTENSION)PhysicalDeviceObject->DeviceExtension; ASSERT_PCI_PDO_EXTENSION(pdoExtension); ASSERT(!pdoExtension->LegacyDriver); fdoExtension = PCI_PARENT_FDOX(pdoExtension); ASSERT_PCI_FDO_EXTENSION(fdoExtension); PciDebugPrint(PciDbgVerbose, "PCI: destroy PDO (b=0x%x, d=0x%x, f=0x%x)\n", PCI_PARENT_FDOX(pdoExtension)->BaseBus, pdoExtension->Slot.u.bits.DeviceNumber, pdoExtension->Slot.u.bits.FunctionNumber); // // Remove this PDO from the Child Pdo List. // ASSERT_MUTEX_HELD(&fdoExtension->ChildListMutex); PciRemoveEntryFromList((PSINGLE_LIST_ENTRY)&fdoExtension->ChildPdoList, (PSINGLE_LIST_ENTRY)pdoExtension, NULL); for (previousBridge = &fdoExtension->ChildBridgePdoList; *previousBridge; previousBridge = &((*previousBridge)->NextBridge)) { if (*previousBridge == pdoExtension) { *previousBridge = pdoExtension->NextBridge; pdoExtension->NextBridge = NULL; break; } } pdoExtension->Next = NULL; // // Delete any secondary extensions this PDO may have. // while (pdoExtension->SecondaryExtension.Next) { PcipDestroySecondaryExtension(&pdoExtension->SecondaryExtension, NULL, pdoExtension->SecondaryExtension.Next); } // // Zap the extension type so we'll trip up if we try to resuse it. // pdoExtension->ExtensionType = 0xdead; // // If there are any resource lists etc associated with this puppy, // give them back to the system. // PciInvalidateResourceInfoCache(pdoExtension); if (pdoExtension->Resources) { ExFreePool(pdoExtension->Resources); } // // And finally,... // IoDeleteDevice(PhysicalDeviceObject); } NTSTATUS PciPdoIrpStartDevice( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { NTSTATUS status; BOOLEAN change, powerOn, isVideoController; PPCI_PDO_EXTENSION pdoExtension; PAGED_CODE(); status = PciBeginStateTransition(DeviceExtension, PciStarted); if (!NT_SUCCESS(status)) { return status; } pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension; // // If there is a motherboard video device and a plug in video // device, the BIOS will have disabled the motherboard one. The // video drivers use this fact to determine if this device should // be disabled,... don't change its settings here. // isVideoController = ((pdoExtension->BaseClass == PCI_CLASS_PRE_20) && (pdoExtension->SubClass == PCI_SUBCLASS_PRE_20_VGA)) || ((pdoExtension->BaseClass == PCI_CLASS_DISPLAY_CTLR) && (pdoExtension->SubClass == PCI_SUBCLASS_VID_VGA_CTLR)); if ( !isVideoController ) { // // Non-VGA, unconditionally enable the IO and Memory for the device. // pdoExtension->CommandEnables |= (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE); } // // Disable interrupt generation for IDE controllers until IDE is up and // running (See comment in PciConfigureIdeController) // if (pdoExtension->IoSpaceUnderNativeIdeControl) { pdoExtension->CommandEnables &= ~PCI_ENABLE_IO_SPACE; } // // Always enable the bus master bit - even for video controllers // pdoExtension->CommandEnables |= PCI_ENABLE_BUS_MASTER; // // Extract the PDO Resources (PCI driver internal style) // from the incoming resource list. // change = PciComputeNewCurrentSettings( pdoExtension, IrpSp->Parameters.StartDevice.AllocatedResources ); // // Remember if we ever move the device // if (change) { pdoExtension->MovedDevice = TRUE; } #if DBG if (!change) { PciDebugPrint( PciDbgObnoxious, "PCI - START not changing resource settings.\n" ); } #endif // // The device should be powered up at this stage. // powerOn = FALSE; if (pdoExtension->PowerState.CurrentDeviceState != PowerDeviceD0) { POWER_STATE powerState; status = PciSetPowerManagedDevicePowerState( pdoExtension, PowerDeviceD0, FALSE ); if (!NT_SUCCESS(status)) { PciCancelStateTransition(DeviceExtension, PciStarted); return STATUS_DEVICE_POWER_FAILURE; } powerState.DeviceState = PowerDeviceD0; PoSetPowerState( pdoExtension->PhysicalDeviceObject, DevicePowerState, powerState ); // // Force PciSetResources to write the configuration // and other extraneous data to the device. // powerOn = TRUE; pdoExtension->PowerState.CurrentDeviceState = PowerDeviceD0; } // // Program the device with the resources allocated. // status = PciSetResources( pdoExtension, powerOn, TRUE ); if (NT_SUCCESS(status)) { PciCommitStateTransition(DeviceExtension, PciStarted); } else { PciCancelStateTransition(DeviceExtension, PciStarted); } return status; } NTSTATUS PciPdoIrpQueryRemoveDevice( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { PPCI_PDO_EXTENSION pdoExtension; PAGED_CODE(); pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension; // // Don't allow the paging device (or a hibernate device) to // be removed or stopped // if (pdoExtension->PowerState.Hibernate || pdoExtension->PowerState.Paging || pdoExtension->PowerState.CrashDump || pdoExtension->OnDebugPath || (pdoExtension->HackFlags & PCI_HACK_FAIL_QUERY_REMOVE)) { return STATUS_DEVICE_BUSY; } // // Don't allow devices with legacy drivers to be removed (even thought the // driver may be root enumerated) // if (pdoExtension->LegacyDriver) { return STATUS_INVALID_DEVICE_REQUEST; } if (DeviceExtension->DeviceState == PciNotStarted) { return STATUS_SUCCESS; } else { return PciBeginStateTransition(DeviceExtension, PciNotStarted); } } NTSTATUS PciPdoIrpRemoveDevice( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { NTSTATUS status; PPCI_PDO_EXTENSION pdoExtension; PAGED_CODE(); pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension; // // If this PDO is for a PCI-PCI bridge, it has a pointer // to the FDO that was attached to it. That FDO was destroyed // as a result of the IRP coming down the stack. Clear the // pointer. (Unconditionally as it is only set for bridges). // pdoExtension->BridgeFdoExtension = NULL; if (!pdoExtension->NotPresent) { // // Turn the device off. (Checks for whether or not // this is a good idea are in the PciDecodeEnable routine). // While you might think this should be done only if we were already // headed to PciNotStarted, we may in fact have a boot config that // needs to be disabled. // PciDecodeEnable(pdoExtension, FALSE, NULL); // // Power it down if we are allowed to disable its decodes - if not then // don't turn it off. eg. Don't turn of the VGA card... // if (pdoExtension->PowerState.CurrentDeviceState != PowerDeviceD3 && PciCanDisableDecodes(pdoExtension, NULL, 0, 0)) { POWER_STATE powerState; status = PciSetPowerManagedDevicePowerState( pdoExtension, PowerDeviceD3, FALSE ); pdoExtension->PowerState.CurrentDeviceState = PowerDeviceD3; powerState.DeviceState = PowerDeviceD3; PoSetPowerState( pdoExtension->PhysicalDeviceObject, DevicePowerState, powerState ); } } // // We can get a remove in one of three states: // 1) We have received a QueryRemove/SurpriseRemove in which case we are // transitioning to PciNotStarted. // 2) We were never started, so we are already in PciNotStarted. // 3) We started the PDO, but the FDO failed start. We are in PciStarted in // this case. // if (!PciIsInTransitionToState(DeviceExtension, PciNotStarted)&& (DeviceExtension->DeviceState == PciStarted)) { PciBeginStateTransition(DeviceExtension, PciNotStarted); } if (PciIsInTransitionToState(DeviceExtension, PciNotStarted)) { PciCommitStateTransition(DeviceExtension, PciNotStarted); } if (pdoExtension->ReportedMissing) { status = PciBeginStateTransition(DeviceExtension, PciDeleted); ASSERT(NT_SUCCESS(status)); PciCommitStateTransition(DeviceExtension, PciDeleted); PciPdoDestroy(pdoExtension->PhysicalDeviceObject); } return STATUS_SUCCESS; } NTSTATUS PciPdoIrpCancelRemoveDevice( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { PAGED_CODE(); PciCancelStateTransition(DeviceExtension, PciNotStarted); return STATUS_SUCCESS; } NTSTATUS PciPdoIrpStopDevice( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { NTSTATUS status; PAGED_CODE(); // // Turn the device off. (Checks for whether or not // this is a good idea are in the PciDecodeEnable routine). // PciDecodeEnable((PPCI_PDO_EXTENSION) DeviceExtension, FALSE, NULL); PciCommitStateTransition(DeviceExtension, PciStopped); return STATUS_SUCCESS; } NTSTATUS PciPdoIrpQueryStopDevice( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { PPCI_PDO_EXTENSION pdoExtension; PAGED_CODE(); // // Don't allow the paging device (or a hibernate device) to // be removed or stopped // pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension; if (pdoExtension->PowerState.Hibernate || pdoExtension->PowerState.Paging || pdoExtension->PowerState.CrashDump || pdoExtension->OnDebugPath) { return STATUS_DEVICE_BUSY; } // // Don't stop PCI->PCI and CardBus bridges // if (pdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV && (pdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI || pdoExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS)) { return STATUS_INVALID_DEVICE_REQUEST; } // // Don't allow devices with legacy drivers to be stopped (even thought the // driver may be root enumerated) // if (pdoExtension->LegacyDriver) { return STATUS_INVALID_DEVICE_REQUEST; } // // If we cannot free the resources, do tell the OS. // if (!PciCanDisableDecodes(pdoExtension, NULL, 0, 0)) { return STATUS_INVALID_DEVICE_REQUEST; } return PciBeginStateTransition(DeviceExtension, PciStopped); } NTSTATUS PciPdoIrpCancelStopDevice( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { PAGED_CODE(); PciCancelStateTransition(DeviceExtension, PciStopped); return STATUS_SUCCESS; } NTSTATUS PciPdoIrpQueryDeviceRelations( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { NTSTATUS status; PPCI_PDO_EXTENSION pdoExtension, childList; PAGED_CODE(); pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension; switch(IrpSp->Parameters.QueryDeviceRelations.Type) { case EjectionRelations: status = PciQueryEjectionRelations( pdoExtension, (PDEVICE_RELATIONS*)&Irp->IoStatus.Information ); break; case TargetDeviceRelation: status = PciQueryTargetDeviceRelations( pdoExtension, (PDEVICE_RELATIONS*)&Irp->IoStatus.Information ); break; default: status = STATUS_NOT_SUPPORTED; break; } return status; } NTSTATUS PciPdoIrpQueryInterface( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { NTSTATUS status; PPCI_PDO_EXTENSION pdoExtension; PAGED_CODE(); pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension; status = PciQueryInterface( pdoExtension, IrpSp->Parameters.QueryInterface.InterfaceType, IrpSp->Parameters.QueryInterface.Size, IrpSp->Parameters.QueryInterface.Version, IrpSp->Parameters.QueryInterface.InterfaceSpecificData, IrpSp->Parameters.QueryInterface.Interface, FALSE ); if (!NT_SUCCESS(status)) { // // KLUDGE: If this pdo has a fake FDO attatched to // it (because it's a cardbus controller), we should // check to see if this interface could have been supplied // by the FDO and supply it if so. // // Yes, this is really gross and yes it breaks the filter // model. The correct thing is for cardbus to pass the // IRP here via the "backdoor" while it has it at the FDO // level. // PPCI_FDO_EXTENSION fakeFdo; fakeFdo = pdoExtension->BridgeFdoExtension; if (fakeFdo && (fakeFdo->Fake == TRUE)) { ASSERT((pdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) && (pdoExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS)); status = PciQueryInterface( fakeFdo, IrpSp->Parameters.QueryInterface.InterfaceType, IrpSp->Parameters.QueryInterface.Size, IrpSp->Parameters.QueryInterface.Version, IrpSp->Parameters.QueryInterface.InterfaceSpecificData, IrpSp->Parameters.QueryInterface.Interface, FALSE ); } } return status; } NTSTATUS PciPdoIrpQueryCapabilities( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { PAGED_CODE(); return PciQueryCapabilities( (PPCI_PDO_EXTENSION) DeviceExtension, IrpSp->Parameters.DeviceCapabilities.Capabilities ); } NTSTATUS PciPdoIrpQueryId( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { PAGED_CODE(); // // Get a pointer to the query id structure and process. // return PciQueryId( (PPCI_PDO_EXTENSION) DeviceExtension, IrpSp->Parameters.QueryId.IdType, (PWSTR*)&Irp->IoStatus.Information ); } NTSTATUS PciPdoIrpQueryResources( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { PAGED_CODE(); return PciQueryResources( (PPCI_PDO_EXTENSION) DeviceExtension, (PCM_RESOURCE_LIST*)&Irp->IoStatus.Information ); } NTSTATUS PciPdoIrpQueryResourceRequirements( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { PAGED_CODE(); return PciQueryRequirements( (PPCI_PDO_EXTENSION) DeviceExtension, (PIO_RESOURCE_REQUIREMENTS_LIST*)&Irp->IoStatus.Information ); } NTSTATUS PciPdoIrpQueryDeviceText( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { PAGED_CODE(); return PciQueryDeviceText( (PPCI_PDO_EXTENSION) DeviceExtension, IrpSp->Parameters.QueryDeviceText.DeviceTextType, IrpSp->Parameters.QueryDeviceText.LocaleId, (PWSTR*)&Irp->IoStatus.Information ); } NTSTATUS PciPdoIrpReadConfig( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { NTSTATUS status; ULONG lengthRead; PPCI_PDO_EXTENSION pdoExtension; PAGED_CODE(); pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension; status = PciReadDeviceSpace(pdoExtension, IrpSp->Parameters.ReadWriteConfig.WhichSpace, IrpSp->Parameters.ReadWriteConfig.Buffer, IrpSp->Parameters.ReadWriteConfig.Offset, IrpSp->Parameters.ReadWriteConfig.Length, &lengthRead ); // // Update the information files with the number of bytes read // Irp->IoStatus.Information = lengthRead; return status; } NTSTATUS PciPdoIrpWriteConfig( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { NTSTATUS status; ULONG lengthWritten; PPCI_PDO_EXTENSION pdoExtension; PAGED_CODE(); pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension; status = PciWriteDeviceSpace(pdoExtension, IrpSp->Parameters.ReadWriteConfig.WhichSpace, IrpSp->Parameters.ReadWriteConfig.Buffer, IrpSp->Parameters.ReadWriteConfig.Offset, IrpSp->Parameters.ReadWriteConfig.Length, &lengthWritten ); // // Update the information files with the number of bytes read // Irp->IoStatus.Information = lengthWritten; return status; } NTSTATUS PciPdoIrpQueryBusInformation( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { PAGED_CODE(); return PciQueryBusInformation( (PPCI_PDO_EXTENSION) DeviceExtension, (PPNP_BUS_INFORMATION *) &Irp->IoStatus.Information ); } NTSTATUS PciPdoIrpDeviceUsageNotification( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { PAGED_CODE(); return PciPdoDeviceUsage((PPCI_PDO_EXTENSION) DeviceExtension, Irp); } NTSTATUS PciPdoIrpQueryLegacyBusInformation( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { PPCI_PDO_EXTENSION PdoExtension; PLEGACY_BUS_INFORMATION information; PAGED_CODE(); // // We're interested in IRP_MN_QUERY_LEGACY_BUS_INFORMATION on a // PDO if the PDO is for a CardBus bridge. In this case, the // CardBus/PCMCIA FDO has passed the irp down so that we can // answer it correctly. // PdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension; if (PciClassifyDeviceType(PdoExtension) != PciTypeCardbusBridge) { return STATUS_NOT_SUPPORTED; } information = ExAllocatePool(PagedPool, sizeof(LEGACY_BUS_INFORMATION)); if (information == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory(&information->BusTypeGuid, &GUID_BUS_TYPE_PCI, sizeof(GUID)); information->LegacyBusType = PCIBus; information->BusNumber = PdoExtension->Dependent.type1.SecondaryBus; (PLEGACY_BUS_INFORMATION) Irp->IoStatus.Information = information; return STATUS_SUCCESS; } NTSTATUS PciPdoIrpSurpriseRemoval( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { NTSTATUS status; PPCI_PDO_EXTENSION pdoExtension; PAGED_CODE(); pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension; // // There are two kinds of surprise removals // - Surprise removals due to removal of our device // - Surprise removals due to failure of our device to start // if (!pdoExtension->NotPresent) { // // Turn the device off. (Checks for whether or not // this is a good idea are in the PciDecodeEnable routine). // While you might think this should be done only if we were already // headed to PciNotStarted, we may in fact have a boot config that // needs to be disabled. Note that we may turn it off again in remove // device. No big deal. // PciDecodeEnable(pdoExtension, FALSE, NULL); // // Power it down if we are allowed to disable its decodes - if not then // don't turn it off. eg. Don't turn of the VGA card... // if (pdoExtension->PowerState.CurrentDeviceState != PowerDeviceD3 && PciCanDisableDecodes(pdoExtension, NULL, 0, 0)) { POWER_STATE powerState; // // Power it down - if it fails we don't care - the hardware may be // gone! // PciSetPowerManagedDevicePowerState( pdoExtension, PowerDeviceD3, FALSE ); pdoExtension->PowerState.CurrentDeviceState = PowerDeviceD3; powerState.DeviceState = PowerDeviceD3; PoSetPowerState( pdoExtension->PhysicalDeviceObject, DevicePowerState, powerState ); } } if (!pdoExtension->ReportedMissing) { PciBeginStateTransition(DeviceExtension, PciNotStarted); } else { // // The device is physically gone, don't dare touch it! // PciBeginStateTransition(DeviceExtension, PciSurpriseRemoved); PciCommitStateTransition(DeviceExtension, PciSurpriseRemoved); } return STATUS_SUCCESS; } NTSTATUS PciPdoIrpQueryDeviceState( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PPCI_COMMON_EXTENSION DeviceExtension ) { PPCI_PDO_EXTENSION pdoExtension; PAGED_CODE(); pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension; // // Host brides cannot be disabled and the user should not be given a // opportunity to do so. // if ((pdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) && (pdoExtension->SubClass == PCI_SUBCLASS_BR_HOST)) { (PNP_DEVICE_STATE)Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE; } return STATUS_SUCCESS; }