/*++

Copyright (c) 1990-1995  Microsoft Corporation

Module Name:

    miniport.c

Abstract:

    NDIS wrapper functions

Author:

    Sean Selitrennikoff (SeanSe) 05-Oct-93
    Jameel Hyder (JameelH) Re-organization 01-Jun-95

Environment:

    Kernel mode, FSD

Revision History:

--*/

#include "precomp.h"
#pragma hdrstop

//
//  Define the module number for debug code.
//
#define MODULE_NUMBER   MODULE_MINISUB

VOID
NdisAllocateSpinLock(
    IN  PNDIS_SPIN_LOCK         SpinLock
    )
{
    INITIALIZE_SPIN_LOCK(&SpinLock->SpinLock);
}

VOID
NdisFreeSpinLock(
    IN  PNDIS_SPIN_LOCK         SpinLock
    )
{
    UNREFERENCED_PARAMETER(SpinLock);
}

VOID
NdisAcquireSpinLock(
    IN  PNDIS_SPIN_LOCK         SpinLock
    )
{
    NDIS_ACQUIRE_SPIN_LOCK(SpinLock, &SpinLock->OldIrql);
}

VOID
NdisReleaseSpinLock(
    IN  PNDIS_SPIN_LOCK         SpinLock
    )
{
    NDIS_RELEASE_SPIN_LOCK(SpinLock, SpinLock->OldIrql);
}

VOID
NdisDprAcquireSpinLock(
    IN  PNDIS_SPIN_LOCK         SpinLock
    )
{
    NDIS_ACQUIRE_SPIN_LOCK_DPC(SpinLock);
    SpinLock->OldIrql = DISPATCH_LEVEL;
}

VOID
NdisDprReleaseSpinLock(
    IN  PNDIS_SPIN_LOCK         SpinLock
    )
{
    NDIS_RELEASE_SPIN_LOCK_DPC(SpinLock);
}

#undef NdisFreeBuffer
VOID
NdisFreeBuffer(
    IN  PNDIS_BUFFER            Buffer
    )
{
    IoFreeMdl(Buffer);
}

#undef NdisQueryBuffer
VOID
NdisQueryBuffer(
    IN  PNDIS_BUFFER            Buffer,
    OUT PVOID *                 VirtualAddress OPTIONAL,
    OUT PUINT                   Length
    )
{
    if (ARGUMENT_PRESENT(VirtualAddress))
    {
        *VirtualAddress = MDL_ADDRESS(Buffer);
    }
    *Length = MDL_SIZE(Buffer);
}


VOID
NdisQueryBufferSafe(
    IN  PNDIS_BUFFER            Buffer,
    OUT PVOID *                 VirtualAddress OPTIONAL,
    OUT PUINT                   Length,
    IN  MM_PAGE_PRIORITY        Priority
    )
{
    if (ARGUMENT_PRESENT(VirtualAddress))
    {
        *VirtualAddress = MDL_ADDRESS_SAFE(Buffer, Priority);
    }
    *Length = MDL_SIZE(Buffer);
}

VOID
NdisQueryBufferOffset(
    IN  PNDIS_BUFFER            Buffer,
    OUT PUINT                   Offset,
    OUT PUINT                   Length
    )
{
    *Offset = MDL_OFFSET(Buffer);
    *Length = MDL_SIZE(Buffer);
}

VOID
NdisGetFirstBufferFromPacket(
    IN  PNDIS_PACKET            Packet,
    OUT PNDIS_BUFFER *          FirstBuffer,
    OUT PVOID *                 FirstBufferVA,
    OUT PUINT                   FirstBufferLength,
    OUT PUINT                   TotalBufferLength
    )
{
    PNDIS_BUFFER    pBuf;

    pBuf = Packet->Private.Head;
    *FirstBuffer = pBuf;
    if (pBuf)
    {
        *FirstBufferVA =    MmGetSystemAddressForMdl(pBuf);
        *FirstBufferLength = *TotalBufferLength = MmGetMdlByteCount(pBuf);
        for (pBuf = pBuf->Next;
             pBuf != NULL;
             pBuf = pBuf->Next)
        {
            *TotalBufferLength += MmGetMdlByteCount(pBuf);
        }
    }
    else
    {
        *FirstBufferVA = 0;
        *FirstBufferLength = 0;
        *TotalBufferLength = 0;
    }
}

//
// safe version of NdisGetFirstBufferFromPacket
// if the memory described by the first buffer can not be mapped
// this function will return NULL for FirstBuferVA
//
VOID
NdisGetFirstBufferFromPacketSafe(
    IN  PNDIS_PACKET            Packet,
    OUT PNDIS_BUFFER *          FirstBuffer,
    OUT PVOID *                 FirstBufferVA,
    OUT PUINT                   FirstBufferLength,
    OUT PUINT                   TotalBufferLength,
    IN  MM_PAGE_PRIORITY        Priority
    )
{
    PNDIS_BUFFER    pBuf;

    pBuf = Packet->Private.Head;
    *FirstBuffer = pBuf;
    if (pBuf)
    {
        *FirstBufferVA =    MmGetSystemAddressForMdlSafe(pBuf, Priority);
        *FirstBufferLength = *TotalBufferLength = MmGetMdlByteCount(pBuf);
        for (pBuf = pBuf->Next;
             pBuf != NULL;
             pBuf = pBuf->Next)
        {
            *TotalBufferLength += MmGetMdlByteCount(pBuf);
        }
    }
    else
    {
        *FirstBufferVA = 0;
        *FirstBufferLength = 0;
        *TotalBufferLength = 0;
    }

}

ULONG
NdisBufferLength(
    IN  PNDIS_BUFFER            Buffer
    )
{
    return (MmGetMdlByteCount(Buffer));
}

PVOID
NdisBufferVirtualAddress(
    IN  PNDIS_BUFFER            Buffer
    )
{
    return (MDL_ADDRESS_SAFE(Buffer, HighPagePriority));
}

ULONG
NDIS_BUFFER_TO_SPAN_PAGES(
    IN  PNDIS_BUFFER                Buffer
    )
{
    if (MDL_SIZE(Buffer) == 0)
    {
        return 1;
    }
    return ADDRESS_AND_SIZE_TO_SPAN_PAGES(MDL_VA(Buffer), MDL_SIZE(Buffer));
}

VOID
NdisGetBufferPhysicalArraySize(
    IN  PNDIS_BUFFER            Buffer,
    OUT PUINT                   ArraySize
    )
{
    if (MDL_SIZE(Buffer) == 0)
    {
        *ArraySize = 1;
    }
    else
    {
        *ArraySize = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MDL_VA(Buffer), MDL_SIZE(Buffer));
    }
}

NDIS_STATUS
NdisAnsiStringToUnicodeString(
    IN  OUT PUNICODE_STRING     DestinationString,
    IN      PANSI_STRING        SourceString
    )
{
    NDIS_STATUS Status;

    Status = RtlAnsiStringToUnicodeString(DestinationString,
                                          SourceString,
                                          FALSE);
    return Status;
}

NDIS_STATUS
NdisUnicodeStringToAnsiString(
    IN  OUT PANSI_STRING        DestinationString,
    IN      PUNICODE_STRING     SourceString
    )
{
    NDIS_STATUS Status;

    Status = RtlUnicodeStringToAnsiString(DestinationString,
                                          SourceString,
                                          FALSE);
    return Status;
}


NDIS_STATUS
NdisUpcaseUnicodeString(
    OUT PUNICODE_STRING         DestinationString,
    IN  PUNICODE_STRING         SourceString
    )
{
    return(RtlUpcaseUnicodeString(DestinationString, SourceString, FALSE));
}

VOID
NdisMStartBufferPhysicalMapping(
    IN  NDIS_HANDLE             MiniportAdapterHandle,
    IN  PNDIS_BUFFER            Buffer,
    IN  ULONG                   PhysicalMapRegister,
    IN  BOOLEAN                 WriteToDevice,
    OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray,
    OUT PUINT                   ArraySize
    )
{
    NdisMStartBufferPhysicalMappingMacro(MiniportAdapterHandle,
                                         Buffer,
                                         PhysicalMapRegister,
                                         WriteToDevice,
                                         PhysicalAddressArray,
                                         ArraySize);
}

VOID
NdisMCompleteBufferPhysicalMapping(
    IN  NDIS_HANDLE             MiniportAdapterHandle,
    IN  PNDIS_BUFFER            Buffer,
    IN  ULONG                   PhysicalMapRegister
    )
{
    NdisMCompleteBufferPhysicalMappingMacro(MiniportAdapterHandle,
                                            Buffer,
                                            PhysicalMapRegister);
}

#undef NdisInterlockedIncrement
ULONG
NdisInterlockedIncrement(
    IN  PULONG                  Addend
    )
/*++

    Return Value:

        (eax) < 0 (but not necessarily -1) if result of add < 0
        (eax) == 0 if result of add == 0
        (eax) > 0 (but not necessarily +1) if result of add > 0

--*/
{
    return(InterlockedIncrement(Addend));
}

#undef NdisInterlockedDecrement
ULONG
NdisInterlockedDecrement(
    IN  PULONG                  Addend
    )
/*++

    Return Value:

        (eax) < 0 (but not necessarily -1) if result of add < 0
        (eax) == 0 if result of add == 0
        (eax) > 0 (but not necessarily +1) if result of add > 0

--*/
{
    return(InterlockedDecrement(Addend));
}

#undef NdisInterlockedAddUlong
ULONG
NdisInterlockedAddUlong(
    IN  PULONG                  Addend,
    IN  ULONG                   Increment,
    IN  PNDIS_SPIN_LOCK         SpinLock
    )
{
    return(ExInterlockedAddUlong(Addend,Increment, &SpinLock->SpinLock));

}

#undef NdisInterlockedInsertHeadList
PLIST_ENTRY
NdisInterlockedInsertHeadList(
    IN  PLIST_ENTRY             ListHead,
    IN  PLIST_ENTRY             ListEntry,
    IN  PNDIS_SPIN_LOCK         SpinLock
    )
{

    return(ExInterlockedInsertHeadList(ListHead,ListEntry,&SpinLock->SpinLock));

}

#undef NdisInterlockedInsertTailList
PLIST_ENTRY
NdisInterlockedInsertTailList(
    IN  PLIST_ENTRY             ListHead,
    IN  PLIST_ENTRY             ListEntry,
    IN  PNDIS_SPIN_LOCK         SpinLock
    )
{
    return(ExInterlockedInsertTailList(ListHead,ListEntry,&SpinLock->SpinLock));
}

#undef NdisInterlockedRemoveHeadList
PLIST_ENTRY
NdisInterlockedRemoveHeadList(
    IN  PLIST_ENTRY             ListHead,
    IN  PNDIS_SPIN_LOCK         SpinLock
    )
{
    return(ExInterlockedRemoveHeadList(ListHead, &SpinLock->SpinLock));
}

#undef NdisInterlockedPushEntryList
PSINGLE_LIST_ENTRY
NdisInterlockedPushEntryList(
    IN  PSINGLE_LIST_ENTRY      ListHead,
    IN  PSINGLE_LIST_ENTRY      ListEntry,
    IN  PNDIS_SPIN_LOCK         Lock
    )
{
    return(ExInterlockedPushEntryList(ListHead, ListEntry, &Lock->SpinLock));
}

#undef NdisInterlockedPopEntryList
PSINGLE_LIST_ENTRY
NdisInterlockedPopEntryList(
    IN  PSINGLE_LIST_ENTRY      ListHead,
    IN  PNDIS_SPIN_LOCK         Lock
    )
{
    return(ExInterlockedPopEntryList(ListHead, &Lock->SpinLock));
}


//
// Logging support for miniports
//
NDIS_STATUS
NdisMCreateLog(
    IN  NDIS_HANDLE             MiniportAdapterHandle,
    IN  UINT                    Size,
    OUT PNDIS_HANDLE            LogHandle
    )
{
    PNDIS_MINIPORT_BLOCK        Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
    PNDIS_LOG                   Log = NULL;
    NDIS_STATUS                 Status;
    KIRQL                       OldIrql;

    NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);

    if (Miniport->Log != NULL)
    {
        Status = NDIS_STATUS_FAILURE;
    }
    else
    {
        Log = ALLOC_FROM_POOL(sizeof(NDIS_LOG) + Size, NDIS_TAG_DBG_LOG);
        if (Log != NULL)
        {
            Status = NDIS_STATUS_SUCCESS;
            Miniport->Log = Log;
            INITIALIZE_SPIN_LOCK(&Log->LogLock);
            Log->Miniport = Miniport;
            Log->Irp = NULL;
            Log->TotalSize = Size;
            Log->CurrentSize = 0;
            Log->InPtr = 0;
            Log->OutPtr = 0;
        }
        else
        {
            Status = NDIS_STATUS_RESOURCES;
        }
    }

    *LogHandle = Log;

    NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);

    return Status;
}


VOID
NdisMCloseLog(
    IN   NDIS_HANDLE            LogHandle
    )
{
    PNDIS_LOG                   Log = (PNDIS_LOG)LogHandle;
    PNDIS_MINIPORT_BLOCK        Miniport;
    KIRQL                       OldIrql;

    Miniport = Log->Miniport;

    NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
    Miniport->Log = NULL;
    NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);

    FREE_POOL(Log);
}


NDIS_STATUS
NdisMWriteLogData(
    IN   NDIS_HANDLE            LogHandle,
    IN   PVOID                  LogBuffer,
    IN   UINT                   LogBufferSize
    )
{
    PNDIS_LOG                   Log = (PNDIS_LOG)LogHandle;
    NDIS_STATUS                 Status = NDIS_STATUS_SUCCESS;
    KIRQL                       OldIrql;
    UINT                        AmtToCopy;

    IoAcquireCancelSpinLock(&OldIrql);

    ACQUIRE_SPIN_LOCK_DPC(&Log->LogLock);

    if (LogBufferSize <= Log->TotalSize)
    {
        if (LogBufferSize <= (Log->TotalSize - Log->InPtr))
        {
            //
            // Can copy the entire buffer
            //
            CopyMemory(Log->LogBuf+Log->InPtr, LogBuffer, LogBufferSize);
        }
        else
        {
            //
            // We are going to wrap around. Copy it in two chunks.
            //
            AmtToCopy = Log->TotalSize - Log->InPtr;
            CopyMemory(Log->LogBuf+Log->InPtr,
                       LogBuffer,
                       AmtToCopy);
            CopyMemory(Log->LogBuf + 0,
                       (PUCHAR)LogBuffer+AmtToCopy,
                       LogBufferSize - AmtToCopy);
        }

        //
        // Update the current size
        //
        Log->CurrentSize += LogBufferSize;
        if (Log->CurrentSize > Log->TotalSize)
            Log->CurrentSize = Log->TotalSize;

        //
        // Update the InPtr and possibly the outptr
        //
        Log->InPtr += LogBufferSize;
        if (Log->InPtr >= Log->TotalSize)
        {
            Log->InPtr -= Log->TotalSize;
        }

        if (Log->CurrentSize == Log->TotalSize)
        {
            Log->OutPtr = Log->InPtr;
        }

        //
        // Check if there is a pending Irp to complete
        //
        if (Log->Irp != NULL)
        {
            PIRP    Irp = Log->Irp;
            PUCHAR  Buffer;

            Log->Irp = NULL;

            //
            // If the InPtr is lagging the OutPtr. then we can simply
            // copy the data over in one shot.
            //
            AmtToCopy = MDL_SIZE(Irp->MdlAddress);
            if (AmtToCopy > Log->CurrentSize)
                AmtToCopy = Log->CurrentSize;
            if ((Log->TotalSize - Log->OutPtr) >= AmtToCopy)
            {
                Buffer = MDL_ADDRESS_SAFE(Irp->MdlAddress, LowPagePriority);

                if (Buffer != NULL)
                {
                    CopyMemory(Buffer,
                               Log->LogBuf+Log->OutPtr,
                               AmtToCopy);
                }
                else Status = NDIS_STATUS_RESOURCES;
            }
            else
            {
                Buffer = MDL_ADDRESS_SAFE(Irp->MdlAddress, LowPagePriority);

                if (Buffer != NULL)
                {
                    CopyMemory(Buffer,
                               Log->LogBuf+Log->OutPtr,
                               Log->TotalSize-Log->OutPtr);
                    CopyMemory(Buffer+Log->TotalSize-Log->OutPtr,
                               Log->LogBuf,
                               AmtToCopy - (Log->TotalSize-Log->OutPtr));
                }
                else Status = NDIS_STATUS_RESOURCES;
            }
            Log->CurrentSize -= AmtToCopy;
            Log->OutPtr += AmtToCopy;
            if (Log->OutPtr >= Log->TotalSize)
                Log->OutPtr -= Log->TotalSize;
            Irp->IoStatus.Information = AmtToCopy;
            IoSetCancelRoutine(Irp, NULL);
            Irp->IoStatus.Status = STATUS_SUCCESS;
            IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
        }
    }
    else
    {
        Status = NDIS_STATUS_BUFFER_OVERFLOW;
    }

    RELEASE_SPIN_LOCK_DPC(&Log->LogLock);

    IoReleaseCancelSpinLock(OldIrql);

    return Status;
}

NDIS_STATUS
FASTCALL
ndisMGetLogData(
    IN  PNDIS_MINIPORT_BLOCK    Miniport,
    IN  PIRP                    Irp
    )
{
    NTSTATUS    Status = STATUS_SUCCESS;
    KIRQL       OldIrql;
    PNDIS_LOG   Log;
    UINT        AmtToCopy;

    IoAcquireCancelSpinLock(&OldIrql);

    NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);

    if ((Log = Miniport->Log) != NULL)
    {
        ACQUIRE_SPIN_LOCK_DPC(&Log->LogLock);

        if (Log->CurrentSize != 0)
        {
            PUCHAR  Buffer;

            //
            // If the InPtr is lagging the OutPtr. then we can simply
            // copy the data over in one shot.
            //
            AmtToCopy = MDL_SIZE(Irp->MdlAddress);
            if (AmtToCopy > Log->CurrentSize)
                AmtToCopy = Log->CurrentSize;
            Buffer = MDL_ADDRESS_SAFE(Irp->MdlAddress, LowPagePriority);

            if (Buffer != NULL)
            {
                if ((Log->TotalSize - Log->OutPtr) >= AmtToCopy)
                {
                    CopyMemory(Buffer,
                               Log->LogBuf+Log->OutPtr,
                               AmtToCopy);
                }
                else
                {
                    CopyMemory(Buffer,
                               Log->LogBuf+Log->OutPtr,
                               Log->TotalSize-Log->OutPtr);
                    CopyMemory(Buffer+Log->TotalSize-Log->OutPtr,
                               Log->LogBuf,
                               AmtToCopy - (Log->TotalSize-Log->OutPtr));
                }
                Log->CurrentSize -= AmtToCopy;
                Log->OutPtr += AmtToCopy;
                if (Log->OutPtr >= Log->TotalSize)
                    Log->OutPtr -= Log->TotalSize;
                Irp->IoStatus.Information = AmtToCopy;
                Status = STATUS_SUCCESS;
            }
            else
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
            }
        }
        else if (Log->Irp != NULL)
        {
            Status = STATUS_UNSUCCESSFUL;
        }
        else
        {
            IoSetCancelRoutine(Irp, ndisCancelLogIrp);
            Log->Irp = Irp;
            Status = STATUS_PENDING;
        }

        RELEASE_SPIN_LOCK_DPC(&Log->LogLock);
    }
    else
    {
        Status = STATUS_UNSUCCESSFUL;
    }

    NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
    IoReleaseCancelSpinLock(OldIrql);

    return Status;
}


VOID
NdisMFlushLog(
    IN   NDIS_HANDLE                LogHandle
    )
{
    PNDIS_LOG                   Log = (PNDIS_LOG)LogHandle;
    KIRQL                       OldIrql;

    ACQUIRE_SPIN_LOCK(&Log->LogLock, &OldIrql);
    Log->InPtr = 0;
    Log->OutPtr = 0;
    Log->CurrentSize = 0;
    RELEASE_SPIN_LOCK(&Log->LogLock, OldIrql);
}

NDIS_STATUS
NdisMQueryAdapterInstanceName(
    OUT PNDIS_STRING    pAdapterInstanceName,
    IN  NDIS_HANDLE     NdisAdapterHandle
    )
{
    PNDIS_MINIPORT_BLOCK    Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
    USHORT                  cbSize;
    PVOID                   ptmp = NULL;
    NDIS_STATUS             Status = NDIS_STATUS_FAILURE;
    NTSTATUS                NtStatus;

    DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
        ("==>NdisMQueryAdapterInstanceName\n"));

    //
    //  If we failed to create the adapter instance name then fail this call.
    //
    if (NULL != Miniport->pAdapterInstanceName)
    {
        //
        //  Allocate storage for the copy of the adapter instance name.
        //
        cbSize = Miniport->pAdapterInstanceName->MaximumLength;
    
        //
        //  Allocate storage for the new string.
        //
        ptmp = ALLOC_FROM_POOL(cbSize, NDIS_TAG_NAME_BUF);
        if (NULL != ptmp)
        {
            RtlZeroMemory(ptmp, cbSize);
            pAdapterInstanceName->Buffer = ptmp;
            pAdapterInstanceName->Length = 0;
            pAdapterInstanceName->MaximumLength = cbSize;
    
            NtStatus = RtlAppendUnicodeStringToString(
                            pAdapterInstanceName, 
                            Miniport->pAdapterInstanceName);
            if (NT_SUCCESS(NtStatus))
            {
                Status = NDIS_STATUS_SUCCESS;
            }
        }
        else
        {    
            Status = NDIS_STATUS_RESOURCES;
        }
    }

    if (NDIS_STATUS_SUCCESS != Status)
    {
        if (NULL != ptmp)
        {    
            FREE_POOL(ptmp);
        }
    }

    DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
        ("<==NdisMQueryAdapterInstanceName: 0x%x\n", Status));

    return(Status);
}


EXPORT
VOID
NdisInitializeReadWriteLock(
    IN  PNDIS_RW_LOCK           Lock
    )
{
    NdisZeroMemory(Lock, sizeof(NDIS_RW_LOCK));
}


VOID
NdisAcquireReadWriteLock(
    IN  PNDIS_RW_LOCK           Lock,
    IN  BOOLEAN                 fWrite,
    IN  PLOCK_STATE             LockState
    )
{
    if (fWrite)
    {
        LockState->LockState = WRITE_LOCK_STATE_UNKNOWN;
        {
            UINT    i, refcount;
            ULONG   Prc;

            /*
             * This means we need to attempt to acquire the lock,
             * if we do not already own it.
             * Set the state accordingly.
             */
            if ((Lock)->Context == CURRENT_THREAD)
            {
                (LockState)->LockState = LOCK_STATE_ALREADY_ACQUIRED;
            }
            else
            {
                ACQUIRE_SPIN_LOCK(&(Lock)->SpinLock, &(LockState)->OldIrql);

                Prc = KeGetCurrentProcessorNumber();
                refcount = (Lock)->RefCount[Prc].RefCount;
                (Lock)->RefCount[Prc].RefCount = 0;

                /* wait for all readers to exit */
                for (i=0; i < ndisNumberOfProcessors; i++)
                {
                    volatile UINT   *_p = &(Lock)->RefCount[i].RefCount;

                    while (*_p != 0)
                        NDIS_INTERNAL_STALL(50);
                }

                (Lock)->RefCount[Prc].RefCount = refcount;
                (Lock)->Context = CURRENT_THREAD;
                (LockState)->LockState = WRITE_LOCK_STATE_FREE;
            }
        }
    }
    else
    {
        LockState->LockState = READ_LOCK;
        {                                                                       
            UINT    refcount;                                                   
            ULONG   Prc;                                                        
                                                                                
            RAISE_IRQL_TO_DISPATCH(&(LockState)->OldIrql);                           
                                                                                
            /* go ahead and bump up the ref count IF no writes are underway */  
            Prc = CURRENT_PROCESSOR;                                            
            refcount = InterlockedIncrement(&Lock->RefCount[Prc].RefCount);                          
                                                                                
            /* Test if spin lock is held, i.e., write is underway   */          
            /* if (KeTestSpinLock(&(_L)->SpinLock) == TRUE)         */          
            /* This processor already is holding the lock, just     */          
            /* allow him to take it again or else we run into a     */          
            /* dead-lock situation with the writer                  */          
            if (TEST_SPIN_LOCK((Lock)->SpinLock) &&                               
                (refcount == 1) &&                                              
                ((Lock)->Context != CURRENT_THREAD))                              
            {                                                                   
                (Lock)->RefCount[Prc].RefCount--;                                 
                ACQUIRE_SPIN_LOCK_DPC(&(Lock)->SpinLock);                         
                (Lock)->RefCount[Prc].RefCount++;                                 
                RELEASE_SPIN_LOCK_DPC(&(Lock)->SpinLock);                         
            }                                                                   
            (LockState)->LockState = READ_LOCK_STATE_FREE;                           
        }
    }
//  LockState->LockState = fWrite ? WRITE_LOCK_STATE_UNKNOWN : READ_LOCK;
//  xLockHandler(Lock, LockState);
}


VOID
NdisReleaseReadWriteLock(
    IN  PNDIS_RW_LOCK           Lock,
    IN  PLOCK_STATE             LockState
    )
{
    xLockHandler(Lock, LockState);
}