//---------------------------------------------------------------------------
//  Bda Topology Implementation Internal Structures
//
//      Minidriver code should not attempt to access these structures
//      directly.
//
//---------------------------------------------------------------------------

#define FILTERNAME          "BdaTopology"
#define DYNAMIC_TOPOLOGY    TRUE


#if defined(__cplusplus)
extern "C" {
#endif // defined(__cplusplus)


//===========================================================================
//
//  MACRO definitions
//
//===========================================================================
#define BDA_PIN_STORAGE_INCREMENT   5

//===========================================================================
//
//  Advance declarations
//
//===========================================================================
typedef struct _BDA_PIN_FACTORY_CONTEXT      BDA_PIN_FACTORY_CONTEXT, 
                                        *PBDA_PIN_FACTORY_CONTEXT;



//===========================================================================
//
//  BDA Object Context Structures
//
//===========================================================================


typedef struct _BDA_CONTEXT_ENTRY
{
    PVOID       pvReference;
    PVOID       pvContext;
    ULONG       ulcbContext;

} BDA_CONTEXT_ENTRY, * PBDA_CONTEXT_ENTRY;

typedef struct _BDA_CONTEXT_LIST
{
    ULONG               ulcListEntries;
    ULONG               ulcMaxListEntries;
    ULONG               ulcListEntriesPerBlock;
    PBDA_CONTEXT_ENTRY  pListEntries;
    KSPIN_LOCK          lock;
    BOOLEAN             fInitialized;

} BDA_CONTEXT_LIST, * PBDA_CONTEXT_LIST;


typedef struct _BDA_TEMPLATE_PATH
{
    LIST_ENTRY      leLinkage;

    ULONG           ulInputPinType;
    ULONG           ulOutputPinType;
    ULONG           uliJoint;

    ULONG           ulcControlNodesInPath;
    PULONG          argulControlNodesInPath;

} BDA_TEMPLATE_PATH, * PBDA_TEMPLATE_PATH;

__inline NTSTATUS
NewBdaTemplatePath(
    PBDA_TEMPLATE_PATH *    ppTemplatePath
    )
{
    NTSTATUS            status = STATUS_SUCCESS;

    if (!ppTemplatePath)
    {
        status = STATUS_INVALID_PARAMETER;
        goto errExit;
    }

    *ppTemplatePath = (PBDA_TEMPLATE_PATH) ExAllocatePool( 
                                               NonPagedPool,
                                               sizeof( BDA_TEMPLATE_PATH)
                                               );
    if (!*ppTemplatePath)
    {
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto errExit;
    }

    RtlZeroMemory( *ppTemplatePath, sizeof( BDA_TEMPLATE_PATH));
    InitializeListHead( &(*ppTemplatePath)->leLinkage);

errExit:
    return status;
}

__inline NTSTATUS
DeleteBdaTemplatePath(
    PBDA_TEMPLATE_PATH  pTemplatePath
    )
{
    NTSTATUS            status = STATUS_SUCCESS;

    if (!pTemplatePath)
    {
        status = STATUS_INVALID_PARAMETER;
        goto errExit;
    }

    if (pTemplatePath->argulControlNodesInPath)
    {
        ExFreePool( pTemplatePath->argulControlNodesInPath);
        pTemplatePath->argulControlNodesInPath = NULL;
    }

    RtlZeroMemory( pTemplatePath, sizeof( BDA_TEMPLATE_PATH));
    ExFreePool( pTemplatePath);

errExit:
    return status;
}



typedef struct _BDA_DEVICE_CONTEXT
{

    ULONG       ulStartEmpty;

    //$BUG  Add global statistics

} BDA_DEVICE_CONTEXT, *PBDA_DEVICE_CONTEXT;


typedef struct _BDA_PATH_STACK_ENTRY
{
    ULONG       ulHop;
    ULONG       uliConnection;
    BOOLEAN     fJoint;
} BDA_PATH_STACK_ENTRY, *PBDA_PATH_STACK_ENTRY;

typedef struct _BDA_NODE_CONTROL_INFO
{
    ULONG           ulNodeType;
    ULONG           ulControllingPinType;

} BDA_NODE_CONTROL_INFO, * PBDA_NODE_CONTROL_INFO;

typedef struct _BDA_PATH_INFO
{
    ULONG                   ulInputPin;
    ULONG                   ulOutputPin;
    ULONG                   ulcPathEntries;
    BDA_PATH_STACK_ENTRY    rgPathEntries[MIN_DIMENSION];

} BDA_PATH_INFO, * PBDA_PATH_INFO;


typedef struct _BDA_FILTER_FACTORY_CONTEXT
{
    const BDA_FILTER_TEMPLATE *     pBdaFilterTemplate;
    const KSFILTER_DESCRIPTOR *     pInitialFilterDescriptor;

    PKSFILTERFACTORY                pKSFilterFactory;

} BDA_FILTER_FACTORY_CONTEXT, *PBDA_FILTER_FACTORY_CONTEXT;

typedef struct _BDA_FILTER_CONTEXT
{
    PKSFILTER                       pKSFilter;
    const BDA_FILTER_TEMPLATE *     pBdaFilterTemplate;

    //  Pins are added as they are created.
    //  Note!  If the filter has m pin factories included in the
    //  initial filter descriptor then the first m entries in this array
    //  will contain null pointers.
    //
    ULONG                           ulcPinFactories;
    ULONG                           ulcPinFactoriesMax;
    PBDA_PIN_FACTORY_CONTEXT        argPinFactoryCtx;

    //  One node path will exist for each pin pairing.
    //
    //$REVIEW - Should we allow more than one path per pin pair?
    //
    ULONG                           ulcPathInfo;
    PBDA_PATH_INFO *                argpPathInfo;

} BDA_FILTER_CONTEXT, *PBDA_FILTER_CONTEXT;


typedef struct _BDA_PIN_FACTORY_CONTEXT
{
    ULONG                   ulPinType;
    ULONG                   ulPinFactoryId;
} BDA_PIN_FACTORY_CONTEXT, *PBDA_PIN_FACTORY_CONTEXT;


typedef struct _BDA_NODE_CONTEXT
{

    ULONG       ulStartEmpty;

} BDA_NODE_CONTEXT, *PBDA_NODE_CONTEXT;


//---------------------------------------------------------------------------
//  BDA Topology Implementation Internal Functions
//
//      Minidriver code should not call these routines directly.
//
//---------------------------------------------------------------------------

/*
**  BdaFindPinPair()
**
**      Returns a pointer to the BDA_PIN_PAIRING that corresponds
**      to the given input and output pins.
**
**  Arguments:
**
**      pTopology   Pointer to the BDA topology that contains the
**                  pin pairing.
**
**      InputPinId  Id of the input Pin to match
**
**      OutputPinId Id of the output Pin to match
**
**  Returns:
**
**      pPinPairing     Pointer to a valid BDA Pin Pairing structure
**
**      NULL            If no valid pin pairing exists with the
**                      given input and output pins.
**
** Side Effects:  none
*/

PBDA_PIN_PAIRING
BdaFindPinPair(
    PBDA_FILTER_TEMPLATE    pFilterTemplate,
    ULONG                   InputPinId,
    ULONG                   OutputPinId
    );


/*
**  BdaGetPinFactoryContext()
**
**  Finds a BDA PinFactory Context that corresponds
**  to the given KS Pin Instance.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects:  none
*/

STDMETHODIMP_(NTSTATUS)
BdaGetPinFactoryContext(
    PKSPIN                          pKSPin,
    PBDA_PIN_FACTORY_CONTEXT        pPinFactoryCtx
    );


/*
**  BdaInitFilterFactoryContext()
**
**      Initializes a BDA Filter Factory Context based on the filter's
**      template descriptor.
**
**
**  Arguments:
**
**
**      pFilterFactoryCtx
**
**  Returns:
**
**      NULL            If no valid pin pairing exists with the
**                      given input and output pins.
**
** Side Effects:  none
*/

STDMETHODIMP_(NTSTATUS)
BdaInitFilterFactoryContext(
    PBDA_FILTER_FACTORY_CONTEXT pFilterFactoryCtx
    );


/*
**  BdaAddNodeAutomationToPin()
**
**      Merges the automation tables for each node type that is controlled
**      by the pin type being created into the automation table for the
**      the pin factory.  This is how the automation tables for BDA
**      control nodes get linked to the controlling pin.  Otherwise the
**      nodes would not be accesable.
**
**
**  Arguments:
**
**
**      pFilterCtx      The BDA filter context to which the pin factory
**                      belongs.  Must have this to get at the template
**                      topology.
**
**      ulPinType       BDA Pin Type of the pin being created.  Need this
**                      to figure out which nodes are controlled by the
**                      pin.
**
**  Returns:
**
**
** Side Effects:  none
*/

STDMETHODIMP_(NTSTATUS)
BdaAddNodeAutomationToPin( 
    PBDA_FILTER_CONTEXT         pFilterCtx, 
    ULONG                       ulControllingPinType,
    KSOBJECT_BAG                ObjectBag,
    const KSAUTOMATION_TABLE *  pOriginalAutomationTable,
    PKSAUTOMATION_TABLE *       ppNewAutomationTable
    );


/*
**  BdaCreateTemplatePaths()
**
**      Creates a list of all possible paths through the template filter.
**      Determines the controlling pin type for each node type in the
**      template filter.
**
**
**  Arguments:
**
**
**      pFilterFactoryCtx
**
**  Returns:
**
**      NULL            If no valid pin pairing exists with the
**                      given input and output pins.
**
** Side Effects:  none
*/

STDMETHODIMP_(NTSTATUS)
BdaCreateTemplatePaths(
    const BDA_FILTER_TEMPLATE *     pBdaFilterTemplate,
    PULONG                          pulcPathInfo,
    PBDA_PATH_INFO **               pargpPathInfo
    );


ULONG __inline
OutputBufferLenFromIrp(
    PIRP    pIrp
    )
{
    PIO_STACK_LOCATION pIrpStack;

    ASSERT( pIrp);
    if (!pIrp)
    {
        return 0;
    }

    pIrpStack = IoGetCurrentIrpStackLocation( pIrp);
    ASSERT( pIrpStack);
    if (pIrpStack)
    {
        return pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
    }
    else
    {
        return 0;
    }
}



//---------------------------------------------------------------------------
//  BDA Topology Const Data
//
//      Minidriver code should not use these fields directly
//
//---------------------------------------------------------------------------

extern const KSAUTOMATION_TABLE     BdaDefaultPinAutomation;
extern const KSAUTOMATION_TABLE     BdaDefaultFilterAutomation;


#if defined(__cplusplus)
}
#endif // defined(__cplusplus)