/*++
*******************************************************************************
* Copyright (c) 1990-98 Digi International Inc., All Rights Reserved                            *
*                                                                                                                                                                                                               *
* This software contains proprietary and confidential information of Digi               *
* International Inc.  By accepting transfer of this copy, Recipient agrees              *
* to retain this software in confidence, to prevent disclosure to others,               *
* and to make no use of this software other than that for which it was                  *
* delivered.  This is an unpublished copyrighted work of Digi International     *
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly     *
* prohibited.                                                                                                                                                                           *
*                                                                                                                                                                                                               *
* Restricted Rights Legend                                                                                                                                              *
*                                                                                                                                                                                                               *
* Use, duplication, or disclosure by the Government is subject to                                       *
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in                   *
* Technical Data and Computer Software clause at DFARS 252.227-7031 or                  *
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -                            *
* Restricted Rights at 48 CFR 52.227-19, as applicable.                                                         *
*                                                                                                                                                                                                               *
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343                            *
*                                                                                                                                                                                                               *
*******************************************************************************

Module Name:

   dxbworkq.h

Abstract:

   Routines to manage and use a dxb work queue.  This queue is implemented as a 
   doubly-linked list with built-in spinlock protection as well ensuring an entry 
   cannot be inserted multiple times on the list.

Author:

   Michael Zarns

--*/

#ifndef DXBWORKQ_H
#define DXBWORKQ_H

__inline PLIST_ENTRY
dxbWorkQRemoveHead( 
        PDXB_WORK_QUEUE pWorkQ )
{
    PLIST_ENTRY pEntry;
    KIRQL Irql;

    ASSERT( pWorkQ != NULL );

    KeAcquireSpinLock( &pWorkQ->Lock, &Irql );

    if ( IsListEmpty( &pWorkQ->Head ) )
        pEntry = NULL;
    else
    {
        PDXB_WORK_QUEUE_ENTRY pItem;
        pEntry = RemoveHeadList( &pWorkQ->Head );
        InitializeListHead(pEntry);
        pItem = CONTAINING_RECORD( pEntry, DXB_WORK_QUEUE_ENTRY, Entry );
        pItem->fInList = FALSE;
    }

    KeReleaseSpinLock( &pWorkQ->Lock, Irql );
    return pEntry;
}


 __inline VOID
dxbWorkQRemoveEntry( 
        PDXB_WORK_QUEUE       pWorkQ,
        PDXB_WORK_QUEUE_ENTRY pEntry )
{
    KIRQL Irql;
    KeAcquireSpinLock( &pWorkQ->Lock, &Irql );

    if ( pEntry->fInList )
    {
        RemoveEntryList( &pEntry->Entry );
        InitializeListHead( &pEntry->Entry );

        pEntry->fInList = FALSE;
    }

    KeReleaseSpinLock( &pWorkQ->Lock, Irql );
}


__inline VOID
dxbWorkQInsertHead( 
        PDXB_WORK_QUEUE       pWorkQ,
        PDXB_WORK_QUEUE_ENTRY pItem )
{
    KIRQL Irql;

    ASSERT( pWorkQ != NULL );
    ASSERT( pItem != NULL );

    KeAcquireSpinLock( &pWorkQ->Lock, &Irql );

    if ( !pItem->fInList )
    {
        InsertHeadList( &pWorkQ->Head, &pItem->Entry );
        pItem->fInList = TRUE;
    }

    KeReleaseSpinLock( &pWorkQ->Lock, Irql );
}


__inline VOID
dxbWorkQInsertTail( 
        PDXB_WORK_QUEUE       pWorkQ,
        PDXB_WORK_QUEUE_ENTRY pItem )
{
    KIRQL Irql;

    ASSERT( pWorkQ != NULL );
    ASSERT( pItem != NULL );

    KeAcquireSpinLock( &pWorkQ->Lock, &Irql );
        
    if ( !pItem->fInList )
    {
        InsertTailList( &pWorkQ->Head, &pItem->Entry );
        pItem->fInList = TRUE;
    }

    KeReleaseSpinLock( &pWorkQ->Lock, Irql );
}

__inline VOID
dxbWorkCmdRemoveEntry( PDXB_STREAM_OBJECT pStream )
{
    dxbWorkQRemoveEntry( &pStream->pExt->Work.Command, &pStream->Entries.Command );
}

__inline VOID
dxbWorkCmdInsertHead( PDXB_STREAM_OBJECT pStream )
{
    dxbWorkQInsertHead( &pStream->pExt->Work.Command, &pStream->Entries.Command );
}

__inline VOID
dxbWorkCmdInsertTail( PDXB_STREAM_OBJECT pStream )
{
    dxbWorkQInsertTail( &pStream->pExt->Work.Command, &pStream->Entries.Command );
}

__inline PDXB_STREAM_OBJECT
dxbWorkCmdRemoveHead( PDXB_DEVICE_EXTENSION pExt )
{
    PDXB_STREAM_OBJECT pStream;
    PLIST_ENTRY pEntry = dxbWorkQRemoveHead( &pExt->Work.Command );
    pStream = pEntry == NULL ? NULL : CONTAINING_RECORD( pEntry, DXB_STREAM_OBJECT, Entries.Command.Entry );
    return pStream;
}

__inline VOID
dxbWorkCreditRemoveEntry( PDXB_STREAM_OBJECT pStream )
{
    dxbWorkQRemoveEntry( &pStream->pExt->Work.Credit, &pStream->Entries.Credit );
}

__inline VOID
dxbWorkCreditInsertHead( PDXB_STREAM_OBJECT pStream )
{
    dxbWorkQInsertHead( &pStream->pExt->Work.Credit, &pStream->Entries.Credit );
}

__inline VOID
dxbWorkCreditInsertTail( PDXB_STREAM_OBJECT pStream )
{
    dxbWorkQInsertTail( &pStream->pExt->Work.Credit, &pStream->Entries.Credit );
}

__inline PDXB_STREAM_OBJECT
dxbWorkCreditRemoveHead( PDXB_DEVICE_EXTENSION pExt )
{
    PDXB_STREAM_OBJECT pStream;
    PLIST_ENTRY pEntry = dxbWorkQRemoveHead( &pExt->Work.Credit );
    pStream = pEntry == NULL ? NULL : CONTAINING_RECORD( pEntry, DXB_STREAM_OBJECT, Entries.Credit.Entry );
    return pStream;
}

#endif // _DXBWORKQ_
