NT4/private/ntos/nthals/halalpha/eisasup.c
2020-09-30 17:12:29 +02:00

1478 lines
34 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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