1761 lines
52 KiB
C
1761 lines
52 KiB
C
//==========================================================================;
|
|
//
|
|
// 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;
|
|
}
|