/*
************************************************************************

Copyright (c) 1996-1997  Microsoft Corporation

Module Name:

    gpcmap.c

Abstract:

    This file contains mapping routines like user handles to
    kernel handles.

Author:

    Ofer Bar - July 14, 1997

Environment:

    Kernel mode

Revision History:


************************************************************************
*/

#include "gpcpre.h"


/*
/////////////////////////////////////////////////////////////////
//
//   globals
//
/////////////////////////////////////////////////////////////////
*/

static MRSW_LOCK		HandleLock;
static HandleFactory   *pMapHandles = NULL;

/*
/////////////////////////////////////////////////////////////////
//
//   prototypes
//
/////////////////////////////////////////////////////////////////
*/



HANDLE
AllocateHandle(
    OUT HANDLE *OutHandle,           
    IN  PVOID  Reference
    )
/*++

Routine Description:

    This function creates a handle.

Arguments:

    OutHandle - a pointer to a location to fill in the result handle
    Reference - to associate with the handle

Return Value:

	The handle factory handle, or NULL in case of en error

--*/
{
    HFHandle	Handle;
    KIRQL		irql;
    
    ASSERT(OutHandle);

	TRACE(MAPHAND, Reference, OutHandle, "AllocateHandle <==");

    WRITE_LOCK( &HandleLock, &irql );

    *OutHandle = (HANDLE) UIntToPtr((Handle = assign_HF_handle(pMapHandles, Reference)));
    
    WRITE_UNLOCK( &HandleLock, irql );

    StatInc(InsertedHF);

	TRACE(MAPHAND, Reference, Handle, "AllocateHandle ==>");

    return (HANDLE) UIntToPtr(Handle);
}


VOID
FreeHandle(
    IN 	HANDLE    Handle
    )
/*++

Routine Description:

    This function frees the handle

Arguments:

    Handle - 

Return Value:

--*/
{
    int  		r;
    KIRQL		irql;

	TRACE(MAPHAND, Handle, 0, "FreeHandle <==");

    if (Handle) {

        WRITE_LOCK( &HandleLock, &irql );
        
        r = release_HF_handle(pMapHandles, (HFHandle)(UINT_PTR)Handle);

        StatInc(RemovedHF);

        //ASSERT(r == 0);
        
        WRITE_UNLOCK( &HandleLock, irql );
    }

	TRACE(MAPHAND, Handle, r, "FreeHandle ==>");
}




VOID
SuspendHandle(
    IN 	HANDLE    Handle
    )
/*++

Routine Description:

    This function suspends the handle

Arguments:

    Handle - 

Return Value:

--*/
{
    int  		r;
    KIRQL		irql;

	TRACE(MAPHAND, Handle, 0, "SuspendHandle <==");

    if (Handle) {

        WRITE_LOCK( &HandleLock, &irql );
        
        r = suspend_HF_handle(pMapHandles, (HFHandle)(UINT_PTR)Handle);

        //ASSERT(r == 0);
        
        WRITE_UNLOCK( &HandleLock, irql );
    }

	TRACE(MAPHAND, Handle, r, "SuspendHandle ==>");
}




VOID
ResumeHandle(
    IN 	HANDLE    Handle
    )
/*++

Routine Description:

    This function resumess the handle

Arguments:

    Handle - 

Return Value:

--*/
{
    int  		r;
    KIRQL		irql;

	TRACE(MAPHAND, Handle, 0, "ResumeHandle <==");

    if (Handle) {

        WRITE_LOCK( &HandleLock, &irql );
        
        r = reinstate_HF_handle(pMapHandles, (HFHandle)(UINT_PTR)Handle);

        //ASSERT(r == 0);
        
        WRITE_UNLOCK( &HandleLock, irql );
    }

	TRACE(MAPHAND, Handle, r, "ResumeHandle ==>");
}




PVOID
GetHandleObject(
	IN  HANDLE					h,
    IN  GPC_ENUM_OBJECT_TYPE	ObjType
    )
{
    GPC_ENUM_OBJECT_TYPE   *p;
    KIRQL					irql;

	TRACE(MAPHAND, h, ObjType, "GetHandleObject <==");

    READ_LOCK(&HandleLock, &irql);

    p = (GPC_ENUM_OBJECT_TYPE *)dereference_HF_handle(pMapHandles, 
                                                      (HFHandle)(UINT_PTR)h);

    if (p != NULL) {

        //
        // we found a reference for the handle
        // we verify that it's the right object type
        //

        if (*p != ObjType) {

            //
            // sorry, wrong type
            //

            p = NULL;
        }
        
    }

    READ_UNLOCK(&HandleLock, irql);
    
	TRACE(MAPHAND, h, p, "GetHandleObject ==>");

    return (PVOID)p;
}




PVOID
GetHandleObjectWithRef(
	IN  HANDLE					h,
    IN  GPC_ENUM_OBJECT_TYPE	ObjType,
    IN  ULONG                   Ref
    )
{
    GPC_ENUM_OBJECT_TYPE   *p;
    KIRQL		irql;
    
	TRACE(MAPHAND, h, ObjType, "GetHandleObjectWithRef ==>");

    READ_LOCK( &HandleLock, &irql );
    
    p = dereference_HF_handle(pMapHandles, (HFHandle)(ULONG_PTR)h);

    if (p != NULL) {

        //
        // we found a reference for the handle
        // we verify that it's the right object type
        //

        if (*p != ObjType) {

            //
            // sorry, wrong type
            //

            p = NULL;
        }
        
    }

    if (p != NULL) {

        switch (ObjType) {

        case GPC_ENUM_CFINFO_TYPE:
            REFADD(&((PBLOB_BLOCK)p)->RefCount, Ref);
            break;

        case GPC_ENUM_CLIENT_TYPE:
            
            REFADD(&((PCLIENT_BLOCK)p)->RefCount, Ref);
            break;

        case GPC_ENUM_PATTERN_TYPE:
            REFADD(&((PPATTERN_BLOCK)p)->RefCount, Ref);
            break;

        default:
            ASSERT(0);
        }
    }
    
    READ_UNLOCK( &HandleLock, irql );

	TRACE(MAPHAND, h, p, "GetHandleObjectWithRef <==");

    return (PVOID)p;
}



/*
************************************************************************

InitMapHandles - 

The initialization handle mapping table

Arguments
	none

Returns
	GPC_STATUS

************************************************************************
*/
GPC_STATUS
InitMapHandles(VOID)
{
    GPC_STATUS Status = GPC_STATUS_SUCCESS;

	TRACE(INIT, 0, 0, "InitMapping");

	INIT_LOCK(&HandleLock);

    NEW_HandleFactory(pMapHandles);

    if (pMapHandles != NULL ) {
        
        if (constructHandleFactory(pMapHandles)) {
            
            FreeHandleFactory(pMapHandles);

            Status = GPC_STATUS_RESOURCES;
        } 
            
    } else {
        
        Status = GPC_STATUS_RESOURCES;
    }
    
	TRACE(INIT, pMapHandles, Status, "InitMapping");

    return Status;
}


/*
************************************************************************

UninitMapHandles - 

	release handle mapping table resources

Arguments
	none

Returns
	void

************************************************************************
*/
VOID
UninitMapHandles(VOID)
{
    GPC_STATUS Status = GPC_STATUS_SUCCESS;

	TRACE(INIT, 0, 0, "UninitMapHandles");

	//NdisFreeSpinLock(&HandleLock);

    destructHandleFactory(pMapHandles);

    FreeHandleFactory(pMapHandles);

	TRACE(INIT, pMapHandles, Status, "UninitMapHandles");

    return;
}