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 + private/ntos/nthals/extender/pnpbios/i386/bus.c | 886 +++++++++++ .../ntos/nthals/extender/pnpbios/i386/busdata.c | 902 +++++++++++ private/ntos/nthals/extender/pnpbios/i386/busp.h | 499 ++++++ .../ntos/nthals/extender/pnpbios/i386/control.c | 725 +++++++++ private/ntos/nthals/extender/pnpbios/i386/data.c | 159 ++ private/ntos/nthals/extender/pnpbios/i386/init.c | 482 ++++++ private/ntos/nthals/extender/pnpbios/i386/misc.c | 471 ++++++ private/ntos/nthals/extender/pnpbios/i386/pbapi.h | 235 +++ .../ntos/nthals/extender/pnpbios/i386/pbcnvrt.c | 1562 +++++++++++++++++++ private/ntos/nthals/extender/pnpbios/i386/pbios.h | 241 +++ .../ntos/nthals/extender/pnpbios/i386/pbiosa.asm | 89 ++ private/ntos/nthals/extender/pnpbios/i386/pbiosc.c | 773 ++++++++++ .../ntos/nthals/extender/pnpbios/i386/resource.c | 367 +++++ private/ntos/nthals/extender/pnpbios/makefile | 6 + private/ntos/nthals/extender/pnpbios/pnpbios.rc | 11 + private/ntos/nthals/extender/pnpbios/sources | 49 + private/ntos/nthals/extender/pnpisa.sur/bus.c | 962 ++++++++++++ private/ntos/nthals/extender/pnpisa.sur/busp.h | 473 ++++++ private/ntos/nthals/extender/pnpisa.sur/convert.c | 1092 +++++++++++++ private/ntos/nthals/extender/pnpisa.sur/data.c | 58 + private/ntos/nthals/extender/pnpisa.sur/init.c | 620 ++++++++ private/ntos/nthals/extender/pnpisa.sur/isolate.c | 1607 ++++++++++++++++++++ private/ntos/nthals/extender/pnpisa.sur/makefile | 6 + private/ntos/nthals/extender/pnpisa.sur/misc.c | 1258 +++++++++++++++ private/ntos/nthals/extender/pnpisa.sur/pbios.h | 241 +++ private/ntos/nthals/extender/pnpisa.sur/pnpisa.h | 164 ++ private/ntos/nthals/extender/pnpisa.sur/pnpisa.rc | 11 + private/ntos/nthals/extender/pnpisa.sur/resource.c | 680 +++++++++ private/ntos/nthals/extender/pnpisa.sur/sources | 47 + private/ntos/nthals/extender/pnpisa/i386/bus.c | 1036 +++++++++++++ private/ntos/nthals/extender/pnpisa/i386/busp.h | 576 +++++++ private/ntos/nthals/extender/pnpisa/i386/control.c | 511 +++++++ private/ntos/nthals/extender/pnpisa/i386/convert.c | 1077 +++++++++++++ private/ntos/nthals/extender/pnpisa/i386/data.c | 156 ++ private/ntos/nthals/extender/pnpisa/i386/init.c | 506 ++++++ private/ntos/nthals/extender/pnpisa/i386/isolate.c | 1574 +++++++++++++++++++ private/ntos/nthals/extender/pnpisa/i386/misc.c | 626 ++++++++ private/ntos/nthals/extender/pnpisa/i386/pnpisa.h | 155 ++ .../ntos/nthals/extender/pnpisa/i386/resource.c | 555 +++++++ private/ntos/nthals/extender/pnpisa/makefile | 6 + private/ntos/nthals/extender/pnpisa/pnpisa.rc | 11 + private/ntos/nthals/extender/pnpisa/sources | 48 + 53 files changed, 26356 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 create mode 100644 private/ntos/nthals/extender/pnpbios/i386/bus.c create mode 100644 private/ntos/nthals/extender/pnpbios/i386/busdata.c create mode 100644 private/ntos/nthals/extender/pnpbios/i386/busp.h create mode 100644 private/ntos/nthals/extender/pnpbios/i386/control.c create mode 100644 private/ntos/nthals/extender/pnpbios/i386/data.c create mode 100644 private/ntos/nthals/extender/pnpbios/i386/init.c create mode 100644 private/ntos/nthals/extender/pnpbios/i386/misc.c create mode 100644 private/ntos/nthals/extender/pnpbios/i386/pbapi.h create mode 100644 private/ntos/nthals/extender/pnpbios/i386/pbcnvrt.c create mode 100644 private/ntos/nthals/extender/pnpbios/i386/pbios.h create mode 100644 private/ntos/nthals/extender/pnpbios/i386/pbiosa.asm create mode 100644 private/ntos/nthals/extender/pnpbios/i386/pbiosc.c create mode 100644 private/ntos/nthals/extender/pnpbios/i386/resource.c create mode 100644 private/ntos/nthals/extender/pnpbios/makefile create mode 100644 private/ntos/nthals/extender/pnpbios/pnpbios.rc create mode 100644 private/ntos/nthals/extender/pnpbios/sources create mode 100644 private/ntos/nthals/extender/pnpisa.sur/bus.c create mode 100644 private/ntos/nthals/extender/pnpisa.sur/busp.h create mode 100644 private/ntos/nthals/extender/pnpisa.sur/convert.c create mode 100644 private/ntos/nthals/extender/pnpisa.sur/data.c create mode 100644 private/ntos/nthals/extender/pnpisa.sur/init.c create mode 100644 private/ntos/nthals/extender/pnpisa.sur/isolate.c create mode 100644 private/ntos/nthals/extender/pnpisa.sur/makefile create mode 100644 private/ntos/nthals/extender/pnpisa.sur/misc.c create mode 100644 private/ntos/nthals/extender/pnpisa.sur/pbios.h create mode 100644 private/ntos/nthals/extender/pnpisa.sur/pnpisa.h create mode 100644 private/ntos/nthals/extender/pnpisa.sur/pnpisa.rc create mode 100644 private/ntos/nthals/extender/pnpisa.sur/resource.c create mode 100644 private/ntos/nthals/extender/pnpisa.sur/sources create mode 100644 private/ntos/nthals/extender/pnpisa/i386/bus.c create mode 100644 private/ntos/nthals/extender/pnpisa/i386/busp.h create mode 100644 private/ntos/nthals/extender/pnpisa/i386/control.c create mode 100644 private/ntos/nthals/extender/pnpisa/i386/convert.c create mode 100644 private/ntos/nthals/extender/pnpisa/i386/data.c create mode 100644 private/ntos/nthals/extender/pnpisa/i386/init.c create mode 100644 private/ntos/nthals/extender/pnpisa/i386/isolate.c create mode 100644 private/ntos/nthals/extender/pnpisa/i386/misc.c create mode 100644 private/ntos/nthals/extender/pnpisa/i386/pnpisa.h create mode 100644 private/ntos/nthals/extender/pnpisa/i386/resource.c create mode 100644 private/ntos/nthals/extender/pnpisa/makefile create mode 100644 private/ntos/nthals/extender/pnpisa/pnpisa.rc create mode 100644 private/ntos/nthals/extender/pnpisa/sources (limited to 'private/ntos/nthals/extender') 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= diff --git a/private/ntos/nthals/extender/pnpbios/i386/bus.c b/private/ntos/nthals/extender/pnpbios/i386/bus.c new file mode 100644 index 000000000..b002bf1cf --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/i386/bus.c @@ -0,0 +1,886 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + port.c + +Abstract: + + +Author: + + Shie-Lin Tzong (shielint) May-20-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "busp.h" + +VOID +MbpInvalidateSlots ( + IN PMB_BUS_EXTENSION BusExtension + ); + +VOID +MbpDeleteSlots ( + IN PMB_BUS_EXTENSION BusExtension + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,MbQueryBusSlots) +#pragma alloc_text(PAGE,MbpCheckBus) +#pragma alloc_text(PAGE,MbpReferenceDeviceHandler) +#endif + + +ULONG +MbGetBusData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG SlotNumber, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) + +/*++ + +Routine Description: + + The function returns the Pnp Bios data for a device. + +Arguments: + + BusHandler - supplies a pointer to the handler of the bus. + + RootHandler - supplies a pointer to a BUS_HANDLER for the originating + request. + + Buffer - Supplies the space to store the data. + + Offset - Supplies the offset to the device data to start reading. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ + +{ + return 0; +} + +ULONG +MbSetBusData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG SlotNumber, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) + +/*++ + +Routine Description: + + The function sets the Pnp Bios data for a device. + +Arguments: + + BusHandler - supplies a pointer to the handler of the bus. + + RootHandler - supplies a pointer to a BUS_HANDLER for the originating + request. + + Buffer - Supplies the space to store the data. + + Offset - Supplies the offset to the device data to be set. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ + +{ + return 0; +} + +ULONG +MbGetDeviceData ( + 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 + ) +/*++ + +Routine Description: + + The function returns the Pnp Bios data for a device. + +Arguments: + + BusHandler - supplies a pointer to the handler of the bus. + + RootHandler - supplies a pointer to a BUS_HANDLER for the originating + request. + + DeviceHandler - supplies a pointer to a DEVICE_HANDLER_OBJECT + + DataType - Specifies the type of device data desired. + + Buffer - Supplies the space to store the data. + + Offset - Supplies the offset to the device data to start reading. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ +{ + ULONG dataLength; + PDEVICE_DATA deviceData; + + UNREFERENCED_PARAMETER ( DataType); + + dataLength = 0; + deviceData = DeviceHandler2DeviceData (DeviceHandler); + + // + // Verify caller has a valid DeviceHandler object + // + + if (!(deviceData->Flags & DEVICE_FLAGS_VALID)) { + + // + // Obsolete object, return no data + // + + return dataLength; + } + + // + // Get the device's data. + // + + // + // Synchronize with other pnp bios service functions. + // + + ExAcquireFastMutex(&MbpMutex); + + dataLength = deviceData->BusDataLength; + if (Offset < dataLength) { + dataLength -= Offset; + if (dataLength > Length) { + dataLength = Length; + } + RtlMoveMemory(Buffer, (PUCHAR)deviceData->BusData + Offset, dataLength); + } else { + dataLength = 0; + } + + ExReleaseFastMutex(&MbpMutex); + return dataLength; +} + +ULONG +MbSetDeviceData ( + 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 + ) +/*++ + +Routine Description: + + The function sets Pnp Bios data for a device. + +Arguments: + + BusHandler - supplies a pointer to the handler of the bus. + + RootHandler - supplies a pointer to a BUS_HANDLER for the originating + request. + + DeviceHandler - supplies a pointer to a DEVICE_HANDLER_OBJECT + + DataType - Specifies the type of device data desired. + + Buffer - Supplies the space to store the data. + + Offset - Supplies the offset to the device data to start reading. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data set. + +--*/ +{ + // + // We don't let drivers change Pnp device data. + // + + return 0; +} + +NTSTATUS +MbQueryBusSlots ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BufferSize, + OUT PULONG SlotNumbers, + OUT PULONG ReturnedLength + ) + +/*++ + +Routine Description: + + The function returns a list of currently available SlotNumber. + +Arguments: + + BusHandler - supplies a pointer to the handler of the bus. + + RootHandler - supplies a pointer to a BUS_HANDLER for the originating + request. + + Buffer - Supplies the space to store the data. + + SlotNumber - Supplies a variable to receives the number of available slots. + + Length - Supplies a count in bytes of the stored data. If this function + returns STATUS_BUFFER_TOO_SMALL, this variable supplies the required + size. + +Return Value: + + STATUS_BUFFER_TOO_SMALL if caller supplied buffer is not big enough. + +--*/ + +{ + PMB_BUS_EXTENSION busExtension; + PSINGLE_LIST_ENTRY link; + PDEVICE_DATA deviceData; + ULONG count = 0; + + PAGED_CODE (); + + busExtension = (PMB_BUS_EXTENSION)BusHandler->BusData; + + // + // Synchronize with other pnp bios device handle assignment. + // + + ExAcquireFastMutex(&MbpMutex); + + // + // Fill in returned buffer length, or what size buffer is needed + // + + + *ReturnedLength = busExtension->NoValidSlots * sizeof (ULONG); + if (BufferSize < *ReturnedLength) { + + // + // Callers buffer is not large enough + // + + ExReleaseFastMutex (&MbpMutex); + return STATUS_BUFFER_TOO_SMALL; + } + + // + // Return caller all the possible slot number + // + + for (link = busExtension->ValidSlots.Next; link; link = link->Next) { + deviceData = CONTAINING_RECORD (link, DEVICE_DATA, Next); + if (deviceData->Flags & DEVICE_FLAGS_VALID) { + *SlotNumbers = DeviceDataSlot(deviceData); + SlotNumbers++; + count += 1; + } + } + + *ReturnedLength = count * sizeof (ULONG); + ExReleaseFastMutex (&MbpMutex); + return STATUS_SUCCESS; +} + +NTSTATUS +MbDeviceControl ( + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ) + +/*++ + +Routine Description: + + The function is the bus handler specific verion of HalDeviceControl. + +Arguments: + + Context - The DeviceControl context. The context has all the information + for the HalDeviceControl operation being performed. + +Return Value: + + A NTSTATUS code to indicate the result of the operation. + +--*/ +{ + ULONG i, junk; + ULONG controlCode; + PULONG bufferLength; + NTSTATUS status = STATUS_INVALID_PARAMETER; + + for (i = 0; i < NUMBER_DEVICE_CONTROL_FUNCTIONS; i++) { + + if (MbpDeviceControl[i].ControlCode == Context->DeviceControl.ControlCode) { + if (MbpDeviceControl[i].ControlHandler == NULL) { + Context->DeviceControl.Status = STATUS_NOT_IMPLEMENTED; + status = STATUS_NOT_IMPLEMENTED; + goto deviceControlDone; + } + + // + // Found DeviceControl handler + // + + Context->ContextControlHandler = (ULONG)(MbpDeviceControl + i); + + // + // Verify callers buffer is the min required length + // + + if (*Context->DeviceControl.BufferLength < MbpDeviceControl[i].MinBuffer) { + Context->DeviceControl.Status = STATUS_BUFFER_TOO_SMALL; + *Context->DeviceControl.BufferLength = MbpDeviceControl[i].MinBuffer; + status = STATUS_BUFFER_TOO_SMALL; + goto deviceControlDone; + } + + if (KeGetCurrentIrql() < DISPATCH_LEVEL) { + + // + // All supported slot control functions touch paged code or data. + // If the current irql is low enough go dispatch now; otherwise, + // queue the request to a worker thread. + // + + MbpDispatchControl (Context); + + } else { + + // + // Enqueue to worker thread + // + + ExInterlockedInsertTailList ( + &MbpControlWorkerList, + (PLIST_ENTRY) &Context->ContextWorkQueue, + &MbpSpinlock + ); + + // + // Make sure worker is requested + // + + MbpStartWorker (); + } + return STATUS_PENDING; + } + } + +deviceControlDone: + HalCompleteDeviceControl (Context); + return status; +} + +VOID +MbpCheckBus ( + IN PBUS_HANDLER BusHandler + ) + +/*++ + +Routine Description: + + The function reenumerates the bus specified by BusHandler. + +Arguments: + + BusHandler - supplies a pointer to the BusHandler of the bus to be enumerated. + +Return Value: + + None. + +--*/ +{ + ULONG slotNumber, nextSlotNumber; + BOOLEAN dockConnector; + PDEVICE_DATA deviceData; + PPNP_BIOS_DEVICE_NODE busData; + PMB_BUS_EXTENSION busExtension; + ULONG length, noSlots; + NTSTATUS status; + PHAL_SYSTEM_DOCK_INFORMATION dockInfo; + PDEVICE_HANDLER_OBJECT deviceHandler; + ULONG objectSize; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE handle; + BOOLEAN notifyBusCheck; + + PAGED_CODE(); + + busExtension = (PMB_BUS_EXTENSION)BusHandler->BusData; + notifyBusCheck = FALSE; + + // + // We may be removing references to this bus handler, so add + // a reference now + // + + HalReferenceBusHandler (BusHandler); + + // + // Acquire fast mutex to access device data + // + + ExAcquireFastMutex (&MbpMutex); + MbpInvalidateSlots(busExtension); + + // + // Check the bus for new devices + // + + nextSlotNumber = 0; + while (nextSlotNumber != (ULONG) -1) { + slotNumber = nextSlotNumber; + status = MbpGetBusData(BusHandler->BusNumber, + &nextSlotNumber, + &busData, + &length, + &dockConnector); + if (NT_SUCCESS(status)) { + deviceData = MbpFindDeviceData (busExtension, slotNumber); + if (deviceData == NULL || + length != deviceData->BusDataLength || + RtlCompareMemory(busData, deviceData->BusData, length) != length) { + + notifyBusCheck = TRUE; + + // + // if Not found - this is a newly added device or + // if devicedata exists already, make sure its busdata is not changed. + // Otherwise, we assign a new handler to this slot. This invalidate + // the access to the old bus data. + // + + // + // Initialize the object attributes that will be used to create the + // Device Handler Object. + // + + InitializeObjectAttributes( + &objectAttributes, + NULL, + 0, + NULL, + NULL + ); + + objectSize = MbpDeviceHandlerObjectSize + 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; + if (dockConnector) { + deviceHandler->SlotNumber = DOCK_VIRTUAL_SLOT_NUMBER; + } else { + deviceHandler->SlotNumber = slotNumber; + } + + // + // 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. Skip this slot. + // + + continue; + } + + ZwClose (handle); + + // + // Intialize device tracking structure + // + + deviceHandler->BusHandler = BusHandler; + HalReferenceBusHandler(BusHandler); + + deviceData = DeviceHandler2DeviceData(deviceHandler); + deviceData->BusData = busData; + deviceData->BusDataLength = length; + deviceData->Flags |= DEVICE_FLAGS_VALID; + + DebugPrint ((DEBUG_MESSAGE, "PnpBios: adding slot %x\n", DeviceDataSlot(deviceData))); + + // + // Add it to the list of devices for this bus + // + + busExtension->NoValidSlots += 1; + ExInterlockedPushEntryList ( + &busExtension->ValidSlots, + &deviceData->Next, + &MbpSpinlock + ); + } else { + ExFreePool(busData); + deviceData->Flags |= DEVICE_FLAGS_VALID; + } + + // + // If this is the docking station slot, remember it. + // + + if (dockConnector) { + busExtension->DockingStationDevice = deviceData; + deviceData->Flags |= DEVICE_FLAGS_DOCKING_STATION; + } + } + } + + // + // Go through the slot data link list to delete all the removed slots. + // + + noSlots = busExtension->NoValidSlots; + MbpDeleteSlots(busExtension); + if (noSlots != busExtension->NoValidSlots) { + notifyBusCheck = TRUE; + } + ExReleaseFastMutex (&MbpMutex); + + // + // If this is top level pnp bios bus we will determine docking station information + // and all Hal to set dock information. + // + + if (BusHandler->BusNumber == MbpBusNumber[0] && + NT_SUCCESS(MbpGetDockInformation(&dockInfo, &length)) ) { + HalSetSystemInformation(HalSystemDockInformation, length, dockInfo); + ExFreePool(dockInfo); + } + + // + // Undo reference to bus handler from top of function + // + + HalDereferenceBusHandler (BusHandler); + + // + // Do we need to notify the system buscheck callback? + // + + if (notifyBusCheck) { + HAL_BUS_INFORMATION busInfo; + + busInfo.BusType = BusHandler->InterfaceType; + busInfo.ConfigurationType = BusHandler->ConfigurationType; + busInfo.BusNumber = BusHandler->BusNumber; + busInfo.Reserved = 0; + ExNotifyCallback ( + MbpHalCallbacks.BusCheck, + &busInfo, + (PVOID)BusHandler->BusNumber + ); + } +} + +PDEVICE_HANDLER_OBJECT +MbpReferenceDeviceHandler ( + IN struct _BUS_HANDLER *BusHandler, + IN struct _BUS_HANDLER *RootHandler, + IN ULONG SlotNumber + ) +/*++ + +Routine Description: + + The function returns a reference to the devce handler specified by SlotNumber + and BusHandler. + +Arguments: + + BusHandler - + + RootHanler - + + SlotNumber - + +Return Value: + + a reference to DEVICE_HANDLER_OBJECT. + +--*/ +{ + PDEVICE_DATA deviceData; + PDEVICE_HANDLER_OBJECT deviceHandler; + PMB_BUS_EXTENSION busExtension; + NTSTATUS status; + + PAGED_CODE (); + + ExAcquireFastMutex (&MbpMutex); + + busExtension = (PMB_BUS_EXTENSION)BusHandler->BusData; + deviceData = MbpFindDeviceData (busExtension, 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 (&MbpMutex); + return deviceHandler; +} + +PDEVICE_DATA +MbpFindDeviceData ( + IN PMB_BUS_EXTENSION BusExtension, + IN ULONG SlotNumber + ) +/*++ + +Routine Description: + + The function goes through device data list to find the desired SlotNumber's + device data. The caller must hold the MbpMutex to call this routine. + +Arguments: + + BusExtension - supplies a pointer to current bus'es extension. + + SlotNumber - specified the desired device data. -1 means docking station device data. + +Return Value: + + A pointer to the DEVICE_DATA if found. Otherwise a value of NULL is returned. + +--*/ +{ + PDEVICE_DATA deviceData; + PSINGLE_LIST_ENTRY link; + PDEVICE_HANDLER_OBJECT deviceHandler; + + // + // Go through the slot data link list to find a match. + // + + if (SlotNumber == DOCK_VIRTUAL_SLOT_NUMBER) { + return BusExtension->DockingStationDevice; + } else { + for (link = BusExtension->ValidSlots.Next; link; link = link->Next) { + deviceData = CONTAINING_RECORD (link, DEVICE_DATA, Next); + if (DeviceDataSlot(deviceData) == SlotNumber) { + break; + } + } + } + + if (!link) { + return NULL; + } else { + return deviceData; + } +} + +VOID +MbpInvalidateSlots ( + IN PMB_BUS_EXTENSION BusExtension + ) +/*++ + +Routine Description: + + The function goes through device data list and marks all the devices as invalid. + The caller must acquire MbpMutex to call this routine. + +Arguments: + + BusExtension - supplies a pointer to the extension data of desired bus. + +Return Value: + + None. + +--*/ +{ + PDEVICE_DATA deviceData; + PSINGLE_LIST_ENTRY link; + + // + // Go through the slot data link list to mark ALL the slots as + // in transition state. + // + + for (link = BusExtension->ValidSlots.Next; link; link = link->Next) { + deviceData = CONTAINING_RECORD (link, DEVICE_DATA, Next); + deviceData->Flags &= ~DEVICE_FLAGS_VALID; + } + + // + // Invalidate the docking station slot pointer + // + + BusExtension->DockingStationDevice = NULL; + BusExtension->DockingStationId = UNKNOWN_DOCKING_IDENTIFIER; + BusExtension->DockingStationSerialNumber = 0; +} + +VOID +MbpDeleteSlots ( + IN PMB_BUS_EXTENSION BusExtension + ) +/*++ + +Routine Description: + + The function goes through device data list and deletes all the invalid + slots/devices. + Note the MbpMutex must be acquired before calling this routine. + +Arguments: + + BusExtension - supplies a pointer to the extension data of desired bus. + +Return Value: + + None. + +--*/ +{ + PDEVICE_DATA deviceData; + PDEVICE_HANDLER_OBJECT deviceHandler; + PSINGLE_LIST_ENTRY *link; + + // + // Go through the slot data link list to free all the slot + // marked as invalid. + // + + link = &BusExtension->ValidSlots.Next; + while (*link) { + deviceData = CONTAINING_RECORD (*link, DEVICE_DATA, Next); + if (!(deviceData->Flags & DEVICE_FLAGS_VALID)) { + DebugPrint((DEBUG_MESSAGE, "Remove slot %x\n", DeviceDataSlot(deviceData))); + + // + // In theory I should deallocate the BusData only when the ref count of the + // deviceData down to zero and deallocated. Here I am safe to do so because + // the DeviceDispatchContol routine checks the DeviceData flag is valid before + // reference the BusData. + // + + if (deviceData->BusData) { + ExFreePool(deviceData->BusData); + } + *link = (*link)->Next; + deviceHandler = DeviceData2DeviceHandler(deviceData); + ObDereferenceObject (deviceHandler); + HalDereferenceBusHandler (BusExtension->BusHandler); + BusExtension->NoValidSlots--; + } else { + link = &((*link)->Next); + } + } +} + + diff --git a/private/ntos/nthals/extender/pnpbios/i386/busdata.c b/private/ntos/nthals/extender/pnpbios/i386/busdata.c new file mode 100644 index 000000000..58dded523 --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/i386/busdata.c @@ -0,0 +1,902 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + busdata.c + +Abstract: + + This module contains code to query/set pnp bios slot data. + +Author: + + Shie-Lin Tzong (shielint) Apr-25-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "busp.h" + +PUCHAR +MbpFindNextPnpEndTag ( + IN PUCHAR BusData, + IN LONG Limit + ); + +#pragma alloc_text(PAGE,MbpGetBusData) +#pragma alloc_text(PAGE,MbpGetCompatibleDeviceId) +#pragma alloc_text(PAGE,MbpGetSlotResources) +#pragma alloc_text(PAGE,MbpGetSlotResourceRequirements) +#pragma alloc_text(PAGE,MbpSetSlotResources) +#pragma alloc_text(PAGE,MbpFindNextPnpEndTag) + +NTSTATUS +MbpGetBusData ( + ULONG BusNumber, + PULONG SlotNumber, + PVOID *BusData, + PULONG Length, + PBOOLEAN DockingSlot + ) +/*++ + +Routine Description: + + This function returns the pnp bios bus data to the caller. + Caller is responsible to release the data buffer. No mater what the returned + status is, this routine always returns a valid next slot number. + +Arguments: + + BusNumber - specifies the desired bus. + + SlotNumber - specifies a variable to indicate the slot whoes data is desired and + to receive the next slot number (-1 if no more slot.) + + BusData - supplies a variable to receive the data buffer pointer. + + Length - supplies a variable to receive the length of the data buffer + + DockingSlot - supplies a variable to receive if the slot is a docking station slot. + +Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status; + PPNP_BIOS_DEVICE_NODE busData; + PUCHAR p, source; + ULONG size, bufferSize, nextSlot = 0; + USHORT junk; + PB_PARAMETERS biosParameters; + + PAGED_CODE(); + + // + // If registry data is availble, we will get it from registry data. + // Note, the registry data is available at init time only. + // + + source = NULL; + *DockingSlot = FALSE; + if (PbBiosRegistryData) { + + // + // First skip Pnp Bios installation check data + // + + p = (PUCHAR)(PbBiosRegistryData + 1); + size = ((PKEY_VALUE_FULL_INFORMATION)PbBiosKeyInformation)->DataLength; + size -= sizeof(PNP_BIOS_INSTALLATION_CHECK) + sizeof(CM_PARTIAL_RESOURCE_LIST); + while (size >= sizeof(PNP_BIOS_DEVICE_NODE)) { + if (*SlotNumber == ((PPNP_BIOS_DEVICE_NODE)p)->Node) { + + // + // Find the desired slot data, determine next slot and + // do some more checks. + // + + bufferSize = ((PPNP_BIOS_DEVICE_NODE)p)->Size; + size -= bufferSize; + if (size >= sizeof(PNP_BIOS_DEVICE_NODE)) { + nextSlot = ((PPNP_BIOS_DEVICE_NODE)(p + bufferSize))->Node; + } else { + nextSlot = (ULONG) -1; + } + + if (((PPNP_BIOS_DEVICE_NODE)p)->DeviceType[0] == BASE_TYPE_DOCKING_STATION) { + if (BusNumber == MbpBusNumber[0]) { + + // + // If this is a docking station slot and the target BusNumber is the first bus, + // return the data and indicate this is a docking station slot. + // + + *DockingSlot = TRUE; + source = p; + } + break; + } + + // + // If this is a device in the deocking station, it can only belong to BusNumber 1 + // If this is a device in the system board, it can only belong to BusNumber 0 + // + + if (((PPNP_BIOS_DEVICE_NODE)p)->DeviceAttributes & DEVICE_DOCKING) { + if (BusNumber == MbpBusNumber[1]) { + source = p; + } + } else if (BusNumber == MbpBusNumber[0]) { + source = p; + } + break; + } + size -= ((PPNP_BIOS_DEVICE_NODE)p)->Size; + p = p + ((PPNP_BIOS_DEVICE_NODE)p)->Size; + } + + if (!source) { + if (*SlotNumber == 0) { + p = (PUCHAR)(PbBiosRegistryData + 1); + *SlotNumber = ((PPNP_BIOS_DEVICE_NODE)p)->Node; + } else { + *SlotNumber = nextSlot; + } + return STATUS_NO_SUCH_DEVICE; + } + } else { + + // + // Registry data is not available. Call pnp bios or hardware to + // get the max buffer size if necessary. + // + + if (MbpMaxDeviceData == 0) { + biosParameters.Function = PNP_BIOS_GET_NUMBER_DEVICE_NODES; + biosParameters.u.GetNumberDeviceNodes.NumberNodes = &junk; + biosParameters.u.GetNumberDeviceNodes.NodeSize = (PUSHORT)&MbpMaxDeviceData; + status = PbHardwareService(&biosParameters); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_BREAK, "GetBusData: calling BIOS GET_NUMBER_NODES failed.\n")); + *SlotNumber = 0; + return STATUS_NO_SUCH_DEVICE; + } else { + bufferSize = MbpMaxDeviceData; + } + } + } + + // + // Allocate space to return the slot data + // + + busData = (PPNP_BIOS_DEVICE_NODE) ExAllocatePoolWithTag ( + PagedPool, bufferSize, 'bPnP'); + + if (busData == NULL) { + + // + // Leave Slot unchanged, so it wil be the next slot number to try. This gives + // us another chance to retry the operation. + // + + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // If the data is available already copy it to data buffer and return. + // + + if (source) { + RtlMoveMemory(busData, source, bufferSize); + *SlotNumber = nextSlot; + *BusData = busData; + *Length = busData->Size; + } else { + + // + // Else we need to resort to Pnp Bios runtime API or hardware ... + // + + nextSlot = *SlotNumber; + biosParameters.Function = PNP_BIOS_GET_DEVICE_NODE; + biosParameters.u.GetDeviceNode.NodeBuffer = busData; + biosParameters.u.GetDeviceNode.Node = (PUSHORT)&nextSlot; + biosParameters.u.GetDeviceNode.Control = GET_CURRENT_CONFIGURATION; + status = PbHardwareService(&biosParameters); + if (!NT_SUCCESS(status)) { + *SlotNumber = 0; + ExFreePool(busData); + return STATUS_NO_SUCH_DEVICE; + } + + if (nextSlot == 0xFF) { + nextSlot = (ULONG) -1; + } + + // + // Make sure the slot matches the bus number. + // + + if (*SlotNumber != (ULONG)busData->Node) { + + // + // This happens when *SlotNumber == 0. In this case, bios + // gives us the first valid slot data. + // + + *SlotNumber = (ULONG)busData->Node; + return STATUS_NO_SUCH_DEVICE; + } else { + *SlotNumber = nextSlot; + } + if ((busData->DeviceType[0] == BASE_TYPE_DOCKING_STATION && BusNumber != MbpBusNumber[0]) || + (busData->DeviceAttributes & DEVICE_DOCKING && BusNumber == MbpBusNumber[0]) || + (!(busData->DeviceAttributes & DEVICE_DOCKING) && BusNumber == MbpBusNumber[1]) ) { + ExFreePool(busData); + return STATUS_NO_SUCH_DEVICE; + } else { + *BusData = busData; + *Length = busData->Size; + } + } + return STATUS_SUCCESS; +} + +NTSTATUS +MbpGetCompatibleDeviceId ( + PVOID BusData, + ULONG IdIndex, + PWCHAR Buffer + ) +/*++ + +Routine Description: + + This function returns the desired pnp bios id for the specified Busdata + and Id index. If Id index = 0, the Hardware ID will be return; if id + index = n, the Nth compatible id will be returned. + +Arguments: + + BusData - supplies a pointer to the pnp bios slot/device data. + + IdIndex - supplies the index of the compatible id desired. + + Buffer - supplies a pointer to a buffer to the compatible Id. Caller must + make sure the buffer is big enough. + +Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PPNP_BIOS_DEVICE_NODE slotData; + PUCHAR p, end; + UCHAR tag; + ULONG count = 0; + LONG size; + UNICODE_STRING unicodeString; + ANSI_STRING ansiString; + UCHAR eisaId[8]; + ULONG id; + + PAGED_CODE(); + + slotData = (PPNP_BIOS_DEVICE_NODE)BusData; + if (IdIndex == 0) { + + // + // Caller is asking for hardware id + // + + id = slotData->ProductId; + } else { + + // + // caller is asking for compatible id + // + + IdIndex--; + p = (PUCHAR)(slotData + 1); + size = slotData->Size - sizeof(PNP_BIOS_DEVICE_NODE); + end = p + size; + + // + // Skip all the resource descriptors to find compatible Id descriptor + // + + p = MbpFindNextPnpEndTag(p, size); // skip allocated resources + if (!p) { + return STATUS_NO_MORE_ENTRIES; + } + p += 2; + p = MbpFindNextPnpEndTag(p, (LONG)(end - p)); // skip possible resources + if (!p) { + return STATUS_NO_MORE_ENTRIES; + } + p += 2; + status = STATUS_NO_MORE_ENTRIES; + while ((tag = *p) != TAG_COMPLETE_END) { + ASSERT (tag == TAG_COMPLETE_COMPATIBLE_ID); + if (count == IdIndex) { + id = *(PULONG)(p + 1); + status = STATUS_SUCCESS; + break; + } else { + count++; + } + + // + // Advance to next compatible id. + // + + p += (TAG_COMPLETE_COMPATIBLE_ID & SMALL_TAG_SIZE_MASK) + 1; + } + } + + if (NT_SUCCESS(status)) { + PbDecompressEisaId(id, eisaId); + RtlInitAnsiString(&ansiString, eisaId); + RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); + swprintf(Buffer, L"BIOS\\*%s", unicodeString.Buffer); + RtlFreeUnicodeString(&unicodeString); + } + return status; +} + +NTSTATUS +MbpGetSlotResources ( + IN ULONG BusNumber, + IN PVOID BusData, + IN OUT PCM_RESOURCE_LIST *CmResources, + OUT PULONG Length + ) +/*++ + +Routine Description: + + This function returns the desired pnp bios slot/device resource in CM + format. Caller is responsible to free the resource buffer. + +Arguments: + + BusData - supplies a pointer to the pnp bios slot/device data. + + CmResources - supplies a variable to receive the returned resource list. + + Length - supplies a variable to receive the length of the data buffer + +Return Value: + + NTSTATUS code + +--*/ +{ + PPNP_BIOS_DEVICE_NODE slotData; + PUCHAR p; + NTSTATUS status; + + PAGED_CODE(); + + slotData = (PPNP_BIOS_DEVICE_NODE)BusData; + p = (PUCHAR)(slotData + 1); + status = PbBiosResourcesToNtResources ( + BusNumber, + slotData->Node, + &p, + PB_CM_FORMAT, + (PUCHAR *) CmResources, + Length + ); + return status; +} + +NTSTATUS +MbpGetSlotResourceRequirements ( + ULONG BusNumber, + PVOID BusData, + PIO_RESOURCE_REQUIREMENTS_LIST *IoResources, + PULONG Length + ) +/*++ + +Routine Description: + + This function returns the desired pnp bios slot/device resource in IO + format. Caller is responsible to free the resource buffer. + +Arguments: + + BusData - supplies a pointer to the pnp bios slot/device data. + + IoResources - supplies a variable to receive the returned resource requirements list. + + Length - supplies a variable to receive the length of the data buffer + +Return Value: + + NTSTATUS code + +--*/ +{ + PPNP_BIOS_DEVICE_NODE slotData; + PUCHAR p; + LONG size; + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + *IoResources = NULL; + *Length = 0; + + slotData = (PPNP_BIOS_DEVICE_NODE)BusData; + p = (PUCHAR)(slotData + 1); + size = slotData->Size - sizeof(PNP_BIOS_DEVICE_NODE); + + // + // Skip allocated resource descriptors + // + + p = MbpFindNextPnpEndTag(p, size); // skip allocated resources + if (p) { + p += 2; + status = PbBiosResourcesToNtResources ( + BusNumber, + slotData->Node, + &p, + PB_IO_FORMAT, + (PUCHAR *)IoResources, + Length + ); + } + return status; +} + +NTSTATUS +MbpSetSlotResources ( + PVOID *BusData, + PCM_RESOURCE_LIST CmResources, + ULONG Length + ) +/*++ + +Routine Description: + + This function sets the caller specified resource to pnp bios slot/device + data. + +Arguments: + + BusData - supplies a pointer to the pnp bios slot/device data. + + CmResources - supplies a variable to receive the returned resource list. + + Length - supplies the length of the resource data + +Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status; + PPNP_BIOS_DEVICE_NODE slotData; + PUCHAR p, pEnd, src, requirements; + PUCHAR biosResources; + ULONG biosResourceSize, totalSize; + LONG size; + PB_PARAMETERS biosParameters; + + PAGED_CODE(); + + slotData = (PPNP_BIOS_DEVICE_NODE)(*BusData); + p = (PUCHAR)(slotData + 1); + size = slotData->Size - sizeof(PNP_BIOS_DEVICE_NODE); + pEnd = p + size; + + // + // Skip allocated resource descriptors to find requirements list + // + + p = MbpFindNextPnpEndTag(p, size); // skip allocated resources + if (!p) { + DebugPrint((DEBUG_BREAK, "SetResource:Could not find allocated resource END tag\n")); + return STATUS_UNSUCCESSFUL; + } + p += 2; + requirements = p; + size = (ULONG)pEnd - (ULONG)p; + + status = PbCmResourcesToBiosResources ( + CmResources, + requirements, + &biosResources, + &biosResourceSize + ); + if (NT_SUCCESS(status)) { + p = ExAllocatePoolWithTag( + PagedPool, + size + sizeof(PNP_BIOS_DEVICE_NODE) + biosResourceSize, + 'bPnP'); + if (!p) { + status = STATUS_INSUFFICIENT_RESOURCES; + } else { + RtlMoveMemory(p, slotData, sizeof(PNP_BIOS_DEVICE_NODE)); + slotData = (PPNP_BIOS_DEVICE_NODE)p; + p += sizeof(PNP_BIOS_DEVICE_NODE); + RtlMoveMemory(p, biosResources, biosResourceSize); + p += biosResourceSize; + RtlMoveMemory(p, requirements, size); + totalSize = size + sizeof(PNP_BIOS_DEVICE_NODE) + biosResourceSize; + slotData->Size = (USHORT)totalSize; + + // + // call Pnp Bios to set the resources + // + + biosParameters.Function = PNP_BIOS_SET_DEVICE_NODE; + biosParameters.u.SetDeviceNode.Node = slotData->Node; + biosParameters.u.SetDeviceNode.NodeBuffer = slotData; + biosParameters.u.SetDeviceNode.Control = SET_CONFIGURATION_NOW; + status = PbHardwareService (&biosParameters); + if (NT_SUCCESS(status)) { + + // + // Update slotdat pointer + // + + ExFreePool(*BusData); + *BusData = slotData; + } else { + ExFreePool(slotData); + } + } + } + return status; +} + +NTSTATUS +MbpGetDockInformation ( + OUT PHAL_SYSTEM_DOCK_INFORMATION *DockInfo, + PULONG Length + ) +/*++ + +Routine Description: + + This function returns the docking station Id and serial number. + Caller must free the Buffer. + +Arguments: + + DockInfo - supplies a pointer to a variable to receive the dock information. + + Length - supplies a pointer to a variable to receive the length of the information. + +Return Value: + + NTSTATUS code + +--*/ +{ + PB_DOCKING_STATION_INFORMATION biosDockInfo; + PB_PARAMETERS biosParameters; + NTSTATUS status; + PUNICODE_STRING unicodeString; + ANSI_STRING ansiString; + UCHAR eisaId[8]; + PHAL_SYSTEM_DOCK_INFORMATION dock; + ULONG dockIdLength = 0, serialLength = 0; + USHORT dockState; + + PAGED_CODE(); + + // + // Invoke pnp bios to get docking station information + // + + biosParameters.Function = PNP_BIOS_GET_DOCK_INFORMATION; + biosParameters.u.GetDockInfo.DockingStationInfo = &biosDockInfo; + biosParameters.u.GetDockInfo.DockState = &dockState; + status = PbHardwareService(&biosParameters); + if (!NT_SUCCESS(status)) { + return STATUS_UNSUCCESSFUL; + } + + // + // Allocate memory to return dock information + // + + dock = (PHAL_SYSTEM_DOCK_INFORMATION)ExAllocatePool ( + PagedPool, + sizeof(HAL_SYSTEM_DOCK_INFORMATION)); + if (dock == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (dockState == SYSTEM_NOT_DOCKED) { + + // + // System is not docked, simply return the dock state. + // + + dock->DockState = SystemUndocked; + } else { + + // + // else system is docked, remember its dock id and serial number. + // + + dock->DockState = SystemDocked; +#if 1 + MbpBusExtension[0]->DockingStationId = biosDockInfo.LocationId; + MbpBusExtension[0]->DockingStationSerialNumber = biosDockInfo.SerialNumber; + ExAcquireFastMutex (&MbpMutex); + if (biosDockInfo.Capabilities && DOCKING_CAPABILITIES_MASK != DOCKING_CAPABILITIES_COLD_DOCKING) { + MbpBusExtension[0]->DockingStationDevice->Flags |= DEVICE_FLAGS_EJECT_SUPPORTED; + } + ExReleaseFastMutex (&MbpMutex); +#else + if (biosDockInfo.LocationId != UNKNOWN_DOCKING_IDENTIFIER) { + + // + // If docking station location Id is present... + // + + unicodeString = &MbpBusExtension[0]->DockingStationId; + PbDecompressEisaId(biosDockInfo.LocationId, eisaId); + RtlInitAnsiString(&ansiString, eisaId); + dockIdLength = sizeof(WCHAR) * (ansiString.Length + 1); + unicodeString->Buffer = (PWCHAR)ExAllocatePool ( + PagedPool, + dockIdLength); + if (unicodeString->Buffer == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + unicodeString->MaximumLength = (USHORT)dockIdLength; + RtlAnsiStringToUnicodeString(unicodeString, &ansiString, FALSE); + } +// if (biosDockInfo.SerialNumber != 0) { + + // + // If docking station serial number is present ... + // + + serialLength = sizeof(ULONG) * 2 * sizeof(WCHAR) + sizeof(WCHAR); + unicodeString = &MbpBusExtension[0]->DockingStationSerialNo; + unicodeString->Buffer = (PWCHAR)ExAllocatePool ( + PagedPool, + serialLength); + if (unicodeString->Buffer == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + unicodeString->MaximumLength = (USHORT)serialLength; + unicodeString->Length = sizeof(ULONG) * 2 * sizeof(WCHAR); + swprintf(unicodeString->Buffer, L"%8x", biosDockInfo.SerialNumber); +// } +#endif + } + dock->DeviceBusType = Internal; + dock->DeviceBusNumber = MbpBusNumber[0]; + dock->SlotNumber = DOCK_VIRTUAL_SLOT_NUMBER; + *Length = sizeof(HAL_SYSTEM_DOCK_INFORMATION); + *DockInfo = dock; + return STATUS_SUCCESS; +} + +NTSTATUS +MbpReplyEjectEvent ( + ULONG SlotNumber, + BOOLEAN Eject + ) +/*++ + +Routine Description: + + This function sends message to pnp bios for event processing. + +Arguments: + + SlotNumber - specifies the slot whoes data is desired. + + Eject - indicates if EJECT operation should be performed. + +Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status; + PB_PARAMETERS biosParameters; + USHORT message; + + PAGED_CODE(); + + // + // Else we need to resort to Pnp Bios runtime API or hardware ... + // + + biosParameters.Function = PNP_BIOS_SEND_MESSAGE; + if (Eject) { + biosParameters.u.SendMessage.Message = OK_TO_CHANGE_CONFIG; + } else { + biosParameters.u.SendMessage.Message = ABORT_CONFIG_CHANGE; + } + + status = PbHardwareService(&biosParameters); + return status; +} + +PUCHAR +MbpFindNextPnpEndTag ( + IN PUCHAR BusData, + IN LONG Limit + ) +/*++ + +Routine Description: + + This function searches the Pnp BIOS device data for the frist END_TAG encountered. + +Arguments: + + BusData - supplies a pointer to the pnp bios resource descriptor. + + Limit - maximum length of the search. + +Return Value: + + The address of the END_TAG location. Null if not found. + +--*/ +{ + UCHAR tag; + USHORT size; + + tag = *BusData; + while (tag != TAG_COMPLETE_END && Limit > 0) { + + // + // Determine the size of the BIOS resource descriptor + // + + if (!(tag & LARGE_RESOURCE_TAG)) { + size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); + size += 1; // length of small tag + } else { + size = *(BusData + 1); + size += 3; // length of large tag + } + + BusData += size; + Limit -= size; + tag = *BusData; + } + if (tag == TAG_COMPLETE_END) { + return BusData; + } else { + return NULL; + } +} + +BOOLEAN +MbpConfigAboutToChange ( + VOID + ) +/*++ + +Routine Description: + + This function is invoked by low level component to signal a dock\undock event + is about to happen. + + This function is called at DPC level. + +Arguments: + + SlotNumber - supplies the docking connector slot number. + +Return Value: + + TRUE - allow the change to happen; FALSE - ignore it for now. + +--*/ +{ + PDEVICE_DATA deviceData; + HAL_BUS_INFORMATION busInfo; + PBUS_HANDLER busHandler; + + // + // Get docking station slot data + // + + deviceData = MbpFindDeviceData (MbpBusExtension[0], DOCK_VIRTUAL_SLOT_NUMBER); + if (deviceData) { + + // + // if docking station slot is present + // + + ASSERT (deviceData->Flags & DEVICE_FLAGS_DOCKING_STATION); + + // + // If it is presently docked, the change is about-to-undock. + // We need to notify Eject callback. + // + + DebugPrint((DEBUG_MESSAGE, "pnpbios: About to UNDOCK...\n")); + busHandler = MbpBusExtension[0]->BusHandler; + busInfo.BusType = busHandler->InterfaceType; + busInfo.ConfigurationType = busHandler->ConfigurationType; + busInfo.BusNumber = busHandler->BusNumber; + busInfo.Reserved = 0; + ExNotifyCallback ( + MbpEjectCallbackObject, + &busInfo, + (PVOID)busHandler->BusNumber + ); + } else { + + DebugPrint((DEBUG_MESSAGE, "pnpbios: About to DOCK...\n")); + + // + // Otherwise, it is about-to-dock. Simply let it happen. + // + + return TRUE; + } + return FALSE; +} + +VOID +MbpConfigChanged ( + VOID + ) +/*++ + +Routine Description: + + This function is invoked by low level component to signal a dock-changed, + a system-device-changed, or a config-change_failed event. We simply notify + bus check callbacks. + This function is called at DPC level. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PBUS_HANDLER busHandler; + ULONG i; + + // + // Notify buscheck for ALL the supported buses and queue check bus requests. + // + + for (i = 0; i <= 1; i++) { + busHandler = MbpBusExtension[i]->BusHandler; + if (busHandler) { + MbpQueueCheckBus(busHandler); + } + } +} + diff --git a/private/ntos/nthals/extender/pnpbios/i386/busp.h b/private/ntos/nthals/extender/pnpbios/i386/busp.h new file mode 100644 index 000000000..ca894ea05 --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/i386/busp.h @@ -0,0 +1,499 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + busp.h + +Abstract: + + Hardware independent header file for pnp bios bus extender. + +Author: + + Shie-Lin Tzong (shielint) Apr-21-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "pbapi.h" +#include "stdio.h" +#include "stdarg.h" + +// +// Structures +// + +// +// 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 virtual slot number for docking station. (We need to return docking +// station slot number before knowing the real slot number. ) +// + +#define DOCK_VIRTUAL_SLOT_NUMBER 0xFFFF + +// +// DEVICE_DATA Flags masks +// + +#define DEVICE_FLAGS_DOCKING_STATION 0x10000000 +#define DEVICE_FLAGS_VALID 0x00000001 +#define DEVICE_FLAGS_WARM_DOCKING 0x00000002 +#define DEVICE_FLAGS_COLD_DOCKING 0x00000004 +#define DEVICE_FLAGS_EJECT_SUPPORTED 0x00000008 + +typedef struct _DEVICE_DATA_ { + SINGLE_LIST_ENTRY Next; + ULONG Flags; + + // + // DeviceControl in progress flags + // + + BOOLEAN SyncBusy; + + // + // Pointer to bus specific data + // + + PVOID BusData; + + // + // Length of the bus data + // + + ULONG BusDataLength; + +} DEVICE_DATA, *PDEVICE_DATA; + +// +// Extension data for Bus extender +// + +typedef struct _MB_BUS_EXTENSION { + + // + // BusHandler points back to the BUS_HANDLER structure for this extension + // + + PBUS_HANDLER BusHandler; + + // + // Bus Check request list + // + + LIST_ENTRY CheckBus; + + // + // Device control request list + // + + LIST_ENTRY DeviceControl; + + // + // Slot Data link list + // + + SINGLE_LIST_ENTRY ValidSlots; + ULONG NoValidSlots; + + // + // Pointer to docking station device data. + // This is mainly for convenience. + // + + PDEVICE_DATA DockingStationDevice; + ULONG DockingStationId; + ULONG DockingStationSerialNumber; +} MB_BUS_EXTENSION, *PMB_BUS_EXTENSION; + +typedef struct { + BOOLEAN Control; +} *PBCTL_SET_CONTROL; + +// +// Pnp Bios bus extender device object extension +// + +typedef struct _MB_DEVICE_EXTENSION { + PBUS_HANDLER BusHandler; +} MB_DEVICE_EXTENSION, *PMB_DEVICE_EXTENSION; + +// +// Only support 2 buses: main bus and docking station bus. +// + +#define MAXIMUM_BUS_NUMBER 2 + +// +// SlotControl related internal definitions +// + +typedef BOOLEAN (FASTCALL * BEGIN_FUNCTION)(PDEVICE_DATA, PHAL_DEVICE_CONTROL_CONTEXT); +typedef VOID (* CONTROL_FUNCTION)(PDEVICE_DATA, PHAL_DEVICE_CONTROL_CONTEXT); + +typedef struct _DEVICE_CONTROL_HANDLER { + ULONG ControlCode; + ULONG MinBuffer; + BEGIN_FUNCTION BeginDeviceControl; + CONTROL_FUNCTION ControlHandler; +} DEVICE_CONTROL_HANDLER, *PDEVICE_CONTROL_HANDLER; + +#define NUMBER_DEVICE_CONTROL_FUNCTIONS 11 + +// +// misc. definitions +// + +#define BUS_0_SIGNATURE 0xabababab +#define MIN_DETECT_SIGNATURE_SIZE (FIELD_OFFSET(CM_RESOURCE_LIST, List) + \ + FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList)) + +// +// Globals +// + +extern FAST_MUTEX MbpMutex; +extern KSPIN_LOCK MbpSpinlock; +extern LIST_ENTRY MbpControlWorkerList; +extern LIST_ENTRY MbpCheckBusList; +extern ULONG MbpWorkerQueued; +extern WORK_QUEUE_ITEM MbpWorkItem; +extern ULONG MbpNextHandle; +extern DEVICE_CONTROL_HANDLER MbpDeviceControl[]; +extern PDRIVER_OBJECT MbpDriverObject; +extern HAL_CALLBACKS MbpHalCallbacks; +extern PCALLBACK_OBJECT MbpEjectCallbackObject; +extern BOOLEAN MbpNoBusyFlag; +extern ULONG MbpMaxDeviceData; +extern PMB_BUS_EXTENSION MbpBusExtension[]; +extern WCHAR rgzBIOSDeviceName[]; +extern ULONG MbpNextBusId; +extern ULONG MbpBusNumber[]; + +extern POBJECT_TYPE *IoDeviceHandlerObjectType; +extern PULONG IoDeviceHandlerObjectSize; +extern ULONG MbpDeviceHandlerObjectSize; + +#define DeviceHandler2DeviceData(a) ((PDEVICE_DATA) (((PUCHAR) a) + MbpDeviceHandlerObjectSize)) +#define DeviceData2DeviceHandler(a) ((PDEVICE_HANDLER_OBJECT) (((PUCHAR) a) - MbpDeviceHandlerObjectSize)) +#define DeviceDataSlot(a) (DeviceData2DeviceHandler(a)->SlotNumber) + +// +// Prototypes +// + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +NTSTATUS +MbAddBusDevices( + IN PUNICODE_STRING ServiceKeyName, + IN OUT PULONG InstanceNumber + ); + +NTSTATUS +MbCreateClose ( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +ULONG +MbGetBusData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG SlotNumber, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +ULONG +MbSetBusData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG SlotNumber, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +ULONG +MbGetDeviceData ( + 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 +MbSetDeviceData ( + 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 +MbQueryBusSlots ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BufferSize, + OUT PULONG SlotNumbers, + OUT PULONG ReturnedLength + ); + +NTSTATUS +MbDeviceControl ( + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +MbpCheckBus ( + IN PBUS_HANDLER BusHandler + ); + +PDEVICE_DATA +MbpFindDeviceData ( + IN PMB_BUS_EXTENSION BusExtension, + IN ULONG SlotNumber + ); + +VOID +MbpStartWorker ( + VOID + ); + +VOID +MbpControlWorker ( + IN PVOID WorkerContext + ); + +VOID +MbpQueueCheckBus ( + IN PBUS_HANDLER BusHandler + ); + +VOID +MbpDispatchControl ( + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +MbpCompleteDeviceControl ( + IN NTSTATUS Status, + IN PHAL_DEVICE_CONTROL_CONTEXT Context, + IN PDEVICE_DATA DeviceData + ); + +BOOLEAN +FASTCALL +MbBCtlNone ( + IN PDEVICE_DATA DeviceData, + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +BOOLEAN +FASTCALL +MbBCtlSync ( + IN PDEVICE_DATA DeviceData, + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +BOOLEAN +FASTCALL +MbBCtlEject ( + IN PDEVICE_DATA DeviceData, + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +BOOLEAN +FASTCALL +MbBCtlLock ( + IN PDEVICE_DATA DeviceData, + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +MbCtlQueryDeviceId ( + IN PDEVICE_DATA DeviceData, + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +MbCtlQueryDeviceResources ( + IN PDEVICE_DATA DeviceData, + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +MbCtlQueryDeviceResourceRequirements ( + IN PDEVICE_DATA DeviceData, + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +MbCtlSetDeviceResources ( + IN PDEVICE_DATA DeviceData, + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +MbCtlQueryDeviceUniqueId ( + IN PDEVICE_DATA DeviceData, + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +MbCtlQueryDeviceCapabilities ( + IN PDEVICE_DATA DeviceData, + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +MbCtlQueryEject ( + IN PDEVICE_DATA DeviceData, + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +MbCtlEject ( + IN PDEVICE_DATA DeviceData, + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +MbCtlLock ( + IN PDEVICE_DATA DeviceData, + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +NTSTATUS +MbpGetBusData ( + IN ULONG BusNumber, + IN PULONG SlotNumber, + IN OUT PVOID *BusData, + OUT PULONG Length, + OUT PBOOLEAN DockConnector + ); + +NTSTATUS +MbpGetCompatibleDeviceId ( + IN PVOID BusData, + IN ULONG IdIndex, + IN PWCHAR CompatibleId + ); + +NTSTATUS +MbpGetSlotResources ( + IN ULONG BusNumber, + IN PVOID BusData, + OUT PCM_RESOURCE_LIST *CmResources, + OUT PULONG Length + ); + +NTSTATUS +MbpGetSlotResourceRequirements ( + IN ULONG BusNumber, + IN PVOID BusData, + OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoResources, + OUT PULONG Length + ); + +NTSTATUS +MbpSetSlotResources ( + OUT PVOID *BusData, + IN PCM_RESOURCE_LIST CmResources, + IN ULONG Length + ); + +NTSTATUS +MbpReplyEjectEvent ( + IN ULONG SlotNumber, + IN BOOLEAN Eject + ); + +NTSTATUS +MbpGetDockInformation ( + OUT PHAL_SYSTEM_DOCK_INFORMATION *DockInfo, + PULONG Length + ); + +PDEVICE_HANDLER_OBJECT +MbpReferenceDeviceHandler ( + IN struct _BUS_HANDLER *BusHandler, + IN struct _BUS_HANDLER *RootHandler, + IN ULONG SlotNumber + ); + +#if 0 + +// +// BUGBUG - should be removed... +// + +NTSTATUS +IoRegisterDetectedDevice( + IN PUNICODE_STRING ServiceKeyName, + IN PCM_RESOURCE_LIST DetectSignature, + OUT PULONG InstanceNumber + ); + +typedef enum _DEVICE_STATUS { + DeviceStatusOK, + DeviceStatusMalfunction, + DeviceStatusDisabled, + DeviceStatusRemoved, + MaximumDeviceStatus +} DEVICE_STATUS, *PDEVICE_STATUS; + +NTSTATUS +IoRegisterDevicePath( + IN PDEVICE_HANDLER_OBJECT DeviceHandler, + IN PUNICODE_STRING NtDeviceObjectPath, + IN BOOLEAN PhysicalDevicePath, + IN PCM_RESOURCE_LIST Configuration, + IN DEVICE_STATUS DeviceStatus + ); + +NTSTATUS +IoGetDeviceHandler( + IN PUNICODE_STRING ServicekeyName, + IN ULONG InstanceOrdinal, + OUT PDEVICE_HANDLER_OBJECT DeviceHandler + ); + +VOID +IoReleaseDevicehandler ( + IN PDEVICE_HANDLER_OBJECT DeviceHandler + ); +#endif diff --git a/private/ntos/nthals/extender/pnpbios/i386/control.c b/private/ntos/nthals/extender/pnpbios/i386/control.c new file mode 100644 index 000000000..ca9942df7 --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/i386/control.c @@ -0,0 +1,725 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + control.c + +Abstract: + + +Author: + + Shie-Lin Tzong (shielint) Apr-23-1995 + Most of the code is adapted from PCI bus extender. + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "busp.h" + +VOID +MbpiCompleteDeviceControl ( + NTSTATUS Status, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PDEVICE_DATA DeviceData, + PBOOLEAN Sync + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,MbpControlWorker) +#pragma alloc_text(PAGE,MbpCompleteDeviceControl) +#endif + +VOID +MbpStartWorker ( + VOID + ) +/*++ + +Routine Description: + + This function is used to start a worker thread. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + ULONG workerQueued; + + if (!MbpWorkerQueued) { + workerQueued = ExInterlockedExchangeUlong ( + &MbpWorkerQueued, + 1, + MbpSpinLock + ); + + if (!workerQueued) { + ExQueueWorkItem (&MbpWorkItem, DelayedWorkQueue); + } + } +} + +VOID +MbpQueueCheckBus ( + IN PBUS_HANDLER BusHandler + ) +/*++ + +Routine Description: + + This function enqueues Bus check request to buscheck list. + +Arguments: + + BusHandler - supplies a pointer to the bus handler of the bus to be checked. + +Return Value: + + None. + +--*/ +{ + ExInterlockedInsertTailList ( + &MbpCheckBusList, + &((PMB_BUS_EXTENSION)BusHandler->BusData)->CheckBus, + &MbpSpinlock + ); + + MbpStartWorker(); +} + +VOID +MbpControlWorker ( + IN PVOID WorkerContext + ) + +/*++ + +Routine Description: + + This function is called by a system worker thread. + + The worker thread dequeues any SlotControls which need to be + processed and dispatches them. + + It then checks for any check bus request. + +Arguments: + + WorkerContext - supplies a pointer to a context for the worker. Here + it is always NULL. + +Return Value: + + None. + +--*/ +{ + PLIST_ENTRY entry; + PMB_BUS_EXTENSION busExtension; + PHAL_DEVICE_CONTROL_CONTEXT context; + + PAGED_CODE (); + + // + // process check bus + // + + for (; ;) { + entry = ExInterlockedRemoveHeadList ( + &MbpCheckBusList, + &MbpSpinlock + ); + + if (!entry) { + break; + } + busExtension = CONTAINING_RECORD ( + entry, + MB_BUS_EXTENSION, + CheckBus + ); + + MbpCheckBus (busExtension->BusHandler); + } + + // + // Reset worker item for next time + // + + ExInitializeWorkItem (&MbpWorkItem, MbpControlWorker, NULL); + ExInterlockedExchangeUlong (&MbpWorkerQueued, 0, MbpSpinLock); + + // + // Dispatch pending device controls + // + + for (; ;) { + entry = ExInterlockedRemoveHeadList ( + &MbpControlWorkerList, + &MbpSpinlock + ); + + if (!entry) { + + // + // All done, exit the loop. + // + + break; + } + + context = CONTAINING_RECORD ( + entry, + HAL_DEVICE_CONTROL_CONTEXT, + ContextWorkQueue, + ); + + MbpDispatchControl (context); + } +} + +VOID +MbpDispatchControl ( + 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: + + None. + +--*/ +{ + PDEVICE_CONTROL_HANDLER deviceControlHandler; + PMB_BUS_EXTENSION busExtension; + PDEVICE_DATA deviceData; + KIRQL oldIrql; + BOOLEAN enqueueIt; + PLIST_ENTRY link; + + deviceControlHandler = (PDEVICE_CONTROL_HANDLER) Context->ContextControlHandler; + deviceData = DeviceHandler2DeviceData (Context->DeviceControl.DeviceHandler); + busExtension = (PMB_BUS_EXTENSION)Context->Handler->BusData; + + // + // Get access to the slot specific data. + // + + ExAcquireFastMutex(&MbpMutex); + + // + // Verify the device data is still valid + // + + if (!deviceData->Flags & DEVICE_FLAGS_VALID) { + + // + // Caller has invalid handle, or handle to a different device + // + + DebugPrint ((DEBUG_MESSAGE, "PnpBios: DeviceControl has invalid device handler \n" )); + Context->DeviceControl.Status = STATUS_NO_SUCH_DEVICE; + ExReleaseFastMutex(&MbpMutex); + 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. + // + + KeAcquireSpinLock (&MbpSpinlock, &oldIrql); + InsertTailList (&busExtension->DeviceControl, link); + KeReleaseSpinLock (&MbpSpinlock, oldIrql); + ExReleaseFastMutex(&MbpMutex); + return ; + } + + // + // Dispatch the function to it's handler + // + + ExReleaseFastMutex(&MbpMutex); + deviceControlHandler->ControlHandler (deviceData, Context); +} + +VOID +MbpiCompleteDeviceControl ( + NTSTATUS Status, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PDEVICE_DATA DeviceData, + PBOOLEAN Sync + ) +/*++ + +Routine Description: + + This function is used to complete a SlotControl. If another SlotControl + was delayed on this device, this function will dispatch them + +Arguments: + + Status - supplies a NTSTATUS code for the completion. + + Context - supplies a pointer to the original device control context. + + DeviceData - supplies a pointer to the device data to be completed. + + Sync - supplies a BOOLEAN variable to indicate + +Return Value: + +--*/ +{ + KIRQL oldIrql; + PLIST_ENTRY link; + PBOOLEAN busyFlag; + BOOLEAN startWorker = FALSE; + PMB_BUS_EXTENSION busExtension; + PDEVICE_HANDLER_OBJECT deviceHandler; + + busyFlag = (PBOOLEAN) Context->ContextBusyFlag; + deviceHandler = DeviceData2DeviceHandler(DeviceData); + busExtension = (PMB_BUS_EXTENSION)Context->Handler->BusData; + + // + // Pass it to the hal for completion + // + + Context->DeviceControl.Status = Status; + HalCompleteDeviceControl (Context); + + // + // Get access to the slot specific data. + // + + KeAcquireSpinLock (&MbpSpinlock, &oldIrql); + + // + // Clear appropiate busy flag + // + + *busyFlag = FALSE; + + // + // Check to see if there are any pending device controls for + // this device. If so, requeue them to the worker thread + // + + for (link = busExtension->DeviceControl.Flink; + link != &busExtension->DeviceControl; + link = link->Flink) { + + Context = CONTAINING_RECORD (link, HAL_DEVICE_CONTROL_CONTEXT, ContextWorkQueue); + if (Context->DeviceControl.DeviceHandler == deviceHandler) { + RemoveEntryList (link); + InsertTailList (&MbpControlWorkerList, link); + startWorker = TRUE; + break; + } + } + + KeReleaseSpinLock (&MbpSpinlock, oldIrql); + + if (startWorker) { + MbpStartWorker (); + } +} + +VOID +MbpCompleteDeviceControl ( + 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(); + + MbpiCompleteDeviceControl ( + Status, + Context, + DeviceData, + &DeviceData->SyncBusy + ); +} + +BOOLEAN +FASTCALL +MbBCtlNone ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function is used to indicate there is no synchronization for this + device control function. + +Arguments: + + Context - supplies a pointer to the device control context. + + DeviceData - supplies a pointer to the device data to be completed. + +Return Value: + + A boolean value to indicate if the request needs to be enqueued for later + processing. + +--*/ +{ + // + // No synchronization needed for this SlotControl + // + + Context->ContextBusyFlag = (ULONG) &MbpNoBusyFlag; + return FALSE; +} + +BOOLEAN +FASTCALL +MbBCtlSync ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function is used to synchronize device control request. it checks the + state (busy/not busy) of the slot and returns a boolean flag to indicate + whether the request can be serviced immediately or it needs to be enqueued for + later processing. + +Arguments: + + DeviceData - supplies a pointer to the device data to be completed. + + Context - supplies a pointer to the device control context. + +Return Value: + + A boolean value to indicate if the request needs to be enqueued for later + processing. + +--*/ +{ + // + // This is a sync command, verify the slot is not busy with a different + // command. + // + + if (DeviceData->SyncBusy) { + + // + // 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 +MbBCtlEject ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function is used to synchronize Eject device control request. it checks the + state (busy/not busy) of the device and returns a boolean flag to indicate + whether the request can be serviced immediately or it needs to be enqueued for + later processing. + +Arguments: + + DeviceData - supplies a pointer to the device data to be completed. + + Context - supplies a pointer to the slot control context. + +Return Value: + + A boolean value to indicate if the request needs to be enqueued for later + processing. + +--*/ +{ + BOOLEAN busy; + + // + // If Slot is busy, then wait + // + + busy = MbBCtlSync (DeviceData, Context); + + if (!busy) { + + // + // Set no device in the slot + // + + DeviceData->Flags &= ~DEVICE_FLAGS_VALID; + DebugPrint ((DEBUG_MESSAGE, "PnpBios: set handle invalid - slot %x for Eject request.\n", + DeviceDataSlot(DeviceData))); + } + + return busy; +} + +BOOLEAN +FASTCALL +MbBCtlLock ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function is used to synchronize LOCK device control request. it checks the + state (busy/not busy) of the device and returns a boolean flag to indicate + whether the request can be serviced immediately or it needs to be enqueued for + later processing. + +Arguments: + + DeviceData - supplies a pointer to the device data to be completed. + + Context - supplies a pointer to the device control context. + +Return Value: + + A boolean value to indicate if the request needs to be enqueued for later + processing. + +--*/ +{ + BOOLEAN busy; + + // + // If Slot is busy, then wait + // + + busy = MbBCtlSync (DeviceData, Context); +#if 0 + if (!busy) { + + lock = ((PBCTL_SET_CONTROL) Context->DeviceControl.Buffer)->Control; + if (!lock) { + + // + // Set no device in the slot + // + + DeviceData->Flags &= ~DEVICE_FLAGS_VALID; + } + } +#endif + return busy; +} + +VOID +MbCtlEject ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function is used to eject the docking station in the docking station + slot. + +Arguments: + + Context - supplies a pointer to the device control context. + + DeviceData - supplies a pointer to the device data to be completed. + +Return Value: + + None. + +--*/ +{ + NTSTATUS status = STATUS_INVALID_PARAMETER; + + if (DeviceData->Flags & DEVICE_FLAGS_DOCKING_STATION) { + status = MbpReplyEjectEvent(DeviceDataSlot(DeviceData), TRUE); + } + MbpCompleteDeviceControl (status, Context, DeviceData); +} + +VOID +MbCtlLock ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function is used to reject the Pnp Bios About-to-undock event. + To accept the about-to-undock event, the EJECT device control function + should be used. If lock = TRUE, it will be handled as a reject eject + request. If lock = FALSE, it will be handled as an accept reject rquest. + +Arguments: + + DeviceData - supplies a pointer to the device data to be completed. + + Context - supplies a pointer to the device control context. + +Return Value: + + None. + +--*/ +{ + BOOLEAN lock; + NTSTATUS status = STATUS_INVALID_PARAMETER; + + lock = ((PBCTL_SET_CONTROL) Context->DeviceControl.Buffer)->Control; + + if (DeviceData->Flags & DEVICE_FLAGS_DOCKING_STATION) { + status = MbpReplyEjectEvent(DeviceDataSlot(DeviceData), (BOOLEAN)!lock); + } + MbpCompleteDeviceControl (status, Context, DeviceData); +} + +VOID +MbCtlQueryEject ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function returns a referenced pointer to a callback object which + the bus extender will notify whenever a given device's eject botton is + pressed. + +Arguments: + + DeviceData - supplies a pointer to the device data to be completed. + + Context - supplies a pointer to the device control context. + +Return Value: + + None. + +--*/ +{ + NTSTATUS status = STATUS_INVALID_PARAMETER; + PULONG callback; + + callback =(PULONG)((PBCTL_SET_CONTROL) Context->DeviceControl.Buffer); + if (DeviceData->Flags == DEVICE_FLAGS_DOCKING_STATION) { + if (MbpEjectCallbackObject) { + status = STATUS_SUCCESS; + *callback = (ULONG)MbpEjectCallbackObject; + } else { + status = STATUS_UNSUCCESSFUL; + } + } + MbpCompleteDeviceControl (status, Context, DeviceData); +} + +VOID +MbCtlQueryDeviceCapabilities ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function returns the BCTL_DEVICE_CAPABILITIES structure to the caller + specified buffer. + +Arguments: + + DeviceData - supplies a pointer to the device data to be completed. + + Context - supplies a pointer to the device control context. + +Return Value: + + None. + +--*/ +{ + PBCTL_DEVICE_CAPABILITIES capabilities; + + capabilities = (PBCTL_DEVICE_CAPABILITIES) Context->DeviceControl.Buffer; + + capabilities->PowerSupported = FALSE; + capabilities->ResumeSupported = FALSE; + capabilities->LockSupported = FALSE; + if (DeviceData->Flags && DEVICE_FLAGS_EJECT_SUPPORTED) { + capabilities->EjectSupported = TRUE; + } else { + capabilities->EjectSupported = FALSE; + } + MbpCompleteDeviceControl (STATUS_SUCCESS, Context, DeviceData); +} + diff --git a/private/ntos/nthals/extender/pnpbios/i386/data.c b/private/ntos/nthals/extender/pnpbios/i386/data.c new file mode 100644 index 000000000..e3c44e2ff --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/i386/data.c @@ -0,0 +1,159 @@ + +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pbdata.c + +Abstract: + + Declares various data which is specific to bus extender architecture and + is independent of BIOS. + +Author: + + Shie-Lin Tzong (shielint) 12-Apr-95 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "busp.h" + +// +// MbpMutex - To synchronize with device handle changes +// + +FAST_MUTEX MbpMutex; + +// +// MbpSpinLock - Lock to protect DeviceControl globals +// + +KSPIN_LOCK MbpSpinlock; + +// +// MbpControlWorkerList - List of device control's which are pending for worker thread +// + +LIST_ENTRY MbpControlWorkerList; +ULONG MbpWorkerQueued; + +// +// MbpWorkItem - Enqueue for DeviceControl worker thread +// + +WORK_QUEUE_ITEM MbpWorkItem; + +// +// MbpCheckBusList - +// + +LIST_ENTRY MbpCheckBusList; + +// +// Eject callback object +// + +PCALLBACK_OBJECT MbpEjectCallbackObject; + +// +// regBIOSDeviceName +// + +WCHAR rgzBIOSDeviceName[] = L"\\Device\\PnpBios_%d"; + +// +// Size of DeviceHandlerObject +// + +ULONG MbpDeviceHandlerObjectSize; + +// +// DeviceControl dispatch table +// + +#define B_EJECT BCTL_EJECT +#define B_UID BCTL_QUERY_DEVICE_UNIQUE_ID +#define B_CAPABILITIES BCTL_QUERY_DEVICE_CAPABILITIES +#define B_ID BCTL_QUERY_DEVICE_ID +#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 + +// +// declare slot control function table. +// NOTE if the number of entries is changed, the NUMBER_SLOT_CONTROL_FUNCTIONS defined in +// busp.h must be chnaged accordingly. +// + +DEVICE_CONTROL_HANDLER MbpDeviceControl[] = { + B_EJECT, 0, MbBCtlEject, MbCtlEject, + B_ID, 32, MbBCtlSync, MbCtlQueryDeviceId, + B_UID, 32, MbBCtlSync, MbCtlQueryDeviceUniqueId, + B_CAPABILITIES, sizeof(BCTL_DEVICE_CAPABILITIES), MbBCtlSync, MbCtlQueryDeviceCapabilities, + B_RES, sizeof(ULONG), MbBCtlSync, MbCtlQueryDeviceResources, + B_RES_REQ, sizeof(ULONG), MbBCtlSync, MbCtlQueryDeviceResourceRequirements, + B_QUERY_EJECT, sizeof(PVOID), MbBCtlNone, MbCtlQueryEject, + B_SET_LOCK, sizeof(BOOLEAN), MbBCtlLock, MbCtlLock, + B_SET_RESUME, sizeof(BOOLEAN), NULL, NULL, + B_SET_POWER, sizeof(POWER_STATE), NULL, NULL, + B_SET_RES, 0, MbBCtlSync, MbCtlSetDeviceResources, +}; + +#ifdef ALLOC_DATA_PRAGMA +#pragma data_seg("PAGE") +#endif + +// +// Bus Extender driver object +// + +PDRIVER_OBJECT MbpDriverObject; + +// +// Pointers to Hal callback objects +// + +HAL_CALLBACKS MbpHalCallbacks; + +// +// MbpNoBusyFlag - scratch memory location to point at +// + +BOOLEAN MbpNoBusyFlag; + +// +// MbpMaxDeviceData - the maximum device data size +// + +ULONG MbpMaxDeviceData; + +// +// Pointers to bus extension data. +// + +PMB_BUS_EXTENSION MbpBusExtension[2]; + +// +// Next Bus number index (i.e. logical bus number) +// + +ULONG MbpNextBusId; + +// +// Array to record bus number of buses +// + +ULONG MbpBusNumber[MAXIMUM_BUS_NUMBER]; diff --git a/private/ntos/nthals/extender/pnpbios/i386/init.c b/private/ntos/nthals/extender/pnpbios/i386/init.c new file mode 100644 index 000000000..0a921bc07 --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/i386/init.c @@ -0,0 +1,482 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + init.c + +Abstract: + + + DriverEntry initialization code for pnp bios bus extender. + +Author: + + Shie-Lin Tzong (shielint) 21-Apr-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "busp.h" + +NTSTATUS +MbInstallBusHandler ( + IN PBUS_HANDLER MbBus + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,DriverEntry) +#pragma alloc_text(PAGE,MbAddBusDevices) +#pragma alloc_text(PAGE,MbInstallBusHandler) +#endif + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + This routine checks if mother board device info is accessible. If yes it + initializes its data structures and invokes h/w dependent initialization + routine. + +Arguments: + + DriverObject - specifies the driver object for the bus extender. + + RegistryPath - supplies a pointer to a unicode string of the service key name in + the CurrentControlSet\Services key for the bus extender. + +Return Value: + + A NTSTATUS code to indicate the result of the initialization. + +--*/ + +{ + UNICODE_STRING unicodeString; + NTSTATUS status; + PVOID p; + ULONG length, count, i, bufferSize; + PDEVICE_HANDLER_OBJECT deviceHandler; + HAL_BUS_INFORMATION busInfo; + PCM_RESOURCE_LIST configuration = NULL; + ULONG deviceFlags; + + // + // Verify Pnp BIOS is present - perform h/w dependent phase 0 initialization. + // + + status = PbInitialize(0, NULL); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE,"PnpBios: Pnp Bios data phase 0 Initialization failed.\n")); + return STATUS_NO_SUCH_DEVICE; + } + + // + // Get pointers to the Hals callback objects. The one we are really interested + // in is Bus Check callback. + // + + status = HalQuerySystemInformation ( + HalCallbackInformation, + sizeof (MbpHalCallbacks), + &MbpHalCallbacks, + &length + ); + + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE,"PnpBios: Failed to query Hal callbacks\n")); + return status; + } + + // + // Initialize globals + // + + MbpDriverObject = DriverObject; + ExInitializeWorkItem (&MbpWorkItem, MbpControlWorker, NULL); + KeInitializeSpinLock (&MbpSpinlock); + InitializeListHead (&MbpControlWorkerList); + InitializeListHead (&MbpCheckBusList); + ExInitializeFastMutex (&MbpMutex); + MbpDeviceHandlerObjectSize = *IoDeviceHandlerObjectSize; + + for (i = 0; i < MAXIMUM_BUS_NUMBER; i++) { + MbpBusNumber[i] = (ULONG) -1; + } + + // + // Initialize driver object add and detect device entries. + // + + DriverObject->DriverExtension->AddDevice = MbAddBusDevices; + DriverObject->MajorFunction[IRP_MJ_CREATE] = MbCreateClose; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = MbCreateClose; + + // + // Query the devices/buses currently controlled by the bus extender + // + + status = IoQueryDeviceEnumInfo (&DriverObject->DriverExtension->ServiceKeyName, &count); + if (!NT_SUCCESS(status)) { + return status; + } + for (i = 0; i < count; i++) { + status = IoGetDeviceHandler(&DriverObject->DriverExtension->ServiceKeyName, + i, + &deviceHandler); + if (NT_SUCCESS(status)) { + bufferSize = sizeof(CM_RESOURCE_LIST); +tryAgain: + configuration = (PCM_RESOURCE_LIST)ExAllocatePool(PagedPool, + bufferSize + ); + if (!configuration) { + IoReleaseDeviceHandler(deviceHandler); + return STATUS_INSUFFICIENT_RESOURCES; + } + status = IoQueryDeviceConfiguration(deviceHandler, + &busInfo, + &deviceFlags, + configuration, + bufferSize, // buffer size + &length // Actual size + ); + IoReleaseDeviceHandler(deviceHandler); + if (NT_SUCCESS(status)) { + + // + // We know we have two buses at most. If this is the first bus, we will add it + // and exit. We don't touch 2nd bus at init time. It should be enumerated + // later. + + if (length >= MIN_DETECT_SIGNATURE_SIZE && + configuration->List[0].BusNumber == 0 && + configuration->List[0].InterfaceType == BUS_0_SIGNATURE) { + if (deviceFlags == DeviceStatusOK) { + MbAddBusDevices(&DriverObject->DriverExtension->ServiceKeyName, &i); + ExFreePool(configuration); + break; + } + } + } else if (status == STATUS_BUFFER_TOO_SMALL) { + ExFreePool(configuration); + bufferSize = length; + goto tryAgain; + } + ExFreePool(configuration); + } + } + + return STATUS_SUCCESS; +} + +NTSTATUS +MbAddBusDevices( + IN PUNICODE_STRING ServiceKeyName, + IN OUT PULONG InstanceNumber + ) + +/*++ + +Routine Description: + +Arguments: + + +Return Value: + + +--*/ + +{ + NTSTATUS status; + PBUS_HANDLER busHandler; + PCM_RESOURCE_LIST detectSignature; + UCHAR configuration[sizeof(CM_RESOURCE_LIST)]; + UNICODE_STRING unicodeString; + WCHAR buffer[60]; + ULONG VirtualBusNumber; + PDEVICE_HANDLER_OBJECT deviceHandler = NULL; + + PAGED_CODE(); + RtlZeroMemory(configuration, sizeof(CM_RESOURCE_LIST)); + + // + // Check if DriverEntry succeeded ... + // + + if (!MbpDriverObject) { + return STATUS_NO_MORE_ENTRIES; + } + + if (*InstanceNumber == PLUGPLAY_NO_INSTANCE) { + if (MbpBusNumber[0] == (ULONG) -1) { + + // + // If bus handler for Pnp Bios bus 0 has not been installed, + // add this bus. + // + // Register bus handler for bus 0 - motherboard devices + // + + status = HalRegisterBusHandler ( + Internal, + -1, + (ULONG)-1, + Isa, // child of Isa bus # 0 + 0, + sizeof (MB_BUS_EXTENSION), + MbInstallBusHandler, + &busHandler + ); + + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE,"PnpBios: Register Pnp bus 0 handler failed\n")); + return status; + } + + // + // Register the bus with Pnp manager. + // + + detectSignature = (PCM_RESOURCE_LIST)configuration; + detectSignature->Count = 1; + detectSignature->List[0].InterfaceType = BUS_0_SIGNATURE; + detectSignature->List[0].BusNumber = 0; + status = IoRegisterDetectedDevice (&MbpDriverObject->DriverExtension->ServiceKeyName, + detectSignature, + InstanceNumber); + if (!NT_SUCCESS(status)) { + + // + // BUGBUG - unregister bus handler? How? + // + + DebugPrint((DEBUG_BREAK,"PnpBios: Failed to register bus 0 to Pnp Mgr\n")); + return STATUS_UNSUCCESSFUL; + } + } else { + + // + // Enumerator should be able to find the docking station bus, if present, + // and should call this routine with a valid InstanceNumber. So, if after + // bus 0 is registered and enumerator calls this function again with + // *InstanceNumber == PLUGPLAY_NO_INSTANCE, it means there is no docking + // station bus - bus 1, we can simply return STATUS_NO_MORE_ENTRIES. + // + + return STATUS_NO_MORE_ENTRIES; + } + } else { + + if (MbpBusNumber[0] == (ULONG) -1) { + + // + // If bus handler for Pnp Bios bus 0 has not been installed, + // add this bus. + // + // Register bus handler for bus 0 - motherboard devices + // + + status = HalRegisterBusHandler ( + Internal, + -1, + (ULONG)-1, + Isa, // child of Isa bus # 0 + 0, + sizeof (MB_BUS_EXTENSION), + MbInstallBusHandler, + &busHandler + ); + + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE,"PnpBios: Register Pnp bus 0 handler failed\n")); + return status; + } + + } else if (MbpBusNumber[1] == (ULONG) -1 && MbpBusExtension[0]->DockingStationDevice ) { + + // + // If bus 1 has not been registered and docking station is present, + // Register bus handler for bus 1 - docking station devices + // + + status = HalRegisterBusHandler ( + Internal, + -1, + (ULONG)-1, + Internal, + MbpBusNumber[0], + sizeof (MB_BUS_EXTENSION), + MbInstallBusHandler, + &busHandler + ); + + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE,"PnpBios: Register Pnp bus handler for bus 1 failed\n")); + return status; + } + } else { + return STATUS_NO_MORE_ENTRIES; + } + } + + // + // Call Pnp Io Mgr to register the new device object path + // + + swprintf (buffer, rgzBIOSDeviceName, busHandler->BusNumber); + RtlInitUnicodeString (&unicodeString, buffer); + + if (!NT_SUCCESS(status = IoGetDeviceHandler(&MbpDriverObject->DriverExtension->ServiceKeyName, + *InstanceNumber, &deviceHandler)) || + !NT_SUCCESS(status = IoRegisterDevicePath(deviceHandler, &unicodeString, TRUE, NULL, + DeviceStatusOK))) { + + // + // BUGBUG - unregister bus handler? How? + // + + if (deviceHandler) { + DebugPrint((DEBUG_MESSAGE,"PnpBios: Register NT device path failed\n")); + IoReleaseDeviceHandler(deviceHandler); + } else { + DebugPrint((DEBUG_MESSAGE,"PnpBios: Unable to get device handler\n")); + } + } + + IoReleaseDeviceHandler(deviceHandler); + + // + // Perform initial bus check + // + + MbpCheckBus(busHandler); + + // + // Give non portable part of initialization another chance - phase 1 initialization. + // + + PbInitialize(1, busHandler->DeviceObject); + return STATUS_SUCCESS; +} + +NTSTATUS +MbInstallBusHandler ( + PBUS_HANDLER MbBus + ) + +/*++ + +Routine Description: + + This routine is invoked by Hal to initialize BUS_HANDLER structure and its + extension. + +Arguments: + + MbBus - spplies a pointer to Pnp BIOS bus handler's BUS_HANDLER structure. + +Return Value: + + A NTSTATUS code to indicate the result of the initialization. + +--*/ + +{ + WCHAR buffer[60]; + UNICODE_STRING unicodeString; + PMB_DEVICE_EXTENSION deviceExtension; + PMB_BUS_EXTENSION busExtension; + NTSTATUS status; + PDEVICE_OBJECT deviceObject; + + PAGED_CODE(); + + // + // Verify there's a parent handler + // + + if (!MbBus->ParentHandler) { + return STATUS_UNSUCCESSFUL; + } + + // + // Create device object for Motherboard/PnpBios bus extender. + // + + swprintf (buffer, rgzBIOSDeviceName, MbBus->BusNumber); + RtlInitUnicodeString (&unicodeString, buffer); + + status = IoCreateDevice( + MbpDriverObject, + sizeof(MB_DEVICE_EXTENSION), // No device extension space + &unicodeString, + FILE_DEVICE_BUS_EXTENDER, + 0, + FALSE, + &deviceObject + ); + + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE,"PnpBios: Failed to create device object\n")); + return status; + } + + // =================================== + // BUGBUG - need to find a solution + // + + deviceObject->Flags &= ~0x80; + + // ================================== + deviceExtension = (PMB_DEVICE_EXTENSION) deviceObject->DeviceExtension; + deviceExtension->BusHandler = MbBus; + + // + // Initialize bus handlers + // + + MbBus->DeviceObject = deviceObject; + MbBus->GetBusData = (PGETSETBUSDATA) MbGetBusData; + MbBus->SetBusData = (PGETSETBUSDATA) MbSetBusData; + MbBus->QueryBusSlots = (PQUERY_BUS_SLOTS) MbQueryBusSlots; + MbBus->DeviceControl = (PDEVICE_CONTROL) MbDeviceControl; + MbBus->ReferenceDeviceHandler = (PREFERENCE_DEVICE_HANDLER) MbpReferenceDeviceHandler; + MbBus->GetDeviceData = (PGET_SET_DEVICE_DATA) MbGetDeviceData; + MbBus->SetDeviceData = (PGET_SET_DEVICE_DATA) MbSetDeviceData; + + // + // Intialize bus extension + // + + busExtension = (PMB_BUS_EXTENSION)MbBus->BusData; + RtlZeroMemory(busExtension, sizeof(MB_BUS_EXTENSION)); + busExtension->BusHandler = MbBus; + + MbpBusNumber[MbpNextBusId] = MbBus->BusNumber; + MbpBusExtension[MbpNextBusId] = busExtension; + MbpNextBusId++; + + InitializeListHead (&busExtension->CheckBus); + InitializeListHead (&busExtension->DeviceControl); + + return STATUS_SUCCESS; +} + + + diff --git a/private/ntos/nthals/extender/pnpbios/i386/misc.c b/private/ntos/nthals/extender/pnpbios/i386/misc.c new file mode 100644 index 000000000..2fb2210fe --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/i386/misc.c @@ -0,0 +1,471 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + misc.c + +Abstract: + + This file contains pnp bios bus extender support routines. + +Author: + + Shie-Lin Tzong (shielint) 20-Apr-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "busp.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,MbCreateClose) +#pragma alloc_text(PAGE,PbGetRegistryValue) +#pragma alloc_text(PAGE,PbDecompressEisaId) +#endif + + +NTSTATUS +MbCreateClose ( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine handles open and close requests such that our device objects + can be opened. All it does it to complete the Irp with success. + +Arguments: + + DeviceObject - Supplies a pointer to the device object to be opened or closed. + + Irp - supplies a pointer to I/O request packet. + +Return Value: + + Always returns STATUS_SUCCESS, since this is a null operation. + +--*/ + +{ + UNREFERENCED_PARAMETER( DeviceObject ); + + PAGED_CODE(); + + // + // Null operation. Do not give an I/O boost since no I/O was + // actually done. IoStatus.Information should be + // FILE_OPENED for an open; it's undefined for a close. + // + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = FILE_OPENED; + + IoCompleteRequest( Irp, 0); + + return STATUS_SUCCESS; +} + +VOID +PbDecompressEisaId( + IN ULONG CompressedId, + IN PUCHAR EisaId + ) + +/*++ + +Routine Description: + + This routine decompressed compressed Eisa Id and returns the Id to caller + specified character buffer. + +Arguments: + + CompressedId - supplies the compressed Eisa Id. + + EisaId - supplies a 8-char buffer to receive the decompressed Eisa Id. + +Return Value: + + None. + +--*/ + +{ + USHORT c1, c2; + LONG i; + + PAGED_CODE(); + + CompressedId &= 0xffffff7f; // remove the reserved bit (bit 7 of byte 0) + c1 = c2 = (USHORT)CompressedId; + c1 = (c1 & 0xff) << 8; + c2 = (c2 & 0xff00) >> 8; + c1 |= c2; + for (i = 2; i >= 0; i--) { + *(EisaId + i) = (UCHAR)(c1 & 0x1f) + 0x40; + c1 >>= 5; + } + EisaId += 3; + c1 = c2 = (USHORT)(CompressedId >> 16); + c1 = (c1 & 0xff) << 8; + c2 = (c2 & 0xff00) >> 8; + c1 |= c2; + sprintf (EisaId, "%04x", c1); +} + +NTSTATUS +PbGetRegistryValue( + IN HANDLE KeyHandle, + IN PWSTR ValueName, + OUT PKEY_VALUE_FULL_INFORMATION *Information + ) + +/*++ + +Routine Description: + + This routine is invoked to retrieve the data for a registry key's value. + This is done by querying the value of the key with a zero-length buffer + to determine the size of the value, and then allocating a buffer and + actually querying the value into the buffer. + + It is the responsibility of the caller to free the buffer. + +Arguments: + + KeyHandle - Supplies the key handle whose value is to be queried + + ValueName - Supplies the null-terminated Unicode name of the value. + + Information - Returns a pointer to the allocated data buffer. + +Return Value: + + The function value is the final status of the query operation. + +--*/ + +{ + UNICODE_STRING unicodeString; + NTSTATUS status; + PKEY_VALUE_FULL_INFORMATION infoBuffer; + ULONG keyValueLength; + + PAGED_CODE(); + + RtlInitUnicodeString( &unicodeString, ValueName ); + + // + // Figure out how big the data value is so that a buffer of the + // appropriate size can be allocated. + // + + status = ZwQueryValueKey( KeyHandle, + &unicodeString, + KeyValueFullInformation, + (PVOID) NULL, + 0, + &keyValueLength ); + if (status != STATUS_BUFFER_OVERFLOW && + status != STATUS_BUFFER_TOO_SMALL) { + return status; + } + + // + // Allocate a buffer large enough to contain the entire key data value. + // + + infoBuffer = ExAllocatePool( NonPagedPool, keyValueLength ); + if (!infoBuffer) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Query the data for the key value. + // + + status = ZwQueryValueKey( KeyHandle, + &unicodeString, + KeyValueFullInformation, + infoBuffer, + keyValueLength, + &keyValueLength ); + if (!NT_SUCCESS( status )) { + ExFreePool( infoBuffer ); + return status; + } + + // + // Everything worked, so simply return the address of the allocated + // buffer to the caller, who is now responsible for freeing it. + // + + *Information = infoBuffer; + return STATUS_SUCCESS; +} +#if DBG + +VOID +PbDebugPrint ( + ULONG Level, + PCCHAR DebugMessage, + ... + ) +/*++ + +Routine Description: + + This routine displays debugging message or causes a break. + +Arguments: + + Level - supplies debugging levelcode. DEBUG_MESSAGE - displays message only. + DEBUG_BREAK - displays message and break. + + DebugMessage - supplies a pointer to the debugging message. + +Return Value: + + None. + +--*/ + +{ + UCHAR Buffer[256]; + va_list ap; + + va_start(ap, DebugMessage); + + vsprintf(Buffer, DebugMessage, ap); + DbgPrint(Buffer); + if (Level == DEBUG_BREAK) { + DbgBreakPoint(); + } + + va_end(ap); +} + +VOID +MbpDumpIoResourceDescriptor ( + IN PUCHAR Indent, + IN PIO_RESOURCE_DESCRIPTOR Desc + ) +/*++ + +Routine Description: + + This routine processes a IO_RESOURCE_DESCRIPTOR and displays it. + +Arguments: + + Indent - # char of indentation. + + Desc - supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be displayed. + +Return Value: + + None. + +--*/ +{ + UCHAR c = ' '; + + if (Desc->Option == IO_RESOURCE_ALTERNATIVE) { + c = 'A'; + } else if (Desc->Option == IO_RESOURCE_PREFERRED) { + c = 'P'; + } + switch (Desc->Type) { + case CmResourceTypePort: + DbgPrint ("%sIO %c Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n", + Indent, c, + Desc->u.Port.MinimumAddress.HighPart, Desc->u.Port.MinimumAddress.LowPart, + Desc->u.Port.MaximumAddress.HighPart, Desc->u.Port.MaximumAddress.LowPart, + Desc->u.Port.Alignment, + Desc->u.Port.Length + ); + break; + + case CmResourceTypeMemory: + DbgPrint ("%sMEM %c Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n", + Indent, c, + Desc->u.Memory.MinimumAddress.HighPart, Desc->u.Memory.MinimumAddress.LowPart, + Desc->u.Memory.MaximumAddress.HighPart, Desc->u.Memory.MaximumAddress.LowPart, + Desc->u.Memory.Alignment, + Desc->u.Memory.Length + ); + break; + + case CmResourceTypeInterrupt: + DbgPrint ("%sINT %c Min: %x, Max: %x\n", + Indent, c, + Desc->u.Interrupt.MinimumVector, + Desc->u.Interrupt.MaximumVector + ); + break; + + case CmResourceTypeDma: + DbgPrint ("%sDMA %c Min: %x, Max: %x\n", + Indent, c, + Desc->u.Dma.MinimumChannel, + Desc->u.Dma.MaximumChannel + ); + break; + } +} + +VOID +MbpDumpIoResourceList ( + IN PIO_RESOURCE_REQUIREMENTS_LIST IoList + ) +/*++ + +Routine Description: + + This routine displays Io resource requirements list. + +Arguments: + + IoList - supplies a pointer to the Io resource requirements list to be displayed. + +Return Value: + + None. + +--*/ +{ + + + PIO_RESOURCE_LIST resList; + PIO_RESOURCE_DESCRIPTOR resDesc; + ULONG listCount, count, i, j; + + DbgPrint("Pnp Bios IO Resource Requirements List for Slot %x -\n", IoList->SlotNumber); + DbgPrint(" List Count = %x, Bus Number = %x\n", IoList->AlternativeLists, IoList->BusNumber); + listCount = IoList->AlternativeLists; + resList = &IoList->List[0]; + for (i = 0; i < listCount; i++) { + DbgPrint(" Version = %x, Revision = %x, Desc count = %x\n", resList->Version, + resList->Revision, resList->Count); + resDesc = &resList->Descriptors[0]; + count = resList->Count; + for (j = 0; j < count; j++) { + MbpDumpIoResourceDescriptor(" ", resDesc); + resDesc++; + } + resList = (PIO_RESOURCE_LIST) resDesc; + } +} + +VOID +MbpDumpCmResourceDescriptor ( + IN PUCHAR Indent, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Desc + ) +/*++ + +Routine Description: + + This routine processes a IO_RESOURCE_DESCRIPTOR and displays it. + +Arguments: + + Indent - # char of indentation. + + Desc - supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be displayed. + +Return Value: + + None. + +--*/ +{ + switch (Desc->Type) { + case CmResourceTypePort: + DbgPrint ("%sIO Start: %x:%08x, Length: %x\n", + Indent, + Desc->u.Port.Start.HighPart, Desc->u.Port.Start.LowPart, + Desc->u.Port.Length + ); + break; + + case CmResourceTypeMemory: + DbgPrint ("%sMEM Start: %x:%08x, Length: %x\n", + Indent, + Desc->u.Memory.Start.HighPart, Desc->u.Memory.Start.LowPart, + Desc->u.Memory.Length + ); + break; + + case CmResourceTypeInterrupt: + DbgPrint ("%sINT Level: %x, Vector: %x, Affinity: %x\n", + Indent, + Desc->u.Interrupt.Level, + Desc->u.Interrupt.Vector, + Desc->u.Interrupt.Affinity + ); + break; + + case CmResourceTypeDma: + DbgPrint ("%sDMA Channel: %x, Port: %x\n", + Indent, + Desc->u.Dma.Channel, + Desc->u.Dma.Port + ); + break; + } +} + +VOID +MbpDumpCmResourceList ( + IN PCM_RESOURCE_LIST CmList, + IN ULONG SlotNumber + ) +/*++ + +Routine Description: + + This routine displays CM resource list. + +Arguments: + + CmList - supplies a pointer to CM resource list + + SlotNumber - slot number of the resources + +Return Value: + + None. + +--*/ +{ + PCM_FULL_RESOURCE_DESCRIPTOR fullDesc; + PCM_PARTIAL_RESOURCE_LIST partialDesc; + PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; + ULONG count, i; + + fullDesc = &CmList->List[0]; + DbgPrint("Pnp Bios Cm Resource List for Slot %x -\n", SlotNumber); + DbgPrint(" List Count = %x, Bus Number = %x\n", CmList->Count, fullDesc->BusNumber); + partialDesc = &fullDesc->PartialResourceList; + DbgPrint(" Version = %x, Revision = %x, Desc count = %x\n", partialDesc->Version, + partialDesc->Revision, partialDesc->Count); + count = partialDesc->Count; + desc = &partialDesc->PartialDescriptors[0]; + for (i = 0; i < count; i++) { + MbpDumpCmResourceDescriptor(" ", desc); + desc++; + } +} +#endif diff --git a/private/ntos/nthals/extender/pnpbios/i386/pbapi.h b/private/ntos/nthals/extender/pnpbios/i386/pbapi.h new file mode 100644 index 000000000..70193117a --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/i386/pbapi.h @@ -0,0 +1,235 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + bpapi.h + +Abstract: + + This module contins definitions/declarations for pnp bios independent code + to call Pnp bios dependent code. This module is considered portable code. + +Author: + + Shie-Lin Tzong (shielint) Apr-26-1995 + +Revision History: + +--*/ + +#include "pbios.h" + +// +// internal structures for resource translation +// + +typedef struct _PB_DEPENDENT_RESOURCES { + ULONG Count; + UCHAR Flags; + UCHAR Priority; + struct _PB_DEPENDENT_RESOURCES *Next; +} PB_DEPENDENT_RESOURCES, *PPB_DEPENDENT_RESOURCES; + +#define DEPENDENT_FLAGS_END 1 + +typedef struct _PB_ATERNATIVE_INFORMATION { + PPB_DEPENDENT_RESOURCES Resources; + ULONG NoDependentFunctions; + ULONG TotalResourceCount; +} PB_ALTERNATIVE_INFORMATION, *PPB_ALTERNATIVE_INFORMATION; + +#define PB_CM_FORMAT 0 +#define PB_IO_FORMAT 1 + +// +// A big structure for calling Pnp BIOS functions +// + +#define PNP_BIOS_GET_NUMBER_DEVICE_NODES 0 +#define PNP_BIOS_GET_DEVICE_NODE 1 +#define PNP_BIOS_SET_DEVICE_NODE 2 +#define PNP_BIOS_GET_EVENT 3 +#define PNP_BIOS_SEND_MESSAGE 4 +#define PNP_BIOS_GET_DOCK_INFORMATION 5 +// Function 6 is reserved +#define PNP_BIOS_SELECT_BOOT_DEVICE 7 +#define PNP_BIOS_GET_BOOT_DEVICE 8 +#define PNP_BIOS_SET_OLD_ISA_RESOURCES 9 +#define PNP_BIOS_GET_OLD_ISA_RESOURCES 0xA +#define PNP_BIOS_GET_ISA_CONFIGURATION 0x40 + +typedef struct _PB_DOCKING_STATION_INFORMATION { + ULONG LocationId; + ULONG SerialNumber; + USHORT Capabilities; +} PB_DOCKING_STATION_INFORMATION, *PPB_DOCKING_STATION_INFORMATION; + +// +// definitions of Docking station capabilities. +// + +#define DOCKING_CAPABILITIES_MASK 6 +#define DOCKING_CAPABILITIES_COLD_DOCKING 0 +#define DOCKING_CAPABILITIES_WARM_DOCKING 1 +#define DOCKING_CAPABILITIES_HOT_DOCKING 2 + +typedef struct _PB_PARAMETERS { + USHORT Function; + union { + struct { + USHORT *NumberNodes; + USHORT *NodeSize; + } GetNumberDeviceNodes; + + struct { + USHORT *Node; + PPNP_BIOS_DEVICE_NODE NodeBuffer; + USHORT Control; + } GetDeviceNode; + + struct { + USHORT Node; + PPNP_BIOS_DEVICE_NODE NodeBuffer; + USHORT Control; + } SetDeviceNode; + + struct { + USHORT *Message; + } GetEvent; + + struct { + USHORT Message; + } SendMessage; + + struct { + PB_DOCKING_STATION_INFORMATION *DockingStationInfo; + USHORT *DockState; + } GetDockInfo; + } u; +} PB_PARAMETERS, *PPB_PARAMETERS; + +#define PB_MAXIMUM_STACK_SIZE (sizeof(PB_PARAMETERS) + sizeof(USHORT) * 2) + +// +// PNP BIOS send message api definitions +// + +#define OK_TO_CHANGE_CONFIG 00 +#define ABORT_CONFIG_CHANGE 01 +#define PNP_OS_ACTIVE 0x42 + +// +// Control Flags for Get_Device_Node +// + +#define GET_CURRENT_CONFIGURATION 1 +#define GET_NEXT_BOOT_CONFIGURATION 2 + +// +// Control Flags for Set_Device_node +// + +#define SET_CONFIGURATION_NOW 1 +#define SET_CONFIGURATION_FOR_NEXT_BOOT 2 + +// +// Debug functions +// + +#if DBG + +VOID +MbpDumpIoResourceList ( + IN PIO_RESOURCE_REQUIREMENTS_LIST IoList + ); + +VOID +MbpDumpCmResourceList ( + IN PCM_RESOURCE_LIST CmList, + IN ULONG SlotNumber + ); + +#define DEBUG_MESSAGE 1 +#define DEBUG_BREAK 2 + +VOID PbDebugPrint ( + ULONG Level, + PCCHAR DebugMessage, + ... + ); + +#define DebugPrint(arg) PbDebugPrint arg +#else +#define DebugPrint(arg) +#endif + +// +// External References +// + +extern PPNP_BIOS_INSTALLATION_CHECK PbBiosRegistryData; +extern PVOID PbBiosKeyInformation; + +// +// prototypes +// + +NTSTATUS +PbBiosResourcesToNtResources ( + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN OUT PUCHAR *BiosData, + IN UCHAR Format, + OUT PUCHAR *ReturnedList, + OUT PULONG ReturnedLength + ); + +NTSTATUS +PbCmResourcesToBiosResources ( + IN PCM_RESOURCE_LIST CmResources, + IN PUCHAR BiosRequirements, + IN PUCHAR *BiosResources, + IN PULONG Length + ); + +NTSTATUS +PbInitialize ( + IN ULONG Phase, + IN PDEVICE_OBJECT DeviceObject + ); + +NTSTATUS +PbGetRegistryValue( + IN HANDLE KeyHandle, + IN PWSTR ValueName, + OUT PKEY_VALUE_FULL_INFORMATION *Information + ); + +NTSTATUS +PbHardwareService ( + IN PPB_PARAMETERS Parameters + ); + +VOID +PbDecompressEisaId( + IN ULONG CompressedId, + IN PUCHAR EisaId + ); + +BOOLEAN +PbVerifyBusAdd ( + VOID + ); + +BOOLEAN +MbpConfigAboutToChange ( + VOID + ); + +VOID +MbpConfigChanged ( + VOID + ); + diff --git a/private/ntos/nthals/extender/pnpbios/i386/pbcnvrt.c b/private/ntos/nthals/extender/pnpbios/i386/pbcnvrt.c new file mode 100644 index 000000000..49a9fbaa3 --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/i386/pbcnvrt.c @@ -0,0 +1,1562 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + xlate.c + +Abstract: + + This file contains routines to translate resources between PnP ISA/BIOS + format and Windows NT formats. + +Author: + + Shie-Lin Tzong (shielint) 12-Apr-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "pbapi.h" + +VOID +PbIoDescriptorToCmDescriptor ( + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor + ); + +PPB_DEPENDENT_RESOURCES +PbAddDependentResourcesToList ( + IN OUT PUCHAR *ResourceDescriptor, + IN ULONG ListNo, + IN PPB_ALTERNATIVE_INFORMATION AlternativeList + ); + +NTSTATUS +PbBiosIrqToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +NTSTATUS +PbBiosDmaToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +NTSTATUS +PbBiosPortFixedToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +NTSTATUS +PbBiosPortToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +NTSTATUS +PbBiosMemoryToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +NTSTATUS +PbCmIrqToBiosDescriptor ( + IN PUCHAR BiosRequirements, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor, + OUT PUCHAR *BiosDescriptor, + OUT PULONG Length + ); + +NTSTATUS +PbCmDmaToBiosDescriptor ( + IN PUCHAR BiosRequirements, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor, + OUT PUCHAR *BiosDescriptor, + OUT PULONG Length + ); + +NTSTATUS +PbCmPortToBiosDescriptor ( + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor, + OUT PUCHAR *BiosDescriptor, + OUT PULONG Length + ); + +NTSTATUS +PbCmMemoryToBiosDescriptor ( + IN PUCHAR BiosRequirements, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor, + OUT PUCHAR *BiosDescriptor, + OUT PULONG Length + ); +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE,PbBiosResourcesToNtResources) +#pragma alloc_text(PAGE,PbIoDescriptorToCmDescriptor) +#pragma alloc_text(PAGE,PbAddDependentResourcesToList) +#pragma alloc_text(PAGE,PbBiosIrqToIoDescriptor) +#pragma alloc_text(PAGE,PbBiosDmaToIoDescriptor) +#pragma alloc_text(PAGE,PbBiosPortFixedToIoDescriptor) +#pragma alloc_text(PAGE,PbBiosPortToIoDescriptor) +#pragma alloc_text(PAGE,PbBiosMemoryToIoDescriptor) +#pragma alloc_text(PAGE,PbCmIrqToBiosDescriptor) +#pragma alloc_text(PAGE,PbCmDmaToBiosDescriptor) +#pragma alloc_text(PAGE,PbCmPortToBiosDescriptor) +#pragma alloc_text(PAGE,PbCmMemoryToBiosDescriptor) +#endif + +NTSTATUS +PbBiosResourcesToNtResources ( + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN OUT PUCHAR *BiosData, + IN UCHAR Format, + OUT PUCHAR *ReturnedList, + OUT PULONG ReturnedLength + ) + +/*++ + +Routine Description: + + This routine parses the Bios resource list and generates + a NT resource list. The returned Nt resource list could be either IO + format or CM format. It is caller's responsibility to release the + returned data buffer. + +Arguments: + + SlotNumber - specifies the slot number of the BIOS resource. + + BiosData - Supplies a pointer to a variable which specifies the bios resource + data buffer and which to receive the pointer to next bios resource data. + + Format - PB_CM_FORMAT (0) if convert bios resources to Cm format; + PB_IO_FORMAT (1) if convert bios resources to Io format. + + ReturnedList - supplies a variable to receive the desired resource list. + + ReturnedLength - Supplies a variable to receive the length of the resource list. + +Return Value: + + NTSTATUS code + +--*/ +{ + PUCHAR buffer; + USHORT mask16, increment; + UCHAR tagName, mask8; + NTSTATUS status; + PPB_ALTERNATIVE_INFORMATION alternativeList = NULL; + ULONG commonResCount = 0, dependDescCount = 0, i, j; + ULONG alternativeListCount = 0, dependFunctionCount = 0; + PIO_RESOURCE_DESCRIPTOR commonResources = NULL, commonIoDesc, dependIoDesc, ioDesc; + PPB_DEPENDENT_RESOURCES dependResList = NULL, dependResources; + BOOLEAN dependent = FALSE; + PCM_RESOURCE_LIST cmResourceList; + ULONG listSize, noResLists; + PUCHAR resourceList = NULL; + + // + // First, scan the bios data to determine the memory requirement and + // the information to build internal data structures. + // + + *ReturnedLength = 0; + alternativeListCount = 0; + buffer = *BiosData; + tagName = *buffer; + while (tagName != TAG_COMPLETE_END) { + + // + // Determine the size of the BIOS resource descriptor + // + + if (!(tagName & LARGE_RESOURCE_TAG)) { + increment = (USHORT)(tagName & SMALL_TAG_SIZE_MASK); + increment += 1; // length of small tag + tagName &= SMALL_TAG_MASK; + } else { + increment = *(PUSHORT)(buffer+1); + increment += 3; // length of large tag + } + + // + // Based on the type of the BIOS resource, determine the count of + // the IO descriptors. + // + + switch (tagName) { + case TAG_IRQ: + mask16 = ((PPNP_IRQ_DESCRIPTOR)buffer)->IrqMask; + i = 0; + while (mask16) { + if (mask16 & 1) { + i++; + } + mask16 >>= 1; + } + if (!dependent) { + commonResCount += i; + } else { + dependDescCount += i; + } + break; + case TAG_DMA: + mask8 = ((PPNP_DMA_DESCRIPTOR)buffer)->ChannelMask; + i = 0; + while (mask8) { + if (mask8 & 1) { + i++; + } + mask8 >>= 1; + } + if (!dependent) { + commonResCount += i; + } else { + dependDescCount += i; + } + break; + case TAG_START_DEPEND: + dependent = TRUE; + dependFunctionCount++; + break; + case TAG_END_DEPEND: + dependent = FALSE; + alternativeListCount++; + break; + case TAG_IO_FIXED: + case TAG_IO: + case TAG_MEMORY: + case TAG_MEMORY32: + case TAG_MEMORY32_FIXED: + if (!dependent) { + commonResCount++; + } else { + dependDescCount++; + } + break; + default: + + // + // Unknown tag. Skip it. + // + + DebugPrint((DEBUG_BREAK, "BiosToNtResources: unknown tag.\n")); + break; + } + + // + // Move to next bios resource descriptor. + // + + buffer += increment; + tagName = *buffer; + } + + // + // if empty bios resources, simply return. + // + + if (commonResCount == 0 && dependFunctionCount == 0) { + *ReturnedList = NULL; + *ReturnedLength = 0; + *BiosData = buffer + 2; + return STATUS_SUCCESS; + } + + // + // Allocate memory for our internal data structures + // + + if (dependFunctionCount) { + dependResources = (PPB_DEPENDENT_RESOURCES)ExAllocatePoolWithTag( + PagedPool, + dependFunctionCount * sizeof(PB_DEPENDENT_RESOURCES) + + dependDescCount * sizeof(IO_RESOURCE_DESCRIPTOR), + 'bPnP' + ); + if (!dependResources) { + return STATUS_INSUFFICIENT_RESOURCES; + } + dependResList = dependResources; // remember it so we can free it. + } + + if (alternativeListCount) { + ASSERT(dependFunctionCount != 0); + alternativeList = (PPB_ALTERNATIVE_INFORMATION)ExAllocatePoolWithTag( + PagedPool, + sizeof(PB_ALTERNATIVE_INFORMATION) * (alternativeListCount + 1), + 'bPnP' + ); + if (!alternativeList) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto exit0; + } + RtlZeroMemory(alternativeList, + sizeof(PB_ALTERNATIVE_INFORMATION) * alternativeListCount + ); + alternativeList[0].Resources = dependResources; + } + if (commonResCount) { + commonResources = (PIO_RESOURCE_DESCRIPTOR)ExAllocatePoolWithTag ( + PagedPool, + sizeof(IO_RESOURCE_DESCRIPTOR) * commonResCount, + 'bPnP' + ); + if (!commonResources) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto exit1; + } + } + + // + // Now start over again to process the bios data and initialize our internal + // resource representation. + // + + commonIoDesc = commonResources; + dependDescCount = 0; + alternativeListCount = 0; + buffer = *BiosData; + tagName = *buffer; + dependent = FALSE; + while (tagName != TAG_COMPLETE_END) { + if (!(tagName & LARGE_RESOURCE_TAG)) { + tagName &= SMALL_TAG_MASK; + } + switch (tagName) { + case TAG_IRQ: + if (dependent) { + ioDesc = dependIoDesc; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosIrqToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + case TAG_DMA: + if (dependent) { + ioDesc = dependIoDesc; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosDmaToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + case TAG_START_DEPEND: + dependent = TRUE; + alternativeList[alternativeListCount].NoDependentFunctions++; + if (dependDescCount != 0) { + + // + // End of current dependent function + // + + dependResources->Count = dependDescCount; + dependResources->Flags = 0; + dependResources->Next = (PPB_DEPENDENT_RESOURCES)dependIoDesc; + dependResources = dependResources->Next; + alternativeList[alternativeListCount].TotalResourceCount += dependDescCount; + } + if (*buffer & SMALL_TAG_SIZE_MASK) { + dependResources->Priority = *(buffer + 1); + } + dependDescCount = 0; + dependIoDesc = (PIO_RESOURCE_DESCRIPTOR)(dependResources + 1); + buffer += 1 + (*buffer & SMALL_TAG_SIZE_MASK); + break; + case TAG_END_DEPEND: + alternativeList[alternativeListCount].TotalResourceCount += dependDescCount; + dependResources->Count = dependDescCount; + dependResources->Flags = DEPENDENT_FLAGS_END; + dependResources->Next = alternativeList[alternativeListCount].Resources; + dependent = FALSE; + dependDescCount = 0; + alternativeListCount++; + alternativeList[alternativeListCount].Resources = (PPB_DEPENDENT_RESOURCES)dependIoDesc; + dependResources = alternativeList[alternativeListCount].Resources; + buffer++; + break; + case TAG_IO: + if (dependent) { + ioDesc = dependIoDesc; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosPortToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + case TAG_IO_FIXED: + if (dependent) { + ioDesc = dependIoDesc; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosPortFixedToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + case TAG_MEMORY: + case TAG_MEMORY32: + case TAG_MEMORY32_FIXED: + if (dependent) { + ioDesc = dependIoDesc; + dependDescCount; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosMemoryToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + default: + + // + // Don't-care tag simpley advance the buffer pointer to next tag. + // + + if (*buffer & LARGE_RESOURCE_TAG) { + increment = *(buffer+1); + increment += 3; // length of large tag + } else { + increment = (UCHAR)(*buffer) & SMALL_TAG_SIZE_MASK; + increment += 1; // length of small tag + } + buffer += increment; + } + tagName = *buffer; + } + + if (alternativeListCount != 0) { + alternativeList[alternativeListCount].Resources = NULL; // dummy alternativeList record + } + *BiosData = buffer + 2; // Skip END_TAG + + // + // prepare Cm/IoResourceList + // + + if (Format == PB_CM_FORMAT) { + listSize = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + (commonResCount - 1); + } else { + ULONG totalDescCount, descCount; + + noResLists = 1; + for (i = 0; i < alternativeListCount; i++) { + noResLists *= alternativeList[i].NoDependentFunctions; + } + totalDescCount = 0; + for (i = 0; i < alternativeListCount; i++) { + descCount = 1; + for (j = 0; j < alternativeListCount; j++) { + if (j == i) { + descCount *= alternativeList[j].TotalResourceCount; + } else { + descCount *= alternativeList[j].NoDependentFunctions; + } + } + totalDescCount += descCount; + } + listSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + + sizeof(IO_RESOURCE_LIST) * (noResLists - 1) + + sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescCount - + sizeof(IO_RESOURCE_DESCRIPTOR) * noResLists + + sizeof(IO_RESOURCE_DESCRIPTOR) * commonResCount * noResLists; + } + resourceList = ExAllocatePoolWithTag(PagedPool, listSize, 'bPnP'); + if (!resourceList) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto exit2; + } + if (Format == PB_CM_FORMAT) { + PCM_PARTIAL_RESOURCE_LIST partialResList; + PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDesc; + + cmResourceList = (PCM_RESOURCE_LIST)resourceList; + cmResourceList->Count = 1; + cmResourceList->List[0].InterfaceType = Internal; + cmResourceList->List[0].BusNumber = BusNumber; + partialResList = (PCM_PARTIAL_RESOURCE_LIST)&cmResourceList->List[0].PartialResourceList; + partialResList->Version = 0; + partialResList->Revision = 0; + partialResList->Count = commonResCount; + commonIoDesc = commonResources; + partialDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)&partialResList->PartialDescriptors[0]; + for (i = 0; i < commonResCount; i++) { + PbIoDescriptorToCmDescriptor(commonIoDesc, partialDesc); + partialDesc++; + commonIoDesc++; + } + } else { + PIO_RESOURCE_REQUIREMENTS_LIST ioResReqList; + PIO_RESOURCE_LIST ioResList; + + ioResReqList = (PIO_RESOURCE_REQUIREMENTS_LIST)resourceList; + ioResReqList->ListSize = listSize; + ioResReqList->InterfaceType = Internal; + ioResReqList->BusNumber = BusNumber; + ioResReqList->SlotNumber = SlotNumber; + ioResReqList->Reserved[0] = 0; + ioResReqList->Reserved[1] = 0; + ioResReqList->Reserved[2] = 0; + ioResReqList->AlternativeLists = noResLists; + ioResList = &ioResReqList->List[0]; + + // + // Build resource lists + // + + for (i = 0; i < noResLists; i++) { + ULONG size; + + ioResList->Version = 1; + ioResList->Revision = 1; + buffer = (PUCHAR)&ioResList->Descriptors[0]; + + // + // Copy common resources to the list + // + + if (commonResources) { + size = sizeof(IO_RESOURCE_DESCRIPTOR) * commonResCount; + RtlMoveMemory(buffer, commonResources, size); + buffer += size; + } + + // + // Copy dependent functions if any. + // + + if (alternativeList) { + PbAddDependentResourcesToList(&buffer, 0, alternativeList); + } + + // + // Update io resource list ptr + // + + ioResList->Count = ((ULONG)buffer - (ULONG)&ioResList->Descriptors[0]) / + sizeof(IO_RESOURCE_DESCRIPTOR); + ioResList = (PIO_RESOURCE_LIST)buffer; + } + } + *ReturnedLength = listSize; + status = STATUS_SUCCESS; + *ReturnedList = resourceList; +exit2: + if (commonResources) { + ExFreePool(commonResources); + } +exit1: + if (alternativeList) { + ExFreePool(alternativeList); + } +exit0: + if (dependResList) { + ExFreePool(dependResList); + } + return status; +} + +PPB_DEPENDENT_RESOURCES +PbAddDependentResourcesToList ( + IN OUT PUCHAR *ResourceDescriptor, + IN ULONG ListNo, + IN PPB_ALTERNATIVE_INFORMATION AlternativeList + ) + +/*++ + +Routine Description: + + This routine adds dependent functions to caller specified list. + +Arguments: + + ResourceDescriptor - supplies a pointer to the descriptor buffer. + + ListNo - supplies an index to the AlternativeList. + + AlternativeList - supplies a pointer to the alternativelist array. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + PPB_DEPENDENT_RESOURCES dependentResources, ptr; + ULONG size; + + // + // Copy dependent resources to caller supplied list buffer and + // update the list buffer pointer. + // + + dependentResources = AlternativeList[ListNo].Resources; + size = sizeof(IO_RESOURCE_DESCRIPTOR) * dependentResources->Count; + RtlMoveMemory(*ResourceDescriptor, dependentResources + 1, size); + *ResourceDescriptor = *ResourceDescriptor + size; + + // + // Add dependent resource of next list to caller's buffer + // + + if (AlternativeList[ListNo + 1].Resources) { + ptr = PbAddDependentResourcesToList(ResourceDescriptor, ListNo + 1, AlternativeList); + } else { + ptr = NULL; + } + if (ptr == NULL) { + AlternativeList[ListNo].Resources = dependentResources->Next; + if (!(dependentResources->Flags & DEPENDENT_FLAGS_END)) { + ptr = dependentResources->Next; + } + } + return ptr; +} + +VOID +PbIoDescriptorToCmDescriptor ( + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor + ) + +/*++ + +Routine Description: + + This routine translates IO_RESOURCE_DESCRIPTOR to CM_PARTIAL_RESOURCE_DESCRIPTOR. + +Arguments: + + IoDescriptor - Supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be converted. + + CmDescriptor - Supplies a pointer to the receiving CM_PARTIAL_RESOURCE_DESCRIPTOR. + +Return Value: + + None. + +--*/ +{ + CmDescriptor->Type = IoDescriptor->Type; + CmDescriptor->ShareDisposition = IoDescriptor->ShareDisposition; + CmDescriptor->Flags = IoDescriptor->Flags; + switch (CmDescriptor->Type) { + case CmResourceTypePort: + CmDescriptor->u.Port.Length = IoDescriptor->u.Port.Length; + CmDescriptor->u.Port.Start = IoDescriptor->u.Port.MinimumAddress; + break; + case CmResourceTypeInterrupt: + CmDescriptor->u.Interrupt.Level = + CmDescriptor->u.Interrupt.Vector = IoDescriptor->u.Interrupt.MinimumVector; + CmDescriptor->u.Interrupt.Affinity = (ULONG)-1; + break; + case CmResourceTypeMemory: + CmDescriptor->u.Memory.Length = IoDescriptor->u.Memory.Length; + CmDescriptor->u.Memory.Start = IoDescriptor->u.Memory.MinimumAddress; + break; + case CmResourceTypeDma: + CmDescriptor->u.Dma.Channel = IoDescriptor->u.Dma.MinimumChannel; + CmDescriptor->u.Dma.Port = 0; + CmDescriptor->u.Dma.Reserved1 = 0; + break; + } +} + +NTSTATUS +PbBiosIrqToIoDescriptor ( + IN OUT PUCHAR *BiosData, + PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS IRQ information to NT usable format. + This routine stops when an irq io resource is generated. if there are + more irq io resource descriptors available, the BiosData pointer will + not advance. So caller will pass us the same resource tag again. + + Note, BIOS DMA info alway uses SMALL TAG. A tag structure is repeated + for each seperated channel required. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + static ULONG bitPosition = 0; + USHORT mask; + ULONG irq; + PPNP_IRQ_DESCRIPTOR buffer; + UCHAR size, option; + NTSTATUS status = STATUS_SUCCESS; + + buffer = (PPNP_IRQ_DESCRIPTOR)*BiosData; + + // + // if this is not the first descriptor for the tag, set + // its option to alternative. + // + + if (bitPosition == 0) { + option = 0; + } else { + option = IO_RESOURCE_ALTERNATIVE; + } + size = buffer->Tag & SMALL_TAG_SIZE_MASK; + mask = buffer->IrqMask; + mask >>= bitPosition; + irq = (ULONG) -1; + + while (mask) { + if (mask & 1) { + irq = bitPosition; + break; + } + mask >>= 1; + bitPosition++; + } + + // + // Fill in Io resource descriptor + // + + if (irq != (ULONG)-1) { + IoDescriptor->Option = option; + IoDescriptor->Type = CmResourceTypeInterrupt; + IoDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; + IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + if (size == 3 && buffer->Information & 0x0C) { + IoDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + IoDescriptor->ShareDisposition = CmResourceShareShared; + } + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Interrupt.MinimumVector = irq; + IoDescriptor->u.Interrupt.MaximumVector = irq; + } else { + status = STATUS_INVALID_PARAMETER; + } + + if (NT_SUCCESS(status)) { + + // + // try to move bitPosition to next 1 bit. + // + + while (mask) { + mask >>= 1; + bitPosition++; + if (mask & 1) { + return status; + } + } + } + + // + // Done with current irq tag, advance pointer to next tag + // + + bitPosition = 0; + *BiosData = (PUCHAR)buffer + size + 1; + return status; +} + +NTSTATUS +PbBiosDmaToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS DMA information to NT usable format. + This routine stops when an dma io resource is generated. if there are + more dma io resource descriptors available, the BiosData pointer will + not advance. So caller will pass us the same resource tag again. + + Note, BIOS DMA info alway uses SMALL TAG. A tag structure is repeated + for each seperated channel required. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + static ULONG bitPosition = 0; + ULONG dma; + PPNP_DMA_DESCRIPTOR buffer; + UCHAR mask, option; + NTSTATUS status = STATUS_SUCCESS; + + buffer = (PPNP_DMA_DESCRIPTOR)*BiosData; + + // + // if this is not the first descriptor for the tag, set + // its option to alternative. + // + + if (bitPosition == 0) { + option = 0; + } else { + option = IO_RESOURCE_ALTERNATIVE; + } + mask = buffer->ChannelMask; + mask >>= bitPosition; + dma = (ULONG) -1; + + while (mask) { + if (mask & 1) { + dma = bitPosition; + break; + } + mask >>= 1; + bitPosition++; + } + + // + // Fill in Io resource descriptor + // + + if (dma != (ULONG)-1) { + IoDescriptor->Option = option; + IoDescriptor->Type = CmResourceTypeDma; + IoDescriptor->Flags = 0; + IoDescriptor->ShareDisposition = CmResourceShareUndetermined; + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Dma.MinimumChannel = dma; + IoDescriptor->u.Dma.MaximumChannel = dma; + } else { + status = STATUS_INVALID_PARAMETER; + } + + if (NT_SUCCESS(status)) { + + // + // try to move bitPosition to next 1 bit. + // + + while (mask) { + mask >>= 1; + bitPosition++; + if (mask & 1) { + return status; + } + } + } + + // + // Done with current dma tag, advance pointer to next tag + // + + bitPosition = 0; + buffer += 1; + *BiosData = (PUCHAR)buffer; + return status; +} + +NTSTATUS +PbBiosPortFixedToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS FIXED IO information to NT usable format. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + PPNP_FIXED_PORT_DESCRIPTOR buffer; + + buffer = (PPNP_FIXED_PORT_DESCRIPTOR)*BiosData; + + // + // Fill in Io resource descriptor + // + + IoDescriptor->Option = 0; + IoDescriptor->Type = CmResourceTypePort; + IoDescriptor->Flags = CM_RESOURCE_PORT_IO; + IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Port.Length = (ULONG)buffer->Length; + IoDescriptor->u.Port.MinimumAddress.LowPart = (ULONG)(buffer->MinimumAddress & 0x3ff); + IoDescriptor->u.Port.MinimumAddress.HighPart = 0; + IoDescriptor->u.Port.MaximumAddress.LowPart = IoDescriptor->u.Port.MinimumAddress.LowPart + + IoDescriptor->u.Port.Length - 1; + IoDescriptor->u.Port.MaximumAddress.HighPart = 0; + IoDescriptor->u.Port.Alignment = 1; + + // + // Done with current fixed port tag, advance pointer to next tag + // + + buffer += 1; + *BiosData = (PUCHAR)buffer; + return STATUS_SUCCESS; +} + +NTSTATUS +PbBiosPortToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS IO information to NT usable format. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + PPNP_PORT_DESCRIPTOR buffer; + + buffer = (PPNP_PORT_DESCRIPTOR)*BiosData; + + // + // Fill in Io resource descriptor + // + + IoDescriptor->Option = 0; + IoDescriptor->Type = CmResourceTypePort; + IoDescriptor->Flags = CM_RESOURCE_PORT_IO; + IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Port.Length = (ULONG)buffer->Length; + IoDescriptor->u.Port.MinimumAddress.LowPart = (ULONG)buffer->MinimumAddress; + IoDescriptor->u.Port.MinimumAddress.HighPart = 0; + IoDescriptor->u.Port.MaximumAddress.LowPart = (ULONG)buffer->MaximumAddress + + IoDescriptor->u.Port.Length - 1; + IoDescriptor->u.Port.MaximumAddress.HighPart = 0; + IoDescriptor->u.Port.Alignment = (ULONG)buffer->Alignment; + + // + // Done with current fixed port tag, advance pointer to next tag + // + + buffer += 1; + *BiosData = (PUCHAR)buffer; + return STATUS_SUCCESS; +} + +NTSTATUS +PbBiosMemoryToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS MEMORY information to NT usable format. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + PUCHAR buffer; + UCHAR tag; + PHYSICAL_ADDRESS minAddr, maxAddr; + ULONG alignment, length; + USHORT increment; + + buffer = *BiosData; + tag = ((PPNP_MEMORY_DESCRIPTOR)buffer)->Tag; + increment = ((PPNP_MEMORY_DESCRIPTOR)buffer)->Length + 3; // larg tag size = 3 + + minAddr.HighPart = 0; + maxAddr.HighPart = 0; + switch (tag) { + case TAG_MEMORY: + minAddr.LowPart = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)buffer)->MinimumAddress)) << 8; + if ((alignment = ((PPNP_MEMORY_DESCRIPTOR)buffer)->Alignment) == 0) { + alignment = 0x10000; + } + length = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)buffer)->MemorySize)) << 8; + maxAddr.LowPart = (((ULONG)(((PPNP_MEMORY_DESCRIPTOR)buffer)->MaximumAddress)) << 8) + length - 1; + break; + case TAG_MEMORY32: + length = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->MemorySize; + minAddr.LowPart = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->MinimumAddress; + maxAddr.LowPart = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->MaximumAddress + length - 1; + alignment = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->Alignment; + break; + case TAG_MEMORY32_FIXED: + length = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)buffer)->MemorySize; + minAddr.LowPart = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)buffer)->BaseAddress; + maxAddr.LowPart = minAddr.LowPart + length - 1; + alignment = 1; + break; + } + // + // Fill in Io resource descriptor + // + + IoDescriptor->Option = 0; + IoDescriptor->Type = CmResourceTypeMemory; + IoDescriptor->Flags = CM_RESOURCE_PORT_MEMORY; + IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Memory.MinimumAddress = minAddr; + IoDescriptor->u.Memory.MaximumAddress = maxAddr; + IoDescriptor->u.Memory.Alignment = alignment; + IoDescriptor->u.Memory.Length = length; + + // + // Done with current tag, advance pointer to next tag + // + + buffer += increment; + *BiosData = (PUCHAR)buffer; + return STATUS_SUCCESS; +} + +NTSTATUS +PbCmResourcesToBiosResources ( + IN PCM_RESOURCE_LIST CmResources, + IN PUCHAR BiosRequirements, + IN PUCHAR *BiosResources, + IN PULONG Length + ) + +/*++ + +Routine Description: + + This routine parses the Cm resource list and generates + a Pnp BIOS resource list. It is caller's responsibility to release the + returned data buffer. + +Arguments: + + CmResources - Supplies a pointer to a Cm resource list buffer. + + BiosRequirements - supplies a pointer to the PnP BIOS possible resources. + + BiosResources - Supplies a variable to receive the pointer to the + converted bios resource buffer. + + Length - supplies a pointer to a variable to receive the length + of the Pnp Bios resources. + +Return Value: + + a pointer to a Pnp Bios resource list if succeeded. Else, + a NULL pointer will be returned. + +--*/ +{ + PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDesc; + ULONG i, count, length, totalSize = 0; + PUCHAR p, biosDesc; + NTSTATUS status; + + count = CmResources->List[0].PartialResourceList.Count; + if (count == 0 || CmResources->Count != 1) { + return STATUS_INVALID_PARAMETER; + } + + // + // Allocate max amount of memory + // + + p= ExAllocatePoolWithTag(PagedPool, + count * sizeof(PNP_MEMORY_DESCRIPTOR), + 'bPnP'); + if (!p) { + return STATUS_INSUFFICIENT_RESOURCES; + } + cmDesc = CmResources->List[0].PartialResourceList.PartialDescriptors; + for (i = 0; i < count; i++) { + switch (cmDesc->Type) { + case CmResourceTypePort: + status = PbCmPortToBiosDescriptor ( + cmDesc, + &biosDesc, + &length + ); + break; + case CmResourceTypeInterrupt: + status = PbCmIrqToBiosDescriptor( + BiosRequirements, + cmDesc, + &biosDesc, + &length + ); + break; + case CmResourceTypeMemory: + status = PbCmMemoryToBiosDescriptor ( + BiosRequirements, + cmDesc, + &biosDesc, + &length + ); + break; + case CmResourceTypeDma: + status = PbCmDmaToBiosDescriptor ( + BiosRequirements, + cmDesc, + &biosDesc, + &length + ); + break; + case CmResourceTypeDeviceSpecific: + length = cmDesc->u.DeviceSpecificData.DataSize; + cmDesc++; + cmDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDesc + length); + continue; + } + if (NT_SUCCESS(status)) { + cmDesc++; + RtlMoveMemory(p, biosDesc, length); + ExFreePool(biosDesc); + p += length; + totalSize += length; + } else { + ExFreePool(p); + break; + } + } + if (NT_SUCCESS(status)) { + *p = TAG_COMPLETE_END; + p++; + *p = 0; // checksum ignored + totalSize += 2; + } + return status; +} + +NTSTATUS +PbCmIrqToBiosDescriptor ( + IN PUCHAR BiosRequirements, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor, + OUT PUCHAR *BiosDescriptor, + OUT PULONG Length + ) + +/*++ + +Routine Description: + + This routine translates CM IRQ information to Pnp BIOS format. + Since there is not enough information in the CM int descriptor to + convert it to Pnp BIOS descriptor. We will search the Bios + possible resource lists for the corresponding resource information. + +Arguments: + + BiosRequirements - Supplies a pointer to the bios possible resource lists. + + CmDescriptor - supplies a pointer to an CM_PARTIAL_RESOURCE_DESCRIPTOR buffer. + +Return Value: + + return a pointer to the desired dma descriptor in the BiosRequirements. Null + if not found. + +--*/ +{ + USHORT irqMask; + UCHAR tag; + PPNP_IRQ_DESCRIPTOR biosDesc; + PUCHAR returnDesc; + NTSTATUS status; + ULONG increment; + + if (!BiosRequirements) { + return STATUS_UNSUCCESSFUL; + } + status = STATUS_UNSUCCESSFUL; + if (!(CmDescriptor->u.Interrupt.Level & 0xfffffff0)) { + irqMask = 1 << CmDescriptor->u.Interrupt.Level; + tag = *BiosRequirements; + while (tag != TAG_COMPLETE_END) { + if ((tag & SMALL_TAG_MASK) == TAG_IRQ) { + biosDesc = (PPNP_IRQ_DESCRIPTOR)BiosRequirements; + if (biosDesc->IrqMask & irqMask) { + *Length = (biosDesc->Tag & SMALL_TAG_SIZE_MASK) + 1; + returnDesc = ExAllocatePoolWithTag(PagedPool, + *Length, + 'bPnP' ); + if (!returnDesc) { + return STATUS_INSUFFICIENT_RESOURCES; + } else { + RtlMoveMemory(returnDesc, BiosRequirements, *Length); + *BiosDescriptor = returnDesc; + status = STATUS_SUCCESS; + } + + break; + } + } + increment = (tag & SMALL_TAG_SIZE_MASK) + 1; + BiosRequirements += increment; + tag = *BiosRequirements; + } + } else { + status = STATUS_INVALID_PARAMETER; + } + return status; +} + +NTSTATUS +PbCmDmaToBiosDescriptor ( + IN PUCHAR BiosRequirements, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor, + OUT PUCHAR *BiosDescriptor, + OUT PULONG Length + ) + +/*++ + +Routine Description: + + This routine translates CM DMA information to Pnp BIOS format. + Since there is not enough information in the CM descriptor to + convert it to Pnp BIOS descriptor. We will search the Bios + possible resource lists for the corresponding resource information. + +Arguments: + + BiosRequirements - Supplies a pointer to the bios possible resource lists. + + CmDescriptor - supplies a pointer to an CM_PARTIAL_RESOURCE_DESCRIPTOR buffer. + +Return Value: + + return a pointer to the desired dma descriptor in the BiosRequirements. Null + if not found. + +--*/ +{ + NTSTATUS status; + UCHAR dmaMask, tag; + PPNP_DMA_DESCRIPTOR biosDesc; + PUCHAR returnDesc; + ULONG increment; + + if (!BiosRequirements) { + return STATUS_UNSUCCESSFUL; + } + status = STATUS_UNSUCCESSFUL; + if (!(CmDescriptor->u.Dma.Channel & 0xfffffff0)) { + dmaMask = 1 << CmDescriptor->u.Dma.Channel; + tag = *BiosRequirements; + while (tag != TAG_COMPLETE_END) { + if ((tag & SMALL_TAG_MASK) == TAG_DMA) { + biosDesc = (PPNP_DMA_DESCRIPTOR)BiosRequirements; + if (biosDesc->ChannelMask & dmaMask) { + *Length = (biosDesc->Tag & SMALL_TAG_SIZE_MASK) + 1; + returnDesc = ExAllocatePoolWithTag(PagedPool, + *Length, + 'bPnP' ); + if (!returnDesc) { + return STATUS_INSUFFICIENT_RESOURCES; + } else { + RtlMoveMemory(returnDesc, BiosRequirements, *Length); + *BiosDescriptor = returnDesc; + status = STATUS_SUCCESS; + } + break; + } + } + increment = (tag & SMALL_TAG_SIZE_MASK) + 1; + BiosRequirements += increment; + tag = *BiosRequirements; + } + } else { + status = STATUS_INVALID_PARAMETER; + } + return status; +} + +NTSTATUS +PbCmPortToBiosDescriptor ( + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor, + OUT PUCHAR *BiosDescriptor, + OUT PULONG Length + ) + +/*++ + +Routine Description: + + This routine translates CM PORT information to Pnp BIOS format. + Since there is not enough information in the CM descriptor to + convert it to Pnp BIOS full function port descriptor. We will + convert it to Pnp Bios fixed PORT descriptor. It is caller's + responsibility to release the returned data buffer. + +Arguments: + + CmDescriptor - supplies a pointer to an CM_PARTIAL_RESOURCE_DESCRIPTOR buffer. + + BiosDescriptor - supplies a variable to receive the buffer which contains + the desired Bios Port descriptor. + + Length - supplies a variable to receive the size the returned bios port + descriptor. + +Return Value: + + A NTSTATUS code. + +--*/ +{ + NTSTATUS status; + PPNP_PORT_DESCRIPTOR portDesc; + + if (CmDescriptor->u.Port.Start.HighPart != 0 || + CmDescriptor->u.Port.Start.LowPart & 0xffff0000 || + CmDescriptor->u.Port.Length & 0xffffff00) { + return STATUS_INVALID_PARAMETER; + } + portDesc = (PPNP_PORT_DESCRIPTOR) ExAllocatePoolWithTag( + PagedPool, sizeof(PNP_PORT_DESCRIPTOR), 'bPnP' ); + if (!portDesc) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Set the return port descriptor + // + + portDesc->Tag = TAG_IO | (sizeof(PNP_PORT_DESCRIPTOR) - 1); + portDesc->Information = 1; // 16 bit decoding + portDesc->Length = (UCHAR)CmDescriptor->u.Port.Length; + portDesc->Alignment = 0; // 1? + portDesc->MinimumAddress = (USHORT)CmDescriptor->u.Port.Start.LowPart; + portDesc->MaximumAddress = (USHORT)CmDescriptor->u.Port.Start.LowPart; + *BiosDescriptor = (PUCHAR)portDesc; + *Length = sizeof(PNP_PORT_DESCRIPTOR); + return STATUS_SUCCESS; +} + +NTSTATUS +PbCmMemoryToBiosDescriptor ( + IN PUCHAR BiosRequirements, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor, + OUT PUCHAR *BiosDescriptor, + OUT PULONG Length + ) + +/*++ + +Routine Description: + + This routine translates CM Memory information to Pnp BIOS format. + Since there is not enough information in the CM descriptor to + convert it to Pnp BIOS descriptor. We will search the Bios + possible resource lists for the corresponding resource information and + build a Pnp BIOS memory descriptor from there. It is caller's responsibility + to release the returned buffer. + +Arguments: + + BiosRequirements - Supplies a pointer to the bios possible resource lists. + + CmDescriptor - supplies a pointer to an CM_PARTIAL_RESOURCE_DESCRIPTOR buffer. + + BiosDescriptor - supplies a variable to receive the buffer which contains + the desired Bios Port descriptor. + + Length - supplies a variable to receive the size the returned bios port + descriptor. + +Return Value: + + A NTSTATUS code. + +--*/ +{ + UCHAR tag, information; + PPNP_FIXED_MEMORY32_DESCRIPTOR memoryDesc; + ULONG address, size, length, minAddr, maxAddr, alignment; + USHORT increment; + + // + // Search the possible resource list to get the information + // for the memory range described by CmDescriptor. + // + + address = CmDescriptor->u.Memory.Start.LowPart; + size = CmDescriptor->u.Memory.Length; + + tag = *BiosRequirements; + while (tag != TAG_COMPLETE_END) { + switch (tag) { + case TAG_MEMORY: + minAddr = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MinimumAddress)) << 8; + if ((alignment = ((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->Alignment) == 0) { + alignment = 0x10000; + } + length = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MemorySize)) << 8; + maxAddr = (((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MaximumAddress)) << 8) + + length - 1; + break; + case TAG_MEMORY32: + length = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MemorySize; + minAddr = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MinimumAddress; + maxAddr = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MaximumAddress + + length - 1; + alignment = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->Alignment; + break; + case TAG_MEMORY32_FIXED: + length = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)BiosRequirements)->MemorySize; + minAddr = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)BiosRequirements)->BaseAddress; + maxAddr = minAddr + length - 1; + alignment = 1; + break; + } + + if (minAddr <= address && maxAddr >= (address + size - 1)) { + information = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->Information; + break; + } + + // + // Advance to next tag + // + + if (tag & LARGE_RESOURCE_TAG) { + increment = *(PUSHORT)(BiosRequirements + 1); + increment += 3; // length of large tag + } else { + increment = tag & SMALL_TAG_SIZE_MASK; + increment += 1; // length of small tag + } + BiosRequirements += increment; + tag = *BiosRequirements; + } + if (tag == TAG_COMPLETE_END) { + return STATUS_UNSUCCESSFUL; + } + + // + // Set up Pnp BIOS memory descriptor + // + + memoryDesc = (PPNP_FIXED_MEMORY32_DESCRIPTOR) ExAllocatePoolWithTag( + PagedPool, sizeof(PNP_FIXED_MEMORY32_DESCRIPTOR), 'bPnP' ); + if (!memoryDesc) { + return STATUS_INSUFFICIENT_RESOURCES; + } else { + memoryDesc->Tag = TAG_MEMORY32_FIXED; + memoryDesc->Length = sizeof (PNP_FIXED_MEMORY32_DESCRIPTOR); + memoryDesc->Information = information; + memoryDesc->BaseAddress = address; + memoryDesc->MemorySize = size; + *BiosDescriptor = (PUCHAR)memoryDesc; + *Length = sizeof(PNP_FIXED_MEMORY32_DESCRIPTOR); + return STATUS_SUCCESS; + } +} + diff --git a/private/ntos/nthals/extender/pnpbios/i386/pbios.h b/private/ntos/nthals/extender/pnpbios/i386/pbios.h new file mode 100644 index 000000000..b400da35a --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/i386/pbios.h @@ -0,0 +1,241 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pbiosp.h + +Abstract: + + PnP BIOS/ISA configuration data definitions + +Author: + + Shie-Lin Tzong (shielint) April 12, 1995 + +Revision History: + +--*/ + +#include "nthal.h" +#include "hal.h" + +// +// Constants +// + +#define SMALL_RESOURCE_TAG (UCHAR)(0x00) +#define LARGE_RESOURCE_TAG (UCHAR)(0x80) +#define SMALL_TAG_MASK 0xf8 +#define SMALL_TAG_SIZE_MASK 7 + +// +// Small Resouce Tags with length bits stripped off +// + +#define TAG_VERSION 0x08 +#define TAG_LOGICAL_ID 0x10 +#define TAG_COMPATIBLE_ID 0x18 +#define TAG_IRQ 0x20 +#define TAG_DMA 0x28 +#define TAG_START_DEPEND 0x30 +#define TAG_END_DEPEND 0x38 +#define TAG_IO 0x40 +#define TAG_IO_FIXED 0x48 +#define TAG_VENDOR 0x70 +#define TAG_END 0x78 + +// +// Large Resouce Tags +// + +#define TAG_MEMORY 0x81 +#define TAG_ANSI_ID 0x82 +#define TAG_UNICODE_ID 0x83 +#define TAG_LVENDOR 0x84 +#define TAG_MEMORY32 0x85 +#define TAG_MEMORY32_FIXED 0x86 + +// +// Complete TAG if applicable. +// + +#define TAG_COMPLETE_COMPATIBLE_ID 0x1C +#define TAG_COMPLETE_END 0x79 + +#include "pshpack1.h" + +// +// PNP ISA Port descriptor definition +// + +typedef struct _PNP_PORT_DESCRIPTOR_ { + UCHAR Tag; // 01000111B, small item name = 08, length = 7 + UCHAR Information; // bit [0] = 1 device decodes full 16 bit addr + // = 0 device decodes ISA addr bits[9-0] + USHORT MinimumAddress; + USHORT MaximumAddress; + UCHAR Alignment; // Increment in 1 byte blocks + UCHAR Length; // # contiguous Port requested +} PNP_PORT_DESCRIPTOR, *PPNP_PORT_DESCRIPTOR; + +// +// PNP ISA fixed Port descriptor definition +// + +typedef struct _PNP_FIXED_PORT_DESCRIPTOR_ { + UCHAR Tag; // 01001011B, small item name = 09, length = 3 + USHORT MinimumAddress; + UCHAR Length; // # contiguous Port requested +} PNP_FIXED_PORT_DESCRIPTOR, *PPNP_FIXED_PORT_DESCRIPTOR; + +// +// PNP ISA IRQ descriptor definition +// + +typedef struct _PNP_IRQ_DESCRIPTOR_ { + UCHAR Tag; // 0010001XB small item name = 4 length = 2/3 + USHORT IrqMask; // bit 0 is irq 0 + UCHAR Information; // Optional +} PNP_IRQ_DESCRIPTOR, *PPNP_IRQ_DESCRIPTOR; + +// +// Masks for PNP_IRQ_DESCRIPTOR Information byte +// + +#define PNP_IRQ_LEVEL_MASK 0xC +#define PNP_IRQ_EDGE_MASK 0x3 + +// +// PNP ISA DMA descriptor definition +// + +typedef struct _PNP_DMA_DESCRIPTOR_ { + UCHAR Tag; // 00101010B, small item name = 05, length = 2 + UCHAR ChannelMask; // bit 0 is channel 0 + UCHAR Flags; // see spec +} PNP_DMA_DESCRIPTOR, *PPNP_DMA_DESCRIPTOR; + +// +// PNP ISA MEMORY descriptor +// + +typedef struct _PNP_MEMORY_DESCRIPTOR_ { + UCHAR Tag; // 10000001B, Large item name = 1 + USHORT Length; // Length of the descriptor = 9 + UCHAR Information; // See def below + USHORT MinimumAddress; // address bit [8-23] + USHORT MaximumAddress; // address bit [8-23] + USHORT Alignment; // 0x0000 = 64KB + USHORT MemorySize; // In 256 byte blocks +} PNP_MEMORY_DESCRIPTOR, *PPNP_MEMORY_DESCRIPTOR; + +// +// PNP ISA MEMORY32 descriptor +// + +typedef struct _PNP_MEMORY32_DESCRIPTOR_ { + UCHAR Tag; // 10000101B, Large item name = 5 + USHORT Length; // Length of the descriptor = 17 + UCHAR Information; // See def below + ULONG MinimumAddress; // 32 bit addr + ULONG MaximumAddress; // 32 bit addr + ULONG Alignment; // 32 bit alignment + ULONG MemorySize; // 32 bit length +} PNP_MEMORY32_DESCRIPTOR, *PPNP_MEMORY32_DESCRIPTOR; + +// +// PNP ISA FIXED MEMORY32 descriptor +// + +typedef struct _PNP_FIXED_MEMORY32_DESCRIPTOR_ { + UCHAR Tag; // 10000110B, Large item name = 6 + USHORT Length; // Length of the descriptor = 9 + UCHAR Information; // See def below + ULONG BaseAddress; // 32 bit addr + ULONG MemorySize; // 32 bit length +} PNP_FIXED_MEMORY32_DESCRIPTOR, *PPNP_FIXED_MEMORY32_DESCRIPTOR; + +#define PNP_MEMORY_ROM_MASK 0x40 +#define PNP_MEMORY_SHADOWABLE_MASK 0x20 +#define PNP_MEMORY_CONTROL_MASK 0x18 + #define PNP_MEMORY_CONTROL_8BIT 00 + #define PNP_MEMORY_CONTROL_16BIT 01 + #define PNP_MEMORY_CONTROL_8AND16BIT 02 + #define PNP_MEMORY_CONTROL_32BIT 03 +#define PNP_MEMORY_SUPPORT_TYPE_MASK 04 +#define PNP_MEMORY_CACHE_SUPPORT_MASK 02 +#define PNP_MEMORY_WRITE_STATUS_MASK 01 + +#define UNKNOWN_DOCKING_IDENTIFIER 0xffffffff +#define UNABLE_TO_DETERMINE_DOCK_CAPABILITIES 0x89 +#define FUNCTION_NOT_SUPPORTED 0x82 +#define SYSTEM_NOT_DOCKED 0x87 + +// +// Pnp BIOS device node structure +// + +typedef struct _PNP_BIOS_DEVICE_NODE { + USHORT Size; + UCHAR Node; + ULONG ProductId; + UCHAR DeviceType[3]; + USHORT DeviceAttributes; + // followed by AllocatedResourceBlock, PossibleResourceBlock + // and CompatibleDeviceId +} PNP_BIOS_DEVICE_NODE, *PPNP_BIOS_DEVICE_NODE; + +// +// DeviceType definition +// + +#define BASE_TYPE_DOCKING_STATION 0xA + +// +// Device attributes definitions +// + +#define DEVICE_DOCKING 0x20 +#define DEVICE_REMOVABLE 0x40 + +// +// Pnp BIOS Installation check +// + +typedef struct _PNP_BIOS_INSTALLATION_CHECK { + UCHAR Signature[4]; // $PnP (ascii) + UCHAR Revision; + UCHAR Length; + USHORT ControlField; + UCHAR Checksum; + ULONG EventFlagAddress; // Physical address + USHORT RealModeEntryOffset; + USHORT RealModeEntrySegment; + USHORT ProtectedModeEntryOffset; + ULONG ProtectedModeCodeBaseAddress; + ULONG OemDeviceId; + USHORT RealModeDataBaseAddress; + ULONG ProtectedModeDataBaseAddress; +} PNP_BIOS_INSTALLATION_CHECK, *PPNP_BIOS_INSTALLATION_CHECK; + +#include "poppack.h" + +// +// Pnp BIOS ControlField masks +// + +#define PNP_BIOS_CONTROL_MASK 0x3 +#define PNP_BIOS_EVENT_NOT_SUPPORTED 0 +#define PNP_BIOS_EVENT_POLLING 1 +#define PNP_BIOS_EVENT_ASYNC 2 + +// +// Pnp Bios event +// + +#define ABOUT_TO_CHANGE_CONFIG 1 +#define DOCK_CHANGED 2 +#define SYSTEM_DEVICE_CHANGED 3 +#define CONFIG_CHANGE_FAILED 4 diff --git a/private/ntos/nthals/extender/pnpbios/i386/pbiosa.asm b/private/ntos/nthals/extender/pnpbios/i386/pbiosa.asm new file mode 100644 index 000000000..4d7857f14 --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/i386/pbiosa.asm @@ -0,0 +1,89 @@ + title "Pnp Bios Bus Extender ASM support routines" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; Biosa.asm +; +; Abstract: +; +; This file contains Pnp Bios Bus Extender ASM support routines. +; +; Author: +; +; Shie-Lin Tzong (shielint) Apr 16, 1995 +; +; Environment: +; +; Kernel mode only. +; +; Revision History: +; +;-- + +.386p +.xlist +include callconv.inc ; calling convention macros +.list + + EXTRNP _RtlMoveMemory, 3 + EXTRNP _KeI386Call16BitCStyleFunction, 4 + +_TEXT SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + +;++ +; +; VOID +; PbCallPnpBiosWorker ( +; IN ULONG EntryOffset, +; IN ULONG EntrySelector, +; IN PUSHORT Parameters, +; IN ULONG ParameterSize +; ); +; +; Routine Description: +; +; This routines copies the specified parameters to stack and invokes +; Pnp Bios Entry point. +; +; Arguments: +; +; EntryOffset and EntrySelector - supplies the entry point of the bios function. +; +; Parameters - Supplies a pointer to argument block. +; +; ParameterSize - Size of the argument block +; +; Return Value: +; +; Registers/context contains the register values returned from pnp bios. +; +;-- + +EntryOffset equ [ebp + 8] +EntrySelector equ [ebp + 12] +Parameters equ [ebp + 16] +ParameterSize equ [ebp + 20] + +cPublicProc _PbCallPnpBiosWorker, 4 + + push ebp + mov ebp, esp + sub esp, ParameterSize + mov eax, esp + + stdCall _RtlMoveMemory, + + stdCall _KeI386Call16BitCStyleFunction, + + mov esp, ebp + pop ebp + stdRET _PbCallPnpBiosWorker + +stdENDP _PbCallPnpBiosWorker + +_TEXT ends + end diff --git a/private/ntos/nthals/extender/pnpbios/i386/pbiosc.c b/private/ntos/nthals/extender/pnpbios/i386/pbiosc.c new file mode 100644 index 000000000..0afce8e4b --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/i386/pbiosc.c @@ -0,0 +1,773 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pbiosc.c + +Abstract: + + This module contains Pnp BIOS dependent routines. It includes code to initialize + 16 bit GDT selectors and to call pnp bios api. + +Author: + + Shie-Lin Tzong (shielint) 26-Apr-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "busp.h" + +WCHAR rgzMultiFunctionAdapter[] = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter"; +WCHAR rgzConfigurationData[] = L"Configuration Data"; +WCHAR rgzIdentifier[] = L"Identifier"; +WCHAR rgzBIOSIdentifier[] = L"PNP BIOS"; + +// +// PbBiosKeyInformation points to the registry data information +// which includes key value full information and data. +// + +PVOID PbBiosKeyInformation; + +// +// PbBiosRegistryData points to the pnp bios data +// + +PPNP_BIOS_INSTALLATION_CHECK PbBiosRegistryData; + +// +// PbBiosCodeSelector contains the selector of the PNP +// BIOS code. +// + +USHORT PbBiosCodeSelector; + +// +// PbBiosDataSelector contains the selector of the PNP +// BIOS data area (F0000-FFFFF) +// + +USHORT PbBiosDataSelector; + +// +// PbSelectors[] contains general purpose preallocated selectors +// + +USHORT PbSelectors[2]; + +// +// PbBiosEventAddress contains the virtual address of the PNP +// BIOS Event Flag. +// + +PUCHAR PbBiosEventAddress; + +// +// PbBiosEntryPoint contains the Pnp Bios entry offset +// + +ULONG PbBiosEntryPoint; + +// +// PbDockConnectorRegistered +// + +BOOLEAN PbDockConnectorRegistered; + +// +// SpinLock to serialize Pnp Bios call +// + +KSPIN_LOCK PbBiosSpinlock; + +// +// 16 bit protected mode event message address +// + +USHORT PbEventMessageOffset; +USHORT PbEventMessageSelector; +USHORT PbBiosEventMessage; + +// +// External References +// + +extern +USHORT +PbCallPnpBiosWorker ( + IN ULONG EntryOffset, + IN ULONG EntrySelector, + IN PUSHORT Parameters, + IN USHORT Size + ); + +extern +BOOLEAN +RtlEqualUnicodeString( + IN PUNICODE_STRING String1, + IN PUNICODE_STRING String2, + IN BOOLEAN CaseInSensitive + ); + +extern +NTSTATUS +KeI386AllocateGdtSelectors( + OUT PUSHORT SelectorArray, + IN USHORT NumberOfSelectors + ); + +extern +NTSTATUS +KeI386SetGdtSelector ( + IN ULONG Selector, + IN PKGDTENTRY GdtValue + ); + +VOID +PbTimerRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PVOID Context + ); + +// +// Internal prototypes +// + +VOID +PbAddress32ToAddress16 ( + IN PVOID Address32, + IN PUSHORT Address16, + IN USHORT Selector + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,PbInitialize) +#pragma alloc_text(PAGE,PbAddress32ToAddress16) +#endif + +NTSTATUS +PbInitialize ( + ULONG Phase, + PDEVICE_OBJECT DeviceObject + ) + +/*++ + +Routine Description: + + At phase 0, this routine checks registry for the data collected by + ntdetect.com to make sure PnP Bios is present and initializes the + internal data structures for pnp bios bus extender. + + Phase 0 init is called only once at DriverEntry. Phase 1 is called + whenever a new bus is registered. If phase 1 is called for bus number + 1 (i.e. docking station bus), a timer will be start to poll Pnp Bios + event if necessary. + + Note, only Bus 0 (mother board devices) and bus 1 (docking station devices) + are supported. + +Arguments: + + Phase - supplies a number to indicate the phase of the initialization. + + DeviceObject - a pointer to the bus extender device object. At phase 0, + it is NULL. + +Return Value: + + A NTSTATUS code to indicate the result of the initialization. + +--*/ +{ + KGDTENTRY gdtEntry; + UNICODE_STRING unicodeString, unicodeValueName, biosId; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE hMFunc, hBus; + WCHAR wbuffer[10]; + ULONG codeBase, i, length; + PWSTR p; + PKEY_VALUE_FULL_INFORMATION valueInfo; + PCM_FULL_RESOURCE_DESCRIPTOR desc; + PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDesc; + NTSTATUS status; + BOOLEAN same; + USHORT selectors[4]; + PHYSICAL_ADDRESS physicalAddr; + PVOID virtualAddr; + PB_PARAMETERS biosParameters; + USHORT pnpControl; + + if (Phase == 1) { + if (((PMB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->BusHandler->BusNumber == + MbpBusNumber[0]) { + if (PbBiosEventAddress) { + + // + // First disable pnp bios default event timeout + // + + biosParameters.Function = PNP_BIOS_SEND_MESSAGE; + biosParameters.u.SendMessage.Message = PNP_OS_ACTIVE; + status = PbHardwareService(&biosParameters); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE, "PnpBios: Disable Event timeout failed\n")); + return STATUS_UNSUCCESSFUL; + } + + // + // Create timer to poll for PNP BIOS events. + // + + IoInitializeTimer (DeviceObject, PbTimerRoutine, NULL); + IoStartTimer (DeviceObject); + } + } + return STATUS_SUCCESS; + } + + // + // Look in the registery for the "PNP BIOS bus" data + // + + RtlInitUnicodeString (&unicodeString, rgzMultiFunctionAdapter); + InitializeObjectAttributes (&objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + NULL, // handle + NULL); + + + status = ZwOpenKey (&hMFunc, KEY_READ, &objectAttributes); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE, "PnpBIos:Can not open MultifunctionAdapter registry key.\n")); + return status; + } + + unicodeString.Buffer = wbuffer; + unicodeString.MaximumLength = sizeof(wbuffer); + RtlInitUnicodeString(&biosId, rgzBIOSIdentifier); + + for (i = 0; TRUE; i++) { + RtlIntegerToUnicodeString (i, 10, &unicodeString); + InitializeObjectAttributes ( + &objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + hMFunc, + NULL); + + status = ZwOpenKey (&hBus, KEY_READ, &objectAttributes); + if (!NT_SUCCESS(status)) { + + // + // Out of Multifunction adapter entries... + // + + DebugPrint((DEBUG_MESSAGE, "PnpBIos: Pnp BIOS MultifunctionAdapter registry key not found.\n")); + ZwClose (hMFunc); + return STATUS_UNSUCCESSFUL; + } + + // + // Check the Indentifier to see if this is a Pnp BIOS entry + // + + status = PbGetRegistryValue (hBus, rgzIdentifier, &valueInfo); + if (!NT_SUCCESS (status)) { + ZwClose (hBus); + continue; + } + + p = (PWSTR) ((PUCHAR) valueInfo + valueInfo->DataOffset); + unicodeValueName.Buffer = p; + unicodeValueName.MaximumLength = (USHORT)valueInfo->DataLength; + length = valueInfo->DataLength; + + // + // Determine the real length of the ID string + // + + while (length) { + if (p[length / sizeof(WCHAR) - 1] == UNICODE_NULL) { + length -= 2; + } else { + break; + } + } + unicodeValueName.Length = (USHORT)length; + same = RtlEqualUnicodeString(&biosId, &unicodeValueName, TRUE); + ExFreePool(valueInfo); + if (!same) { + ZwClose (hBus); + continue; + } + + status = PbGetRegistryValue(hBus, rgzConfigurationData, &valueInfo); + ZwClose (hBus); + if (!NT_SUCCESS(status)) { + continue ; + } + + desc = (PCM_FULL_RESOURCE_DESCRIPTOR) ((PUCHAR) + valueInfo + valueInfo->DataOffset); + partialDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR) + desc->PartialResourceList.PartialDescriptors); + + if (partialDesc->Type == CmResourceTypeDeviceSpecific) { + + // + // got it.. Perform sanity check + // + + PbBiosRegistryData = (PPNP_BIOS_INSTALLATION_CHECK) (partialDesc+1); + if (PbBiosRegistryData->Signature[0] == '$'&& + PbBiosRegistryData->Signature[1] == 'P'&& + PbBiosRegistryData->Signature[2] == 'n'&& + PbBiosRegistryData->Signature[3] == 'P') { + PbBiosKeyInformation = (PVOID)valueInfo; + ZwClose (hMFunc); + break; + } + } + ExFreePool(valueInfo); + } + + // + // We find the Pnp BIOS data stored by ntdetect.com. Initialize Pnp BIOS + // get/set event if supported. + // + + pnpControl = PbBiosRegistryData->ControlField & PNP_BIOS_CONTROL_MASK; + if ((pnpControl & PNP_BIOS_CONTROL_MASK) != PNP_BIOS_EVENT_NOT_SUPPORTED) { + if ((pnpControl & PNP_BIOS_CONTROL_MASK) == PNP_BIOS_EVENT_POLLING) { + + // + // Pnp BIOS event notification is supported thru polling. We need + // to map event address to non paged pool virtual address. + // + + physicalAddr.LowPart = PbBiosRegistryData->EventFlagAddress; + physicalAddr.HighPart = 0; + virtualAddr = MmMapIoSpace (physicalAddr, 1, FALSE); + PbBiosEventAddress = (PUCHAR)virtualAddr; + } else if ((pnpControl & PNP_BIOS_CONTROL_MASK) == PNP_BIOS_EVENT_ASYNC) { + + // + // Add code here + // + } + + // + // Create eject callback object to notify dock/undock events + // + + RtlInitUnicodeString(&unicodeString, L"\\Callback\\PnpBiosEvent"); + + InitializeObjectAttributes( + &objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + status = ExCreateCallback (&MbpEjectCallbackObject, &objectAttributes, TRUE, TRUE); + if (!NT_SUCCESS(status)) { + return status; + } + + } + + // + // Allocate 4 or 5 selectors for calling PnP Bios Apis. + // If event notification is supported thru polling, we set up an selector for the event + // addr (16 bit.). Because the GET EVENT call is made from DPC level and we can not + // call kernel routine to set selector at DPC level. + // + + if (PbBiosEventAddress) { + i = 5; + } else { + i = 4; + } + status = KeI386AllocateGdtSelectors (selectors, (USHORT) i); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE, "PnpBios: Failed to allocate selectors\n")); + ExFreePool(valueInfo); + return status; + } + + PbBiosCodeSelector = selectors[0]; + PbBiosDataSelector = selectors[1]; + PbSelectors[0] = selectors[2]; + PbSelectors[1] = selectors[3]; + + PbBiosEntryPoint = (ULONG)PbBiosRegistryData->ProtectedModeEntryOffset; + + // + // Initialize selectors to use PNP bios code + // + + // + // initialize 16 bit code selector + // + + gdtEntry.LimitLow = 0xFFFF; + gdtEntry.HighWord.Bytes.Flags1 = 0; + gdtEntry.HighWord.Bytes.Flags2 = 0; + gdtEntry.HighWord.Bits.Pres = 1; + gdtEntry.HighWord.Bits.Dpl = DPL_SYSTEM; + gdtEntry.HighWord.Bits.Granularity = GRAN_BYTE; + gdtEntry.HighWord.Bits.Type = 31; + gdtEntry.HighWord.Bits.Default_Big = 0; + physicalAddr.LowPart = PbBiosRegistryData->ProtectedModeCodeBaseAddress; + virtualAddr = MmMapIoSpace (physicalAddr, 0x10000, TRUE); + codeBase = (ULONG)virtualAddr; + gdtEntry.BaseLow = (USHORT) (codeBase & 0xffff); + gdtEntry.HighWord.Bits.BaseMid = (UCHAR) (codeBase >> 16) & 0xff; + gdtEntry.HighWord.Bits.BaseHi = (UCHAR) (codeBase >> 24) & 0xff; + KeI386SetGdtSelector (PbBiosCodeSelector, &gdtEntry); + + // + // initialize 16 bit data selector for Pnp BIOS + // + + gdtEntry.LimitLow = 0xFFFF; + gdtEntry.HighWord.Bytes.Flags1 = 0; + gdtEntry.HighWord.Bytes.Flags2 = 0; + gdtEntry.HighWord.Bits.Pres = 1; + gdtEntry.HighWord.Bits.Dpl = DPL_SYSTEM; + gdtEntry.HighWord.Bits.Granularity = GRAN_BYTE; + gdtEntry.HighWord.Bits.Type = 19; + gdtEntry.HighWord.Bits.Default_Big = 1; + physicalAddr.LowPart = PbBiosRegistryData->ProtectedModeDataBaseAddress; + virtualAddr = MmMapIoSpace (physicalAddr, 0x10000, TRUE); + codeBase = (ULONG)virtualAddr; + gdtEntry.BaseLow = (USHORT) (codeBase & 0xffff); + gdtEntry.HighWord.Bits.BaseMid = (UCHAR) (codeBase >> 16) & 0xff; + gdtEntry.HighWord.Bits.BaseHi = (UCHAR) (codeBase >> 24) & 0xff; + KeI386SetGdtSelector (PbBiosDataSelector, &gdtEntry); + + // + // initialize selecot part of message address for calling BIOS + // + + if (PbBiosEventAddress) { + PbEventMessageSelector = selectors[4]; + PbEventMessageOffset = 0; + + gdtEntry.LimitLow = 0x3; // 1? + gdtEntry.HighWord.Bytes.Flags1 = 0; + gdtEntry.HighWord.Bytes.Flags2 = 0; + gdtEntry.HighWord.Bits.Pres = 1; + gdtEntry.HighWord.Bits.Dpl = DPL_SYSTEM; + gdtEntry.HighWord.Bits.Granularity = GRAN_BYTE; + gdtEntry.HighWord.Bits.Type = 19; + gdtEntry.HighWord.Bits.Default_Big = 1; + codeBase = (ULONG)&PbBiosEventMessage; + gdtEntry.BaseLow = (USHORT) (codeBase & 0xffff); + gdtEntry.HighWord.Bits.BaseMid = (UCHAR) (codeBase >> 16) & 0xff; + gdtEntry.HighWord.Bits.BaseHi = (UCHAR) (codeBase >> 24) & 0xff; + KeI386SetGdtSelector (PbEventMessageSelector, &gdtEntry); + } + + + // + // Initialize the other two general purpose data selector such that + // on subsequent init we only need to init the base addr. + // + + KeI386SetGdtSelector (PbSelectors[0], &gdtEntry); + KeI386SetGdtSelector (PbSelectors[1], &gdtEntry); + + // + // Initialize BIOS call spinlock + // + + KeInitializeSpinLock (&PbBiosSpinlock); + + // + // Get maximum pnp bios slot data size + // + + biosParameters.Function = PNP_BIOS_GET_NUMBER_DEVICE_NODES; + biosParameters.u.GetNumberDeviceNodes.NumberNodes = (PUSHORT)&i; + biosParameters.u.GetNumberDeviceNodes.NodeSize = (PUSHORT) &MbpMaxDeviceData; + status = PbHardwareService(&biosParameters); + + return STATUS_SUCCESS; +} + +NTSTATUS +PbHardwareService ( + IN PPB_PARAMETERS Parameters + ) + +/*++ + +Routine Description: + + This routine sets up stack parameters and calls an + assembly worker routine to actually invoke the PNP BIOS code. + +Arguments: + + Parameters - supplies a pointer to the parameter block. + +Return Value: + + An NTSTATUS code to indicate the result of the operation. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + USHORT stackParameters[PB_MAXIMUM_STACK_SIZE / 2]; + ULONG i = 0; + USHORT retCode; + KIRQL oldIrql; + + // + // Convert and copy the caller's parameters to the format that + // will be used to invoked pnp bios. + // + + stackParameters[i] = Parameters->Function; + i++; + + switch (Parameters->Function) { + case PNP_BIOS_GET_NUMBER_DEVICE_NODES: + PbAddress32ToAddress16(Parameters->u.GetNumberDeviceNodes.NumberNodes, + &stackParameters[i], + PbSelectors[0]); + i += 2; + PbAddress32ToAddress16(Parameters->u.GetNumberDeviceNodes.NodeSize, + &stackParameters[i], + PbSelectors[1]); + i += 2; + stackParameters[i++] = PbBiosDataSelector; + break; + case PNP_BIOS_GET_DEVICE_NODE: + PbAddress32ToAddress16(Parameters->u.GetDeviceNode.Node, + &stackParameters[i], + PbSelectors[0]); + i += 2; + PbAddress32ToAddress16(Parameters->u.GetDeviceNode.NodeBuffer, + &stackParameters[i], + PbSelectors[1]); + i += 2; + stackParameters[i++] = Parameters->u.GetDeviceNode.Control; + stackParameters[i++] = PbBiosDataSelector; + break; + case PNP_BIOS_SET_DEVICE_NODE: + stackParameters[i++] = Parameters->u.SetDeviceNode.Node; + PbAddress32ToAddress16(Parameters->u.SetDeviceNode.NodeBuffer, + &stackParameters[i], + PbSelectors[0]); + i += 2; + stackParameters[i++] = Parameters->u.SetDeviceNode.Control; + stackParameters[i++] = PbBiosDataSelector; + break; + case PNP_BIOS_GET_EVENT: + stackParameters[i++] = PbEventMessageOffset; + stackParameters[i++] = PbEventMessageSelector; + stackParameters[i++] = PbBiosDataSelector; + break; + case PNP_BIOS_SEND_MESSAGE: + stackParameters[i++] = Parameters->u.SendMessage.Message; + stackParameters[i++] = PbBiosDataSelector; + break; + case PNP_BIOS_GET_DOCK_INFORMATION: + PbAddress32ToAddress16(Parameters->u.GetDockInfo.DockingStationInfo, + &stackParameters[i], + PbSelectors[0]); + i += 2; + stackParameters[i++] = PbBiosDataSelector; + break; + default: + return STATUS_NOT_IMPLEMENTED; + + } + + // + // Copy the parameters to stack and invoke Pnp Bios. + // + + KeAcquireSpinLock (&PbBiosSpinlock, &oldIrql); + + retCode = PbCallPnpBiosWorker ( + PbBiosEntryPoint, + PbBiosCodeSelector, + stackParameters, + (USHORT)(i * sizeof(USHORT))); + + KeReleaseSpinLock (&PbBiosSpinlock, oldIrql); + + // + // Special handling for Get Docking station information. We need to + // return the docking state (i.e. the returned code.) + // + + if (Parameters->Function == PNP_BIOS_GET_DOCK_INFORMATION) { + *(Parameters->u.GetDockInfo.DockState) = 0; + if (retCode == SYSTEM_NOT_DOCKED) { + *(Parameters->u.GetDockInfo.DockState) = retCode; + retCode = 0; + } else if (retCode == UNABLE_TO_DETERMINE_DOCK_CAPABILITIES) { + Parameters->u.GetDockInfo.DockingStationInfo->Capabilities = (USHORT) -1; + retCode = 0; + } + } + + // + // Map Bios returned code to nt status code. + // + + if (retCode == 0) { + return STATUS_SUCCESS; + } else { + DebugPrint((DEBUG_BREAK, "PnpBios: Bios API call failed.\n")); + return STATUS_UNSUCCESSFUL; + } +} + +VOID +PbAddress32ToAddress16 ( + IN PVOID Address32, + IN PUSHORT Address16, + IN USHORT Selector + ) + +/*++ + +Routine Description: + + This routine converts the 32 bit address to 16 bit selector:offset address + and stored in user specified location. + +Arguments: + + Address32 - the 32 bit address to be converted. + + Address16 - supplies the location to receive the 16 bit sel:offset address + + Selector - the 16 bit selector for seg:offset address + +Return Value: + + None. + +--*/ +{ + KGDTENTRY gdtEntry; + ULONG baseAddr; + + // + // Map virtual address to selector:0 address + // + + gdtEntry.LimitLow = 0xFFFF; + gdtEntry.HighWord.Bytes.Flags1 = 0; + gdtEntry.HighWord.Bytes.Flags2 = 0; + gdtEntry.HighWord.Bits.Pres = 1; + gdtEntry.HighWord.Bits.Dpl = DPL_SYSTEM; + gdtEntry.HighWord.Bits.Granularity = GRAN_BYTE; + gdtEntry.HighWord.Bits.Type = 19; + gdtEntry.HighWord.Bits.Default_Big = 1; + baseAddr = (ULONG)Address32; + gdtEntry.BaseLow = (USHORT) (baseAddr & 0xffff); + gdtEntry.HighWord.Bits.BaseMid = (UCHAR) (baseAddr >> 16) & 0xff; + gdtEntry.HighWord.Bits.BaseHi = (UCHAR) (baseAddr >> 24) & 0xff; + KeI386SetGdtSelector (Selector, &gdtEntry); + *Address16 = 0; + *(Address16 + 1) = Selector; +} + +VOID +PbTimerRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PVOID Context + ) +{ + PB_PARAMETERS biosParameters; + NTSTATUS status; + USHORT junk; + + // + // Check for Pnp BIOS event + // + + if (*PbBiosEventAddress & 1) { + + // + // Get Pnp BIOS event. + // + + biosParameters.Function = PNP_BIOS_GET_EVENT; + biosParameters.u.GetEvent.Message = &PbBiosEventMessage; + status = PbHardwareService(&biosParameters); + if (!NT_SUCCESS(status)) { + return; + } + + // + // Process the event ... + // + + switch (PbBiosEventMessage) { + case ABOUT_TO_CHANGE_CONFIG: + DebugPrint((DEBUG_MESSAGE, "PnpBios:Configuration about to change ...\n")); + if (MbpConfigAboutToChange()) { + biosParameters.Function = PNP_BIOS_SEND_MESSAGE; + biosParameters.u.SendMessage.Message = OK_TO_CHANGE_CONFIG; + PbHardwareService(&biosParameters); + } + break; + + case DOCK_CHANGED: + case SYSTEM_DEVICE_CHANGED: + + // + // For dock, undock and system device changes, we invalidate cached + // pnp bios data and notify enumerator to reenumerate the devices. + // + + DebugPrint((DEBUG_MESSAGE, "PnpBios:Configuration changed\n")); + if (PbBiosKeyInformation) { + PbBiosKeyInformation = NULL; + PbBiosRegistryData = NULL; + ExFreePool(PbBiosKeyInformation); + } + + // + // Invalidate maximum slot data information after configuration changed. + // + + MbpMaxDeviceData = 0; + + MbpConfigChanged(); + break; + + case CONFIG_CHANGE_FAILED: + + // + // do nothing. + // BUGBUG - We should define someway to notify the dock/undock + // failed. So, user can be notified. + // + + break; + default: + break; + } + } +} diff --git a/private/ntos/nthals/extender/pnpbios/i386/resource.c b/private/ntos/nthals/extender/pnpbios/i386/resource.c new file mode 100644 index 000000000..daad0c72c --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/i386/resource.c @@ -0,0 +1,367 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + devres.c + +Abstract: + + This module contains the high level device resources support routines. + +Author: + + Shie-Lin Tzong (shielint) Apr-25-1995 + Adapted from Pci bus extender. + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "busp.h" + +#pragma alloc_text(PAGE,MbCtlQueryDeviceId) +#pragma alloc_text(PAGE,MbCtlQueryDeviceUniqueId) +#pragma alloc_text(PAGE,MbCtlQueryDeviceResources) +#pragma alloc_text(PAGE,MbCtlQueryDeviceResourceRequirements) +#pragma alloc_text(PAGE,MbCtlSetDeviceResources) + +VOID +MbCtlQueryDeviceUniqueId ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function returns the unique id for the particular device. + +Arguments: + + DeviceData - Device data information for the specificied device. + + Context - Device control context of the request. + +Return Value: + + The device control is completed + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PWCHAR deviceId; + ULONG idNumber; + PMB_BUS_EXTENSION busExtension; + + PAGED_CODE(); + + // + // Set up device's unique id. + // + + deviceId = (PWCHAR) Context->DeviceControl.Buffer; + + // + // If the device is a docking station, we return its docking station + // serial number. Else its device id/slot number is returned as the + // unique id. + // + + if (DeviceData->Flags & DEVICE_FLAGS_DOCKING_STATION) { + busExtension = (PMB_BUS_EXTENSION)Context->Handler->BusData; + idNumber = busExtension->DockingStationSerialNumber; + } else { + idNumber = DeviceDataSlot(DeviceData); + } + swprintf (deviceId, L"%04x", idNumber); + +#if DBG + { + ANSI_STRING ansiString; + UNICODE_STRING unicodeString; + + RtlInitUnicodeString(&unicodeString, (PWCHAR)Context->DeviceControl.Buffer); + RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE); + DbgPrint("Bus %x Slot %x Unique Id = %s\n", + Context->Handler->BusNumber, + DeviceDataSlot(DeviceData), + ansiString.Buffer + ); + RtlFreeAnsiString(&ansiString); + } +#endif + + MbpCompleteDeviceControl (STATUS_SUCCESS, Context, DeviceData); +} + +VOID +MbCtlQueryDeviceId ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function returns the device id for the particular device. + +Arguments: + + DeviceData - Device data information for the specificied device. + + Context - Device control context of the request. + +Return Value: + + The device control is completed + +--*/ +{ + NTSTATUS status; + PWCHAR deviceId; + ULONG idIndex; + + PAGED_CODE(); + + // + // Determine which device ID the caller wants back + // + + idIndex = *((PULONG) Context->DeviceControl.Buffer); + + // + // Call worker routine to get the desired Id. + // + + deviceId = (PWCHAR) Context->DeviceControl.Buffer; + status = MbpGetCompatibleDeviceId(DeviceData->BusData, + idIndex, + (PWCHAR) deviceId); + +#if DBG + if (NT_SUCCESS(status)) { + ANSI_STRING ansiString; + UNICODE_STRING unicodeString; + + RtlInitUnicodeString(&unicodeString, deviceId); + RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE); + DbgPrint("Bus %x Slot %x IdIndex %x Compatible Id = %s\n", + Context->Handler->BusNumber, + DeviceDataSlot(DeviceData), + idIndex, + ansiString.Buffer + ); + RtlFreeAnsiString(&ansiString); + } +#endif + + MbpCompleteDeviceControl (status, Context, DeviceData); +} + +VOID +MbCtlQueryDeviceResources ( + 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 - Device data information for the specificied slot + + Context - Device control context of the request + +Return Value: + + The device control is completed + +--*/ +{ + ULONG length; + PCM_RESOURCE_LIST cmResources; + NTSTATUS status; + + PAGED_CODE(); + + status = MbpGetSlotResources(Context->RootHandler->BusNumber, + DeviceData->BusData, + &cmResources, + &length); + + // + // Return results + // + + if (NT_SUCCESS(status)) { + if (length == 0) { + + // + // If resource info is not available, return an empty CM_RESOURCE_LIST + // + + cmResources = (PCM_RESOURCE_LIST) ExAllocatePoolWithTag ( + PagedPool, sizeof(CM_RESOURCE_LIST), 'bPnP'); + if (!cmResources) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto exitLocal; + } else { + cmResources->Count = 0; + cmResources->List[0].InterfaceType = Context->RootHandler->InterfaceType; + cmResources->List[0].BusNumber = Context->RootHandler->BusNumber; + cmResources->List[0].PartialResourceList.Version = 0; + cmResources->List[0].PartialResourceList.Revision = 0; + cmResources->List[0].PartialResourceList.Count = 0; + length = sizeof(CM_RESOURCE_LIST); + } + } + if (length > *Context->DeviceControl.BufferLength) { + status = STATUS_BUFFER_TOO_SMALL; + } else { + RtlCopyMemory (Context->DeviceControl.Buffer, cmResources, length); + } + *Context->DeviceControl.BufferLength = length; +#if DBG + if (NT_SUCCESS(status)) { + MbpDumpCmResourceList(cmResources, DeviceDataSlot(DeviceData)); + } +#endif + ExFreePool(cmResources); + } +exitLocal: + MbpCompleteDeviceControl (status, Context, DeviceData); +} + +VOID +MbCtlQueryDeviceResourceRequirements ( + 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 - Device data information for the specificied slot + + Context - Device control context of the request + +Return Value: + + The device control is completed + +--*/ +{ + ULONG length; + PIO_RESOURCE_REQUIREMENTS_LIST ioResources; + NTSTATUS status; + + PAGED_CODE(); + + status = MbpGetSlotResourceRequirements(Context->RootHandler->BusNumber, + DeviceData->BusData, + &ioResources, + &length); + + // + // Return results + // + + if (NT_SUCCESS(status)) { + if (length == 0) { + + // + // If resource info is not available, return an empty CM_RESOURCE_LIST + // + + ioResources = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePoolWithTag ( + PagedPool, sizeof(IO_RESOURCE_REQUIREMENTS_LIST), 'bPnP'); + if (!ioResources) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto exitLocal; + } else { + ioResources->ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); + ioResources->InterfaceType = Context->RootHandler->InterfaceType; + ioResources->BusNumber = Context->RootHandler->BusNumber; + ioResources->SlotNumber = DeviceDataSlot(DeviceData); + ioResources->Reserved[0] = 0; + ioResources->Reserved[1] = 0; + ioResources->Reserved[2] = 0; + ioResources->AlternativeLists = 0; + ioResources->List[0].Version = 1; + ioResources->List[0].Revision = 1; + ioResources->List[0].Count = 0; + length = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); + } + } + if (length > *Context->DeviceControl.BufferLength) { + status = STATUS_BUFFER_TOO_SMALL; + } else { + RtlCopyMemory (Context->DeviceControl.Buffer, ioResources, length); + } + *Context->DeviceControl.BufferLength = length; +#if DBG + if (NT_SUCCESS(status)) { + MbpDumpIoResourceList(ioResources); + } +#endif + ExFreePool(ioResources); + } +exitLocal: + MbpCompleteDeviceControl (status, Context, DeviceData); +} + +VOID +MbCtlSetDeviceResources ( + 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 - Device data information for the specificied slot + + Context - Device control context of the request + +Return Value: + + The device control is completed + +--*/ +{ + NTSTATUS status; + + PAGED_CODE(); + + // + // Get the resource requirements list for the device + // + + status = MbpSetSlotResources ( + &DeviceData->BusData, + (PCM_RESOURCE_LIST) Context->DeviceControl.Buffer, + *Context->DeviceControl.BufferLength + ); + MbpCompleteDeviceControl (status, Context, DeviceData); +} diff --git a/private/ntos/nthals/extender/pnpbios/makefile b/private/ntos/nthals/extender/pnpbios/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/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/pnpbios/pnpbios.rc b/private/ntos/nthals/extender/pnpbios/pnpbios.rc new file mode 100644 index 000000000..5a305dd63 --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/pnpbios.rc @@ -0,0 +1,11 @@ +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "PNP BIOS Extension Driver" +#define VER_INTERNALNAME_STR "pnpbios.sys" +#define VER_ORIGINALFILENAME_STR "pnpbios.sys" + +#include "common.ver" diff --git a/private/ntos/nthals/extender/pnpbios/sources b/private/ntos/nthals/extender/pnpbios/sources new file mode 100644 index 000000000..85413d9ed --- /dev/null +++ b/private/ntos/nthals/extender/pnpbios/sources @@ -0,0 +1,49 @@ +!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=extender + +TARGETNAME=pnpbios +TARGETPATH=$(BASEDIR)\public\sdk\lib +TARGETTYPE=DRIVER + +INCLUDES=..\..\..\inc + +SOURCES= + +i386_SOURCES=pnpbios.rc \ + i386\bus.c \ + i386\data.c \ + i386\init.c \ + i386\control.c \ + i386\resource.c \ + i386\busdata.c \ + i386\pbcnvrt.c \ + i386\pbiosa.asm \ + i386\pbiosc.c \ + i386\misc.c +NTTEST= +OPTIONAL_NTTEST= +UMTEST= diff --git a/private/ntos/nthals/extender/pnpisa.sur/bus.c b/private/ntos/nthals/extender/pnpisa.sur/bus.c new file mode 100644 index 000000000..24955bbf3 --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa.sur/bus.c @@ -0,0 +1,962 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + bus.c + +Abstract: + + +Author: + + Shie-Lin Tzong (shielint) July-26-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "busp.h" +#include "pnpisa.h" + +// +// Internal references +// + +BOOLEAN +PipIsDeviceInstanceInstalled( + IN HANDLE Handle, + IN PUNICODE_STRING DeviceInstanceName + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,PipCheckBus) +#pragma alloc_text(INIT,PipCheckDevices) +#pragma alloc_text(INIT,PipDeleteCards) +#pragma alloc_text(INIT,PipIsDeviceInstanceInstalled) +#endif + + +VOID +PipCheckBus ( + IN PPI_BUS_EXTENSION BusExtension + ) + +/*++ + +Routine Description: + + The function enumerates the bus specified by BusExtension + +Arguments: + + BusExtension - supplies a pointer to the BusExtension structure of the bus + to be enumerated. + +Return Value: + + None. + +--*/ +{ + NTSTATUS status; + ULONG objectSize, noDevices; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE handle; + PUCHAR cardData; + ULONG dataLength; + USHORT csn, i, detectedCsn = 0; + PDEVICE_INFORMATION deviceInfo; + PCARD_INFORMATION cardInfo; + UCHAR tmp; + PSINGLE_LIST_ENTRY link; + + // + // Perform Pnp isolation process. This will assign card select number for each + // Pnp Isa card isolated by the system. All the isolated cards will be put into + // wait-for-key state. + // + + PipIsolateCards(&BusExtension->NumberCSNs); + + // + // send initiation key to put cards into sleep state + // + + PipLFSRInitiation (); + + // + // For each card selected build CardInformation and DeviceInformation structures. + // + + for (csn = 1; csn <= BusExtension->NumberCSNs; csn++) { + + status = PipReadCardResourceData ( + csn, + &noDevices, + &cardData, + &dataLength); + if (!NT_SUCCESS(status)) { + continue; + } + + detectedCsn++; + + // + // Allocate and initialize card information and its associate device + // information structures. + // + + cardInfo = (PCARD_INFORMATION)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(CARD_INFORMATION), + 'iPnP'); + if (!cardInfo) { + ExFreePool(cardData); + DebugPrint((DEBUG_MESSAGE, "PnpIsaCheckBus: failed to allocate CARD_INFO structure\n")); + continue; + } + + // + // Initialize card information structure + // + + RtlZeroMemory(cardInfo, sizeof(CARD_INFORMATION)); + cardInfo->CardSelectNumber = csn; + cardInfo->NumberLogicalDevices = noDevices; + cardInfo->CardData = cardData; + cardInfo->CardDataLength = dataLength; + + PushEntryList (&BusExtension->CardList, + &cardInfo->CardList + ); + DebugPrint ((DEBUG_MESSAGE, "PnpIsaCheckBus: adding one pnp card %x\n")); + + // + // For each logical device supported by the card build its DEVICE_INFORMATION + // structures. + // + + cardData += sizeof(SERIAL_IDENTIFIER); + dataLength -= sizeof(SERIAL_IDENTIFIER); + PipFindNextLogicalDeviceTag(&cardData, &dataLength); + for (i = 0; i < noDevices; i++) { // logical device number starts from 0 + + // + // Create and initialize device tracking structure (Device_Information.) + // + + deviceInfo = (PDEVICE_INFORMATION) ExAllocatePoolWithTag( + NonPagedPool, + sizeof(DEVICE_INFORMATION), + 'iPnP'); + if (!deviceInfo) { + DebugPrint((DEBUG_MESSAGE, "PnpIsa:failed to allocate DEVICEINFO structure\n")); + continue; + } + + deviceInfo->CardInformation = cardInfo; + deviceInfo->LogicalDeviceNumber = i; + deviceInfo->DeviceData = cardData; + deviceInfo->DeviceDataLength = PipFindNextLogicalDeviceTag(&cardData, &dataLength); + + // + // Add it to the logical device list of the pnp isa card. + // + + PushEntryList (&cardInfo->LogicalDeviceList, + &deviceInfo->LogicalDeviceList + ); + + // + // Add it to the list of devices for this bus + // + + BusExtension->NoValidSlots += 1; + PushEntryList (&BusExtension->DeviceList, + &deviceInfo->DeviceList + ); + + // + // Select the logical device, disable its io range check + // (Card is not enabled yet.) + // + + PipWriteAddress(LOGICAL_DEVICE_PORT); + PipWriteData(i); + PipWriteAddress(IO_RANGE_CHECK_PORT); + tmp = PipReadData(); + tmp &= ~2; + PipWriteAddress(IO_RANGE_CHECK_PORT); + PipWriteData(tmp); + } + } + + // + // Finaly put all cards into wait for key state. + // + + PipWriteAddress(CONFIG_CONTROL_PORT); + PipWriteData(CONTROL_WAIT_FOR_KEY); + BusExtension->NumberCSNs = detectedCsn; +} + +VOID +PipCheckDevices ( + PUNICODE_STRING RegistryPath, + PPI_BUS_EXTENSION BusExtension + ) + +/*++ + +Routine Description: + + The function goes through every pnp device and check if it is *installed*, + if yes, the device will be enabled. Otherwise, we create a device instance + key for the device and leave the device disabled. + +Arguments: + + RegistryPath - Supplies a pointer to the registry path passed to the driver + entry. + + BusExtension - supplies a pointer to the pnp isa bus extension structure. + +Return Value: + + None. + +--*/ +{ + NTSTATUS status; + PCARD_INFORMATION cardInfo; + PDEVICE_INFORMATION deviceInfo; + PSINGLE_LIST_ENTRY cardLink, deviceLink; + PWCHAR cardId, deviceId, uniqueId, compatibleId, ids; + WCHAR buffer[128]; + ULONG disposition, tmpValue, length, cardIdLength; + UNICODE_STRING unicodeDeviceId, unicodeUniqueId, unicodeBusId; + UNICODE_STRING unicodeDeviceInstance, unicodeString; + HANDLE handle, busIdHandle, deviceIdHandle, uniqueIdHandle, logConfHandle; + PKEY_VALUE_FULL_INFORMATION keyValueInformation; + PCM_RESOURCE_LIST cmResource; + PIO_RESOURCE_REQUIREMENTS_LIST ioResource; + UNICODE_STRING madeupInstancePath; + HANDLE madeupKeyHandle; + + // + // If there is no PnpISA card, we are done. + // Oterwise, open HKLM\System\CCS\ENUM\PNPISA. + // + + if (BusExtension->NumberCSNs == 0) { + return; + } + + RtlInitUnicodeString( + &unicodeString, + L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM"); + status = PipOpenRegistryKey(&handle, + NULL, + &unicodeString, + KEY_ALL_ACCESS, + FALSE + ); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE, "PnPIsa: Unable to open HKLM\\SYSTEM\\CCS\\ENUM")); + return; + } + + // + // Open/Create PNPISA key under HKLM\CCS\System\Enum + // + + RtlInitUnicodeString(&unicodeBusId, L"ISAPNP"); + status = PipOpenRegistryKeyPersist(&busIdHandle, + handle, + &unicodeBusId, + KEY_ALL_ACCESS, + TRUE, + &disposition + ); + ZwClose(handle); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE, "PnPIsa: Unable to open ENUM\\PNPISA")); + return; + } + + // + // Since this driver always return failure, Pnp manager will clean up the + // madeup key for this driver. If we detect any pnp isa card and create + // IsaPnP key. We need to keep the madeup key by deleting its *NewlyCreated* + // value entry. + // + + status = PipServiceInstanceToDeviceInstance ( + RegistryPath, + 0, + &madeupInstancePath, + &madeupKeyHandle, + KEY_ALL_ACCESS + ); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE, "PnPIsa: Unable to open madeup key")); + return; + } + RtlInitUnicodeString(&unicodeString, L"Control"); + status = PipOpenRegistryKey(&handle, + madeupKeyHandle, + &unicodeString, + KEY_ALL_ACCESS, + FALSE + ); + if (NT_SUCCESS(status)) { + RtlInitUnicodeString(&unicodeString, L"*NewlyCreated*"); + ZwDeleteValueKey(handle, &unicodeString); + ZwClose(handle); + } + + // + // Go through the card link list to process each of its logical device. + // + + for (cardLink = BusExtension->CardList.Next; cardLink; cardLink = cardLink->Next) { + cardInfo = CONTAINING_RECORD (cardLink, CARD_INFORMATION, CardList); + + PipGetCardIdentifier((PUCHAR)cardInfo->CardData + NUMBER_CARD_ID_BYTES, + &cardId, + &cardIdLength); + + // + // For each logical device of the card, check if device instance key installed + // if yes, we will configure the resource and turn on the device. Otherwise + // we create a device instance key and store possible configuration and leave + // the device disabled. + // + + for (deviceLink = cardInfo->LogicalDeviceList.Next; deviceLink; deviceLink = deviceLink->Next) { + deviceInfo = CONTAINING_RECORD (deviceLink, + DEVICE_INFORMATION, + LogicalDeviceList); + + // + // First, get the device id this will be the device key name + // + + status = PipQueryDeviceId(deviceInfo, &deviceId, 0); + if (!NT_SUCCESS(status)) { + continue; + } else { + + // + // Open/create this registry path under HKLM\CCS\System\Enum\PnPIsa + // + + RtlInitUnicodeString( + &unicodeDeviceId, + deviceId + (unicodeBusId.Length / sizeof(WCHAR)) + 1 ); + status = PipOpenRegistryKeyPersist(&deviceIdHandle, + busIdHandle, + &unicodeDeviceId, + KEY_ALL_ACCESS, + TRUE, + &disposition + ); + if (!NT_SUCCESS(status)) { + ExFreePool(deviceId); + continue; + } + + // + // Query the unique id for the device + // + + status = PipQueryDeviceUniqueId(deviceInfo, &uniqueId); + if (!NT_SUCCESS(status)) { + ZwClose(deviceIdHandle); + ExFreePool(deviceId); + continue; + } + + // + // Open/create this registry device instance path under + // HKLM\System\Enum\IsaPnp\deviceId + // + + RtlInitUnicodeString(&unicodeUniqueId, uniqueId); + status = PipOpenRegistryKeyPersist(&uniqueIdHandle, + deviceIdHandle, + &unicodeUniqueId, + KEY_ALL_ACCESS, + TRUE, + &disposition + ); + ZwClose(deviceIdHandle); + if (!NT_SUCCESS(status)) { + ExFreePool(deviceId); + ExFreePool(uniqueId); + continue; + } + + RtlInitUnicodeString(&unicodeString, L"FoundAtEnum"); + tmpValue = 1; + ZwSetValueKey(uniqueIdHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_DWORD, + &tmpValue, + sizeof(tmpValue) + ); + + RtlInitUnicodeString(&unicodeString, L"LogConf"); + status = PipOpenRegistryKeyPersist(&logConfHandle, + uniqueIdHandle, + &unicodeString, + KEY_ALL_ACCESS, + TRUE, + &tmpValue + ); + if (!NT_SUCCESS(status)) { + logConfHandle = NULL; // just to make sure + } + + swprintf(buffer, L"%s\\%s", deviceId, uniqueId); + RtlInitUnicodeString(&unicodeDeviceInstance, buffer); + + if (disposition == REG_CREATED_NEW_KEY) { + + // + // Create all the default value entry for the newly created key. + // DeviceDesc = Card Identifier string + // BaseDevicePath = PNPISA a default parent + // Configuration = REG_RESOURCE_LIST + // ConfigurationVector = REG_RESOUCE_REQUIREMENTS_LIST + // HardwareID = MULTI_SZ + // CompatibleIDs = MULTI_SZ + // ConfigFlags = REG_DWORD CONFIGFLAG_REINSTALL + // Status = REG_DWORD DN_HAS_PROBLEM + // Problem = REG_DWORD CM_PROB_REINSTALL + // Create "Control" volatile subkey. + // + + RtlInitUnicodeString(&unicodeString, L"Control"); + PipOpenRegistryKey(&handle, + uniqueIdHandle, + &unicodeString, + KEY_ALL_ACCESS, + TRUE + ); + if (NT_SUCCESS(status)) { + ZwClose(handle); + } + + if (cardId) { + RtlInitUnicodeString(&unicodeString, L"DeviceDesc"); + ZwSetValueKey(uniqueIdHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_SZ, + cardId, + cardIdLength + ); + } + + RtlInitUnicodeString(&unicodeString, L"BaseDevicePath"); + ZwSetValueKey(uniqueIdHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_SZ, + madeupInstancePath.Buffer, + madeupInstancePath.Length + sizeof(UNICODE_NULL) + ); + + RtlInitUnicodeString(&unicodeString, L"ConfigFlags"); + tmpValue = CONFIGFLAG_REINSTALL; + ZwSetValueKey(uniqueIdHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_DWORD, + &tmpValue, + sizeof(tmpValue) + ); + + RtlInitUnicodeString(&unicodeString, L"Problem"); + tmpValue = CM_PROB_REINSTALL; + ZwSetValueKey(uniqueIdHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_DWORD, + &tmpValue, + sizeof(tmpValue) + ); + + RtlInitUnicodeString(&unicodeString, L"StatusFlags"); + tmpValue = DN_HAS_PROBLEM; + ZwSetValueKey(uniqueIdHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_DWORD, + &tmpValue, + sizeof(tmpValue) + ); + + if (logConfHandle) { + status = PipQueryDeviceResources ( + deviceInfo, + 0, // BusNumber + &cmResource, + &length + ); + + if (NT_SUCCESS(status) && cmResource) { + RtlInitUnicodeString(&unicodeString, L"BootConfig"); + ZwSetValueKey( + logConfHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_RESOURCE_LIST, + cmResource, + length + ); + ExFreePool(cmResource); + } + + status = PipQueryDeviceResourceRequirements ( + deviceInfo, + 0, // Bus Number + 0, // Slot number?? + &ioResource, + &length + ); + if (NT_SUCCESS(status) && ioResource) { + RtlInitUnicodeString(&unicodeString, L"BasicConfigVector"); + ZwSetValueKey(logConfHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_RESOURCE_REQUIREMENTS_LIST, + ioResource, + length + ); + ExFreePool(ioResource); + } + } + + status = PipGetCompatibleDeviceId(deviceInfo->DeviceData, 0, &compatibleId); + if (NT_SUCCESS(status) && compatibleId) { + + // + // create HardwareId value name. Even though it is a MULTI_SZ, + // we know there is only one HardwareId for PnpIsa. + // + + length = wcslen(compatibleId) * sizeof(WCHAR) + 2 * sizeof(WCHAR); + ids = (PWCHAR)ExAllocatePool(PagedPool, length); + if (ids) { + RtlMoveMemory(ids, compatibleId, length - 2 *sizeof(WCHAR)); + ids[length / sizeof(WCHAR) - 1] = UNICODE_NULL; + ids[length / sizeof(WCHAR) - 2] = UNICODE_NULL; + RtlInitUnicodeString(&unicodeString, L"HardwareID"); + ZwSetValueKey(uniqueIdHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_MULTI_SZ, + ids, + length + ); + ExFreePool(ids); + } + ExFreePool(compatibleId); + } + + ids = (PWCHAR)ExAllocatePool(PagedPool, 0x1000); + if (ids) { + PWCHAR p1; + ULONG i; + + p1 = ids; + length = 0; + for (i = 1; TRUE; i++) { + status = PipGetCompatibleDeviceId( + deviceInfo->DeviceData, + i, + &compatibleId); + if (NT_SUCCESS(status) && compatibleId) { + if ((length + wcslen(compatibleId) * sizeof(WCHAR) + 2 * sizeof(WCHAR)) + <= 0x1000) { + RtlMoveMemory(p1, compatibleId, wcslen(compatibleId) * sizeof(WCHAR)); + p1 += wcslen(compatibleId); + *p1 = UNICODE_NULL; + p1++; + length += wcslen(compatibleId) * sizeof(WCHAR) + sizeof(WCHAR); + ExFreePool(compatibleId); + } else { + ExFreePool(compatibleId); + break; + } + } else { + break; + } + } + *p1 = UNICODE_NULL; + length += sizeof(WCHAR); + RtlInitUnicodeString(&unicodeString, L"CompatibleIDs"); + ZwSetValueKey(uniqueIdHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_MULTI_SZ, + ids, + length + ); + ExFreePool(ids); + } + + // + // Add this device instance key to ENUM\PNPISA AttachedComponents + // value entry. + // + + PipRemoveStringFromValueKey( + madeupKeyHandle, + L"AttachedComponents", + &unicodeDeviceInstance + ); + PipAppendStringToValueKey( + madeupKeyHandle, + L"AttachedComponents", + &unicodeDeviceInstance, + TRUE + ); + + } else { + + // + // The device instance key exists. We need to propagate the ConfigFlag + // to problem and StatusFlags + // + + ULONG configFlags; + + configFlags = 0; + status = PipGetRegistryValue(uniqueIdHandle, + L"ConfigFlags", + &keyValueInformation); + if (NT_SUCCESS(status)) { + if ((keyValueInformation->Type == REG_DWORD) && + (keyValueInformation->DataLength >= sizeof(ULONG))) { + configFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation); + } + ExFreePool(keyValueInformation); + } + if (configFlags & CONFIGFLAG_REINSTALL) { + + RtlInitUnicodeString(&unicodeString, L"Problem"); + tmpValue = CM_PROB_REINSTALL; + ZwSetValueKey(uniqueIdHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_DWORD, + &tmpValue, + sizeof(tmpValue) + ); + + RtlInitUnicodeString(&unicodeString, L"StatusFlags"); + tmpValue = DN_HAS_PROBLEM; + ZwSetValueKey(uniqueIdHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_DWORD, + &tmpValue, + sizeof(tmpValue) + ); + } else { + + RtlInitUnicodeString(&unicodeString, L"Problem"); + tmpValue = 0; + ZwSetValueKey(uniqueIdHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_DWORD, + &tmpValue, + sizeof(tmpValue) + ); + + RtlInitUnicodeString(&unicodeString, L"StatusFlags"); + ZwSetValueKey(uniqueIdHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_DWORD, + &tmpValue, + sizeof(tmpValue) + ); + + } + + + // + // The device instance key exists. we will enabled the device + // if it is installed. + // + + if (logConfHandle && PipIsDeviceInstanceInstalled(uniqueIdHandle, &unicodeDeviceInstance)) { + + // + // Read the boot config selected by user and activate the device. + // First check if ForcedConfig is set. If not, check BootConfig. + // + + status = PipGetRegistryValue(logConfHandle, + L"ForcedConfig", + &keyValueInformation); + if (!NT_SUCCESS(status)) { + status = PipGetRegistryValue(logConfHandle, + L"BootConfig", + &keyValueInformation); + } + if (NT_SUCCESS(status)) { + if ((keyValueInformation->Type == REG_RESOURCE_LIST) && + (keyValueInformation->DataLength != 0)) { + cmResource = (PCM_RESOURCE_LIST) + KEY_VALUE_DATA(keyValueInformation); + status = PipSetDeviceResources (deviceInfo, cmResource); + if (NT_SUCCESS(status)) { + RtlInitUnicodeString(&unicodeString, L"AllocConfig"); + ZwSetValueKey(logConfHandle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_RESOURCE_LIST, + cmResource, + keyValueInformation->DataLength + ); + PipSelectLogicalDevice( + deviceInfo->CardInformation->CardSelectNumber, + deviceInfo->LogicalDeviceNumber, + TRUE + ); + } + } + ExFreePool(keyValueInformation); + } + } + } + + // + // Clean up + // + + ZwClose(logConfHandle); + ZwClose(uniqueIdHandle); + ExFreePool(deviceId); + ExFreePool(uniqueId); + } + } + if (cardId) { + ExFreePool(cardId); + } + } + + // + // Clean up + // + + ZwClose(madeupKeyHandle); + ZwClose(busIdHandle); + ExFreePool(madeupInstancePath.Buffer); +} + +VOID +PipDeleteCards ( + IN PPI_BUS_EXTENSION BusExtension + ) +/*++ + +Routine Description: + + The function goes through card list and deletes all the invalid + cards and their associated logical devices. + +Arguments: + + BusExtension - supplies a pointer to the extension data of desired bus. + +Return Value: + + None. + +--*/ +{ + PDEVICE_INFORMATION deviceInfo; + PCARD_INFORMATION cardInfo; + PDEVICE_HANDLER_OBJECT deviceHandler; + PSINGLE_LIST_ENTRY *cardLink, *deviceLink ; + + // + // Go through the card link list to free all the devices + // marked as invalid. + // + + cardLink = &BusExtension->CardList.Next; + while (*cardLink) { + cardInfo = CONTAINING_RECORD (*cardLink, CARD_INFORMATION, CardList); + + // + // For each logical device of the card mark it as invalid + // + + deviceLink = &cardInfo->LogicalDeviceList.Next; + while (*deviceLink) { + deviceInfo = CONTAINING_RECORD (*deviceLink, DEVICE_INFORMATION, LogicalDeviceList); + BusExtension->NoValidSlots--; + *deviceLink = (*deviceLink)->Next; // Get the next addr before releasing pool + ExFreePool(deviceInfo); + } + + *cardLink = (*cardLink)->Next; // Get the next addr before releasing pool + if (cardInfo->CardData) { + ExFreePool(cardInfo->CardData); + } + ExFreePool(cardInfo); + } + + // + // Reset the CSN number, card and device link lists. + // + + BusExtension->NumberCSNs = 0; + BusExtension->CardList.Next = NULL; + BusExtension->DeviceList.Next = NULL; +} + +BOOLEAN +PipIsDeviceInstanceInstalled( + IN HANDLE Handle, + IN PUNICODE_STRING DeviceInstanceName + ) + +/*++ + +Routine Description: + + This routine checks if the device instance is installed. + +Arguments: + + Handle - Supplies a handle to the device instanace key to be checked. + + DeviceInstanceName - supplies a pointer to a UNICODE_STRING which specifies + the path of the device instance to be checked. + +Returns: + + A BOOLEAN value. + +--*/ + +{ + NTSTATUS status; + ULONG deviceFlags; + PKEY_VALUE_FULL_INFORMATION keyValueInformation; + BOOLEAN installed; + UNICODE_STRING serviceName, unicodeString; + HANDLE handle, handlex; + + // + // Check if the "Service=" value entry initialized. If no, its driver + // is not installed yet. + // + status = PipGetRegistryValue(Handle, + L"Service", + &keyValueInformation); + if (NT_SUCCESS(status)) { + if ((keyValueInformation->Type == REG_SZ) && + (keyValueInformation->DataLength != 0)) { + serviceName.Buffer = (PWSTR)((PCHAR)keyValueInformation + + keyValueInformation->DataOffset); + serviceName.MaximumLength = serviceName.Length = (USHORT)keyValueInformation->DataLength; + if (serviceName.Buffer[keyValueInformation->DataLength / sizeof(WCHAR)] == UNICODE_NULL) { + serviceName.Length -= sizeof(WCHAR); + } + + // + // try open the service key to make sure it is a valid key + // + + RtlInitUnicodeString( + &unicodeString, + L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\SERVICES"); + status = PipOpenRegistryKey(&handle, + NULL, + &unicodeString, + KEY_READ, + FALSE + ); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE, "PnPIsaCheckDeviceInstalled: Can not open CCS\\SERVICES key")); + ExFreePool(keyValueInformation); + return FALSE; + } + + status = PipOpenRegistryKey(&handlex, + handle, + &serviceName, + KEY_READ, + FALSE + ); + ZwClose (handle); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE, "PnPIsaCheckDeviceInstalled: Can not open CCS\\SERVICES key")); + ExFreePool(keyValueInformation); + return FALSE; + } + ZwClose(handlex); + } + ExFreePool(keyValueInformation); + } else { + return FALSE; + } + + // + // Check if the device instance has been disabled. + // First check global flag: CONFIGFLAG and then CSCONFIGFLAG. + // + + deviceFlags = 0; + status = PipGetRegistryValue(Handle, + L"ConfigFlags", + &keyValueInformation); + if (NT_SUCCESS(status)) { + if ((keyValueInformation->Type == REG_DWORD) && + (keyValueInformation->DataLength >= sizeof(ULONG))) { + deviceFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation); + } + ExFreePool(keyValueInformation); + } + + if (!(deviceFlags & CONFIGFLAG_DISABLED)) { + deviceFlags = 0; + status = PipGetDeviceInstanceCsConfigFlags( + DeviceInstanceName, + &deviceFlags + ); + if (NT_SUCCESS(status)) { + if ((deviceFlags & CSCONFIGFLAG_DISABLED) || + (deviceFlags & CSCONFIGFLAG_DO_NOT_CREATE)) { + deviceFlags = CONFIGFLAG_DISABLED; + } else { + deviceFlags = 0; + } + } + } + + installed = TRUE; + if (deviceFlags & CONFIGFLAG_DISABLED) { + installed = FALSE; + } + + return installed; +} + diff --git a/private/ntos/nthals/extender/pnpisa.sur/busp.h b/private/ntos/nthals/extender/pnpisa.sur/busp.h new file mode 100644 index 000000000..d8fd12f07 --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa.sur/busp.h @@ -0,0 +1,473 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + busp.h + +Abstract: + + Hardware independent header file for Pnp Isa bus extender. + +Author: + + Shie-Lin Tzong (shielint) July-26-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ +#ifndef _KERNEL_PNPI_ +#define _KERNEL_PNPI_ +#endif + +#include +#include +#include +#include + +#define TITLE_INDEX_VALUE 0 +#define CM_PROB_REINSTALL (0x00000012) // HACK +#define DN_HAS_PROBLEM (0x00000400) +#define KEY_VALUE_DATA(k) ((PCHAR)(k) + (k)->DataOffset) + +// +// Structures +// + +// +// CARD_INFORMATION Flags masks +// + +typedef struct _CARD_INFORMATION_ { + + // + // Next points to next CARD_INFORMATION structure + // + + SINGLE_LIST_ENTRY CardList; + + // + // Card select number for this Pnp Isa card. + // + + USHORT CardSelectNumber; + + // + // Number logical devices in the card. + // + + ULONG NumberLogicalDevices; + + // + // Logical device link list + // + + SINGLE_LIST_ENTRY LogicalDeviceList; + + // + // Pointer to card data which includes: + // 9 byte serial identifier for the pnp isa card + // PlugPlay Version number type for the pnp isa card + // Identifier string resource type for the pnp isa card + // Logical device Id resource type (repeat for each logical device) + // + + PVOID CardData; + ULONG CardDataLength; + +} CARD_INFORMATION, *PCARD_INFORMATION; + +// +// DEVICE_INFORMATION Flags masks +// + +typedef struct _DEVICE_INFORMATION_ { + + // + // Link list for ALL the Pnp Isa logical devices. + // NextDevice points to next DEVICE_INFORMATION structure + // + + SINGLE_LIST_ENTRY DeviceList; + + // + // Pointer to the CARD_INFORMATION for this device + // + + PCARD_INFORMATION CardInformation; + + // + // Link list for all the logical devices in a Pnp Isa card. + // + + SINGLE_LIST_ENTRY LogicalDeviceList; + + // + // LogicalDeviceNumber selects the corresponding logical device in the + // pnp isa card specified by CSN. + // + + USHORT LogicalDeviceNumber; + + // + // Pointer to device specific data + // + + PUCHAR DeviceData; + + // + // Length of the device data + // + + ULONG DeviceDataLength; + +} DEVICE_INFORMATION, *PDEVICE_INFORMATION; + +// +// Extension data for Bus extender +// + +typedef struct _PI_BUS_EXTENSION { + + // + // Number of cards selected + // + + ULONG NumberCSNs; + + // + // ReadDataPort addr + // + + PUCHAR ReadDataPort; + BOOLEAN DataPortMapped; + + // + // Address Port + // + + PUCHAR AddressPort; + BOOLEAN AddrPortMapped; + + // + // Command port + // + + PUCHAR CommandPort; + BOOLEAN CmdPortMapped; + + // + // Next Slot Number to assign + // + + ULONG NextSlotNumber; + + // + // DeviceList is the DEVICE_INFORMATION link list. + // + + SINGLE_LIST_ENTRY DeviceList; + + // + // NoValidSlots is the number of valid slots + // + + ULONG NoValidSlots; + + // + // CardList is the list of CARD_INFORMATION + // + + SINGLE_LIST_ENTRY CardList; + +} PI_BUS_EXTENSION, *PPI_BUS_EXTENSION; + +// +// The read data port range is from 0x200 - 0x3ff. +// We will try the following optimal ranges first +// if they all fail, we then pick any port from 0x200 - 0x3ff +// +// BEST: +// One 4-byte range in 274-2FF +// One 4-byte range in 374-3FF +// One 4-byte range in 338-37F +// One 4-byte range in 238-27F +// +// NORMAL: +// One 4-byte range in 200-3FF +// + +#define READ_DATA_PORT_RANGE_CHOICES 5 +typedef struct _READ_DATA_PORT_RANGE { + ULONG MinimumAddress; + ULONG MaximumAddress; + ULONG Alignment; +} READ_DATA_PORT_RANGE, *PREAD_DATA_PORT_RANGE; + +// +// Global Data references +// + +extern PI_BUS_EXTENSION PipBusExtension; +extern WCHAR rgzPNPISADeviceName[]; +extern PUCHAR PipReadDataPort; +extern PUCHAR PipCommandPort; +extern PUCHAR PipAddressPort; +extern READ_DATA_PORT_RANGE PipReadDataPortRanges[]; + +// +// Prototypes +// + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +NTSTATUS +PipGetCardIdentifier ( + PUCHAR CardData, + PWCHAR *Buffer, + PULONG BufferLength + ); + +NTSTATUS +PipGetFunctionIdentifier ( + PUCHAR DeviceData, + PWCHAR *Buffer, + PULONG BufferLength + ); + +NTSTATUS +PipQueryDeviceUniqueId ( + PDEVICE_INFORMATION DeviceInfo, + PWCHAR *DeviceId + ); + +NTSTATUS +PipQueryDeviceId ( + PDEVICE_INFORMATION DeviceInfo, + PWCHAR *DeviceId, + ULONG IdIndex + ); + +NTSTATUS +PipQueryDeviceResources ( + PDEVICE_INFORMATION DeviceInfo, + ULONG BusNumber, + PCM_RESOURCE_LIST *CmResources, + PULONG Length + ); + +NTSTATUS +PipQueryDeviceResourceRequirements ( + PDEVICE_INFORMATION DeviceInfo, + ULONG BusNumber, + ULONG Slot, + PIO_RESOURCE_REQUIREMENTS_LIST *IoResources, + ULONG *Size + ); + +NTSTATUS +PipSetDeviceResources ( + PDEVICE_INFORMATION DeviceInfo, + PCM_RESOURCE_LIST CmResources + ); + +VOID +PipDecompressEisaId( + IN ULONG CompressedId, + IN PUCHAR EisaId + ); + +NTSTATUS +PipOpenRegistryKey( + OUT PHANDLE Handle, + IN HANDLE BaseHandle OPTIONAL, + IN PUNICODE_STRING KeyName, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN Create + ); + +NTSTATUS +PipOpenRegistryKeyPersist( + OUT PHANDLE Handle, + IN HANDLE BaseHandle OPTIONAL, + IN PUNICODE_STRING KeyName, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN Create, + OUT PULONG Disposition OPTIONAL + ); + +NTSTATUS +PipGetRegistryValue( + IN HANDLE KeyHandle, + IN PWSTR ValueName, + OUT PKEY_VALUE_FULL_INFORMATION *Information + ); + +NTSTATUS +PipOpenCurrentHwProfileDeviceInstanceKey( + OUT PHANDLE Handle, + IN PUNICODE_STRING DeviceInstanceName, + IN ACCESS_MASK DesiredAccess + ); + +NTSTATUS +PipGetDeviceInstanceCsConfigFlags( + IN PUNICODE_STRING DeviceInstance, + OUT PULONG CsConfigFlags + ); + +NTSTATUS +PipRemoveStringFromValueKey ( + IN HANDLE Handle, + IN PWSTR ValueName, + IN PUNICODE_STRING String + ); + +NTSTATUS +PipAppendStringToValueKey ( + IN HANDLE Handle, + IN PWSTR ValueName, + IN PUNICODE_STRING String, + IN BOOLEAN Create + ); + +NTSTATUS +PbBiosResourcesToNtResources ( + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN OUT PUCHAR *BiosData, + OUT PIO_RESOURCE_REQUIREMENTS_LIST *ReturnedList, + OUT PULONG ReturnedLength + ); + +VOID +PipCheckBus ( + IN PPI_BUS_EXTENSION BusExtension + ); + +VOID +PipCheckDevices ( + IN PUNICODE_STRING RegistryPath, + IN PPI_BUS_EXTENSION BusExtension + ); + +NTSTATUS +PipReadCardResourceData ( + IN ULONG Csn, + OUT PULONG NumberLogicalDevices, + IN PVOID *ResourceData, + OUT PULONG ResourceDataLength + ); + +NTSTATUS +PipReadDeviceBootResourceData ( + IN ULONG BusNumber, + IN PUCHAR BiosRequirements, + OUT PCM_RESOURCE_LIST *ResourceData, + OUT PULONG Length + ); + +NTSTATUS +PipWriteDeviceBootResourceData ( + IN PUCHAR BiosRequirements, + IN PCM_RESOURCE_LIST CmResources + ); + +VOID +PipSelectLogicalDevice ( + IN USHORT Csn, + IN USHORT LogicalDeviceNumber, + IN BOOLEAN ActivateDevice + ); + +VOID +PipLFSRInitiation ( + VOID + ); + +VOID +PipIsolateCards ( + OUT PULONG NumberCSNs + ); + +ULONG +PipFindNextLogicalDeviceTag ( + IN OUT PUCHAR *CardData, + IN OUT LONG *Limit + ); + +VOID +PipDeleteCards ( + IN PPI_BUS_EXTENSION busExtension + ); + +NTSTATUS +PipServiceInstanceToDeviceInstance ( + IN PUNICODE_STRING RegistryPath, + IN ULONG ServiceInstanceOrdinal, + OUT PUNICODE_STRING DeviceInstanceRegistryPath OPTIONAL, + OUT PHANDLE DeviceInstanceHandle OPTIONAL, + IN ACCESS_MASK DesiredAccess + ); + +NTSTATUS +PipGetCompatibleDeviceId ( + PUCHAR DeviceData, + ULONG IdIndex, + PWCHAR *Buffer + ); + +NTSTATUS +ZwDeleteValueKey( + IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName + ); + +#if DBG + +#define DEBUG_MESSAGE 1 +#define DEBUG_BREAK 2 + +VOID +PipDebugPrint ( + ULONG Level, + PCCHAR DebugMessage, + ... + ); + +VOID +PipDumpIoResourceDescriptor ( + IN PUCHAR Indent, + IN PIO_RESOURCE_DESCRIPTOR Desc + ); + +VOID +PipDumpIoResourceList ( + IN PIO_RESOURCE_REQUIREMENTS_LIST IoList + ); + +VOID +PipDumpCmResourceDescriptor ( + IN PUCHAR Indent, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Desc + ); + +VOID +PipDumpCmResourceList ( + IN PCM_RESOURCE_LIST CmList + ); + +#define DebugPrint(arg) PipDebugPrint arg +#else +#define DebugPrint(arg) +#endif + diff --git a/private/ntos/nthals/extender/pnpisa.sur/convert.c b/private/ntos/nthals/extender/pnpisa.sur/convert.c new file mode 100644 index 000000000..1e144bb5e --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa.sur/convert.c @@ -0,0 +1,1092 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + xlate.c + +Abstract: + + This file contains routines to translate resources between PnP ISA/BIOS + format and Windows NT formats. + +Author: + + Shie-Lin Tzong (shielint) 12-Apr-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "busp.h" +#include "pnpisa.h" +#include "pbios.h" + +// +// internal structures for resource translation +// + +typedef struct _PB_DEPENDENT_RESOURCES { + ULONG Count; + UCHAR Flags; + UCHAR Priority; + struct _PB_DEPENDENT_RESOURCES *Next; +} PB_DEPENDENT_RESOURCES, *PPB_DEPENDENT_RESOURCES; + +#define DEPENDENT_FLAGS_END 1 + +typedef struct _PB_ATERNATIVE_INFORMATION { + PPB_DEPENDENT_RESOURCES Resources; + ULONG NoDependentFunctions; + ULONG TotalResourceCount; +} PB_ALTERNATIVE_INFORMATION, *PPB_ALTERNATIVE_INFORMATION; + +// +// Internal function references +// + +VOID +PbIoDescriptorToCmDescriptor ( + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor + ); + +PPB_DEPENDENT_RESOURCES +PbAddDependentResourcesToList ( + IN OUT PUCHAR *ResourceDescriptor, + IN ULONG ListNo, + IN PPB_ALTERNATIVE_INFORMATION AlternativeList + ); + +NTSTATUS +PbBiosIrqToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +NTSTATUS +PbBiosDmaToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +NTSTATUS +PbBiosPortFixedToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +NTSTATUS +PbBiosPortToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +NTSTATUS +PbBiosMemoryToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(INIT,PbBiosResourcesToNtResources) +#pragma alloc_text(INIT,PbIoDescriptorToCmDescriptor) +#pragma alloc_text(INIT,PbAddDependentResourcesToList) +#pragma alloc_text(INIT,PbBiosIrqToIoDescriptor) +#pragma alloc_text(INIT,PbBiosDmaToIoDescriptor) +#pragma alloc_text(INIT,PbBiosPortFixedToIoDescriptor) +#pragma alloc_text(INIT,PbBiosPortToIoDescriptor) +#pragma alloc_text(INIT,PbBiosMemoryToIoDescriptor) +#endif + +NTSTATUS +PbBiosResourcesToNtResources ( + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN OUT PUCHAR *BiosData, + OUT PIO_RESOURCE_REQUIREMENTS_LIST *ReturnedList, + OUT PULONG ReturnedLength + ) + +/*++ + +Routine Description: + + This routine parses the Bios resource list and generates + a NT resource list. The returned Nt resource list could be either IO + format or CM format. It is caller's responsibility to release the + returned data buffer. + +Arguments: + + SlotNumber - specifies the slot number of the BIOS resource. + + BiosData - Supplies a pointer to a variable which specifies the bios resource + data buffer and which to receive the pointer to next bios resource data. + + ReturnedList - supplies a variable to receive the desired resource list. + + ReturnedLength - Supplies a variable to receive the length of the resource list. + +Return Value: + + NTSTATUS code + +--*/ +{ + PUCHAR buffer; + USHORT mask16, increment; + UCHAR tagName, mask8; + NTSTATUS status; + PPB_ALTERNATIVE_INFORMATION alternativeList = NULL; + ULONG commonResCount = 0, dependDescCount = 0, i, j; + ULONG alternativeListCount = 0, dependFunctionCount = 0; + PIO_RESOURCE_DESCRIPTOR commonResources = NULL, commonIoDesc, dependIoDesc, ioDesc; + PPB_DEPENDENT_RESOURCES dependResList = NULL, dependResources; + BOOLEAN dependent = FALSE; + ULONG listSize, noResLists; + ULONG totalDescCount, descCount; + PIO_RESOURCE_REQUIREMENTS_LIST ioResReqList; + PIO_RESOURCE_LIST ioResList; + + // + // First, scan the bios data to determine the memory requirement and + // the information to build internal data structures. + // + + *ReturnedLength = 0; + alternativeListCount = 0; + buffer = *BiosData; + tagName = *buffer; + while (tagName != TAG_COMPLETE_END) { + + // + // Determine the size of the BIOS resource descriptor + // + + if (!(tagName & LARGE_RESOURCE_TAG)) { + increment = (USHORT)(tagName & SMALL_TAG_SIZE_MASK); + increment += 1; // length of small tag + tagName &= SMALL_TAG_MASK; + } else { + increment = *(PUSHORT)(buffer+1); + increment += 3; // length of large tag + } + + // + // Based on the type of the BIOS resource, determine the count of + // the IO descriptors. + // + + switch (tagName) { + case TAG_IRQ: + mask16 = ((PPNP_IRQ_DESCRIPTOR)buffer)->IrqMask; + i = 0; + while (mask16) { + if (mask16 & 1) { + i++; + } + mask16 >>= 1; + } + if (!dependent) { + commonResCount += i; + } else { + dependDescCount += i; + } + break; + case TAG_DMA: + mask8 = ((PPNP_DMA_DESCRIPTOR)buffer)->ChannelMask; + i = 0; + while (mask8) { + if (mask8 & 1) { + i++; + } + mask8 >>= 1; + } + if (!dependent) { + commonResCount += i; + } else { + dependDescCount += i; + } + break; + case TAG_START_DEPEND: + dependent = TRUE; + dependFunctionCount++; + break; + case TAG_END_DEPEND: + dependent = FALSE; + alternativeListCount++; + break; + case TAG_IO_FIXED: + case TAG_IO: + case TAG_MEMORY: + case TAG_MEMORY32: + case TAG_MEMORY32_FIXED: + if (!dependent) { + commonResCount++; + } else { + dependDescCount++; + } + break; + default: + + // + // Unknown tag. Skip it. + // + + break; + } + + // + // Move to next bios resource descriptor. + // + + buffer += increment; + tagName = *buffer; + if ((tagName & SMALL_TAG_MASK) == TAG_LOGICAL_ID) { + break; + } + } + + // + // if empty bios resources, simply return. + // + + if (commonResCount == 0 && dependFunctionCount == 0) { + *ReturnedList = NULL; + *ReturnedLength = 0; + *BiosData = buffer + 2; + return STATUS_SUCCESS; + } + + // + // Allocate memory for our internal data structures + // + + if (dependFunctionCount) { + dependResources = (PPB_DEPENDENT_RESOURCES)ExAllocatePoolWithTag( + PagedPool, + dependFunctionCount * sizeof(PB_DEPENDENT_RESOURCES) + + dependDescCount * sizeof(IO_RESOURCE_DESCRIPTOR), + 'bPnP' + ); + if (!dependResources) { + return STATUS_INSUFFICIENT_RESOURCES; + } + dependResList = dependResources; // remember it so we can free it. + } + + if (alternativeListCount) { + ASSERT(dependFunctionCount != 0); + alternativeList = (PPB_ALTERNATIVE_INFORMATION)ExAllocatePoolWithTag( + PagedPool, + sizeof(PB_ALTERNATIVE_INFORMATION) * (alternativeListCount + 1), + 'bPnP' + ); + if (!alternativeList) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto exit0; + } + RtlZeroMemory(alternativeList, + sizeof(PB_ALTERNATIVE_INFORMATION) * alternativeListCount + ); + alternativeList[0].Resources = dependResources; + } + if (commonResCount) { + commonResources = (PIO_RESOURCE_DESCRIPTOR)ExAllocatePoolWithTag ( + PagedPool, + sizeof(IO_RESOURCE_DESCRIPTOR) * commonResCount, + 'bPnP' + ); + if (!commonResources) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto exit1; + } + } + + // + // Now start over again to process the bios data and initialize our internal + // resource representation. + // + + commonIoDesc = commonResources; + dependDescCount = 0; + alternativeListCount = 0; + buffer = *BiosData; + tagName = *buffer; + dependent = FALSE; + while (tagName != TAG_COMPLETE_END) { + if (!(tagName & LARGE_RESOURCE_TAG)) { + tagName &= SMALL_TAG_MASK; + } + switch (tagName) { + case TAG_IRQ: + if (dependent) { + ioDesc = dependIoDesc; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosIrqToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + case TAG_DMA: + if (dependent) { + ioDesc = dependIoDesc; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosDmaToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + case TAG_START_DEPEND: + dependent = TRUE; + alternativeList[alternativeListCount].NoDependentFunctions++; + if (dependDescCount != 0) { + + // + // End of current dependent function + // + + dependResources->Count = dependDescCount; + dependResources->Flags = 0; + dependResources->Next = (PPB_DEPENDENT_RESOURCES)dependIoDesc; + dependResources = dependResources->Next; + alternativeList[alternativeListCount].TotalResourceCount += dependDescCount; + } + if (*buffer & SMALL_TAG_SIZE_MASK) { + dependResources->Priority = *(buffer + 1); + } + dependDescCount = 0; + dependIoDesc = (PIO_RESOURCE_DESCRIPTOR)(dependResources + 1); + buffer += 1 + (*buffer & SMALL_TAG_SIZE_MASK); + break; + case TAG_END_DEPEND: + alternativeList[alternativeListCount].TotalResourceCount += dependDescCount; + dependResources->Count = dependDescCount; + dependResources->Flags = DEPENDENT_FLAGS_END; + dependResources->Next = alternativeList[alternativeListCount].Resources; + dependent = FALSE; + dependDescCount = 0; + alternativeListCount++; + alternativeList[alternativeListCount].Resources = (PPB_DEPENDENT_RESOURCES)dependIoDesc; + dependResources = alternativeList[alternativeListCount].Resources; + buffer++; + break; + case TAG_IO: + if (dependent) { + ioDesc = dependIoDesc; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosPortToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + case TAG_IO_FIXED: + if (dependent) { + ioDesc = dependIoDesc; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosPortFixedToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + case TAG_MEMORY: + case TAG_MEMORY32: + case TAG_MEMORY32_FIXED: + if (dependent) { + ioDesc = dependIoDesc; + dependDescCount; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosMemoryToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + default: + + // + // Don't-care tag simpley advance the buffer pointer to next tag. + // + + if (*buffer & LARGE_RESOURCE_TAG) { + increment = *(PUSHORT)(buffer+1); + increment += 3; // length of large tag + } else { + increment = (USHORT)(*buffer & SMALL_TAG_SIZE_MASK); + increment += 1; // length of small tag + } + buffer += increment; + } + tagName = *buffer; + if ((tagName & SMALL_TAG_MASK) == TAG_LOGICAL_ID) { + break; + } + } + + if (alternativeListCount != 0) { + alternativeList[alternativeListCount].Resources = NULL; // dummy alternativeList record + } + *BiosData = buffer + 2; // Skip END_TAG + + // + // prepare IoResourceList + // + + noResLists = 1; + for (i = 0; i < alternativeListCount; i++) { + noResLists *= alternativeList[i].NoDependentFunctions; + } + totalDescCount = 0; + for (i = 0; i < alternativeListCount; i++) { + descCount = 1; + for (j = 0; j < alternativeListCount; j++) { + if (j == i) { + descCount *= alternativeList[j].TotalResourceCount; + } else { + descCount *= alternativeList[j].NoDependentFunctions; + } + } + totalDescCount += descCount; + } + listSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + + sizeof(IO_RESOURCE_LIST) * (noResLists - 1) + + sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescCount - + sizeof(IO_RESOURCE_DESCRIPTOR) * noResLists + + sizeof(IO_RESOURCE_DESCRIPTOR) * commonResCount * noResLists; + + ioResReqList = (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePoolWithTag(PagedPool, listSize, 'bPnP'); + if (!ioResReqList) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto exit2; + } + + ioResReqList->ListSize = listSize; + ioResReqList->InterfaceType = Internal; + ioResReqList->BusNumber = BusNumber; + ioResReqList->SlotNumber = SlotNumber; + ioResReqList->Reserved[0] = 0; + ioResReqList->Reserved[1] = 0; + ioResReqList->Reserved[2] = 0; + ioResReqList->AlternativeLists = noResLists; + ioResList = &ioResReqList->List[0]; + + // + // Build resource lists + // + + for (i = 0; i < noResLists; i++) { + ULONG size; + USHORT j; + + ioResList->Version = 1; + ioResList->Revision = 0x30 | (USHORT)i; + buffer = (PUCHAR)&ioResList->Descriptors[0]; + + // + // Copy common resources to the list + // + + if (commonResources) { + size = sizeof(IO_RESOURCE_DESCRIPTOR) * commonResCount; + RtlMoveMemory(buffer, commonResources, size); + buffer += size; + } + + // + // Copy dependent functions if any. + // + + if (alternativeList) { + PbAddDependentResourcesToList(&buffer, 0, alternativeList); + } + + // + // Update io resource list ptr + // + + ioResList->Count = ((ULONG)buffer - (ULONG)&ioResList->Descriptors[0]) / + sizeof(IO_RESOURCE_DESCRIPTOR); + + // + // Hack for user mode pnp mgr + // + + for (j = 0; j < ioResList->Count; j++) { + ioResList->Descriptors[j].Spare2 = j; + } + ioResList = (PIO_RESOURCE_LIST)buffer; + } + + *ReturnedLength = listSize; + status = STATUS_SUCCESS; + *ReturnedList = ioResReqList; +exit2: + if (commonResources) { + ExFreePool(commonResources); + } +exit1: + if (alternativeList) { + ExFreePool(alternativeList); + } +exit0: + if (dependResList) { + ExFreePool(dependResList); + } + return status; +} + +PPB_DEPENDENT_RESOURCES +PbAddDependentResourcesToList ( + IN OUT PUCHAR *ResourceDescriptor, + IN ULONG ListNo, + IN PPB_ALTERNATIVE_INFORMATION AlternativeList + ) + +/*++ + +Routine Description: + + This routine adds dependent functions to caller specified list. + +Arguments: + + ResourceDescriptor - supplies a pointer to the descriptor buffer. + + ListNo - supplies an index to the AlternativeList. + + AlternativeList - supplies a pointer to the alternativelist array. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + PPB_DEPENDENT_RESOURCES dependentResources, ptr; + ULONG size; + + // + // Copy dependent resources to caller supplied list buffer and + // update the list buffer pointer. + // + + dependentResources = AlternativeList[ListNo].Resources; + size = sizeof(IO_RESOURCE_DESCRIPTOR) * dependentResources->Count; + RtlMoveMemory(*ResourceDescriptor, dependentResources + 1, size); + *ResourceDescriptor = *ResourceDescriptor + size; + + // + // Add dependent resource of next list to caller's buffer + // + + if (AlternativeList[ListNo + 1].Resources) { + ptr = PbAddDependentResourcesToList(ResourceDescriptor, ListNo + 1, AlternativeList); + } else { + ptr = NULL; + } + if (ptr == NULL) { + AlternativeList[ListNo].Resources = dependentResources->Next; + if (!(dependentResources->Flags & DEPENDENT_FLAGS_END)) { + ptr = dependentResources->Next; + } + } + return ptr; +} + +VOID +PbIoDescriptorToCmDescriptor ( + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor + ) + +/*++ + +Routine Description: + + This routine translates IO_RESOURCE_DESCRIPTOR to CM_PARTIAL_RESOURCE_DESCRIPTOR. + +Arguments: + + IoDescriptor - Supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be converted. + + CmDescriptor - Supplies a pointer to the receiving CM_PARTIAL_RESOURCE_DESCRIPTOR. + +Return Value: + + None. + +--*/ +{ + CmDescriptor->Type = IoDescriptor->Type; + CmDescriptor->ShareDisposition = IoDescriptor->ShareDisposition; + CmDescriptor->Flags = IoDescriptor->Flags; + switch (CmDescriptor->Type) { + case CmResourceTypePort: + CmDescriptor->u.Port.Length = IoDescriptor->u.Port.Length; + CmDescriptor->u.Port.Start = IoDescriptor->u.Port.MinimumAddress; + break; + case CmResourceTypeInterrupt: + CmDescriptor->u.Interrupt.Level = + CmDescriptor->u.Interrupt.Vector = IoDescriptor->u.Interrupt.MinimumVector; + CmDescriptor->u.Interrupt.Affinity = (ULONG)-1; + break; + case CmResourceTypeMemory: + CmDescriptor->u.Memory.Length = IoDescriptor->u.Memory.Length; + CmDescriptor->u.Memory.Start = IoDescriptor->u.Memory.MinimumAddress; + break; + case CmResourceTypeDma: + CmDescriptor->u.Dma.Channel = IoDescriptor->u.Dma.MinimumChannel; + CmDescriptor->u.Dma.Port = 0; + CmDescriptor->u.Dma.Reserved1 = 0; + break; + } +} + +NTSTATUS +PbBiosIrqToIoDescriptor ( + IN OUT PUCHAR *BiosData, + PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS IRQ information to NT usable format. + This routine stops when an irq io resource is generated. if there are + more irq io resource descriptors available, the BiosData pointer will + not advance. So caller will pass us the same resource tag again. + + Note, BIOS DMA info alway uses SMALL TAG. A tag structure is repeated + for each seperated channel required. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + static ULONG bitPosition = 0; + USHORT mask; + ULONG irq; + PPNP_IRQ_DESCRIPTOR buffer; + UCHAR size, option; + NTSTATUS status = STATUS_SUCCESS; + + buffer = (PPNP_IRQ_DESCRIPTOR)*BiosData; + + // + // if this is not the first descriptor for the tag, set + // its option to alternative. + // + + if (bitPosition == 0) { + option = 0; + } else { + option = IO_RESOURCE_ALTERNATIVE; + } + size = buffer->Tag & SMALL_TAG_SIZE_MASK; + mask = buffer->IrqMask; + mask >>= bitPosition; + irq = (ULONG) -1; + + while (mask) { + if (mask & 1) { + irq = bitPosition; + break; + } + mask >>= 1; + bitPosition++; + } + + // + // Fill in Io resource descriptor + // + + if (irq != (ULONG)-1) { + IoDescriptor->Option = option; + IoDescriptor->Type = CmResourceTypeInterrupt; + IoDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; + IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + if (size == 3 && buffer->Information & 0x0C) { + IoDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + IoDescriptor->ShareDisposition = CmResourceShareShared; + } + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Interrupt.MinimumVector = irq; + IoDescriptor->u.Interrupt.MaximumVector = irq; + } else { + status = STATUS_INVALID_PARAMETER; + } + + if (NT_SUCCESS(status)) { + + // + // try to move bitPosition to next 1 bit. + // + + while (mask) { + mask >>= 1; + bitPosition++; + if (mask & 1) { + return status; + } + } + } + + // + // Done with current irq tag, advance pointer to next tag + // + + bitPosition = 0; + *BiosData = (PUCHAR)buffer + size + 1; + return status; +} + +NTSTATUS +PbBiosDmaToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS DMA information to NT usable format. + This routine stops when an dma io resource is generated. if there are + more dma io resource descriptors available, the BiosData pointer will + not advance. So caller will pass us the same resource tag again. + + Note, BIOS DMA info alway uses SMALL TAG. A tag structure is repeated + for each seperated channel required. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + static ULONG bitPosition = 0; + ULONG dma; + PPNP_DMA_DESCRIPTOR buffer; + UCHAR mask, option; + NTSTATUS status = STATUS_SUCCESS; + + buffer = (PPNP_DMA_DESCRIPTOR)*BiosData; + + // + // if this is not the first descriptor for the tag, set + // its option to alternative. + // + + if (bitPosition == 0) { + option = 0; + } else { + option = IO_RESOURCE_ALTERNATIVE; + } + mask = buffer->ChannelMask; + mask >>= bitPosition; + dma = (ULONG) -1; + + while (mask) { + if (mask & 1) { + dma = bitPosition; + break; + } + mask >>= 1; + bitPosition++; + } + + // + // Fill in Io resource descriptor + // + + if (dma != (ULONG)-1) { + IoDescriptor->Option = option; + IoDescriptor->Type = CmResourceTypeDma; + IoDescriptor->Flags = 0; + IoDescriptor->ShareDisposition = CmResourceShareUndetermined; + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Dma.MinimumChannel = dma; + IoDescriptor->u.Dma.MaximumChannel = dma; + } else { + status = STATUS_INVALID_PARAMETER; + } + + if (NT_SUCCESS(status)) { + + // + // try to move bitPosition to next 1 bit. + // + + while (mask) { + mask >>= 1; + bitPosition++; + if (mask & 1) { + return status; + } + } + } + + // + // Done with current dma tag, advance pointer to next tag + // + + bitPosition = 0; + buffer += 1; + *BiosData = (PUCHAR)buffer; + return status; +} + +NTSTATUS +PbBiosPortFixedToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS FIXED IO information to NT usable format. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + PPNP_FIXED_PORT_DESCRIPTOR buffer; + + buffer = (PPNP_FIXED_PORT_DESCRIPTOR)*BiosData; + + // + // Fill in Io resource descriptor + // + + IoDescriptor->Option = 0; + IoDescriptor->Type = CmResourceTypePort; + IoDescriptor->Flags = CM_RESOURCE_PORT_IO; + IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Port.Length = (ULONG)buffer->Length; + IoDescriptor->u.Port.MinimumAddress.LowPart = (ULONG)(buffer->MinimumAddress & 0x3ff); + IoDescriptor->u.Port.MinimumAddress.HighPart = 0; + IoDescriptor->u.Port.MaximumAddress.LowPart = IoDescriptor->u.Port.MinimumAddress.LowPart + + IoDescriptor->u.Port.Length - 1; + IoDescriptor->u.Port.MaximumAddress.HighPart = 0; + IoDescriptor->u.Port.Alignment = 1; + + // + // Done with current fixed port tag, advance pointer to next tag + // + + buffer += 1; + *BiosData = (PUCHAR)buffer; + return STATUS_SUCCESS; +} + +NTSTATUS +PbBiosPortToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS IO information to NT usable format. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + PPNP_PORT_DESCRIPTOR buffer; + + buffer = (PPNP_PORT_DESCRIPTOR)*BiosData; + + // + // Fill in Io resource descriptor + // + + IoDescriptor->Option = 0; + IoDescriptor->Type = CmResourceTypePort; + IoDescriptor->Flags = CM_RESOURCE_PORT_IO; + IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Port.Length = (ULONG)buffer->Length; + IoDescriptor->u.Port.MinimumAddress.LowPart = (ULONG)buffer->MinimumAddress; + IoDescriptor->u.Port.MinimumAddress.HighPart = 0; + IoDescriptor->u.Port.MaximumAddress.LowPart = (ULONG)buffer->MaximumAddress + + IoDescriptor->u.Port.Length - 1; + IoDescriptor->u.Port.MaximumAddress.HighPart = 0; + IoDescriptor->u.Port.Alignment = (ULONG)buffer->Alignment; + + // + // Done with current fixed port tag, advance pointer to next tag + // + + buffer += 1; + *BiosData = (PUCHAR)buffer; + return STATUS_SUCCESS; +} + +NTSTATUS +PbBiosMemoryToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS MEMORY information to NT usable format. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + PUCHAR buffer; + UCHAR tag; + PHYSICAL_ADDRESS minAddr, maxAddr; + ULONG alignment, length; + USHORT increment; + + buffer = *BiosData; + tag = ((PPNP_MEMORY_DESCRIPTOR)buffer)->Tag; + increment = ((PPNP_MEMORY_DESCRIPTOR)buffer)->Length + 3; // larg tag size = 3 + + minAddr.HighPart = 0; + maxAddr.HighPart = 0; + switch (tag) { + case TAG_MEMORY: + minAddr.LowPart = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)buffer)->MinimumAddress)) << 8; + if ((alignment = ((PPNP_MEMORY_DESCRIPTOR)buffer)->Alignment) == 0) { + alignment = 0x10000; + } + length = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)buffer)->MemorySize)) << 8; + maxAddr.LowPart = (((ULONG)(((PPNP_MEMORY_DESCRIPTOR)buffer)->MaximumAddress)) << 8) + length - 1; + break; + case TAG_MEMORY32: + length = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->MemorySize; + minAddr.LowPart = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->MinimumAddress; + maxAddr.LowPart = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->MaximumAddress + length - 1; + alignment = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->Alignment; + break; + case TAG_MEMORY32_FIXED: + length = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)buffer)->MemorySize; + minAddr.LowPart = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)buffer)->BaseAddress; + maxAddr.LowPart = minAddr.LowPart + length - 1; + alignment = 1; + break; + } + // + // Fill in Io resource descriptor + // + + IoDescriptor->Option = 0; + IoDescriptor->Type = CmResourceTypeMemory; + IoDescriptor->Flags = CM_RESOURCE_PORT_MEMORY; + IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Memory.MinimumAddress = minAddr; + IoDescriptor->u.Memory.MaximumAddress = maxAddr; + IoDescriptor->u.Memory.Alignment = alignment; + IoDescriptor->u.Memory.Length = length; + + // + // Done with current tag, advance pointer to next tag + // + + buffer += increment; + *BiosData = (PUCHAR)buffer; + return STATUS_SUCCESS; +} diff --git a/private/ntos/nthals/extender/pnpisa.sur/data.c b/private/ntos/nthals/extender/pnpisa.sur/data.c new file mode 100644 index 000000000..8afb53ce0 --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa.sur/data.c @@ -0,0 +1,58 @@ + +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pbdata.c + +Abstract: + + Declares various data which is specific to PNP ISA bus extender architecture and + is independent of BIOS. + +Author: + + Shie-Lin Tzong (shielint) July-26-95 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "busp.h" + +// +// regPNPISADeviceName +// + +WCHAR rgzPNPISADeviceName[] = L"\\Device\\PnpIsa_%d"; + +// +// Pointers to bus extension data. +// + +PI_BUS_EXTENSION PipBusExtension; + +// +// Read_data_port address +// (This is mainly for convinience. It duplicates the +// ReadDataPort field in BUS extension structure.) +// + +PUCHAR PipReadDataPort; +PUCHAR PipCommandPort; +PUCHAR PipAddressPort; + +// +// Read data port range selection array +// + +READ_DATA_PORT_RANGE +PipReadDataPortRanges[READ_DATA_PORT_RANGE_CHOICES] = + {{0x274, 0x2ff, 4}, {0x374, 0x3ff, 4}, {0x338, 0x37f, 4}, {0x238, 0x27f, 4}, {0x200, 0x3ff}}; diff --git a/private/ntos/nthals/extender/pnpisa.sur/init.c b/private/ntos/nthals/extender/pnpisa.sur/init.c new file mode 100644 index 000000000..538820af1 --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa.sur/init.c @@ -0,0 +1,620 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + init.c + +Abstract: + + DriverEntry initialization code for pnp isa bus extender. + +Author: + + Shie-Lin Tzong (shielint) 29-Apr-1996 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "busp.h" +#include "pnpisa.h" + +// +// Internal References +// + +PVOID +PipGetMappedAddress( + IN INTERFACE_TYPE BusType, + IN ULONG BusNumber, + IN PHYSICAL_ADDRESS IoAddress, + IN ULONG NumberOfBytes, + IN ULONG AddressSpace, + OUT PBOOLEAN MappedAddress + ); + +NTSTATUS +PipAcquirePortResources( + IN PPI_BUS_EXTENSION BusExtension, + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath, + IN PHYSICAL_ADDRESS BaseAddressLow, + IN PHYSICAL_ADDRESS BaseAddressHi, + IN ULONG Alignment, + IN ULONG PortLength, + OUT PCM_RESOURCE_LIST *CmResourceList + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,DriverEntry) +#pragma alloc_text(INIT,PipAcquirePortResources) +#pragma alloc_text(INIT,PipGetMappedAddress) +#endif + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + This is a temporary driver. It isolates all the PNP ISA cards. For each + Pnp Isa device, if its driver is installed, we retrieve user specified + resource information to configure the card and turn on the device. + Otherwise, we create a device instance for the device and record its resource + requirements list. + + All the work is done in the Init/DriverEntry routine. So, this driver always + return failure to let itself be unloaded. + +Arguments: + + DriverObject - specifies the driver object for the bus extender. + + RegistryPath - supplies a pointer to a unicode string of the service key name in + the CurrentControlSet\Services key for the bus extender. + +Return Value: + + Always return STATUS_UNSUCCESSFUL. + +--*/ + +{ + NTSTATUS status; + ULONG size, i, j, csn, cardDetected, maxCardDetected = 0; + PHYSICAL_ADDRESS baseAddrHi, baseAddrLow; + PUCHAR readDataPort = NULL; + PCM_RESOURCE_LIST cmResource, maxCmResource = NULL; + PCM_PARTIAL_RESOURCE_DESCRIPTOR cmResourceDescriptor; + + // + // In the first pass, we try to isolate pnpisa cards in the machine + // using read data port from each predefined ranges. One some machine + // different number of isapnp cards can be detected. We will choose + // the read data port which gives the max number of pnpisa cards. + // + + for (i = 0; i < READ_DATA_PORT_RANGE_CHOICES; i++) { + + baseAddrLow.LowPart = PipReadDataPortRanges[i].MinimumAddress; + baseAddrLow.HighPart = 0; + baseAddrHi.LowPart = PipReadDataPortRanges[i].MaximumAddress; + baseAddrHi.HighPart = 0; + status = PipAcquirePortResources( + &PipBusExtension, + DriverObject, + RegistryPath, + baseAddrLow, + baseAddrHi, + PipReadDataPortRanges[i].Alignment, + 4, + &cmResource + ); + if (!NT_SUCCESS(status)) { + continue; + } + + // + // Perform Pnp isolation process. This will assign card select number for each + // Pnp Isa card isolated by the system. All the isolated cards will be put into + // wait-for-key state. + // + + PipIsolateCards(&csn); + + // + // send initiation key to put cards into sleep state + // + + PipLFSRInitiation (); + + // + // For each card selected, make sure it returns valid card resource data + // + + cardDetected = 0; + for (j = 1; j <= csn; j++) { + + ULONG noDevices, dataLength; + PUCHAR cardData; + + status = PipReadCardResourceData ( + j, + &noDevices, + &cardData, + &dataLength); + if (!NT_SUCCESS(status)) { + continue; + } else { + ExFreePool(cardData); + cardDetected++; + } + } + + // + // Finaly put all cards into wait for key state. + // + + PipWriteAddress(CONFIG_CONTROL_PORT); + PipWriteData(CONTROL_WAIT_FOR_KEY); + + if ((cardDetected != 0) && (cardDetected >= maxCardDetected)) { + maxCardDetected = cardDetected; + readDataPort = PipReadDataPort; + if (maxCmResource) { + ExFreePool(maxCmResource); + } + maxCmResource = cmResource; + } else { + ExFreePool(cmResource); + } + } + + if (readDataPort != NULL) { + + if (readDataPort != PipReadDataPort) { + if (PipReadDataPort) { + if (PipBusExtension.DataPortMapped) { + MmUnmapIoSpace(PipReadDataPort - 3, 4); + } + PipReadDataPort = NULL; + } + cmResourceDescriptor = + &maxCmResource->List->PartialResourceList.PartialDescriptors[0]; + PipReadDataPort = PipGetMappedAddress( + Isa, // InterfaceType + 0, // BusNumber, + cmResourceDescriptor->u.Port.Start, + cmResourceDescriptor->u.Port.Length, + cmResourceDescriptor->Flags, + &PipBusExtension.DataPortMapped + ); + if (PipReadDataPort) { + PipReadDataPort += 3; + ASSERT(readDataPort == PipReadDataPort); + PipBusExtension.ReadDataPort = PipReadDataPort; + } else { + goto exit; + } + } + + // + // Perform initial bus check to find all the PnP ISA devices + // + + PipCheckBus(&PipBusExtension); + ASSERT(PipBusExtension.NumberCSNs == maxCardDetected); + + // + // Perform PnP ISA device check to see if we should enable it. + // + + PipCheckDevices(RegistryPath, &PipBusExtension); + + // + // Delete all the device info structures and card info structures + // + + PipDeleteCards(&PipBusExtension); + } + + // + // Release address, command and read data port resources. + // + +exit: + if (maxCmResource) { + ExFreePool(maxCmResource); + } + + if (PipCommandPort && PipBusExtension.CmdPortMapped) { + MmUnmapIoSpace(PipCommandPort, 1); + } + if (PipAddressPort && PipBusExtension.AddrPortMapped) { + MmUnmapIoSpace(PipAddressPort, 1); + } + if (PipReadDataPort && PipBusExtension.DataPortMapped) { + MmUnmapIoSpace(PipReadDataPort - 3, 4); + } + + IoAssignResources(RegistryPath, + NULL, + DriverObject, + NULL, + NULL, + NULL); + + // + // Finally, return failure to get ourself unloaded. + // + + return STATUS_UNSUCCESSFUL; +} + +NTSTATUS +PipAcquirePortResources( + IN PPI_BUS_EXTENSION BusExtension, + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath, + IN PHYSICAL_ADDRESS BaseAddressLow, + IN PHYSICAL_ADDRESS BaseAddressHi, + IN ULONG Alignment, + IN ULONG PortLength, + OUT PCM_RESOURCE_LIST *CmResourceList + ) + +/*++ + +Routine Description: + + This routine acquires specified port resources. + +Arguments: + + BusExtension - Supplies a pointer to the pnp bus extension. + + BaseAddressLow, + BaseAddressHi - Supplies the read data port base address range to be mapped. + + Alignment - supplies the port allignment. + + PortLength = Number of ports required. + +Return Value: + + NTSTATUS code. + +--*/ + +{ + +#if 1 + + PCM_RESOURCE_LIST cmResource; + PCM_PARTIAL_RESOURCE_DESCRIPTOR cmResourceDescriptor; + NTSTATUS status; + ULONG size; + PIO_RESOURCE_REQUIREMENTS_LIST ioResource; + ULONG i; + PHYSICAL_ADDRESS physicalAddress; + + *CmResourceList = NULL; + + // + // Create a static Io resource requirements list and + // Call I/O mgr to get address, command and read data port addresses assigned. + // + + size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); + ioResource = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, size); + RtlZeroMemory(ioResource, size); + ioResource->ListSize = size; + ioResource->InterfaceType = Isa; + ioResource->AlternativeLists = 1; + ioResource->List[0].Version = 1; + ioResource->List[0].Revision = 1; + ioResource->List[0].Count = 1; + ioResource->List[0].Descriptors[0].Type = CmResourceTypePort; + ioResource->List[0].Descriptors[0].ShareDisposition = CmResourceShareDeviceExclusive; + ioResource->List[0].Descriptors[0].Flags = CM_RESOURCE_PORT_IO; + ioResource->List[0].Descriptors[0].u.Port.Length = PortLength; + ioResource->List[0].Descriptors[0].u.Port.Alignment = Alignment; + ioResource->List[0].Descriptors[0].u.Port.MinimumAddress = BaseAddressLow; + ioResource->List[0].Descriptors[0].u.Port.MaximumAddress = BaseAddressHi; + + status = IoAssignResources(RegistryPath, + NULL, + DriverObject, + NULL, + ioResource, + &cmResource); + ExFreePool(ioResource); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE,"PnpIsa: IoAssignResources failed\n")); + return status; + } + + // + // Map port addr to memory addr if necessary. + // + + if (PipAddressPort == NULL) { + physicalAddress.LowPart = ADDRESS_PORT; + physicalAddress.HighPart = 0; + BusExtension->AddressPort = + PipAddressPort = PipGetMappedAddress( + Isa, // InterfaceType + 0, // BusNumber, + physicalAddress, + 1, + CM_RESOURCE_PORT_IO, + &BusExtension->AddrPortMapped + ); + if (PipAddressPort == NULL) { + goto exit0; + } + } + if (PipCommandPort == NULL) { + physicalAddress.LowPart = COMMAND_PORT; + physicalAddress.HighPart = 0; + BusExtension->CommandPort = + PipCommandPort = PipGetMappedAddress( + Isa, // InterfaceType + 0, // BusNumber, + physicalAddress, + 1, + CM_RESOURCE_PORT_IO, + &BusExtension->CmdPortMapped + ); + if (PipCommandPort == NULL) { + goto exit0; + } + } + cmResourceDescriptor = + &cmResource->List->PartialResourceList.PartialDescriptors[0]; + if ((cmResourceDescriptor->u.Port.Start.LowPart & 0xf) == 0) { + + // + // Some cards (e.g. 3COM elnkiii) do not response to 0xyy3 addr. + // + + DebugPrint((DEBUG_BREAK, "PnpIsa:ReadDataPort is at yy3\n")); + goto exit0; + } + if (PipReadDataPort && BusExtension->DataPortMapped) { + MmUnmapIoSpace(PipReadDataPort - 3, 4); + PipReadDataPort = NULL; + BusExtension->DataPortMapped = FALSE; + } + PipReadDataPort = PipGetMappedAddress( + Isa, // InterfaceType + 0, // BusNumber, + cmResourceDescriptor->u.Port.Start, + cmResourceDescriptor->u.Port.Length, + cmResourceDescriptor->Flags, + &BusExtension->DataPortMapped + ); + if (PipReadDataPort) { + PipReadDataPort += 3; + PipBusExtension.ReadDataPort = PipReadDataPort; + } +exit0: + //ExFreePool(cmResource); + if (PipReadDataPort && PipCommandPort && PipAddressPort) { + *CmResourceList = cmResource; + return STATUS_SUCCESS; + } else { + return STATUS_INSUFFICIENT_RESOURCES; + } + +#else + + PCM_RESOURCE_LIST cmResource; + PCM_PARTIAL_RESOURCE_DESCRIPTOR cmResourceDescriptor; + NTSTATUS status; + ULONG size; + PIO_RESOURCE_REQUIREMENTS_LIST ioResource; + ULONG i; + + // + // Create a static Io resource requirements list and + // Call I/O mgr to get address, command and read data port addresses assigned. + // + + size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + + sizeof (IO_RESOURCE_DESCRIPTOR) * 2; + ioResource = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, size); + RtlZeroMemory(ioResource, size); + ioResource->ListSize = size; + ioResource->InterfaceType = Isa; + ioResource->AlternativeLists = 1; + ioResource->List[0].Version = 1; + ioResource->List[0].Revision = 1; + ioResource->List[0].Count = 3; + ioResource->List[0].Descriptors[0].Type = CmResourceTypePort; + ioResource->List[0].Descriptors[0].ShareDisposition = CmResourceShareDeviceExclusive; + ioResource->List[0].Descriptors[0].Flags = CM_RESOURCE_PORT_IO; + ioResource->List[0].Descriptors[0].u.Port.Length = PortLength; + ioResource->List[0].Descriptors[0].u.Port.Alignment = Alignment; + ioResource->List[0].Descriptors[0].u.Port.MinimumAddress = BaseAddressLow; + ioResource->List[0].Descriptors[0].u.Port.MaximumAddress = BaseAddressHi; + ioResource->List[0].Descriptors[1].Type = CmResourceTypePort; + ioResource->List[0].Descriptors[1].ShareDisposition = CmResourceShareDeviceExclusive; + ioResource->List[0].Descriptors[1].Flags = CM_RESOURCE_PORT_IO; + ioResource->List[0].Descriptors[1].u.Port.Length = 1; + ioResource->List[0].Descriptors[1].u.Port.Alignment = 1; + ioResource->List[0].Descriptors[1].u.Port.MinimumAddress.LowPart = ADDRESS_PORT; + ioResource->List[0].Descriptors[1].u.Port.MaximumAddress.LowPart = ADDRESS_PORT; + ioResource->List[0].Descriptors[2].Type = CmResourceTypePort; + ioResource->List[0].Descriptors[2].ShareDisposition = CmResourceShareDeviceExclusive; + ioResource->List[0].Descriptors[2].Flags = CM_RESOURCE_PORT_IO; + ioResource->List[0].Descriptors[2].u.Port.Length = 1; + ioResource->List[0].Descriptors[2].u.Port.Alignment = 1; + ioResource->List[0].Descriptors[2].u.Port.MinimumAddress.LowPart = COMMAND_PORT; + ioResource->List[0].Descriptors[2].u.Port.MaximumAddress.LowPart = COMMAND_PORT; + + status = IoAssignResources(RegistryPath, + NULL, + DriverObject, + NULL, + ioResource, + &cmResource); + ExFreePool(ioResource); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE,"PnpIsa: IoAssignResources failed\n")); + return status; + } + + // + // Map port addr to memory addr if necessary. + // + + ASSERT(cmResource->List->PartialResourceList.Count == 3); + for (i = 0; i < cmResource->List->PartialResourceList.Count; i++) { + cmResourceDescriptor = + &cmResource->List->PartialResourceList.PartialDescriptors[i]; + ASSERT(cmResourceDescriptor->Type == CmResourceTypePort); + if (cmResourceDescriptor->u.Port.Start.LowPart == ADDRESS_PORT) { + if (PipAddressPort == NULL) { + BusExtension->AddressPort = + PipAddressPort = PipGetMappedAddress( + Isa, // InterfaceType + 0, // BusNumber, + cmResourceDescriptor->u.Port.Start, + cmResourceDescriptor->u.Port.Length, + cmResourceDescriptor->Flags, + &BusExtension->AddrPortMapped + ); + } + } else if (cmResourceDescriptor->u.Port.Start.LowPart == COMMAND_PORT) { + if (PipCommandPort == NULL) { + BusExtension->CommandPort = + PipCommandPort = PipGetMappedAddress( + Isa, // InterfaceType + 0, // BusNumber, + cmResourceDescriptor->u.Port.Start, + cmResourceDescriptor->u.Port.Length, + cmResourceDescriptor->Flags, + &BusExtension->CmdPortMapped + ); + } + } else { + if ((cmResourceDescriptor->u.Port.Start.LowPart & 0xf) == 0) { + + // + // Some cards (e.g. 3COM elnkiii) do not response to 0xyy3 addr. + // + + DebugPrint((DEBUG_BREAK, "PnpIsa:ReadDataPort is at yy3\n")); + goto exit0; + } + if (PipReadDataPort && BusExtension->DataPortMapped) { + MmUnmapIoSpace(PipReadDataPort, 4); + PipReadDataPort = NULL; + BusExtension->DataPortMapped = FALSE; + } + PipReadDataPort = PipGetMappedAddress( + Isa, // InterfaceType + 0, // BusNumber, + cmResourceDescriptor->u.Port.Start, + cmResourceDescriptor->u.Port.Length, + cmResourceDescriptor->Flags, + &BusExtension->DataPortMapped + ); + if (PipReadDataPort) { + PipReadDataPort += 3; + PipBusExtension.ReadDataPort = PipReadDataPort; + } + } + } +exit0: + ExFreePool(cmResource); + if (PipReadDataPort && PipCommandPort && PipAddressPort) { + return STATUS_SUCCESS; + } else { + IoAssignResources(RegistryPath, + NULL, + DriverObject, + NULL, + NULL, + NULL); + return STATUS_INSUFFICIENT_RESOURCES; + } +#endif // 1 +} + +PVOID +PipGetMappedAddress( + IN INTERFACE_TYPE BusType, + IN ULONG BusNumber, + IN PHYSICAL_ADDRESS IoAddress, + IN ULONG NumberOfBytes, + IN ULONG AddressSpace, + OUT PBOOLEAN MappedAddress + ) + +/*++ + +Routine Description: + + This routine maps an IO address to system address space. + +Arguments: + + BusType - Supplies the type of bus - eisa, mca, isa... + + IoBusNumber - Supplies the bus number. + + IoAddress - Supplies the base device address to be mapped. + + NumberOfBytes - Supplies the number of bytes for which the address is + valid. + + AddressSpace - Supplies whether the address is in io space or memory. + + MappedAddress - Supplies whether the address was mapped. This only has + meaning if the address returned is non-null. + +Return Value: + + The mapped address. + +--*/ + +{ + PHYSICAL_ADDRESS cardAddress; + PVOID address; + + HalTranslateBusAddress(BusType, BusNumber, IoAddress, &AddressSpace, + &cardAddress); + + // + // Map the device base address into the virtual address space + // if the address is in memory space. + // + + if (!AddressSpace) { + + address = MmMapIoSpace(cardAddress, NumberOfBytes, FALSE); + *MappedAddress = (address ? TRUE : FALSE); + + } else { + + address = (PVOID) cardAddress.LowPart; + *MappedAddress = FALSE; + } + + return address; +} + diff --git a/private/ntos/nthals/extender/pnpisa.sur/isolate.c b/private/ntos/nthals/extender/pnpisa.sur/isolate.c new file mode 100644 index 000000000..8e050358f --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa.sur/isolate.c @@ -0,0 +1,1607 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + isolate.c + +Abstract: + + +Author: + + Shie-Lin Tzong (shielint) July-10-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "busp.h" +#include "pbios.h" +#include "pnpisa.h" + +BOOLEAN +PipFindIrqInformation ( + IN ULONG IrqLevel, + IN PUCHAR BiosRequirements, + OUT PUCHAR Information + ); + +BOOLEAN +PipFindMemoryInformation ( + IN ULONG Base, + IN ULONG Limit, + IN PUCHAR BiosRequirements, + OUT PUCHAR NameTag, + OUT PUCHAR Information + ); + +BOOLEAN +PipFindIoPortInformation ( + IN ULONG BaseAddress, + IN PUCHAR BiosRequirements, + OUT PUCHAR Information, + OUT PUCHAR Alignment, + OUT PUCHAR RangeLength + ); + +VOID +PipReadCardResourceDataBytes ( + IN USHORT BytesToRead, + IN PUCHAR Buffer + ); + +// +// Internal type definitions +// + +typedef struct _MEMORY_DESC_{ + ULONG Base; + ULONG Length; + BOOLEAN Memory32; +} MEMORY_DESC, *PMEMORY_DESC; + +typedef struct _IRQ_DESC_{ + UCHAR Level; + ULONG Type; +}IRQ_DESC, *PIRQ_DESC; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,PipFindIrqInformation) +#pragma alloc_text(INIT,PipFindMemoryInformation) +#pragma alloc_text(INIT,PipFindIoPortInformation) +#pragma alloc_text(INIT,PipReadCardResourceData) +#pragma alloc_text(INIT,PipReadDeviceBootResourceData) +#pragma alloc_text(INIT,PipWriteDeviceBootResourceData) +#pragma alloc_text(INIT,PipLFSRInitiation) +#pragma alloc_text(INIT,PipIsolateCards) +#pragma alloc_text(INIT,PipFindNextLogicalDeviceTag) +#pragma alloc_text(INIT,PipSelectLogicalDevice) +#pragma alloc_text(INIT,PipReadCardResourceDataBytes) +#endif + +BOOLEAN +PipFindIrqInformation ( + IN ULONG IrqLevel, + IN PUCHAR BiosRequirements, + OUT PUCHAR Information + ) + +/*++ + +Routine Description: + + This routine searches the Bios resource requirement lists for the corresponding + Irq descriptor information. The search stops when we encounter another logical + device id tag or the END tag. On input, the BiosRequirements points to current + logical id tag. + +Arguments: + + IrqLevel - Supplies the irq level. + + BiosRequirements - Supplies a pointer to the bios resource requirement lists. This + parameter must point to the logical device Id tag. + + Information - supplies a pointer to a UCHAR to receive the port information/flags. + +Return Value: + + TRUE - if memory information found. Else False. + +--*/ +{ + UCHAR tag; + ULONG increment; + USHORT irqMask; + PPNP_IRQ_DESCRIPTOR biosDesc; + + // + // Skip current logical id tag + // + + tag = *BiosRequirements; + ASSERT((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID); + BiosRequirements += (tag & SMALL_TAG_SIZE_MASK) + 1; + + // + // Search the possible resource list to get the information + // for the Irq. + // + + irqMask = 1 << IrqLevel; + tag = *BiosRequirements; + while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)) { + if ((tag & SMALL_TAG_MASK) == TAG_IRQ) { + biosDesc = (PPNP_IRQ_DESCRIPTOR)BiosRequirements; + if (biosDesc->IrqMask & irqMask) { + if ((tag & SMALL_TAG_SIZE_MASK) == 2) { + + // + // if no irq info is available, a value of zero is returned. + // (o is not a valid irq information.) + // + + *Information = 0; + } else { + *Information = biosDesc->Information; + } + return TRUE; + } + } + increment = (tag & SMALL_TAG_SIZE_MASK) + 1; + BiosRequirements += increment; + tag = *BiosRequirements; + } + return FALSE; +} + +BOOLEAN +PipFindMemoryInformation ( + IN ULONG BaseAddress, + IN ULONG Limit, + IN PUCHAR BiosRequirements, + OUT PUCHAR NameTag, + OUT PUCHAR Information + ) + +/*++ + +Routine Description: + + This routine searches the Bios resource requirement lists for the corresponding + memory descriptor information. The search stops when we encounter another logical + device id tag or the END tag. Note, the memory range specified by Base + and Limit must be within a single Pnp ISA memory descriptor. + +Arguments: + + BaseAddress - Supplies the base address of the memory range. + + Limit - Supplies the upper limit of the memory range. + + BiosRequirements - Supplies a pointer to the bios resource requirement lists. This + parameter must point to the logical device Id tag. + + NameTag - Supplies a variable to receive the Tag of the memory descriptor which + describes the memory information. + + Information - supplies a pointer to a UCHAR to receive the memory information + for the specified memory range. + +Return Value: + + TRUE - if memory information found. Else False. + +--*/ +{ + UCHAR tag; + BOOLEAN found = FALSE; + ULONG minAddr, length, maxAddr, alignment; + USHORT increment; + + // + // Skip current logical id tag. + // + + tag = *BiosRequirements; + ASSERT((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID); + BiosRequirements += (tag & SMALL_TAG_SIZE_MASK) + 1; + + // + // Search the possible resource list to get the information + // for the memory range described by Base and Limit. + // + + tag = *BiosRequirements; + while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)) { + switch (tag) { + case TAG_MEMORY: + minAddr = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MinimumAddress)) << 8; + length = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MemorySize)) << 8; + maxAddr = (((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MaximumAddress)) << 8) + + length - 1; + break; + case TAG_MEMORY32: + length = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MemorySize; + minAddr = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MinimumAddress; + maxAddr = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MaximumAddress + + length - 1; + break; + case TAG_MEMORY32_FIXED: + length = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)BiosRequirements)->MemorySize; + minAddr = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)BiosRequirements)->BaseAddress; + maxAddr = minAddr + length - 1; + break; + } + + if (minAddr <= BaseAddress && maxAddr >= Limit) { + *Information = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->Information; + *NameTag = tag; + found = TRUE; + break; + } + + // + // Advance to next tag + // + + if (tag & LARGE_RESOURCE_TAG) { + increment = *(PUCHAR)(BiosRequirements + 1); + increment += 3; // length of large tag + } else { + increment = tag & SMALL_TAG_SIZE_MASK; + increment += 1; // length of small tag + } + BiosRequirements += increment; + tag = *BiosRequirements; + } + return found; +} + +BOOLEAN +PipFindIoPortInformation ( + IN ULONG BaseAddress, + IN PUCHAR BiosRequirements, + OUT PUCHAR Information, + OUT PUCHAR Alignment, + OUT PUCHAR RangeLength + ) + +/*++ + +Routine Description: + + This routine searches the Bios resource requirement lists for the corresponding + Io port descriptor information. The search stops when we encounter another logical + device id tag or the END tag. + +Arguments: + + BaseAddress - Supplies the base address of the Io port range. + + BiosRequirements - Supplies a pointer to the bios resource requirement lists. This + parameter must point to the logical device Id tag. + + Information - supplies a pointer to a UCHAR to receive the port information/flags. + + Alignment - supplies a pointer to a UCHAR to receive the port alignment + information. + + RangeLength - supplies a pointer to a UCHAR to receive the port range length + information. + +Return Value: + + TRUE - if memory information found. Else False. + +--*/ +{ + UCHAR tag; + BOOLEAN found = FALSE; + ULONG minAddr, length, maxAddr, alignment; + USHORT increment; + PPNP_PORT_DESCRIPTOR portDesc; + PPNP_FIXED_PORT_DESCRIPTOR fixedPortDesc; + + tag = *BiosRequirements; + ASSERT((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID); + BiosRequirements += (tag & SMALL_TAG_SIZE_MASK) + 1; + + // + // Search the possible resource list to get the information + // for the io port range described by Base. + // + + tag = *BiosRequirements; + while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)) { + switch (tag & SMALL_TAG_MASK) { + case TAG_IO: + portDesc = (PPNP_PORT_DESCRIPTOR)BiosRequirements; + minAddr = portDesc->MinimumAddress; + maxAddr = portDesc->MaximumAddress; + if (minAddr <= BaseAddress && maxAddr >= BaseAddress) { + *Information = portDesc->Information; + *Alignment = portDesc->Alignment; + *RangeLength = portDesc->Length; + found = TRUE; + } + break; + case TAG_IO_FIXED: + fixedPortDesc = (PPNP_FIXED_PORT_DESCRIPTOR)BiosRequirements; + minAddr = fixedPortDesc->MinimumAddress; + if (BaseAddress == minAddr) { + *Information = 0; // 10 bit decode + *Alignment = 1; + *RangeLength = fixedPortDesc->Length; + found = TRUE; + } + break; + } + + if (found) { + break; + } + + // + // Advance to next tag + // + + if (tag & LARGE_RESOURCE_TAG) { + increment = *(PUCHAR)(BiosRequirements + 1); + increment += 3; // length of large tag + } else { + increment = tag & SMALL_TAG_SIZE_MASK; + increment += 1; // length of small tag + } + BiosRequirements += increment; + tag = *BiosRequirements; + } + return found; +} + +NTSTATUS +PipReadCardResourceData ( + IN ULONG Csn, + OUT PULONG NumberLogicalDevices, + IN PUCHAR *ResourceData, + OUT PULONG ResourceDataLength + ) + +/*++ + +Routine Description: + + This routine reads resources data from a specified PnP ISA card. It is + caller's responsibility to release the memory. Before calling this routine, + the Pnp ISA card should be in sleep state (i.e. Initiation Key was sent.) + After exiting this routine, the card will be left in Config state. + +Arguments: + + Csn - Specifies the CardSelectNumber to indicate which PNP ISA card. + + NumberLogicalDevices - supplies a variable to receive the number of logical devices + associated with the Pnp Isa card. + + ResourceData - Supplies a variable to receive the pointer to the resource data. + + ResourceDataLength - Supplies a variable to receive the length of the ResourceData. + +Return Value: + + NT STATUS code. + +--*/ +{ + + PUCHAR buffer, p; + LONG sizeToRead, limit, i; + USHORT size; + UCHAR tag; + ULONG noDevices; + BOOLEAN failed; + + // + // Allocate memory to store the resource data. + // N.B. The buffer size should cover 99.999% of the machines. + // + + sizeToRead = 4096; + +tryAgain: + + noDevices = 0; + buffer = (PUCHAR)ExAllocatePoolWithTag(PagedPool, sizeToRead, 'iPnP'); + if (!buffer) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Send card from sleep state to configuration state + // Note, by doing this the resource data includes 9 bytes Id. + // + + PipWriteAddress (WAKE_CSN_PORT); + PipWriteData((UCHAR)Csn); + + // + // Read card id bytes + // + + p = buffer; + PipReadCardResourceDataBytes(NUMBER_CARD_ID_BYTES, p); + i = NUMBER_CARD_ID_BYTES; + p += NUMBER_CARD_ID_BYTES; + + // + // read all the tag descriptors of the card resource data + // + + failed = FALSE; + limit = sizeToRead - 4 - NUMBER_CARD_ID_BYTES;; + + while (TRUE) { + + // + // Read tag byte. Make sure it's a valid tag and determine + // the size of the descriptor. + // + + PipReadCardResourceDataBytes(1, p); + tag = *p; + i++; + p++; + if (tag == TAG_COMPLETE_END) { + PipReadCardResourceDataBytes(1, p); + p++; + i++; + break; + } + if (tag & LARGE_RESOURCE_TAG) { + if (tag & 0x70) { + failed = TRUE; + break; + } else { + PipReadCardResourceDataBytes(2, p); + size = *((PUSHORT)p); + p += 2; + i += 2; + } + } else { + if ((tag & 0x70) == 0x50 || (tag & 0x70) == 0x60 || (((tag & 0x70) == 0) && (tag != 0xa))) { + failed = TRUE; + break; + } else { + if ((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID) { + noDevices++; + } + size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); + } + } + + // + // read 'size' number of bytes for the current descriptor + // + + i += size; + if (i < limit) { + PipReadCardResourceDataBytes(size, p); + p += size; + } else { + ExFreePool(buffer); + sizeToRead <<= 1; // double the buffer + + // + // If we can find the END tag with 32K byte, assume the resource + // requirement list is bad. + // + + if (sizeToRead > 0x80000) { + return STATUS_INVALID_PARAMETER; + } else { + goto tryAgain; + } + } + } + if (failed) { + ExFreePool(buffer); + return STATUS_UNSUCCESSFUL; + } + + // + // Determine the real size of the buffer required and + // resize the buffer. + // + + size = p - buffer; // i + p = (PUCHAR)ExAllocatePoolWithTag(PagedPool, size, 'iPnP'); + if (p) { + RtlMoveMemory(p, buffer, size); + ExFreePool(buffer); + } else { + + // + // Fail to resize the buffer. Simply leave it alone. + // + + p = buffer; + } + + // + // Should we leave card in config state??? + // + + *ResourceData = p; + *NumberLogicalDevices = noDevices; + *ResourceDataLength = size; + return STATUS_SUCCESS; +} + +NTSTATUS +PipReadDeviceBootResourceData ( + IN ULONG BusNumber, + IN PUCHAR BiosRequirements, + OUT PCM_RESOURCE_LIST *ResourceData, + OUT PULONG Length + ) + +/*++ + +Routine Description: + + This routine reads boot resource data from an enabled logical device of a PNP ISA + card. Caller must put the card into configuration state and select the logical + device before calling this function. It is caller's responsibility to release + the memory. ( The boot resource data is the resources that a card assigned during + boot.) + +Arguments: + + BusNumber - specifies the bus number of the device whose resource data to be read. + + BiosRequirements - Supplies a pointer to the resource requirement list for the logical + device. This parameter must point to the logical device Id tag. + + ResourceData - Supplies a variable to receive the pointer to the resource data. + + Length - Supplies a variable to recieve the length of the resource data. + +Return Value: + + NT STATUS code. + +--*/ +{ + + UCHAR c, junk1, junk2; + PUCHAR base; + ULONG l, resourceCount; + BOOLEAN limit; + LONG i, j, noMemoryDesc = 0, noIoDesc = 0, noDmaDesc =0, noIrqDesc = 0; + MEMORY_DESC memoryDesc[NUMBER_MEMORY_DESCRIPTORS + NUMBER_32_MEMORY_DESCRIPTORS]; + IRQ_DESC irqDesc[NUMBER_IRQ_DESCRIPTORS]; + UCHAR dmaDesc[NUMBER_DMA_DESCRIPTORS]; + USHORT ioDesc[NUMBER_IO_DESCRIPTORS]; + PCM_RESOURCE_LIST cmResource; + PCM_PARTIAL_RESOURCE_LIST partialResList; + PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDesc; + +#if 0 + PipWriteAddress(ACTIVATE_PORT); + if (!(PipReadData() & 1)) { + DebugPrint((DEBUG_MESSAGE, "PnpIsa-ReadDeviceBootResourceData:The logical device has not been activated\n")); + } +#endif // DBG + + // + // First make sure the specified BiosRequirements is valid and at the right tag. + // + + if (!BiosRequirements && ((*BiosRequirements & SMALL_TAG_MASK) != TAG_LOGICAL_ID)) { + return STATUS_INVALID_PARAMETER; + } + + // + // Read memory configuration + // + + base = (PUCHAR)ADDRESS_MEMORY_BASE; + for (i = 0; i < NUMBER_MEMORY_DESCRIPTORS; i++) { + + // + // Read memory base address + // + + PipWriteAddress(base + ADDRESS_MEMORY_HI); + c = PipReadData(); + l = c; + l <<= 8; + PipWriteAddress(base + ADDRESS_MEMORY_LO); + c = PipReadData(); + l |= c; + l <<= 8; // l = memory base address + if (l == 0) { + break; + } + + memoryDesc[noMemoryDesc].Base = l; + + // + // Read memory control byte + // + + PipWriteAddress(base + ADDRESS_MEMORY_CTL); + c= PipReadData(); + limit = c & 1; + + // + // Read memory upper limit address or range length + // + + PipWriteAddress(base + ADDRESS_MEMORY_UPPER_HI); + c = PipReadData(); + l = c; + l <<= 8; + PipWriteAddress(base + ADDRESS_MEMORY_UPPER_LO); + c = PipReadData(); + l |= c; + l <<= 8; + + if (limit == ADDRESS_MEMORY_CTL_LIMIT) { + l = l - memoryDesc[noMemoryDesc].Base; + } + memoryDesc[noMemoryDesc].Length = l; + memoryDesc[noMemoryDesc].Memory32 = FALSE; + noMemoryDesc++; + base += ADDRESS_MEMORY_INCR; + } + + // + // Read memory 32 configuration + // + + for (i = 0; i < NUMBER_32_MEMORY_DESCRIPTORS; i++) { + + base = ADDRESS_32_MEMORY_BASE(i); + + // + // Read memory base address + // + + l = 0; + for (j = ADDRESS_32_MEMORY_B3; j <= ADDRESS_32_MEMORY_B0; j++) { + PipWriteAddress(base + j); + c = PipReadData(); + l <<= 8; + l |= c; + } + if (l == 0) { + break; + } + + memoryDesc[noMemoryDesc].Base = l; + + // + // Read memory control byte + // + + PipWriteAddress(base + ADDRESS_32_MEMORY_CTL); + c= PipReadData(); + limit = c & 1; + + // + // Read memory upper limit address or range length + // + + l = 0; + for (j = ADDRESS_32_MEMORY_E3; j <= ADDRESS_32_MEMORY_E0; j++) { + PipWriteAddress(base + j); + c = PipReadData(); + l <<= 8; + l |= c; + } + + if (limit == ADDRESS_MEMORY_CTL_LIMIT) { + l = l - memoryDesc[noMemoryDesc].Base; + } + memoryDesc[noMemoryDesc].Length = l; + memoryDesc[noMemoryDesc].Memory32 = TRUE; + noMemoryDesc++; + } + + // + // Read Io Port Configuration + // + + base = (PUCHAR)ADDRESS_IO_BASE; + for (i = 0; i < NUMBER_IO_DESCRIPTORS; i++) { + PipWriteAddress(base + ADDRESS_IO_BASE_HI); + c = PipReadData(); + l = c; + PipWriteAddress(base + ADDRESS_IO_BASE_LO); + c = PipReadData(); + l <<= 8; + l |= c; + if (l == 0) { + break; + } + ioDesc[noIoDesc++] = (USHORT)l; + base += ADDRESS_IO_INCR; + } + + // + // Read Interrupt configuration + // + + base = (PUCHAR)ADDRESS_IRQ_BASE; + for (i = 0; i < NUMBER_IRQ_DESCRIPTORS; i++) { + PipWriteAddress(base + ADDRESS_IRQ_VALUE); + c = PipReadData() & 0xf; + if (c == 0) { + break; + } + irqDesc[noIrqDesc].Level = c; + PipWriteAddress(base + ADDRESS_IRQ_TYPE); + c = PipReadData(); + irqDesc[noIrqDesc++].Type = c; + base += ADDRESS_IRQ_INCR; + } + + // + // Read DMA configuration + // + + base = (PUCHAR)ADDRESS_DMA_BASE; + for (i = 0; i < NUMBER_DMA_DESCRIPTORS; i++) { + PipWriteAddress(base + ADDRESS_DMA_VALUE); + c = PipReadData() & 0x7; + if (c == 4) { + break; + } + dmaDesc[noDmaDesc++] = c; + base += ADDRESS_DMA_INCR; + } + + // + // Construct CM_RESOURCE_LIST structure based on the resource data + // we collect so far. + // + + resourceCount = noMemoryDesc + noIoDesc + noDmaDesc + noIrqDesc; + + // + // if empty bios resources, simply return. + // + + if (resourceCount == 0) { + *ResourceData = NULL; + *Length = 0; + return STATUS_SUCCESS; + } + + l = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + ( resourceCount - 1); + cmResource = ExAllocatePoolWithTag(PagedPool, l, 'iPnP'); + if (!cmResource) { + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlZeroMemory(cmResource, l); + *Length = l; // Set returned resource data length + cmResource->Count = 1; + cmResource->List[0].InterfaceType = Isa; + cmResource->List[0].BusNumber = BusNumber; + partialResList = (PCM_PARTIAL_RESOURCE_LIST)&cmResource->List[0].PartialResourceList; + partialResList->Version = 0; + partialResList->Revision = 0x3000; + partialResList->Count = resourceCount; + partialDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)&partialResList->PartialDescriptors[0]; + + // + // Set up all the CM memory descriptors + // + + for (i = 0; i < noMemoryDesc; i++) { + partialDesc->Type = CmResourceTypeMemory; + partialDesc->ShareDisposition = CmResourceShareDeviceExclusive; + partialDesc->u.Memory.Length = memoryDesc[i].Length; + partialDesc->u.Memory.Start.HighPart = 0; + partialDesc->u.Memory.Start.LowPart = memoryDesc[i].Base; + + // + // Need to consult configuration data for the Flags + // + + l = memoryDesc[i].Base + memoryDesc[i].Length - 1; + if (PipFindMemoryInformation (memoryDesc[i].Base, l, BiosRequirements, &junk1, &c)) { + if (c & PNP_MEMORY_WRITE_STATUS_MASK) { + partialDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE; + } else { + partialDesc->Flags = CM_RESOURCE_MEMORY_READ_ONLY; + } + } else { + DebugPrint((DEBUG_BREAK, "PnpIsa-ReadDeviceBootResourceData:No matched memory information in config data\n")); + partialDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE; + } + if (memoryDesc[i].Memory32 == FALSE) { + partialDesc->Flags |= CM_RESOURCE_MEMORY_24; + } + partialDesc++; + } + + // + // Set up all the CM io/port descriptors + // + + for (i = 0; i < noIoDesc; i++) { + partialDesc->Type = CmResourceTypePort; + partialDesc->ShareDisposition = CmResourceShareDeviceExclusive; + partialDesc->Flags = CM_RESOURCE_PORT_IO; + partialDesc->u.Port.Start.LowPart = ioDesc[i]; + + // + // Need to consult configuration data for the Port length + // + + if (PipFindIoPortInformation (ioDesc[i], BiosRequirements, &junk1, &junk2, &c)) { + partialDesc->u.Port.Length = c; + partialDesc++; + } else { + DebugPrint((DEBUG_BREAK, "PnpIsa-ReadDeviceBootResourceData:No matched port length in config data\n")); + ExFreePool(cmResource); + *ResourceData = NULL; + return STATUS_UNSUCCESSFUL; + } + } + + // + // Set up all the CM DMA descriptors + // + + for (i = 0; i < noDmaDesc; i++) { + partialDesc->Type = CmResourceTypeDma; + partialDesc->ShareDisposition = CmResourceShareDeviceExclusive; + partialDesc->Flags = 0; // no flags for DMA descriptor + partialDesc->u.Dma.Channel = (ULONG) dmaDesc[i]; + partialDesc->u.Dma.Port = 0; + partialDesc->u.Dma.Reserved1 = 0; + partialDesc++; + } + + // + // Set up all the CM interrupt descriptors + // + + for (i = 0; i < noIrqDesc; i++) { + partialDesc->Type = CmResourceTypeInterrupt; + partialDesc->ShareDisposition = CmResourceShareDeviceExclusive; + if (irqDesc[i].Type & 1) { + partialDesc->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + } else { + partialDesc->Flags = CM_RESOURCE_INTERRUPT_LATCHED; + } + partialDesc->u.Interrupt.Vector = + partialDesc->u.Interrupt.Level = irqDesc[i].Level; + partialDesc->u.Interrupt.Affinity = (ULONG)-1; + partialDesc++; + } + + *ResourceData = cmResource; + return STATUS_SUCCESS; +} + +NTSTATUS +PipWriteDeviceBootResourceData ( + IN PUCHAR BiosRequirements, + IN PCM_RESOURCE_LIST CmResources + ) + +/*++ + +Routine Description: + + This routine writes boot resource data to an enabled logical device of + a Pnp ISA card. Caller must put the card into configuration state and select + the logical device before calling this function. + +Arguments: + + BiosRequirements - Supplies a pointer to the possible resources for the logical + device. This parameter must point to the logical device Id tag. + + ResourceData - Supplies a pointer to the cm resource data. + +Return Value: + + NT STATUS code. + +--*/ +{ + UCHAR c, information; + ULONG count, i, j, pass, base, limit; + PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDesc; + ULONG noIrq =0, noIo = 0, noDma = 0, noMemory = 0, no32Memory = 0; + PUCHAR memoryBase, irqBase, dmaBase, ioBase, tmp; + ULONG memory32Base; + +#if 0 + PipWriteAddress(ACTIVATE_PORT); + if (!(PipReadData() & 1)) { + DbgPrint("PnpIsa-WriteDeviceBootResourceData:The logical device has not been activated\n"); + } +#endif // DBG + + // + // First make sure the specified BiosRequirements is valid and at the right tag. + // + + if ((*BiosRequirements & SMALL_TAG_MASK) != TAG_LOGICAL_ID) { + return STATUS_INVALID_PARAMETER; + } + + count = CmResources->List[0].PartialResourceList.Count; + memoryBase = (PUCHAR)ADDRESS_MEMORY_BASE; + memory32Base = 0; + ioBase = (PUCHAR)ADDRESS_IO_BASE; + irqBase = (PUCHAR)ADDRESS_IRQ_BASE; + dmaBase = (PUCHAR)ADDRESS_DMA_BASE; + for (pass = 1; pass <= 2; pass++) { + + // + // First pass we make sure the resources to be set is acceptable. + // Second pass we actually write the resources to the logical device's + // configuration space. + // + + cmDesc = CmResources->List[0].PartialResourceList.PartialDescriptors; + for (i = 0; i < count; i++) { + switch (cmDesc->Type) { + case CmResourceTypePort: + if (pass == 1) { + noIo++; + if (noIo > NUMBER_IO_DESCRIPTORS || + cmDesc->u.Port.Start.HighPart != 0 || + cmDesc->u.Port.Start.LowPart & 0xffff0000 || + cmDesc->u.Port.Length & 0xffffff00) { + return STATUS_INVALID_PARAMETER; + } + } else { + + // + // Set the Io port base address to logical device configuration space + // + + c = (UCHAR)cmDesc->u.Port.Start.LowPart; + PipWriteAddress(ioBase + ADDRESS_IO_BASE_LO); + PipWriteData(c); + c = (UCHAR)(cmDesc->u.Port.Start.LowPart >> 8); + PipWriteAddress(ioBase + ADDRESS_IO_BASE_HI); + PipWriteData(c); + ioBase += ADDRESS_IO_INCR; + } + break; + case CmResourceTypeInterrupt: + if (pass == 1) { + noIrq++; + if (noIrq > NUMBER_IRQ_DESCRIPTORS || + (cmDesc->u.Interrupt.Level & 0xfffffff0)) { + return STATUS_INVALID_PARAMETER; + } + + // + // See if we can get the interrupt information from possible resource + // data. We need it to set the configuration register. + // + + if (!PipFindIrqInformation(cmDesc->u.Interrupt.Level, BiosRequirements, &information)) { + return STATUS_INVALID_PARAMETER; + } + } else { + + // + // Set the Irq to logical device configuration space + // + + c = (UCHAR)cmDesc->u.Interrupt.Level; + PipWriteAddress(irqBase + ADDRESS_IRQ_VALUE); + PipWriteData(c); + PipFindIrqInformation(cmDesc->u.Interrupt.Level, BiosRequirements, &information); + if (information != 0) { + switch (information & 0xf) { + case 1: // High true edge sensitive + c = 2; + break; + case 2: // Low true edge sensitive + c = 0; + break; + case 4: // High true level sensitive + c = 3; + break; + case 8: // Low true level sensitive + c = 1; + break; + } + PipWriteAddress(irqBase + ADDRESS_IRQ_TYPE); + PipWriteData(c); + } + irqBase += ADDRESS_IRQ_INCR; + } + break; + case CmResourceTypeDma: + if (pass == 1) { + noDma++; + if (noDma > NUMBER_IRQ_DESCRIPTORS || + (cmDesc->u.Dma.Channel & 0xfffffff8)) { + return STATUS_INVALID_PARAMETER; + } + } else { + + // + // Set the Dma channel to logical device configuration space + // + + c = (UCHAR)cmDesc->u.Dma.Channel; + PipWriteAddress(dmaBase + ADDRESS_DMA_VALUE); + PipWriteData(c); + dmaBase += ADDRESS_DMA_INCR; + } + break; + case CmResourceTypeMemory: + if (pass == 1) { + base = cmDesc->u.Memory.Start.LowPart; + limit = base + cmDesc->u.Memory.Length - 1; + if (!PipFindMemoryInformation(base, limit, BiosRequirements, &c, &information)) { + return STATUS_INVALID_PARAMETER; + } else { + if (cmDesc->Flags & CM_RESOURCE_MEMORY_24) { + noMemory++; + + // + // Make sure the lower 8 bits of the base address are zero. + // + + if (noMemory > NUMBER_MEMORY_DESCRIPTORS || + base & 0xff) { + return STATUS_INVALID_PARAMETER; + } + } else { + no32Memory++; + if (no32Memory > NUMBER_32_MEMORY_DESCRIPTORS) { + return STATUS_INVALID_PARAMETER; + } + } + } + } else { + + // + // Find information in BiosRequirements to help determine how to write + // the memory configuration space. + // + + base = cmDesc->u.Memory.Start.LowPart; + limit = base + cmDesc->u.Memory.Length - 1; + PipFindMemoryInformation(base, limit, BiosRequirements, &c, &information); + if (cmDesc->Flags & CM_RESOURCE_MEMORY_24) { + PipWriteAddress(memoryBase + ADDRESS_MEMORY_LO); + base >>= 8; + PipWriteData(base); + PipWriteAddress(memoryBase + ADDRESS_MEMORY_HI); + base >>= 8; + PipWriteData(base); + PipWriteAddress(memoryBase + ADDRESS_MEMORY_CTL); + c = 2 + ADDRESS_MEMORY_CTL_LIMIT; // assume 16 bit memory + if (information & 0x18 == 0) { // 8 bit memory only + c = 0 + ADDRESS_MEMORY_CTL_LIMIT; + } + PipWriteData(c); + limit >>= 8; + PipWriteAddress(memoryBase + ADDRESS_MEMORY_UPPER_LO); + PipWriteData((UCHAR)limit); + limit >>= 8; + PipWriteAddress(memoryBase + ADDRESS_MEMORY_UPPER_HI); + PipWriteData((UCHAR)limit); + memoryBase += ADDRESS_MEMORY_INCR; + } else { + tmp = ADDRESS_32_MEMORY_BASE(memory32Base); + PipWriteAddress(tmp + ADDRESS_32_MEMORY_B0); + PipWriteData(base); + PipWriteAddress(tmp + ADDRESS_32_MEMORY_B1); + base >>= 8; + PipWriteData(base); + PipWriteAddress(tmp + ADDRESS_32_MEMORY_B2); + base >>= 8; + PipWriteData(base); + PipWriteAddress(tmp + ADDRESS_32_MEMORY_B3); + base >>= 8; + PipWriteData(base); + switch (information & 0x18) { + case 0: // 8 bit only + c = ADDRESS_MEMORY_CTL_LIMIT; + case 8: // 16 bit only + case 0x10: // 8 and 16 bit supported + c = 2 + ADDRESS_MEMORY_CTL_LIMIT; + break; + case 0x18: // 32 bit only + c = 6 + ADDRESS_MEMORY_CTL_LIMIT; + break; + } + PipWriteAddress(ADDRESS_32_MEMORY_CTL); + PipWriteData(c); + PipWriteAddress(tmp + ADDRESS_32_MEMORY_E0); + PipWriteData(limit); + limit >>= 8; + PipWriteAddress(tmp + ADDRESS_32_MEMORY_E1); + PipWriteData(limit); + limit >>= 8; + PipWriteAddress(tmp + ADDRESS_32_MEMORY_E2); + PipWriteData(limit); + limit >>= 8; + PipWriteAddress(tmp + ADDRESS_32_MEMORY_E3); + PipWriteData(limit); + memory32Base++; + } + } + } + cmDesc++; + } + } + + // + // Finally, mark all the unused descriptors as disabled. + // + + for (i = noMemory; i < NUMBER_MEMORY_DESCRIPTORS; i++) { + for (j = 0; j < 5; j++) { + PipWriteAddress(memoryBase + j); + PipWriteData(0); + } + memoryBase += ADDRESS_MEMORY_INCR; + } + for (i = no32Memory; i < NUMBER_32_MEMORY_DESCRIPTORS; i++) { + tmp = ADDRESS_32_MEMORY_BASE(memory32Base); + for (j = 0; j < 9; j++) { + PipWriteAddress(tmp + j); + PipWriteData(0); + } + memory32Base++; + } + for (i = noIo; i < NUMBER_IO_DESCRIPTORS; i++) { + for (j = 0; j < 2; j++) { + PipWriteAddress(ioBase + j); + PipWriteData(0); + } + ioBase += ADDRESS_IO_INCR; + } + for (i = noIrq; i < NUMBER_IRQ_DESCRIPTORS; i++) { + for (j = 0; j < 2; j++) { + PipWriteAddress(irqBase + j); + PipWriteData(0); + } + irqBase += ADDRESS_IRQ_INCR; + } + for (i = noDma; i < NUMBER_DMA_DESCRIPTORS; i++) { + PipWriteAddress(dmaBase); + PipWriteData(4); + dmaBase += ADDRESS_DMA_INCR; + } + return STATUS_SUCCESS; +} + +VOID +PipLFSRInitiation ( + VOID + ) + +/*++ + +Routine Description: + + This routine insures the LFSR (linear feedback shift register) is in its + initial state and then performs 32 writes to the ADDRESS port to initiation + LFSR function. + + Pnp software sends the initiation key to all the Pnp ISA cards to place them + into configuration mode. The software then ready to perform isolation + protocol. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + UCHAR seed, bit7; + ULONG i; + + // + // First perform two writes of value zero to insure the LFSR is in the + // initial state. + // + + PipWriteAddress (0); + PipWriteAddress (0); + + // + // Perform the initiation key. + // + + seed = LFSR_SEED; // initial value of 0x6a + for (i = 0; i < 32; i++) { + PipWriteAddress (seed); + bit7=(((seed & 2) >> 1) ^ (seed & 1)) << 7; + seed =(seed >> 1) | bit7; + } +} + +VOID +PipIsolateCards ( + OUT PULONG NumberCSNs + ) + +/*++ + +Routine Description: + + This routine performs PnP ISA cards isolation sequence. + +Arguments: + + NumberCSNs - supplies the addr of a variable to receive the number of + Pnp Isa cards isolated. + + ReadDataPort - Supplies the address of a variable to supply ReadData port + address. + +Return Value: + + None. + +--*/ +{ + USHORT j, i; + UCHAR cardId[NUMBER_CARD_ID_BYTES]; + UCHAR bit, bit7, checksum, byte1, byte2; + ULONG csn = 0; + + *NumberCSNs = 0; + + // + // First send Initiation Key to all the PNP ISA cards to enable PnP auto-config + // ports and put all cards in configuration mode. + // + + PipLFSRInitiation (); + + // + // Reset all Pnp ISA cards' CSN to 0 and return to wait-for-key state + // + + PipWriteAddress (CONFIG_CONTROL_PORT); + PipWriteData (CONTROL_WAIT_FOR_KEY | CONTROL_RESET_CSN); + + // + // Delay 2 msec for cards to load initial configuration state. + // + + KeStallExecutionProcessor(20000); // delay 2 msec + + // + // Put cards into configuration mode to ready isolation process. + // The hardware on each PnP Isa card expects 72 pairs of I/O read + // access to the read data port. + // + + PipLFSRInitiation (); + + // + // Starting Pnp Isa card isolation process. + // + + // + // Send WAKE[CSN=0] to force all cards without CSN into isolation + // state to set READ DATA PORT. + // + + PipWriteAddress(WAKE_CSN_PORT); + PipWriteData(0); + + // + // Set read data port to current testing value. + // + + PipWriteAddress(SET_READ_DATA_PORT); + PipWriteData((UCHAR)((ULONG)PipReadDataPort >> 2)); + + // + // Isolate one PnP ISA card until fail + // + + while (TRUE) { + + // + // Read serial isolation port to cause PnP cards in the isolation + // state to compare one bit of the boards ID. + // + + PipWriteAddress(SERIAL_ISOLATION_PORT); + + // + // We need to delay 1 msec prior to starting the first pair of isolation + // reads and must wait 250usec between each subsequent pair of isolation + // reads. This delay gives the ISA cards time to access information from + // possible very slow storage device. + // + + KeStallExecutionProcessor(10000); // delay 1 msec + + RtlZeroMemory(cardId, NUMBER_CARD_ID_BYTES); + checksum = LFSR_SEED; + for (j = 0; j < NUMBER_CARD_ID_BITS; j++) { + + // + // Read card id bit by bit + // + + byte1 = PipReadData(); + byte2 = PipReadData(); + bit = (byte1 == ISOLATION_TEST_BYTE_1) && (byte2 == ISOLATION_TEST_BYTE_2); + cardId[j / 8] |= bit << (j % 8); + if (j < CHECKSUMED_BITS) { + + // + // Calculate checksum and only do it for the first 64 bits + // + + bit7 = (((checksum & 2) >> 1) ^ (checksum & 1) ^ (bit)) << 7; + checksum = (checksum >> 1) | bit7; + } + KeStallExecutionProcessor(2500); // delay 250 usec + } + + // + // Verify the card id we read is legitimate + // First make sure checksum is valid. Note zero checksum is considered valid. + // + + if (cardId[8] == 0 || checksum == cardId[8]) { + + // + // Next make sure cardId is not zero + // + + byte1 = 0; + for (j = 0; j < NUMBER_CARD_ID_BYTES; j++) { + byte1 |= cardId[j]; + } + if (byte1 != 0) { + + // + // We found a valid Pnp Isa card, assign it a CSN number + // + + PipWriteAddress(SET_CSN_PORT); + + PipWriteData(++csn); + + // + // Do Wake[CSN] command to put the newly isolated card to + // sleep state and other un-isolated cards to isolation + // state. + // + + PipWriteAddress(WAKE_CSN_PORT); + PipWriteData(0); + + continue; // ... to isolate more cards ... + } + } + break; // could not isolate more cards ... + } + + // + // Finaly put all cards into wait for key state. + // + + PipWriteAddress(CONFIG_CONTROL_PORT); + PipWriteData(CONTROL_WAIT_FOR_KEY); + *NumberCSNs = csn; +} + +ULONG +PipFindNextLogicalDeviceTag ( + IN OUT PUCHAR *CardData, + IN OUT LONG *Limit + ) + +/*++ + +Routine Description: + + This function searches the Pnp Isa card data for the Next logical + device tag encountered. The input *CardData should point to an logical device id tag, + which is the current logical device tag. If the *CardData does not point to a logical + device id tag (but, it must point to some kind of tag), it will be moved to next + logical device id tag. + +Arguments: + + CardData - a variable to supply a pointer to the pnp Isa resource descriptors and to + receive next logical device tag pointer. + + Limit - a variable to supply the maximum length of the search and to receive the new + lemit after the search. + +Return Value: + + Length of the data between current and next logical device tags, ie the data length + of the current logical device. + In case there is no 'next' logical device tag, the returned *CardData = NULL, + *Limit = zero and the data length of current logical tag is returned as function + returned value. + +--*/ +{ + UCHAR tag; + USHORT size; + LONG l; + ULONG retLength; + PUCHAR p; + BOOLEAN atIdTag = FALSE;; + + p = *CardData; + l = *Limit; + tag = *p; + retLength = 0; + while (tag != TAG_COMPLETE_END && l > 0) { + + // + // Determine the size of the BIOS resource descriptor + // + + if (!(tag & LARGE_RESOURCE_TAG)) { + size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); + size += 1; // length of small tag + } else { + size = *((PUSHORT)(p + 1)); + size += 3; // length of large tag + } + + p += size; + retLength += size; + l -= size; + tag = *p; + if ((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID) { + *CardData = p; + *Limit = l; + return retLength; + } + } + *CardData = NULL; + *Limit = 0; + if (tag == TAG_COMPLETE_END) { + return (retLength + 2); // add 2 for the length of end tag descriptor + } else { + return 0; + } +} + +VOID +PipSelectLogicalDevice ( + IN USHORT Csn, + IN USHORT LogicalDeviceNumber, + IN BOOLEAN Activate + ) + +/*++ + +Routine Description: + + This function selects the logical logical device in the specified device. + +Arguments: + + Csn - Supplies a CardSelectNumber to select the card. + + LogicalDeviceNumber - supplies a logical device number to select the logical device. + + Activate - supplies a BOOLEAN variable to specify if the logical device should be + enabled. + +Return Value: + + None +--*/ +{ + UCHAR tmp; + + // + // Put cards into configuration mode to ready isolation process. + // + + PipLFSRInitiation (); + + // + // Send WAKE[CSN] to force the card into config state. + // + + PipWriteAddress(WAKE_CSN_PORT); + PipWriteData(Csn); + + // + // Select the logical device. + // + + PipWriteAddress(LOGICAL_DEVICE_PORT); + PipWriteData(LogicalDeviceNumber); + if (Activate) { + + // + // If we need to activate the logical device, disable its io range check and + // then enable the device. + // + + PipWriteAddress(IO_RANGE_CHECK_PORT); + tmp = PipReadData(); + tmp &= ~2; + PipWriteAddress(IO_RANGE_CHECK_PORT); + PipWriteData(tmp); + PipWriteAddress(ACTIVATE_PORT); + PipWriteData(1); + } +} + +VOID +PipReadCardResourceDataBytes ( + IN USHORT BytesToRead, + IN PUCHAR Buffer + ) + +/*++ + +Routine Description: + + This function reads specified number of bytes of card resource data . + +Arguments: + + BytesToRead - supplies number of bytes to read. + + Buffer - supplies a pointer to a buffer to receive the read bytes. + +Return Value: + + None +--*/ +{ + USHORT i; + PUCHAR p; + + for (i = 0, p = Buffer; i < BytesToRead; i++, p++) { + + PipWriteAddress(CONFIG_DATA_STATUS_PORT); + + // + // Waiting for data ready status bit + // + + while ((PipReadData() & 1) != 1) { + } + + // + // Read the data ... + // + + PipWriteAddress(CONFIG_DATA_PORT); + *p = PipReadData(); + } + +} diff --git a/private/ntos/nthals/extender/pnpisa.sur/makefile b/private/ntos/nthals/extender/pnpisa.sur/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa.sur/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/pnpisa.sur/misc.c b/private/ntos/nthals/extender/pnpisa.sur/misc.c new file mode 100644 index 000000000..df32be4a8 --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa.sur/misc.c @@ -0,0 +1,1258 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + misc.c + +Abstract: + + This file contains pnp isa bus extender support routines. + +Author: + + Shie-Lin Tzong (shielint) 27-Jusly-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "busp.h" +#include "pnpisa.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,PipDecompressEisaId) +#pragma alloc_text(INIT,PipOpenRegistryKey) +#pragma alloc_text(INIT,PipOpenRegistryKeyPersist) +#pragma alloc_text(INIT,PipGetRegistryValue) +#pragma alloc_text(INIT,PipOpenCurrentHwProfileDeviceInstanceKey) +#pragma alloc_text(INIT,PipGetDeviceInstanceCsConfigFlags) +#pragma alloc_text(INIT,PipRemoveStringFromValueKey) +#pragma alloc_text(INIT,PipAppendStringToValueKey) +#pragma alloc_text(INIT,PipServiceInstanceToDeviceInstance) +#if DBG +#pragma alloc_text(INIT,PipDebugPrint) +#pragma alloc_text(INIT,PipDumpIoResourceDescriptor) +#pragma alloc_text(INIT,PipDumpIoResourceList) +#pragma alloc_text(INIT,PipDumpCmResourceDescriptor) +#pragma alloc_text(INIT,PipDumpCmResourceList) +#endif +#endif + + +VOID +PipDecompressEisaId( + IN ULONG CompressedId, + IN PUCHAR EisaId + ) + +/*++ + +Routine Description: + + This routine decompressed compressed Eisa Id and returns the Id to caller + specified character buffer. + +Arguments: + + CompressedId - supplies the compressed Eisa Id. + + EisaId - supplies a 8-char buffer to receive the decompressed Eisa Id. + +Return Value: + + None. + +--*/ + +{ + USHORT c1, c2; + LONG i; + + PAGED_CODE(); + + CompressedId &= 0xffffff7f; // remove the reserved bit (bit 7 of byte 0) + c1 = c2 = (USHORT)CompressedId; + c1 = (c1 & 0xff) << 8; + c2 = (c2 & 0xff00) >> 8; + c1 |= c2; + for (i = 2; i >= 0; i--) { + *(EisaId + i) = (UCHAR)(c1 & 0x1f) + 0x40; + c1 >>= 5; + } + EisaId += 3; + c1 = c2 = (USHORT)(CompressedId >> 16); + c1 = (c1 & 0xff) << 8; + c2 = (c2 & 0xff00) >> 8; + c1 |= c2; + sprintf (EisaId, "%04x", c1); +} + +NTSTATUS +PipOpenRegistryKey( + OUT PHANDLE Handle, + IN HANDLE BaseHandle OPTIONAL, + IN PUNICODE_STRING KeyName, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN Create + ) + +/*++ + +Routine Description: + + Opens or creates a VOLATILE registry key using the name passed in based + at the BaseHandle node. + +Arguments: + + Handle - Pointer to the handle which will contain the registry key that + was opened. + + BaseHandle - Handle to the base path from which the key must be opened. + + KeyName - Name of the Key that must be opened/created. + + DesiredAccess - Specifies the desired access that the caller needs to + the key. + + Create - Determines if the key is to be created if it does not exist. + +Return Value: + + The function value is the final status of the operation. + +--*/ + +{ + OBJECT_ATTRIBUTES objectAttributes; + ULONG disposition; + + PAGED_CODE(); + + // + // Initialize the object for the key. + // + + InitializeObjectAttributes( &objectAttributes, + KeyName, + OBJ_CASE_INSENSITIVE, + BaseHandle, + (PSECURITY_DESCRIPTOR) NULL ); + + // + // Create the key or open it, as appropriate based on the caller's + // wishes. + // + + if (Create) { + return ZwCreateKey( Handle, + DesiredAccess, + &objectAttributes, + 0, + (PUNICODE_STRING) NULL, + REG_OPTION_VOLATILE, + &disposition ); + } else { + return ZwOpenKey( Handle, + DesiredAccess, + &objectAttributes ); + } +} +NTSTATUS +PipOpenRegistryKeyPersist( + OUT PHANDLE Handle, + IN HANDLE BaseHandle OPTIONAL, + IN PUNICODE_STRING KeyName, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN Create, + OUT PULONG Disposition OPTIONAL + ) + +/*++ + +Routine Description: + + Opens or creates a PERSIST (non-volatile) registry key using the name + passed in based at the BaseHandle node. This name may specify a key + that is actually a registry path, in which case each intermediate subkey + will be created (if Create is TRUE). + + NOTE: Creating a registry path (i.e., more than one of the keys in the path + do not presently exist) requires that a BaseHandle be specified. + +Arguments: + + Handle - Pointer to the handle which will contain the registry key that + was opened. + + BaseHandle - Optional handle to the base path from which the key must be opened. + If KeyName specifies a registry path that must be created, then this parameter + must be specified, and KeyName must be a relative path. + + KeyName - Name of the Key that must be opened/created (possibly a registry path) + + DesiredAccess - Specifies the desired access that the caller needs to + the key. + + Create - Determines if the key is to be created if it does not exist. + + Disposition - If Create is TRUE, this optional pointer receives a ULONG indicating + whether the key was newly created: + + REG_CREATED_NEW_KEY - A new Registry Key was created + REG_OPENED_EXISTING_KEY - An existing Registry Key was opened + +Return Value: + + The function value is the final status of the operation. + +--*/ + +{ + OBJECT_ATTRIBUTES objectAttributes; + ULONG disposition, baseHandleIndex = 0, keyHandleIndex = 1, closeBaseHandle; + HANDLE handles[2]; + BOOLEAN continueParsing; + PWCHAR pathEndPtr, pathCurPtr, pathBeginPtr; + ULONG pathComponentLength; + UNICODE_STRING unicodeString; + NTSTATUS status; + + PAGED_CODE(); + + InitializeObjectAttributes(&objectAttributes, + KeyName, + OBJ_CASE_INSENSITIVE, + BaseHandle, + (PSECURITY_DESCRIPTOR) NULL + ); + if(Create) { + // + // Attempt to create the path as specified. We have to try it this + // way first, because it allows us to create a key without a BaseHandle + // (if only the last component of the registry path is not present). + // + status = ZwCreateKey(&(handles[keyHandleIndex]), + DesiredAccess, + &objectAttributes, + 0, + (PUNICODE_STRING) NULL, + REG_OPTION_NON_VOLATILE, + &disposition + ); + + if(!((status == STATUS_OBJECT_NAME_NOT_FOUND) && ARGUMENT_PRESENT(BaseHandle))) { + // + // Then either we succeeded, or failed, but there's nothing we can do + // about it. In either case, prepare to return. + // + goto PrepareForReturn; + } + + } else { + // + // Simply attempt to open the path, as specified. + // + return ZwOpenKey(Handle, + DesiredAccess, + &objectAttributes + ); + } + + // + // If we get to here, then there must be more than one element of the + // registry path that does not currently exist. We will now parse the + // specified path, extracting each component and doing a ZwCreateKey on it. + // + handles[baseHandleIndex] = NULL; + handles[keyHandleIndex] = BaseHandle; + closeBaseHandle = 0; + continueParsing = TRUE; + pathBeginPtr = KeyName->Buffer; + pathEndPtr = (PWCHAR)((PCHAR)pathBeginPtr + KeyName->Length); + status = STATUS_SUCCESS; + + while(continueParsing) { + // + // There's more to do, so close the previous base handle (if necessary), + // and replace it with the current key handle. + // + if(closeBaseHandle > 1) { + ZwClose(handles[baseHandleIndex]); + } + baseHandleIndex = keyHandleIndex; + keyHandleIndex = (keyHandleIndex + 1) & 1; // toggle between 0 and 1. + handles[keyHandleIndex] = NULL; + + // + // Extract next component out of the specified registry path. + // + for(pathCurPtr = pathBeginPtr; + ((pathCurPtr < pathEndPtr) && (*pathCurPtr != OBJ_NAME_PATH_SEPARATOR)); + pathCurPtr++); + + if (pathComponentLength = (PCHAR)pathCurPtr - (PCHAR)pathBeginPtr) { + // + // Then we have a non-empty path component (key name). Attempt + // to create this key. + // + unicodeString.Buffer = pathBeginPtr; + unicodeString.Length = unicodeString.MaximumLength = (USHORT)pathComponentLength; + + InitializeObjectAttributes(&objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + handles[baseHandleIndex], + (PSECURITY_DESCRIPTOR) NULL + ); + status = ZwCreateKey(&(handles[keyHandleIndex]), + DesiredAccess, + &objectAttributes, + 0, + (PUNICODE_STRING) NULL, + REG_OPTION_NON_VOLATILE, + &disposition + ); + if (NT_SUCCESS(status)) { + // + // Increment the closeBaseHandle value, which basically tells us whether + // the BaseHandle passed in has been 'shifted out' of our way, so that + // we should start closing our base handles when we're finished with them. + // + closeBaseHandle++; + } else { + continueParsing = FALSE; + continue; + } + } else { + // + // Either a path separator ('\') was included at the beginning of + // the path, or we hit 2 consecutive separators. + // + status = STATUS_INVALID_PARAMETER; + continueParsing = FALSE; + continue; + } + + if ((pathCurPtr == pathEndPtr) || + ((pathBeginPtr = pathCurPtr + 1) == pathEndPtr)) { + // + // Then we've reached the end of the path + // + continueParsing = FALSE; + } + } + + if (closeBaseHandle > 1) { + ZwClose(handles[baseHandleIndex]); + } + +PrepareForReturn: + + if (NT_SUCCESS(status)) { + *Handle = handles[keyHandleIndex]; + + if(ARGUMENT_PRESENT(Disposition)) { + *Disposition = disposition; + } + } + + return status; +} + +NTSTATUS +PipGetRegistryValue( + IN HANDLE KeyHandle, + IN PWSTR ValueName, + OUT PKEY_VALUE_FULL_INFORMATION *Information + ) + +/*++ + +Routine Description: + + This routine is invoked to retrieve the data for a registry key's value. + This is done by querying the value of the key with a zero-length buffer + to determine the size of the value, and then allocating a buffer and + actually querying the value into the buffer. + + It is the responsibility of the caller to free the buffer. + +Arguments: + + KeyHandle - Supplies the key handle whose value is to be queried + + ValueName - Supplies the null-terminated Unicode name of the value. + + Information - Returns a pointer to the allocated data buffer. + +Return Value: + + The function value is the final status of the query operation. + +--*/ + +{ + UNICODE_STRING unicodeString; + NTSTATUS status; + PKEY_VALUE_FULL_INFORMATION infoBuffer; + ULONG keyValueLength; + + PAGED_CODE(); + + *Information = NULL; + RtlInitUnicodeString( &unicodeString, ValueName ); + + // + // Figure out how big the data value is so that a buffer of the + // appropriate size can be allocated. + // + + status = ZwQueryValueKey( KeyHandle, + &unicodeString, + KeyValueFullInformation, + (PVOID) NULL, + 0, + &keyValueLength ); + if (status != STATUS_BUFFER_OVERFLOW && + status != STATUS_BUFFER_TOO_SMALL) { + return status; + } + + // + // Allocate a buffer large enough to contain the entire key data value. + // + + infoBuffer = ExAllocatePool( NonPagedPool, keyValueLength ); + if (!infoBuffer) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Query the data for the key value. + // + + status = ZwQueryValueKey( KeyHandle, + &unicodeString, + KeyValueFullInformation, + infoBuffer, + keyValueLength, + &keyValueLength ); + if (!NT_SUCCESS( status )) { + ExFreePool( infoBuffer ); + return status; + } + + // + // Everything worked, so simply return the address of the allocated + // buffer to the caller, who is now responsible for freeing it. + // + + *Information = infoBuffer; + return STATUS_SUCCESS; +} + +NTSTATUS +PipOpenCurrentHwProfileDeviceInstanceKey( + OUT PHANDLE Handle, + IN PUNICODE_STRING DeviceInstanceName, + IN ACCESS_MASK DesiredAccess + ) + +/*++ + +Routine Description: + + This routine sets the csconfig flags for the specified device + which is specified by the instance number under ServiceKeyName\Enum. + +Arguments: + + ServiceKeyName - Supplies a pointer to the name of the subkey in the + system service list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services) + that caused the driver to load. This is the RegistryPath parameter + to the DriverEntry routine. + + Instance - Supplies the instance value under ServiceKeyName\Enum key + + DesiredAccess - Specifies the desired access that the caller needs to + the key. + + Create - Determines if the key is to be created if it does not exist. + +Return Value: + + status + +--*/ + +{ + NTSTATUS status; + UNICODE_STRING unicodeString; + HANDLE profileEnumHandle; + + // + // See if we can open the device instance key of current hardware profile + // + RtlInitUnicodeString ( + &unicodeString, + L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\HARDWARE PROFILES\\CURRENT\\SYSTEM\\CURRENTCONTROLSET\\ENUM" + ); + status = PipOpenRegistryKey(&profileEnumHandle, + NULL, + &unicodeString, + KEY_READ, + FALSE + ); + if (NT_SUCCESS(status)) { + status = PipOpenRegistryKey(Handle, + profileEnumHandle, + DeviceInstanceName, + DesiredAccess, + FALSE + ); + ZwClose(profileEnumHandle); + } + return status; +} + +NTSTATUS +PipGetDeviceInstanceCsConfigFlags( + IN PUNICODE_STRING DeviceInstance, + OUT PULONG CsConfigFlags + ) + +/*++ + +Routine Description: + + This routine retrieves the csconfig flags for the specified device + which is specified by the instance number under ServiceKeyName\Enum. + +Arguments: + + ServiceKeyName - Supplies a pointer to the name of the subkey in the + system service list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services) + that caused the driver to load. + +// Instance - Supplies the instance value under ServiceKeyName\Enum key +// + CsConfigFlags - Supplies a variable to receive the device's CsConfigFlags + +Return Value: + + status + +--*/ + +{ + NTSTATUS status; + HANDLE handle; + PKEY_VALUE_FULL_INFORMATION keyValueInformation; + + *CsConfigFlags = 0; + + status = PipOpenCurrentHwProfileDeviceInstanceKey(&handle, + DeviceInstance, + KEY_READ + ); + if(NT_SUCCESS(status)) { + status = PipGetRegistryValue(handle, + L"CsConfigFlags", + &keyValueInformation + ); + if(NT_SUCCESS(status)) { + if((keyValueInformation->Type == REG_DWORD) && + (keyValueInformation->DataLength >= sizeof(ULONG))) { + *CsConfigFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation); + } + ExFreePool(keyValueInformation); + } + ZwClose(handle); + } + return status; +} + +NTSTATUS +PipRemoveStringFromValueKey ( + IN HANDLE Handle, + IN PWSTR ValueName, + IN PUNICODE_STRING String + ) + +/*++ + +Routine Description: + + This routine remove a string from a value entry specified by ValueName + under an already opened registry handle. Note, this routine will not + delete the ValueName entry even it becomes empty after the removal. + +Parameters: + + Handle - Supplies the handle to a registry key whose value entry will + be modified. + + ValueName - Supplies a unicode string to specify the value entry. + + String - Supplies a unicode string to remove from value entry. + +Return Value: + + Status code that indicates whether or not the function was successful. + +--*/ + +{ + PKEY_VALUE_FULL_INFORMATION keyValueInformation; + UNICODE_STRING unicodeString; + PWSTR nextString, currentString; + ULONG length, leftLength; + NTSTATUS status; + BOOLEAN found = FALSE; + + if (String == NULL || String->Length / sizeof(WCHAR) == 0) { + return STATUS_SUCCESS; + } + + // + // Read registry value entry data + // + + status = PipGetRegistryValue(Handle, ValueName, &keyValueInformation); + + if (!NT_SUCCESS( status )) { + return status; + } else if ((keyValueInformation->Type != REG_MULTI_SZ) || + (keyValueInformation->DataLength == 0)) { + + ExFreePool(keyValueInformation); + return (keyValueInformation->Type == REG_MULTI_SZ) ? STATUS_SUCCESS + : STATUS_INVALID_PARAMETER; + } + + // + // Scan through the multi_sz string to find the matching string + // and remove it. + // + + status = STATUS_SUCCESS; + currentString = (PWSTR)KEY_VALUE_DATA(keyValueInformation); + leftLength = keyValueInformation->DataLength; + while (!found && leftLength >= String->Length + sizeof(WCHAR)) { + unicodeString.Buffer = currentString; + length = wcslen( currentString ) * sizeof( WCHAR ); + unicodeString.Length = (USHORT)length; + length += sizeof(UNICODE_NULL); + unicodeString.MaximumLength = (USHORT)length; + nextString = currentString + length / sizeof(WCHAR); + leftLength -= length; + + if (RtlEqualUnicodeString(&unicodeString, String, TRUE)) { + found = TRUE; + RtlMoveMemory(currentString, nextString, leftLength); + RtlInitUnicodeString(&unicodeString, ValueName); + status = ZwSetValueKey( + Handle, + &unicodeString, + TITLE_INDEX_VALUE, + REG_MULTI_SZ, + KEY_VALUE_DATA(keyValueInformation), + keyValueInformation->DataLength - length + ); + break; + } else { + currentString = nextString; + } + } + ExFreePool(keyValueInformation); + return status; +} + +NTSTATUS +PipAppendStringToValueKey ( + IN HANDLE Handle, + IN PWSTR ValueName, + IN PUNICODE_STRING String, + IN BOOLEAN Create + ) + +/*++ + +Routine Description: + + This routine appends a string to a value entry specified by ValueName + under an already opened registry handle. If the ValueName is not present + and Create is TRUE, a new value entry will be created using the name + ValueName. + +Parameters: + + Handle - Supplies the handle to a registry key whose value entry will + be modified. + + ValueName - Supplies a pointer to a string to specify the value entry. + + String - Supplies a unicode string to append to the value entry. + + Create - Supplies a BOOLEAN variable to indicate if the ValueName + value entry should be created if it is not present. + +Return Value: + + Status code that indicates whether or not the function was successful. + +--*/ + +{ + PKEY_VALUE_FULL_INFORMATION keyValueInformation; + PWSTR destinationString, p; + UNICODE_STRING unicodeValueName; + ULONG size; + NTSTATUS status; + + if ( !String || (String->Length < sizeof(WCHAR)) ) { + return STATUS_SUCCESS; + } + + // + // Read registry value entry data + // + + status = PipGetRegistryValue(Handle, ValueName, &keyValueInformation); + + if(!NT_SUCCESS( status )) { + if (status == STATUS_OBJECT_NAME_NOT_FOUND && Create) { + + // + // if no valid entry exists and user said ok to create one + // + + keyValueInformation = NULL; + } else { + return status; + } + } else if(keyValueInformation->Type != REG_MULTI_SZ) { + + ExFreePool(keyValueInformation); + + if(Create) { + keyValueInformation = NULL; + } else { + return STATUS_INVALID_PARAMETER_2; + } + + } else if(keyValueInformation->DataLength < sizeof(WCHAR)) { + + ExFreePool(keyValueInformation); + keyValueInformation = NULL; + } + + // + // Allocate a buffer to hold new data for the specified key value entry + // Make sure the buffer is at least an empty MULTI_SZ big. + // + + if (keyValueInformation) { + size = keyValueInformation->DataLength + String->Length + sizeof (UNICODE_NULL); + } else { + size = String->Length + 2 * sizeof(UNICODE_NULL); + } + + destinationString = p = (PWSTR)ExAllocatePool(PagedPool, size); + if (destinationString == NULL) { + if (keyValueInformation) { + ExFreePool(keyValueInformation); + } + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Copy the existing data to our newly allocated buffer, if any + // + + if (keyValueInformation) { + + // + // Note we need to remove a UNICODE_NULL because the + // MULTI_SZ has two terminating UNICODE_NULL. + // + + RtlMoveMemory(p, + KEY_VALUE_DATA(keyValueInformation), + keyValueInformation->DataLength - sizeof(WCHAR) + ); + p += keyValueInformation->DataLength / sizeof(WCHAR) - 1; + + ExFreePool(keyValueInformation); + } + + // + // Append the user specified unicode string to our buffer + // + RtlMoveMemory(p, + String->Buffer, + String->Length + ); + p += String->Length / sizeof(WCHAR); + *p = UNICODE_NULL; + p++; + *p = UNICODE_NULL; + + // + // Finally write the data to the specified registy value entry + // + + RtlInitUnicodeString(&unicodeValueName, ValueName); + status = ZwSetValueKey( + Handle, + &unicodeValueName, + TITLE_INDEX_VALUE, + REG_MULTI_SZ, + destinationString, + size + ); + + ExFreePool(destinationString); + return status; +} + +NTSTATUS +PipServiceInstanceToDeviceInstance ( + IN PUNICODE_STRING RegistryPath, + IN ULONG ServiceInstanceOrdinal, + OUT PUNICODE_STRING DeviceInstanceRegistryPath OPTIONAL, + OUT PHANDLE DeviceInstanceHandle OPTIONAL, + IN ACCESS_MASK DesiredAccess + ) + +/*++ + +Routine Description: + + This routine reads the service node enum entry to find the desired device instance + under the System\Enum tree. It then optionally returns the registry path of the + specified device instance (relative to HKLM\System\Enum) and an open handle + to that registry key. + + It is the caller's responsibility to close the handle returned if + DeviceInstanceHandle is supplied, and also to free the (PagedPool) memory + allocated for the unicode string buffer of DeviceInstanceRegistryPath, if + supplied. + +Parameters: + + RegistryPath - Supplies the name of the service entry that controls + the device instance. This is the registry path passed to DriverEntry. + + ServiceInstanceOrdinal - Supplies the instance value under the service entry's + volatile Enum subkey that references the desired device instance. + + DeviceInstanceRegistryPath - Optionally, supplies a pointer to a unicode string + that will be initialized with the registry path (relative to HKLM\System\Enum) + to the device instance key. + + DeviceInstanceHandle - Optionally, supplies a pointer to a variable that will + receive a handle to the opened device instance registry key. + + DesiredAccess - If DeviceInstanceHandle is specified (i.e., the device instance + key is to be opened), then this variable specifies the access that is needed + to this key. + +Return Value: + + NT status code indicating whether the function was successful. + +--*/ + +{ + WCHAR unicodeBuffer[20]; + UNICODE_STRING unicodeKeyName, unicodeString; + NTSTATUS status; + HANDLE handle, handlex; + PKEY_VALUE_FULL_INFORMATION keyValueInformation; + PWSTR buffer; + + // + // Open registry ServiceKeyName\Enum branch + // + + status = PipOpenRegistryKey(&handle, + NULL, + RegistryPath, + KEY_ALL_ACCESS, + FALSE + ); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE, "PnPIsa: Unable to open Service RegistryPath\n")); + return status; + } + + RtlInitUnicodeString(&unicodeKeyName, L"ENUM"); + status = PipOpenRegistryKey(&handlex, + handle, + &unicodeKeyName, + KEY_READ, + FALSE + ); + ZwClose(handle); + if (!NT_SUCCESS( status )) { + + // + // There is no registry key for the ServiceKeyName\Enum information. + // + + return status; + } + + // + // Read a path to System\Enum hardware tree branch specified by the service + // instance ordinal + // + + swprintf(unicodeBuffer, L"%u", ServiceInstanceOrdinal); + status = PipGetRegistryValue ( handlex, + unicodeBuffer, + &keyValueInformation + ); + + ZwClose(handlex); + if (!NT_SUCCESS( status )) { + return status; + } else { + if (keyValueInformation->Type == REG_SZ) { + unicodeKeyName.Buffer = (PWSTR)KEY_VALUE_DATA(keyValueInformation); + unicodeKeyName.MaximumLength = (USHORT)keyValueInformation->DataLength; + unicodeKeyName.Length = unicodeKeyName.MaximumLength - sizeof(UNICODE_NULL); + if(!unicodeKeyName.Length) { + status = STATUS_OBJECT_PATH_NOT_FOUND; + } + } else { + status = STATUS_INVALID_PLUGPLAY_DEVICE_PATH; + } + + if(!NT_SUCCESS(status)) { + goto PrepareForReturn; + } + } + + // + // If the DeviceInstanceHandle argument was specified, open the device instance + // key under HKLM\System\CurrentControlSet\Enum + // + + if (ARGUMENT_PRESENT(DeviceInstanceHandle)) { + RtlInitUnicodeString(&unicodeString, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM"); + status = PipOpenRegistryKey(&handle, + NULL, + &unicodeString, + KEY_READ, + FALSE + ); + + if (NT_SUCCESS( status )) { + + status = PipOpenRegistryKey (DeviceInstanceHandle, + handle, + &unicodeKeyName, + DesiredAccess, + FALSE + ); + ZwClose(handle); + } + + if (!NT_SUCCESS( status )) { + goto PrepareForReturn; + } + } + + // + // If the DeviceInstanceRegistryPath argument was specified, then store a + // copy of the device instance path in the supplied unicode string variable. + // + + if (ARGUMENT_PRESENT(DeviceInstanceRegistryPath)) { + + buffer = (PWSTR)ExAllocatePool(PagedPool, unicodeKeyName.MaximumLength); + if (!buffer) { + if(ARGUMENT_PRESENT(DeviceInstanceHandle)) { + ZwClose(*DeviceInstanceHandle); + } + status = STATUS_INSUFFICIENT_RESOURCES; + } else { + RtlMoveMemory(buffer, unicodeKeyName.Buffer, unicodeKeyName.MaximumLength); + DeviceInstanceRegistryPath->Buffer = buffer; + DeviceInstanceRegistryPath->Length = unicodeKeyName.Length; + DeviceInstanceRegistryPath->MaximumLength = unicodeKeyName.MaximumLength; + } + } + +PrepareForReturn: + + ExFreePool(keyValueInformation); + return status; +} +#if DBG + +VOID +PipDebugPrint ( + ULONG Level, + PCCHAR DebugMessage, + ... + ) +/*++ + +Routine Description: + + This routine displays debugging message or causes a break. + +Arguments: + + Level - supplies debugging levelcode. DEBUG_MESSAGE - displays message only. + DEBUG_BREAK - displays message and break. + + DebugMessage - supplies a pointer to the debugging message. + +Return Value: + + None. + +--*/ + +{ + UCHAR Buffer[256]; + va_list ap; + + va_start(ap, DebugMessage); + + vsprintf(Buffer, DebugMessage, ap); + DbgPrint(Buffer); + if (Level == DEBUG_BREAK) { + DbgBreakPoint(); + } + + va_end(ap); +} + +VOID +PipDumpIoResourceDescriptor ( + IN PUCHAR Indent, + IN PIO_RESOURCE_DESCRIPTOR Desc + ) +/*++ + +Routine Description: + + This routine processes a IO_RESOURCE_DESCRIPTOR and displays it. + +Arguments: + + Indent - # char of indentation. + + Desc - supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be displayed. + +Return Value: + + None. + +--*/ +{ + UCHAR c = ' '; + + if (Desc->Option == IO_RESOURCE_ALTERNATIVE) { + c = 'A'; + } else if (Desc->Option == IO_RESOURCE_PREFERRED) { + c = 'P'; + } + switch (Desc->Type) { + case CmResourceTypePort: + DbgPrint ("%sIO %c Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n", + Indent, c, + Desc->u.Port.MinimumAddress.HighPart, Desc->u.Port.MinimumAddress.LowPart, + Desc->u.Port.MaximumAddress.HighPart, Desc->u.Port.MaximumAddress.LowPart, + Desc->u.Port.Alignment, + Desc->u.Port.Length + ); + break; + + case CmResourceTypeMemory: + DbgPrint ("%sMEM %c Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n", + Indent, c, + Desc->u.Memory.MinimumAddress.HighPart, Desc->u.Memory.MinimumAddress.LowPart, + Desc->u.Memory.MaximumAddress.HighPart, Desc->u.Memory.MaximumAddress.LowPart, + Desc->u.Memory.Alignment, + Desc->u.Memory.Length + ); + break; + + case CmResourceTypeInterrupt: + DbgPrint ("%sINT %c Min: %x, Max: %x\n", + Indent, c, + Desc->u.Interrupt.MinimumVector, + Desc->u.Interrupt.MaximumVector + ); + break; + + case CmResourceTypeDma: + DbgPrint ("%sDMA %c Min: %x, Max: %x\n", + Indent, c, + Desc->u.Dma.MinimumChannel, + Desc->u.Dma.MaximumChannel + ); + break; + } +} + +VOID +PipDumpIoResourceList ( + IN PIO_RESOURCE_REQUIREMENTS_LIST IoList + ) +/*++ + +Routine Description: + + This routine displays Io resource requirements list. + +Arguments: + + IoList - supplies a pointer to the Io resource requirements list to be displayed. + +Return Value: + + None. + +--*/ +{ + + + PIO_RESOURCE_LIST resList; + PIO_RESOURCE_DESCRIPTOR resDesc; + ULONG listCount, count, i, j; + + if (IoList == NULL) { + return; + } + DbgPrint("Pnp Bios IO Resource Requirements List for Slot %x -\n", IoList->SlotNumber); + DbgPrint(" List Count = %x, Bus Number = %x\n", IoList->AlternativeLists, IoList->BusNumber); + listCount = IoList->AlternativeLists; + resList = &IoList->List[0]; + for (i = 0; i < listCount; i++) { + DbgPrint(" Version = %x, Revision = %x, Desc count = %x\n", resList->Version, + resList->Revision, resList->Count); + resDesc = &resList->Descriptors[0]; + count = resList->Count; + for (j = 0; j < count; j++) { + PipDumpIoResourceDescriptor(" ", resDesc); + resDesc++; + } + resList = (PIO_RESOURCE_LIST) resDesc; + } +} + +VOID +PipDumpCmResourceDescriptor ( + IN PUCHAR Indent, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Desc + ) +/*++ + +Routine Description: + + This routine processes a IO_RESOURCE_DESCRIPTOR and displays it. + +Arguments: + + Indent - # char of indentation. + + Desc - supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be displayed. + +Return Value: + + None. + +--*/ +{ + switch (Desc->Type) { + case CmResourceTypePort: + DbgPrint ("%sIO Start: %x:%08x, Length: %x\n", + Indent, + Desc->u.Port.Start.HighPart, Desc->u.Port.Start.LowPart, + Desc->u.Port.Length + ); + break; + + case CmResourceTypeMemory: + DbgPrint ("%sMEM Start: %x:%08x, Length: %x\n", + Indent, + Desc->u.Memory.Start.HighPart, Desc->u.Memory.Start.LowPart, + Desc->u.Memory.Length + ); + break; + + case CmResourceTypeInterrupt: + DbgPrint ("%sINT Level: %x, Vector: %x, Affinity: %x\n", + Indent, + Desc->u.Interrupt.Level, + Desc->u.Interrupt.Vector, + Desc->u.Interrupt.Affinity + ); + break; + + case CmResourceTypeDma: + DbgPrint ("%sDMA Channel: %x, Port: %x\n", + Indent, + Desc->u.Dma.Channel, + Desc->u.Dma.Port + ); + break; + } +} + +VOID +PipDumpCmResourceList ( + IN PCM_RESOURCE_LIST CmList + ) +/*++ + +Routine Description: + + This routine displays CM resource list. + +Arguments: + + CmList - supplies a pointer to CM resource list + +Return Value: + + None. + +--*/ +{ + PCM_FULL_RESOURCE_DESCRIPTOR fullDesc; + PCM_PARTIAL_RESOURCE_LIST partialDesc; + PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; + ULONG count, i; + + if (CmList) { + fullDesc = &CmList->List[0]; + DbgPrint("Pnp Bios Cm Resource List -\n"); + DbgPrint(" List Count = %x, Bus Number = %x\n", CmList->Count, fullDesc->BusNumber); + partialDesc = &fullDesc->PartialResourceList; + DbgPrint(" Version = %x, Revision = %x, Desc count = %x\n", partialDesc->Version, + partialDesc->Revision, partialDesc->Count); + count = partialDesc->Count; + desc = &partialDesc->PartialDescriptors[0]; + for (i = 0; i < count; i++) { + PipDumpCmResourceDescriptor(" ", desc); + desc++; + } + } +} +#endif diff --git a/private/ntos/nthals/extender/pnpisa.sur/pbios.h b/private/ntos/nthals/extender/pnpisa.sur/pbios.h new file mode 100644 index 000000000..6c1b2e333 --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa.sur/pbios.h @@ -0,0 +1,241 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pbiosp.h + +Abstract: + + PnP BIOS/ISA configuration data definitions + +Author: + + Shie-Lin Tzong (shielint) April 12, 1995 + +Revision History: + +--*/ + +//#include "nthal.h" +//#include "hal.h" + +// +// Constants +// + +#define SMALL_RESOURCE_TAG (UCHAR)(0x00) +#define LARGE_RESOURCE_TAG (UCHAR)(0x80) +#define SMALL_TAG_MASK 0xf8 +#define SMALL_TAG_SIZE_MASK 7 + +// +// Small Resouce Tags with length bits stripped off +// + +#define TAG_VERSION 0x08 +#define TAG_LOGICAL_ID 0x10 +#define TAG_COMPATIBLE_ID 0x18 +#define TAG_IRQ 0x20 +#define TAG_DMA 0x28 +#define TAG_START_DEPEND 0x30 +#define TAG_END_DEPEND 0x38 +#define TAG_IO 0x40 +#define TAG_IO_FIXED 0x48 +#define TAG_VENDOR 0x70 +#define TAG_END 0x78 + +// +// Large Resouce Tags +// + +#define TAG_MEMORY 0x81 +#define TAG_ANSI_ID 0x82 +#define TAG_UNICODE_ID 0x83 +#define TAG_LVENDOR 0x84 +#define TAG_MEMORY32 0x85 +#define TAG_MEMORY32_FIXED 0x86 + +// +// Complete TAG if applicable. +// + +#define TAG_COMPLETE_COMPATIBLE_ID 0x1C +#define TAG_COMPLETE_END 0x79 + +#include "pshpack1.h" + +// +// PNP ISA Port descriptor definition +// + +typedef struct _PNP_PORT_DESCRIPTOR_ { + UCHAR Tag; // 01000111B, small item name = 08, length = 7 + UCHAR Information; // bit [0] = 1 device decodes full 16 bit addr + // = 0 device decodes ISA addr bits[9-0] + USHORT MinimumAddress; + USHORT MaximumAddress; + UCHAR Alignment; // Increment in 1 byte blocks + UCHAR Length; // # contiguous Port requested +} PNP_PORT_DESCRIPTOR, *PPNP_PORT_DESCRIPTOR; + +// +// PNP ISA fixed Port descriptor definition +// + +typedef struct _PNP_FIXED_PORT_DESCRIPTOR_ { + UCHAR Tag; // 01001011B, small item name = 09, length = 3 + USHORT MinimumAddress; + UCHAR Length; // # contiguous Port requested +} PNP_FIXED_PORT_DESCRIPTOR, *PPNP_FIXED_PORT_DESCRIPTOR; + +// +// PNP ISA IRQ descriptor definition +// + +typedef struct _PNP_IRQ_DESCRIPTOR_ { + UCHAR Tag; // 0010001XB small item name = 4 length = 2/3 + USHORT IrqMask; // bit 0 is irq 0 + UCHAR Information; // Optional +} PNP_IRQ_DESCRIPTOR, *PPNP_IRQ_DESCRIPTOR; + +// +// Masks for PNP_IRQ_DESCRIPTOR Information byte +// + +#define PNP_IRQ_LEVEL_MASK 0xC +#define PNP_IRQ_EDGE_MASK 0x3 + +// +// PNP ISA DMA descriptor definition +// + +typedef struct _PNP_DMA_DESCRIPTOR_ { + UCHAR Tag; // 00101010B, small item name = 05, length = 2 + UCHAR ChannelMask; // bit 0 is channel 0 + UCHAR Flags; // see spec +} PNP_DMA_DESCRIPTOR, *PPNP_DMA_DESCRIPTOR; + +// +// PNP ISA MEMORY descriptor +// + +typedef struct _PNP_MEMORY_DESCRIPTOR_ { + UCHAR Tag; // 10000001B, Large item name = 1 + USHORT Length; // Length of the descriptor = 9 + UCHAR Information; // See def below + USHORT MinimumAddress; // address bit [8-23] + USHORT MaximumAddress; // address bit [8-23] + USHORT Alignment; // 0x0000 = 64KB + USHORT MemorySize; // In 256 byte blocks +} PNP_MEMORY_DESCRIPTOR, *PPNP_MEMORY_DESCRIPTOR; + +// +// PNP ISA MEMORY32 descriptor +// + +typedef struct _PNP_MEMORY32_DESCRIPTOR_ { + UCHAR Tag; // 10000101B, Large item name = 5 + USHORT Length; // Length of the descriptor = 17 + UCHAR Information; // See def below + ULONG MinimumAddress; // 32 bit addr + ULONG MaximumAddress; // 32 bit addr + ULONG Alignment; // 32 bit alignment + ULONG MemorySize; // 32 bit length +} PNP_MEMORY32_DESCRIPTOR, *PPNP_MEMORY32_DESCRIPTOR; + +// +// PNP ISA FIXED MEMORY32 descriptor +// + +typedef struct _PNP_FIXED_MEMORY32_DESCRIPTOR_ { + UCHAR Tag; // 10000110B, Large item name = 6 + USHORT Length; // Length of the descriptor = 9 + UCHAR Information; // See def below + ULONG BaseAddress; // 32 bit addr + ULONG MemorySize; // 32 bit length +} PNP_FIXED_MEMORY32_DESCRIPTOR, *PPNP_FIXED_MEMORY32_DESCRIPTOR; + +#define PNP_MEMORY_ROM_MASK 0x40 +#define PNP_MEMORY_SHADOWABLE_MASK 0x20 +#define PNP_MEMORY_CONTROL_MASK 0x18 + #define PNP_MEMORY_CONTROL_8BIT 00 + #define PNP_MEMORY_CONTROL_16BIT 01 + #define PNP_MEMORY_CONTROL_8AND16BIT 02 + #define PNP_MEMORY_CONTROL_32BIT 03 +#define PNP_MEMORY_SUPPORT_TYPE_MASK 04 +#define PNP_MEMORY_CACHE_SUPPORT_MASK 02 +#define PNP_MEMORY_WRITE_STATUS_MASK 01 + +#define UNKNOWN_DOCKING_IDENTIFIER 0xffffffff +#define UNABLE_TO_DETERMINE_DOCK_CAPABILITIES 0x89 +#define FUNCTION_NOT_SUPPORTED 0x82 +#define SYSTEM_NOT_DOCKED 0x87 + +// +// Pnp BIOS device node structure +// + +typedef struct _PNP_BIOS_DEVICE_NODE { + USHORT Size; + UCHAR Node; + ULONG ProductId; + UCHAR DeviceType[3]; + USHORT DeviceAttributes; + // followed by AllocatedResourceBlock, PossibleResourceBlock + // and CompatibleDeviceId +} PNP_BIOS_DEVICE_NODE, *PPNP_BIOS_DEVICE_NODE; + +// +// DeviceType definition +// + +#define BASE_TYPE_DOCKING_STATION 0xA + +// +// Device attributes definitions +// + +#define DEVICE_DOCKING 0x20 +#define DEVICE_REMOVABLE 0x40 + +// +// Pnp BIOS Installation check +// + +typedef struct _PNP_BIOS_INSTALLATION_CHECK { + UCHAR Signature[4]; // $PnP (ascii) + UCHAR Revision; + UCHAR Length; + USHORT ControlField; + UCHAR Checksum; + ULONG EventFlagAddress; // Physical address + USHORT RealModeEntryOffset; + USHORT RealModeEntrySegment; + USHORT ProtectedModeEntryOffset; + ULONG ProtectedModeCodeBaseAddress; + ULONG OemDeviceId; + USHORT RealModeDataBaseAddress; + ULONG ProtectedModeDataBaseAddress; +} PNP_BIOS_INSTALLATION_CHECK, *PPNP_BIOS_INSTALLATION_CHECK; + +#include "poppack.h" + +// +// Pnp BIOS ControlField masks +// + +#define PNP_BIOS_CONTROL_MASK 0x3 +#define PNP_BIOS_EVENT_NOT_SUPPORTED 0 +#define PNP_BIOS_EVENT_POLLING 1 +#define PNP_BIOS_EVENT_ASYNC 2 + +// +// Pnp Bios event +// + +#define ABOUT_TO_CHANGE_CONFIG 1 +#define DOCK_CHANGED 2 +#define SYSTEM_DEVICE_CHANGED 3 +#define CONFIG_CHANGE_FAILED 4 diff --git a/private/ntos/nthals/extender/pnpisa.sur/pnpisa.h b/private/ntos/nthals/extender/pnpisa.sur/pnpisa.h new file mode 100644 index 000000000..15b12eeda --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa.sur/pnpisa.h @@ -0,0 +1,164 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pnpisa.h + +Abstract: + + This module contins definitions/declarations for PNP ISA related + definitions. + +Author: + + Shie-Lin Tzong (shielint) July-12-1995 + +Revision History: + +--*/ + +// +// External references +// + +extern PUCHAR PipReadDataPort; +extern PUCHAR PipAddressPort; +extern PUCHAR PipCommandPort; + +// +// Definitions +// + +#ifndef NEC_98 + +#define ADDRESS_PORT 0x0279 +#define COMMAND_PORT 0x0a79 + +#else + +#define ADDRESS_PORT 0x0259 +#define COMMAND_PORT 0x0a59 + +#endif // NEC_98 + +// +// Plug and Play Card Control Registers +// + +#define SET_READ_DATA_PORT 0x00 +#define SERIAL_ISOLATION_PORT 0x01 +#define CONFIG_CONTROL_PORT 0x02 +#define WAKE_CSN_PORT 0x03 +#define CONFIG_DATA_PORT 0x04 +#define CONFIG_DATA_STATUS_PORT 0x05 +#define SET_CSN_PORT 0x06 +#define LOGICAL_DEVICE_PORT 0x07 + +// +// Plug and Play Logical Device Control Registers +// + +#define ACTIVATE_PORT 0x30 +#define IO_RANGE_CHECK_PORT 0x31 + +// +// Config Control command +// + +#define CONTROL_WAIT_FOR_KEY 0x02 +#define CONTROL_RESET_CSN 0x04 + +// +// Memory Space Configuration +// + +#define NUMBER_MEMORY_DESCRIPTORS 4 +#define ADDRESS_MEMORY_BASE 0x40 +#define ADDRESS_MEMORY_INCR 0x08 +#define ADDRESS_MEMORY_HI 0x00 +#define ADDRESS_MEMORY_LO 0x01 +#define ADDRESS_MEMORY_CTL 0x02 +#define ADDRESS_MEMORY_CTL_LIMIT 0x01 +#define ADDRESS_MEMORY_UPPER_HI 0x03 +#define ADDRESS_MEMORY_UPPER_LO 0x04 + +// +// 32 Bit Memory Space Configuration +// + +#define NUMBER_32_MEMORY_DESCRIPTORS 4 +#define ADDRESS_32_MEMORY_BASE(x) ((PUCHAR)(0x70+((x)*0x10)+((x==0) ? 6 : 0))) +#define ADDRESS_32_MEMORY_B3 0x0 +#define ADDRESS_32_MEMORY_B2 0x1 +#define ADDRESS_32_MEMORY_B1 0x2 +#define ADDRESS_32_MEMORY_B0 0x3 +#define ADDRESS_32_MEMORY_CTL 0x4 +#define ADDRESS_32_MEMORY_E3 0x5 +#define ADDRESS_32_MEMORY_E2 0x6 +#define ADDRESS_32_MEMORY_E1 0x7 +#define ADDRESS_32_MEMORY_E0 0x8 + +// +// Io Space Configuration +// + +#define NUMBER_IO_DESCRIPTORS 8 +#define ADDRESS_IO_BASE 0x60 +#define ADDRESS_IO_INCR 0x02 +#define ADDRESS_IO_BASE_HI 0x00 +#define ADDRESS_IO_BASE_LO 0x01 + +// +// Interrupt Configuration +// + +#define NUMBER_IRQ_DESCRIPTORS 2 +#define ADDRESS_IRQ_BASE 0x70 +#define ADDRESS_IRQ_INCR 0x02 +#define ADDRESS_IRQ_VALUE 0x00 +#define ADDRESS_IRQ_TYPE 0x01 + +// +// DMA Configuration +// + +#define NUMBER_DMA_DESCRIPTORS 2 +#define ADDRESS_DMA_BASE 0x74 +#define ADDRESS_DMA_INCR 0x01 +#define ADDRESS_DMA_VALUE 0x00 +#define NO_DMA 0x04 + +// +// 9 byte serial identifier of a PNP ISA Card +// + +#include "pshpack1.h" +typedef struct _SERIAL_IDENTIFIER_ { + ULONG VenderId; + ULONG SerialNumber; + UCHAR Checksum; +} SERIAL_IDENTIFIER, *PSERIAL_IDENTIFIER; +#include "poppack.h" + +// +// Misc. definitions +// + +#define MIN_READ_DATA_PORT 0x200 +#define MAX_READ_DATA_PORT 0x3ff +#define MAX_CHARACTER_LENGTH 255 +#define NUMBER_CARD_ID_BYTES 9 +#define NUMBER_CARD_ID_BITS (NUMBER_CARD_ID_BYTES * 8) +#define CHECKSUMED_BITS 64 +#define LFSR_SEED 0x6A +#define ISOLATION_TEST_BYTE_1 0x55 +#define ISOLATION_TEST_BYTE_2 0xAA + +#define PipWriteAddress(data) WRITE_PORT_UCHAR (PipAddressPort, (UCHAR)(data)) +#define PipWriteData(data) WRITE_PORT_UCHAR (PipCommandPort, (UCHAR)(data)) +#define PipReadData() READ_PORT_UCHAR (PipReadDataPort) + + + diff --git a/private/ntos/nthals/extender/pnpisa.sur/pnpisa.rc b/private/ntos/nthals/extender/pnpisa.sur/pnpisa.rc new file mode 100644 index 000000000..4422bbfd2 --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa.sur/pnpisa.rc @@ -0,0 +1,11 @@ +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "PNP ISA Driver" +#define VER_INTERNALNAME_STR "pnpisa.sys" +#define VER_ORIGINALFILENAME_STR "pnpisa.sys" + +#include "common.ver" diff --git a/private/ntos/nthals/extender/pnpisa.sur/resource.c b/private/ntos/nthals/extender/pnpisa.sur/resource.c new file mode 100644 index 000000000..4e81668a5 --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa.sur/resource.c @@ -0,0 +1,680 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + devres.c + +Abstract: + + This module contains the high level device resources support routines. + +Author: + + Shie-Lin Tzong (shielint) July-27-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "busp.h" +#include "pnpisa.h" +#include "pbios.h" + +#define IDBG 0 + +#pragma alloc_text(INIT,PipGetCardIdentifier) +#pragma alloc_text(INIT,PipGetFunctionIdentifier) +#pragma alloc_text(INIT,PipGetCompatibleDeviceId) +#pragma alloc_text(INIT,PipQueryDeviceId) +#pragma alloc_text(INIT,PipQueryDeviceUniqueId) +#pragma alloc_text(INIT,PipQueryDeviceResources) +#pragma alloc_text(INIT,PipQueryDeviceResourceRequirements) +#pragma alloc_text(INIT,PipSetDeviceResources) + +NTSTATUS +PipGetCardIdentifier ( + PUCHAR CardData, + PWCHAR *Buffer, + PULONG BufferLength + ) +/*++ + +Routine Description: + + This function returns the identifier for a pnpisa card. + +Arguments: + + CardData - supplies a pointer to the pnp isa device data. + + Buffer - supplies a pointer to variable to receive a pointer to the Id. + + BufferLength - supplies a pointer to a variable to receive the size of the id buffer. + +Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + UCHAR tag; + LONG size, length; + UNICODE_STRING unicodeString; + ANSI_STRING ansiString; + PCHAR ansiBuffer; + + *Buffer = NULL; + *BufferLength = 0; + + tag = *CardData; + + // + // Make sure CardData does *NOT* point to a Logical Device Id tag + // + + if ((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID) { + DbgPrint("PipGetCardIdentifier: CardData is at a Logical Id tag\n"); + return status; + } + + // + // Find the resource descriptor which describle identifier string + // + + do { + + // + // Do we find the identifer resource tag? + // + + if (tag == TAG_ANSI_ID) { + CardData++; + length = *(PUSHORT)CardData; + CardData += 2; + ansiBuffer = (PCHAR)ExAllocatePool(PagedPool, length+1); + if (ansiBuffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + RtlMoveMemory(ansiBuffer, CardData, length); + ansiBuffer[length] = 0; + RtlInitAnsiString(&ansiString, ansiBuffer); + RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); + ExFreePool(ansiBuffer); + *Buffer = unicodeString.Buffer; + *BufferLength = unicodeString.Length + sizeof(WCHAR); + break; + } + + // + // Determine the size of the BIOS resource descriptor and + // advance to next resource descriptor. + // + + if (!(tag & LARGE_RESOURCE_TAG)) { + size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); + size += 1; // length of small tag + } else { + size = *(PUSHORT)(CardData + 1); + size += 3; // length of large tag + } + + CardData += size; + tag = *CardData; + + } while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)); + + return status; +} + +NTSTATUS +PipGetFunctionIdentifier ( + PUCHAR DeviceData, + PWCHAR *Buffer, + PULONG BufferLength + ) +/*++ + +Routine Description: + + This function returns the desired pnp isa identifier for the specified + DeviceData/LogicalFunction. The Identifier for a logical function is + optional. If no Identifier available , Buffer is set to NULL. + +Arguments: + + DeviceData - supplies a pointer to the pnp isa device data. + + Buffer - supplies a pointer to variable to receive a pointer to the Id. + + BufferLength - supplies a pointer to a variable to receive the size of the id buffer. + +Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + UCHAR tag; + LONG size, length; + UNICODE_STRING unicodeString; + ANSI_STRING ansiString; + PCHAR ansiBuffer; + + *Buffer = NULL; + *BufferLength = 0; + + tag = *DeviceData; + +#if DBG + + // + // Make sure device data points to Logical Device Id tag + // + + if ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID) { + DbgPrint("PipGetFunctionIdentifier: DeviceData is not at a Logical Id tag\n"); + } +#endif + + // + // Skip all the resource descriptors to find compatible Id descriptor + // + + do { + + // + // Determine the size of the BIOS resource descriptor and + // advance to next resource descriptor. + // + + if (!(tag & LARGE_RESOURCE_TAG)) { + size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); + size += 1; // length of small tag + } else { + size = *(PUSHORT)(DeviceData + 1); + size += 3; // length of large tag + } + + DeviceData += size; + tag = *DeviceData; + + // + // Do we find the identifer resource tag? + // + + if (tag == TAG_ANSI_ID) { + DeviceData++; + length = *(PUSHORT)DeviceData; + DeviceData += 2; + ansiBuffer = (PCHAR)ExAllocatePool(PagedPool, length+1); + if (ansiBuffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + RtlMoveMemory(ansiBuffer, DeviceData, length); + ansiBuffer[length] = 0; + RtlInitAnsiString(&ansiString, ansiBuffer); + RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); + ExFreePool(ansiBuffer); + *Buffer = unicodeString.Buffer; + *BufferLength = unicodeString.Length + sizeof(WCHAR); + break; + } + + } while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)); + + return status; +} + +NTSTATUS +PipGetCompatibleDeviceId ( + PUCHAR DeviceData, + ULONG IdIndex, + PWCHAR *Buffer + ) +/*++ + +Routine Description: + + This function returns the desired pnp isa id for the specified DeviceData + and Id index. If Id index = 0, the Hardware ID will be return; if id + index = n, the Nth compatible id will be returned. + +Arguments: + + DeviceData - supplies a pointer to the pnp isa device data. + + IdIndex - supplies the index of the compatible id desired. + + Buffer - supplies a pointer to variable to receive a pointer to the compatible Id. + +Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status = STATUS_NO_MORE_ENTRIES; + UCHAR tag; + ULONG count = 0; + LONG size; + UNICODE_STRING unicodeString; + ANSI_STRING ansiString; + UCHAR eisaId[8]; + ULONG id; + + tag = *DeviceData; + +#if DBG + + // + // Make sure device data points to Logical Device Id tag + // + + if ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID) { + DbgPrint("PipGetCompatibleDeviceId: DeviceData is not at Logical Id tag\n"); + } +#endif + + if (IdIndex == 0) { + + // + // Caller is asking for hardware id + // + + DeviceData++; // Skip tag + id = *(PULONG)DeviceData; + status = STATUS_SUCCESS; + } else { + + // + // caller is asking for compatible id + // + + IdIndex--; + + // + // Skip all the resource descriptors to find compatible Id descriptor + // + + do { + + // + // Determine the size of the BIOS resource descriptor and + // advance to next resource descriptor. + // + + if (!(tag & LARGE_RESOURCE_TAG)) { + size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); + size += 1; // length of small tag + } else { + size = *(PUSHORT)(DeviceData + 1); + size += 3; // length of large tag + } + + DeviceData += size; + tag = *DeviceData; + + // + // Do we reach the compatible ID descriptor? + // + + if ((tag & SMALL_TAG_MASK) == TAG_COMPATIBLE_ID) { + if (count == IdIndex) { + id = *(PULONG)(DeviceData + 1); + status = STATUS_SUCCESS; + break; + } else { + count++; + } + } + + } while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)); + } + + if (NT_SUCCESS(status)) { + PipDecompressEisaId(id, eisaId); + RtlInitAnsiString(&ansiString, eisaId); + RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); + *Buffer = (PWCHAR)ExAllocatePool ( + PagedPool, + sizeof(L"*") + sizeof(WCHAR) + unicodeString.Length + ); + if (*Buffer) { + swprintf(*Buffer, L"*%s", unicodeString.Buffer); + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + RtlFreeUnicodeString(&unicodeString); + } + return status; +} + +NTSTATUS +PipQueryDeviceUniqueId ( + PDEVICE_INFORMATION DeviceInfo, + PWCHAR *DeviceId + ) +/*++ + +Routine Description: + + This function returns the unique id for the particular device. + +Arguments: + + DeviceData - Device data information for the specificied device. + + DeviceId - supplies a pointer to a variable to receive device id. + +Return Value: + + NTSTATUS code. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + // + // Set up device's unique id. + // device unique id = SerialNumber of the card + // + + *DeviceId = (PWCHAR)ExAllocatePool ( + PagedPool, + (8 + 1) * sizeof(WCHAR) // serial number + null + ); + if (*DeviceId) { + swprintf (*DeviceId, + L"%08X", + ((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->SerialNumber + ); +#if IDBG + { + ANSI_STRING ansiString; + UNICODE_STRING unicodeString; + + RtlInitUnicodeString(&unicodeString, *DeviceId); + RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE); + DbgPrint("PnpIsa: return Unique Id = %s\n", ansiString.Buffer); + RtlFreeAnsiString(&ansiString); + } +#endif + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + + } + + return status; +} + +NTSTATUS +PipQueryDeviceId ( + PDEVICE_INFORMATION DeviceInfo, + PWCHAR *DeviceId, + ULONG IdIndex + ) +/*++ + +Routine Description: + + This function returns the device id for the particular device. + +Arguments: + + DeviceInfo - Device information for the specificied device. + + DeviceId - supplies a pointer to a variable to receive the device id. + + IdIndex - specifies device id or compatible id (0 - device id) + +Return Value: + + NTSTATUS code. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PWSTR format; + ULONG size; + UCHAR eisaId[8]; + UNICODE_STRING unicodeString; + ANSI_STRING ansiString; + + // + // Set up device's id. + // device id = VenderId + Logical device number + // + + if (DeviceInfo->CardInformation->NumberLogicalDevices == 1) { + format = L"ISAPNP\\%s"; + size = sizeof(L"ISAPNP\\*") + sizeof(WCHAR); + } else { + format = L"ISAPNP\\%s_DEV%04X"; + size = sizeof(L"ISAPNP\\_DEV") + 4 * sizeof(WCHAR) + sizeof(WCHAR); + } + PipDecompressEisaId( + ((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->VenderId, + eisaId + ); + RtlInitAnsiString(&ansiString, eisaId); + RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); + size += unicodeString.Length; + *DeviceId = (PWCHAR)ExAllocatePool (PagedPool, size); + if (*DeviceId) { + swprintf (*DeviceId, + format, + unicodeString.Buffer, + DeviceInfo->LogicalDeviceNumber + ); +#if IDBG + { + ANSI_STRING dbgAnsiString; + UNICODE_STRING dbgUnicodeString; + + RtlInitUnicodeString(&dbgUnicodeString, *DeviceId); + RtlUnicodeStringToAnsiString(&dbgAnsiString, &dbgUnicodeString, TRUE); + DbgPrint("PnpIsa: return device Id = %s\n", dbgAnsiString.Buffer); + RtlFreeAnsiString(&dbgAnsiString); + } +#endif + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + RtlFreeUnicodeString(&unicodeString); + + return status; +} + +NTSTATUS +PipQueryDeviceResources ( + PDEVICE_INFORMATION DeviceInfo, + ULONG BusNumber, + PCM_RESOURCE_LIST *CmResources, + ULONG *Size + ) +/*++ + +Routine Description: + + This function returns the bus resources being used by the specified device + +Arguments: + + DeviceInfo - Device information for the specificied slot + + BusNumber - should always be 0 + + CmResources - supplies a pointer to a variable to receive the device resource + data. + + Size - Supplies a pointer to avariable to receive the size of device resource + data. + +Return Value: + + NTSTATUS code. + +--*/ +{ + ULONG length; + NTSTATUS status; + PCM_RESOURCE_LIST cmResources; + + PipSelectLogicalDevice(DeviceInfo->CardInformation->CardSelectNumber, + DeviceInfo->LogicalDeviceNumber, + FALSE + ); + + status = PipReadDeviceBootResourceData ( + BusNumber, + DeviceInfo->DeviceData, + &cmResources, + &length + ); + + // + // Put all cards into wait for key state. + // + + PipWriteAddress(CONFIG_CONTROL_PORT); + PipWriteData(CONTROL_WAIT_FOR_KEY); + + // + // Return results + // + + if (NT_SUCCESS(status)) { + if (length == 0) { + cmResources = NULL; // Just to make sure. + } + *CmResources = cmResources; + *Size = length; +#if IDBG + PipDumpCmResourceList(cmResources); +#endif + } + return status; +} + +NTSTATUS +PipQueryDeviceResourceRequirements ( + PDEVICE_INFORMATION DeviceInfo, + ULONG BusNumber, + ULONG Slot, + PIO_RESOURCE_REQUIREMENTS_LIST *IoResources, + ULONG *Size + ) +/*++ + +Routine Description: + + This function returns the possible bus resources that this device may be + satisfied with. + +Arguments: + + DeviceData - Device data information for the specificied slot + + BusNumber - Supplies the bus number + + Slot - supplies the slot number of the BusNumber + + IoResources - supplies a pointer to a variable to receive the IO resource + requirements list + +Return Value: + + The device control is completed + +--*/ +{ + ULONG length = 0; + NTSTATUS status; + PUCHAR deviceData; + PIO_RESOURCE_REQUIREMENTS_LIST ioResources; + + deviceData = DeviceInfo->DeviceData; + status = PbBiosResourcesToNtResources ( + BusNumber, + Slot, + &deviceData, + &ioResources, + &length + ); + + // + // Return results + // + + if (NT_SUCCESS(status)) { + if (length == 0) { + ioResources = NULL; // Just ot make sure + } + *IoResources = ioResources; + *Size = length; +#if IDBG + PipDumpIoResourceList(ioResources); +#endif + } + return status; +} + +NTSTATUS +PipSetDeviceResources ( + PDEVICE_INFORMATION DeviceInfo, + PCM_RESOURCE_LIST CmResources + ) +/*++ + +Routine Description: + + This function configures the device to the specified device setttings + +Arguments: + + DeviceInfo - Device information for the specificied slot + + CmResources - pointer to the desired resource list + +Return Value: + + NTSTATUS code. + +--*/ +{ + NTSTATUS status; + + PAGED_CODE(); + + PipSelectLogicalDevice(DeviceInfo->CardInformation->CardSelectNumber, + DeviceInfo->LogicalDeviceNumber, + FALSE + ); + + // + // Set resource settings for the device + // + + status = PipWriteDeviceBootResourceData ( + DeviceInfo->DeviceData, + (PCM_RESOURCE_LIST) CmResources + ); + // + // Put all cards into wait for key state. + // + + PipWriteAddress(CONFIG_CONTROL_PORT); + PipWriteData(CONTROL_WAIT_FOR_KEY); + + return status; +} diff --git a/private/ntos/nthals/extender/pnpisa.sur/sources b/private/ntos/nthals/extender/pnpisa.sur/sources new file mode 100644 index 000000000..f0b391be2 --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa.sur/sources @@ -0,0 +1,47 @@ +!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 + +ALT_PROJECT_TARGET=dlibbin + +MAJORCOMP=ntos +MINORCOMP=extender + +TARGETNAME=pnpisa +TARGETPATH=$(BASEDIR)\public\sdk\lib +TARGETTYPE=DRIVER + +INCLUDES=..\..\..\inc + +SOURCES=pnpisa.rc \ + bus.c \ + data.c \ + init.c \ + isolate.c \ + misc.c \ + convert.c \ + resource.c + +NTTEST= +OPTIONAL_NTTEST= +UMTEST= diff --git a/private/ntos/nthals/extender/pnpisa/i386/bus.c b/private/ntos/nthals/extender/pnpisa/i386/bus.c new file mode 100644 index 000000000..f4c6dd4df --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa/i386/bus.c @@ -0,0 +1,1036 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + bus.c + +Abstract: + + +Author: + + Shie-Lin Tzong (shielint) July-26-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "busp.h" +#include "pnpisa.h" + +PDEVICE_INFORMATION +PipFindDeviceInformation ( + IN PPI_BUS_EXTENSION BusExtension, + IN ULONG SlotNumber + ); + +PCARD_INFORMATION +PipFindCardInformation ( + IN PPI_BUS_EXTENSION BusExtension, + IN PSERIAL_IDENTIFIER Id + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,PiQueryBusSlots) +#pragma alloc_text(PAGE,PiReferenceDeviceHandler) +#pragma alloc_text(PAGE,PipCheckBus) +#endif + + +ULONG +PiGetBusData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG SlotNumber, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) + +/*++ + +Routine Description: + + The function returns the Pnp Isa bus data for a device. + This API is not supported. + +Arguments: + + BusHandler - supplies a pointer to the handler of the bus. + + RootHandler - supplies a pointer to a BUS_HANDLER for the originating + request. + + Buffer - Supplies the space to store the data. + + Offset - Supplies the offset to the device data to start reading. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ + +{ + return 0; +} + +ULONG +PiSetBusData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG SlotNumber, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) + +/*++ + +Routine Description: + + The function sets the Pnp Isa bus data for a device. + This API is not supported. + +Arguments: + + BusHandler - supplies a pointer to the handler of the bus. + + RootHandler - supplies a pointer to a BUS_HANDLER for the originating + request. + + Buffer - Supplies the space to store the data. + + Offset - Supplies the offset to the device data to be set. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ + +{ + return 0; +} + +ULONG +PiGetDeviceData ( + 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 + ) +/*++ + +Routine Description: + + The function returns the Pnp Isa device data for a device. + +Arguments: + + BusHandler - supplies a pointer to the handler of the bus. + + RootHandler - supplies a pointer to a BUS_HANDLER for the originating + request. + + DeviceHandler - supplies a pointer to a DEVICE_HANDLER_OBJECT + + DataType - Specifies the type of device data desired. + + Buffer - Supplies the space to store the data. + + Offset - Supplies the offset to the device data to start reading. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ +{ + ULONG dataLength; + PDEVICE_INFORMATION deviceInfo; + + UNREFERENCED_PARAMETER ( DataType); + + dataLength = 0; + deviceInfo = DeviceHandler2DeviceInfo (DeviceHandler); + + // + // Synchronize with other pnp Isa service functions accessing device data. + // + + ExAcquireFastMutex(&PipMutex); + + // + // Verify caller has a valid DeviceHandler object + // + + if (!(deviceInfo->Flags & DEVICE_FLAGS_VALID)) { + + // + // Obsolete object, return no data + // + + ExReleaseFastMutex(&PipMutex); + return dataLength; + } + + // + // Get the device's data. + // + + dataLength = deviceInfo->DeviceDataLength; + if (Offset < dataLength) { + dataLength -= Offset; + if (dataLength > Length) { + dataLength = Length; + } + RtlMoveMemory(Buffer, (PUCHAR)deviceInfo->DeviceData + Offset, dataLength); + } else { + dataLength = 0; + } + + ExReleaseFastMutex(&PipMutex); + return dataLength; +} + +ULONG +PiSetDeviceData ( + 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 + ) +/*++ + +Routine Description: + + The function sets Pnp Isa device data for a device. + +Arguments: + + BusHandler - supplies a pointer to the handler of the bus. + + RootHandler - supplies a pointer to a BUS_HANDLER for the originating + request. + + DeviceHandler - supplies a pointer to a DEVICE_HANDLER_OBJECT + + DataType - Specifies the type of device data desired. + + Buffer - Supplies the space to store the data. + + Offset - Supplies the offset to the device data to start reading. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data set. + +--*/ +{ + // + // We don't let drivers change Pnp device data. + // + + return 0; +} + +NTSTATUS +PiQueryBusSlots ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BufferSize, + OUT PULONG SlotNumbers, + OUT PULONG ReturnedLength + ) + +/*++ + +Routine Description: + + The function returns a list of currently available SlotNumber. + +Arguments: + + BusHandler - supplies a pointer to the handler of the bus. + + RootHandler - supplies a pointer to a BUS_HANDLER for the originating + request. + + Buffer - Supplies the space to store the data. + + SlotNumber - Supplies a variable to receives the number of available slots. + + Length - Supplies a count in bytes of the stored data. If this function + returns STATUS_BUFFER_TOO_SMALL, this variable supplies the required + size. + +Return Value: + + STATUS_BUFFER_TOO_SMALL if caller supplied buffer is not big enough. + +--*/ + +{ + PPI_BUS_EXTENSION busExtension; + PSINGLE_LIST_ENTRY link; + PDEVICE_INFORMATION deviceInfo; + ULONG count = 0; + + PAGED_CODE (); + + busExtension = (PPI_BUS_EXTENSION)BusHandler->BusData; + + // + // Synchronize with other pnp Isa device handle assignment. + // + + ExAcquireFastMutex(&PipMutex); + + // + // Fill in returned buffer length, or what size buffer is needed + // + + *ReturnedLength = busExtension->NoValidSlots * sizeof (ULONG); + if (BufferSize < *ReturnedLength) { + + // + // Callers buffer is not large enough + // + + ExReleaseFastMutex (&PipMutex); + return STATUS_BUFFER_TOO_SMALL; + } + + // + // Return caller all the possible slot number + // + + for (link = busExtension->DeviceList.Next; link; link = link->Next) { + deviceInfo = CONTAINING_RECORD (link, DEVICE_INFORMATION, DeviceList); + if (deviceInfo->Flags & DEVICE_FLAGS_VALID) { + *SlotNumbers = DeviceInfoSlot(deviceInfo); + SlotNumbers++; + count += 1; + } + } + + *ReturnedLength = count * sizeof (ULONG); + ExReleaseFastMutex (&PipMutex); + return STATUS_SUCCESS; +} + +NTSTATUS +PiDeviceControl ( + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ) + +/*++ + +Routine Description: + + The function is the bus handler specific verion of HalDeviceControl. + +Arguments: + + Context - The DeviceControl context. The context has all the information + for the HalDeviceControl operation being performed. + +Return Value: + + A NTSTATUS code to indicate the result of the operation. + +--*/ +{ + ULONG i, junk; + ULONG controlCode; + PULONG bufferLength; + NTSTATUS status = STATUS_INVALID_PARAMETER; + + for (i = 0; i < NUMBER_DEVICE_CONTROL_FUNCTIONS; i++) { + + if (PipDeviceControl[i].ControlCode == Context->DeviceControl.ControlCode) { + if (PipDeviceControl[i].ControlHandler == NULL) { + status = Context->DeviceControl.Status = STATUS_NOT_IMPLEMENTED; + goto deviceControlDone; + } + + // + // Found DeviceControl handler and save it to HAL_DEVICE_CONTROL_CONTEXT + // structure. + // + + Context->ContextControlHandler = (ULONG)(PipDeviceControl + i); + + // + // Verify callers buffer is the min required length + // + + if (*Context->DeviceControl.BufferLength < PipDeviceControl[i].MinBuffer) { + Context->DeviceControl.Status = STATUS_BUFFER_TOO_SMALL; + *Context->DeviceControl.BufferLength = PipDeviceControl[i].MinBuffer; + status = STATUS_BUFFER_TOO_SMALL; + goto deviceControlDone; + } + + if (KeGetCurrentIrql() < DISPATCH_LEVEL) { + + // + // All supported slot control functions touch paged code or data. + // If the current irql is low enough go dispatch now; otherwise, + // queue the request to a worker thread. + // + + PipDispatchControl (Context); + + } else { + + // + // Enqueue to worker thread + // + + ExInterlockedInsertTailList ( + &PipControlWorkerList, + (PLIST_ENTRY) &Context->ContextWorkQueue, + &PipSpinlock + ); + + // + // Make sure worker is requested + // + + PipStartWorker (); + } + return STATUS_PENDING; + } + } + +deviceControlDone: + HalCompleteDeviceControl (Context); + return status; +} + +PDEVICE_HANDLER_OBJECT +PiReferenceDeviceHandler ( + IN struct _BUS_HANDLER *BusHandler, + IN struct _BUS_HANDLER *RootHandler, + IN ULONG SlotNumber + ) +/*++ + +Routine Description: + + The function returns a reference to the devce handler specified by SlotNumber + and BusHandler. + +Arguments: + + BusHandler - Supplies a pointer to the bus handler structure for the bus + + RootHanler - Supplies a pointer to the root bus handler structure for the bus + + SlotNumber - Specifies the SlotNumber of the device to be referenced + +Return Value: + + a reference to DEVICE_HANDLER_OBJECT. + +--*/ +{ + PDEVICE_INFORMATION deviceInfo; + PDEVICE_HANDLER_OBJECT deviceHandler; + PPI_BUS_EXTENSION busExtension; + NTSTATUS status; + + PAGED_CODE (); + + ExAcquireFastMutex (&PipMutex); + + busExtension = (PPI_BUS_EXTENSION)BusHandler->BusData; + deviceInfo = PipFindDeviceInformation (busExtension, SlotNumber); + deviceHandler = NULL; + if (deviceInfo) { + deviceHandler = DeviceInfo2DeviceHandler (deviceInfo); + status = ObReferenceObjectByPointer( + deviceHandler, + FILE_READ_DATA | FILE_WRITE_DATA, + *IoDeviceHandlerObjectType, + KernelMode + ); + + if (!NT_SUCCESS(status)) { + deviceHandler = NULL; + } + } + + ExReleaseFastMutex (&PipMutex); + return deviceHandler; +} + +PDEVICE_INFORMATION +PipFindDeviceInformation ( + IN PPI_BUS_EXTENSION BusExtension, + IN ULONG SlotNumber + ) +/*++ + +Routine Description: + + The function goes through device data list to find the desired SlotNumber's + device data. The caller must hold the PipMutex to call this routine. + +Arguments: + + BusExtension - supplies a pointer to current bus'es extension. + + SlotNumber - specified the desired device data. + +Return Value: + + A pointer to the DEVICE_INFORMATION if found. Otherwise a value of NULL is returned. + +--*/ +{ + PDEVICE_INFORMATION deviceInfo; + PSINGLE_LIST_ENTRY link; + PDEVICE_HANDLER_OBJECT deviceHandler; + + // + // Go through the slot data link list to find a match. + // + + for (link = BusExtension->DeviceList.Next; link; link = link->Next) { + deviceInfo = CONTAINING_RECORD (link, DEVICE_INFORMATION, DeviceList); + if (DeviceInfoSlot(deviceInfo) == SlotNumber) { + break; + } + } + + if (!link) { + return NULL; + } else { + return deviceInfo; + } +} + +VOID +PipCheckBus ( + IN PBUS_HANDLER BusHandler + ) + +/*++ + +Routine Description: + + The function enumerates the bus specified by BusHandler. + BUGBUG, Currently the bus extender will not unload even if all the pnp isa + cards are gone. + +Arguments: + + BusHandler - supplies a pointer to the BusHandler of the bus to be enumerated. + +Return Value: + + None. + +--*/ +{ + PPI_BUS_EXTENSION busExtension; + NTSTATUS status; + PDEVICE_HANDLER_OBJECT deviceHandler; + ULONG objectSize, noDevices; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE handle; + PUCHAR cardData; + ULONG dataLength; + USHORT csn, i; + PDEVICE_INFORMATION deviceInfo; + PCARD_INFORMATION cardInfo; + UCHAR tmp; + BOOLEAN notifyBusCheck; + PSINGLE_LIST_ENTRY link; + + PAGED_CODE(); + + busExtension = (PPI_BUS_EXTENSION)BusHandler->BusData; + notifyBusCheck = FALSE; + + // + // We may be removing references to this bus handler, so add + // a reference now. + // + + HalReferenceBusHandler (BusHandler); + + // + // Acquire fast mutex to access device data + // + + ExAcquireFastMutex (&PipMutex); + PipInvalidateCards(busExtension); + + // + // Perform Pnp isolation process. This will assign card select number for each + // Pnp Isa card isolated by the system. All the isolated cards will be put into + // wait-for-key state. + // + + ExAcquireFastMutex(&PipPortMutex); + + PipIsolateCards(&busExtension->NumberCSNs, &busExtension->ReadDataPort); + PipLFSRInitiation (); // send initiation key to put cards into sleep state + + // + // For each card selected build CardInformation and DeviceInformation structures. + // + + for (csn = 1; csn <= busExtension->NumberCSNs; csn++) { + + status = PipReadCardResourceData ( + csn, + &noDevices, + &cardData, + &dataLength); + if (!NT_SUCCESS(status)) { + continue; + } + cardInfo = PipFindCardInformation(busExtension, (PSERIAL_IDENTIFIER)cardData); + if (cardInfo) { + + // + // Find an existing card information structure with the same serial identifier + // Go validate the card information and its associated device information. + // + + cardInfo->Flags |= CARD_FLAGS_VALID; + cardInfo->CardSelectNumber = csn; + for (link = cardInfo->LogicalDeviceList.Next; link; link = link->Next) { + deviceInfo = CONTAINING_RECORD (link, DEVICE_INFORMATION, LogicalDeviceList); + deviceInfo->Flags |= DEVICE_FLAGS_VALID; + } + ExFreePool(cardData); + } else { + + // + // Did not find an existing card information matched the card data. + // Allocate and initialize new card information and its associate device + // information structures. + // + + cardInfo = (PCARD_INFORMATION)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(CARD_INFORMATION), + 'iPnP'); + if (!cardInfo) { + ExFreePool(cardData); +#if DBG + DebugPrint((DEBUG_MESSAGE, "PnpIsa:failed to allocate CARD_INFO structure\n")); +#endif + continue; + } + + // + // Initialize card information structure + // + + RtlZeroMemory(cardInfo, sizeof(CARD_INFORMATION)); + cardInfo->Flags = CARD_FLAGS_VALID; + cardInfo->CardSelectNumber = csn; + cardInfo->NumberLogicalDevices = noDevices; + cardInfo->CardData = cardData; + cardInfo->CardDataLength = dataLength; + + ExInterlockedPushEntryList ( + &busExtension->CardList, + &cardInfo->CardList, + &PipSpinlock + ); +#if DBG + DebugPrint ((DEBUG_MESSAGE, "PnpIsa: adding one pnp card %x\n")); +#endif + // + // For each logical device supported by the card build its DEVICE_INFORMATION + // structures and enable it. + // + + cardData += sizeof(SERIAL_IDENTIFIER); + dataLength -= sizeof(SERIAL_IDENTIFIER); + PipFindNextLogicalDeviceTag(&cardData, &dataLength); + for (i = 0; i < noDevices; i++) { // logical device number starts from 0 + + // + // Select the logical device, disable its io range check and + // enable the device. + // + + PipWriteAddress(LOGICAL_DEVICE_PORT); + PipWriteData(i); + PipWriteAddress(IO_RANGE_CHECK_PORT); + tmp = PipReadData(); + tmp &= ~2; + PipWriteAddress(IO_RANGE_CHECK_PORT); + PipWriteData(tmp); +// PipWriteAddress(ACTIVATE_PORT); +// PipWriteData(1); + + notifyBusCheck = TRUE; + + // + // Initialize the object attributes that will be used to create the + // Device Handler Object. + // + + InitializeObjectAttributes( + &objectAttributes, + NULL, + 0, + NULL, + NULL + ); + + objectSize = PipDeviceHandlerObjectSize + sizeof (DEVICE_INFORMATION); + + // + // 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 = busExtension->NextSlotNumber++; + + // + // 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)) { + + // + // BUGBUG, Deallocate, free reference of the device handler? + // + + // + // Object not created correctly. Skip this slot. + // + + continue; + } + + ZwClose (handle); + + // + // Intialize device tracking structure + // + + deviceHandler->BusHandler = BusHandler; + HalReferenceBusHandler(BusHandler); + + deviceInfo = DeviceHandler2DeviceInfo(deviceHandler); + deviceInfo->Flags |= DEVICE_FLAGS_VALID; + deviceInfo->CardInformation = cardInfo; + deviceInfo->LogicalDeviceNumber = i; + deviceInfo->DeviceData = cardData; + deviceInfo->DeviceDataLength = PipFindNextLogicalDeviceTag(&cardData, &dataLength); + + ExInterlockedPushEntryList ( + &cardInfo->LogicalDeviceList, + &deviceInfo->LogicalDeviceList, + &PipSpinlock + ); +#if DBG + DebugPrint ((DEBUG_MESSAGE, "PnpIsa: adding slot %x\n", DeviceInfoSlot(deviceInfo))); +#endif + + // + // Add it to the list of devices for this bus + // + + busExtension->NoValidSlots += 1; + ExInterlockedPushEntryList ( + &busExtension->DeviceList, + &deviceInfo->DeviceList, + &PipSpinlock + ); + + } + } + } + + // + // Finaly put all cards into wait for key state. + // + + PipWriteAddress(CONFIG_CONTROL_PORT); + PipWriteData(CONTROL_WAIT_FOR_KEY); + + ExReleaseFastMutex(&PipPortMutex); + + // + // Go through the slot data link list to delete all the removed slots. + // + + noDevices = busExtension->NoValidSlots; + PipDeleteCards(busExtension); + if (noDevices != busExtension->NoValidSlots) { + notifyBusCheck = TRUE; + } + ExReleaseFastMutex (&PipMutex); + + // + // Undo reference to bus handler from top of function + // + + HalDereferenceBusHandler (BusHandler); + + // + // Do we need to notify the system buscheck callback? + // + + if (notifyBusCheck) { + HAL_BUS_INFORMATION busInfo; + + busInfo.BusType = BusHandler->InterfaceType; + busInfo.ConfigurationType = BusHandler->ConfigurationType; + busInfo.BusNumber = BusHandler->BusNumber; + busInfo.Reserved = 0; + ExNotifyCallback ( + PipHalCallbacks.BusCheck, + &busInfo, + (PVOID)BusHandler->BusNumber + ); + } +} + +VOID +PipInvalidateCards ( + IN PPI_BUS_EXTENSION BusExtension + ) + +/*++ + +Routine Description: + + The function goes through Pnp Isa Card list and marks all the cards and + the devices associated with the cards as invalid. + The caller must acquire PipMutex to call this routine. + +Arguments: + + BusExtension - supplies a pointer to the extension data of desired bus. + +Return Value: + + None. + +--*/ +{ + PCARD_INFORMATION cardInfo; + PDEVICE_INFORMATION deviceInfo; + PSINGLE_LIST_ENTRY cardLink, deviceLink; + + // + // Go through the card link list to mark ALL the devices as + // in transition state. + // + + for (cardLink = BusExtension->CardList.Next; cardLink; cardLink = cardLink->Next) { + cardInfo = CONTAINING_RECORD (cardLink, CARD_INFORMATION, CardList); + cardInfo->Flags &= ~CARD_FLAGS_VALID; + + // + // For each logical device of the card mark it as invalid + // + + for (deviceLink = cardInfo->LogicalDeviceList.Next; deviceLink; deviceLink = deviceLink->Next) { + deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, LogicalDeviceList); + deviceInfo->Flags &= ~DEVICE_FLAGS_VALID; + } + } + + // + // Reset the CSN number. + // + + BusExtension->NumberCSNs = 0; +} + +VOID +PipDeleteCards ( + IN PPI_BUS_EXTENSION BusExtension + ) +/*++ + +Routine Description: + + The function goes through card list and deletes all the invalid + cards and their associated logical devices. + Note the PipMutex must be acquired before calling this routine. + +Arguments: + + BusExtension - supplies a pointer to the extension data of desired bus. + +Return Value: + + None. + +--*/ +{ + PDEVICE_INFORMATION deviceInfo; + PCARD_INFORMATION cardInfo; + PDEVICE_HANDLER_OBJECT deviceHandler; + PSINGLE_LIST_ENTRY *cardLink, *deviceLink ; + + // + // Go through the card link list to free all the devices + // marked as invalid. + // + + cardLink = &BusExtension->CardList.Next; + while (*cardLink) { + cardInfo = CONTAINING_RECORD (*cardLink, CARD_INFORMATION, CardList); + if (!(cardInfo->Flags & CARD_FLAGS_VALID)) { + + // + // For each logical device of the card mark it as invalid + // + + deviceLink = &cardInfo->LogicalDeviceList.Next; + while (*deviceLink) { + deviceInfo = CONTAINING_RECORD (*deviceLink, DEVICE_INFORMATION, LogicalDeviceList); +#if DBG + DebugPrint((DEBUG_MESSAGE, "Remove slot %x on PnpIsa bus\n", DeviceInfoSlot(deviceInfo))); +#endif + deviceHandler = DeviceInfo2DeviceHandler(deviceInfo); + ObDereferenceObject (deviceHandler); + HalDereferenceBusHandler (BusExtension->BusHandler); + BusExtension->NoValidSlots--; + *deviceLink = (*deviceLink)->Next; + } + + // + // In theory I can't deallocate the card data and card info structures. Because device + // info structure may still exist. The deallocation should be done after device info + // structure ref count is decremented to zero and deallocated. Here I am safe to do + // so because DispatchControl routine checks DeviceInfo flag to make sure it is valid + // before reference card data and card info. + // + + if (cardInfo->CardData) { + ExFreePool(cardInfo->CardData); + } + *cardLink = (*cardLink)->Next; + ExFreePool(cardInfo); + } else { + cardLink = &((*cardLink)->Next); + } + } +} + +PCARD_INFORMATION +PipFindCardInformation ( + PPI_BUS_EXTENSION BusExtension, + PSERIAL_IDENTIFIER Id + ) + +/*++ + +Routine Description: + + The function goes through card list to find the card information structure + which matches the caller supplied Id. Note, this routine ignore the card + structure flags. So, it may return the card information whcih is marked + as invalid. + Note the PipMutex must be acquired before calling this routine. + +Arguments: + + Id - supplies a pointer to the serial identifier of the card. + +Return Value: + + If succeed, the pointer to the card information structure is return. + Otherwise a NULL pointer is returned. + +--*/ +{ + PCARD_INFORMATION cardInfo; + PSINGLE_LIST_ENTRY cardLink; + + // + // Go through the card link list to match the id. + // + + cardLink = BusExtension->CardList.Next; + while (cardLink) { + cardInfo = CONTAINING_RECORD (cardLink, CARD_INFORMATION, CardList); + ASSERT (cardInfo->CardData); + if (RtlEqualMemory(cardInfo->CardData, Id, sizeof(SERIAL_IDENTIFIER))) { + return cardInfo; + } + cardLink = cardLink->Next; + } + return NULL; +} + + diff --git a/private/ntos/nthals/extender/pnpisa/i386/busp.h b/private/ntos/nthals/extender/pnpisa/i386/busp.h new file mode 100644 index 000000000..bef6851ee --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa/i386/busp.h @@ -0,0 +1,576 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + busp.h + +Abstract: + + Hardware independent header file for Pnp Isa bus extender. + +Author: + + Shie-Lin Tzong (shielint) July-26-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "nthal.h" +#include "hal.h" +#include "stdio.h" +#include "stdarg.h" + +// +// Structures +// + +// +// 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] + +// +// CARD_INFORMATION Flags masks +// + +#define CARD_FLAGS_VALID 0x00000001 + +typedef struct _CARD_INFORMATION_ { + + // + // Next points to next CARD_INFORMATION structure + // + + SINGLE_LIST_ENTRY CardList; + ULONG Flags; + + // + // Card select number for this Pnp Isa card. + // + + USHORT CardSelectNumber; + + // + // Number logical devices in the card. + // + + ULONG NumberLogicalDevices; + + // + // Logical device link list + // + + SINGLE_LIST_ENTRY LogicalDeviceList; + + // + // Pointer to card data which includes: + // 9 byte serial identifier for the pnp isa card + // PlugPlay Version number type for the pnp isa card + // Identifier string resource type for the pnp isa card + // Logical device Id resource type (repeat for each logical device) + // + + PVOID CardData; + ULONG CardDataLength; + +} CARD_INFORMATION, *PCARD_INFORMATION; + +// +// DEVICE_INFORMATION Flags masks +// + +#define DEVICE_FLAGS_VALID 0x00000001 + +typedef struct _DEVICE_INFORMATION_ { + + // + // Link list for ALL the Pnp Isa logical devices. + // NextDevice points to next DEVICE_INFORMATION structure + // + + SINGLE_LIST_ENTRY DeviceList; + ULONG Flags; + + // + // Pointer to the CARD_INFORMATION for this device + // + + PCARD_INFORMATION CardInformation; + + // + // Link list for all the logical devices in a Pnp Isa card. + // + + SINGLE_LIST_ENTRY LogicalDeviceList; + + // + // LogicalDeviceNumber selects the corresponding logical device in the + // pnp isa card specified by CSN. + // + + USHORT LogicalDeviceNumber; + + // + // DeviceControl in progress flags + // + + BOOLEAN SyncBusy; + + // + // Pointer to device specific data + // + + PUCHAR DeviceData; + + // + // Length of the device data + // + + ULONG DeviceDataLength; + +} DEVICE_INFORMATION, *PDEVICE_INFORMATION; + +// +// Extension data for Bus extender +// + +typedef struct _PI_BUS_EXTENSION { + + // + // BusHandler points back to the BUS_HANDLER structure for this extension + // + + PBUS_HANDLER BusHandler; + + // + // Number of cards selected + // + + ULONG NumberCSNs; + + // + // ReadDataPort addr + // + + PUCHAR ReadDataPort; + + // + // Next Slot Number to assign + // + + ULONG NextSlotNumber; + + // + // Bus Check request list + // + + LIST_ENTRY CheckBus; + + // + // Device control request list + // + + LIST_ENTRY DeviceControl; + + // + // DeviceList is the DEVICE_INFORMATION link list. + // + + SINGLE_LIST_ENTRY DeviceList; + + // + // NoValidSlots is the number of valid slots + // + + ULONG NoValidSlots; + + // + // CardList is the list of CARD_INFORMATION + // + + SINGLE_LIST_ENTRY CardList; + + // + // NoValidCards is the number of valid card in the CardList + // + +// ULONG NoValidCards; + +} PI_BUS_EXTENSION, *PPI_BUS_EXTENSION; + +typedef struct { + BOOLEAN Control; +} *PBCTL_SET_CONTROL; + +// +// Pnp Bios bus extender device object extension +// + +typedef struct _PI_DEVICE_EXTENSION { + + // + // BusHandler points to the BusHandler structure for the bus + // extender device object. + // + + PBUS_HANDLER BusHandler; + +} PI_DEVICE_EXTENSION, *PPI_DEVICE_EXTENSION; + +// +// SlotControl related internal definitions +// + +typedef VOID (* CONTROL_FUNCTION)(PDEVICE_INFORMATION, PHAL_DEVICE_CONTROL_CONTEXT); + +typedef struct _DEVICE_CONTROL_HANDLER { + + ULONG ControlCode; // Operation code + ULONG MinBuffer; // Minimum buffer requirement for the operation + CONTROL_FUNCTION ControlHandler; // Function to do the actual work + +} DEVICE_CONTROL_HANDLER, *PDEVICE_CONTROL_HANDLER; + +#define NUMBER_DEVICE_CONTROL_FUNCTIONS 11 + +// +// Global Data references +// + +extern FAST_MUTEX PipMutex; +extern FAST_MUTEX PipPortMutex; +extern KSPIN_LOCK PipSpinlock; +extern LIST_ENTRY PipControlWorkerList; +extern LIST_ENTRY PipCheckBusList; +extern ULONG PipWorkerQueued; +extern WORK_QUEUE_ITEM PipWorkItem; +extern ULONG PipNextHandle; +extern DEVICE_CONTROL_HANDLER PipDeviceControl[]; +extern PDRIVER_OBJECT PipDriverObject; +extern HAL_CALLBACKS PipHalCallbacks; +extern PCALLBACK_OBJECT PipEjectCallbackObject; +extern BOOLEAN PipNoBusyFlag; +extern PPI_BUS_EXTENSION PipBusExtension; +extern WCHAR rgzPNPISADeviceName[]; +extern POBJECT_TYPE *IoDeviceHandlerObjectType; +extern PULONG IoDeviceHandlerObjectSize; +extern ULONG PipDeviceHandlerObjectSize; + +#define DeviceHandler2DeviceInfo(a) ((PDEVICE_INFORMATION) (((PUCHAR) a) + PipDeviceHandlerObjectSize)) +#define DeviceInfo2DeviceHandler(a) ((PDEVICE_HANDLER_OBJECT) (((PUCHAR) a) - PipDeviceHandlerObjectSize)) +#define DeviceInfoSlot(a) (DeviceInfo2DeviceHandler(a)->SlotNumber) + +// +// Prototypes +// + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +NTSTATUS +PiAddBusDevices( + IN PUNICODE_STRING ServiceKeyName, + IN PULONG InstanceNumber + ); + +NTSTATUS +PiCreateClose ( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ); + +VOID +PiUnload ( + IN PDRIVER_OBJECT DriverObject + ); + +NTSTATUS +PiReconfigureResources ( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN DRIVER_RECONFIGURE_OPERATION Operation, + IN PCM_RESOURCE_LIST CmResources + ); + +VOID +PipDecompressEisaId( + IN ULONG CompressedId, + IN PUCHAR EisaId + ); + +NTSTATUS +PipGetRegistryValue( + IN HANDLE KeyHandle, + IN PWSTR ValueName, + OUT PKEY_VALUE_FULL_INFORMATION *Information + ); + +NTSTATUS +PbBiosResourcesToNtResources ( + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN OUT PUCHAR *BiosData, + OUT PIO_RESOURCE_REQUIREMENTS_LIST *ReturnedList, + OUT PULONG ReturnedLength + ); + +VOID +PipStartWorker ( + VOID + ); + +VOID +PipQueueCheckBus ( + IN PBUS_HANDLER BusHandler + ); + +VOID +PipControlWorker ( + IN PVOID WorkerContext + ); + +VOID +PipDispatchControl ( + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PipCompleteDeviceControl ( + NTSTATUS Status, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PDEVICE_INFORMATION DeviceData + ); + +BOOLEAN +FASTCALL +PiBCtlNone ( + PDEVICE_INFORMATION DeviceInfo, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +BOOLEAN +FASTCALL +PiBCtlSync ( + PDEVICE_INFORMATION DeviceInfo, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PiCtlQueryDeviceCapabilities ( + PDEVICE_INFORMATION DeviceInfo, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PiCtlQueryDeviceUniqueId ( + PDEVICE_INFORMATION DeviceInfo, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PiCtlQueryDeviceId ( + PDEVICE_INFORMATION DeviceInfo, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PiCtlQueryDeviceResources ( + PDEVICE_INFORMATION DeviceInfo, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PiCtlQueryDeviceResourceRequirements ( + PDEVICE_INFORMATION DeviceInfo, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +VOID +PiCtlSetDeviceResources ( + PDEVICE_INFORMATION DeviceInfo, + PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +ULONG +PiGetBusData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG SlotNumber, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +ULONG +PiSetBusData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG SlotNumber, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +ULONG +PiGetDeviceData ( + 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 +PiSetDeviceData ( + 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 +PiQueryBusSlots ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BufferSize, + OUT PULONG SlotNumbers, + OUT PULONG ReturnedLength + ); + +NTSTATUS +PiDeviceControl ( + IN PHAL_DEVICE_CONTROL_CONTEXT Context + ); + +PDEVICE_HANDLER_OBJECT +PiReferenceDeviceHandler ( + IN struct _BUS_HANDLER *BusHandler, + IN struct _BUS_HANDLER *RootHandler, + IN ULONG SlotNumber + ); + +VOID +PipCheckBus ( + IN PBUS_HANDLER BusHandler + ); + +NTSTATUS +PipReadCardResourceData ( + IN ULONG Csn, + OUT PULONG NumberLogicalDevices, + IN PVOID *ResourceData, + OUT PULONG ResourceDataLength + ); + +NTSTATUS +PipReadDeviceBootResourceData ( + IN ULONG BusNumber, + IN PUCHAR BiosRequirements, + OUT PCM_RESOURCE_LIST *ResourceData, + OUT PULONG Length + ); + +NTSTATUS +PipWriteDeviceBootResourceData ( + IN PUCHAR BiosRequirements, + IN PCM_RESOURCE_LIST CmResources + ); + +VOID +PipSelectLogicalDevice ( + IN USHORT Csn, + IN USHORT LogicalDeviceNumber + ); + +VOID +PipLFSRInitiation ( + VOID + ); + +VOID +PipIsolateCards ( + OUT PULONG NumberCSNs, + IN OUT PUCHAR *ReadDataPort + ); + +ULONG +PipFindNextLogicalDeviceTag ( + IN OUT PUCHAR *CardData, + IN OUT LONG *Limit + ); + +VOID +PipInvalidateCards ( + IN PPI_BUS_EXTENSION busExtension + ); + +VOID +PipDeleteCards ( + IN PPI_BUS_EXTENSION busExtension + ); + +#if DBG + +#define DEBUG_MESSAGE 1 +#define DEBUG_BREAK 2 + +VOID +PipDebugPrint ( + ULONG Level, + PCCHAR DebugMessage, + ... + ); + +VOID +PipDumpIoResourceDescriptor ( + IN PUCHAR Indent, + IN PIO_RESOURCE_DESCRIPTOR Desc + ); + +VOID +PipDumpIoResourceList ( + IN PIO_RESOURCE_REQUIREMENTS_LIST IoList + ); + +VOID +PipDumpCmResourceDescriptor ( + IN PUCHAR Indent, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Desc + ); + +VOID +PipDumpCmResourceList ( + IN PCM_RESOURCE_LIST CmList, + IN ULONG SlotNumber + ); + +#define DebugPrint(arg) PipDebugPrint arg +#else +#define DebugPrint(arg) +#endif + diff --git a/private/ntos/nthals/extender/pnpisa/i386/control.c b/private/ntos/nthals/extender/pnpisa/i386/control.c new file mode 100644 index 000000000..451a86d91 --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa/i386/control.c @@ -0,0 +1,511 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + control.c + +Abstract: + + +Author: + + Shie-Lin Tzong (shielint) Apr-23-1995 + Most of the code is adapted from PCI bus extender. + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "busp.h" + +VOID +PipiCompleteDeviceControl ( + NTSTATUS Status, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PDEVICE_INFORMATION DeviceData, + PBOOLEAN Sync + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,PipControlWorker) +#pragma alloc_text(PAGE,PipCompleteDeviceControl) +#endif + +VOID +PipStartWorker ( + VOID + ) +/*++ + +Routine Description: + + This function is used to start a worker thread. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + ULONG workerQueued; + + if (!PipWorkerQueued) { + workerQueued = ExInterlockedExchangeUlong ( + &PipWorkerQueued, + 1, + PipSpinLock + ); + + if (!workerQueued) { + ExQueueWorkItem (&PipWorkItem, DelayedWorkQueue); + } + } +} + +VOID +PipQueueCheckBus ( + IN PBUS_HANDLER BusHandler + ) +/*++ + +Routine Description: + + This function enqueues Bus check request to buscheck list. + +Arguments: + + BusHandler - supplies a pointer to the bus handler of the bus to be checked. + +Return Value: + + None. + +--*/ +{ + ExInterlockedInsertTailList ( + &PipCheckBusList, + &((PPI_BUS_EXTENSION)BusHandler->BusData)->CheckBus, + &PipSpinlock + ); + + PipStartWorker(); +} + +VOID +PipControlWorker ( + IN PVOID WorkerContext + ) + +/*++ + +Routine Description: + + This function is called by a system worker thread. + + The worker thread dequeues any SlotControls which need to be + processed and dispatches them. + + It then checks for any check bus request. + +Arguments: + + WorkerContext - supplies a pointer to a context for the worker. Here + it is always NULL. + +Return Value: + + None. + +--*/ +{ + PLIST_ENTRY entry; + PPI_BUS_EXTENSION busExtension; + PHAL_DEVICE_CONTROL_CONTEXT context; + + PAGED_CODE (); + + // + // process check bus + // + + for (; ;) { + entry = ExInterlockedRemoveHeadList ( + &PipCheckBusList, + &PipSpinlock + ); + + if (!entry) { + break; + } + busExtension = CONTAINING_RECORD ( + entry, + PI_BUS_EXTENSION, + CheckBus + ); + + PipCheckBus (busExtension->BusHandler); + } + + // + // Reset worker item for next time + // + + ExInitializeWorkItem (&PipWorkItem, PipControlWorker, NULL); + ExInterlockedExchangeUlong (&PipWorkerQueued, 0, PipSpinLock); + + // + // Dispatch pending device controls + // + + for (; ;) { + entry = ExInterlockedRemoveHeadList ( + &PipControlWorkerList, + &PipSpinlock + ); + + if (!entry) { + + // + // All done, exit the loop. + // + + break; + } + + context = CONTAINING_RECORD ( + entry, + HAL_DEVICE_CONTROL_CONTEXT, + ContextWorkQueue, + ); + + PipDispatchControl (context); + } +} + +VOID +PipDispatchControl ( + 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: + + None. + +--*/ +{ + PDEVICE_CONTROL_HANDLER deviceControlHandler; + PPI_BUS_EXTENSION busExtension; + PDEVICE_INFORMATION deviceInfo; + KIRQL oldIrql; + BOOLEAN enqueueIt; + PLIST_ENTRY link; + + deviceControlHandler = (PDEVICE_CONTROL_HANDLER) Context->ContextControlHandler; + deviceInfo = DeviceHandler2DeviceInfo (Context->DeviceControl.DeviceHandler); + + // + // Get access to the slot specific data. + // + + ExAcquireFastMutex(&PipMutex); + + // + // Verify the device data is still valid + // + + if (!(deviceInfo->Flags & DEVICE_FLAGS_VALID)) { + + // + // Caller has invalid handle, or handle to a different device + // + + DebugPrint ((DEBUG_MESSAGE, "PnpIsa: DeviceControl has invalid device handler \n" )); + Context->DeviceControl.Status = STATUS_NO_SUCH_DEVICE; + ExReleaseFastMutex(&PipMutex); + HalCompleteDeviceControl (Context); + return ; + } + busExtension = (PPI_BUS_EXTENSION)Context->Handler->BusData; + + // + // Check to see if this request can be begun now + // + + link = (PLIST_ENTRY) &Context->ContextWorkQueue; + enqueueIt = PiBCtlSync (deviceInfo, Context); + + if (enqueueIt) { + + // + // Enqueue this command to be handled when the slot is no longer busy. + // + + KeAcquireSpinLock (&PipSpinlock, &oldIrql); + InsertTailList (&busExtension->DeviceControl, link); + KeReleaseSpinLock (&PipSpinlock, oldIrql); + ExReleaseFastMutex(&PipMutex); + return ; + } + + // + // Dispatch the function to it's handler + // + + ExReleaseFastMutex(&PipMutex); + deviceControlHandler->ControlHandler (deviceInfo, Context); +} + +VOID +PipiCompleteDeviceControl ( + NTSTATUS Status, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PDEVICE_INFORMATION DeviceInfo, + PBOOLEAN Sync + ) +/*++ + +Routine Description: + + This function is used to complete a SlotControl. If another SlotControl + was delayed on this device, this function will dispatch them + +Arguments: + + Status - supplies a NTSTATUS code for the completion. + + Context - supplies a pointer to the original device control context. + + DeviceInfo - supplies a pointer to the device info structure to be completed. + + Sync - supplies a BOOLEAN variable to indicate + +Return Value: + +--*/ +{ + KIRQL oldIrql; + PLIST_ENTRY link; + PBOOLEAN busyFlag; + BOOLEAN startWorker = FALSE; + PPI_BUS_EXTENSION busExtension; + PDEVICE_HANDLER_OBJECT deviceHandler; + + busyFlag = (PBOOLEAN) Context->ContextBusyFlag; + deviceHandler = DeviceInfo2DeviceHandler(DeviceInfo); + busExtension = (PPI_BUS_EXTENSION)Context->Handler->BusData; + + // + // Pass it to the hal for completion + // + + Context->DeviceControl.Status = Status; + HalCompleteDeviceControl (Context); + + // + // Get access to the slot specific data. + // + + KeAcquireSpinLock (&PipSpinlock, &oldIrql); + + // + // Clear appropiate busy flag + // + + *busyFlag = FALSE; + + // + // Check to see if there are any pending device controls for + // this device. If so, requeue them to the worker thread + // + + for (link = busExtension->DeviceControl.Flink; + link != &busExtension->DeviceControl; + link = link->Flink) { + + Context = CONTAINING_RECORD (link, HAL_DEVICE_CONTROL_CONTEXT, ContextWorkQueue); + if (Context->DeviceControl.DeviceHandler == deviceHandler) { + RemoveEntryList (link); + InsertTailList (&PipControlWorkerList, link); + startWorker = TRUE; + break; + } + } + + KeReleaseSpinLock (&PipSpinlock, oldIrql); + + if (startWorker) { + PipStartWorker (); + } +} + +VOID +PipCompleteDeviceControl ( + NTSTATUS Status, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PDEVICE_INFORMATION DeviceInfo + ) +/*++ + +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(); + + PipiCompleteDeviceControl ( + Status, + Context, + DeviceInfo, + &DeviceInfo->SyncBusy + ); +} + +BOOLEAN +FASTCALL +PiBCtlNone ( + PDEVICE_INFORMATION DeviceInfo, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function is used to indicate there is no synchronization for this + device control function. + +Arguments: + + Context - supplies a pointer to the device control context. + + DeviceInfo - supplies a pointer to the device data to be completed. + +Return Value: + + A boolean value to indicate if the request needs to be enqueued for later + processing. + +--*/ +{ + // + // No synchronization needed for this SlotControl + // + + Context->ContextBusyFlag = (ULONG) &PipNoBusyFlag; + return FALSE; +} + +BOOLEAN +FASTCALL +PiBCtlSync ( + PDEVICE_INFORMATION DeviceInfo, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function is used to synchronize device control request. it checks the + state (busy/not busy) of the slot and returns a boolean flag to indicate + whether the request can be serviced immediately or it needs to be enqueued for + later processing. + +Arguments: + + DeviceInfo - supplies a pointer to the device data to be completed. + + Context - supplies a pointer to the device control context. + +Return Value: + + A boolean value to indicate if the request needs to be enqueued for later + processing. + +--*/ +{ + // + // This is a sync command, verify the slot is not busy with a different + // command. + // + + if (DeviceInfo->SyncBusy) { + + // + // Enqueue this command to be handled when the slot is no longer busy. + // + + return TRUE; + } + + // + // Don't enqueue, dispatch it now + // + + DeviceInfo->SyncBusy = TRUE; + Context->ContextBusyFlag = (ULONG) &DeviceInfo->SyncBusy; + return FALSE; +} + +VOID +PiCtlQueryDeviceCapabilities ( + PDEVICE_INFORMATION DeviceInfo, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function returns the BCTL_DEVICE_CAPABILITIES structure to the caller + specified buffer. + +Arguments: + + DeviceInfo - supplies a pointer to the device data to be completed. + + Context - supplies a pointer to the device control context. + +Return Value: + + None. + +--*/ +{ + PBCTL_DEVICE_CAPABILITIES capabilities; + + capabilities = (PBCTL_DEVICE_CAPABILITIES) Context->DeviceControl.Buffer; + + capabilities->PowerSupported = FALSE; + capabilities->ResumeSupported = FALSE; + capabilities->LockSupported = FALSE; + capabilities->EjectSupported = FALSE; + PipCompleteDeviceControl (STATUS_SUCCESS, Context, DeviceInfo); +} + diff --git a/private/ntos/nthals/extender/pnpisa/i386/convert.c b/private/ntos/nthals/extender/pnpisa/i386/convert.c new file mode 100644 index 000000000..36cf35f99 --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa/i386/convert.c @@ -0,0 +1,1077 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + xlate.c + +Abstract: + + This file contains routines to translate resources between PnP ISA/BIOS + format and Windows NT formats. + +Author: + + Shie-Lin Tzong (shielint) 12-Apr-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "busp.h" +#include "pnpisa.h" +#include "..\..\pnpbios\i386\pbios.h" + +// +// internal structures for resource translation +// + +typedef struct _PB_DEPENDENT_RESOURCES { + ULONG Count; + UCHAR Flags; + UCHAR Priority; + struct _PB_DEPENDENT_RESOURCES *Next; +} PB_DEPENDENT_RESOURCES, *PPB_DEPENDENT_RESOURCES; + +#define DEPENDENT_FLAGS_END 1 + +typedef struct _PB_ATERNATIVE_INFORMATION { + PPB_DEPENDENT_RESOURCES Resources; + ULONG NoDependentFunctions; + ULONG TotalResourceCount; +} PB_ALTERNATIVE_INFORMATION, *PPB_ALTERNATIVE_INFORMATION; + +// +// Internal function references +// + +VOID +PbIoDescriptorToCmDescriptor ( + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor + ); + +PPB_DEPENDENT_RESOURCES +PbAddDependentResourcesToList ( + IN OUT PUCHAR *ResourceDescriptor, + IN ULONG ListNo, + IN PPB_ALTERNATIVE_INFORMATION AlternativeList + ); + +NTSTATUS +PbBiosIrqToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +NTSTATUS +PbBiosDmaToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +NTSTATUS +PbBiosPortFixedToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +NTSTATUS +PbBiosPortToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +NTSTATUS +PbBiosMemoryToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ); + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE,PbBiosResourcesToNtResources) +#pragma alloc_text(PAGE,PbIoDescriptorToCmDescriptor) +#pragma alloc_text(PAGE,PbAddDependentResourcesToList) +#pragma alloc_text(PAGE,PbBiosIrqToIoDescriptor) +#pragma alloc_text(PAGE,PbBiosDmaToIoDescriptor) +#pragma alloc_text(PAGE,PbBiosPortFixedToIoDescriptor) +#pragma alloc_text(PAGE,PbBiosPortToIoDescriptor) +#pragma alloc_text(PAGE,PbBiosMemoryToIoDescriptor) +#endif + +NTSTATUS +PbBiosResourcesToNtResources ( + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN OUT PUCHAR *BiosData, + OUT PIO_RESOURCE_REQUIREMENTS_LIST *ReturnedList, + OUT PULONG ReturnedLength + ) + +/*++ + +Routine Description: + + This routine parses the Bios resource list and generates + a NT resource list. The returned Nt resource list could be either IO + format or CM format. It is caller's responsibility to release the + returned data buffer. + +Arguments: + + SlotNumber - specifies the slot number of the BIOS resource. + + BiosData - Supplies a pointer to a variable which specifies the bios resource + data buffer and which to receive the pointer to next bios resource data. + + ReturnedList - supplies a variable to receive the desired resource list. + + ReturnedLength - Supplies a variable to receive the length of the resource list. + +Return Value: + + NTSTATUS code + +--*/ +{ + PUCHAR buffer; + USHORT mask16, increment; + UCHAR tagName, mask8; + NTSTATUS status; + PPB_ALTERNATIVE_INFORMATION alternativeList = NULL; + ULONG commonResCount = 0, dependDescCount = 0, i, j; + ULONG alternativeListCount = 0, dependFunctionCount = 0; + PIO_RESOURCE_DESCRIPTOR commonResources = NULL, commonIoDesc, dependIoDesc, ioDesc; + PPB_DEPENDENT_RESOURCES dependResList = NULL, dependResources; + BOOLEAN dependent = FALSE; + ULONG listSize, noResLists; + ULONG totalDescCount, descCount; + PIO_RESOURCE_REQUIREMENTS_LIST ioResReqList; + PIO_RESOURCE_LIST ioResList; + + // + // First, scan the bios data to determine the memory requirement and + // the information to build internal data structures. + // + + *ReturnedLength = 0; + alternativeListCount = 0; + buffer = *BiosData; + tagName = *buffer; + while (tagName != TAG_COMPLETE_END) { + + // + // Determine the size of the BIOS resource descriptor + // + + if (!(tagName & LARGE_RESOURCE_TAG)) { + increment = (USHORT)(tagName & SMALL_TAG_SIZE_MASK); + increment += 1; // length of small tag + tagName &= SMALL_TAG_MASK; + } else { + increment = *(PUSHORT)(buffer+1); + increment += 3; // length of large tag + } + + // + // Based on the type of the BIOS resource, determine the count of + // the IO descriptors. + // + + switch (tagName) { + case TAG_IRQ: + mask16 = ((PPNP_IRQ_DESCRIPTOR)buffer)->IrqMask; + i = 0; + while (mask16) { + if (mask16 & 1) { + i++; + } + mask16 >>= 1; + } + if (!dependent) { + commonResCount += i; + } else { + dependDescCount += i; + } + break; + case TAG_DMA: + mask8 = ((PPNP_DMA_DESCRIPTOR)buffer)->ChannelMask; + i = 0; + while (mask8) { + if (mask8 & 1) { + i++; + } + mask8 >>= 1; + } + if (!dependent) { + commonResCount += i; + } else { + dependDescCount += i; + } + break; + case TAG_START_DEPEND: + dependent = TRUE; + dependFunctionCount++; + break; + case TAG_END_DEPEND: + dependent = FALSE; + alternativeListCount++; + break; + case TAG_IO_FIXED: + case TAG_IO: + case TAG_MEMORY: + case TAG_MEMORY32: + case TAG_MEMORY32_FIXED: + if (!dependent) { + commonResCount++; + } else { + dependDescCount++; + } + break; + default: + + // + // Unknown tag. Skip it. + // + + break; + } + + // + // Move to next bios resource descriptor. + // + + buffer += increment; + tagName = *buffer; + } + + // + // if empty bios resources, simply return. + // + + if (commonResCount == 0 && dependFunctionCount == 0) { + *ReturnedList = NULL; + *ReturnedLength = 0; + *BiosData = buffer + 2; + return STATUS_SUCCESS; + } + + // + // Allocate memory for our internal data structures + // + + if (dependFunctionCount) { + dependResources = (PPB_DEPENDENT_RESOURCES)ExAllocatePoolWithTag( + PagedPool, + dependFunctionCount * sizeof(PB_DEPENDENT_RESOURCES) + + dependDescCount * sizeof(IO_RESOURCE_DESCRIPTOR), + 'bPnP' + ); + if (!dependResources) { + return STATUS_INSUFFICIENT_RESOURCES; + } + dependResList = dependResources; // remember it so we can free it. + } + + if (alternativeListCount) { + ASSERT(dependFunctionCount != 0); + alternativeList = (PPB_ALTERNATIVE_INFORMATION)ExAllocatePoolWithTag( + PagedPool, + sizeof(PB_ALTERNATIVE_INFORMATION) * (alternativeListCount + 1), + 'bPnP' + ); + if (!alternativeList) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto exit0; + } + RtlZeroMemory(alternativeList, + sizeof(PB_ALTERNATIVE_INFORMATION) * alternativeListCount + ); + alternativeList[0].Resources = dependResources; + } + if (commonResCount) { + commonResources = (PIO_RESOURCE_DESCRIPTOR)ExAllocatePoolWithTag ( + PagedPool, + sizeof(IO_RESOURCE_DESCRIPTOR) * commonResCount, + 'bPnP' + ); + if (!commonResources) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto exit1; + } + } + + // + // Now start over again to process the bios data and initialize our internal + // resource representation. + // + + commonIoDesc = commonResources; + dependDescCount = 0; + alternativeListCount = 0; + buffer = *BiosData; + tagName = *buffer; + dependent = FALSE; + while (tagName != TAG_COMPLETE_END) { + if (!(tagName & LARGE_RESOURCE_TAG)) { + tagName &= SMALL_TAG_MASK; + } + switch (tagName) { + case TAG_IRQ: + if (dependent) { + ioDesc = dependIoDesc; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosIrqToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + case TAG_DMA: + if (dependent) { + ioDesc = dependIoDesc; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosDmaToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + case TAG_START_DEPEND: + dependent = TRUE; + alternativeList[alternativeListCount].NoDependentFunctions++; + if (dependDescCount != 0) { + + // + // End of current dependent function + // + + dependResources->Count = dependDescCount; + dependResources->Flags = 0; + dependResources->Next = (PPB_DEPENDENT_RESOURCES)dependIoDesc; + dependResources = dependResources->Next; + alternativeList[alternativeListCount].TotalResourceCount += dependDescCount; + } + if (*buffer & SMALL_TAG_SIZE_MASK) { + dependResources->Priority = *(buffer + 1); + } + dependDescCount = 0; + dependIoDesc = (PIO_RESOURCE_DESCRIPTOR)(dependResources + 1); + buffer += 1 + (*buffer & SMALL_TAG_SIZE_MASK); + break; + case TAG_END_DEPEND: + alternativeList[alternativeListCount].TotalResourceCount += dependDescCount; + dependResources->Count = dependDescCount; + dependResources->Flags = DEPENDENT_FLAGS_END; + dependResources->Next = alternativeList[alternativeListCount].Resources; + dependent = FALSE; + dependDescCount = 0; + alternativeListCount++; + alternativeList[alternativeListCount].Resources = (PPB_DEPENDENT_RESOURCES)dependIoDesc; + dependResources = alternativeList[alternativeListCount].Resources; + buffer++; + break; + case TAG_IO: + if (dependent) { + ioDesc = dependIoDesc; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosPortToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + case TAG_IO_FIXED: + if (dependent) { + ioDesc = dependIoDesc; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosPortFixedToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + case TAG_MEMORY: + case TAG_MEMORY32: + case TAG_MEMORY32_FIXED: + if (dependent) { + ioDesc = dependIoDesc; + dependDescCount; + } else { + ioDesc = commonIoDesc; + } + status = PbBiosMemoryToIoDescriptor(&buffer, ioDesc); + if (NT_SUCCESS(status)) { + if (dependent) { + dependIoDesc++; + dependDescCount++; + } else { + commonIoDesc++; + } + } + break; + default: + + // + // Don't-care tag simpley advance the buffer pointer to next tag. + // + + if (*buffer & LARGE_RESOURCE_TAG) { + increment = *(PUSHORT)(buffer+1); + increment += 3; // length of large tag + } else { + increment = (USHORT)(*buffer & SMALL_TAG_SIZE_MASK); + increment += 1; // length of small tag + } + buffer += increment; + } + tagName = *buffer; + } + + if (alternativeListCount != 0) { + alternativeList[alternativeListCount].Resources = NULL; // dummy alternativeList record + } + *BiosData = buffer + 2; // Skip END_TAG + + // + // prepare IoResourceList + // + + noResLists = 1; + for (i = 0; i < alternativeListCount; i++) { + noResLists *= alternativeList[i].NoDependentFunctions; + } + totalDescCount = 0; + for (i = 0; i < alternativeListCount; i++) { + descCount = 1; + for (j = 0; j < alternativeListCount; j++) { + if (j == i) { + descCount *= alternativeList[j].TotalResourceCount; + } else { + descCount *= alternativeList[j].NoDependentFunctions; + } + } + totalDescCount += descCount; + } + listSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + + sizeof(IO_RESOURCE_LIST) * (noResLists - 1) + + sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescCount - + sizeof(IO_RESOURCE_DESCRIPTOR) * noResLists + + sizeof(IO_RESOURCE_DESCRIPTOR) * commonResCount * noResLists; + + ioResReqList = (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePoolWithTag(PagedPool, listSize, 'bPnP'); + if (!ioResReqList) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto exit2; + } + + ioResReqList->ListSize = listSize; + ioResReqList->InterfaceType = Internal; + ioResReqList->BusNumber = BusNumber; + ioResReqList->SlotNumber = SlotNumber; + ioResReqList->Reserved[0] = 0; + ioResReqList->Reserved[1] = 0; + ioResReqList->Reserved[2] = 0; + ioResReqList->AlternativeLists = noResLists; + ioResList = &ioResReqList->List[0]; + + // + // Build resource lists + // + + for (i = 0; i < noResLists; i++) { + ULONG size; + + ioResList->Version = 1; + ioResList->Revision = 1; + buffer = (PUCHAR)&ioResList->Descriptors[0]; + + // + // Copy common resources to the list + // + + if (commonResources) { + size = sizeof(IO_RESOURCE_DESCRIPTOR) * commonResCount; + RtlMoveMemory(buffer, commonResources, size); + buffer += size; + } + + // + // Copy dependent functions if any. + // + + if (alternativeList) { + PbAddDependentResourcesToList(&buffer, 0, alternativeList); + } + + // + // Update io resource list ptr + // + + ioResList->Count = ((ULONG)buffer - (ULONG)&ioResList->Descriptors[0]) / + sizeof(IO_RESOURCE_DESCRIPTOR); + ioResList = (PIO_RESOURCE_LIST)buffer; + } + + *ReturnedLength = listSize; + status = STATUS_SUCCESS; + *ReturnedList = ioResReqList; +exit2: + if (commonResources) { + ExFreePool(commonResources); + } +exit1: + if (alternativeList) { + ExFreePool(alternativeList); + } +exit0: + if (dependResList) { + ExFreePool(dependResList); + } + return status; +} + +PPB_DEPENDENT_RESOURCES +PbAddDependentResourcesToList ( + IN OUT PUCHAR *ResourceDescriptor, + IN ULONG ListNo, + IN PPB_ALTERNATIVE_INFORMATION AlternativeList + ) + +/*++ + +Routine Description: + + This routine adds dependent functions to caller specified list. + +Arguments: + + ResourceDescriptor - supplies a pointer to the descriptor buffer. + + ListNo - supplies an index to the AlternativeList. + + AlternativeList - supplies a pointer to the alternativelist array. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + PPB_DEPENDENT_RESOURCES dependentResources, ptr; + ULONG size; + + // + // Copy dependent resources to caller supplied list buffer and + // update the list buffer pointer. + // + + dependentResources = AlternativeList[ListNo].Resources; + size = sizeof(IO_RESOURCE_DESCRIPTOR) * dependentResources->Count; + RtlMoveMemory(*ResourceDescriptor, dependentResources + 1, size); + *ResourceDescriptor = *ResourceDescriptor + size; + + // + // Add dependent resource of next list to caller's buffer + // + + if (AlternativeList[ListNo + 1].Resources) { + ptr = PbAddDependentResourcesToList(ResourceDescriptor, ListNo + 1, AlternativeList); + } else { + ptr = NULL; + } + if (ptr == NULL) { + AlternativeList[ListNo].Resources = dependentResources->Next; + if (!(dependentResources->Flags & DEPENDENT_FLAGS_END)) { + ptr = dependentResources->Next; + } + } + return ptr; +} + +VOID +PbIoDescriptorToCmDescriptor ( + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor + ) + +/*++ + +Routine Description: + + This routine translates IO_RESOURCE_DESCRIPTOR to CM_PARTIAL_RESOURCE_DESCRIPTOR. + +Arguments: + + IoDescriptor - Supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be converted. + + CmDescriptor - Supplies a pointer to the receiving CM_PARTIAL_RESOURCE_DESCRIPTOR. + +Return Value: + + None. + +--*/ +{ + CmDescriptor->Type = IoDescriptor->Type; + CmDescriptor->ShareDisposition = IoDescriptor->ShareDisposition; + CmDescriptor->Flags = IoDescriptor->Flags; + switch (CmDescriptor->Type) { + case CmResourceTypePort: + CmDescriptor->u.Port.Length = IoDescriptor->u.Port.Length; + CmDescriptor->u.Port.Start = IoDescriptor->u.Port.MinimumAddress; + break; + case CmResourceTypeInterrupt: + CmDescriptor->u.Interrupt.Level = + CmDescriptor->u.Interrupt.Vector = IoDescriptor->u.Interrupt.MinimumVector; + CmDescriptor->u.Interrupt.Affinity = (ULONG)-1; + break; + case CmResourceTypeMemory: + CmDescriptor->u.Memory.Length = IoDescriptor->u.Memory.Length; + CmDescriptor->u.Memory.Start = IoDescriptor->u.Memory.MinimumAddress; + break; + case CmResourceTypeDma: + CmDescriptor->u.Dma.Channel = IoDescriptor->u.Dma.MinimumChannel; + CmDescriptor->u.Dma.Port = 0; + CmDescriptor->u.Dma.Reserved1 = 0; + break; + } +} + +NTSTATUS +PbBiosIrqToIoDescriptor ( + IN OUT PUCHAR *BiosData, + PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS IRQ information to NT usable format. + This routine stops when an irq io resource is generated. if there are + more irq io resource descriptors available, the BiosData pointer will + not advance. So caller will pass us the same resource tag again. + + Note, BIOS DMA info alway uses SMALL TAG. A tag structure is repeated + for each seperated channel required. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + static ULONG bitPosition = 0; + USHORT mask; + ULONG irq; + PPNP_IRQ_DESCRIPTOR buffer; + UCHAR size, option; + NTSTATUS status = STATUS_SUCCESS; + + buffer = (PPNP_IRQ_DESCRIPTOR)*BiosData; + + // + // if this is not the first descriptor for the tag, set + // its option to alternative. + // + + if (bitPosition == 0) { + option = 0; + } else { + option = IO_RESOURCE_ALTERNATIVE; + } + size = buffer->Tag & SMALL_TAG_SIZE_MASK; + mask = buffer->IrqMask; + mask >>= bitPosition; + irq = (ULONG) -1; + + while (mask) { + if (mask & 1) { + irq = bitPosition; + break; + } + mask >>= 1; + bitPosition++; + } + + // + // Fill in Io resource descriptor + // + + if (irq != (ULONG)-1) { + IoDescriptor->Option = option; + IoDescriptor->Type = CmResourceTypeInterrupt; + IoDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; + IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + if (size == 3 && buffer->Information & 0x0C) { + IoDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + IoDescriptor->ShareDisposition = CmResourceShareShared; + } + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Interrupt.MinimumVector = irq; + IoDescriptor->u.Interrupt.MaximumVector = irq; + } else { + status = STATUS_INVALID_PARAMETER; + } + + if (NT_SUCCESS(status)) { + + // + // try to move bitPosition to next 1 bit. + // + + while (mask) { + mask >>= 1; + bitPosition++; + if (mask & 1) { + return status; + } + } + } + + // + // Done with current irq tag, advance pointer to next tag + // + + bitPosition = 0; + *BiosData = (PUCHAR)buffer + size + 1; + return status; +} + +NTSTATUS +PbBiosDmaToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS DMA information to NT usable format. + This routine stops when an dma io resource is generated. if there are + more dma io resource descriptors available, the BiosData pointer will + not advance. So caller will pass us the same resource tag again. + + Note, BIOS DMA info alway uses SMALL TAG. A tag structure is repeated + for each seperated channel required. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + static ULONG bitPosition = 0; + ULONG dma; + PPNP_DMA_DESCRIPTOR buffer; + UCHAR mask, option; + NTSTATUS status = STATUS_SUCCESS; + + buffer = (PPNP_DMA_DESCRIPTOR)*BiosData; + + // + // if this is not the first descriptor for the tag, set + // its option to alternative. + // + + if (bitPosition == 0) { + option = 0; + } else { + option = IO_RESOURCE_ALTERNATIVE; + } + mask = buffer->ChannelMask; + mask >>= bitPosition; + dma = (ULONG) -1; + + while (mask) { + if (mask & 1) { + dma = bitPosition; + break; + } + mask >>= 1; + bitPosition++; + } + + // + // Fill in Io resource descriptor + // + + if (dma != (ULONG)-1) { + IoDescriptor->Option = option; + IoDescriptor->Type = CmResourceTypeDma; + IoDescriptor->Flags = 0; + IoDescriptor->ShareDisposition = CmResourceShareUndetermined; + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Dma.MinimumChannel = dma; + IoDescriptor->u.Dma.MaximumChannel = dma; + } else { + status = STATUS_INVALID_PARAMETER; + } + + if (NT_SUCCESS(status)) { + + // + // try to move bitPosition to next 1 bit. + // + + while (mask) { + mask >>= 1; + bitPosition++; + if (mask & 1) { + return status; + } + } + } + + // + // Done with current dma tag, advance pointer to next tag + // + + bitPosition = 0; + buffer += 1; + *BiosData = (PUCHAR)buffer; + return status; +} + +NTSTATUS +PbBiosPortFixedToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS FIXED IO information to NT usable format. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + PPNP_FIXED_PORT_DESCRIPTOR buffer; + + buffer = (PPNP_FIXED_PORT_DESCRIPTOR)*BiosData; + + // + // Fill in Io resource descriptor + // + + IoDescriptor->Option = 0; + IoDescriptor->Type = CmResourceTypePort; + IoDescriptor->Flags = CM_RESOURCE_PORT_IO; + IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Port.Length = (ULONG)buffer->Length; + IoDescriptor->u.Port.MinimumAddress.LowPart = (ULONG)(buffer->MinimumAddress & 0x3ff); + IoDescriptor->u.Port.MinimumAddress.HighPart = 0; + IoDescriptor->u.Port.MaximumAddress.LowPart = IoDescriptor->u.Port.MinimumAddress.LowPart + + IoDescriptor->u.Port.Length - 1; + IoDescriptor->u.Port.MaximumAddress.HighPart = 0; + IoDescriptor->u.Port.Alignment = 1; + + // + // Done with current fixed port tag, advance pointer to next tag + // + + buffer += 1; + *BiosData = (PUCHAR)buffer; + return STATUS_SUCCESS; +} + +NTSTATUS +PbBiosPortToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS IO information to NT usable format. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + PPNP_PORT_DESCRIPTOR buffer; + + buffer = (PPNP_PORT_DESCRIPTOR)*BiosData; + + // + // Fill in Io resource descriptor + // + + IoDescriptor->Option = 0; + IoDescriptor->Type = CmResourceTypePort; + IoDescriptor->Flags = CM_RESOURCE_PORT_IO; + IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Port.Length = (ULONG)buffer->Length; + IoDescriptor->u.Port.MinimumAddress.LowPart = (ULONG)buffer->MinimumAddress; + IoDescriptor->u.Port.MinimumAddress.HighPart = 0; + IoDescriptor->u.Port.MaximumAddress.LowPart = (ULONG)buffer->MaximumAddress + + IoDescriptor->u.Port.Length - 1; + IoDescriptor->u.Port.MaximumAddress.HighPart = 0; + IoDescriptor->u.Port.Alignment = (ULONG)buffer->Alignment; + + // + // Done with current fixed port tag, advance pointer to next tag + // + + buffer += 1; + *BiosData = (PUCHAR)buffer; + return STATUS_SUCCESS; +} + +NTSTATUS +PbBiosMemoryToIoDescriptor ( + IN OUT PUCHAR *BiosData, + IN PIO_RESOURCE_DESCRIPTOR IoDescriptor + ) + +/*++ + +Routine Description: + + This routine translates BIOS MEMORY information to NT usable format. + +Arguments: + + BiosData - Supplies a pointer to the bios resource data buffer. + + IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer. + Converted resource will be stored here. + +Return Value: + + return NTSTATUS code to indicate the result of the operation. + +--*/ +{ + PUCHAR buffer; + UCHAR tag; + PHYSICAL_ADDRESS minAddr, maxAddr; + ULONG alignment, length; + USHORT increment; + + buffer = *BiosData; + tag = ((PPNP_MEMORY_DESCRIPTOR)buffer)->Tag; + increment = ((PPNP_MEMORY_DESCRIPTOR)buffer)->Length + 3; // larg tag size = 3 + + minAddr.HighPart = 0; + maxAddr.HighPart = 0; + switch (tag) { + case TAG_MEMORY: + minAddr.LowPart = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)buffer)->MinimumAddress)) << 8; + if ((alignment = ((PPNP_MEMORY_DESCRIPTOR)buffer)->Alignment) == 0) { + alignment = 0x10000; + } + length = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)buffer)->MemorySize)) << 8; + maxAddr.LowPart = (((ULONG)(((PPNP_MEMORY_DESCRIPTOR)buffer)->MaximumAddress)) << 8) + length - 1; + break; + case TAG_MEMORY32: + length = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->MemorySize; + minAddr.LowPart = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->MinimumAddress; + maxAddr.LowPart = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->MaximumAddress + length - 1; + alignment = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->Alignment; + break; + case TAG_MEMORY32_FIXED: + length = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)buffer)->MemorySize; + minAddr.LowPart = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)buffer)->BaseAddress; + maxAddr.LowPart = minAddr.LowPart + length - 1; + alignment = 1; + break; + } + // + // Fill in Io resource descriptor + // + + IoDescriptor->Option = 0; + IoDescriptor->Type = CmResourceTypeMemory; + IoDescriptor->Flags = CM_RESOURCE_PORT_MEMORY; + IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + IoDescriptor->Spare1 = 0; + IoDescriptor->Spare2 = 0; + IoDescriptor->u.Memory.MinimumAddress = minAddr; + IoDescriptor->u.Memory.MaximumAddress = maxAddr; + IoDescriptor->u.Memory.Alignment = alignment; + IoDescriptor->u.Memory.Length = length; + + // + // Done with current tag, advance pointer to next tag + // + + buffer += increment; + *BiosData = (PUCHAR)buffer; + return STATUS_SUCCESS; +} diff --git a/private/ntos/nthals/extender/pnpisa/i386/data.c b/private/ntos/nthals/extender/pnpisa/i386/data.c new file mode 100644 index 000000000..be0a9a08f --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa/i386/data.c @@ -0,0 +1,156 @@ + +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pbdata.c + +Abstract: + + Declares various data which is specific to PNP ISA bus extender architecture and + is independent of BIOS. + +Author: + + Shie-Lin Tzong (shielint) July-26-95 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "busp.h" + +// +// PipMutex - To synchronize with device handle changes +// + +FAST_MUTEX PipMutex; + +// +// PipPortMutex - To synchronize with Read data port access. +// Note, you can *not* ask for PipMutex while owning PipPortMutex. +// + +FAST_MUTEX PipPortMutex; + +// +// PipSpinLock - Lock to protect DeviceControl globals +// + +KSPIN_LOCK PipSpinlock; + +// +// PipControlWorkerList - List of device control's which are pending for worker thread +// + +LIST_ENTRY PipControlWorkerList; +ULONG PipWorkerQueued; + +// +// PipWorkItem - Enqueue for DeviceControl worker thread +// + +WORK_QUEUE_ITEM PipWorkItem; + +// +// PipCheckBusList - List to enqueue bus check request +// + +LIST_ENTRY PipCheckBusList; + +// +// Eject callback object +// + +PCALLBACK_OBJECT PipEjectCallbackObject; + +// +// regPNPISADeviceName +// + +WCHAR rgzPNPISADeviceName[] = L"\\Device\\PnpIsa_%d"; + +// +// Size of DeviceHandlerObject +// + +ULONG PipDeviceHandlerObjectSize; + +// +// DeviceControl dispatch table +// + +#define B_EJECT BCTL_EJECT +#define B_UID BCTL_QUERY_DEVICE_UNIQUE_ID +#define B_CAPABILITIES BCTL_QUERY_DEVICE_CAPABILITIES +#define B_ID BCTL_QUERY_DEVICE_ID +#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 + +// +// declare slot control function table. +// NOTE if the number of entries is changed, the NUMBER_SLOT_CONTROL_FUNCTIONS defined in +// busp.h must be chnaged accordingly. +// + +DEVICE_CONTROL_HANDLER PipDeviceControl[] = { + B_EJECT, 0, NULL, + B_ID, 32, PiCtlQueryDeviceId, + B_UID, 32, PiCtlQueryDeviceUniqueId, + B_CAPABILITIES, sizeof(BCTL_DEVICE_CAPABILITIES), PiCtlQueryDeviceCapabilities, + B_RES, sizeof(ULONG), PiCtlQueryDeviceResources, + B_RES_REQ, sizeof(ULONG), PiCtlQueryDeviceResourceRequirements, + B_QUERY_EJECT, sizeof(PVOID), NULL, + B_SET_LOCK, sizeof(BOOLEAN), NULL, + B_SET_RESUME, sizeof(BOOLEAN), NULL, + B_SET_POWER, sizeof(POWER_STATE), NULL, + B_SET_RES, 0, PiCtlSetDeviceResources, +}; + +#ifdef ALLOC_DATA_PRAGMA +#pragma data_seg("PAGE") +#endif + +// +// Bus Extender driver object +// + +PDRIVER_OBJECT PipDriverObject; + +// +// Pointers to Hal callback objects +// + +HAL_CALLBACKS PipHalCallbacks; + +// +// PipNoBusyFlag - scratch memory location to point at +// + +BOOLEAN PipNoBusyFlag; + +// +// Pointers to bus extension data. +// + +PPI_BUS_EXTENSION PipBusExtension; + +// +// Read_data_port address +// (This is mainly for convinience. It duplicates the +// ReadDataPort field in BUS extension structure.) +// + +PUCHAR PipReadDataPort; diff --git a/private/ntos/nthals/extender/pnpisa/i386/init.c b/private/ntos/nthals/extender/pnpisa/i386/init.c new file mode 100644 index 000000000..68108ed7c --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa/i386/init.c @@ -0,0 +1,506 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + init.c + +Abstract: + + DriverEntry initialization code for pnp isa bus extender. + +Author: + + Shie-Lin Tzong (shielint) 3-Aug-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "busp.h" +#include "pnpisa.h" + +NTSTATUS +PiInstallBusHandler ( + IN PBUS_HANDLER PiBus + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,DriverEntry) +#pragma alloc_text(PAGE,PiAddBusDevices) +#pragma alloc_text(PAGE,PiInstallBusHandler) +#endif + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + This routine checks if pnp isa bus exists. if yes, it builds and + initializes pnp isa card information and its associated device information + structure. + +Arguments: + + DriverObject - specifies the driver object for the bus extender. + + RegistryPath - supplies a pointer to a unicode string of the service key name in + the CurrentControlSet\Services key for the bus extender. + +Return Value: + + A NTSTATUS code to indicate the result of the initialization. + +--*/ + +{ + UNICODE_STRING unicodeString; + NTSTATUS status; + PVOID p; + PHAL_BUS_INFORMATION pBusInfo; + HAL_BUS_INFORMATION busInfo; + ULONG length, i, bufferSize, count; + PCM_RESOURCE_LIST configuration = NULL; + ULONG deviceFlags; + PDEVICE_HANDLER_OBJECT deviceHandler; + + // + // First make sure this is the only pnp Isa bus extender running in the system. + // + + status = HalQuerySystemInformation ( + HalInstalledBusInformation, + 0, + pBusInfo, + &length + ); +tryAgain: + if (status == STATUS_BUFFER_TOO_SMALL) { + pBusInfo = ExAllocatePool(PagedPool, length); + if (pBusInfo == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + } else { + DebugPrint((DEBUG_MESSAGE,"PnpIsa: Failed to query installed bus info.\n")); + return STATUS_UNSUCCESSFUL; + } + status = HalQuerySystemInformation ( + HalInstalledBusInformation, + length, + pBusInfo, + &length + ); + + if (!NT_SUCCESS(status)) { + + // + // We need to check the buffer size again. It is possible another bus was added + // between the two HalQuerySystemInformation calls. In this case, the buffer + // requirement is changed. + // + + if (status == STATUS_BUFFER_TOO_SMALL) { + ExFreePool(pBusInfo); + goto tryAgain; + } else { + DebugPrint((DEBUG_MESSAGE,"PnpIsa: Failed to query installed bus info.\n")); + return status; + } + } + + // + // Check installed bus information to make sure there is no existing Pnp Isa + // bus extender. + // + + p = pBusInfo; + for (i = 0; i < length / sizeof(HAL_BUS_INFORMATION); i++, pBusInfo++) { + if (pBusInfo->BusType == PNPISABus && + pBusInfo->ConfigurationType == PNPISAConfiguration) { + DebugPrint((DEBUG_MESSAGE,"PnpIsa: A Pnp Isa bus extender is currently running in the system.\n")); + status = STATUS_UNSUCCESSFUL; + } + } + + ExFreePool(p); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Get pointers to the Hals callback objects. The one we are really interested + // in is Bus Check callback. + // + + status = HalQuerySystemInformation ( + HalCallbackInformation, + sizeof (PipHalCallbacks), + &PipHalCallbacks, + &length + ); + + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE,"PnpIsa: Failed to query Hal callbacks\n")); + return status; + } + + // + // Initialize globals + // + + PipDriverObject = DriverObject; + ExInitializeWorkItem (&PipWorkItem, PipControlWorker, NULL); + KeInitializeSpinLock (&PipSpinlock); + InitializeListHead (&PipControlWorkerList); + InitializeListHead (&PipCheckBusList); + ExInitializeFastMutex (&PipMutex); + ExInitializeFastMutex (&PipPortMutex); + PipDeviceHandlerObjectSize = *IoDeviceHandlerObjectSize; + + // + // Initialize driver object add and detect device entries. + // + + DriverObject->DriverExtension->AddDevice = PiAddBusDevices; + DriverObject->DriverExtension->ReconfigureDevice = PiReconfigureResources; + DriverObject->DriverUnload = PiUnload; + DriverObject->MajorFunction[IRP_MJ_CREATE] = PiCreateClose; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = PiCreateClose; + // + // Query the devices/buses currently controlled by the bus extender + // + + status = IoQueryDeviceEnumInfo (&DriverObject->DriverExtension->ServiceKeyName, &count); + if (!NT_SUCCESS(status)) { + return status; + } + + ASSERT(count == 0 || count == 1); + for (i = 0; i < count; i++) { + status = IoGetDeviceHandler(&DriverObject->DriverExtension->ServiceKeyName, + i, + &deviceHandler); + if (NT_SUCCESS(status)) { + bufferSize = sizeof(CM_RESOURCE_LIST); +tryAgain1: + configuration = (PCM_RESOURCE_LIST)ExAllocatePool(PagedPool, + bufferSize + ); + if (!configuration) { + IoReleaseDeviceHandler(deviceHandler); + return STATUS_INSUFFICIENT_RESOURCES; + } + status = IoQueryDeviceConfiguration(deviceHandler, + &busInfo, + &deviceFlags, + configuration, + bufferSize, // buffer size + &length // Actual size + ); + if (NT_SUCCESS(status)) { + + IoReleaseDeviceHandler(deviceHandler); + + // + // We know we have two buses at most. If this is the first bus, we will add it + // and exit. We don't touch 2nd bus at init time. It should be enumerated + // later. + + if (configuration->List[0].BusNumber == 0 && + configuration->List[0].InterfaceType == PNPISABus) { + if (deviceFlags == DeviceStatusOK) { + PiAddBusDevices(&DriverObject->DriverExtension->ServiceKeyName, &i); + ExFreePool(configuration); + break; + } + } + } else if (status == STATUS_BUFFER_TOO_SMALL) { + ExFreePool(configuration); + bufferSize = length; + goto tryAgain1; + } + ExFreePool(configuration); + } + } + return STATUS_SUCCESS; +} + +NTSTATUS +PiAddBusDevices( + IN PUNICODE_STRING ServiceKeyName, + IN PULONG InstanceNumber + ) + +/*++ + +Routine Description: + +Arguments: + + +Return Value: + + +--*/ + +{ + NTSTATUS status; + PBUS_HANDLER busHandler; + HAL_BUS_INFORMATION busInfo; + ULONG deviceInstanceFlags, actualSize; + PCM_RESOURCE_LIST detectSignature; + UCHAR configuration[sizeof(CM_RESOURCE_LIST)]; + UNICODE_STRING unicodeString; + WCHAR buffer[60]; + PDEVICE_HANDLER_OBJECT deviceHandler; + IO_RESOURCE_REQUIREMENTS_LIST ioResource; + PCM_RESOURCE_LIST cmResource; + PWSTR str; + + PAGED_CODE(); + + // + // Check if DriverEntry succeeded and if the Pnp Isa bus has been + // added already. (There is ONE and only one Pnp Isa bus) + // + + if (!PipDriverObject || (PipBusExtension && PipBusExtension->ReadDataPort)) { + return STATUS_NO_MORE_ENTRIES; + } + + // + // Register bus handler for Pnp Isa bus + // + + status = HalRegisterBusHandler ( + PNPISABus, + PNPISAConfiguration, + (ULONG)-1, + Internal, + 0, + sizeof (PI_BUS_EXTENSION), + PiInstallBusHandler, + &busHandler + ); + + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE,"PnpIsa: Register Pnp bus handler failed\n")); + return status; + } + + if (*InstanceNumber == PLUGPLAY_NO_INSTANCE) { + + // + // Register the bus with Pnp manager as a detected bus. + // + + RtlZeroMemory(configuration, sizeof(CM_RESOURCE_LIST)); + detectSignature = (PCM_RESOURCE_LIST)configuration; + detectSignature->Count = 1; + detectSignature->List[0].InterfaceType = PNPISABus; + detectSignature->List[0].BusNumber = 0; + status = IoRegisterDetectedDevice (ServiceKeyName, detectSignature, InstanceNumber); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_BREAK,"PnpIsa: Failed to register bus as detected bus\n")); + goto errorExit; + } + } + + // + // Call Pnp Io Mgr to register the new device object path + // + + swprintf (buffer, rgzPNPISADeviceName, busHandler->BusNumber); + RtlInitUnicodeString (&unicodeString, buffer); + + if (!NT_SUCCESS(status = IoGetDeviceHandler(&PipDriverObject->DriverExtension->ServiceKeyName, + *InstanceNumber, &deviceHandler)) || + !NT_SUCCESS(status = IoRegisterDevicePath(deviceHandler, &unicodeString, TRUE, NULL, + DeviceStatusOK))) { + + // + // BUGBUG - unregister bus handler? How? + // + + if (deviceHandler) { + DebugPrint((DEBUG_MESSAGE,"PnpIsa: Register NT device path failed\n")); + IoReleaseDeviceHandler(deviceHandler); + } else { + DebugPrint((DEBUG_MESSAGE,"PnpIsa: Unable to get device handler\n")); + } + goto errorExit; + } + + IoReleaseDeviceHandler(deviceHandler); + + + // + // Call I/O mgr to get read data port addr + // + + RtlZeroMemory(&ioResource, sizeof(IO_RESOURCE_REQUIREMENTS_LIST)); + ioResource.ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); + ioResource.InterfaceType = Isa; + ioResource.AlternativeLists = 1; + ioResource.List[0].Version = 1; + ioResource.List[0].Revision = 1; + ioResource.List[0].Count = 1; + ioResource.List[0].Descriptors[0].Type = CmResourceTypePort; + ioResource.List[0].Descriptors[0].ShareDisposition = CmResourceShareDeviceExclusive; + ioResource.List[0].Descriptors[0].Flags = CM_RESOURCE_PORT_IO; + ioResource.List[0].Descriptors[0].u.Port.Length = 4; + ioResource.List[0].Descriptors[0].u.Port.Alignment = 4; + ioResource.List[0].Descriptors[0].u.Port.MinimumAddress.LowPart = MIN_READ_DATA_PORT; + ioResource.List[0].Descriptors[0].u.Port.MaximumAddress.LowPart = MAX_READ_DATA_PORT; + str = (PWSTR)ExAllocatePool(PagedPool, 512); + if (!str) { + status = STATUS_INSUFFICIENT_RESOURCES; + DebugPrint((DEBUG_MESSAGE,"PnpIsa: IoAssignResources failed\n")); + goto errorExit; + } + swprintf(str, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\%s", + ServiceKeyName->Buffer); + RtlInitUnicodeString(&unicodeString, str); + status = IoAssignResources(&unicodeString, + NULL, + PipDriverObject, + PipBusExtension->BusHandler->DeviceObject, + &ioResource, + &cmResource); + ExFreePool(str); + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE,"PnpIsa: IoAssignResources failed\n")); + goto errorExit; + } + + PipBusExtension->ReadDataPort = (PUCHAR)(cmResource->List[0].PartialResourceList. + PartialDescriptors[0].u.Port.Start.LowPart + 3); + ExFreePool(cmResource); + + // + // Perform initial bus check + // + + PipCheckBus(busHandler); + + return STATUS_SUCCESS; + +errorExit: + + // + // BUGBUG We should unregister the bus handler and exit. + // HalUnregisterBusHandler is not supported. + // + + return status; +} + +NTSTATUS +PiInstallBusHandler ( + PBUS_HANDLER BusHandler + ) + +/*++ + +Routine Description: + + This routine is invoked by Hal to initialize BUS_HANDLER structure and its + extension. + +Arguments: + + BusHandler - spplies a pointer to Pnp Isa bus handler's BUS_HANDLER structure. + +Return Value: + + A NTSTATUS code to indicate the result of the initialization. + +--*/ + +{ + WCHAR buffer[60]; + UNICODE_STRING unicodeString; + PPI_DEVICE_EXTENSION deviceExtension; + NTSTATUS status; + PDEVICE_OBJECT deviceObject; + + PAGED_CODE(); + + // + // Verify there's a parent handler + // + + if (!BusHandler->ParentHandler) { + return STATUS_UNSUCCESSFUL; + } + + // + // Create device object for Pnp Isa bus extender. + // + + swprintf (buffer, rgzPNPISADeviceName, BusHandler->BusNumber); + RtlInitUnicodeString (&unicodeString, buffer); + + status = IoCreateDevice( + PipDriverObject, + sizeof(PI_DEVICE_EXTENSION), + &unicodeString, + FILE_DEVICE_BUS_EXTENDER, + 0, + FALSE, + &deviceObject + ); + + if (!NT_SUCCESS(status)) { + DebugPrint((DEBUG_MESSAGE,"PnpIsa: Failed to create device object for Pnp isa bus\n")); + return status; + } + + // =================================== + // BUGBUG - need to find a solution + // + + deviceObject->Flags &= ~0x80; + + // ================================== + deviceExtension = (PPI_DEVICE_EXTENSION) deviceObject->DeviceExtension; + deviceExtension->BusHandler = BusHandler; + + // + // Initialize bus handlers + // + + BusHandler->DeviceObject = deviceObject; + BusHandler->GetBusData = (PGETSETBUSDATA) PiGetBusData; + BusHandler->SetBusData = (PGETSETBUSDATA) PiSetBusData; + BusHandler->QueryBusSlots = (PQUERY_BUS_SLOTS) PiQueryBusSlots; + BusHandler->DeviceControl = (PDEVICE_CONTROL) PiDeviceControl; + BusHandler->ReferenceDeviceHandler = (PREFERENCE_DEVICE_HANDLER) PiReferenceDeviceHandler; + BusHandler->GetDeviceData = (PGET_SET_DEVICE_DATA) PiGetDeviceData; + BusHandler->SetDeviceData = (PGET_SET_DEVICE_DATA) PiSetDeviceData; + + // + // Intialize bus extension + // + + PipBusExtension = (PPI_BUS_EXTENSION)BusHandler->BusData; + RtlZeroMemory(PipBusExtension, sizeof(PI_BUS_EXTENSION)); + PipBusExtension->BusHandler = BusHandler; + + InitializeListHead (&PipBusExtension->CheckBus); + InitializeListHead (&PipBusExtension->DeviceControl); + + return STATUS_SUCCESS; +} diff --git a/private/ntos/nthals/extender/pnpisa/i386/isolate.c b/private/ntos/nthals/extender/pnpisa/i386/isolate.c new file mode 100644 index 000000000..53983ef71 --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa/i386/isolate.c @@ -0,0 +1,1574 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + isolate.c + +Abstract: + + +Author: + + Shie-Lin Tzong (shielint) July-10-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "busp.h" +#include "..\..\pnpbios\i386\pbios.h" +#include "pnpisa.h" + +BOOLEAN +PipFindIrqInformation ( + IN ULONG IrqLevel, + IN PUCHAR BiosRequirements, + OUT PUCHAR Information + ); + +BOOLEAN +PipFindMemoryInformation ( + IN ULONG Base, + IN ULONG Limit, + IN PUCHAR BiosRequirements, + OUT PUCHAR NameTag, + OUT PUCHAR Information + ); + +BOOLEAN +PipFindIoPortInformation ( + IN ULONG BaseAddress, + IN PUCHAR BiosRequirements, + OUT PUCHAR Information, + OUT PUCHAR Alignment, + OUT PUCHAR RangeLength + ); + +// +// Internal type definitions +// + +typedef struct _MEMORY_DESC_{ + ULONG Base; + ULONG Length; +} MEMORY_DESC, *PMEMORY_DESC; + +typedef struct _IRQ_DESC_{ + UCHAR Level; + ULONG Type; +}IRQ_DESC, *PIRQ_DESC; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,PipFindIrqInformation) +#pragma alloc_text(PAGE,PipFindMemoryInformation) +#pragma alloc_text(PAGE,PipFindIoPortInformation) +#pragma alloc_text(PAGE,PipReadCardResourceData) +#pragma alloc_text(PAGE,PipWriteDeviceBootResourceData) +#pragma alloc_text(PAGE,PipLFSRInitiation) +#pragma alloc_text(PAGE,PipIsolateCards) +#endif + +BOOLEAN +PipFindIrqInformation ( + IN ULONG IrqLevel, + IN PUCHAR BiosRequirements, + OUT PUCHAR Information + ) + +/*++ + +Routine Description: + + This routine searches the Bios resource requirement lists for the corresponding + Irq descriptor information. The search stops when we encounter another logical + device id tag or the END tag. On input, the BiosRequirements points to current + logical id tag. + +Arguments: + + IrqLevel - Supplies the irq level. + + BiosRequirements - Supplies a pointer to the bios resource requirement lists. This + parameter must point to the logical device Id tag. + + Information - supplies a pointer to a UCHAR to receive the port information/flags. + +Return Value: + + TRUE - if memory information found. Else False. + +--*/ +{ + UCHAR tag; + ULONG increment; + USHORT irqMask; + PPNP_IRQ_DESCRIPTOR biosDesc; + + // + // Skip current logical id tag + // + + tag = *BiosRequirements; + ASSERT((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID); + BiosRequirements += (tag & SMALL_TAG_SIZE_MASK) + 1; + + // + // Search the possible resource list to get the information + // for the Irq. + // + + irqMask = 1 << IrqLevel; + tag = *BiosRequirements; + while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)) { + if ((tag & SMALL_TAG_MASK) == TAG_IRQ) { + biosDesc = (PPNP_IRQ_DESCRIPTOR)BiosRequirements; + if (biosDesc->IrqMask & irqMask) { + if ((tag & SMALL_TAG_MASK) == 2) { + + // + // if no irq info is available, a value of zero is returned. + // (o is not a valid irq information.) + // + + *Information = 0; + } else { + *Information = biosDesc->Information; + } + return TRUE; + } + } + increment = (tag & SMALL_TAG_SIZE_MASK) + 1; + BiosRequirements += increment; + tag = *BiosRequirements; + } + return FALSE; +} + +BOOLEAN +PipFindMemoryInformation ( + IN ULONG BaseAddress, + IN ULONG Limit, + IN PUCHAR BiosRequirements, + OUT PUCHAR NameTag, + OUT PUCHAR Information + ) + +/*++ + +Routine Description: + + This routine searches the Bios resource requirement lists for the corresponding + memory descriptor information. The search stops when we encounter another logical + device id tag or the END tag. Note, the memory range specified by Base + and Limit must be within a single Pnp ISA memory descriptor. + +Arguments: + + BaseAddress - Supplies the base address of the memory range. + + Limit - Supplies the upper limit of the memory range. + + BiosRequirements - Supplies a pointer to the bios resource requirement lists. This + parameter must point to the logical device Id tag. + + NameTag - Supplies a variable to receive the Tag of the memory descriptor which + describes the memory information. + + Information - supplies a pointer to a UCHAR to receive the memory information + for the specified memory range. + +Return Value: + + TRUE - if memory information found. Else False. + +--*/ +{ + UCHAR tag; + BOOLEAN found = FALSE; + ULONG minAddr, length, maxAddr, alignment; + USHORT increment; + + // + // Skip current logical id tag. + // + + tag = *BiosRequirements; + ASSERT((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID); + BiosRequirements += (tag & SMALL_TAG_SIZE_MASK) + 1; + + // + // Search the possible resource list to get the information + // for the memory range described by Base and Limit. + // + + tag = *BiosRequirements; + while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)) { + switch (tag) { + case TAG_MEMORY: + minAddr = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MinimumAddress)) << 8; + length = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MemorySize)) << 8; + maxAddr = (((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MaximumAddress)) << 8) + + length - 1; + break; + case TAG_MEMORY32: + length = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MemorySize; + minAddr = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MinimumAddress; + maxAddr = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MaximumAddress + + length - 1; + break; + case TAG_MEMORY32_FIXED: + length = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)BiosRequirements)->MemorySize; + minAddr = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)BiosRequirements)->BaseAddress; + maxAddr = minAddr + length - 1; + break; + } + + if (minAddr <= BaseAddress && maxAddr >= Limit) { + *Information = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->Information; + *NameTag = tag; + found = TRUE; + break; + } + + // + // Advance to next tag + // + + if (tag & LARGE_RESOURCE_TAG) { + increment = *(PUCHAR)(BiosRequirements + 1); + increment += 3; // length of large tag + } else { + increment = tag & SMALL_TAG_SIZE_MASK; + increment += 1; // length of small tag + } + BiosRequirements += increment; + tag = *BiosRequirements; + } + return found; +} + +BOOLEAN +PipFindIoPortInformation ( + IN ULONG BaseAddress, + IN PUCHAR BiosRequirements, + OUT PUCHAR Information, + OUT PUCHAR Alignment, + OUT PUCHAR RangeLength + ) + +/*++ + +Routine Description: + + This routine searches the Bios resource requirement lists for the corresponding + Io port descriptor information. The search stops when we encounter another logical + device id tag or the END tag. + +Arguments: + + BaseAddress - Supplies the base address of the Io port range. + + BiosRequirements - Supplies a pointer to the bios resource requirement lists. This + parameter must point to the logical device Id tag. + + Information - supplies a pointer to a UCHAR to receive the port information/flags. + + Alignment - supplies a pointer to a UCHAR to receive the port alignment + information. + + RangeLength - supplies a pointer to a UCHAR to receive the port range length + information. + +Return Value: + + TRUE - if memory information found. Else False. + +--*/ +{ + UCHAR tag; + BOOLEAN found = FALSE; + ULONG minAddr, length, maxAddr, alignment; + USHORT increment; + PPNP_PORT_DESCRIPTOR portDesc; + PPNP_FIXED_PORT_DESCRIPTOR fixedPortDesc; + + tag = *BiosRequirements; + ASSERT((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID); + BiosRequirements += (tag & SMALL_TAG_SIZE_MASK) + 1; + + // + // Search the possible resource list to get the information + // for the io port range described by Base. + // + + tag = *BiosRequirements; + while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)) { + switch (tag & SMALL_TAG_MASK) { + case TAG_IO: + portDesc = (PPNP_PORT_DESCRIPTOR)BiosRequirements; + minAddr = portDesc->MinimumAddress; + maxAddr = portDesc->MaximumAddress; + if (minAddr <= BaseAddress && maxAddr >= BaseAddress) { + *Information = portDesc->Information; + *Alignment = portDesc->Alignment; + *RangeLength = portDesc->Length; + found = TRUE; + } + break; + case TAG_IO_FIXED: + fixedPortDesc = (PPNP_FIXED_PORT_DESCRIPTOR)BiosRequirements; + minAddr = fixedPortDesc->MinimumAddress; + if (BaseAddress == minAddr) { + *Information = 0; // 10 bit decode + *Alignment = 1; + *RangeLength = fixedPortDesc->Length; + found = TRUE; + } + break; + } + + if (found) { + break; + } + + // + // Advance to next tag + // + + if (tag & LARGE_RESOURCE_TAG) { + increment = *(PUCHAR)(BiosRequirements + 1); + increment += 3; // length of large tag + } else { + increment = tag & SMALL_TAG_SIZE_MASK; + increment += 1; // length of small tag + } + BiosRequirements += increment; + tag = *BiosRequirements; + } + return found; +} + +NTSTATUS +PipReadCardResourceData ( + IN ULONG Csn, + OUT PULONG NumberLogicalDevices, + IN PUCHAR *ResourceData, + OUT PULONG ResourceDataLength + ) + +/*++ + +Routine Description: + + This routine reads resources data from a specified PnP ISA card. It is + caller's responsibility to release the memory. Before calling this routine, + the Pnp ISA card should be in sleep state (i.e. Initiation Key was sent.) + After exiting this routine, the card will be left in Config state. + +Arguments: + + Csn - Specifies the CardSelectNumber to indicate which PNP ISA card. + + NumberLogicalDevices - supplies a variable to receive the number of logical devices + associated with the Pnp Isa card. + + ResourceData - Supplies a variable to receive the pointer to the resource data. + + ResourceDataLength - Supplies a variable to receive the length of the ResourceData. + +Return Value: + + NT STATUS code. + +--*/ +{ + + PUCHAR buffer, p; + USHORT sizeToRead, size, limit, i; + UCHAR tag; + ULONG noDevices; + + // + // Allocate memory to store the resource data. + // N.B. The buffer size should cover 99.999% of the machines. + // + + sizeToRead = 4096; + +tryAgain: + + noDevices = 0; + buffer = (PUCHAR)ExAllocatePoolWithTag(PagedPool, sizeToRead, 'iPnP'); + if (!buffer) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Send card from sleep state to configuration state + // Note, by doing this the resource data includes 9 bytes Id. + // + + PipWriteAddress (WAKE_CSN_PORT); + PipWriteData((UCHAR)Csn); + + // + // Read the data until the buffer is full. + // + + for (i = 0, p = buffer; i < sizeToRead; i++, p++) { + PipWriteAddress(CONFIG_DATA_STATUS_PORT); + + // + // Waiting for data ready status bit + // + + while ((PipReadData() & 1) != 1) { + } + + // + // Read the data ... + // + + PipWriteAddress(CONFIG_DATA_PORT); + *p = PipReadData(); + } + + // + // Next check if we got all the resource data and find out the real + // size of the resource data. + // + + p = buffer + NUMBER_CARD_ID_BYTES; + + // + // set search limit to be one byte less the (buffer size - + // size of ID bytes) to make sure the END TAG can be found before + // the last byte of the buffer. (This is because END tag contains + // one byte checksum.) + // + + limit = sizeToRead - NUMBER_CARD_ID_BYTES - 1; + tag = *p; + while (tag != TAG_COMPLETE_END && limit > 0) { + + // + // Determine the size of the BIOS resource descriptor and + // move to next descriptor. + // + + if (!(tag & LARGE_RESOURCE_TAG)) { + size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); + size += 1; // length of small tag + if ((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID) { + noDevices++; + } + } else { + size = *(PUSHORT)(p + 1); + size += 3; // length of large tag + } + + p += size; + limit -= size; + tag = *p; + } + if (tag == TAG_COMPLETE_END) { + + // + // Determine the real size of the buffer required and + // resize the buffer. + // + + size = p - buffer + 1 + 1; // add 1 for end tag checksum byte + p = (PUCHAR)ExAllocatePoolWithTag(PagedPool, size, 'iPnP'); + if (p) { + RtlMoveMemory(p, buffer, size); + ExFreePool(buffer); + } else { + + // + // Fail to resize the buffer. Simply leave it alone. + // + + p = buffer; + } + + // + // Should we leave card in config state??? + // + + *ResourceData = p; + *NumberLogicalDevices = noDevices; + *ResourceDataLength = size; + return STATUS_SUCCESS; + } else { + + // + // We did not find the resource END TAG. This means we did not + // get all the resource data on previous read. Try to expand the + // data buffer and read again. + // +#if DBG + DbgBreakPoint(); +#endif + ExFreePool(buffer); + sizeToRead <<= 1; // double the buffer + + // + // If we can find the END tag with 32K byte, assume the resource + // requirement list is bad. + // + + if (sizeToRead > 0x80000) { + return STATUS_INVALID_PARAMETER; + } + goto tryAgain; + } +} + +NTSTATUS +PipReadDeviceBootResourceData ( + IN ULONG BusNumber, + IN PUCHAR BiosRequirements, + OUT PCM_RESOURCE_LIST *ResourceData, + OUT PULONG Length + ) + +/*++ + +Routine Description: + + This routine reads boot resource data from an enabled logical device of a PNP ISA card. + Caller must put the card into configuration state and select the logical device before + calling this function. It is caller's responsibility to release the memory. ( The boot + resource data is the resources that a card assigned during boot.) + +Arguments: + + BusNumber - specifies the bus number of the device whose resource data to be read. + + BiosRequirements - Supplies a pointer to the resource requirement list for the logical + device. This parameter must point to the logical device Id tag. + + ResourceData - Supplies a variable to receive the pointer to the resource data. + + Length - Supplies a variable to recieve the length of the resource data. + +Return Value: + + NT STATUS code. + +--*/ +{ + + UCHAR c, junk1, junk2; + PUCHAR base; + ULONG l, resourceCount; + BOOLEAN limit; + LONG i, j, noMemoryDesc = 0, noIoDesc = 0, noDmaDesc =0, noIrqDesc = 0; + MEMORY_DESC memoryDesc[NUMBER_MEMORY_DESCRIPTORS + NUMBER_32_MEMORY_DESCRIPTORS]; + IRQ_DESC irqDesc[NUMBER_IRQ_DESCRIPTORS]; + UCHAR dmaDesc[NUMBER_DMA_DESCRIPTORS]; + USHORT ioDesc[NUMBER_IO_DESCRIPTORS]; + PCM_RESOURCE_LIST cmResource; + PCM_PARTIAL_RESOURCE_LIST partialResList; + PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDesc; + +#if DBG + PipWriteAddress(ACTIVATE_PORT); + if (!(PipReadData() & 1)) { + DbgPrint("PnpIsa-ReadDeviceBootResourceData:The logical device has not been activated\n"); + } +#endif // DBG + + // + // First make sure the specified BiosRequirements is valid and at the right tag. + // + + if ((*BiosRequirements & SMALL_TAG_MASK) != TAG_LOGICAL_ID) { + return STATUS_INVALID_PARAMETER; + } + + // + // Read memory configuration + // + + base = (PUCHAR)ADDRESS_MEMORY_BASE; + for (i = 0; i < NUMBER_MEMORY_DESCRIPTORS; i++) { + + // + // Read memory base address + // + + PipWriteAddress(base + ADDRESS_MEMORY_HI); + c = PipReadData(); + l = c; + l <<= 8; + PipWriteAddress(base + ADDRESS_MEMORY_LO); + c = PipReadData(); + l |= c; + l <<= 8; // l = memory base address + if (l == 0) { + break; + } + + memoryDesc[noMemoryDesc].Base = l; + + // + // Read memory control byte + // + + PipWriteAddress(base + ADDRESS_MEMORY_CTL); + c= PipReadData(); + limit = c & 1; + + // + // Read memory upper limit address or range length + // + + PipWriteAddress(base + ADDRESS_MEMORY_UPPER_HI); + c = PipReadData(); + l = c; + l <<= 8; + PipWriteAddress(base + ADDRESS_MEMORY_UPPER_LO); + c = PipReadData(); + l |= c; + l <<= 8; + + if (limit == ADDRESS_MEMORY_CTL_LIMIT) { + l = l - memoryDesc[noMemoryDesc].Base; + } + memoryDesc[noMemoryDesc].Length = l; + noMemoryDesc++; + base += ADDRESS_MEMORY_INCR; + } + + // + // Read memory 32 configuration + // + + for (i = 0; i < NUMBER_32_MEMORY_DESCRIPTORS; i++) { + + base = ADDRESS_32_MEMORY_BASE(i); + + // + // Read memory base address + // + + l = 0; + for (j = ADDRESS_32_MEMORY_B3; j <= ADDRESS_32_MEMORY_B0; j++) { + PipWriteAddress(base + j); + c = PipReadData(); + l <<= 8; + l |= c; + } + if (l == 0) { + break; + } + + memoryDesc[noMemoryDesc].Base = l; + + // + // Read memory control byte + // + + PipWriteAddress(base + ADDRESS_32_MEMORY_CTL); + c= PipReadData(); + limit = c & 1; + + // + // Read memory upper limit address or range length + // + + l = 0; + for (j = ADDRESS_32_MEMORY_E3; j <= ADDRESS_32_MEMORY_E0; j++) { + PipWriteAddress(base + j); + c = PipReadData(); + l <<= 8; + l |= c; + } + + if (limit == ADDRESS_MEMORY_CTL_LIMIT) { + l = l - memoryDesc[noMemoryDesc].Base; + } + memoryDesc[noMemoryDesc].Length = l; + noMemoryDesc++; + } + + // + // Read Io Port Configuration + // + + base = (PUCHAR)ADDRESS_IO_BASE; + for (i = 0; i < NUMBER_IO_DESCRIPTORS; i++) { + PipWriteAddress(base + ADDRESS_IO_BASE_HI); + c = PipReadData(); + l = c; + PipWriteAddress(base + ADDRESS_IO_BASE_LO); + c = PipReadData(); + l <<= 8; + l |= c; + if (l == 0) { + break; + } + ioDesc[noIoDesc++] = (USHORT)l; + base += ADDRESS_IO_INCR; + } + + // + // Read Interrupt configuration + // + + base = (PUCHAR)ADDRESS_IRQ_BASE; + for (i = 0; i < NUMBER_IRQ_DESCRIPTORS; i++) { + PipWriteAddress(base + ADDRESS_IRQ_VALUE); + c = PipReadData(); + if (c == 0) { + break; + } + irqDesc[noIrqDesc].Level = c; + PipWriteAddress(base + ADDRESS_IRQ_TYPE); + c = PipReadData(); + irqDesc[noIrqDesc++].Type = c; + base += ADDRESS_IRQ_INCR; + } + + // + // Read DMA configuration + // + + base = (PUCHAR)ADDRESS_DMA_BASE; + for (i = 0; i < NUMBER_DMA_DESCRIPTORS; i++) { + PipWriteAddress(base + ADDRESS_DMA_VALUE); + c = PipReadData(); + if (c == 4) { + break; + } + dmaDesc[noDmaDesc++] = c; + base += ADDRESS_IRQ_INCR; + } + + // + // Construct CM_RESOURCE_LIST structure based on the resource data + // we collect so far. + // + + resourceCount = noMemoryDesc + noIoDesc + noDmaDesc + noIrqDesc; + + // + // if empty bios resources, simply return. + // + + if (resourceCount == 0) { + *ResourceData = NULL; + *Length = 0; + return STATUS_SUCCESS; + } + + l = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + ( resourceCount - 1); + cmResource = ExAllocatePoolWithTag(PagedPool, l, 'iPnP'); + if (!cmResource) { + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlZeroMemory(cmResource, l); + *Length = l; // Set returned resource data length + cmResource->Count = 1; + cmResource->List[0].InterfaceType = Isa; + cmResource->List[0].BusNumber = BusNumber; + partialResList = (PCM_PARTIAL_RESOURCE_LIST)&cmResource->List[0].PartialResourceList; + partialResList->Version = 0; + partialResList->Revision = 0; + partialResList->Count = resourceCount; + partialDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)&partialResList->PartialDescriptors[0]; + + // + // Set up all the CM memory descriptors + // + + for (i = 0; i < noMemoryDesc; i++) { + partialDesc->Type = CmResourceTypeMemory; + partialDesc->ShareDisposition = CmResourceShareDeviceExclusive; + partialDesc->u.Memory.Length = memoryDesc[i].Length; + partialDesc->u.Memory.Start.HighPart = 0; + partialDesc->u.Memory.Start.LowPart = memoryDesc[i].Base; + + // + // Need to consult configuration data for the Flags + // + + l = memoryDesc[i].Base + memoryDesc[i].Length - 1; + if (PipFindMemoryInformation (memoryDesc[i].Base, l, BiosRequirements, &junk1, &c)) { + if (c & PNP_MEMORY_WRITE_STATUS_MASK) { + partialDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE; + } else { + partialDesc->Flags = CM_RESOURCE_MEMORY_READ_ONLY; + } + partialDesc++; + } else { +#if DBG + DbgPrint("PnpIsa-ReadDeviceBootResourceData:No matched memory information in config data\n"); + DbgBreakPoint(); +#endif + } + } + + // + // Set up all the CM io/port descriptors + // + + for (i = 0; i < noIoDesc; i++) { + partialDesc->Type = CmResourceTypePort; + partialDesc->ShareDisposition = CmResourceShareDeviceExclusive; + partialDesc->Flags = CM_RESOURCE_PORT_IO; + partialDesc->u.Port.Start.LowPart = ioDesc[i]; + + // + // Need to consult configuration data for the Port length + // + + if (PipFindIoPortInformation (ioDesc[i], BiosRequirements, &junk1, &junk2, &c)) { + partialDesc->u.Port.Length = c; + partialDesc++; + } else { +#if DBG + DbgPrint("PnpIsa-ReadDeviceBootResourceData:No matched port length in config data\n"); + DbgBreakPoint(); +#endif + } + } + + // + // Set up all the CM DMA descriptors + // + + for (i = 0; i < noDmaDesc; i++) { + partialDesc->Type = CmResourceTypeDma; + partialDesc->ShareDisposition = CmResourceShareDeviceExclusive; + partialDesc->Flags = 0; // no flags for DMA descriptor + partialDesc->u.Dma.Channel = (ULONG) dmaDesc[i]; + partialDesc->u.Dma.Port = 0; + partialDesc->u.Dma.Reserved1 = 0; + partialDesc++; + } + + // + // Set up all the CM interrupt descriptors + // + + for (i = 0; i < noIrqDesc; i++) { + partialDesc->Type = CmResourceTypeInterrupt; + partialDesc->ShareDisposition = CmResourceShareDeviceExclusive; + if (irqDesc[i].Type & 1) { + partialDesc->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + } else { + partialDesc->Flags = CM_RESOURCE_INTERRUPT_LATCHED; + } + partialDesc->u.Interrupt.Vector = + partialDesc->u.Interrupt.Level = irqDesc[i].Level; + partialDesc->u.Interrupt.Affinity = (ULONG)-1; + partialDesc++; + } + + *ResourceData = cmResource; + return STATUS_SUCCESS; +} + +NTSTATUS +PipWriteDeviceBootResourceData ( + IN PUCHAR BiosRequirements, + IN PCM_RESOURCE_LIST CmResources + ) + +/*++ + +Routine Description: + + This routine writes boot resource data to an enabled logical device of + a Pnp ISA card. Caller must put the card into configuration state and select + the logical device before calling this function. + +Arguments: + + BiosRequirements - Supplies a pointer to the possible resources for the logical + device. This parameter must point to the logical device Id tag. + + ResourceData - Supplies a pointer to the cm resource data. + +Return Value: + + NT STATUS code. + +--*/ +{ + UCHAR c, information; + ULONG count, i, j, pass, base, limit; + PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDesc; + ULONG noIrq =0, noIo = 0, noDma = 0, noMemory = 0, no32Memory = 0; + PUCHAR memoryBase, irqBase, dmaBase, ioBase, tmp; + ULONG memory32Base; + +#if DBG + PipWriteAddress(ACTIVATE_PORT); + if (!(PipReadData() & 1)) { + DbgPrint("PnpIsa-WriteDeviceBootResourceData:The logical device has not been activated\n"); + } +#endif // DBG + + // + // First make sure the specified BiosRequirements is valid and at the right tag. + // + + if ((*BiosRequirements & SMALL_TAG_MASK) != TAG_LOGICAL_ID) { + return STATUS_INVALID_PARAMETER; + } + + count = CmResources->List[0].PartialResourceList.Count; + memoryBase = (PUCHAR)ADDRESS_MEMORY_BASE; + memory32Base = 0; + ioBase = (PUCHAR)ADDRESS_IO_BASE; + irqBase = (PUCHAR)ADDRESS_IRQ_BASE; + dmaBase = (PUCHAR)ADDRESS_DMA_BASE; + for (pass = 1; pass <= 2; pass++) { + + // + // First pass we make sure the resources to be set is acceptable. + // Second pass we actually write the resources to the logical device's + // configuration space. + // + + cmDesc = CmResources->List[0].PartialResourceList.PartialDescriptors; + for (i = 0; i < count; i++) { + switch (cmDesc->Type) { + case CmResourceTypePort: + if (pass == 1) { + noIo++; + if (noIo > NUMBER_IO_DESCRIPTORS || + cmDesc->u.Port.Start.HighPart != 0 || + cmDesc->u.Port.Start.LowPart & 0xffff0000 || + cmDesc->u.Port.Length & 0xffffff00) { + return STATUS_INVALID_PARAMETER; + } + } else { + + // + // Set the Io port base address to logical device configuration space + // + + c = (UCHAR)cmDesc->u.Port.Start.LowPart; + PipWriteAddress(ioBase + ADDRESS_IO_BASE_LO); + PipWriteData(c); + c = (UCHAR)(cmDesc->u.Port.Start.LowPart >> 8); + PipWriteAddress(ioBase + ADDRESS_IO_BASE_HI); + PipWriteData(c); + ioBase += ADDRESS_IO_INCR; + } + break; + case CmResourceTypeInterrupt: + if (pass == 1) { + noIrq++; + if (noIrq > NUMBER_IRQ_DESCRIPTORS || + (cmDesc->u.Interrupt.Level & 0xfffffff0)) { + return STATUS_INVALID_PARAMETER; + } + + // + // See if we can get the interrupt information from possible resource + // data. We need it to set the configuration register. + // + + if (!PipFindIrqInformation(cmDesc->u.Interrupt.Level, BiosRequirements, &information)) { + return STATUS_INVALID_PARAMETER; + } + } else { + + // + // Set the Irq to logical device configuration space + // + + c = (UCHAR)cmDesc->u.Interrupt.Level; + PipWriteAddress(irqBase + ADDRESS_IRQ_VALUE); + PipWriteData(c); + PipFindIrqInformation(cmDesc->u.Interrupt.Level, BiosRequirements, &information); + if (information != 0) { + switch (information & 0xf) { + case 1: // High true edge sensitive + c = 2; + break; + case 2: // Low true edge sensitive + c = 0; + break; + case 4: // High true level sensitive + c = 3; + break; + case 8: // Low true level sensitive + c = 1; + break; + } + PipWriteAddress(irqBase + ADDRESS_IRQ_TYPE); + PipWriteData(c); + } + irqBase += ADDRESS_IRQ_INCR; + } + break; + case CmResourceTypeDma: + if (pass == 1) { + noDma++; + if (noDma > NUMBER_IRQ_DESCRIPTORS || + (cmDesc->u.Dma.Channel & 0xfffffff8)) { + return STATUS_INVALID_PARAMETER; + } + } else { + + // + // Set the Dma channel to logical device configuration space + // + + c = (UCHAR)cmDesc->u.Dma.Channel; + PipWriteAddress(dmaBase + ADDRESS_DMA_VALUE); + PipWriteData(c); + dmaBase += ADDRESS_DMA_INCR; + } + break; + case CmResourceTypeMemory: + if (pass == 1) { + base = cmDesc->u.Memory.Start.LowPart; + limit = base + cmDesc->u.Memory.Length - 1; + if (!PipFindMemoryInformation(base, limit, BiosRequirements, &c, &information)) { + return STATUS_INVALID_PARAMETER; + } else { + switch (c) { + case TAG_MEMORY: + noMemory++; + + // + // Make sure the lower 8 bits of the base address are zero. + // + + if (noMemory > NUMBER_MEMORY_DESCRIPTORS || + base & 0xff) { + return STATUS_INVALID_PARAMETER; + } + break; + case TAG_MEMORY32: + case TAG_MEMORY32_FIXED: + no32Memory++; + if (no32Memory > NUMBER_32_MEMORY_DESCRIPTORS) { + return STATUS_INVALID_PARAMETER; + } + break; + default: + return STATUS_INVALID_PARAMETER; + } + } + } else { + + // + // Find information in BiosRequirements to help determine how to write + // the memory configuration space. + // + + base = cmDesc->u.Memory.Start.LowPart; + limit = base + cmDesc->u.Memory.Length - 1; + PipFindMemoryInformation(base, limit, BiosRequirements, &c, &information); + switch (c) { + case TAG_MEMORY: + PipWriteAddress(memoryBase + ADDRESS_MEMORY_LO); + base >>= 8; + PipWriteData(base); + PipWriteAddress(memoryBase + ADDRESS_MEMORY_HI); + base >>= 8; + PipWriteData(base); + PipWriteAddress(memoryBase + ADDRESS_MEMORY_CTL); + c = 2 + ADDRESS_MEMORY_CTL_LIMIT; // assume 16 bit memory + if (information & 0x18 == 0) { // 8 bit memory only + c = 0 + ADDRESS_MEMORY_CTL_LIMIT; + } + PipWriteData(c); + limit >>= 8; + PipWriteAddress(memoryBase + ADDRESS_MEMORY_UPPER_LO); + PipWriteData((UCHAR)limit); + limit >>= 8; + PipWriteAddress(memoryBase + ADDRESS_MEMORY_UPPER_HI); + PipWriteData((UCHAR)limit); + memoryBase += ADDRESS_MEMORY_INCR; + break; + case TAG_MEMORY32: + case TAG_MEMORY32_FIXED: + tmp = ADDRESS_32_MEMORY_BASE(memory32Base); + PipWriteAddress(tmp + ADDRESS_32_MEMORY_B0); + PipWriteData(base); + PipWriteAddress(tmp + ADDRESS_32_MEMORY_B1); + base >>= 8; + PipWriteData(base); + PipWriteAddress(tmp + ADDRESS_32_MEMORY_B2); + base >>= 8; + PipWriteData(base); + PipWriteAddress(tmp + ADDRESS_32_MEMORY_B3); + base >>= 8; + PipWriteData(base); + switch (information & 0x18) { + case 0: // 8 bit only + c = ADDRESS_MEMORY_CTL_LIMIT; + case 8: // 16 bit only + case 0x10: // 8 and 16 bit supported + c = 2 + ADDRESS_MEMORY_CTL_LIMIT; + break; + case 0x18: // 32 bit only + c = 6 + ADDRESS_MEMORY_CTL_LIMIT; + break; + } + PipWriteAddress(ADDRESS_32_MEMORY_CTL); + PipWriteData(c); + PipWriteAddress(tmp + ADDRESS_32_MEMORY_E0); + PipWriteData(limit); + limit >>= 8; + PipWriteAddress(tmp + ADDRESS_32_MEMORY_E1); + PipWriteData(limit); + limit >>= 8; + PipWriteAddress(tmp + ADDRESS_32_MEMORY_E2); + PipWriteData(limit); + limit >>= 8; + PipWriteAddress(tmp + ADDRESS_32_MEMORY_E3); + PipWriteData(limit); + memory32Base++; + break; + } + } + break; + default: + return STATUS_INVALID_PARAMETER; + } + cmDesc++; + } + } + + // + // Finally, mark all the unused descriptors as disabled. + // + + for (i = noMemory; i < NUMBER_MEMORY_DESCRIPTORS; i++) { + for (j = 0; j < 5; j++) { + PipWriteAddress(memoryBase + j); + PipWriteData(0); + } + memoryBase += ADDRESS_MEMORY_INCR; + } + for (i = no32Memory; i < NUMBER_32_MEMORY_DESCRIPTORS; i++) { + tmp = ADDRESS_32_MEMORY_BASE(memory32Base); + for (j = 0; j < 9; j++) { + PipWriteAddress(tmp + j); + PipWriteData(0); + } + memory32Base++; + } + for (i = noIo; i < NUMBER_IO_DESCRIPTORS; i++) { + for (j = 0; j < 2; j++) { + PipWriteAddress(ioBase + j); + PipWriteData(0); + } + ioBase += ADDRESS_IO_INCR; + } + for (i = noIrq; i < NUMBER_IRQ_DESCRIPTORS; i++) { + for (j = 0; j < 2; j++) { + PipWriteAddress(irqBase + j); + PipWriteData(0); + } + irqBase += ADDRESS_IRQ_INCR; + } + for (i = noDma; i < NUMBER_DMA_DESCRIPTORS; i++) { + PipWriteAddress(dmaBase); + PipWriteData(4); + dmaBase += ADDRESS_DMA_INCR; + } + return STATUS_SUCCESS; +} + +VOID +PipLFSRInitiation ( + VOID + ) + +/*++ + +Routine Description: + + This routine insures the LFSR (linear feedback shift register) is in its + initial state and then performs 32 writes to the ADDRESS port to initiation + LFSR function. + + Pnp software sends the initiation key to all the Pnp ISA cards to place them + into configuration mode. The software then ready to perform isolation + protocol. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + UCHAR seed, bit7; + ULONG i; + + // + // First perform two writes of value zero to insure the LFSR is in the + // initial state. + // + + PipWriteAddress (0); + PipWriteAddress (0); + + // + // Perform the initiation key. + // + + seed = LFSR_SEED; // initial value of 0x6a + for (i = 0; i < 32; i++) { + PipWriteAddress (seed); + bit7=(((seed & 2) >> 1) ^ (seed & 1)) << 7; + seed =(seed >> 1) | bit7; + } +} + +VOID +PipIsolateCards ( + OUT PULONG NumberCSNs, + IN OUT PUCHAR *ReadDataPort + ) + +/*++ + +Routine Description: + + This routine performs PnP ISA cards isolation sequence. + +Arguments: + + NumberCSNs - supplies the addr of a variable to receive the number of + Pnp Isa cards isolated. + + ReadDataPort - Supplies the address of a variable to supply ReadData port + address. If NULL is supplied, this function returns detected ReadData + port to this variable. + +Return Value: + + None. + +--*/ +{ + USHORT j, i; + UCHAR cardId[NUMBER_CARD_ID_BYTES]; + UCHAR bit, bit7, checksum, byte1, byte2; + ULONG csn = 0; + + // + // First send Initiation Key to all the PNP ISA cards to put them into + // configuration mode. + // + + PipLFSRInitiation (); + + // + // Reset all Pnp ISA cards' CSN to 0 and return to wait-for-key state + // + + PipWriteAddress (CONFIG_CONTROL_PORT); + PipWriteData (CONTROL_WAIT_FOR_KEY | CONTROL_RESET_CSN); + + // + // Delay 2 msec for cards to load initial configuration state. + // + + KeStallExecutionProcessor(20000); // delay 2 msec + + // + // Put cards into configuration mode to ready isolation process. + // + + PipLFSRInitiation (); + + // + // Starting Pnp Isa card isolation process. + // Try Read_Data_port from 200 to 3ff if ReadData port addr is not supplied. + // + + for (i = MIN_READ_DATA_PORT; i < MAX_READ_DATA_PORT; i += 4) { + + if ((i & 0xf) == 0) { + + // + // Some cards (e.g. 3COM elnkiii) do not response to 0xyy3 addr. + // + + continue; + } + if (*ReadDataPort) { + PipReadDataPort = *ReadDataPort; + } else { + PipReadDataPort = (PUCHAR)(i + 3);; + } + + // + // Send WAKE[CSN=0] to force all cards without CSN into isolation + // state to set READ DATA PORT. + // + + PipWriteAddress(WAKE_CSN_PORT); + PipWriteData(0); + + // + // Set read data port to current testing value. + // + + PipWriteAddress(SET_READ_DATA_PORT); + PipWriteData((UCHAR)((ULONG)PipReadDataPort >> 2)); + + // + // Isolate one PnP ISA card until fail + // + + while (TRUE) { + + // + // Read serial isolation port to cause PnP cards in the isolation + // state to compare one bit of the boards ID. + // + + PipWriteAddress(SERIAL_ISOLATION_PORT); + + // + // We need to delay 1msec prior to starting the first pair of isolation + // reads and must wait 250usec between each subsequent pair of isolation + // reads. This delay gives the ISA cards time to access information from + // possible very slow storage device. + // + + KeStallExecutionProcessor(10000); // delay 1 msec + + RtlZeroMemory(cardId, NUMBER_CARD_ID_BYTES); + checksum = LFSR_SEED; + for (j = 0; j < NUMBER_CARD_ID_BITS; j++) { + + // + // Read card id bit by bit + // + + byte1 = READ_PORT_UCHAR (PipReadDataPort); + byte2 = READ_PORT_UCHAR (PipReadDataPort); + bit = (byte1 == ISOLATION_TEST_BYTE_1) && (byte2 == ISOLATION_TEST_BYTE_2); + cardId[j / 8] |= bit << (j % 8); + if (j < CHECKSUMED_BITS) { + + // + // Calculate checksum + // + + bit7 = (((checksum & 2) >> 1) ^ (checksum & 1) ^ (bit)) << 7; + checksum = (checksum >> 1) | bit7; + } + KeStallExecutionProcessor(2500); // delay 250 usec + } + + // + // Verify the card id we read is legitimate + // First make sure checksum is valid. Note zero checksum is considered valid. + // + + if (cardId[8] == 0 || checksum == cardId[8]) { + + // + // Next make sure cardId is not zero + // + + byte1 = 0; + for (j = 0; j < NUMBER_CARD_ID_BYTES; j++) { + byte1 |= cardId[j]; + } + if (byte1 != 0) { + + // + // We found a valid Pnp Isa card, assign it a CSN number + // + + PipWriteAddress(SET_CSN_PORT); + + PipWriteData(++csn); + + // + // Do Wake[CSN] command to put the newly isolated card to + // sleep state and other un-isolated cards to isolation + // state. + // + + PipWriteAddress(WAKE_CSN_PORT); + PipWriteData(0); + + continue; // ... to isolate more cards ... + } + } + break; // could not isolate more cards ... + } + + // + // If we isolated at least one card, it means the read data port we use + // must be good and we can stop the isolation process. Otherwise try another + // read data port address. + // + + if (csn != 0 || *ReadDataPort) { + if (*ReadDataPort == NULL) { + *ReadDataPort = PipReadDataPort; + } + break; + } + } + + // + // Finaly put all cards into wait for key state. + // + + PipWriteAddress(CONFIG_CONTROL_PORT); + PipWriteData(CONTROL_WAIT_FOR_KEY); + *NumberCSNs = csn; +} + +ULONG +PipFindNextLogicalDeviceTag ( + IN OUT PUCHAR *CardData, + IN OUT LONG *Limit + ) + +/*++ + +Routine Description: + + This function searches the Pnp Isa card data for the Next logical + device tag encountered. The input *CardData should point to an logical device id tag, + which is the current logical device tag. If the *CardData does not point to a logical + device id tag, it will be moved to next tag. + +Arguments: + + CardData - a variable to supply a pointer to the pnp Isa resource descriptors and to + receive next logical device tag pointer. + + Limit - a variable to supply the maximum length of the search and to receive the new + lemit after the search. + +Return Value: + + Length of the data between current and next logical device tags, ie the data length + of the current logical device. + In case there is no 'next' logical device tag, the returned *CardData = NULL, + *Limit = zero and the data length of current logical tag is returned as function + returned value. + +--*/ +{ + UCHAR tag; + USHORT size; + LONG l; + ULONG retLength; + PUCHAR p; + BOOLEAN atIdTag = FALSE;; + + p = *CardData; + l = *Limit; + tag = *p; + retLength = 0; + while (tag != TAG_COMPLETE_END && l > 0) { + + // + // Determine the size of the BIOS resource descriptor + // + + if (!(tag & LARGE_RESOURCE_TAG)) { + size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); + size += 1; // length of small tag + } else { + size = *(PUSHORT)(p + 1); + size += 3; // length of large tag + } + + p += size; + retLength += size; + l -= size; + tag = *p; + if ((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID) { + *CardData = p; + *Limit = l; + return retLength; + } + } + *CardData = NULL; + *Limit = 0; + if (tag == TAG_COMPLETE_END) { + return (retLength + 2); // add 2 for the length of end tag descriptor + } else { + return 0; + } +} + +VOID +PipSelectLogicalDevice ( + IN USHORT Csn, + IN USHORT LogicalDeviceNumber + ) + +/*++ + +Routine Description: + + This function selects the logical logical device in the specified device. + +Arguments: + + Csn - Supplies a CardSelectNumber to select the card. + + LogicalDeviceNumber - supplies a logical device number to select the logical device. + +Return Value: + + None +--*/ +{ + UCHAR tmp; + + // + // Put cards into configuration mode to ready isolation process. + // + + PipLFSRInitiation (); + + // + // Send WAKE[CSN] to force the card into config state. + // + + PipWriteAddress(WAKE_CSN_PORT); + PipWriteData(Csn); + + // + // Select the logical device, disable its io range check and + // enable the device. + // + + PipWriteAddress(LOGICAL_DEVICE_PORT); + PipWriteData(LogicalDeviceNumber); + PipWriteAddress(IO_RANGE_CHECK_PORT); + tmp = PipReadData(); + tmp &= ~2; + PipWriteAddress(IO_RANGE_CHECK_PORT); + PipWriteData(tmp); + PipWriteAddress(ACTIVATE_PORT); + PipWriteData(1); +} diff --git a/private/ntos/nthals/extender/pnpisa/i386/misc.c b/private/ntos/nthals/extender/pnpisa/i386/misc.c new file mode 100644 index 000000000..0ba14e5ec --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa/i386/misc.c @@ -0,0 +1,626 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + misc.c + +Abstract: + + This file contains pnp isa bus extender support routines. + +Author: + + Shie-Lin Tzong (shielint) 27-Jusly-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "busp.h" +#include "pnpisa.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,PiCreateClose) +#pragma alloc_text(PAGE,PiUnload) +#pragma alloc_text(PAGE,PipGetRegistryValue) +#pragma alloc_text(PAGE,PipDecompressEisaId) +#endif + + +NTSTATUS +PiCreateClose ( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp + ) + +/*++ + +Routine Description: + + This routine handles open and close requests such that our device objects + can be opened. All it does it to complete the Irp with success. + +Arguments: + + DeviceObject - Supplies a pointer to the device object to be opened or closed. + + Irp - supplies a pointer to I/O request packet. + +Return Value: + + Always returns STATUS_SUCCESS, since this is a null operation. + +--*/ + +{ + UNREFERENCED_PARAMETER( DeviceObject ); + + PAGED_CODE(); + + // + // Null operation. Do not give an I/O boost since no I/O was + // actually done. IoStatus.Information should be + // FILE_OPENED for an open; it's undefined for a close. + // + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = FILE_OPENED; + + IoCompleteRequest( Irp, 0); + + return STATUS_SUCCESS; +} + +VOID +PiUnload( + IN PDRIVER_OBJECT DriverObject + ) + +/*++ + +Routine Description: + + This routine cleans up all of the memory associated with + any of the devices belonging to the driver. + +Arguments: + + DriverObject - Supplies a pointer to the driver object controling + all of the devices. + +Return Value: + + None. + +--*/ + +{ + + PVOID lockPtr; + + // + // Lock the pageable code section + // + + lockPtr = MmLockPagableCodeSection(PiUnload); + + ExAcquireFastMutex (&PipMutex); + + ObDereferenceObject(PipBusExtension->BusHandler->DeviceObject); + + // + // Delete all the device info structures and card info structures + // + + PipInvalidateCards(PipBusExtension); + PipDeleteCards(PipBusExtension); + + // + // Finally remove the bus handler reference. + // + + HalDereferenceBusHandler (PipBusExtension->BusHandler); + + ExReleaseFastMutex (&PipMutex); + + // + // Unlock pageable code section + // + + MmUnlockPagableImageSection(lockPtr); +} + +NTSTATUS +PiReconfigureResources ( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN DRIVER_RECONFIGURE_OPERATION Operation, + IN PCM_RESOURCE_LIST CmResources + ) + +/*++ + +Routine Description: + + This routine reconfigures Read Data Port address. + +Arguments: + + DriverObject - Supplies a pointer to the driver object controling + all of the devices. + + DeviceObject - Supplies a pointer to the device object whoes resources + are going to be reconfigured. + + Operation - the operation of the reconfiguration request. + + CmResources - supplies a pointer to the cm resource list. + +Return Value: + + NTSTATUS code. + +--*/ + +{ + PCM_PARTIAL_RESOURCE_LIST partialDesc; + PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; + ULONG port, count, i; + + UNREFERENCED_PARAMETER( DriverObject ); + UNREFERENCED_PARAMETER( DeviceObject ); + + switch (Operation) { + case ReconfigureResources: + ExAcquireFastMutex(&PipPortMutex); + + // + // retrieve the new read data port address + // + + ASSERT(CmResources->Count == 1); + partialDesc = &CmResources->List[0].PartialResourceList; + count = partialDesc->Count; + desc = &partialDesc->PartialDescriptors[0]; + for (i = 0; i < count; i++) { + switch (desc->Type) { + case CmResourceTypePort: + port = desc->u.Port.Start.LowPart; + if (desc->u.Port.Length != 4 || port & 0x3) { + return STATUS_UNSUCCESSFUL; + } else { + port += 3; + } + break; + + case CmResourceTypeMemory: + case CmResourceTypeInterrupt: + case CmResourceTypeDma: + break; + } + desc++; + } + + // + // Set read data port to the new setting. + // + + PipBusExtension->ReadDataPort = (PUCHAR)port; + PipReadDataPort = (PUCHAR)port; + + PipWriteAddress(SET_READ_DATA_PORT); + PipWriteData((UCHAR)((ULONG)PipReadDataPort >> 2)); + + ExReleaseFastMutex(&PipPortMutex); + break; + + case QueryReconfigureResources: + case CancelReconfigureQuery: + case QueryHardwareProfileChange: + case HardwareProfileChanged: + default: + break; + } + return STATUS_SUCCESS; +} + +VOID +PipDecompressEisaId( + IN ULONG CompressedId, + IN PUCHAR EisaId + ) + +/*++ + +Routine Description: + + This routine decompressed compressed Eisa Id and returns the Id to caller + specified character buffer. + +Arguments: + + CompressedId - supplies the compressed Eisa Id. + + EisaId - supplies a 8-char buffer to receive the decompressed Eisa Id. + +Return Value: + + None. + +--*/ + +{ + USHORT c1, c2; + LONG i; + + PAGED_CODE(); + + CompressedId &= 0xffffff7f; // remove the reserved bit (bit 7 of byte 0) + c1 = c2 = (USHORT)CompressedId; + c1 = (c1 & 0xff) << 8; + c2 = (c2 & 0xff00) >> 8; + c1 |= c2; + for (i = 2; i >= 0; i--) { + *(EisaId + i) = (UCHAR)(c1 & 0x1f) + 0x40; + c1 >>= 5; + } + EisaId += 3; + c1 = c2 = (USHORT)(CompressedId >> 16); + c1 = (c1 & 0xff) << 8; + c2 = (c2 & 0xff00) >> 8; + c1 |= c2; + sprintf (EisaId, "%04x", c1); +} + +NTSTATUS +PipGetRegistryValue( + IN HANDLE KeyHandle, + IN PWSTR ValueName, + OUT PKEY_VALUE_FULL_INFORMATION *Information + ) + +/*++ + +Routine Description: + + This routine is invoked to retrieve the data for a registry key's value. + This is done by querying the value of the key with a zero-length buffer + to determine the size of the value, and then allocating a buffer and + actually querying the value into the buffer. + + It is the responsibility of the caller to free the buffer. + +Arguments: + + KeyHandle - Supplies the key handle whose value is to be queried + + ValueName - Supplies the null-terminated Unicode name of the value. + + Information - Returns a pointer to the allocated data buffer. + +Return Value: + + The function value is the final status of the query operation. + +--*/ + +{ + UNICODE_STRING unicodeString; + NTSTATUS status; + PKEY_VALUE_FULL_INFORMATION infoBuffer; + ULONG keyValueLength; + + PAGED_CODE(); + + RtlInitUnicodeString( &unicodeString, ValueName ); + + // + // Figure out how big the data value is so that a buffer of the + // appropriate size can be allocated. + // + + status = ZwQueryValueKey( KeyHandle, + &unicodeString, + KeyValueFullInformation, + (PVOID) NULL, + 0, + &keyValueLength ); + if (status != STATUS_BUFFER_OVERFLOW && + status != STATUS_BUFFER_TOO_SMALL) { + return status; + } + + // + // Allocate a buffer large enough to contain the entire key data value. + // + + infoBuffer = ExAllocatePool( NonPagedPool, keyValueLength ); + if (!infoBuffer) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Query the data for the key value. + // + + status = ZwQueryValueKey( KeyHandle, + &unicodeString, + KeyValueFullInformation, + infoBuffer, + keyValueLength, + &keyValueLength ); + if (!NT_SUCCESS( status )) { + ExFreePool( infoBuffer ); + return status; + } + + // + // Everything worked, so simply return the address of the allocated + // buffer to the caller, who is now responsible for freeing it. + // + + *Information = infoBuffer; + return STATUS_SUCCESS; +} +#if DBG + +VOID +PipDebugPrint ( + ULONG Level, + PCCHAR DebugMessage, + ... + ) +/*++ + +Routine Description: + + This routine displays debugging message or causes a break. + +Arguments: + + Level - supplies debugging levelcode. DEBUG_MESSAGE - displays message only. + DEBUG_BREAK - displays message and break. + + DebugMessage - supplies a pointer to the debugging message. + +Return Value: + + None. + +--*/ + +{ + UCHAR Buffer[256]; + va_list ap; + + va_start(ap, DebugMessage); + + vsprintf(Buffer, DebugMessage, ap); + DbgPrint(Buffer); + if (Level == DEBUG_BREAK) { + DbgBreakPoint(); + } + + va_end(ap); +} + +VOID +PipDumpIoResourceDescriptor ( + IN PUCHAR Indent, + IN PIO_RESOURCE_DESCRIPTOR Desc + ) +/*++ + +Routine Description: + + This routine processes a IO_RESOURCE_DESCRIPTOR and displays it. + +Arguments: + + Indent - # char of indentation. + + Desc - supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be displayed. + +Return Value: + + None. + +--*/ +{ + UCHAR c = ' '; + + if (Desc->Option == IO_RESOURCE_ALTERNATIVE) { + c = 'A'; + } else if (Desc->Option == IO_RESOURCE_PREFERRED) { + c = 'P'; + } + switch (Desc->Type) { + case CmResourceTypePort: + DbgPrint ("%sIO %c Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n", + Indent, c, + Desc->u.Port.MinimumAddress.HighPart, Desc->u.Port.MinimumAddress.LowPart, + Desc->u.Port.MaximumAddress.HighPart, Desc->u.Port.MaximumAddress.LowPart, + Desc->u.Port.Alignment, + Desc->u.Port.Length + ); + break; + + case CmResourceTypeMemory: + DbgPrint ("%sMEM %c Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n", + Indent, c, + Desc->u.Memory.MinimumAddress.HighPart, Desc->u.Memory.MinimumAddress.LowPart, + Desc->u.Memory.MaximumAddress.HighPart, Desc->u.Memory.MaximumAddress.LowPart, + Desc->u.Memory.Alignment, + Desc->u.Memory.Length + ); + break; + + case CmResourceTypeInterrupt: + DbgPrint ("%sINT %c Min: %x, Max: %x\n", + Indent, c, + Desc->u.Interrupt.MinimumVector, + Desc->u.Interrupt.MaximumVector + ); + break; + + case CmResourceTypeDma: + DbgPrint ("%sDMA %c Min: %x, Max: %x\n", + Indent, c, + Desc->u.Dma.MinimumChannel, + Desc->u.Dma.MaximumChannel + ); + break; + } +} + +VOID +PipDumpIoResourceList ( + IN PIO_RESOURCE_REQUIREMENTS_LIST IoList + ) +/*++ + +Routine Description: + + This routine displays Io resource requirements list. + +Arguments: + + IoList - supplies a pointer to the Io resource requirements list to be displayed. + +Return Value: + + None. + +--*/ +{ + + + PIO_RESOURCE_LIST resList; + PIO_RESOURCE_DESCRIPTOR resDesc; + ULONG listCount, count, i, j; + + DbgPrint("Pnp Bios IO Resource Requirements List for Slot %x -\n", IoList->SlotNumber); + DbgPrint(" List Count = %x, Bus Number = %x\n", IoList->AlternativeLists, IoList->BusNumber); + listCount = IoList->AlternativeLists; + resList = &IoList->List[0]; + for (i = 0; i < listCount; i++) { + DbgPrint(" Version = %x, Revision = %x, Desc count = %x\n", resList->Version, + resList->Revision, resList->Count); + resDesc = &resList->Descriptors[0]; + count = resList->Count; + for (j = 0; j < count; j++) { + PipDumpIoResourceDescriptor(" ", resDesc); + resDesc++; + } + resList = (PIO_RESOURCE_LIST) resDesc; + } +} + +VOID +PipDumpCmResourceDescriptor ( + IN PUCHAR Indent, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Desc + ) +/*++ + +Routine Description: + + This routine processes a IO_RESOURCE_DESCRIPTOR and displays it. + +Arguments: + + Indent - # char of indentation. + + Desc - supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be displayed. + +Return Value: + + None. + +--*/ +{ + switch (Desc->Type) { + case CmResourceTypePort: + DbgPrint ("%sIO Start: %x:%08x, Length: %x\n", + Indent, + Desc->u.Port.Start.HighPart, Desc->u.Port.Start.LowPart, + Desc->u.Port.Length + ); + break; + + case CmResourceTypeMemory: + DbgPrint ("%sMEM Start: %x:%08x, Length: %x\n", + Indent, + Desc->u.Memory.Start.HighPart, Desc->u.Memory.Start.LowPart, + Desc->u.Memory.Length + ); + break; + + case CmResourceTypeInterrupt: + DbgPrint ("%sINT Level: %x, Vector: %x, Affinity: %x\n", + Indent, + Desc->u.Interrupt.Level, + Desc->u.Interrupt.Vector, + Desc->u.Interrupt.Affinity + ); + break; + + case CmResourceTypeDma: + DbgPrint ("%sDMA Channel: %x, Port: %x\n", + Indent, + Desc->u.Dma.Channel, + Desc->u.Dma.Port + ); + break; + } +} + +VOID +PipDumpCmResourceList ( + IN PCM_RESOURCE_LIST CmList, + IN ULONG SlotNumber + ) +/*++ + +Routine Description: + + This routine displays CM resource list. + +Arguments: + + CmList - supplies a pointer to CM resource list + + SlotNumber - slot number of the resources + +Return Value: + + None. + +--*/ +{ + PCM_FULL_RESOURCE_DESCRIPTOR fullDesc; + PCM_PARTIAL_RESOURCE_LIST partialDesc; + PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; + ULONG count, i; + + fullDesc = &CmList->List[0]; + DbgPrint("Pnp Bios Cm Resource List for Slot %x -\n", SlotNumber); + DbgPrint(" List Count = %x, Bus Number = %x\n", CmList->Count, fullDesc->BusNumber); + partialDesc = &fullDesc->PartialResourceList; + DbgPrint(" Version = %x, Revision = %x, Desc count = %x\n", partialDesc->Version, + partialDesc->Revision, partialDesc->Count); + count = partialDesc->Count; + desc = &partialDesc->PartialDescriptors[0]; + for (i = 0; i < count; i++) { + PipDumpCmResourceDescriptor(" ", desc); + desc++; + } +} +#endif diff --git a/private/ntos/nthals/extender/pnpisa/i386/pnpisa.h b/private/ntos/nthals/extender/pnpisa/i386/pnpisa.h new file mode 100644 index 000000000..b36f77d16 --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa/i386/pnpisa.h @@ -0,0 +1,155 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pnpisa.h + +Abstract: + + This module contins definitions/declarations for PNP ISA related + definitions. + +Author: + + Shie-Lin Tzong (shielint) July-12-1995 + +Revision History: + +--*/ + +#ifndef NEC_98 +#define ADDRESS_PORT 0x0279 +#define COMMAND_PORT 0x0a79 +#else +#define ADDRESS_PORT 0x0259 +#define COMMAND_PORT 0x0a59 +#endif // NEC_98 + +// +// Plug and Play Card Control Registers +// + +#define SET_READ_DATA_PORT 0x00 +#define SERIAL_ISOLATION_PORT 0x01 +#define CONFIG_CONTROL_PORT 0x02 +#define WAKE_CSN_PORT 0x03 +#define CONFIG_DATA_PORT 0x04 +#define CONFIG_DATA_STATUS_PORT 0x05 +#define SET_CSN_PORT 0x06 +#define LOGICAL_DEVICE_PORT 0x07 + +// +// Plug and Play Logical Device Control Registers +// + +#define ACTIVATE_PORT 0x30 +#define IO_RANGE_CHECK_PORT 0x31 + +// +// Config Control command +// + +#define CONTROL_WAIT_FOR_KEY 0x02 +#define CONTROL_RESET_CSN 0x04 + +// +// Memory Space Configuration +// + +#define NUMBER_MEMORY_DESCRIPTORS 4 +#define ADDRESS_MEMORY_BASE 0x40 +#define ADDRESS_MEMORY_INCR 0x08 +#define ADDRESS_MEMORY_HI 0x00 +#define ADDRESS_MEMORY_LO 0x01 +#define ADDRESS_MEMORY_CTL 0x02 +#define ADDRESS_MEMORY_CTL_LIMIT 0x01 +#define ADDRESS_MEMORY_UPPER_HI 0x03 +#define ADDRESS_MEMORY_UPPER_LO 0x04 + +// +// 32 Bit Memory Space Configuration +// + +#define NUMBER_32_MEMORY_DESCRIPTORS 4 +#define ADDRESS_32_MEMORY_BASE(x) ((PUCHAR)(0x70+((x)*0x10)+((x==0) ? 6 : 0))) +#define ADDRESS_32_MEMORY_B3 0x0 +#define ADDRESS_32_MEMORY_B2 0x1 +#define ADDRESS_32_MEMORY_B1 0x2 +#define ADDRESS_32_MEMORY_B0 0x3 +#define ADDRESS_32_MEMORY_CTL 0x4 +#define ADDRESS_32_MEMORY_E3 0x5 +#define ADDRESS_32_MEMORY_E2 0x6 +#define ADDRESS_32_MEMORY_E1 0x7 +#define ADDRESS_32_MEMORY_E0 0x8 + +// +// Io Space Configuration +// + +#define NUMBER_IO_DESCRIPTORS 8 +#define ADDRESS_IO_BASE 0x60 +#define ADDRESS_IO_INCR 0x02 +#define ADDRESS_IO_BASE_HI 0x00 +#define ADDRESS_IO_BASE_LO 0x01 + +// +// Interrupt Configuration +// + +#define NUMBER_IRQ_DESCRIPTORS 2 +#define ADDRESS_IRQ_BASE 0x70 +#define ADDRESS_IRQ_INCR 0x02 +#define ADDRESS_IRQ_VALUE 0x00 +#define ADDRESS_IRQ_TYPE 0x01 + +// +// DMA Configuration +// + +#define NUMBER_DMA_DESCRIPTORS 2 +#define ADDRESS_DMA_BASE 0x74 +#define ADDRESS_DMA_INCR 0x01 +#define ADDRESS_DMA_VALUE 0x00 +#define NO_DMA 0x04 + +// +// 9 byte serial identifier of a PNP ISA Card +// + +#include "pshpack1.h" +typedef struct _SERIAL_IDENTIFIER_ { + ULONG VenderId; + ULONG SerialNumber; + UCHAR Checksum; +} SERIAL_IDENTIFIER, *PSERIAL_IDENTIFIER; +#include "poppack.h" + +// +// Misc. definitions +// + +#define MIN_READ_DATA_PORT 0x200 +#define MAX_READ_DATA_PORT 0x3ff +#define MAX_CHARACTER_LENGTH 255 +#define NUMBER_CARD_ID_BYTES 9 +#define NUMBER_CARD_ID_BITS (NUMBER_CARD_ID_BYTES * 8) +#define CHECKSUMED_BITS 64 +#define LFSR_SEED 0x6A +#define ISOLATION_TEST_BYTE_1 0x55 +#define ISOLATION_TEST_BYTE_2 0xAA + +#define PipWriteAddress(data) WRITE_PORT_UCHAR ((PUCHAR)ADDRESS_PORT, (UCHAR)(data)) +#define PipWriteData(data) WRITE_PORT_UCHAR ((PUCHAR)COMMAND_PORT, (UCHAR)(data)) +#define PipReadData() READ_PORT_UCHAR (PipReadDataPort) + +// +// External references +// + + +extern PUCHAR PipReadDataPort; + + + diff --git a/private/ntos/nthals/extender/pnpisa/i386/resource.c b/private/ntos/nthals/extender/pnpisa/i386/resource.c new file mode 100644 index 000000000..f1b4c2fee --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa/i386/resource.c @@ -0,0 +1,555 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + devres.c + +Abstract: + + This module contains the high level device resources support routines. + +Author: + + Shie-Lin Tzong (shielint) July-27-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "busp.h" +#include "pnpisa.h" +#include "..\..\pnpbios\i386\pbios.h" + +NTSTATUS +PipGetCompatibleDeviceId ( + PUCHAR DeviceData, + ULONG IdIndex, + PWCHAR Buffer + ); + +#define IDBG 1 + +#pragma alloc_text(PAGE,PipGetCompatibleDeviceId) +#pragma alloc_text(PAGE,PiCtlQueryDeviceId) +#pragma alloc_text(PAGE,PiCtlQueryDeviceUniqueId) +#pragma alloc_text(PAGE,PiCtlQueryDeviceResources) +#pragma alloc_text(PAGE,PiCtlQueryDeviceResourceRequirements) +#pragma alloc_text(PAGE,PiCtlSetDeviceResources) + +NTSTATUS +PipGetCompatibleDeviceId ( + PUCHAR DeviceData, + ULONG IdIndex, + PWCHAR Buffer + ) +/*++ + +Routine Description: + + This function returns the desired pnp isa id for the specified DeviceData + and Id index. If Id index = 0, the Hardware ID will be return; if id + index = n, the Nth compatible id will be returned. + +Arguments: + + DeviceData - supplies a pointer to the pnp isa device data. + + IdIndex - supplies the index of the compatible id desired. + + Buffer - supplies a pointer to a buffer to receive the compatible Id. + +Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status = STATUS_NO_MORE_ENTRIES; + UCHAR tag; + ULONG count = 0; + LONG size; + UNICODE_STRING unicodeString; + ANSI_STRING ansiString; + UCHAR eisaId[8]; + ULONG id; + + PAGED_CODE(); + + tag = *DeviceData; + +#if DBG + + // + // Make sure device data points to Logical Device Id tag + // + + if ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID) { + DbgPrint("PipGetCompatibleDeviceId: DeviceData is not at Logical Id tag\n"); + } +#endif + + if (IdIndex == 0) { + + // + // Caller is asking for hardware id + // + + DeviceData++; // Skip tag + id = *(PULONG)DeviceData; + status = STATUS_SUCCESS; + } else { + + // + // caller is asking for compatible id + // + + IdIndex--; + + // + // Skip all the resource descriptors to find compatible Id descriptor + // + + while (tag != TAG_COMPLETE_END) { + + // + // Do we reach the compatible ID descriptor? + // + + if ((tag & SMALL_TAG_MASK) == TAG_COMPATIBLE_ID) { + if (count == IdIndex) { + id = *(PULONG)(DeviceData + 1); + status = STATUS_SUCCESS; + break; + } else { + count++; + } + } + + // + // Determine the size of the BIOS resource descriptor and + // advance to next resource descriptor. + // + + if (!(tag & LARGE_RESOURCE_TAG)) { + size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); + size += 1; // length of small tag + } else { + size = *(PUSHORT)(DeviceData + 1); + size += 3; // length of large tag + } + + DeviceData += size; + tag = *DeviceData; + } + } + + if (NT_SUCCESS(status)) { + PipDecompressEisaId(id, eisaId); + RtlInitAnsiString(&ansiString, eisaId); + RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); + swprintf(Buffer, L"PNPISA\\*%s", unicodeString.Buffer); + RtlFreeUnicodeString(&unicodeString); + } + return status; +} + +VOID +PiCtlQueryDeviceUniqueId ( + PDEVICE_INFORMATION DeviceInfo, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function returns the unique id for the particular device. + +Arguments: + + DeviceData - Device data information for the specificied device. + + Context - Device control context of the request. + +Return Value: + + The device control is completed + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PWCHAR deviceId; + PUCHAR deviceData; + ULONG eisaid; + + PAGED_CODE(); + + // + // Set up device's unique id. + // device unique id = card series number + logical device eisa id in compressed form + // + + deviceId = (PWCHAR) Context->DeviceControl.Buffer; + deviceData = DeviceInfo->DeviceData; + + // + // Make sure device data points to Logical Device Id tag + // + + if ((*deviceData & SMALL_TAG_MASK) != TAG_LOGICAL_ID) { + + // + // Can not get the eisa compressed id. Use logical device number instead. + // +#if DBG + DbgPrint("PipGetCompatibleDeviceId: DeviceData is not at Logical Id tag\n"); +#endif + eisaid = DeviceInfo->LogicalDeviceNumber; + } else { + + // + // Get the eisa compressed id for the logical device. + // + + deviceData++; // Skip tag + eisaid = *(PULONG)deviceData; + } + swprintf (deviceId, + L"%08x%08x", + ((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->SerialNumber, + eisaid + ); +#if IDBG + { + ANSI_STRING ansiString; + UNICODE_STRING unicodeString; + + RtlInitUnicodeString(&unicodeString, (PWCHAR)Context->DeviceControl.Buffer); + RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE); + DbgPrint("Bus %x Slot %x Unique Id = %s\n", + Context->Handler->BusNumber, + DeviceInfoSlot(DeviceInfo), + ansiString.Buffer + ); + RtlFreeAnsiString(&ansiString); + } +#endif + + PipCompleteDeviceControl (STATUS_SUCCESS, Context, DeviceInfo); +} + +VOID +PiCtlQueryDeviceId ( + PDEVICE_INFORMATION DeviceInfo, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function returns the device id for the particular device. + +Arguments: + + DeviceInfo - Device information for the specificied device. + + Context - Device control context of the request. + +Return Value: + + The device control is completed + +--*/ +{ + NTSTATUS status; + PWCHAR deviceId; + ULONG idIndex; + + PAGED_CODE(); + + // + // Determine which device ID the caller wants back + // + + idIndex = *((PULONG) Context->DeviceControl.Buffer); + + // + // Call worker routine to get the desired Id. + // + + deviceId = (PWCHAR) Context->DeviceControl.Buffer; + status = PipGetCompatibleDeviceId(DeviceInfo->DeviceData, + idIndex, + (PWCHAR) deviceId); + +#if IDBG + if (NT_SUCCESS(status)) { + ANSI_STRING ansiString; + UNICODE_STRING unicodeString; + + RtlInitUnicodeString(&unicodeString, deviceId); + RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE); + DbgPrint("Bus %x Slot %x IdIndex %x Compatible Id = %s\n", + Context->Handler->BusNumber, + DeviceInfoSlot(DeviceInfo), + idIndex, + ansiString.Buffer + ); + RtlFreeAnsiString(&ansiString); + } +#endif + + PipCompleteDeviceControl (status, Context, DeviceInfo); +} + +VOID +PiCtlQueryDeviceResources ( + PDEVICE_INFORMATION DeviceInfo, + 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: + + DeviceInfo - Device information for the specificied slot + + Context - Device control context of the request + +Return Value: + + The device control is completed + +--*/ +{ + ULONG length; + PCM_RESOURCE_LIST cmResources; + NTSTATUS status; + + PAGED_CODE(); + + // + // protect port access + // + + ExAcquireFastMutex(&PipPortMutex); + + PipSelectLogicalDevice(DeviceInfo->CardInformation->CardSelectNumber, + DeviceInfo->LogicalDeviceNumber + ); + + status = PipReadDeviceBootResourceData ( + Context->Handler->BusNumber, + DeviceInfo->DeviceData, + &cmResources, + &length + ); + + PipWriteAddress(ACTIVATE_PORT); + PipWriteData(0); + + // + // Put all cards into wait for key state. + // + + PipWriteAddress(CONFIG_CONTROL_PORT); + PipWriteData(CONTROL_WAIT_FOR_KEY); + + ExReleaseFastMutex(&PipPortMutex); + + // + // Return results + // + + if (NT_SUCCESS(status)) { + if (length == 0) { + + // + // If resource info is not available, return an empty CM_RESOURCE_LIST + // + + cmResources = (PCM_RESOURCE_LIST) ExAllocatePoolWithTag ( + PagedPool, sizeof(CM_RESOURCE_LIST), 'iPnP'); + if (!cmResources) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto exitLocal; + } else { + cmResources->Count = 0; + cmResources->List[0].InterfaceType = Context->RootHandler->InterfaceType; + cmResources->List[0].BusNumber = Context->RootHandler->BusNumber; + cmResources->List[0].PartialResourceList.Version = 0; + cmResources->List[0].PartialResourceList.Revision = 0; + cmResources->List[0].PartialResourceList.Count = 0; + length = sizeof(CM_RESOURCE_LIST); + } + } + if (length > *Context->DeviceControl.BufferLength) { + status = STATUS_BUFFER_TOO_SMALL; + } else { + RtlCopyMemory (Context->DeviceControl.Buffer, cmResources, length); + } + *Context->DeviceControl.BufferLength = length; +#if IDBG + if (NT_SUCCESS(status)) { + PipDumpCmResourceList(cmResources, DeviceInfoSlot(DeviceInfo)); + } +#endif + ExFreePool(cmResources); + } +exitLocal: + PipCompleteDeviceControl (status, Context, DeviceInfo); +} + +VOID +PiCtlQueryDeviceResourceRequirements ( + PDEVICE_INFORMATION DeviceInfo, + 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 - Device data information for the specificied slot + + Context - Device control context of the request + +Return Value: + + The device control is completed + +--*/ +{ + ULONG length = 0; + PIO_RESOURCE_REQUIREMENTS_LIST ioResources = NULL; + NTSTATUS status; + PUCHAR deviceData; + PAGED_CODE(); + + deviceData = DeviceInfo->DeviceData; + status = PbBiosResourcesToNtResources ( + Context->RootHandler->BusNumber, + DeviceInfoSlot(DeviceInfo), + &deviceData, + &ioResources, + &length + ); + + // + // Return results + // + + if (NT_SUCCESS(status)) { + if (length == 0) { + + // + // If resource info is not available, return an empty CM_RESOURCE_LIST + // + + ioResources = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePoolWithTag ( + PagedPool, sizeof(IO_RESOURCE_REQUIREMENTS_LIST), 'bPnP'); + if (!ioResources) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto exitLocal; + } else { + ioResources->ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); + ioResources->InterfaceType = Context->RootHandler->InterfaceType; + ioResources->BusNumber = Context->RootHandler->BusNumber; + ioResources->SlotNumber = DeviceInfoSlot(DeviceInfo); + ioResources->Reserved[0] = 0; + ioResources->Reserved[1] = 0; + ioResources->Reserved[2] = 0; + ioResources->AlternativeLists = 0; + ioResources->List[0].Version = 1; + ioResources->List[0].Revision = 1; + ioResources->List[0].Count = 0; + length = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); + } + } + if (length > *Context->DeviceControl.BufferLength) { + status = STATUS_BUFFER_TOO_SMALL; + } else { + RtlCopyMemory (Context->DeviceControl.Buffer, ioResources, length); + } + *Context->DeviceControl.BufferLength = length; +#if IDBG + if (NT_SUCCESS(status)) { + PipDumpIoResourceList(ioResources); + } +#endif + ExFreePool(ioResources); + } +exitLocal: + PipCompleteDeviceControl (status, Context, DeviceInfo); +} + +VOID +PiCtlSetDeviceResources ( + PDEVICE_INFORMATION DeviceInfo, + 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: + + DeviceInfo - Device information for the specificied slot + + Context - Device control context of the request + +Return Value: + + The device control is completed + +--*/ +{ + NTSTATUS status; + + PAGED_CODE(); + + // + // Protect port access + // + + ExAcquireFastMutex(&PipPortMutex); + + PipSelectLogicalDevice(DeviceInfo->CardInformation->CardSelectNumber, + DeviceInfo->LogicalDeviceNumber + ); + + // + // Set resource settings for the device + // + + status = PipWriteDeviceBootResourceData ( + DeviceInfo->DeviceData, + (PCM_RESOURCE_LIST) Context->DeviceControl.Buffer + ); + // + // Put all cards into wait for key state. + // + + PipWriteAddress(CONFIG_CONTROL_PORT); + PipWriteData(CONTROL_WAIT_FOR_KEY); + + ExReleaseFastMutex(&PipPortMutex); + PipCompleteDeviceControl (status, Context, DeviceInfo); +} diff --git a/private/ntos/nthals/extender/pnpisa/makefile b/private/ntos/nthals/extender/pnpisa/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa/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/pnpisa/pnpisa.rc b/private/ntos/nthals/extender/pnpisa/pnpisa.rc new file mode 100644 index 000000000..1a87276e5 --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa/pnpisa.rc @@ -0,0 +1,11 @@ +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "PNP ISA Extension Driver" +#define VER_INTERNALNAME_STR "pnpisa.sys" +#define VER_ORIGINALFILENAME_STR "pnpisa.sys" + +#include "common.ver" diff --git a/private/ntos/nthals/extender/pnpisa/sources b/private/ntos/nthals/extender/pnpisa/sources new file mode 100644 index 000000000..cbea7153e --- /dev/null +++ b/private/ntos/nthals/extender/pnpisa/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=extender + +TARGETNAME=pnpisa +TARGETPATH=$(BASEDIR)\public\sdk\lib +TARGETTYPE=DRIVER + +INCLUDES=..\..\..\inc + +SOURCES= + +i386_SOURCES=pnpisa.rc \ + i386\bus.c \ + i386\control.c \ + i386\data.c \ + i386\init.c \ + i386\isolate.c \ + i386\misc.c \ + i386\convert.c \ + i386\resource.c + +NTTEST= +OPTIONAL_NTTEST= +UMTEST= -- cgit v1.2.3