-/* $Id$
+/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
/* INCLUDES *****************************************************************/
#include <hal.h>
+#include <suppress.h>
+
#define NDEBUG
#include <debug.h>
+#define MAX_SG_ELEMENTS 0x10
+
#ifndef _MINIHAL_
static KEVENT HalpDmaLock;
static LIST_ENTRY HalpDmaAdapterList;
(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*/,
+ (PGET_SCATTER_GATHER_LIST)HalGetScatterGatherList,
+ (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*/
#ifndef _MINIHAL_
VOID
+INIT_FUNCTION
HalpInitDma(VOID)
{
/*
KIRQL OldIrql;
ULONG MapRegisterCount;
- /* FIXME: Check if enough map register slots are available. */
+ /* Check if enough map register slots are available. */
MapRegisterCount = BYTES_TO_PAGES(SizeOfMapBuffers);
+ if (MapRegisterCount + AdapterObject->NumberOfMapRegisters > MAX_MAP_REGISTERS)
+ {
+ DPRINT("No more map register slots available! (Current: %d | Requested: %d | Limit: %d)\n",
+ AdapterObject->NumberOfMapRegisters,
+ MapRegisterCount,
+ MAX_MAP_REGISTERS);
+ return FALSE;
+ }
/*
* Allocate memory for the new map registers. For 32-bit adapters we use
}
RtlClearBit(AdapterObject->MapRegisters,
- CurrentEntry - AdapterObject->MapRegisterBase);
+ (ULONG)(CurrentEntry - AdapterObject->MapRegisterBase));
CurrentEntry->VirtualAddress = VirtualAddress;
CurrentEntry->PhysicalAddress = PhysicalAddress;
if (Controller == 1)
{
/* Set the Request Data */
+ _PRAGMA_WARNING_SUPPRESS(__WARNING_DEREF_NULL_PTR)
WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->Mode, DmaMode.Byte);
-
+
/* Unmask DMA Channel */
WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->SingleMask,
AdapterObject->ChannelNumber | DMA_CLEARMASK);
{
/* Set the Request Data */
WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->Mode, DmaMode.Byte);
-
+
/* Unmask DMA Channel */
WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->SingleMask,
AdapterObject->ChannelNumber | DMA_CLEARMASK);
OUT PULONG NumberOfMapRegisters)
{
PADAPTER_OBJECT AdapterObject = NULL;
- PADAPTER_OBJECT MasterAdapter;
BOOLEAN EisaAdapter;
ULONG MapRegisters;
ULONG MaximumLength;
* Also note that we check for channel number since there are only 8 DMA
* channels on ISA, so any request above this requires new adapter.
*/
- if ((DeviceDescription->InterfaceType == Isa) || !(DeviceDescription->Master))
+ if (((DeviceDescription->InterfaceType == Eisa) ||
+ (DeviceDescription->InterfaceType == Isa)) || !(DeviceDescription->Master))
{
- if ((DeviceDescription->InterfaceType == Isa) && (DeviceDescription->DmaChannel >= 8))
+ if (((DeviceDescription->InterfaceType == Isa) ||
+ (DeviceDescription->InterfaceType == Eisa)) &&
+ (DeviceDescription->DmaChannel >= 8))
{
EisaAdapter = FALSE;
}
if (MapRegisters > 0)
{
AdapterObject->NeedsMapRegisters = TRUE;
- MasterAdapter = HalpMasterAdapter;
AdapterObject->MapRegistersPerChannel = MapRegisters;
-
- /*
- * FIXME: Verify that the following makes sense. Actually
- * MasterAdapter->NumberOfMapRegisters contains even the number
- * of gaps, so this will not work correctly all the time. It
- * doesn't matter much since it's only optimization to avoid
- * queuing work items in HalAllocateAdapterChannel.
- */
- MasterAdapter->CommittedMapRegisters += MapRegisters;
- if (MasterAdapter->CommittedMapRegisters > MasterAdapter->NumberOfMapRegisters)
- {
- HalpGrowMapBuffers(MasterAdapter, 0x10000);
- }
}
else
{
Length,
CacheEnabled ? MmCached : MmNonCached);
}
+
+typedef struct _SCATTER_GATHER_CONTEXT {
+ PADAPTER_OBJECT AdapterObject;
+ PMDL Mdl;
+ PUCHAR CurrentVa;
+ ULONG Length;
+ PDRIVER_LIST_CONTROL AdapterListControlRoutine;
+ PVOID AdapterListControlContext, MapRegisterBase;
+ ULONG MapRegisterCount;
+ BOOLEAN WriteToDevice;
+} SCATTER_GATHER_CONTEXT, *PSCATTER_GATHER_CONTEXT;
+
+
+IO_ALLOCATION_ACTION
+NTAPI
+HalpScatterGatherAdapterControl(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context)
+{
+ PSCATTER_GATHER_CONTEXT AdapterControlContext = Context;
+ PADAPTER_OBJECT AdapterObject = AdapterControlContext->AdapterObject;
+ PSCATTER_GATHER_LIST ScatterGatherList;
+ SCATTER_GATHER_ELEMENT TempElements[MAX_SG_ELEMENTS];
+ ULONG ElementCount = 0, RemainingLength = AdapterControlContext->Length;
+ PUCHAR CurrentVa = AdapterControlContext->CurrentVa;
+
+ /* Store the map register base for later in HalPutScatterGatherList */
+ AdapterControlContext->MapRegisterBase = MapRegisterBase;
+
+ while (RemainingLength > 0 && ElementCount < MAX_SG_ELEMENTS)
+ {
+ TempElements[ElementCount].Length = RemainingLength;
+ TempElements[ElementCount].Reserved = 0;
+ TempElements[ElementCount].Address = IoMapTransfer(AdapterObject,
+ AdapterControlContext->Mdl,
+ MapRegisterBase,
+ CurrentVa + (AdapterControlContext->Length - RemainingLength),
+ &TempElements[ElementCount].Length,
+ AdapterControlContext->WriteToDevice);
+ if (TempElements[ElementCount].Length == 0)
+ break;
+
+ DPRINT("Allocated one S/G element: 0x%I64u with length: 0x%x\n",
+ TempElements[ElementCount].Address.QuadPart,
+ TempElements[ElementCount].Length);
+
+ ASSERT(TempElements[ElementCount].Length <= RemainingLength);
+ RemainingLength -= TempElements[ElementCount].Length;
+ ElementCount++;
+ }
+
+ if (RemainingLength > 0)
+ {
+ DPRINT1("Scatter/gather list construction failed!\n");
+ return DeallocateObject;
+ }
+
+ ScatterGatherList = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(SCATTER_GATHER_LIST) + sizeof(SCATTER_GATHER_ELEMENT) * ElementCount,
+ TAG_DMA);
+ ASSERT(ScatterGatherList);
+
+ ScatterGatherList->NumberOfElements = ElementCount;
+ ScatterGatherList->Reserved = (ULONG_PTR)AdapterControlContext;
+ RtlCopyMemory(ScatterGatherList->Elements,
+ TempElements,
+ sizeof(SCATTER_GATHER_ELEMENT) * ElementCount);
+
+ DPRINT("Initiating S/G DMA with %d element(s)\n", ElementCount);
+
+ AdapterControlContext->AdapterListControlRoutine(DeviceObject,
+ Irp,
+ ScatterGatherList,
+ AdapterControlContext->AdapterListControlContext);
+
+ return DeallocateObjectKeepRegisters;
+}
+
+/**
+ * @name HalGetScatterGatherList
+ *
+ * Creates a scatter-gather list to be using in scatter/gather DMA
+ *
+ * @param AdapterObject
+ * Adapter object representing the bus master or system dma controller.
+ * @param DeviceObject
+ * The device target for DMA.
+ * @param Mdl
+ * The MDL that describes the buffer to be mapped.
+ * @param CurrentVa
+ * The current VA in the buffer to be mapped for transfer.
+ * @param Length
+ * Specifies the length of data in bytes to be mapped.
+ * @param ExecutionRoutine
+ * A caller supplied AdapterListControl routine to be called when DMA is available.
+ * @param Context
+ * Context passed to the AdapterListControl routine.
+ * @param WriteToDevice
+ * Indicates direction of DMA operation.
+ *
+ * @return The status of the operation.
+ *
+ * @see HalPutScatterGatherList
+ *
+ * @implemented
+ */
+ NTSTATUS
+ NTAPI
+ HalGetScatterGatherList(IN PADAPTER_OBJECT AdapterObject,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PMDL Mdl,
+ IN PVOID CurrentVa,
+ IN ULONG Length,
+ IN PDRIVER_LIST_CONTROL ExecutionRoutine,
+ IN PVOID Context,
+ IN BOOLEAN WriteToDevice)
+{
+ PSCATTER_GATHER_CONTEXT AdapterControlContext;
+
+ AdapterControlContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCATTER_GATHER_CONTEXT), TAG_DMA);
+ if (!AdapterControlContext) return STATUS_INSUFFICIENT_RESOURCES;
+
+ AdapterControlContext->AdapterObject = AdapterObject;
+ AdapterControlContext->Mdl = Mdl;
+ AdapterControlContext->CurrentVa = CurrentVa;
+ AdapterControlContext->Length = Length;
+ AdapterControlContext->MapRegisterCount = PAGE_ROUND_UP(Length) >> PAGE_SHIFT;
+ AdapterControlContext->AdapterListControlRoutine = ExecutionRoutine;
+ AdapterControlContext->AdapterListControlContext = Context;
+ AdapterControlContext->WriteToDevice = WriteToDevice;
+
+ return IoAllocateAdapterChannel(AdapterObject,
+ DeviceObject,
+ AdapterControlContext->MapRegisterCount,
+ HalpScatterGatherAdapterControl,
+ AdapterControlContext);
+}
+
+/**
+ * @name HalPutScatterGatherList
+ *
+ * Frees a scatter-gather list allocated from HalGetScatterGatherList
+ *
+ * @param AdapterObject
+ * Adapter object representing the bus master or system dma controller.
+ * @param ScatterGather
+ * The scatter/gather list to be freed.
+ * @param WriteToDevice
+ * Indicates direction of DMA operation.
+ *
+ * @return None
+ *
+ * @see HalGetScatterGatherList
+ *
+ * @implemented
+ */
+ VOID
+ NTAPI
+ HalPutScatterGatherList(IN PADAPTER_OBJECT AdapterObject,
+ IN PSCATTER_GATHER_LIST ScatterGather,
+ IN BOOLEAN WriteToDevice)
+{
+ PSCATTER_GATHER_CONTEXT AdapterControlContext = (PSCATTER_GATHER_CONTEXT)ScatterGather->Reserved;
+ ULONG i;
+
+ for (i = 0; i < ScatterGather->NumberOfElements; i++)
+ {
+ IoFlushAdapterBuffers(AdapterObject,
+ AdapterControlContext->Mdl,
+ AdapterControlContext->MapRegisterBase,
+ AdapterControlContext->CurrentVa,
+ ScatterGather->Elements[i].Length,
+ AdapterControlContext->WriteToDevice);
+ AdapterControlContext->CurrentVa += ScatterGather->Elements[i].Length;
+ }
+
+ IoFreeMapRegisters(AdapterObject,
+ AdapterControlContext->MapRegisterBase,
+ AdapterControlContext->MapRegisterCount);
+
+ DPRINT("S/G DMA has finished!\n");
+
+ ExFreePoolWithTag(AdapterControlContext, TAG_DMA);
+ ExFreePoolWithTag(ScatterGather, TAG_DMA);
+}
#endif
/**
do
{
OldCount = Count;
-
+
/* Send Reset */
WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0);
-
+
/* Read Count */
Count = READ_PORT_UCHAR(&DmaControl1->DmaAddressCount
[AdapterObject->ChannelNumber].DmaBaseCount);
do
{
OldCount = Count;
-
+
/* Send Reset */
WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0);
-
+
/* Read Count */
Count = READ_PORT_UCHAR(&DmaControl2->DmaAddressCount
[AdapterObject->ChannelNumber].DmaBaseCount);
*/
KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, FALSE, NULL);
Succeeded = HalpGrowMapBuffers(WorkItem->AdapterObject->MasterAdapter,
- WorkItem->NumberOfMapRegisters);
+ WorkItem->NumberOfMapRegisters << PAGE_SHIFT);
KeSetEvent(&HalpDmaLock, 0, 0);
if (Succeeded)
if (Index == MAXULONG)
{
+ InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue);
+
WorkItem = ExAllocatePoolWithTag(NonPagedPool,
sizeof(GROW_WORK_ITEM),
TAG_DMA);
- if (!WorkItem)
+ if (WorkItem)
{
- KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
- AdapterObject->NumberOfMapRegisters = 0;
- IoFreeAdapterChannel(AdapterObject);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue);
+ ExInitializeWorkItem(&WorkItem->WorkQueueItem, HalpGrowMapBufferWorker, WorkItem);
+ WorkItem->AdapterObject = AdapterObject;
+ WorkItem->NumberOfMapRegisters = NumberOfMapRegisters;
- ExInitializeWorkItem(&WorkItem->WorkQueueItem, HalpGrowMapBufferWorker, WorkItem);
- WorkItem->AdapterObject = AdapterObject;
- WorkItem->NumberOfMapRegisters = NumberOfMapRegisters;
-
- ExQueueWorkItem(&WorkItem->WorkQueueItem, DelayedWorkQueue);
+ ExQueueWorkItem(&WorkItem->WorkQueueItem, DelayedWorkQueue);
+ }
KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
DeviceQueueEntry = KeRemoveDeviceQueue(&AdapterObject->ChannelWaitQueue);
if (!DeviceQueueEntry) break;
-
+
WaitContextBlock = CONTAINING_RECORD(DeviceQueueEntry,
WAIT_CONTEXT_BLOCK,
WaitQueueEntry);
RealMapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG);
RtlClearBits(MasterAdapter->MapRegisters,
- RealMapRegisterBase - MasterAdapter->MapRegisterBase,
+ (ULONG)(RealMapRegisterBase - MasterAdapter->MapRegisterBase),
NumberOfMapRegisters);
}
Index = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters,
AdapterObject->NumberOfMapRegisters,
- MasterAdapter->NumberOfMapRegisters);
+ 0);
if (Index == MAXULONG)
{
InsertHeadList(&MasterAdapter->AdapterQueue, ListEntry);
{
KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql);
RtlClearBits(MasterAdapter->MapRegisters,
- AdapterObject->MapRegisterBase -
- MasterAdapter->MapRegisterBase,
+ (ULONG)(AdapterObject->MapRegisterBase -
+ MasterAdapter->MapRegisterBase),
AdapterObject->NumberOfMapRegisters);
KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
}
-
+
IoFreeAdapterChannel(AdapterObject);
break;
/* Reset Register */
WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0);
-
+
/* Set the Mode */
WRITE_PORT_UCHAR(&DmaControl1->Mode, AdapterMode.Byte);
-
+
/* Set the Offset Register */
WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress,
(UCHAR)(TransferOffset));
WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress,
(UCHAR)(TransferOffset >> 8));
-
+
/* Set the Page Register */
WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController1Pages),
(UCHAR)(PhysicalAddress.LowPart >> 16));
WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController2Pages),
0);
}
-
+
/* Set the Length */
WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
(UCHAR)(TransferLength - 1));
WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
(UCHAR)((TransferLength - 1) >> 8));
-
+
/* Unmask the Channel */
WRITE_PORT_UCHAR(&DmaControl1->SingleMask, AdapterObject->ChannelNumber | DMA_CLEARMASK);
}
/* Reset Register */
WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0);
-
+
/* Set the Mode */
WRITE_PORT_UCHAR(&DmaControl2->Mode, AdapterMode.Byte);
-
+
/* Set the Offset Register */
WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress,
(UCHAR)(TransferOffset));
WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress,
(UCHAR)(TransferOffset >> 8));
-
+
/* Set the Page Register */
WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController1Pages),
(UCHAR)(PhysicalAddress.u.LowPart >> 16));
WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController2Pages),
0);
}
-
+
/* Set the Length */
WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
(UCHAR)(TransferLength - 1));
WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
(UCHAR)((TransferLength - 1) >> 8));
-
+
/* Unmask the Channel */
WRITE_PORT_UCHAR(&DmaControl2->SingleMask,
AdapterObject->ChannelNumber | DMA_CLEARMASK);