summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halfxs/mips/jxhwsup.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nthals/halfxs/mips/jxhwsup.c')
-rw-r--r--private/ntos/nthals/halfxs/mips/jxhwsup.c2927
1 files changed, 2927 insertions, 0 deletions
diff --git a/private/ntos/nthals/halfxs/mips/jxhwsup.c b/private/ntos/nthals/halfxs/mips/jxhwsup.c
new file mode 100644
index 000000000..c53367cf7
--- /dev/null
+++ b/private/ntos/nthals/halfxs/mips/jxhwsup.c
@@ -0,0 +1,2927 @@
+/*++
+
+Copyright (c) 1990-1993 Microsoft Corporation
+
+Module Name:
+
+ jxhwsup.c
+
+Abstract:
+
+ This module contains the HalpXxx routines for the NT I/O system that
+ are hardware dependent. Were these routines not hardware dependent,
+ they would normally reside in the internal.c module.
+
+Author:
+
+ Jeff Havens (jhavens) 14-Feb-1990
+
+Environment:
+
+ Kernel mode, local to I/O system
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#include "bugcodes.h"
+#include "eisa.h"
+
+//
+// Put all code for HAL initialization in the INIT section. It will be
+// deallocated by memory management when phase 1 initialization is
+// completed.
+//
+
+#if defined(ALLOC_PRAGMA)
+
+#pragma alloc_text(INIT, HalpCreateDmaStructures)
+
+#endif
+
+extern POBJECT_TYPE IoAdapterObjectType;
+
+
+
+//
+// The DMA controller has a larger number of map registers which may be used
+// by any adapter channel. 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.
+//
+
+PADAPTER_OBJECT MasterAdapterObject;
+
+//
+// The following is the interrupt object used for DMA controller interrupts.
+// DMA controller interrupts occur when a memory parity error occurs or a
+// programming error occurs to the DMA controller.
+//
+
+KINTERRUPT HalpDmaChannelInterrupt;
+
+UCHAR DmaChannelMsg[] = "\nHAL: DMA channel x interrupted. ";
+
+//
+// Pointer to phyiscal memory for map registers.
+//
+
+ULONG HalpMapRegisterPhysicalBase;
+
+//
+// The following function is called when a DMA channel interrupt occurs.
+//
+
+BOOLEAN
+HalpDmaChannel(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ );
+
+//
+// The following is an array of adapter object structures for the internal DMA
+// channels.
+//
+
+PADAPTER_OBJECT HalpInternalAdapters[8];
+
+IO_ALLOCATION_ACTION
+HalpAllocationRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+ULONG
+HalpReadEisaData (
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+NTSTATUS
+HalAllocateAdapterChannel(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PWAIT_CONTEXT_BLOCK Wcb,
+ IN ULONG NumberOfMapRegisters,
+ IN PDRIVER_CONTROL ExecutionRoutine
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates the adapter channel specified by the adapter object.
+ This is accomplished by placing the device object of the driver that wants
+ to allocate the adapter on the adapter's queue. If the queue is already
+ "busy", then the adapter has already been allocated, so the device object
+ is simply placed onto the queue and waits until the adapter becomes free.
+
+ Once the adapter becomes free (or if it already is), then the driver's
+ execution routine is invoked.
+
+ Also, a number of map registers may be allocated to the driver by specifying
+ a non-zero value for NumberOfMapRegisters. Then the map register must be
+ allocated from the master adapter. Once there are a sufficient number of
+ map registers available, then the execution routine is called and the
+ base address of the allocated map registers in the adapter is also passed
+ to the driver's execution routine.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter control object to allocate to the
+ driver.
+
+ Wcb - Supplies a wait context block for saving the allocation parameters.
+ The DeviceObject, CurrentIrp and DeviceContext should be initalized.
+
+ NumberOfMapRegisters - The number of map registers that are to be allocated
+ from the channel, if any.
+
+ ExecutionRoutine - The address of the driver's execution routine that is
+ invoked once the adapter channel (and possibly map registers) have been
+ allocated.
+
+Return Value:
+
+ Returns STATUS_SUCESS unless too many map registers are requested.
+
+Notes:
+
+ Note that this routine MUST be invoked at DISPATCH_LEVEL or above.
+
+--*/
+
+{
+ PADAPTER_OBJECT MasterAdapter;
+ BOOLEAN Busy = FALSE;
+ IO_ALLOCATION_ACTION Action;
+ LONG MapRegisterNumber;
+ KIRQL Irql;
+ ULONG Hint;
+
+ //
+ // Begin by obtaining a pointer to the master adapter associated with this
+ // request.
+ //
+
+ if (AdapterObject->MasterAdapter != NULL) {
+ MasterAdapter = AdapterObject->MasterAdapter;
+ } else {
+ MasterAdapter = AdapterObject;
+ }
+
+ //
+ // Initialize the device object's wait context block in case this device
+ // must wait before being able to allocate the adapter.
+ //
+
+ Wcb->DeviceRoutine = ExecutionRoutine;
+ Wcb->NumberOfMapRegisters = NumberOfMapRegisters;
+
+ //
+ // Allocate the adapter object for this particular device. If the
+ // adapter cannot be allocated because it has already been allocated
+ // to another device, then return to the caller now; otherwise,
+ // continue.
+ //
+
+ if (!KeInsertDeviceQueue( &AdapterObject->ChannelWaitQueue,
+ &Wcb->WaitQueueEntry )) {
+
+ //
+ // The adapter was not busy so it has been allocated. Now 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.
+ //
+
+ AdapterObject->CurrentWcb = Wcb;
+ AdapterObject->NumberOfMapRegisters = Wcb->NumberOfMapRegisters;
+
+ if (NumberOfMapRegisters != 0) {
+ if (NumberOfMapRegisters > MasterAdapter->MapRegistersPerChannel) {
+ AdapterObject->NumberOfMapRegisters = 0;
+ IoFreeAdapterChannel(AdapterObject);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ //
+ // 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)) {
+
+ Hint = AdapterObject->PagePort ? (0x100000 / PAGE_SIZE) : 0;
+
+ MapRegisterNumber = RtlFindClearBitsAndSet(
+ MasterAdapter->MapRegisters,
+ NumberOfMapRegisters,
+ Hint
+ );
+
+ //
+ // Make sure this map register is valid for this adapter.
+ //
+
+ if ((ULONG) MapRegisterNumber < Hint) {
+
+ //
+ // Make it look like there are no map registers.
+ //
+
+ RtlClearBits(
+ MasterAdapter->MapRegisters,
+ MapRegisterNumber,
+ NumberOfMapRegisters
+ );
+
+ MapRegisterNumber = -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;
+
+ } else {
+ AdapterObject->MapRegisterBase = (PVOID) ((PTRANSLATION_ENTRY) MasterAdapter->MapRegisterBase + MapRegisterNumber);
+ }
+
+ KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
+ }
+
+ //
+ // 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) {
+
+ Action = ExecutionRoutine( 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) {
+ IoFreeAdapterChannel( AdapterObject );
+ }
+ }
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+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;
+
+ numberOfMapRegisters = BYTES_TO_PAGES(Length);
+
+ //
+ // Allocate the actual buffer.
+ //
+
+ if (CacheEnabled != FALSE) {
+ virtualAddress = ExAllocatePool(NonPagedPoolCacheAligned, Length);
+
+ } else {
+ virtualAddress = MmAllocateNonCachedMemory(Length);
+ }
+
+
+ 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.
+ //
+
+ return(virtualAddress);
+
+}
+
+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;
+ ULONG Hint;
+
+ //
+ // Begin by obtaining a pointer to the master adapter associated with this
+ // request.
+ //
+
+ if (AdapterObject->MasterAdapter) {
+ MasterAdapter = AdapterObject->MasterAdapter;
+ } else {
+ MasterAdapter = AdapterObject;
+ }
+
+ //
+ // 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. Note that once again the map registers to be allocated
+ // must be above the 1MB range if this is an EISA bus device.
+ //
+
+ MapRegisterNumber = (ULONG)-1;
+
+ Hint = AdapterObject->PagePort ? (0x100000 / PAGE_SIZE) : 0;
+
+ MapRegisterNumber = RtlFindClearBitsAndSet(
+ MasterAdapter->MapRegisters,
+ *NumberOfMapRegisters,
+ Hint
+ );
+
+ //
+ // Ensure that any allocated map registers are valid for this adapter.
+ //
+
+ if ((ULONG) MapRegisterNumber < Hint) {
+
+ //
+ // Make it appear as if there are no map registers.
+ //
+
+ RtlClearBits(
+ MasterAdapter->MapRegisters,
+ MapRegisterNumber,
+ *NumberOfMapRegisters
+ );
+
+ MapRegisterNumber = (ULONG) -1;
+ }
+
+ 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,
+ Hint,
+ *NumberOfMapRegisters
+ );
+ MapRegisterNumber = Hint;
+
+ }
+
+ //
+ // Calculate the map register base from the allocated map
+ // register and base of the master adapter object.
+ //
+
+ AdapterObject->MapRegisterBase = (PVOID) ((PTRANSLATION_ENTRY) MasterAdapter->MapRegisterBase + MapRegisterNumber);
+
+ return AdapterObject->MapRegisterBase;
+}
+
+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;
+ ULONG numberOfMapRegisters;
+ ULONG mapRegisterNumber;
+
+ //
+ // 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
+ + mapRegisterNumber;
+
+ //
+ // Free the map registers.
+ //
+
+ IoFreeMapRegisters(
+ AdapterObject,
+ (PVOID) mapRegisterBase,
+ numberOfMapRegisters
+ );
+
+ //
+ // Free the memory for the common buffer.
+ //
+
+ if (CacheEnabled != FALSE) {
+ ExFreePool(VirtualAddress);
+
+ } else {
+ MmFreeNonCachedMemory(VirtualAddress, Length);
+ }
+
+ return;
+
+}
+
+PADAPTER_OBJECT
+HalGetAdapter(
+ IN PDEVICE_DESCRIPTION DeviceDescription,
+ IN OUT PULONG NumberOfMapRegisters
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the appropriate adapter object for the device defined
+ in the device description structure. Three bus types are supported for the
+ system: Internal, Isa, and Eisa.
+
+Arguments:
+
+ DeviceDescription - Supplies a description of the deivce.
+
+ 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;
+
+ //
+ // Make sure this is the correct version.
+ //
+
+ if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION1) {
+
+ return(NULL);
+
+ }
+
+ //
+ // Return number of map registers requested based on the maximum
+ // transfer length.
+ //
+
+ *NumberOfMapRegisters = BYTES_TO_PAGES(DeviceDescription->MaximumLength) + 1;
+
+ if (*NumberOfMapRegisters > DMA_REQUEST_LIMIT) {
+ *NumberOfMapRegisters = DMA_REQUEST_LIMIT;
+ }
+
+ if (DeviceDescription->InterfaceType == Internal) {
+
+
+ //
+ // Return the adapter pointer for internal adapters.
+ //
+ // If this is a master controler such as the SONIC then return the
+ // last channel.
+ //
+
+ if (DeviceDescription->Master) {
+
+ //
+ // Create an adapter if necessary.
+ //
+
+ if (HalpInternalAdapters[7] == NULL) {
+
+ HalpInternalAdapters[7] = HalpAllocateAdapter(
+ 0,
+ (PVOID) &(DMA_CONTROL)->Channel[7],
+ NULL
+ );
+
+ }
+
+ return(HalpInternalAdapters[7]);
+
+ }
+
+ //
+ // Make sure the DMA channel range is valid. Only use channels 0-6.
+ //
+
+ if (DeviceDescription->DmaChannel > 6) {
+
+ return(NULL);
+ }
+
+ //
+ // If necessary allocate an adapter; otherwise,
+ // just return the adapter for the requested channel.
+ //
+
+ if (HalpInternalAdapters[DeviceDescription->DmaChannel] == NULL) {
+
+ HalpInternalAdapters[DeviceDescription->DmaChannel] =
+ HalpAllocateAdapter(
+ 0,
+ (PVOID) &(DMA_CONTROL)->Channel[DeviceDescription->DmaChannel],
+ NULL
+ );
+
+ }
+
+ if (*NumberOfMapRegisters > MasterAdapterObject->MapRegistersPerChannel / 4) {
+
+ *NumberOfMapRegisters = MasterAdapterObject->MapRegistersPerChannel / 4;
+ }
+
+ return(HalpInternalAdapters[DeviceDescription->DmaChannel]);
+ }
+
+ //
+ // If the request is for a unsupported bus then return NULL.
+ //
+
+ if (DeviceDescription->InterfaceType != Isa &&
+ DeviceDescription->InterfaceType != Eisa) {
+
+ //
+ // This bus type is unsupported return NULL.
+ //
+
+ return(NULL);
+ }
+
+ //
+ // Create an adapter object.
+ //
+
+ adapterObject = HalpAllocateEisaAdapter( DeviceDescription );
+
+ if (*NumberOfMapRegisters > MasterAdapterObject->MapRegistersPerChannel / 4) {
+
+ *NumberOfMapRegisters = MasterAdapterObject->MapRegistersPerChannel / 4;
+ }
+
+ return(adapterObject);
+}
+
+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
+
+--*/
+
+{
+ TranslatedAddress->HighPart = 0;
+
+ //
+ // If this is for the internal bus then just return the passed parameter.
+ //
+
+ if (InterfaceType == Internal) {
+
+ //
+ // Return the passed parameters.
+ //
+
+ TranslatedAddress->LowPart = BusAddress.LowPart;
+ return(TRUE);
+ }
+
+ if (InterfaceType != Isa && InterfaceType != Eisa) {
+
+ //
+ // Not on this system return nothing.
+ //
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+ }
+
+ //
+ // There is only one I/O bus which is an EISA, so the bus number is unused.
+ //
+ // 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.
+ //
+
+ *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.
+ //
+
+ *AddressSpace = 0;
+
+#if !defined(_DUO_)
+
+ if (DMA_CONTROL->RevisionLevel.Long < 2) {
+ TranslatedAddress->LowPart = BusAddress.LowPart + EISA_MEMORY_PHYSICAL_BASE;
+ } else {
+ TranslatedAddress->LowPart = BusAddress.LowPart + EISA_MEMORY_VERSION2_LOW;
+ TranslatedAddress->HighPart = EISA_MEMORY_VERSION2_HIGH;
+
+ }
+#else
+
+ TranslatedAddress->LowPart = BusAddress.LowPart + EISA_MEMORY_VERSION2_LOW;
+ TranslatedAddress->HighPart = EISA_MEMORY_VERSION2_HIGH;
+
+#endif
+
+ if (TranslatedAddress->LowPart < BusAddress.LowPart) {
+
+ //
+ // A carry occurred.
+ //
+
+ TranslatedAddress->HighPart = 1;
+ }
+ return(TRUE);
+
+ }
+}
+
+PADAPTER_OBJECT
+HalpAllocateAdapter(
+ IN ULONG MapRegistersPerChannel,
+ IN PVOID AdapterBaseVa,
+ IN PVOID MapRegisterBase
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and initializes an adapter object to represent an
+ adapter or a DMA controller on the system.
+
+Arguments:
+
+ MapRegistersPerChannel - Unused.
+
+ AdapterBaseVa - Base virtual address of the adapter itself. If AdapterBaseVa
+ is NULL then the MasterAdapterObject is allocated.
+
+ MapRegisterBase - 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;
+ ULONG Mode;
+
+ //
+ // Initalize the master adapter if necessary.
+ //
+
+ if (MasterAdapterObject == NULL && AdapterBaseVa != NULL ) {
+
+ MasterAdapterObject = HalpAllocateAdapter( 0,
+ NULL,
+ 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 == NULL) {
+
+
+ BitmapSize = (((sizeof( RTL_BITMAP ) +
+ ((DMA_TRANSLATION_LIMIT / sizeof( TRANSLATION_ENTRY)) + 7 >> 3))
+ + 3) & ~3);
+
+ Size = sizeof( ADAPTER_OBJECT ) + BitmapSize;
+
+ } else {
+
+ Size = sizeof( ADAPTER_OBJECT );
+
+ }
+
+ //
+ // Now create the adapter object.
+ //
+
+ Status = ObCreateObject( KernelMode,
+ *((POBJECT_TYPE *)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,
+ *((POBJECT_TYPE *)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 )) {
+
+ ZwClose( Handle );
+
+ //
+ // Initialize the adapter object itself.
+ //
+
+ AdapterObject->Type = IO_TYPE_ADAPTER;
+ AdapterObject->Size = (USHORT) Size;
+ AdapterObject->MapRegistersPerChannel =
+ DMA_TRANSLATION_LIMIT / sizeof( TRANSLATION_ENTRY);
+ AdapterObject->AdapterBaseVa = AdapterBaseVa;
+ AdapterObject->MasterAdapter = MasterAdapterObject;
+ AdapterObject->PagePort = 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 == NULL ) {
+ ULONG MapRegisterSize;
+
+ KeInitializeSpinLock( &AdapterObject->SpinLock );
+
+ InitializeListHead( &AdapterObject->AdapterQueue );
+
+ AdapterObject->MapRegisters = (PVOID) ( AdapterObject + 1);
+ RtlInitializeBitMap( AdapterObject->MapRegisters,
+ (PULONG) (((PCHAR) (AdapterObject->MapRegisters)) + sizeof( RTL_BITMAP )),
+ DMA_TRANSLATION_LIMIT / sizeof( TRANSLATION_ENTRY)
+ );
+ RtlClearAllBits( AdapterObject->MapRegisters );
+
+ //
+ // The memory for the map registers was allocated by
+ // HalpAllocateMapRegisters during phase 0 initialization.
+ //
+
+ MapRegisterSize = DMA_TRANSLATION_LIMIT;
+ MapRegisterSize = ROUND_TO_PAGES(MapRegisterSize);
+
+ //
+ // Convert the physical address to a non-cached virtual address.
+ //
+
+ AdapterObject->MapRegisterBase = (PVOID)
+ (HalpMapRegisterPhysicalBase | KSEG1_BASE);
+
+ WRITE_REGISTER_ULONG(
+ &DMA_CONTROL->TranslationBase.Long,
+ HalpMapRegisterPhysicalBase
+ );
+
+ WRITE_REGISTER_ULONG(
+ &DMA_CONTROL->TranslationLimit.Long,
+ MapRegisterSize
+ );
+
+ //
+ // Initialize the DMA mode registers for the Floppy, SCSI and Sound.
+ // The initialization values come fomr the System Specification.
+ //
+
+#if defined(_JAZZ_)
+
+ Mode = 0;
+ ((PDMA_CHANNEL_MODE) &Mode)->AccessTime = ACCESS_80NS;
+ ((PDMA_CHANNEL_MODE) &Mode)->TransferWidth = WIDTH_16BITS;
+ ((PDMA_CHANNEL_MODE) &Mode)->InterruptEnable = 0;
+ ((PDMA_CHANNEL_MODE) &Mode)->BurstMode = 0;
+ ((PDMA_CHANNEL_MODE) &Mode)->FastDmaCycle = 1;
+ WRITE_REGISTER_ULONG(
+ &DMA_CONTROL->Channel[SCSI_CHANNEL].Mode.Long,
+ (ULONG) Mode
+ );
+
+ ((PDMA_CHANNEL_MODE) &Mode)->AccessTime = ACCESS_120NS;
+ ((PDMA_CHANNEL_MODE) &Mode)->TransferWidth = WIDTH_8BITS;
+ ((PDMA_CHANNEL_MODE) &Mode)->InterruptEnable = 0;
+ ((PDMA_CHANNEL_MODE) &Mode)->FastDmaCycle = 1;
+ WRITE_REGISTER_ULONG(
+ &DMA_CONTROL->Channel[FLOPPY_CHANNEL].Mode.Long,
+ (ULONG) Mode
+ );
+
+ ((PDMA_CHANNEL_MODE) &Mode)->AccessTime = ACCESS_80NS;
+ ((PDMA_CHANNEL_MODE) &Mode)->TransferWidth = WIDTH_16BITS;
+ ((PDMA_CHANNEL_MODE) &Mode)->InterruptEnable = 0;
+ ((PDMA_CHANNEL_MODE) &Mode)->BurstMode = 1;
+ WRITE_REGISTER_ULONG(
+ &DMA_CONTROL->Channel[SOUND_CHANNEL_A].Mode.Long,
+ (ULONG) Mode
+ );
+
+ ((PDMA_CHANNEL_MODE) &Mode)->AccessTime = ACCESS_80NS;
+ ((PDMA_CHANNEL_MODE) &Mode)->TransferWidth = WIDTH_16BITS;
+ ((PDMA_CHANNEL_MODE) &Mode)->InterruptEnable = 0;
+ ((PDMA_CHANNEL_MODE) &Mode)->BurstMode = 1;
+ WRITE_REGISTER_ULONG(
+ &DMA_CONTROL->Channel[SOUND_CHANNEL_B].Mode.Long,
+ (ULONG) Mode
+ );
+
+#endif
+
+ }
+
+ } 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;
+
+ return (PADAPTER_OBJECT) NULL;
+}
+
+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;
+ PLIST_ENTRY Packet;
+ IO_ALLOCATION_ACTION Action;
+ PWAIT_CONTEXT_BLOCK Wcb;
+ KIRQL Irql;
+ ULONG Hint;
+
+
+ //
+ // Begin by getting the address of the master adapter.
+ //
+
+ if (AdapterObject->MasterAdapter != NULL) {
+ MasterAdapter = AdapterObject->MasterAdapter;
+ } else {
+ MasterAdapter = AdapterObject;
+ }
+
+ 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.
+ //
+
+ Hint = AdapterObject->PagePort ? (0x100000 / PAGE_SIZE) : 0;
+
+ MapRegisterNumber = RtlFindClearBitsAndSet(
+ MasterAdapter->MapRegisters,
+ NumberOfMapRegisters,
+ Hint
+ );
+
+ //
+ // Make sure this map register is valid for this adapter.
+ //
+
+ if ((ULONG) MapRegisterNumber < Hint) {
+
+ //
+ // Make it look like there are no map registers.
+ //
+
+ RtlClearBits(
+ MasterAdapter->MapRegisters,
+ MapRegisterNumber,
+ NumberOfMapRegisters
+ );
+
+ MapRegisterNumber = -1;
+ }
+
+ 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);
+
+ //
+ // 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 );
+}
+
+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;
+ PADAPTER_OBJECT MasterAdapter;
+ BOOLEAN Busy = FALSE;
+ IO_ALLOCATION_ACTION Action;
+ PWAIT_CONTEXT_BLOCK Wcb;
+ KIRQL Irql;
+ LONG MapRegisterNumber;
+ ULONG Hint;
+
+ //
+ // Begin by getting the address of the master adapter.
+ //
+
+ if (AdapterObject->MasterAdapter != NULL) {
+ MasterAdapter = AdapterObject->MasterAdapter;
+ } else {
+ MasterAdapter = AdapterObject;
+ }
+
+ //
+ // 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) {
+ if (Wcb->NumberOfMapRegisters > MasterAdapter->MapRegistersPerChannel) {
+ KeBugCheck( INSUFFICIENT_SYSTEM_MAP_REGS );
+ }
+
+ //
+ // 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)) {
+
+ Hint = AdapterObject->PagePort ? (0x100000 / PAGE_SIZE) : 0;
+
+ MapRegisterNumber = RtlFindClearBitsAndSet(
+ MasterAdapter->MapRegisters,
+ Wcb->NumberOfMapRegisters,
+ Hint
+ );
+
+ //
+ // Make sure this map register is valid for this adapter.
+ //
+
+ if ((ULONG) MapRegisterNumber < Hint) {
+
+ //
+ // Make it look like there are no map registers.
+ //
+
+ RtlClearBits(
+ MasterAdapter->MapRegisters,
+ MapRegisterNumber,
+ Wcb->NumberOfMapRegisters
+ );
+
+ MapRegisterNumber = -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;
+
+ } else {
+ AdapterObject->MapRegisterBase = (PVOID) ((PTRANSLATION_ENTRY) MasterAdapter->MapRegisterBase + MapRegisterNumber);
+ }
+
+ KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql );
+ }
+
+ //
+ // 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;
+ }
+ }
+}
+
+BOOLEAN
+HalpCreateDmaStructures (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the structures necessary for DMA operations
+ and connects the intermediate interrupt dispatcher. It also connects
+ an interrupt handler to the DMA channel interrupt.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the second level interrupt dispatcher is connected, then a value of
+ TRUE is returned. Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+
+ //
+ // Initialize the DMA interrupt dispatcher for I/O interrupts.
+ //
+
+ KeInitializeInterrupt( &HalpDmaChannelInterrupt,
+ HalpDmaChannel,
+ (PVOID) NULL,
+ (PKSPIN_LOCK) NULL,
+ DMA_LEVEL,
+ DMA_LEVEL,
+ DMA_LEVEL,
+ LevelSensitive,
+ FALSE,
+ 0,
+ FALSE
+ );
+
+ //
+ // Don't fail if the interrupt cannot be connected.
+ //
+
+ KeConnectInterrupt( &HalpDmaChannelInterrupt );
+
+ //
+ // Directly connect the local device interrupt dispatcher to the local
+ // device interrupt vector.
+ //
+ // N.B. This vector is reserved for exclusive use by the HAL (see
+ // interrupt initialization).
+ //
+
+ PCR->InterruptRoutine[DEVICE_LEVEL] = (PKINTERRUPT_ROUTINE) HalpDmaDispatch;
+ return TRUE;
+}
+
+PHYSICAL_ADDRESS
+IoMapTransfer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PMDL Mdl,
+ IN PVOID MapRegisterBase,
+ IN PVOID CurrentVa,
+ IN OUT PULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is invoked to set up the map registers in the DMA controller
+ to allow a transfer to or from a device.
+
+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.
+
+Return Value:
+
+ Returns the logical address to be used by bus masters.
+
+--*/
+
+{
+ PTRANSLATION_ENTRY DmaMapRegister = MapRegisterBase;
+ PULONG PageFrameNumber;
+ ULONG NumberOfPages;
+ ULONG Offset;
+ ULONG i;
+
+ //
+ // Begin by determining where in the buffer this portion of the operation
+ // is taking place.
+ //
+
+ Offset = BYTE_OFFSET( (PCHAR) CurrentVa - (PCHAR) Mdl->StartVa );
+
+ PageFrameNumber = (PULONG) (Mdl + 1);
+ NumberOfPages = (Offset + *Length + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ PageFrameNumber += (((PCHAR) CurrentVa - (PCHAR) Mdl->StartVa) >> PAGE_SHIFT);
+ for (i = 0; i < NumberOfPages; i++) {
+ (DmaMapRegister++)->PageFrame = (ULONG) *PageFrameNumber++ << PAGE_SHIFT;
+ }
+
+ //
+ // Set the offset to point to the map register plus the offset.
+ //
+
+ Offset += ((PTRANSLATION_ENTRY) MapRegisterBase - (PTRANSLATION_ENTRY) MasterAdapterObject->MapRegisterBase) << PAGE_SHIFT;
+
+ //
+ // Invalidate the translation entry.
+ //
+
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->TranslationInvalidate.Long, 1);
+
+ if ( AdapterObject == NULL) {
+ return(RtlConvertUlongToLargeInteger(Offset));
+ }
+
+ if (AdapterObject->PagePort == NULL) {
+
+ //
+ // Set the local DMA Registers.
+ //
+
+ WRITE_REGISTER_ULONG(&((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Address.Long, Offset);
+ WRITE_REGISTER_ULONG(&((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->ByteCount.Long, *Length);
+
+ i = 0;
+ ((PDMA_CHANNEL_ENABLE) &i)->ChannelEnable = 1;
+ ((PDMA_CHANNEL_ENABLE) &i)->TransferDirection =
+ WriteToDevice ? DMA_WRITE_OP : DMA_READ_OP;
+ WRITE_REGISTER_ULONG(&((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Enable.Long, i);
+
+
+ } else {
+
+ //
+ // Start the EISA DMA controller.
+ //
+
+ HalpEisaMapTransfer(
+ AdapterObject,
+ Offset,
+ *Length,
+ WriteToDevice
+ );
+
+ }
+ return(RtlConvertUlongToLargeInteger(Offset));
+}
+
+BOOLEAN
+IoFlushAdapterBuffers(
+ 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 and 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.
+
+--*/
+
+{
+
+ ULONG i;
+ UCHAR DataByte;
+
+ if (AdapterObject == NULL) {
+
+ //
+ // This is a master adadapter so there is nothing to do.
+ //
+
+ return(TRUE);
+ }
+
+ if (AdapterObject->PagePort) {
+
+ //
+ // If this is a master channel, then just return since the DMA
+ // request does not need to be disabled.
+ //
+
+ DataByte = AdapterObject->AdapterMode;
+
+ if (((PDMA_EISA_MODE) &DataByte)->RequestMode == CASCADE_REQUEST_MODE) {
+
+ return(TRUE);
+
+ }
+
+ //
+ // Clear the EISA DMA adapter.
+ //
+
+ if (AdapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber)
+ );
+
+ }
+
+ } else {
+
+ //
+ // Clear on board DMA
+ //
+
+ i = READ_REGISTER_ULONG(
+ &((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Enable.Long
+ );
+
+ ((PDMA_CHANNEL_ENABLE) &i)->ChannelEnable = 0;
+ WRITE_REGISTER_ULONG(
+ &((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Enable.Long,
+ i
+ );
+
+ i = READ_REGISTER_USHORT(
+ &((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Enable
+ );
+ }
+
+ return(TRUE);
+}
+
+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);
+}
+
+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
+ )
+/*++
+
+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;
+}
+
+ULONG
+HalReadDmaCounter(
+ 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 i;
+ ULONG saveEnable;
+ ULONG count;
+ ULONG high;
+
+ if (AdapterObject->PagePort) {
+
+ //
+ // 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;
+
+ //
+ // 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;
+
+ //
+ // 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));
+
+ }
+
+ //
+ // The DMA counter has a bias of one and can only be 16 bit long.
+ //
+
+ count = (count + 1) & 0xFFFF;
+
+ } else {
+
+ //
+ // Disable the DMA
+ //
+
+ i = READ_REGISTER_ULONG(
+ &((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Enable.Long
+ );
+
+ saveEnable = i;
+
+ ((PDMA_CHANNEL_ENABLE) &i)->ChannelEnable = 0;
+ WRITE_REGISTER_ULONG(
+ &((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Enable.Long,
+ i
+ );
+
+ //
+ // Read the transfer count.
+ //
+
+ count = READ_REGISTER_ULONG(&((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->ByteCount.Long);
+
+ //
+ // Reset the Enable register.
+ //
+
+ WRITE_REGISTER_ULONG(
+ &((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Enable.Long,
+ saveEnable
+ );
+
+ }
+
+ return(count);
+}
+
+
+BOOLEAN
+HalpDmaChannel(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a DMA channel interrupt occurs.
+ These should never occur. Bugcheck is called if an error does occur.
+
+Arguments:
+
+ Interrupt - Supplies a pointer to the interrupt object
+
+ ServiceContext - Bug number to call bugcheck with.
+
+Return Value:
+
+ Returns TRUE.
+
+--*/
+{
+
+ ULONG DataWord;
+ ULONG Channel;
+ DMA_CHANNEL_ENABLE ChannelWord;
+
+#if defined(_JAZZ_)
+
+ //
+ // Read the DMA channel interrupt source register.
+ //
+
+ DataWord = READ_REGISTER_ULONG(&DMA_CONTROL->InterruptSource.Long);
+
+ for (Channel = 0; Channel < 8; Channel++) {
+
+ //
+ // Determine which channel is interrupting.
+ //
+
+ if (!(DataWord & ( 1 << Channel))) {
+ continue;
+ }
+
+ DmaChannelMsg[18] = (CHAR) Channel + '0';
+
+ HalDisplayString(DmaChannelMsg);
+
+ *((PULONG) &ChannelWord) =
+ READ_REGISTER_ULONG(&DMA_CONTROL->Channel[Channel].Enable.Long);
+
+ if (ChannelWord.TerminalCount) {
+ HalDisplayString("Terminal count was reached.\n");
+ }
+
+ if (ChannelWord.MemoryError) {
+ HalDisplayString("A memory error was detected.\n");
+ }
+
+ if (ChannelWord.TranslationError) {
+ HalDisplayString("A translation error occured.\n");
+ }
+
+ }
+
+ KeBugCheck(NMI_HARDWARE_FAILURE);
+
+#endif
+
+ return(TRUE);
+}
+
+VOID
+HalpAllocateMapRegisters(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates memory for map registers directly from the loader
+ block information. This memory must be non-cached and contiguous.
+
+Arguments:
+
+ LoaderBlock - Pointer to the loader block which contains the memory descriptors.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+ PLIST_ENTRY NextMd;
+ ULONG MaxPageAddress;
+ ULONG PhysicalAddress;
+ ULONG MapRegisterSize;
+
+ MapRegisterSize = DMA_TRANSLATION_LIMIT;
+ MapRegisterSize = BYTES_TO_PAGES(MapRegisterSize);
+
+ //
+ // The address must be in KSEG 0.
+ //
+
+ MaxPageAddress = (KSEG1_BASE >> PAGE_SHIFT) - 1 ;
+
+ //
+ // Scan the memory allocation descriptors and allocate map buffers
+ //
+
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
+ Descriptor = CONTAINING_RECORD(NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ //
+ // Search for a block of memory which is contains a memory chuck
+ // that is greater than size pages, and has a physical address less
+ // than MAXIMUM_PHYSICAL_ADDRESS.
+ //
+
+ if ((Descriptor->MemoryType == LoaderFree ||
+ Descriptor->MemoryType == MemoryFirmwareTemporary) &&
+ (Descriptor->BasePage) &&
+ (Descriptor->PageCount >= MapRegisterSize) &&
+ (Descriptor->BasePage + MapRegisterSize < MaxPageAddress)) {
+
+ PhysicalAddress = Descriptor->BasePage << PAGE_SHIFT;
+ break;
+ }
+
+ NextMd = NextMd->Flink;
+ }
+
+ //
+ // Use the extra descriptor to define the memory at the end of the
+ // original block.
+ //
+
+ ASSERT(NextMd != &LoaderBlock->MemoryDescriptorListHead);
+
+ if (NextMd == &LoaderBlock->MemoryDescriptorListHead)
+ return;
+
+ //
+ // Adjust the memory descriptors.
+ //
+
+ Descriptor->BasePage += MapRegisterSize;
+ Descriptor->PageCount -= MapRegisterSize;
+
+ if (Descriptor->PageCount == 0) {
+
+ //
+ // The whole block was allocated,
+ // Remove the entry from the list completely.
+ //
+
+ RemoveEntryList(&Descriptor->ListEntry);
+
+ }
+
+ //
+ // Save the map register base.
+ //
+
+ HalpMapRegisterPhysicalBase = PhysicalAddress;
+
+}