From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/nthals/extender/pci/bus.c | 670 ++++++++++++++++ private/ntos/nthals/extender/pci/control.c | 662 ++++++++++++++++ private/ntos/nthals/extender/pci/devres.c | 1139 +++++++++++++++++++++++++++ private/ntos/nthals/extender/pci/init.c | 357 +++++++++ private/ntos/nthals/extender/pci/makefile | 6 + private/ntos/nthals/extender/pci/misc.c | 544 +++++++++++++ private/ntos/nthals/extender/pci/pcidata.c | 123 +++ private/ntos/nthals/extender/pci/pciport.h | 570 ++++++++++++++ private/ntos/nthals/extender/pci/pciport.rc | 11 + private/ntos/nthals/extender/pci/port.c | 713 +++++++++++++++++ private/ntos/nthals/extender/pci/sources | 48 ++ 11 files changed, 4843 insertions(+) create mode 100644 private/ntos/nthals/extender/pci/bus.c create mode 100644 private/ntos/nthals/extender/pci/control.c create mode 100644 private/ntos/nthals/extender/pci/devres.c create mode 100644 private/ntos/nthals/extender/pci/init.c create mode 100644 private/ntos/nthals/extender/pci/makefile create mode 100644 private/ntos/nthals/extender/pci/misc.c create mode 100644 private/ntos/nthals/extender/pci/pcidata.c create mode 100644 private/ntos/nthals/extender/pci/pciport.h create mode 100644 private/ntos/nthals/extender/pci/pciport.rc create mode 100644 private/ntos/nthals/extender/pci/port.c create mode 100644 private/ntos/nthals/extender/pci/sources (limited to 'private/ntos/nthals/extender/pci') diff --git a/private/ntos/nthals/extender/pci/bus.c b/private/ntos/nthals/extender/pci/bus.c new file mode 100644 index 000000000..bd6e3aaf5 --- /dev/null +++ b/private/ntos/nthals/extender/pci/bus.c @@ -0,0 +1,670 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + bus.c + +Abstract: + + +Author: + + Ken Reneris (kenr) March-13-1885 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "pciport.h" + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,PcipCheckBus) +#pragma alloc_text(PAGE,PciCtlCheckDevice) +#pragma alloc_text(PAGE,PcipCrackBAR) +#pragma alloc_text(PAGE,PcipVerifyBarBits) +#pragma alloc_text(PAGE,PcipGetBarBits) +#pragma alloc_text(PAGE,PcipFindDeviceData) +#endif + + +VOID +PcipCheckBus ( + PPCI_PORT PciPort, + BOOLEAN Initialize + ) +{ + NTSTATUS Status; + PBUS_HANDLER Handler; + PCI_SLOT_NUMBER SlotNumber; + ULONG Device, Function; + PPCIBUSDATA PciBusData; + PPCI_COMMON_CONFIG PciData; + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + BOOLEAN BusCheck, SkipDevice; + PDEVICE_DATA DeviceData; + PDEVICE_HANDLER_OBJECT DeviceHandler; + ULONG ObjectSize; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE Handle; + PSINGLE_LIST_ENTRY *Link; + BOOLEAN State; + POWER_STATE PowerState; + ULONG BufferSize; + + PAGED_CODE(); + + Handler = PciPort->Handler; + BusCheck = FALSE; + PciBusData = (PPCIBUSDATA) (Handler->BusData); + PciData = (PPCI_COMMON_CONFIG) buffer; + + // + // We may be removing references to this bus handler, so add + // a reference now + // + + HalReferenceBusHandler (Handler); + + // + // Check for any obslete device data entries + // + + ExAcquireFastMutex (&PcipMutex); + + Link = &PciPort->ValidSlots.Next; + while (*Link) { + DeviceData = CONTAINING_RECORD (*Link, DEVICE_DATA, Next); + if (!DeviceData->Valid) { + + // + // Remove it from the list + // + + *Link = (*Link)->Next; + BusCheck = TRUE; + PciPort->NoValidSlots -= 1; + HalDereferenceBusHandler (Handler); + + // + // Dereference each obsolete device handler object once. This + // counters the original reference made to the device handler + // object when the object was created by this driver. + // + + DeviceHandler = DeviceData2DeviceHandler(DeviceData); + ObDereferenceObject (DeviceHandler); + continue; + } + + Link = & ((*Link)->Next); + } + + ExReleaseFastMutex (&PcipMutex); + + + // + // Check the bus for new devices + // + + SlotNumber.u.AsULONG = 0; + for (Device=0; Device < PCI_MAX_DEVICES; Device++) { + SlotNumber.u.bits.DeviceNumber = Device; + for (Function=0; Function < PCI_MAX_FUNCTION; Function++) { + SlotNumber.u.bits.FunctionNumber = Function; + + // + // Read in the device id + // + + PciBusData->ReadConfig ( + Handler, + SlotNumber, + PciData, + 0, + PCI_COMMON_HDR_LENGTH + ); + + // + // If not valid, skip it + // + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PciData->VendorID == 0) { + break; + } + + // + // Check to see if this known configuration type + // + + switch (PCI_CONFIG_TYPE(PciData)) { + case PCI_DEVICE_TYPE: + case PCI_BRIDGE_TYPE: + SkipDevice = FALSE; + break; + default: + SkipDevice = TRUE; + break; + } + + if (SkipDevice) { + break; + } + + ExAcquireFastMutex (&PcipMutex); + DeviceData = PcipFindDeviceData (PciPort, SlotNumber); + + if (DeviceData == NULL) { + + // + // Initialize the object attributes that will be used to create the + // Device Handler Object. + // + + InitializeObjectAttributes( + &ObjectAttributes, + NULL, + 0, + NULL, + NULL + ); + + ObjectSize = PcipDeviceHandlerObjectSize + sizeof (DEVICE_DATA); + + // + // Create the object + // + + Status = ObCreateObject( + KernelMode, + *IoDeviceHandlerObjectType, + &ObjectAttributes, + KernelMode, + NULL, + ObjectSize, + 0, + 0, + (PVOID *) &DeviceHandler + ); + + if (NT_SUCCESS(Status)) { + RtlZeroMemory (DeviceHandler, ObjectSize); + + DeviceHandler->Type = (USHORT) *IoDeviceHandlerObjectType; + DeviceHandler->Size = (USHORT) ObjectSize; + DeviceHandler->SlotNumber = SlotNumber.u.AsULONG; + + // + // Get a reference to the object + // + + Status = ObReferenceObjectByPointer( + DeviceHandler, + FILE_READ_DATA | FILE_WRITE_DATA, + *IoDeviceHandlerObjectType, + KernelMode + ); + } + + if (NT_SUCCESS(Status)) { + + // + // Insert it into the object table + // + + Status = ObInsertObject( + DeviceHandler, + NULL, + FILE_READ_DATA | FILE_WRITE_DATA, + 0, + NULL, + &Handle + ); + } + + + if (!NT_SUCCESS(Status)) { + + // + // Object not created correctly + // + + ExReleaseFastMutex (&PcipMutex); + break; + } + + ZwClose (Handle); + + + // + // Intialize structure to track device + // + + DebugPrint ((8, "PCI: adding slot %x (for device %04x-%04x)\n", + SlotNumber, + PciData->VendorID, + PciData->DeviceID + )); + + DeviceData = DeviceHandler2DeviceData (DeviceHandler); + + // + // Get BAR decode bits which are supported + // + + Status = PcipGetBarBits (DeviceData, PciPort->Handler); + + if (NT_SUCCESS(Status)) { + + // + // Add it to the list of devices for this bus + // + + DeviceHandler->BusHandler = Handler; + HalReferenceBusHandler (Handler); + + DeviceData->Valid = TRUE; + PciPort->NoValidSlots += 1; + PushEntryList (&PciPort->ValidSlots, &DeviceData->Next); + BusCheck = TRUE; + } + + // + // Obtain an extra reference to the device handler for + // sending some DeviceControls + // + + ObReferenceObjectByPointer ( + DeviceHandler, + FILE_READ_DATA | FILE_WRITE_DATA, + *IoDeviceHandlerObjectType, + KernelMode + ); + + // + // If we are installing the initail bus support, then + // all devices are installed as locked & powered up. + // If this is a dynamically located new device, then + // the device is started as unlocked & powered down. + // + + if (Initialize) { + + // + // Set initial state as locked + // + + State = TRUE; + BufferSize = sizeof (State); + HalDeviceControl ( + DeviceHandler, + NULL, + BCTL_SET_LOCK, + &State, + &BufferSize, + NULL, + NULL + ); + + // + // Set initial power state as Powered Up + // + + PowerState = PowerUp; + BufferSize = sizeof (PowerState); + HalDeviceControl ( + DeviceHandler, + NULL, + BCTL_SET_POWER, + (PVOID) &PowerState, + &BufferSize, + NULL, + NULL + ); + } + + // + // Free once + // + + ObDereferenceObject (DeviceHandler); + } + + ExReleaseFastMutex (&PcipMutex); + } + } + + // + // Undo reference to bus handler from top of function + // + + HalDereferenceBusHandler (Handler); + + // + // Do we need to notify the system buscheck callback? + // + + if (BusCheck) { + ExNotifyCallback ( + PciHalCallbacks.BusCheck, + (PVOID) PciPort->Handler->InterfaceType, + (PVOID) PciPort->Handler->BusNumber + ); + } + +} + +NTSTATUS +PcipVerifyBarBits ( + PDEVICE_DATA DeviceData, + PBUS_HANDLER Handler + ) +{ + NTSTATUS Status; + + PAGED_CODE (); + + Status = STATUS_SUCCESS; + if (!DeviceData->BARBitsSet) { + + DeviceData->BARBitsSet = TRUE; + Status = PcipGetBarBits (DeviceData, Handler); + + if (!NT_SUCCESS(Status)) { + DeviceData->BARBitsSet = FALSE; + } + } + + return Status; +} + + + +NTSTATUS +PcipGetBarBits ( + PDEVICE_DATA DeviceData, + PBUS_HANDLER Handler + ) +{ + PPCIBUSDATA PciBusData; + PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1]; + ULONG NoBaseAddress, RomIndex; + PULONG BaseAddress2[PCI_TYPE0_ADDRESSES + 1]; + ULONG NoBaseAddress2, RomIndex2; + ULONG j; + PPCI_COMMON_CONFIG PciData; + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + LONGLONG bits, base, length, max; + BOOLEAN BrokenDevice; + PCI_SLOT_NUMBER SlotNumber; + + PAGED_CODE (); + + PciData = (PPCI_COMMON_CONFIG) buffer; + PciBusData = (PPCIBUSDATA) (Handler->BusData); + SlotNumber.u.AsULONG = DeviceDataSlot(DeviceData); + + // + // Get the device's current configuration + // + + if (!DeviceData->CurrentConfig) { + DeviceData->CurrentConfig = (PPCI_COMMON_CONFIG) + ExAllocatePoolWithTag (NonPagedPool, PCI_COMMON_HDR_LENGTH, 'cICP'); + + if (!DeviceData->CurrentConfig) { + return STATUS_INSUFFICIENT_RESOURCES; + } + } + + PciBusData->ReadConfig ( + Handler, + SlotNumber, + PciData, + 0, + PCI_COMMON_HDR_LENGTH + ); + + RtlCopyMemory (DeviceData->CurrentConfig, PciData, PCI_COMMON_HDR_LENGTH); + + // + // Get BaseAddress array, and check if ROM was originally enabled + // + + DeviceData->EnableRom = PcipCalcBaseAddrPointers ( + DeviceData, + PciData, + BaseAddress, + &NoBaseAddress, + &RomIndex + ); + + // + // If the device's current configuration isn't enabled, then set for + // not powered on + // + + if (!(PciData->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE))) { + DeviceData->Power = FALSE; + DeviceData->Locked = FALSE; + } + + // + // Check to see if there are any BARs + // + + for (j=0; j < NoBaseAddress; j++) { + DeviceData->BARBits[j] = 0; + if (*BaseAddress[j]) { + DeviceData->BARBitsSet = TRUE; + } + } + + // + // If not BarBitsSet, then don't attempt to determine the possible + // device settings now + // + + if (!DeviceData->BARBitsSet) { + DebugPrint ((2, "PCI: ghost added device %04x-%04x in slot %x\n", + PciData->VendorID, + PciData->DeviceID, + SlotNumber)); + + return STATUS_SUCCESS; + } + + // + // Set BARs to all on, and read them back + // + + DebugPrint ((3, "PCI: getting valid BAR bits on device %04x-%04x in slot %x\n", + PciData->VendorID, + PciData->DeviceID, + SlotNumber + )); + + + PciData->Command &= ~(PCI_ENABLE_IO_SPACE | + PCI_ENABLE_MEMORY_SPACE | + PCI_ENABLE_BUS_MASTER); + + for (j=0; j < NoBaseAddress; j++) { + *BaseAddress[j] = 0xFFFFFFFF; + } + + PciBusData->WriteConfig ( + Handler, + SlotNumber, + PciData, + 0, + PCI_COMMON_HDR_LENGTH + ); + + PciBusData->ReadConfig ( + Handler, + SlotNumber, + PciData, + 0, + PCI_COMMON_HDR_LENGTH + ); + + + PcipCalcBaseAddrPointers ( + DeviceData, + PciData, + BaseAddress, + &NoBaseAddress, + &RomIndex + ); + + PcipCalcBaseAddrPointers ( + DeviceData, + DeviceData->CurrentConfig, + BaseAddress2, + &NoBaseAddress2, + &RomIndex2 + ); + + + for (j=0; j < NoBaseAddress; j++) { + if (*BaseAddress[j]) { + + // + // Remember the original bits + // + + DeviceData->BARBits[j] = *BaseAddress[j]; + if (Is64BitBaseAddress(*BaseAddress[j])) { + DeviceData->BARBits[j+1] = *BaseAddress[j+1]; + } + + // + // Crack bits & check for BrokenDevice + // + + BrokenDevice = PcipCrackBAR ( + BaseAddress2, + DeviceData->BARBits, + &j, + &base, + &length, + &max + ); + + if (BrokenDevice) { + DeviceData->BrokenDevice = TRUE; + } + } + } + + if (DeviceData->BrokenDevice) { + DebugPrint ((2, "PCI: added defective device %04x-%04x in slot %x\n", + PciData->VendorID, + PciData->DeviceID, + SlotNumber)); + + } else { + DebugPrint ((2, "PCI: added device %04x-%04x in slot %x\n", + PciData->VendorID, + PciData->DeviceID, + SlotNumber)); + } + + return STATUS_SUCCESS; +} + +PDEVICE_DATA +PcipFindDeviceData ( + IN PPCI_PORT PciPort, + IN PCI_SLOT_NUMBER SlotNumber + ) +{ + PDEVICE_DATA DeviceData; + PSINGLE_LIST_ENTRY Link; + PDEVICE_HANDLER_OBJECT DeviceHandler; + + PAGED_CODE (); + + for (Link = PciPort->ValidSlots.Next; Link; Link = Link->Next) { + DeviceData = CONTAINING_RECORD (Link, DEVICE_DATA, Next); + DeviceHandler = DeviceData2DeviceHandler(DeviceData); + if (DeviceHandler->SlotNumber == SlotNumber.u.AsULONG) { + break; + } + } + + if (!Link) { + return NULL; + } + + return DeviceData; +} + + +BOOLEAN +PcipCrackBAR ( + IN PULONG *BaseAddress, + IN PULONG BarBits, + IN OUT PULONG Index, + OUT PLONGLONG pbase, + OUT PLONGLONG plength, + OUT PLONGLONG pmax + ) +{ + LONGLONG base, length, max, bits; + BOOLEAN Status; + + PAGED_CODE (); + + // + // Get initial base & bits + // + + base = *BaseAddress[*Index]; + bits = BarBits[*Index]; + + if (Is64BitBaseAddress(base)) { + *Index += 1; + base |= ((LONGLONG) *BaseAddress[*Index]) << 32; + bits |= ((LONGLONG) BarBits[*Index]) << 32; + } + + // + // Scan for first set bit, that's the BARs length and alignment + // + + length = (base & PCI_ADDRESS_IO_SPACE) ? 1 << 2 : 1 << 4; + while (!(bits & length) && length) { + length <<= 1; + } + + // + // Scan for last set bit, that's that BARs max address + 1 + // + + for (max = length; bits & max; max <<= 1) ; + max -= 1; + + // + // Check for defective BAR + // + + Status = (bits & ~max) ? TRUE : FALSE; + + // + // return results + // + + *pbase = base; + *plength = length; + *pmax = max; + return Status; +} diff --git a/private/ntos/nthals/extender/pci/control.c b/private/ntos/nthals/extender/pci/control.c new file mode 100644 index 000000000..2ac6e2b24 --- /dev/null +++ b/private/ntos/nthals/extender/pci/control.c @@ -0,0 +1,662 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + control.c + +Abstract: + + +Author: + + Ken Reneris (kenr) March-13-1885 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "pciport.h" + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,PcipControlWorker) +#pragma alloc_text(PAGE,PciCtlEject) +#pragma alloc_text(PAGE,PciCtlLock) +#pragma alloc_text(PAGE,PciCtlForward) +#pragma alloc_text(PAGE,PcipCompleteDeviceControl) +#endif + + +VOID +PcipStartWorker ( + VOID + ) +/*++ + +Routine Description: + + This function is used to verify a worker thread is dispatched + +Arguments: + +Return Value: + +--*/ +{ + ULONG WorkerQueued; + + if (!PcipWorkerQueued) { + WorkerQueued = ExInterlockedExchangeUlong ( + &PcipWorkerQueued, + 1, + PcipSpinLock + ); + + if (!WorkerQueued) { + ExQueueWorkItem (&PcipWorkItem, DelayedWorkQueue); + } + } +} + +VOID +PcipQueueCheckBus ( + PBUS_HANDLER Handler + ) +{ + PPCI_PORT PciPort; + + PciPort = PCIPORTDATA(Handler); + ExInterlockedInsertTailList ( + &PcipCheckBusList, + &PciPort->CheckBus, + &PcipSpinlock + ); + + PcipStartWorker(); +} + + +VOID +PcipControlWorker ( + IN PVOID WorkerContext + ) +/*++ + +Routine Description: + + This function is called by a system worker thread. + + The worker thread dequeues any DeviceControls which need to be + processed and dispatches them. + + It then checks for any + +Arguments: + +Return Value: + +--*/ +{ + PLIST_ENTRY Entry; + PPCI_PORT PciPort; + PHAL_DEVICE_CONTROL_CONTEXT Context; + + PAGED_CODE (); + + // + // Dispatch pending slot controls + // + + for (; ;) { + Entry = ExInterlockedRemoveHeadList ( + &PcipControlWorkerList, + &PcipSpinlock + ); + + if (!Entry) { + break; + } + + Context = CONTAINING_RECORD ( + Entry, + HAL_DEVICE_CONTROL_CONTEXT, + ContextWorkQueue, + ); + + PcipDispatchControl (Context); + } + + // + // Reset worker item for next time + // + + ExInitializeWorkItem (&PcipWorkItem, PcipControlWorker, NULL); + ExInterlockedExchangeUlong (&PcipWorkerQueued, 0, PcipSpinLock); + + // + // Process check buses + // + + for (; ;) { + Entry = ExInterlockedRemoveHeadList ( + &PcipCheckBusList, + &PcipSpinlock + ); + + if (!Entry) { + break; + } + + PciPort = CONTAINING_RECORD ( + Entry, + PCI_PORT, + CheckBus + ); + + PcipCheckBus (PciPort, FALSE); + } +} + + +VOID +PcipDispatchControl ( + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function dispatches a DeviceControl to the appropiate handler. + If the slot is busy, the DeviceControl may be queued for dispatching at + a later time + +Arguments: + + Context - The DeviceControl context to dispatch + +Return Value: + +--*/ +{ + PDEVICE_CONTROL_HANDLER DeviceControlHandler; + PDEVICE_DATA DeviceData; + PPCI_PORT PciPort; + KIRQL OldIrql; + BOOLEAN EnqueueIt; + PLIST_ENTRY Link; + + DeviceControlHandler = (PDEVICE_CONTROL_HANDLER) Context->ContextControlHandler; + PciPort = PCIPORTDATA(Context->Handler); + DeviceData = DeviceHandler2DeviceData (Context->DeviceControl.DeviceHandler); + + // + // Get access to the device specific data. + // + + KeAcquireSpinLock (&PcipSpinlock, &OldIrql); + + // + // Verify the device data is still valid + // + + if (!DeviceData->Valid) { + + // + // Caller has invalid handle, or handle to a different device + // + + DebugPrint ((2, "PCI: DeviceControl has invalid device handler \n" )); + Context->DeviceControl.Status = STATUS_NO_SUCH_DEVICE; + KeReleaseSpinLock (&PcipSpinlock, OldIrql); + HalCompleteDeviceControl (Context); + return ; + } + + // + // Check to see if this request can be begun now + // + + Link = (PLIST_ENTRY) &Context->ContextWorkQueue; + EnqueueIt = DeviceControlHandler->BeginDeviceControl (DeviceData, Context); + + if (EnqueueIt) { + + // + // Enqueue this command to be handled when the slot is no longer busy. + // + + InsertTailList (&PciPort->DeviceControl, Link); + KeReleaseSpinLock (&PcipSpinlock, OldIrql); + return ; + } + + // + // Dispatch the function to it's handler + // + + KeReleaseSpinLock (&PcipSpinlock, OldIrql); + DeviceControlHandler->ControlHandler (DeviceData, Context); +} + +VOID +PcipiCompleteDeviceControl ( + NTSTATUS Status, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PDEVICE_DATA DeviceData, + PBOOLEAN Sync + ) +/*++ + +Routine Description: + + This function is used to complete a DeviceControl. If another DeviceControl + was delayed on this device, this function will dispatch them + +Arguments: + +Return Value: + +--*/ +{ + KIRQL OldIrql; + PPCI_PORT PciPort; + PLIST_ENTRY Link; + PBOOLEAN BusyFlag; + BOOLEAN StartWorker; + PDEVICE_HANDLER_OBJECT DeviceHandler; + + + DeviceHandler = DeviceData2DeviceHandler(DeviceData); + BusyFlag = (PBOOLEAN) Context->ContextBusyFlag; + PciPort = PCIPORTDATA(Context->Handler); + + // + // Pass it to the hal for completion + // + + Context->DeviceControl.Status = Status; + HalCompleteDeviceControl (Context); + StartWorker = FALSE; + + // + // Get access to the slot specific data. + // + + KeAcquireSpinLock (&PcipSpinlock, &OldIrql); + + // + // Clear appropiate busy flag + // + + *BusyFlag = FALSE; + + // + // Check to see if there are any pending slot controls for + // this device. If so, requeue them to the worker thread. + // (yes, this code is not efficient, but doing it this way + // saves a little on the nonpaged pool device_data structure size) + // + + for (Link = PciPort->DeviceControl.Flink; Link != &PciPort->DeviceControl; Link = Link->Flink) { + Context = CONTAINING_RECORD (Link, HAL_DEVICE_CONTROL_CONTEXT, ContextWorkQueue); + if (Context->DeviceControl.DeviceHandler == DeviceHandler) { + RemoveEntryList (Link); + InsertTailList (&PcipControlWorkerList, Link); + StartWorker = TRUE; + break; + } + } + + KeReleaseSpinLock (&PcipSpinlock, OldIrql); + + if (StartWorker) { + PcipStartWorker (); + } +} + +VOID +PcipCompleteDeviceControl ( + NTSTATUS Status, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PDEVICE_DATA DeviceData + ) +/*++ + +Routine Description: + + This function is used to complete a DeviceControl. If another DeviceControl + was delayed on this device, this function will dispatch them + +Arguments: + +Return Value: + +--*/ +{ + PAGED_CODE(); + + PcipiCompleteDeviceControl ( + Status, + Context, + DeviceData, + &DeviceData->SyncBusy + ); +} + +BOOLEAN +FASTCALL +PciBCtlPower ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +{ + if ( *((PPOWER_STATE) Context->DeviceControl.Buffer) == PowerUp ) { + + // + // This is a power on, there can only be one of these on the + // slot at any one time + // + + ASSERT (DeviceData->AsyncBusy == FALSE); + + // + // If PowerUp needs to pend, then queue the request + // + + if (DeviceData->PendPowerUp) { + return TRUE; + } + + DeviceData->AsyncBusy = TRUE; + Context->ContextBusyFlag = (ULONG) &DeviceData->AsyncBusy; + return FALSE; + } + + // + // Something other then a PowerUp. Some form of power down, + // treat it like any other sync request + // + + return PciBCtlSync (DeviceData, Context); +} + +BOOLEAN +FASTCALL +PciBCtlSync ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +{ + // + // This is a sync command, verify the slot is not busy with a different + // command. + // + + if (DeviceData->SyncBusy || DeviceData->AsyncBusy) { + + // + // Enqueue this command to be handled when the slot is no longer busy. + // + + return TRUE; + } + + // + // Don't enqueue, dispatch it now + // + + DeviceData->SyncBusy = TRUE; + Context->ContextBusyFlag = (ULONG) &DeviceData->SyncBusy; + return FALSE; +} + +BOOLEAN +FASTCALL +PciBCtlEject ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +{ + BOOLEAN Busy; + + // + // If Slot is busy, then wait + // + + Busy = PciBCtlSync (DeviceData, Context); + + if (!Busy) { + + // + // Just trying to eject a device will invalidate the current + // device handler object for it... + // + + DeviceData->Valid = FALSE; + DebugPrint ((5, "PCI: set handle invalid - slot %x\n", DeviceDataSlot(DeviceData))); + } + + return Busy; +} + +BOOLEAN +FASTCALL +PciBCtlLock ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +{ + BOOLEAN Busy; + + // + // If Slot is busy, then wait + // + + Busy = PciBCtlSync (DeviceData, Context); + if (!Busy && + ((PBCTL_SET_CONTROL) Context->DeviceControl.Buffer) ) { + + // + // About to perform an unlock, set PendPowerUp + // This will stop any async power up requests + // + + ASSERT (DeviceData->PendPowerUp == FALSE); + DeviceData->PendPowerUp = TRUE; + } + + return Busy; +} + +VOID +PciCtlEject ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +{ + NTSTATUS Status; + + PAGED_CODE(); + + // + // We don't know how to lock or unlock, but we track various + // device state. Event attempting to ejecting a device effectively + // unlocks & powers it down. + // + + DeviceData->Locked = FALSE; + Status = PcipPowerDownSlot (Context->Handler, DeviceData); + + // + // Pass the eject request + // + + if (NT_SUCCESS(Status)) { + Status = BugBugSubclass (); + } + + DebugPrint ((2, "PCI: Eject complete - Slot %x, Status %x\n", + DeviceDataSlot(DeviceData), Status)); + + PcipCompleteDeviceControl (Status, Context, DeviceData); +} + + +VOID +PciCtlLock ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +{ + BOOLEAN Lock; + NTSTATUS Status; + + PAGED_CODE(); + + // + // We don't know how to lock or unlock, but we track the + // device's locked state + // + + Lock = ((PBCTL_SET_CONTROL) Context->DeviceControl.Buffer)->Control; + + // + // If this is an unlock request, powered down the slot + // + + Status = STATUS_SUCCESS; + if (!Lock) { + Status = PcipPowerDownSlot (Context->Handler, DeviceData); + } + + // + // Pass the lock request to miniport driver to lock/unlock the slot + // + + if (NT_SUCCESS(Status)) { + Status = BugBugSubclass (); + } + + // + // If it worked, set the new locked state + // + + if (NT_SUCCESS(Status)) { + DeviceData->Locked = Lock; + } + + // + // Allow power requests to continue + // + + DeviceData->PendPowerUp = FALSE; + DebugPrint ((2, "PCI: %s complete - Slot %x, Status %x\n", + Lock ? "Lock" : "Unlock", DeviceDataSlot(DeviceData), Status)); + + PcipCompleteDeviceControl (Status, Context, DeviceData); +} + +VOID +PciCtlPower ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +{ + POWER_STATE Power; + NTSTATUS Status; + + // not pagable + + // + // We don't know how to power on or off the device, but we track the + // device's power state + // + + Power = *((PPOWER_STATE) Context->DeviceControl.Buffer); + + // + // If this is a power down request, complete it + // + + if (Power != PowerUp) { + Status = PcipPowerDownSlot (Context->Handler, DeviceData); + PcipCompleteDeviceControl (Status, Context, DeviceData); + return ; + } + + // + // Device must be locked, or the power up request should have + // received an invalid device error. + // + + ASSERT (DeviceData->Locked); + + // + // If the device already has power, then there's nothing to do + // + + if (DeviceData->Power) { + PcipiCompleteDeviceControl (STATUS_SUCCESS, Context, DeviceData, &DeviceData->AsyncBusy); + return ; + } + + // bugbug pass it to a child driver, for now just complete it + + PcipCompletePowerUp (DeviceData, Context); +} + +VOID +PcipCompletePowerUp ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +{ + NTSTATUS Status; + + // + // Put the device's prior configuration back. + // + + DeviceData->Power = TRUE; + Status = PcipFlushConfig (Context->Handler, DeviceData); + + if (!NT_SUCCESS(Status)) { + + // + // The device's state could not be restored. The decodes + // for the device shouldn't be enabled, so there's no immidiate + // problem. But break the current handle to the device and + // kick off a bus check. This will cause us to assign the + // device a new handle, and to power it off. + // + + DeviceData->Valid = FALSE; + PcipQueueCheckBus (Context->Handler); + } + + if (Context->DeviceControl.ControlCode == BCTL_SET_POWER) { + DebugPrint ((2, "PCI: Powerup complete - Slot %x, Status %x\n", + DeviceDataSlot(DeviceData), Status)); + + PcipiCompleteDeviceControl (Status, Context, DeviceData, &DeviceData->AsyncBusy); + } +} + + +VOID +PciCtlForward ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +{ + PAGED_CODE (); + + DbgPrint ("PCI: BUGBUG Forward\n"); + PcipCompleteDeviceControl (STATUS_NOT_IMPLEMENTED, Context, DeviceData); +} diff --git a/private/ntos/nthals/extender/pci/devres.c b/private/ntos/nthals/extender/pci/devres.c new file mode 100644 index 000000000..578c4ac46 --- /dev/null +++ b/private/ntos/nthals/extender/pci/devres.c @@ -0,0 +1,1139 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + devres.c + +Abstract: + + Device Resources + +Author: + + Ken Reneris (kenr) March-13-1885 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "pciport.h" + + +NTSTATUS +PcipQueryResourceRequirements ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PIO_RESOURCE_REQUIREMENTS_LIST *ResourceList + ); + +NTSTATUS +PcipSetResources ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PCM_RESOURCE_LIST ResourceList, + ULONG ListSize + ); + + +#pragma alloc_text(PAGE,PciCtlQueryDeviceId) +#pragma alloc_text(PAGE,PciCtlQueryDeviceUniqueId) +#pragma alloc_text(PAGE,PciCtlQueryDeviceResources) +#pragma alloc_text(PAGE,PciCtlQueryDeviceResourceRequirements) +#pragma alloc_text(PAGE,PciCtlSetDeviceResources) +#pragma alloc_text(PAGE,PciCtlAssignSlotResources) +#pragma alloc_text(PAGE,PcipQueryResourceRequirements) +#pragma alloc_text(PAGE,PcipSetResources) + + + + +VOID +PciCtlQueryDeviceId ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function returns the device id for the particular slot. + +Arguments: + + DeviceData - Slot data information for the specificied slot + + Context - Slot control context of the request + +Return Value: + + The slot control is completed + +--*/ +{ + NTSTATUS Status; + PPCI_COMMON_CONFIG PciData; + PWCHAR DeviceID; + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + ULONG length; + ULONG IDNumber; + + PAGED_CODE(); + + // + // Read the PCI device's info + // + + PciData = (PPCI_COMMON_CONFIG) buffer; + PcipReadConfig (Context->Handler, DeviceData, PciData); + + // + // Determine which device ID the caller wants back + // + + IDNumber = *((PULONG) Context->DeviceControl.Buffer); + + // + // For PCI devices: + // ID #0 is the specific PCI device ID. + // ID #1 is the compatible device ID based on the BaseClass & SubClass fields + // + + Status = STATUS_NO_MORE_ENTRIES; + DeviceID = (PWCHAR) Context->DeviceControl.Buffer; + + if (IDNumber == 0) { + + // + // Return the PCI device ID + // + + swprintf (DeviceID, PCI_ID, PciData->VendorID, PciData->DeviceID); + Status = STATUS_SUCCESS; + } + + if (IDNumber == 1) { + + // + // Return the first compatible device id for the device + // + + if ( (PciData->BaseClass == 0 && + PciData->SubClass == 1 && + PciData->ProgIf == 0) || + + (PciData->BaseClass == 3 && + PciData->SubClass == 0 && + PciData->ProgIf == 0) ) { + + // + // This is an industry standard VGA controller + // + + swprintf (DeviceID, PNP_VGA); + Status = STATUS_SUCCESS; + } + + if (PciData->BaseClass == 1 && + PciData->SubClass == 0 && + PciData->ProgIf == 0) { + + // + // This is an industry standard IDE controller + // + + swprintf (DeviceID, PNP_IDE); + Status = STATUS_SUCCESS; + + } + } + + PcipCompleteDeviceControl (Status, Context, DeviceData); +} + +VOID +PciCtlQueryDeviceUniqueId ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function returns a unique device id for the particular slot. + The id is a sequence of numbers separated by dots ('.'). The first + number is the bus number of the root of the heirarchy of PCI buses + that the slot belongs to. The last number in the sequence is the + slot number in question. A possibly empty set of numbers in between + these two, represents the slot numbers of intermediate PCI-PCI bridges + in the hierarchy between the root bus and the slot. + + For example, L"0.1.2.3": + 0 PCI bus number of the root of the heirarchy. + 1 Slot number within PCI bus 0 were a PCI-PCI bridge is + located, the secondary bus that it bridges to is PCI bus X. + 2 Slot number within PCI bus X were a PCI-PCI bridge is + located, the secondary bus that it bridges to is PCI bus Y. + 3 Slot number within PCI bus Y for which we are wanting to + obtain the unique id (i.e. the targer of this control operation). + +Arguments: + + DeviceData - Slot data information for the specificied slot + + Context - Slot control context of the request + +Return Value: + + The slot control is completed + +--*/ +{ + NTSTATUS Status; + PBUS_HANDLER BusHandler; + PBUS_HANDLER ParentHandler; + PWCHAR UniqueDeviceId; + PWCHAR UniqueDeviceIdEnd; + PDEVICE_HANDLER_OBJECT DeviceHandler; + BOOLEAN Done; + UCHAR UidComponent; + PPCIBUSDATA PciBusData; + PWCHAR DelimiterPointer; + WCHAR Delimiter; + + PAGED_CODE(); + + // + // Set [UniqueDeviceId, UniqueDeviceIdEnd) to the range of + // wide characters for which the caller provided storage. + // + + Status = STATUS_SUCCESS; + UniqueDeviceId = (PWCHAR) Context->DeviceControl.Buffer; + UniqueDeviceIdEnd = UniqueDeviceId + + *Context->DeviceControl.BufferLength / sizeof(WCHAR); + DeviceHandler = DeviceData2DeviceHandler(DeviceData); + + // + // Determine the memory required for the unique id. + // Note that this loop exits in the middle and that it will + // always be executed at least 1.5 times. If there are PCI-PCI + // bridges between the slot's bus and the root bus of the PCI + // hierarchy, then an extra iteration of the loop will be done + // for each one of them. + // + // The bus hierarchy is being walked backwards (from leaf to root). + // Finally, note that the rightmost uid component is the slot's + // number (set before we enter the loop). + // + + BusHandler = DeviceHandler->BusHandler; + UidComponent = (UCHAR) DeviceHandler->SlotNumber; + Done = FALSE; + + for (;;) { + + // + // On each iteration, given the value of one of the components of + // the unique id, determine how much memory the swprintf would use + // for it (note that the 2, 3 & 4 below include a +1, which is + // for the nul terminator or for the '.' delimiter between two + // unique id components. + // + + if (UidComponent <= 9) { + UniqueDeviceId += 2; + } else if (UidComponent <= 99) { + UniqueDeviceId += 3; + } else { + UniqueDeviceId += 4; + } + + if (Done) { + break; + } + + // + // If there is no parent bus handler for the current bus, + // or if it is not a PCI bus, then we are at the root of + // this hierarchy of PCI buses. In this case the unique id + // component is the bus number (instead of a slot number), + // furthermore, we are almost done (just account for the + // space required in the unique id for it). + // + // Otherwise, the current bus is a PCI-PCI bridge and its + // unique id component is the slot number of the bridge + // within its parent bus. + // + + ParentHandler = BusHandler->ParentHandler; + if (!ParentHandler || ParentHandler->InterfaceType != PCIBus) { + UidComponent = (UCHAR) BusHandler->BusNumber; + Done = TRUE; + } else { + PciBusData = (PPCIBUSDATA) BusHandler->BusData; + UidComponent = (UCHAR) PciBusData->ParentSlot.u.AsULONG; + BusHandler = ParentHandler; + } + } + + // + // If there is not enough space for the unique id, fail + // and return the size required. + // + + if (UniqueDeviceId > UniqueDeviceIdEnd) { + *Context->DeviceControl.BufferLength = (UniqueDeviceIdEnd + - (PWCHAR) Context->DeviceControl.Buffer) * sizeof(WCHAR); + Status = STATUS_BUFFER_TOO_SMALL; + } else { + + // + // Otherwise, traverse the bus heirarchy again (just like + // above), except that this time we decrement the UniqueDeviceId + // on each iteration and swprintf the uid component. Note that + // for all components except for the right most one we store + // a delimiter after it (i.e. a '.'). + // + + BusHandler = DeviceHandler->BusHandler; + UidComponent = (UCHAR) DeviceHandler->SlotNumber; + Done = FALSE; + Delimiter = L'\0'; + for (;;) { + DelimiterPointer = UniqueDeviceId; + if (UidComponent <= 9) { + UniqueDeviceId -= 2; + } else if (UidComponent <= 99) { + UniqueDeviceId -= 3; + } else { + UniqueDeviceId -= 4; + } + swprintf(UniqueDeviceId, L"%d", UidComponent); + DelimiterPointer[-1] = Delimiter; + Delimiter = L'.'; + + if (Done) { + break; + } + + ParentHandler = BusHandler->ParentHandler; + if (!ParentHandler || ParentHandler->InterfaceType != PCIBus) { + UidComponent = (UCHAR) BusHandler->BusNumber; + Done = TRUE; + } else { + PciBusData = (PPCIBUSDATA) BusHandler->BusData; + UidComponent = (UCHAR) PciBusData->ParentSlot.u.AsULONG; + BusHandler = ParentHandler; + } + } + } + + PcipCompleteDeviceControl(Status, Context, DeviceData); +} + + +VOID +PciCtlQueryDeviceResources ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function completes the QUERY_DEVICE_RESOURCES DeviceControl + which returns the bus resources being used by the specified device + +Arguments: + + DeviceData - Slot data information for the specificied slot + + Context - Slot control context of the request + +Return Value: + + The slot control is completed + +--*/ +{ + PPCIBUSDATA PciBusData; + PPCI_COMMON_CONFIG PciData; + ULONG NoBaseAddress, RomIndex; + PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1]; + ULONG i, j; + PCM_RESOURCE_LIST CompleteList; + PCM_PARTIAL_RESOURCE_LIST PartialList; + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; + LONGLONG base, length, max; + NTSTATUS Status; + PUCHAR WorkingPool; + PCI_SLOT_NUMBER SlotNumber; + + PAGED_CODE(); + +// BUGBUG if the device is a pci-2-pci bus controller, then +// this function should return the addresses which are bridged + + // + // Allocate some pool for working space + // + + i = sizeof (CM_RESOURCE_LIST) + + sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) + + PCI_COMMON_HDR_LENGTH; + + WorkingPool = (PUCHAR) ExAllocatePool (PagedPool, i); + if (!WorkingPool) { + PcipCompleteDeviceControl (STATUS_INSUFFICIENT_RESOURCES, Context, DeviceData); + return ; + } + + // + // Zero initialize pool, and get pointers into memory + // + + RtlZeroMemory (WorkingPool, i); + CompleteList = (PCM_RESOURCE_LIST) WorkingPool; + PciData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH); + SlotNumber.u.AsULONG = DeviceDataSlot(DeviceData); + + // + // Read the PCI device's info + // + + PciBusData = (PPCIBUSDATA) (Context->Handler->BusData); + PcipReadConfig (Context->Handler, DeviceData, PciData); + + // + // Initialize base addresses base on configuration data type + // + + PcipCalcBaseAddrPointers ( + DeviceData, + PciData, + BaseAddress, + &NoBaseAddress, + &RomIndex + ); + + // + // Build a CM_RESOURCE_LIST for the PCI device + // + + CompleteList->Count = 1; + CompleteList->List[0].InterfaceType = Context->RootHandler->InterfaceType; + CompleteList->List[0].BusNumber = Context->RootHandler->BusNumber; + + PartialList = &CompleteList->List[0].PartialResourceList; + Descriptor = PartialList->PartialDescriptors; + + // + // If PCI device has an interrupt resource, add it + // + + if (PciData->u.type0.InterruptPin) { + Descriptor->Type = CmResourceTypeInterrupt; + Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + Descriptor->ShareDisposition = CmResourceShareShared; + + PciBusData->Pin2Line ( + Context->Handler, + Context->RootHandler, + SlotNumber, + PciData + ); + + Descriptor->u.Interrupt.Level = PciData->u.type0.InterruptLine; + Descriptor->u.Interrupt.Vector = PciData->u.type0.InterruptLine; + Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF; + + PartialList->Count++; + Descriptor++; + } + + // + // Add any memory / port resources being used + // + + for (j=0; j < NoBaseAddress; j++) { + if (*BaseAddress[j]) { + + ASSERT (DeviceData->BARBitsSet); + PcipCrackBAR (BaseAddress, DeviceData->BARBits, &j, &base, &length, &max); + + if (base & PCI_ADDRESS_IO_SPACE) { + + if (PciData->Command & PCI_ENABLE_IO_SPACE) { + Descriptor->Type = CmResourceTypePort; + Descriptor->Flags = CM_RESOURCE_PORT_IO; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + + Descriptor->u.Port.Start.QuadPart = base & ~0x3; + ASSERT (length <= 0xFFFFFFFF); + Descriptor->u.Port.Length = (ULONG) length; + } + + + } else { + + if (PciData->Command & PCI_ENABLE_MEMORY_SPACE) { + Descriptor->Type = CmResourceTypeMemory; + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + + if (j == RomIndex) { + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY; + } + + if (base & PCI_ADDRESS_MEMORY_PREFETCHABLE) { + Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; + } + + Descriptor->u.Memory.Start.QuadPart = base & ~0xF; + ASSERT (length < 0xFFFFFFFF); + Descriptor->u.Memory.Length = (ULONG) length; + } + } + + PartialList->Count++; + Descriptor++; + } + } + + // + // Return results + // + + i = (ULONG) ((PUCHAR) Descriptor - (PUCHAR) CompleteList); + if (i > *Context->DeviceControl.BufferLength) { + Status = STATUS_BUFFER_TOO_SMALL; + } else { + RtlCopyMemory (Context->DeviceControl.Buffer, CompleteList, i); + Status = STATUS_SUCCESS; + } + + *Context->DeviceControl.BufferLength = i; + ExFreePool (WorkingPool); + PcipCompleteDeviceControl (Status, Context, DeviceData); +} + +VOID +PciCtlQueryDeviceResourceRequirements ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function completes the QUERY_DEVICE_RESOURCE_REQUIREMENTS DeviceControl + which returns the possible bus resources that this device may be + satisfied with. + +Arguments: + + DeviceData - Slot data information for the specificied slot + + Context - Slot control context of the request + +Return Value: + + The slot control is completed + +--*/ +{ + PIO_RESOURCE_REQUIREMENTS_LIST ResourceList; + NTSTATUS Status; + + PAGED_CODE(); + + // + // Get the resource requirements list for the device + // + + Status = PcipQueryResourceRequirements (DeviceData, Context, &ResourceList); + + if (NT_SUCCESS(Status)) { + + // + // Return results + // + + if (ResourceList->ListSize > *Context->DeviceControl.BufferLength) { + Status = STATUS_BUFFER_TOO_SMALL; + } else { + RtlCopyMemory (Context->DeviceControl.Buffer, ResourceList, ResourceList->ListSize); + Status = STATUS_SUCCESS; + } + + *Context->DeviceControl.BufferLength = ResourceList->ListSize; + + } + + if (ResourceList) { + ExFreePool (ResourceList); + } + + PcipCompleteDeviceControl (Status, Context, DeviceData); +} + + +NTSTATUS +PcipQueryResourceRequirements ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PIO_RESOURCE_REQUIREMENTS_LIST *ResourceList + ) +/*++ + +Routine Description: + + This function allocates and returns the specified devices + IO_RESOURCE_REQUIREMENTS_LIST + +Arguments: + + DeviceData - Slot data information for the specificied slot + + Context - Slot control context of the request + +Return Value: + + The slot control is completed + +--*/ +{ + PPCIBUSDATA PciBusData; + PPCI_COMMON_CONFIG PciData; + ULONG NoBaseAddress, RomIndex; + PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1]; + ULONG i, j; + PIO_RESOURCE_REQUIREMENTS_LIST CompleteList; + PIO_RESOURCE_DESCRIPTOR Descriptor; + LONGLONG base, length, max; + NTSTATUS Status; + PUCHAR WorkingPool; + + PAGED_CODE(); + + // + // Allocate some pool for working space + // + + i = sizeof (IO_RESOURCE_REQUIREMENTS_LIST) + + sizeof (IO_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) * 2 + + PCI_COMMON_HDR_LENGTH; + + WorkingPool = (PUCHAR) ExAllocatePool (PagedPool, i); + *ResourceList = (PIO_RESOURCE_REQUIREMENTS_LIST) WorkingPool; + if (!*ResourceList) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Zero initialize pool, and get pointers into memory + // + + RtlZeroMemory (WorkingPool, i); + CompleteList = (PIO_RESOURCE_REQUIREMENTS_LIST) WorkingPool; + PciData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH); + + // + // Read the PCI device's info + // + + PciBusData = (PPCIBUSDATA) (Context->Handler->BusData); + PcipReadConfig (Context->Handler, DeviceData, PciData); + + // + // Initialize base addresses base on configuration data type + // + + PcipCalcBaseAddrPointers ( + DeviceData, + PciData, + BaseAddress, + &NoBaseAddress, + &RomIndex + ); + + // + // Build an IO_RESOURCE_REQUIREMENTS_LIST for the PCI device + // + + CompleteList->InterfaceType = Context->RootHandler->InterfaceType; + CompleteList->BusNumber = Context->RootHandler->BusNumber; + CompleteList->SlotNumber = DeviceDataSlot(DeviceData); + CompleteList->AlternativeLists = 1; + + CompleteList->List[0].Version = 1; + CompleteList->List[0].Revision = 1; + + Descriptor = CompleteList->List[0].Descriptors; + + // + // If PCI device has an interrupt resource, add it + // + + if (PciData->u.type0.InterruptPin) { + Descriptor->Type = CmResourceTypeInterrupt; + Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + Descriptor->ShareDisposition = CmResourceShareShared; + + // BUGBUG: this is not correct + Descriptor->u.Interrupt.MinimumVector = 0; + Descriptor->u.Interrupt.MaximumVector = 0xff; + + CompleteList->List[0].Count++; + Descriptor++; + } + + // + // Add any memory / port resources being used + // + + for (j=0; j < NoBaseAddress; j++) { + if (*BaseAddress[j]) { + + PcipCrackBAR (BaseAddress, DeviceData->BARBits, &j, &base, &length, &max); + + // + // Add a descriptor for this address + // + + Descriptor->Option = 0; + if (base & PCI_ADDRESS_IO_SPACE) { + Descriptor->Type = CmResourceTypePort; + Descriptor->Flags = CM_RESOURCE_PORT_IO; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + + ASSERT (length <= 0xFFFFFFFF); + Descriptor->u.Port.Alignment = (ULONG) length; + Descriptor->u.Port.Length = (ULONG) length; + Descriptor->u.Port.MinimumAddress.QuadPart = 0; + Descriptor->u.Port.MaximumAddress.QuadPart = max; + + } else { + Descriptor->Type = CmResourceTypeMemory; + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + + if (j == RomIndex) { + // this is a ROM address + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY; + } + + if (base & PCI_ADDRESS_MEMORY_PREFETCHABLE) { + Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; + } + + ASSERT (length <= 0xFFFFFFFF); + Descriptor->u.Memory.Alignment = (ULONG) length; + Descriptor->u.Memory.Length = (ULONG) length; + Descriptor->u.Memory.MinimumAddress.QuadPart = 0; + Descriptor->u.Memory.MaximumAddress.QuadPart = max; + } + + CompleteList->List[0].Count++; + Descriptor++; + } + } + + if (DeviceData->BrokenDevice) { + + // + // This device has something wrong with its base address register implementation + // + + ExFreePool (WorkingPool); + return STATUS_DEVICE_PROTOCOL_ERROR; + } + + // + // Return results + // + + CompleteList->ListSize = (ULONG) ((PUCHAR) Descriptor - (PUCHAR) CompleteList); + *ResourceList = CompleteList; + return STATUS_SUCCESS; +} + +VOID +PciCtlSetDeviceResources ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function completes the SET_DEVICE_RESOURCES DeviceControl + which configures the device to the specified device setttings + +Arguments: + + DeviceData - Slot data information for the specificied slot + + Context - Slot control context of the request + +Return Value: + + The slot control is completed + +--*/ +{ + NTSTATUS Status; + + PAGED_CODE(); + + // + // Get the resource requirements list for the device + // + + Status = PcipSetResources ( + DeviceData, + Context, + (PCM_RESOURCE_LIST) Context->DeviceControl.Buffer, + *Context->DeviceControl.BufferLength + ); + + PcipCompleteDeviceControl (Status, Context, DeviceData); +} + + +NTSTATUS +PcipSetResources ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PCM_RESOURCE_LIST ResourceList, + ULONG ListSize + ) +/*++ + +Routine Description: + + This function set the specified device to the CM_RESOURCE_LIST + +Arguments: + +Return Value: + + The slot control is completed + +--*/ +{ + PPCIBUSDATA PciBusData; + PPCI_COMMON_CONFIG PciData, PciOrigData; + ULONG NoBaseAddress, RomIndex; + PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1]; + ULONG i, j; + PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor; + LONGLONG base, length; + NTSTATUS Status; + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + PCI_SLOT_NUMBER SlotNumber; + + PAGED_CODE(); + + PciBusData = (PPCIBUSDATA) (Context->Handler->BusData); + SlotNumber.u.AsULONG = DeviceDataSlot(DeviceData); + + // + // If BARBits haven't been deteremined, go do it now + // + + Status = PcipVerifyBarBits (DeviceData, Context->Handler); + if (!NT_SUCCESS(Status)) { + return Status; + } + + + // + // Get current device configuration + // + + if (DeviceData->Power) { + ASSERT (DeviceData->CurrentConfig == NULL); + DeviceData->CurrentConfig = (PPCI_COMMON_CONFIG) + ExAllocatePool (NonPagedPool, PCI_COMMON_HDR_LENGTH); + + if (!DeviceData->CurrentConfig) { + return STATUS_INSUFFICIENT_RESOURCES; + } + } + + // + // Read the PCI device's info + // + + PciData = DeviceData->CurrentConfig; + PciOrigData = (PPCI_COMMON_CONFIG) buffer; + PcipReadConfig (Context->Handler, DeviceData, PciData); + + // + // Save current config + // + + RtlCopyMemory (PciOrigData, PciData, PCI_COMMON_HDR_LENGTH); + + // + // Initialize base addresses base on configuration data type + // + + PcipCalcBaseAddrPointers ( + DeviceData, + PciData, + BaseAddress, + &NoBaseAddress, + &RomIndex + ); + + // + // Slurp the assigments back into the PciData structure and + // perform them + // + + CmDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors; + + // + // If PCI device has an interrupt resource then that was + // passed in as the first requested resource + // + + if (PciData->u.type0.InterruptPin) { + + // + // Assign the interrupt line + // + + if (CmDescriptor->Type != CmResourceTypeInterrupt) { + Status = STATUS_INVALID_PARAMETER; + goto CleanUp; + } + + PciData->u.type0.InterruptLine = (UCHAR) CmDescriptor->u.Interrupt.Vector; + + PciBusData->Pin2Line ( + Context->Handler, + Context->RootHandler, + SlotNumber, + PciData + ); + + CmDescriptor++; + } + + for (j=0; j < NoBaseAddress; j++) { + base = *BaseAddress[j]; + if (base) { + // + // Set 32bits and mask + // + + if (base & PCI_ADDRESS_IO_SPACE) { + if (CmDescriptor->Type != CmResourceTypePort) { + Status = STATUS_INVALID_PARAMETER; + goto CleanUp; + } + + *BaseAddress[j] = CmDescriptor->u.Port.Start.LowPart; + + } else { + if (CmDescriptor->Type != CmResourceTypeMemory) { + Status = STATUS_INVALID_PARAMETER; + goto CleanUp; + } + + *BaseAddress[j] = CmDescriptor->u.Memory.Start.LowPart; + } + + if (Is64BitBaseAddress(base)) { + + // + // Set upper 32bits + // + + if (base & PCI_ADDRESS_IO_SPACE) { + *BaseAddress[j+1] = CmDescriptor->u.Port.Start.HighPart; + } else { + *BaseAddress[j+1] = CmDescriptor->u.Memory.Start.HighPart; + } + + j++; + } + + CmDescriptor++; + } + } + + // + // Enabel decodes and set the new addresses + // + + if (DeviceData->EnableRom && *BaseAddress[RomIndex]) { + // a rom address was allocated and should be enabled + *BaseAddress[RomIndex] |= PCI_ROMADDRESS_ENABLED; + } + + PciData->Command |= PCI_ENABLE_IO_SPACE | + PCI_ENABLE_MEMORY_SPACE | + PCI_ENABLE_BUS_MASTER; + + // + // If the device is powered on, flush the cached config information + // to the device; otherwise, leave the new configuration in memory - + // it will get flushed to the device when it's powered on + // + + Status = STATUS_SUCCESS; + if (DeviceData->Power) { + Status = PcipFlushConfig (Context->Handler, DeviceData); + } + +CleanUp: + // + // If there was an error, and the device still has a cached current + // config, put the configuration back as it was when we found it + // + + if (!NT_SUCCESS (Status) && DeviceData->CurrentConfig) { + RtlCopyMemory (DeviceData->CurrentConfig, PciOrigData, PCI_COMMON_HDR_LENGTH); + } + + return Status; +} + + +VOID +PciCtlAssignSlotResources ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function completes the internal AssignSlotResources DeviceControl + +Arguments: + + DeviceData - Slot data information for the specificied slot + + Context - Slot control context of the request + +Return Value: + + The slot control is completed + +--*/ +{ + PIO_RESOURCE_REQUIREMENTS_LIST ResourceList; + PCTL_ASSIGN_RESOURCES AssignResources; + PCM_RESOURCE_LIST AllocatedResources; + NTSTATUS Status; + ULONG l; + POWER_STATE PowerControl; + + PAGED_CODE(); + + ResourceList = NULL; + AllocatedResources = NULL; + AssignResources = (PCTL_ASSIGN_RESOURCES) Context->DeviceControl.Buffer; + + // + // If BARBits haven't been deteremined, go do it now + // + + Status = PcipVerifyBarBits (DeviceData, Context->Handler); + if (!NT_SUCCESS(Status)) { + goto CleanUp; + } + + // + // Get the resource requirements list for the device + // + + Status = PcipQueryResourceRequirements (DeviceData, Context, &ResourceList); + if (!NT_SUCCESS(Status)) { + goto CleanUp; + } + + // + // Get device settings from IO + // + + Status = IoAssignResources ( + AssignResources->RegistryPath, + AssignResources->DriverClassName, + AssignResources->DriverObject, + Context->DeviceControl.DeviceObject, + ResourceList, + &AllocatedResources + ); + + if (!NT_SUCCESS(Status)) { + goto CleanUp; + } + + // + // Set the resources into the device + // + + Status = PcipSetResources (DeviceData, Context, AllocatedResources, 0xFFFFFFFF); + if (!NT_SUCCESS(Status)) { + goto CleanUp; + } + + // + // Turn the device on + // + + PowerControl = PowerUp; + l = sizeof (PowerControl); + + Status = HalDeviceControl ( + Context->DeviceControl.DeviceHandler, + Context->DeviceControl.DeviceObject, + BCTL_SET_POWER, + &PowerControl, + &l, + NULL, + NULL + ); + +CleanUp: + *AssignResources->AllocatedResources = AllocatedResources; + + if (!NT_SUCCESS(Status)) { + + // + // Failure, if there are any allocated resources free them + // + + if (AllocatedResources) { + IoAssignResources ( + AssignResources->RegistryPath, + AssignResources->DriverClassName, + AssignResources->DriverObject, + Context->DeviceControl.DeviceObject, + NULL, + NULL + ); + + ExFreePool (AllocatedResources); + *AssignResources->AllocatedResources = NULL; + } + } + + if (ResourceList) { + ExFreePool (ResourceList); + } + + PcipCompleteDeviceControl (Status, Context, DeviceData); +} diff --git a/private/ntos/nthals/extender/pci/init.c b/private/ntos/nthals/extender/pci/init.c new file mode 100644 index 000000000..f33acf18f --- /dev/null +++ b/private/ntos/nthals/extender/pci/init.c @@ -0,0 +1,357 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + init.c + +Abstract: + + initialization code for pciport.sys + +Author: + + Ken Reneris (kenr) March-13-1885 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "pciport.h" +#include "stdio.h" +#include "stdarg.h" + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,DriverEntry) +#pragma alloc_text(PAGE,PciPortInitialize) +#endif + +#if DBG +VOID +PcipTestIds ( + PBUS_HANDLER PciBus + ) +{ + NTSTATUS Status; + PCI_SLOT_NUMBER SlotNumber; + ULONG Device, Function; + PPCIBUSDATA PciBusData; + PPCI_COMMON_CONFIG PciData; + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + PDEVICE_DATA DeviceData; + PDEVICE_HANDLER_OBJECT DeviceHandler; + ULONG BufferSize; + PWCHAR Wptr; + WCHAR Wchar; + WCHAR DeviceId[64]; + PPCI_PORT PciPort; + + PAGED_CODE(); + + PciPort = PciBus->DeviceObject->DeviceExtension; + PciBusData = (PPCIBUSDATA) (PciBus->BusData); + PciData = (PPCI_COMMON_CONFIG) buffer; + + SlotNumber.u.AsULONG = 0; + for (Device=0; Device < PCI_MAX_DEVICES; Device++) { + SlotNumber.u.bits.DeviceNumber = Device; + for (Function=0; Function < PCI_MAX_FUNCTION; Function++) { + SlotNumber.u.bits.FunctionNumber = Function; + + // + // Read in the device id + // + + PciBusData->ReadConfig ( + PciBus, + SlotNumber, + PciData, + 0, + PCI_COMMON_HDR_LENGTH + ); + + // + // If not valid, skip it + // + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PciData->VendorID == 0 || + (PCI_CONFIG_TYPE(PciData) != PCI_DEVICE_TYPE && + PCI_CONFIG_TYPE(PciData) != PCI_BRIDGE_TYPE)) { + break; + } + + DeviceData = PcipFindDeviceData (PciPort, SlotNumber); + ASSERT(DeviceData); + DeviceHandler = DeviceData2DeviceHandler(DeviceData); + + BufferSize = sizeof (DeviceId); + Status = HalDeviceControl ( + DeviceHandler, + NULL, + BCTL_QUERY_DEVICE_UNIQUE_ID, + DeviceId, + &BufferSize, + NULL, + NULL + ); + + ASSERT(NT_SUCCESS(Status)); + DebugPrint ((2, "PCI: Device Unique ID: ")); + for (Wptr = DeviceId; Wchar = *Wptr++; ) { + char buf[2]; + buf[0] = (char) Wchar; + buf[1] = 0; + DebugPrint ((2, buf)); + } + DebugPrint ((2, "\n")); + } + } +} +#endif // DBG + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + Finds any currently installed PCI buses and initializes them as + pci miniport drivers + +Arguments: + +Return Value: + +--*/ + +{ + PDEVICE_OBJECT DeviceObject; + PBUS_HANDLER PciBus; + NTSTATUS Status; + UNICODE_STRING unicodeString; + ULONG BusNo, junk; + BOOLEAN Install; + OBJECT_ATTRIBUTES ObjectAttributes; + PCALLBACK_OBJECT CallbackObject; + + + PciDriverObject = DriverObject; + + // + // Add IRP handler for IRPs we care about + // + + // DriverObject->MajorFunction[IRP_MJ_CREATE] = + // DriverObject->MajorFunction[IRP_MJ_CLOSE] = + // DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = + // DriverObject->MajorFunction[IRP_MJ_SET_POWER] = + + // + // Initialize globals + // + + ExInitializeWorkItem (&PcipWorkItem, PcipControlWorker, NULL); + KeInitializeSpinLock (&PcipSpinlock); + InitializeListHead (&PcipControlWorkerList); + InitializeListHead (&PcipControlDpcList); + InitializeListHead (&PcipCheckBusList); + ExInitializeFastMutex (&PcipMutex); + ASSERT(PcipMutex.Owner == NULL); + PcipDeviceHandlerObjectSize = *IoDeviceHandlerObjectSize; + + // + // Register on system suspend/hibernate callback + // + + RtlInitUnicodeString(&unicodeString, rgzSuspendCallbackName); + + InitializeObjectAttributes( + &ObjectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + Status = ExCreateCallback (&CallbackObject, &ObjectAttributes, FALSE, FALSE); + if (!NT_SUCCESS(Status)) { + return Status; + } + + PciSuspendRegistration = ExRegisterCallback ( + CallbackObject, + PcipSuspendNotification, + NULL + ); + + ObDereferenceObject (CallbackObject); + + // + // Get access to the HAL callback objects + // + + HalQuerySystemInformation ( + HalCallbackInformation, + sizeof (PciHalCallbacks), + &PciHalCallbacks, + &junk + ); + + // + // For each installed PCI bus + // + + _asm int 3; + + Install = FALSE; + for (BusNo=0; TRUE; BusNo += 1) { + PciBus = HalHandlerForBus (PCIBus, BusNo); + + if (!PciBus) { + break; + } + + Status = PciPortInitialize (PciBus); + if (NT_SUCCESS(Status)) { + Install = TRUE; + } + } + + if (Install) { + DebugPrint ((1, "PCI: Installed\n")); +#if DBG + for (BusNo=0; PciBus = HalHandlerForBus (PCIBus, BusNo); BusNo += 1) { + PcipTestIds(PciBus); + } +#endif + return STATUS_SUCCESS; + } + + // + // Not installing - uninitialize + // + + DebugPrint ((1, "PCI: No internal PCI buses found - not installing\n")); + ExUnregisterCallback (PciSuspendRegistration); + + return STATUS_NO_SUCH_DEVICE; +} + + +NTSTATUS +PciPortInitialize ( + PBUS_HANDLER PciBus + ) +{ + PPCIBUSDATA PciBusData; + PDEVICE_OBJECT BusDeviceObject; + WCHAR buffer[100]; + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + UNICODE_STRING unicodeString; + PPCI_PORT PciPort; + + PAGED_CODE(); + + // + // Verify bus handler is a PCI miniport driver + // + + PciBusData = (PPCIBUSDATA) PciBus->BusData; + if (PciBus->InterfaceType != PCIBus || + PciBus->ConfigurationType != PCIConfiguration || + !PciBusData || + PciBusData->Tag != PCI_DATA_TAG || + PciBusData->Version != PCI_DATA_VERSION) { + + return STATUS_INVALID_PARAMETER; + } + + // + // Create device object for this bus extention + // + + swprintf (buffer, rgzPCIDeviceName, PciBus->BusNumber); + RtlInitUnicodeString (&unicodeString, buffer); + + Status = IoCreateDevice( + PciDriverObject, + sizeof (PCI_PORT), + &unicodeString, + FILE_DEVICE_BUS_EXTENDER, + 0, + FALSE, + &BusDeviceObject + ); + + if (!NT_SUCCESS(Status)) { + return Status; + } + + DebugPrint ((1, "PCI: Adding PCI bus %d\n", PciBus->BusNumber)); + + // + // Install pointer to pci extension structure + // + + PciBusData->Version = 0; + PciBusData->PciExtension = (PVOID) BusDeviceObject->DeviceExtension; + PciBus->DeviceObject = BusDeviceObject; + + // + // Initialize internal pci port structure + // + + PciPort = (PPCI_PORT) BusDeviceObject->DeviceExtension; + RtlZeroMemory (PciPort, sizeof (PCI_PORT)); + PciPort->Handler = PciBus; + InitializeListHead (&PciPort->CheckBus); + InitializeListHead (&PciPort->DeviceControl); + + // + // Intall bus specific handlers + // + + PciBus->GetBusData = (PGETSETBUSDATA) PcipGetBusData; + PciBus->SetBusData = (PGETSETBUSDATA) PcipSetBusData; + PciBus->AssignSlotResources = (PASSIGNSLOTRESOURCES) PcipAssignSlotResources; + PciBus->QueryBusSlots = (PQUERY_BUS_SLOTS) PcipQueryBusSlots; + PciBus->DeviceControl = (PDEVICE_CONTROL) PcipDeviceControl; + PciBus->ReferenceDeviceHandler = (PREFERENCE_DEVICE_HANDLER) PcipReferenceDeviceHandler; + PciBus->GetDeviceData = (PGET_SET_DEVICE_DATA) PcipGetDeviceData; + PciBus->SetDeviceData = (PGET_SET_DEVICE_DATA) PcipSetDeviceData; + PciBus->HibernateBus = (PHIBERNATEBRESUMEBUS) PcipHibernateBus; + PciBus->ResumeBus = (PHIBERNATEBRESUMEBUS) PcipResumeBus; + + // + // We don't need power control irps - we'll handle all system power + // requests via the SystemSuspendHiberante callback and the + // bus extender Hibernate & Resume bus entry points + // + + BusDeviceObject->DeviceObjectExtension->PowerControlNeeded = FALSE; + + // + // BUGBUG: we need to report the resources this PCI bus is using + // + + // + // Perform initial bus check + // + + PcipCheckBus (PciPort, TRUE); + return STATUS_SUCCESS; +} diff --git a/private/ntos/nthals/extender/pci/makefile b/private/ntos/nthals/extender/pci/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/nthals/extender/pci/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/nthals/extender/pci/misc.c b/private/ntos/nthals/extender/pci/misc.c new file mode 100644 index 000000000..beffbc80b --- /dev/null +++ b/private/ntos/nthals/extender/pci/misc.c @@ -0,0 +1,544 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + misc.c + +Abstract: + + +Author: + + Ken Reneris (kenr) March-13-1885 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "pciport.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,PcipReadConfig) +#pragma alloc_text(PAGE,PcipPowerDownSlot) +#endif + +NTSTATUS +PcipPowerDownSlot ( + PBUS_HANDLER Handler, + PDEVICE_DATA DeviceData + ) +/*++ + +Routine Description: + + This function is called to power down a particular slot. + +Arguments: + +Return Value: + + returns once the slot has powered down + +--*/ +{ + USHORT Command; + PPCIBUSDATA PciBusData; + PCI_SLOT_NUMBER SlotNumber; + + PAGED_CODE(); + + PciBusData = (PPCIBUSDATA) (Handler->BusData); + SlotNumber.u.AsULONG = DeviceDataSlot(DeviceData); + + // + // If already powered down, do nothing + // + + if (!DeviceData->Power) { + return STATUS_SUCCESS; + } + + DebugPrint ((2, "PCI: Powering down device - slot %d\n", SlotNumber )); + + // + // Allocate buffer to save current device configuration + // + + ASSERT (DeviceData->CurrentConfig == NULL); + DeviceData->CurrentConfig = (PPCI_COMMON_CONFIG) + ExAllocatePoolWithTag (NonPagedPool, PCI_COMMON_HDR_LENGTH, 'cICP'); + + if (!DeviceData->CurrentConfig) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Read the current configuration + // + + PciBusData->ReadConfig ( + Handler, + SlotNumber, + DeviceData->CurrentConfig, + 0, + PCI_COMMON_HDR_LENGTH + ); + + // + // Power down the device + // + + DeviceData->Power = FALSE; + + // BUGBUG: should pass this request on + + // + // Emulate a powered down device by turning off the device decodes + // + + Command = DeviceData->CurrentConfig->Command; + Command &= ~(PCI_ENABLE_IO_SPACE | + PCI_ENABLE_MEMORY_SPACE | + PCI_ENABLE_BUS_MASTER); + + + PciBusData->WriteConfig ( + Handler, + SlotNumber, + &Command, + FIELD_OFFSET (PCI_COMMON_CONFIG, Command), + sizeof (Command) + ); + + DebugPrint ((2, "PCI: Powerdown complete - Slot %x, Status %x\n", + SlotNumber, STATUS_SUCCESS)); + + return STATUS_SUCCESS; +} + + + +NTSTATUS +PcipPowerUpSlot ( + PBUS_HANDLER Handler, + PDEVICE_DATA DeviceData + ) +/*++ + +Routine Description: + + This function is called to power down a particular slot. + +Arguments: + +Return Value: + + returns once the slot has powered down + +--*/ +{ + // + // If already powered up, do nothing + // + + if (!DeviceData->Power) { + return STATUS_SUCCESS; + } + + // + // Power up the device + // + + DebugPrint ((2, "PCI: Powering up device - slot %d\n", DeviceDataSlot(DeviceData) )); + + DeviceData->Power = TRUE; + + // BUGBUG: should pass this request on + +} + + + +VOID +PcipReadConfig ( + IN PBUS_HANDLER Handler, + IN PDEVICE_DATA DeviceData, + OUT PPCI_COMMON_CONFIG PciData + ) +/*++ + +Routine Description: + + This function returns the current PCI_COMMON_HDR for the device. + If the device is powered off, then the pci_common_hdr is returned + from it's memory image; otherwise, it is read from the device. + +Arguments: + +Return Value: + +--*/ +{ + PPCIBUSDATA PciBusData; + PCI_SLOT_NUMBER SlotNumber; + + PAGED_CODE(); + + PciBusData = (PPCIBUSDATA) (Handler->BusData); + SlotNumber.u.AsULONG = DeviceDataSlot (DeviceData); + + if (!DeviceData->Power) { + + // + // The slot is powered down, return the devices + // current configuration from memory + // + + RtlCopyMemory (PciData, DeviceData->CurrentConfig, PCI_COMMON_HDR_LENGTH); + return ; + } + + // + // Read the devices current configuration from the device + // + + PciBusData->ReadConfig ( + Handler, + SlotNumber, + PciData, + 0, + PCI_COMMON_HDR_LENGTH + ); +} + +NTSTATUS +PcipFlushConfig ( + IN PBUS_HANDLER Handler, + IN PDEVICE_DATA DeviceData + ) +/*++ + +Routine Description: + + This function flushes the cached configuration to the PCI device. + It properly handles disabling & enabling of the memory & io decodes, + and verifies the new base address register settings. If the device + does not take the new settings, if the original settings are known + they are put back into the device. + +Arguments: + +Return Value: + +--*/ +{ + PPCIBUSDATA PciBusData; + USHORT HoldCommand; + PPCI_COMMON_CONFIG PciData, PciData2; + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + NTSTATUS Status; + PCI_SLOT_NUMBER SlotNumber; + + PciBusData = (PPCIBUSDATA) (Handler->BusData); + PciData2 = (PPCI_COMMON_CONFIG) buffer; + PciData = DeviceData->CurrentConfig; + SlotNumber.u.AsULONG = DeviceDataSlot(DeviceData); + + // + // To flush the settings, the device must be in the powered on state + // + + ASSERT (DeviceData->Power); + + // + // Read what is currently in the device + // + + PciBusData->ReadConfig ( + Handler, + SlotNumber, + PciData2, + 0, + PCI_COMMON_HDR_LENGTH + ); + + // + // Had better be correct device + // + + ASSERT (PciData->VendorID == PciData2->VendorID); + ASSERT (PciData->DeviceID == PciData2->DeviceID); + + // + // If decodes aren't the same, then clear decode enables before + // performing initial set + // + + HoldCommand = DeviceData->CurrentConfig->Command; + if (!PcipCompareDecodes (DeviceData, PciData, PciData2)) { + PciData->Command &= ~(PCI_ENABLE_IO_SPACE | + PCI_ENABLE_MEMORY_SPACE | + PCI_ENABLE_BUS_MASTER); + } + + // + // Write the current device condifuragtion + // + + PciBusData->WriteConfig ( + Handler, + SlotNumber, + DeviceData->CurrentConfig, + 0, + PCI_COMMON_HDR_LENGTH + ); + + // + // Read back the configuration and verify it took + // + + PciBusData->ReadConfig ( + Handler, + SlotNumber, + PciData2, + 0, + PCI_COMMON_HDR_LENGTH + ); + + // + // See if configuration matches + // + + if (!PcipCompareDecodes (DeviceData, PciData, PciData2)) { + + // + // The CurrentConfig did not get successfully set + // + + DebugPrint ((1, "PCI: defective device - slot %d\n", SlotNumber)); + DeviceData->BrokenDevice = TRUE; + Status = STATUS_DEVICE_PROTOCOL_ERROR; + + } else { + + // + // Settings are fine - write final decode enable bits + // + + PciBusData->WriteConfig ( + Handler, + SlotNumber, + &HoldCommand, + FIELD_OFFSET (PCI_COMMON_CONFIG, Command), + sizeof (HoldCommand) + ); + + Status = STATUS_SUCCESS; + } + + // + // Current config now flushed to the device. Free memory. + // + + if (DeviceData->CurrentConfig) { + ExFreePool (DeviceData->CurrentConfig); + DeviceData->CurrentConfig = NULL; + } + + return Status; +} + +BOOLEAN +PcipCompareDecodes ( + IN PDEVICE_DATA DeviceData, + IN PPCI_COMMON_CONFIG PciData, + IN PPCI_COMMON_CONFIG PciData2 + ) +/*++ + +Routine Description: + + This function compares the base address registers of PciData and PciData2. + +Arguments: + +Return Value: + +--*/ +{ + PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1]; + PULONG BaseAddress2[PCI_TYPE0_ADDRESSES + 1]; + ULONG NoBaseAddress, RomIndex; + ULONG NoBaseAddress2, RomIndex2; + ULONG i, j; + BOOLEAN Match; + + // + // Initialize base addresses base on configuration data type + // + + PcipCalcBaseAddrPointers ( + DeviceData, + PciData, + BaseAddress, + &NoBaseAddress, + &RomIndex + ); + + PcipCalcBaseAddrPointers ( + DeviceData, + PciData2, + BaseAddress2, + &NoBaseAddress2, + &RomIndex2 + ); + + if (NoBaseAddress != NoBaseAddress2 || + RomIndex != RomIndex2) { + return FALSE; + } + + Match = TRUE; + if (PciData->u.type0.InterruptLine != PciData2->u.type0.InterruptLine || + PciData->u.type0.InterruptPin != PciData2->u.type0.InterruptPin || + PciData->u.type0.ROMBaseAddress != PciData2->u.type0.ROMBaseAddress) { + Match = FALSE; + } + + for (j=0; j < NoBaseAddress; j++) { + if (*BaseAddress[j]) { + if (*BaseAddress[j] & PCI_ADDRESS_IO_SPACE) { + i = (ULONG) ~0x3; + } else { + i = (ULONG) ~0xF; + } + + if ((*BaseAddress[j] & i) != (*BaseAddress2[j] & i)) { + Match = FALSE; + } + + if (Is64BitBaseAddress(*BaseAddress[j])) { + j++; + if ((*BaseAddress[j] & i) != (*BaseAddress2[j] & i)) { + Match = FALSE; + } + } + } + } + + return Match; +} + + + +BOOLEAN +PcipCalcBaseAddrPointers ( + IN PDEVICE_DATA DeviceData, + IN PPCI_COMMON_CONFIG PciData, + OUT PULONG *BaseAddress, + OUT PULONG NoBaseAddress, + OUT PULONG RomIndex + ) +/*++ + +Routine Description: + + This function returns the an array of BaseAddress pointers + in PciData. + +Arguments: + +Return Value: + +--*/ +{ + ULONG j; + BOOLEAN RomEnabled; + + switch (PCI_CONFIG_TYPE(PciData)) { + case PCI_DEVICE_TYPE: + *NoBaseAddress = PCI_TYPE0_ADDRESSES+1; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + BaseAddress[j] = &PciData->u.type0.BaseAddresses[j]; + } + BaseAddress[j] = &PciData->u.type0.ROMBaseAddress; + *RomIndex = j; + break; + + case PCI_BRIDGE_TYPE: + *NoBaseAddress = PCI_TYPE1_ADDRESSES+1; + for (j=0; j < PCI_TYPE1_ADDRESSES; j++) { + BaseAddress[j] = &PciData->u.type1.BaseAddresses[j]; + } + BaseAddress[j] = &PciData->u.type1.ROMBaseAddress; + *RomIndex = j; + break; + + default: + + // BUGBUG: unkown type + + *NoBaseAddress = 0; + ASSERT (*NoBaseAddress); + } + + RomEnabled = (*BaseAddress[*RomIndex] & PCI_ROMADDRESS_ENABLED) ? TRUE : FALSE; + + // + // The device's Rom Base Address register is only enabled if it + // was originaly found that way. + // + + // Clear ROM reserved bits + *BaseAddress[*RomIndex] &= ~0x7FF; + + if (!DeviceData->EnableRom) { + ASSERT (*RomIndex+1 == *NoBaseAddress); + *NoBaseAddress -= 1; + } + + return RomEnabled; +} + + +#if DBG +ULONG ApmDebug = 9; + +VOID +PciDebugPrint ( + ULONG Level, + PCCHAR DebugMessage, + ... + ) + +{ + UCHAR Buffer[256]; + va_list ap; + + va_start(ap, DebugMessage); + + if (Level <= ApmDebug) { + vsprintf(Buffer, DebugMessage, ap); + DbgPrint(Buffer); + } + + va_end(ap); +} +#endif + + + +NTSTATUS +BugBugSubclass ( + VOID + ) +{ + DbgPrint ("PCI: BUGBUG SUBCLASS\n"); + return STATUS_SUCCESS; +} diff --git a/private/ntos/nthals/extender/pci/pcidata.c b/private/ntos/nthals/extender/pci/pcidata.c new file mode 100644 index 000000000..b6783c526 --- /dev/null +++ b/private/ntos/nthals/extender/pci/pcidata.c @@ -0,0 +1,123 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + ixdat.c + +Abstract: + + Declares various data which is initialize data, or pagable data. + +Author: + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "pciport.h" + +// +// PcipWorkdListLock - Lock to protect DeviceControl globals +// PcipControlWorkerList - List of slot control's which are pending for worker thread +// PcipControlDpcList - List of slot control's which are waiting, but are non-paged +// PcipWorkItem - Enqueue for DeviceControl worker thread +// PcipWorkDpc - Enqueue for DeviceControl DPC +// + +FAST_MUTEX PcipMutex; +KSPIN_LOCK PcipSpinlock; +LIST_ENTRY PcipControlWorkerList; +LIST_ENTRY PcipControlDpcList; +LIST_ENTRY PcipCheckBusList; +ULONG PcipWorkerQueued; +WORK_QUEUE_ITEM PcipWorkItem; +KDPC PcipWorkDpc; +ULONG PcipDeviceHandlerObjectSize; + +// +// DeviceControl dispatch table +// + +#define B_EJECT BCTL_EJECT +#define B_ID BCTL_QUERY_DEVICE_ID +#define B_UID BCTL_QUERY_DEVICE_UNIQUE_ID +#define B_CAPABILITIES BCTL_QUERY_DEVICE_CAPABILITIES +#define B_RES BCTL_QUERY_DEVICE_RESOURCES +#define B_RES_REQ BCTL_QUERY_DEVICE_RESOURCE_REQUIREMENTS +#define B_QUERY_EJECT BCTL_QUERY_EJECT +#define B_SET_LOCK BCTL_SET_LOCK +#define B_SET_POWER BCTL_SET_POWER +#define B_SET_RESUME BCTL_SET_RESUME +#define B_SET_RES BCTL_SET_DEVICE_RESOURCES +#define B_ASSIGN_RES BCTL_ASSIGN_SLOT_RESOURCES + +#define SIZE_BRES sizeof(CTL_ASSIGN_RESOURCES) +#define SIZE_CAP sizeof(BCTL_DEVICE_CAPABILITIES) +#define SIZE_CALL sizeof(PCALLBACK_OBJECT) + +DEVICE_CONTROL_HANDLER PcipControl[] = { + B_EJECT, 0, PciBCtlEject, PciCtlEject, + B_ID, 128, PciBCtlSync, PciCtlQueryDeviceId, + B_UID, 128, PciBCtlSync, PciCtlQueryDeviceUniqueId, + B_CAPABILITIES, SIZE_CAP, PciBCtlSync, PciCtlForward, // bugbug + B_RES, sizeof(ULONG), PciBCtlSync, PciCtlQueryDeviceResources, + B_RES_REQ, sizeof(ULONG), PciBCtlSync, PciCtlQueryDeviceResourceRequirements, + B_QUERY_EJECT, SIZE_CALL, PciBCtlSync, PciCtlForward, + B_SET_LOCK, sizeof(BOOLEAN), PciBCtlLock, PciCtlLock, + B_SET_RESUME, sizeof(BOOLEAN), PciBCtlSync, PciCtlForward, + B_SET_POWER, sizeof(POWER_STATE), PciBCtlPower, PciCtlPower, + B_SET_RES, 0, PciBCtlSync, PciCtlSetDeviceResources, + B_ASSIGN_RES, SIZE_BRES, PciBCtlSync, PciCtlAssignSlotResources, + 0, 0, NULL, NULL +}; + + +#ifdef ALLOC_DATA_PRAGMA +#pragma data_seg("PAGE") +#endif + +// +// PciDriverObject - the driver object for pciport.sys +// + + +PDRIVER_OBJECT PciDriverObject; + +// +// PciCodeLock - Handle for locked code (only used during system +// Suspend/Hibernate/Resume procedure) +// + +PVOID PciCodeLock; + +// +// PciSuspendRegistration - A registration to the systems +// Suspend/Hibernate/Resume callback +// + +HAL_CALLBACKS PciHalCallbacks; + +// +// PciSuspendRegistration - A registration to the systems +// Suspend/Hibernate/Resume callback +// + +PVOID PciSuspendRegistration; + +// +// Some global strings +// + +WCHAR rgzPCIDeviceName[] = L"\\Device\\PciBus_%d"; +WCHAR rgzSuspendCallbackName[] = L"\\Callback\\SuspendHibernateSystem"; + +WCHAR PCI_ID[] = L"PCI\\%04x_%04x"; +WCHAR PNP_VGA[] = L"PCI\\*PNP_VGA"; +WCHAR PNP_IDE[] = L"PCI\\*PNP_IDE"; diff --git a/private/ntos/nthals/extender/pci/pciport.h b/private/ntos/nthals/extender/pci/pciport.h new file mode 100644 index 000000000..9e4870ebc --- /dev/null +++ b/private/ntos/nthals/extender/pci/pciport.h @@ -0,0 +1,570 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + pciport.h + +Abstract: + + header file for pciport.sys + +Author: + + Ken Reneris (kenr) March-13-1885 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "nthal.h" +#include "hal.h" +#include "pci.h" +#include "stdio.h" +#include "stdarg.h" + +// +// Structures +// + + +#define PciExtension Reserved[0] + +// +// When queued, the following HAL_DEVICE_CONTROL_CONTEXT values are defined +// + +#define ContextWorkQueue BusExtenderReserved[0] +#define ContextControlHandler BusExtenderReserved[2] + +// +// When in progress, the following HAL_DEVICE_CONTROL_CONTEXT values are defined +// + +#define ContextArgument1 BusExtenderReserved[0] +#define ContextArgument2 BusExtenderReserved[1] +#define ContextBusyFlag BusExtenderReserved[2] + +#define PCIPORTDATA(a) \ + ((PPCI_PORT) ( ((PPCIBUSDATA) (a)->BusData)->PciExtension)) + +#define PCI_CONFIG_TYPE(PciData) \ + ((PciData)->HeaderType & ~PCI_MULTIFUNCTION) + + +#define Is64BitBaseAddress(a) \ + (((a & PCI_ADDRESS_IO_SPACE) == 0) && \ + ((a & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)) + + +#define MAX_VALID_DEVICE_HANDLE 0x7FFFFFFF + +// the follow are handle value states when the handle is > MAX_VALID_DEVICE_HANDLE +#define INITIALIZE_DEVICE_HANDLE 0x80000000 +#define TRANSISTION_DEVICE_HANDLE 0x80000001 +#define INVALID_DEVICE_HANDLE 0x80000002 + +typedef struct _DEVICE_DATA_ { + SINGLE_LIST_ENTRY Next; + + // + // SlotNumber for which this device data corrisponds + // + + //PCI_SLOT_NUMBER SlotNumber; + + // + // + // + + BOOLEAN Valid; + + // + // DeviceControl in progress flags + // + + BOOLEAN SyncBusy; + BOOLEAN AsyncBusy; + + + // + // Track the lock state of the device + // PendPowerUp is used while an Unlock is in progress + // to cause a power up request to wait + // + + BOOLEAN Locked; + BOOLEAN PendPowerUp; + + // + // Track the power state of the device. + // If it's powered off, track the device's configuration. + // + // If the powered off configuration has changed, track the + // original configuration in case the new configuration is + // not supported by the h/w. (would be a defective device) + // + + BOOLEAN Power; + PPCI_COMMON_CONFIG CurrentConfig; + + // + // Since PCI doesn't have a runtime safe way to determine + // the length of it's base register's will we keep track + // of them here. + // + + ULONG BARBits[PCI_TYPE0_ADDRESSES+1]; + + // + // + // + + BOOLEAN BARBitsSet; + + + // + // Determine if the device's rom base address register should + // be enabled + // + + BOOLEAN EnableRom; + + // + // Flag defective hardware which we've noticed that it's base + // address registers do not function properly. + // + + BOOLEAN BrokenDevice; + +} DEVICE_DATA, *PDEVICE_DATA; + +extern POBJECT_TYPE *IoDeviceHandlerObjectType; +extern PULONG IoDeviceHandlerObjectSize; +#define DeviceHandler2DeviceData(a) ((PDEVICE_DATA) (((PUCHAR) a) + PcipDeviceHandlerObjectSize)) +#define DeviceData2DeviceHandler(a) ((PDEVICE_HANDLER_OBJECT) (((PUCHAR) a) - PcipDeviceHandlerObjectSize)) +#define DeviceDataSlot(a) DeviceData2DeviceHandler(a)->SlotNumber + +typedef struct { + BOOLEAN Control; +} *PBCTL_SET_CONTROL; + +typedef struct { + PBUS_HANDLER Handler; + LIST_ENTRY CheckBus; + LIST_ENTRY DeviceControl; + + ULONG NoValidSlots; + SINGLE_LIST_ENTRY ValidSlots; + + PVOID Spare; +} PCI_PORT, *PPCI_PORT; + + +// +// Internal DeviceControls +// + +#define BCTL_ASSIGN_SLOT_RESOURCES 0x90000001 +#define BCTL_CHECK_DEVICE 0x90000002 +#define BCTL_INITIAL_DEVICE 0x90000003 + +typedef struct { + PUNICODE_STRING RegistryPath; + PUNICODE_STRING DriverClassName; + PDRIVER_OBJECT DriverObject; + PCM_RESOURCE_LIST *AllocatedResources; +} CTL_ASSIGN_RESOURCES, *PCTL_ASSIGN_RESOURCES; + +typedef BOOLEAN (FASTCALL * BGNFNC)(PDEVICE_DATA, PHAL_DEVICE_CONTROL_CONTEXT); +typedef VOID (* CTLFNC)(PDEVICE_DATA, PHAL_DEVICE_CONTROL_CONTEXT); + +typedef struct { + ULONG ControlCode; + ULONG MinBuffer; + BGNFNC BeginDeviceControl; + CTLFNC ControlHandler; +} DEVICE_CONTROL_HANDLER, *PDEVICE_CONTROL_HANDLER; + +// +// +// + +#if DBG +VOID PciDebugPrint ( + ULONG Level, + PCCHAR DebugMessage, + ... + ); + +#define DebugPrint(arg) PciDebugPrint arg +#else +#define DebugPrint(arg) +#endif + + +// +// Globals +// + +extern FAST_MUTEX PcipMutex; +extern KSPIN_LOCK PcipSpinlock; +extern LIST_ENTRY PcipControlWorkerList; +extern LIST_ENTRY PcipControlDpcList; +extern LIST_ENTRY PcipCheckBusList; +extern ULONG PcipWorkerQueued; +extern WORK_QUEUE_ITEM PcipWorkItem; +extern KDPC PcipWorkDpc; +extern ULONG PcipNextHandle; +extern DEVICE_CONTROL_HANDLER PcipControl[]; +extern PDRIVER_OBJECT PciDriverObject; +extern HAL_CALLBACKS PciHalCallbacks; +extern PVOID PciSuspendRegistration; +extern PVOID PciCodeLock; +extern WCHAR rgzPCIDeviceName[]; +extern WCHAR rgzSuspendCallbackName[]; +extern WCHAR PCI_ID[]; +extern WCHAR PNP_VGA[]; +extern WCHAR PNP_IDE[]; +extern BOOLEAN PcipNoBusyFlag; +extern ULONG PcipDeviceHandlerObjectSize; + +// +// Prototypes +// + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + + +NTSTATUS +PciPortInitialize ( + PBUS_HANDLER PciBus + ); + +ULONG +PcipGetBusData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +ULONG +PcipGetDeviceData ( + IN struct _BUS_HANDLER *BusHandler, + IN struct _BUS_HANDLER *RootHandler, + IN PDEVICE_HANDLER_OBJECT DeviceHandler, + IN ULONG DataType, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +ULONG +PcipSetBusData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +ULONG +PcipSetDeviceData ( + IN struct _BUS_HANDLER *BusHandler, + IN struct _BUS_HANDLER *RootHandler, + IN PDEVICE_HANDLER_OBJECT DeviceHandler, + IN ULONG DataType, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +NTSTATUS +PcipAssignSlotResources ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG SlotNumber, + IN OUT PCM_RESOURCE_LIST *AllocatedResources + ); + +NTSTATUS +PcipQueryBusSlots ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BufferSize, + OUT PULONG SlotNumbers, + OUT PULONG ReturnedLength + ); + +PDEVICE_HANDLER_OBJECT +PcipReferenceDeviceHandler ( + IN struct _BUS_HANDLER *BusHandler, + IN struct _BUS_HANDLER *RootHandler, + IN PCI_SLOT_NUMBER SlotNumber + ); + +NTSTATUS +PcipDeviceControl ( + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +NTSTATUS +PcipHibernateBus ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler + ); + +NTSTATUS +PcipResumeBus ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler + ); + +VOID +PcipSuspendNotification ( + IN PVOID CallbackContext, + IN PVOID Argument1, + IN PVOID Argument2 + ); + +VOID +PcipStartWorker ( + VOID + ); + +VOID +PcipControlWorker ( + IN PVOID WorkerContext + ); + +VOID +PcipControlDpc ( + PKDPC Dpc, + PVOID DeferredContext, + PVOID SystemArgument1, + PVOID SystemArgument2 + ); + +VOID +PcipDispatchControl ( + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +BOOLEAN +FASTCALL +PciBCtlNone ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +BOOLEAN +FASTCALL +PciBCtlPower ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +BOOLEAN +FASTCALL +PciBCtlSync ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +BOOLEAN +FASTCALL +PciBCtlEject ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +BOOLEAN +FASTCALL +PciBCtlLock ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PciCtlEject ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PciCtlLock ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PciCtlPower ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PciCtlQueryDeviceId ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PciCtlQueryDeviceUniqueId ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PciCtlQueryDeviceResources ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PciCtlQueryDeviceResourceRequirements ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PciCtlSetDeviceResources ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PciCtlAssignSlotResources ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +BOOLEAN +FASTCALL +PciBCtlNone ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +BOOLEAN +FASTCALL +PciBCtlResume ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PciCtlForward ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PcipCompletePowerUp ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PcipCompleteDeviceControl ( + NTSTATUS Status, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PDEVICE_DATA DeviceData + ); + +VOID +PcipReadConfig ( + IN PBUS_HANDLER Handler, + IN PDEVICE_DATA DeviceData, + OUT PPCI_COMMON_CONFIG PciData + ); + +NTSTATUS +PcipFlushConfig ( + IN PBUS_HANDLER Handler, + IN PDEVICE_DATA DeviceData + ); + +BOOLEAN +PcipCompareDecodes ( + IN PDEVICE_DATA DeviceData, + IN PPCI_COMMON_CONFIG PciData, + IN PPCI_COMMON_CONFIG PciData2 + ); + +BOOLEAN +PcipCalcBaseAddrPointers ( + IN PDEVICE_DATA DeviceData, + IN PPCI_COMMON_CONFIG PciData, + OUT PULONG *BaseAddress, + OUT PULONG NoBaseAddress, + OUT PULONG RomIndex + ); + +NTSTATUS +PcipPowerDownSlot ( + PBUS_HANDLER Handler, + PDEVICE_DATA DeviceData + ); + +VOID +PciCtlCheckDevice ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +NTSTATUS +PcipVerifyBarBits ( + PDEVICE_DATA DeviceData, + PBUS_HANDLER Handler + ); + +NTSTATUS +PcipGetBarBits ( + PDEVICE_DATA DeviceData, + PBUS_HANDLER Handler + ); + +PDEVICE_DATA +PcipFindDeviceData ( + IN PPCI_PORT PciPort, + IN PCI_SLOT_NUMBER SlotNumber + ); + +VOID +PcipCheckBus ( + PPCI_PORT PciPort, + BOOLEAN Initialize + ); + +BOOLEAN +PcipCrackBAR ( + IN PULONG *BaseAddress, + IN PULONG BarBits, + IN OUT PULONG Index, + OUT PLONGLONG pbase, + OUT PLONGLONG plength, + OUT PLONGLONG pmax + ); + +NTSTATUS +BugBugSubclass ( + VOID + ); diff --git a/private/ntos/nthals/extender/pci/pciport.rc b/private/ntos/nthals/extender/pci/pciport.rc new file mode 100644 index 000000000..a9a5fec4b --- /dev/null +++ b/private/ntos/nthals/extender/pci/pciport.rc @@ -0,0 +1,11 @@ +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "PCI Bus Class Driver" +#define VER_INTERNALNAME_STR "pciext.sys" +#define VER_ORIGINALFILENAME_STR "pciext.sys" + +#include "common.ver" diff --git a/private/ntos/nthals/extender/pci/port.c b/private/ntos/nthals/extender/pci/port.c new file mode 100644 index 000000000..e78ba1537 --- /dev/null +++ b/private/ntos/nthals/extender/pci/port.c @@ -0,0 +1,713 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + port.c + +Abstract: + + +Author: + + Ken Reneris (kenr) March-13-1885 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "pciport.h" + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,PcipAssignSlotResources) +#pragma alloc_text(PAGE,PcipQueryBusSlots) +#pragma alloc_text(PAGE,PcipHibernateBus) +#pragma alloc_text(PAGE,PcipResumeBus) +#pragma alloc_text(PAGE,PcipSuspendNotification) +#pragma alloc_text(PAGE,PcipReferenceDeviceHandler) +#endif + + +ULONG +PcipGetBusData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + The function returns the Pci bus data for a device. + +Arguments: + + BusNumber - Indicates which bus. + + VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word) + + Buffer - Supplies the space to store the data. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + + If this PCI slot has never been set, then the configuration information + returned is zeroed. + +--*/ +{ + PPCI_COMMON_CONFIG PciData; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + PPCIBUSDATA BusData; + ULONG Len; + ULONG i, bit; + + BusData = (PPCIBUSDATA) BusHandler->BusData; + + if (Length > sizeof (PCI_COMMON_CONFIG)) { + Length = sizeof (PCI_COMMON_CONFIG); + } + + Len = 0; + PciData = (PPCI_COMMON_CONFIG) iBuffer; + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The user did not request any data from the common + // header. Verify the PCI device exists, then continue + // in the device specific area. + // + + BusData->ReadConfig (BusHandler, SlotNumber, PciData, 0, sizeof (ULONG)); + + if (PciData->VendorID == PCI_INVALID_VENDORID) { + return 0; + } + + } else { + + // + // Caller requested at least some data within the + // common header. Read the whole header, effect the + // fields we need to and then copy the user's requested + // bytes from the header + // + + + // + // Read this PCI devices slot data + // + + Len = PCI_COMMON_HDR_LENGTH; + BusData->ReadConfig (BusHandler, SlotNumber, PciData, 0, Len); + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) { + PciData->VendorID = PCI_INVALID_VENDORID; + Len = 2; // only return invalid id + + } else { + + BusData->Pin2Line (BusHandler, RootHandler, SlotNumber, PciData); + } + + // + // Copy whatever data overlaps into the callers buffer + // + + if (Len < Offset) { + // no data at caller's buffer + return 0; + } + + Len -= Offset; + if (Len > Length) { + Len = Length; + } + + RtlMoveMemory(Buffer, iBuffer + Offset, Len); + + Offset += Len; + Buffer += Len; + Length -= Len; + } + + if (Length) { + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The remaining Buffer comes from the Device Specific + // area - put on the kitten gloves and read from it. + // + // Specific read/writes to the PCI device specific area + // are guarenteed: + // + // Not to read/write any byte outside the area specified + // by the caller. (this may cause WORD or BYTE references + // to the area in order to read the non-dword aligned + // ends of the request) + // + // To use a WORD access if the requested length is exactly + // a WORD long. + // + // To use a BYTE access if the requested length is exactly + // a BYTE long. + // + + BusData->ReadConfig (BusHandler, SlotNumber, Buffer, Offset, Length); + Len += Length; + } + } + + return Len; +} + + +ULONG +PcipGetDeviceData ( + IN struct _BUS_HANDLER *BusHandler, + IN struct _BUS_HANDLER *RootHandler, + IN PDEVICE_HANDLER_OBJECT DeviceHandler, + IN ULONG DataType, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ + ULONG Status; + PDEVICE_DATA DeviceData; + PCI_SLOT_NUMBER SlotNumber; + + Status = 0; + DeviceData = DeviceHandler2DeviceData (DeviceHandler); + + // + // Verify caller has a valid DeviceHandler object + // + + if (!DeviceData->Valid) { + + // + // Obsolete object, return no data + // + + return 0; + } + + // + // Get the device's data. + // + + if (DataType == 0) { + + // + // Type 0 is the same as GetBusData for the slot + // + + SlotNumber.u.AsULONG = DeviceHandler->SlotNumber; + Status = PcipGetBusData ( + BusHandler, + RootHandler, + SlotNumber, + Buffer, + Offset, + Length + ); + } + + return Status; +} + + +ULONG +PcipSetBusData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ + PPCI_COMMON_CONFIG PciData, PciData2; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH]; + PPCIBUSDATA BusData; + ULONG Len, cnt; + + BusData = (PPCIBUSDATA) BusHandler->BusData; + + if (Length > sizeof (PCI_COMMON_CONFIG)) { + Length = sizeof (PCI_COMMON_CONFIG); + } + + Len = 0; + PciData = (PPCI_COMMON_CONFIG) iBuffer; + PciData2 = (PPCI_COMMON_CONFIG) iBuffer2; + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The user did not request any data from the common + // header. Verify the PCI device exists, then continue in + // the device specific area. + // + + BusData->ReadConfig (BusHandler, SlotNumber, PciData, 0, sizeof(ULONG)); + + if (PciData->VendorID == PCI_INVALID_VENDORID) { + return 0; + } + + } else { + + // + // Caller requested to set at least some data within the + // common header. + // + + Len = PCI_COMMON_HDR_LENGTH; + BusData->ReadConfig (BusHandler, SlotNumber, PciData, 0, Len); + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) { + + // no device, or header type unkown + return 0; + } + + // + // Copy COMMON_HDR values to buffer2, then overlay callers changes. + // + + RtlMoveMemory (iBuffer2, iBuffer, Len); + BusData->Pin2Line (BusHandler, RootHandler, SlotNumber, PciData2); + + Len -= Offset; + if (Len > Length) { + Len = Length; + } + + RtlMoveMemory (iBuffer2+Offset, Buffer, Len); + + // in case interrupt line or pin was editted + BusData->Line2Pin (BusHandler, RootHandler, SlotNumber, PciData2, PciData); + +#if DBG + // + // Verify R/O fields haven't changed + // + if (PciData2->VendorID != PciData->VendorID || + PciData2->DeviceID != PciData->DeviceID || + PciData2->RevisionID != PciData->RevisionID || + PciData2->ProgIf != PciData->ProgIf || + PciData2->SubClass != PciData->SubClass || + PciData2->BaseClass != PciData->BaseClass || + PciData2->HeaderType != PciData->HeaderType || + PciData2->BaseClass != PciData->BaseClass || + PciData2->u.type0.MinimumGrant != PciData->u.type0.MinimumGrant || + PciData2->u.type0.MaximumLatency != PciData->u.type0.MaximumLatency) { + DbgPrint ("PCI SetBusData: Read-Only configuration value changed\n"); + DbgBreakPoint (); + } +#endif + // + // Set new PCI configuration + // + + BusData->WriteConfig (BusHandler, SlotNumber, iBuffer2+Offset, Offset, Len); + + Offset += Len; + Buffer += Len; + Length -= Len; + } + + if (Length) { + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The remaining Buffer comes from the Device Specific + // area - put on the kitten gloves and write it + // + // Specific read/writes to the PCI device specific area + // are guarenteed: + // + // Not to read/write any byte outside the area specified + // by the caller. (this may cause WORD or BYTE references + // to the area in order to read the non-dword aligned + // ends of the request) + // + // To use a WORD access if the requested length is exactly + // a WORD long. + // + // To use a BYTE access if the requested length is exactly + // a BYTE long. + // + + BusData->WriteConfig (BusHandler, SlotNumber, Buffer, Offset, Length); + Len += Length; + } + } + + return Len; +} + +ULONG +PcipSetDeviceData ( + IN struct _BUS_HANDLER *BusHandler, + IN struct _BUS_HANDLER *RootHandler, + IN PDEVICE_HANDLER_OBJECT DeviceHandler, + IN ULONG DataType, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ + ULONG Status; + PDEVICE_DATA DeviceData; + PCI_SLOT_NUMBER SlotNumber; + + Status = 0; + DeviceData = DeviceHandler2DeviceData (DeviceHandler); + + // + // Verify caller has a valid DeviceHandler object + // + + if (!DeviceData->Valid) { + + // + // Obsolete object, return no data + // + + return 0; + } + + // + // Get the device's data. + // + + if (DataType == 0) { + + // + // Type 0 is the same as SetBusData for the slot + // + + SlotNumber.u.AsULONG = DeviceHandler->SlotNumber; + Status = PcipGetBusData ( + BusHandler, + RootHandler, + SlotNumber, + Buffer, + Offset, + Length + ); + } + + return Status; +} + + + +NTSTATUS +PcipAssignSlotResources ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG SlotNumber, + IN OUT PCM_RESOURCE_LIST *AllocatedResources + ) +{ + CTL_ASSIGN_RESOURCES AssignResources; + KEVENT CompletionEvent; + ULONG BufferSize; + PDEVICE_HANDLER_OBJECT DeviceHandler; + NTSTATUS Status; + + PAGED_CODE (); + + // + // Foreward this request through a DeviceControl such that it + // gets the proper synchronzation on the device + // + + DeviceHandler = BusHandler->ReferenceDeviceHandler ( + BusHandler, + BusHandler, + SlotNumber + ); + + if (!DeviceHandler) { + return STATUS_NO_SUCH_DEVICE; + } + + AssignResources.RegistryPath = RegistryPath; + AssignResources.DriverClassName = DriverClassName; + AssignResources.DriverObject = DriverObject; + AssignResources.AllocatedResources = AllocatedResources; + BufferSize = sizeof (AssignResources); + + // + // Make synchrous DeviceControl request + // + + Status = HalDeviceControl ( + DeviceHandler, + DeviceObject, + BCTL_ASSIGN_SLOT_RESOURCES, + &AssignResources, + &BufferSize, + NULL, + NULL + ); + + // + // Free the reference to DeviceHandler + // + + ObDereferenceObject (DeviceHandler); + + // + // Done + // + + return Status; +} + + +NTSTATUS +PcipQueryBusSlots ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BufferSize, + OUT PULONG SlotNumbers, + OUT PULONG ReturnedLength + ) +{ + PSINGLE_LIST_ENTRY Link; + PPCI_PORT PciPort; + PDEVICE_DATA DeviceData; + ULONG cnt; + + PAGED_CODE (); + + PciPort = PCIPORTDATA (BusHandler); + + // + // Synchronize will new devices being added + // + + ExAcquireFastMutex (&PcipMutex); + + // + // Fill in returned buffer length, or what size buffer is needed + // + + + *ReturnedLength = PciPort->NoValidSlots * sizeof (ULONG); + if (BufferSize < *ReturnedLength) { + + // + // Callers buffer is not large enough + // + + ExReleaseFastMutex (&PcipMutex); + return STATUS_BUFFER_TOO_SMALL; + } + + // + // Return caller all the possible slot number + // + + cnt = 0; + for (Link = PciPort->ValidSlots.Next; Link; Link = Link->Next) { + DeviceData = CONTAINING_RECORD (Link, DEVICE_DATA, Next); + if (DeviceData->Valid) { + cnt += 1; + *(SlotNumbers++) = DeviceDataSlot(DeviceData); + } + } + + *ReturnedLength = cnt * sizeof (ULONG); + ExReleaseFastMutex (&PcipMutex); + return STATUS_SUCCESS; +} + + +NTSTATUS +PcipDeviceControl ( + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ) +{ + ULONG i; + ULONG ControlCode; + ULONG Junk; + PULONG BufferLength; + PLIST_ENTRY OldTail; + BOOLEAN UseWorker; + + for (i=0; PcipControl[i].ControlHandler; i++) { + if (PcipControl[i].ControlCode == Context->DeviceControl.ControlCode) { + + // + // Found DeviceControl handler + // + + Context->ContextControlHandler = (ULONG) (PcipControl + i); + + // + // Verify callers buffer is the min required length + // + + + if (*Context->DeviceControl.BufferLength < PcipControl[i].MinBuffer) { + Context->DeviceControl.Status = STATUS_BUFFER_TOO_SMALL; + *Context->DeviceControl.BufferLength = PcipControl[i].MinBuffer; + HalCompleteDeviceControl (Context); + return STATUS_BUFFER_TOO_SMALL; + } + + if (KeGetCurrentIrql() < DISPATCH_LEVEL || + (Context->DeviceControl.ControlCode == BCTL_SET_POWER && + *((PPOWER_STATE) Context->DeviceControl.Buffer) == PowerUp)){ + + // + // All slot controls, expect a power up request, may touch + // paged code or data. If the current irql is low enough or + // this is a power up go dispatch now; otherwise, queue the + // request to a worker thread. + // + + PcipDispatchControl (Context); + + } else { + + // + // Enqueue to worker thread + // + + ExInterlockedInsertTailList ( + &PcipControlWorkerList, + (PLIST_ENTRY) &Context->ContextWorkQueue, + &PcipSpinlock + ); + + // + // Make sure worker is requested + // + + PcipStartWorker (); + } + + + return STATUS_PENDING; + } + } + + // + // Unkown control code + // + + return STATUS_INVALID_PARAMETER; +} + +PDEVICE_HANDLER_OBJECT +PcipReferenceDeviceHandler ( + IN struct _BUS_HANDLER *BusHandler, + IN struct _BUS_HANDLER *RootHandler, + IN PCI_SLOT_NUMBER SlotNumber + ) +{ + PDEVICE_DATA DeviceData; + PDEVICE_HANDLER_OBJECT DeviceHandler; + PPCI_PORT PciPort; + NTSTATUS Status; + + PAGED_CODE (); + + ExAcquireFastMutex (&PcipMutex); + + PciPort = PCIPORTDATA(BusHandler); + DeviceData = PcipFindDeviceData (PciPort, SlotNumber); + DeviceHandler = NULL; + if (DeviceData) { + DeviceHandler = DeviceData2DeviceHandler (DeviceData); + Status = ObReferenceObjectByPointer( + DeviceHandler, + FILE_READ_DATA | FILE_WRITE_DATA, + *IoDeviceHandlerObjectType, + KernelMode + ); + + if (!NT_SUCCESS(Status)) { + DeviceHandler = NULL; + } + } + + ExReleaseFastMutex (&PcipMutex); + return DeviceHandler; +} + + + +NTSTATUS +PcipHibernateBus ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler + ) +{ + return STATUS_NOT_IMPLEMENTED; +} + + + + +NTSTATUS +PcipResumeBus ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler + ) +{ + return STATUS_NOT_IMPLEMENTED; +} + +VOID +PcipSuspendNotification ( + IN PVOID CallbackContext, + IN PVOID Argument1, + IN PVOID Argument2 + ) +{ + PAGED_CODE(); + + switch ((ULONG) Argument1) { + case 0: + // + // Lock code down which might be needed to perform a suspend + // + + ASSERT (PciCodeLock == NULL); + PciCodeLock = MmLockPagableCodeSection (&PcipHibernateBus); + break; + + case 1: + // + // Release the code lock + // + + MmUnlockPagableImageSection (PciCodeLock); + PciCodeLock = NULL; + break; + } +} diff --git a/private/ntos/nthals/extender/pci/sources b/private/ntos/nthals/extender/pci/sources new file mode 100644 index 000000000..4f5a2e927 --- /dev/null +++ b/private/ntos/nthals/extender/pci/sources @@ -0,0 +1,48 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=dd + +TARGETNAME=pciport +TARGETPATH=\nt\public\sdk\lib +TARGETTYPE=DRIVER + +INCLUDES=..\..\..\inc + +SOURCES=pciport.rc \ + pcidata.c \ + bus.c \ + control.c \ + devres.c \ + init.c \ + misc.c \ + port.c + + +MSC_WARNING_LEVEL=/W3 /WX + +NTTEST= +OPTIONAL_NTTEST= +UMTEST= -- cgit v1.2.3