windows-nt/Source/XPSP1/NT/net/atm/epvc/sys/util.c
2020-09-26 16:20:57 +08:00

840 lines
18 KiB
C

/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
util.c
Abstract:
ATMEPVC - utilities
Author:
Revision History:
Who When What
-------- -------- ----
ADube 03-23-00 created, .
--*/
#include "precomp.h"
#pragma hdrstop
#if DO_TIMESTAMPS
void
epvcTimeStamp(
char *szFormatString,
UINT Val
)
{
UINT Minutes;
UINT Seconds;
UINT Milliseconds;
LARGE_INTEGER Time;
NdisGetCurrentSystemTime(&Time);
Time.QuadPart /= 10000; //10-nanoseconds to milliseconds.
Milliseconds = Time.LowPart; // don't care about highpart.
Seconds = Milliseconds/1000;
Milliseconds %= 1000;
Minutes = Seconds/60;
Seconds %= 60;
DbgPrint( szFormatString, Minutes, Seconds, Milliseconds, Val);
}
#endif // DO_TIMESTAMPS
//------------------------------------------------------------------------
// //
// Task Data structures and functions begin here //
// //
//----------------------------------------------------------------------//
//
// EpvcTasks_StaticInfo contains static information about
// objects of type EPVC_TASK;
//
RM_STATIC_OBJECT_INFO
EpvcTasks_StaticInfo =
{
0, // TypeUID
0, // TypeFlags
"ATM Epvc Task", // TypeName
0, // Timeout
NULL, // pfnCreate
epvcTaskDelete, // pfnDelete
NULL, // LockVerifier
0, // length of resource table
NULL // Resource Table
};
VOID
epvcTaskDelete (
PRM_OBJECT_HEADER pObj,
PRM_STACK_RECORD psr
)
/*++
Routine Description:
Free an object of type EPVC_TASK.
Arguments:
pHdr - Actually a pointer to the EPVC_TASK to be deleted.
--*/
{
EPVC_FREE(pObj);
}
NDIS_STATUS
epvcAllocateTask(
IN PRM_OBJECT_HEADER pParentObject,
IN PFN_RM_TASK_HANDLER pfnHandler,
IN UINT Timeout,
IN const char * szDescription, OPTIONAL
OUT PRM_TASK *ppTask,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Allocates and initializes a task of subtype ARP1394_TASK.
Arguments:
pParentObject - Object that is to be the parent of the allocated task.
pfnHandler - The task handler for the task.
Timeout - Unused.
szDescription - Text describing this task.
ppTask - Place to store pointer to the new task.
Return Value:
NDIS_STATUS_SUCCESS if we could allocate and initialize the task.
NDIS_STATUS_RESOURCES otherwise
--*/
{
EPVC_TASK *pATask;
NDIS_STATUS Status;
Status = EPVC_ALLOCSTRUCT(pATask, TAG_TASK); // TODO use lookaside lists.
*ppTask = NULL;
if (pATask != NULL && (FAIL(Status)== FALSE))
{
EPVC_ZEROSTRUCT(pATask);
RmInitializeTask(
&(pATask->TskHdr),
pParentObject,
pfnHandler,
&EpvcTasks_StaticInfo,
szDescription,
Timeout,
pSR
);
*ppTask = &(pATask->TskHdr);
Status = NDIS_STATUS_SUCCESS;
}
else
{
Status = NDIS_STATUS_RESOURCES;
}
return Status;
}
NDIS_STATUS
epvcAllocateTaskUsingLookasideList(
IN PRM_OBJECT_HEADER pParentObject,
IN PEPVC_NPAGED_LOOKASIDE_LIST pList,
IN PFN_RM_TASK_HANDLER pfnHandler,
IN UINT Timeout,
IN const char * szDescription, OPTIONAL
OUT PRM_TASK *ppTask,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Allocates and initializes a task of subtype ARP1394_TASK.
Arguments:
pParentObject - Object that is to be the parent of the allocated task.
pfnHandler - The task handler for the task.
Timeout - Unused.
szDescription - Text describing this task.
ppTask - Place to store pointer to the new task.
Return Value:
NDIS_STATUS_SUCCESS if we could allocate and initialize the task.
NDIS_STATUS_RESOURCES otherwise
--*/
{
EPVC_TASK *pATask;
NDIS_STATUS Status;
pATask = epvcGetLookasideBuffer (pList);
Status = EPVC_ALLOCSTRUCT(pATask, TAG_TASK); // TODO use lookaside lists.
*ppTask = NULL;
if (pATask != NULL && (FAIL(Status)== FALSE))
{
EPVC_ZEROSTRUCT(pATask);
RmInitializeTask(
&(pATask->TskHdr),
pParentObject,
pfnHandler,
&EpvcTasks_StaticInfo,
szDescription,
Timeout,
pSR
);
*ppTask = &(pATask->TskHdr);
Status = NDIS_STATUS_SUCCESS;
}
else
{
Status = NDIS_STATUS_RESOURCES;
}
return Status;
}
VOID
epvcSetPrimaryAdapterTask(
PEPVC_ADAPTER pAdapter, // LOCKIN LOCKOUT
PRM_TASK pTask,
ULONG PrimaryState,
PRM_STACK_RECORD pSR
)
{
ENTER("epvcSetPrimaryAdapterTask", 0x49c9e2d5)
RM_ASSERT_OBJLOCKED(&pAdapter->Hdr, pSR);
ASSERT(pAdapter->bind.pPrimaryTask==NULL);
#if DBG
// Veriy that this is a valid primary task. Also verify that PrimaryState
// is a valid primary state.
//
{
PFN_RM_TASK_HANDLER pfn = pTask->pfnHandler;
ASSERT(
((pfn == epvcTaskInitializeAdapter) && (PrimaryState == EPVC_AD_PS_INITING))
|| ((pfn == epvcTaskShutdownAdapter) && (PrimaryState == EPVC_AD_PS_DEINITING))
);
}
#endif // DBG
//
// Although it's tempting to put pTask as entity1 and pRask->Hdr.szDescption as
// entity2 below, we specify NULL for both so that we can be sure that ONLY one
// primary task can be active at any one time.
//
DBG_ADDASSOC(
&pAdapter->Hdr,
NULL, // Entity1
NULL, // Entity2
EPVC_ASSOC_AD_PRIMARY_TASK,
" Primary task\n",
pSR
);
pAdapter->bind.pPrimaryTask = pTask;
SET_AD_PRIMARY_STATE(pAdapter, PrimaryState);
EXIT()
}
VOID
epvcClearPrimaryAdapterTask(
PEPVC_ADAPTER pAdapter, // LOCKIN LOCKOUT
PRM_TASK pTask,
ULONG PrimaryState,
PRM_STACK_RECORD pSR
)
{
ENTER("epvcClearPrimaryAdapterTask", 0x593087b1)
RM_ASSERT_OBJLOCKED(&pAdapter->Hdr, pSR);
ASSERT(pAdapter->bind.pPrimaryTask==pTask);
// Veriy that PrimaryState is a valid primary state.
//
ASSERT(
(PrimaryState == EPVC_AD_PS_INITED)
|| (PrimaryState == EPVC_AD_PS_FAILEDINIT)
|| (PrimaryState == EPVC_AD_PS_DEINITED)
);
// Delete the association added when setting the primary IF task
//
DBG_DELASSOC(
&pAdapter->Hdr,
NULL,
NULL,
EPVC_ASSOC_AD_PRIMARY_TASK,
pSR
);
pAdapter->bind.pPrimaryTask = NULL;
SET_AD_PRIMARY_STATE(pAdapter, PrimaryState);
EXIT()
}
VOID
epvcSetSecondaryAdapterTask(
PEPVC_ADAPTER pAdapter, // LOCKIN LOCKOUT
PRM_TASK pTask,
ULONG SecondaryState,
PRM_STACK_RECORD pSR
)
{
ENTER("epvcSetSecondaryAdapterTask", 0x56bbb567)
RM_ASSERT_OBJLOCKED(&pAdapter->Hdr, pSR);
if (pAdapter->bind.pSecondaryTask != NULL)
{
ASSERT(FALSE);
return; // EARLY RETURN
}
#if DBG
// Veriy that this is a valid act/deact task. Also verify that SecondaryState
// is a valid state.
//
{
PFN_RM_TASK_HANDLER pfn = pTask->pfnHandler;
ASSERT(
((pfn == epvcTaskActivateAdapter) && (SecondaryState == EPVC_AD_AS_ACTIVATING))
|| ((pfn == epvcTaskDeactivateAdapter) && (SecondaryState == EPVC_AD_AS_DEACTIVATING))
);
}
#endif // DBG
//
// Although it's tempting to put pTask as entity1 and pRask->Hdr.szDescption as
// entity2 below, we specify NULL for both so that we can be sure that ONLY one
// primary task can be active at any one time.
//
DBG_ADDASSOC(
&pAdapter->Hdr,
NULL, // Entity1
NULL, // Entity2
EPVC_ASSOC_ACTDEACT_AD_TASK,
" Secondary task\n",
pSR
);
pAdapter->bind.pSecondaryTask = pTask;
SET_AD_ACTIVE_STATE(pAdapter, SecondaryState);
EXIT()
}
VOID
epvcClearSecondaryAdapterTask(
PEPVC_ADAPTER pAdapter, // LOCKIN LOCKOUT
PRM_TASK pTask,
ULONG SecondaryState,
PRM_STACK_RECORD pSR
)
{
ENTER("epvcClearSecondaryAdapterTask", 0x698552bd)
RM_ASSERT_OBJLOCKED(&pAdapter->Hdr, pSR);
if (pAdapter->bind.pSecondaryTask != pTask)
{
ASSERT(FALSE);
return; // EARLY RETURN
}
// Veriy that SecondaryState is a valid primary state.
//
ASSERT(
(SecondaryState == EPVC_AD_AS_ACTIVATED)
|| (SecondaryState == EPVC_AD_AS_FAILEDACTIVATE)
|| (SecondaryState == EPVC_AD_AS_DEACTIVATED)
);
// Delete the association added when setting the primary IF task
//
DBG_DELASSOC(
&pAdapter->Hdr,
NULL,
NULL,
EPVC_ASSOC_ACTDEACT_AD_TASK,
pSR
);
pAdapter->bind.pSecondaryTask = NULL;
SET_AD_ACTIVE_STATE(pAdapter, SecondaryState);
EXIT()
}
NDIS_STATUS
epvcCopyUnicodeString(
OUT PNDIS_STRING pDest,
IN PNDIS_STRING pSrc,
BOOLEAN fUpCase
)
/*++
Routine Description:
Copy the contents of unicode string pSrc into pDest.
pDest->Buffer is allocated using NdisAllocateMemoryWithTag; Caller is
responsible for freeing it.
EXTRA EXTRA EXTRA:
This make sure the destination is NULL terminated.
IPAddInterface expects the Unicode string passed in to be
NULL terminated.
Return Value:
NDIS_STATUS_SUCCESS on success;
NDIS failure status on failure.
--*/
{
USHORT Length = pSrc->Length;
PWCHAR pwStr;
epvcAllocateMemoryWithTag(&pwStr, Length+sizeof(WCHAR), MTAG_STRING);
EPVC_ZEROSTRUCT(pDest);
if (pwStr == NULL)
{
return NDIS_STATUS_RESOURCES;
}
else
{
pDest->Length = Length;
pDest->MaximumLength = Length+sizeof(WCHAR);
pDest->Buffer = pwStr;
{
NdisMoveMemory(pwStr, pSrc->Buffer, Length);
if (Length & 0x1)
{
((PUCHAR)pwStr)[Length] = 0;
}
else
{
pwStr[Length/sizeof(*pwStr)] = 0;
}
}
return NDIS_STATUS_SUCCESS;
}
}
VOID
epvcSetFlags(
IN OUT ULONG* pulFlags,
IN ULONG ulMask )
// Set 'ulMask' bits in '*pulFlags' flags as an interlocked operation.
//
{
ULONG ulFlags;
ULONG ulNewFlags;
do
{
ulFlags = *pulFlags;
ulNewFlags = ulFlags | ulMask;
}
while (InterlockedCompareExchange(
pulFlags, ulNewFlags, ulFlags ) != (LONG )ulFlags);
}
VOID
epvcClearFlags(
IN OUT ULONG* pulFlags,
IN ULONG ulMask )
// Set 'ulMask' bits in '*pulFlags' flags as an interlocked operation.
//
{
ULONG ulFlags;
ULONG ulNewFlags;
do
{
ulFlags = *pulFlags;
ulNewFlags = ulFlags & ~(ulMask);
}
while (InterlockedCompareExchange(
pulFlags, ulNewFlags, ulFlags ) != (LONG )ulFlags);
}
ULONG
epvcReadFlags(
IN ULONG* pulFlags )
// Read the value of '*pulFlags' as an interlocked operation.
//
{
return *pulFlags;
}
BOOLEAN
epvcIsThisTaskPrimary (
PRM_TASK pTask,
PRM_TASK* ppLocation
)
{
BOOLEAN fIsThisTaskPrimary = FALSE;
ASSERT (*ppLocation != pTask);
if (*ppLocation == NULL)
{
*ppLocation = pTask;
return TRUE;
}
else
{
return FALSE;
}
}
VOID
epvcClearPrimaryTask (
PRM_TASK* ppLocation
)
{
*ppLocation = NULL;
}
#if DBG
VOID
CheckList(
IN LIST_ENTRY* pList,
IN BOOLEAN fShowLinks )
// Tries to detect corruption in list 'pList', printing verbose linkage
// output if 'fShowLinks' is set.
//
{
LIST_ENTRY* pLink;
ULONG ul;
ul = 0;
for (pLink = pList->Flink;
pLink != pList;
pLink = pLink->Flink)
{
if (fShowLinks)
{
DbgPrint( "EPVC: CheckList($%p) Flink(%d)=$%p\n",
pList, ul, pLink );
}
++ul;
}
for (pLink = pList->Blink;
pLink != pList;
pLink = pLink->Blink)
{
if (fShowLinks)
{
DbgPrint( "EPVC: CheckList($%p) Blink(%d)=$%p\n",
pList, ul, pLink );
}
--ul;
}
if (ul)
{
DbgBreakPoint();
}
}
#endif
#if DBG
VOID
Dump(
IN CHAR* p,
IN ULONG cb,
IN BOOLEAN fAddress,
IN ULONG ulGroup )
// Hex dump 'cb' bytes starting at 'p' grouping 'ulGroup' bytes together.
// For example, with 'ulGroup' of 1, 2, and 4:
//
// 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
// 0000 0000 0000 0000 0000 0000 0000 0000 |................|
// 00000000 00000000 00000000 00000000 |................|
//
// If 'fAddress' is true, the memory address dumped is prepended to each
// line.
//
{
while (cb)
{
INT cbLine;
cbLine = (cb < DUMP_BytesPerLine) ? cb : DUMP_BytesPerLine;
DumpLine( p, cbLine, fAddress, ulGroup );
cb -= cbLine;
p += cbLine;
}
}
#endif
#if DBG
VOID
DumpLine(
IN CHAR* p,
IN ULONG cb,
IN BOOLEAN fAddress,
IN ULONG ulGroup )
{
CHAR* pszDigits = "0123456789ABCDEF";
CHAR szHex[ ((2 + 1) * DUMP_BytesPerLine) + 1 ];
CHAR* pszHex = szHex;
CHAR szAscii[ DUMP_BytesPerLine + 1 ];
CHAR* pszAscii = szAscii;
ULONG ulGrouped = 0;
if (fAddress)
DbgPrint( "EPVC: %p: ", p );
else
DbgPrint( "EPVC: " );
while (cb)
{
*pszHex++ = pszDigits[ ((UCHAR )*p) / 16 ];
*pszHex++ = pszDigits[ ((UCHAR )*p) % 16 ];
if (++ulGrouped >= ulGroup)
{
*pszHex++ = ' ';
ulGrouped = 0;
}
*pszAscii++ = (*p >= 32 && *p < 128) ? *p : '.';
++p;
--cb;
}
*pszHex = '\0';
*pszAscii = '\0';
DbgPrint(
"%-*s|%-*s|\n",
(2 * DUMP_BytesPerLine) + (DUMP_BytesPerLine / ulGroup), szHex,
DUMP_BytesPerLine, szAscii );
}
#endif
VOID
epvcInitializeLookasideList(
IN OUT PEPVC_NPAGED_LOOKASIDE_LIST pLookasideList,
ULONG Size,
ULONG Tag,
USHORT Depth
)
/*++
Routine Description:
Allocates and initializes a epvc Lookaside list
Arguments:
Return Value:
--*/
{
TRACE( TL_T, TM_Mp, ( "==> epvcInitializeLookasideList pLookaside List %x, size %x, Tag %x, Depth %x, ",
pLookasideList, Size, Tag, Depth) );
NdisInitializeNPagedLookasideList( &pLookasideList->List,
NULL, //Allocate
NULL, // Free
0, // Flags
Size,
Tag,
Depth ); // Depth
pLookasideList->Size = Size;
pLookasideList->bIsAllocated = TRUE;
TRACE( TL_T, TM_Mp, ( "<== epvcInitializeLookasideList " ) );
}
VOID
epvcDeleteLookasideList (
IN OUT PEPVC_NPAGED_LOOKASIDE_LIST pLookasideList
)
/*++
Routine Description:
Deletes a lookaside list, only if it has been allocated
Arguments:
Return Value:
--*/
{
TRACE( TL_T, TM_Mp, ( "==> epvcDeleteLookasideList pLookaside List %x",pLookasideList ) );
if (pLookasideList && pLookasideList->bIsAllocated == TRUE)
{
while (pLookasideList->OutstandingPackets != 0)
{
NdisMSleep( 10000);
}
NdisDeleteNPagedLookasideList (&pLookasideList->List);
}
TRACE( TL_T, TM_Mp, ( "<== epvcDeleteLookasideList pLookaside List %x", pLookasideList) );
}
PVOID
epvcGetLookasideBuffer(
IN PEPVC_NPAGED_LOOKASIDE_LIST pLookasideList
)
// Function Description:
// Allocate an buffer from the lookaside list.
// will be changed to a macro
//
//
//
// Arguments
// Lookaside list - from which the buffer is allocated
//
//
// Return Value:
// Return buffer can be NULL
//
{
PVOID pLocalBuffer = NULL;
TRACE( TL_T, TM_Send, ( "==>epvcGetLookasideBuffer pList %x",pLookasideList) );
ASSERT (pLookasideList != NULL);
//
// Optimize the lookaside list code path
//
pLocalBuffer = NdisAllocateFromNPagedLookasideList (&pLookasideList->List);
if (pLocalBuffer != NULL)
{
NdisZeroMemory (pLocalBuffer, pLookasideList->Size);
NdisInterlockedIncrement (&pLookasideList->OutstandingPackets);
}
else
{
epvcIncrementMallocFailure();
}
TRACE( TL_T, TM_Send, ( "<==epvcGetLookasideBuffer, %x", pLocalBuffer ) );
return pLocalBuffer ;
}
VOID
epvcFreeToNPagedLookasideList (
IN PEPVC_NPAGED_LOOKASIDE_LIST pLookasideList,
IN PVOID pBuffer
)
// Function Description:
// Return the local buffer to the lookaside list
//
// Atguments
// Lookaside list and its buffer
// Return Value:
// None
{
TRACE( TL_T, TM_Send, ( "==> epvcFreeToNPagedLookasideList , Lookaside list %x, plocalbuffer %x",pLookasideList, pBuffer ) );
NdisFreeToNPagedLookasideList (&pLookasideList->List, pBuffer);
NdisInterlockedDecrement (&pLookasideList->OutstandingPackets);
TRACE( TL_T, TM_Send, ( "<== epvcFreeToNPagedLookasideList ") );
}