1937 lines
45 KiB
C
1937 lines
45 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
Copyright (c) 1993 Digital Equipment Corporation
|
||
|
||
Module Name:
|
||
|
||
jxhwsup.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the IopXxx 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.
|
||
|
||
Like the MIPS module, this is a hacked-up version of
|
||
\nt\private\ntos\hal\alpha\jxhwsup.c.
|
||
|
||
|
||
Author:
|
||
|
||
Jeff Havens (jhavens) 14-Feb-1990
|
||
Miche Baker-Harvey (miche) 22-May-1992
|
||
Jeff McLeman (mcleman) 27-May-1992
|
||
|
||
Environment:
|
||
|
||
Kernel mode, local to I/O system
|
||
|
||
Revision History:
|
||
|
||
3-August-1992 John DeRosa
|
||
|
||
Made this from \nt\private\ntos\hal\alpha\jxhwsup.c and
|
||
\nt\private\ntos\fw\mips\jxhwsup.c.
|
||
|
||
--*/
|
||
|
||
#include "fwp.h"
|
||
#include "ntalpha.h"
|
||
#include "jxfwhal.h"
|
||
|
||
#ifdef JENSEN
|
||
#include "jnsndma.h"
|
||
#else
|
||
#include "mrgndma.h" // morgan
|
||
#endif
|
||
|
||
#include "eisa.h"
|
||
#include "jxisa.h"
|
||
|
||
|
||
//
|
||
// Firmware-specific definitions to aid compilation and linking.
|
||
//
|
||
|
||
//
|
||
// HalpBusType is used by the Hal so to run properly on EISA or ISA
|
||
// machines. It is a static that is initialized in hal\alpha\xxinithl.c.
|
||
|
||
#ifdef EISA_PLATFORM
|
||
|
||
//
|
||
// This definition is correct for any EISA-based Alpha machines.
|
||
//
|
||
|
||
#define HalpBusType MACHINE_TYPE_EISA
|
||
|
||
#else
|
||
|
||
#define HalpBusType MACHINE_TYPE_ISA
|
||
|
||
#endif
|
||
|
||
//
|
||
// This is a BOOLEAN variable in the real Hal code.
|
||
//
|
||
|
||
#define LessThan16Mb (MemorySize <= (16 * 1024 * 1024))
|
||
|
||
#define HAL_32MB 0x2000000
|
||
|
||
PVOID HalpEisaControlBase;
|
||
|
||
//
|
||
// The following is an array of adapter object structures for the Eisa DMA
|
||
// channels.
|
||
//
|
||
|
||
//
|
||
// Define the area for the Eisa objects
|
||
//
|
||
|
||
PADAPTER_OBJECT HalpEisaAdapter[8];
|
||
|
||
PADAPTER_OBJECT MasterAdapterObject;
|
||
|
||
//
|
||
// function prototypes
|
||
//
|
||
|
||
BOOLEAN
|
||
HalpGrowMapBuffers(
|
||
PADAPTER_OBJECT AdapterObject,
|
||
ULONG Amount
|
||
);
|
||
|
||
|
||
PADAPTER_OBJECT
|
||
IopAllocateAdapter(
|
||
IN ULONG MapRegistersPerChannel,
|
||
IN PVOID AdapterBaseVa,
|
||
IN PVOID ChannelNumber
|
||
);
|
||
|
||
VOID
|
||
HalpCopyBufferMap(
|
||
IN PMDL Mdl,
|
||
IN PTRANSLATION_ENTRY translationEntry,
|
||
IN PVOID CurrentVa,
|
||
IN ULONG Length,
|
||
IN BOOLEAN WriteToDevice
|
||
);
|
||
|
||
QUASI_VIRTUAL_ADDRESS
|
||
HalCreateQva(
|
||
IN PHYSICAL_ADDRESS PA,
|
||
IN PVOID VA
|
||
);
|
||
|
||
VOID
|
||
HalpCopyBufferMap(
|
||
IN PMDL Mdl,
|
||
IN PTRANSLATION_ENTRY translationEntry,
|
||
IN PVOID CurrentVa,
|
||
IN ULONG Length,
|
||
IN BOOLEAN WriteToDevice
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine copies the specified data between the user buffer and the
|
||
map register buffer. First, the user buffer is mapped, if need be then
|
||
the data is copied. Finally, the user buffer will be unmapped, if need be.
|
||
|
||
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 xfer.
|
||
|
||
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 - A Boolean value that indicates whether this is a write
|
||
to the device from memory of vise-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);
|
||
bufferAddress = (PCCHAR) CurrentVa;
|
||
|
||
mapAddress = (PCCHAR) translationEntry->VirtualAddress +
|
||
BYTE_OFFSET(CurrentVa);
|
||
|
||
//
|
||
// Copy the data between the user buffer and the map buffer.
|
||
//
|
||
|
||
if (WriteToDevice) {
|
||
|
||
RtlMoveMemory( mapAddress, bufferAddress, Length);
|
||
|
||
} else {
|
||
|
||
RtlMoveMemory ( bufferAddress, mapAddress, Length);
|
||
|
||
}
|
||
}
|
||
|
||
NTSTATUS
|
||
IoAllocateAdapterChannel(
|
||
IN PADAPTER_OBJECT AdapterObject,
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN ULONG NumberOfMapRegisters,
|
||
IN PDRIVER_CONTROL ExecutionRoutine,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
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.
|
||
|
||
DeviceObject - Pointer to the driver's device object that represents the
|
||
device allocating the adapter.
|
||
|
||
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.
|
||
|
||
Context - An untyped longword context parameter passed to the driver's
|
||
execution routine.
|
||
|
||
|
||
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;
|
||
IO_ALLOCATION_ACTION Action;
|
||
|
||
//
|
||
// Begin by obtaining a pointer to the master adapter associated with this
|
||
// request.
|
||
//
|
||
|
||
if (AdapterObject->MasterAdapter != NULL) {
|
||
MasterAdapter = AdapterObject->MasterAdapter;
|
||
} else {
|
||
MasterAdapter = AdapterObject;
|
||
}
|
||
|
||
//
|
||
// Make sure the adapter is free.
|
||
//
|
||
|
||
if (AdapterObject->AdapterInUse) {
|
||
DbgPrint("IoAllocateAdapterChannel: Called while adapter in use.\n");
|
||
}
|
||
|
||
//
|
||
// Make sure there are enough map registers.
|
||
//
|
||
|
||
AdapterObject->NumberOfMapRegisters = NumberOfMapRegisters;
|
||
|
||
if ((NumberOfMapRegisters != 0) && AdapterObject->NeedsMapRegisters) {
|
||
|
||
if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) {
|
||
DbgPrint("IoAllocateAdapterChannel: Out of map registers.\r\n");
|
||
AdapterObject->NumberOfMapRegisters = 0;
|
||
IoFreeAdapterChannel(AdapterObject);
|
||
return(STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
AdapterObject->MapRegisterBase =
|
||
(PVOID)(PTRANSLATION_ENTRY)MasterAdapter->MapRegisterBase;
|
||
|
||
} else {
|
||
AdapterObject->MapRegisterBase = NULL;
|
||
AdapterObject->NumberOfMapRegisters = 0;
|
||
}
|
||
|
||
Action = ExecutionRoutine( DeviceObject,
|
||
DeviceObject->CurrentIrp,
|
||
AdapterObject->MapRegisterBase,
|
||
Context );
|
||
|
||
//
|
||
// If the driver wishes to keep the map registers then
|
||
// increment the current base and decrease the number of existing map
|
||
// registers.
|
||
//
|
||
|
||
if (Action == DeallocateObjectKeepRegisters) {
|
||
|
||
AdapterObject->MapRegistersPerChannel -= NumberOfMapRegisters;
|
||
(PTRANSLATION_ENTRY) MasterAdapter->MapRegisterBase +=
|
||
NumberOfMapRegisters;
|
||
|
||
} else if (Action == KeepObject) {
|
||
|
||
AdapterObject->AdapterInUse = TRUE;
|
||
|
||
} else if (Action == DeallocateObject) {
|
||
|
||
IoFreeAdapterChannel( AdapterObject );
|
||
|
||
}
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
PADAPTER_OBJECT
|
||
HalGetAdapter(
|
||
IN PDEVICE_DESCRIPTION DeviceDescriptor,
|
||
IN OUT PULONG NumberOfMapRegisters
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function returns the appropriate adapter object for the device defined
|
||
in the device description structure. Two bus types are supported for the
|
||
Jensen system: Isa, and Eisa.
|
||
|
||
Arguments:
|
||
|
||
DeviceDescriptor - 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;
|
||
PVOID adapterBaseVa;
|
||
ULONG channelNumber;
|
||
ULONG controllerNumber;
|
||
DMA_EXTENDED_MODE extendedMode;
|
||
UCHAR adapterMode;
|
||
ULONG numberOfMapRegisters;
|
||
BOOLEAN useChannel;
|
||
BOOLEAN eisaSystem;
|
||
ULONG maximumLength;
|
||
|
||
eisaSystem = HalpBusType == MACHINE_TYPE_EISA ? TRUE : FALSE;
|
||
|
||
//
|
||
// Determine if the channel number is important. Master cards on
|
||
// Eisa systems do not use channel numbers.
|
||
//
|
||
|
||
if (DeviceDescriptor->InterfaceType != Isa &&
|
||
DeviceDescriptor->Master) {
|
||
|
||
useChannel = FALSE;
|
||
} else {
|
||
|
||
useChannel = TRUE;
|
||
}
|
||
|
||
//
|
||
// Limit the max length to 2GB. This is done to make BYTES_TO_PAGES
|
||
// work correctly.
|
||
//
|
||
|
||
maximumLength = DeviceDescriptor->MaximumLength & 0x7FFFFFFF;
|
||
|
||
//
|
||
// Channel 4 cannot be used since it reserved for chaining. Return
|
||
// NULL if it has been requested.
|
||
//
|
||
|
||
if (DeviceDescriptor->DmaChannel == 4 && useChannel) {
|
||
return(NULL);
|
||
}
|
||
|
||
//
|
||
// Determine the number of map registers for this device
|
||
//
|
||
|
||
if (DeviceDescriptor->ScatterGather && (LessThan16Mb ||
|
||
DeviceDescriptor->InterfaceType == Eisa)) {
|
||
|
||
//
|
||
// Since the device is a master and does scatter/gather
|
||
// we don't need any map registers.
|
||
//
|
||
|
||
numberOfMapRegisters = 0;
|
||
|
||
} else {
|
||
|
||
|
||
//
|
||
// Return number of map registers requested based on the maximum
|
||
// transfer length.
|
||
//
|
||
|
||
//numberOfMapRegisters = BYTES_TO_PAGES(
|
||
// maximumLength
|
||
// ) + 1;
|
||
numberOfMapRegisters = DMA_TRANSLATION_LIMIT / sizeof(TRANSLATION_ENTRY);
|
||
|
||
numberOfMapRegisters = numberOfMapRegisters > MAXIMUM_ISA_MAP_REGISTER ? MAXIMUM_ISA_MAP_REGISTER : numberOfMapRegisters;
|
||
|
||
//
|
||
// If this device is not a master then it only needs one register
|
||
// and does scatter/gather.
|
||
//
|
||
|
||
if (DeviceDescriptor->ScatterGather && !DeviceDescriptor->Master) {
|
||
|
||
numberOfMapRegisters = 1;
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// Set the channel number.
|
||
//
|
||
|
||
channelNumber = DeviceDescriptor->DmaChannel & 0x03;
|
||
|
||
//
|
||
// set the adapter base address to the Base address register and
|
||
// controller number.
|
||
|
||
if (!(DeviceDescriptor->DmaChannel & 0x04)) {
|
||
|
||
controllerNumber = 1;
|
||
adapterBaseVa = &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort;
|
||
} else {
|
||
|
||
controllerNumber = 2;
|
||
adapterBaseVa = &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort;
|
||
|
||
}
|
||
|
||
//
|
||
// Determine if a new adapter object is necessary
|
||
//
|
||
|
||
if (useChannel && HalpEisaAdapter[DeviceDescriptor->DmaChannel] != NULL) {
|
||
|
||
adapterObject = HalpEisaAdapter[DeviceDescriptor->DmaChannel];
|
||
|
||
} else {
|
||
|
||
//
|
||
// Allocate an adapter object
|
||
//
|
||
|
||
adapterObject = (PADAPTER_OBJECT) IopAllocateAdapter(
|
||
numberOfMapRegisters,
|
||
adapterBaseVa,
|
||
NULL);
|
||
|
||
if (adapterObject == NULL) {
|
||
|
||
return(NULL);
|
||
|
||
}
|
||
|
||
if (useChannel) {
|
||
|
||
HalpEisaAdapter[DeviceDescriptor->DmaChannel] = adapterObject;
|
||
|
||
}
|
||
|
||
//
|
||
// Set the maximum number of map registers for this channel based
|
||
// on the number requested andthe type of the device.
|
||
//
|
||
|
||
if (numberOfMapRegisters) {
|
||
|
||
//
|
||
// The specified number of registers are actually allowed to be
|
||
// allocated.
|
||
//
|
||
|
||
adapterObject->MapRegistersPerChannel = numberOfMapRegisters;
|
||
|
||
//
|
||
// Increase the commitment for the map registers
|
||
//
|
||
|
||
if (DeviceDescriptor->Master) {
|
||
|
||
//
|
||
// Double the commitment for Master I/O devices
|
||
//
|
||
|
||
MasterAdapterObject->CommittedMapRegisters +=
|
||
numberOfMapRegisters * 2;
|
||
|
||
} else {
|
||
|
||
MasterAdapterObject->CommittedMapRegisters +=
|
||
numberOfMapRegisters;
|
||
|
||
}
|
||
|
||
//
|
||
// If the committed map registers is significantly greater than
|
||
// the number allocated, then grow the map buffer.
|
||
//
|
||
|
||
if (MasterAdapterObject->CommittedMapRegisters >
|
||
MasterAdapterObject->NumberOfMapRegisters &&
|
||
MasterAdapterObject->CommittedMapRegisters -
|
||
MasterAdapterObject->NumberOfMapRegisters >
|
||
MAXIMUM_ISA_MAP_REGISTER ) {
|
||
|
||
HalpGrowMapBuffers(
|
||
MasterAdapterObject,
|
||
INCREMENT_MAP_BUFFER_SIZE);
|
||
|
||
}
|
||
|
||
adapterObject->NeedsMapRegisters = TRUE;
|
||
|
||
} else {
|
||
|
||
//
|
||
// No real registers were allocated. If this is a master, then
|
||
// it is allowed as many registers as it wants.
|
||
//
|
||
|
||
adapterObject->NeedsMapRegisters = FALSE;
|
||
|
||
if (DeviceDescriptor->Master) {
|
||
|
||
adapterObject->MapRegistersPerChannel = BYTES_TO_PAGES(
|
||
maximumLength) + 1;
|
||
} else {
|
||
|
||
//
|
||
// The device only gets one register. It must call
|
||
// IoMapTransfer repeatedly to do a large transfer.
|
||
//
|
||
|
||
adapterObject->MapRegistersPerChannel = 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
*NumberOfMapRegisters = adapterObject->MapRegistersPerChannel;
|
||
|
||
//
|
||
// If the channel number is not used, we are done. If we do use one,
|
||
// we have to set up the following.
|
||
//
|
||
|
||
if (!useChannel) {
|
||
|
||
return(adapterObject);
|
||
|
||
}
|
||
|
||
//
|
||
// Setup pointers to the various and sundry registers.
|
||
//
|
||
|
||
adapterObject->ChannelNumber = (UCHAR) channelNumber;
|
||
|
||
if (controllerNumber == 1) {
|
||
|
||
switch (channelNumber) {
|
||
|
||
case 0:
|
||
adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel0;
|
||
break;
|
||
case 1:
|
||
adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel1;
|
||
break;
|
||
case 2:
|
||
adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel2;
|
||
break;
|
||
case 3:
|
||
adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel3;
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// Set the adapter number
|
||
//
|
||
|
||
adapterObject->AdapterNumber = 1;
|
||
|
||
//
|
||
// Save the extended mode register
|
||
//
|
||
|
||
adapterBaseVa =
|
||
&((PEISA_CONTROL) HalpEisaControlBase)->Dma1ExtendedModePort;
|
||
|
||
} else {
|
||
|
||
switch (channelNumber) {
|
||
|
||
case 1:
|
||
adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel5;
|
||
break;
|
||
case 2:
|
||
adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel6;
|
||
break;
|
||
case 3:
|
||
adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel7;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Set the adapter number
|
||
//
|
||
|
||
adapterObject->AdapterNumber = 2;
|
||
|
||
//
|
||
// Save the extended mode register
|
||
//
|
||
|
||
adapterBaseVa =
|
||
&((PEISA_CONTROL) HalpEisaControlBase)->Dma2ExtendedModePort;
|
||
|
||
}
|
||
|
||
adapterObject->Width16Bits = FALSE;
|
||
|
||
if (eisaSystem) {
|
||
|
||
//
|
||
// Init the extended mode port
|
||
//
|
||
|
||
*((PUCHAR) &extendedMode) = 0;
|
||
|
||
switch (DeviceDescriptor->DmaSpeed) {
|
||
case Compatible:
|
||
extendedMode.TimingMode =COMPATIBILITY_TIMING;
|
||
break;
|
||
|
||
case TypeA:
|
||
extendedMode.TimingMode = TYPE_A_TIMING;
|
||
break;
|
||
|
||
case TypeB:
|
||
extendedMode.TimingMode = TYPE_B_TIMING;
|
||
break;
|
||
|
||
case TypeC:
|
||
extendedMode.TimingMode = BURST_TIMING;
|
||
break;
|
||
|
||
default:
|
||
/* error return, don't bother to dereference the object. */
|
||
//ObDereferenceObject(adapterObject);
|
||
return(NULL);
|
||
|
||
}
|
||
|
||
switch (DeviceDescriptor->DmaWidth) {
|
||
case Width8Bits:
|
||
extendedMode.TransferSize = BY_BYTE_8_BITS;
|
||
break;
|
||
|
||
case Width16Bits:
|
||
extendedMode.TransferSize = BY_BYTE_16_BITS;
|
||
break;
|
||
|
||
case Width32Bits:
|
||
extendedMode.TransferSize = BY_BYTE_32_BITS;
|
||
break;
|
||
|
||
default:
|
||
/* error return, don't bother to dereference the object. */
|
||
//ObDereferenceObject(adapterObject);
|
||
return(NULL);
|
||
|
||
}
|
||
|
||
WRITE_PORT_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode));
|
||
} else if (!DeviceDescriptor->Master) {
|
||
|
||
switch (DeviceDescriptor->DmaWidth) {
|
||
case Width8Bits:
|
||
|
||
//
|
||
// The channel must use controller 1.
|
||
//
|
||
if (controllerNumber != 1) {
|
||
/* error return, don't bother to dereference the object. */
|
||
//ObDereferenceObject(adapterObject);
|
||
return(NULL);
|
||
}
|
||
break;
|
||
|
||
case Width16Bits:
|
||
|
||
//
|
||
// The channel must use controller 2
|
||
//
|
||
|
||
if (controllerNumber != 2) {
|
||
/* error return, don't bother to dereference the object. */
|
||
//ObDereferenceObject(adapterObject);
|
||
return(NULL);
|
||
}
|
||
adapterObject->Width16Bits = TRUE;
|
||
break;
|
||
|
||
default:
|
||
/* error return, don't bother to dereference the object. */
|
||
//ObDereferenceObject(adapterObject);
|
||
return(NULL);
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// Init the adapter mode register to the correct parameters and save
|
||
// them in the adapter object.
|
||
//
|
||
|
||
adapterMode = 0;
|
||
((PDMA_EISA_MODE) &adapterMode)->Channel = adapterObject->ChannelNumber;
|
||
|
||
if (DeviceDescriptor->Master) {
|
||
|
||
adapterObject->MasterDevice = TRUE;
|
||
|
||
((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE;
|
||
|
||
//
|
||
// Set the mode and grant the request.
|
||
//
|
||
|
||
if (adapterObject->AdapterNumber == 1) {
|
||
|
||
//
|
||
// This is for DMA controller 1
|
||
//
|
||
|
||
PDMA1_CONTROL dmaControl;
|
||
dmaControl = adapterObject->AdapterBaseVa;
|
||
WRITE_PORT_UCHAR(&dmaControl->Mode, adapterMode);
|
||
|
||
//
|
||
// unmask the DMA channel
|
||
//
|
||
|
||
WRITE_PORT_UCHAR(
|
||
&dmaControl->SingleMask,
|
||
(UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
|
||
);
|
||
|
||
} else {
|
||
|
||
//
|
||
// This is form DMA controller 2
|
||
//
|
||
|
||
PDMA2_CONTROL dmaControl;
|
||
dmaControl = adapterObject->AdapterBaseVa;
|
||
WRITE_PORT_UCHAR(&dmaControl->Mode, adapterMode);
|
||
|
||
//
|
||
// unmask the DMA channel
|
||
//
|
||
|
||
WRITE_PORT_UCHAR(
|
||
&dmaControl->SingleMask,
|
||
(UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
|
||
);
|
||
|
||
}
|
||
|
||
} else if (DeviceDescriptor->DemandMode) {
|
||
|
||
((PDMA_EISA_MODE) &adapterMode)->RequestMode = DEMAND_REQUEST_MODE;
|
||
} else {
|
||
((PDMA_EISA_MODE) &adapterMode)->RequestMode = SINGLE_REQUEST_MODE;
|
||
}
|
||
|
||
if (DeviceDescriptor->AutoInitialize) {
|
||
|
||
((PDMA_EISA_MODE) &adapterMode)->AutoInitialize = 1;
|
||
}
|
||
|
||
adapterObject->AdapterMode = adapterMode;
|
||
|
||
|
||
return(adapterObject);
|
||
}
|
||
|
||
BOOLEAN
|
||
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;
|
||
BOOLEAN eisaSystem;
|
||
PHYSICAL_ADDRESS physicalAddress;
|
||
|
||
eisaSystem = HalpBusType == MACHINE_TYPE_EISA ? TRUE : FALSE;
|
||
|
||
NumberOfPages = BYTES_TO_PAGES(Amount);
|
||
|
||
//
|
||
// Make sure there is room for the addition 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 allocatation amount to so it will fit.
|
||
//
|
||
|
||
NumberOfPages += i;
|
||
}
|
||
|
||
if (NumberOfPages <= 0) {
|
||
//
|
||
// No more memory can be allocated.
|
||
//
|
||
|
||
return(FALSE);
|
||
|
||
}
|
||
|
||
//
|
||
// Allocate the map buffers.
|
||
//
|
||
// Remember: for the firmware, virtual = physical.
|
||
//
|
||
|
||
MapBufferVirtualAddress = FwAllocatePool(NumberOfPages * PAGE_SIZE);
|
||
|
||
if (MapBufferVirtualAddress == NULL) {
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// Get the physical address of the map base.
|
||
//
|
||
|
||
MapBufferPhysicalAddress = (ULONG)MapBufferVirtualAddress;
|
||
|
||
//
|
||
// Initialize the map registers where memory has been allocated.
|
||
//
|
||
|
||
TranslationEntry = ((PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase) +
|
||
AdapterObject->NumberOfMapRegisters;
|
||
|
||
for (i = 0; (ULONG) i < NumberOfPages; i++) {
|
||
|
||
//
|
||
// Make sure the previous entry is physically contiguous with the next
|
||
// entry and that a 64K physical bountry is not crossed unless this
|
||
// is an Eisa system.
|
||
//
|
||
|
||
if (TranslationEntry != AdapterObject->MapRegisterBase &&
|
||
(((TranslationEntry - 1)->PhysicalAddress + PAGE_SIZE) !=
|
||
MapBufferPhysicalAddress || (!eisaSystem &&
|
||
((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 bountry.
|
||
//
|
||
|
||
TranslationEntry++;
|
||
AdapterObject->NumberOfMapRegisters++;
|
||
}
|
||
|
||
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;
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
PADAPTER_OBJECT
|
||
IopAllocateAdapter(
|
||
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 - Specifies the number of map registers that each
|
||
channel provides for I/O memory mapping.
|
||
|
||
AdapterBaseVa - Base virtual address of the adapter itself. If this
|
||
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;
|
||
ULONG Size;
|
||
|
||
UNREFERENCED_PARAMETER(MapRegisterBase);
|
||
|
||
//
|
||
// Initialize the master adapter if necessary.
|
||
//
|
||
|
||
if (MasterAdapterObject == NULL && (AdapterBaseVa != (PVOID) -1) &&
|
||
MapRegistersPerChannel) {
|
||
|
||
MasterAdapterObject = IopAllocateAdapter(MapRegistersPerChannel,
|
||
(PVOID) -1,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// If we could not allocate the master adapter then give up.
|
||
//
|
||
|
||
if (MasterAdapterObject == NULL) {
|
||
return(NULL);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Determine the size of the adapter.
|
||
//
|
||
|
||
Size = sizeof( ADAPTER_OBJECT );
|
||
|
||
//
|
||
// Now create the adapter object.
|
||
//
|
||
|
||
AdapterObject = FwAllocatePool(Size);
|
||
|
||
//
|
||
// If the adapter object was successfully created, then attempt to insert
|
||
// it into the the object table.
|
||
//
|
||
|
||
if (AdapterObject) {
|
||
|
||
//
|
||
// Initialize the adapter object itself.
|
||
//
|
||
|
||
AdapterObject->Type = IO_TYPE_ADAPTER;
|
||
AdapterObject->Size = Size;
|
||
AdapterObject->MapRegistersPerChannel = 1;
|
||
AdapterObject->AdapterBaseVa = AdapterBaseVa;
|
||
|
||
if (MapRegistersPerChannel) {
|
||
|
||
AdapterObject->MasterAdapter = MasterAdapterObject;
|
||
|
||
} else {
|
||
|
||
AdapterObject->MasterAdapter = NULL;
|
||
|
||
}
|
||
|
||
//
|
||
// If this is the MasterAdapter then initialize the register bit map,
|
||
// AdapterQueue and the spin lock.
|
||
//
|
||
|
||
if ( AdapterBaseVa == (PVOID) -1 ) {
|
||
|
||
AdapterObject->NumberOfMapRegisters = 0;
|
||
AdapterObject->CommittedMapRegisters = 0;
|
||
AdapterObject->PagePort = NULL;
|
||
AdapterObject->AdapterInUse = FALSE;
|
||
|
||
//
|
||
// Allocate the memory map registers. N.B.: FwAllocatePool
|
||
// returns zeroed memory.
|
||
//
|
||
|
||
AdapterObject->MapRegisterBase = FwAllocatePool(0x2000);
|
||
|
||
if ((AdapterObject->MapRegisterBase == NULL) ||
|
||
(!HalpGrowMapBuffers(AdapterObject, 0x2000))) {
|
||
|
||
//
|
||
// No map registers could be allocated, so take error return.
|
||
//
|
||
|
||
return(NULL);
|
||
|
||
}
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// An error was incurred for some reason. Set the return value
|
||
// to NULL.
|
||
//
|
||
|
||
return(NULL);
|
||
}
|
||
|
||
|
||
AdapterObject->MasterDevice = FALSE;
|
||
|
||
return AdapterObject;
|
||
}
|
||
|
||
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;
|
||
PTRANSLATION_ENTRY translationEntry;
|
||
|
||
//
|
||
// Begin by obtaining a pointer to the master adapter associated with this
|
||
// request.
|
||
//
|
||
|
||
if (AdapterObject->MasterAdapter != NULL) {
|
||
MasterAdapter = AdapterObject->MasterAdapter;
|
||
} else {
|
||
MasterAdapter = AdapterObject;
|
||
}
|
||
|
||
//
|
||
// Determine if this was the last allocation from the adapter. If is was
|
||
// then free the map registers by restoring the map register base and the
|
||
// channel count; otherwise the registers are lost. This handles the
|
||
// normal case.
|
||
//
|
||
|
||
translationEntry = MasterAdapter->MapRegisterBase;
|
||
translationEntry -= NumberOfMapRegisters;
|
||
|
||
if (translationEntry == MapRegisterBase) {
|
||
|
||
//
|
||
// The last allocated registers are being freed.
|
||
//
|
||
|
||
MasterAdapter->MapRegisterBase = (PVOID) translationEntry;
|
||
AdapterObject->MapRegistersPerChannel += NumberOfMapRegisters;
|
||
}
|
||
}
|
||
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
AdapterObject->AdapterInUse = FALSE;
|
||
}
|
||
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN useBuffer;
|
||
ULONG transferLength;
|
||
ULONG logicalAddress;
|
||
ULONG returnAddress;
|
||
PULONG pageFrame;
|
||
PUCHAR bytePointer;
|
||
UCHAR adapterMode;
|
||
UCHAR dataByte;
|
||
PTRANSLATION_ENTRY translationEntry;
|
||
BOOLEAN masterDevice;
|
||
ULONG pageOffset;
|
||
BOOLEAN eisaSystem;
|
||
|
||
eisaSystem = HalpBusType == MACHINE_TYPE_EISA ? TRUE : FALSE;
|
||
|
||
masterDevice = (AdapterObject == NULL) ||
|
||
(AdapterObject->MasterDevice ? TRUE : FALSE);
|
||
|
||
translationEntry = MapRegisterBase;
|
||
transferLength = *Length;
|
||
pageOffset = BYTE_OFFSET(CurrentVa);
|
||
|
||
|
||
//
|
||
// Determine if the data transfer needs to use the map buffer
|
||
//
|
||
|
||
if ((translationEntry) && (!masterDevice) &&
|
||
(ADDRESS_AND_SIZE_TO_SPAN_PAGES(CurrentVa, transferLength) > 1)) {
|
||
|
||
logicalAddress = translationEntry->PhysicalAddress + pageOffset;
|
||
useBuffer = TRUE;
|
||
|
||
} else {
|
||
|
||
//
|
||
// The transfer can only be done for one page
|
||
//
|
||
|
||
transferLength = PAGE_SIZE - pageOffset;
|
||
pageFrame = (PULONG)(Mdl+1);
|
||
pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) / PAGE_SIZE;
|
||
logicalAddress = ((*pageFrame << PAGE_SHIFT) + pageOffset);
|
||
|
||
//
|
||
// If the buffer is contiguous and does not cross a 64K boundary
|
||
// then just extend the buffer. This restriction does not apply
|
||
// to eisa systems.
|
||
//
|
||
|
||
while (transferLength < *Length) {
|
||
if (*pageFrame +1 != *(pageFrame +1) || (!eisaSystem &&
|
||
*pageFrame & ~0x0f != *(pageFrame + 1) & ~0x0f)) {
|
||
break;
|
||
}
|
||
|
||
transferLength += PAGE_SIZE;
|
||
pageFrame ++;
|
||
}
|
||
|
||
transferLength = transferLength > *Length ? *Length : transferLength;
|
||
useBuffer = FALSE;
|
||
}
|
||
|
||
//
|
||
// If the logical address is greater than 16Mb, then mapping registers
|
||
// (buffer xfer) nust be used. This is due to ISA devices only addressing
|
||
// a max of 16Mb.
|
||
//
|
||
|
||
if (translationEntry && logicalAddress >= MAXIMUM_ISA_PHYSICAL_ADDRESS) {
|
||
|
||
logicalAddress = (translationEntry + translationEntry->Index)->
|
||
PhysicalAddress + pageOffset;
|
||
useBuffer = TRUE;
|
||
}
|
||
|
||
//
|
||
// Return the length
|
||
//
|
||
|
||
*Length = transferLength;
|
||
|
||
//
|
||
// Copy the data if necessary
|
||
//
|
||
|
||
if (useBuffer && WriteToDevice) {
|
||
|
||
HalpCopyBufferMap(
|
||
Mdl,
|
||
translationEntry + translationEntry->Index,
|
||
CurrentVa,
|
||
*Length,
|
||
WriteToDevice
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// If there are map registers, update them to reflect the number
|
||
// used.
|
||
//
|
||
|
||
if (translationEntry) {
|
||
|
||
translationEntry->Index += ADDRESS_AND_SIZE_TO_SPAN_PAGES(
|
||
CurrentVa,
|
||
transferLength
|
||
);
|
||
}
|
||
|
||
//
|
||
// If no adapter was specified, then work is done.
|
||
//
|
||
//
|
||
// We only support 32 bits, but the return is 64. Just
|
||
// zero extend
|
||
//
|
||
|
||
if (masterDevice) {
|
||
return(RtlConvertUlongToLargeInteger(logicalAddress));
|
||
}
|
||
|
||
//
|
||
// Determine the mode based on the trasnfer direction.
|
||
//
|
||
|
||
adapterMode = AdapterObject->AdapterMode;
|
||
((PDMA_EISA_MODE) &adapterMode)->TransferType =
|
||
(UCHAR) (WriteToDevice ? WRITE_TRANSFER : READ_TRANSFER);
|
||
|
||
returnAddress = logicalAddress;
|
||
bytePointer = (PUCHAR) &logicalAddress;
|
||
|
||
if (AdapterObject->Width16Bits) {
|
||
|
||
//
|
||
// if this is 16 bit wide, adjust the length and address
|
||
//
|
||
|
||
transferLength >>= 1;
|
||
|
||
//
|
||
// In 16 bit dma mode, the low 16 bits are shifted right one and
|
||
// the page register value is unchanged. So save the page register
|
||
// value and shift the logical address then restore the page value.
|
||
//
|
||
|
||
dataByte = bytePointer[2];
|
||
logicalAddress >>= 1;
|
||
bytePointer[2] = dataByte;
|
||
|
||
}
|
||
|
||
//
|
||
// Determine the controller number based on the adapter number.
|
||
//
|
||
|
||
if (AdapterObject->AdapterNumber == 1) {
|
||
|
||
//
|
||
// A request for DMA controller 1
|
||
//
|
||
|
||
PDMA1_CONTROL dmaControl;
|
||
|
||
dmaControl = AdapterObject->AdapterBaseVa;
|
||
|
||
WRITE_PORT_UCHAR ( &dmaControl->ClearBytePointer, 0);
|
||
|
||
WRITE_PORT_UCHAR ( &dmaControl->Mode, adapterMode);
|
||
|
||
WRITE_PORT_UCHAR (
|
||
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
|
||
.DmaBaseAddress,
|
||
bytePointer[0]
|
||
);
|
||
|
||
|
||
WRITE_PORT_UCHAR (
|
||
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
|
||
.DmaBaseAddress,
|
||
bytePointer[1]
|
||
);
|
||
|
||
|
||
WRITE_PORT_UCHAR (
|
||
((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort)
|
||
+ (ULONG) AdapterObject->PagePort,
|
||
bytePointer[2]
|
||
);
|
||
|
||
if (eisaSystem) {
|
||
|
||
//
|
||
// Write the high page register with zero. This sets a mode
|
||
// that allows the page register to be tied with the base count
|
||
// into a single address register
|
||
//
|
||
|
||
WRITE_PORT_UCHAR(
|
||
((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort)
|
||
+ (ULONG)AdapterObject->PagePort,
|
||
0
|
||
);
|
||
}
|
||
|
||
//
|
||
// Notify the DMA chip of the length
|
||
//
|
||
|
||
WRITE_PORT_UCHAR(
|
||
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
|
||
.DmaBaseCount,
|
||
(UCHAR) ((transferLength -1) & 0xff)
|
||
);
|
||
|
||
WRITE_PORT_UCHAR(
|
||
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
|
||
.DmaBaseCount,
|
||
(UCHAR) ((transferLength -1) >> 8)
|
||
);
|
||
|
||
//
|
||
// Set the DMA chip to read or write and unmask it
|
||
//
|
||
|
||
WRITE_PORT_UCHAR(
|
||
&dmaControl->SingleMask,
|
||
(UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
|
||
);
|
||
|
||
|
||
} else {
|
||
|
||
//
|
||
// This is a request for DMA controller 2
|
||
//
|
||
|
||
PDMA2_CONTROL dmaControl;
|
||
dmaControl = AdapterObject->AdapterBaseVa;
|
||
|
||
WRITE_PORT_UCHAR ( &dmaControl->ClearBytePointer, 0);
|
||
|
||
WRITE_PORT_UCHAR ( &dmaControl->Mode, adapterMode);
|
||
|
||
WRITE_PORT_UCHAR (
|
||
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
|
||
.DmaBaseAddress,
|
||
bytePointer[0]
|
||
);
|
||
|
||
|
||
WRITE_PORT_UCHAR (
|
||
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
|
||
.DmaBaseAddress,
|
||
bytePointer[1]
|
||
);
|
||
|
||
|
||
WRITE_PORT_UCHAR (
|
||
((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort)
|
||
+ (ULONG) AdapterObject->PagePort,
|
||
bytePointer[2]
|
||
);
|
||
|
||
if (eisaSystem) {
|
||
|
||
//
|
||
// Write the high page register with zero. This sets a mode
|
||
// that allows the page register to be tied with the base count
|
||
// into a single address register
|
||
//
|
||
|
||
WRITE_PORT_UCHAR(
|
||
((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort)
|
||
+ (ULONG)AdapterObject->PagePort,
|
||
0
|
||
);
|
||
}
|
||
|
||
//
|
||
// Notify the DMA chip of the length
|
||
//
|
||
|
||
WRITE_PORT_UCHAR(
|
||
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
|
||
.DmaBaseCount,
|
||
(UCHAR) ((transferLength -1) & 0xff)
|
||
);
|
||
|
||
WRITE_PORT_UCHAR(
|
||
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
|
||
.DmaBaseCount,
|
||
(UCHAR) ((transferLength -1) >> 8)
|
||
);
|
||
|
||
//
|
||
// Set the DMA chip to read or write and unmask it
|
||
//
|
||
|
||
WRITE_PORT_UCHAR(
|
||
&dmaControl->SingleMask,
|
||
(UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
|
||
);
|
||
|
||
|
||
}
|
||
|
||
return(RtlConvertUlongToLargeInteger(returnAddress));
|
||
|
||
}
|
||
|
||
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. For the Jensen system
|
||
its clears the enable flag which aborts the dma.
|
||
|
||
Arguments:
|
||
|
||
AdapterObject - Pointer to the adapter object representing the DMA
|
||
controller channel.
|
||
|
||
Mdl - A pointer to a Memory Descriptor List (MDL) that maps the locked-down
|
||
buffer to/from which the I/O occured.
|
||
|
||
MapRegisterBase - A pointer to the base of the map registers in the adapter
|
||
or DMA controller.
|
||
|
||
CurrentVa - The current virtual address in the buffer described the the Mdl
|
||
where the I/O operation occurred.
|
||
|
||
Length - Supplies the length of the transfer.
|
||
|
||
WriteToDevice - Supplies a BOOLEAN value that indicates the direction of
|
||
the data transfer was to the device.
|
||
|
||
Return Value:
|
||
|
||
TRUE - If the transfer was successful.
|
||
|
||
FALSE - If there was an error in the transfer.
|
||
|
||
--*/
|
||
{
|
||
|
||
PTRANSLATION_ENTRY translationEntry;
|
||
PULONG pageFrame;
|
||
ULONG transferLength;
|
||
ULONG partialLength;
|
||
BOOLEAN masterDevice;
|
||
|
||
masterDevice = AdapterObject == NULL || AdapterObject->MasterDevice ?
|
||
TRUE : FALSE;
|
||
|
||
translationEntry = MapRegisterBase;
|
||
|
||
//
|
||
// Clear the index of used buffers
|
||
//
|
||
|
||
if (translationEntry) {
|
||
|
||
translationEntry->Index = 0;
|
||
|
||
}
|
||
|
||
//
|
||
// Determine if the data needs to be copied to the orignal buffer.
|
||
// This happens if the transfer is from a device, the MapRegisterBase
|
||
// is not NULL and the xfer spans a page.
|
||
//
|
||
|
||
if (!WriteToDevice && translationEntry) {
|
||
|
||
//
|
||
// if this is not a master device, then just xfer the buffer
|
||
//
|
||
|
||
if (ADDRESS_AND_SIZE_TO_SPAN_PAGES(CurrentVa, Length) > 1 &&
|
||
!masterDevice) {
|
||
|
||
HalpCopyBufferMap(
|
||
Mdl,
|
||
translationEntry,
|
||
CurrentVa,
|
||
Length,
|
||
WriteToDevice
|
||
);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Cycle through the pages of the xfer to determine if there
|
||
// are any which need to be copied back
|
||
//
|
||
|
||
transferLength = PAGE_SIZE - BYTE_OFFSET(CurrentVa);
|
||
partialLength = transferLength;
|
||
pageFrame = (PULONG) (Mdl + 1);
|
||
pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) / PAGE_SIZE;
|
||
|
||
while (transferLength <= Length) {
|
||
|
||
if (*pageFrame >= BYTES_TO_PAGES(MAXIMUM_ISA_PHYSICAL_ADDRESS)) {
|
||
|
||
HalpCopyBufferMap(
|
||
Mdl,
|
||
translationEntry,
|
||
CurrentVa,
|
||
partialLength,
|
||
WriteToDevice
|
||
);
|
||
}
|
||
|
||
(PCCHAR) CurrentVa += partialLength;
|
||
partialLength = PAGE_SIZE;
|
||
|
||
//
|
||
// Note that transferLength indicates the amount which will be
|
||
// transfered after the next loop. thus it is updated with the
|
||
// new partial length.
|
||
//
|
||
|
||
transferLength += partialLength;
|
||
pageFrame++;
|
||
translationEntry++;
|
||
}
|
||
|
||
//
|
||
// Process any remaining residue
|
||
//
|
||
|
||
partialLength = Length - transferLength + partialLength;
|
||
if (partialLength && *pageFrame >= BYTES_TO_PAGES(MAXIMUM_ISA_PHYSICAL_ADDRESS)) {
|
||
|
||
HalpCopyBufferMap(
|
||
Mdl,
|
||
translationEntry,
|
||
CurrentVa,
|
||
partialLength,
|
||
WriteToDevice
|
||
);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// If this is a master device, then there's no more work to do.
|
||
|
||
if (masterDevice) {
|
||
|
||
return(TRUE);
|
||
|
||
}
|
||
|
||
//
|
||
// Mask the DMA request line so that DMA requests are inhibited
|
||
//
|
||
|
||
if (AdapterObject->AdapterNumber == 1) {
|
||
|
||
//
|
||
// DMA controller 1
|
||
//
|
||
|
||
PDMA1_CONTROL dmaControl;
|
||
|
||
dmaControl = AdapterObject->AdapterBaseVa;
|
||
|
||
WRITE_PORT_UCHAR(
|
||
&dmaControl->SingleMask,
|
||
(UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber)
|
||
);
|
||
|
||
} else {
|
||
|
||
//
|
||
// DMA controller 2
|
||
//
|
||
|
||
PDMA2_CONTROL dmaControl;
|
||
|
||
dmaControl = AdapterObject->AdapterBaseVa;
|
||
|
||
WRITE_PORT_UCHAR(
|
||
&dmaControl->SingleMask,
|
||
(UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber)
|
||
);
|
||
|
||
}
|
||
|
||
return(TRUE);
|
||
|
||
}
|
||
|
||
PHYSICAL_ADDRESS
|
||
MmGetPhysicalAddress (
|
||
IN PVOID BaseAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function returns the corresponding physical address for a
|
||
valid virtual address. I mask out the superpage mode bit, so that
|
||
what is returned is a real physical address.
|
||
|
||
Arguments:
|
||
|
||
BaseAddress - Supplies the virtual address for which to return the
|
||
physical address.
|
||
|
||
Return Value:
|
||
|
||
Returns the corresponding physical address.
|
||
|
||
Environment:
|
||
|
||
Kernel mode. Any IRQL level.
|
||
|
||
--*/
|
||
|
||
{
|
||
PHYSICAL_ADDRESS PhysicalAddress;
|
||
|
||
PhysicalAddress.HighPart = 0;
|
||
PhysicalAddress.LowPart = (ULONG)BaseAddress & 0x07fffffff;
|
||
|
||
return(PhysicalAddress);
|
||
}
|
||
|
||
PVOID
|
||
MmAllocateNonCachedMemory (
|
||
IN ULONG NumberOfBytes
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The MIPS description:
|
||
|
||
This function allocates a range of noncached memory in
|
||
the non-paged portion of the system address space.
|
||
|
||
This routine is designed to be used by a driver's initialization
|
||
routine to allocate a noncached block of virtual memory for
|
||
various device specific buffers.
|
||
|
||
The Alpha description:
|
||
|
||
Since Alpha data caches are kept coherent with DMA, this just
|
||
allocates a section of memory for the caller. It may be in the
|
||
cache.
|
||
|
||
|
||
Arguments:
|
||
|
||
NumberOfBytes - Supplies the number of bytes to allocate.
|
||
|
||
Return Value:
|
||
|
||
NULL - the specified request could not be satisfied.
|
||
|
||
NON-NULL - Returns a pointer (virtual address in the nonpaged portion
|
||
of the system) to the allocated physically contiguous
|
||
memory.
|
||
|
||
Environment:
|
||
|
||
Kernel mode, IRQL of APC_LEVEL or below.
|
||
|
||
--*/
|
||
|
||
{
|
||
return (FwAllocatePool(NumberOfBytes));
|
||
}
|
||
|
||
PVOID
|
||
MmMapIoSpace (
|
||
IN PHYSICAL_ADDRESS PhysicalAddress,
|
||
IN ULONG NumberOfBytes,
|
||
IN BOOLEAN CacheEnable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function returns the corresponding virtual address for a
|
||
known physical I/O address.
|
||
|
||
Arguments:
|
||
|
||
PhysicalAddress - Supplies the physical address.
|
||
|
||
NumberOfBytes - Unused.
|
||
|
||
CacheEnable - Unused.
|
||
|
||
Return Value:
|
||
|
||
Returns the corresponding meta-virtual address.
|
||
|
||
Environment:
|
||
|
||
Kernel mode. Any IRQL level.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// For ISA machines, this routine should be null.
|
||
//
|
||
|
||
#ifdef EISA_PLATFORM
|
||
|
||
PCCHAR VirtualAddress;
|
||
|
||
//
|
||
// switch on bits <33:32> of the physical address
|
||
//
|
||
|
||
switch (PhysicalAddress.HighPart & 3) {
|
||
|
||
case 0: /* memory space, this is an error. */
|
||
return(NULL);
|
||
break;
|
||
|
||
case 1: /* "Combo" space */
|
||
VirtualAddress =
|
||
(PVOID)
|
||
(COMBO_QVA |
|
||
0x800000 |
|
||
((PhysicalAddress.LowPart >> COMBO_BIT_SHIFT) &
|
||
0x7fffff)
|
||
);
|
||
break;
|
||
|
||
case 2: /* EISA memory space */
|
||
VirtualAddress =
|
||
(PVOID)
|
||
(EISA_QVA |
|
||
0x0000000 |
|
||
((PhysicalAddress.LowPart >> EISA_BIT_SHIFT) &
|
||
0x1ffffff)
|
||
);
|
||
break;
|
||
|
||
case 3: /* EISA I/O space */
|
||
VirtualAddress =
|
||
(PVOID)
|
||
(EISA_QVA |
|
||
0x8000000 |
|
||
((PhysicalAddress.LowPart >> EISA_BIT_SHIFT) &
|
||
0x1ffffff)
|
||
);
|
||
break;
|
||
|
||
}
|
||
|
||
return(VirtualAddress);
|
||
|
||
#endif // EISA_PLATFORM
|
||
|
||
}
|