//==========================================================================;
//
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
//  PURPOSE.
//
//  Copyright (c) 1992 - 1998  Microsoft Corporation.  All Rights Reserved.
//
//==========================================================================;

#include <wdm.h>
#include <strmini.h>
#include <ksmedia.h>
#include "kskludge.h"
#include "codmain.h"
#include "codstrm.h"
#include "codprop.h"
#include "coddebug.h"


//
// Fake VBI Info header.  Infinite Pin Tee Filter can't pass real ones
// one from capture so we rely on this.  MSTee can so this gets
// overwritten.
//
KS_VBIINFOHEADER FakeVBIInfoHeader = {
   10,       /* StartLine;           IGNORED */
   21,       /* EndLine;             IGNORED */
   28636360, /* SamplingFrequency;   Hz. */
   780,      /* MinLineStartTime;    IGNORED */
   780,      /* MaxLineStartTime;    IGNORED */
   780,      /* ActualLineStartTime; microSec * 100 from HSync LE */
   0,        /* ActualLineEndTime;   IGNORED */
   0,        /* VideoStandard;       IGNORED */
   1600,     /* SamplesPerLine;                              */
   1600,     /* StrideInBytes;       May be > SamplesPerLine */
   1600*12   /* BufferSize;          Bytes */
};



/*
** DriverEntry()
**
**   This routine is called when the driver is first loaded by PnP.
**   It in turn, calls upon the stream class to perform registration services.
**
** Arguments:
**
**   DriverObject - 
**          Driver object for this driver 
**
**   RegistryPath - 
**          Registry path string for this driver's key
**
** Returns:
**
**   Results of StreamClassRegisterAdapter()
**
** Side Effects:  none
*/

ULONG 
DriverEntry( IN PDRIVER_OBJECT DriverObject,
			 IN PUNICODE_STRING RegistryPath )
{
    ULONG					status = 0;
    HW_INITIALIZATION_DATA	HwInitData;

    CDebugPrint(DebugLevelTrace,(CODECNAME ":--->DriverEntry(DriverObject=%x,RegistryPath=%x)\n", 
				DriverObject, RegistryPath));

    RtlZeroMemory(&HwInitData, sizeof(HwInitData));

    HwInitData.HwInitializationDataSize = sizeof(HwInitData);

    /*CDEBUG_BREAK();*/

    //
    // Set the codec entry points for the driver
    //

    HwInitData.HwInterrupt              = NULL; // HwInterrupt is only for HW devices

    HwInitData.HwReceivePacket          = CodecReceivePacket;
    HwInitData.HwCancelPacket           = CodecCancelPacket;
    HwInitData.HwRequestTimeoutHandler  = CodecTimeoutPacket;

    HwInitData.DeviceExtensionSize      = sizeof(HW_DEVICE_EXTENSION);
    HwInitData.PerRequestExtensionSize  = sizeof(SRB_EXTENSION); 
    HwInitData.FilterInstanceExtensionSize = 0;
    HwInitData.PerStreamExtensionSize   = sizeof(STREAMEX); 
    HwInitData.BusMasterDMA             = FALSE;  
    HwInitData.Dma24BitAddresses        = FALSE;
    HwInitData.BufferAlignment          = 3;
    HwInitData.TurnOffSynchronization   = TRUE;
    HwInitData.DmaBufferSize            = 0;

    CDebugPrint(DebugLevelVerbose,(CODECNAME ": StreamClassRegisterAdapter\n"));

    status = StreamClassRegisterAdapter(DriverObject, RegistryPath, &HwInitData);

    CDebugPrint(DebugLevelTrace,(CODECNAME ":<---DriverEntry(DriverObject=%x,RegistryPath=%x)=%d\n",
			    DriverObject, RegistryPath, status));

    return status;     
}

//==========================================================================;
//                   Codec Request Handling Routines
//==========================================================================;

/*
** CodecInitialize()
**
**   This routine is called when an SRB_INITIALIZE_DEVICE request is received
**
** Arguments:
**
**   pSrb - pointer to stream request block for the Initialize command
**
** Returns:
**
** Side Effects:  none
*/

BOOLEAN 
CodecInitialize ( IN OUT PHW_STREAM_REQUEST_BLOCK pSrb )
{
    BOOLEAN							bStatus = FALSE;
    PPORT_CONFIGURATION_INFORMATION ConfigInfo = pSrb->CommandData.ConfigInfo;
    PHW_DEVICE_EXTENSION			pHwDevExt =
        (PHW_DEVICE_EXTENSION)ConfigInfo->HwDeviceExtension;

    CDebugPrint(DebugLevelTrace,(CODECNAME ":--->CodecInitialize(pSrb=%x)\n",pSrb));
    
    if (ConfigInfo->NumberOfAccessRanges == 0) 
    {
        CDebugPrint(DebugLevelVerbose,(CODECNAME ": CodecInitialize\n"));

        ConfigInfo->StreamDescriptorSize = sizeof (HW_STREAM_HEADER) +
            DRIVER_STREAM_COUNT * sizeof (HW_STREAM_INFORMATION);

        // These are the driver defaults for scanline filtering.
        // Modify these WHEN you change the codec type to be more correct.
        SETBIT( pHwDevExt->ScanlinesRequested.DwordBitArray, 21 );

        // These are the driver defaults for subtream filtering. 
        // Modify these WHEN you change the codec type 
		
        pHwDevExt->SubstreamsRequested.SubstreamMask = KS_CC_SUBSTREAM_ODD;
		pHwDevExt->Streams = Streams;
        pHwDevExt->fTunerChange = FALSE;

		//
		// Allocate the results array based on the number of scanlines
		//
		pHwDevExt->DSPResultStartLine = pHwDevExt->DSPResultEndLine = 0;
	    pHwDevExt->DSPResult = ( PDSPRESULT )
			ExAllocatePool( NonPagedPool, 
				sizeof( DSPRESULT ) *
				(FakeVBIInfoHeader.EndLine - FakeVBIInfoHeader.StartLine + 1) );
	    if( !pHwDevExt->DSPResult )
	    {
		   CDebugPrint( DebugLevelError,
			   (CODECNAME ": DSP Result array allocation FAILED\n" ));
		   //pSrb->Status = STATUS_INVALID_PARAMETER;
		}
		else {
			pHwDevExt->DSPResultStartLine = FakeVBIInfoHeader.StartLine;
			pHwDevExt->DSPResultEndLine = FakeVBIInfoHeader.EndLine;
		}

        // Zero out the substream state information (no substreams discovered yet)
        RtlZeroMemory( pHwDevExt->SubStreamState, sizeof(pHwDevExt->SubStreamState) );

#ifdef CCINPUTPIN
		// Init LastPictureNumber's FastMutex
		ExInitializeFastMutex(&pHwDevExt->LastPictureMutex);
#endif // CCINPUTPIN        
        
        pSrb->Status = STATUS_SUCCESS;
        bStatus = TRUE;
    }
    else
    {
        CDebugPrint(DebugLevelError,(CODECNAME ": illegal config info\n"));
        pSrb->Status = STATUS_NO_SUCH_DEVICE;
    }

    CDebugPrint(DebugLevelTrace,
                (CODECNAME ":<---CodecInitialize(pSrb=%x)=%d\n", pSrb, bStatus));
    return (bStatus);
}

/*
** CodecUnInitialize()
**
**   This routine is called when an SRB_UNINITIALIZE_DEVICE request is received
**
** Arguments:
**
**   pSrb - pointer to stream request block for the UnInitialize command
**
** Returns:
**
** Side Effects:  none
*/

BOOLEAN 
CodecUnInitialize ( 
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
   PHW_DEVICE_EXTENSION    pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
   
   CDebugPrint(DebugLevelTrace,(CODECNAME ":--->CodecUnInitialize(pSrb=%x)\n",pSrb));
   pSrb->Status = STATUS_SUCCESS;
   CDebugPrint(DebugLevelTrace,(CODECNAME ":<---CodecUnInitialize(pSrb=%x)\n",pSrb));

    //
    // Free up the results buffer
    //
    if (pHwDevExt->DSPResult) {
		ExFreePool( pHwDevExt->DSPResult );
		pHwDevExt->DSPResult = NULL;
		pHwDevExt->DSPResultStartLine = pHwDevExt->DSPResultEndLine = 0;
	}

    return TRUE;
}


/*
** CodecOpenStream()
**
**   This routine is called when an OpenStream SRB request is received.
**   A stream is identified by a stream number, which indexes an array
**   of KSDATARANGE structures.  The particular KSDATAFORMAT format to
**   be used is also passed in, which should be verified for validity.
**   
** Arguments:
**
**   pSrb - pointer to stream request block for the Open command
**
** Returns:
**
** Side Effects:  none
*/

VOID 
CodecOpenStream( PHW_STREAM_REQUEST_BLOCK pSrb )
{
    //
    // the stream extension structure is allocated by the stream class driver
    //

    PSTREAMEX               pStrmEx = pSrb->StreamObject->HwStreamExtension;
    PHW_DEVICE_EXTENSION    pHwDevExt = pSrb->HwDeviceExtension;
    int                     StreamNumber = pSrb->StreamObject->StreamNumber;

    PKSDATAFORMAT pKSVBIDataFormat =
		(PKSDATAFORMAT)pSrb->CommandData.OpenFormat;

	CDebugPrint(DebugLevelTrace,(CODECNAME ":--->CodecOpenStream(pSrb=%x)\n", pSrb));
    CDebugPrint(DebugLevelVerbose,(CODECNAME ": CodecOpenStream : StreamNumber=%d\n", StreamNumber));

    RtlZeroMemory(pStrmEx, sizeof (STREAMEX));
    
    //
    // check that the stream index requested isn't too high
    // or that the maximum number of instances hasn't been exceeded
    //

    if ( 0 <= StreamNumber && StreamNumber < DRIVER_STREAM_COUNT ) 
	{
        unsigned StreamInstance;
        unsigned maxInstances =
                  Streams[StreamNumber].hwStreamInfo.NumberOfPossibleInstances;

		// Search for next open slot
	    for (StreamInstance=0; StreamInstance < maxInstances; ++StreamInstance)
		{
			if (pHwDevExt->pStrmEx[StreamNumber][StreamInstance] == NULL)
				break;
		}

	    if (StreamInstance < maxInstances)
		{
			if (CodecVerifyFormat(pKSVBIDataFormat, StreamNumber, &pStrmEx->MatchedFormat)) 
			{
				CASSERT (pHwDevExt->pStrmEx[StreamNumber][StreamInstance] == NULL);
               
               InitializeListHead( &pStrmEx->StreamControlQueue );
               InitializeListHead( &pStrmEx->StreamDataQueue );
               KeInitializeSpinLock( &pStrmEx->StreamControlSpinLock );
               KeInitializeSpinLock( &pStrmEx->StreamDataSpinLock );
				// Maintain an array of all the StreamEx structures in the HwDevExt
				// so that we can reference IRPs from any stream

				pHwDevExt->pStrmEx[StreamNumber][StreamInstance] = pStrmEx;
    
                // Save the Stream Format in the Stream Extension as well.
                pStrmEx->OpenedFormat = *pKSVBIDataFormat;

				// Set up pointers to the handlers for the stream data and control handlers

				pSrb->StreamObject->ReceiveDataPacket = 
						(PVOID) Streams[StreamNumber].hwStreamObject.ReceiveDataPacket;
				pSrb->StreamObject->ReceiveControlPacket = 
						(PVOID) Streams[StreamNumber].hwStreamObject.ReceiveControlPacket;
    
				//
				// The DMA flag must be set when the device will be performing DMA directly
				// to the data buffer addresses passed in to the ReceiceDataPacket routines.
				//

				pSrb->StreamObject->Dma = Streams[StreamNumber].hwStreamObject.Dma;

				//
				// The PIO flag must be set when the mini driver will be accessing the data
				// buffers passed in using logical addressing
				//

				pSrb->StreamObject->Pio = Streams[StreamNumber].hwStreamObject.Pio;
               pSrb->StreamObject->Allocator = Streams[StreamNumber].hwStreamObject.Allocator;
				//
				// How many extra bytes will be passed up from the driver for each frame?
				//

				pSrb->StreamObject->StreamHeaderMediaSpecific = 
					Streams[StreamNumber].hwStreamObject.StreamHeaderMediaSpecific;

				pSrb->StreamObject->StreamHeaderWorkspace =
					Streams[StreamNumber].hwStreamObject.StreamHeaderWorkspace;

				//
				// Indicate the clock support available on this stream
				//

				pSrb->StreamObject->HwClockObject = 
					Streams[StreamNumber].hwStreamObject.HwClockObject;

				// 
				// Increment the instance count on this stream
				//
                pStrmEx->StreamInstance = StreamInstance;
				pHwDevExt->ActualInstances[StreamNumber]++;


				// Retain a private copy of the HwDevExt and StreamObject in the stream extension
				// so we can use a timer 

				pStrmEx->pHwDevExt = pHwDevExt;                     // For timer use
				pStrmEx->pStreamObject = pSrb->StreamObject;        // For timer use
               CDebugPrint( DebugLevelVerbose, ( CODECNAME ": Stream Instance %d\n",
               	pStrmEx->StreamInstance ));

                // Copy the default filtering settings
                
                pStrmEx->ScanlinesRequested = pHwDevExt->ScanlinesRequested;
                pStrmEx->SubstreamsRequested = pHwDevExt->SubstreamsRequested;
                //
                // Load up default VBI info header
                RtlCopyMemory( &pStrmEx->CurrentVBIInfoHeader, &FakeVBIInfoHeader,
                	sizeof( KS_VBIINFOHEADER ) );
#ifdef CCINPUTPIN
				// Init VBISrbOnHold's spin lock
				KeInitializeSpinLock(&pStrmEx->VBIOnHoldSpinLock);
#endif // CCINPUTPIN        
				// Init DSP state
                CCStateNew(&pStrmEx->State);
			}
			else
			{
				CDebugPrint(DebugLevelError,
					(CODECNAME ": CodecOpenStream : Invalid Stream Format=%x\n", 
					pKSVBIDataFormat ));
				pSrb->Status = STATUS_INVALID_PARAMETER;
			}
		}
		else
		{
		    CDebugPrint(DebugLevelError,
				(CODECNAME ": CodecOpenStream : Stream %d Too Many Instances=%d\n", 
				StreamNumber, pHwDevExt->ActualInstances[StreamNumber] ));
	        pSrb->Status = STATUS_INVALID_PARAMETER;
		}
	}
	else
	{
	    CDebugPrint(DebugLevelError,
			(CODECNAME ": CodecOpenStream : Invalid StreamNumber=%d\n", 
			StreamNumber ));
        pSrb->Status = STATUS_INVALID_PARAMETER;
    }

    CDebugPrint(DebugLevelTrace,(CODECNAME ":<---CodecOpenStream(pSrb=%x)\n",	pSrb));
}

/*
** CodecCloseStream()
**
**   Close the requested data stream
**
** Arguments:
**
**   pSrb the request block requesting to close the stream
**
** Returns:
**
** Side Effects:  none
*/

VOID 
CodecCloseStream (
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    PSTREAMEX               pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension;
    PHW_DEVICE_EXTENSION    pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
    PHW_STREAM_REQUEST_BLOCK pCurrentSrb;
    PKSDATAFORMAT           pKSDataFormat = pSrb->CommandData.OpenFormat;
    ULONG                   StreamNumber = pSrb->StreamObject->StreamNumber;
    ULONG                   StreamInstance = pStrmEx->StreamInstance;
#ifdef CCINPUTPIN           
    KIRQL                   Irql;
#endif // CCINPUTPIN           

    CDebugPrint(DebugLevelTrace,(CODECNAME ":--->CodecCloseStream(pSrb=%x)\n", pSrb));

    // CDEBUG_BREAK(); // Uncomment this code to break here.


    CDebugPrint( DebugLevelVerbose, ( CODECNAME "Strm %d StrmInst %d ActualInst %d\n",
    	StreamNumber, StreamInstance, pHwDevExt->ActualInstances[StreamNumber] ));
       
   //
   // Flush the stream data queue
   //
#ifdef CCINPUTPIN           
    // Is there an SRB 'on hold'??
	KeAcquireSpinLock(&pStrmEx->VBIOnHoldSpinLock, &Irql);
	if (pStrmEx->pVBISrbOnHold)
	{
		PHW_STREAM_REQUEST_BLOCK pHoldSrb;

		pHoldSrb = pStrmEx->pVBISrbOnHold;
		pStrmEx->pVBISrbOnHold = NULL;
		KeReleaseSpinLock(&pStrmEx->VBIOnHoldSpinLock, Irql);

        pHoldSrb->Status = STATUS_CANCELLED;
	    CDebugPrint(DebugLevelVerbose,
	    	(CODECNAME ":StreamClassStreamNotification(pHoldSrb->Status=0x%x)\n", 
	    	pHoldSrb->Status));
           
        StreamClassStreamNotification(
		   StreamRequestComplete, pHoldSrb->StreamObject, pHoldSrb);
		pSrb = NULL;
	}
	else
		KeReleaseSpinLock(&pStrmEx->VBIOnHoldSpinLock, Irql);
#endif // CCINPUTPIN           
   while( QueueRemove( &pCurrentSrb, &pStrmEx->StreamDataSpinLock,
       &pStrmEx->StreamDataQueue ))
   {
       CDebugPrint( DebugLevelVerbose, 
           ( CODECNAME ": Removing control SRB %x\n", pCurrentSrb ));
       pCurrentSrb->Status = STATUS_CANCELLED;
       StreamClassStreamNotification( StreamRequestComplete,
           pCurrentSrb->StreamObject, pCurrentSrb );
   }
   //
   // Flush the stream control queue
   //
    while( QueueRemove( &pCurrentSrb, &pStrmEx->StreamControlSpinLock,
       &pStrmEx->StreamControlQueue ))
    {
       CDebugPrint( DebugLevelVerbose, 
           ( CODECNAME ": Removing control SRB %x\n", pCurrentSrb ));
       pCurrentSrb->Status = STATUS_CANCELLED;
       StreamClassStreamNotification( StreamRequestComplete,
           pCurrentSrb->StreamObject, pCurrentSrb );
    }

    // Destroy DSP state
    CCStateDestroy(&pStrmEx->State);
           
	pHwDevExt->ActualInstances[StreamNumber]--;  

    CASSERT (pHwDevExt->pStrmEx [StreamNumber][StreamInstance] != 0);

    pHwDevExt->pStrmEx [StreamNumber][StreamInstance] = 0;

    //
    // the minidriver may wish to free any resources that were allocate at
    // open stream time etc.
    //
    pStrmEx->hMasterClock = NULL;

    CDebugPrint(DebugLevelTrace,(CODECNAME ":<---CodecCloseStream(pSrb=%x)\n", pSrb));
}


/*
** CodecStreamInfo()
**
**   Returns the information of all streams that are supported by the
**   mini-driver
**
** Arguments:
**
**   pSrb - Pointer to the STREAM_REQUEST_BLOCK
**        pSrb->HwDeviceExtension - will be the hardware device extension for
**                                  as initialised in HwInitialise
**
** Returns:
**
** Side Effects:  none
*/

VOID 
CodecStreamInfo (
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
{

    int j; 
    
    PHW_DEVICE_EXTENSION pHwDevExt =
        ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);

    //
    // pick up the pointer to header which preceeds the stream info structs
    //

    PHW_STREAM_HEADER pstrhdr =
            (PHW_STREAM_HEADER)&(pSrb->CommandData.StreamBuffer->StreamHeader);

     //
     // pick up the pointer to the array of stream information data structures
     //

    PHW_STREAM_INFORMATION pstrinfo =
            (PHW_STREAM_INFORMATION)&(pSrb->CommandData.StreamBuffer->StreamInfo);


	CDebugPrint(DebugLevelTrace,(CODECNAME ":--->CodecStreamInfo(pSrb=%x)\n", pSrb));
  
    // 
    // verify that the buffer is large enough to hold our return data
    //

    CASSERT (pSrb->NumberOfBytesToTransfer >= 
            sizeof (HW_STREAM_HEADER) +
            sizeof (HW_STREAM_INFORMATION) * DRIVER_STREAM_COUNT);

     //
     // Set the header
     // 

#define GLOBAL_PROPERTIES
#ifdef GLOBAL_PROPERTIES
     StreamHeader.NumDevPropArrayEntries = NUMBER_OF_CODEC_PROPERTY_SETS;
     StreamHeader.DevicePropertiesArray = (PKSPROPERTY_SET) CodecPropertyTable; 
#else // !GLOBAL_PROPERTIES
     StreamHeader.NumDevPropArrayEntries = 0;
     StreamHeader.DevicePropertiesArray = (PKSPROPERTY_SET)NULL; 
#endif // GLOBAL_PROPERTIES
     *pstrhdr = StreamHeader;

     // 
     // stuff the contents of each HW_STREAM_INFORMATION struct 
     //

     for (j = 0; j < DRIVER_STREAM_COUNT; j++) {
        *pstrinfo++ = Streams[j].hwStreamInfo;
     }

     CDebugPrint(DebugLevelTrace,(CODECNAME ":<---CodecStreamInfo(pSrb=%x)\n", pSrb));
}


/*
** CodecReceivePacket()
**
**   Main entry point for receiving codec based request SRBs.  This routine
**   will always be called at High Priority.
**
**   Note: This is an asyncronous entry point.  The request does not complete
**         on return from this function, the request only completes when a
**         StreamClassDeviceNotification on this request block, of type
**         DeviceRequestComplete, is issued.
**
** Arguments:
**
**   pSrb - Pointer to the STREAM_REQUEST_BLOCK
**        pSrb->HwDeviceExtension - will be the hardware device extension for
**                                  as initialised in HwInitialise
**
** Returns:
**
** Side Effects:  none
*/

VOID 
STREAMAPI 
CodecReceivePacket(
    IN PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    PHW_DEVICE_EXTENSION pHwDevExt = pSrb->HwDeviceExtension;

    CDebugPrint(DebugLevelTrace,(CODECNAME ":--->CodecReceivePacket(pSrb=%x)\n", pSrb));

    //
    // Assume success
    //

    pSrb->Status = STATUS_SUCCESS;
    
    if( !pHwDevExt->bAdapterQueueInitialized )
    {
       InitializeListHead( &pHwDevExt->AdapterSRBQueue );
       KeInitializeSpinLock( &pHwDevExt->AdapterSRBSpinLock );
       pHwDevExt->bAdapterQueueInitialized = TRUE;
    }
 
    //
    // determine the type of packet.
    //
    if( QueueAddIfNotEmpty( pSrb, &pHwDevExt->AdapterSRBSpinLock,
       &pHwDevExt->AdapterSRBQueue ))
       return;
       
    do
    {
       CDebugPrint(DebugLevelVerbose,
		    (CODECNAME ": CodecReceivePacket: pSrb->Command=0x%x\n", 
		    pSrb->Command));

       switch (pSrb->Command)
       {

       case SRB_INITIALIZE_DEVICE:

           // open the device
           
           CodecInitialize(pSrb);

           break;

       case SRB_UNINITIALIZE_DEVICE:

           // close the device.  

           CodecUnInitialize(pSrb);

           break;

       case SRB_OPEN_STREAM:

           // open a stream

           CodecOpenStream(pSrb);

           break;

       case SRB_CLOSE_STREAM:

           // close a stream

           CodecCloseStream(pSrb);

           break;

       case SRB_GET_STREAM_INFO:

           //
           // return a block describing all the streams
           //

           CodecStreamInfo(pSrb);

           break;

       case SRB_GET_DATA_INTERSECTION:

           //
           // Return a format, given a range
           //
           switch( pSrb->CommandData.IntersectInfo->StreamNumber )
           {
           case STREAM_VBI:
           	CodecVBIFormatFromRange( pSrb );
              break;
              
#ifdef CCINPUTPIN           
		   // Both streams can use CodecCCFormatFromRange() because they
		   //  both use KSDATAFORMAT structures.
           case STREAM_CCINPUT:		
#endif // CCINPUTPIN           
           case STREAM_CC:
           	  CodecCCFormatFromRange( pSrb );
              break;
              
           default:  // Unknown stream number?
           	CDebugPrint( DebugLevelError, ( CODECNAME ": Unknown Stream Number\n" ));
              CDEBUG_BREAK();
              pSrb->Status = STATUS_NOT_IMPLEMENTED;
              break;
           }
           break;

           // We should never get the following since this is a single instance
           // device
       case SRB_OPEN_DEVICE_INSTANCE:
       case SRB_CLOSE_DEVICE_INSTANCE:
           CDebugPrint(DebugLevelError,
             (CODECNAME ": CodecReceivePacket : SRB_%s_DEVICE_INSTANCE not supported\n", 
              (pSrb->Command == SRB_OPEN_DEVICE_INSTANCE)? "OPEN":"CLOSE" ));
           CDEBUG_BREAK();
   		   // Fall through to NOT IMPLEMENTED

       case SRB_UNKNOWN_DEVICE_COMMAND:		// But this one we don't care about
       case SRB_INITIALIZATION_COMPLETE:	// This one we don't care about
       case SRB_CHANGE_POWER_STATE:	    	// This one we don't care about
           pSrb->Status = STATUS_NOT_IMPLEMENTED;
           break;

       case SRB_GET_DEVICE_PROPERTY:

           //
           // Get codec wide properties
           //

           CodecGetProperty (pSrb);
           break;        

       case SRB_SET_DEVICE_PROPERTY:

           //
           // Set codec wide properties
           //
           CodecSetProperty (pSrb);
           break;

       case SRB_PAGING_OUT_DRIVER:
       case SRB_SURPRISE_REMOVAL:
           CDebugPrint(DebugLevelVerbose,
                (CODECNAME ": CodecReceivePacket: SRB_%s\n", 
                  (pSrb->Command == SRB_SURPRISE_REMOVAL)?
                    "SURPRISE_REMOVAL" : "PAGING_OUT_DRIVER"));
#if 0
       {
           PSTREAMEX   pStrmEx;
           unsigned StreamNumber, StreamInstance;
           unsigned maxInstances =
                  Streams[StreamNumber].hwStreamInfo.NumberOfPossibleInstances;

           // Do we have any pins connected and paused/running?
           //  Search any used slots...
           for (StreamNumber = 0; StreamNumber < DRIVER_STREAM_COUNT; ++StreamNumber) {
               for (StreamInstance=0; StreamInstance < maxInstances; ++StreamInstance)
               {
                   pStrmEx = pHwDevExt->pStrmEx[StreamNumber][StreamInstance];
                   if (pStrmEx != NULL) {
                       switch (pStrmEx->KSState) {
                           case KSSTATE_RUN:
                           case KSSTATE_PAUSE:
                               CDebugPrint(DebugLevelError,
                                 (CODECNAME ": CodecReceivePacket : PAGING_OUT_DRIVER during RUN or PAUSE; failing request\n"));
                               CDEBUG_BREAK();
                               pSrb->Status = STATUS_UNSUCCESSFUL;
                               goto break3;

                           default:
                               // Shouldn't have to do anything here except return SUCCESS
                               break;
                       }
                   }
               }
           }

    break3:
       }
#endif //0
       break;

       case SRB_UNKNOWN_STREAM_COMMAND:
       default:

           CDebugPrint(DebugLevelError,
             (CODECNAME ": CodecReceivePacket : UNKNOWN srb.Command = 0x%x\n", 
              pSrb->Command));
           CDEBUG_BREAK();

           //
           // this is a request that we do not understand.  Indicate invalid
           // command and complete the request
           //
           pSrb->Status = STATUS_NOT_IMPLEMENTED;
       }
       //
       // NOTE:
       //
       // all of the commands that we do, or do not understand can all be completed
       // syncronously at this point, so we can use a common callback routine here.
       // If any of the above commands require asyncronous processing, this will
       // have to change
       //
	    CDebugPrint(DebugLevelVerbose,
		    (CODECNAME ": CodecReceivePacket : DeviceRequestComplete(pSrb->Status=0x%x)\n", 
		    pSrb->Status));
       StreamClassDeviceNotification( DeviceRequestComplete, 
           pSrb->HwDeviceExtension, pSrb );
    }while( QueueRemove( &pSrb, &pHwDevExt->AdapterSRBSpinLock,
           &pHwDevExt->AdapterSRBQueue ));
    
    CDebugPrint(DebugLevelTrace,(CODECNAME ":<---CodecReceivePacket(pSrb=%x)\n", pSrb));
}

/*
** CodecCancelPacket ()
**
**   Request to cancel a packet that is currently in process in the minidriver
**
** Arguments:
**
**   pSrb - pointer to request packet to cancel
**
** Returns:
**
** Side Effects:  none
*/

VOID 
STREAMAPI 
CodecCancelPacket(
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    PSTREAMEX               pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension;
    PHW_DEVICE_EXTENSION    pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
    CDebugPrint(DebugLevelTrace,(CODECNAME ":--->CodecCancelPacket(pSrb=%x)\n", pSrb));
    CASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
    //
    // Check whether the SRB to cancel is in use by this stream
    //
#ifdef CCINPUTPIN
    // Is SRB to cancel 'on hold'??
	KeAcquireSpinLockAtDpcLevel(&pStrmEx->VBIOnHoldSpinLock);
	if (pStrmEx->pVBISrbOnHold && pSrb == pStrmEx->pVBISrbOnHold)
	{
		pStrmEx->pVBISrbOnHold = NULL;
		KeReleaseSpinLockFromDpcLevel(&pStrmEx->VBIOnHoldSpinLock);

        pSrb->Status = STATUS_CANCELLED;
	    CDebugPrint(DebugLevelVerbose,
	    	(CODECNAME ":StreamClassStreamNotification(pSrb->Status=0x%x)\n", 
	    	pSrb->Status));
           
        StreamClassStreamNotification(
		   StreamRequestComplete, pSrb->StreamObject, pSrb);
		pSrb = NULL;
	}
	else
		KeReleaseSpinLockFromDpcLevel(&pStrmEx->VBIOnHoldSpinLock);

   if (NULL == pSrb)
		; // We're done; we CANCELLED the SRB above
   else
#endif // CCINPUTPIN        
   //
   // Attempt removal from data queue
   //
   if( QueueRemoveSpecific( pSrb, &pStrmEx->StreamDataSpinLock,
       &pStrmEx->StreamDataQueue ))
   {
       pSrb->Status = STATUS_CANCELLED;
	    CDebugPrint(DebugLevelVerbose,
	    	(CODECNAME ":StreamRequestComplete(ReadyForNextStreamDataRequest,pSrb->Status=0x%x)\n", 
	    	pSrb->Status));
           
       StreamClassStreamNotification( StreamRequestComplete,
           pSrb->StreamObject, pSrb );
   }
   else
   //
   // Attempt removal from command queue
   //
   if( QueueRemoveSpecific( pSrb, &pStrmEx->StreamControlSpinLock,
       &pStrmEx->StreamControlQueue ))
   {
       pSrb->Status = STATUS_CANCELLED;
	    CDebugPrint(DebugLevelVerbose,
	        (CODECNAME ":StreamRequestComplete(ReadyForNextStreamControlRequest,pSrb->Status=0x%x)\n", 
	        pSrb->Status));
       StreamClassStreamNotification( StreamRequestComplete, pSrb->StreamObject,
           pSrb );
   }
   else
   //
   // Attempt removal from adapter queue
   //
   if( QueueRemoveSpecific( pSrb, &pHwDevExt->AdapterSRBSpinLock,
       &pHwDevExt->AdapterSRBQueue ))
   {
       pSrb->Status = STATUS_CANCELLED;
	    CDebugPrint(DebugLevelVerbose,
	        (CODECNAME ":DeviceRequestComplete(pSrb->Status=0x%x)\n", 
	     	pSrb->Status));
       StreamClassDeviceNotification( DeviceRequestComplete, pSrb->StreamObject,
           pSrb );
   }
   else
       CDebugPrint( DebugLevelWarning, ( CODECNAME "SRB %x not found to cancel\n", pSrb ));
   
    CDebugPrint(DebugLevelTrace,(CODECNAME ":<---CodecCancelPacket(pSrb=%x)\n", pSrb));
}


/*
** CodecTimeoutPacket()
**
**   This routine is called when a packet has been in the minidriver for
**   too long.  The codec must decide what to do with the packet
**
** Arguments:
**
**   pSrb - pointer to the request packet that timed out
**
** Returns:
**
** Side Effects:  none
*/

VOID
STREAMAPI  
CodecTimeoutPacket(
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    CDebugPrint(DebugLevelTrace,(CODECNAME ":--->CodecTimeoutPacket(pSrb=%x)\n", pSrb));

    //
    // if we timeout while playing, then we need to consider this
    // condition an error, and reset the hardware, and reset everything
    // as well as cancelling this and all requests
    //

    //
    // if we are not playing, and this is a CTRL request, we still
    // need to reset everything as well as cancelling this and all requests
    //

    //
    // if this is a data request, and the device is paused, we probably have
    // run out of data buffer, and need more time, so just reset the timer,
    // and let the packet continue
    //

//    pSrb->TimeoutCounter = pSrb->TimeoutOriginal;
    pSrb->TimeoutCounter = 0;
    
    CDebugPrint(DebugLevelTrace,(CODECNAME ":<---CodecTimeoutPacket(pSrb=%x)\n", pSrb));
}

#if 0
/*
** CompleteStreamSRB ()
**
**   This routine is called when a packet is being completed.
**   The optional second notification type is used to indicate ReadyForNext
**
** Arguments:
**
**   pSrb - pointer to the request packet that timed out
**
**   NotificationType1 - what kind of notification to return
**
**   NotificationType2 - what kind of notification to return (may be 0)
**
**
** Returns:
**
** Side Effects:  none
*/

VOID 
CompleteStreamSRB (
     IN PHW_STREAM_REQUEST_BLOCK pSrb, 
     STREAM_MINIDRIVER_STREAM_NOTIFICATION_TYPE NotificationType1,
     BOOL fUseNotification2,
     STREAM_MINIDRIVER_STREAM_NOTIFICATION_TYPE NotificationType2
    )
{
    CDebugPrint(DebugLevelTrace,
		(CODECNAME ":--->CompleteStreamSRB(pSrb=%x)\n", pSrb));

	CDebugPrint(DebugLevelVerbose,
		(CODECNAME ": CompleteStreamSRB : NotificationType1=%d\n", 
		NotificationType1 ));

    StreamClassStreamNotification(
            NotificationType1,
            pSrb->StreamObject,
            pSrb);

    if (fUseNotification2) 
	{            
		// ReadyForNext

		CDebugPrint(DebugLevelVerbose,
			(CODECNAME ": CompleteStreamSRB : NotificationType2=%d\n", 
			NotificationType2 ));

		StreamClassStreamNotification(
			NotificationType2,
			pSrb->StreamObject);
	}

    CDebugPrint(DebugLevelTrace,(CODECNAME ":<---CompleteStreamSRB(pSrb=%x)\n", pSrb));
}

/*
** CompleteDeviceSRB ()
**
**   This routine is called when a packet is being completed.
**   The optional second notification type is used to indicate ReadyForNext
**
** Arguments:
**
**   pSrb - pointer to the request packet that timed out
**
**   NotificationType - what kind of notification to return
**
**   fReadyForNext - Send the "ReadyForNextSRB" 
**
**
** Returns:
**
** Side Effects:  none
*/

VOID
CompleteDeviceSRB (
     IN PHW_STREAM_REQUEST_BLOCK pSrb, 
     IN STREAM_MINIDRIVER_DEVICE_NOTIFICATION_TYPE NotificationType,
     BOOL fReadyForNext
    )
{
    CDebugPrint(DebugLevelTrace,(CODECNAME ":--->CompleteDeviceSRB(pSrb=%x)\n", pSrb));

	CDebugPrint(DebugLevelVerbose,
		(CODECNAME ": CompleteDeviceSRB : NotificationType=%d\n", 
		NotificationType ));

    StreamClassDeviceNotification(
            NotificationType,
            pSrb->HwDeviceExtension,
            pSrb);

    if (fReadyForNext) 
	{
		CDebugPrint(DebugLevelVerbose,
			(CODECNAME ": CompleteDeviceSRB : ReadyForNextDeviceRequest\n"));

		StreamClassDeviceNotification( 
			ReadyForNextDeviceRequest,
			pSrb->HwDeviceExtension);
    }

    CDebugPrint(DebugLevelTrace,(CODECNAME ":<---CompleteDeviceSRB(pSrb=%x)\n", pSrb));
}
#endif //0

/*
** CodecCompareGUIDsAndFormatSize()
**
**   Checks for a match on the three GUIDs and FormatSize
**
** Arguments:
**
**         IN DataRange1
**         IN DataRange2
**
** Returns:
** 
**   TRUE if all elements match
**   FALSE if any are different
**
** Side Effects:  none
*/

BOOL 
CodecCompareGUIDsAndFormatSize(
    IN PKSDATARANGE DataRange1,
    IN PKSDATARANGE DataRange2,
    BOOLEAN bCheckSize
    )
{
    BOOL	rval = FALSE;
    
    CDebugPrint(DebugLevelTrace,
		(CODECNAME ":--->CodecCompareGUIDsAndFormatSize(DataRange1=%x,DataRange2=%x,bCheckSize=%s)\r\n", 
        DataRange1, DataRange2, bCheckSize ? "TRUE":"FALSE"));

	if ( IsEqualGUID(&DataRange1->MajorFormat, &KSDATAFORMAT_TYPE_WILDCARD)
	  || IsEqualGUID(&DataRange2->MajorFormat, &KSDATAFORMAT_TYPE_WILDCARD)
	  || IsEqualGUID(&DataRange1->MajorFormat, &DataRange2->MajorFormat) )
	{
		if ( !IsEqualGUID(&DataRange1->MajorFormat, &DataRange2->MajorFormat) )
		{
			CDebugPrint(DebugLevelVerbose,
				(CODECNAME ": CodecCompareGUIDsAndFormatSize : Matched MajorFormat Using Wildcard:\n\t[%s] vs. [%s]\n", 
				&DataRange1->MajorFormat, &DataRange2->MajorFormat ));
		}

		if ( IsEqualGUID(&DataRange1->SubFormat, &KSDATAFORMAT_SUBTYPE_WILDCARD)
		  || IsEqualGUID(&DataRange2->SubFormat, &KSDATAFORMAT_SUBTYPE_WILDCARD)
	      || IsEqualGUID(&DataRange1->SubFormat, &DataRange2->SubFormat) )
		{
			if ( !IsEqualGUID(&DataRange1->SubFormat, &DataRange2->SubFormat) )
			{
				CDebugPrint(DebugLevelVerbose,
					(CODECNAME ": CodecCompareGUIDsAndFormatSize : Matched SubFormat Using Wildcard:\n\t[%s] vs. [%s]\n", 
					&DataRange1->SubFormat, &DataRange2->SubFormat ));
			}

			if ( IsEqualGUID(&DataRange1->Specifier, &KSDATAFORMAT_SPECIFIER_NONE)
			  || IsEqualGUID(&DataRange2->Specifier, &KSDATAFORMAT_SPECIFIER_NONE)
			  || IsEqualGUID(&DataRange1->Specifier, &DataRange2->Specifier) )
			{
				if ( !IsEqualGUID(&DataRange1->Specifier, &DataRange2->Specifier) )
				{
					CDebugPrint(DebugLevelVerbose,
						(CODECNAME ": CodecCompareGUIDsAndFormatSize : Matched Specifier Using Wildcard:\n\t[%s] vs. [%s]\n", 
						&DataRange1->Specifier, &DataRange2->Specifier ));
				}

				if ( !bCheckSize || DataRange1->FormatSize == DataRange2->FormatSize)
				{
					rval = TRUE;
				}
				else
				{
					CDebugPrint(DebugLevelVerbose,
						(CODECNAME ": CodecCompareGUIDsAndFormatSize : FormatSize mismatch=%d vs. %d\n", 
						DataRange1->FormatSize, DataRange2->FormatSize ));
				}
			}
			else
			{
				CDebugPrint(DebugLevelVerbose,
					(CODECNAME ": CodecCompareGUIDsAndFormatSize : Specifier mismatch:\n\t[%s] vs. [%s]\n", 
					&DataRange1->Specifier, &DataRange2->Specifier ));
			}
		}
		else
		{
			CDebugPrint(DebugLevelVerbose,
				(CODECNAME ": CodecCompareGUIDsAndFormatSize : Subformat mismatch:\n\t[%s] vs. [%s]\n", 
				&DataRange1->SubFormat, &DataRange2->SubFormat ));
		}
	}
    else
	{
		CDebugPrint(DebugLevelVerbose,
			(CODECNAME ": CodecCompareGUIDsAndFormatSize : MajorFormat mismatch:\n\t[%s] vs. [%s]\n", 
			&DataRange1->MajorFormat, &DataRange2->MajorFormat ));
	}

    CDebugPrint(DebugLevelTrace,
		(CODECNAME ":<---CodecCompareGUIDsAndFormatSize(DataRange1=%x,DataRange2=%x,bCheckSize=%s)=%s\n", 
		DataRange1, DataRange2, bCheckSize ? "TRUE":"FALSE", rval? "TRUE":"FALSE"));

    return rval;
}

/*
** CodecVerifyFormat()
**
**   Checks the validity of a format request
**
** Arguments:
**
**   pKSDataFormat - pointer to a KS_DATAFORMAT_VBIINFOHEADER structure.
**
** Returns:
** 
**   TRUE if the format is supported
**   FALSE if the format cannot be suppored
**
** Side Effects:  none
*/

BOOL 
CodecVerifyFormat(IN KSDATAFORMAT *pKSDataFormat, UINT StreamNumber, PKSDATARANGE pMatchedFormat )
{
    BOOL	rval = FALSE;
    ULONG     FormatCount;
    PKS_DATARANGE_VIDEO ThisFormat;
    PKS_DATAFORMAT_VBIINFOHEADER    pKSVBIDataFormat = ( PKS_DATAFORMAT_VBIINFOHEADER )pKSDataFormat;

    CDebugPrint(DebugLevelTrace,(CODECNAME ":--->CodecVerifyFormat(%x)\n", pKSDataFormat));
    
    for( FormatCount = 0; rval == FALSE && FormatCount < Streams[StreamNumber].hwStreamInfo.NumberOfFormatArrayEntries;
        FormatCount++ )
    {
        CDebugPrint(DebugLevelTrace,(CODECNAME , "Testing stream %d against format %x\r\n", StreamNumber, FormatCount ));
        
        ThisFormat = ( PKS_DATARANGE_VIDEO )Streams[StreamNumber].hwStreamInfo.StreamFormatsArray[FormatCount];

        if( !CodecCompareGUIDsAndFormatSize( pKSDataFormat, &ThisFormat->DataRange, FALSE ) )
        {
        	CDebugPrint( DebugLevelVerbose, ( CODECNAME ": General format mismatch\n" ));
        	continue;
        }
        if( IsEqualGUID( &ThisFormat->DataRange.Specifier, &KSDATAFORMAT_SPECIFIER_VBI ) )
        {
        	if( pKSVBIDataFormat->VBIInfoHeader.VideoStandard != KS_AnalogVideo_NTSC_M )
        	{
        		CDebugPrint( DebugLevelVerbose, ( CODECNAME ": Incompatible video standard\n" ));
	           continue;
	        }
	        if( pKSVBIDataFormat->VBIInfoHeader.StartLine < MIN_VBI_Y_SAMPLES )
	        {
	        	CDebugPrint( DebugLevelVerbose, ( CODECNAME ": VBIInfoHeader.StartLine too small %u\n",
	           	pKSVBIDataFormat->VBIInfoHeader.StartLine ));
	           continue;
	        }
	        if( pKSVBIDataFormat->VBIInfoHeader.EndLine > MAX_VBI_Y_SAMPLES )
	        {
	        	CDebugPrint( DebugLevelVerbose, ( CODECNAME ": VBIInfoHeader.EndLine too big %u\n",
	           	pKSVBIDataFormat->VBIInfoHeader.EndLine ));
	           continue;
	        }
	        if( pKSVBIDataFormat->VBIInfoHeader.SamplesPerLine < MIN_VBI_X_SAMPLES ||
				pKSVBIDataFormat->VBIInfoHeader.SamplesPerLine > MAX_VBI_X_SAMPLES )
	        {
	        	CDebugPrint( DebugLevelVerbose, ( CODECNAME ": Invalid VBIInfoHeader.SamplesPerLine %u\n",
	           	pKSVBIDataFormat->VBIInfoHeader.SamplesPerLine ));
				continue;
	        }             
	        rval = TRUE;
        }
        else
        if( IsEqualGUID( &ThisFormat->DataRange.Specifier, &KSDATAFORMAT_SPECIFIER_NONE ) )
        	rval = TRUE;
        else
        {
        	CDebugPrint( DebugLevelVerbose, ( CODECNAME ": Incompatible major format\n" ));
        	continue;
        }
        if( rval == TRUE && pMatchedFormat )
           *pMatchedFormat = ThisFormat->DataRange;
    }
    CDebugPrint(DebugLevelTrace,(CODECNAME ":<---CodecVerifyFormat(%x)=%s\n", pKSDataFormat, rval? "TRUE":"FALSE"));
	return rval;
}

/*
** CodecVBIFormatFromRange()
**
**   Returns a DATAFORMAT from a DATARANGE
**
** Arguments:
**
**         IN PHW_STREAM_REQUEST_BLOCK pSrb 
**
** Returns:
** 
**   TRUE if the format is supported
**   FALSE if the format cannot be suppored
**
** Side Effects:  none
*/

BOOL 
CodecVBIFormatFromRange( IN PHW_STREAM_REQUEST_BLOCK pSrb )
{
	BOOL						bStatus = FALSE;
    PSTREAM_DATA_INTERSECT_INFO IntersectInfo;
    PKSDATARANGE                DataRange;
    BOOL                        OnlyWantsSize;
    ULONG                       StreamNumber;
    ULONG                       j;
    ULONG                       NumberOfFormatArrayEntries;
    PKSDATAFORMAT               *pAvailableFormats;

    CDebugPrint(DebugLevelTrace,(CODECNAME ":--->CodecVBIFormatFromRange(pSrb=%x)\n", pSrb));

    IntersectInfo = pSrb->CommandData.IntersectInfo;
    StreamNumber = IntersectInfo->StreamNumber;
    DataRange = IntersectInfo->DataRange;

    pSrb->ActualBytesTransferred = 0;

    //
    // Check that the stream number is valid
    //

//    if (StreamNumber < DRIVER_STREAM_COUNT) 
//	{
		NumberOfFormatArrayEntries = 
				Streams[StreamNumber].hwStreamInfo.NumberOfFormatArrayEntries;

		//
		// Get the pointer to the array of available formats
		//

		pAvailableFormats = Streams[StreamNumber].hwStreamInfo.StreamFormatsArray;

		//
		// Is the caller trying to get the format, or the size of the format?
		//

		OnlyWantsSize = (IntersectInfo->SizeOfDataFormatBuffer == sizeof(ULONG));

		//
		// Walk the formats supported by the stream searching for a match
		// of the three GUIDs which together define a DATARANGE
		//
		for (j = 0; j < NumberOfFormatArrayEntries; j++, pAvailableFormats++) 
		{
			if ( CodecCompareGUIDsAndFormatSize(DataRange, *pAvailableFormats, TRUE) )
			{
#ifdef KS_DATARANGE_VIDEO_VBI__EQ__KS_DATAFORMAT_VBIINFOHEADER
				ULONG	FormatSize = (*pAvailableFormats)->FormatSize;
#else
                PKS_DATARANGE_VIDEO_VBI pDataRangeVBI = (PKS_DATARANGE_VIDEO_VBI)*pAvailableFormats;
				ULONG	FormatSize = sizeof( KS_DATAFORMAT_VBIINFOHEADER );
#endif

				// Is the caller trying to get the format, or the size of the format?

				if ( IntersectInfo->SizeOfDataFormatBuffer == sizeof(FormatSize) )
				{					
       				CDebugPrint(DebugLevelVerbose,
						(CODECNAME ": CodecVBIFormatFromRange : Format Size=%d\n", 
						FormatSize));
					*(PULONG)IntersectInfo->DataFormatBuffer = FormatSize;
					pSrb->ActualBytesTransferred = sizeof(FormatSize);
					bStatus = TRUE;
				}
				else
				{
					// Verify that there is enough room in the supplied buffer for the whole thing
					if ( IntersectInfo->SizeOfDataFormatBuffer >= FormatSize ) 
					{
#ifdef KS_DATARANGE_VIDEO_VBI__EQ__KS_DATAFORMAT_VBIINFOHEADER
						RtlCopyMemory(IntersectInfo->DataFormatBuffer, *pAvailableFormats, FormatSize);
						pSrb->ActualBytesTransferred = FormatSize;
#else
                        PKS_DATAFORMAT_VBIINFOHEADER InterVBIHdr =
							(PKS_DATAFORMAT_VBIINFOHEADER)IntersectInfo->DataFormatBuffer;

						RtlCopyMemory(&InterVBIHdr->DataFormat, &pDataRangeVBI->DataRange, sizeof(KSDATARANGE));

						((PKSDATAFORMAT)IntersectInfo->DataFormatBuffer)->FormatSize = FormatSize;

						RtlCopyMemory(&InterVBIHdr->VBIInfoHeader, &pDataRangeVBI->VBIInfoHeader, sizeof(KS_VBIINFOHEADER));
						pSrb->ActualBytesTransferred = FormatSize;
#endif
						bStatus = TRUE;
					}
					else
					{
       					CDebugPrint(DebugLevelVerbose,
							(CODECNAME ": CodecVBIFormatFromRange : Buffer Too Small=%d vs. %d\n", 
							IntersectInfo->SizeOfDataFormatBuffer, FormatSize));
						pSrb->Status = STATUS_BUFFER_TOO_SMALL;
					}
				}
				break;
			}
		}

		if ( j == NumberOfFormatArrayEntries )
		{
			CDebugPrint(DebugLevelVerbose,(CODECNAME ": CodecVBIFormatFromRange : Stream Format not found.\n" ));
		}

//	}
//	else
//	{
//		CDebugPrint(DebugLevelVerbose,(CODECNAME ": CodecVBIFormatFromRange : StreamNumber too big=%d\n", StreamNumber));
//        pSrb->Status = STATUS_NOT_IMPLEMENTED;
//        bStatus = FALSE;
//        CDEBUG_BREAK();
//    }

    CDebugPrint(DebugLevelTrace,
		(CODECNAME ":<---CodecVBIFormatFromRange(pSrb=%x)=%s\n", 
		pSrb, bStatus ? "TRUE" : "FALSE" ));
    return bStatus;
}


/*
** CodecCCFormatFromRange()
**
**   Returns a DATAFORMAT from a DATARANGE
**
** Arguments:
**
**         IN PHW_STREAM_REQUEST_BLOCK pSrb 
**
** Returns:
** 
**   TRUE if the format is supported
**   FALSE if the format cannot be suppored
**
** Side Effects:  none
*/

BOOL 
CodecCCFormatFromRange( IN PHW_STREAM_REQUEST_BLOCK pSrb )
{
	BOOL						bStatus = FALSE;
    PSTREAM_DATA_INTERSECT_INFO IntersectInfo;
    PKSDATARANGE                DataRange;
    BOOL                        OnlyWantsSize;
    ULONG                       StreamNumber;
    ULONG                       j;
    ULONG                       NumberOfFormatArrayEntries;
    PKSDATAFORMAT               *pAvailableFormats;

    CDebugPrint(DebugLevelTrace,(CODECNAME ":--->CodecCCFormatFromRange(pSrb=%x)\n", pSrb));

    IntersectInfo = pSrb->CommandData.IntersectInfo;
    StreamNumber = IntersectInfo->StreamNumber;
    DataRange = IntersectInfo->DataRange;

    pSrb->ActualBytesTransferred = 0;

    //
    // Check that the stream number is valid
    //

//    if (StreamNumber < DRIVER_STREAM_COUNT) 
//	{
		NumberOfFormatArrayEntries = 
				Streams[StreamNumber].hwStreamInfo.NumberOfFormatArrayEntries;

		//
		// Get the pointer to the array of available formats
		//

		pAvailableFormats = Streams[StreamNumber].hwStreamInfo.StreamFormatsArray;

		//
		// Is the caller trying to get the format, or the size of the format?
		//

		OnlyWantsSize = (IntersectInfo->SizeOfDataFormatBuffer == sizeof(ULONG));

		//
		// Walk the formats supported by the stream searching for a match
		// of the three GUIDs which together define a DATARANGE
		//
		for (j = 0; j < NumberOfFormatArrayEntries; j++, pAvailableFormats++) 
		{
			if ( CodecCompareGUIDsAndFormatSize(DataRange, *pAvailableFormats, TRUE) )
			{
                PKSDATARANGE pDataRangeCC = (PKSDATARANGE)*pAvailableFormats;
				ULONG	FormatSize = sizeof( KSDATARANGE );

				// Is the caller trying to get the format, or the size of it?

				if ( IntersectInfo->SizeOfDataFormatBuffer == sizeof(FormatSize) )
				{					
       				CDebugPrint(DebugLevelVerbose,
						(CODECNAME ": CodecCCFormatFromRange : Format Size=%d\n", 
						FormatSize));
					*(PULONG)IntersectInfo->DataFormatBuffer = FormatSize;
					pSrb->ActualBytesTransferred = sizeof(FormatSize);
					bStatus = TRUE;
				}
				else
				{
					// Verify that there is enough room in the supplied buffer
					//  for the whole thing
					if ( IntersectInfo->SizeOfDataFormatBuffer >= FormatSize ) 
					{
						PKSDATAFORMAT InterCCHdr =
							(PKSDATAFORMAT)IntersectInfo->DataFormatBuffer;

                        *InterCCHdr = *pDataRangeCC;

						InterCCHdr->FormatSize = FormatSize;

						pSrb->ActualBytesTransferred = FormatSize;

						bStatus = TRUE;
					}
					else
					{
       					CDebugPrint(DebugLevelVerbose,
							(CODECNAME ": CodecCCFormatFromRange : Buffer Too Small=%d vs. %d\n", 
							IntersectInfo->SizeOfDataFormatBuffer, FormatSize));
						pSrb->Status = STATUS_BUFFER_TOO_SMALL;
					}
				}
				break;
			}
		}

		if ( j == NumberOfFormatArrayEntries )
		{
			CDebugPrint(DebugLevelVerbose,(CODECNAME ": CodecCCFormatFromRange : Stream Format not found.\n" ));
		}

//	}
//	else
//	{
//		CDebugPrint(DebugLevelVerbose,(CODECNAME ": CodecVBIFormatFromRange : StreamNumber too big=%d\n", StreamNumber));
//        pSrb->Status = STATUS_NOT_IMPLEMENTED;
//        bStatus = FALSE;
//        CDEBUG_BREAK();
//    }

    CDebugPrint(DebugLevelTrace,
		(CODECNAME ":<---CodecCCFormatFromRange(pSrb=%x)=%s\n", 
		pSrb, bStatus ? "TRUE" : "FALSE" ));
    return bStatus;
}

/*
** QueueAddIfNotEmpty
**
**   Adds an SRB to the current queue if it is not empty
**
** Arguments:
**
**         IN PHW_STREAM_REQUEST_BLOCK pSrb 
**         IN PKSPIN_LOCK              pQueueSpinLock
**         IN PLIST_ENTRY              pQueue
**
** Returns:
** 
** TRUE if SRB was added (queue is not empty)
** FALSE if SRB was not added (queue is empty)
** Side Effects:  none
*/
BOOL STREAMAPI QueueAddIfNotEmpty( IN PHW_STREAM_REQUEST_BLOCK pSrb,
							IN PKSPIN_LOCK pQueueSpinLock,
                           IN PLIST_ENTRY pQueue
                           )
{
   KIRQL           Irql;
   PSRB_EXTENSION  pSrbExtension;
   BOOL            bAddedSRB = FALSE;
   
   CDebugPrint( DebugLevelVerbose, ( CODECNAME ":--->QueueAddIfNotEmpty %x\n", pSrb ));
   CASSERT( pSrb );
   pSrbExtension = ( PSRB_EXTENSION )pSrb->SRBExtension;
   CASSERT( pSrbExtension );
   KeAcquireSpinLock( pQueueSpinLock, &Irql );
   if( !IsListEmpty( pQueue ))
   {
       pSrbExtension->pSrb = pSrb;
       InsertTailList( pQueue, &pSrbExtension->ListEntry );
       bAddedSRB = TRUE;
   }
   KeReleaseSpinLock( pQueueSpinLock, Irql );
   CDebugPrint( DebugLevelVerbose, ( CODECNAME ": %s%x\n", bAddedSRB ? 
       "Added SRB to Queue " : ": Queue is empty, not adding ", pSrb ));
   CDebugPrint( DebugLevelVerbose, ( CODECNAME ":<---QueueAddIfNotEmpty %x\n", bAddedSRB ));
   
   return bAddedSRB;
}

/*
** QueueAdd
**
**   Adds an SRB to the current queue unconditionally
**
** Arguments:
**
**         IN PHW_STREAM_REQUEST_BLOCK pSrb 
**         IN PKSPIN_LOCK              pQueueSpinLock
**         IN PLIST_ENTRY              pQueue
**
** Returns:
** 
** TRUE 
** Side Effects:  none
*/
BOOL STREAMAPI QueueAdd( IN PHW_STREAM_REQUEST_BLOCK pSrb,
							IN PKSPIN_LOCK pQueueSpinLock,
                           IN PLIST_ENTRY pQueue
                           )
{
   KIRQL           Irql;
   PSRB_EXTENSION  pSrbExtension;
   
   CDebugPrint( DebugLevelVerbose, ( CODECNAME ":--->QueueAdd %x\n", pSrb ));
   
   CASSERT( pSrb );
   pSrbExtension = ( PSRB_EXTENSION )pSrb->SRBExtension;
   CASSERT( pSrbExtension );
   
   KeAcquireSpinLock( pQueueSpinLock, &Irql );
   
   pSrbExtension->pSrb = pSrb;
   InsertTailList( pQueue, &pSrbExtension->ListEntry );
   
   KeReleaseSpinLock( pQueueSpinLock, Irql );
   
   CDebugPrint( DebugLevelVerbose, ( CODECNAME ": Added SRB %x to Queue\n", pSrb ));
   CDebugPrint( DebugLevelVerbose, ( CODECNAME ":<---QueueAdd\n" ));
   
   return TRUE;
}


/*
** QueueRemove
**
**   Removes the next available SRB from the current queue
**
** Arguments:
**
**         IN PHW_STREAM_REQUEST_BLOCK * pSrb 
**         IN PKSPIN_LOCK              pQueueSpinLock
**         IN PLIST_ENTRY              pQueue
**
** Returns:
**
** TRUE if SRB was removed
** FALSE if SRB was not removed
** Side Effects:  none
*/
                         
BOOL STREAMAPI QueueRemove( 
                           IN OUT PHW_STREAM_REQUEST_BLOCK * pSrb,
							IN PKSPIN_LOCK pQueueSpinLock,
                           IN PLIST_ENTRY pQueue
                           )
{
   KIRQL                       Irql;
   BOOL                        bRemovedSRB = FALSE;
   
   CDebugPrint( DebugLevelVerbose, ( CODECNAME ":--->QueueRemove\n" ));
   
   KeAcquireSpinLock( pQueueSpinLock, &Irql );
   *pSrb = ( PHW_STREAM_REQUEST_BLOCK )NULL;
   CDebugPrint( DebugLevelVerbose,
       ( CODECNAME ": QFlink %x QBlink %x\n", pQueue->Flink, pQueue->Blink ));
   if( !IsListEmpty( pQueue ))
   {
       PHW_STREAM_REQUEST_BLOCK * pCurrentSrb;
       PUCHAR          Ptr = ( PUCHAR )RemoveHeadList( pQueue );
       pCurrentSrb = ( PHW_STREAM_REQUEST_BLOCK * )((( PUCHAR )Ptr ) +
           sizeof( LIST_ENTRY ));
       CASSERT( *pCurrentSrb );
       *pSrb = *pCurrentSrb;
       bRemovedSRB = TRUE;
   }
   else
       CDebugPrint( DebugLevelVerbose, ( CODECNAME ": Queue is empty\n" ));
   KeReleaseSpinLock( pQueueSpinLock, Irql );
   
   CDebugPrint( DebugLevelVerbose, ( CODECNAME ":<---QueueRemove %x %x\n",
       bRemovedSRB, *pSrb ));
   return bRemovedSRB;
}

/*
** QueueRemoveSpecific
**
**   Removes a specific SRB from the queue
**
** Arguments:
**
**         IN PHW_STREAM_REQUEST_BLOCK pSrb           
**         IN PKSPIN_LOCK              pQueueSpinLock
**         IN PLIST_ENTRY              pQueue
**
** Returns:
**
** TRUE if the SRB was found and removed
** FALSE if the SRB was not found
** 
** Side Effects:  none
*/

BOOL STREAMAPI QueueRemoveSpecific( 
							IN PHW_STREAM_REQUEST_BLOCK pSrb,
                           IN PKSPIN_LOCK pQueueSpinLock,
                           IN PLIST_ENTRY pQueue
                           )
{
   KIRQL           Irql;
   PHW_STREAM_REQUEST_BLOCK * pCurrentSrb;
   PLIST_ENTRY     pCurrentEntry;
   BOOL            bRemovedSRB = FALSE;
   
   CASSERT( pSrb );
   CDebugPrint( DebugLevelVerbose, ( CODECNAME ":--->QueueRemoveSpecific %x\n", pSrb ));
   
   KeAcquireSpinLock( pQueueSpinLock, &Irql );
   
   if( !IsListEmpty( pQueue ))
   {
       pCurrentEntry = pQueue->Flink;
       while(( pCurrentEntry != pQueue ) && !bRemovedSRB )
       {
           pCurrentSrb = ( PHW_STREAM_REQUEST_BLOCK * )((( PUCHAR )pCurrentEntry ) + 
               sizeof( LIST_ENTRY ));
           CASSERT( *pCurrentSrb );
           if( *pCurrentSrb == pSrb )
           {
               RemoveEntryList( pCurrentEntry );
               bRemovedSRB = TRUE;
           }
           pCurrentEntry = pCurrentEntry->Flink;
       }
   }
   KeReleaseSpinLock( pQueueSpinLock, Irql );
   if( IsListEmpty( pQueue ))
       CDebugPrint( DebugLevelVerbose, ( CODECNAME ": Queue is empty\n" ));   
   CDebugPrint( DebugLevelVerbose, ( CODECNAME ":<---QueueRemoveSpecific %x\n",
       bRemovedSRB ));
   return bRemovedSRB;
}                                                        
/*
** QueueEmpty
**
**   Indicates whether or not the queue is empty
**
** Arguments:
**
**         IN PKSPIN_LOCK              pQueueSpinLock
**         IN PLIST_ENTRY              pQueue
**
** Returns:
**
** TRUE if queue is empty
** FALSE if queue is not empty
** Side Effects:  none
*/
BOOL STREAMAPI QueueEmpty(
                           IN PKSPIN_LOCK pQueueSpinLock,
                           IN PLIST_ENTRY pQueue
                           )
{
   KIRQL       Irql;
   BOOL        bEmpty = FALSE;
   
   CDebugPrint( DebugLevelVerbose, ( CODECNAME ":---> QueueEmpty\n" ));
   KeAcquireSpinLock( pQueueSpinLock, &Irql );
   bEmpty = IsListEmpty( pQueue );  
   KeReleaseSpinLock( pQueueSpinLock, Irql );
   CDebugPrint( DebugLevelVerbose, ( CODECNAME ":<--- QueueEmpty %x\n", bEmpty ));
   return bEmpty;
}