/*++

Copyright (C) Microsoft Corporation, 1999 - 2000  

Module Name:

    MSDVUppr.c

Abstract:

    Interface code with stream class driver.

Last changed by:
    
    Author:      Yee J. Wu

Environment:

    Kernel mode only

Revision History:

    $Revision::                    $
    $Date::                        $

--*/

#include "strmini.h"
#include "ksmedia.h"
#include "1394.h"
#include "61883.h"
#include "avc.h"
#include "dbg.h"
#include "msdvfmt.h"
#include "msdvdef.h"
#include "MsdvGuts.h"  // Function prototypes
#include "MsdvAvc.h"
#include "MsdvUtil.h"

#include "EDevCtrl.h"

#ifdef TIME_BOMB
#include "..\..\inc\timebomb.c"
#endif

// global flag for debugging.  Inlines are defined in dbg.h.  The debug level is set for
// minimal amount of messages.
#if DBG

#define DVTraceMaskCheckIn  TL_PNP_ERROR | TL_STRM_ERROR | TL_61883_ERROR

#define DVTraceMaskDefault  TL_PNP_ERROR   | TL_PNP_WARNING \
                          | TL_61883_ERROR | TL_61883_WARNING \
                          | TL_CIP_ERROR  \
                          | TL_FCP_ERROR  \
                          | TL_STRM_ERROR  | TL_STRM_WARNING \
                          | TL_CLK_ERROR

#define DVTraceMaskDebug  TL_PNP_ERROR  | TL_PNP_WARNING \
                          | TL_61883_ERROR| TL_61883_WARNING \
                          | TL_CIP_ERROR  \
                          | TL_FCP_ERROR  | TL_FCP_WARNING \
                          | TL_STRM_ERROR | TL_STRM_WARNING \
                          | TL_CLK_ERROR


#ifdef USE_WDM110   // Win2000 code base
ULONG  DVTraceMask    = DVTraceMaskCheckIn | TL_FCP_ERROR;
#else
ULONG  DVTraceMask    = DVTraceMaskCheckIn;
#endif

ULONG  DVAssertLevel  = 1;  // Turn on assert (>0)
ULONG  DVDebugXmt     = 0;  // Debug data transfer flag; (> 0) to turn it on.

#endif


extern DV_FORMAT_INFO        DVFormatInfoTable[];

//
// Function prototypes
//
VOID
DVRcvStreamDevicePacket(
    IN PHW_STREAM_REQUEST_BLOCK pSrb
    );
VOID
DVSRBRead(
    IN PKSSTREAM_HEADER pStrmHeader,
    IN ULONG            ulFrameSize,
    IN PDVCR_EXTENSION  pDevExt,
    IN PSTREAMEX        pStrmExt,
    IN PHW_STREAM_REQUEST_BLOCK pSrb        // needs Srb->Status 
    );
NTSTATUS
DVAttachWriteFrame(
    IN PSTREAMEX  pStrmExt
    );
NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    ); 

#if 0  // Enable later
#ifdef ALLOC_PRAGMA   
     #pragma alloc_text(PAGE, DVRcvStreamDevicePacket)
     #pragma alloc_text(PAGE, DVRcvControlPacket)
     #pragma alloc_text(PAGE, DVRcvDataPacket)
     // #pragma alloc_text(INIT, DriverEntry)
#endif
#endif


VOID
DVRcvStreamDevicePacket(
    IN PHW_STREAM_REQUEST_BLOCK pSrb
    )
/*++

Routine Description:

    This is where most of the interesting Stream requests come to us

--*/
{
    PDVCR_EXTENSION     pDevExt;  
    PAV_61883_REQUEST      pAVReq;
    PIO_STACK_LOCATION  pIrpStack;


    PAGED_CODE();


    //
    // Get these extensions from a SRB
    //
    pDevExt = (PDVCR_EXTENSION) pSrb->HwDeviceExtension; 
    pAVReq  = (PAV_61883_REQUEST) pSrb->SRBExtension;       // Use in IrpSync is OK, 
                             
#if DBG
    if(pSrb->Command != SRB_INITIALIZE_DEVICE && // PowerState is initialize in this SRB so ignore it.
       pDevExt->PowerState != PowerDeviceD0) {
        TRACE(TL_PNP_WARNING,("RcvDevPkt; pSrb:%x; Cmd:%x; Dev is OFF state\n", pSrb, pSrb->Command));
    }
#endif

    TRACE(TL_PNP_TRACE,("\'DVRcvStreamDevicePacket: pSrb %x, Cmd %d, pdevExt %x\n", pSrb, pSrb->Command, pDevExt));

    //
    // Assume success
    //
    pSrb->Status = STATUS_SUCCESS;

    switch (pSrb->Command) {

    case SRB_INITIALIZE_DEVICE:

        ASSERT(((PPORT_CONFIGURATION_INFORMATION) pSrb->CommandData.ConfigInfo)->HwDeviceExtension == pDevExt);
        pSrb->Status = 
            DVInitializeDevice(
                (PDVCR_EXTENSION) ((PPORT_CONFIGURATION_INFORMATION)pSrb->CommandData.ConfigInfo)->HwDeviceExtension,
                pSrb->CommandData.ConfigInfo,
                pAVReq
                );
        break;



    case SRB_INITIALIZATION_COMPLETE:

        //
        // Stream class has finished initialization.  Get device interface registry value/
        //
        DVInitializeCompleted(
            (PDVCR_EXTENSION) pSrb->HwDeviceExtension); 
        break;


    case SRB_GET_STREAM_INFO:

        //
        // this is a request for the driver to enumerate requested streams
        //
        pSrb->Status = 
            DVGetStreamInfo(
                pDevExt,
                pSrb->NumberOfBytesToTransfer,
                &pSrb->CommandData.StreamBuffer->StreamHeader,
                &pSrb->CommandData.StreamBuffer->StreamInfo
                );
        break;



    case SRB_GET_DATA_INTERSECTION:

        // Since format can dynamically change, we will query new format here.
        // Note: during data intersection, we compare FrameSize and that is 
        // format related.

        if((GetSystemTime() - pDevExt->tmLastFormatUpdate) > FORMAT_UPDATE_INTERVAL) {

            // Get mode of operation (Camera or VCR)
            DVGetDevModeOfOperation(pDevExt);

            if(!DVGetDevSignalFormat(pDevExt, KSPIN_DATAFLOW_OUT,0)) {
                // If querying its format has failed, we cannot open this stream.
                TRACE(TL_STRM_WARNING,("SRB_GET_DATA_INTERSECTION:Failed getting signal format.\n"));
            }
        
            // Update system time to reflect last update
            pDevExt->tmLastFormatUpdate = GetSystemTime();              
        }

        pSrb->Status = 
            DVGetDataIntersection(
                pSrb->CommandData.IntersectInfo->StreamNumber,
                pSrb->CommandData.IntersectInfo->DataRange,
                pSrb->CommandData.IntersectInfo->DataFormatBuffer,
                pSrb->CommandData.IntersectInfo->SizeOfDataFormatBuffer,
                DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize,
                &pSrb->ActualBytesTransferred,
                pDevExt->paCurrentStrmInfo
#ifdef SUPPORT_NEW_AVC            
                ,pDevExt->paCurrentStrmInfo[pSrb->CommandData.IntersectInfo->StreamNumber].DataFlow == KSPIN_DATAFLOW_OUT ? pDevExt->hOPcrDV : pDevExt->hIPcrDV
#endif
                );          
        break;



    case SRB_OPEN_STREAM:

        //
        // Serialize SRB_OPEN/CLOSE_STREAMs
        //
        KeWaitForSingleObject( &pDevExt->hMutex, Executive, KernelMode, FALSE, 0 );

        pSrb->Status = 
            DVOpenStream(
                pSrb->StreamObject,
                pSrb->CommandData.OpenFormat,
                pAVReq
                );

        KeReleaseMutex(&pDevExt->hMutex, FALSE);
        break;



    case SRB_CLOSE_STREAM:

        //
        // Serialize SRB_OPEN/CLOSE_STREAMs
        //
        KeWaitForSingleObject( &pDevExt->hMutex, Executive, KernelMode, FALSE, 0 );

        pSrb->Status = 
            DVCloseStream(
                pSrb->StreamObject,
                pSrb->CommandData.OpenFormat,
                pAVReq
                );
        KeReleaseMutex(&pDevExt->hMutex, FALSE);
        break;



    case SRB_GET_DEVICE_PROPERTY:

        pSrb->Status = 
            DVGetDeviceProperty(
                pDevExt,
                pSrb->CommandData.PropertyInfo,
                &pSrb->ActualBytesTransferred
                );
        break;

        
    case SRB_SET_DEVICE_PROPERTY:

        pSrb->Status = 
            DVSetDeviceProperty(
                pDevExt,
                pSrb->CommandData.PropertyInfo,
                &pSrb->ActualBytesTransferred
                );
        break;



    case SRB_CHANGE_POWER_STATE:
            
        pIrpStack = IoGetCurrentIrpStackLocation(pSrb->Irp);

        if(pIrpStack->MinorFunction == IRP_MN_SET_POWER) {
            pSrb->Status = 
                DVChangePower(
                    (PDVCR_EXTENSION) pSrb->HwDeviceExtension,
                    pAVReq,
                    pSrb->CommandData.DeviceState
                    );
        } else 
        if(pIrpStack->MinorFunction == IRP_MN_QUERY_POWER) {
            TRACE(TL_PNP_WARNING,("IRP_MN_QUERY_POWER: PwrSt:%d\n", pDevExt->PowerState)); 
            pSrb->Status = STATUS_SUCCESS;
        }
        else {
            TRACE(TL_PNP_WARNING,("NOT_IMPL POWER_STATE MinorFunc:%d\n", pIrpStack->MinorFunction)); 
            pSrb->Status = STATUS_NOT_IMPLEMENTED; 
        }

        break;


    case SRB_UNKNOWN_DEVICE_COMMAND:

        //
        // We might be interested in unknown commands if they pertain
        // to bus resets.  Bus resets are important cuz we need to know
        // what the current generation count is.
        //
        pIrpStack = IoGetCurrentIrpStackLocation(pSrb->Irp);

        if(pIrpStack->MajorFunction == IRP_MJ_PNP) {
            if(pIrpStack->MinorFunction == IRP_MN_BUS_RESET) {
            
                DVProcessPnPBusReset(
                    pDevExt
                    );
                
                //  Always success                
                pSrb->Status = STATUS_SUCCESS;
            }        
            else  {
                /* Known: IRP_MN_QUERY_PNP_DEVICE_STATE */
                TRACE(TL_PNP_WARNING,("\'DVRcvStreamDevicePacket: NOT_IMPL; IRP_MJ_PNP IRP_MN_:%x\n",
                    pIrpStack->MinorFunction
                    )); 
                // Canot return STATUS_NOT_SUPPORTED for PNP irp or device will not load.
                pSrb->Status = STATUS_NOT_IMPLEMENTED; 
            } 
        }
        else {
            TRACE(TL_PNP_WARNING,("\'DVRcvStreamDevicePacket: NOT_IMPL; IRP_MJ_ %x; IRP_MN_:%x\n",
                pIrpStack->MajorFunction,
                pIrpStack->MinorFunction
                ));
            // Canot return STATUS_NOT_SUPPORTED for PNP irp or device will not load.
            pSrb->Status = STATUS_NOT_IMPLEMENTED;
        }
        break;


    case SRB_SURPRISE_REMOVAL:

        TRACE(TL_PNP_WARNING,("\' #SURPRISE_REMOVAL# pSrb %x, pDevExt %x\n", pSrb, pDevExt));
        pSrb->Status = 
             DVSurpriseRemoval(
                 pDevExt,
                 pAVReq
                 );
        break;            


        
    case SRB_UNINITIALIZE_DEVICE:

        TRACE(TL_PNP_WARNING,("\' #UNINITIALIZE_DEVICE# pSrb %x, pDevExt %x\n", pSrb, pDevExt));                   
        pSrb->Status = 
            DVUninitializeDevice(
                (PDVCR_EXTENSION) pSrb->HwDeviceExtension
                );          
        break;           


    default:
            
        TRACE(TL_PNP_WARNING,("\'DVRcvStreamDevicePacket: Unknown or unprocessed SRB cmd 0x%x\n", pSrb->Command));

        //
        // this is a request that we do not understand.  Indicate invalid
        // command and complete the request
        //

        pSrb->Status = STATUS_NOT_IMPLEMENTED; // SUPPORTED;
    }

    //
    // NOTE:
    //
    // all of the commands that we do, or do not understand can all be completed
    // synchronously at this point, so we can use a common callback routine here.
    // If any of the above commands require asynchronous processing, this will
    // have to change
    //
#if DBG
    if (pSrb->Status != STATUS_SUCCESS && 
        pSrb->Status != STATUS_NOT_SUPPORTED &&
        pSrb->Status != STATUS_NOT_IMPLEMENTED &&
        pSrb->Status != STATUS_BUFFER_TOO_SMALL &&
        pSrb->Status != STATUS_BUFFER_OVERFLOW &&
        pSrb->Status != STATUS_NO_MATCH
        && pSrb->Status != STATUS_TIMEOUT
        ) {
        TRACE(TL_PNP_WARNING,("\'pSrb->Command (%x) ->Status:%x\n", pSrb->Command, pSrb->Status));
    }
#endif

    if(STATUS_PENDING != pSrb->Status) {

        StreamClassDeviceNotification(
            DeviceRequestComplete,
            pSrb->HwDeviceExtension,
           pSrb
           );
    } 
    else {

        // Pending pSrb which will be completed asynchronously
        // Does StreamClass allow device SRB to be in the pending state?
        TRACE(TL_PNP_WARNING,("\'DVReceiveDevicePacket:Pending pSrb %x\n", pSrb));
    }
}


VOID
DVRcvControlPacket(
    IN PHW_STREAM_REQUEST_BLOCK pSrb
    )
/*++

Routine Description:

    Called with packet commands that control the video stream

--*/
{
    PAV_61883_REQUEST   pAVReq;
    PSTREAMEX        pStrmExt;
    PDVCR_EXTENSION  pDevExt;


    PAGED_CODE();

    //
    // Get these three extension from SRB
    //
    pAVReq   = (PAV_61883_REQUEST) pSrb->SRBExtension;  // This is OK to be used us IrpSync operation
    pDevExt  = (PDVCR_EXTENSION) pSrb->HwDeviceExtension;
    pStrmExt = (PSTREAMEX) pSrb->StreamObject->HwStreamExtension;      // Only valid in SRB_OPEN/CLOSE_STREAM

    ASSERT(pStrmExt && pDevExt && pAVReq);

    //
    // Default to success
    //
    pSrb->Status = STATUS_SUCCESS;

    switch (pSrb->Command) {

    case SRB_GET_STREAM_STATE:

        pSrb->Status =
            DVGetStreamState( 
                pStrmExt,
                &(pSrb->CommandData.StreamState),
                &(pSrb->ActualBytesTransferred)
                );
        break;
            
    case SRB_SET_STREAM_STATE:
            
        pSrb->Status =
            DVSetStreamState(
                pStrmExt,
                pDevExt,
                pAVReq,
                pSrb->CommandData.StreamState   // Target KSSTATE
               );       
        break;

        
    case SRB_GET_STREAM_PROPERTY:

        pSrb->Status =
            DVGetStreamProperty( 
                pSrb 
                );
        break;


    case SRB_SET_STREAM_PROPERTY:

        pSrb->Status =        
            DVSetStreamProperty( 
                pSrb 
                );
        break;

    case SRB_OPEN_MASTER_CLOCK:
    case SRB_CLOSE_MASTER_CLOCK:

        //
        // This stream is being selected to provide a Master clock.
        //
        pSrb->Status =
            DVOpenCloseMasterClock(                 
                pStrmExt, 
                pSrb->Command == SRB_OPEN_MASTER_CLOCK ? pSrb->CommandData.MasterClockHandle: NULL);
        break;

    case SRB_INDICATE_MASTER_CLOCK:

        //
        // Assigns a clock to a stream.
        //
        pSrb->Status = 
            DVIndicateMasterClock(
                pStrmExt, 
                pSrb->CommandData.MasterClockHandle);
        break;

    case SRB_PROPOSE_DATA_FORMAT:
    
        //
        // The SRB_PROPOSE_DATA_FORMAT command queries the minidriver
        // to determine if the minidriver can change the format of a 
        // particular stream. If the minidriver is able to switch the 
        // stream to the specified format, STATUS_SUCCESS is returned. 
        // Note that this function only proposes a new format, but does
        // not change it. 
        //
        // The CommandData.OpenFormat passes the format to validate.
        // If the minidriver is able to accept the new format, at some 
        // later time the class driver may send the minidriver a format 
        // change, which is indicated by an OptionsFlags flag in a 
        // KSSTREAM_HEADER structure. 
        //
 
        TRACE(TL_STRM_INFO,("\'DVRcvControlPacket: SRB_PROPOSE_DATA_FORMAT\n"));
        if(!DVVerifyDataFormat(
            pSrb->CommandData.OpenFormat, 
            pSrb->StreamObject->StreamNumber,
            DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize,
            pDevExt->paCurrentStrmInfo
            ))  {
            TRACE(TL_STRM_WARNING,("\'DVRcvControlPacket: AdapterVerifyFormat failed.\n"));
            pSrb->Status = STATUS_NO_MATCH;
        }
        break;

    case SRB_PROPOSE_STREAM_RATE:
        pSrb->Status = STATUS_NOT_IMPLEMENTED; // if returned STATUS_NOT_SUPPORTED, it will send EOStream.
        TRACE(TL_STRM_TRACE,("\'SRB_PROPOSE_STREAM_RATE: NOT_IMPLEMENTED!\n"));
        break;
    case SRB_BEGIN_FLUSH:
        pSrb->Status = STATUS_NOT_SUPPORTED;
        TRACE(TL_STRM_TRACE,("\'SRB_BEGIN_FLUSH: NOT_SUPPORTED!\n"));
        break;
    case SRB_END_FLUSH:
        pSrb->Status = STATUS_NOT_SUPPORTED;
        TRACE(TL_STRM_TRACE,("\'SRB_END_FLUSH: NOT_SUPPORTED!\n"));
        break;
    default:

        //
        // invalid / unsupported command. Fail it as such
        //
        TRACE(TL_STRM_WARNING,("\'DVRcvControlPacket: unknown cmd = %x\n",pSrb->Command));
            pSrb->Status = STATUS_NOT_IMPLEMENTED; // SUPPORTED;
    }

    TRACE(TL_STRM_TRACE,("\'DVRcvControlPacket: Command %x, ->Status %x, ->CommandData %x\n",
         pSrb->Command, pSrb->Status, &(pSrb->CommandData.StreamState) ));

    StreamClassStreamNotification(          
        StreamRequestComplete,
        pSrb->StreamObject,
        pSrb);
}




VOID
DVRcvDataPacket(
    IN PHW_STREAM_REQUEST_BLOCK pSrb
    )

/*++

Routine Description:

    Called with video data packet commands

--*/

{
    PSTREAMEX       pStrmExt;
    PDVCR_EXTENSION pDevExt;

    
    PAGED_CODE();

    pStrmExt = (PSTREAMEX) pSrb->StreamObject->HwStreamExtension;  
    pDevExt  = (PDVCR_EXTENSION) pSrb->HwDeviceExtension;

#if DBG
    if(pDevExt->PowerState != PowerDeviceD0) {
        TRACE(TL_STRM_WARNING|TL_PNP_WARNING,("\'SRB_READ/WRITE; PowerSt:OFF; pSrb:%x\n", pSrb));
    }
#endif

    // The stream has to be open before we can do anything.
    if (pStrmExt == NULL) {
        TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("DVRcvDataPacket: stream not opened for SRB %x. kicking out...\n", pSrb->Command));
        pSrb->Status = STATUS_UNSUCCESSFUL;
        pSrb->CommandData.DataBufferArray->DataUsed = 0;
        StreamClassStreamNotification(StreamRequestComplete, pSrb->StreamObject, pSrb);
        return;        
    }


    //
    // Serialize attach, cancel and state change
    //
    KeWaitForSingleObject( pStrmExt->hStreamMutex, Executive, KernelMode, FALSE, 0 );


    TRACE(TL_CIP_TRACE,("\'XXX_DATA(%d, %d);Srb:%x;Flg:%x;FExt:%d:%d\n", 
        (DWORD) pStrmExt->cntSRBReceived, 
        (DWORD) pSrb->CommandData.DataBufferArray->PresentationTime.Time/10000,
        pSrb, 
        pSrb->CommandData.DataBufferArray->OptionsFlags,
        pSrb->CommandData.DataBufferArray->FrameExtent,
        DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize
        ));

    //
    // determine the type of packet.
    //
    pSrb->Status = STATUS_SUCCESS;

#if DBG
    pStrmExt->cntSRBPending++;
#endif

    switch (pSrb->Command) {

    case SRB_READ_DATA:

        // Rule: 
        // Only accept read requests when in either the Pause or Run
        // States.  If Stopped, immediately return the SRB.

        if (pStrmExt->lCancelStateWorkItem) {
            // TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("\'SRB_READ_DATA: Abort while getting SRB_READ_DATA!\n"));                        
            // ASSERT(pStrmExt->lCancelStateWorkItem == 0 && "Encounter SRB_READ_DATA while aborting or aborted.\n");
            pSrb->Status = (pDevExt->bDevRemoved ? STATUS_DEVICE_REMOVED : STATUS_CANCELLED);
            pSrb->CommandData.DataBufferArray->DataUsed = 0;
            break; 

        } else if( pStrmExt->StreamState == KSSTATE_STOP       ||
            pStrmExt->StreamState == KSSTATE_ACQUIRE    ||
            pStrmExt->hConnect == NULL                  ||    
            pDevExt->bDevRemoved 
            ) {
            TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("\'SRB_READ_DATA: (DV->) State %d, bDevRemoved %d\n", pStrmExt->StreamState, pDevExt->bDevRemoved));            
            pSrb->Status = (pDevExt->bDevRemoved ? STATUS_DEVICE_REMOVED : STATUS_CANCELLED);
            pSrb->CommandData.DataBufferArray->DataUsed = 0;

            break;
  
        } else {

            TRACE(TL_STRM_INFO|TL_CIP_INFO,("\'SRB_READ_DATA pSrb %x, pStrmExt %x\n", pSrb, pStrmExt));
            pStrmExt->cntSRBReceived++;

            // Set state thread in halt while while Read/Write SRB is being processed
            DVSRBRead(
                pSrb->CommandData.DataBufferArray,
                DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize,
                pDevExt,
                pStrmExt,
                pSrb
                );

            KeReleaseMutex(pStrmExt->hStreamMutex, FALSE); 
            
            // Note: This SRB will be completed asynchronously.

            return;
        }
            
        break;
            
    case SRB_WRITE_DATA:

        if( pStrmExt->StreamState == KSSTATE_STOP       ||
            pStrmExt->StreamState == KSSTATE_ACQUIRE    ||
#ifdef SUPPORT_NEW_AVC
            (pStrmExt->hConnect == NULL && !pStrmExt->bDV2DVConnect) ||
#else
            pStrmExt->hConnect == NULL                  ||
#endif
            pDevExt->bDevRemoved     
            ) {
            pSrb->Status = (pDevExt->bDevRemoved ? STATUS_DEVICE_REMOVED : STATUS_CANCELLED);
            pSrb->CommandData.DataBufferArray->DataUsed = 0;
            TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\'SRB_WRITE_DATA: (DV->) State %d, bDevRemoved %d; Status:%x\n", pStrmExt->StreamState, pDevExt->bDevRemoved, pSrb->Status));
            break;  // Complete SRB with error status
            
        } else {

            KIRQL  oldIrql;
            PLONG plSrbUseCount; // When this count is 0, it can be completed.

            TRACE(TL_STRM_INFO|TL_CIP_INFO,("\'SRB_WRITE_DATA pSrb %x, pStrmExt %x\n", pSrb, pStrmExt));

            //
            // Process EOSream frame separately
            //
            if(pSrb->CommandData.DataBufferArray->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_ENDOFSTREAM) {
                KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
                TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\'*** EOStream: ST:%d; bIsochIsActive:%d; Wait (cndAttached:%d+cndSRQ:%d) to complete......\n", \
                    pStrmExt->StreamState, pStrmExt->bIsochIsActive, pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued));        
                pStrmExt->bEOStream = TRUE;
                KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql); 
                pSrb->Status = STATUS_SUCCESS;
                break;

            } else if(pSrb->CommandData.DataBufferArray->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TYPECHANGED) {
                TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\'DVRcvDataPacket:KSSTREAM_HEADER_OPTIONSF_TYPECHANGED.\n"));
                pSrb->CommandData.DataBufferArray->DataUsed = 0;
                // May need to compare the data format; instead of return STATUS_SUCCESS??
                pSrb->Status = STATUS_SUCCESS; // May need to check the format when dynamic format change is allowed.
                break;  

#ifdef SUPPORT_NEW_AVC
            } else if(pStrmExt->bDV2DVConnect) {
                pSrb->Status = STATUS_SUCCESS;
                pSrb->CommandData.DataBufferArray->DataUsed = 0;
                TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\'SRB_WRITE_DATA: [DV2DV] (pStrmExt:%x), pSrb:%x, FrameExt:%d\n", 
                    pStrmExt, pSrb, pSrb->CommandData.DataBufferArray->FrameExtent));
                break;              
#endif                
            } else {

                PSRB_ENTRY  pSrbEntry;

                //
                // Validation
                //
                if(pSrb->CommandData.DataBufferArray->FrameExtent < DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize) {
                    TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("\' FrameExt %d < FrameSize %d\n", pSrb->CommandData.DataBufferArray->FrameExtent, DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize));
                    ASSERT(pSrb->CommandData.DataBufferArray->FrameExtent >= DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize);
                    pSrb->Status = STATUS_INVALID_PARAMETER;  
                    break;  // Complete SRB with error status                 
                }

                //
                // Dynamically allocate a SRB_ENTRY and append it to SRBQueue
                //
                if(!(pSrbEntry = ExAllocatePool(NonPagedPool, sizeof(SRB_ENTRY)))) {
                    pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
                    pSrb->CommandData.DataBufferArray->DataUsed = 0;
                    break;  // Complete SRB with error status
                }

#if DBG
                if(pStrmExt->bEOStream) {
                    TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\'SRB_WRITE_DATA: pSrb:%x after EOStream!\n", pSrb));
                }
#endif

                //
                // For statistics
                //
                pStrmExt->cntSRBReceived++;

                //
                // Save SRB and add it to SRB queue
                // No need for spin lock since StreamClass will serialize it for us.
                //
                pSrb->Status = STATUS_PENDING;
                pSrbEntry->pSrb = pSrb; pSrbEntry->bStale = FALSE; pSrbEntry->bAudioMute  = FALSE;
#if DBG
                pSrbEntry->SrbNum = (ULONG) pStrmExt->cntSRBReceived -1;
#endif
                //
                // Note: plSrbUseCount is initialize to 1
                // When it is insert: ++
                // When it is removed: --
                // when this count is 0; it can be completed.
                //
                plSrbUseCount = (PLONG) pSrb->SRBExtension; *plSrbUseCount = 1;  // Can be completed if this is 0

                KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql); 
                InsertTailList(&pStrmExt->SRBQueuedListHead, &pSrbEntry->ListEntry); pStrmExt->cntSRBQueued++;
                TRACE(TL_CIP_INFO,("\'%d) Fresh Srb:%x; RefCnt:%d; cntSrbQ:%d\n", (DWORD) pStrmExt->cntSRBReceived, pSrb, *plSrbUseCount, pStrmExt->cntSRBQueued));
                KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);


#ifdef SUPPORT_PREROLL_AT_RUN_STATE
                // We can operate "smoothly" if we hace N number of media sample.
                if(pStrmExt->cntSRBReceived == NUM_BUFFER_BEFORE_TRANSMIT_BEGIN) {
                    KeSetEvent(&pStrmExt->hPreRollEvent, 0, FALSE);
                }
#endif
                if(pStrmExt->pAttachFrameThreadObject) {
                    // Signal that a new frame has arrived.
                    KeSetEvent(&pStrmExt->hSrbArriveEvent, 0, FALSE);
                }
                else {
                    TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("\'No thread to attach frame ?\n"));
                }
            }            

            KeReleaseMutex(pStrmExt->hStreamMutex, FALSE); 

            return;  // Note: This SRB will be completed asynchronously.
        }

        break;  // Complete SRB with error status 

    default:
        //
        // invalid / unsupported command. Fail it as such
        //
        pSrb->Status = STATUS_NOT_SUPPORTED;
        break;
    }   

    KeReleaseMutex(pStrmExt->hStreamMutex, FALSE); 


    ASSERT(pSrb->Status != STATUS_PENDING);

    // Finally, send the srb back up ...
    StreamClassStreamNotification( 
        StreamRequestComplete,
        pSrb->StreamObject,
        pSrb );
#if DBG
    pStrmExt->cntSRBPending--;
#endif
}

NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    )

/*++

Routine Description:

    This where life begins for a driver.  The stream class takes care
    of alot of stuff for us, but we still need to fill in an initialization
    structure for the stream class and call it.

Arguments:

    Context1 - DriverObject
    Context2 - RegistryPath

Return Value:

    The function value is the final status from the initialization operation.

--*/
{

    HW_INITIALIZATION_DATA HwInitData;


    TRACE(TL_PNP_ERROR,("<<<<<<< MSDV.sys: %s; %s; %x %x >>>>>>>>\n", 
        __DATE__, __TIME__, DriverObject, RegistryPath));

#ifdef TIME_BOMB
    if (HasEvaluationTimeExpired()) {
        TRACE(TL_PNP_ERROR, ("Evaluation period expired!") );
        return STATUS_EVALUATION_EXPIRATION;
    }
#endif

    TRACE(TL_PNP_ERROR,("===================================================================\n"));
    TRACE(TL_PNP_ERROR,("DVTraceMask=0x%.8x = 0x[7][6][5][4][3][2][1][0] where\n", DVTraceMask));
    TRACE(TL_PNP_ERROR,("\n"));
    TRACE(TL_PNP_ERROR,("PNP:   [0]:Loading, power state, surprise removal, device SRB..etc.\n"));
    TRACE(TL_PNP_ERROR,("61883: [1]:Plugs, connection, CMP info and call to 61883.\n"));
    TRACE(TL_PNP_ERROR,("CIP:   [2]:Isoch data transfer.\n"));
    TRACE(TL_PNP_ERROR,("AVC:   [3]:AVC commands.\n"));
    TRACE(TL_PNP_ERROR,("Stream:[4]:Data intersec, open/close,.state, property etc.\n"));
    TRACE(TL_PNP_ERROR,("Clock: [5]:Clock (event and signal)etc.\n"));
    TRACE(TL_PNP_ERROR,("===================================================================\n"));
    TRACE(TL_PNP_ERROR,("dd msdv!DVTraceMask L1\n"));
    TRACE(TL_PNP_ERROR,("e msdv!DVTraceMask <new value> <enter>\n"));
    TRACE(TL_PNP_ERROR,("<for each nibble: ERROR:8, WARNING:4, TRACE:2, INFO:1, MASK:f>\n"));
    TRACE(TL_PNP_ERROR,("===================================================================\n\n"));


    //
    // Fill in the HwInitData structure    
    //
    RtlZeroMemory( &HwInitData, sizeof(HW_INITIALIZATION_DATA) );

    HwInitData.HwInitializationDataSize = sizeof(HwInitData);
    HwInitData.HwInterrupt              = NULL;

    HwInitData.HwReceivePacket          = DVRcvStreamDevicePacket;
    HwInitData.HwRequestTimeoutHandler  = DVTimeoutHandler; 
    HwInitData.HwCancelPacket           = DVCancelOnePacket;
    HwInitData.DeviceExtensionSize      = sizeof(DVCR_EXTENSION);   // Per device

    //
    // The ULONG is used in SRB_WRITE_DATA to keep track of 
    // number of times the same SRB was attached for transmit.
    // 
    // Data SRB: ULONG is used (< sizeof(AV_61883_REQ)
    // DeviceControl or StreamControl Srb: AV_61883_REQ is used.
    HwInitData.PerRequestExtensionSize  = sizeof(AV_61883_REQUEST);    // Per SRB
    HwInitData.PerStreamExtensionSize   = sizeof(STREAMEX);         // Per pin/stream
    HwInitData.FilterInstanceExtensionSize = 0;

    HwInitData.BusMasterDMA             = FALSE;
    HwInitData.Dma24BitAddresses        = FALSE;
    HwInitData.BufferAlignment          = sizeof(ULONG) - 1;
    HwInitData.TurnOffSynchronization   = TRUE;
    HwInitData.DmaBufferSize            = 0;

    return StreamClassRegisterAdapter(DriverObject, RegistryPath, &HwInitData); 
}