diff options
Diffstat (limited to 'private/ntos/nthals/halalpha/eisasup.c')
-rw-r--r-- | private/ntos/nthals/halalpha/eisasup.c | 1477 |
1 files changed, 1477 insertions, 0 deletions
diff --git a/private/ntos/nthals/halalpha/eisasup.c b/private/ntos/nthals/halalpha/eisasup.c new file mode 100644 index 000000000..4f907fa1d --- /dev/null +++ b/private/ntos/nthals/halalpha/eisasup.c @@ -0,0 +1,1477 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + eisasup.c + +Abstract: + + The module provides the platform-independent + EISA bus support for Alpha systems. + +Author: + + Jeff Havens (jhavens) 19-Jun-1991 + Miche Baker-Harvey (miche) 13-May-1992 + Jeff McLeman (DEC) 1-Jun-1992 + +Revision History: + + +--*/ + + +#include "halp.h" +#include "eisa.h" + + +// +// Define save area for ESIA adapter objects. +// + +PADAPTER_OBJECT HalpEisaAdapter[8]; + +// +// This value indicates if Eisa DMA is supported on this system. +// + +BOOLEAN HalpEisaDma; + + +VOID +HalpEisaInitializeDma( + VOID + ) +/*++ + +Routine Description: + + Initialize DMA support for Eisa/Isa systems. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + UCHAR DataByte; + + // + // Determine if Eisa DMA is supported. + // + + HalpEisaDma = FALSE; + + WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort.Channel2, 0x55); + DataByte = READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort.Channel2); + + if (DataByte == 0x55) { + HalpEisaDma = TRUE; + } +} + + +PADAPTER_OBJECT +HalpAllocateEisaAdapter( + IN PDEVICE_DESCRIPTION DeviceDescriptor, + OUT PULONG NumberOfMapRegisters + ) + +/*++ + +Routine Description: + + This function returns the appropriate adapter object for the device defined + in the device description structure. This code works for Isa and Eisa + systems. + +Arguments: + + DeviceDescriptor - Supplies a description of the device. + + NumberOfMapRegisters - Returns the maximum number of map registers which + may be allocated by the device driver. + +Return Value: + + A pointer to the requested adapter object or NULL if an adapter could not + be created. + +--*/ + +{ + PADAPTER_OBJECT adapterObject; + PVOID adapterBaseVa; + ULONG channelNumber; + ULONG controllerNumber; + DMA_EXTENDED_MODE extendedMode; + UCHAR adapterMode; + ULONG numberOfMapRegisters; + BOOLEAN useChannel; + ULONG maximumLength; + UCHAR DataByte; + + useChannel = TRUE; + + // + // Support for ISA local bus machines: + // If the driver is a Master but really does not want a channel since it + // is using the local bus DMA, just don't use an ISA channel. + // + + if (DeviceDescriptor->InterfaceType == Isa && + DeviceDescriptor->DmaChannel > 7) { + + useChannel = FALSE; + } + + // + // Limit the maximum length to 2 GB this is done so that the BYTES_TO_PAGES + // macro works correctly. + // + + maximumLength = DeviceDescriptor->MaximumLength & 0x7fffffff; + + // + // Channel 4 cannot be used since it is used for chaining. Return null if + // it is requested. + // + + if (DeviceDescriptor->DmaChannel == 4 && useChannel) { + return(NULL); + } + + // + // Determine the number of map registers required based on the maximum + // transfer length. Limit the maximum transfer to 64K. + // + +#define MAXIMUM_ISA_MAP_REGISTER (__64K >> PAGE_SHIFT) + + numberOfMapRegisters = BYTES_TO_PAGES(maximumLength) + 1; + numberOfMapRegisters = numberOfMapRegisters > MAXIMUM_ISA_MAP_REGISTER ? + MAXIMUM_ISA_MAP_REGISTER : numberOfMapRegisters; + + // + // Set the channel number number. + // + + channelNumber = DeviceDescriptor->DmaChannel & 0x03; + + // + // Set the adapter base address to the Base address register and controller + // number. + // + + if (!(DeviceDescriptor->DmaChannel & 0x04)) { + + controllerNumber = 1; + adapterBaseVa = (PVOID) &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort; + + } else { + + controllerNumber = 2; + adapterBaseVa = &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort; + + } + + // + // Determine if a new adapter object is necessary. If so then allocate it. + // + + if (useChannel && HalpEisaAdapter[DeviceDescriptor->DmaChannel] != NULL) { + + adapterObject = HalpEisaAdapter[DeviceDescriptor->DmaChannel]; + + if (numberOfMapRegisters > adapterObject->MapRegistersPerChannel) { + adapterObject->MapRegistersPerChannel = numberOfMapRegisters; + } + + } else { + + // + // Allocate an adapter object. + // + + adapterObject = HalpAllocateAdapter(); + + if (adapterObject == NULL) { + return(NULL); + } + + if (useChannel == TRUE) { + HalpEisaAdapter[DeviceDescriptor->DmaChannel] = adapterObject; + } + + // + // Set the maximum number of map registers for this channel bus on + // the number requested and the type of device. + // + + adapterObject->MapRegistersPerChannel = numberOfMapRegisters; + + // + // Establish the base va used to program the DMA controller. + // + + adapterObject->AdapterBaseVa = adapterBaseVa; + + } + + *NumberOfMapRegisters = adapterObject->MapRegistersPerChannel; + + if (DeviceDescriptor->Master) { + adapterObject->MasterDevice = TRUE; + } else { + adapterObject->MasterDevice = FALSE; + } + + // + // If the channel number is not used then we are finished. The rest of + // the work deals with channels. + // + + if (useChannel == FALSE) { + return(adapterObject); + } + + // + // Setup the pointers to all the random registers. + // + + adapterObject->ChannelNumber = (UCHAR) channelNumber; + + if (controllerNumber == 1) { + + switch ((UCHAR)channelNumber) { + + case 0: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel0; + break; + + case 1: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel1; + break; + + case 2: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel2; + break; + + case 3: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel3; + break; + } + + // + // Set the adapter number. + // + + adapterObject->AdapterNumber = 1; + + // + // Save the extended mode register address. + // + + adapterBaseVa = + &((PEISA_CONTROL) HalpEisaControlBase)->Dma1ExtendedModePort; + + } else { + + switch (channelNumber) { + case 1: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel5; + break; + + case 2: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel6; + break; + + case 3: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel7; + break; + } + + // + // Set the adapter number. + // + + adapterObject->AdapterNumber = 2; + + // + // Save the extended mode register address. + // + adapterBaseVa = + &((PEISA_CONTROL) HalpEisaControlBase)->Dma2ExtendedModePort; + + } + + + adapterObject->Width16Bits = FALSE; + + if (HalpEisaDma) { + + // + // Initialzie the extended mode port. + // + + *((PUCHAR) &extendedMode) = 0; + extendedMode.ChannelNumber = (UCHAR)channelNumber; + + switch (DeviceDescriptor->DmaSpeed) { + case Compatible: + extendedMode.TimingMode = COMPATIBLITY_TIMING; + break; + + case TypeA: + extendedMode.TimingMode = TYPE_A_TIMING; + break; + + case TypeB: + extendedMode.TimingMode = TYPE_B_TIMING; + break; + + case TypeC: + extendedMode.TimingMode = BURST_TIMING; + break; + + default: + ObDereferenceObject( adapterObject ); + return(NULL); + + } + + switch (DeviceDescriptor->DmaWidth) { + case Width8Bits: + extendedMode.TransferSize = BY_BYTE_8_BITS; + break; + + case Width16Bits: + extendedMode.TransferSize = BY_BYTE_16_BITS; + + // + // Note Width16bits should not be set here because there is no need + // to shift the address and the transfer count. + // + + break; + + case Width32Bits: + extendedMode.TransferSize = BY_BYTE_32_BITS; + break; + + default: + ObDereferenceObject( adapterObject ); + return(NULL); + + } + + // + // Save the extended mode in the adapter. + // Then write the extended mode value for this channel. + // + + adapterObject->ExtendedMode = *((PDMA_EXTENDED_MODE)&extendedMode); + + WRITE_PORT_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode)); + + } else if (DeviceDescriptor->Master == FALSE) { + + + switch (DeviceDescriptor->DmaWidth) { + case Width8Bits: + + // + // The channel must use controller 1. + // + + if (controllerNumber != 1) { + ObDereferenceObject( adapterObject ); + return(NULL); + } + + break; + + case Width16Bits: + + // + // The channel must use controller 2. + // + + if (controllerNumber != 2) { + ObDereferenceObject( adapterObject ); + return(NULL); + } + + adapterObject->Width16Bits = TRUE; + break; + + default: + ObDereferenceObject( adapterObject ); + return(NULL); + + } + } + + // + // Initialize the adapter mode register value to the correct parameters, + // and save them in the adapter object. + // + + adapterMode = 0; + ((PDMA_EISA_MODE) &adapterMode)->Channel = adapterObject->ChannelNumber; + + if (DeviceDescriptor->Master) { + + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE; + + // + // Set the mode, and enable the request. + // + + if (adapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = adapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode ); + + // + // Unmask the DMA channel. + // + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber) + ); + + } else { + + // + // This request is for DMA controller 1 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = adapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode ); + + // + // Unmask the DMA channel. + // + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber) + ); + + } + + } else if (DeviceDescriptor->DemandMode) { + + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = DEMAND_REQUEST_MODE; + + } else { + + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = SINGLE_REQUEST_MODE; + + } + + if (DeviceDescriptor->AutoInitialize) { + + ((PDMA_EISA_MODE) &adapterMode)->AutoInitialize = 1; + + } + + adapterObject->AdapterMode = adapterMode; + + return(adapterObject); +} + +BOOLEAN +HalpMapEisaTransfer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG LogicalAddress, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + This routine is invoked to perform the actual programming of the + DMA controllers to perform a transfer for Eisa/Isa systems. + +Arguments: + + AdapterObject - Pointer to the adapter object representing the DMA + controller channel that has been allocated. + + Mdl - Pointer to the MDL that describes the pages of memory that are + being read or written. + + MapRegisterBase - The address of the base map register that has been + allocated to the device driver for use in mapping the transfer. + + CurrentVa - Current virtual address in the buffer described by the MDL + that the transfer is being done to or from. + + Length - Supplies the length of the transfer. This determines the + number of map registers that need to be written to map the transfer. + Returns the length of the transfer which was actually mapped. + + WriteToDevice - Boolean value that indicates whether this is a write + to the device from memory (TRUE), or vice versa. + + LogicalAddress - Supplies the logical address of the transfer. + +Return Value: + + Returns a boolean identifying if the operation was successful. + +--*/ + +{ + KIRQL Irql; + UCHAR adapterMode; + PUCHAR bytePointer; + UCHAR dataByte; + ULONG logicalAddress; + ULONG transferLength; + + logicalAddress = LogicalAddress; + transferLength = Length; + + // + // Determine the mode based on the transfer direction. + // + + adapterMode = AdapterObject->AdapterMode; + ((PDMA_EISA_MODE) &adapterMode)->TransferType = (UCHAR) (WriteToDevice ? + WRITE_TRANSFER : READ_TRANSFER); + + bytePointer = (PUCHAR) &logicalAddress; + + // + // Check to see if this request is for a master I/O card. + // + +//jnfix - this code not in Jensen + if( ((PDMA_EISA_MODE)&adapterMode)->RequestMode == CASCADE_REQUEST_MODE) { + + // + // Set the mode, disable the request and return. + // + + if( AdapterObject->AdapterNumber == 1 ){ + + // + // Request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); + + // + // Unmask the DMA channel. + // + + WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, + (UCHAR)(DMA_CLEARMASK | AdapterObject->ChannelNumber) ); + + } else { + + // + // Request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); + + // + // Unmask the DMA channel. + // + + WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, + (UCHAR)(DMA_CLEARMASK | AdapterObject->ChannelNumber) ); + + } + + return TRUE; + + } + + if (AdapterObject->Width16Bits) { + + // + // If this is a 16 bit transfer then adjust the length and the address + // for the 16 bit DMA mode. + // + + transferLength >>= 1; + + } + + // + // Grab the spinlock for the system DMA controller. + // + + KeAcquireSpinLock( &AdapterObject->MapAdapter->SpinLock, &Irql ); + + // + // Determine the controller number based on the Adapter number. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode ); + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + bytePointer[0] + ); + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + bytePointer[1] + ); + + WRITE_PORT_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) + + (ULONG)AdapterObject->PagePort, + bytePointer[2] + ); + + if (HalpEisaDma) { + + // + // Write the high page register with zero value. This enable a + // special mode which allows ties the page register and base + // count into a single 24 bit address register. + // + + WRITE_PORT_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) + + (ULONG)AdapterObject->PagePort, + 0 + ); + } + + // + // Notify DMA chip of the length to transfer. + // + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((transferLength - 1) & 0xff) + ); + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((transferLength - 1) >> 8) + ); + + + // + // Set the DMA chip to read or write mode; and unmask it. + // + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) + ); + + } else { + + // + // This request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode ); + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + bytePointer[0] + ); + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + bytePointer[1] + ); + + WRITE_PORT_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) + + (ULONG)AdapterObject->PagePort, + bytePointer[2] + ); + + if (HalpEisaDma) { + + // + // Write the high page register with zero value. This enable + // a special mode which allows ties the page register and base + // count into a single 24 bit address register. + // + + WRITE_PORT_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) + + (ULONG)AdapterObject->PagePort, + 0 + ); + } + + // + // Notify DMA chip of the length to transfer. + // + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((transferLength - 1) & 0xff) + ); + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((transferLength - 1) >> 8) + ); + + + // + // Set the DMA chip to read or write mode; and unmask it. + // + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) + ); + + } + + KeReleaseSpinLock (&AdapterObject->MapAdapter->SpinLock, Irql); + + return TRUE; +} + + +BOOLEAN +HalpFlushEisaAdapter( + IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl, + IN PVOID MapRegisterBase, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + This routine flushes the DMA adapter object buffers. For EISA systems + its clears the enable flag which aborts the dma. + +Arguments: + + AdapterObject - Pointer to the adapter object representing the DMA + controller channel. + + Mdl - A pointer to a Memory Descriptor List (MDL) that maps the locked-down + buffer to/from which the I/O occured. + + MapRegisterBase - A pointer to the base of the map registers in the adapter + or DMA controller. + + CurrentVa - The current virtual address in the buffer described the the Mdl + where the I/O operation occurred. + + Length - Supplies the length of the transfer. + + WriteToDevice - Supplies a BOOLEAN value that indicates the direction of + the data transfer was to the device. + +Return Value: + + TRUE - If the transfer was successful. + + FALSE - If there was an error in the transfer. + +--*/ +{ + + BOOLEAN masterDevice; + KIRQL Irql; + + masterDevice = AdapterObject->MasterDevice; + + KeAcquireSpinLock( &AdapterObject->MapAdapter->SpinLock, &Irql ); + + // + // If this is a slave device, then stop the DMA controller. + // + + if (masterDevice == FALSE) { + + // + // Mask the DMA request line so that DMA requests cannot occur. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber) + ); + + } else { + + // + // This request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber) + ); + + } + + } + + KeReleaseSpinLock( &AdapterObject->MapAdapter->SpinLock, Irql ); + + return TRUE; + +} + +ULONG +HalpReadEisaDmaCounter( + IN PADAPTER_OBJECT AdapterObject + ) +/*++ + +Routine Description: + + This function reads the DMA counter and returns the number of bytes left + to be transfered. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object to be read. + +Return Value: + + Returns the number of bytes still be be transfered. + +--*/ + +{ + + ULONG count; + ULONG high; + KIRQL Irql; + + // + // Grab the spinlock for the system DMA controller. + // + + KeAcquireSpinLock( &AdapterObject->MapAdapter->SpinLock, &Irql ); + + // + // Determine the controller number based on the Adapter number. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + + // + // Initialize count to a value which will not match. + // + + count = 0xFFFF00; + + // + // Loop until the same high byte is read twice. + // + + do { + + high = count; + + WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + // + // Read the current DMA count. + // + + count = READ_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ); + + count |= READ_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ) << 8; + + } while ((count & 0xFFFF00) != (high & 0xFFFF00)); + + } else { + + // + // This request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + // + // Initialize count to a value which will not match. + // + + count = 0xFFFF00; + + // + // Loop until the same high byte is read twice. + // + + do { + + high = count; + + WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + // + // Read the current DMA count. + // + + count = READ_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ); + + count |= READ_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ) << 8; + + } while ((count & 0xFFFF00) != (high & 0xFFFF00)); + + + } + + // + // Release the spinlock for the system DMA controller. + // + + KeReleaseSpinLock( &AdapterObject->MapAdapter->SpinLock, Irql ); + + // + // The DMA counter has a bias of one and can only be 16 bit long. + // + + count = (count + 1) & 0xFFFF; + + // + // If this is a 16 bit dma the multiply the count by 2. + // + + if (AdapterObject->Width16Bits) { + + count *= 2; + + } + + return(count); + +} + +#if !defined(AXP_FIRMWARE) + +ULONG +HalpGetEisaData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + The function returns the Eisa bus data for a slot or address. + +Arguments: + + + BusHandler - Registered BUSHANDLER for the target configuration space + + RootHandler - Registered BUSHANDLER for the orginating HalGetBusData + request. + + Buffer - Supplies the space to store the data. + + Offset - Supplies the offset into data to begin access. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ +{ + OBJECT_ATTRIBUTES ObjectAttributes; + OBJECT_ATTRIBUTES BusObjectAttributes; + PWSTR EisaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\EisaAdapter"; + PWSTR ConfigData = L"Configuration Data"; + ANSI_STRING TmpString; + ULONG BusNumber; + UCHAR BusString[] = "00"; + UNICODE_STRING RootName, BusName; + UNICODE_STRING ConfigDataName; + NTSTATUS NtStatus; + PKEY_VALUE_FULL_INFORMATION ValueInformation; + PCM_FULL_RESOURCE_DESCRIPTOR Descriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResource; + PCM_EISA_SLOT_INFORMATION SlotInformation; + ULONG PartialCount; + ULONG TotalDataSize, SlotDataSize; + HANDLE EisaHandle, BusHandle; + ULONG BytesWritten, BytesNeeded; + PUCHAR KeyValueBuffer; + ULONG i; + ULONG DataLength = 0; + PUCHAR DataBuffer = Buffer; + BOOLEAN Found = FALSE; + + UNREFERENCED_PARAMETER( RootHandler ); + + RtlInitUnicodeString( + &RootName, + EisaPath + ); + + InitializeObjectAttributes( + &ObjectAttributes, + &RootName, + OBJ_CASE_INSENSITIVE, + (HANDLE)NULL, + NULL + ); + + // + // Open the EISA root + // + + NtStatus = ZwOpenKey( + &EisaHandle, + KEY_READ, + &ObjectAttributes + ); + + if (!NT_SUCCESS(NtStatus)) { +#if DBG + DbgPrint("HAL: Open Status = %x\n",NtStatus); +#endif + return(0); + } + + // + // Init bus number path + // + + BusNumber = BusHandler->BusNumber; + + if (BusNumber > 99) { + return (0); + } + + if (BusNumber > 9) { + BusString[0] += (UCHAR) (BusNumber/10); + BusString[1] += (UCHAR) (BusNumber % 10); + } else { + BusString[0] += (UCHAR) BusNumber; + BusString[1] = '\0'; + } + + RtlInitAnsiString( + &TmpString, + BusString + ); + + RtlAnsiStringToUnicodeString( + &BusName, + &TmpString, + TRUE + ); + + + InitializeObjectAttributes( + &BusObjectAttributes, + &BusName, + OBJ_CASE_INSENSITIVE, + (HANDLE)EisaHandle, + NULL + ); + + // + // Open the EISA root + Bus Number + // + + NtStatus = ZwOpenKey( + &BusHandle, + KEY_READ, + &BusObjectAttributes + ); + + if (!NT_SUCCESS(NtStatus)) { +#if DBG + DbgPrint("HAL: Opening Bus Number: Status = %x\n",NtStatus); +#endif + return(0); + } + + // + // opening the configuration data. This first call tells us how + // much memory we need to allocate + // + + RtlInitUnicodeString( + &ConfigDataName, + ConfigData + ); + + // + // This should fail. We need to make this call so we can + // get the actual size of the buffer to allocate. + // + + ValueInformation = (PKEY_VALUE_FULL_INFORMATION) &i; + NtStatus = ZwQueryValueKey( + BusHandle, + &ConfigDataName, + KeyValueFullInformation, + ValueInformation, + 0, + &BytesNeeded + ); + + KeyValueBuffer = ExAllocatePool( + NonPagedPool, + BytesNeeded + ); + + if (KeyValueBuffer == NULL) { +#if DBG + DbgPrint("HAL: Cannot allocate Key Value Buffer\n"); +#endif + ZwClose(BusHandle); + return(0); + } + + ValueInformation = (PKEY_VALUE_FULL_INFORMATION)KeyValueBuffer; + + NtStatus = ZwQueryValueKey( + BusHandle, + &ConfigDataName, + KeyValueFullInformation, + ValueInformation, + BytesNeeded, + &BytesWritten + ); + + + ZwClose(BusHandle); + + if (!NT_SUCCESS(NtStatus) || ValueInformation->DataLength == 0) { +#if DBG + DbgPrint("HAL: Query Config Data: Status = %x\n",NtStatus); +#endif + ExFreePool(KeyValueBuffer); + return(0); + } + + + // + // We get back a Full Resource Descriptor List + // + + Descriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)ValueInformation + + ValueInformation->DataOffset); + + PartialResource = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) + &(Descriptor->PartialResourceList.PartialDescriptors); + PartialCount = Descriptor->PartialResourceList.Count; + + for (i = 0; i < PartialCount; i++) { + + // + // Do each partial Resource + // + + switch (PartialResource->Type) { + case CmResourceTypeNull: + case CmResourceTypePort: + case CmResourceTypeInterrupt: + case CmResourceTypeMemory: + case CmResourceTypeDma: + + // + // We dont care about these. + // + + PartialResource++; + + break; + + case CmResourceTypeDeviceSpecific: + + // + // Bingo! + // + + TotalDataSize = PartialResource->u.DeviceSpecificData.DataSize; + + SlotInformation = (PCM_EISA_SLOT_INFORMATION) + ((PUCHAR)PartialResource + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + + while (((LONG)TotalDataSize) > 0) { + + if (SlotInformation->ReturnCode == EISA_EMPTY_SLOT) { + + SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION); + + } else { + + SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION) + + SlotInformation->NumberFunctions * + sizeof(CM_EISA_FUNCTION_INFORMATION); + } + + if (SlotDataSize > TotalDataSize) { + + // + // Something is wrong again + // + + ExFreePool(KeyValueBuffer); + return(0); + + } + + if (SlotNumber != 0) { + + SlotNumber--; + + SlotInformation = (PCM_EISA_SLOT_INFORMATION) + ((PUCHAR)SlotInformation + SlotDataSize); + + TotalDataSize -= SlotDataSize; + + continue; + + } + + // + // This is our slot + // + + Found = TRUE; + break; + + } + + // + // End loop + // + + i = PartialCount; + + break; + + default: + +#if DBG + DbgPrint("Bad Data in registry!\n"); +#endif + + ExFreePool(KeyValueBuffer); + return(0); + + } + + } + + if (Found) { + + i = Length + Offset; + if (i > SlotDataSize) { + i = SlotDataSize; + } + + DataLength = i - Offset; + RtlMoveMemory (Buffer, ((PUCHAR)SlotInformation + Offset), DataLength); + + } + + ExFreePool(KeyValueBuffer); + return DataLength; +} + + +NTSTATUS +HalpAdjustEisaResourceList ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ) +/*++ + +Routine Description: + + The function adjusts pResourceList to keep it in the bounds of the EISA bus + resources. + +Arguments: + + BusHandler - Registered BUSHANDLER for the target configuration space + + RootHandler - Register BUSHANDLER for the orginating HalAdjustResourceList request. + + pResourceList - Supplies the PIO_RESOURCE_REQUIREMENTS_LIST to be checked. + +Return Value: + + STATUS_SUCCESS + +--*/ +{ + LARGE_INTEGER li64k, li4g; + + li64k.QuadPart = 0xffff; + li4g.QuadPart = 0xffffffff; + + HalpAdjustResourceListUpperLimits ( + pResourceList, + li64k, // Bus supports up to I/O port 0xFFFF + li4g, // Bus supports up to memory 0xFFFFFFFF + 15, // Bus supports up to 15 IRQs + 7 // Bus supports up to Dma channel 7 + ); + + return STATUS_SUCCESS; +} + +NTSTATUS +HalpAdjustIsaResourceList ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ) +/*++ + +Routine Description: + + The function adjusts pResourceList to keep it in the bounds of ISA bus + resources. + +Arguments: + + BusHandler - Registered BUSHANDLER for the target configuration space + + RootHandler - Register BUSHANDLER for the orginating HalAdjustResourceList request. + + pResourceList - Supplies the PIO_RESOURCE_REQUIREMENTS_LIST to be checked. + +Return Value: + + STATUS_SUCCESS + +--*/ +{ + LARGE_INTEGER li64k, limem; + + li64k.QuadPart = 0xffff; + limem.QuadPart = 0xffffff; + + HalpAdjustResourceListUpperLimits ( + pResourceList, + li64k, // Bus supports up to I/O port 0xFFFF + limem, // Bus supports up to memory 0xFFFFFF + 15, // Bus supports up to 15 IRQs + 7 // Bus supports up to Dma channel 7 + ); + + return STATUS_SUCCESS; +} +#endif // AXP_FIRMWARE |