NT4/private/ntos/nthals/halsni4x/mips/jxhwsup.c
2020-09-30 17:12:29 +02:00

2438 lines
60 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.

#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk351/src/hal/halsni4x/mips/RCS/jxhwsup.c,v 1.1 1995/05/19 11:19:03 flo Exp $")
/*++
Copyright (c) 1989-1993 Microsoft Corporation
Module Name:
jxhwsup.c
Abstract:
This module contains the IoXxx routines for the NT I/O system that
are hardware dependent. Were these routines not hardware dependent,
they would reside in the iosubs.c module.
Environment:
Kernel mode
+++*/
#include "halp.h"
#include "eisa.h"
extern VOID NtClose();
ULONG
HalpReadEisaData (
IN ULONG BusNumber,
IN ULONG SlotNumber,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
);
IO_ALLOCATION_ACTION
HalpAllocationRoutine (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID MapRegisterBase,
IN PVOID Context
);
//
// Some devices require a phyicially contiguous data buffers for DMA transfers.
// Map registers are used give the appearance that all data buffers are
// contiguous. In order to pool all of the map registers a master
// adapter object is used. This object is allocated and saved internal to this
// file. It contains a bit map for allocation of the registers and a queue
// for requests which are waiting for more map registers. This object is
// allocated during the first request to allocate an adapter which requires
// map registers.
//
PADAPTER_OBJECT MasterAdapterObject;
//
// Map buffer parameters. These are initialized in HalInitSystem
//
BOOLEAN
HalpGrowMapBuffers(
PADAPTER_OBJECT AdapterObject,
ULONG Amount
)
/*++
Routine Description:
This function attempts to allocate additional map buffers for use by I/O
devices. The map register table is updated to indicate the additional
buffers.
Arguments:
AdapterObject - Supplies the adapter object for which the buffers are to be
allocated.
Amount - Indicates the size of the map buffers which should be allocated.
Return Value:
TRUE is returned if the memory could be allocated.
FALSE is returned if the memory could not be allocated.
--*/
{
ULONG MapBufferPhysicalAddress;
PVOID MapBufferVirtualAddress;
PTRANSLATION_ENTRY TranslationEntry;
LONG NumberOfPages;
LONG i;
KIRQL Irql;
PHYSICAL_ADDRESS physicalAddress;
KeAcquireSpinLock( &AdapterObject->SpinLock, &Irql );
NumberOfPages = BYTES_TO_PAGES(Amount);
//
// Make sure there is room for the additional pages. The maximum number of
// slots needed is equal to NumberOfPages + Amount / 64K + 1.
//
i = BYTES_TO_PAGES(MAXIMUM_MAP_BUFFER_SIZE) - (NumberOfPages +
(NumberOfPages * PAGE_SIZE) / 0x10000 + 1 +
AdapterObject->NumberOfMapRegisters);
if (i < 0) {
//
// Reduce the allocation amount so it will fit.
//
NumberOfPages += i;
}
if (NumberOfPages <= 0) {
//
// No more memory can be allocated.
//
KeReleaseSpinLock( &AdapterObject->SpinLock, Irql );
return(FALSE);
}
if (AdapterObject->NumberOfMapRegisters == 0 && HalpMapBufferSize) {
NumberOfPages = BYTES_TO_PAGES(HalpMapBufferSize);
//
// Since this is the initial allocation, use the buffer allocated by
// HalInitSystem rather than allocating a new one.
//
MapBufferPhysicalAddress = HalpMapBufferPhysicalAddress.LowPart;
//
// Map the buffer for access.
//
MapBufferVirtualAddress = MmMapIoSpace(
HalpMapBufferPhysicalAddress,
HalpMapBufferSize,
FALSE // Cache disable. Importent for DMA if we
// have more than 16Mb memory in our SNI
);
if (MapBufferVirtualAddress == NULL) {
//
// The buffer could not be mapped.
//
HalpMapBufferSize = 0;
KeReleaseSpinLock( &AdapterObject->SpinLock, Irql );
return(FALSE);
}
} else {
//
// Allocate the map buffers.
//
physicalAddress.LowPart = MAXIMUM_PHYSICAL_ADDRESS - 1;
physicalAddress.HighPart = 0;
MapBufferVirtualAddress = MmAllocateContiguousMemory(
NumberOfPages * PAGE_SIZE,
physicalAddress
);
if (MapBufferVirtualAddress == NULL) {
KeReleaseSpinLock( &AdapterObject->SpinLock, Irql );
return(FALSE);
}
//
// Get the physical address of the map base.
//
MapBufferPhysicalAddress = MmGetPhysicalAddress(
MapBufferVirtualAddress
).LowPart;
}
//
// Initialize the map registers where memory has been allocated.
//
TranslationEntry = ((PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase) +
AdapterObject->NumberOfMapRegisters;
for (i = 0; i < NumberOfPages; i++) {
//
// Make sure the previous entry is physically contiguous with the next
// entry and that a 64K physical boundary is not crossed unless this
// is an Eisa system.
//
if (TranslationEntry != AdapterObject->MapRegisterBase &&
(((TranslationEntry - 1)->PhysicalAddress + PAGE_SIZE) !=
MapBufferPhysicalAddress || (!HalpEisaDma &&
((TranslationEntry - 1)->PhysicalAddress & ~0x0ffff) !=
(MapBufferPhysicalAddress & ~0x0ffff)))) {
//
// An entry needs to be skipped in the table. This entry will
// remain marked as allocated so that no allocation of map
// registers will cross this boundary.
//
TranslationEntry++;
AdapterObject->NumberOfMapRegisters++;
}
//
// Clear the bits where the memory has been allocated.
//
RtlClearBits(
AdapterObject->MapRegisters,
TranslationEntry - (PTRANSLATION_ENTRY)
AdapterObject->MapRegisterBase,
1
);
TranslationEntry->VirtualAddress = MapBufferVirtualAddress;
TranslationEntry->PhysicalAddress = MapBufferPhysicalAddress;
TranslationEntry++;
(PCCHAR) MapBufferVirtualAddress += PAGE_SIZE;
MapBufferPhysicalAddress += PAGE_SIZE;
}
//
// Remember the number of pages that where allocated.
//
AdapterObject->NumberOfMapRegisters += NumberOfPages;
KeReleaseSpinLock( &AdapterObject->SpinLock, Irql );
return(TRUE);
}
PADAPTER_OBJECT
HalpAllocateAdapter(
IN ULONG MapRegistersPerChannel,
IN PVOID AdapterBaseVa,
IN PVOID ChannelNumber
)
/*++
Routine Description:
This routine allocates and initializes an adapter object to represent an
adapter or a DMA controller on the system. If no map registers are required
then a standalone adapter object is allocated with no master adapter.
If map registers are required, then a master adapter object is used to
allocate the map registers. For Isa systems these registers are really
physically contiguous memory pages.
Arguments:
MapRegistersPerChannel - Specifies the number of map registers that each
channel provides for I/O memory mapping.
AdapterBaseVa - Address of the the DMA controller.
ChannelNumber - Unused.
Return Value:
The function value is a pointer to the allocate adapter object.
--*/
{
PADAPTER_OBJECT AdapterObject;
OBJECT_ATTRIBUTES ObjectAttributes;
ULONG Size;
ULONG BitmapSize;
HANDLE Handle;
NTSTATUS Status;
UNREFERENCED_PARAMETER(ChannelNumber);
//
// Initalize the master adapter if necessary.
//
if (MasterAdapterObject == NULL && AdapterBaseVa != (PVOID) -1 &&
MapRegistersPerChannel) {
MasterAdapterObject = HalpAllocateAdapter(
MapRegistersPerChannel,
(PVOID) -1,
NULL
);
//
// If we could not allocate the master adapter then give up.
//
if (MasterAdapterObject == NULL) {
return(NULL);
}
}
//
// Begin by initializing the object attributes structure to be used when
// creating the adapter object.
//
InitializeObjectAttributes( &ObjectAttributes,
NULL,
OBJ_PERMANENT,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL
);
//
// Determine the size of the adapter object. If this is the master object
// then allocate space for the register bit map; otherwise, just allocate
// an adapter object.
//
if (AdapterBaseVa == (PVOID) -1) {
//
// Allocate a bit map large enough MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE
// of map register buffers.
//
BitmapSize = (((sizeof( RTL_BITMAP ) +
(( ((MAXIMUM_MAP_BUFFER_SIZE*9)/8) / PAGE_SIZE ) + 7 >> 3)) + 3) & ~3);
Size = sizeof( ADAPTER_OBJECT ) + BitmapSize;
} else {
Size = sizeof( ADAPTER_OBJECT );
}
//
// Now create the adapter object.
//
Status = ObCreateObject( KernelMode,
*IoAdapterObjectType,
&ObjectAttributes,
KernelMode,
(PVOID) NULL,
Size,
0,
0,
(PVOID *)&AdapterObject );
//
// Reference the object.
//
if (NT_SUCCESS(Status)) {
Status = ObReferenceObjectByPointer(
AdapterObject,
FILE_READ_DATA | FILE_WRITE_DATA,
*IoAdapterObjectType,
KernelMode
);
}
//
// If the adapter object was successfully created, then attempt to insert
// it into the the object table.
//
if (NT_SUCCESS( Status )) {
Status = ObInsertObject( AdapterObject,
NULL,
FILE_READ_DATA | FILE_WRITE_DATA,
0,
(PVOID *) NULL,
&Handle );
if (NT_SUCCESS( Status )) {
NtClose( Handle );
//
// Initialize the adapter object itself.
//
AdapterObject->Type = IO_TYPE_ADAPTER;
AdapterObject->Size = (USHORT) Size;
AdapterObject->MapRegistersPerChannel = 1;
AdapterObject->AdapterBaseVa = AdapterBaseVa;
if (MapRegistersPerChannel) {
AdapterObject->MasterAdapter = MasterAdapterObject;
} else {
AdapterObject->MasterAdapter = NULL;
}
//
// Initialize the channel wait queue for this
// adapter.
//
KeInitializeDeviceQueue( &AdapterObject->ChannelWaitQueue );
//
// If this is the MasterAdatper then initialize the register bit map,
// AdapterQueue and the spin lock.
//
if ( AdapterBaseVa == (PVOID) -1 ) {
KeInitializeSpinLock( &AdapterObject->SpinLock );
InitializeListHead( &AdapterObject->AdapterQueue );
AdapterObject->MapRegisters = (PVOID) ( AdapterObject + 1);
RtlInitializeBitMap( AdapterObject->MapRegisters,
(PULONG) (((PCHAR) (AdapterObject->MapRegisters)) + sizeof( RTL_BITMAP )),
((9 * MAXIMUM_MAP_BUFFER_SIZE) / 8) / PAGE_SIZE
);
//
// Set all the bits in the memory to indicate that memory
// has not been allocated for the map buffers
//
RtlSetAllBits( AdapterObject->MapRegisters );
AdapterObject->NumberOfMapRegisters = 0;
AdapterObject->CommittedMapRegisters = 0;
//
// ALlocate the memory map registers.
//
AdapterObject->MapRegisterBase = ExAllocatePool(
NonPagedPool,
(((9 * MAXIMUM_MAP_BUFFER_SIZE) / 8) / PAGE_SIZE ) *
sizeof(TRANSLATION_ENTRY)
);
if (AdapterObject->MapRegisterBase == NULL) {
ObDereferenceObject( AdapterObject );
AdapterObject = NULL;
return(NULL);
}
//
// Zero the map registers.
//
RtlZeroMemory(
AdapterObject->MapRegisterBase,
(((9 * MAXIMUM_MAP_BUFFER_SIZE) / 8) / PAGE_SIZE ) *
sizeof(TRANSLATION_ENTRY)
);
if (!HalpGrowMapBuffers(AdapterObject, INITIAL_MAP_BUFFER_SMALL_SIZE))
{
//
// If no map registers could be allocated then free the
// object.
//
ObDereferenceObject( AdapterObject );
AdapterObject = NULL;
return(NULL);
}
}
} else {
//
// An error was incurred for some reason. Set the return value
// to NULL.
//
AdapterObject = (PADAPTER_OBJECT) NULL;
}
} else {
AdapterObject = (PADAPTER_OBJECT) NULL;
}
return AdapterObject;
}
VOID
HalpCopyBufferMap(
IN PMDL Mdl,
IN PTRANSLATION_ENTRY TranslationEntry,
IN PVOID CurrentVa,
IN ULONG Length,
IN BOOLEAN WriteToDevice,
IN ULONG noncachedAddress
)
/*++
Routine Description:
This routine copies the specific data between the user's buffer and the
map register buffer. First a the user buffer is mapped if necessary, then
the data is copied. Finally the user buffer will be unmapped if
neccessary.
Arguments:
Mdl - Pointer to the MDL that describes the pages of memory that are
being read or written.
TranslationEntry - 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 - The length of the transfer. This determines the number of map
registers that need to be written to map the transfer.
WriteToDevice - Boolean value that indicates whether this is a write
to the device from memory (TRUE), or vice versa.
Return Value:
None.
--*/
{
PCCHAR bufferAddress;
PCCHAR mapAddress;
//
// Get the system address of the MDL.
//
bufferAddress = MmGetSystemAddressForMdl(Mdl);
//
// Calculate the actual start of the buffer based on the system VA and
// the current VA.
//
bufferAddress += (PCCHAR) CurrentVa - (PCCHAR) MmGetMdlVirtualAddress(Mdl);
mapAddress = (PCCHAR) TranslationEntry->VirtualAddress +
BYTE_OFFSET(CurrentVa);
//
// Copy the data between the user buffer and map buffer
//
if (WriteToDevice) {
RtlMoveMemory( mapAddress, (PCCHAR)noncachedAddress, Length);
} else {
RtlMoveMemory( (PCCHAR)noncachedAddress, mapAddress, Length);
}
}
IO_ALLOCATION_ACTION
HalpAllocationRoutine (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID MapRegisterBase,
IN PVOID Context
)
/*++
Routine Description:
This function is called by HalAllocateAdapterChannel when sufficent resources
are available to the driver. This routine saves the MapRegisterBase,
and set the event pointed to by the context parameter.
Arguments:
DeviceObject - Supplies a pointer where the map register base should be
stored.
Irp - Unused.
MapRegisterBase - Supplied by the Io subsystem for use in IoMapTransfer.
Context - Supplies a pointer to an event which is set to indicate the
AdapterObject has been allocated.
Return Value:
DeallocateObjectKeepRegisters - Indicates the adapter should be freed
and mapregisters should remain allocated after return.
--*/
{
UNREFERENCED_PARAMETER(Irp);
*((PVOID *) DeviceObject) = MapRegisterBase;
(VOID) KeSetEvent( (PKEVENT) Context, 0L, FALSE );
return(DeallocateObjectKeepRegisters);
}
PTRANSLATION_ENTRY
HalpAcquireMapBuffers(
ULONG NumberOfMapRegisters,
PADAPTER_OBJECT MasterAdapter)
{
KIRQL Irql;
ULONG MapRegisterNumber;
PTRANSLATION_ENTRY MapRegisterBase;
KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql );
MapRegisterNumber = (ULONG)-1;
MapRegisterNumber = RtlFindClearBitsAndSet(
MasterAdapter->MapRegisters,
NumberOfMapRegisters,
0
);
if (MapRegisterNumber > MasterAdapter->NumberOfMapRegisters) {
HalpGrowMapBuffers(
MasterAdapterObject,
INCREMENT_MAP_BUFFER_SIZE
);
MapRegisterNumber = RtlFindClearBitsAndSet(
MasterAdapter->MapRegisters,
NumberOfMapRegisters,
0
);
if (MapRegisterNumber > MasterAdapter->NumberOfMapRegisters)
MapRegisterNumber = (ULONG)-1;
}
if (MapRegisterNumber == -1) {
//
// There were not enough free map registers. Queue this request
// on the master adapter where is will wait until some registers
// are deallocated.
//
// InsertTailList( &MasterAdapter->AdapterQueue,
// &AdapterObject->AdapterQueue
// );
// Busy = 1;
MapRegisterBase = NULL;
} else {
//
// Calculate the map register base from the allocated map
// register and base of the master adapter object.
//
MapRegisterBase = ((PTRANSLATION_ENTRY)
MasterAdapter->MapRegisterBase + MapRegisterNumber);
}
KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
return(MapRegisterBase);
}
PVOID
HalAllocateCommonBuffer(
IN PADAPTER_OBJECT AdapterObject,
IN ULONG Length,
OUT PPHYSICAL_ADDRESS LogicalAddress,
IN BOOLEAN CacheEnabled
)
/*++
Routine Description:
This function allocates the memory for a common buffer and maps so that it
can be accessed by a master device and the CPU.
Arguments:
AdapterObject - Supplies a pointer to the adapter object used by this
device.
Length - Supplies the length of the common buffer to be allocated.
LogicalAddress - Returns the logical address of the common buffer.
CacheEnable - Indicates whether the memeory is cached or not.
Return Value:
Returns the virtual address of the common buffer. If the buffer cannot be
allocated then NULL is returned.
--*/
{
PVOID virtualAddress;
PVOID mapRegisterBase;
ULONG numberOfMapRegisters;
ULONG mappedLength;
WAIT_CONTEXT_BLOCK wcb;
KEVENT allocationEvent;
NTSTATUS status;
PMDL mdl;
KIRQL irql;
PTRANSLATION_ENTRY MapRegisterTranslation;
numberOfMapRegisters = BYTES_TO_PAGES(Length);
//
// Allocate the actual buffer.
//
if (CacheEnabled != FALSE) {
virtualAddress = ExAllocatePool(NonPagedPoolCacheAligned, Length);
} else {
MapRegisterTranslation = HalpAcquireMapBuffers(numberOfMapRegisters,MasterAdapterObject);
if (MapRegisterTranslation == NULL) return(NULL);
virtualAddress = MapRegisterTranslation->VirtualAddress;
LogicalAddress->LowPart = MapRegisterTranslation->PhysicalAddress;
LogicalAddress->HighPart = 0;
KeStallExecutionProcessor(50000);
return(virtualAddress);
}
if (virtualAddress == NULL) {
return(virtualAddress);
}
//
// Initialize an event.
//
KeInitializeEvent( &allocationEvent, NotificationEvent, FALSE);
//
// Initialize the wait context block. Use the device object to indicate
// where the map register base should be stored.
//
wcb.DeviceObject = &mapRegisterBase;
wcb.CurrentIrp = NULL;
wcb.DeviceContext = &allocationEvent;
//
// Allocate the adapter and the map registers.
//
KeRaiseIrql(DISPATCH_LEVEL, &irql);
status = HalAllocateAdapterChannel(
AdapterObject,
&wcb,
numberOfMapRegisters,
HalpAllocationRoutine
);
KeLowerIrql(irql);
if (!NT_SUCCESS(status)) {
//
// Cleanup and return NULL.
//
if (CacheEnabled != FALSE) {
ExFreePool(virtualAddress);
} else {
MmFreeNonCachedMemory(virtualAddress, Length);
}
return(NULL);
}
//
// Wait for the map registers to be allocated.
//
status = KeWaitForSingleObject(
&allocationEvent,
Executive,
KernelMode,
FALSE,
NULL
);
if (!NT_SUCCESS(status)) {
//
// Cleanup and return NULL.
//
if (CacheEnabled != FALSE) {
ExFreePool(virtualAddress);
} else {
MmFreeNonCachedMemory(virtualAddress, Length);
}
return(NULL);
}
//
// Create an mdl to use with call to I/O map transfer.
//
mdl = IoAllocateMdl(
virtualAddress,
Length,
FALSE,
FALSE,
NULL
);
MmBuildMdlForNonPagedPool(mdl);
//
// Map the transfer so that the controller can access the memory.
//
mappedLength = Length;
*LogicalAddress = IoMapTransfer(
NULL,
mdl,
mapRegisterBase,
virtualAddress,
&mappedLength,
TRUE
);
IoFreeMdl(mdl);
if (mappedLength < Length) {
//
// Cleanup and indicate that the allocation failed.
//
HalFreeCommonBuffer(
AdapterObject,
Length,
*LogicalAddress,
virtualAddress,
CacheEnabled
);
return(NULL);
}
//
// The allocation completed successfully.
// for some reason, we have to pause if we have the onboard scsi controller AND
// an Adaptec AHA1740 Eisa SCSI controller ...
// trial and error ...
//
KeStallExecutionProcessor(50000);
//
// The allocation completed successfully.
//
return(virtualAddress);
}
BOOLEAN
HalFlushCommonBuffer(
IN PADAPTER_OBJECT AdapterObject,
IN ULONG Length,
IN PHYSICAL_ADDRESS LogicalAddress,
IN PVOID VirtualAddress
)
/*++
Routine Description:
This function is called to flush any hardware adapter buffers when the
driver needs to read data written by an I/O master device to a common
buffer.
Arguments:
AdapterObject - Supplies a pointer to the adapter object used by this
device.
Length - Supplies the length of the common buffer. This should be the same
value used for the allocation of the buffer.
LogicalAddress - Supplies the logical address of the common buffer. This
must be the same value return by HalAllocateCommonBuffer.
VirtualAddress - Supplies the virtual address of the common buffer. This
must be the same value return by HalAllocateCommonBuffer.
Return Value:
Returns TRUE if no errors were detected; otherwise, FALSE is return.
--*/
{
return(TRUE);
}
VOID
HalFreeCommonBuffer(
IN PADAPTER_OBJECT AdapterObject,
IN ULONG Length,
IN PHYSICAL_ADDRESS LogicalAddress,
IN PVOID VirtualAddress,
IN BOOLEAN CacheEnabled
)
/*++
Routine Description:
This function frees a common buffer and all of the resouces it uses.
Arguments:
AdapterObject - Supplies a pointer to the adapter object used by this
device.
Length - Supplies the length of the common buffer. This should be the same
value used for the allocation of the buffer.
LogicalAddress - Supplies the logical address of the common buffer. This
must be the same value return by HalAllocateCommonBuffer.
VirtualAddress - Supplies the virtual address of the common buffer. This
must be the same value return by HalAllocateCommonBuffer.
CacheEnable - Indicates whether the memeory is cached or not.
Return Value:
None
--*/
{
PTRANSLATION_ENTRY mapRegisterBase,resultat;
ULONG numberOfMapRegisters;
ULONG i;
//
// Free the memory for the common buffer.
//
if (CacheEnabled != FALSE) {
ExFreePool(VirtualAddress);
} else {
// MmFreeNonCachedMemory(VirtualAddress, Length);
// if(AdapterObject->NeedsMapRegisters == FALSE) return;
// }
}
//
// Calculate the number of map registers, the map register number and
// the map register base.
//
numberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, Length);
// mapRegisterNumber = LogicalAddress.LowPart >> PAGE_SHIFT;
mapRegisterBase = (PTRANSLATION_ENTRY) MasterAdapterObject->MapRegisterBase;
resultat = NULL;
for (i = 0; i < MasterAdapterObject->NumberOfMapRegisters; i++) {
if (mapRegisterBase->VirtualAddress == VirtualAddress) {
resultat = mapRegisterBase;
break;
}
mapRegisterBase++;
}
//
// Free the map registers.
//
IoFreeMapRegisters(
AdapterObject,
(PVOID) resultat,
numberOfMapRegisters
);
return;
}
#ifdef NEVER
PVOID
HalAllocateCommonBuffer(
IN PADAPTER_OBJECT AdapterObject,
IN ULONG Length,
OUT PPHYSICAL_ADDRESS LogicalAddress,
IN BOOLEAN CacheEnabled
)
/*++
Routine Description:
This function allocates the memory for a common buffer and maps so that it
can be accessed by a master device and the CPU.
Arguments:
AdapterObject - Supplies a pointer to the adapter object used by this
device.
Length - Supplies the length of the common buffer to be allocated.
LogicalAddress - Returns the logical address of the common buffer.
CacheEnable - Indicates whether the memory is cached or not.
Return Value:
Returns the virtual address of the common buffer. If the buffer cannot be
allocated then NULL is returned.
--*/
{
PVOID virtualAddress;
PHYSICAL_ADDRESS physicalAddress;
UNREFERENCED_PARAMETER(AdapterObject);
UNREFERENCED_PARAMETER(CacheEnabled);
// Because we support ISA devices, and they cannot reference
// past 16MB of memory, we must make sure that the contiguous
// memory we allocate is below 16Mb.
physicalAddress.LowPart = MAXIMUM_PHYSICAL_ADDRESS -1;
physicalAddress.HighPart = 0;
//
// Allocate the actual buffer.
//
virtualAddress = MmAllocateContiguousMemory(
Length,
physicalAddress
);
DbgPrint("MmAllocateContiguousMemory returns 0x%x ... \n", virtualAddress);
if (!HALP_IS_PHYSICAL_ADDRESS(virtualAddress)) {
*LogicalAddress = MmGetPhysicalAddress(virtualAddress);
} else {
*LogicalAddress = RtlConvertUlongToLargeInteger(
(ULONG)virtualAddress &
(~KSEG0_BASE)
);
}
return((PVOID)((ULONG)virtualAddress | KSEG1_BASE));
}
BOOLEAN
HalFlushCommonBuffer(
IN PADAPTER_OBJECT AdapterObject,
IN ULONG Length,
IN PHYSICAL_ADDRESS LogicalAddress,
IN PVOID VirtualAddress
)
/*++
Routine Description:
This function is called to flush any hardware adapter buffers when the
driver needs to read data written by an I/O master device to a common
buffer.
Arguments:
AdapterObject - Supplies a pointer to the adapter object used by this
device.
Length - Supplies the length of the common buffer. This should be the same
value used for the allocation of the buffer.
LogicalAddress - Supplies the logical address of the common buffer. This
must be the same value return by HalAllocateCommonBuffer.
VirtualAddress - Supplies the virtual address of the common buffer. This
must be the same value return by HalAllocateCommonBuffer.
Return Value:
Returns TRUE if no errors were detected; otherwise, FALSE is return.
--*/
{
UNREFERENCED_PARAMETER(AdapterObject);
UNREFERENCED_PARAMETER(Length);
UNREFERENCED_PARAMETER(LogicalAddress);
UNREFERENCED_PARAMETER(VirtualAddress);
return(TRUE);
}
VOID
HalFreeCommonBuffer(
IN PADAPTER_OBJECT AdapterObject,
IN ULONG Length,
IN PHYSICAL_ADDRESS LogicalAddress,
IN PVOID VirtualAddress,
IN BOOLEAN CacheEnabled
)
/*++
Routine Description:
This function frees a common buffer and all of the resouces it uses.
Arguments:
AdapterObject - Supplies a pointer to the adapter object used by this
device.
Length - Supplies the length of the common buffer. This should be the same
value used for the allocation of the buffer.
LogicalAddress - Supplies the logical address of the common buffer. This
must be the same value return by HalAllocateCommonBuffer.
VirtualAddress - Supplies the virtual address of the common buffer. This
must be the same value return by HalAllocateCommonBuffer.
CacheEnable - Indicates whether the memeory is cached or not.
Return Value:
None
--*/
{
UNREFERENCED_PARAMETER(AdapterObject);
UNREFERENCED_PARAMETER(Length);
UNREFERENCED_PARAMETER(LogicalAddress);
UNREFERENCED_PARAMETER(CacheEnabled);
MmFreeContiguousMemory((PVOID)(((ULONG)VirtualAddress & (~KSEG1_BASE)) | KSEG0_BASE));
}
#endif
PVOID
HalAllocateCrashDumpRegisters(
IN PADAPTER_OBJECT AdapterObject,
IN PULONG NumberOfMapRegisters
)
/*++
Routine Description:
This routine is called during the crash dump disk driver's initialization
to allocate a number map registers permanently.
Arguments:
AdapterObject - Pointer to the adapter control object to allocate to the
driver.
NumberOfMapRegisters - Number of map registers requested and update to show
number actually allocated.
Return Value:
Returns STATUS_SUCESS if map registers allocated.
--*/
{
PADAPTER_OBJECT MasterAdapter;
ULONG MapRegisterNumber;
//
// Begin by obtaining a pointer to the master adapter associated with this
// request.
//
MasterAdapter = AdapterObject->MasterAdapter;
//
// Check to see whether this driver needs to allocate any map registers.
//
if (AdapterObject->NeedsMapRegisters) {
//
// Ensure that this adapter has enough total map registers to satisfy
// the request.
//
if (*NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) {
AdapterObject->NumberOfMapRegisters = 0;
return NULL;
}
//
// Attempt to allocate the required number of map registers w/o
// affecting those registers that were allocated when the system
// crashed.
//
MapRegisterNumber = (ULONG)-1;
MapRegisterNumber = RtlFindClearBitsAndSet(
MasterAdapter->MapRegisters,
*NumberOfMapRegisters,
0
);
if (MapRegisterNumber == (ULONG)-1) {
//
// Not enough free map registers were found, so they were busy
// being used by the system when it crashed. Force the appropriate
// number to be "allocated" at the base by simply overjamming the
// bits and return the base map register as the start.
//
RtlSetBits(
MasterAdapter->MapRegisters,
0,
*NumberOfMapRegisters
);
MapRegisterNumber = 0;
}
//
// Calculate the map register base from the allocated map
// register and base of the master adapter object.
//
AdapterObject->MapRegisterBase = ((PTRANSLATION_ENTRY)
MasterAdapter->MapRegisterBase + MapRegisterNumber);
//
// Set the no scatter/gather flag if scatter/gather not
// supported.
//
if (!AdapterObject->ScatterGather) {
AdapterObject->MapRegisterBase = (PVOID)
((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER);
}
} else {
AdapterObject->MapRegisterBase = NULL;
AdapterObject->NumberOfMapRegisters = 0;
}
return AdapterObject->MapRegisterBase;
}
VOID
IoFreeAdapterChannel(
IN PADAPTER_OBJECT AdapterObject
)
/*++
Routine Description:
This routine is invoked to deallocate the specified adapter object.
Any map registers that were allocated are also automatically deallocated.
No checks are made to ensure that the adapter is really allocated to
a device object. However, if it is not, then kernel will bugcheck.
If another device is waiting in the queue to allocate the adapter object
it will be pulled from the queue and its execution routine will be
invoked.
Arguments:
AdapterObject - Pointer to the adapter object to be deallocated.
Return Value:
None.
--*/
{
PKDEVICE_QUEUE_ENTRY Packet;
PWAIT_CONTEXT_BLOCK Wcb;
PADAPTER_OBJECT MasterAdapter;
BOOLEAN Busy = FALSE;
IO_ALLOCATION_ACTION Action;
KIRQL Irql;
LONG MapRegisterNumber;
//
// Begin by getting the address of the master adapter.
//
MasterAdapter = AdapterObject->MasterAdapter;
//
// Pull requests of the adapter's device wait queue as long as the
// adapter is free and there are sufficient map registers available.
//
while( TRUE ) {
//
// Begin by checking to see whether there are any map registers that
// need to be deallocated. If so, then deallocate them now.
//
if (AdapterObject->NumberOfMapRegisters != 0) {
IoFreeMapRegisters( AdapterObject,
AdapterObject->MapRegisterBase,
AdapterObject->NumberOfMapRegisters
);
}
//
// Simply remove the next entry from the adapter's device wait queue.
// If one was successfully removed, allocate any map registers that it
// requires and invoke its execution routine.
//
Packet = KeRemoveDeviceQueue( &AdapterObject->ChannelWaitQueue );
if (Packet == NULL) {
//
// There are no more requests break out of the loop.
//
break;
}
Wcb = CONTAINING_RECORD( Packet,
WAIT_CONTEXT_BLOCK,
WaitQueueEntry );
AdapterObject->CurrentWcb = Wcb;
AdapterObject->NumberOfMapRegisters = Wcb->NumberOfMapRegisters;
//
// Check to see whether this driver wishes to allocate any map
// registers. If so, then queue the device object to the master
// adapter queue to wait for them to become available. If the driver
// wants map registers, ensure that this adapter has enough total
// map registers to satisfy the request.
//
if (Wcb->NumberOfMapRegisters != 0 &&
AdapterObject->MasterAdapter != NULL) {
//
// Lock the map register bit map and the adapter queue in the
// master adapter object. The channel structure offset is used as
// a hint for the register search.
//
KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql );
MapRegisterNumber = -1;
if (IsListEmpty( &MasterAdapter->AdapterQueue)) {
MapRegisterNumber = RtlFindClearBitsAndSet(
MasterAdapter->MapRegisters,
Wcb->NumberOfMapRegisters,
0);
}
if (MapRegisterNumber == -1) {
//
// There were not enough free map registers. Queue this request
// on the master adapter where is will wait until some registers
// are deallocated.
//
InsertTailList( &MasterAdapter->AdapterQueue,
&AdapterObject->AdapterQueue
);
Busy = 1;
} else {
AdapterObject->MapRegisterBase = (PVOID)((PTRANSLATION_ENTRY)
MasterAdapter->MapRegisterBase + MapRegisterNumber);
//
// Set the no scatter/gather flag if scatter/gather not
// supported.
//
if (!AdapterObject->ScatterGather) {
AdapterObject->MapRegisterBase = (PVOID)
((ULONG)AdapterObject->MapRegisterBase |NO_SCATTER_GATHER);
}
}
KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
} else {
AdapterObject->MapRegisterBase = NULL;
AdapterObject->NumberOfMapRegisters = 0;
}
//
// If there were either enough map registers available or no map
// registers needed to be allocated, invoke the driver's execution
// routine now.
//
if (!Busy) {
AdapterObject->CurrentWcb = Wcb;
Action = Wcb->DeviceRoutine( Wcb->DeviceObject,
Wcb->CurrentIrp,
AdapterObject->MapRegisterBase,
Wcb->DeviceContext );
//
// If the execution routine would like to have the adapter
// deallocated, then release the adapter object.
//
if (Action == KeepObject) {
//
// This request wants to keep the channel a while so break
// out of the loop.
//
break;
}
//
// If the driver wants to keep the map registers then set the
// number allocated to 0. This keeps the deallocation routine
// from deallocating them.
//
if (Action == DeallocateObjectKeepRegisters) {
AdapterObject->NumberOfMapRegisters = 0;
}
} else {
//
// This request did not get the requested number of map registers so
// out of the loop.
//
break;
}
}
}
VOID
IoFreeMapRegisters(
PADAPTER_OBJECT AdapterObject,
PVOID MapRegisterBase,
ULONG NumberOfMapRegisters
)
/*++
Routine Description:
This routine deallocates the map registers for the adapter. If there are
any queued adapter waiting for an attempt is made to allocate the next
entry.
Arguments:
AdapterObject - The adapter object to where the map register should be
returned.
MapRegisterBase - The map register base of the registers to be deallocated.
NumberOfMapRegisters - The number of registers to be deallocated.
Return Value:
None
--+*/
{
PADAPTER_OBJECT MasterAdapter;
LONG MapRegisterNumber;
PWAIT_CONTEXT_BLOCK Wcb;
PLIST_ENTRY Packet;
IO_ALLOCATION_ACTION Action;
KIRQL Irql;
//
// Begin by getting the address of the master adapter.
//
if (AdapterObject->MasterAdapter != NULL && MapRegisterBase != NULL) {
MasterAdapter = AdapterObject->MasterAdapter;
} else {
//
// There are no map registers to return.
//
return;
}
//
// Strip no scatter/gather flag.
//
MapRegisterBase = (PVOID) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER);
MapRegisterNumber = (PTRANSLATION_ENTRY) MapRegisterBase -
(PTRANSLATION_ENTRY) MasterAdapter->MapRegisterBase;
//
// Acquire the master adapter spinlock which locks the adapter queue and the
// bit map for the map registers.
//
KeAcquireSpinLock(&MasterAdapter->SpinLock, &Irql);
//
// Return the registers to the bit map.
//
RtlClearBits( MasterAdapter->MapRegisters,
MapRegisterNumber,
NumberOfMapRegisters
);
//
// Process any requests waiting for map registers in the adapter queue.
// Requests are processed until a request cannot be satisfied or until
// there are no more requests in the queue.
//
while(TRUE) {
if ( IsListEmpty(&MasterAdapter->AdapterQueue) ){
break;
}
Packet = RemoveHeadList( &MasterAdapter->AdapterQueue );
AdapterObject = CONTAINING_RECORD( Packet,
ADAPTER_OBJECT,
AdapterQueue
);
Wcb = AdapterObject->CurrentWcb;
//
// Attempt to allocate map registers for this request. Use the previous
// register base as a hint.
//
MapRegisterNumber = RtlFindClearBitsAndSet( MasterAdapter->MapRegisters,
AdapterObject->NumberOfMapRegisters,
MasterAdapter->NumberOfMapRegisters
);
if (MapRegisterNumber == -1) {
//
// There were not enough free map registers. Put this request back on
// the adapter queue where is came from.
//
InsertHeadList( &MasterAdapter->AdapterQueue,
&AdapterObject->AdapterQueue
);
break;
}
KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
AdapterObject->MapRegisterBase = (PVOID) ((PTRANSLATION_ENTRY)
MasterAdapter->MapRegisterBase + MapRegisterNumber);
//
// Set the no scatter/gather flag if scatter/gather not
// supported.
//
if (!AdapterObject->ScatterGather) {
AdapterObject->MapRegisterBase = (PVOID)
((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER);
}
//
// Invoke the driver's execution routine now.
//
Action = Wcb->DeviceRoutine( Wcb->DeviceObject,
Wcb->CurrentIrp,
AdapterObject->MapRegisterBase,
Wcb->DeviceContext );
//
// If the driver wishes to keep the map registers then set the number
// allocated to zero and set the action to deallocate object.
//
if (Action == DeallocateObjectKeepRegisters) {
AdapterObject->NumberOfMapRegisters = 0;
Action = DeallocateObject;
}
//
// If the driver would like to have the adapter deallocated,
// then deallocate any map registers allocated and then release
// the adapter object.
//
if (Action == DeallocateObject) {
//
// The map registers registers are deallocated here rather than in
// IoFreeAdapterChannel. This limits the number of times
// this routine can be called recursively possibly overflowing
// the stack. The worst case occurs if there is a pending
// request for the adapter that uses map registers and whos
// excution routine decallocates the adapter. In that case if
// there are no requests in the master adapter queue, then
// IoFreeMapRegisters will get called again.
//
if (AdapterObject->NumberOfMapRegisters != 0) {
//
// Deallocate the map registers and clear the count so that
// IoFreeAdapterChannel will not deallocate them again.
//
KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql );
RtlClearBits( MasterAdapter->MapRegisters,
MapRegisterNumber,
AdapterObject->NumberOfMapRegisters
);
AdapterObject->NumberOfMapRegisters = 0;
KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
}
IoFreeAdapterChannel( AdapterObject );
}
KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql );
}
KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
}
BOOLEAN
HalTranslateBusAddress(
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN PHYSICAL_ADDRESS BusAddress,
IN OUT PULONG AddressSpace,
OUT PPHYSICAL_ADDRESS TranslatedAddress
)
/*++
Routine Description:
This function returns the system physical address for a specified I/O bus
address. The return value is suitable for use in a subsequent call to
MmMapIoSpace.
Arguments:
InterfaceType - Supplies the type of bus which the address is for.
BusNumber - Supplies the bus number for the device.
BusAddress - Supplies the bus relative address.
AddressSpace - Supplies the address space number for the device: 0 for
memory and 1 for I/O space. Returns the address space on this system.
TranslatedAddress - Supplies a pointer to return the translated address
Return Value:
A return value of TRUE indicates that a system physical address
corresponding to the supplied bus relative address and bus address
number has been returned in TranslatedAddress.
A return value of FALSE occurs if the translation for the address was
not possible
--*/
{
//
// SNI only has one I/O bus which is an EISA, so the bus number is unused.
//
UNREFERENCED_PARAMETER( BusNumber );
TranslatedAddress->HighPart = 0;
//
// If this is for the internal bus then just return the passed parameter.
//
if (InterfaceType == Internal) {
//
// There is no difference between IoSpace and MemorySpace in the internal Interface.
// Mips Processors have only memory mapped I/O
//
*AddressSpace = 0;
//
// Return the passed parameters.
//
TranslatedAddress->LowPart = BusAddress.LowPart;
return(TRUE);
}
if (InterfaceType != Isa && InterfaceType != Eisa) {
DebugPrint(("HAL: HalTranslateBusAddress: WRONG INTERFACE (%d) ", InterfaceType));
//
// Not on this system -- return nothing.
//
*AddressSpace = 0;
TranslatedAddress->LowPart = 0;
return(FALSE);
}
//
// Determine the address based on whether the bus address is in I/O space
// or bus memory space.
//
if (*AddressSpace) {
//
// The address is in I/O space.
// we always direct Isa and Eisa Adresses to the extension board
//
*AddressSpace = 0;
TranslatedAddress->LowPart = BusAddress.LowPart +
EISA_CONTROL_PHYSICAL_BASE;
if (TranslatedAddress->LowPart < BusAddress.LowPart) {
//
// A carry occurred.
//
TranslatedAddress->HighPart = 1;
}
return(TRUE);
} else {
//
// The address is in memory space.
// we always direct Isa and Eisa Adresses to the extension board
//
*AddressSpace = 0;
TranslatedAddress->LowPart = BusAddress.LowPart +
EISA_MEMORY_PHYSICAL_BASE;
if (TranslatedAddress->LowPart < BusAddress.LowPart) {
//
// A carry occurred.
//
TranslatedAddress->HighPart = 1;
}
return(TRUE);
}
DebugPrint(("HAL: HalTranslateBusAddress: Beeing in the very bad tree\n"));
TranslatedAddress->LowPart = BusAddress.LowPart;
TranslatedAddress->HighPart = 0;
return(FALSE);
}
ULONG
HalGetBusDataByOffset(
IN BUS_DATA_TYPE BusDataType,
IN ULONG BusNumber,
IN ULONG SlotNumber,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
)
/*++
Routine Description:
The function returns the bus data for a slot or address.
Arguments:
BusDataType - Supplies the type of bus.
BusNumber - Indicates which bus.
Buffer - Supplies the space to store the data.
Offset - Offset in the BusData buffer
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 = 0;
switch (BusDataType) {
case EisaConfiguration:
DataLength = HalpReadEisaData(BusNumber, SlotNumber, Buffer, Offset, Length);
break;
}
return(DataLength);
}
ULONG
HalGetBusData(
IN BUS_DATA_TYPE BusDataType,
IN ULONG BusNumber,
IN ULONG SlotNumber,
IN PVOID Buffer,
IN ULONG Length
)
/*++
Routine Description:
Subset of HalGetBusDataByOffset, just pass the request along.
--*/
{
return HalGetBusDataByOffset (
BusDataType,
BusNumber,
SlotNumber,
Buffer,
0,
Length
);
}
ULONG
HalSetBusDataByOffset(
IN BUS_DATA_TYPE BusDataType,
IN ULONG BusNumber,
IN ULONG SlotNumber,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
)
/*++
Routine Description:
The function sets the bus data for a slot or address.
Arguments:
BusDataType - Supplies the type of bus.
BusNumber - Indicates which bus.
Buffer - Supplies the space to store the data.
Offset - Offset in the BusData buffer
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 = 0;
return(DataLength);
}
ULONG
HalSetBusData(
IN BUS_DATA_TYPE BusDataType,
IN ULONG BusNumber,
IN ULONG SlotNumber,
IN PVOID Buffer,
IN ULONG Length
)
/*++
Routine Description:
Subset of HalGetBusDataByOffset, just pass the request along.
--*/
{
return HalSetBusDataByOffset(
BusDataType,
BusNumber,
SlotNumber,
Buffer,
0,
Length
);
}
NTSTATUS
HalAssignSlotResources (
IN PUNICODE_STRING RegistryPath,
IN PUNICODE_STRING DriverClassName OPTIONAL,
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
IN INTERFACE_TYPE BusType,
IN ULONG BusNumber,
IN ULONG SlotNumber,
IN OUT PCM_RESOURCE_LIST *AllocatedResources
)
/*++
Routine Description:
Reads the targeted device to determine it's required resources.
Calls IoAssignResources to allocate them.
Sets the targeted device with it's assigned resoruces
and returns the assignments to the caller.
Arguments:
RegistryPath - Passed to IoAssignResources.
A device specific registry path in the current-control-set, used
to check for pre-assigned settings and to track various resource
assignment information for this device.
DriverClassName Used to report the assigned resources for the driver/device
DriverObject - Used to report the assigned resources for the driver/device
DeviceObject - Used to report the assigned resources for the driver/device
(ie, IoReportResoruceUsage)
BusType
BusNumber
SlotNumber - Together BusType,BusNumber,SlotNumber uniquely
indentify the device to be queried & set.
Return Value:
STATUS_SUCCESS or error
--*/
{
//
// This HAL doesn't support any buses which support
// HalAssignSlotResources
//
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
HalAdjustResourceList (
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
// IN OUT PVOID Argument0
)
/*++
Routine Description:
Takes the pResourceList and limits any requested resource to
it's corrisponding bus requirements.
Arguments:
pResourceList - The resource list to adjust.
Return Value:
STATUS_SUCCESS or error
--*/
{
//
// BUGBUG: This function should verify that the resoruces fit
// the bus requirements - for now we will assume that the bus
// can support anything the device may ask for.
//
return STATUS_SUCCESS;
}
ULONG
HalpReadEisaData (
IN ULONG BusNumber,
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:
BusDataType - Supplies the type of bus.
BusNumber - Indicates which bus.
Buffer - Supplies the space to store the data.
Length - Supplies a count in bytes of the maximum amount to return.
Return Value:
Returns the amount of data stored into the buffer.
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
OBJECT_ATTRIBUTES BusObjectAttributes;
PWSTR EisaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\EisaAdapter";
PWSTR ConfigData = L"Configuration Data";
ANSI_STRING TmpString;
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;
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)) {
KdPrint(("HAL: Open Status = %x\n",NtStatus));
return(0);
}
//
// Init bus number path
//
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)) {
KdPrint(("HAL: Opening Bus Number: Status = %x\n",NtStatus));
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.
//
NtStatus = ZwQueryValueKey(
BusHandle,
&ConfigDataName,
KeyValueFullInformation,
ValueInformation,
0,
&BytesNeeded
);
KeyValueBuffer = ExAllocatePool(
NonPagedPool,
BytesNeeded
);
if (KeyValueBuffer == NULL) {
KdPrint(("HAL: Cannot allocate Key Value Buffer\n"));
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) {
KdPrint(("HAL: Query Config Data: Status = %x\n",NtStatus));
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:
KdPrint(("Bad Data in registry!\n"));
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;
}