/*++

Copyright (C) Microsoft Corporation, 1999 - 2000  

Module Name:

    MSDVGuts.c

Abstract:

    Main service functions.

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 "ksguid.h"

#include "msdvfmt.h"  // Before msdvdefs.h
#include "msdvdef.h"

#include "MSDVGuts.h"
#include "MsdvUtil.h"
#include "MsdvAvc.h"

#include "XPrtDefs.h"
#include "EDevCtrl.h"

//
// Define formats supported
//
#include "avcstrm.h"
#include "strmdata.h"

#if DBG
extern ULONG DVDebugXmt;        // this is defined in msdvuppr.c
#endif

NTSTATUS
DVGetDevInfo(
    IN PDVCR_EXTENSION  pDevExt,
    IN PAV_61883_REQUEST  pAVReq
    );
VOID 
DVIniStrmExt(
    PHW_STREAM_OBJECT  pStrmObject,
    PSTREAMEX          pStrmExt,
    PDVCR_EXTENSION    pDevExt,
    const PALL_STREAM_INFO   pStream
    );
NTSTATUS 
DVStreamGetConnectionProperty (
    PDVCR_EXTENSION pDevExt,
    PSTREAMEX          pStrmExt,
    PSTREAM_PROPERTY_DESCRIPTOR pSPD,
    PULONG pulActualBytesTransferred
    );
NTSTATUS
DVGetDroppedFramesProperty(  
    PDVCR_EXTENSION pDevExt,
    PSTREAMEX       pStrmExt,
    PSTREAM_PROPERTY_DESCRIPTOR pSPD,
    PULONG pulBytesTransferred
    );

#if 0  // Enable later
#ifdef ALLOC_PRAGMA   
     #pragma alloc_text(PAGE, DVGetDevInfo)
     #pragma alloc_text(PAGE, DVInitializeDevice)
     #pragma alloc_text(PAGE, DVGetStreamInfo)
     #pragma alloc_text(PAGE, DVVerifyDataFormat)
     #pragma alloc_text(PAGE, DVGetDataIntersection)
     #pragma alloc_text(PAGE, DVIniStrmExt)
     #pragma alloc_text(PAGE, DVOpenStream)
     #pragma alloc_text(PAGE, DVCloseStream)
     #pragma alloc_text(PAGE, DVChangePower)
     #pragma alloc_text(PAGE, DVSurpriseRemoval)
     #pragma alloc_text(PAGE, DVProcessPnPBusReset)
     #pragma alloc_text(PAGE, DVUninitializeDevice)
     #pragma alloc_text(PAGE, DVGetStreamState)
     #pragma alloc_text(PAGE, DVStreamingStop)
     #pragma alloc_text(PAGE, DVStreamingStart)
     #pragma alloc_text(PAGE, DVSetStreamState)
     #pragma alloc_text(PAGE, DVStreamGetConnectionProperty)
     #pragma alloc_text(PAGE, DVGetDroppedFramesProperty)
     #pragma alloc_text(PAGE, DVGetStreamProperty)
     #pragma alloc_text(PAGE, DVSetStreamProperty)
     #pragma alloc_text(PAGE, DVCancelAllPackets)
     #pragma alloc_text(PAGE, DVOpenCloseMasterClock)
     #pragma alloc_text(PAGE, DVIndicateMasterClock)
#endif
#endif

DV_FORMAT_INFO DVFormatInfoTable[] = {

//
// SD DVCR
//
    { 
        {
            FMT_DVCR,
            FDF0_50_60_NTSC,
            0,
            0
        },
        DIF_SEQS_PER_NTSC_FRAME,
        DV_NUM_OF_RCV_BUFFERS,
        DV_NUM_OF_XMT_BUFFERS,
        FRAME_SIZE_SD_DVCR_NTSC,
        FRAME_TIME_NTSC,
        SRC_PACKETS_PER_NTSC_FRAME,
        MAX_SRC_PACKETS_PER_NTSC_FRAME,
        CIP_DBS_SD_DVCR,
        CIP_FN_SD_DVCR,
        0,
        FALSE,                    // Source packet header
    },
    {
        {
            FMT_DVCR,
            FDF0_50_60_PAL,
            0,
            0
        },
        DIF_SEQS_PER_PAL_FRAME,
        DV_NUM_OF_RCV_BUFFERS,
        DV_NUM_OF_XMT_BUFFERS,
        FRAME_SIZE_SD_DVCR_PAL,
        FRAME_TIME_PAL,
        SRC_PACKETS_PER_PAL_FRAME,
        MAX_SRC_PACKETS_PER_PAL_FRAME,
        CIP_DBS_SD_DVCR,
        CIP_FN_SD_DVCR,
        0,
        FALSE,                   // Source packet header
    },

#ifdef SUPPORT_HD_DVCR

//
// HD DVCR
//
    { 
        {
            FMT_DVCR,
            FDF0_50_60_NTSC,
            0,
            0
        },
        DIF_SEQS_PER_NTSC_FRAME_HD, 
        DV_NUM_OF_RCV_BUFFERS,
        DV_NUM_OF_XMT_BUFFERS,            
        FRAME_SIZE_HD_DVCR_NTSC,
        FRAME_TIME_NTSC,
        SRC_PACKETS_PER_NTSC_FRAME,
        MAX_SRC_PACKETS_PER_NTSC_FRAME,
        CIP_DBS_HD_DVCR,
        CIP_FN_HD_DVCR,
        0,
        FALSE,    // Source packet header
    },
    {
        {
            FMT_DVCR,
            FDF0_50_60_PAL,
            0,
            0
        },
        DIF_SEQS_PER_PAL_FRAME_HD,
        DV_NUM_OF_RCV_BUFFERS,
        DV_NUM_OF_XMT_BUFFERS,
        FRAME_SIZE_HD_DVCR_PAL,
        FRAME_TIME_PAL,
        SRC_PACKETS_PER_PAL_FRAME,
        MAX_SRC_PACKETS_PER_PAL_FRAME,
        CIP_DBS_HD_DVCR,
        CIP_FN_HD_DVCR,
        0,
        FALSE,    // Source packet header
    },
#endif

#ifdef MSDV_SUPPORT_SDL_DVCR
//
// SDL DVCR
//
    { 
        {
            FMT_DVCR,
            FDF0_50_60_NTSC,
            0,
            0
        },
        DIF_SEQS_PER_NTSC_FRAME_SDL,  
        DV_NUM_OF_RCV_BUFFERS,
        DV_NUM_OF_XMT_BUFFERS,            
        FRAME_SIZE_SDL_DVCR_NTSC,
        FRAME_TIME_NTSC,
        SRC_PACKETS_PER_NTSC_FRAME,
        MAX_SRC_PACKETS_PER_NTSC_FRAME,
        CIP_DBS_SDL_DVCR,
        CIP_FN_SDL_DVCR,
        0,
        FALSE,    // Source packet header
    },
    {
        {
            FMT_DVCR,
            FDF0_50_60_PAL,
            0,
            0
        },
        DIF_SEQS_PER_PAL_FRAME_SDL,
        DV_NUM_OF_RCV_BUFFERS,
        DV_NUM_OF_XMT_BUFFERS,
        FRAME_SIZE_SDL_DVCR_PAL,
        FRAME_TIME_PAL,
        SRC_PACKETS_PER_PAL_FRAME,
        MAX_SRC_PACKETS_PER_PAL_FRAME,
        CIP_DBS_SDL_DVCR,
        CIP_FN_SDL_DVCR,
        0,
        FALSE,    // Source packet header
    },

#endif  // Not implemented.
};


#define MSDV_FORMATS_SUPPORTED        (SIZEOF_ARRAY(DVFormatInfoTable))




VOID
DVTerminateAttachFrameThread(
    IN PSTREAMEX  pStrmExt
    );

VOID
DVIniDevExtStruct(
    IN PDVCR_EXTENSION  pDevExt,
    IN PPORT_CONFIGURATION_INFORMATION pConfigInfo    
    )
/*++

Routine Description:

    Initialiaze the device extension structure.

--*/
{
    ULONG            i;


    RtlZeroMemory( pDevExt, sizeof(DVCR_EXTENSION) );

    //
    // Cache what are in ConfigInfo in device extension
    //
    pDevExt->pBusDeviceObject      = pConfigInfo->PhysicalDeviceObject;      // IoCallDriver()
    pDevExt->pPhysicalDeviceObject = pConfigInfo->RealPhysicalDeviceObject;  // Used in PnP API

    //
    // Allow only one stream open at a time to avoid cyclic format
    //
    pDevExt->cndStrmOpen = 0;

    //
    // Serialize in the event of getting two consecutive SRB_OPEN_STREAMs
    //
    KeInitializeMutex( &pDevExt->hMutex, 0);  // Level 0 and in Signal state

    //
    // Initialize our pointer to stream extension
    //
    for (i=0; i<DV_STREAM_COUNT; i++) {
        pDevExt->paStrmExt[i] = NULL;  
    }

    //
    // Bus reset, surprise removal 
    //
    pDevExt->bDevRemoved = FALSE;

    pDevExt->PowerState = PowerDeviceD0;
    
    //
    // External device control (AV/C commands)
    // 
    KeInitializeSpinLock( &pDevExt->AVCCmdLock );  // To guard the count  

    pDevExt->cntCommandQueued   = 0; // Cmd that is completed its life cycle waiting to be read (most for RAW_AVC's Set/Read model)

    InitializeListHead(&pDevExt->AVCCmdList);      

    // Initialize the list of possible opcode values of the response
    // from a Transport State status or notify command. The first item
    // is the number of values that follow.
    ASSERT(sizeof(pDevExt->TransportModes) == 5);
    pDevExt->TransportModes[0] = 4;
    pDevExt->TransportModes[1] = 0xC1;
    pDevExt->TransportModes[2] = 0xC2;
    pDevExt->TransportModes[3] = 0xC3;
    pDevExt->TransportModes[4] = 0xC4;

#ifdef SUPPORT_OPTIMIZE_AVCCMD_RETRIES
    // Set to default values used by avc.sys
    pDevExt->AVCCmdRetries = DEFAULT_AVC_RETRIES;

    pDevExt->DrvLoadCompleted  = FALSE;
    pDevExt->AVCCmdRespTimeMax = 0;
    pDevExt->AVCCmdRespTimeMin = DEFAULT_AVC_TIMEOUT * (DEFAULT_AVC_RETRIES+1) / 10000;
    pDevExt->AVCCmdRespTimeSum = 0;
    pDevExt->AVCCmdCount       = 0;
#endif

    // AVC Command flow control
    KeInitializeMutex(&pDevExt->hMutexIssueAVCCmd, 0);
}


NTSTATUS
DVGetDevInfo(
    IN PDVCR_EXTENSION  pDevExt,
    IN PAV_61883_REQUEST  pAVReq
    )
/*++

Routine Description:

    Issue AVC command to determine basic device information and cache them in the device extension.

--*/
{
    NTSTATUS    Status;
    BYTE                   bAvcBuf[MAX_FCP_PAYLOAD_SIZE];  // For issue AV/C command within this module
    PKSPROPERTY_EXTXPORT_S pXPrtProperty;                  // Point to bAvcBuf;

    PAGED_CODE();

    //
    // Get unit's capabilities such as 
    //     Number of input/output plugs, data rate
    //     UniqueID, VendorID and ModelID
    //

    if(!NT_SUCCESS(
        Status = DVGetUnitCapabilities(
            pDevExt
            ))) {
         TRACE(TL_PNP_ERROR,("Av61883_GetUnitCapabilities Failed = 0x%x\n", Status));
         return Status;
    }

#ifdef NT51_61883
    //
    // Set to create local plug in exclusive address mode:  
    //      This is needed for device that does not support CCM, such as DV.
    //
    // PBinder:  the problem is that you cannot expose a global plug (all nodes on the bus can see it), 
    // since they have no knowledge of what that plug is used for (mpeg2/dv/audio/etc). 
    // so instead, you must create a plug in an exclusive address range. this means that only the device 
    // that you loaded for will see the plug. this means that if you had two pc's and a dv camcorder, 
    // on both pc's, you'll have a plug you created for the dv camcorder, but the pc's will not be able 
    // to see the plug you created, only the dv camcorder.  Keep in mind, this should only be used for 
    // devices that do not support some mechanism of determining what plug to use (such as ccm). 
    // so for any device that just goes out and uses plug #0, this must be enabled.
    //

    if(!NT_SUCCESS(
        Status = DVSetAddressRangeExclusive( 
            pDevExt
            ))) {        
        return Status;
    }
#endif  // NT51_61883

    //
    // Get DV's oPCR[0]
    //
    if(pDevExt->NumOutputPlugs) {
        if(!NT_SUCCESS(
            Status = DVGetDVPlug( 
                pDevExt,
                CMP_PlugOut,
                0,           // Plug [0]
                &pDevExt->hOPcrDV
                ))) {        
            return Status;
        }
    } 
    else {

        pDevExt->hOPcrDV = NULL;  // Redundant since we Zero the whole DeviceExtension


        TRACE(TL_PNP_ERROR,("\'No output plug!\n"));
        // 
        // This is bad!  We cannot even stream from this DV device.
        //
    }

    //
    // Get DV's iPCR
    //
    if(pDevExt->NumInputPlugs) {
        if(!NT_SUCCESS(
            Status = DVGetDVPlug( 
                pDevExt,
                CMP_PlugIn,
                0,           // Plug [0]
                &pDevExt->hIPcrDV
                ))) {        
            return Status;
        }
    }
    else {

        pDevExt->hIPcrDV = NULL;  // Redundant since we Zero the whole DeviceExtension

        TRACE(TL_PNP_ERROR,("\'No input plug!\n"));
        // 
        // Some PAL camcorder has no DVIN plug; we will refuse to make PC->DV connection.
        //
    }

#if 0  // Device control can still work!
    // 
    // Need plug to stream DV (either direction)
    //
    if(   pDevExt->hOPcrDV == NULL
       && pDevExt->hIPcrDV == NULL) {

        TRACE(TL_PNP_ERROR,("\'No input or output plug; return STATUS_INSUFFICIENT_RESOURCES!\n"));
        // 
        // Cannot stream
        //
        return = STATUS_INSUFFICIENT_RESOUCES;
    }
#endif


    // 
    // Subunit_Info : VCR or camera
    //

    DVDelayExecutionThread(DV_AVC_CMD_DELAY_INTER_CMD);
    Status = 
        DVIssueAVCCommand(
            pDevExt, 
            AVC_CTYPE_STATUS, 
            DV_SUBUNIT_INFO, 
            (PVOID) bAvcBuf
            );

    if(STATUS_SUCCESS == Status) {
        TRACE(TL_PNP_WARNING|TL_FCP_WARNING,("\'DVGetDevInfo: Status %x DV_SUBUNIT_INFO (%x %x %x %x)\n", 
            Status, bAvcBuf[0], bAvcBuf[1], bAvcBuf[2], bAvcBuf[3]));

        // Support DV (Camera+DVCR), DVCR, or analog-DV converter
        if(   bAvcBuf[0] != AVC_DEVICE_TAPE_REC 
           && bAvcBuf[1] != AVC_DEVICE_TAPE_REC
           && bAvcBuf[2] != AVC_DEVICE_TAPE_REC
           && bAvcBuf[3] != AVC_DEVICE_TAPE_REC)
        {
            TRACE(TL_PNP_ERROR,("DVGetDevInfo:Device supported: %x, %x; (VCR %x, Camera %x)\n",
                bAvcBuf[0], bAvcBuf[1], AVC_DEVICE_TAPE_REC, AVC_DEVICE_CAMERA));
            
            return STATUS_NOT_SUPPORTED;  // We only support unit with a tape subunit
        }
        else {
            // DVCR..
        }
    } else {
        TRACE(TL_PNP_ERROR,("DVGetDevInfo: DV_SUBUNIT_INFO failed, Status %x\n", Status));
        //
        // Cannot open this device if it does not support manadatory AVC SUBUnit status command.
        // However, we are making an exception for the DV converter box (will return TIMEOUT).
        //

        // Has our device gone away?
        if (   STATUS_IO_DEVICE_ERROR == Status 
            || STATUS_REQUEST_ABORTED == Status)
            return Status;       
    }


    //
    // Medium_Info: MediaPresent, MediaType, RecordInhibit
    //
    pXPrtProperty = (PKSPROPERTY_EXTXPORT_S) bAvcBuf;
    DVDelayExecutionThread(DV_AVC_CMD_DELAY_INTER_CMD);
    Status = 
        DVIssueAVCCommand(
            pDevExt, 
            AVC_CTYPE_STATUS, 
            VCR_MEDIUM_INFO, 
            (PVOID) pXPrtProperty
            );

    if(STATUS_SUCCESS == Status) {
        pDevExt->bHasTape = pXPrtProperty->u.MediumInfo.MediaPresent;
        TRACE(TL_PNP_WARNING|TL_FCP_WARNING,("\'DVGetDevInfo: Status %x HasTape %s, VCR_MEDIUM_INFO (%x %x %x %x)\n", 
            Status, pDevExt->bHasTape ? "Yes" : "No", bAvcBuf[0], bAvcBuf[1], bAvcBuf[2], bAvcBuf[3]));
    } else {
        pDevExt->bHasTape = FALSE;
        TRACE(TL_PNP_ERROR,("DVGetDevInfo: VCR_MEDIUM_INFO failed, Status %x\n", Status));

        // Has our device gone away?
        if (   STATUS_IO_DEVICE_ERROR == Status
            || STATUS_REQUEST_ABORTED == Status)
            return Status;
    }


    //
    // If this is a Panasonic AVC device, we will detect if it is a DVCPro format; 
    // This needs to be called before MediaFormat
    //
    if(pDevExt->ulVendorID == VENDORID_PANASONIC) {
        DVDelayExecutionThread(DV_AVC_CMD_DELAY_INTER_CMD);
        DVGetDevIsItDVCPro(
            pDevExt
            );
    }


    //
    // Medium format: NTSC or PAL
    //
    pDevExt->VideoFormatIndex = FMT_IDX_SD_DVCR_NTSC;  // Default
    DVDelayExecutionThread(DV_AVC_CMD_DELAY_INTER_CMD);
    if(!DVGetDevSignalFormat(
        pDevExt,
        KSPIN_DATAFLOW_OUT,
        0)) {
        TRACE(TL_PNP_ERROR,("\'!!! Cannot determine IN/OUTPUT SIGNAL MODE!!!! Driver abort !!!\n"));
        return STATUS_UNSUCCESSFUL; // STATUS_NOT_SUPPORTED;
    } else {
        if(   pDevExt->VideoFormatIndex != FMT_IDX_SD_DVCR_NTSC 
           && pDevExt->VideoFormatIndex != FMT_IDX_SD_DVCR_PAL
           && pDevExt->VideoFormatIndex != FMT_IDX_SDL_DVCR_NTSC
           && pDevExt->VideoFormatIndex != FMT_IDX_SDL_DVCR_PAL
           ) {
            TRACE(TL_PNP_ERROR,("**** Format idx %d not supported by this driver ***\n", pDevExt->VideoFormatIndex));
            ASSERT(pDevExt->VideoFormatIndex == FMT_IDX_SD_DVCR_NTSC \
                || pDevExt->VideoFormatIndex == FMT_IDX_SD_DVCR_PAL \
                || pDevExt->VideoFormatIndex == FMT_IDX_SDL_DVCR_NTSC \
                || pDevExt->VideoFormatIndex == FMT_IDX_SDL_DVCR_PAL \
                );
            return STATUS_UNSUCCESSFUL; // STATUS_NOT_SUPPORTED;
        }
    }

    //
    // Mode of Operation: 0(Undetermined), Camera or VCR
    //
    DVDelayExecutionThread(DV_AVC_CMD_DELAY_INTER_CMD);
    DVGetDevModeOfOperation(
        pDevExt
        );

         
    return STATUS_SUCCESS; // Status;
}



NTSTATUS
DVInitializeDevice(
    IN PDVCR_EXTENSION  pDevExt,
    IN PPORT_CONFIGURATION_INFORMATION pConfigInfo,
    IN PAV_61883_REQUEST  pAVReq
    )
/*++

Routine Description:

    This where we perform the necessary initialization tasks.

--*/

{
    int i;
    NTSTATUS Status = STATUS_SUCCESS;

    PAGED_CODE();

    //
    // Initialize the device extension structure
    //
    DVIniDevExtStruct(
        pDevExt,
        pConfigInfo
        );

#ifdef READ_CUTOMIZE_REG_VALUES
    //
    // Get values from this device's own registry 
    //
    DVGetPropertyValuesFromRegistry(
        pDevExt
        );
#endif

    //
    // Query device information at the laod time:
    //    Subunit
    //    Unit Info
    //    Mode of operation
    //    NTSC or PAL
    //    Speed
    //    oPCR/iPCR
    //
    Status = 
        DVGetDevInfo(
            pDevExt,
            pAVReq
            );

    if(!NT_SUCCESS(Status)) {
        TRACE(TL_PNP_ERROR,("\'DVGetDevInfo failed %x\n", Status));
        // While driver is loading, the device could be unplug.
        // In this case, the AVC command can return STATUS_REQUEST_ABORTED.
        // In DvGetDevInfo may then return STATUS_NOT_SUPPORTED or STATUS_UNSUCCESSFUL.
        // We will then return this status to indicate loading failure.
#if 0 // DBG
        if(Status != STATUS_REQUEST_ABORTED && !NT_SUCCESS(Status)) {
            ASSERT(NT_SUCCESS(Status) && "DVGetDevInfo failed");
        }
#endif
        return Status;
    }


#ifdef NT51_61883

    //
    // Get Unit isoch parameters
    //
    if(!NT_SUCCESS(
        Status = DVGetUnitIsochParam(
            pDevExt, 
            &pDevExt->UnitIoschParams
            )))
        return Status;


    //
    // Create a local output plug.  This plug is used to updated isoch
    // resource used when connection was made. 
    //
    if(!NT_SUCCESS(
        Status = DVCreateLocalPlug(
            pDevExt, 
            CMP_PlugOut,
            0,                   // Plug number
            &pDevExt->hOPcrPC
            )))
        return Status;

#endif


    //
    // Note: Must do ExAllocatePool after DVIniDevExtStruct() since ->paCurrentStrmInfo is initialized.
    // Since the format that this driver support is known when this driver is known,'
    // the stream information table need to be custonmized.  Make a copy and customized it.
    //

    //
    // Set the size of the stream inforamtion structure that we returned in SRB_GET_STREAM_INFO
    //
        
    pDevExt->paCurrentStrmInfo = (HW_STREAM_INFORMATION *) 
        ExAllocatePool(NonPagedPool, sizeof(HW_STREAM_INFORMATION) * DV_STREAM_COUNT);

    if(!pDevExt->paCurrentStrmInfo) 
        return STATUS_INSUFFICIENT_RESOURCES;   
        
    pConfigInfo->StreamDescriptorSize = 
        (DV_STREAM_COUNT * sizeof(HW_STREAM_INFORMATION)) +      // number of stream descriptors
        sizeof(HW_STREAM_HEADER);                                // and 1 stream header

    // Make a copy of the default stream information
    for(i = 0; i < DV_STREAM_COUNT; i++ ) 
        pDevExt->paCurrentStrmInfo[i] = DVStreams[i].hwStreamInfo;          

    // Set AUDIO AUX to reflect: NTSC/PAL, consumer DV or DVCPRO
    if(pDevExt->bDVCPro) {
        // Note: there is no DVInfo in VideoInfoHeader but there is for the iAV streams.
        SDDV_IavPalStream.DVVideoInfo.dwDVAAuxSrc  = AAUXSRC_SD_PAL_DVCPRO;
        SDDV_IavPalStream.DVVideoInfo.dwDVAAuxSrc1 = AAUXSRC_SD_PAL_DVCPRO | AAUXSRC_AMODE_F;
        SDDV_IavPalStream.DVVideoInfo.dwDVVAuxSrc  = VAUXSRC_DEFAULT | AUXSRC_PAL | AUXSRC_STYPE_SD_DVCPRO;

        SDDV_IavNtscStream.DVVideoInfo.dwDVAAuxSrc = AAUXSRC_SD_NTSC_DVCPRO;
        SDDV_IavNtscStream.DVVideoInfo.dwDVAAuxSrc1= AAUXSRC_SD_NTSC_DVCPRO | AAUXSRC_AMODE_F;
        SDDV_IavNtscStream.DVVideoInfo.dwDVVAuxSrc = VAUXSRC_DEFAULT | AUXSRC_NTSC | AUXSRC_STYPE_SD_DVCPRO;

    } else {
        // This might be necessary for the 2nd instance of MSDV (1st:DVCPRO; 2nd:DVSD)
        SDDV_IavPalStream.DVVideoInfo.dwDVAAuxSrc  = AAUXSRC_SD_PAL;
        SDDV_IavPalStream.DVVideoInfo.dwDVAAuxSrc1 = AAUXSRC_SD_PAL  | AAUXSRC_AMODE_F;
        SDDV_IavPalStream.DVVideoInfo.dwDVVAuxSrc  = VAUXSRC_DEFAULT | AUXSRC_PAL | AUXSRC_STYPE_SD;

        SDDV_IavNtscStream.DVVideoInfo.dwDVAAuxSrc = AAUXSRC_SD_NTSC;
        SDDV_IavNtscStream.DVVideoInfo.dwDVAAuxSrc1= AAUXSRC_SD_NTSC | AAUXSRC_AMODE_F;
        SDDV_IavNtscStream.DVVideoInfo.dwDVVAuxSrc = VAUXSRC_DEFAULT | AUXSRC_NTSC | AUXSRC_STYPE_SD;
    }


    // Initialize last time format was updated
    pDevExt->tmLastFormatUpdate = GetSystemTime(); 


    TRACE(TL_PNP_WARNING,("\'#### %s%s:%s:%s PhyDO %x, BusDO %x, DevExt %x, FrmSz %d; StrmIf %d\n", 
        (pDevExt->ulDevType == ED_DEVTYPE_VCR ? "DVCR" : (pDevExt->ulDevType == ED_DEVTYPE_CAMERA ? "Camera" : "Tuner?")),
        pDevExt->bDVCPro ? "(DVCPRO)":"",
        (pDevExt->VideoFormatIndex == FMT_IDX_SD_DVCR_NTSC || pDevExt->VideoFormatIndex == FMT_IDX_SDL_DVCR_NTSC)? "SD:NTSC" : (pDevExt->VideoFormatIndex == FMT_IDX_SD_DVCR_PAL || pDevExt->VideoFormatIndex == FMT_IDX_SDL_DVCR_PAL) ? "PAL" : "MPEG_TS?",
        (pDevExt->ulDevType == ED_DEVTYPE_VCR && pDevExt->NumInputPlugs > 0) ? "CanRec" : "NotRec",
        pDevExt->pPhysicalDeviceObject, 
        pDevExt->pBusDeviceObject, 
        pDevExt,  
        DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize,
        pConfigInfo->StreamDescriptorSize
        ));
    
    return STATUS_SUCCESS;
}

NTSTATUS
DVInitializeCompleted(
    IN PDVCR_EXTENSION  pDevExt
    )
/*++

Routine Description:

    This where we perform the necessary initialization tasks.

--*/

{
    PAGED_CODE();


#ifdef SUPPORT_OPTIMIZE_AVCCMD_RETRIES

    //
    // Determine retries 
    //
    pDevExt->DrvLoadCompleted = TRUE;

    if((pDevExt->AVCCmdRespTimeSum / pDevExt->AVCCmdCount) > 
       (DEFAULT_AVC_TIMEOUT * DEFAULT_AVC_RETRIES / 10000)) {
        // If every AVC command was timed out, do not bother to retry.
        pDevExt->AVCCmdRetries = 0;
    } else {

#if 0
        // Some camcorders do not queue up comand so follow a transport
        // state change, it will not accept any AVC command until transport
        // state is in the stable state.  So further delay is needed.

        if(
          // Exception for Samsung; always timeout following XPrt command
          // Or maybe it does not support transport state status command!
          pDevExt->ulVendorID == VENDORID_SAMSUNG                  
          ) {
            TRACE(TL_PNP_ERROR,("Samsung DV device: use default AVC setting.\n"));
        } else {
            pDevExt->AVCCmdRetries = MAX_AVC_CMD_RETRIES;
        }
#endif
    }

    TRACE(TL_PNP_ERROR,("AVCCMd Response Time: pDevExt:%x; Range (%d..%d); Avg %d/%d = %d; Retries:%d\n",
        pDevExt,
        pDevExt->AVCCmdRespTimeMin,
        pDevExt->AVCCmdRespTimeMax,
        pDevExt->AVCCmdRespTimeSum,
        pDevExt->AVCCmdCount,
        pDevExt->AVCCmdRespTimeSum / pDevExt->AVCCmdCount,
        pDevExt->AVCCmdRetries
        ));
#endif

    return STATUS_SUCCESS;
}

NTSTATUS
DVGetStreamInfo(
    IN PDVCR_EXTENSION        pDevExt,
    IN ULONG                  ulBytesToTransfer, 
    IN PHW_STREAM_HEADER      pStreamHeader,       
    IN PHW_STREAM_INFORMATION pStreamInfo
    )

/*++

Routine Description:

    Returns the information of all streams that are supported by the driver

--*/

{
    ULONG i;

    PAGED_CODE();


    //
    // Make sure we have enough space to return our stream informations
    //
    if(ulBytesToTransfer < sizeof (HW_STREAM_HEADER) + sizeof(HW_STREAM_INFORMATION) * DV_STREAM_COUNT ) {
        TRACE(TL_PNP_ERROR,("\'DVGetStrmInfo: ulBytesToTransfer %d ?= %d\n",  
            ulBytesToTransfer, sizeof(HW_STREAM_HEADER) + sizeof(HW_STREAM_INFORMATION) * DV_STREAM_COUNT ));
        return STATUS_INVALID_PARAMETER;
    }

    //
    // Initialize stream header:
    //   Device properties
    //   Streams
    //

    RtlZeroMemory(pStreamHeader, sizeof(HW_STREAM_HEADER));

    pStreamHeader->NumberOfStreams           = DV_STREAM_COUNT;
    pStreamHeader->SizeOfHwStreamInformation = sizeof(HW_STREAM_INFORMATION);

    pStreamHeader->NumDevPropArrayEntries    = NUMBER_VIDEO_DEVICE_PROPERTIES;
    pStreamHeader->DevicePropertiesArray     = (PKSPROPERTY_SET) VideoDeviceProperties;

    pStreamHeader->NumDevEventArrayEntries   = NUMBER_VIDEO_DEVICE_EVENTS;
    pStreamHeader->DeviceEventsArray         = (PKSEVENT_SET) VideoDeviceEvents;


    TRACE(TL_PNP_TRACE,("\'DVGetStreamInfo: StreamPropEntries %d, DevicePropEntries %d\n",
        pStreamHeader->NumberOfStreams, pStreamHeader->NumDevPropArrayEntries));


    //
    // Initialize the stream structure.
    //
    for( i = 0; i < DV_STREAM_COUNT; i++ )
        *pStreamInfo++ = pDevExt->paCurrentStrmInfo[i];

    //
    //
    // store a pointer to the topology for the device
    //        
    pStreamHeader->Topology = &Topology;


    return STATUS_SUCCESS;
}


BOOL 
DVVerifyDataFormat(
    PKSDATAFORMAT  pKSDataFormatToVerify, 
    ULONG          StreamNumber,
    ULONG          ulSupportedFrameSize,
    HW_STREAM_INFORMATION * paCurrentStrmInfo    
    )
/*++

Routine Description:

    Checks the validity of a format request by walking through the array of 
    supported KSDATA_RANGEs for a given stream.

Arguments:

     pKSDataFormat - pointer of a KS_DATAFORMAT_VIDEOINFOHEADER structure.
     StreamNumber - index of the stream being queried / opened.

Return Value:

     TRUE if the format is supported
     FALSE if the format cannot be suppored

--*/
{
    PKSDATAFORMAT  *pAvailableFormats;
    int            NumberOfFormatArrayEntries;
    int            j;
     
    PAGED_CODE();

    //
    // Make sure the stream index is valid (0..DV_STREAM_COUNT-1)
    //
    if(StreamNumber >= DV_STREAM_COUNT) {
        return FALSE;
    }

    //
    // How many formats does this stream support?
    //
    NumberOfFormatArrayEntries = paCurrentStrmInfo[StreamNumber].NumberOfFormatArrayEntries;

    //
    // Get the pointer to the array of available formats
    //
    pAvailableFormats = paCurrentStrmInfo[StreamNumber].StreamFormatsArray;
    
    
    //
    // Walk the array, searching for a match
    //
    for (j = 0; j < NumberOfFormatArrayEntries; j++, pAvailableFormats++) {
        
        //
        // Check supported sample size (== frame size). e.g. SD and SDL have different sample size.
        //
        if( (*pAvailableFormats)->SampleSize != ulSupportedFrameSize) {
            TRACE(TL_STRM_TRACE,("\'  StrmNum %d, %d of %d formats, SizeToVerify %d *!=* SupportedSampleSize %d\n", 
                StreamNumber,
                j+1, NumberOfFormatArrayEntries, 
                (*pAvailableFormats)->SampleSize,  
                ulSupportedFrameSize));
            continue;
        }

        if (!DVCmpGUIDsAndFormatSize(
                 pKSDataFormatToVerify, 
                 *pAvailableFormats,
                 TRUE, // Compare subformat
                 FALSE /* CompareFormatSize */ )) {
            continue;
        }

        //
        // Additional verification test
        //
        if(IsEqualGUID (&pKSDataFormatToVerify->Specifier, &KSDATAFORMAT_SPECIFIER_VIDEOINFO)) {
            // Make sure 
            if( ((PKS_DATAFORMAT_VIDEOINFOHEADER)pKSDataFormatToVerify)->VideoInfoHeader.bmiHeader.biSizeImage !=
                ulSupportedFrameSize) {
                TRACE(TL_STRM_WARNING,("VIDEOINFO: biSizeToVerify %d != Supported %d\n",
                    ((PKS_DATAFORMAT_VIDEOINFOHEADER)pKSDataFormatToVerify)->VideoInfoHeader.bmiHeader.biSizeImage,
                    ulSupportedFrameSize
                    ));
                continue;
            } else {
                TRACE(TL_STRM_TRACE,("VIDOINFO: **** biSizeToVerify %d == Supported %d\n",
                    ((PKS_DATAFORMAT_VIDEOINFOHEADER)pKSDataFormatToVerify)->VideoInfoHeader.bmiHeader.biSizeImage,
                    ulSupportedFrameSize
                    ));
            }
#ifdef SUPPORT_NEW_AVC 
        } else if (IsEqualGUID (&pKSDataFormatToVerify->Specifier, &KSDATAFORMAT_SPECIFIER_DVINFO) ||
                   IsEqualGUID (&pKSDataFormatToVerify->Specifier, &KSDATAFORMAT_SPECIFIER_DV_AVC)
            ) {
#else
        } else if (IsEqualGUID (&pKSDataFormatToVerify->Specifier, &KSDATAFORMAT_SPECIFIER_DVINFO)) {
#endif

            // Test 50/60 bit
            if((((PKS_DATARANGE_DVVIDEO) pKSDataFormatToVerify)->DVVideoInfo.dwDVAAuxSrc & MASK_AUX_50_60_BIT) != 
               (((PKS_DATARANGE_DVVIDEO) *pAvailableFormats)->DVVideoInfo.dwDVAAuxSrc    & MASK_AUX_50_60_BIT)  ||
               (((PKS_DATARANGE_DVVIDEO) pKSDataFormatToVerify)->DVVideoInfo.dwDVVAuxSrc & MASK_AUX_50_60_BIT) != 
               (((PKS_DATARANGE_DVVIDEO) *pAvailableFormats)->DVVideoInfo.dwDVVAuxSrc    & MASK_AUX_50_60_BIT) ) {

                TRACE(TL_STRM_WARNING,("VerifyFormat failed: ASrc: %x!=%x (MSDV);or VSrc: %x!=%x\n",                    
                 ((PKS_DATARANGE_DVVIDEO) pKSDataFormatToVerify)->DVVideoInfo.dwDVAAuxSrc, 
                    ((PKS_DATARANGE_DVVIDEO) *pAvailableFormats)->DVVideoInfo.dwDVAAuxSrc,
                 ((PKS_DATARANGE_DVVIDEO) pKSDataFormatToVerify)->DVVideoInfo.dwDVVAuxSrc,
                    ((PKS_DATARANGE_DVVIDEO) *pAvailableFormats)->DVVideoInfo.dwDVVAuxSrc
                     ));

                continue;

            } 

#if 0
            // Make sure the verified format's sample size is supported by the device
            if(ulSupportedFrameSize != ((PKS_DATARANGE_DVVIDEO) pKSDataFormatToVerify)->DataRange.SampleSize) {
                TRACE(TL_STRM_WARNING,("\'SupportedFrameSize %d != SampleSize:%d\n", 
                    ulSupportedFrameSize, ((PKS_DATARANGE_DVVIDEO)pKSDataFormatToVerify)->DataRange.SampleSize));
                continue;
            }
#endif

            TRACE(TL_STRM_TRACE,("\'DVINFO: dwDVAAuxCtl %x, Supported %x\n", 
                ((PKS_DATARANGE_DVVIDEO) pKSDataFormatToVerify)->DVVideoInfo.dwDVAAuxSrc,
                ((PKS_DATARANGE_DVVIDEO) *pAvailableFormats)->DVVideoInfo.dwDVAAuxSrc
                ));

            TRACE(TL_STRM_TRACE,("\'DVINFO: dwDVVAuxSrc %x, Supported %x\n", 
                ((PKS_DATARANGE_DVVIDEO) pKSDataFormatToVerify)->DVVideoInfo.dwDVVAuxSrc,
                ((PKS_DATARANGE_DVVIDEO) *pAvailableFormats)->DVVideoInfo.dwDVVAuxSrc
                ));

        }
        else {
            continue;
        }


        return TRUE;
    }

    return FALSE;
} 




NTSTATUS
DVGetDataIntersection(
    IN  ULONG          ulStreamNumber,
    IN  PKSDATARANGE   pDataRange,
    OUT PVOID          pDataFormatBuffer,
    IN  ULONG          ulSizeOfDataFormatBuffer,
    IN  ULONG          ulSupportedFrameSize,
    OUT ULONG          *pulActualBytesTransferred,
    HW_STREAM_INFORMATION * paCurrentStrmInfo
#ifdef SUPPORT_NEW_AVC            
    ,IN HANDLE hPlug
#endif
    )
/*++

Routine Description:

    Called to get a DATAFORMAT from a DATARANGE.

--*/
{
    BOOL                        bMatchFound = FALSE;
    ULONG                       ulFormatSize;
    ULONG                       j;
    ULONG                       ulNumberOfFormatArrayEntries;
    PKSDATAFORMAT               *pAvailableFormats;

    PAGED_CODE();

    
    
    //
    // Check that the stream number is valid
    //
    if(ulStreamNumber >= DV_STREAM_COUNT) {
        TRACE(TL_STRM_ERROR,("\'DVCRFormatFromRange: ulStreamNumber %d >= DV_STREAM_COUNT %d\n", ulStreamNumber, DV_STREAM_COUNT)); 
        return STATUS_NOT_SUPPORTED;
    }


    // Number of format this stream supports
    ulNumberOfFormatArrayEntries = paCurrentStrmInfo[ulStreamNumber].NumberOfFormatArrayEntries;

    //
    // Get the pointer to the array of available formats
    //
    pAvailableFormats = paCurrentStrmInfo[ulStreamNumber].StreamFormatsArray;


    //
    // Walk the formats supported by the stream searching for a match
    // Note: DataIntersection is really enumerating supported MediaType only!
    //       SO matter compare format is NTSC or PAL, we need suceeded both;
    //       however, we will copy back only the format is currently supported (NTSC or PAL).
    //
    for(j = 0; j < ulNumberOfFormatArrayEntries; j++, pAvailableFormats++) {

        if(!DVCmpGUIDsAndFormatSize(pDataRange, *pAvailableFormats, FALSE, TRUE)) {
            TRACE(TL_STRM_TRACE,("\'DVCmpGUIDsAndFormatSize failed!\n"));
            continue;
        }

        //
        // Check supported sample size (== frame size).
        //
        if( (*pAvailableFormats)->SampleSize != ulSupportedFrameSize) {
            TRACE(TL_STRM_TRACE,("\'  StrmNum %d, %d of %d formats, SizeToVerify %d *!=* SupportedSampleSize %d\n", 
                ulStreamNumber,
                j+1, ulNumberOfFormatArrayEntries, 
                (*pAvailableFormats)->SampleSize,  
                ulSupportedFrameSize));
            continue;
        }

         
        // -------------------------------------------------------------------
        // Specifier FORMAT_VideoInfo for VIDEOINFOHEADER
        // -------------------------------------------------------------------

        if(IsEqualGUID (&pDataRange->Specifier, &KSDATAFORMAT_SPECIFIER_VIDEOINFO)) {
         
            PKS_DATARANGE_VIDEO pDataRangeVideoToVerify = (PKS_DATARANGE_VIDEO) pDataRange;
            PKS_DATARANGE_VIDEO pDataRangeVideo         = (PKS_DATARANGE_VIDEO) *pAvailableFormats;

#if 0
            //
            // Check that the other fields match
            //
            if ((pDataRangeVideoToVerify->bFixedSizeSamples      != pDataRangeVideo->bFixedSizeSamples)
                || (pDataRangeVideoToVerify->bTemporalCompression   != pDataRangeVideo->bTemporalCompression) 
                || (pDataRangeVideoToVerify->StreamDescriptionFlags != pDataRangeVideo->StreamDescriptionFlags) 
                || (pDataRangeVideoToVerify->MemoryAllocationFlags  != pDataRangeVideo->MemoryAllocationFlags) 
#ifdef COMPARE_CONFIG_CAP
                || (RtlCompareMemory (&pDataRangeVideoToVerify->ConfigCaps,
                    &pDataRangeVideo->ConfigCaps,
                    sizeof (KS_VIDEO_STREAM_CONFIG_CAPS)) != 
                    sizeof (KS_VIDEO_STREAM_CONFIG_CAPS))
#endif
                    )   {

                TRACE(TL_STRM_TRACE,("\'DVFormatFromRange: *!=* bFixSizeSample (%d %d) (%d %d) (%d %d) (%x %x)\n",
                    pDataRangeVideoToVerify->bFixedSizeSamples,      pDataRangeVideo->bFixedSizeSamples,
                    pDataRangeVideoToVerify->bTemporalCompression ,  pDataRangeVideo->bTemporalCompression,
                    pDataRangeVideoToVerify->StreamDescriptionFlags, pDataRangeVideo->StreamDescriptionFlags,
                    pDataRangeVideoToVerify->ConfigCaps.VideoStandard, pDataRangeVideo->ConfigCaps.VideoStandard 
                    ));
                    
                continue;
            } else {
                TRACE(TL_STRM_TRACE,("\'DVFormatFromRange: == bFixSizeSample (%d %d) (%d %d) (%d %d) (%x %x)\n",
                    pDataRangeVideoToVerify->bFixedSizeSamples,      pDataRangeVideo->bFixedSizeSamples,
                    pDataRangeVideoToVerify->bTemporalCompression ,  pDataRangeVideo->bTemporalCompression,
                    pDataRangeVideoToVerify->StreamDescriptionFlags, pDataRangeVideo->StreamDescriptionFlags,
                    pDataRangeVideoToVerify->ConfigCaps.VideoStandard, pDataRangeVideo->ConfigCaps.VideoStandard 
                    ));
            }
           
#endif
            bMatchFound = TRUE;            
            ulFormatSize = sizeof (KSDATAFORMAT) + 
                KS_SIZE_VIDEOHEADER (&pDataRangeVideo->VideoInfoHeader);
            
            if(ulSizeOfDataFormatBuffer == 0) {

                // We actually have not returned this much data,
                // this "size" will be used by Ksproxy to send down 
                // a buffer of that size in next query.
                *pulActualBytesTransferred = ulFormatSize;

                return STATUS_BUFFER_OVERFLOW;
            }


            // Caller wants the full data format
            if(ulSizeOfDataFormatBuffer < ulFormatSize) {
                TRACE(TL_STRM_ERROR,("VIDEOINFO: StreamNum %d, SizeOfDataFormatBuffer %d < ulFormatSize %d\n",ulStreamNumber, ulSizeOfDataFormatBuffer, ulFormatSize));
                return STATUS_BUFFER_TOO_SMALL;
            }

            // KS_DATAFORMAT_VIDEOINFOHEADER
            //    KSDATAFORMAT            DataFormat;
            //    KS_VIDEOINFOHEADER      VideoInfoHeader;                
            RtlCopyMemory(
                &((PKS_DATAFORMAT_VIDEOINFOHEADER)pDataFormatBuffer)->DataFormat,
                &pDataRangeVideo->DataRange, 
                sizeof (KSDATAFORMAT));

            // This size is differnt from our data range size which also contains ConfigCap
            ((PKSDATAFORMAT)pDataFormatBuffer)->FormatSize = ulFormatSize;
            *pulActualBytesTransferred = ulFormatSize;

            RtlCopyMemory(
                &((PKS_DATAFORMAT_VIDEOINFOHEADER) pDataFormatBuffer)->VideoInfoHeader,
                &pDataRangeVideo->VideoInfoHeader,  
                KS_SIZE_VIDEOHEADER (&pDataRangeVideo->VideoInfoHeader));

            TRACE(TL_STRM_TRACE,("\'DVFormatFromRange: Matched, StrmNum %d, FormatSize %d, CopySize %d; FormatBufferSize %d, biSizeImage.\n", 
                ulStreamNumber, (*pAvailableFormats)->FormatSize, ulFormatSize, ulSizeOfDataFormatBuffer,
                ((PKS_DATAFORMAT_VIDEOINFOHEADER) pDataFormatBuffer)->VideoInfoHeader.bmiHeader.biSizeImage));

            return STATUS_SUCCESS;

        } else if (IsEqualGUID (&pDataRange->Specifier, &KSDATAFORMAT_SPECIFIER_DVINFO)) {
            // -------------------------------------------------------------------
            // Specifier FORMAT_DVInfo for KS_DATARANGE_DVVIDEO
            // -------------------------------------------------------------------

            // MATCH FOUND!
            bMatchFound = TRUE;            

            ulFormatSize = sizeof(KS_DATARANGE_DVVIDEO);

            if(ulSizeOfDataFormatBuffer == 0) {
                // We actually have not returned this much data,
                // this "size" will be used by Ksproxy to send down 
                // a buffer of that size in next query.
                *pulActualBytesTransferred = ulFormatSize;
                return STATUS_BUFFER_OVERFLOW;
            }
            
            // Caller wants the full data format
            if (ulSizeOfDataFormatBuffer < ulFormatSize) {
                TRACE(TL_STRM_ERROR,("\'DVINFO: StreamNum %d, SizeOfDataFormatBuffer %d < ulFormatSize %d\n", ulStreamNumber, ulSizeOfDataFormatBuffer, ulFormatSize));
                return STATUS_BUFFER_TOO_SMALL;
            }

            RtlCopyMemory(
                pDataFormatBuffer,
                *pAvailableFormats, 
                (*pAvailableFormats)->FormatSize); 

            
            ((PKSDATAFORMAT)pDataFormatBuffer)->FormatSize = ulFormatSize;
            *pulActualBytesTransferred = ulFormatSize;

            TRACE(TL_STRM_TRACE,("\'** DVFormatFromRange: (DVINFO) Matched, StrmNum %d, FormatSize %d, CopySize %d; FormatBufferSize %d.\n", 
                ulStreamNumber, (*pAvailableFormats)->FormatSize, ulFormatSize, ulSizeOfDataFormatBuffer));

            return STATUS_SUCCESS;

#ifdef SUPPORT_NEW_AVC            
        } else if (IsEqualGUID (&pDataRange->Specifier, &KSDATAFORMAT_SPECIFIER_DV_AVC)) {
            // -------------------------------------------------------------------
            // Specifier FORMAT_DVInfo for KS_DATARANGE_DVVIDEO
            // -------------------------------------------------------------------

            // MATCH FOUND!
            bMatchFound = TRUE;            

            ulFormatSize = sizeof(KS_DATARANGE_DV_AVC);

            if(ulSizeOfDataFormatBuffer == 0) {
                // We actually have not returned this much data,
                // this "size" will be used by Ksproxy to send down 
                // a buffer of that size in next query.
                *pulActualBytesTransferred = ulFormatSize;
                return STATUS_BUFFER_OVERFLOW;
            }
            
            // Caller wants the full data format
            if (ulSizeOfDataFormatBuffer < ulFormatSize) {
                TRACE(TL_STRM_ERROR,("\'** DV_AVC: StreamNum %d, SizeOfDataFormatBuffer %d < ulFormatSize %d\n", ulStreamNumber, ulSizeOfDataFormatBuffer, ulFormatSize));
                return STATUS_BUFFER_TOO_SMALL;
            }

            RtlCopyMemory(
                pDataFormatBuffer,
                *pAvailableFormats, 
                (*pAvailableFormats)->FormatSize); 
            
            ((KS_DATAFORMAT_DV_AVC *)pDataFormatBuffer)->ConnectInfo.hPlug = hPlug;

            ((PKSDATAFORMAT)pDataFormatBuffer)->FormatSize = ulFormatSize;
            *pulActualBytesTransferred = ulFormatSize;

            TRACE(TL_STRM_TRACE,("\'*** DVFormatFromRange: (DV_AVC) Matched, StrmNum %d, FormatSize %d, CopySize %d; FormatBufferSize %d.\n", 
                ulStreamNumber, (*pAvailableFormats)->FormatSize, ulFormatSize, ulSizeOfDataFormatBuffer));

            return STATUS_SUCCESS;

#endif // SUPPORT_NEW_AVC 
        }         
        else {
            TRACE(TL_STRM_ERROR,("\'Invalid Specifier, No match !\n"));
            return STATUS_NO_MATCH;
        }

    } // End of loop on all formats for this stream
    
    if(!bMatchFound) {

        TRACE(TL_STRM_TRACE,("\'DVFormatFromRange: No Match! StrmNum %d, pDataRange %x\n", ulStreamNumber, pDataRange));
    }

    return STATUS_NO_MATCH;         
}



VOID 
DVIniStrmExt(
    PHW_STREAM_OBJECT  pStrmObject,
    PSTREAMEX          pStrmExt,
    PDVCR_EXTENSION    pDevExt,
    const PALL_STREAM_INFO   pStream
    )
/*++

Routine Description:

    Initialize stream extension strcuture.

--*/
{

    PAGED_CODE();


    RtlZeroMemory( pStrmExt, sizeof(STREAMEX) );

    pStrmExt->bEOStream     = TRUE;       // Stream has not started yet!

    pStrmExt->pStrmObject   = pStrmObject;
    pStrmExt->StreamState   = KSSTATE_STOP;
    pStrmExt->pDevExt       = pDevExt;

    pStrmExt->hMyClock      = 0;
    pStrmExt->hMasterClock  = 0;
    pStrmExt->hClock        = 0;


//
// Aplly to both IN/OUT data flow
//
    //
    // Init isoch resources
    //
    pStrmExt->CurrentStreamTime = 0;  

    pStrmExt->cntSRBReceived  = 0;  // number of SRB_READ/WRITE_DATA
    pStrmExt->cntSRBCancelled = 0;  // number of SRB_READ/WRITE_DATA cancelled
    

    pStrmExt->FramesProcessed = 0;
    pStrmExt->PictureNumber   = 0;
    pStrmExt->FramesDropped   = 0;   


#ifdef MSDV_SUPPORT_EXTRACT_SUBCODE_DATA
    //
    // Subcode data that can be extract from a DV frame
    //

    pStrmExt->AbsTrackNumber = 0;
    pStrmExt->bATNUpdated    = FALSE;

    pStrmExt->Timecode[0] = 0;
    pStrmExt->Timecode[1] = 0;
    pStrmExt->Timecode[2] = 0;
    pStrmExt->Timecode[3] = 0;
    pStrmExt->bTimecodeUpdated = FALSE;
#endif

    //
    //  Flow control and queue management
    //

    pStrmExt->lStartIsochToken = 0;

    pStrmExt->pAttachFrameThreadObject = NULL;

    pStrmExt->cntSRBQueued = 0;                        // SRB_WRITE_DATA only
    InitializeListHead(&pStrmExt->SRBQueuedListHead);  // SRB_WRITE_DATA only

    pStrmExt->cntDataDetached = 0;
    InitializeListHead(&pStrmExt->DataDetachedListHead);

    pStrmExt->cntDataAttached = 0;
    InitializeListHead(&pStrmExt->DataAttachedListHead);

    pStrmExt->b1stNewFrameFromPauseState = TRUE;  // STOP State-> RUN will have discontinuity

    //
    // Work item variables use to cancel all SRBs
    //
    pStrmExt->lCancelStateWorkItem = 0;
    pStrmExt->bAbortPending = FALSE;
#ifdef USE_WDM110
    pStrmExt->pIoWorkItem = NULL;
#endif

   
    //
    // Cache the pointer
    // What in DVStreams[] are READONLY
    //
    pStrmExt->pStrmInfo = &pStream->hwStreamInfo;

    pStrmObject->ReceiveDataPacket    = (PVOID) pStream->hwStreamObject.ReceiveDataPacket;
    pStrmObject->ReceiveControlPacket = (PVOID) pStream->hwStreamObject.ReceiveControlPacket;
    pStrmObject->Dma                          = pStream->hwStreamObject.Dma;
    pStrmObject->Pio                          = pStream->hwStreamObject.Pio;
    pStrmObject->StreamHeaderWorkspace        = pStream->hwStreamObject.StreamHeaderWorkspace;
    pStrmObject->StreamHeaderMediaSpecific    = pStream->hwStreamObject.StreamHeaderMediaSpecific;
    pStrmObject->HwClockObject                = pStream->hwStreamObject.HwClockObject;
    pStrmObject->Allocator                    = pStream->hwStreamObject.Allocator;
    pStrmObject->HwEventRoutine               = pStream->hwStreamObject.HwEventRoutine;

}



NTSTATUS
DVOpenStream(
    IN PHW_STREAM_OBJECT pStrmObject,
    IN PKSDATAFORMAT     pOpenFormat,
    IN PAV_61883_REQUEST    pAVReq
    )

/*++

Routine Description:

    Verify the OpenFormat and then allocate PC resource needed for this stream.
    The isoch resource, if needed, is allocated when streaming is transition to PAUSE state.

--*/

{
    NTSTATUS         Status = STATUS_SUCCESS;
    PSTREAMEX        pStrmExt;
    PDVCR_EXTENSION  pDevExt;
    ULONG            idxStreamNumber;
    KSPIN_DATAFLOW   DataFlow;
    PIRP             pIrp;
    FMT_INDEX        VideoFormatIndexLast;  // Last format index; used to detect change.
#ifdef SUPPORT_NEW_AVC
    AVCCONNECTINFO * pAvcConnectInfo;
#endif


    PAGED_CODE();

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

    idxStreamNumber =            pStrmObject->StreamNumber;

    TRACE(TL_STRM_TRACE,("\'DVOpenStream: pStrmObject %x, pOpenFormat %x, cntOpen %d, idxStream %d\n", pStrmObject, pOpenFormat, pDevExt->cndStrmOpen, idxStreamNumber));

    //
    // Only one string can be open at any time to prevent cyclin connection
    //
    if(pDevExt->cndStrmOpen > 0) {
        TRACE(TL_STRM_WARNING,("\'DVOpenStream: %d stream open already; failed hr %x\n", pDevExt->cndStrmOpen, Status));
        return STATUS_UNSUCCESSFUL;
    }

    if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE)))
        return STATUS_INSUFFICIENT_RESOURCES;

    //
    // If a user switch from Camera to VCR mode very quickly (passing the OFF position), 
    // the driver may not be relaoded to detect correct mode of operation.
    // It is safe to redetect here.
    // Note: MSDV does return all the stream info for both input and output pin format.
    //
    DVGetDevModeOfOperation(pDevExt);


    //
    // WARNING: !! we advertise both input and output pin regardless of its mode of operation,
    // but Camera does not support input pin so open should failed!
    // If a VCR does not have input pin should fail as well.
    //
    // Ignore checking for ED_DEVTYOPE_UNKNOWN (most likely a hardware decoder box)
    //
    if((pDevExt->ulDevType == ED_DEVTYPE_CAMERA || 
        (pDevExt->ulDevType == ED_DEVTYPE_VCR && pDevExt->NumInputPlugs == 0))
        && idxStreamNumber == 2) {
        TRACE(TL_STRM_ERROR,("\'OpenStream failed: Camera or VCR (0 inpin).\n"));
        Status =  STATUS_UNSUCCESSFUL;
        goto AbortOpenStream;
    }


    ASSERT(idxStreamNumber < DV_STREAM_COUNT);
    ASSERT(pDevExt->paStrmExt[idxStreamNumber] == NULL);  // Not yet open!

    //
    // Initialize the stream extension structure
    //
    DVIniStrmExt(
         pStrmObject, 
         pStrmExt,
         pDevExt,
         &DVStreams[idxStreamNumber]
         );

    // Sony's NTSC can play PAL tape and its plug will change its supported format accordingly.
    //
    // Query video format (NTSC/PAL) supported.
    // Compare with its default (set at load time or last opensteam),
    // if difference, change our internal video format table.
    //

    DataFlow= pDevExt->paCurrentStrmInfo[idxStreamNumber].DataFlow;

    VideoFormatIndexLast = pDevExt->VideoFormatIndex;
    if(!DVGetDevSignalFormat(
            pDevExt,
            DataFlow,
            pStrmExt
            )) {
            // If querying its format has failed, we cannot open this stream.
            TRACE(TL_STRM_ERROR,("\'OpenStream failed:cannot determine signal mode (NTSC/PAL, SD.SDL).\n"));
            Status = STATUS_UNSUCCESSFUL;
            goto AbortOpenStream;
    }


    //
    // Check the video data format is okay.
    //
    if(!DVVerifyDataFormat(
            pOpenFormat, 
            idxStreamNumber,
            DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize,
            pDevExt->paCurrentStrmInfo
            ) ) { 
        TRACE(TL_STRM_ERROR,("\'DVOpenStream: AdapterVerifyFormat failed.\n"));        
        Status = STATUS_INVALID_PARAMETER;
        goto AbortOpenStream;
    }

           
    //
    // Initialize events used for synchronization
    //

#ifdef SUPPORT_PREROLL_AT_RUN_STATE
    KeInitializeEvent(&pStrmExt->hPreRollEvent,    NotificationEvent, FALSE);  // Non-signal; Satisfy multple thread; manual reset
#endif
    KeInitializeEvent(&pStrmExt->hSrbArriveEvent,  NotificationEvent, FALSE);  // Non-signal; Satisfy multiple thread; manual reset
    KeInitializeEvent(&pStrmExt->hCancelDoneEvent, NotificationEvent, TRUE);   // Signal!

    //
    // Synchronize attaching frame thread and other critical operations:
    //     (1) power off/on; and 
    //     (2) surprise removal
    //
    if(KSPIN_DATAFLOW_IN == DataFlow) {
        KeInitializeEvent(&pStrmExt->hRunThreadEvent,  SynchronizationEvent /*NotificationEvent*/, FALSE);

        // Def to SIGNAL state
        KeInitializeEvent(&pStrmExt->hStopThreadEvent, /*SynchronizationEvent*/ NotificationEvent, TRUE);  
    }


    //
    // Alloccate synchronization structures for flow control and queue management
    //

    if(!(pStrmExt->hStreamMutex = (KMUTEX *) ExAllocatePool(NonPagedPool, sizeof(KMUTEX)))) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto AbortOpenStream;
    }
    KeInitializeMutex( pStrmExt->hStreamMutex, 0);      // Level 0 and in Signal state

    if(!(pStrmExt->DataListLock = (KSPIN_LOCK *) ExAllocatePool(NonPagedPool, sizeof(KSPIN_LOCK)))) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto AbortOpenStream;
    }
    KeInitializeSpinLock(pStrmExt->DataListLock);
#if DBG
    pStrmExt->DataListLockSave = pStrmExt->DataListLock;
#endif

    //
    // Allocate resource for timer DPC
    //

    if(!(pStrmExt->DPCTimer = (KDPC *) ExAllocatePool(NonPagedPool, sizeof(KDPC)))) {  
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto AbortOpenStream;
    }

    if(!(pStrmExt->Timer = (KTIMER *) ExAllocatePool(NonPagedPool, sizeof(KTIMER)))) {  
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto AbortOpenStream;
    }

    //
    // Set a timer to periodically check for expired clock events.
    // This timer is active only in RUN state and if we are the clock provider.
    //
    KeInitializeDpc(
        pStrmExt->DPCTimer,
        DVSignalClockEvent,
        pStrmExt
        );
    KeInitializeTimer(
        pStrmExt->Timer
        );
    pStrmExt->bTimerEnabled = FALSE;


#ifdef SUPPORT_NEW_AVC
    if(IsEqualGUID (&pOpenFormat->Specifier, &KSDATAFORMAT_SPECIFIER_DV_AVC)) {
     
        pAvcConnectInfo = &((KS_DATAFORMAT_DV_AVC *) pOpenFormat)->ConnectInfo;
        if(DataFlow == KSPIN_DATAFLOW_OUT) {
            // DV1(that is us) (oPCR) -> DV2 (iPCR)
            pStrmExt->hOutputPcr = pDevExt->hOPcrDV;         // DV1's oPCR
            pStrmExt->hInputPcr  = pAvcConnectInfo->hPlug;   // DV2's iPCR
            TRACE(TL_STRM_WARNING,("\'!!!!! (pStrmExt:%x) DV1 (oPCR:%x) -> DV2 (iPCR:%x) !!!!!\n\n", pStrmExt, pStrmExt->hOutputPcr, pStrmExt->hInputPcr));
        } else {
            // DV1(that is us) (iPCR) <- DV2 (oPCR)
            pStrmExt->hOutputPcr = pAvcConnectInfo->hPlug;   // DV2's oPCR
            pStrmExt->hInputPcr  = pDevExt->hIPcrDV;         // DV1's iPCR
            TRACE(TL_STRM_WARNING,("\'!!!!! (pStrmExt:%x) DV1 (iPCR:%x) <- DV2 (oPCR:%x) !!!!!\n\n", pStrmExt, pStrmExt->hInputPcr, pStrmExt->hOutputPcr));
        }

        pStrmExt->bDV2DVConnect = TRUE;

    } else {

        if(DataFlow == KSPIN_DATAFLOW_OUT) {
            // DV1(that is us) (oPCR) -> PC (iPCR)
            pStrmExt->hOutputPcr = pDevExt->hOPcrDV;
            pStrmExt->hInputPcr  = 0; // We do not create local iPCR
            TRACE(TL_STRM_WARNING,("\'!!!!! (pStrmExt:%x) DV (oPCR:%x) -> PC (iPCR:%x) !!!!!\n\n", pStrmExt, pStrmExt->hOutputPcr, pStrmExt->hInputPcr));

        } else {
            // DV1(that is us) (iPCR) <- PC (oPCR)
            pStrmExt->hOutputPcr = pDevExt->hOPcrPC;
            pStrmExt->hInputPcr  = pDevExt->hIPcrDV;
            TRACE(TL_STRM_WARNING,("\'!!!!! (pStrmExt:%x) DV (iPCR:%x) <- PC (oPCR:%x) !!!!!\n\n", pStrmExt, pStrmExt->hInputPcr, pStrmExt->hOutputPcr));
        }

        pStrmExt->bDV2DVConnect = FALSE;
    }
#else
    if(DataFlow == KSPIN_DATAFLOW_OUT) {
        // DV1(that is us) (oPCR) -> PC (iPCR)
        pStrmExt->hOutputPcr = pDevExt->hOPcrDV;
        pStrmExt->hInputPcr  = 0; // We do not create local iPCR
        TRACE(TL_STRM_WARNING,("\'!!!!! (pStrmExt:%x) DV (oPCR:%x) -> PC (iPCR:%x) !!!!!\n\n", pStrmExt, pStrmExt->hOutputPcr, pStrmExt->hInputPcr));

    } else {
        // DV1(that is us) (iPCR) <- PC (oPCR)
        pStrmExt->hOutputPcr = pDevExt->hOPcrPC;
        pStrmExt->hInputPcr  = pDevExt->hIPcrDV;
        TRACE(TL_STRM_WARNING,("\'!!!!! (pStrmExt:%x) DV (iPCR:%x) <- PC (oPCR:%x) !!!!!\n\n", pStrmExt, pStrmExt->hInputPcr, pStrmExt->hOutputPcr));
    }
#endif

    IoFreeIrp(pIrp); pIrp = NULL;


#if DBG
    // Allocate buffer to keep statistic of transmitted buffers.
    pStrmExt->paXmtStat = (XMT_FRAME_STAT *) 
        ExAllocatePool(NonPagedPool, sizeof(XMT_FRAME_STAT) * MAX_XMT_FRAMES_TRACED);

    if(!pStrmExt->paXmtStat) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto AbortOpenStream;         
    }
    pStrmExt->ulStatEntries = 0;
#endif

    //
    // Pre-allcoate resource (Lists)
    //
    if(!NT_SUCCESS(
        Status = DvAllocatePCResource(
            DataFlow,
            pStrmExt
            ))) {
        goto AbortOpenStream; 
    }


    //
    //  Cache it and reference when pDevExt is all we have, 
    //  such as BusReset and SurprieseRemoval
    //
    pDevExt->idxStreamNumber = idxStreamNumber;  // index of current active stream; work only if there is only one active stream at any time.
    pDevExt->paStrmExt[idxStreamNumber] = pStrmExt;

    //
    // In the future, a DV can be unplug and plug back in, 
    // and restore its state if the application is not yet closed.
    //
    pDevExt->bDevRemoved    = FALSE;

    //
    // No one else can open another stream (inout or output) unitil this is release.
    // This is done to avoid cyclic graph.
    //
    pDevExt->cndStrmOpen++;    
    ASSERT(pDevExt->cndStrmOpen == 1);  // Only one can be open at any time.
    
    TRACE(TL_STRM_WARNING,("\'OpenStream: %d stream open, idx %d, Status %x, pStrmExt %x, pDevExt %x\n", 
        pDevExt->cndStrmOpen, pDevExt->idxStreamNumber, Status, pStrmExt, pDevExt));     
    TRACE(TL_STRM_WARNING,("\' #OPEN_STREAM#: Status %x, idxStream %d, pDevExt %x, pStrmExt %x\n", 
        Status, idxStreamNumber, pDevExt, pStrmExt));

    return Status;

AbortOpenStream:       

    if(pIrp) {
        IoFreeIrp(pIrp);  pIrp = NULL;        
    }

    if(pStrmExt->DataListLock) {
        ExFreePool(pStrmExt->DataListLock); pStrmExt->DataListLock = NULL;
    }

    if(pStrmExt->hStreamMutex) {
        ExFreePool(pStrmExt->hStreamMutex); pStrmExt->hStreamMutex = NULL;
    }

    if(pStrmExt->DPCTimer) {
        ExFreePool(pStrmExt->DPCTimer); pStrmExt->DPCTimer = NULL;
    }

    if(pStrmExt->Timer) {
        ExFreePool(pStrmExt->Timer); pStrmExt->Timer = NULL;
    }

#if DBG
    if(pStrmExt->paXmtStat) {
        ExFreePool(pStrmExt->paXmtStat); pStrmExt->paXmtStat = NULL;
    }
#endif

    TRACE(TL_STRM_WARNING,("\'#OPEN_STREAM# failed!: Status %x, idxStream %d, pDevExt %x, pStrmExt %x\n", 
        Status, idxStreamNumber, pDevExt, pStrmExt));

    return Status;
}


NTSTATUS
DVCloseStream(
    IN PHW_STREAM_OBJECT pStrmObject,
    IN PKSDATAFORMAT     pOpenFormat,
    IN PAV_61883_REQUEST    pAVReq
    )

/*++

Routine Description:

    Called when an CloseStream Srb request is received

--*/

{
    ULONG             i;
    PSTREAMEX         pStrmExt;
    PDVCR_EXTENSION   pDevExt;
    ULONG             idxStreamNumber;   


    PAGED_CODE();

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

    idxStreamNumber =            pStrmObject->StreamNumber;


    TRACE(TL_STRM_WARNING,("\'DVCloseStream: >> pStrmExt %x, pDevExt %x\n", pStrmExt, pDevExt));    


    //
    // If the stream isn't open, just return
    //
    if(pStrmExt == NULL) {
        ASSERT(pStrmExt && "CloseStream but pStrmExt is NULL!");   
        return STATUS_SUCCESS;  // ????
    }


    // 
    // If surprise removal, we may get a close stream before surprise is completed.
    //
    if(
          pStrmExt->pAttachFrameThreadObject  // If thread is created!
       && !pStrmExt->bTerminateThread
       && pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN
      ) {
        NTSTATUS StatusWait;

        TRACE(TL_PNP_WARNING|TL_STRM_WARNING,("\'>>>> CloseStream: Enter WFSO(hStopThreadEvent; lNeedService:%d)\n", pStrmExt->lNeedService));
        StatusWait = 
            KeWaitForSingleObject(
                &pStrmExt->hStopThreadEvent,
                Executive, 
                KernelMode, 
                FALSE, 
                0
                );
        TRACE(TL_PNP_WARNING|TL_STRM_WARNING,("\'<<<< CloseStream: Exit WFSO(hStopThreadEvent; lNeedService:%d)\n", pStrmExt->lNeedService));
    }

    //
    // Wait until the pending work item is completed.  
    //
    TRACE(TL_STRM_WARNING,("\'CloseStream: pStrmExt->lCancelStateWorkItem:%d\n", pStrmExt->lCancelStateWorkItem)); 
    KeWaitForSingleObject( &pStrmExt->hCancelDoneEvent, Executive, KernelMode, FALSE, 0 );


    // Cancel should have been done when we are in PAUSE state.
    // But if an application is close, it might not transtioning into PAUSE state.
    if(pStrmExt->bTimerEnabled) {
         TRACE(TL_STRM_WARNING,("\'*** (CloseStream) CancelTimer *\n"));
         KeCancelTimer(
            pStrmExt->Timer
            );
         pStrmExt->bTimerEnabled = FALSE;
    }


    //
    // If talking or listening (i.e. streaming), stop it!
    // In case of system shutdown while streaming or application crash
    //

    DVStopCancelDisconnect(
        pStrmExt
        );

    //
    // Free all allocated PC resoruce
    //
    DvFreePCResource(
        pStrmExt
        );

    ASSERT(pStrmExt->cntDataDetached == 0 && IsListEmpty(&pStrmExt->DataDetachedListHead) && "Detach List not empty!");
    ASSERT(pStrmExt->cntDataAttached == 0 && IsListEmpty(&pStrmExt->DataAttachedListHead) && "Attach List not empty!");
    ASSERT(pStrmExt->cntSRBQueued    == 0 && IsListEmpty(&pStrmExt->SRBQueuedListHead)    && "SrbQ List not empty!");


    // Terminate the system thread that is used for attaching frame for transmit to DV
    if(
          KSPIN_DATAFLOW_IN == pStrmExt->pStrmInfo->DataFlow
       && !pStrmExt->bTerminateThread
       && pStrmExt->pAttachFrameThreadObject
      ) { 
        DVTerminateAttachFrameThread(pStrmExt);
        pStrmExt->pAttachFrameThreadObject = NULL;
        TRACE(TL_STRM_WARNING,("** DVCloseStream: thread terminated!\n"));
    }



#if DBG
    // Print this only if the debug flag is set.
    if(pStrmExt->paXmtStat) {
        if(DVDebugXmt) {
            TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("Data transmission statistics: (%s %s); (Pause:%d; Run:%d); hMasterClk:%x; hClock:%x\n\n", 
                __DATE__, __TIME__, pStrmExt->lFramesAccumulatedPaused, 
                pStrmExt->lFramesAccumulatedRun, pStrmExt->hMasterClock, pStrmExt->hClock));
            TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("ST \tSrbRcv \tSrbQ \tSrbPend \tAttached \tSlot \ttmStream \tDrop \tSrb# \tFlags \ttmPres \tSCnt \tCyCnt \tCyOfst\n"));
            for(i=0; i < pStrmExt->ulStatEntries; i++) {
                TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("%d \t%d \t%d \t%d \t%d \t%d \t%d \t%d \t%d \t%x \t%d \t%d \t%d \t%d\n",
                    pStrmExt->paXmtStat[i].StreamState,
                    pStrmExt->paXmtStat[i].cntSRBReceived,
                    pStrmExt->paXmtStat[i].cntSRBQueued,
                    pStrmExt->paXmtStat[i].cntSRBPending,
                    pStrmExt->paXmtStat[i].cntDataAttached,
                    (DWORD) pStrmExt->paXmtStat[i].FrameSlot,
                    (DWORD) pStrmExt->paXmtStat[i].tmStreamTime, // /10000,
                    pStrmExt->paXmtStat[i].DropCount,
                    pStrmExt->paXmtStat[i].FrameNumber,
                    (DWORD) pStrmExt->paXmtStat[i].OptionsFlags,
                    (DWORD) pStrmExt->paXmtStat[i].tmPresentation, // /10000,
                    pStrmExt->paXmtStat[i].tsTransmitted.CL_SecondCount,
                    pStrmExt->paXmtStat[i].tsTransmitted.CL_CycleCount,
                    pStrmExt->paXmtStat[i].tsTransmitted.CL_CycleOffset                 
                ));
            }
        }

        ExFreePool(pStrmExt->paXmtStat); pStrmExt->paXmtStat = NULL;
    }
#endif

    //
    //  Find the matching stream extension and invalidate it.
    //
    for (i=0; i<DV_STREAM_COUNT; i++) {

        if(pStrmExt == pDevExt->paStrmExt[i]) {
            ASSERT(!pDevExt->paStrmExt[i]->bAbortPending && "Cannot close a stream when abort is pending"); 
            pDevExt->paStrmExt[i] = NULL;
            break;
        }
    }

    // Release this count so other can open.   
    pDevExt->cndStrmOpen--;
    ASSERT(pDevExt->cndStrmOpen == 0);

    TRACE(TL_STRM_WARNING,("\'DVCloseStream: %d stream; AQD [%d:%d:%d]\n", 
        pDevExt->cndStrmOpen,
        pStrmExt->cntDataAttached,
        pStrmExt->cntSRBQueued,
        pStrmExt->cntDataDetached
        ));

#if DBG
    ASSERT(pStrmExt->DataListLockSave == pStrmExt->DataListLock);
#endif
    if(pStrmExt->DataListLock) {
        ExFreePool(pStrmExt->DataListLock); pStrmExt->DataListLock = NULL;
    }

    if(pStrmExt->hStreamMutex) {
        ExFreePool(pStrmExt->hStreamMutex); pStrmExt->hStreamMutex = NULL;
    }

    if(pStrmExt->DPCTimer) {
        ExFreePool(pStrmExt->DPCTimer); pStrmExt->DPCTimer = NULL;
    }

    if(pStrmExt->Timer) {
        ExFreePool(pStrmExt->Timer); pStrmExt->Timer = NULL;
    }


    //
    // Done with stream extention.  Will be invalid from this point on.
    //
#if 0
    RtlZeroMemory(pStrmExt, sizeof(STREAMEX));
#endif
    return STATUS_SUCCESS;
}


NTSTATUS
DVChangePower(
    PDVCR_EXTENSION  pDevExt,
    PAV_61883_REQUEST pAVReq,
    DEVICE_POWER_STATE NewPowerState
    )
/*++

Routine Description:

    Process changing this device's power state.  

--*/
{
    ULONG i;   
    NTSTATUS Status;

    PAGED_CODE();


    // 
    //    D0: Device is on and can be streaming.
    //    D1,D2: not supported.
    //    D3: Device is off and can not streaming. The context is lost.  
    //        Power can be removed from the device.
    //        When power is back on, we will get a bus reset.
    //

    TRACE(TL_PNP_WARNING,("\'PowrSt: %d->%d; (d0:[1:On],D3[4:off])\n", pDevExt->PowerState, NewPowerState));

    Status = STATUS_SUCCESS;

    if(pDevExt->PowerState == NewPowerState) {
        TRACE(TL_PNP_WARNING,("\'ChangePower: same power state!\n"));
        return STATUS_SUCCESS;
    }

    switch (NewPowerState) {
    case PowerDeviceD3:  // Power OFF   
        // We are at D0 and ask to go to D3: save state, stop streaming and Sleep
        if( pDevExt->PowerState == PowerDeviceD0)  {

            pDevExt->PowerState = NewPowerState;

            // For a supported power state change
            for (i=0; i<DV_STREAM_COUNT; i++) {
                if(pDevExt->paStrmExt[i]) {
                    TRACE(TL_PNP_WARNING,("\'D0->D3 (PowerOff), pStrmExt:%x; StrmSt:%d; IsochActive:%d; SrbQ:%d\n", 
                        pDevExt->paStrmExt[i], pDevExt->paStrmExt[i]->StreamState, pDevExt->paStrmExt[i]->bIsochIsActive, pDevExt->paStrmExt[i]->cntSRBQueued));

                    //
                    // Halt attach frame thread if it is an input pin
                    //
                    if(
                          pDevExt->paStrmExt[i]->pAttachFrameThreadObject  // If thread is created!
                       && !pDevExt->paStrmExt[i]->bTerminateThread         // Not terminated abnormally
                       && pDevExt->paStrmExt[i]->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN
                      ) {
                        NTSTATUS StatusWait;
#if 1
                        // Will be set in the thread attaching thread.
                        KeClearEvent(&pDevExt->paStrmExt[i]->hStopThreadEvent);
#endif
                        InterlockedIncrement(&pDevExt->paStrmExt[i]->lNeedService);   // Need thread to stop for other service.
                        
                        // In case the attach frame thread is idle! (no data to attach!)
                        KeSetEvent(&pDevExt->paStrmExt[i]->hSrbArriveEvent, 0 ,FALSE);
#ifdef SUPPORT_PREROLL_AT_RUN_STATE
                        KeSetEvent(&pDevExt->paStrmExt[i]->hPreRollEvent, 0 ,FALSE);
#endif

                        TRACE(TL_PNP_WARNING,("\'>>>> DVChangePower: Enter WFSO(hStopThreadEvent; lNeedService:%d)\n", pDevExt->paStrmExt[i]->lNeedService));
                        StatusWait = 
                            KeWaitForSingleObject(
                                &pDevExt->paStrmExt[i]->hStopThreadEvent,  // Signal when thread has stopped. 
                                Executive, 
                                KernelMode, 
                                FALSE, 
                                0  
                                );
                        TRACE(TL_PNP_WARNING,("\'<<<< DVChangePower: Exit WFSO(hStopThreadEvent; lNeedService:%d)\n", pDevExt->paStrmExt[i]->lNeedService));
                    }

                    if(pDevExt->paStrmExt[i]->bIsochIsActive) {
                        // Stop isoch but do not change the streaming state
                        TRACE(TL_PNP_WARNING,("\'ChangePower: Stop isoche; StrmSt:%d\n", pDevExt->paStrmExt[i]->StreamState)); 
                        DVStreamingStop(
                            pDevExt->paStrmExt[i], 
                            pDevExt, 
                            pAVReq
                            ) ;
                    }

                    // Complete all the pending events so that the downstream 
                    // filter (Video render) can release this buffer from AdviseTime() event.
                    // However, not sure why this is necessary since the lower filter 
                    // will get a PAUSE() or STOP() from the filter manager.  In such                    
                    DVSignalClockEvent(0, pDevExt->paStrmExt[i], 0, 0); 
                }
            }
        }
        else {
            TRACE(TL_PNP_WARNING,("\'ChangePower: unsupported %d -> %d; (do nothing!).\n", pDevExt->PowerState, DevicePowerState));           
        }
        break;

    case PowerDeviceD0:  // Powering ON (waking up)
        if( pDevExt->PowerState == PowerDeviceD3) {

            // Set PowerState change and then Signal PowerOn event
            pDevExt->PowerState = NewPowerState; 

            // For a supported power state change
            for (i=0; i<DV_STREAM_COUNT; i++) {
                if(pDevExt->paStrmExt[i]) {
                    TRACE(TL_PNP_WARNING,("\'D3->D0 (PowerOn), pStrmExt:%x; StrmSt:%d; IsochActive:%d; SrbQ:%d\n", 
                        pDevExt->paStrmExt[i], pDevExt->paStrmExt[i]->StreamState, pDevExt->paStrmExt[i]->bIsochIsActive, pDevExt->paStrmExt[i]->cntSRBQueued));
                    if(!pDevExt->paStrmExt[i]->bIsochIsActive) {
                        TRACE(TL_PNP_WARNING,("\'ChangePower: StrmSt:%d; Start isoch\n", pDevExt->paStrmExt[i]->StreamState)); 
                        // Start isoch depending on streaming state for DATAFLOW_IN/OUT
                        if(pDevExt->paStrmExt[i]->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN) {
                            if(pDevExt->paStrmExt[i]->StreamState == KSSTATE_PAUSE ||
                                pDevExt->paStrmExt[i]->StreamState == KSSTATE_RUN) {                             
                                DVStreamingStart(
                                    pDevExt->paStrmExt[i]->pStrmInfo->DataFlow, 
                                    pDevExt->paStrmExt[i], 
                                    pDevExt
                                    ) ;
                            }
                        }
                        else if(pDevExt->paStrmExt[i]->pStrmInfo->DataFlow == KSPIN_DATAFLOW_OUT) {
                            if(pDevExt->paStrmExt[i]->StreamState == KSSTATE_RUN) {                             
                                DVStreamingStart(
                                    pDevExt->paStrmExt[i]->pStrmInfo->DataFlow, 
                                    pDevExt->paStrmExt[i], 
                                    pDevExt
                                    ) ;
                            }
                        }                    
                    }  // IsochActive
#if 1  // Clear any buffer queued in the downstream.
                    // Complete all the pending events so that the downstream 
                    // filter (Video render) can release this buffer from AdviseTime() event.
                    // However, not sure why this is necessary since the lower filter 
                    // will get a PAUSE() or STOP() from the filter manager.  In such                    
                    DVSignalClockEvent(0, pDevExt->paStrmExt[i], 0, 0); 
#endif

                    //
                    // Resume attaching frame operation
                    //
                    if(
                          pDevExt->paStrmExt[i]->pAttachFrameThreadObject  // If thread is created!
                       && !pDevExt->paStrmExt[i]->bTerminateThread         // Not terminated abnormally
                       && pDevExt->paStrmExt[i]->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN
                      ) {
                        KeSetEvent(&pDevExt->paStrmExt[i]->hRunThreadEvent, 0 ,FALSE);
                    }
                }
            }
        }
        else {
            TRACE(TL_PNP_WARNING,("\'ChangePower: supported %d -> %d; (do nothing!).\n", pDevExt->PowerState, DevicePowerState));           
        }
        break;

    // These state are not supported.
    case PowerDeviceD1:
    case PowerDeviceD2:               
    default:
        TRACE(TL_PNP_WARNING,("\'ChangePower: unsupported %d to %d (do nothing).\n", pDevExt->PowerState, DevicePowerState));
        Status = STATUS_SUCCESS; // STATUS_INVALID_PARAMETER;
        break;
    }
           

    if(Status == STATUS_SUCCESS) 
        pDevExt->PowerState = NewPowerState;         
    else 
        Status = STATUS_NOT_IMPLEMENTED;

    TRACE(TL_PNP_WARNING,("\'DVChangePower: Exiting; Status:%x\n", Status));

    return STATUS_SUCCESS;     
}


NTSTATUS
DVSurpriseRemoval(
    PDVCR_EXTENSION pDevExt,
    PAV_61883_REQUEST  pAVReq
    )

/*++

Routine Description:

    Response to SRB_SURPRISE_REMOVAL.

--*/

{
    ULONG i;
    KIRQL    oldIrql;
    PKSEVENT_ENTRY   pEvent = NULL;

    PAGED_CODE();

    //
    // ONLY place this flag is set to TRUE.
    // Block incoming read although there might still in the process of being attached
    //
    KeAcquireSpinLock(&pDevExt->AVCCmdLock, &oldIrql);            
    pDevExt->bDevRemoved = TRUE;
    KeReleaseSpinLock(&pDevExt->AVCCmdLock, oldIrql);


    //
    // Now Stop the stream and clean up
    //

    for(i=0; i < DV_STREAM_COUNT; i++) {
        
        if(pDevExt->paStrmExt[i] != NULL) {

            TRACE(TL_PNP_WARNING,("\' #SURPRISE_REMOVAL# StrmNum %d, pStrmExt %x, Attached %d\n", 
                i, pDevExt->paStrmExt[i], pDevExt->paStrmExt[i]->cntDataAttached));

            // Signal this event so SRB can complete.
            if(pDevExt->paStrmExt[i]->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN ) {

                //
                // Imply EOStream! so the data source will stop sending us data.
                //
                KeAcquireSpinLock( pDevExt->paStrmExt[i]->DataListLock, &oldIrql);             
                if(!pDevExt->paStrmExt[i]->bEOStream)
                    pDevExt->paStrmExt[i]->bEOStream = TRUE;
                //
                // Signal EOStream
                //
                StreamClassStreamNotification(
                    SignalMultipleStreamEvents,
                    pDevExt->paStrmExt[i]->pStrmObject,
                    (GUID *)&KSEVENTSETID_Connection_Local,
                    KSEVENT_CONNECTION_ENDOFSTREAM
                    );
                TRACE(TL_PNP_WARNING,("\'Signal KSEVENT_CONNECTION_ENDOFSTREAM\n"));

                //
                // Stop the attaching frame thread
                //
                if(
                      pDevExt->paStrmExt[i]->pAttachFrameThreadObject  // If thread is created!
                   && !pDevExt->paStrmExt[i]->bTerminateThread
                  ) {
                    NTSTATUS StatusWait;
#if 1
                    // Will be set in the thread attaching thread.
                    KeClearEvent(&pDevExt->paStrmExt[i]->hStopThreadEvent);
#endif
                    InterlockedIncrement(&pDevExt->paStrmExt[i]->lNeedService);   // Request count
                        
                    // In case the attach frame thread is idle! (no data to attach!)
                    KeSetEvent(&pDevExt->paStrmExt[i]->hSrbArriveEvent, 0 ,FALSE);
#ifdef SUPPORT_PREROLL_AT_RUN_STATE
                    KeSetEvent(&pDevExt->paStrmExt[i]->hPreRollEvent,   0 ,FALSE);
#endif
                    KeReleaseSpinLock( pDevExt->paStrmExt[i]->DataListLock, oldIrql);                  

                    TRACE(TL_PNP_WARNING,("\'>>>> DVSurpriseRemoval: Enter WFSO(hStopThreadEvent; lNeedService:%d)\n", pDevExt->paStrmExt[i]->lNeedService));
                    StatusWait = 
                        KeWaitForSingleObject(
                            &pDevExt->paStrmExt[i]->hStopThreadEvent,  // Signal when thread has stopped. 
                            Executive, 
                            KernelMode, 
                            FALSE, 
                            0  
                            );
                    TRACE(TL_PNP_WARNING,("\'<<<< DVSurpriseRemoval: Exit WFSO(hStopThreadEvent; lNeedService:%d)\n", pDevExt->paStrmExt[i]->lNeedService));

                    //
                    // Note:
                    //   Terminate AttachFraameThread: KeSetEvent(&pDevExt->hRunThreadEvent, 0 ,FALSE) 
                    // 
                } else {
                    KeReleaseSpinLock( pDevExt->paStrmExt[i]->DataListLock, oldIrql); 
                }
            }

            //
            // Abort stream; stop and cancel pending data request
            //
            TRACE(TL_PNP_WARNING,("\'DVSurpriseRemoval: AbortStream enter...\n"));
            if(!DVAbortStream(pDevExt, pDevExt->paStrmExt[i])) {
                TRACE(TL_PNP_ERROR,("\'DVSurpriseRemoval: AbortStream failed\n"));
            }

            //
            // Adter surprise removal, all call to lower stack will be returned
            // with error.  Let's disconnect if it is connected.
            //

            //
            // Disable the timer
            //
            if(pDevExt->paStrmExt[i]->bTimerEnabled) {
                KeCancelTimer(
                    pDevExt->paStrmExt[i]->Timer
                    );
                pDevExt->paStrmExt[i]->bTimerEnabled = FALSE;
            }

            //
            // Wait until the pending work item is completed.  
            //
            TRACE(TL_PNP_WARNING,("\'SupriseRemoval: Wait for CancelDoneEvent <entering>; lCancelStateWorkItem:%d\n", pDevExt->paStrmExt[i]->lCancelStateWorkItem));
            KeWaitForSingleObject( &pDevExt->paStrmExt[i]->hCancelDoneEvent, Executive, KernelMode, FALSE, 0 );
            TRACE(TL_PNP_WARNING,("\'SupriseRemoval: Wait for CancelDoneEvent <exited>...\n"));
        }
    }


    // Signal KSEvent that device is removed.
    // After this SRb, there will be no more Set/Get property Srb into this driver.
    // By notifying the COM I/F, it will wither signal application that device is removed and
    // return ERROR_DEVICE_REMOVED error code for subsequent calls.

    // There might be multiple instances/threads of IAMExtTransport instance with the same KS event.
    // There is only one device so they all enabled event are singalled.
    do {
        if(pEvent = StreamClassGetNextEvent((PVOID) pDevExt, 0, \
            (GUID *)&KSEVENTSETID_EXTDEV_Command, KSEVENT_EXTDEV_NOTIFY_REMOVAL, pEvent)) {            
            // Make sure the right event and then signal it
            if(pEvent->EventItem->EventId == KSEVENT_EXTDEV_NOTIFY_REMOVAL) {
                StreamClassDeviceNotification(SignalDeviceEvent, pDevExt, pEvent);
                TRACE(TL_PNP_WARNING,("\'->Signal NOTIFY_REMOVAL; pEvent:%x, EventId %d.\n", pEvent, pEvent->EventItem->EventId));
            }          
        }  
    } while (pEvent != NULL);

    //
    // Since we may not get the busreset, let's go ahead and cancel all pending device control
    //
    DVAVCCmdResetAfterBusReset(pDevExt);

#ifdef NT51_61883
    //
    // Delete plug; 61883 will not accept 61883 request after surprise removal is processed.
    //
    if(pDevExt->hOPcrPC) {
        // Do not care about return status since we are being unloaded.
        DVDeleteLocalPlug( 
            pDevExt,
            pDevExt->hOPcrPC
            );
        pDevExt->hOPcrPC = NULL;
    }
#endif
   
    TRACE(TL_PNP_WARNING,("\'SurpriseRemoval exiting.\n"));
    return STATUS_SUCCESS;
}


// Return code is basically return in pSrb->Status.
NTSTATUS
DVProcessPnPBusReset(
    PDVCR_EXTENSION  pDevExt
    )
/*++

Routine Description:

    Process a bus reset.

Arguments:

    Srb - Pointer to stream request block

Return Value:

    Nothing

--*/
{   
#ifdef MSDVDV_SUPPORT_BUSRESET_EVENT
    PKSEVENT_ENTRY   pEvent;
#endif

    PAGED_CODE();


    TRACE(TL_PNP_WARNING,("\'DVProcessPnPBusReset: >>\n"));
    
#ifdef MSDVDV_SUPPORT_BUSRESET_EVENT
    //
    // Signal (if enabled) busreset event to let upper layer know that a busreset has occurred.
    //
    pEvent = NULL;
    pEvent = 
        StreamClassGetNextEvent(
            (PVOID) pDevExt,
            0, 
            (GUID *)&KSEVENTSETID_EXTDEV_Command,
            KSEVENT_EXTDEV_COMMAND_BUSRESET,
            pEvent
            );

    if(pEvent) {
        //
        // signal the event here
        //    
        if(pEvent->EventItem->EventId == KSEVENT_EXTDEV_COMMAND_BUSRESET) {
            StreamClassDeviceNotification(
                SignalDeviceEvent,
                pDevExt,
                pEvent
                );        

            TRACE(TL_PNP_WARNING,("\'DVProcessPnPBusReset: Signal BUSRESET; EventId %d.\n", pEvent->EventItem->EventId));
        }
    }
#endif   

    //
    // Reset pending count and AVC command that is in Interim
    //
    DVAVCCmdResetAfterBusReset(pDevExt);


    //
    // Can we return anything other than SUCCESS ?
    //
    return STATUS_SUCCESS;
}   


NTSTATUS
DVUninitializeDevice(
    IN PDVCR_EXTENSION  pDevExt
    )
/*++

Routine Description:

    This where we perform the necessary initialization tasks.

Arguments:

    Srb - Pointer to stream request block
'
Return Value:

    Nothing

--*/
{
    PAGED_CODE();

    TRACE(TL_PNP_WARNING,("\'DVUnInitialize: enter with DeviceExtension=0x%8x\n", pDevExt));

    //
    // Clear all pending AVC command entries.
    //
    DVAVCCmdResetAfterBusReset(pDevExt);


    // Free stream information allocated
    if(pDevExt->paCurrentStrmInfo) {
        ExFreePool(pDevExt->paCurrentStrmInfo);
        pDevExt->paCurrentStrmInfo = NULL;
    }

#ifdef NT51_61883
    if(pDevExt->hOPcrPC) {
        // Do not care about return status since we are being unloaded.
        DVDeleteLocalPlug( 
            pDevExt,
            pDevExt->hOPcrPC
            );
        pDevExt->hOPcrPC = NULL;
    }
#endif

    TRACE(TL_PNP_WARNING,("\'DVUnInitialize: Rest of allocated resources freed.\n"));

    return STATUS_SUCCESS;
}


//*****************************************************************************
//*****************************************************************************
// S T R E A M    S R B
//*****************************************************************************
//*****************************************************************************


NTSTATUS
DVGetStreamState(
    PSTREAMEX  pStrmExt,
    PKSSTATE   pStreamState,
    PULONG     pulActualBytesTransferred
    )
/*++

Routine Description:

    Gets the current state of the requested stream

--*/
{

    PAGED_CODE();

    if(!pStrmExt) {
        TRACE(TL_STRM_ERROR,("\'GetStreamState: pStrmExt is NULL; STATUS_UNSUCCESSFUL\n"));
        return STATUS_UNSUCCESSFUL;        
    }

    *pStreamState = pStrmExt->StreamState;
    *pulActualBytesTransferred = sizeof (KSSTATE);

    TRACE(TL_STRM_TRACE,("\'GetStreamState: %d (was %d)\n", pStrmExt->StreamState, pStrmExt->StreamStatePrevious));

    if(pStrmExt->StreamState == KSSTATE_PAUSE) {

        // One way to preroll is to delay when querying getting into the PAUSE state.
        // However, this routine is never executed!  So we move this section of code
        // to the thread.
#ifdef SUPPORT_PREROLL_AT_RUN_STATE
        if(   pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN
           && pStrmExt->hMasterClock  
           && pStrmExt->CurrentStreamTime == 0
          ) {
            // Simulate preroll at the RUN state
            // We do this only when we are the clock provider to avoid dropping frame
#define PREROLL_WAITTIME 2000000
            NTSTATUS StatusWait;
            LARGE_INTEGER DueTime;                 
            DueTime = RtlConvertLongToLargeInteger(-((LONG) PREROLL_WAITTIME));

            StatusWait =  // Can only return STATUS_SUCCESS (signal) or STATUS_TIMEOUT
                KeWaitForSingleObject( 
                    &pStrmExt->hPreRollEvent,
                    Executive,
                    KernelMode,          // Cannot return STATUS_USER_APC
                    FALSE,               // Cannot be alerted STATUS_ALERTED
                    &DueTime
                    );
             TRACE(TL_STRM_WARNING,("\'GetState: *Preroll*, waited %d msec; waitStatus:%x; srbRcved:%d\n", 
                 (DWORD) ((GetSystemTime() - pStrmExt->tmStreamPause)/10000), StatusWait,
                 (DWORD) pStrmExt->cntSRBReceived));
        }
#endif
        // A very odd rule:
        // When transitioning from stop to pause (and run->pause), DShow tries to preroll
        // the graph.  Capture sources can't preroll (there is no data until 
        // capture begin/run state), and indicate this by returning 
        // VFW_S_CANT_CUE (Map by KsProxy) in user mode.  To indicate this
        // condition from drivers, they must return ERROR_NO_DATA_DETECTED
        if(pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_OUT)            
            return STATUS_NO_DATA_DETECTED;        
        else 
            return STATUS_SUCCESS;
    } else 
        return STATUS_SUCCESS;
}

NTSTATUS
DVStreamingStop( 
    PSTREAMEX        pStrmExt,
    PDVCR_EXTENSION  pDevExt,
    PAV_61883_REQUEST   pAVReq
    )
/*++
Routine Description:

    Transitioning from any state to ->STOP state.
    Stops the video stream and cleans up all the descriptors;
    
++*/
{
    NTSTATUS   Status = STATUS_SUCCESS;
    PIRP pIrp;
    KIRQL oldIrql;

    PAGED_CODE();

#ifdef SUPPORT_NEW_AVC
    // No need to do CIP if it is device to device connection
    if(pStrmExt->bDV2DVConnect) {
        if(pStrmExt->bIsochIsActive)
            pStrmExt->bIsochIsActive = FALSE;
        return STATUS_SUCCESS;
    }
#endif

    //
    // Stop isoch listen or talk
    // Note: streaming and stream state can be separate; e.g. SURPRISE_REMOVAL, 
    //       we will stop stream but stream state does note get changed by this SRB.
    //

    if(pStrmExt->bIsochIsActive && pStrmExt->hConnect) {
       
        if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE)))
            return STATUS_INSUFFICIENT_RESOURCES;              

        RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
        INIT_61883_HEADER(pAVReq, Av61883_Stop);
        pAVReq->Stop.hConnect = pStrmExt->hConnect;

        if(!NT_SUCCESS(
            Status = DVSubmitIrpSynch( 
                pDevExt,
                pIrp,
                pAVReq
                ))) {

            TRACE(TL_61883_ERROR|TL_STRM_ERROR,("\'Av61883_Stop Failed; Status:%x\n", Status));
#if 1
            KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
            pStrmExt->bIsochIsActive = FALSE;  // Set it.  If this fail, it is a lower stack problem!
            KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
            ASSERT(NT_SUCCESS(Status) && "Av61883_Stop failed!");
            Status = STATUS_SUCCESS;
#endif
        } else {
            KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
            pStrmExt->bIsochIsActive = FALSE;
            KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
        }

        IoFreeIrp(pIrp);

        TRACE(TL_STRM_WARNING,("\'StreamingSTOPped; AQD [%d:%d:%d]\n", 
            pStrmExt->cntDataAttached,
            pStrmExt->cntSRBQueued,
            pStrmExt->cntDataDetached
            ));
    }

    return Status;
}


NTSTATUS
DVStreamingStart(
    KSPIN_DATAFLOW  ulDataFlow,
    PSTREAMEX       pStrmExt,
    PDVCR_EXTENSION pDevExt
    )
/*++
Routine Description:

    Tell device to start streaming.

++*/
{  
    PIRP         pIrp;
    NTSTATUS     Status;
    PAV_61883_REQUEST  pAVReq;
#if DBG
    ULONGLONG tmStart = GetSystemTime();
#endif


    PAGED_CODE();

#ifdef SUPPORT_NEW_AVC
    // No need to do CIP if it is device to device connection
    if(pStrmExt->bDV2DVConnect) {
        if(!pStrmExt->bIsochIsActive)
            pStrmExt->bIsochIsActive = TRUE;
        return STATUS_SUCCESS;
    }
#endif


    // NOTE: MUTEX is not needed since we are not staring isoch while attaching data.
    // This call is not reentry!!



    // Since it take time to activate isoch transfer, 
    // this sychronous function might get call again.
    // Need to start streaming only once.
    if(InterlockedExchange(&pStrmExt->lStartIsochToken, 1) == 1) {        
        TRACE(TL_STRM_WARNING,("\'lStartIsochToken taken already; return STATUS_SUCCESS\n"));
        return STATUS_SUCCESS;
    } 

#if DBG
    // Can stream only if in power on state.
    if(pDevExt->PowerState != PowerDeviceD0) {
        TRACE(TL_STRM_ERROR,("\'StreamingStart: PowerSt:%d; StrmSt:%d\n", pDevExt->PowerState, pStrmExt->StreamState));
        ASSERT(pDevExt->PowerState == PowerDeviceD0 && "Power state must be ON to start streaming!");
    }
#endif

    if(pStrmExt->bIsochIsActive) {
        TRACE(TL_STRM_WARNING,("\nIsoch already active!\n"));
        InterlockedExchange(&pStrmExt->lStartIsochToken, 0);
        return STATUS_SUCCESS;
    }
    else 
    if(!pStrmExt->hConnect) {
        TRACE(TL_STRM_WARNING,("hConnect=0, Cannot start isoch!\n"));
        InterlockedExchange(&pStrmExt->lStartIsochToken, 0);
        return STATUS_INVALID_PARAMETER;
    }
    else {
       
        if(!(pAVReq = (AV_61883_REQUEST *) ExAllocatePool(NonPagedPool, sizeof(AV_61883_REQUEST)))) {
            InterlockedExchange(&pStrmExt->lStartIsochToken, 0);
            return STATUS_INSUFFICIENT_RESOURCES;            
        }

        if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE))) {
            InterlockedExchange(&pStrmExt->lStartIsochToken, 0);
            ExFreePool(pAVReq);  pAVReq = NULL;
            return STATUS_INSUFFICIENT_RESOURCES;
        }

        RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
        if(ulDataFlow == KSPIN_DATAFLOW_OUT) {
            INIT_61883_HEADER(pAVReq, Av61883_Listen);
            pAVReq->Listen.hConnect = pStrmExt->hConnect;
        } else {
            INIT_61883_HEADER(pAVReq, Av61883_Talk);
            pAVReq->Talk.hConnect = pStrmExt->hConnect;
        }

        TRACE(TL_STRM_WARNING,("\'StreamingSTART; flow %d; AQD [%d:%d:%d]\n", 
            ulDataFlow, 
            pStrmExt->cntDataAttached,
            pStrmExt->cntSRBQueued,
            pStrmExt->cntDataDetached
            ));

        if(NT_SUCCESS(
            Status = DVSubmitIrpSynch( 
                pDevExt,
                pIrp,
                pAVReq
                ))) {
            pStrmExt->bIsochIsActive = TRUE;
            TRACE(TL_STRM_WARNING,("\'Av61883_%s; Status %x; Streaming...; took:%d (msec)\n", 
                (ulDataFlow == KSPIN_DATAFLOW_OUT ? "Listen" : "Talk"), Status, 
                (DWORD) ((GetSystemTime() - tmStart)/10000) ));
        }
        else {
            TRACE(TL_61883_ERROR|TL_STRM_ERROR,("Av61883_%s; failed %x; pAVReq:%x\n", (ulDataFlow == KSPIN_DATAFLOW_OUT ? "Listen" : "Talk"), Status, pAVReq));
            // ASSERT(NT_SUCCESS(Status) && "Start isoch failed!");
        }

        ExFreePool(pAVReq);  pAVReq = NULL;
        IoFreeIrp(pIrp);  pIrp = NULL;
    }

    InterlockedExchange(&pStrmExt->lStartIsochToken, 0);

    return Status;
}



NTSTATUS
DVSetStreamState(
    PSTREAMEX        pStrmExt,
    PDVCR_EXTENSION  pDevExt,
    PAV_61883_REQUEST   pAVReq,
    KSSTATE          StreamState
    )
/*++

Routine Description:

    Set to a new stream state.

--*/

{
    NTSTATUS Status = STATUS_SUCCESS;
    
    PAGED_CODE();

    if(!pStrmExt)  
        return STATUS_UNSUCCESSFUL;          

    TRACE(TL_STRM_WARNING,("\'** (%x) Set StrmST from %d to %d; PowerSt:%d (1/On;4/Off]); SrbRcved:%d\n",
        pStrmExt, pStrmExt->StreamState, StreamState, pDevExt->PowerState, (DWORD) pStrmExt->cntSRBReceived ));

#if DBG
    if(StreamState == KSSTATE_RUN) {
        ASSERT(pDevExt->PowerState == PowerDeviceD0 && "Cannot set to RUN while power is off!");
    }
#endif
    switch(StreamState) {

    case KSSTATE_STOP:
      
        if(pStrmExt->StreamState != KSSTATE_STOP) { 
     
            KeWaitForSingleObject( pStrmExt->hStreamMutex, Executive, KernelMode, FALSE, 0 );

            // Once this is set, data stream will reject SRB_WRITE/READ_DATA
            pStrmExt->StreamStatePrevious = pStrmExt->StreamState;  // Cache previous stream state.
            pStrmExt->StreamState = KSSTATE_STOP;

            // If stop, must be EOStream; but not vice versa.
            if(!pStrmExt->bEOStream) {
                pStrmExt->bEOStream = TRUE;
            }

            // Stop the IOThread from processing
            if(pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN) {
                KeClearEvent(&pStrmExt->hSrbArriveEvent);
#ifdef SUPPORT_PREROLL_AT_RUN_STATE
                KeClearEvent(&pStrmExt->hPreRollEvent);
#endif
            }

            KeReleaseMutex(pStrmExt->hStreamMutex, FALSE); 

            //
            // If there is a cancel event, we must wait for it to complete.
            //

            TRACE(TL_STRM_WARNING,("\'KSSTATE_STOP: pStrmExt->lCancelStateWorkItem:%d\n", pStrmExt->lCancelStateWorkItem)); 
            KeWaitForSingleObject( &pStrmExt->hCancelDoneEvent, Executive, KernelMode, FALSE, 0 );
            ASSERT(pStrmExt->lCancelStateWorkItem == 0 && "KSSTATE_STOP while there is an active CancelStateWorkItem");
            
            //
            // Stop stream, cacel data requests, terminate thread and disconnect.
            // This routine must suceeded in setting to STOP state
            //
            if(!NT_SUCCESS(
                Status = DVStopCancelDisconnect(
                    pStrmExt
                    ))) {
                Status = STATUS_SUCCESS;  // Cannot fail setting to stop state.
            }

        }

        break;

    case KSSTATE_ACQUIRE:
        //
        // This is a KS only state, that has no correspondence in DirectShow
        // It is our opportunity to allcoate resoruce (isoch bandwidth and program PCR (make connection)).
        //

        if(pStrmExt->StreamState == KSSTATE_STOP) { 

            //
            // Create a dispatch thread to attach frame to transmit to DV
            // This is create the first time transitioning from STOP->ACQUIRE state
            //

            if(
                  KSPIN_DATAFLOW_IN == pStrmExt->pStrmInfo->DataFlow
               && pStrmExt->pAttachFrameThreadObject == NULL 
              ) {

                //
                // Create a system thread for attaching data (for transmiut to DV only).
                //
                if(!NT_SUCCESS(
                    Status = DVCreateAttachFrameThread(
                        pStrmExt
                        ))) {
                    // Note that intially hConnect is NULL.
                    break;  // Cannot attach frame without this thread.
                }
            }


            //
            // Make connection
            //
            Status = 
                DVConnect(
                    pStrmExt->pStrmInfo->DataFlow,
                    pDevExt,
                    pStrmExt,
                    pAVReq
                    );

            if(!NT_SUCCESS(Status)) {

                TRACE(TL_STRM_ERROR,("\'Acquire failed; ST %x\n", Status));
                // ASSERT(NT_SUCCESS(Status));

                //
                // Change to generic insufficient resource status.
                //
                Status = STATUS_INSUFFICIENT_RESOURCES;

                //
                // Note: even setting to this state failed, KSSTATE_PAUSE will still be called;
                // Since hConnect is NULL, STATUS_INSUFFICIENT_RESOURCES will be returned.
                //
            } else {

                //
                // Verify connection by query the plug state
                //            
                DVGetPlugState(
                    pDevExt,
                    pStrmExt,
                    pAVReq
                    );
            }
        }

        break;

    case KSSTATE_PAUSE:                   

           
        if(pStrmExt->StreamState == KSSTATE_ACQUIRE || 
           pStrmExt->StreamState == KSSTATE_STOP)   {  

#ifdef SUPPORT_NEW_AVC
            if(!pStrmExt->bDV2DVConnect && pStrmExt->hConnect == NULL) {
#else
            if(pStrmExt->hConnect == NULL) {
#endif
                TRACE(TL_STRM_ERROR,("\'hConnect is NULL; STATUS_INSUFFICIENT_RESOURCES\n"));
                // Cannot stream without connection!
                Status = STATUS_INSUFFICIENT_RESOURCES;
                break;
            }

            //
            // Reset when transition from STOP to PAUSE state
            //

            // The system time (1394 CycleTime) will continue while setting
            // from RUN to PAUSE state.  
            pStrmExt->b1stNewFrameFromPauseState = TRUE;

#ifdef SUPPORT_QUALITY_CONTROL
            // +: late; -: early
            pStrmExt->KSQuality.DeltaTime = 0; // On time
            // Percentage * 10 of frame transmitted
            pStrmExt->KSQuality.Proportion = 1000;  // 100% sent
            pStrmExt->KSQuality.Context = /* NOT USED */ 0; 
#endif

            pStrmExt->CurrentStreamTime = 0;

            pStrmExt->FramesProcessed = 0;
            pStrmExt->PictureNumber   = 0;
            pStrmExt->FramesDropped   = 0;

            pStrmExt->cntSRBReceived  = 0;
            pStrmExt->cntSRBCancelled = 0;  // number of SRB_READ/WRITE_DATA cancelled
            pStrmExt->bEOStream       = FALSE;
#if DBG
            //
            // Initialize the debug log structure.
            //
            if(pStrmExt->paXmtStat) {
                pStrmExt->ulStatEntries   = 0;
                pStrmExt->lFramesAccumulatedPaused = 0;
                pStrmExt->lFramesAccumulatedRun    = 0;
                RtlZeroMemory(pStrmExt->paXmtStat, sizeof(XMT_FRAME_STAT) * MAX_XMT_FRAMES_TRACED);
            }
#endif

            //
            // Reset this event in case graph is restarted.
            // This evant will wait for enough buffers before start attaching frame for transmit
            //
            if(pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN) {
                KeClearEvent(&pStrmExt->hSrbArriveEvent);

#ifdef SUPPORT_PREROLL_AT_RUN_STATE                
                KeClearEvent(&pStrmExt->hPreRollEvent);
#if DBG
                pStrmExt->tmStreamPause = GetSystemTime();
#endif
#ifdef SUPPORT_KSPROXY_PREROLL_CHANGE
                pStrmExt->StreamStatePrevious = pStrmExt->StreamState;  // Cache previous stream state.
                pStrmExt->StreamState = StreamState;
#ifdef SUPPORT_NEW_AVC
                if(pStrmExt->bDV2DVConnect)
                    return STATUS_SUCCESS;
                else {
#endif  // SUPPORT_NEW_AVC
                    TRACE(TL_STRM_WARNING,("\'Set to KSSTATE_PAUSE; return STATUS_ALERTED\n"));
                    // We want to preroll.
                    return STATUS_ALERTED; 
#ifdef SUPPORT_NEW_AVC
                }
#endif  // SUPPORT_NEW_AVC
#endif  // SUPPORT_KSPROXY_PREROLL_CHANGE
#endif  // SUPPORT_PREROLL_AT_RUN_STATE
            }

        } else if (pStrmExt->StreamState == KSSTATE_RUN) {

            // The system time (1394 CycleTime) will continue while setting
            // from RUN to PAUSE state.  
            pStrmExt->b1stNewFrameFromPauseState = TRUE;

            //
            // Stop only if listening; for talking, the "pause" frame will be repeated
            //
            if(pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_OUT) {               
                // stop the stream internally inside 1394 stack
                DVStreamingStop(
                    pStrmExt,
                    pDevExt,
                    pAVReq
                    );
            } else {
                // Talk will continue.
                //    Do not stop isoch talk until stop state.
            }

            //
            // StreamTime pauses, so pause checking for expired clock events.
            // Resume if we enter RUN state again.
            //
            if(pStrmExt->bTimerEnabled) {
                TRACE(TL_STRM_TRACE,("\'*** (RUN->PAUSE) CancelTimer *********************************************...\n"));               
                KeCancelTimer(
                    pStrmExt->Timer
                    );
                pStrmExt->bTimerEnabled = FALSE;

                //
                // Complete any pending clock events
                //
                DVSignalClockEvent(0, pStrmExt, 0, 0);
            }
        }
        break;
                    
    case KSSTATE_RUN:

        if(pStrmExt->StreamState != KSSTATE_RUN) { 

            TRACE(TL_STRM_WARNING,("\'*RUN: hClock %x; hMasterClk %x; cntAttached:%d; StrmTm:%d\n", pStrmExt->hClock, pStrmExt->hMasterClock, pStrmExt->cntDataAttached, (DWORD) (pStrmExt->CurrentStreamTime/10000) ));

#if DBG
            if(!pStrmExt->hMasterClock && !pStrmExt->hClock)
                TRACE(TL_STRM_WARNING,("\'KSSTATE_RUN: no clock so free flowing!\n"));
#endif            

            // Use to mark the tick count when the stream start running.
            // It is later used to calculate current stream time and dropped frames.
            pStrmExt->tmStreamStart = GetSystemTime();
            pStrmExt->LastSystemTime = pStrmExt->tmStreamStart;


            // We start the timer to signal clock event only if we are the clock provider.
            // The interval is set to half of a DV frame time.
            if(pStrmExt->hMasterClock) {
                LARGE_INTEGER DueTime;

                DueTime = RtlConvertLongToLargeInteger(-((LONG) DVFormatInfoTable[pDevExt->VideoFormatIndex].ulAvgTimePerFrame/2));
                TRACE(TL_STRM_WARNING,("\'*** ScheduleTimer (RUN) ***\n"));
                KeSetTimerEx(
                    pStrmExt->Timer,
                    DueTime,
                    DVFormatInfoTable[pDevExt->VideoFormatIndex].ulAvgTimePerFrame/20000,  // Repeat every 40 MilliSecond
                    pStrmExt->DPCTimer
                    );
                pStrmExt->bTimerEnabled = TRUE;
            }

            if(pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_OUT) {

                // Start isoch listen; isoch talk will be start in the dispatch thread in either PAUSE or RUN state.
                // VfW application may use only one buffer!  61883 is attaching the descriptor list 
                // not this subunit driver so so it is ok to start streaming immediately without checking 
                // number of buffers attached.
                Status = 
                    DVStreamingStart(
                        pStrmExt->pStrmInfo->DataFlow,
                        pStrmExt,
                        pDevExt
                        );         
            }
        }

        break;
                    
    default:
                    
        TRACE(TL_STRM_ERROR,("\'SetStreamState:  unknown state = %x\n",StreamState));
        Status = STATUS_NOT_SUPPORTED;
        break;
    }

    // Be sure to save the state of the stream.
    TRACE(TL_STRM_WARNING,("\'DVSetStreamState: (%x)  from %d -> %d, Status %x\n", pStrmExt, pStrmExt->StreamState, StreamState, Status));

    if(Status == STATUS_SUCCESS) {
        pStrmExt->StreamStatePrevious = pStrmExt->StreamState;  // Cache previous stream state.
        pStrmExt->StreamState = StreamState;
    }

    return Status;
}



NTSTATUS 
DVStreamGetConnectionProperty (
    PDVCR_EXTENSION pDevExt,
    PSTREAMEX pStrmExt,
    PSTREAM_PROPERTY_DESCRIPTOR pSPD,
    PULONG pulActualBytesTransferred
    )
/*++

Routine Description:

    Handles KS_PROPERTY_CONNECTION* request.  For now, only ALLOCATORFRAMING and
    CONNECTION_STATE are supported.

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;

    PAGED_CODE();


    TRACE(TL_STRM_TRACE,("\'DVStreamGetConnectionProperty:  entered ...\n"));

    switch (pSPD->Property->Id) {

    case KSPROPERTY_CONNECTION_ALLOCATORFRAMING:
        if (pDevExt != NULL && pDevExt->cndStrmOpen)  {
            PKSALLOCATOR_FRAMING pFraming = (PKSALLOCATOR_FRAMING) pSPD->PropertyInfo;
            
#ifdef SUPPORT_NEW_AVC 
            if(pStrmExt->bDV2DVConnect) {
                // No framing required.
                pFraming->RequirementsFlags = 0;
                pFraming->PoolType = DontUseThisType;
                pFraming->Frames = 0;
                pFraming->FrameSize = 0;
                pFraming->FileAlignment = 0; 
                pFraming->Reserved = 0;
            } else {
#endif
            pFraming->RequirementsFlags =
                KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY |
                KSALLOCATOR_REQUIREMENTF_INPLACE_MODIFIER |
                KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY;
            pFraming->PoolType = NonPagedPool;

            pFraming->Frames = \
                (pDevExt->paStrmExt[pDevExt->idxStreamNumber]->pStrmInfo->DataFlow == KSPIN_DATAFLOW_OUT ? \
                DVFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfRcvBuffers : \
                 DVFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfXmtBuffers);

            // Note:  we'll allocate the biggest frame.  We need to make sure when we're
            // passing the frame back up we also set the number of bytes in the frame.
            pFraming->FrameSize = DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize;
            pFraming->FileAlignment = 0; // FILE_LONG_ALIGNMENT;
            pFraming->Reserved = 0;
#ifdef SUPPORT_NEW_AVC 
            }
#endif
            *pulActualBytesTransferred = sizeof (KSALLOCATOR_FRAMING);

            TRACE(TL_STRM_TRACE,("\'AllocFraming: cntStrmOpen:%d; VdoFmtIdx:%d; Frames %d; size:%d\n", \
                pDevExt->cndStrmOpen, pDevExt->VideoFormatIndex, pFraming->Frames, pFraming->FrameSize));
        } else {
            TRACE(TL_STRM_WARNING,("\'AllocFraming: pDevExt:%x; cntStrmOpen:%d\n", pDevExt, pDevExt->cndStrmOpen));
            Status = STATUS_INVALID_PARAMETER;
        }
        break;
        
    default:
        *pulActualBytesTransferred = 0;
        Status = STATUS_NOT_SUPPORTED;
        break;
    }

    TRACE(TL_STRM_TRACE,("\'DVStreamGetConnectionProperty:  exit.\n"));
    return Status;
}


NTSTATUS
DVGetDroppedFramesProperty(  
    PDVCR_EXTENSION pDevExt,
    PSTREAMEX       pStrmExt,
    PSTREAM_PROPERTY_DESCRIPTOR pSPD,
    PULONG pulBytesTransferred
    )
/*++

Routine Description:

    Return the dropped frame information while captureing.

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
  
    PAGED_CODE();

    switch (pSPD->Property->Id) {

    case KSPROPERTY_DROPPEDFRAMES_CURRENT:
         {

         PKSPROPERTY_DROPPEDFRAMES_CURRENT_S pDroppedFrames = 
                     (PKSPROPERTY_DROPPEDFRAMES_CURRENT_S) pSPD->PropertyInfo;
         
         pDroppedFrames->AverageFrameSize = DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].ulFrameSize;

         if(pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN) {     
             // This is the picture number that MSDV is actually sending, and in a slow harddisk case,
             // it will be greater than (FramesProcessed + FramesDropped) considering repeat frame.
             pDroppedFrames->PictureNumber = pStrmExt->PictureNumber;
             pDroppedFrames->DropCount     = pStrmExt->FramesDropped; // pStrmExt->PictureNumber - pStrmExt->FramesProcessed;    // For transmit, this value includes both dropped and repeated.

         } else {
             pDroppedFrames->PictureNumber = pStrmExt->PictureNumber;         
             pDroppedFrames->DropCount     = pStrmExt->FramesDropped;    // For transmit, this value includes both dropped and repeated.
         }

         TRACE(TL_STRM_TRACE,("\'hMasClk:%x; *DroppedFP: Pic#(%d), Drp(%d); tmCurStream:%d\n", 
             pStrmExt->hMasterClock, 
             (LONG) pDroppedFrames->PictureNumber, (LONG) pDroppedFrames->DropCount,
             (DWORD) (pStrmExt->CurrentStreamTime/10000)
             ));
               
         *pulBytesTransferred = sizeof (KSPROPERTY_DROPPEDFRAMES_CURRENT_S);
         Status = STATUS_SUCCESS;

         }
         break;

    default:
        *pulBytesTransferred = 0;
        Status = STATUS_NOT_SUPPORTED;
        break;
    }

    return Status;
}

#ifdef SUPPORT_QUALITY_CONTROL
NTSTATUS
DVGetQualityControlProperty(  
    PDVCR_EXTENSION pDevExt,
    PSTREAMEX       pStrmExt,
    PSTREAM_PROPERTY_DESCRIPTOR pSPD,
    PULONG pulBytesTransferred
    )
/*++

Routine Description:

    Return the dropped frame information while captureing.

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
  
    PAGED_CODE();

    switch (pSPD->Property->Id) {

    case KSPROPERTY_STREAM_QUALITY:
        if(pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN) {     

            PKSQUALITY pKSQuality = (PKSQUALITY) pSPD->PropertyInfo;

            // Quality control only 
            if(pStrmExt->StreamState == KSSTATE_STOP || pStrmExt->StreamState == KSSTATE_ACQUIRE) {
                *pulBytesTransferred = 0;
                Status = STATUS_UNSUCCESSFUL;  // Data is not ready
                ASSERT(pSPD->Property->Id == KSPROPERTY_STREAM_QUALITY);
                break;                
            }
            /*
            log.Init_Quality(KSPROPERTY_QUALITY_REPORT, fSuccess);
            log.LogInt("Proportion", ksQuality.Proportion,
                "Indicates the percentage of frames currently being received which are actually being used. "
                " This is expressed in units of 0.1 of a percent, where 1000 is optimal.");
            log.LogLONGLONG("DeltaTime", ksQuality.DeltaTime,
                "Indicates the delta in native units (as indicated by the Interface) from optimal time at which "
                "the frames are being delivered, where a positive number means too late, and a negative number means too early. "
                "Zero indicate a correct delta.");
            log.LogPVOID("pvContext", ksQuality.Context,
                "Context parameter which could be a pointer to the filter pin interface used to "
                "locate the source of the complaint in the graph topology.");
            */
            pKSQuality->DeltaTime  = pStrmExt->KSQuality.DeltaTime;
            pKSQuality->Proportion = pStrmExt->KSQuality.Proportion;
            pKSQuality->Context    = 0;  // Not used!
            TRACE(TL_STRM_WARNING,("\'Get QualityControl: Context:%x; DeltaTime:%d; Proportion:%d\n", 
                pKSQuality->Context, (DWORD) pKSQuality->DeltaTime, pKSQuality->Proportion));
            Status = STATUS_SUCCESS;
            *pulBytesTransferred = sizeof(KSQUALITY);
         
         } else {
            *pulBytesTransferred = 0;
            Status = STATUS_NOT_SUPPORTED;       
         }
         break;
    default:
        *pulBytesTransferred = 0;
        Status = STATUS_NOT_SUPPORTED;
        break;
    }

    return Status;
}
#endif // SUPPORT_QUALITY_CONTROL


#ifdef SUPPORT_NEW_AVC
NTSTATUS
DVGetPinProperty(  
    PDVCR_EXTENSION pDevExt,
    PSTREAMEX       pStrmExt,
    PSTREAM_PROPERTY_DESCRIPTOR pSPD,
    PULONG pulBytesTransferred
    )
/*++

Routine Description:

    Return the dropped frame information while captureing.

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
    PKSPIN_MEDIUM pPinMediums;
    KSMULTIPLE_ITEM * pMultipleItem;
    ULONG idxStreamNumber;
    ULONG ulMediumsSize;
  
    PAGED_CODE();

    switch (pSPD->Property->Id) {

    case KSPROPERTY_PIN_MEDIUMS:
        if(!pStrmExt->pStrmObject) {         
            *pulBytesTransferred = 0;
            return STATUS_UNSUCCESSFUL;
        }

        idxStreamNumber = pStrmExt->pStrmObject->StreamNumber;
        ulMediumsSize = DVStreams[idxStreamNumber].hwStreamInfo.MediumsCount * sizeof(KSPIN_MEDIUM);

        TRACE(TL_STRM_WARNING,("\'KSPROPERTY_PIN_MEDIUMS: idx:%d; MediumSize:%d\n", idxStreamNumber, ulMediumsSize));

        // Its is KSMULTIPLE_ITEM so it is a two step process to return the data:
        // (1) return size in pActualBytesTransferred with STATUS_BUFFER_OVERFLOW
        // (2) 2nd time to get its actual data.
        if(pSPD->PropertyOutputSize == 0) {
            *pulBytesTransferred = sizeof(KSMULTIPLE_ITEM) + ulMediumsSize;
            Status = STATUS_BUFFER_OVERFLOW;          
        } else if(pSPD->PropertyOutputSize >= (sizeof(KSMULTIPLE_ITEM) + ulMediumsSize)) {
            pMultipleItem = (KSMULTIPLE_ITEM *) pSPD->PropertyInfo;    // pointer to the data
            pMultipleItem->Count = DVStreams[idxStreamNumber].hwStreamInfo.MediumsCount;
            pMultipleItem->Size  = sizeof(KSMULTIPLE_ITEM) + ulMediumsSize;
            pPinMediums = (PKSPIN_MEDIUM) (pMultipleItem + 1);    // pointer to the data
            memcpy(pPinMediums, DVStreams[idxStreamNumber].hwStreamInfo.Mediums, ulMediumsSize);
            *pulBytesTransferred = sizeof(KSMULTIPLE_ITEM) + ulMediumsSize;
            Status = STATUS_SUCCESS;         

        } else {
            TRACE(TL_STRM_ERROR,("DVCRMediaSeekingProperty: KSPROPERTY_MEDIASEEKING_FORMAT; STATUS_INVALID_PARAMETER\n"));
            Status = STATUS_INVALID_PARAMETER;
        }  
        break;

    default:
        *pulBytesTransferred = 0;
        Status = STATUS_NOT_SUPPORTED;
        break;
    }

    return Status;
}
#endif 

NTSTATUS
DVGetStreamProperty(
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
/*++

Routine Description:

    Routine to process property request

--*/

{
    NTSTATUS Status = STATUS_SUCCESS;
    PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;

    PAGED_CODE();

    TRACE(TL_STRM_TRACE,("\'DVGetStreamProperty:  entered ...\n"));

    if(IsEqualGUID (&KSPROPSETID_Connection, &pSPD->Property->Set)) {

        Status = 
            DVStreamGetConnectionProperty (
                pSrb->HwDeviceExtension,
                (PSTREAMEX) pSrb->StreamObject->HwStreamExtension,
                pSrb->CommandData.PropertyInfo,
                &pSrb->ActualBytesTransferred
                );
    } 
    else if (IsEqualGUID (&PROPSETID_VIDCAP_DROPPEDFRAMES, &pSPD->Property->Set)) {

        Status = 
            DVGetDroppedFramesProperty (
                pSrb->HwDeviceExtension,
                (PSTREAMEX) pSrb->StreamObject->HwStreamExtension,
                pSrb->CommandData.PropertyInfo,
                &pSrb->ActualBytesTransferred
                );
    } 
#ifdef SUPPORT_QUALITY_CONTROL
    else if (IsEqualGUID (&KSPROPSETID_Stream, &pSPD->Property->Set)) {

        Status = 
            DVGetQualityControlProperty (
                pSrb->HwDeviceExtension,
                (PSTREAMEX) pSrb->StreamObject->HwStreamExtension,
                pSrb->CommandData.PropertyInfo,
                &pSrb->ActualBytesTransferred
                );
    } 
#endif
#ifdef SUPPORT_NEW_AVC
    else if (IsEqualGUID (&KSPROPSETID_Pin, &pSPD->Property->Set)) {

        Status = 
            DVGetPinProperty (
                pSrb->HwDeviceExtension,
                (PSTREAMEX) pSrb->StreamObject->HwStreamExtension,
                pSrb->CommandData.PropertyInfo,
                &pSrb->ActualBytesTransferred
                );
    } 
#endif    
    else {
        Status = STATUS_NOT_SUPPORTED;
    }

    return Status;
}


NTSTATUS 
DVSetStreamProperty(
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
/*++

Routine Description:

    Routine to process set property request

--*/

{
    PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;

    PAGED_CODE();

    TRACE(TL_STRM_WARNING,("\'DVSetStreamProperty:  entered ...\n"));

    return STATUS_NOT_SUPPORTED;

}



NTSTATUS
DVCancelOnePacketCR(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP pIrp,
    IN PSRB_DATA_PACKET pSrbDataPacket    
    )
/*++

Routine Description:

    Completion routine for detach an isoch descriptor associate with a pending read SRB.
    Will cancel the pending SRB here if detaching descriptor has suceeded.

--*/
{
    PSTREAMEX        pStrmExt;
    PLONG            plSrbUseCount;
    PHW_STREAM_REQUEST_BLOCK pSrbToCancel;
    KIRQL oldIrql;



    if(!NT_SUCCESS(pIrp->IoStatus.Status)) {
        TRACE(TL_STRM_ERROR,("CancelOnePacketCR: Srb:%x failed pIrp->Status %x\n", pSrbDataPacket->pSrb, pIrp->IoStatus.Status));
        IoFreeIrp(pIrp);  // Allocated locally 
        return STATUS_MORE_PROCESSING_REQUIRED;        
    }


    pStrmExt = pSrbDataPacket->pStrmExt;


    //
    // Add this to the attached list
    //
    KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);

    // while it is being cancelled, it was completed ?
    if(pStrmExt->cntDataAttached <= 0) {
        TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\'DVCancelOnePacketCR:pStrmExt:%x, pSrbDataPacket:%x, AQD[%d:%d:%d]\n", \
            pStrmExt, pSrbDataPacket, 
            pStrmExt->cntDataAttached,
            pStrmExt->cntSRBQueued,
            pStrmExt->cntDataDetached
            ));
        ASSERT(pStrmExt->cntDataAttached > 0);
        KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql); 
        IoFreeIrp(pIrp);  // Allocated locally        
        return STATUS_MORE_PROCESSING_REQUIRED;
    }


    pSrbToCancel = pSrbDataPacket->pSrb;  // Offload pSrb so this list entry can be inserted to available list.
    plSrbUseCount = (PLONG) pSrbDataPacket->pSrb->SRBExtension;
  
    // Remove from attached and add it to the detach list
    RemoveEntryList(&pSrbDataPacket->ListEntry); pStrmExt->cntDataAttached--; (*plSrbUseCount)--;

#if DBG
    // Detect if 61883 is starve.  This cause discontinuity.
    // This can happen for many valid reasons (slow system).
    // An assert is added to detect other unknown reason.
    if(pStrmExt->cntDataAttached == 0 && pStrmExt->StreamState == KSSTATE_RUN) {
        TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\n**** 61883 starve in RUN state (cancel); AQD[%d:%d:%d]\n\n", 
            pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached
        ));
        // ASSERT(pStrmExt->cntDataAttached > 0 && "61883 is starve at RUN state!!");
    }
#endif

    ASSERT(pStrmExt->cntDataAttached >= 0);
    ASSERT(*plSrbUseCount >= 0);
    
    InsertTailList(&pStrmExt->DataDetachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataDetached++;
    pSrbDataPacket->State |= DE_IRP_CANCELLED;


    // 
    // Complete this Srb if its refCount is 0.
    // 
    if(*plSrbUseCount == 0) {
        PDVCR_EXTENSION  pDevExt;

        pDevExt = pStrmExt->pDevExt;
        pSrbToCancel->Status = (pDevExt->bDevRemoved ? STATUS_DEVICE_REMOVED : STATUS_CANCELLED);
        pSrbToCancel->CommandData.DataBufferArray->DataUsed = 0;
        pSrbToCancel->ActualBytesTransferred                = 0;
        pStrmExt->cntSRBCancelled++;  // RefCnt is 0, and cancelled.
        TRACE(TL_CIP_TRACE,("\'DVCancelOnePacketCR: Srb:%x cancelled; St:%x; cntCancel:%d\n", pSrbToCancel, pSrbToCancel->Status, pStrmExt->cntSRBCancelled));        

        StreamClassStreamNotification(StreamRequestComplete, pSrbToCancel->StreamObject, pSrbToCancel);  
        pSrbDataPacket->State |= DE_IRP_SRB_COMPLETED;  pSrbDataPacket->pSrb = NULL;
#if DBG
        pStrmExt->cntSRBPending--;
#endif
       
    }
    else {
        TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\'DVCancelOnePacketCR: Srb:%x; RefCnt:%d; not completed!\n", pSrbDataPacket->pSrb, *plSrbUseCount));
    }

    KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
    IoFreeIrp(pIrp);  // Allocated locally 

    return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS
DVStopCancelDisconnect(
    PSTREAMEX  pStrmExt
)
/*++

Routine Description:

   Stop a stream, cacel all pening data requests, terminate system thread, and disconnect.

--*/
{
    AV_61883_REQUEST * pAVReq;
    
    if(!(pAVReq = (AV_61883_REQUEST *) ExAllocatePool(NonPagedPool, sizeof(AV_61883_REQUEST)) )) 
        return STATUS_INSUFFICIENT_RESOURCES;              

    //
    // Set stream state and the work item thread can both call this routine.
    // Use a mutex to synchronize them.
    //
    KeWaitForSingleObject( pStrmExt->hStreamMutex, Executive, KernelMode, FALSE, 0 );

    //
    // Stop the 1394 isoch data transfer; Stream state is unchanged.
    //
    DVStreamingStop(
        pStrmExt,
        pStrmExt->pDevExt,
        pAVReq
        );

    ExFreePool(pAVReq);  pAVReq = NULL;

    //
    // Cancel all packets
    //
    DVCancelAllPackets(
        pStrmExt,
        pStrmExt->pDevExt
        );

    //
    // If the device is removed, terminate the system thread for attach frame.
    // 
    if(   pStrmExt->pDevExt->bDevRemoved
       && KSPIN_DATAFLOW_IN == pStrmExt->pStrmInfo->DataFlow
       && !pStrmExt->bTerminateThread
       && pStrmExt->pAttachFrameThreadObject
      ) {
        DVTerminateAttachFrameThread(pStrmExt);
        pStrmExt->pAttachFrameThreadObject = NULL;
        TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("** DVStopCancelDisconnect: AttachFrameThread terminated;\n"));
    }


    //
    // Break the connection so 61883 will free isoch resource   
    //
    DVDisconnect(
        pStrmExt->pStrmInfo->DataFlow,
        pStrmExt->pDevExt,
        pStrmExt
        );

    
    KeReleaseMutex(pStrmExt->hStreamMutex, FALSE);

    return STATUS_SUCCESS;
}


void
DVCancelSrbWorkItemRoutine(
#ifdef USE_WDM110  // Win2000 code base
    // Extra parameter if using WDM10
    PDEVICE_OBJECT DeviceObject,
#endif
    PSTREAMEX  pStrmExt
    )
/*++

Routine Description:

   This work item routine will stop streaming and cancel all SRBs.   

--*/
{
    PAGED_CODE();

    TRACE(TL_STRM_WARNING,("\'CancelWorkItem: StreamState:%d; lCancel:%d\n", 
        pStrmExt->StreamState, pStrmExt->lCancelStateWorkItem));

    ASSERT(pStrmExt->lCancelStateWorkItem == 1);
#ifdef USE_WDM110  // Win2000 code base
    ASSERT(pStrmExt->pIoWorkItem);
#endif
   
    //
    // Stop the stream and cancel all pending requests.
    //
    if(!NT_SUCCESS(DVStopCancelDisconnect(pStrmExt))) {
        // Canceling is in theory done!
        InterlockedExchange(&pStrmExt->lCancelStateWorkItem, 0);
        KeSetEvent(&pStrmExt->hCancelDoneEvent, 0, FALSE);  pStrmExt->bAbortPending = FALSE;
        goto DVAbortWorkItemRoutine;           
    } 


    //
    // Canceling is in theory done!
    //
    InterlockedExchange(&pStrmExt->lCancelStateWorkItem, 0); 
    KeSetEvent(&pStrmExt->hCancelDoneEvent, 0, FALSE);  pStrmExt->bAbortPending = FALSE;


    // If the device is removed, terminate the system thread that is used 
    // for attaching frame for transmit to DV
    if(   pStrmExt->pDevExt->bDevRemoved
       && KSPIN_DATAFLOW_IN == pStrmExt->pStrmInfo->DataFlow
       && !pStrmExt->bTerminateThread
       && pStrmExt->pAttachFrameThreadObject
      ) {

        DVTerminateAttachFrameThread(pStrmExt);
        pStrmExt->pAttachFrameThreadObject = NULL;
        TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("** WortItemRoutine: thread terminated;\n"));
    }

DVAbortWorkItemRoutine:
;
#ifdef USE_WDM110  // Win2000 code base
    // Release work item and release the cancel token
    IoFreeWorkItem(pStrmExt->pIoWorkItem);  pStrmExt->pIoWorkItem = NULL; 
#endif
}


BOOL
DVAbortStream(
    PDVCR_EXTENSION pDevExt,
    PSTREAMEX pStrmExt
    )
/*++

Routine Description:

   Start a work item to abort streaming.

--*/
{
    //
    // Claim this token; only one abort streaming per STOP->PAUSE transition.
    //
    if(InterlockedExchange(&pStrmExt->lCancelStateWorkItem, 1) == 1) {
        TRACE(TL_STRM_TRACE,("\'Cancel work item is already issued.\n"));
        return FALSE;
    }  

    TRACE(TL_STRM_WARNING,("\'DVAbortStream is issued; lCancelStateWorkItem:%d\n", pStrmExt->lCancelStateWorkItem));

    //
    // Non-signal this event so other thread depending on the completion will wait.
    //
    KeClearEvent(&pStrmExt->hCancelDoneEvent);  pStrmExt->bAbortPending = TRUE;

    //
    // If we are not running at DISPATFCH level or higher, we abort the stream without scheduleing
    // a work item; else schedule a work item is necessary.
    //
    if (KeGetCurrentIrql() <= APC_LEVEL) { 
        DVStopCancelDisconnect(pStrmExt);
        InterlockedExchange(&pStrmExt->lCancelStateWorkItem, 0); 
        KeSetEvent(&pStrmExt->hCancelDoneEvent, 0, FALSE);   pStrmExt->bAbortPending = FALSE;
        return TRUE;
    }


#ifdef USE_WDM110  // Win2000 code base
    ASSERT(pStrmExt->pIoWorkItem == NULL);  // Have not yet queued work item.

    // We will queue work item to stop and cancel all SRBs
    if(pStrmExt->pIoWorkItem = IoAllocateWorkItem(pDevExt->pBusDeviceObject)) { 

        IoQueueWorkItem(
            pStrmExt->pIoWorkItem,
            DVCancelSrbWorkItemRoutine,
            DelayedWorkQueue, // CriticalWorkQueue 
            pStrmExt
            );

#else  // Win9x code base
    ExInitializeWorkItem( &pStrmExt->IoWorkItem, DVCancelSrbWorkItemRoutine, pStrmExt);
    if(TRUE) {

        ExQueueWorkItem( 
            &pStrmExt->IoWorkItem,
            DelayedWorkQueue // CriticalWorkQueue 
            ); 
#endif

        TRACE(TL_STRM_WARNING,("\'CancelWorkItm queued; SrbRcv:%d;Pic#:%d;Prc:%d;;Drop:%d;Cncl:%d; AQD [%d:%d:%d]\n",
            (DWORD) pStrmExt->cntSRBReceived,
            (DWORD) pStrmExt->PictureNumber,
            (DWORD) pStrmExt->FramesProcessed, 
            (DWORD) pStrmExt->FramesDropped,
            (DWORD) pStrmExt->cntSRBCancelled,
            pStrmExt->cntDataAttached,
            pStrmExt->cntSRBQueued,
            pStrmExt->cntDataDetached
            ));

    } 
#ifdef USE_WDM110  // Win2000 code base
    else {
        InterlockedExchange(&pStrmExt->lCancelStateWorkItem, 0); 
        KeSetEvent(&pStrmExt->hCancelDoneEvent, 0, FALSE);   pStrmExt->bAbortPending = FALSE;
        ASSERT(pStrmExt->pIoWorkItem && "IoAllocateWorkItem failed.\n");
        return FALSE;
    }
#endif

    return TRUE;
}


VOID
DVCancelOnePacket(
    IN PHW_STREAM_REQUEST_BLOCK pSrbToCancel
    )
/*++

Routine Description:

   Search pending read lists for the SRB to be cancel.  If found cancel it.   

--*/
{
    PDVCR_EXTENSION pDevExt;
    PSTREAMEX pStrmExt;
    KIRQL OldIrql;


                                                                                                              
    pDevExt = (PDVCR_EXTENSION) pSrbToCancel->HwDeviceExtension; 
               
    // Cannot cancel device Srb.
    if ((pSrbToCancel->Flags & SRB_HW_FLAGS_STREAM_REQUEST) != SRB_HW_FLAGS_STREAM_REQUEST) {
        TRACE(TL_CIP_ERROR|TL_STRM_ERROR,("\'DVCancelOnePacket: Device SRB %x; cannot cancel!\n", pSrbToCancel));
        ASSERT((pSrbToCancel->Flags & SRB_HW_FLAGS_STREAM_REQUEST) == SRB_HW_FLAGS_STREAM_REQUEST );
        return;
    }         
        
    // Can try to cancel a stream Srb and only if the stream extension still around.
    pStrmExt = (PSTREAMEX) pSrbToCancel->StreamObject->HwStreamExtension;

    if(pStrmExt == NULL) {
        TRACE(TL_CIP_ERROR|TL_STRM_ERROR,("DVCancelOnePacket: pSrbTocancel %x but pStrmExt %x\n", pSrbToCancel, pStrmExt));
        ASSERT(pStrmExt && "Stream SRB but stream extension is NULL\n");
        return;
    }

    // We can only cancel SRB_READ/WRITE_DATA SRB
    if((pSrbToCancel->Command != SRB_READ_DATA) && (pSrbToCancel->Command != SRB_WRITE_DATA)) {
        TRACE(TL_CIP_ERROR|TL_STRM_ERROR,("DVCancelOnePacket: pSrbTocancel %x; Command:%d not SRB_READ,WRITE_DATA\n", pSrbToCancel, pSrbToCancel->Command));
        return;
    }

    TRACE(TL_STRM_TRACE|TL_CIP_TRACE,("\'DVCancelOnePacket: KSSt %d; Srb:%x; AQD[%d:%d:%d]\n",
        pStrmExt->StreamState, pSrbToCancel, pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached));

   
    KeAcquireSpinLock(&pDevExt->AVCCmdLock, &OldIrql);
    //
    // If device is removed, the surprise removal routine will do the cancelling.
    //
    if(!pDevExt->bDevRemoved) {
        KeReleaseSpinLock(&pDevExt->AVCCmdLock, OldIrql);
        // We will start an work item to stop streaming if we ever get an cancel Srb.
        if(!DVAbortStream(pDevExt, pStrmExt)) {
            TRACE(TL_STRM_WARNING,("\'CancelOnePacket: pSrb:%x; AbortStream not taken!\n", pSrbToCancel));
        }
    } else {
        TRACE(TL_STRM_WARNING,("\'CancelOnePacket: DevRemoved; pSrb:%x; AbortStream not taken!\n", pSrbToCancel));
        KeReleaseSpinLock(&pDevExt->AVCCmdLock, OldIrql);
    }
}



VOID
DVCancelAllPackets(
    PSTREAMEX        pStrmExt,
    PDVCR_EXTENSION  pDevExt
    )
/*++

Routine Description:

    Cancel all packet when This is where most of the interesting Stream requests come to us

--*/
{
    PHW_STREAM_REQUEST_BLOCK pSrb;
    PSRB_DATA_PACKET pSrbDataPacket;
    PAV_61883_REQUEST   pAVReq;
    PSRB_ENTRY       pSrbEntry;
    NTSTATUS         Status;

    PIRP               pIrp;
    PLIST_ENTRY        pEntry;    
    PIO_STACK_LOCATION NextIrpStack;
    KIRQL oldIrql;



    PAGED_CODE();

#if DBG
    if(pStrmExt->StreamState != KSSTATE_STOP) {
        TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("DVCancelAllPackets: Enter; pStrmExt:%x; StrmSt:%d; IsochActive:%d\n", 
            pStrmExt, pStrmExt->StreamState, pStrmExt->bIsochIsActive));
    }
#endif

    //
    // Detached request only if not streaming
    //

    // Note: no need to spin lock this if isoch has stopped.
    if(!pStrmExt->bIsochIsActive) {

        PLONG plSrbUseCount;

        TRACE(TL_STRM_WARNING,("\'CancelAll: AQD: [%d:%d:%d]; DataAttachedListHead:%x\n",  
            pStrmExt->cntDataAttached, 
            pStrmExt->cntSRBQueued,
            pStrmExt->cntDataDetached,
            pStrmExt->DataAttachedListHead
            )); 


        //
        // Cancel buffer(s) that are still attached.
        //

        KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);

        pEntry = pStrmExt->DataAttachedListHead.Flink;
        while(pEntry != &pStrmExt->DataAttachedListHead) {        

            ASSERT(pStrmExt->cntDataAttached > 0 && "List and cntAttached out of sync!");

            // Get an irp and detached the buffer        
            if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE)))  {
                KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
                return;            
            }

            pSrbDataPacket = CONTAINING_RECORD(pEntry, SRB_DATA_PACKET, ListEntry);

#if DBG
            if(!IsStateSet(pSrbDataPacket->State, DE_IRP_ATTACHED_COMPLETED)) {
                TRACE(TL_STRM_ERROR,("Cancel (unattached) entry; pStrmExt:%x; pSrbDataPacket:%x\n", pStrmExt, pSrbDataPacket)); 
                ASSERT(IsStateSet(pSrbDataPacket->State, DE_IRP_ATTACHED_COMPLETED));
            }
#endif

 
            pEntry = pEntry->Flink;  // Next since this may get changed in the completion routine

            KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);

            pSrb = pSrbDataPacket->pSrb;
            ASSERT(pSrbDataPacket->pSrb);
            plSrbUseCount = (PLONG) pSrb->SRBExtension;
            pAVReq = &pSrbDataPacket->AVReq;
            RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
            INIT_61883_HEADER(pAVReq, Av61883_CancelFrame);

            pAVReq->CancelFrame.hConnect     = pStrmExt->hConnect;
            pAVReq->CancelFrame.Frame        = pSrbDataPacket->Frame;
            TRACE(TL_CIP_TRACE,("\'Canceling AttachList: pSrb %x, AvReq %x; UseCount %d\n", pSrb, pAVReq, *plSrbUseCount));
            ASSERT(pSrbDataPacket->Frame);

            NextIrpStack = IoGetNextIrpStackLocation(pIrp);
            NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
            NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_61883_CLASS;
            NextIrpStack->Parameters.Others.Argument1 = pAVReq;

            IoSetCompletionRoutine( 
                pIrp,
                DVCancelOnePacketCR,
                pSrbDataPacket,
                TRUE,
                TRUE,
                TRUE
                );

            Status = 
                IoCallDriver(
                    pDevExt->pBusDeviceObject,
                    pIrp
                    );


            ASSERT(Status == STATUS_PENDING || Status == STATUS_SUCCESS); 

            KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
        }

        KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);

#if DBG
        if(pStrmExt->cntDataAttached != 0) {
            TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\'DVCancelAllPackets: cntDataAttached:%d !!\n", pStrmExt->cntDataAttached));
            ASSERT(pStrmExt->cntDataAttached == 0);
        }
#endif
         
        //
        // Cancel SRB that are still the SrbQ; this applies only to SRB_WRITE_DATA
        //
        pEntry = pStrmExt->SRBQueuedListHead.Flink;
        while(pEntry != &pStrmExt->SRBQueuedListHead) {  

            pSrbEntry = CONTAINING_RECORD(pEntry, SRB_ENTRY, ListEntry);
            plSrbUseCount = (PLONG) pSrbEntry->pSrb->SRBExtension;

            pEntry = pEntry->Flink;  // Next since this may get changed if removed

            TRACE(TL_CIP_TRACE,("\'DVCnclAllPkts (SrbQ): cntQ:%d; pSrb:%x; UseCnt:%d (=? 1)\n", pStrmExt->cntSRBQueued, pSrbEntry->pSrb, *plSrbUseCount));
            if(*plSrbUseCount == 1) {
                RemoveEntryList(&pSrbEntry->ListEntry); pStrmExt->cntSRBQueued--; (*plSrbUseCount)--;  // Remove from queueed.
                pStrmExt->cntSRBCancelled++;
                pSrbEntry->pSrb->Status = (pDevExt->bDevRemoved ? STATUS_DEVICE_REMOVED : STATUS_CANCELLED);
                pSrbEntry->pSrb->CommandData.DataBufferArray->DataUsed = 0;
                pSrbEntry->pSrb->ActualBytesTransferred                = 0;
                TRACE(TL_STRM_WARNING,("\'Cancel queued SRB: pSRB:%x, Status:%x; cntSrbCancelled:%d\n", pSrbEntry->pSrb, pSrbEntry->pSrb->Status, pStrmExt->cntSRBCancelled));
                StreamClassStreamNotification(StreamRequestComplete, pSrbEntry->pSrb->StreamObject, pSrbEntry->pSrb);
#if DBG
                pStrmExt->cntSRBPending--;
#endif
                ExFreePool(pSrbEntry);
            } else {
                TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("\'NOT Cancel queued SRB: pSRB:%x, Status:%x; *plSrbUseCount:%d, cntSrbCancelled:%d\n", pSrbEntry->pSrb, pSrbEntry->pSrb->Status, *plSrbUseCount, pStrmExt->cntSRBCancelled));
                ASSERT(*plSrbUseCount == 0 && "Still in use ?");
                break;  // Still in used.  Perhaps, free it in TimeoutHandler() or CancelOnePacket()
            }
        }
#if DBG
        if(pStrmExt->cntSRBQueued != 0 || !IsListEmpty(&pStrmExt->SRBQueuedListHead)) {
            TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("\'DVCancelAllPackets: cntSRBQueued:%d !! Empty?%d\n", pStrmExt->cntSRBQueued, IsListEmpty(&pStrmExt->SRBQueuedListHead)));
            ASSERT(pStrmExt->cntSRBQueued == 0);
        }
#endif
    } 
    else {
        TRACE(TL_STRM_ERROR,("\'IsochActive; cannot cancel! cntSrbQ:%d; cntAttached:%d.\n", pStrmExt->cntSRBQueued, pStrmExt->cntDataAttached));
        ASSERT(pStrmExt->bIsochIsActive);
    }   



    TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\'DVCancelAllPackets: ************************ Exit!\n"));
}


VOID
DVTimeoutHandler(
    IN PHW_STREAM_REQUEST_BLOCK pSrb
    )

/*++

Routine Description:

    This routine is called when a packet has been in the minidriver too long.
    It can only valid if we are it wa a streaming packet and in PAUSE state;
    else we have a problem!

Arguments:

    pSrb - Pointer to Stream request block

Return Value:

    Nothing

--*/

{
    //
    // Note:
    //    Called from StreamClass at DisptchLevel
    //    

    //
    // We only expect stream SRB, but not device SRB.  
    //

    if ( (pSrb->Flags & SRB_HW_FLAGS_STREAM_REQUEST) != SRB_HW_FLAGS_STREAM_REQUEST) {
        TRACE(TL_PNP_ERROR,("TimeoutHandler: Device SRB %x (cmd:%x) timed out!\n", pSrb, pSrb->Command));
        return;
    } else {

        //
        // pSrb->StreamObject (and pStrmExt) only valid if it is a stream SRB
        //
        PSTREAMEX pStrmExt;

        pStrmExt = (PSTREAMEX) pSrb->StreamObject->HwStreamExtension;

        if(!pStrmExt) {
            TRACE(TL_PNP_ERROR,("TimeoutHandler: Stream SRB %x timeout with pStrmExt %x\n", pSrb, pStrmExt));
            ASSERT(pStrmExt);
            return;
        }

        TRACE(TL_STRM_WARNING,("\'TimeoutHandler: KSSt %d; Srb:%x (cmd:%x); AQD[%d:%d:%d]\n",
            pStrmExt->StreamState, pSrb, pSrb->Command, pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached));

 
        //
        // Stream SRB (esp the data SRB) can time out if there is not 
        // data on the bus; however, it can only happen while in PAUSE 
        // or RUN state when attaching data SRB is valid.
        //
        if(pStrmExt->StreamState != KSSTATE_PAUSE &&
           pStrmExt->StreamState != KSSTATE_RUN) {
            TRACE(TL_PNP_ERROR|TL_STRM_ERROR,("\'TmOutHndlr:(Irql:%d) Srb %x (cmd:%x); %s, pStrmExt %x, AQD [%d:%d:%d]\n", 
                KeGetCurrentIrql(),
                pSrb, pSrb->Command, 
                pStrmExt->StreamState == KSSTATE_RUN   ? "RUN" : 
                pStrmExt->StreamState == KSSTATE_PAUSE ? "PAUSE":
                pStrmExt->StreamState == KSSTATE_STOP  ? "STOP": "Unknown",
                pStrmExt,
                pStrmExt->cntDataAttached,
                pStrmExt->cntSRBQueued,
                pStrmExt->cntDataDetached
                ));   
        }

        //
        // Reset Timeout counter, or we are going to get this call immediately.
        //

        pSrb->TimeoutCounter = pSrb->TimeoutOriginal;
    }
}

NTSTATUS 
DVEventHandler(
    IN PHW_EVENT_DESCRIPTOR pEventDescriptor
    )
/*++

Routine Description:

    This routine is called to process events.

--*/
{

    PSTREAMEX  pStrmExt;

    if(IsEqualGUID (&KSEVENTSETID_Clock, pEventDescriptor->EventEntry->EventSet->Set)) {
        if(pEventDescriptor->EventEntry->EventItem->EventId == KSEVENT_CLOCK_POSITION_MARK) {
            if(pEventDescriptor->Enable) {
                // Note: According to the DDK, StreamClass queues pEventDescriptor->EventEntry, and dellaocate
                // every other structures, including the pEventDescriptor->EventData.
                if(pEventDescriptor->StreamObject) { 
                    PKSEVENT_TIME_MARK  pEventTime;

                    pStrmExt = (PSTREAMEX) pEventDescriptor->StreamObject->HwStreamExtension;
                    pEventTime = (PKSEVENT_TIME_MARK) pEventDescriptor->EventData;
                    // Cache the event data (Specified in the ExtraEntryData of KSEVENT_ITEM)
                    RtlCopyMemory((pEventDescriptor->EventEntry+1), pEventDescriptor->EventData, sizeof(KSEVENT_TIME_MARK));
                    TRACE(TL_STRM_TRACE,("\'CurrentStreamTime:%d, MarkTime:%d\n", (DWORD) pStrmExt->CurrentStreamTime, (DWORD) pEventTime->MarkTime));
                }
            } else {
               // Disabled!
                TRACE(TL_STRM_TRACE,("\'KSEVENT_CLOCK_POSITION_MARK disabled!\n"));            
            }
            return STATUS_SUCCESS;
        }
    } else if(IsEqualGUID (&KSEVENTSETID_Connection, pEventDescriptor->EventEntry->EventSet->Set)) {
        TRACE(TL_STRM_WARNING,("\'Connection event: pEventDescriptor:%x; id:%d\n", pEventDescriptor, pEventDescriptor->EventEntry->EventItem->EventId));

        pStrmExt = (PSTREAMEX) pEventDescriptor->StreamObject->HwStreamExtension;
        if(pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN) {
            if(pEventDescriptor->EventEntry->EventItem->EventId == KSEVENT_CONNECTION_ENDOFSTREAM) {
                if(pEventDescriptor->Enable) {
                    TRACE(TL_STRM_TRACE,("\'KSEVENT_CONNECTION_ENDOFSTREAM enabled!\n"));
                } else {
                    TRACE(TL_STRM_TRACE,("\'KSEVENT_CONNECTION_ENDOFSTREAM disabled!\n"));            
                }
                return STATUS_SUCCESS;
            }
        }
    }

    TRACE(TL_STRM_ERROR,("\'NOT_SUPPORTED event: pEventDescriptor:%x\n", pEventDescriptor));
    ASSERT(FALSE && "Event not advertised and not supported!");

    return STATUS_NOT_SUPPORTED;
}

VOID
DVSignalClockEvent(
    IN PKDPC Dpc,
    IN PSTREAMEX  pStrmExt,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2 
)
/*++

Routine Description:

    This routine is called when we are the clock provider and when our clock "tick".  
    Find a pending clock event, signal it if it has expired.

--*/
{
    PKSEVENT_ENTRY pEvent, pLast;
    ULONGLONG tmStreamTime;
#if DBG
    ULONG EventPendings = 0;
#endif

    pEvent = NULL;
    pLast = NULL;


    //
    // A clock tick for DV is one frame time.  For better precision, 
    // we calculate current stream time with an offset from the last system time being queried.
    // We also add a max latency of one frame for decoding a DV frame.
    //
    tmStreamTime = 
        pStrmExt->CurrentStreamTime + 
        (GetSystemTime() - pStrmExt->LastSystemTime) + 
        DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].ulAvgTimePerFrame;  // Allow one frame of latency

    while(( 
        pEvent = StreamClassGetNextEvent(
            pStrmExt->pDevExt,
            pStrmExt->pStrmObject,
            (GUID *)&KSEVENTSETID_Clock,
            KSEVENT_CLOCK_POSITION_MARK,
            pLast )) 
        != NULL ) {

#if DBG
        EventPendings++;
#endif

        if (
            // For real time capture (DV->PC), signal every frame. 
            // No frame that is produce can be "early" and requires AdviseTime().
            pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_OUT ||
                pStrmExt->bEOStream 
            || (pStrmExt->StreamState != KSSTATE_RUN)            // If not in RUN state, Data should be completed.
            || pStrmExt->pDevExt->PowerState != PowerDeviceD0    // If not power ON, data should be completed.
            || ((PKSEVENT_TIME_MARK)(pEvent +1))->MarkTime <= (LONGLONG) tmStreamTime ) {
            TRACE(TL_STRM_TRACE,("\'PowerSt:%d (ON:1?); StrmSt:%d; Clock event %x with id %d; Data:%x; \ttmMark\t%d \ttmCurrentStream \t%d; Notify!\n", 
                pStrmExt->pDevExt->PowerState, pStrmExt->StreamState,
                pEvent, KSEVENT_CLOCK_POSITION_MARK, (PKSEVENT_TIME_MARK)(pEvent +1),
                (DWORD) (((PKSEVENT_TIME_MARK)(pEvent +1))->MarkTime), (DWORD) tmStreamTime));
            ASSERT( ((PKSEVENT_TIME_MARK)(pEvent +1))->MarkTime > 0 );

            //
            // signal the event here
            //
            StreamClassStreamNotification(
                SignalStreamEvent,
                pStrmExt->pStrmObject,
                pEvent
                );
#if DBG
            if(pStrmExt->bEOStream) {
                TRACE(TL_STRM_WARNING,("\'bEOStream: Clock event %x with id %d; Data:%x; \ttmMark \t%d \ttmCurStream \t%d\n", 
                    pEvent, KSEVENT_CLOCK_POSITION_MARK, (PKSEVENT_TIME_MARK)(pEvent +1),
                    (DWORD) (((PKSEVENT_TIME_MARK)(pEvent +1))->MarkTime), (DWORD) tmStreamTime));
            }
#endif
        } else {
            TRACE(TL_STRM_WARNING,("\'PowerST:%d; StrmST:%d; AQD[%d:%d:%d]; Still early! ClockEvent: \tMarkTime \t%d \ttmStream \t%d \tdetla \t%d\n",
                pStrmExt->pDevExt->PowerState, pStrmExt->StreamState,
                pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached,
                (DWORD) (((PKSEVENT_TIME_MARK)(pEvent +1))->MarkTime), (DWORD) tmStreamTime,
                (DWORD) ((((PKSEVENT_TIME_MARK)(pEvent +1))->MarkTime) - tmStreamTime)
                ));

        }
        pLast = pEvent;
    }

#if DBG
    if(EventPendings == 0) {
        TRACE(TL_STRM_TRACE,("\'No event pending; PowerSt:%d (ON:1?); StrmSt:%d; AQD[%d:%d:%d]\n", 
            pStrmExt->pDevExt->PowerState, pStrmExt->StreamState, 
            pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached
        ));
    }
#endif

}


VOID 
StreamClockRtn(
    IN PHW_TIME_CONTEXT TimeContext
    )
/*++

Routine Description:

    This routine is called whenever someone in the graph wants to know what time it is, and we are the Master Clock.

--*/
{
    PDVCR_EXTENSION    pDevExt;
    PHW_STREAM_OBJECT  pStrmObj;
    PSTREAMEX          pStrmExt;
    
    // Call at dispatch level

    pDevExt  = (PDVCR_EXTENSION) TimeContext->HwDeviceExtension;
    pStrmObj = TimeContext->HwStreamObject;
    if(pStrmObj)
        pStrmExt = pStrmObj->HwStreamExtension;
    else 
        pStrmExt = 0;

    if(!pDevExt || !pStrmExt) {
        ASSERT(pDevExt && pStrmExt);
        return;
    }


    switch (TimeContext->Function) {
    
    case TIME_GET_STREAM_TIME:

        //
        // How long since the stream was first set into the run state?
        //
        ASSERT(pStrmExt->hMasterClock && "We are not master clock but we were qureied?");

        TimeContext->SystemTime = GetSystemTime();

        if(pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN) {
            if(pStrmExt->StreamState == KSSTATE_RUN)  { // Stream time is only meaningful in RUN state
                if(TimeContext->SystemTime >= pStrmExt->LastSystemTime)
                    TimeContext->Time = 
                        pStrmExt->CurrentStreamTime + (TimeContext->SystemTime - pStrmExt->LastSystemTime); 
                else {
                    TimeContext->Time = pStrmExt->CurrentStreamTime;
                    TRACE(TL_STRM_WARNING,("\'Clock went backward? %d -> %d\n", (DWORD) (TimeContext->SystemTime/10000), (DWORD) (pStrmExt->LastSystemTime/10000) ));
                    // ASSERT(TimeContext->SystemTime >= pStrmExt->LastSystemTime);
                }
        
                // Make current stream time one frame behind
                if(TimeContext->Time > DVFormatInfoTable[pDevExt->VideoFormatIndex].ulAvgTimePerFrame)
                    TimeContext->Time = TimeContext->Time - DVFormatInfoTable[pDevExt->VideoFormatIndex].ulAvgTimePerFrame;
                else 
                    TimeContext->Time = 0;
            } else  {
                if(pStrmExt->FramesProcessed > 0)
                    TimeContext->Time = pStrmExt->CurrentStreamTime;
                else
                    TimeContext->Time = 0;  // if get queried at the PAUSE state.
            }
           
        } else {

            if(pStrmExt->StreamState == KSSTATE_RUN) {
#ifdef NT51_61883
                // Can advance at most MAX_CYCLES_TIME (supported by 1394 OHCI).
                if((TimeContext->SystemTime - pStrmExt->LastSystemTime) > MAX_CYCLES_TIME)
                    TimeContext->Time = pStrmExt->CurrentStreamTime + MAX_CYCLES_TIME;
#else
                // Cannot advance more than one frame time.
                if((TimeContext->SystemTime - pStrmExt->LastSystemTime) >= DVFormatInfoTable[pDevExt->VideoFormatIndex].ulAvgTimePerFrame)
                    TimeContext->Time = pStrmExt->CurrentStreamTime + DVFormatInfoTable[pDevExt->VideoFormatIndex].ulAvgTimePerFrame;
#endif  // NT51_61883
                else 
                    TimeContext->Time = 
                        pStrmExt->CurrentStreamTime + (TimeContext->SystemTime - pStrmExt->LastSystemTime); 

                // Necessary tuning ?
                //     Make current stream time one frame behind so that the downstream filter 
                //     can render the data promptly instead of discarding it if it is late.
                if(TimeContext->Time > DVFormatInfoTable[pDevExt->VideoFormatIndex].ulAvgTimePerFrame)
                    TimeContext->Time = TimeContext->Time - DVFormatInfoTable[pDevExt->VideoFormatIndex].ulAvgTimePerFrame;
                else 
                    TimeContext->Time = 0;                

            } else {
                if(pStrmExt->FramesProcessed > 0)
                    TimeContext->Time = pStrmExt->CurrentStreamTime;
                else
                    TimeContext->Time = 0;
            }
        }
        TRACE(TL_STRM_TRACE,("\'TIME_GET_STREAM_TIME: ST:%d; Frame:%d; tmSys:%d; tmStream:%d msec\n", 
            pStrmExt->StreamState,
            (DWORD) pStrmExt->PictureNumber,
            (DWORD)(TimeContext->SystemTime/10000), (DWORD)(TimeContext->Time/10000)));  
        break;
   
    default:
        ASSERT(TimeContext->Function == TIME_GET_STREAM_TIME && "Unsupport clock func");
        break;
    } // switch TimeContext->Function
}



NTSTATUS 
DVOpenCloseMasterClock (
    PSTREAMEX  pStrmExt,
    HANDLE  hMasterClockHandle
    )
/*++

Routine Description:

    We can be a clock provider.

--*/
{

    PAGED_CODE();

    // Make sure the stream exist.
    if(pStrmExt == NULL) {
        TRACE(TL_STRM_ERROR,("\'DVOpenCloseMasterClock: stream is not yet running.\n"));
        ASSERT(pStrmExt);
        return  STATUS_UNSUCCESSFUL;
    } 

    TRACE(TL_STRM_TRACE,("\'DVOpenCloseMasterClock: pStrmExt %x; hMyClock:%x->%x\n", 
        pStrmExt, pStrmExt->hMyClock, hMasterClockHandle));

    if(hMasterClockHandle) {
        // Open master clock
        ASSERT(pStrmExt->hMyClock == NULL && "OpenMasterClk while hMyClock is not NULL!");
        pStrmExt->hMyClock = hMasterClockHandle;
    } else {
        // Close master clock
        ASSERT(pStrmExt->hMyClock && "CloseMasterClk while hMyClock is NULL!");
        pStrmExt->hMyClock = NULL;
    }
    return STATUS_SUCCESS;
}


NTSTATUS 
DVIndicateMasterClock (
    PSTREAMEX  pStrmExt,
    HANDLE  hIndicateClockHandle
    )
/*++

Routine Description:

    Compare the indicate clock handle with my clock handle.
    If the same, we are the master clock; else, other device is 
    the master clock.

    Note: either hMasterClock or hClock can be set.

--*/
{
    PAGED_CODE();

    // Make sure the stream exist.
    if (pStrmExt == NULL) {
        TRACE(TL_STRM_ERROR,("DVIndicateMasterClock: stream is not yet running.\n"));
        ASSERT(pStrmExt);
        return STATUS_UNSUCCESSFUL;
    }

    TRACE(TL_STRM_TRACE,("\'*>IndicateMasterClk[Enter]: pStrmExt:%x; hMyClk:%x; IndMClk:%x; pClk:%x, pMClk:%x\n",
        pStrmExt, pStrmExt->hMyClock, hIndicateClockHandle, pStrmExt->hClock, pStrmExt->hMasterClock));

    // it not null, set master clock accordingly.    
    if(hIndicateClockHandle == pStrmExt->hMyClock) {
        pStrmExt->hMasterClock = hIndicateClockHandle;
        pStrmExt->hClock       = NULL;
    } else {
        pStrmExt->hMasterClock = NULL;
        pStrmExt->hClock       = hIndicateClockHandle;
    }

    TRACE(TL_STRM_TRACE,("\'<*IndicateMasterClk[Exit]: hMyClk:%x; IndMClk:%x; pClk:%x; pMClk:%x\n",
        pStrmExt->hMyClock, hIndicateClockHandle, pStrmExt->hClock, pStrmExt->hMasterClock));

    return STATUS_SUCCESS;
}