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/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 + 13 files changed, 6837 insertions(+) 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/pnpisa') 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