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@mcmail.com) - * Vizzini (vizzini@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@mcmail.com) + * Filip Navara (navaraf@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]