/*++

Copyright (c) Microsoft.  All rights reserved.

Module Name:

    shmisc.cpp

Abstract:

    This module contains miscellaneous functions for the kernel streaming
    filter shell.







--*/

#include "private.h"
#include "ksshellp.h"
#include <kcom.h>

#pragma code_seg("PAGE")


void
KspShellStandardConnect(
    IN PIKSSHELLTRANSPORT NewTransport OPTIONAL,
    OUT PIKSSHELLTRANSPORT *OldTransport OPTIONAL,
    IN KSPIN_DATAFLOW DataFlow,
    IN PIKSSHELLTRANSPORT ThisTransport,
    IN PIKSSHELLTRANSPORT* SourceTransport,
    IN PIKSSHELLTRANSPORT* SinkTransport
    )

/*++

Routine Description:

    This routine establishes a transport connection.

Arguments:

Return Value:

--*/

{
    _DbgPrintF(DEBUGLVL_BLAB,("KspShellStandardConnect"));

    PAGED_CODE();

    ASSERT(ThisTransport);
    ASSERT(SourceTransport);
    ASSERT(SinkTransport);

    //
    // Make sure this object sticks around until we are done.
    //
    ThisTransport->AddRef();

    PIKSSHELLTRANSPORT* transport =
        (DataFlow & KSPIN_DATAFLOW_IN) ?
        SourceTransport :
        SinkTransport;

    //
    // Release the current source/sink.
    //
    if (*transport) {
        //
        // First disconnect the old back link.  If we are connecting a back
        // link for a new connection, we need to do this too.  If we are
        // clearing a back link (disconnecting), this request came from the
        // component we're connected to, so we don't bounce back again.
        //
        switch (DataFlow) {
        case KSPIN_DATAFLOW_IN:
            (*transport)->Connect(NULL,NULL,KSPSHELL_BACKCONNECT_OUT);
            break;

        case KSPIN_DATAFLOW_OUT:
            (*transport)->Connect(NULL,NULL,KSPSHELL_BACKCONNECT_IN);
            break;




#pragma warning(suppress: 4063)
        case KSPSHELL_BACKCONNECT_IN:
            if (NewTransport) {
                (*transport)->Connect(NULL,NULL,KSPSHELL_BACKCONNECT_OUT);
            }
            break;

#pragma warning(suppress: 4063)
        case KSPSHELL_BACKCONNECT_OUT:
            if (NewTransport) {
                (*transport)->Connect(NULL,NULL,KSPSHELL_BACKCONNECT_IN);
            }
            break;
        }

        //
        // Now release the old neighbor or hand it off to the caller.
        //
        if (OldTransport) {
            *OldTransport = *transport;
        } else {
            (*transport)->Release();
        }
    } else if (OldTransport) {
        *OldTransport = NULL;
    }

    //
    // Copy the new source/sink.
    //
    *transport = NewTransport;

    if (NewTransport) {
        //
        // Add a reference if necessary.
        //
        NewTransport->AddRef();

        //
        // Do the back connect if necessary.
        //
        switch (DataFlow) {
        case KSPIN_DATAFLOW_IN:
            NewTransport->Connect(ThisTransport,NULL,KSPSHELL_BACKCONNECT_OUT);
            break;

        case KSPIN_DATAFLOW_OUT:
            NewTransport->Connect(ThisTransport,NULL,KSPSHELL_BACKCONNECT_IN);
            break;
        }
    }

    //
    // Now this object may die if it has no references.
    //
    ThisTransport->Release();
}

#pragma code_seg()


NTSTATUS
KspShellTransferKsIrp(
    IN PIKSSHELLTRANSPORT NewTransport,
    IN PIRP Irp
    )

/*++

Routine Description:

    This routine transfers a streaming IRP using the kernel streaming shell
    transport.

Arguments:

Return Value:

--*/

{
    _DbgPrintF(DEBUGLVL_BLAB,("KspShellTransferKsIrp"));

    ASSERT(NewTransport);
    ASSERT(Irp);

    NTSTATUS status = STATUS_UNSUCCESSFUL;
    while (NewTransport) {
        PIKSSHELLTRANSPORT nextTransport;
        status = NewTransport->TransferKsIrp(Irp,&nextTransport);

        ASSERT(NT_SUCCESS(status) || ! nextTransport);

        NewTransport = nextTransport;
    }

    return status;
}

#pragma code_seg("PAGE")

#if DBG

void
DbgPrintCircuit(
    IN PIKSSHELLTRANSPORT Transport
    )

/*++

Routine Description:

    This routine spews a transport circuit.

Arguments:

Return Value:

--*/

{
    _DbgPrintF(DEBUGLVL_BLAB,("DbgPrintCircuit"));

    PAGED_CODE();

    ASSERT(Transport);

#define MAX_NAME_SIZE 64

    PIKSSHELLTRANSPORT transport = Transport;
    while (transport) {
        CHAR name[MAX_NAME_SIZE + 1];
        PIKSSHELLTRANSPORT next;
        PIKSSHELLTRANSPORT prev;

        transport->DbgRollCall(MAX_NAME_SIZE,name,&next,&prev);
        DbgPrint("  %s",name);

        if (prev) {
            PIKSSHELLTRANSPORT next2;
            PIKSSHELLTRANSPORT prev2;
            prev->DbgRollCall(MAX_NAME_SIZE,name,&next2,&prev2);
            if (next2 != transport) {
                DbgPrint(" SOURCE'S(0x%08x) SINK(0x%08x) != THIS(%08x)",prev,next2,transport);
            }
        } else {
            DbgPrint(" NO SOURCE");
        }

        if (next) {
            PIKSSHELLTRANSPORT next2;
            PIKSSHELLTRANSPORT prev2;
            next->DbgRollCall(MAX_NAME_SIZE,name,&next2,&prev2);
            if (prev2 != transport) {
                DbgPrint(" SINK'S(0x%08x) SOURCE(0x%08x) != THIS(%08x)",next,prev2,transport);
            }
        } else {
            DbgPrint(" NO SINK");
        }

        DbgPrint("\n");

        transport = next;
        if (transport == Transport) {
            break;
        }
    }
}
#endif
