mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 09:34:43 +00:00
Fixes to get slave DMA working again, as well as more architectural changes
that bring us closer to the Windows 2000 DMA model. adapter.c: significantly re-worked and heavily commented hal.h: more additions to ADAPTER_OBJECT; more pending dma.c: added initialization of ADAPTER_OBJECT ndis/io.c: minor DMA changes and addition of fixmes svn path=/trunk/; revision=6411
This commit is contained in:
parent
47be3186ac
commit
3c640340fe
4 changed files with 194 additions and 85 deletions
|
@ -363,9 +363,8 @@ NdisMAllocateMapRegisters(
|
|||
|
||||
Description.Version = DEVICE_DESCRIPTION_VERSION;
|
||||
Description.Master = TRUE; /* implied by calling this function */
|
||||
Description.ScatterGather = TRUE; /* All BM DMA are S/G (ms seems to do this) */
|
||||
Description.ScatterGather = TRUE; /* XXX UNTRUE: All BM DMA are S/G (ms seems to do this) */
|
||||
Description.Dma32BitAddresses = DmaSize;
|
||||
Description.Dma64BitAddresses = 0; /* FIXME figure this out based on input */
|
||||
Description.BusNumber = Adapter->BusNumber;
|
||||
Description.InterfaceType = Adapter->BusType;
|
||||
Description.DmaChannel = DmaChannel;
|
||||
|
@ -373,6 +372,7 @@ NdisMAllocateMapRegisters(
|
|||
|
||||
if(Adapter->NdisMiniportBlock.AdapterType == Isa)
|
||||
{
|
||||
/* system dma */
|
||||
if(DmaChannel < 4)
|
||||
Description.DmaWidth = Width8Bits;
|
||||
else
|
||||
|
@ -382,7 +382,6 @@ NdisMAllocateMapRegisters(
|
|||
}
|
||||
else if(Adapter->NdisMiniportBlock.AdapterType == PCIBus)
|
||||
{
|
||||
/* Width and Speed are automatically determined on PCI */
|
||||
if(DmaSize == NDIS_DMA_64BITS)
|
||||
Description.Dma64BitAddresses = TRUE;
|
||||
else
|
||||
|
@ -394,12 +393,6 @@ NdisMAllocateMapRegisters(
|
|||
ASSERT(0);
|
||||
}
|
||||
|
||||
Description.Reserved1 = 0; /* Must Be Zero (ref DDK) */
|
||||
Description.DemandMode = 0; /* unused due to bus master */
|
||||
Description.AutoInitialize = 0; /* unused due to bus master */
|
||||
Description.IgnoreCount = 0; /* unused due to bus master */
|
||||
Description.DmaPort = 0; /* unused due to bus type */
|
||||
|
||||
AvailableMapRegisters = MapRegistersRequired;
|
||||
AdapterObject = HalGetAdapter(&Description, &AvailableMapRegisters);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: adapter.c,v 1.6 2003/10/20 06:03:28 vizzini Exp $
|
||||
/* $Id: adapter.c,v 1.7 2003/10/23 09:03:51 vizzini Exp $
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
|
@ -22,6 +22,7 @@
|
|||
|
||||
/* NOTE: IoAllocateAdapterChannel in NTOSKRNL.EXE */
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
HalAllocateAdapterChannel(PADAPTER_OBJECT AdapterObject,
|
||||
PWAIT_CONTEXT_BLOCK WaitContextBlock,
|
||||
|
@ -39,76 +40,77 @@ HalAllocateAdapterChannel(PADAPTER_OBJECT AdapterObject,
|
|||
* STATUS_SUCCESS in all other cases, including if the callbacak had
|
||||
* to be queued for later delivery
|
||||
* NOTES:
|
||||
* - Map registers don't exist on X86 so we can just call the callback
|
||||
* with a map register base of 0
|
||||
* - the ADAPTER_OBJECT struct is undocumented; please make copious
|
||||
* notes here if anything is changed or improved since there is
|
||||
* no other documentation for this routine or its data structures
|
||||
* - The original implementation of this function allocated a contiguous
|
||||
* physical buffer the size of NumberOfMapRegisters * PAGE_SIZE, which
|
||||
* is unnecessary and very expensive (contiguous memory is rare). It
|
||||
* also leaked in some circumstances (drivers allocate and sometimes
|
||||
* don't free map registers)
|
||||
* notes in hal.h if anything is changed or improved since there is
|
||||
* no other documentation for this data structure
|
||||
* BUGS:
|
||||
* - This routine should check whether or not map registers are needed
|
||||
* (rather than assuming they're not) and allocate them on platforms
|
||||
* that support them.
|
||||
* - it's possible that some of this code is in the wrong place
|
||||
* - there are many unhandled cases
|
||||
*/
|
||||
{
|
||||
#if 0
|
||||
KIRQL OldIrql;
|
||||
PVOID Buffer;
|
||||
int ret;
|
||||
LARGE_INTEGER MaxAddress;
|
||||
IO_ALLOCATION_ACTION Retval;
|
||||
|
||||
/* 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->DeviceQueue, (PKDEVICE_QUEUE_ENTRY)WaitContextBlock))
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
/* 24-bit max address due to 16-bit dma controllers */
|
||||
MaxAddress.QuadPart = 0x1000000;
|
||||
|
||||
/* why 64K alignment? */
|
||||
Buffer = MmAllocateContiguousAlignedMemory( NumberOfMapRegisters * PAGE_SIZE,
|
||||
MaxAddress,
|
||||
0x10000 );
|
||||
if( !Buffer )
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
AdapterObject->MapRegisterBase = MmAllocateContiguousAlignedMemory(
|
||||
NumberOfMapRegisters * PAGE_SIZE, MaxAddress, 0x10000 );
|
||||
|
||||
if(!AdapterObject->MapRegisterBase)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
KeAcquireSpinLock( &AdapterObject->SpinLock, &OldIrql );
|
||||
if( AdapterObject->Inuse )
|
||||
{
|
||||
// someone is already using it, we need to wait
|
||||
// create a wait block, and add it to the chain
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
else {
|
||||
AdapterObject->Inuse = TRUE;
|
||||
KeReleaseSpinLock( &AdapterObject->SpinLock, OldIrql );
|
||||
ret = ExecutionRoutine( DeviceObject,
|
||||
NULL,
|
||||
Buffer,
|
||||
WaitContextBlock->DriverContext );
|
||||
KeAcquireSpinLock( &AdapterObject->SpinLock, &OldIrql );
|
||||
if( ret == DeallocateObject )
|
||||
{
|
||||
MmFreeContiguousMemory( Buffer );
|
||||
AdapterObject->Inuse = FALSE;
|
||||
}
|
||||
else AdapterObject->Buffer = Buffer;
|
||||
}
|
||||
KeReleaseSpinLock( &AdapterObject->SpinLock, OldIrql );
|
||||
#endif
|
||||
|
||||
AdapterObject->MapRegisterBase = 0;
|
||||
AdapterObject->AllocatedMapRegisters = 0;
|
||||
AdapterObject->AllocatedMapRegisters = NumberOfMapRegisters;
|
||||
|
||||
IO_ALLOCATION_ACTION Retval = ExecutionRoutine(WaitContextBlock->DeviceObject,
|
||||
WaitContextBlock->CurrentIrp, 0, WaitContextBlock->DeviceContext);
|
||||
/* call the client's AdapterControl callback with its map registers and context */
|
||||
Retval = ExecutionRoutine(WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp,
|
||||
AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext);
|
||||
|
||||
if(Retval == DeallocateObject)
|
||||
IoFreeAdapterChannel(AdapterObject);
|
||||
/*
|
||||
* 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)
|
||||
AdapterObject->AllocatedMapRegisters = 0;
|
||||
{
|
||||
/* don't free the allocated map registers - this is what IoFreeAdapterChannel checks */
|
||||
AdapterObject->AllocatedMapRegisters = 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 STDCALL
|
||||
IoFlushAdapterBuffers (PADAPTER_OBJECT AdapterObject,
|
||||
PMDL Mdl,
|
||||
|
@ -116,44 +118,124 @@ IoFlushAdapterBuffers (PADAPTER_OBJECT AdapterObject,
|
|||
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.
|
||||
*/
|
||||
{
|
||||
// if this was a read from device, copy data back to caller buffer, otherwise, do nothing
|
||||
if( !WriteToDevice )
|
||||
memcpy( (PVOID)((DWORD)MmGetSystemAddressForMdl( Mdl ) + (DWORD)CurrentVa - (DWORD)MmGetMdlVirtualAddress( Mdl )), MapRegisterBase, Length );
|
||||
/* FIXME we don't have ASSERT */
|
||||
//ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
||||
|
||||
/* this can happen if the card supports scatter/gather */
|
||||
if(!MapRegisterBase)
|
||||
return TRUE;
|
||||
|
||||
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.
|
||||
*/
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
|
||||
KeAcquireSpinLock( &AdapterObject->SpinLock, &OldIrql );
|
||||
if( AdapterObject->Inuse == FALSE )
|
||||
LARGE_INTEGER MaxAddress;
|
||||
PWAIT_CONTEXT_BLOCK WaitContextBlock;
|
||||
IO_ALLOCATION_ACTION Retval;
|
||||
|
||||
while(1)
|
||||
{
|
||||
DbgPrint( "Attempting to IoFreeAdapterChannel on a channel not in use\n" );
|
||||
KEBUGCHECK(0);
|
||||
/* To keep map registers, call here with the following set to 0 */
|
||||
if(AdapterObject->AllocatedMapRegisters)
|
||||
IoFreeMapRegisters(AdapterObject, AdapterObject->MapRegisterBase, AdapterObject->AllocatedMapRegisters);
|
||||
|
||||
if(!(WaitContextBlock = (PWAIT_CONTEXT_BLOCK)KeRemoveDeviceQueue(&AdapterObject->DeviceQueue)))
|
||||
break;
|
||||
|
||||
/*
|
||||
* the following should really be done elsewhere since this
|
||||
* function really can't return an error code. FIXME.
|
||||
*/
|
||||
|
||||
/* 24-bit max address due to 16-bit dma controllers */
|
||||
MaxAddress.QuadPart = 0x1000000;
|
||||
|
||||
AdapterObject->MapRegisterBase = MmAllocateContiguousAlignedMemory(
|
||||
WaitContextBlock->NumberOfMapRegisters * PAGE_SIZE, MaxAddress, 0x10000 );
|
||||
|
||||
if(!AdapterObject->MapRegisterBase)
|
||||
return;
|
||||
|
||||
/* call the adapter control routine */
|
||||
Retval = ((PDRIVER_CONTROL)WaitContextBlock->DeviceRoutine)(WaitContextBlock->DeviceObject, 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->AllocatedMapRegisters = 0;
|
||||
}
|
||||
}
|
||||
AdapterObject->Inuse = FALSE;
|
||||
if( AdapterObject->Buffer )
|
||||
{
|
||||
MmFreeContiguousMemory( AdapterObject->Buffer );
|
||||
AdapterObject->Buffer = 0;
|
||||
}
|
||||
KeReleaseSpinLock( &AdapterObject->SpinLock, OldIrql );
|
||||
}
|
||||
|
||||
|
||||
|
||||
VOID STDCALL
|
||||
IoFreeMapRegisters (PADAPTER_OBJECT AdapterObject,
|
||||
PVOID MapRegisterBase,
|
||||
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
|
||||
*/
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
if( AdapterObject->AllocatedMapRegisters )
|
||||
{
|
||||
MmFreeContiguousMemory(AdapterObject->MapRegisterBase);
|
||||
AdapterObject->MapRegisterBase = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
PHYSICAL_ADDRESS STDCALL
|
||||
IoMapTransfer (PADAPTER_OBJECT AdapterObject,
|
||||
PMDL Mdl,
|
||||
|
@ -161,6 +243,24 @@ IoMapTransfer (PADAPTER_OBJECT AdapterObject,
|
|||
PVOID CurrentVa,
|
||||
PULONG Length,
|
||||
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
|
||||
* Mdl: locked-down user buffer to DMA in to or out of
|
||||
* MapRegisterBase: handle to map registers to use for this dma
|
||||
* CurrentVa: index into Mdl to transfer into/out of
|
||||
* Length: length of transfer in/out
|
||||
* 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;
|
||||
// program up the dma controller, and return
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: dma.c,v 1.7 2003/09/11 11:45:28 ekohl Exp $
|
||||
/* $Id: dma.c,v 1.8 2003/10/23 09:03:51 vizzini Exp $
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
|
@ -16,6 +16,9 @@
|
|||
#include <internal/debug.h>
|
||||
#include <hal.h>
|
||||
|
||||
/* XXX This initialization is out of date - ADAPTER_OBJECT has changed */
|
||||
/* NOTE: The following initializations have to be kept in synch with ADAPTER_OBJECT in hal.h */
|
||||
/* FIXME: we need the 16-bit dma channels */
|
||||
ADAPTER_OBJECT IsaSlaveAdapterObjects[] = {
|
||||
{ Isa, FALSE, 0, (PVOID)0x87, (PVOID)0x1, (PVOID)0x0, 0, NULL },
|
||||
{ Isa, FALSE, 1, (PVOID)0x83, (PVOID)0x3, (PVOID)0x2, 0, NULL },
|
||||
|
@ -25,6 +28,8 @@ ADAPTER_OBJECT IsaSlaveAdapterObjects[] = {
|
|||
ADAPTER_OBJECT PciBusMasterAdapterObjects[] = {
|
||||
{ PCIBus, TRUE, 0, (PVOID)0, (PVOID)0, (PVOID)0x0, 0, NULL } };
|
||||
|
||||
/* Global flag to tell whether or not the adapter's device queue should be initialized (first call only) */
|
||||
BOOLEAN AdaptersInitialized = FALSE;
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
|
@ -112,6 +117,17 @@ HalGetAdapter (PDEVICE_DESCRIPTION DeviceDescription,
|
|||
* Figure out what to do with the commented-out cases
|
||||
*/
|
||||
{
|
||||
/* TODO: find a better home for this */
|
||||
if(!AdaptersInitialized)
|
||||
{
|
||||
KeInitializeDeviceQueue(&PciBusMasterAdapterObjects[0].DeviceQueue);
|
||||
KeInitializeDeviceQueue(&IsaSlaveAdapterObjects[0].DeviceQueue);
|
||||
KeInitializeDeviceQueue(&IsaSlaveAdapterObjects[1].DeviceQueue);
|
||||
KeInitializeDeviceQueue(&IsaSlaveAdapterObjects[2].DeviceQueue);
|
||||
KeInitializeDeviceQueue(&IsaSlaveAdapterObjects[3].DeviceQueue);
|
||||
AdaptersInitialized = TRUE;
|
||||
}
|
||||
|
||||
/* Validate parameters in device description, and return a pointer to
|
||||
the adapter object for the requested dma channel */
|
||||
if( DeviceDescription->Version != DEVICE_DESCRIPTION_VERSION )
|
||||
|
|
|
@ -57,8 +57,8 @@ struct _ADAPTER_OBJECT {
|
|||
PVOID MapRegisterBase;
|
||||
ULONG AllocatedMapRegisters;
|
||||
PWAIT_CONTEXT_BLOCK WaitContextBlock;
|
||||
PKDEVICE_QUEUE DeviceQueue;
|
||||
BOOLEAN UsesPhysicalMapRegisters;
|
||||
KDEVICE_QUEUE DeviceQueue;
|
||||
BOOLEAN ScatterGather;
|
||||
};
|
||||
|
||||
/* sysinfo.c */
|
||||
|
|
Loading…
Reference in a new issue