windows-nt/Source/XPSP1/NT/drivers/wdm/capture/mini/testcap/ddraw.c
2020-09-26 16:20:57 +08:00

663 lines
20 KiB
C

//==========================================================================;
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved.
//
//==========================================================================;
#include "strmini.h"
#include "ksmedia.h"
#include "ddkmapi.h"
#include "capmain.h"
#include "capdebug.h"
#define _NO_COM
#include "ddkernel.h"
#define DD_OK 0
// The following should be defined in ddkmapi.h, but for some reason are not!
#ifndef booboo // DDKERNELCAPS_SKIPFIELDS
/*
* Indicates that the device supports field skipping.
*/
#define DDKERNELCAPS_SKIPFIELDS 0x00000001l
/*
* Indicates that the device can support software autoflipping.
*/
#define DDKERNELCAPS_AUTOFLIP 0x00000002l
/*
* Indicates that the device can switch between bob and weave.
*/
#define DDKERNELCAPS_SETSTATE 0x00000004l
/*
* Indicates that a client can gain direct access to the frame buffer.
*/
#define DDKERNELCAPS_LOCK 0x00000008l
/*
* Indicates that a client can manually flip the video port.
*/
#define DDKERNELCAPS_FLIPVIDEOPORT 0x00000010l
/*
* Indicates that a client can manually flip the overlay.
*/
#define DDKERNELCAPS_FLIPOVERLAY 0x00000020l
/*
* Indicates that the device supports a fast, asynchronous transfer
* mechanism to system memory.
*/
#define DDKERNELCAPS_TRANSFER_SYSMEM 0x00000040l
/*
* Indicates that the device supports a fast, asynchronous transfer
* mechanism via AGP.
*/
#define DDKERNELCAPS_TRANSFER_AGP 0x00000080l
/*
* Indicates that the device can report the polarity (even/odd) of
* the curent video field.
*/
#define DDKERNELCAPS_FIELDPOLARITY 0x00000100l
/****************************************************************************
*
* DDKERNELCAPS IRQ CAPS
*
****************************************************************************/
/*
* The device can generate display VSYNC IRQs
*/
#define DDIRQ_DISPLAY_VSYNC 0x00000001l
/*
* Reserved
*/
#define DDIRQ_RESERVED1 0x00000002l
/*
* The device can generate video ports VSYNC IRQs using video port 0
*/
#define DDIRQ_VPORT0_VSYNC 0x00000004l
/*
* The device can generate video ports line IRQs using video port 0
*/
#define DDIRQ_VPORT0_LINE 0x00000008l
/*
* The device can generate video ports VSYNC IRQs using video port 1
*/
#define DDIRQ_VPORT1_VSYNC 0x00000010l
/*
* The device can generate video ports line IRQs using video port 1
*/
#define DDIRQ_VPORT1_LINE 0x00000020l
/*
* The device can generate video ports VSYNC IRQs using video port 2
*/
#define DDIRQ_VPORT2_VSYNC 0x00000040l
/*
* The device can generate video ports line IRQs using video port 2
*/
#define DDIRQ_VPORT2_LINE 0x00000080l
/*
* The device can generate video ports VSYNC IRQs using video port 3
*/
#define DDIRQ_VPORT3_VSYNC 0x00000100l
/*
* The device can generate video ports line IRQs using video port 3
*/
#define DDIRQ_VPORT3_LINE 0x00000200l
/*
* The device can generate video ports VSYNC IRQs using video port 4
*/
#define DDIRQ_VPORT4_VSYNC 0x00000400l
/*
* The device can generate video ports line IRQs using video port 4
*/
#define DDIRQ_VPORT4_LINE 0x00000800l
/*
* The device can generate video ports VSYNC IRQs using video port 5
*/
#define DDIRQ_VPORT5_VSYNC 0x00001000l
/*
* The device can generate video ports line IRQs using video port 5
*/
#define DDIRQ_VPORT5_LINE 0x00002000l
/*
* The device can generate video ports VSYNC IRQs using video port 6
*/
#define DDIRQ_VPORT6_VSYNC 0x00004000l
/*
* The device can generate video ports line IRQs using video port 6
*/
#define DDIRQ_VPORT6_LINE 0x00008000l
/*
* The device can generate video ports VSYNC IRQs using video port 7
*/
#define DDIRQ_VPORT7_VSYNC 0x00010000l
/*
* The device can generate video ports line IRQs using video port 7
*/
#define DDIRQ_VPORT7_LINE 0x00020000l
/*
* The device can generate video ports VSYNC IRQs using video port 8
*/
#define DDIRQ_VPORT8_VSYNC 0x00040000l
/*
* The device can generate video ports line IRQs using video port 8
*/
#define DDIRQ_VPORT8_LINE 0x00080000l
/*
* The device can generate video ports VSYNC IRQs using video port 9
*/
#define DDIRQ_VPORT9_VSYNC 0x00010000l
/*
* The device can generate video ports line IRQs using video port 9
*/
#define DDIRQ_VPORT9_LINE 0x00020000l
#endif
DWORD FAR PASCAL
DirectDrawEventCallback (
DWORD dwEvent, PVOID pContext, DWORD dwParam1, DWORD dwParam2
)
{
switch (dwEvent)
{
case DDNOTIFY_PRERESCHANGE:
{
PSTREAMEX pStrmEx = (PSTREAMEX)pContext;
PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt;
int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
DbgLogInfo(("Testcap: DDNOTIFY_PRERESCHANGE; stream = %d\n", StreamNumber));
pStrmEx->PreEventOccurred = TRUE;
}
break;
case DDNOTIFY_POSTRESCHANGE:
{
PSTREAMEX pStrmEx = (PSTREAMEX)pContext;
PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt;
int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
DbgLogInfo(("Testcap: DDNOTIFY_POSTRESCHANGE; stream = %d\n", StreamNumber));
pStrmEx->PostEventOccurred = TRUE;
DbgLogInfo(("Testcap: Before Attempted Renegotiation due to DDNOTIFY_POSTRESCHANGE\n"));
// AttemptRenegotiation(pStrmEx);
DbgLogInfo(("Testcap: Afer Attempted Renegotiation due to DDNOTIFY_POSTRESCHANGE\n"));
}
break;
case DDNOTIFY_PREDOSBOX:
{
PSTREAMEX pStrmEx = (PSTREAMEX)pContext;
PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt;
int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
DbgLogInfo(("Testcap: DDNOTIFY_PREDOSBOX; stream = %d\n", StreamNumber));
pStrmEx->PreEventOccurred = TRUE;
}
break;
case DDNOTIFY_POSTDOSBOX:
{
PSTREAMEX pStrmEx = (PSTREAMEX)pContext;
PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt;
int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
DbgLogInfo(("Testcap: DDNOTIFY_POSTDOSBOX; stream = %d\n", StreamNumber));
pStrmEx->PostEventOccurred = TRUE;
DbgLogInfo(("Testcap: Before Attempted Renegotiation due to DDNOTIFY_POSTDOSBOX\n"));
// AttemptRenegotiation(pStrmEx);
DbgLogInfo(("Testcap: After Attempted Renegotiation due to DDNOTIFY_POSTDOSBOX\n"));
}
break;
case DDNOTIFY_CLOSEDIRECTDRAW:
{
PSTREAMEX pStrmEx = (PSTREAMEX)pContext;
PHW_DEVICE_EXTENSION pHwDevExt = (PHW_DEVICE_EXTENSION)pContext;
DbgLogInfo(("Testcap: DDNOTIFY_CLOSEDIRECTDRAW\n"));
pStrmEx->KernelDirectDrawHandle = 0;
pStrmEx->UserDirectDrawHandle = 0;
}
break;
case DDNOTIFY_CLOSESURFACE:
{
PHW_STREAM_REQUEST_BLOCK pSrb = (PHW_STREAM_REQUEST_BLOCK)pContext;
PSRB_EXTENSION pSrbExt = (PSRB_EXTENSION)pSrb->SRBExtension;
DbgLogInfo(("Testcap: DDNOTIFY_CLOSESURFACE\n"));
pSrbExt->KernelSurfaceHandle = 0;
}
break;
default:
TRAP;
break;
}
return 0;
}
BOOL
RegisterForDirectDrawEvents (
PSTREAMEX pStrmEx
)
{
PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt;
int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
DDREGISTERCALLBACK ddRegisterCallback;
DWORD ddOut;
DbgLogInfo(("Testcap: Stream %d registering for DirectDraw events\n", StreamNumber));
// =============== DDEVENT_PRERESCHANGE ===============
RtlZeroMemory(&ddRegisterCallback, sizeof(ddRegisterCallback));
RtlZeroMemory(&ddOut, sizeof(ddOut));
ddRegisterCallback.hDirectDraw = pStrmEx->KernelDirectDrawHandle;
ddRegisterCallback.dwEvents = DDEVENT_PRERESCHANGE;
ddRegisterCallback.pfnCallback = DirectDrawEventCallback;
ddRegisterCallback.pContext = pStrmEx;
DxApi(DD_DXAPI_REGISTER_CALLBACK, &ddRegisterCallback, sizeof(ddRegisterCallback), &ddOut, sizeof(ddOut));
if (ddOut != DD_OK) {
DbgLogInfo(("Testcap: DD_DXAPI_REGISTER_CALLBACK failed.\n"));
TRAP;
return FALSE;
}
// =============== DDEVENT_POSTRESCHANGE ==============
RtlZeroMemory(&ddRegisterCallback, sizeof(ddRegisterCallback));
RtlZeroMemory(&ddOut, sizeof(ddOut));
ddRegisterCallback.hDirectDraw = pStrmEx->KernelDirectDrawHandle;
ddRegisterCallback.dwEvents = DDEVENT_POSTRESCHANGE;
ddRegisterCallback.pfnCallback = DirectDrawEventCallback;
ddRegisterCallback.pContext = pStrmEx;
DxApi(DD_DXAPI_REGISTER_CALLBACK, &ddRegisterCallback, sizeof(ddRegisterCallback), &ddOut, sizeof(ddOut));
if (ddOut != DD_OK) {
DbgLogInfo(("Testcap: DD_DXAPI_REGISTER_CALLBACK failed.\n"));
TRAP;
return FALSE;
}
// =============== DDEVENT_PREDOSBOX =================
RtlZeroMemory(&ddRegisterCallback, sizeof(ddRegisterCallback));
RtlZeroMemory(&ddOut, sizeof(ddOut));
ddRegisterCallback.hDirectDraw = pStrmEx->KernelDirectDrawHandle;
ddRegisterCallback.dwEvents = DDEVENT_PREDOSBOX;
ddRegisterCallback.pfnCallback = DirectDrawEventCallback;
ddRegisterCallback.pContext = pStrmEx;
DxApi(DD_DXAPI_REGISTER_CALLBACK, &ddRegisterCallback, sizeof(ddRegisterCallback), &ddOut, sizeof(ddOut));
if (ddOut != DD_OK) {
DbgLogInfo(("Testcap: DD_DXAPI_REGISTER_CALLBACK failed.\n"));
TRAP;
return FALSE;
}
// =============== DDEVENT_POSTDOSBOX ================
RtlZeroMemory(&ddRegisterCallback, sizeof(ddRegisterCallback));
RtlZeroMemory(&ddOut, sizeof(ddOut));
ddRegisterCallback.hDirectDraw = pStrmEx->KernelDirectDrawHandle;
ddRegisterCallback.dwEvents = DDEVENT_POSTDOSBOX;
ddRegisterCallback.pfnCallback = DirectDrawEventCallback;
ddRegisterCallback.pContext = pStrmEx;
DxApi(DD_DXAPI_REGISTER_CALLBACK, &ddRegisterCallback, sizeof(ddRegisterCallback), &ddOut, sizeof(ddOut));
if (ddOut != DD_OK) {
DbgLogInfo(("Testcap: DD_DXAPI_REGISTER_CALLBACK failed.\n"));
TRAP;
return FALSE;
}
pStrmEx->KernelDirectDrawRegistered = TRUE;
return TRUE;
}
BOOL
UnregisterForDirectDrawEvents (
PSTREAMEX pStrmEx
)
{
PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt;
int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
DDREGISTERCALLBACK ddRegisterCallback;
DWORD ddOut;
DbgLogInfo(("Testcap: Stream %d UNregistering for DirectDraw events\n", StreamNumber));
// =============== DDEVENT_PRERESCHANGE ===============
RtlZeroMemory(&ddRegisterCallback, sizeof(ddRegisterCallback));
RtlZeroMemory(&ddOut, sizeof(ddOut));
ddRegisterCallback.hDirectDraw = pStrmEx->KernelDirectDrawHandle;
ddRegisterCallback.dwEvents = DDEVENT_PRERESCHANGE ;
ddRegisterCallback.pfnCallback = DirectDrawEventCallback;
ddRegisterCallback.pContext = pStrmEx;
DxApi(DD_DXAPI_UNREGISTER_CALLBACK, &ddRegisterCallback, sizeof(ddRegisterCallback), &ddOut, sizeof(ddOut));
if (ddOut != DD_OK) {
DbgLogInfo(("Testcap: DD_DXAPI_UNREGISTER_CALLBACK failed.\n"));
TRAP;
return FALSE;
}
// =============== DDEVENT_POSTRESCHANGE ==============
RtlZeroMemory(&ddRegisterCallback, sizeof(ddRegisterCallback));
RtlZeroMemory(&ddOut, sizeof(ddOut));
ddRegisterCallback.hDirectDraw = pStrmEx->KernelDirectDrawHandle;
ddRegisterCallback.dwEvents = DDEVENT_POSTRESCHANGE;
ddRegisterCallback.pfnCallback = DirectDrawEventCallback;
ddRegisterCallback.pContext = pStrmEx;
DxApi(DD_DXAPI_UNREGISTER_CALLBACK, &ddRegisterCallback, sizeof(ddRegisterCallback), &ddOut, sizeof(ddOut));
if (ddOut != DD_OK) {
DbgLogInfo(("Testcap: DD_DXAPI_UNREGISTER_CALLBACK failed.\n"));
TRAP;
return FALSE;
}
// =============== DDEVENT_PREDOSBOX ==================
RtlZeroMemory(&ddRegisterCallback, sizeof(ddRegisterCallback));
RtlZeroMemory(&ddOut, sizeof(ddOut));
ddRegisterCallback.hDirectDraw = pStrmEx->KernelDirectDrawHandle;
ddRegisterCallback.dwEvents = DDEVENT_PREDOSBOX;
ddRegisterCallback.pfnCallback = DirectDrawEventCallback;
ddRegisterCallback.pContext = pStrmEx;
DxApi(DD_DXAPI_UNREGISTER_CALLBACK, &ddRegisterCallback, sizeof(ddRegisterCallback), &ddOut, sizeof(ddOut));
if (ddOut != DD_OK) {
DbgLogInfo(("Testcap: DD_DXAPI_UNREGISTER_CALLBACK failed.\n"));
TRAP;
return FALSE;
}
// =============== DDEVENT_POSTDOSBOX =================
RtlZeroMemory(&ddRegisterCallback, sizeof(ddRegisterCallback));
RtlZeroMemory(&ddOut, sizeof(ddOut));
ddRegisterCallback.hDirectDraw = pStrmEx->KernelDirectDrawHandle;
ddRegisterCallback.dwEvents = DDEVENT_POSTDOSBOX;
ddRegisterCallback.pfnCallback = DirectDrawEventCallback;
ddRegisterCallback.pContext = pStrmEx;
DxApi(DD_DXAPI_UNREGISTER_CALLBACK, &ddRegisterCallback, sizeof(ddRegisterCallback), &ddOut, sizeof(ddOut));
if (ddOut != DD_OK) {
DbgLogInfo(("Testcap: DD_DXAPI_UNREGISTER_CALLBACK failed.\n"));
TRAP;
return FALSE;
}
pStrmEx->KernelDirectDrawRegistered = FALSE;
return TRUE;
}
BOOL
OpenKernelDirectDraw (
PSTREAMEX pStrmEx
)
{
PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt;
int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
if (pStrmEx->UserDirectDrawHandle != 0) {
DDOPENDIRECTDRAWIN ddOpenIn;
DDOPENDIRECTDRAWOUT ddOpenOut;
ASSERT (pStrmEx->KernelDirectDrawHandle == 0);
DbgLogInfo(("Testcap: Stream %d getting Kernel ddraw handle\n", StreamNumber));
RtlZeroMemory(&ddOpenIn, sizeof(ddOpenIn));
RtlZeroMemory(&ddOpenOut, sizeof(ddOpenOut));
ddOpenIn.dwDirectDrawHandle = (DWORD_PTR) pStrmEx->UserDirectDrawHandle;
ddOpenIn.pfnDirectDrawClose = DirectDrawEventCallback;
ddOpenIn.pContext = pStrmEx;
DxApi(DD_DXAPI_OPENDIRECTDRAW,
&ddOpenIn,
sizeof(ddOpenIn),
&ddOpenOut,
sizeof(ddOpenOut));
if (ddOpenOut.ddRVal != DD_OK) {
DbgLogInfo(("Testcap: DD_DXAPI_OPENDIRECTDRAW failed.\n"));
}
else {
pStrmEx->KernelDirectDrawHandle = ddOpenOut.hDirectDraw;
return TRUE;
}
}
return FALSE;
}
BOOL
CloseKernelDirectDraw (
PSTREAMEX pStrmEx
)
{
PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt;
int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
if (pStrmEx->KernelDirectDrawHandle != 0) {
DWORD ddOut;
DDCLOSEHANDLE ddClose;
DbgLogInfo(("Testcap: Stream %d CloseKernelDirectDraw\n", StreamNumber));
ddClose.hHandle = pStrmEx->KernelDirectDrawHandle;
DxApi(DD_DXAPI_CLOSEHANDLE,
&ddClose,
sizeof(ddClose),
&ddOut,
sizeof(ddOut));
pStrmEx->KernelDirectDrawHandle = 0;
if (ddOut != DD_OK) {
DbgLogInfo(("Testcap: CloseKernelDirectDraw FAILED.\n"));
TRAP;
return FALSE;
}
}
return TRUE;
}
BOOL
IsKernelLockAndFlipAvailable (
PSTREAMEX pStrmEx
)
{
PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt;
int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
if (pStrmEx->KernelDirectDrawHandle != 0) {
DDGETKERNELCAPSOUT ddGetKernelCapsOut;
DbgLogInfo(("Testcap: Stream %d getting Kernel Caps\n", StreamNumber));
RtlZeroMemory(&ddGetKernelCapsOut, sizeof(ddGetKernelCapsOut));
DxApi(DD_DXAPI_GETKERNELCAPS,
&pStrmEx->KernelDirectDrawHandle,
sizeof(pStrmEx->KernelDirectDrawHandle),
&ddGetKernelCapsOut,
sizeof(ddGetKernelCapsOut));
if (ddGetKernelCapsOut.ddRVal != DD_OK) {
DbgLogInfo(("Testcap: DDGETKERNELCAPSOUT failed.\n"));
}
else {
DbgLogInfo(("Testcap: Stream %d KernelCaps = %x\n",
StreamNumber, ddGetKernelCapsOut.dwCaps));
if ((ddGetKernelCapsOut.dwCaps & (DDKERNELCAPS_LOCK | DDKERNELCAPS_FLIPOVERLAY)) ==
(DDKERNELCAPS_LOCK | DDKERNELCAPS_FLIPOVERLAY)) {
// TODO: Check where we may need to set up for kernel flipping
}
return TRUE;
}
}
return FALSE;
}
BOOL
OpenKernelDDrawSurfaceHandle(
IN PHW_STREAM_REQUEST_BLOCK pSrb
)
{
PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension;
int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
PSRB_EXTENSION pSrbExt = (PSRB_EXTENSION)pSrb->SRBExtension;
ASSERT (pStrmEx->KernelDirectDrawHandle != 0);
ASSERT (pSrbExt->UserSurfaceHandle != 0);
if (pSrbExt->UserSurfaceHandle == 0) {
DDOPENSURFACEIN ddOpenSurfaceIn;
DDOPENSURFACEOUT ddOpenSurfaceOut;
DbgLogInfo(("Testcap: Stream %d getting Kernel surface handle\n", StreamNumber));
RtlZeroMemory(&ddOpenSurfaceIn, sizeof(ddOpenSurfaceIn));
RtlZeroMemory(&ddOpenSurfaceOut, sizeof(ddOpenSurfaceOut));
ddOpenSurfaceIn.hDirectDraw = pStrmEx->UserDirectDrawHandle;
ddOpenSurfaceIn.pfnSurfaceClose = DirectDrawEventCallback;
ddOpenSurfaceIn.pContext = pSrb;
ddOpenSurfaceIn.dwSurfaceHandle = (DWORD_PTR) pSrbExt->UserSurfaceHandle;
DxApi(DD_DXAPI_OPENSURFACE,
&ddOpenSurfaceIn,
sizeof(ddOpenSurfaceIn),
&ddOpenSurfaceOut,
sizeof(ddOpenSurfaceOut));
if (ddOpenSurfaceOut.ddRVal != DD_OK) {
pSrbExt->KernelSurfaceHandle = 0;
DbgLogInfo(("Testcap: DD_DXAPI_OPENSURFACE failed.\n"));
TRAP;
}
else {
pSrbExt->KernelSurfaceHandle = ddOpenSurfaceOut.hSurface;
return TRUE;
}
}
return FALSE;
}
BOOL
CloseKernelDDrawSurfaceHandle (
IN PHW_STREAM_REQUEST_BLOCK pSrb
)
{
PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension;
int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
PSRB_EXTENSION pSrbExt = (PSRB_EXTENSION)pSrb->SRBExtension;
ASSERT (pStrmEx->KernelDirectDrawHandle != 0);
ASSERT (pSrbExt->UserSurfaceHandle != 0);
ASSERT (pSrbExt->KernelSurfaceHandle != 0);
if (pSrbExt->KernelSurfaceHandle != 0) {
DWORD ddOut;
DDCLOSEHANDLE ddClose;
DbgLogInfo(("Testcap: Stream %d ReleaseKernelDDrawSurfaceHandle\n", StreamNumber));
ddClose.hHandle = pSrbExt->KernelSurfaceHandle;
DxApi(DD_DXAPI_CLOSEHANDLE, &ddClose, sizeof(ddClose), &ddOut, sizeof(ddOut));
pSrbExt->KernelSurfaceHandle = 0; // what else can we do?
if (ddOut != DD_OK) {
DbgLogInfo(("Testcap: ReleaseKernelDDrawSurfaceHandle FAILED.\n"));
TRAP;
return FALSE;
}
else {
return TRUE;
}
}
return FALSE;
}