Complete reimplementation of HAL DMA routines.
The key changes are
* Proper support for bus-master device adapters.
* Real implementation of map registers.
* Basic support for emulating scatter/gather DMA on
devices that don't support it in hardware.
* Support for transfers that aren't page aligned.
* Proper detection and support of EISA DMA controllers.
* Fixed prototype for HalFlushCommonBuffer.
Modified: trunk/reactos/hal/hal/hal.c
Modified: trunk/reactos/hal/hal/hal.def
Deleted: trunk/reactos/hal/halx86/generic/adapter.c
Modified: trunk/reactos/hal/halx86/generic/dma.c
Modified: trunk/reactos/hal/halx86/generic/generic.xml
Modified: trunk/reactos/hal/halx86/include/hal.h
Added: trunk/reactos/hal/halx86/include/haldma.h
Modified: trunk/reactos/hal/halx86/include/halp.h
_____
Modified: trunk/reactos/hal/hal/hal.c
--- trunk/reactos/hal/hal/hal.c 2005-08-21 20:44:47 UTC (rev 17469)
+++ trunk/reactos/hal/hal/hal.c 2005-08-22 08:39:42 UTC (rev 17470)
@@ -211,10 +211,7 @@
ULONG Unknown2,
ULONG Unknown3,
ULONG Unknown4,
- ULONG Unknown5,
- ULONG Unknown6,
- ULONG Unknown7,
- ULONG Unknown8)
+ ULONG Unknown5)
{
UNIMPLEMENTED;
_____
Modified: trunk/reactos/hal/hal/hal.def
--- trunk/reactos/hal/hal/hal.def 2005-08-21 20:44:47 UTC (rev
17469)
+++ trunk/reactos/hal/hal/hal.def 2005-08-22 08:39:42 UTC (rev
17470)
@@ -20,7 +20,7 @@
HalDisplayString@4
HalEnableSystemInterrupt@12
HalEndSystemInterrupt@8
-HalFlushCommonBuffer@32
+HalFlushCommonBuffer@20
HalFreeCommonBuffer@24
HalGetAdapter@8
HalGetBusData@20
_____
Deleted: trunk/reactos/hal/halx86/generic/adapter.c
--- trunk/reactos/hal/halx86/generic/adapter.c 2005-08-21 20:44:47 UTC
(rev 17469)
+++ trunk/reactos/hal/halx86/generic/adapter.c 2005-08-22 08:39:42 UTC
(rev 17470)
@@ -1,717 +0,0 @@
-/* $Id$
- *
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: hal/x86/adapter.c (from ntoskrnl/io/adapter.c)
- * PURPOSE: DMA handling
- * PROGRAMMERS: David Welch (welch(a)mcmail.com)
- * Vizzini (vizzini(a)plasmic.com)
- * UPDATE HISTORY:
- * Created 22/05/98
- * 18-Oct-2003 Vizzini DMA support modifications
- */
-
-/* INCLUDES
*****************************************************************/
-
-#include <hal.h>
-#define NDEBUG
-#include <debug.h>
-
-/* FUNCTIONS
*****************************************************************/
-
-/* NOTE: IoAllocateAdapterChannel in NTOSKRNL.EXE */
-
-
-NTSTATUS STDCALL
-HalAllocateAdapterChannel(
- PADAPTER_OBJECT AdapterObject,
- PWAIT_CONTEXT_BLOCK WaitContextBlock,
- ULONG NumberOfMapRegisters,
- PDRIVER_CONTROL ExecutionRoutine)
-/*
- * FUNCTION: Sets up an ADAPTER_OBJECT with map registers
- * ARGUMENTS:
- * - AdapterObject: pointer to an ADAPTER_OBJECT to set up
- * - WaitContextBlock: Context block to be used with
ExecutionRoutine
- * - NumberOfMapRegisters: number of map registers requested
- * - ExecutionRoutine: callback to call when map registers are
allocated
- * RETURNS:
- * STATUS_INSUFFICIENT_RESOURCES if map registers cannot be
allocated
- * STATUS_SUCCESS in all other cases, including if the callbacak
had
- * to be queued for later delivery
- * NOTES:
- * - the ADAPTER_OBJECT struct is undocumented; please make copious
- * notes in hal.h if anything is changed or improved since there
is
- * no other documentation for this data structure
- * BUGS:
- * - it's possible that some of this code is in the wrong place
- * - there are many unhandled cases
- */
-{
- LARGE_INTEGER MinAddress;
- LARGE_INTEGER MaxAddress;
- LARGE_INTEGER BoundryAddressMultiple;
- IO_ALLOCATION_ACTION Retval;
-
- ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-
- /*
- FIXME: return STATUS_INSUFFICIENT_RESOURCES if the
NumberOfMapRegisters
- requested is larger than the value returned by IoGetDmaAdapter.
- */
-
- /* set up the wait context block in case we can't run right away */
- WaitContextBlock->DeviceRoutine = ExecutionRoutine;
- WaitContextBlock->NumberOfMapRegisters = NumberOfMapRegisters;
-
- /* returns true if queued, else returns false and sets the queue to
busy */
- if(KeInsertDeviceQueue(&AdapterObject->ChannelWaitQueue,
&WaitContextBlock->WaitQueueEntry))
- return STATUS_SUCCESS;
-
- /* why 64K alignment? */
- /*
- * X86 lacks map registers, so for now, we allocate a contiguous
- * block of physical memory <16MB and copy all DMA buffers into
- * that. This can be optimized.
- *
- * FIXME: We propably shouldn't allocate the memory here for common
- * buffer transfers. See a comment in IoMapTransfer about common
buffer
- * support.
- */
-
- MinAddress.QuadPart = 0;
- BoundryAddressMultiple.QuadPart = 0;
- if ((AdapterObject->Dma64BitAddresses) &&
(AdapterObject->MasterDevice))
- {
- MaxAddress.QuadPart = 0xFFFFFFFFFFFFFFFFLL; /* 64Bit: >4GB
address range */
- }
- else if ((AdapterObject->Dma32BitAddresses) &&
(AdapterObject->MasterDevice))
- {
- MaxAddress.QuadPart = 0xFFFFFFFF; /* 32Bit: 4GB address range */
- }
- else
- {
- MaxAddress.QuadPart = 0x00FFFFFF; /* 24Bit: 16MB address range */
- if (AdapterObject->Width16Bits)
- {
- BoundryAddressMultiple.QuadPart = 0x20000; /* 128k boundary
*/
- }
- else
- {
- BoundryAddressMultiple.QuadPart = 0x10000; /* 64k boundary
*/
- }
- }
- AdapterObject->MapRegisterBase =
MmAllocateContiguousMemorySpecifyCache(
- NumberOfMapRegisters * PAGE_SIZE,
- MinAddress,
- MaxAddress,
- BoundryAddressMultiple,
- MmCached);
-
- if(!AdapterObject->MapRegisterBase)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- AdapterObject->CommittedMapRegisters = NumberOfMapRegisters;
-
- /* call the client's AdapterControl callback with its map registers
and context */
- Retval = ExecutionRoutine(WaitContextBlock->DeviceObject,
WaitContextBlock->CurrentIrp,
- AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext);
-
- /*
- * KeepObject: don't free any resources; the ADAPTER_OBJECT is still
in use
- * and the caller will call IoFreeAdapterChannel later
- *
- * DeallocateObject: Deallocate the map registers and release the
ADAPTER_OBJECT
- * so someone else can use it
- *
- * DeallocateObjectKeepRegisters: release the ADAPTER_OBJECT but hang
on to
- * the map registers. The client will later call
IoFreeMapRegisters.
- *
- * NOTE - IoFreeAdapterChannel runs the queue, so it must be called
- * unless the adapter object is not to be freed.
- */
- if( Retval == DeallocateObject )
- IoFreeAdapterChannel(AdapterObject);
- else if(Retval == DeallocateObjectKeepRegisters)
- {
- /* don't free the allocated map registers - this is what
IoFreeAdapterChannel checks */
- AdapterObject->CommittedMapRegisters = 0;
- IoFreeAdapterChannel(AdapterObject);
- }
-
- /*
- * if we don't call IoFreeAdapterChannel, the next device won't get
de-queued,
- * which is what we want.
- */
-
- return STATUS_SUCCESS;
-}
-
-
-BOOLEAN
-HalpGrowMapBuffers(
- IN PADAPTER_OBJECT AdapterObject,
- IN ULONG SizeOfMapBuffers)
-/*
- * FUNCTION: Allocate initial, or additional, map buffers for IO
adapters.
- * ARGUMENTS:
- * AdapterObject: DMA adapter to allocate buffers for.
- * SizeOfMapBuffers: Size of the map buffers to allocate
- * NOTES:
- * - Needs to be tested...
- */
-{
- //ULONG PagesToAllocate = BYTES_TO_PAGES(SizeOfMapBuffers);
-
- /* TODO: Allocation */
-
- return TRUE;
-}
-
-PADAPTER_OBJECT STDCALL
-HalpAllocateAdapterEx(
- ULONG NumberOfMapRegisters,
- BOOLEAN IsMaster,
- BOOLEAN Dma32BitAddresses)
-/*
- * FUNCTION: Allocates an ADAPTER_OBJECT, optionally creates the Master
Adapter.
- * ARGUMENTS:
- * - NumberOfMapRegisters: Number of map registers to allocate
- * - IsMaster: Wether this is a Master Device or not
- * - Dma32BitAddresses: Wether 32-bit Addresses are supported
- * RETURNS:
- * - Pointer to Adapter Object, or NULL if failure.
- * BUGS:
- * - Some stuff is unhandled/incomplete
- */
-{
- OBJECT_ATTRIBUTES ObjectAttributes;
- ULONG ObjectSize;
- ULONG BitmapSize;
- NTSTATUS Status;
- ULONG AllowedMapRegisters = 64;
- PADAPTER_OBJECT AdapterObject;
- HANDLE Handle;
-
- /* Allocate the Master Adapter if we haven't already
- but make sure we're not asked to do it now, and also check if
we need it */
- if ((MasterAdapter == NULL) && (!IsMaster) &&
(NumberOfMapRegisters)) {
-
- /* Allocate and Save */
- DPRINT("Allocating the Master Adapter Object\n");
- MasterAdapter =
HalpAllocateAdapterEx(NumberOfMapRegisters,
- TRUE,
- Dma32BitAddresses);
-
- /* Cancel on Failure */
- DPRINT("Checking if Master Adapter was allocated
properly\n");
- if (!MasterAdapter) return NULL;
- }
-
- /* Initialize the Object Attributes for the Adapter Object */
- InitializeObjectAttributes(&ObjectAttributes,
- NULL,
- OBJ_PERMANENT,
- NULL,
- NULL);
-
- /* Check if this is the Master Adapter, in which case we need to
allocate the bitmap */
- if (IsMaster) {
- /* Size due to the Bitmap + Bytes in the Bitmap Buffer
(8 bytes, 64 bits)*/
- BitmapSize = sizeof(RTL_BITMAP) + (AllowedMapRegisters +
7) / 8;
-
- /* We will put the Bitmap Buffer after the Adapter
Object for simplicity */
- ObjectSize = sizeof(ADAPTER_OBJECT) + BitmapSize;
- } else {
- ObjectSize = sizeof(ADAPTER_OBJECT);
- }
-
- /* Create and Allocate the Object */
- DPRINT("Creating the Object\n");
- Status = ObCreateObject(KernelMode,
- IoAdapterObjectType,
- &ObjectAttributes,
- KernelMode,
- NULL,
- ObjectSize,
- 0,
- 0,
- (PVOID)&AdapterObject);
-
- if (!NT_SUCCESS(Status)) return NULL;
-
- /* Add a Reference */
- DPRINT("Referencing the Object\n");
- Status = ObReferenceObjectByPointer(AdapterObject,
- FILE_READ_DATA |
FILE_WRITE_DATA,
- IoAdapterObjectType,
- KernelMode);
-
- if (!NT_SUCCESS(Status)) return NULL;
-
- /* It's a Valid Object, so now we can play with the memory */
- RtlZeroMemory(AdapterObject, sizeof(ADAPTER_OBJECT));
-
- /* Insert it into the Object Table */
- DPRINT("Inserting the Object\n");
- Status = ObInsertObject(AdapterObject,
- NULL,
- FILE_READ_DATA | FILE_WRITE_DATA,
- 0,
- NULL,
- &Handle);
-
- if (!NT_SUCCESS(Status)) return NULL;
-
- /* We don't want the handle */
- NtClose(Handle);
-
- /* Set up the Adapter Object fields */
- AdapterObject->MapRegistersPerChannel = 1;
-
- /* Set the Master if needed (master only needed if we use Map
Registers) */
- if (NumberOfMapRegisters) AdapterObject->MasterAdapter =
MasterAdapter;
-
- /* Initalize the Channel Wait queue, which every adapter has */
- DPRINT("Initializing the Device Queue of the Object\n");
- KeInitializeDeviceQueue(&AdapterObject->ChannelWaitQueue);
-
- /* Initialize the SpinLock, Queue and Bitmap, which are kept in
the Master Adapter only */
- if (IsMaster) {
-
- DPRINT("Initializing the Master Adapter Stuff\n");
- KeInitializeSpinLock(&AdapterObject->SpinLock);
- InitializeListHead(&AdapterObject->AdapterQueue);
-
- /* As said previously, we put them here for simplicity
*/
- AdapterObject->MapRegisters = (PVOID)(AdapterObject +
1);
-
- /* Set up Bitmap */
- RtlInitializeBitMap(AdapterObject->MapRegisters,
- (PULONG)(AdapterObject->MapRegisters
+ 1),
- AllowedMapRegisters);
-
- /* Reset the Bitmap */
- RtlSetAllBits(AdapterObject->MapRegisters);
- AdapterObject->NumberOfMapRegisters = 0;
- AdapterObject->CommittedMapRegisters = 0;
-
- /* Allocate Memory for the Map Registers */
- AdapterObject->MapRegisterBase =
ExAllocatePool(NonPagedPool,
-
AllowedMapRegisters * sizeof(DWORD));
-
- /* Clear them */
- RtlZeroMemory(AdapterObject->MapRegisterBase,
AllowedMapRegisters * sizeof(DWORD));
-
- /* Allocate the contigous memory */
- DPRINT("Allocating Buffers\n");
- HalpGrowMapBuffers(AdapterObject, 0x1000000);
- }
-
- DPRINT("Adapter Object allocated\n");
- return AdapterObject;
-}
-
-
-BOOLEAN STDCALL
-IoFlushAdapterBuffers (
- PADAPTER_OBJECT AdapterObject,
- PMDL Mdl,
- PVOID MapRegisterBase,
- PVOID CurrentVa,
- ULONG Length,
- BOOLEAN WriteToDevice)
-/*
- * FUNCTION: flush any data remaining in the dma controller's memory
into the host memory
- * ARGUMENTS:
- * AdapterObject: the adapter object to flush
- * Mdl: original MDL to flush data into
- * MapRegisterBase: map register base that was just used by
IoMapTransfer, etc
- * CurrentVa: offset into Mdl to be flushed into, same as was
passed to IoMapTransfer
- * Length: length of the buffer to be flushed into
- * WriteToDevice: True if it's a write, False if it's a read
- * RETURNS:
- * TRUE in all cases
- * NOTES:
- * - This copies data from the map register-backed buffer to the
user's target buffer.
- * Data is not in the user buffer until this is called.
- * - This is only meaningful on a read operation. Return
immediately for a write.
- */
-{
- ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
-
- /* this can happen if the card supports scatter/gather */
- if(!MapRegisterBase)
- return TRUE;
-
- /* mask out (disable) the dma channel */
- if (AdapterObject->AdapterNumber == 1) {
-
- /* Set this for Ease */
- PDMA1_CONTROL DmaControl1 =
AdapterObject->AdapterBaseVa;
-
- /* Set Channel */
- WRITE_PORT_UCHAR(&DmaControl1->SingleMask,
AdapterObject->ChannelNumber | DMA_SETMASK);
- } else {
- /* Set this for Ease */
- PDMA2_CONTROL DmaControl2 =
AdapterObject->AdapterBaseVa;
-
- /* Set Channel */
- WRITE_PORT_UCHAR(&DmaControl2->SingleMask,
(AdapterObject->ChannelNumber - 4) | DMA_SETMASK);
- }
-
- if(WriteToDevice)
- return TRUE;
-
- memcpy(
- (PVOID)((DWORD)MmGetSystemAddressForMdl( Mdl ) +
(DWORD)CurrentVa - (DWORD)MmGetMdlVirtualAddress( Mdl )),
- MapRegisterBase, Length );
-
- return TRUE;
-}
-
-
-VOID STDCALL
-IoFreeAdapterChannel (PADAPTER_OBJECT AdapterObject)
-/*
- * FUNCTION: frees DMA resources allocated by IoAllocateAdapterChannel
- * ARGUMENTS:
- * AdapterObject: Adapter object with resources to free
- * NOTES:
- * - This function releases the DMA adapter and optionally the map
registers
- * - After releasing the adapter, it checks the adapter's queue and
runs
- * each queued device object in series until the queue is empty
- * - This is the only way the device queue is emptied.
- */
-{
- LARGE_INTEGER MaxAddress;
- LARGE_INTEGER MinAddress;
- LARGE_INTEGER BoundryAddressMultiple;
- PWAIT_CONTEXT_BLOCK WaitContextBlock;
- IO_ALLOCATION_ACTION Retval;
-
- while(1)
- {
- /* To keep map registers, call here with the following set to 0
*/
- if(AdapterObject->CommittedMapRegisters)
- IoFreeMapRegisters(AdapterObject,
AdapterObject->MapRegisterBase, AdapterObject->CommittedMapRegisters);
-
- if(!(WaitContextBlock =
(PWAIT_CONTEXT_BLOCK)KeRemoveDeviceQueue(&AdapterObject->ChannelWaitQueu
e)))
- break;
-
- /*
- * the following should really be done elsewhere since this
- * function really can't return an error code. FIXME.
- */
-
- MinAddress.QuadPart = 0;
- BoundryAddressMultiple.QuadPart = 0;
- if ((AdapterObject->Dma64BitAddresses) &&
(AdapterObject->MasterDevice))
- {
- MaxAddress.QuadPart = 0xFFFFFFFFFFFFFFFFLL; /* 64Bit: >4GB
address range */
- }
- else if ((AdapterObject->Dma32BitAddresses) &&
(AdapterObject->MasterDevice))
- {
- MaxAddress.QuadPart = 0xFFFFFFFF; /* 32Bit: 4GB address range
*/
- }
- else
- {
- MaxAddress.QuadPart = 0x00FFFFFF; /* 24Bit: 16MB address
range */
- if (AdapterObject->Width16Bits)
- {
- BoundryAddressMultiple.QuadPart = 0x20000; /* 128k
boundary */
- }
- else
- {
- BoundryAddressMultiple.QuadPart = 0x10000; /* 64k
boundary */
- }
- }
-
- AdapterObject->MapRegisterBase =
MmAllocateContiguousMemorySpecifyCache(
- WaitContextBlock->NumberOfMapRegisters * PAGE_SIZE,
- MinAddress,
- MaxAddress,
- BoundryAddressMultiple,
- MmCached);
-
- if(!AdapterObject->MapRegisterBase)
- return;
-
- /* call the adapter control routine */
- Retval =
((PDRIVER_CONTROL)WaitContextBlock->DeviceRoutine)(WaitContextBlock->Dev
iceObject, WaitContextBlock->CurrentIrp,
- AdapterObject->MapRegisterBase,
WaitContextBlock->DeviceContext);
-
- if(Retval == KeepObject)
- {
- /* we're done until the caller manually calls
IoFreeAdapterChannel */
- break;
- }
- else if(Retval == DeallocateObjectKeepRegisters)
- {
- /* hide the map registers so they aren't deallocated next
time around */
- AdapterObject->CommittedMapRegisters = 0;
- }
- }
-}
-
-
-VOID STDCALL
-IoFreeMapRegisters (
- IN PADAPTER_OBJECT AdapterObject,
- IN PVOID MapRegisterBase,
- IN ULONG NumberOfMapRegisters)
-/*
- * FUNCTION: free map registers reserved by the system for a DMA
- * ARGUMENTS:
- * AdapterObject: dma adapter to free map registers on
- * MapRegisterBase: hadle to map registers to free
- * NumberOfRegisters: number of map registers to be freed
- * NOTES:
- * - XXX real windows has a funky interdependence between
IoFreeMapRegisters
- * and IoFreeAdapterChannel
- * BUGS:
- * - needs to be improved to use a real map register implementation
- */
-{
- if( AdapterObject->CommittedMapRegisters )
- {
- MmFreeContiguousMemory(AdapterObject->MapRegisterBase);
- AdapterObject->MapRegisterBase = 0;
- }
-}
-
-
-PHYSICAL_ADDRESS STDCALL
-IoMapTransfer (
- IN PADAPTER_OBJECT AdapterObject,
- IN PMDL Mdl,
- IN PVOID MapRegisterBase,
- IN PVOID CurrentVa,
- IN OUT PULONG Length,
- IN BOOLEAN WriteToDevice)
-/*
- * FUNCTION: map a dma for transfer and do the dma if it's a slave
- * ARGUMENTS:
- * AdapterObject: adapter object to do the dma on. busmaster may
pass NULL.
- * Mdl: locked-down user buffer to DMA in to or out of
- * MapRegisterBase: handle to map registers to use for this dma.
allways NULL
- * when doing s/g.
- * CurrentVa: index into Mdl to transfer into/out of
- * Length: length of transfer in/out. Only modified on out when
doing s/g.
- * WriteToDevice: TRUE if it's an output dma, FALSE otherwise
- * RETURNS:
- * If a busmaster: A logical address that can be used to program a
dma controller
- * Otherwise: nothing meaningful
- * NOTES:
- * - This function does a copyover to contiguous memory <16MB
- * - If it's a slave transfer, this function actually performs it.
- * BUGS:
- * - If the controller supports scatter/gather, the copyover should
not happen
- */
-{
- PHYSICAL_ADDRESS Address;
- KIRQL OldIrql;
- ULONG LengthShift = 0;
-
- Address.QuadPart = 0;
-
- /* Isa System (slave) DMA? */
- if (MapRegisterBase && !AdapterObject->MasterDevice)
- {
- KeAcquireSpinLock(&AdapterObject->SpinLock, &OldIrql);
-
- /*
- * FIXME: Handle case when doing common-buffer System DMA. In this
case,
- * the buffer described by MDL is already phys. contiguous and
below
- * 16 mega. Driver makes a one-shot call to IoMapTransfer during
init.
- * to program controller with the common-buffer.
- *
- * UPDATE: Common buffer support is in place, but it's not done in
a
- * clean way. We use the buffer passed by the MDL in case that the
- * adapter object is marked as auto initialize. I'm not sure if
this
- * is correct and if not, how to do it properly. Note that it's
also
- * possible to allocate the common buffer with different adapter
object
- * and IoMapTransfer must still work in this case. Eventually this
should
- * be cleaned up somehow or at least this comment modified to
reflect
- * the reality.
- * -- Filip Navara, 19/07/2004
- */
-
- /* if it is a write to the device, copy the caller buffer to the
low buffer */
- if (WriteToDevice && !AdapterObject->AdapterMode.AutoInitialize)
- {
- memcpy(MapRegisterBase,
- (char*)MmGetSystemAddressForMdl(Mdl) + ((ULONG)CurrentVa -
(ULONG)MmGetMdlVirtualAddress(Mdl)),
- *Length );
- }
-
- /* Writer Adapter Mode, transfer type */
- AdapterObject->AdapterMode.TransferType = (WriteToDevice ?
WRITE_TRANSFER : READ_TRANSFER);
-
- /* program up the dma controller, and return */
- if (!AdapterObject->AdapterMode.AutoInitialize) {
- Address = MmGetPhysicalAddress( MapRegisterBase );
- } else {
- Address = MmGetPhysicalAddress( CurrentVa );
- }
-
- /* 16-bit DMA has a shifted length */
- if (AdapterObject->Width16Bits) {
- LengthShift = 1;
- }
-
- /* Make the Transfer */
- if (AdapterObject->AdapterNumber == 1) {
-
- PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; /* For
Writing Less Code */
-
- /* Mask the Channel */
- WRITE_PORT_UCHAR(&DmaControl1->SingleMask,
AdapterObject->ChannelNumber | DMA_SETMASK);
-
- /* Reset Register */
- WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0);
-
- /* Set the Mode */
- WRITE_PORT_UCHAR(&DmaControl1->Mode,
AdapterObject->AdapterModeByte);
-
- /* Set the Page Register */
- WRITE_PORT_UCHAR(AdapterObject->PagePort,
(UCHAR)(Address.u.LowPart >> 16));
-
- /* Set the Offset Register (apparently always 0 for us if I
trust the previous comment) */
-
WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNum
ber].DmaBaseAddress, 0);
-
WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNum
ber].DmaBaseAddress, 0);
-
- /* Set the Length */
-
WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNum
ber].DmaBaseCount,
- (UCHAR)((*Length >> LengthShift) - 1));
-
WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNum
ber].DmaBaseCount,
- (UCHAR)(((*Length >> LengthShift) - 1) >> 8));
-
- /* Unmask the Channel */
- WRITE_PORT_UCHAR(&DmaControl1->SingleMask,
AdapterObject->ChannelNumber | DMA_CLEARMASK);
- } else {
- PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; /*
For Writing Less Code */
-
- /* Mask the Channel */
- WRITE_PORT_UCHAR(&DmaControl2->SingleMask,
AdapterObject->ChannelNumber | DMA_SETMASK);
-
- /* Reset Register */
- WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0);
-
- /* Set the Mode */
- WRITE_PORT_UCHAR(&DmaControl2->Mode,
AdapterObject->AdapterModeByte);
-
- /* Set the Page Register */
- WRITE_PORT_UCHAR(AdapterObject->PagePort,
(UCHAR)(Address.u.LowPart >> 16));
-
- /* Set the Offset Register (apparently always 0 for us if I
trust the previous comment) */
-
WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNum
ber].DmaBaseAddress, 0);
-
WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNum
ber].DmaBaseAddress, 0);
-
- /* Set the Length */
-
WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNum
ber].DmaBaseCount,
- (UCHAR)((*Length >> LengthShift) - 1));
-
WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNum
ber].DmaBaseCount,
- (UCHAR)(((*Length >> LengthShift) - 1) >> 8));
-
- /* Unmask the Channel */
- WRITE_PORT_UCHAR(&DmaControl2->SingleMask,
AdapterObject->ChannelNumber | DMA_CLEARMASK);
- }
-
- /* Release Spinlock */
- KeReleaseSpinLock(&AdapterObject->SpinLock, OldIrql);
-
- /*
- NOTE: Return value should be ignored when doing System DMA.
- Maybe return some more obvious invalid address here (thou returning
- MapRegisterBase is also wrong;-)to catch invalid use?
- */
- Address.QuadPart = (ULONG)MapRegisterBase;
- return Address;
- }
-
-
- /*
- Busmaster with s/g support?
- NOTE: old docs allowed busmasters to pass a NULL Adapter. In this
case, MapRegisterBase
- being NULL is used to detect a s/g busmaster.
- */
- if ((!AdapterObject && !MapRegisterBase) ||
- (AdapterObject && AdapterObject->MasterDevice &&
AdapterObject->ScatterGather))
- {
- /*
- Just return the passed VA's corresponding phys. address.
- Update length to the number of phys. contiguous bytes found.
- */
-
- PULONG MdlPages;
- ULONG MdlPageIndex, PhysContiguousLen;
- ULONG PhysAddress;
-
- MdlPages = (PULONG)(Mdl + 1);
-
- /* Get VA's corresponding mdl phys. page index */
- MdlPageIndex = ((ULONG)CurrentVa - (ULONG)Mdl->StartVa) /
PAGE_SIZE;
-
- /* Get phys. page containing the VA */
- PhysAddress = MdlPages[MdlPageIndex];
-
- PhysContiguousLen = PAGE_SIZE - BYTE_OFFSET(CurrentVa);
-
- /* VA to map may span several contiguous phys. pages (unlikely) */
- while (PhysContiguousLen < *Length &&
- MdlPages[MdlPageIndex++] + PAGE_SIZE ==
MdlPages[MdlPageIndex])
- {
- /*
- Note that allways adding PAGE_SIZE may make PhysContiguousLen
greater
- than Length if buffer doesn't end on page boundary. Take this
- into consideration below.
- */
- PhysContiguousLen += PAGE_SIZE;
- }
-
- if (PhysContiguousLen < *Length)
- {
- *Length = PhysContiguousLen;
- }
-
- //add offset to phys. page address
- Address.QuadPart = PhysAddress + BYTE_OFFSET(CurrentVa);
- return Address;
- }
-
-
- /*
- Busmaster without s/g support?
- NOTE: old docs allowed busmasters to pass a NULL Adapter. In this
case, MapRegisterBase
- not being NULL is used to detect a non s/g busmaster.
- */
- if ((!AdapterObject && MapRegisterBase) ||
- (AdapterObject && AdapterObject->MasterDevice &&
!AdapterObject->ScatterGather))
- {
- /*
- NOTE: Busmasters doing common-buffer DMA shouldn't call
IoMapTransfer, but I don't
- know if it's illegal... Maybe figure out what to do in this case...
- */
-
- if( WriteToDevice )
- {
- memcpy(MapRegisterBase,
- (char*)MmGetSystemAddressForMdl(Mdl) + ((ULONG)CurrentVa -
(ULONG)MmGetMdlVirtualAddress(Mdl)),
- *Length );
- }
-
- return MmGetPhysicalAddress(MapRegisterBase);
- }
-
- DPRINT("IoMapTransfer: Unsupported operation\n");
- KEBUGCHECK(0);
- return Address;
-}
-
-
-/* EOF */
-
-
-
-
_____
Modified: trunk/reactos/hal/halx86/generic/dma.c
--- trunk/reactos/hal/halx86/generic/dma.c 2005-08-21 20:44:47 UTC
(rev 17469)
+++ trunk/reactos/hal/halx86/generic/dma.c 2005-08-22 08:39:42 UTC
(rev 17470)
@@ -5,459 +5,1898 @@
* FILE: ntoskrnl/hal/x86/dma.c
* PURPOSE: DMA functions
* PROGRAMMERS: David Welch (welch(a)mcmail.com)
+ * Filip Navara (navaraf(a)reactos.com)
* UPDATE HISTORY:
* Created 22/05/98
*/
+/**
+ * @page DMA Implementation Notes
+ *
+ * Concepts:
+ *
+ * - Map register
+ *
+ * Abstract encapsulation of physically contiguous buffer that
resides
+ * in memory accessible by both the DMA device / controller and the
system.
+ * The map registers are allocated and distributed on demand and are
+ * scarce resource.
+ *
+ * The actual use of map registers is to allow transfers from/to
buffer
+ * located in physical memory at address inaccessible by the DMA
device /
+ * controller directly. For such transfers the map register buffers
+ * are used as intermediate data storage.
+ *
+ * - Master adapter
+ *
+ * A container for map registers (typically corresponding to one
physical
+ * bus connection type). There can be master adapters for 24-bit
address
+ * ranges, 32-bit address ranges, etc. Every time a new DMA adapter
is
+ * created it's associated with a corresponding master adapter that
+ * is used for any map register allocation requests.
+ *
+ * - Bus-master / Slave DMA
+ *
+ * Slave DMA is term used for DMA transfers done by the system (E)ISA
+ * controller as opposed to transfers mastered by the device itself
+ * (hence the name).
+ *
+ * For slave DMA special care is taken to actually access the system
+ * controller and handle the transfers. The relevant code is in
+ * HalpDmaInitializeEisaAdapter, HalReadDmaCounter,
IoFlushAdapterBuffers
+ * and IoMapTransfer.
+ *
+ * Implementation:
+ *
+ * - Allocation of map registers
+ *
+ * Initial set of map registers is allocated on the system start to
+ * ensure that low memory won't get filled up later. Additional map
+ * registers are allocated as needed by HalpGrowMapBuffers. This
+ * routine is called on two places:
+ *
+ * - HalGetAdapter, since we're at PASSIVE_LEVEL and it's known that
+ * more map registers will probably be needed.
+ * - IoAllocateAdapterChannel (indirectly using
HalpGrowMapBufferWorker
+ * since we're at DISPATCH_LEVEL and call HalpGrowMapBuffers
directly)
+ * when no more map registers are free.
+ *
+ * Note that even if no more map registers can be allocated it's not
+ * the end of the world. The adapters waiting for free map registers
+ * are queued in the master adapter's queue and once one driver hands
+ * back it's map registers (using IoFreeMapRegisters or indirectly
using
+ * the execution routine callback in IoAllocateAdapterChannel) the
+ * queue gets processed and the map registers are reassigned.
+ */
+
/* INCLUDES
*****************************************************************/
#include <hal.h>
#define NDEBUG
#include <debug.h>
-/* Adapters for each channel */
-PADAPTER_OBJECT HalpEisaAdapter[8];
+static KEVENT HalpDmaLock;
+static LIST_ENTRY HalpDmaAdapterList;
+static PADAPTER_OBJECT HalpEisaAdapter[8];
+static BOOLEAN HalpEisaDma;
+static PADAPTER_OBJECT HalpMasterAdapter;
+static const ULONG_PTR HalpEisaPortPage[8] = {
+ FIELD_OFFSET(DMA_PAGE, Channel0),
+ FIELD_OFFSET(DMA_PAGE, Channel1),
+ FIELD_OFFSET(DMA_PAGE, Channel2),
+ FIELD_OFFSET(DMA_PAGE, Channel3),
+ 0,
+ FIELD_OFFSET(DMA_PAGE, Channel5),
+ FIELD_OFFSET(DMA_PAGE, Channel6),
+ FIELD_OFFSET(DMA_PAGE, Channel7)
+};
+
+static DMA_OPERATIONS HalpDmaOperations = {
+ sizeof(DMA_OPERATIONS),
+ (PPUT_DMA_ADAPTER)HalPutDmaAdapter,
+ (PALLOCATE_COMMON_BUFFER)HalAllocateCommonBuffer,
+ (PFREE_COMMON_BUFFER)HalFreeCommonBuffer,
+ (PALLOCATE_ADAPTER_CHANNEL)IoAllocateAdapterChannel,
+ (PFLUSH_ADAPTER_BUFFERS)IoFlushAdapterBuffers,
+ (PFREE_ADAPTER_CHANNEL)IoFreeAdapterChannel,
+ (PFREE_MAP_REGISTERS)IoFreeMapRegisters,
+ (PMAP_TRANSFER)IoMapTransfer,
+ (PGET_DMA_ALIGNMENT)HalpDmaGetDmaAlignment,
+ (PREAD_DMA_COUNTER)HalReadDmaCounter,
+ /* FIXME: Implement the S/G funtions. */
+ NULL /*(PGET_SCATTER_GATHER_LIST)HalGetScatterGatherList*/,
+ NULL /*(PPUT_SCATTER_GATHER_LIST)HalPutScatterGatherList*/,
+ NULL
/*(PCALCULATE_SCATTER_GATHER_LIST_SIZE)HalCalculateScatterGatherListSize
*/,
+ NULL /*(PBUILD_SCATTER_GATHER_LIST)HalBuildScatterGatherList*/,
+ NULL
/*(PBUILD_MDL_FROM_SCATTER_GATHER_LIST)HalBuildMdlFromScatterGatherList*
/
+};
+
+#define MAX_MAP_REGISTERS 64
+
+#define TAG_DMA TAG('D','M','A',' ')
+
/* FUNCTIONS
*****************************************************************/
VOID
-HalpInitDma (VOID)
+HalpInitDma(VOID)
{
- /* TODO: Initialize the first Map Buffer */
+ /*
+ * Check if Extended DMA is available. We're just going to do a
random
+ * read and write.
+ */
+
+ WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL,
DmaController2Pages.Channel2), 0x2A);
+ if (READ_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL,
DmaController2Pages.Channel2)) == 0x2A)
+ HalpEisaDma = TRUE;
+
+ /*
+ * Intialize all the global variables and allocate master adapter
with
+ * first map buffers.
+ */
+
+ InitializeListHead(&HalpDmaAdapterList);
+ KeInitializeEvent(&HalpDmaLock, NotificationEvent, TRUE);
+
+ HalpMasterAdapter = HalpDmaAllocateMasterAdapter();
}
-PVOID STDCALL
-HalAllocateCommonBuffer (PADAPTER_OBJECT AdapterObject,
- ULONG Length,
- PPHYSICAL_ADDRESS LogicalAddress,
- BOOLEAN CacheEnabled)
-/*
- * FUNCTION: Allocates memory that is visible to both the processor(s)
and
- * a dma device
- * ARGUMENTS:
- * AdapterObject = Adapter object representing the bus master
or
- * system dma controller
- * Length = Number of bytes to allocate
- * LogicalAddress = Logical address the driver can use to
access the
- * buffer
- * CacheEnabled = Specifies if the memory can be cached
- * RETURNS: The base virtual address of the memory allocated
- * NULL on failure
- * NOTES:
- * CacheEnabled is ignored - it's all cache-disabled (like in NT)
- * UPDATE: It's not ignored now. If that's wrong just modify the
- * CacheEnabled comparsion below.
+/**
+ * @name HalpGetAdapterMaximumPhysicalAddress
+ *
+ * Get the maximum physical address acceptable by the device
represented
+ * by the passed DMA adapter.
*/
+
+PHYSICAL_ADDRESS STDCALL
+HalpGetAdapterMaximumPhysicalAddress(
+ IN PADAPTER_OBJECT AdapterObject)
{
- PHYSICAL_ADDRESS LowestAddress, HighestAddress,
BoundryAddressMultiple;
- PVOID BaseAddress;
+ PHYSICAL_ADDRESS HighestAddress;
- LowestAddress.QuadPart = 0;
- BoundryAddressMultiple.QuadPart = 0;
- if ((AdapterObject->Dma64BitAddresses) &&
(AdapterObject->MasterDevice)) {
- HighestAddress.QuadPart = 0xFFFFFFFFFFFFFFFFLL; /* 64Bit: >4GB
address range */
-
- } else if ((AdapterObject->Dma32BitAddresses) &&
(AdapterObject->MasterDevice)) {
- HighestAddress.QuadPart = 0xFFFFFFFF; /* 32Bit: 4GB address range
*/
- } else {
- HighestAddress.QuadPart = 0x00FFFFFF; /* 24Bit: 16MB address
range */
- if (AdapterObject->Width16Bits)
+ if (AdapterObject->MasterDevice)
+ {
+ if (AdapterObject->Dma64BitAddresses)
{
- BoundryAddressMultiple.QuadPart = 0x20000; /* 128k boundary
*/
+ HighestAddress.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
+ return HighestAddress;
}
- else
+ else if (AdapterObject->Dma32BitAddresses)
{
- BoundryAddressMultiple.QuadPart = 0x10000; /* 64k boundary */
+ HighestAddress.QuadPart = 0xFFFFFFFF;
+ return HighestAddress;
}
- }
+ }
- BaseAddress = MmAllocateContiguousMemorySpecifyCache(
- Length,
- LowestAddress,
- HighestAddress,
- BoundryAddressMultiple,
- CacheEnabled ? MmCached : MmNonCached);
- if (!BaseAddress)
- return 0;
+ HighestAddress.QuadPart = 0xFFFFFF;
+ return HighestAddress;
+}
- *LogicalAddress = MmGetPhysicalAddress(BaseAddress);
+/**
+ * @name HalpGrowMapBuffers
+ *
+ * Allocate initial, or additional, map buffers for DMA master adapter.
+ *
+ * @param MasterAdapter
+ * DMA master adapter to allocate buffers for.
+ * @param SizeOfMapBuffers
+ * Size of the map buffers to allocate (not including the size
+ * already allocated).
+ */
- return BaseAddress;
+BOOLEAN STDCALL
+HalpGrowMapBuffers(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG SizeOfMapBuffers)
+{
+ PVOID VirtualAddress;
+ PHYSICAL_ADDRESS PhysicalAddress;
+ PHYSICAL_ADDRESS HighestAcceptableAddress;
+ PHYSICAL_ADDRESS LowestAcceptableAddress;
+ PHYSICAL_ADDRESS BoundryAddressMultiple;
+ KIRQL OldIrql;
[truncated at 1000 lines; 2839 more skipped]