|
|
/******************************Module*Header*******************************\
* Module Name: dxapi.cxx * * Contains the public kernel-mode APIs for DirectX. * * All of the stuff that has to happen at raised IRQL happens here, because * win32k is entirely pageable. * * Created: 11-Apr-1997 * Author: J. Andrew Goossen [andrewgo] * * Copyright (c) 1997 Microsoft Corporation * \**************************************************************************/
#include "precomp.hxx"
#if DBG
#define RIPDX(x) { KdPrint((x)); DbgBreakPoint();}
#define ASSERTDX(x, y) if (!(x)) RIPDX(y)
#else
#define RIPDX(x)
#define ASSERTDX(x, y)
#endif
extern "C" {
VOID APIENTRY DxIrqCallBack( DX_IRQDATA* pIrqData );
NTSTATUS DriverEntry( PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath );
VOID APIENTRY DxGetVersionNumber( DWORD dwNotUsed, DDGETVERSIONNUMBER* pGetVersionNumber );
BOOL bDxModifyPassiveEventList( EDD_DXDIRECTDRAW* peDxDirectDraw, BOOL bAdd, DWORD dwEvent, LPDD_NOTIFYCALLBACK pfnCallBack, PVOID pContext );
DWORD dwDxRegisterEvent( DDREGISTERCALLBACK* pRegisterEvent, BOOL bRegister );
VOID APIENTRY DxRegisterEvent( DDREGISTERCALLBACK* pRegisterEvent, DWORD* pdwRet );
VOID APIENTRY DxUnregisterEvent( DDREGISTERCALLBACK* pRegisterEvent, DWORD* pdwRet );
VOID APIENTRY DxOpenDirectDraw( DDOPENDIRECTDRAWIN* pOpenDirectDrawIn, DDOPENDIRECTDRAWOUT* pOpenDirectDrawOut );
VOID APIENTRY DxApiInitialize( PFNDXAPIOPENDIRECTDRAW pfnOpenDirectDraw, PFNDXAPIOPENVIDEOPORT pfnOpenVideoPort, PFNDXAPIOPENSURFACE pfnOpenSurface, PFNDXAPICLOSEHANDLE pfnCloseHandle, PFNDXAPIGETKERNELCAPS pfnGetKernelCaps, PFNDXAPIOPENCAPTUREDEVICE pfnOpenCaptureDevice, PFNDXAPILOCKDEVICE pfnLockDevice, PFNDXAPIUNLOCKDEVICE pfnUnlockDevice );
DWORD APIENTRY DxApi( DWORD iFunction, VOID* pInBuffer, DWORD cInBuffer, VOID* pOutBuffer, DWORD cOutBuffer );
VOID APIENTRY DxAutoflipDpc( DWORD dwEvent, PVOID pContext, DWORD dwParam1, DWORD dwParam2 );
VOID APIENTRY DxAutoflipUpdate( EDD_DXVIDEOPORT* peDxVideoPort, EDD_DXSURFACE** apeDxSurfaceVideo, ULONG cSurfacesVideo, EDD_DXSURFACE** apeDxSurfaceVbi, ULONG cSurfacesVbi );
VOID APIENTRY DxLoseObject( VOID* pvObject, LOTYPE loType );
VOID APIENTRY DxEnableIRQ( EDD_DXVIDEOPORT* peDxVideoPort, BOOL bEnable );
VOID APIENTRY DxUpdateCapture( EDD_DXVIDEOPORT* peDxVideoPort, EDD_DXCAPTURE* peDxCapture, BOOL bRemove );
DWORD APIENTRY DxApiGetVersion( VOID );
}; // end "extern "C"
// Marke whatever we can as pageable:
#if defined(ALLOC_PRAGMA)
#pragma alloc_text(PAGE,DriverEntry)
#pragma alloc_text(PAGE,DxGetVersionNumber)
#pragma alloc_text(PAGE,bDxModifyPassiveEventList)
#pragma alloc_text(PAGE,dwDxRegisterEvent)
#pragma alloc_text(PAGE,DxRegisterEvent)
#pragma alloc_text(PAGE,DxUnregisterEvent)
#pragma alloc_text(PAGE,DxOpenDirectDraw)
#pragma alloc_text(PAGE,DxApiInitialize)
#pragma alloc_text(PAGE,DxApiGetVersion)
#endif
PFNDXAPIOPENDIRECTDRAW gpfnOpenDirectDraw; PFNDXAPILOCKDEVICE gpfnLockDevice; PFNDXAPIUNLOCKDEVICE gpfnUnlockDevice;
/***************************************************************************\
* NTSTATUS DriverEntry * * This routine is never actually called, but we need it to link. * \***************************************************************************/
extern "C" NTSTATUS DriverEntry( PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath ) { return(STATUS_SUCCESS); }
/******************************Public*Routine******************************\
* DWORD DxGetVersionNumber * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxGetVersionNumber( DWORD dwNotUsed, DDGETVERSIONNUMBER* pGetVersionNumber ) { ASSERTDX(KeGetCurrentIrql() == PASSIVE_LEVEL, "DxGetVersionNumber: Call only at passive level (it's not pageable)");
pGetVersionNumber->dwMajorVersion = DXAPI_MAJORVERSION; pGetVersionNumber->dwMinorVersion = DXAPI_MINORVERSION; pGetVersionNumber->ddRVal = DD_OK; }
/******************************Public*Routine******************************\
* VOID DxGetFieldNumber * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxGetFieldNumber( DDGETFIELDNUMIN* pGetFieldNumIn, DDGETFIELDNUMOUT* pGetFieldNumOut ) { DXOBJ* pDxObjDirectDraw; DXOBJ* pDxObjVideoPort; EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXVIDEOPORT* peDxVideoPort;
pGetFieldNumOut->ddRVal = DDERR_INVALIDPARAMS; if (pGetFieldNumIn == NULL) { return; }
pDxObjDirectDraw = (DXOBJ*) pGetFieldNumIn->hDirectDraw; if (pDxObjDirectDraw != NULL) { peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
pDxObjVideoPort = (DXOBJ*) pGetFieldNumIn->hVideoPort; if (pDxObjVideoPort != NULL) { peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW, "Invalid DirectDraw object"); ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT, "Invalid VideoPort object"); ASSERTDX(peDxDirectDraw == peDxVideoPort->peDxDirectDraw, "VideoPort and DirectDraw objects don't match");
if (peDxVideoPort->peDxDirectDraw->dwIRQCaps & DDIRQ_VPORT0_VSYNC ) { pGetFieldNumOut->dwFieldNum = peDxVideoPort->dwCurrentField; pGetFieldNumOut->ddRVal = DD_OK; } else { KdPrint(("DxGetFieldNumber: Device doesn't support an interrupt\n")); pGetFieldNumOut->ddRVal = DDERR_UNSUPPORTED; } } } }
/******************************Public*Routine******************************\
* VOID DxSetFieldNumber * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxSetFieldNumber( DDSETFIELDNUM* pSetFieldNum, DWORD* pdwRet ) { DXOBJ* pDxObjDirectDraw; DXOBJ* pDxObjVideoPort; EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXVIDEOPORT* peDxVideoPort;
*pdwRet = DDERR_INVALIDPARAMS; if (pSetFieldNum == NULL) { return; }
pDxObjDirectDraw = (DXOBJ*) pSetFieldNum->hDirectDraw; if (pDxObjDirectDraw != NULL) { peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
pDxObjVideoPort = (DXOBJ*) pSetFieldNum->hVideoPort; if (pDxObjVideoPort != NULL) { peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW, "Invalid DirectDraw object"); ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT, "Invalid VideoPort object"); ASSERTDX(peDxDirectDraw == peDxVideoPort->peDxDirectDraw, "VideoPort and DirectDraw objects don't match");
if (peDxVideoPort->peDxDirectDraw->dwIRQCaps & DDIRQ_VPORT0_VSYNC ) { peDxVideoPort->dwCurrentField = pSetFieldNum->dwFieldNum; *pdwRet = DD_OK; } else { KdPrint(("DxSetFieldNumber: Device doesn't support an interrupt\n")); *pdwRet = DDERR_UNSUPPORTED; } } } }
/******************************Public*Routine******************************\
* VOID DxSetSkipPattern * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxSetSkipPattern( DDSETSKIPFIELD* pSetSkipPattern, DWORD* pdwRet ) { DXOBJ* pDxObjDirectDraw; DXOBJ* pDxObjVideoPort; EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXVIDEOPORT* peDxVideoPort; KIRQL OldIrql; DWORD dwStartField;
*pdwRet = DDERR_INVALIDPARAMS; if (pSetSkipPattern == NULL) { return; }
pDxObjDirectDraw = (DXOBJ*) pSetSkipPattern->hDirectDraw; if (pDxObjDirectDraw != NULL) { peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
pDxObjVideoPort = (DXOBJ*) pSetSkipPattern->hVideoPort; if (pDxObjVideoPort != NULL) { peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW, "Invalid DirectDraw object"); ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT, "Invalid VideoPort object"); ASSERTDX(peDxDirectDraw == peDxVideoPort->peDxDirectDraw, "VideoPort and DirectDraw objects don't match");
// Acquire the spinlock while we muck around
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
// We assume that we are called during the VSYNC callback notification
// so all that we do is store the value and do the actual skipping
// during the AutoflipDpc call.
dwStartField = pSetSkipPattern->dwStartField; if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_SKIP_SET ) { if( peDxVideoPort->dwFieldToSkip > dwStartField ) { peDxVideoPort->dwNextFieldToSkip = peDxVideoPort->dwFieldToSkip; peDxVideoPort->dwFieldToSkip = dwStartField; peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_NEXT_SKIP_SET; } else if ( dwStartField != peDxVideoPort->dwFieldToSkip ) { peDxVideoPort->dwFieldToSkip = dwStartField; peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_NEXT_SKIP_SET; } } else { peDxVideoPort->dwFieldToSkip = dwStartField; peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_SKIP_SET; }
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
*pdwRet = DX_OK; } } }
/******************************Public*Routine******************************\
* VOID EffectStateChange * * 09-Jan-1998 -by- Scott MacDonald [smac] * Wrote it. \**************************************************************************/
VOID EffectStateChange( EDD_DXVIDEOPORT* peDxVideoPort, EDD_DXSURFACE* peDxSurface, DWORD dwNewState ) { EDD_DXDIRECTDRAW* peDxDirectDraw; DDSETSTATEININFO ddStateInInfo; DDSETSTATEOUTINFO ddStateOutInfo; DWORD dwOldFlags; DWORD dwOldVPFlags; DWORD ddRVal; DWORD i; DWORD dwRet;
dwOldVPFlags = 0; if( peDxVideoPort != NULL ) { peDxVideoPort->dwSetStateState = 0; peDxSurface = peDxVideoPort->apeDxSurfaceVideo[0]; dwOldVPFlags = peDxVideoPort->dwVPFlags; if( dwNewState & DDSTATE_SKIPEVENFIELDS ) { peDxVideoPort->dwVPFlags |= DDVP_SKIPEVENFIELDS; } else { peDxVideoPort->dwVPFlags &= ~DDVP_SKIPEVENFIELDS; } }
if( peDxSurface != NULL ) { dwOldFlags = peDxSurface->dwOverlayFlags; if( dwNewState & DDSTATE_BOB ) { peDxSurface->dwOverlayFlags |= DDOVER_BOB; } else if( dwNewState & ( DDSTATE_WEAVE | DDSTATE_SKIPEVENFIELDS ) ) { peDxSurface->dwOverlayFlags &= ~DDOVER_BOB; }
peDxDirectDraw = peDxSurface->peDxDirectDraw;
ddStateInInfo.lpSurfaceData = peDxSurface; ddStateInInfo.lpVideoPortData = peDxVideoPort; ddStateOutInfo.bSoftwareAutoflip = 0;
dwRet = DDERR_UNSUPPORTED; if (peDxDirectDraw->DxApiInterface.DxSetState != NULL) { dwRet = peDxDirectDraw->DxApiInterface.DxSetState( peDxDirectDraw->HwDeviceExtension, &ddStateInInfo, &ddStateOutInfo); } if( dwRet != DD_OK ) { peDxSurface->dwOverlayFlags = dwOldFlags; if( peDxVideoPort != NULL ) { peDxVideoPort->dwVPFlags = dwOldVPFlags; } } peDxSurface->flFlags |= DD_DXSURFACE_FLAG_STATE_SET; if( peDxVideoPort != NULL ) { if( peDxSurface->dwOverlayFlags & DDOVER_BOB ) { peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_BOB; } else { peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_BOB; }
// Do they want to switch from hardware autoflipping to
// software autoflipping?
if( ( ddStateOutInfo.bSoftwareAutoflip ) && ( peDxVideoPort->dwVPFlags & DDVP_AUTOFLIP ) && !( peDxVideoPort->flFlags & (DD_DXVIDEOPORT_FLAG_AUTOFLIP|DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI))) { if( peDxVideoPort->cAutoflipVideo > 0 ) { peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_AUTOFLIP; } if( peDxVideoPort->cAutoflipVbi > 0 ) { peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI; } if( ddStateOutInfo.dwSurfaceIndex >= peDxVideoPort->cAutoflipVideo ) { peDxVideoPort->iCurrentVideo = 0; } else { peDxVideoPort->iCurrentVideo = ddStateOutInfo.dwSurfaceIndex; } if( ddStateOutInfo.dwVBISurfaceIndex >= peDxVideoPort->cAutoflipVbi ) { peDxVideoPort->iCurrentVbi = 0; } else { peDxVideoPort->iCurrentVbi = ddStateOutInfo.dwVBISurfaceIndex; } }
for( i = 0; i < peDxVideoPort->iCurrentVideo; i++ ) { peDxSurface = peDxVideoPort->apeDxSurfaceVideo[i]; peDxSurface->flFlags &= ~(DD_DXSURFACE_FLAG_STATE_BOB|DD_DXSURFACE_FLAG_STATE_WEAVE); if( dwNewState & DDSTATE_BOB ) { peDxSurface->dwOverlayFlags |= DDOVER_BOB; peDxSurface->flFlags |= DD_DXSURFACE_FLAG_STATE_BOB; } else if( dwNewState & ( DDSTATE_WEAVE | DDSTATE_SKIPEVENFIELDS ) ) { peDxSurface->dwOverlayFlags &= ~DDOVER_BOB; if( dwNewState == DDSTATE_WEAVE ) { peDxSurface->flFlags |= DD_DXSURFACE_FLAG_STATE_WEAVE; } } peDxSurface->flFlags |= DD_DXSURFACE_FLAG_STATE_SET; } } } }
/******************************Public*Routine******************************\
* VOID DxGetSurfaceState * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxGetSurfaceState( DDGETSURFACESTATEIN* pGetSurfaceStateIn, DDGETSURFACESTATEOUT* pGetSurfaceStateOut ) { DXOBJ* pDxObjDirectDraw; DXOBJ* pDxObjSurface; EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXVIDEOPORT* peDxVideoPort; EDD_DXSURFACE* peDxSurface;
pGetSurfaceStateOut->ddRVal = DDERR_INVALIDPARAMS; if (pGetSurfaceStateIn == NULL) { return; }
pDxObjDirectDraw = (DXOBJ*) pGetSurfaceStateIn->hDirectDraw; pDxObjSurface = (DXOBJ*) pGetSurfaceStateIn->hSurface;
if ((pDxObjDirectDraw != NULL) && (pDxObjSurface != NULL)) { peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw; peDxSurface = pDxObjSurface->peDxSurface;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW, "Invalid DirectDraw object"); ASSERTDX(pDxObjSurface->iDxType == DXT_SURFACE, "Invalid Surface object"); ASSERTDX(peDxDirectDraw == peDxSurface->peDxDirectDraw, "Surface and DirectDraw objects don't match"); ASSERTDX(peDxSurface->ddsCaps & DDSCAPS_OVERLAY, "Surface is not an overlay surface");
// Fill in the available caps
pGetSurfaceStateOut->dwStateCaps = 0; pGetSurfaceStateOut->dwStateStatus = 0; peDxVideoPort = peDxSurface->peDxVideoPort;
// If the DDOVER_OVERRIDEBOBWEAVE flag was set, the status is equal
// to the caps.
if( peDxSurface->dwOverlayFlags & DDOVER_OVERRIDEBOBWEAVE ) { if( peDxSurface->dwOverlayFlags & DDOVER_BOB ) { pGetSurfaceStateOut->dwStateStatus |= DDSTATE_BOB; pGetSurfaceStateOut->dwStateCaps |= DDSTATE_BOB; } else if( ( peDxVideoPort != NULL ) && ( peDxVideoPort->dwVPFlags & (DDVP_SKIPEVENFIELDS|DDVP_SKIPODDFIELDS) ) ) { pGetSurfaceStateOut->dwStateStatus |= DDSTATE_SKIPEVENFIELDS; pGetSurfaceStateOut->dwStateCaps |= DDSTATE_SKIPEVENFIELDS; } else if( ( peDxVideoPort != NULL ) && ( peDxVideoPort->dwVPFlags & DDVP_INTERLEAVE ) ) { pGetSurfaceStateOut->dwStateStatus |= DDSTATE_WEAVE; pGetSurfaceStateOut->dwStateCaps |= DDSTATE_WEAVE; } else if( ( peDxVideoPort == NULL ) && ( peDxSurface->dwOverlayFlags & DDOVER_INTERLEAVED ) ) { pGetSurfaceStateOut->dwStateStatus |= DDSTATE_WEAVE; pGetSurfaceStateOut->dwStateCaps |= DDSTATE_WEAVE; } } else { // The status is different from the caps
if( ( peDxVideoPort != NULL ) && ( peDxVideoPort->dwVPFlags & (DDVP_SKIPEVENFIELDS|DDVP_SKIPODDFIELDS) ) ) { pGetSurfaceStateOut->dwStateStatus |= DDSTATE_SKIPEVENFIELDS; } else if( peDxSurface->dwOverlayFlags & DDOVER_BOB ) { pGetSurfaceStateOut->dwStateStatus |= DDSTATE_BOB; }
if( ( ( peDxVideoPort != NULL ) && ( peDxVideoPort->dwVPFlags & DDVP_INTERLEAVE ) ) || ( ( peDxVideoPort == NULL ) && ( peDxSurface->dwOverlayFlags & DDOVER_INTERLEAVED ) ) ) { pGetSurfaceStateOut->dwStateCaps |= DDSTATE_WEAVE; if( peDxSurface->flFlags & DD_DXSURFACE_FLAG_CAN_BOB_INTERLEAVED ) { pGetSurfaceStateOut->dwStateCaps |= DDSTATE_BOB; } if( pGetSurfaceStateOut->dwStateStatus == 0 ) { pGetSurfaceStateOut->dwStateStatus |= DDSTATE_WEAVE; } } else if( peDxSurface->flFlags & DD_DXSURFACE_FLAG_CAN_BOB_NONINTERLEAVED ) { pGetSurfaceStateOut->dwStateCaps |= DDSTATE_BOB; } if( peDxVideoPort != NULL ) { pGetSurfaceStateOut->dwStateCaps |= DDSTATE_SKIPEVENFIELDS; } }
// Notify the client that the state was explicity set by a
// kernel mode client.
if( peDxSurface->flFlags & DD_DXSURFACE_FLAG_STATE_SET ) { pGetSurfaceStateOut->dwStateStatus |= DDSTATE_EXPLICITLY_SET; }
// Tell if software autoflipping vs. hardware autofliping. This
// is mostly for DDraw's benefit.
if( ( peDxVideoPort != NULL ) && ( peDxVideoPort->bSoftwareAutoflip ) ) { pGetSurfaceStateOut->dwStateStatus |= DDSTATE_SOFTWARE_AUTOFLIP; }
pGetSurfaceStateOut->ddRVal = DD_OK; } }
/******************************Public*Routine******************************\
* VOID DxSetSurfaceState * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxSetSurfaceState( DDSETSURFACESTATE* pSetSurfaceState, DWORD* pdwRet ) { DWORD dwState; DXOBJ* pDxObjDirectDraw; DXOBJ* pDxObjSurface; EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXVIDEOPORT* peDxVideoPort; EDD_DXSURFACE* peDxSurface; DDGETSURFACESTATEIN GetSurfaceStateIn; DDGETSURFACESTATEOUT GetSurfaceStateOut; DDSETSTATEININFO SetStateInInfo; DDSETSTATEOUTINFO SetStateOutInfo; DWORD iCurrentVideo; KIRQL OldIrql; DWORD dwRet; DWORD dwVPFlags;
*pdwRet = dwRet = DDERR_INVALIDPARAMS; if (pSetSurfaceState == NULL) { return; }
pDxObjDirectDraw = (DXOBJ*) pSetSurfaceState->hDirectDraw; pDxObjSurface = (DXOBJ*) pSetSurfaceState->hSurface; if ((pDxObjDirectDraw != NULL) && (pDxObjSurface != NULL)) { peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw; peDxSurface = pDxObjSurface->peDxSurface;
GetSurfaceStateIn.hDirectDraw = pSetSurfaceState->hDirectDraw; GetSurfaceStateIn.hSurface = pSetSurfaceState->hSurface;
DxGetSurfaceState(&GetSurfaceStateIn, &GetSurfaceStateOut);
ASSERTDX(GetSurfaceStateOut.ddRVal == DD_OK, "DxSetSurfaceState: Didn't expect failure from DxGetSurfaceState");
dwState = pSetSurfaceState->dwState;
// Get the video port if one is associated with the surface
if( peDxSurface->peDxVideoPort == NULL ) { peDxVideoPort = NULL; dwVPFlags = 0; } else { peDxVideoPort = peDxSurface->peDxVideoPort; dwVPFlags = peDxVideoPort->dwVPFlags; }
if ((dwState != DDSTATE_BOB) && (dwState != DDSTATE_WEAVE) && (dwState != DDSTATE_SKIPEVENFIELDS)) { RIPDX("DxSetSurfaceState: Invalid dwState flags"); } else if ((dwState & GetSurfaceStateOut.dwStateCaps) != dwState) { RIPDX("DxSetSurfaceState: State not supported"); } else if ((dwState == DDSTATE_SKIPEVENFIELDS) && (peDxVideoPort == NULL )) { RIPDX("DxSetSurfaceState: Surface not attached to video port"); } else if (((dwState & DDSTATE_BOB) && (peDxSurface->dwOverlayFlags & DDOVER_BOB)) || ((dwState & DDSTATE_WEAVE) && !(peDxSurface->dwOverlayFlags & DDOVER_BOB) && !(dwVPFlags & (DDVP_SKIPEVENFIELDS|DDVP_SKIPODDFIELDS))) || ((dwState & DDSTATE_SKIPEVENFIELDS ) && (dwVPFlags & (DDVP_SKIPEVENFIELDS|DDVP_SKIPODDFIELDS)))) { // Don't do nothin, it's already in the requested state.
dwRet = DD_OK; } else if (peDxDirectDraw->DxApiInterface.DxSetState != NULL) { // Acquire the spinlock while we muck around in the 'dwSetStateState'
// and 'dwSetStateField' members, which are accessed by the videoport
// DPC.
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) || ((peDxVideoPort != NULL) && (peDxVideoPort->bLost)) || (peDxSurface->bLost)) { KdPrint(("DxSetSurfaceState: Objects are lost\n")); dwRet = DDERR_SURFACELOST; }
// If they want it to happen for the next field or we are not
// using a video port, call the mini port now; otherwise, we'll let
// the IRQ logoic handle this later.
else if ((pSetSurfaceState->dwStartField == 0) || (peDxVideoPort == NULL) || !(peDxVideoPort->bSoftwareAutoflip)) { EffectStateChange( peDxVideoPort, peDxSurface, dwState ); } else { peDxVideoPort->dwSetStateState = dwState; peDxVideoPort->dwSetStateField = pSetSurfaceState->dwStartField; peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_NEW_STATE; }
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
dwRet = DD_OK; }
if (peDxDirectDraw->DxApiInterface.DxSetState == NULL) { dwRet = DDERR_UNSUPPORTED; }
*pdwRet = dwRet; } }
/******************************Public*Routine******************************\
* VOID DxLock * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxLock( DDLOCKIN* pLockIn, DDLOCKOUT* pLockOut ) { DWORD dwRet; DXOBJ* pDxObjDirectDraw; DXOBJ* pDxObjSurface; EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXSURFACE* peDxSurface; DDLOCKININFO LockInInfo; DDLOCKOUTINFO LockOutInfo; KIRQL OldIrql;
pLockOut->ddRVal = DDERR_INVALIDPARAMS; if (pLockIn == NULL) { return; }
dwRet = DD_OK;
pDxObjDirectDraw = (DXOBJ*) pLockIn->hDirectDraw; pDxObjSurface = (DXOBJ*) pLockIn->hSurface; if ((pDxObjDirectDraw != NULL) && (pDxObjSurface != NULL)) { peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw; peDxSurface = pDxObjSurface->peDxSurface;
ASSERTDX(peDxDirectDraw == peDxSurface->peDxDirectDraw, "Surface and DirectDraw objects don't match"); ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW, "Invalid DirectDraw object"); ASSERTDX(pDxObjSurface->iDxType == DXT_SURFACE, "Invalid surface object");
LockInInfo.lpSurfaceData = peDxSurface; LockOutInfo.dwSurfacePtr = peDxSurface->fpLockPtr;
// The display driver can set 'fpLockPtr' to NULL in its SyncSurfaceData
// routine if it doesn't want to support a DXAPI lock.
if (peDxSurface->fpLockPtr == NULL) { KdPrint(("DxLock: Video miniport doesn't support lock on this surface\n")); dwRet = DDERR_UNSUPPORTED; } else { // NOTE: The miniport should not wait for accelerator complete!
if (peDxDirectDraw->DxApiInterface.DxLock) { KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) || (peDxSurface->bLost)) { KdPrint(("DxLock: Objects are lost\n")); dwRet = DDERR_SURFACELOST; } else { dwRet = peDxDirectDraw->DxApiInterface.DxLock( peDxDirectDraw->HwDeviceExtension, &LockInInfo, &LockOutInfo); }
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
if (dwRet != DD_OK) { KdPrint(("DxLock: Driver failed call\n"));
// Pass the return code on down...
} }
pLockOut->lpSurface = (LPVOID) LockOutInfo.dwSurfacePtr;
pLockOut->dwSurfHeight = peDxSurface->dwHeight; pLockOut->dwSurfWidth = peDxSurface->dwWidth; pLockOut->lSurfPitch = peDxSurface->lPitch; pLockOut->SurfaceCaps = peDxSurface->ddsCaps; pLockOut->dwFormatFlags = peDxSurface->dwFormatFlags; pLockOut->dwFormatFourCC = peDxSurface->dwFormatFourCC; pLockOut->dwFormatBitCount = peDxSurface->dwFormatBitCount; pLockOut->dwRBitMask = peDxSurface->dwRBitMask; pLockOut->dwGBitMask = peDxSurface->dwGBitMask; pLockOut->dwBBitMask = peDxSurface->dwBBitMask; }
pLockOut->ddRVal = dwRet; } }
/******************************Public*Routine******************************\
* VOID DxFlipOverlay * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxFlipOverlay( DDFLIPOVERLAY* pFlipOverlay, DWORD* pdwRet ) { DWORD dwRet; DXOBJ* pDxObjDirectDraw; DXOBJ* pDxObjTarget; DXOBJ* pDxObjCurrent; EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXSURFACE* peDxTarget; EDD_DXSURFACE* peDxCurrent; DDFLIPOVERLAYINFO FlipOverlayInfo; KIRQL OldIrql;
*pdwRet = DDERR_INVALIDPARAMS; if (pFlipOverlay == NULL) { return; }
dwRet = DDERR_UNSUPPORTED; // Assume failure
pDxObjDirectDraw = (DXOBJ*) pFlipOverlay->hDirectDraw; pDxObjTarget = (DXOBJ*) pFlipOverlay->hTargetSurface; pDxObjCurrent = (DXOBJ*) pFlipOverlay->hCurrentSurface;
if ((pDxObjDirectDraw != NULL) && (pDxObjTarget != NULL) && (pDxObjCurrent != NULL)) { peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw; peDxTarget = pDxObjTarget->peDxSurface; peDxCurrent = pDxObjCurrent->peDxSurface;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW, "Invalid DirectDraw object"); ASSERTDX(pDxObjTarget->iDxType == DXT_SURFACE, "Invalid target object"); ASSERTDX(pDxObjCurrent->iDxType == DXT_SURFACE, "Invalid current object"); ASSERTDX((peDxDirectDraw == peDxTarget->peDxDirectDraw) && (peDxDirectDraw == peDxCurrent->peDxDirectDraw), "Surface and DirectDraw objects don't match"); ASSERTDX((peDxCurrent->dwWidth == peDxTarget->dwWidth) && (peDxCurrent->dwHeight == peDxTarget->dwHeight), "Surfaces are different sizes");
if (!(peDxCurrent->ddsCaps & DDSCAPS_OVERLAY) || (peDxCurrent->dwOverlayFlags & DDOVER_AUTOFLIP)) { RIPDX("Invalid current overlay status"); } else if (!(peDxTarget->ddsCaps & DDSCAPS_OVERLAY) || (peDxTarget->dwOverlayFlags & DDOVER_AUTOFLIP)) { RIPDX("Invalid target overlay status"); } else { FlipOverlayInfo.lpCurrentSurface = peDxCurrent; FlipOverlayInfo.lpTargetSurface = peDxTarget; FlipOverlayInfo.dwFlags = pFlipOverlay->dwFlags;
if (peDxDirectDraw->DxApiInterface.DxFlipOverlay) { KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) || (peDxTarget->bLost) || (peDxCurrent->bLost)) { KdPrint(("DxFlipOverlay: Objects are lost\n")); dwRet = DDERR_SURFACELOST; } else { dwRet = peDxDirectDraw->DxApiInterface.DxFlipOverlay( peDxDirectDraw->HwDeviceExtension, &FlipOverlayInfo, NULL); }
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql); }
if (dwRet != DD_OK) { KdPrint(("DxFlipOverlay: Driver failed call\n")); } }
*pdwRet = dwRet; } }
/******************************Public*Routine******************************\
* VOID DxFlipVideoPort * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxFlipVideoPort( DDFLIPVIDEOPORT* pFlipVideoPort, DWORD* pdwRet ) { DWORD dwRet; DXOBJ* pDxObjDirectDraw; DXOBJ* pDxObjVideoPort; DXOBJ* pDxObjTarget; DXOBJ* pDxObjCurrent; EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXVIDEOPORT* peDxVideoPort; EDD_DXSURFACE* peDxTarget; EDD_DXSURFACE* peDxCurrent; DDFLIPVIDEOPORTINFO FlipVideoPortInfo; KIRQL OldIrql;
*pdwRet = DDERR_INVALIDPARAMS; if (pFlipVideoPort == NULL) { return; }
dwRet = DDERR_UNSUPPORTED; // Assume failure
pDxObjDirectDraw = (DXOBJ*) pFlipVideoPort->hDirectDraw; pDxObjVideoPort = (DXOBJ*) pFlipVideoPort->hVideoPort; pDxObjTarget = (DXOBJ*) pFlipVideoPort->hTargetSurface; pDxObjCurrent = (DXOBJ*) pFlipVideoPort->hCurrentSurface;
if ((pDxObjDirectDraw != NULL) && (pDxObjVideoPort != NULL) && (pDxObjTarget != NULL) && (pDxObjCurrent != NULL)) { peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw; peDxVideoPort = pDxObjVideoPort->peDxVideoPort; peDxTarget = pDxObjTarget->peDxSurface; peDxCurrent = pDxObjCurrent->peDxSurface;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW, "Invalid DirectDraw object"); ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT, "Invalid VideoPort object"); ASSERTDX(pDxObjTarget->iDxType == DXT_SURFACE, "Invalid target object"); ASSERTDX(pDxObjCurrent->iDxType == DXT_SURFACE, "Invalid current object"); ASSERTDX((peDxDirectDraw == peDxTarget->peDxDirectDraw) && (peDxDirectDraw == peDxCurrent->peDxDirectDraw) && (peDxDirectDraw == peDxVideoPort->peDxDirectDraw), "Surface, VideoPort, and DirectDraw objects don't match"); ASSERTDX((peDxCurrent->dwWidth == peDxTarget->dwWidth) && (peDxCurrent->dwHeight == peDxTarget->dwHeight), "Surfaces are different sizes"); ASSERTDX((pFlipVideoPort->dwFlags == DDVPFLIP_VIDEO) || (pFlipVideoPort->dwFlags == DDVPFLIP_VBI), "Invalid flags"); ASSERTDX(!(peDxVideoPort->dwVPFlags & DDVP_AUTOFLIP), "Flip not available while autoflipping");
FlipVideoPortInfo.lpVideoPortData = peDxVideoPort; FlipVideoPortInfo.lpCurrentSurface = peDxCurrent; FlipVideoPortInfo.lpTargetSurface = peDxTarget; FlipVideoPortInfo.dwFlipVPFlags = pFlipVideoPort->dwFlags;
if (peDxDirectDraw->DxApiInterface.DxFlipVideoPort) { KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) || (peDxVideoPort->bLost) || (peDxTarget->bLost) || (peDxCurrent->bLost)) { KdPrint(("DxFlipVideoPort: Objects are lost\n")); dwRet = DDERR_SURFACELOST; } else { dwRet = peDxDirectDraw->DxApiInterface.DxFlipVideoPort( peDxDirectDraw->HwDeviceExtension, &FlipVideoPortInfo, NULL); } peDxCurrent->peDxVideoPort = NULL; peDxTarget->peDxVideoPort = peDxVideoPort;
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql); }
if (dwRet != DD_OK) { KdPrint(("DxFlipVideoPort: Driver failed call\n")); }
*pdwRet = dwRet; } }
/******************************Public*Routine******************************\
* VOID DxGetCurrentAutoflip * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxGetCurrentAutoflip( DDGETAUTOFLIPIN* pGetCurrentAutoflipIn, DDGETAUTOFLIPOUT* pGetCurrentAutoflipOut ) { DWORD dwRet; DXOBJ* pDxObjDirectDraw; DXOBJ* pDxObjVideoPort; DXOBJ* pDxObjTarget; DXOBJ* pDxObjCurrent; EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXVIDEOPORT* peDxVideoPort; EDD_DXSURFACE* peDxTarget; EDD_DXSURFACE* peDxCurrent; DDGETPOLARITYININFO GetPolarityInInfo; DDGETPOLARITYOUTINFO GetPolarityOutInfo; DDGETCURRENTAUTOFLIPININFO GetCurrentAutoflipInInfo; DDGETCURRENTAUTOFLIPOUTINFO GetCurrentAutoflipOutInfo; KIRQL OldIrql; DWORD dwVideo; DWORD dwVBI; BOOL bFlipping;
pGetCurrentAutoflipOut->ddRVal = DDERR_INVALIDPARAMS; if (pGetCurrentAutoflipIn == NULL) { return; }
dwRet = DDERR_UNSUPPORTED; // Assume failure
pDxObjDirectDraw = (DXOBJ*) pGetCurrentAutoflipIn->hDirectDraw; pDxObjVideoPort = (DXOBJ*) pGetCurrentAutoflipIn->hVideoPort; if ((pDxObjDirectDraw != NULL) && (pDxObjVideoPort != NULL)) { peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw; peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW, "Invalid DirectDraw object"); ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT, "Invalid VideoPort object"); ASSERTDX(peDxDirectDraw == peDxVideoPort->peDxDirectDraw, "Surface, VideoPort, and DirectDraw objects don't match"); ASSERTDX(peDxVideoPort->dwVPFlags & DDVP_AUTOFLIP, "Not currently autoflipping");
GetPolarityInInfo.lpVideoPortData = peDxVideoPort;
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) || (peDxVideoPort->bLost)) { KdPrint(("DxGetCurrentAutoflip: Objects are lost\n")); dwRet = DDERR_SURFACELOST; } else { dwRet = DDERR_UNSUPPORTED; if (peDxDirectDraw->DxApiInterface.DxGetPolarity) { dwRet = peDxDirectDraw->DxApiInterface.DxGetPolarity( peDxDirectDraw->HwDeviceExtension, &GetPolarityInInfo, &GetPolarityOutInfo); }
if (dwRet != DD_OK) { KdPrint(("DxGetCurrentAutoflip: Driver failed GetPolarity\n")); } else { // Determine which field is currently receiving the data. If they
// are software autoflipping, I can do that myself; otherwise, I
// have to call the HAL
//
// When software autoflipping, there is an issue that if this
// function is called between the time that the IRQ occured
// and the time that the DPC ran, this function would return
// the wrong surface. Since fixing this requires that we do all
// of the work at IRQ time (bad), we can probably assume that
// this will always be the case since anybody using this
// function would be calling it during the IRQ callback. We
// will therefore work around it.
dwVideo = (DWORD) -1; dwVBI = (DWORD) -1;
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP ) { dwVideo = peDxVideoPort->iCurrentVideo; bFlipping = TRUE; if( ( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_SKIP_SET ) && ( peDxVideoPort->dwFieldToSkip == 1 ) ) { bFlipping = FALSE; } else if( !( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_SKIPPED_LAST ) && ( peDxVideoPort->dwVPFlags & DDVP_INTERLEAVE ) && !( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_FLIP_NEXT ) ) { bFlipping = FALSE; } if( bFlipping ) { if( ++dwVideo >= peDxVideoPort->cAutoflipVideo ) { dwVideo = 0; } } }
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI ) { dwVBI = peDxVideoPort->iCurrentVbi; if( ( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_VBI_INTERLEAVED ) && !( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_FLIP_NEXT_VBI ) ) { if( ++dwVBI >= peDxVideoPort->cAutoflipVbi ) { dwVBI = 0; } } }
if( ( dwVideo == (DWORD) -1 ) && ( dwVBI == (DWORD) -1 ) ) { GetCurrentAutoflipInInfo.lpVideoPortData = peDxVideoPort; GetCurrentAutoflipOutInfo.dwSurfaceIndex = 0; GetCurrentAutoflipOutInfo.dwVBISurfaceIndex = 0; if (peDxDirectDraw->DxApiInterface.DxGetCurrentAutoflip) { dwRet = peDxDirectDraw->DxApiInterface.DxGetCurrentAutoflip( peDxDirectDraw->HwDeviceExtension, &GetCurrentAutoflipInInfo, &GetCurrentAutoflipOutInfo); } dwVideo = GetCurrentAutoflipOutInfo.dwSurfaceIndex; dwVBI = GetCurrentAutoflipOutInfo.dwVBISurfaceIndex; }
pGetCurrentAutoflipOut->hVideoSurface = NULL; pGetCurrentAutoflipOut->hVBISurface = NULL; if( ( peDxVideoPort->cAutoflipVideo > 0 ) && ( dwVideo != (DWORD) -1 ) ) { pGetCurrentAutoflipOut->hVideoSurface = peDxVideoPort->apeDxSurfaceVideo[dwVideo]; } if( ( peDxVideoPort->cAutoflipVbi > 0 ) && ( dwVBI != (DWORD) -1 ) ) { pGetCurrentAutoflipOut->hVBISurface = peDxVideoPort->apeDxSurfaceVbi[dwVBI]; } pGetCurrentAutoflipOut->bPolarity = GetPolarityOutInfo.bPolarity; } }
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
pGetCurrentAutoflipOut->ddRVal = dwRet; } }
/******************************Public*Routine******************************\
* VOID DxGetPreviousAutoflip * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxGetPreviousAutoflip( DDGETAUTOFLIPIN* pGetPreviousAutoflipIn, DDGETAUTOFLIPOUT* pGetPreviousAutoflipOut ) { DWORD dwRet; DXOBJ* pDxObjDirectDraw; DXOBJ* pDxObjVideoPort; DXOBJ* pDxObjTarget; DXOBJ* pDxObjCurrent; EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXVIDEOPORT* peDxVideoPort; EDD_DXSURFACE* peDxTarget; EDD_DXSURFACE* peDxPrevious; DDGETPOLARITYININFO GetPolarityInInfo; DDGETPOLARITYOUTINFO GetPolarityOutInfo; DDGETPREVIOUSAUTOFLIPININFO GetPreviousAutoflipInInfo; DDGETPREVIOUSAUTOFLIPOUTINFO GetPreviousAutoflipOutInfo; KIRQL OldIrql; DWORD dwVideo; DWORD dwVBI;
pGetPreviousAutoflipOut->ddRVal = DDERR_INVALIDPARAMS; if (pGetPreviousAutoflipIn == NULL) { return; }
dwRet = DDERR_UNSUPPORTED; // Assume failure
pDxObjDirectDraw = (DXOBJ*) pGetPreviousAutoflipIn->hDirectDraw; pDxObjVideoPort = (DXOBJ*) pGetPreviousAutoflipIn->hVideoPort; if ((pDxObjDirectDraw != NULL) && (pDxObjVideoPort != NULL)) { peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw; peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW, "Invalid DirectDraw object"); ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT, "Invalid VideoPort object"); ASSERTDX(peDxDirectDraw == peDxVideoPort->peDxDirectDraw, "Surface, VideoPort, and DirectDraw objects don't match"); ASSERTDX(peDxVideoPort->dwVPFlags & DDVP_AUTOFLIP, "Not currently autoflipping");
GetPolarityInInfo.lpVideoPortData = peDxVideoPort;
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) || (peDxVideoPort->bLost)) { KdPrint(("DxGetPreviousAutoflip: Objects are lost\n")); dwRet = DDERR_SURFACELOST; } else { dwRet = DDERR_UNSUPPORTED; if (peDxDirectDraw->DxApiInterface.DxGetPolarity) { dwRet = peDxDirectDraw->DxApiInterface.DxGetPolarity( peDxDirectDraw->HwDeviceExtension, &GetPolarityInInfo, &GetPolarityOutInfo); }
if (dwRet != DD_OK) { KdPrint(("DxGetPreviousAutoflip: Driver failed GetPolarity\n")); } else { // Determine which field is currently receiving the data. If they
// are software autoflipping, I can do that myself; otherwise, I
// have to call the HAL
//
// This is complicated by the facts that:
// 1) Skipping may be enabled.
// 3) When interleaving, they flip every other field, but its not
// guarenteed that the flip always occurs between the even and the
// odd fields.
//
// When software autoflipping, there is an issue that if this
// function is called between the time that the IRQ occured
// and the time that the DPC ran, this function would return
// the wrong surface. Since fixing this requires that we do all
// of the work at IRQ time (bad), we can probably assume that
// this will always be the case since anybody using this
// function would be calling it during the IRQ callback. We
// will therefore work around it.
dwVideo = (DWORD) -1; dwVBI = (DWORD) -1; if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP ) { dwVideo = peDxVideoPort->iCurrentVideo; } if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI ) { dwVBI = peDxVideoPort->iCurrentVbi; } if( ( dwVideo == (DWORD) -1 ) && ( dwVBI == (DWORD) -1 ) ) { GetPreviousAutoflipInInfo.lpVideoPortData = peDxVideoPort; GetPreviousAutoflipOutInfo.dwSurfaceIndex = 0; GetPreviousAutoflipOutInfo.dwVBISurfaceIndex = 0; if (peDxDirectDraw->DxApiInterface.DxGetPreviousAutoflip) { dwRet = peDxDirectDraw->DxApiInterface.DxGetPreviousAutoflip( peDxDirectDraw->HwDeviceExtension, &GetPreviousAutoflipInInfo, &GetPreviousAutoflipOutInfo); } dwVideo = GetPreviousAutoflipOutInfo.dwSurfaceIndex; dwVBI = GetPreviousAutoflipOutInfo.dwVBISurfaceIndex; }
pGetPreviousAutoflipOut->hVideoSurface = NULL; pGetPreviousAutoflipOut->hVBISurface = NULL; if( ( peDxVideoPort->cAutoflipVideo > 0 ) && ( dwVideo != (DWORD) -1 ) ) { pGetPreviousAutoflipOut->hVideoSurface = peDxVideoPort->apeDxSurfaceVideo[dwVideo]; } if( ( peDxVideoPort->cAutoflipVbi > 0 ) && ( dwVBI != (DWORD) -1 ) ) { pGetPreviousAutoflipOut->hVBISurface = peDxVideoPort->apeDxSurfaceVbi[dwVBI]; } pGetPreviousAutoflipOut->bPolarity = ( GetPolarityOutInfo.bPolarity == FALSE ); // invert
} }
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
pGetPreviousAutoflipOut->ddRVal = dwRet; } }
/******************************Public*Routine******************************\
* BOOL bDxModifyPassiveEventList * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOL bDxModifyPassiveEventList( EDD_DXDIRECTDRAW* peDxDirectDraw, BOOL bAdd, // TRUE to add, FALSE to delete
DWORD dwEvent, LPDD_NOTIFYCALLBACK pfnCallBack, PVOID pContext ) { BOOL bRet; DXAPI_EVENT* pDxEvent; DXAPI_EVENT* pDxEvent_New; DXAPI_EVENT* pDxEvent_Previous; KIRQL OldIrql;
bRet = FALSE; // Assume failure
ASSERTDX(KeGetCurrentIrql() == PASSIVE_LEVEL, "Expected passive level"); ASSERTDX((bAdd == FALSE) || (bAdd == TRUE), "Bad boolean");
if (bAdd) { pDxEvent_New = (DXAPI_EVENT*) ExAllocatePoolWithTag(PagedPool, sizeof(*pDxEvent), 'eddG');
if (pDxEvent_New == NULL) return(FALSE);
RtlZeroMemory(pDxEvent_New, sizeof(*pDxEvent_New)); }
// We must synchronize additions or deletions to the passive-level
// event list via our devlock.
ASSERTDX(gpfnLockDevice, "bDxModifyPassiveEventList: gpfnLockDevice is NULL"); gpfnLockDevice(peDxDirectDraw->hdev);
if (peDxDirectDraw->bLost) { KdPrint(("bDxModifyPassiveEventList: Object is lost\n")); } else { // First, try to find this event in the list:
pDxEvent_Previous = NULL;
for (pDxEvent = peDxDirectDraw->pDxEvent_PassiveList; pDxEvent != NULL; pDxEvent = pDxEvent->pDxEvent_Next) { if ((pDxEvent->dwEvent == dwEvent) && (pDxEvent->pfnCallBack == pfnCallBack) && (pDxEvent->pContext == pContext)) { break; }
pDxEvent_Previous = pDxEvent; } // It's a failure when:
//
// 1) If adding, the same event is already in the list;
// 2) If deleting, the event is not in the list.
if ((bAdd) == (pDxEvent == NULL)) { if (bAdd) { // Add the event.
pDxEvent_New->peDxDirectDraw = peDxDirectDraw; pDxEvent_New->dwEvent = dwEvent; pDxEvent_New->dwIrqFlag = 0; pDxEvent_New->pfnCallBack = pfnCallBack; pDxEvent_New->pContext = pContext; pDxEvent_New->pDxEvent_Next = peDxDirectDraw->pDxEvent_PassiveList;
peDxDirectDraw->pDxEvent_PassiveList = pDxEvent_New;
bRet = TRUE; } else { // Delete the event.
if (pDxEvent_Previous == NULL) { ASSERTDX(peDxDirectDraw->pDxEvent_PassiveList == pDxEvent, "Deletion code is confused");
peDxDirectDraw->pDxEvent_PassiveList = pDxEvent->pDxEvent_Next; } else { pDxEvent_Previous->pDxEvent_Next = pDxEvent->pDxEvent_Next; }
bRet = TRUE; } } }
ASSERTDX(gpfnUnlockDevice, "bDxModifyPassiveEventList: gpfnUnlockDevice is NULL"); gpfnUnlockDevice(peDxDirectDraw->hdev);
if (bAdd) // Add case
{ if (!bRet) { // Add failed, so free the new node we allocated up front:
ExFreePool(pDxEvent_New);
RIPDX("DD_DXAPI_REGISTER_EVENT: Event was already registered"); } } else // Remove case
{ if (bRet) { // Delete succeeded, so free the old node:
ExFreePool(pDxEvent); } else { KdPrint(("DD_DXAPI_UNREGISTEREVENT: Couldn't find an event registered with those\n")); KdPrint(("same parameters, so the unregister failed.\n")); RIPDX("This will probably cause a leak of non-paged memory!"); } }
return(bRet); }
/******************************Public*Routine******************************\
* BOOL bDxModifyDispatchEventList * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOL bDxModifyDispatchEventList( EDD_DXDIRECTDRAW* peDxDirectDraw, EDD_DXVIDEOPORT* peDxVideoPort, BOOL bAdd, // TRUE to add, FALSE to delete
DWORD dwEvent, DWORD dwIrqFlag, LPDD_NOTIFYCALLBACK pfnCallBack, PVOID pContext, DWORD dwListEntry ) { BOOL bRet; DXAPI_EVENT* pDxEvent; DXAPI_EVENT* pDxEvent_New; DXAPI_EVENT* pDxEvent_Previous; KIRQL OldIrql;
bRet = FALSE; // Assume failure
ASSERTDX(KeGetCurrentIrql() == PASSIVE_LEVEL, "Expected passive level"); ASSERTDX((bAdd == FALSE) || (bAdd == TRUE), "Bad boolean");
// The event list is traversed at dispatch-level, so needs
// to be allocated non-paged.
if (bAdd) { pDxEvent_New = (DXAPI_EVENT*) ExAllocatePoolWithTag(NonPagedPool, sizeof(*pDxEvent), 'eddG'); if (pDxEvent_New == NULL) return(FALSE);
RtlZeroMemory(pDxEvent_New, sizeof(*pDxEvent_New)); }
// We must synchronize additions or deletions to the dispatch-level
// event list via our spin lock. Note that this spinlock (of course)
// raises our IRQL level, which means we can't touch any pageable code!
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) || ((peDxVideoPort != NULL) && (peDxVideoPort->bLost))) { KdPrint(("bDxModifyDispatchEventList: Objects are lost\n")); } else { // First, try to find this event in the list:
pDxEvent_Previous = NULL;
for (pDxEvent = peDxDirectDraw->pDxEvent_DispatchList[dwListEntry]; pDxEvent != NULL; pDxEvent = pDxEvent->pDxEvent_Next) { if ((pDxEvent->dwEvent == dwEvent) && (pDxEvent->dwIrqFlag == dwIrqFlag) && (pDxEvent->pfnCallBack == pfnCallBack) && (pDxEvent->pContext == pContext)) { break; }
pDxEvent_Previous = pDxEvent; }
// It's a failure when:
//
// 1) If adding, the same event is already in the list;
// 2) If deleting, the event is not in the list.
if ((bAdd) == (pDxEvent == NULL)) { if (bAdd) { // Add the event.
pDxEvent_New->peDxDirectDraw = peDxVideoPort->peDxDirectDraw; pDxEvent_New->peDxVideoPort = peDxVideoPort; pDxEvent_New->dwEvent = dwEvent; pDxEvent_New->dwIrqFlag = dwIrqFlag; pDxEvent_New->pfnCallBack = pfnCallBack; pDxEvent_New->pContext = pContext; pDxEvent_New->pDxEvent_Next = peDxDirectDraw->pDxEvent_DispatchList[dwListEntry];
peDxDirectDraw->pDxEvent_DispatchList[dwListEntry] = pDxEvent_New;
bRet = TRUE; } else { // Delete the event.
if (pDxEvent_Previous == NULL) { ASSERTDX(peDxDirectDraw->pDxEvent_DispatchList[dwListEntry] == pDxEvent, "Deletion code is confused");
peDxDirectDraw->pDxEvent_DispatchList[dwListEntry] = pDxEvent->pDxEvent_Next; } else { pDxEvent_Previous->pDxEvent_Next = pDxEvent->pDxEvent_Next; }
bRet = TRUE; } } }
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
if (bAdd) // Add case
{ if (!bRet) { // Add failed, so free the new node we allocated up front:
ExFreePool(pDxEvent_New); } } else // Remove case
{ if (bRet) { // Delete succeeded, so free the old node:
ExFreePool(pDxEvent); } else { KdPrint(("DD_DXAPI_UNREGISTEREVENT: Couldn't find an event registered with those\n")); KdPrint(("same parameters, so the unregister failed.\n")); RIPDX("This will probably cause a leak of non-paged memory!"); } }
return(bRet); }
/******************************Public*Routine******************************\
* VOID vDxEnableInterrupts * * NOTE: Drivers may not fail DxEnableIrq. * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID vDxEnableInterrupts( EDD_DXDIRECTDRAW* peDxDirectDraw, DWORD dwLine ) { DWORD dwIRQSources = 0; KIRQL OldIrql; DXAPI_EVENT* pDxEvent; DDENABLEIRQINFO EnableIrqInfo; DWORD dwRet; DWORD i;
ASSERTDX(KeGetCurrentIrql() == PASSIVE_LEVEL, "Expected passive level"); ASSERTDX(peDxDirectDraw->DxApiInterface.DxEnableIrq != NULL, "DxEnableIrq must be hooked if supporting interrupts.");
// We acquire both the devlock and the spinlock to ensure that no other
// activity in the driver is occurring while interrupts are enabled.
//
// The motivation for acquiring both (the spinlock could have been
// sufficient) is that we want to allow drivers to touch the CRTC
// registers in their interrupt enable routine (typically, both the
// display driver and the enable interrupt routine use CRTC registers,
// the usage of which must be synchronized).
ASSERTDX(gpfnLockDevice, "vDxEnableInterrupts: gpfnLockDevice is NULL"); gpfnLockDevice(peDxDirectDraw->hdev);
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
// Compute the interrupts that are to be enabled by traversing the
// active event list:
for( i = 0; i < NUM_DISPATCH_LISTS; i++ ) { for (pDxEvent = peDxDirectDraw->pDxEvent_DispatchList[i]; pDxEvent != NULL; pDxEvent = pDxEvent->pDxEvent_Next) { dwIRQSources |= pDxEvent->dwIrqFlag; } }
EnableIrqInfo.dwIRQSources = dwIRQSources; EnableIrqInfo.dwLine = dwLine; EnableIrqInfo.IRQCallback = DxIrqCallBack; EnableIrqInfo.lpIRQData = &peDxDirectDraw->IrqData;
dwRet = peDxDirectDraw->DxApiInterface.DxEnableIrq( peDxDirectDraw->HwDeviceExtension, &EnableIrqInfo, NULL);
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
ASSERTDX(gpfnUnlockDevice, "vDxEnableInterrupts: gpfnUnlockDevice is NULL"); gpfnUnlockDevice(peDxDirectDraw->hdev);
ASSERTDX(dwRet == DD_OK, "vDxEnableInterrupts: Driver failed DxEnableIrq"); }
/******************************Public*Routine******************************\
* DWORD dwDxRegisterEvent * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
DWORD dwDxRegisterEvent( DDREGISTERCALLBACK* pRegisterEvent, BOOL bRegister // TRUE if register, FALSE if unregister
) { DWORD dwRet; DXOBJ* pDxObjDirectDraw; DXOBJ* pDxObjVideoPort; EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXVIDEOPORT* peDxVideoPort; DWORD dwEvent; DWORD dwIrqFlag; BOOL bPassiveEvent; BOOL bDispatchEvent; DWORD dwLine;
dwRet = DDERR_GENERIC; // Assume failure
// Passive level is required because we have to acquire the devlock
// for the RESCHANGE and DOSBOX notifications.
ASSERTDX(KeGetCurrentIrql() == PASSIVE_LEVEL, "Expected passive level"); ASSERTDX(pRegisterEvent->pfnCallback != NULL, "Null callback specified"); ASSERTDX(pRegisterEvent->hDirectDraw != NULL, "Null hDirectDraw specified");
pDxObjDirectDraw = (DXOBJ*) pRegisterEvent->hDirectDraw; if (pDxObjDirectDraw != NULL) { peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
// Note that we don't support the hooking of DDEVENT_CLOSEDIRECTDRAW,
// DDEVENT_CLOSESURFACE, or DDEVENT_CLOSEVIDEOPORT because those are
// always explictly registered with the object open call. If multiple
// clients want object close notification, they should each open their
// own object instances.
dwEvent = pRegisterEvent->dwEvents;
// Memphis doesn't bother checking to verify that 'dwParam1' and
// 'dwParam2' are zero when unused, so we won't either.
bPassiveEvent = FALSE; bDispatchEvent = FALSE; peDxVideoPort = NULL; dwLine = 0; dwIrqFlag = 0;
switch (dwEvent) { case DDEVENT_VP_VSYNC: case DDEVENT_VP_LINE:
ASSERTDX(pRegisterEvent->dwParam1 != NULL, "dwParam1 should be videoport handle");
pDxObjVideoPort = (DXOBJ*) pRegisterEvent->dwParam1; if (pDxObjVideoPort != NULL) { peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT, "dwParam1 should be videoport handle");
if (dwEvent == DDEVENT_VP_LINE) { dwIrqFlag = DDIRQ_VPORT0_LINE; // We're going to shift this...
// We make it so that the 'dwLine' parameter is non-zero only
// when the event is registered, not unregistered,
dwLine = (bRegister) ? (DWORD) pRegisterEvent->dwParam2 : 0; } else { dwIrqFlag = DDIRQ_VPORT0_VSYNC; // We're going to shift this...
}
dwIrqFlag <<= (2 * peDxVideoPort->dwVideoPortID);
bDispatchEvent = TRUE; } break;
case DDEVENT_DISPLAY_VSYNC:
dwIrqFlag = DDIRQ_DISPLAY_VSYNC; bDispatchEvent = TRUE; break;
case DDEVENT_PRERESCHANGE: case DDEVENT_POSTRESCHANGE: case DDEVENT_PREDOSBOX: case DDEVENT_POSTDOSBOX:
bPassiveEvent = TRUE; break;
default:
KdPrint(("dwDxRegisterEvent: Invalid dwEvents specified\n")); dwRet = DDERR_UNSUPPORTED; break; }
if (bPassiveEvent) { if (bDxModifyPassiveEventList(peDxDirectDraw, bRegister, dwEvent, pRegisterEvent->pfnCallback, pRegisterEvent->pContext)) { dwRet = DD_OK; } } else if (bDispatchEvent) { // First, verify that the requested interrupt is supported:
if (!(peDxDirectDraw->dwIRQCaps & dwIrqFlag)) { KdPrint(("dwDxRegisterEvent: Interrupt not supported by driver.\n")); dwRet = DDERR_UNSUPPORTED; } else { if (bDxModifyDispatchEventList(peDxDirectDraw, peDxVideoPort, bRegister, dwEvent, dwIrqFlag, pRegisterEvent->pfnCallback, pRegisterEvent->pContext, CLIENT_DISPATCH_LIST)) { vDxEnableInterrupts(peDxDirectDraw, dwLine); dwRet = DD_OK; } } } } return(dwRet); }
/******************************Public*Routine******************************\
* VOID DxRegisterEvent * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxRegisterEvent( DDREGISTERCALLBACK* pRegisterEvent, DWORD* pdwRet ) { if (pRegisterEvent == NULL) { *pdwRet = DDERR_INVALIDPARAMS; } else { *pdwRet = dwDxRegisterEvent(pRegisterEvent, TRUE); } }
/******************************Public*Routine******************************\
* VOID DxUnregisterEvent * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxUnregisterEvent( DDREGISTERCALLBACK* pRegisterEvent, DWORD* pdwRet ) { if (pRegisterEvent == NULL) { *pdwRet = DDERR_INVALIDPARAMS; } else { *pdwRet = dwDxRegisterEvent(pRegisterEvent, FALSE); } }
/******************************Public*Routine******************************\
* VOID DxGetPolarity * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxGetPolarity( DDGETPOLARITYIN* pGetPolarityIn, DDGETPOLARITYOUT* pGetPolarityOut ) { DWORD dwRet; DXOBJ* pDxObjDirectDraw; DXOBJ* pDxObjVideoPort; DXOBJ* pDxObjTarget; DXOBJ* pDxObjCurrent; EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXVIDEOPORT* peDxVideoPort; DDGETPOLARITYININFO GetPolarityInInfo; DDGETPOLARITYOUTINFO GetPolarityOutInfo; KIRQL OldIrql;
pGetPolarityOut->ddRVal = DDERR_INVALIDPARAMS; if (pGetPolarityIn == NULL) { return; }
dwRet = DDERR_UNSUPPORTED; // Assume failure
pDxObjDirectDraw = (DXOBJ*) pGetPolarityIn->hDirectDraw; pDxObjVideoPort = (DXOBJ*) pGetPolarityIn->hVideoPort; if ((pDxObjDirectDraw != NULL) && (pDxObjVideoPort != NULL)) { peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw; peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW, "Invalid DirectDraw object"); ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT, "Invalid VideoPort object"); ASSERTDX(peDxDirectDraw == peDxVideoPort->peDxDirectDraw, "Surface, VideoPort, and DirectDraw objects don't match");
GetPolarityInInfo.lpVideoPortData = peDxVideoPort; GetPolarityOutInfo.bPolarity = 0;
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) || (peDxVideoPort->bLost)) { KdPrint(("DxGetPolarity: Objects are lost\n")); dwRet = DDERR_SURFACELOST; } else { if (peDxDirectDraw->DxApiInterface.DxGetPolarity) { dwRet = peDxDirectDraw->DxApiInterface.DxGetPolarity( peDxDirectDraw->HwDeviceExtension, &GetPolarityInInfo, &GetPolarityOutInfo); } }
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
pGetPolarityOut->ddRVal = dwRet; pGetPolarityOut->bPolarity = GetPolarityOutInfo.bPolarity; } }
/******************************Public*Routine******************************\
* VOID DxAddVpCaptureBuffer * * 01-Nov-1997 -by- smac * Wrote it. \**************************************************************************/
VOID APIENTRY DxAddVpCaptureBuffer( DDADDVPCAPTUREBUFF* pAddCaptureBuff, DWORD* pdwRet ) { DXOBJ* pDxObjCapture; EDD_DXCAPTURE* peDxCapture; EDD_DXVIDEOPORT* peDxVideoPort; EDD_DXDIRECTDRAW* peDxDirectDraw; DWORD dwTop; KIRQL OldIrql;
*pdwRet = DDERR_INVALIDPARAMS; if (pAddCaptureBuff == NULL) { return; }
pDxObjCapture = (DXOBJ*) pAddCaptureBuff->hCapture; if (pDxObjCapture != NULL) { peDxCapture = pDxObjCapture->peDxCapture;
ASSERTDX(pDxObjCapture->iDxType == DXT_CAPTURE, "Invalid Capture object"); ASSERTDX(pAddCaptureBuff->pKEvent != NULL, "No KEvent specified"); ASSERTDX(pAddCaptureBuff->pMDL != NULL, "No MDL specified"); ASSERTDX((pAddCaptureBuff->dwFlags != 0 ) && !(pAddCaptureBuff->dwFlags & ~(DDADDBUFF_SYSTEMMEMORY|DDADDBUFF_NONLOCALVIDMEM|DDADDBUFF_INVERT)), "Invalid flags specified"); ASSERTDX(pAddCaptureBuff->lpBuffInfo != NULL, "lpBuffInfo not specified");
*pdwRet = DDERR_INVALIDOBJECT; peDxVideoPort = peDxCapture->peDxVideoPort; if( peDxVideoPort != NULL ) { peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if( !( peDxVideoPort->bLost ) && !( peDxCapture->bLost ) ) { // Is the queue full?
dwTop = peDxCapture->dwTop; if( ( peDxCapture->CaptureQueue[dwTop].flFlags & DD_DXCAPTUREBUFF_FLAG_IN_USE ) || !( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_ON ) ) { *pdwRet = DDERR_CURRENTLYNOTAVAIL; } else { // Save the new buffer in the queque
peDxCapture->CaptureQueue[dwTop].dwClientFlags = pAddCaptureBuff->dwFlags; peDxCapture->CaptureQueue[dwTop].pBuffMDL = pAddCaptureBuff->pMDL; peDxCapture->CaptureQueue[dwTop].pBuffKEvent = pAddCaptureBuff->pKEvent; peDxCapture->CaptureQueue[dwTop].lpBuffInfo = (PVOID) pAddCaptureBuff->lpBuffInfo; peDxCapture->CaptureQueue[dwTop].flFlags = DD_DXCAPTUREBUFF_FLAG_IN_USE; peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_CAPTURING;
if( ++(peDxCapture->dwTop) >= DXCAPTURE_MAX_CAPTURE_BUFFS ) { peDxCapture->dwTop = 0; } *pdwRet = DD_OK; } } KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql); } } }
/******************************Public*Routine******************************\
* VOID DxInternalFlushVpCaptureBuffs * * 12-Apr-1999 -by- smac * Wrote it. \**************************************************************************/
VOID APIENTRY DxInternalFlushVpCaptureBuffs( EDD_DXDIRECTDRAW* peDxDirectDraw, EDD_DXVIDEOPORT* peDxVideoPort, EDD_DXCAPTURE* peDxCapture ) { DDTRANSFERININFO ddTransferIn; DDTRANSFEROUTINFO ddTransferOut; LPDDCAPBUFFINFO lpBuffInfo; DWORD i;
// Turn off all video port capture if nobody else is capturing
if( peDxVideoPort->peDxCapture && ( peDxCapture->peDxCaptureNext == NULL ) ) { peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_CAPTURING; }
// If a buffer is in the queue and the busmaster has not yet been
// initiated, clear it now so we don't do it. If the busmaster has
// already been initiated, we will tell the miniport to stop it now.
peDxCapture->dwTop = peDxCapture->dwBottom = 0; for( i = 0; i < DXCAPTURE_MAX_CAPTURE_BUFFS; i++ ) { if( peDxCapture->CaptureQueue[i].flFlags & DD_DXCAPTUREBUFF_FLAG_IN_USE ) { if( peDxCapture->CaptureQueue[i].flFlags & DD_DXCAPTUREBUFF_FLAG_WAITING ) { ddTransferIn.dwStartLine = 0; ddTransferIn.dwEndLine = 0; ddTransferIn.dwTransferFlags = DDTRANSFER_CANCEL; ddTransferIn.lpDestMDL = NULL; ddTransferIn.lpSurfaceData = NULL; ddTransferIn.dwTransferID = ((ULONG_PTR)peDxCapture & ~0xf) + i;
if (peDxDirectDraw->DxApiInterface.DxTransfer) { peDxDirectDraw->DxApiInterface.DxTransfer( peDxDirectDraw->HwDeviceExtension, &ddTransferIn, &ddTransferOut); }
peDxCapture->CaptureQueue[i].peDxSurface->flFlags &= ~DD_DXSURFACE_FLAG_TRANSFER; }
lpBuffInfo = (LPDDCAPBUFFINFO) peDxCapture->CaptureQueue[i].lpBuffInfo; lpBuffInfo->bPolarity = 0; lpBuffInfo->dwFieldNumber = 0; lpBuffInfo->ddRVal = (DWORD) DDERR_GENERIC; peDxCapture->CaptureQueue[i].flFlags = 0;
KeSetEvent( peDxCapture->CaptureQueue[i].pBuffKEvent, 0, 0 ); } } }
/******************************Public*Routine******************************\
* VOID DxFlushVpCaptureBuffs * * 01-Nov-1997 -by- smac * Wrote it. \**************************************************************************/
VOID APIENTRY DxFlushVpCaptureBuffs( DWORD** hCapture, DWORD* pdwRet ) { DXOBJ* pDxObjCapture; EDD_DXCAPTURE* peDxCapture; EDD_DXVIDEOPORT* peDxVideoPort; EDD_DXDIRECTDRAW* peDxDirectDraw; KIRQL OldIrql;
*pdwRet = DDERR_INVALIDPARAMS; if (hCapture == NULL) { return; }
ASSERTDX(KeGetCurrentIrql() <= DISPATCH_LEVEL, "DxFlushCaptureBuffs: Call less than or equl to DISPATCH_LEVEL (it accesses the dispatch table)");
pDxObjCapture = (DXOBJ*) (*hCapture); if (pDxObjCapture != NULL) { peDxCapture = pDxObjCapture->peDxCapture; peDxVideoPort = peDxCapture->peDxVideoPort; peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
DxInternalFlushVpCaptureBuffs( peDxDirectDraw, peDxVideoPort, peDxCapture );
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
*pdwRet = DD_OK; } }
/******************************Public*Routine******************************\
* VOID DxIrqCallBack * * This routine is called by the miniport at interrupt time to notify us * of interrupt-based events. We simply queue a DPC to handle the request * at the more appropriate dispatch level, instead of interrupt level that * we're currently at. * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxIrqCallBack( DX_IRQDATA* pIrqData ) { EDD_DXDIRECTDRAW* peDxDirectDraw;
// We always tell the miniport to call us back with the pointer to
// &peDxDirectDraw->IrqData, so we can get back to the original
// peDxDirectDraw by subtracting the offset. If we ever need to
// change this in the future, we can simply add a field to DX_IRQDATA
// to point to the context:
peDxDirectDraw = (EDD_DXDIRECTDRAW*) ((BYTE*) pIrqData - offsetof(EDD_DXDIRECTDRAW, IrqData));
// It's okay if KeInsertQueueDpc fails because the same DPC for a
// previous interrupt is still queued -- the miniport always ORs
// its interrupt flags into pIrqData->dwIrqflags.
KeInsertQueueDpc(&peDxDirectDraw->EventDpc, pIrqData, NULL); }
/******************************Public*Routine******************************\
* VOID DxGetIrqFlags * * Out interrupt processing code runs at DPC level, and can be interrupt * by an ISR. Consequently, when we look at the interrupt status, we * must synchronize with the ISR. This is accomplished by having * VideoPortSynchronizeExecution (which does a KeSynchronizeExecution) * call-back to this routine. * * All we do here is copy the flags to the device extension (actually, * we use the EDD_DXDIRECTDRAW which is allocated one-to-one with the * device extension). * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOLEAN DxGetIrqFlags( PVOID pvContext ) { EDD_DXDIRECTDRAW* peDxDirectDraw;
peDxDirectDraw = (EDD_DXDIRECTDRAW*) pvContext;
// Copy the flags to a safe place:
peDxDirectDraw->dwSynchedIrqFlags = peDxDirectDraw->IrqData.dwIrqFlags;
// We have to zero the current flags because the miniport always ORs
// its flags in:
peDxDirectDraw->IrqData.dwIrqFlags = 0;
return(TRUE); }
/******************************Public*Routine******************************\
* VOID DxEventDpc * * This routine does all the work of handling interrupt notification * from the miniport. It makes the synchronous call-backs to anyone * who has hooked the particular event. * * Note that to be synchronous we're making the call-backs at dispatch * level. So if a callee doesn't require a truly synchronous notification, * they should do nothing but kick off an event. * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
// We can't call KeSynchronizeExecution directly, because we don't
// have the device's interrupt object. Videoport.sys does, however.
// Unfortunately, 'video.h', which is used to access the videoport.sys
// routines, was never intended to be mixed with GDI and USER header
// files (among other problems, there are conflicts in the PEVENT and
// PVIDEO_POWER_MANAGEMENT structures). So we define what prototypes
// we need here:
extern "C" {
typedef enum VIDEO_SYNCHRONIZE_PRIORITY { VpLowPriority, VpMediumPriority, VpHighPriority } VIDEO_SYNCHRONIZE_PRIORITY, *PVIDEO_SYNCHRONIZE_PRIORITY;
typedef BOOLEAN (*PMINIPORT_SYNCHRONIZE_ROUTINE)( PVOID Context );
VOID VideoPortSynchronizeExecution( PVOID HwDeviceExtension, VIDEO_SYNCHRONIZE_PRIORITY Priority, PMINIPORT_SYNCHRONIZE_ROUTINE synchronizeRoutine, PVOID Context );
};
VOID DxEventDpc( PKDPC pDpc, PVOID pvContext, PVOID pvArgument1, PVOID pvArgument2 ) { EDD_DXDIRECTDRAW* peDxDirectDraw; DX_IRQDATA* pIrqData; DXAPI_EVENT* pDxEvent; DWORD dwIrqFlags; DWORD i;
pIrqData = (DX_IRQDATA*) pvArgument1; peDxDirectDraw = (EDD_DXDIRECTDRAW*) pvContext;
// The ISR can be triggered even while we're processing the DPC for
// its previous interrupt. Consequently, we have to access the
// interrupt flags in a routine that is synchronized to the ISR
// routine.
//
// Note that we don't call KeSynchronizeExecution directly, because
// we don't have the device's interrupt object.
VideoPortSynchronizeExecution(peDxDirectDraw->HwDeviceExtension, VpMediumPriority, DxGetIrqFlags, peDxDirectDraw);
dwIrqFlags = peDxDirectDraw->dwSynchedIrqFlags;
// We must acquire a spinlock while traversing the event list to
// protect against simultaneous modifications to the list.
KeAcquireSpinLockAtDpcLevel(&peDxDirectDraw->SpinLock);
// We call the callbacks registered by the client before we
// call the ones that we registered so we give the client a chance
// to skip fields before we execute our skip logic. This is why
// we keep two dispatch lists.
for (i = 0; i < NUM_DISPATCH_LISTS; i++) { for (pDxEvent = peDxDirectDraw->pDxEvent_DispatchList[i]; pDxEvent != NULL; pDxEvent = pDxEvent->pDxEvent_Next) { if (pDxEvent->dwIrqFlag & dwIrqFlags) { pDxEvent->pfnCallBack(pDxEvent->dwEvent, pDxEvent->pContext, 0, 0); } } }
// If it was a busmaster IRQ, take care of them as well
if (dwIrqFlags & DDIRQ_BUSMASTER) { for (pDxEvent = peDxDirectDraw->pDxEvent_CaptureList; pDxEvent != NULL; pDxEvent = pDxEvent->pDxEvent_Next) { pDxEvent->pfnCallBack(pDxEvent->dwEvent, pDxEvent->pContext, 0, 0); } }
KeReleaseSpinLockFromDpcLevel(&peDxDirectDraw->SpinLock); }
/******************************Public*Routine******************************\
* VOID vDxFlip * * Assumes the spinlock is held. * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID vDxFlip( EDD_DXVIDEOPORT* peDxVideoPort, DWORD dwFlags ) { EDD_DXDIRECTDRAW* peDxDirectDraw; DWORD iOldVideo; DWORD iOldVbi; DWORD iOldOverlay; DWORD iNewVideo; DWORD iNewVbi; DWORD iNewOverlay; DDFLIPVIDEOPORTINFO FlipVideoPortInfo; DDFLIPOVERLAYINFO FlipOverlayInfo; DWORD dwRet; DWORD dwTemp;
ASSERTDX(KeGetCurrentIrql() == DISPATCH_LEVEL, "Expected held spinlock");
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
if( dwFlags == DDVPFLIP_VBI ) { if (peDxVideoPort->cAutoflipVbi != 0) { // Flip videoport VBI surface:
iOldVbi = peDxVideoPort->iCurrentVbi; iNewVbi = iOldVbi + 1; if (iNewVbi >= peDxVideoPort->cAutoflipVbi) iNewVbi = 0; peDxVideoPort->iCurrentVbi = iNewVbi;
FlipVideoPortInfo.lpVideoPortData = peDxVideoPort; FlipVideoPortInfo.lpCurrentSurface = peDxVideoPort->apeDxSurfaceVbi[iOldVbi]; FlipVideoPortInfo.lpTargetSurface = peDxVideoPort->apeDxSurfaceVbi[iNewVbi]; FlipVideoPortInfo.dwFlipVPFlags = DDVPFLIP_VBI;
if (peDxDirectDraw->DxApiInterface.DxFlipVideoPort) { dwRet = peDxDirectDraw->DxApiInterface.DxFlipVideoPort( peDxDirectDraw->HwDeviceExtension, &FlipVideoPortInfo, NULL); } } }
else if( dwFlags == DDVPFLIP_VIDEO ) { if (peDxVideoPort->cAutoflipVideo != 0) { // Flip videoport video surface:
iOldVideo = peDxVideoPort->iCurrentVideo; iNewVideo = iOldVideo + 1; if (iNewVideo >= peDxVideoPort->cAutoflipVideo) iNewVideo = 0; peDxVideoPort->iCurrentVideo = iNewVideo;
FlipVideoPortInfo.lpVideoPortData = peDxVideoPort; FlipVideoPortInfo.lpCurrentSurface = peDxVideoPort->apeDxSurfaceVideo[iOldVideo]; FlipVideoPortInfo.lpTargetSurface = peDxVideoPort->apeDxSurfaceVideo[iNewVideo]; FlipVideoPortInfo.dwFlipVPFlags = DDVPFLIP_VIDEO;
if (peDxDirectDraw->DxApiInterface.DxFlipVideoPort) { dwRet = peDxDirectDraw->DxApiInterface.DxFlipVideoPort( peDxDirectDraw->HwDeviceExtension, &FlipVideoPortInfo, NULL); }
// Flip overlay surface:
if( ( peDxVideoPort->apeDxSurfaceVideo[0] != NULL ) && ( peDxVideoPort->apeDxSurfaceVideo[0]->ddsCaps & DDSCAPS_OVERLAY ) && ( ( peDxVideoPort->apeDxSurfaceVideo[0]->dwOverlayFlags & DDOVER_AUTOFLIP ) || ( peDxVideoPort->bSoftwareAutoflip ) ) ) { // If there are two surfaces, flip to the opposite surface. If
// there are more than two surfaces, flip to dwNumAutoflip - 2.
dwTemp = 1; if( peDxVideoPort->cAutoflipVideo != 2 ) { dwTemp++; } dwTemp = peDxVideoPort->iCurrentVideo + peDxVideoPort->cAutoflipVideo - dwTemp; if( dwTemp >= peDxVideoPort->cAutoflipVideo ) { dwTemp -= peDxVideoPort->cAutoflipVideo; }
FlipOverlayInfo.lpTargetSurface = peDxVideoPort->apeDxSurfaceVideo[dwTemp]; if( dwTemp == 0 ) { dwTemp = peDxVideoPort->cAutoflipVideo; } FlipOverlayInfo.lpCurrentSurface = peDxVideoPort->apeDxSurfaceVideo[--dwTemp]; FlipOverlayInfo.dwFlags = 0;
if (peDxDirectDraw->DxApiInterface.DxFlipOverlay) { dwRet = peDxDirectDraw->DxApiInterface.DxFlipOverlay( peDxDirectDraw->HwDeviceExtension, &FlipOverlayInfo, NULL); } } } } }
/******************************Public*Routine******************************\
* VOID vDxBob * * Assumes the spinlock is held. * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID vDxBob( EDD_DXVIDEOPORT* peDxVideoPort ) { EDD_DXDIRECTDRAW* peDxDirectDraw; DDBOBNEXTFIELDINFO BobNextFieldInfo; DWORD dwRet; DWORD dwTemp;
ASSERTDX(KeGetCurrentIrql() == DISPATCH_LEVEL, "Expected held spinlock");
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
// Get the current surface handle. This is tricky because
// dwCurrentBuffer tells us which surface the video port is
// writting to - not which surface has the overlay. Therefore,
// we re-create the algorithm used in DoFlip to get the surface.
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP ) { dwTemp = 1; if( peDxVideoPort->cAutoflipVideo != 2 ) { dwTemp++; } dwTemp = peDxVideoPort->iCurrentVideo + peDxVideoPort->cAutoflipVideo - dwTemp; if( dwTemp >= peDxVideoPort->cAutoflipVideo ) { dwTemp -= peDxVideoPort->cAutoflipVideo; } } else { dwTemp = 0; }
BobNextFieldInfo.lpSurface = peDxVideoPort->apeDxSurfaceVideo[dwTemp];
if (peDxDirectDraw->DxApiInterface.DxBobNextField) { dwRet = peDxDirectDraw->DxApiInterface.DxBobNextField( peDxDirectDraw->HwDeviceExtension, &BobNextFieldInfo, NULL); } }
/******************************Public*Routine******************************\
* VOID vDxSkip * * Assumes the spinlock is held. * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID vDxSkip( EDD_DXVIDEOPORT* peDxVideoPort, DWORD dwFlags ) { EDD_DXDIRECTDRAW* peDxDirectDraw; DDSKIPNEXTFIELDINFO SkipNextFieldInfo; DWORD dwRet;
ASSERTDX(KeGetCurrentIrql() == DISPATCH_LEVEL, "Expected held spinlock");
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
if (peDxDirectDraw->DxApiInterface.DxSkipNextField) { SkipNextFieldInfo.lpVideoPortData = peDxVideoPort; SkipNextFieldInfo.dwSkipFlags = dwFlags;
dwRet = peDxDirectDraw->DxApiInterface.DxSkipNextField( peDxDirectDraw->HwDeviceExtension, &SkipNextFieldInfo, NULL); } }
/******************************Public*Routine******************************\
* VOID IRQCapture * * This routine initiates video/VBI capture based on a video port VSYNC. * * NOTE: The spinlock is already held. * * 10-Jan-1998 -by- Scott MacDonald [smac] * Wrote it. \**************************************************************************/
VOID IRQCapture( EDD_DXVIDEOPORT* peDxVideoPort, EDD_DXDIRECTDRAW* peDxDirectDraw ) { DDGETCURRENTAUTOFLIPININFO ddAutoflipInInfo; DDGETCURRENTAUTOFLIPOUTINFO ddAutoflipOutInfo; EDD_DXCAPTURE* peDxCapture; LPDDCAPBUFFINFO lpBuffInfo; DXCAPTUREBUFF* lpBuff; DDTRANSFERININFO ddTransferIn; DDTRANSFEROUTINFO ddTransferOut; ULONGLONG ullTimeStamp; PULONGLONG pullTemp; ULONGLONG rate; DWORD dwVBIIndex; DWORD dwVideoIndex; BOOL bStarved = TRUE; DWORD ddRVal;
// Get the current time stamp
ullTimeStamp = (ULONGLONG)KeQueryPerformanceCounter((PLARGE_INTEGER)&rate).QuadPart; ullTimeStamp = (ullTimeStamp & 0xFFFFFFFF00000000) / rate * 10000000 + (ullTimeStamp & 0xFFFFFFFF) * 10000000 / rate;
// If either the VBI or video is being hardware autoflipped, figure out
// the correct buffers.
dwVBIIndex = 0; dwVideoIndex = 0; if( ( ( peDxVideoPort->cAutoflipVbi > 1 ) && !( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI ) ) || ( ( peDxVideoPort->cAutoflipVideo > 1 ) && !( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP ) ) ) { ddAutoflipInInfo.lpVideoPortData = peDxVideoPort; ddAutoflipOutInfo.dwSurfaceIndex = 0; if (peDxDirectDraw->DxApiInterface.DxGetCurrentAutoflip) { ddRVal = peDxDirectDraw->DxApiInterface.DxGetCurrentAutoflip( peDxDirectDraw->HwDeviceExtension, &ddAutoflipInInfo, &ddAutoflipOutInfo); } if( peDxVideoPort->cAutoflipVideo > 0 ) { dwVideoIndex = ddAutoflipOutInfo.dwSurfaceIndex; if( dwVideoIndex-- == 0 ) { dwVideoIndex = peDxVideoPort->cAutoflipVideo - 1; } } if( peDxVideoPort->cAutoflipVbi > 0 ) { dwVBIIndex = ddAutoflipOutInfo.dwVBISurfaceIndex; if( dwVBIIndex-- == 0 ) { dwVBIIndex = peDxVideoPort->cAutoflipVbi - 1; } } }
// Which is the surface containing the most recent VBI data?
if( ( peDxVideoPort->cAutoflipVbi > 0 ) && ( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI ) ) { dwVBIIndex = peDxVideoPort->iCurrentVbi; if( dwVBIIndex-- == 0 ) { dwVBIIndex = peDxVideoPort->cAutoflipVbi - 1; } }
// Which is the surface containing the most recent video data?
if( ( peDxVideoPort->cAutoflipVideo > 0 ) && ( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP ) ) { dwVideoIndex = peDxVideoPort->iCurrentVideo; if( dwVideoIndex-- == 0 ) { dwVideoIndex = peDxVideoPort->cAutoflipVideo - 1; } }
// Look at each capture device to determine if it has to do a busmaster
// or not
peDxCapture = peDxVideoPort->peDxCapture; while( peDxCapture != NULL ) { if( ( peDxCapture->CaptureQueue[peDxCapture->dwBottom].flFlags & DD_DXCAPTUREBUFF_FLAG_IN_USE ) && !( peDxCapture->CaptureQueue[peDxCapture->dwBottom].flFlags & DD_DXCAPTUREBUFF_FLAG_WAITING ) ) { bStarved = FALSE;
if( peDxCapture->dwCaptureCountDown-- == 1 ) { peDxCapture->dwCaptureCountDown = peDxCapture->dwCaptureEveryNFields; lpBuff = &(peDxCapture->CaptureQueue[peDxCapture->dwBottom]);
// Fill in the buffer info
lpBuffInfo = (LPDDCAPBUFFINFO) lpBuff->lpBuffInfo; lpBuffInfo->dwFieldNumber = peDxVideoPort->dwCurrentField; pullTemp = (PULONGLONG) &(lpBuffInfo->liTimeStamp); *pullTemp = ullTimeStamp;
// Tell mini port to do the transfer
ddTransferIn.dwStartLine = peDxCapture->dwStartLine; ddTransferIn.dwEndLine = peDxCapture->dwEndLine; ddTransferIn.dwTransferFlags = lpBuff->dwClientFlags; if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_HALFLINES ) { ddTransferIn.dwTransferFlags |= DDTRANSFER_HALFLINES; } ddTransferIn.lpDestMDL = lpBuff->pBuffMDL; if( peDxCapture->flFlags & DD_DXCAPTURE_FLAG_VIDEO ) { ddTransferIn.lpSurfaceData = peDxVideoPort->apeDxSurfaceVideo[dwVideoIndex]; } else { ddTransferIn.lpSurfaceData = peDxVideoPort->apeDxSurfaceVbi[dwVBIIndex]; }
if (ddTransferIn.lpSurfaceData) { ddTransferIn.dwTransferID = (ULONG_PTR) peDxCapture; ddTransferIn.dwTransferID &= ~0xf; ddTransferIn.dwTransferID |= peDxCapture->dwBottom;
ddRVal = DDERR_UNSUPPORTED; if (peDxDirectDraw->DxApiInterface.DxTransfer) { ddRVal = peDxDirectDraw->DxApiInterface.DxTransfer( peDxDirectDraw->HwDeviceExtension, &ddTransferIn, &ddTransferOut); } } else { ddRVal = DDERR_INVALIDPARAMS; }
lpBuffInfo->ddRVal = ddRVal; if( ddRVal != DD_OK ) { // Set the KEvent now
KeSetEvent( lpBuff->pBuffKEvent, 0, 0 ); lpBuff->flFlags = 0; lpBuff->pBuffKEvent = 0; } else { // Mark the lucky surface as doing a transfer
lpBuffInfo->bPolarity = ddTransferOut.dwBufferPolarity; lpBuff->peDxSurface = (EDD_DXSURFACE*) ddTransferIn.lpSurfaceData; lpBuff->peDxSurface->flFlags |= DD_DXSURFACE_FLAG_TRANSFER; lpBuff->flFlags |= DD_DXCAPTUREBUFF_FLAG_WAITING; }
// Next time use the next buffer
if( ++( peDxCapture->dwBottom ) >= DXCAPTURE_MAX_CAPTURE_BUFFS ) { peDxCapture->dwBottom = 0; } } } peDxCapture = peDxCapture->peDxCaptureNext; }
if( bStarved ) { peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_CAPTURING; } }
/******************************Public*Routine******************************\
* VOID DxAutoflipDpc * * This routine handles 'software autoflipping' and is called at dispatch * level when the miniport's videoport interrupt is triggered. This routine * can't be kept in 'win32k.sys' because it needs to be non-pageable. * * NOTE: The spinlock is already held. * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxAutoflipDpc( DWORD dwEvent, PVOID pContext, DWORD dwParam1, DWORD dwParam2 ) { EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXVIDEOPORT* peDxVideoPort; DWORD dwCurrentField; BOOL bAdjustFirstWeave; BOOL bSkipped; BOOL bFlipped;
ASSERTDX(KeGetCurrentIrql() == DISPATCH_LEVEL, "Expected dispath level"); ASSERTDX(dwEvent == DDEVENT_VP_VSYNC, "Expected VP_VSYNC event");
peDxVideoPort = (EDD_DXVIDEOPORT*) pContext; peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
// If capturing, do it now
if( ( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_CAPTURING ) && ( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_ON ) ) { IRQCapture(peDxVideoPort, peDxDirectDraw); }
// Do we need to notify user mode that a vsync occurred?
if ((peDxVideoPort->pNotifyEvent != NULL) && (peDxVideoPort->pNotifyBuffer != NULL) && (1 == InterlockedExchange( &peDxVideoPort->pNotifyBuffer->lDone, 0 ) ) ) { DDGETCURRENTAUTOFLIPININFO ddAutoflipInInfo; DDGETCURRENTAUTOFLIPOUTINFO ddAutoflipOutInfo;
ULONGLONG ullTimeStamp; ULONGLONG rate; UINT dwVideoIndex;
// Fill in the buffer
peDxVideoPort->pNotifyBuffer->lField = -1; if ( peDxDirectDraw->DxApiInterface.DxGetPolarity ) { DDGETPOLARITYININFO ddPolarityInInfo; DDGETPOLARITYOUTINFO ddPolarityOutInfo; ddPolarityInInfo.lpVideoPortData = peDxVideoPort; peDxDirectDraw->DxApiInterface.DxGetPolarity( peDxDirectDraw->HwDeviceExtension, &ddPolarityInInfo, &ddPolarityOutInfo ); peDxVideoPort->pNotifyBuffer->lField = ddPolarityOutInfo.bPolarity ? 1 : 0; }
dwVideoIndex = 0; if (peDxVideoPort->cAutoflipVideo > 1 ) { if (peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP) { dwVideoIndex = peDxVideoPort->iCurrentVideo; } else { ddAutoflipInInfo.lpVideoPortData = peDxVideoPort; ddAutoflipOutInfo.dwSurfaceIndex = 0; if (peDxDirectDraw->DxApiInterface.DxGetCurrentAutoflip) { peDxDirectDraw->DxApiInterface.DxGetCurrentAutoflip( peDxDirectDraw->HwDeviceExtension, &ddAutoflipInInfo, &ddAutoflipOutInfo); } dwVideoIndex = ddAutoflipOutInfo.dwSurfaceIndex; } if( dwVideoIndex-- == 0 ) { dwVideoIndex = peDxVideoPort->cAutoflipVideo - 1; } } peDxVideoPort->pNotifyBuffer->dwSurfaceIndex = dwVideoIndex;
ullTimeStamp = (ULONGLONG)KeQueryPerformanceCounter((PLARGE_INTEGER)&rate).QuadPart; ullTimeStamp = (ullTimeStamp & 0xFFFFFFFF00000000) / rate * 10000000 + (ullTimeStamp & 0xFFFFFFFF) * 10000000 / rate; *((ULONGLONG*)&(peDxVideoPort->pNotifyBuffer->ApproximateTimeStamp)) = ullTimeStamp;
KeSetEvent (peDxVideoPort->pNotifyEvent, IO_NO_INCREMENT, FALSE); }
// Note that it is okay to modify 'dwCurrentField' outside of a spinlock,
// as the only other routine that modifies it is 'DxSetFieldNumber' and
// it always does an atomic write.
dwCurrentField = InterlockedIncrement((LONG*) &peDxVideoPort->dwCurrentField);
// Check for posted state changes
bAdjustFirstWeave = FALSE; if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_NEW_STATE ) { if( peDxVideoPort->dwSetStateField-- == 0 ) { peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_NEW_STATE;
// If we'll be weaving, we need to make sure that
// we only flip at the beginning of a frame and not
// during the middle. We assume that we're told to
// star weaving at the beginning of the frame.
if( ( peDxVideoPort->dwSetStateState & DDSTATE_WEAVE ) && !( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_FLIP_NEXT ) ) { bAdjustFirstWeave = TRUE; peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_FLIP_NEXT; } EffectStateChange( peDxVideoPort, NULL, peDxVideoPort->dwSetStateState ); } }
// Check the skip logic
bSkipped = FALSE; if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_SKIP_SET ) { if( peDxVideoPort->dwFieldToSkip-- == 0 ) { // Tell the MiniPort to skip the next field
vDxSkip( peDxVideoPort, DDSKIP_SKIPNEXT ); peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_SKIPPED_LAST; bSkipped = TRUE;
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_NEXT_SKIP_SET ) { peDxVideoPort->dwFieldToSkip = peDxVideoPort->dwNextFieldToSkip; peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_NEXT_SKIP_SET; } else { peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_SKIP_SET; } } else if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_NEXT_SKIP_SET ) { peDxVideoPort->dwNextFieldToSkip--; } } if( ( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_SKIPPED_LAST ) && !bSkipped ) { // Tell the MiniPort to un-skip the next field
vDxSkip( peDxVideoPort, DDSKIP_ENABLENEXT ); peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_SKIPPED_LAST;
// This next part is a hack.We keep track of which fields
// to flip on in weave mode during the ISR, but what if we
// happen to miss an IRQ (due to DOS box, etc.)? We can't
// use to polarity to re-sync because field skipping screws
// that up, so this code assume that the repeat field will
// always be the last field of a frame and so the following
// field will be the first field. This will make it re-sync
// if we ever miss an IRQ.
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_FLIP_NEXT; }
// Now do all of the autoflipping
if( peDxVideoPort->flFlags & (DD_DXVIDEOPORT_FLAG_AUTOFLIP| DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI|DD_DXVIDEOPORT_FLAG_BOB ) ) { // Check for autoflipping the VBI surface in which case we
// don't care about the skip logic
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI ) { if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_VBI_INTERLEAVED ) { if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_FLIP_NEXT_VBI ) { peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_FLIP_NEXT_VBI; vDxFlip( peDxVideoPort, DDVPFLIP_VBI ); } else { peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_FLIP_NEXT_VBI; } } else { peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_FLIP_NEXT_VBI; vDxFlip( peDxVideoPort, DDVPFLIP_VBI ); } }
// Autoflip the vhe video if we are not skipping this field
if( !bSkipped ) { bFlipped = FALSE; if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP ) { if( peDxVideoPort->dwVPFlags & DDVP_INTERLEAVE ) { if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_FLIP_NEXT ) { peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_FLIP_NEXT; if( !bAdjustFirstWeave ) { vDxFlip( peDxVideoPort, DDVPFLIP_VIDEO ); bFlipped = TRUE; } } else { peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_FLIP_NEXT; } } else { vDxFlip( peDxVideoPort, DDVPFLIP_VIDEO ); bFlipped = TRUE; peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_FLIP_NEXT; } }
// They may be bobbing even when not autoflipping
// (they may have one interleaved buffer that they
// use for bob - technically this is not a flip since
// only one surface is involved).
if( ( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_BOB ) && !bFlipped ) { vDxBob( peDxVideoPort ); } } } }
/******************************Public*Routine******************************\
* VOID DxBusmasterDpc * * This routine handles the video capture and is called when one of * the buffers is filled. It figures out which one and then sets the * compeletion event for that buffer. * * NOTE: The spinlock is already held. * * 10-Jan-1998 -by- Scott MacDonald [smac] * Wrote it. \**************************************************************************/
VOID APIENTRY DxBusmasterDpc( DWORD dwEvent, PVOID pContext, DWORD dwParam1, DWORD dwParam2 ) { DDGETTRANSFERSTATUSOUTINFO ddGetTransferStatus; EDD_DXVIDEOPORT* peDxVideoPort; EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXCAPTURE* peDxCapture; DWORD ddRVal; ULONG_PTR dwTempId; DWORD dwTempIndex;
// Call the miniport to get the transfer ID of the completed busmaster
ddRVal = DDERR_UNSUPPORTED; peDxVideoPort = (EDD_DXVIDEOPORT*) pContext; peDxDirectDraw = peDxVideoPort->peDxDirectDraw; if (peDxDirectDraw->DxApiInterface.DxGetTransferStatus) { ddRVal = peDxDirectDraw->DxApiInterface.DxGetTransferStatus( peDxDirectDraw->HwDeviceExtension, NULL, &ddGetTransferStatus); } if( ddRVal == DD_OK ) { // Find the capture object. It may not even be associated with this
// video port if multiple vidoe ports exist in the system.
dwTempId = ddGetTransferStatus.dwTransferID & ~0xf; peDxCapture = peDxVideoPort->peDxCapture; while (peDxCapture && (((ULONG_PTR)peDxCapture & ~0xf) != dwTempId)) { peDxCapture = peDxCapture->peDxCaptureNext; }
if (peDxCapture != NULL) { // We've found the capture object
dwTempIndex = (DWORD)(ddGetTransferStatus.dwTransferID & 0xf); if (peDxCapture->CaptureQueue[dwTempIndex].flFlags & DD_DXCAPTUREBUFF_FLAG_WAITING ) { peDxCapture->CaptureQueue[dwTempIndex].flFlags = 0; KeSetEvent(peDxCapture->CaptureQueue[dwTempIndex].pBuffKEvent, 0, 0); }
// Mark the lucky surface as being done w/ the transfer
peDxCapture->CaptureQueue[dwTempIndex].peDxSurface->flFlags &= ~DD_DXSURFACE_FLAG_TRANSFER; peDxCapture->CaptureQueue[dwTempIndex].peDxSurface = NULL; } } }
/******************************Public*Routine******************************\
* VOID DxAutoflipUpdate * * This routine handles 'software autoflipping' and is called at dispatch * level when the miniport's videoport interrupt is triggered. This routine * can't be kept in 'win32k.sys' because it needs to be non-pageable. * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxAutoflipUpdate( EDD_DXVIDEOPORT* peDxVideoPort, EDD_DXSURFACE** apeDxSurfaceVideo, ULONG cSurfacesVideo, EDD_DXSURFACE** apeDxSurfaceVbi, ULONG cSurfacesVbi ) { KIRQL OldIrql; ULONG i;
KeAcquireSpinLock(&peDxVideoPort->peDxDirectDraw->SpinLock, &OldIrql);
peDxVideoPort->cAutoflipVideo = cSurfacesVideo; for (i = 0; i < cSurfacesVideo; i++) { peDxVideoPort->apeDxSurfaceVideo[i] = apeDxSurfaceVideo[i]; peDxVideoPort->apeDxSurfaceVideo[i]->peDxVideoPort = peDxVideoPort; } peDxVideoPort->cAutoflipVbi = cSurfacesVbi; for (i = 0; i < cSurfacesVbi; i++) { peDxVideoPort->apeDxSurfaceVbi[i] = apeDxSurfaceVbi[i]; peDxVideoPort->apeDxSurfaceVbi[i]->peDxVideoPort = peDxVideoPort; }
KeReleaseSpinLock(&peDxVideoPort->peDxDirectDraw->SpinLock, OldIrql); }
/******************************Public*Routine******************************\
* VOID DxLoseObject * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxLoseObject( VOID* pvObject, LOTYPE loType ) { KIRQL OldIrql; EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DXVIDEOPORT* peDxVideoPort; EDD_DXSURFACE* peDxSurface; EDD_DXCAPTURE* peDxCapture; DXAPI_EVENT* pDxEvent; DDENABLEIRQINFO EnableIrqInfo; DWORD dwRet;
switch (loType) { case LO_DIRECTDRAW: peDxDirectDraw = (EDD_DXDIRECTDRAW*) pvObject;
peDxDirectDraw->peDirectDrawGlobal->peDxDirectDraw = NULL; // Passive
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
peDxDirectDraw->bLost = TRUE; peDxDirectDraw->peDirectDrawGlobal = NULL;
if (peDxDirectDraw->DxApiInterface.DxEnableIrq) { // Make sure all IRQs are disabled
EnableIrqInfo.dwIRQSources = 0; EnableIrqInfo.dwLine = 0; EnableIrqInfo.IRQCallback = NULL; EnableIrqInfo.lpIRQData = NULL;
peDxDirectDraw->DxApiInterface.DxEnableIrq( peDxDirectDraw->HwDeviceExtension, &EnableIrqInfo, NULL); }
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql); break;
case LO_VIDEOPORT: peDxVideoPort = (EDD_DXVIDEOPORT*) pvObject; peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
peDxVideoPort->peVideoPort->peDxVideoPort = NULL; // Passive
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
peDxVideoPort->bLost = TRUE; peDxVideoPort->peVideoPort = NULL; peDxVideoPort->peDxCapture = NULL;
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql); break;
case LO_SURFACE: peDxSurface = (EDD_DXSURFACE*) pvObject; peDxDirectDraw = peDxSurface->peDxDirectDraw;
peDxSurface->peSurface->peDxSurface = NULL; // Passive
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
peDxSurface->bLost = TRUE; peDxSurface->peSurface = NULL; peDxSurface->peDxVideoPort = NULL;
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql); break;
case LO_CAPTURE: peDxCapture = (EDD_DXCAPTURE*) pvObject; peDxVideoPort = peDxCapture->peDxVideoPort; if( peDxVideoPort != NULL ) { peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
// First flush the capture buffers
DxInternalFlushVpCaptureBuffs( peDxDirectDraw, peDxVideoPort, peDxCapture );
// Disassociate the capture object from the video port
peDxCapture->peDxVideoPort = NULL; peDxCapture->bLost = TRUE; if( peDxVideoPort->peDxCapture == peDxCapture ) { peDxVideoPort->peDxCapture = peDxCapture->peDxCaptureNext; } else { EDD_DXCAPTURE* peDxTemp;
for( peDxTemp = peDxVideoPort->peDxCapture; ( peDxTemp != NULL ) && ( peDxTemp->peDxCaptureNext != peDxCapture ); peDxTemp = peDxTemp->peDxCaptureNext ); if( peDxTemp != NULL ) { peDxTemp->peDxCaptureNext = peDxCapture->peDxCaptureNext; } else { RIPDX("Capture object not in video port list"); } }
// If there are no more capture objects associated with the
// video port, remove the video port from the capture list.
pDxEvent = NULL; if( peDxVideoPort->peDxCapture == NULL ) { if( peDxDirectDraw->pDxEvent_CaptureList->peDxVideoPort == peDxVideoPort ) { pDxEvent = peDxDirectDraw->pDxEvent_CaptureList; peDxDirectDraw->pDxEvent_CaptureList = pDxEvent->pDxEvent_Next; } else { for( pDxEvent = peDxDirectDraw->pDxEvent_CaptureList; (pDxEvent != NULL) && (pDxEvent->pDxEvent_Next->peDxVideoPort != peDxVideoPort); pDxEvent = pDxEvent->pDxEvent_Next ); if( pDxEvent != NULL ) { pDxEvent->pDxEvent_Next = pDxEvent->pDxEvent_Next->pDxEvent_Next; pDxEvent = pDxEvent->pDxEvent_Next; } } }
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
if( pDxEvent != NULL ) { ExFreePool(pDxEvent); } } break;
default: RIPDX("Unexpected type"); } }
/******************************Public*Routine******************************\
* VOID DxUpdateCapture * * This routine inserts capture devices intot he list handling off of the * video port. Since this list is walked at DPC level, we need to * synchronize this with the DPC. * * 10-Jan-1997 -by- Scott MacDonald [smac] * Wrote it. \**************************************************************************/
VOID APIENTRY DxUpdateCapture( EDD_DXVIDEOPORT* peDxVideoPort, EDD_DXCAPTURE* peDxCapture, BOOL bRemove ) { KIRQL OldIrql; EDD_DXCAPTURE* peDxTemp; EDD_DXDIRECTDRAW* peDxDirectDraw; DXAPI_EVENT* pDxEvent_New; DXAPI_EVENT* pDxEvent_Temp = NULL; DWORD dwRet;
// If adding to the list, also an event to the capture list so we
// can get the busmaster complete notification. Allocate the
// memory for this now.
peDxDirectDraw = peDxVideoPort->peDxDirectDraw; if( !bRemove ) { pDxEvent_New = (DXAPI_EVENT*) ExAllocatePoolWithTag(NonPagedPool, sizeof(*pDxEvent_New), 'eddG'); if (pDxEvent_New == NULL) return;
RtlZeroMemory(pDxEvent_New, sizeof(*pDxEvent_New)); pDxEvent_New->peDxDirectDraw = peDxDirectDraw; pDxEvent_New->peDxVideoPort = peDxVideoPort; pDxEvent_New->pfnCallBack = (LPDD_NOTIFYCALLBACK) DxBusmasterDpc; pDxEvent_New->pContext = peDxVideoPort; }
KeAcquireSpinLock(&peDxVideoPort->peDxDirectDraw->SpinLock, &OldIrql);
if( bRemove ) { // First flush the capture buffers
DxInternalFlushVpCaptureBuffs( peDxDirectDraw, peDxVideoPort, peDxCapture );
// Disassociate the capture object with the video port
if( peDxVideoPort->peDxCapture == peDxCapture ) { peDxVideoPort->peDxCapture = peDxCapture->peDxCaptureNext; } else { for( peDxTemp = peDxVideoPort->peDxCapture; ( peDxTemp != NULL ) && ( peDxTemp->peDxCaptureNext != peDxCapture ); peDxTemp = peDxTemp->peDxCaptureNext ); if( peDxTemp != NULL ) { peDxTemp->peDxCaptureNext = peDxCapture->peDxCaptureNext; } } peDxCapture->peDxVideoPort = NULL;
// If there are no more capture objects associated with the
// video port, remove the video port from the capture list.
if( peDxVideoPort->peDxCapture == NULL ) { pDxEvent_Temp = NULL; if( peDxDirectDraw->pDxEvent_CaptureList->peDxVideoPort == peDxVideoPort ) { pDxEvent_Temp = peDxDirectDraw->pDxEvent_CaptureList; peDxDirectDraw->pDxEvent_CaptureList = pDxEvent_Temp->pDxEvent_Next; } else { for( pDxEvent_Temp = peDxDirectDraw->pDxEvent_CaptureList; (pDxEvent_Temp != NULL) && (pDxEvent_Temp->pDxEvent_Next->peDxVideoPort != NULL); pDxEvent_Temp = pDxEvent_Temp->pDxEvent_Next ); if( pDxEvent_Temp != NULL ) { pDxEvent_Temp->pDxEvent_Next = pDxEvent_Temp->pDxEvent_Next->pDxEvent_Next; pDxEvent_Temp = pDxEvent_Temp->pDxEvent_Next; } } } } else { // Associate the capture object with the video port
peDxCapture->peDxCaptureNext = peDxVideoPort->peDxCapture; peDxVideoPort->peDxCapture = peDxCapture;
// Add an event to the capture list so we can get the busmaster
// complete notification. First check to see if it's already in
// in the list.
for (pDxEvent_Temp = peDxDirectDraw->pDxEvent_CaptureList; pDxEvent_Temp != NULL; pDxEvent_Temp = pDxEvent_Temp->pDxEvent_Next) { if (pDxEvent_Temp->peDxVideoPort == peDxVideoPort) { break; } } if( pDxEvent_Temp == NULL ) { // Not already in list - add it
pDxEvent_New->pDxEvent_Next = peDxDirectDraw->pDxEvent_CaptureList; peDxDirectDraw->pDxEvent_CaptureList = pDxEvent_New; } }
KeReleaseSpinLock(&peDxVideoPort->peDxDirectDraw->SpinLock, OldIrql);
if( bRemove && ( pDxEvent_Temp != NULL ) ) { ExFreePool(pDxEvent_Temp); } else if( pDxEvent_Temp != NULL ) { ExFreePool(pDxEvent_New); } }
/******************************Public*Routine******************************\
* DWORD DxOpenDirectDraw * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxOpenDirectDraw( DDOPENDIRECTDRAWIN* pOpenDirectDrawIn, DDOPENDIRECTDRAWOUT* pOpenDirectDrawOut ) { pOpenDirectDrawOut->ddRVal = DDERR_UNSUPPORTED; if (pOpenDirectDrawIn != NULL) { if (gpfnOpenDirectDraw != NULL) { gpfnOpenDirectDraw(pOpenDirectDrawIn, pOpenDirectDrawOut, DxEventDpc, DXAPI_PRIVATE_VERSION_NUMBER); } } }
/******************************Public*Routine******************************\
* VOID DxEnableIRQ * * This routine enables/disables the video port VSYNC IRQ and is * is called at dispatch level. * * 17-Oct-1997 -by- smac * Wrote it. \**************************************************************************/
VOID APIENTRY DxEnableIRQ( EDD_DXVIDEOPORT* peDxVideoPort, BOOL bEnable ) { EDD_DXDIRECTDRAW* peDxDirectDraw; EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal; DWORD dwBit;
peDxDirectDraw = peDxVideoPort->peDxDirectDraw; peDirectDrawGlobal = peDxDirectDraw->peDirectDrawGlobal; dwBit = DDIRQ_VPORT0_VSYNC << ( peDxVideoPort->dwVideoPortID * 2);
/*
* Don't enable or disable of the IRQ isn't supported */ if( ( peDirectDrawGlobal != NULL ) && ( peDirectDrawGlobal->DDKernelCaps.dwIRQCaps & dwBit ) ) { if( bEnable ) { if( !( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_REGISTERED_IRQ ) ) { bDxModifyDispatchEventList(peDxDirectDraw, peDxVideoPort, bEnable, DDEVENT_VP_VSYNC, dwBit, (LPDD_NOTIFYCALLBACK) DxAutoflipDpc, (PVOID)peDxVideoPort, INTERNAL_DISPATCH_LIST); peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_REGISTERED_IRQ; } } else { if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_REGISTERED_IRQ ) { bDxModifyDispatchEventList(peDxDirectDraw, peDxVideoPort, bEnable, DDEVENT_VP_VSYNC, dwBit, (LPDD_NOTIFYCALLBACK) DxAutoflipDpc, (PVOID)peDxVideoPort, INTERNAL_DISPATCH_LIST); peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_REGISTERED_IRQ; } } vDxEnableInterrupts( peDxDirectDraw, 0 ); } }
/******************************Public*Routine******************************\
* DxApi * * Single entry point for all DXAPI.SYS public functionality. * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
typedef VOID (APIENTRY* PDX_FUNCTION)(VOID*, VOID*);
typedef struct _DXAPI_ENTRY_POINT { PDX_FUNCTION pfn; DWORD cInBuffer; DWORD cOutBuffer; BOOLEAN bMapProcess; } DXAPI_ENTRY_POINT;
#define DX(fn, structin, structout, boolean) \
(PDX_FUNCTION) fn, structin, sizeof(structout), boolean
DXAPI_ENTRY_POINT gDxApiEntryPoint[] = { DX(DxGetVersionNumber, 0, DDGETVERSIONNUMBER, FALSE ), // 0
DX(NULL, sizeof(DDCLOSEHANDLE), DWORD, TRUE ), // 1
DX(DxOpenDirectDraw, sizeof(DDOPENDIRECTDRAWIN), DDOPENDIRECTDRAWOUT, FALSE ), // 2
DX(NULL, sizeof(DDOPENSURFACEIN), DDOPENSURFACEOUT, TRUE ), // 3
DX(NULL, sizeof(DDOPENVIDEOPORTIN), DDOPENVIDEOPORTOUT, TRUE ), // 4
DX(NULL, sizeof(DWORD), DDGETKERNELCAPSOUT, TRUE ), // 5
DX(DxGetFieldNumber, sizeof(DDGETFIELDNUMIN), DDGETFIELDNUMOUT, FALSE ), // 6
DX(DxSetFieldNumber, sizeof(DDSETFIELDNUM), DWORD, FALSE ), // 7
DX(DxSetSkipPattern, sizeof(DDSETSKIPFIELD), DWORD, FALSE ), // 8
DX(DxGetSurfaceState, sizeof(DDGETSURFACESTATEIN), DDGETSURFACESTATEOUT, FALSE ), // 9
DX(DxSetSurfaceState, sizeof(DDSETSURFACESTATE), DWORD, FALSE ), // 10
DX(DxLock, sizeof(DDLOCKIN), DDLOCKOUT, FALSE ), // 11
DX(DxFlipOverlay, sizeof(DDFLIPOVERLAY), DWORD, FALSE ), // 12
DX(DxFlipVideoPort, sizeof(DDFLIPVIDEOPORT), DWORD, FALSE ), // 13
DX(DxGetCurrentAutoflip, sizeof(DDGETAUTOFLIPIN), DDGETAUTOFLIPOUT, FALSE ), // 14
DX(DxGetPreviousAutoflip, sizeof(DDGETAUTOFLIPIN), DDGETAUTOFLIPOUT, FALSE ), // 15
DX(DxRegisterEvent, sizeof(DDREGISTERCALLBACK), DWORD, FALSE ), // 16
DX(DxUnregisterEvent, sizeof(DDREGISTERCALLBACK), DWORD, FALSE ), // 17
DX(DxGetPolarity, sizeof(DDGETPOLARITYIN), DDGETPOLARITYOUT, FALSE ), // 18
DX(NULL, sizeof(DDOPENVPCAPTUREDEVICEIN),DDOPENVPCAPTUREDEVICEOUT, TRUE ), // 19
DX(DxAddVpCaptureBuffer, sizeof(DDADDVPCAPTUREBUFF), DWORD, FALSE ), // 20
DX(DxFlushVpCaptureBuffs, sizeof(DWORD), DWORD, FALSE ), // 21
};
DWORD APIENTRY DxApi( DWORD iFunction, VOID* pInBuffer, DWORD cInBuffer, VOID* pOutBuffer, DWORD cOutBuffer ) { DWORD dwRet; BOOL bProcessAttached = FALSE;
dwRet = 0;
iFunction -= DD_FIRST_DXAPI;
if ((iFunction >= sizeof(gDxApiEntryPoint) / sizeof(DXAPI_ENTRY_POINT)) || (gDxApiEntryPoint[iFunction].pfn == NULL)) { KdPrint(("DxApi: Invalid function\n")); } else if ((cInBuffer < gDxApiEntryPoint[iFunction].cInBuffer) || (cOutBuffer < gDxApiEntryPoint[iFunction].cOutBuffer)) { KdPrint(("DxApi: Input or output buffer too small\n")); } else if (pOutBuffer == NULL) { KdPrint(("DxApi: Invalid output buffer specified\n")); } else { if (gDxApiEntryPoint[iFunction].bMapProcess) { PEPROCESS pepSession;
switch (iFunction) { case (DD_DXAPI_CLOSEHANDLE - DD_FIRST_DXAPI): case (DD_DXAPI_OPENSURFACE - DD_FIRST_DXAPI): case (DD_DXAPI_OPENVIDEOPORT - DD_FIRST_DXAPI): case (DD_DXAPI_OPENVPCAPTUREDEVICE - DD_FIRST_DXAPI):
// pInBuffer is a pointer to a structure that has
// a pointer to DXOBJ as its first element.
pepSession = ((DXOBJ *)(*(HANDLE *)pInBuffer))->pepSession; break;
case (DD_DXAPI_GETKERNELCAPS - DD_FIRST_DXAPI):
// pInBuffer is a pointer to DXOBJ.
pepSession = ((DXOBJ *)pInBuffer)->pepSession; break;
default: return (dwRet); }
if (!KeIsAttachedProcess()) { KeAttachProcess(PsGetProcessPcb(pepSession)); bProcessAttached = TRUE; } }
// The return value is the size of the output buffer:
dwRet = gDxApiEntryPoint[iFunction].cOutBuffer;
// Call the actual routine:
gDxApiEntryPoint[iFunction].pfn(pInBuffer, pOutBuffer);
if (bProcessAttached) { KeDetachProcess(); } }
return(dwRet); }
/******************************Public*Routine******************************\
* VOID DxApiInitialize * * Called by win32k.sys to initialize dxapi.sys state. * * 14-Apr-1997 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY DxApiInitialize( PFNDXAPIOPENDIRECTDRAW pfnOpenDirectDraw, PFNDXAPIOPENVIDEOPORT pfnOpenVideoPort, PFNDXAPIOPENSURFACE pfnOpenSurface, PFNDXAPICLOSEHANDLE pfnCloseHandle, PFNDXAPIGETKERNELCAPS pfnGetKernelCaps, PFNDXAPIOPENCAPTUREDEVICE pfnOpenCaptureDevice, PFNDXAPILOCKDEVICE pfnLockDevice, PFNDXAPIUNLOCKDEVICE pfnUnlockDevice ) { gpfnOpenDirectDraw = pfnOpenDirectDraw; gpfnLockDevice = pfnLockDevice; gpfnUnlockDevice = pfnUnlockDevice;
gDxApiEntryPoint[DD_DXAPI_OPENVIDEOPORT - DD_FIRST_DXAPI].pfn = (PDX_FUNCTION) pfnOpenVideoPort;
gDxApiEntryPoint[DD_DXAPI_OPENSURFACE - DD_FIRST_DXAPI].pfn = (PDX_FUNCTION) pfnOpenSurface;
gDxApiEntryPoint[DD_DXAPI_CLOSEHANDLE - DD_FIRST_DXAPI].pfn = (PDX_FUNCTION) pfnCloseHandle;
gDxApiEntryPoint[DD_DXAPI_GETKERNELCAPS - DD_FIRST_DXAPI].pfn = (PDX_FUNCTION) pfnGetKernelCaps;
gDxApiEntryPoint[DD_DXAPI_OPENVPCAPTUREDEVICE - DD_FIRST_DXAPI].pfn = (PDX_FUNCTION) pfnOpenCaptureDevice; }
/******************************Public*Routine******************************\
* ULONG DxApiGetVersion * * The original Memphis DXAPI had this entry point and although it doesn't * do anything usefull, some drivers called it so we have to support it * for those drivers to load. It does not return a real version number * because the original incorrectly returned the DSOUND version 4.02, * which has no correlation to the DxApi version number. If we return the * real version, however, we risk breaking drivers. * * 16-Apr-1998 -by- Scott MacDonald [smac] * Wrote it. \**************************************************************************/
ULONG APIENTRY DxApiGetVersion( VOID ) { return( 0x402 ); }
|