Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

299 lines
8.6 KiB

/******************************Module*Header**********************************\
*
* *******************
* * GDI SAMPLE CODE *
* *******************
*
* Module Name: dma.c
*
* Content: Handling of DMA buffers.
*
* Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved.
* Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved.
\*****************************************************************************/
#include "precomp.h"
#include "glint.h"
//
// Normally, we should not use global variables but the DMA buffers provided
// by the miniport are global across all PDEVs and need be initialized only
// once.
//
typedef struct _DMA_INFORMATION {
ULONG NumDMABuffers;
QUERY_DMA_BUFFERS DMABuffer[1];
} DMAInformation, *LPDMAInformation;
LPDMAInformation gpDMABufferInfo = (LPDMAInformation)0;
/******************************Public*Routine******************************\
* VOID bGlintInitializeDMA
*
* Interrogate the miniport to see if DMA is supported. If it is, map in the
* DMA buffers ready for use by the 3D extension.
*
\**************************************************************************/
VOID vGlintInitializeDMA(PPDEV ppdev)
{
DMA_NUM_BUFFERS queryDMA;
ULONG enableFlags;
LONG Length;
LONG ExtraLength;
ULONG i;
GLINT_DECL;
glintInfo->pxrxDMA = &glintInfo->pxrxDMAnonInterrupt;
return; //azntst for multimon
// check the miniport has initialised DMA
//
glintInfo->MaxDMASubBuffers = 0;
if (!(ppdev->flCaps & CAPS_DMA_AVAILABLE))
{
return;
}
// in the multi-board case we only want one set of DMA buffers which
// are global across all boards. But we have an interrupt per board.
// So if the DMA buffers are sorted out try setting up the interrupt.
//
if (gpDMABufferInfo != NULL)
{
goto TryInterrupts;
}
// query the number of DMA buffers. If this fails we have no DMA
//
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_QUERY_NUM_DMA_BUFFERS,
NULL,
0,
&queryDMA,
sizeof(DMA_NUM_BUFFERS),
&Length))
{
DISPDBG((ERRLVL, "QUERY_NUM_DMA_BUFFERS failed: "
"No GLINT DMA available"));
return;
}
Length = queryDMA.NumBuffers * queryDMA.BufferInformationLength;
ExtraLength = sizeof(DMAInformation) - sizeof(QUERY_DMA_BUFFERS);
DISPDBG((ERRLVL, "%d DMA buffers available. Total info size = 0x%x",
queryDMA.NumBuffers, Length));
// allocate space for the DMA information
//
gpDMABufferInfo = (LPDMAInformation)ENGALLOCMEM(
FL_ZERO_MEMORY,
ExtraLength + Length,
ALLOC_TAG_GDI(1));
if (gpDMABufferInfo == NULL)
{
DISPDBG((ERRLVL, "vGlintInitializeDMA: Out of memory"));
return;
}
gpDMABufferInfo->NumDMABuffers = queryDMA.NumBuffers;
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_QUERY_DMA_BUFFERS,
NULL,
0,
(PVOID)(&gpDMABufferInfo->DMABuffer[0]),
Length,
&Length))
{
ENGFREEMEM(gpDMABufferInfo);
gpDMABufferInfo = NULL;
DISPDBG((ERRLVL, "QUERY_DMA_BUFFERS failed: No GLINT DMA available"));
return;
}
DISPDBG((ERRLVL, "IOCTL returned length %d", Length));
// zero the flags for each record
//
for (i = 0; i < queryDMA.NumBuffers; ++i)
{
gpDMABufferInfo->DMABuffer[i].flags = 0;
}
#if DBG
{
ULONG j;
PUCHAR pAddr;
for (i = 0; i < queryDMA.NumBuffers; ++i)
{
DISPDBG((ERRLVL,"DMA buffer %d: phys 0x%x, virt 0x%x"
", size 0x%x, flags 0x%x", i,
gpDMABufferInfo->DMABuffer[i].physAddr.LowPart,
gpDMABufferInfo->DMABuffer[i].virtAddr,
gpDMABufferInfo->DMABuffer[i].size,
gpDMABufferInfo->DMABuffer[i].flags));
pAddr = gpDMABufferInfo->DMABuffer[i].virtAddr;
for (j = 0; j < gpDMABufferInfo->DMABuffer[i].size; ++j)
*pAddr++ = (UCHAR)(j & 0xff);
}
}
#endif
TryInterrupts:
if (!INTERRUPTS_ENABLED)
{
return;
}
// map in the interrupt command control block. This is a piece of memory
// shared with the intrerrupt controller which allows us to send control
// what happens on VBLANK and DMA interrupts.
//
Length = sizeof(PVOID);
DISPDBG((WRNLVL, "calling IOCTL_VIDEO_MAP_INTERRUPT_CMD_BUF"));
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_MAP_INTERRUPT_CMD_BUF,
NULL,
0,
(PVOID)&(glintInfo->pInterruptCommandBlock),
Length,
&Length))
{
DISPDBG((ERRLVL, "IOCTL_VIDEO_MAP_INTERRUPT_CMD_BUF failed."));
return;
}
#if DBG
else
{
DISPDBG((WRNLVL, "got command buffer at 0x%x",
glintInfo->pInterruptCommandBlock));
DISPDBG((WRNLVL, "front, back, end indexes = %d, %d, %d",
glintInfo->pInterruptCommandBlock->frontIndex,
glintInfo->pInterruptCommandBlock->backIndex,
glintInfo->pInterruptCommandBlock->endIndex));
}
#endif
// if we get here we have both DMA and interrupts so set for interrupt
// driven DMA. Don't turn on interrupts yet. That has to be done on a
// per context basis.
//
DISPDBG((WRNLVL, "Using interrupt driven DMA"));
glintInfo->flags |= GLICAP_INTERRUPT_DMA;
glintInfo->MaxDMASubBuffers = glintInfo->pInterruptCommandBlock->maximumIndex;
glintInfo->pxrxDMA = &glintInfo->pInterruptCommandBlock->pxrxDMA;
return;
}
/******************************Public*Routine******************************\
* ULONG anyFreeDMABuffers
*
* Return number of unused DMA buffers available
*
\**************************************************************************/
ULONG anyFreeDMABuffers(void)
{
PQUERY_DMA_BUFFERS pDma;
ULONG i;
ULONG numAvailable = 0;
if (!gpDMABufferInfo)
{
return 0;
}
pDma = &gpDMABufferInfo->DMABuffer[0];
for (i = 0; i < gpDMABufferInfo->NumDMABuffers; ++i)
{
if (!(pDma->flags & DMA_BUFFER_INUSE))
{
numAvailable++;
}
++pDma;
}
return numAvailable;
}
/******************************Public*Routine******************************\
* ULONG GetFreeDMABuffer
*
* Return info about a DMA buffer and mark it as in use.
* -1 is returned if no buffer is available.
*
\**************************************************************************/
LONG GetFreeDMABuffer(PQUERY_DMA_BUFFERS dmaBuf)
{
PQUERY_DMA_BUFFERS pDma;
ULONG i;
if (!gpDMABufferInfo)
{
return(-1);
}
pDma = &gpDMABufferInfo->DMABuffer[0];
for (i = 0; i < gpDMABufferInfo->NumDMABuffers; ++i)
{
if (!(pDma->flags & DMA_BUFFER_INUSE))
{
pDma->flags |= DMA_BUFFER_INUSE;
*dmaBuf = *pDma;
DISPDBG((WRNLVL, "Allocated DMA buffer %d", i));
return(i);
}
++pDma;
}
// all are in use
DISPDBG((ERRLVL, "No more DMA buffers available"));
return(-1);
}
/******************************Public*Routine******************************\
* VOID FreeDMABuffer
*
* Mark the given DMA buffer as free. The caller passes in the physical
* address of the buffer.
*
\**************************************************************************/
VOID FreeDMABuffer(PVOID physAddr)
{
PQUERY_DMA_BUFFERS pDma;
ULONG i;
if (!gpDMABufferInfo)
{
return;
}
pDma = &gpDMABufferInfo->DMABuffer[0];
for (i = 0; i < gpDMABufferInfo->NumDMABuffers; ++i)
{
if (pDma->physAddr.LowPart == (UINT_PTR)physAddr)
{
pDma->flags &= ~DMA_BUFFER_INUSE;
break;
}
++pDma;
}
return;
}