// // update interrupt line [checked] // VOID PciUpdateInterruptLine(__in PDEVICE_OBJECT Pdo,__in UCHAR LineRegister) { PAGED_CODE(); PPCI_LEGACY_DEVICE_INFO Info = CONTAINING_RECORD(PciLegacyDeviceHead.Next,PCI_LEGACY_DEVICE_INFO,ListEntry); PPCI_PDO_EXTENSION PdoExt = static_cast<PPCI_PDO_EXTENSION>(Pdo->DeviceExtension); while(Info) { if(Info->OwnerDevice == Pdo) { PdoExt = Info->PdoExt; break; } Info = CONTAINING_RECORD(Info->ListEntry.Next,PCI_LEGACY_DEVICE_INFO,ListEntry); } ASSERT(PdoExt->Common.ExtensionType == PciPdoExtensionType); // // set raw/adjusted interrupt line // PdoExt->AdjustedInterruptLine = LineRegister; PdoExt->RawInterruptLine = LineRegister; // // and program hardware // PciWriteDeviceConfig(PdoExt,&LineRegister,FIELD_OFFSET(PCI_COMMON_CONFIG,u.type0.InterruptLine),sizeof(LineRegister)); // // update registry data // PCI_COMMON_HEADER BiosConfig; NTSTATUS Status = PciGetBiosConfig(PdoExt,&BiosConfig); ASSERT(NT_SUCCESS(Status)); if(BiosConfig.u.type0.InterruptLine != LineRegister) { Status = PciSaveBiosConfig(PdoExt,&BiosConfig); ASSERT(NT_SUCCESS(Status)); } }
// // update subordinate bus [checked] // VOID PciUpdateAncestorSubordinateBuses(__in PPCI_FDO_EXTENSION FdoExt,__in UCHAR MaxBus) { PAGED_CODE(); while(FdoExt->ParentFdoExtension) { PPCI_PDO_EXTENSION PdoExt = static_cast<PPCI_PDO_EXTENSION>(FdoExt->PhysicalDeviceObject->DeviceExtension); ASSERT(!PdoExt->NotPresent); if(PdoExt->Dependent.type1.SubordinateBus < MaxBus) { PdoExt->Dependent.type1.SubordinateBus = MaxBus; PciWriteDeviceConfig(PdoExt,&MaxBus,FIELD_OFFSET(PCI_COMMON_HEADER,u.type1.SubordinateBus),sizeof(MaxBus)); } FdoExt = FdoExt->ParentFdoExtension; } ASSERT(FdoExt == FdoExt->BusRootFdoExtension); ASSERT(MaxBus <= FdoExt->MaxSubordinateBus); }
// // set bus number [checked] // NTSTATUS PciSetBusNumbers(__in PPCI_PDO_EXTENSION PdoExt,__in UCHAR Primary,__in UCHAR Secondary,__in UCHAR Subordinate) { PAGED_CODE(); ASSERT(Primary < Secondary || (Primary == 0 && Secondary == 0)); ASSERT(Secondary <= Subordinate); UCHAR Buffer[3] = {Primary,Secondary,Subordinate}; KeEnterCriticalRegion(); KeWaitForSingleObject(&PciBusLock,Executive,KernelMode,FALSE,0); PdoExt->Dependent.type1.PrimaryBus = Primary; PdoExt->Dependent.type1.SecondaryBus = Secondary; PdoExt->Dependent.type1.SubordinateBus = Subordinate; PdoExt->Dependent.type1.WeChangedBusNumbers = TRUE; PciWriteDeviceConfig(PdoExt,Buffer,FIELD_OFFSET(PCI_COMMON_HEADER,u.type1.PrimaryBus),sizeof(Buffer)); KeSetEvent(&PciBusLock,IO_NO_INCREMENT,FALSE); KeLeaveCriticalRegion(); return STATUS_SUCCESS; }
NTSTATUS NTAPI PciSetPowerManagedDevicePowerState(IN PPCI_PDO_EXTENSION DeviceExtension, IN DEVICE_POWER_STATE DeviceState, IN BOOLEAN IrpSet) { NTSTATUS Status; PCI_PM_CAPABILITY PmCaps; ULONG CapsOffset; /* Assume success */ Status = STATUS_SUCCESS; /* Check if this device can support low power states */ if (!(PciCanDisableDecodes(DeviceExtension, NULL, 0, TRUE)) && (DeviceState != PowerDeviceD0)) { /* Simply return success, ignoring this request */ DPRINT1("Cannot disable decodes on this device, ignoring PM request...\n"); return Status; } /* Does the device support power management at all? */ if (!(DeviceExtension->HackFlags & PCI_HACK_NO_PM_CAPS)) { /* Get the PM capabailities register */ CapsOffset = PciReadDeviceCapability(DeviceExtension, DeviceExtension->CapabilitiesPtr, PCI_CAPABILITY_ID_POWER_MANAGEMENT, &PmCaps.Header, sizeof(PCI_PM_CAPABILITY)); ASSERT(CapsOffset); ASSERT(DeviceState != PowerDeviceUnspecified); /* Check if the device is being powered up */ if (DeviceState == PowerDeviceD0) { /* Set full power state */ PmCaps.PMCSR.ControlStatus.PowerState = 0; /* Check if the device supports Cold-D3 poweroff */ if (PmCaps.PMC.Capabilities.Support.PMED3Cold) { /* If there was a pending PME, clear it */ PmCaps.PMCSR.ControlStatus.PMEStatus = 1; } } else { /* Otherwise, just set the new power state, converting from NT */ PmCaps.PMCSR.ControlStatus.PowerState = DeviceState - 1; } /* Write the new power state in the PMCSR */ PciWriteDeviceConfig(DeviceExtension, &PmCaps.PMCSR, CapsOffset + FIELD_OFFSET(PCI_PM_CAPABILITY, PMCSR), sizeof(PCI_PMCSR)); /* Now wait for the change to "stick" based on the spec-mandated time */ Status = PciStallForPowerChange(DeviceExtension, DeviceState, CapsOffset); if (!NT_SUCCESS(Status)) return Status; } else { /* Nothing to do! */ DPRINT1("No PM on this device, ignoring request\n"); } /* Check if new resources have to be assigned */ if (IrpSet) { /* Check if the new device state is lower (higher power) than now */ if (DeviceState < DeviceExtension->PowerState.CurrentDeviceState) { /* We would normally re-assign resources after powerup */ UNIMPLEMENTED_DBGBREAK(); Status = STATUS_NOT_IMPLEMENTED; } } /* Return the power state change status */ return Status; }