You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2309 lines
78 KiB
2309 lines
78 KiB
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
// Copyright (c) 1996, 1997 Microsoft Corporation
|
|
//
|
|
//
|
|
// Module Name:
|
|
// mpe.c
|
|
//
|
|
// Abstract:
|
|
//
|
|
//
|
|
// Author:
|
|
//
|
|
// P Porzuczek
|
|
//
|
|
// Environment:
|
|
//
|
|
// Revision History:
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <wdm.h>
|
|
#include <strmini.h>
|
|
#include <ksmedia.h>
|
|
#include <BdaTypes.h>
|
|
#include <BdaMedia.h>
|
|
|
|
#include "Mpe.h"
|
|
#include "MpeMedia.h"
|
|
#include "MpeStream.h"
|
|
|
|
#include "Main.h"
|
|
#include "filter.h"
|
|
|
|
|
|
#pragma pack (1)
|
|
|
|
typedef struct
|
|
{
|
|
BYTE table_id;
|
|
USHORT section_syntax_indicator : 1;
|
|
USHORT private_indicator: 1;
|
|
USHORT reserved1: 2;
|
|
USHORT section_length: 12;
|
|
BYTE MAC_address_6;
|
|
BYTE MAC_address_5;
|
|
BYTE reserved2 : 2;
|
|
BYTE payload_scrambling : 2;
|
|
BYTE address_scrambling : 2;
|
|
BYTE LLC_SNAP_flag : 1;
|
|
BYTE current_next_indicator : 1;
|
|
BYTE section_number;
|
|
BYTE last_section_number;
|
|
BYTE MAC_address_4;
|
|
BYTE MAC_address_3;
|
|
BYTE MAC_address_2;
|
|
BYTE MAC_address_1;
|
|
BYTE Data [0];
|
|
|
|
} SECTION_HEADER, *PSECTION_HEADER;
|
|
|
|
typedef struct
|
|
{
|
|
BYTE dsap;
|
|
BYTE ssap;
|
|
BYTE cntl;
|
|
BYTE org [3];
|
|
USHORT type;
|
|
BYTE Data [0];
|
|
|
|
} LLC_SNAP, *PLLC_SNAP;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
BYTE MAC_Dest_Address [6];
|
|
BYTE MAC_Src_Address [6];
|
|
USHORT usLength;
|
|
|
|
} MAC_Address, *PMAC_Address;
|
|
|
|
typedef struct _HEADER_IP_
|
|
{
|
|
UCHAR ucVersion_Length;
|
|
UCHAR ucTOS;
|
|
USHORT usLength;
|
|
USHORT usId;
|
|
USHORT usFlags_Offset;
|
|
UCHAR ucTTL;
|
|
UCHAR ucProtocol;
|
|
USHORT usHdrChecksum;
|
|
UCHAR ucSrcAddress [4];
|
|
UCHAR ucDestAddress [4];
|
|
|
|
} HEADER_IP, *PHEADER_IP;
|
|
|
|
|
|
#pragma pack ()
|
|
|
|
|
|
|
|
#define ES2(s) ((((s) >> 8) & 0x00FF) + (((s) << 8) & 0xFF00))
|
|
|
|
|
|
#ifdef DBG
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
DumpData (
|
|
PUCHAR pData,
|
|
ULONG ulSize
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
ULONG ulCount;
|
|
ULONG ul;
|
|
UCHAR uc;
|
|
|
|
while (ulSize)
|
|
{
|
|
ulCount = 16 < ulSize ? 16 : ulSize;
|
|
|
|
for (ul = 0; ul < ulCount; ul++)
|
|
{
|
|
uc = *pData;
|
|
|
|
TEST_DEBUG (TEST_DBG_RECV, ("%02X ", uc));
|
|
ulSize -= 1;
|
|
pData += 1;
|
|
}
|
|
|
|
TEST_DEBUG (TEST_DBG_RECV, ("\n"));
|
|
}
|
|
|
|
}
|
|
|
|
#endif //DBG
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOLEAN
|
|
ValidSection (
|
|
PSECTION_HEADER pSection
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
if (pSection->table_id != 0x3E)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOLEAN
|
|
ValidSnap (
|
|
PLLC_SNAP pSnap
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
|
|
if (pSnap->dsap != 0xAA)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (pSnap->ssap != 0xAA)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (pSnap->cntl != 0x03)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (pSnap->type != 0x0800)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
NormalizeSection (
|
|
PBYTE pStream,
|
|
PSECTION_HEADER pSection
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
PBYTE pb = pStream;
|
|
PUSHORT ps = (PUSHORT) pStream;
|
|
|
|
if (pSection)
|
|
{
|
|
pSection->table_id = *pb;
|
|
|
|
pb += 1;
|
|
pSection->section_syntax_indicator = (*pb >> 7) & 0x01;
|
|
pSection->private_indicator = (*pb >> 6 )& 0x01;
|
|
pSection->reserved1 = (*pb >> 4) & 0x03;
|
|
|
|
ps = (PUSHORT) pb;
|
|
pSection->section_length = ES2 (*ps) & 0x0FFF;
|
|
|
|
pb += 2;
|
|
pSection->MAC_address_6 = *pb;
|
|
|
|
pb += 1;
|
|
pSection->MAC_address_5 = *pb;
|
|
|
|
pb += 1;
|
|
pSection->reserved2 = (*pb >> 6) & 0x03;
|
|
pSection->payload_scrambling = (*pb >> 4) & 0x3;
|
|
pSection->address_scrambling = (*pb >> 2) & 0x3;
|
|
pSection->LLC_SNAP_flag = (*pb >> 1) & 0x01;
|
|
pSection->current_next_indicator = *pb & 0x01;
|
|
|
|
pb += 1;
|
|
pSection->section_number = *pb;
|
|
|
|
pb += 1;
|
|
pSection->last_section_number = *pb;
|
|
|
|
pb += 1;
|
|
pSection->MAC_address_4 = *pb;
|
|
|
|
pb += 1;
|
|
pSection->MAC_address_3 = *pb;
|
|
|
|
pb += 1;
|
|
pSection->MAC_address_2 = *pb;
|
|
|
|
pb += 1;
|
|
pSection->MAC_address_1 = *pb;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
NormalizeSnap (
|
|
PBYTE pStream,
|
|
PLLC_SNAP pSnap
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
PUSHORT ps = (PUSHORT) pStream;
|
|
|
|
if (pSnap)
|
|
{
|
|
pSnap->type = ES2 (pSnap->type);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
VOID
|
|
DumpDataFormat (
|
|
PKSDATAFORMAT pF
|
|
);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
MpeGetConnectionProperty(
|
|
PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
PSTREAM pStream = (PSTREAM)pSrb->StreamObject->HwStreamExtension;
|
|
PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;
|
|
ULONG Id = pSPD->Property->Id; // index of the property
|
|
ULONG ulStreamNumber = pSrb->StreamObject->StreamNumber;
|
|
|
|
pSrb->ActualBytesTransferred = 0;
|
|
|
|
switch (Id)
|
|
{
|
|
case KSPROPERTY_CONNECTION_ALLOCATORFRAMING:
|
|
{
|
|
PKSALLOCATOR_FRAMING Framing = (PKSALLOCATOR_FRAMING) pSPD->PropertyInfo;
|
|
|
|
Framing->RequirementsFlags = KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY |
|
|
KSALLOCATOR_REQUIREMENTF_INPLACE_MODIFIER |
|
|
KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY;
|
|
|
|
Framing->PoolType = NonPagedPool;
|
|
Framing->Frames = 0;
|
|
Framing->FrameSize = 0;
|
|
Framing->FileAlignment = 0; // None OR FILE_QUAD_ALIGNMENT-1 OR PAGE_SIZE-1;
|
|
Framing->Reserved = 0;
|
|
|
|
switch (ulStreamNumber)
|
|
{
|
|
case MPE_IPV4:
|
|
Framing->Frames = 16;
|
|
Framing->FrameSize = pStream->OpenedFormat.SampleSize;
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case MPE_STREAM:
|
|
Framing->Frames = 32;
|
|
Framing->FrameSize = pStream->OpenedFormat.SampleSize;
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
pSrb->ActualBytesTransferred = sizeof (KSALLOCATOR_FRAMING);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
NTSTATUS
|
|
MpeDriverInitialize (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
HW_INITIALIZATION_DATA HwInitData;
|
|
UNICODE_STRING DeviceNameString;
|
|
UNICODE_STRING SymbolicNameString;
|
|
|
|
RtlZeroMemory(&HwInitData, sizeof(HwInitData));
|
|
HwInitData.HwInitializationDataSize = sizeof(HwInitData);
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Setup the stream class dispatch table
|
|
//
|
|
HwInitData.HwInterrupt = NULL; // HwInterrupt is only for HW devices
|
|
|
|
HwInitData.HwReceivePacket = CodecReceivePacket;
|
|
HwInitData.HwCancelPacket = CodecCancelPacket;
|
|
HwInitData.HwRequestTimeoutHandler = CodecTimeoutPacket;
|
|
|
|
HwInitData.DeviceExtensionSize = sizeof(MPE_FILTER);
|
|
HwInitData.PerRequestExtensionSize = sizeof(SRB_EXTENSION);
|
|
HwInitData.FilterInstanceExtensionSize = 0;
|
|
HwInitData.PerStreamExtensionSize = sizeof(STREAM);
|
|
HwInitData.BusMasterDMA = FALSE;
|
|
HwInitData.Dma24BitAddresses = FALSE;
|
|
HwInitData.BufferAlignment = 3;
|
|
HwInitData.TurnOffSynchronization = TRUE;
|
|
HwInitData.DmaBufferSize = 0;
|
|
|
|
|
|
ntStatus = StreamClassRegisterAdapter (DriverObject, RegistryPath, &HwInitData);
|
|
if (ntStatus != STATUS_SUCCESS)
|
|
{
|
|
goto ret;
|
|
}
|
|
|
|
ret:
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOLEAN
|
|
CodecInitialize (
|
|
IN OUT PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
BOOLEAN bStatus = FALSE;
|
|
PPORT_CONFIGURATION_INFORMATION pConfigInfo = pSrb->CommandData.ConfigInfo;
|
|
PMPE_FILTER pFilter = (PMPE_FILTER) pConfigInfo->HwDeviceExtension;
|
|
|
|
//
|
|
// Define the default return codes
|
|
//
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
bStatus = TRUE;
|
|
|
|
//
|
|
// Check out init flag so we don't try to init more then once. The Streaming
|
|
// Class driver appears to call the init handler several times for some reason.
|
|
//
|
|
if (pFilter->bInitializationComplete)
|
|
{
|
|
goto ret;
|
|
}
|
|
|
|
//
|
|
// Initialize Statistics block
|
|
//
|
|
RtlZeroMemory(&pFilter->Stats, sizeof (STATS));
|
|
|
|
|
|
if (pConfigInfo->NumberOfAccessRanges == 0)
|
|
{
|
|
pConfigInfo->StreamDescriptorSize = sizeof (HW_STREAM_HEADER) +
|
|
DRIVER_STREAM_COUNT * sizeof (HW_STREAM_INFORMATION);
|
|
|
|
}
|
|
else
|
|
{
|
|
pSrb->Status = STATUS_NO_SUCH_DEVICE;
|
|
bStatus = FALSE;
|
|
goto ret;
|
|
}
|
|
|
|
|
|
//
|
|
// Create a filter object to represent our context
|
|
//
|
|
pSrb->Status = CreateFilter (pConfigInfo->ClassDeviceObject->DriverObject, pConfigInfo->ClassDeviceObject, pFilter);
|
|
if (pSrb->Status != STATUS_SUCCESS)
|
|
{
|
|
bStatus = FALSE;
|
|
goto ret;
|
|
}
|
|
|
|
pFilter->bInitializationComplete = TRUE;
|
|
|
|
ret:
|
|
|
|
return (bStatus);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOLEAN
|
|
CodecUnInitialize (
|
|
IN OUT PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
BOOLEAN bStatus = FALSE;
|
|
PPORT_CONFIGURATION_INFORMATION pConfigInfo = pSrb->CommandData.ConfigInfo;
|
|
PMPE_FILTER pFilter = ((PMPE_FILTER)pSrb->HwDeviceExtension);
|
|
PSTREAM pStream = NULL;
|
|
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Codec Unitialize called\n"));
|
|
|
|
if (pSrb->StreamObject != NULL)
|
|
{
|
|
pStream = (PSTREAM)pSrb->StreamObject->HwStreamExtension;
|
|
}
|
|
|
|
if (pStream)
|
|
{
|
|
|
|
//
|
|
// Clean up the NAB_STREAM QUEUE used for deframing
|
|
//
|
|
//$$BUG
|
|
//DeleteNabStreamQueue (pFilter);
|
|
|
|
//
|
|
// Clean up any queues we have and complete any outstanding SRB's
|
|
//
|
|
while (QueueRemove (&pSrb, &pFilter->StreamUserSpinLock, &pFilter->StreamContxList))
|
|
{
|
|
pSrb->Status = STATUS_CANCELLED;
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 5Completed SRB %08X\n", pSrb));
|
|
|
|
}
|
|
|
|
while (QueueRemove (&pSrb, &pFilter->IpV4StreamDataSpinLock, &pFilter->IpV4StreamDataQueue))
|
|
{
|
|
pSrb->Status = STATUS_CANCELLED;
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb );
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 6Completed SRB %08X\n", pSrb));
|
|
}
|
|
|
|
|
|
while (QueueRemove (&pSrb, &pFilter->StreamDataSpinLock, &pFilter->StreamDataQueue))
|
|
{
|
|
pSrb->Status = STATUS_CANCELLED;
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb );
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 7Completed SRB %08X\n", pSrb));
|
|
}
|
|
|
|
|
|
while (QueueRemove (&pSrb, &pFilter->StreamControlSpinLock, &pFilter->StreamControlQueue))
|
|
{
|
|
pSrb->Status = STATUS_CANCELLED;
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 8Completed SRB %08X\n", pSrb));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
while (QueueRemove (&pSrb, &pFilter->AdapterSRBSpinLock, &pFilter->AdapterSRBQueue))
|
|
{
|
|
pSrb->Status = STATUS_CANCELLED;
|
|
StreamClassDeviceNotification (DeviceRequestComplete, pSrb->StreamObject, pSrb);
|
|
TEST_DEBUG( TEST_DBG_RECV, ("MPE 9Completed SRB %08X\n", pSrb));
|
|
}
|
|
|
|
|
|
bStatus = TRUE;
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Codec Unitialize completed\n"));
|
|
|
|
return (bStatus);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
CodecStreamInfo (
|
|
PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
int j;
|
|
|
|
PMPE_FILTER pFilter =
|
|
((PMPE_FILTER)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);
|
|
|
|
|
|
//
|
|
// Set the header
|
|
//
|
|
StreamHeader.NumDevPropArrayEntries = 0;
|
|
StreamHeader.DevicePropertiesArray = (PKSPROPERTY_SET)NULL;
|
|
|
|
*pstrhdr = StreamHeader;
|
|
|
|
//
|
|
// stuff the contents of each HW_STREAM_INFORMATION struct
|
|
//
|
|
for (j = 0; j < DRIVER_STREAM_COUNT; j++)
|
|
{
|
|
*pstrinfo++ = Streams[j].hwStreamInfo;
|
|
}
|
|
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
STREAMAPI
|
|
CodecCancelPacket(
|
|
PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
PSTREAM pStream = (PSTREAM)pSrb->StreamObject->HwStreamExtension;
|
|
PMPE_FILTER pFilter = ((PMPE_FILTER)pSrb->HwDeviceExtension);
|
|
|
|
//
|
|
// Check whether the SRB to cancel is in use by this stream
|
|
//
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: CancelPacket Called\n"));
|
|
|
|
//
|
|
//$$BUG
|
|
//
|
|
//CancelNabStreamSrb (pFilter, pSrb);
|
|
|
|
|
|
if (QueueRemoveSpecific (pSrb, &pFilter->IpV4StreamDataSpinLock, &pFilter->IpV4StreamDataQueue))
|
|
{
|
|
pSrb->Status = STATUS_CANCELLED;
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb );
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 10Completed SRB %08X\n", pSrb));
|
|
return;
|
|
}
|
|
|
|
|
|
if (QueueRemoveSpecific (pSrb, &pFilter->StreamDataSpinLock, &pFilter->StreamDataQueue))
|
|
{
|
|
pSrb->Status = STATUS_CANCELLED;
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb );
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 11Completed SRB %08X\n", pSrb));
|
|
return;
|
|
}
|
|
|
|
|
|
if (QueueRemoveSpecific (pSrb, &pFilter->StreamControlSpinLock, &pFilter->StreamControlQueue))
|
|
{
|
|
pSrb->Status = STATUS_CANCELLED;
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 12Completed SRB %08X\n", pSrb));
|
|
return;
|
|
}
|
|
|
|
if (QueueRemoveSpecific (pSrb, &pFilter->AdapterSRBSpinLock, &pFilter->AdapterSRBQueue))
|
|
{
|
|
pSrb->Status = STATUS_CANCELLED;
|
|
StreamClassDeviceNotification (DeviceRequestComplete, pSrb->StreamObject, pSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 13Completed SRB %08X\n", pSrb));
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
STREAMAPI
|
|
CodecTimeoutPacket(
|
|
PHW_STREAM_REQUEST_BLOCK 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
|
|
//
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: TimeoutPacket Called\n"));
|
|
|
|
pSrb->TimeoutCounter = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
STREAMAPI
|
|
CodecReceivePacket(
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
PMPE_FILTER pFilter = ((PMPE_FILTER)pSrb->HwDeviceExtension);
|
|
|
|
|
|
//
|
|
// Make sure queue & SL initted
|
|
//
|
|
if (!pFilter->bAdapterQueueInitialized)
|
|
{
|
|
InitializeListHead (&pFilter->AdapterSRBQueue);
|
|
KeInitializeSpinLock (&pFilter->AdapterSRBSpinLock);
|
|
pFilter->bAdapterQueueInitialized = TRUE;
|
|
}
|
|
|
|
//
|
|
// Assume success
|
|
//
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// determine the type of packet.
|
|
//
|
|
QueueAdd (pSrb, &pFilter->AdapterSRBSpinLock, &pFilter->AdapterSRBQueue);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE Queuing SRB %08X\n", pSrb));
|
|
|
|
|
|
while (QueueRemove( &pSrb, &pFilter->AdapterSRBSpinLock, &pFilter->AdapterSRBQueue ))
|
|
{
|
|
switch (pSrb->Command)
|
|
{
|
|
|
|
case SRB_INITIALIZE_DEVICE:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_INITIALIZE Command\n"));
|
|
CodecInitialize(pSrb);
|
|
break;
|
|
|
|
case SRB_UNINITIALIZE_DEVICE:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_UNINITIALIZE Command\n"));
|
|
CodecUnInitialize(pSrb);
|
|
break;
|
|
|
|
case SRB_INITIALIZATION_COMPLETE:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_INITIALIZE_COMPLETE Command\n"));
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case SRB_OPEN_STREAM:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_OPEN_STREAM Command\n"));
|
|
OpenStream (pSrb);
|
|
break;
|
|
|
|
case SRB_CLOSE_STREAM:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_CLOSE_STREAM Command\n"));
|
|
CloseStream (pSrb);
|
|
break;
|
|
|
|
case SRB_GET_STREAM_INFO:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_GET_STREAM_INFO Command\n"));
|
|
CodecStreamInfo (pSrb);
|
|
break;
|
|
|
|
case SRB_GET_DATA_INTERSECTION:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_GET_DATA_INTERSECTION Command\n"));
|
|
|
|
//
|
|
// Compare our stream formats. NOTE, the compare functions sets the SRB
|
|
// status fields
|
|
//
|
|
CompareStreamFormat (pSrb);
|
|
break;
|
|
|
|
case SRB_OPEN_DEVICE_INSTANCE:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_OPEN_DEVICE_INSTANCE Command\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case SRB_CLOSE_DEVICE_INSTANCE:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_CLOSE_DEVICE_INSTANCE Command\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case SRB_UNKNOWN_DEVICE_COMMAND:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_UNKNOWN_DEVICE Command\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case SRB_CHANGE_POWER_STATE:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_CHANGE_POWER_STATE Command\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case SRB_GET_DEVICE_PROPERTY:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_GET_DEVICE_PROPERTY Command\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case SRB_SET_DEVICE_PROPERTY:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_SET_DEVICE_PROPERTY Command\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case SRB_UNKNOWN_STREAM_COMMAND:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_UNKNOWN Command\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
default:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_DEFAULT Command\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
};
|
|
|
|
|
|
//
|
|
// 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
|
|
//
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB Status returned: %08X\n", pSrb->Status));
|
|
|
|
StreamClassDeviceNotification (DeviceRequestComplete, pFilter, pSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 14Completed SRB %08X\n", pSrb));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL STREAMAPI
|
|
QueueAdd (
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb,
|
|
IN PKSPIN_LOCK pQueueSpinLock,
|
|
IN PLIST_ENTRY pQueue
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
KIRQL Irql;
|
|
PSRB_EXTENSION pSrbExtension;
|
|
|
|
pSrbExtension = ( PSRB_EXTENSION )pSrb->SRBExtension;
|
|
|
|
KeAcquireSpinLock( pQueueSpinLock, &Irql );
|
|
|
|
pSrbExtension->pSrb = pSrb;
|
|
InsertTailList( pQueue, &pSrbExtension->ListEntry );
|
|
|
|
KeReleaseSpinLock( pQueueSpinLock, Irql );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL STREAMAPI
|
|
QueuePush (
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb,
|
|
IN PKSPIN_LOCK pQueueSpinLock,
|
|
IN PLIST_ENTRY pQueue
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
KIRQL Irql;
|
|
PSRB_EXTENSION pSrbExtension;
|
|
|
|
pSrbExtension = ( PSRB_EXTENSION )pSrb->SRBExtension;
|
|
|
|
KeAcquireSpinLock( pQueueSpinLock, &Irql );
|
|
|
|
pSrbExtension->pSrb = pSrb;
|
|
InsertHeadList( pQueue, &pSrbExtension->ListEntry );
|
|
|
|
KeReleaseSpinLock( pQueueSpinLock, Irql );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
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;
|
|
|
|
pSrbExtension = ( PSRB_EXTENSION )pSrb->SRBExtension;
|
|
|
|
KeAcquireSpinLock( pQueueSpinLock, &Irql );
|
|
|
|
if( !IsListEmpty( pQueue ))
|
|
{
|
|
pSrbExtension->pSrb = pSrb;
|
|
InsertTailList (pQueue, &pSrbExtension->ListEntry );
|
|
bAddedSRB = TRUE;
|
|
}
|
|
|
|
KeReleaseSpinLock( pQueueSpinLock, Irql );
|
|
|
|
return bAddedSRB;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL STREAMAPI
|
|
QueueRemove (
|
|
IN OUT PHW_STREAM_REQUEST_BLOCK * pSrb,
|
|
IN PKSPIN_LOCK pQueueSpinLock,
|
|
IN PLIST_ENTRY pQueue
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
KIRQL Irql;
|
|
BOOL bRemovedSRB = FALSE;
|
|
|
|
KeAcquireSpinLock (pQueueSpinLock, &Irql);
|
|
|
|
*pSrb = (PHW_STREAM_REQUEST_BLOCK) NULL;
|
|
|
|
if( !IsListEmpty( pQueue ))
|
|
{
|
|
PHW_STREAM_REQUEST_BLOCK *pCurrentSrb = NULL;
|
|
PUCHAR Ptr = (PUCHAR) RemoveHeadList(pQueue);
|
|
|
|
pCurrentSrb = (PHW_STREAM_REQUEST_BLOCK *) (((PUCHAR)Ptr) + sizeof (LIST_ENTRY));
|
|
|
|
*pSrb = *pCurrentSrb;
|
|
bRemovedSRB = TRUE;
|
|
|
|
}
|
|
|
|
KeReleaseSpinLock (pQueueSpinLock, Irql);
|
|
|
|
return bRemovedSRB;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL STREAMAPI
|
|
QueueRemoveSpecific (
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb,
|
|
IN PKSPIN_LOCK pQueueSpinLock,
|
|
IN PLIST_ENTRY pQueue
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
KIRQL Irql;
|
|
BOOL bRemovedSRB = FALSE;
|
|
PLIST_ENTRY pCurrentEntry;
|
|
PHW_STREAM_REQUEST_BLOCK * pCurrentSrb;
|
|
|
|
KeAcquireSpinLock( pQueueSpinLock, &Irql );
|
|
|
|
if( !IsListEmpty( pQueue ))
|
|
{
|
|
pCurrentEntry = pQueue->Flink;
|
|
while ((pCurrentEntry != pQueue ) && !bRemovedSRB)
|
|
{
|
|
pCurrentSrb = (PHW_STREAM_REQUEST_BLOCK * ) ((( PUCHAR )pCurrentEntry ) + sizeof( LIST_ENTRY ));
|
|
|
|
if( *pCurrentSrb == pSrb )
|
|
{
|
|
RemoveEntryList( pCurrentEntry );
|
|
bRemovedSRB = TRUE;
|
|
}
|
|
pCurrentEntry = pCurrentEntry->Flink;
|
|
}
|
|
}
|
|
KeReleaseSpinLock( pQueueSpinLock, Irql );
|
|
|
|
return bRemovedSRB;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
NTSTATUS
|
|
StreamIPIndicateEvent (
|
|
PVOID pvEvent
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
CompareGUIDsAndFormatSize(
|
|
IN PKSDATARANGE pDataRange1,
|
|
IN PKSDATARANGE pDataRange2,
|
|
BOOLEAN bCheckSize
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
if ( IsEqualGUID(&pDataRange1->MajorFormat, &KSDATAFORMAT_TYPE_WILDCARD) ||
|
|
IsEqualGUID(&pDataRange2->MajorFormat, &KSDATAFORMAT_TYPE_WILDCARD) ||
|
|
IsEqualGUID(&pDataRange1->MajorFormat, &pDataRange2->MajorFormat) )
|
|
{
|
|
|
|
if ( IsEqualGUID(&pDataRange1->SubFormat, &KSDATAFORMAT_SUBTYPE_WILDCARD) ||
|
|
IsEqualGUID(&pDataRange2->SubFormat, &KSDATAFORMAT_SUBTYPE_WILDCARD) ||
|
|
IsEqualGUID(&pDataRange1->SubFormat, &pDataRange2->SubFormat) )
|
|
{
|
|
|
|
if ( IsEqualGUID(&pDataRange1->Specifier, &KSDATAFORMAT_SPECIFIER_WILDCARD) ||
|
|
IsEqualGUID(&pDataRange2->Specifier, &KSDATAFORMAT_SPECIFIER_WILDCARD) ||
|
|
IsEqualGUID(&pDataRange1->Specifier, &pDataRange2->Specifier) )
|
|
{
|
|
if ( !bCheckSize || pDataRange1->FormatSize == pDataRange2->FormatSize)
|
|
{
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
DumpDataFormat (
|
|
PKSDATAFORMAT pF
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: DATA Format\n"));
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Format Size: %08X\n", pF->FormatSize));
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Flags: %08X\n", pF->Flags));
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SampleSize: %08X\n", pF->SampleSize));
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Reserved: %08X\n", pF->Reserved));
|
|
|
|
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Major GUID: %08X %04X %04X %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
|
pF->MajorFormat.Data1,
|
|
pF->MajorFormat.Data2,
|
|
pF->MajorFormat.Data3,
|
|
pF->MajorFormat.Data4[0],
|
|
pF->MajorFormat.Data4[1],
|
|
pF->MajorFormat.Data4[2],
|
|
pF->MajorFormat.Data4[3],
|
|
pF->MajorFormat.Data4[4],
|
|
pF->MajorFormat.Data4[5],
|
|
pF->MajorFormat.Data4[6],
|
|
pF->MajorFormat.Data4[7]
|
|
));
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Sub GUID: %08X %04X %04X %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
|
pF->SubFormat.Data1,
|
|
pF->SubFormat.Data2,
|
|
pF->SubFormat.Data3,
|
|
pF->SubFormat.Data4[0],
|
|
pF->SubFormat.Data4[1],
|
|
pF->SubFormat.Data4[2],
|
|
pF->SubFormat.Data4[3],
|
|
pF->SubFormat.Data4[4],
|
|
pF->SubFormat.Data4[5],
|
|
pF->SubFormat.Data4[6],
|
|
pF->SubFormat.Data4[7]
|
|
));
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Specifier: %08X %04X %04X %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
|
pF->Specifier.Data1,
|
|
pF->Specifier.Data2,
|
|
pF->Specifier.Data3,
|
|
pF->Specifier.Data4[0],
|
|
pF->Specifier.Data4[1],
|
|
pF->Specifier.Data4[2],
|
|
pF->Specifier.Data4[3],
|
|
pF->Specifier.Data4[4],
|
|
pF->Specifier.Data4[5],
|
|
pF->Specifier.Data4[6],
|
|
pF->Specifier.Data4[7]
|
|
));
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("\n"));
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
CompareStreamFormat (
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
BOOL bStatus = FALSE;
|
|
PSTREAM_DATA_INTERSECT_INFO pIntersectInfo;
|
|
PKSDATARANGE pDataRange1;
|
|
PKSDATARANGE pDataRange2;
|
|
ULONG FormatSize = 0;
|
|
ULONG ulStreamNumber;
|
|
ULONG j;
|
|
ULONG ulNumberOfFormatArrayEntries;
|
|
PKSDATAFORMAT *pAvailableFormats;
|
|
|
|
|
|
pIntersectInfo = pSrb->CommandData.IntersectInfo;
|
|
ulStreamNumber = pIntersectInfo->StreamNumber;
|
|
|
|
|
|
pSrb->ActualBytesTransferred = 0;
|
|
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Comparing Stream Formats\n"));
|
|
|
|
|
|
//
|
|
// Check that the stream number is valid
|
|
//
|
|
if (ulStreamNumber < DRIVER_STREAM_COUNT)
|
|
{
|
|
ulNumberOfFormatArrayEntries = Streams[ulStreamNumber].hwStreamInfo.NumberOfFormatArrayEntries;
|
|
|
|
//
|
|
// Get the pointer to the array of available formats
|
|
//
|
|
pAvailableFormats = Streams[ulStreamNumber].hwStreamInfo.StreamFormatsArray;
|
|
|
|
//
|
|
// Walk the formats supported by the stream searching for a match
|
|
// of the three GUIDs which together define a DATARANGE
|
|
//
|
|
for (pDataRange1 = pIntersectInfo->DataRange, j = 0;
|
|
j < ulNumberOfFormatArrayEntries;
|
|
j++, pAvailableFormats++)
|
|
|
|
{
|
|
bStatus = FALSE;
|
|
pSrb->Status = STATUS_UNSUCCESSFUL;
|
|
|
|
pDataRange2 = *pAvailableFormats;
|
|
|
|
if (CompareGUIDsAndFormatSize (pDataRange1, pDataRange2, TRUE))
|
|
{
|
|
|
|
ULONG ulFormatSize = pDataRange2->FormatSize;
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Stream Formats compare\n"));
|
|
|
|
//
|
|
// Is the caller trying to get the format, or the size of the format?
|
|
//
|
|
if (pIntersectInfo->SizeOfDataFormatBuffer == sizeof (ULONG))
|
|
{
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Returning Stream Format size\n"));
|
|
|
|
*(PULONG) pIntersectInfo->DataFormatBuffer = ulFormatSize;
|
|
pSrb->ActualBytesTransferred = sizeof (ULONG);
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
bStatus = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Verify that there is enough room in the supplied buffer for the whole thing
|
|
//
|
|
pSrb->Status = STATUS_BUFFER_TOO_SMALL;
|
|
bStatus = FALSE;
|
|
|
|
if (pIntersectInfo->SizeOfDataFormatBuffer >= ulFormatSize)
|
|
{
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Returning Stream Format\n"));
|
|
RtlCopyMemory (pIntersectInfo->DataFormatBuffer, pDataRange2, ulFormatSize);
|
|
pSrb->ActualBytesTransferred = ulFormatSize;
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
bStatus = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Stream Format return buffer too small\n"));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Stream Formats DO NOT compare\n"));
|
|
}
|
|
}
|
|
|
|
if ( j >= ulNumberOfFormatArrayEntries )
|
|
{
|
|
pSrb->ActualBytesTransferred = 0;
|
|
pSrb->Status = STATUS_UNSUCCESSFUL;
|
|
bStatus = FALSE;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
pSrb->ActualBytesTransferred = 0;
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
bStatus = FALSE;
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
CloseStream (
|
|
PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
//
|
|
// the stream extension structure is allocated by the stream class driver
|
|
//
|
|
PSTREAM pStream = (PSTREAM)pSrb->StreamObject->HwStreamExtension;
|
|
PMPE_FILTER pFilter = (PMPE_FILTER)pSrb->HwDeviceExtension;
|
|
ULONG ulStreamNumber = (ULONG) pSrb->StreamObject->StreamNumber;
|
|
ULONG ulStreamInstance = pStream->ulStreamInstance;
|
|
PHW_STREAM_REQUEST_BLOCK pCurrentSrb = NULL;
|
|
|
|
//
|
|
// check that the stream index requested isn't too high
|
|
// or that the maximum number of instances hasn't been exceeded
|
|
//
|
|
if (ulStreamNumber < DRIVER_STREAM_COUNT )
|
|
{
|
|
//
|
|
// Flush the stream data queue
|
|
//
|
|
while (QueueRemove( &pCurrentSrb, &pFilter->IpV4StreamDataSpinLock, &pFilter->IpV4StreamDataQueue))
|
|
{
|
|
pCurrentSrb->Status = STATUS_CANCELLED;
|
|
StreamClassStreamNotification( StreamRequestComplete, pCurrentSrb->StreamObject, pCurrentSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 15Completed SRB %08X\n", pCurrentSrb));
|
|
}
|
|
|
|
//
|
|
// Flush the stream data queue
|
|
//
|
|
while (QueueRemove( &pCurrentSrb, &pFilter->StreamDataSpinLock, &pFilter->StreamDataQueue))
|
|
{
|
|
pCurrentSrb->Status = STATUS_CANCELLED;
|
|
StreamClassStreamNotification( StreamRequestComplete, pCurrentSrb->StreamObject, pCurrentSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 16Completed SRB %08X\n", pCurrentSrb));
|
|
}
|
|
|
|
//
|
|
// Flush the stream control queue
|
|
//
|
|
while (QueueRemove( &pCurrentSrb, &pFilter->StreamControlSpinLock, &pFilter->StreamControlQueue))
|
|
{
|
|
pCurrentSrb->Status = STATUS_CANCELLED;
|
|
StreamClassStreamNotification (StreamRequestComplete, pCurrentSrb->StreamObject, pCurrentSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 17Completed SRB %08X\n", pCurrentSrb));
|
|
}
|
|
|
|
//
|
|
// Clear this streams spot in the filters stream array
|
|
//
|
|
pFilter->pStream[ulStreamNumber][ulStreamInstance] = NULL;
|
|
|
|
//
|
|
// decrement the stream instance count for this filter
|
|
//
|
|
pFilter->ulActualInstances[ulStreamNumber]--;
|
|
|
|
|
|
//
|
|
// Reset the stream state to stopped
|
|
//
|
|
pStream->KSState = KSSTATE_STOP;
|
|
|
|
//
|
|
//
|
|
//
|
|
pStream->hMasterClock = NULL;
|
|
|
|
//
|
|
// Cleanup the streams transform buffer
|
|
//
|
|
if (pStream->pTransformBuffer)
|
|
{
|
|
ExFreePool (pStream->pTransformBuffer);
|
|
pStream->pTransformBuffer = NULL;
|
|
}
|
|
|
|
//
|
|
// Reset the stream extension blob
|
|
//
|
|
RtlZeroMemory(pStream, sizeof (STREAM));
|
|
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
else
|
|
{
|
|
pSrb->Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
OpenStream (
|
|
PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
//
|
|
// the stream extension structure is allocated by the stream class driver
|
|
//
|
|
PSTREAM pStream = (PSTREAM)pSrb->StreamObject->HwStreamExtension;
|
|
PMPE_FILTER pFilter = ((PMPE_FILTER)pSrb->HwDeviceExtension);
|
|
ULONG ulStreamNumber = (ULONG) pSrb->StreamObject->StreamNumber;
|
|
PKSDATAFORMAT pKSDataFormat = (PKSDATAFORMAT)pSrb->CommandData.OpenFormat;
|
|
|
|
//
|
|
// Initialize the next stream life check time.
|
|
//
|
|
KeQuerySystemTime( &pFilter->liLastTimeChecked );
|
|
|
|
//
|
|
// check that the stream index requested isn't too high
|
|
// or that the maximum number of instances hasn't been exceeded
|
|
//
|
|
if (ulStreamNumber < DRIVER_STREAM_COUNT )
|
|
{
|
|
ULONG ulStreamInstance;
|
|
ULONG ulMaxInstances = Streams[ulStreamNumber].hwStreamInfo.NumberOfPossibleInstances;
|
|
|
|
//
|
|
// Search for next open slot
|
|
//
|
|
for (ulStreamInstance = 0; ulStreamInstance < ulMaxInstances; ++ulStreamInstance)
|
|
{
|
|
if (pFilter->pStream[ulStreamNumber][ulStreamInstance] == NULL)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ulStreamInstance < ulMaxInstances)
|
|
{
|
|
if (VerifyFormat(pKSDataFormat, ulStreamNumber, &pStream->MatchedFormat))
|
|
{
|
|
//
|
|
// Initialize Data queues and SpinLocks
|
|
//
|
|
InitializeListHead(&pFilter->StreamControlQueue);
|
|
KeInitializeSpinLock(&pFilter->StreamControlSpinLock);
|
|
|
|
InitializeListHead(&pFilter->StreamDataQueue);
|
|
KeInitializeSpinLock(&pFilter->StreamDataSpinLock);
|
|
|
|
InitializeListHead(&pFilter->IpV4StreamDataQueue);
|
|
KeInitializeSpinLock(&pFilter->IpV4StreamDataSpinLock);
|
|
|
|
InitializeListHead(&pFilter->StreamContxList);
|
|
KeInitializeSpinLock(&pFilter->StreamUserSpinLock);
|
|
|
|
|
|
//
|
|
// Maintain an array of all the StreamEx structures in the HwDevExt
|
|
// so that we can reference IRPs from any stream
|
|
//
|
|
pFilter->pStream[ulStreamNumber][ulStreamInstance] = pStream;
|
|
|
|
//
|
|
// Save the Stream Format in the Stream Extension as well.
|
|
//
|
|
pStream->OpenedFormat = *pKSDataFormat;
|
|
|
|
//
|
|
// Set up pointers to the handlers for the stream data and control handlers
|
|
//
|
|
pSrb->StreamObject->ReceiveDataPacket =
|
|
(PVOID) Streams[ulStreamNumber].hwStreamObject.ReceiveDataPacket;
|
|
pSrb->StreamObject->ReceiveControlPacket =
|
|
(PVOID) Streams[ulStreamNumber].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 ReceiveDataPacket routines.
|
|
//
|
|
pSrb->StreamObject->Dma = Streams[ulStreamNumber].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[ulStreamNumber].hwStreamObject.Pio;
|
|
|
|
pSrb->StreamObject->Allocator = Streams[ulStreamNumber].hwStreamObject.Allocator;
|
|
|
|
//
|
|
// How many extra bytes will be passed up from the driver for each frame?
|
|
//
|
|
pSrb->StreamObject->StreamHeaderMediaSpecific =
|
|
Streams[ulStreamNumber].hwStreamObject.StreamHeaderMediaSpecific;
|
|
|
|
pSrb->StreamObject->StreamHeaderWorkspace =
|
|
Streams[ulStreamNumber].hwStreamObject.StreamHeaderWorkspace;
|
|
|
|
//
|
|
// Indicate the clock support available on this stream
|
|
//
|
|
pSrb->StreamObject->HwClockObject =
|
|
Streams[ulStreamNumber].hwStreamObject.HwClockObject;
|
|
|
|
//
|
|
// Increment the instance count on this stream
|
|
//
|
|
pStream->ulStreamInstance = ulStreamInstance;
|
|
pFilter->ulActualInstances[ulStreamNumber]++;
|
|
|
|
//
|
|
// Allocate a transform buffer
|
|
//
|
|
pStream->pTransformBuffer = ExAllocatePool (NonPagedPool, sizeof(SECTION_HEADER) + 4096);
|
|
|
|
if (pStream->pTransformBuffer == NULL)
|
|
{
|
|
pSrb->Status = STATUS_NO_MEMORY;
|
|
return;
|
|
}
|
|
|
|
RtlZeroMemory (pStream->pTransformBuffer, sizeof(SECTION_HEADER) + 4096);
|
|
|
|
//
|
|
// Initalize persistent pointer to output buffer to NULL
|
|
//
|
|
pStream->pOut = NULL;
|
|
|
|
//
|
|
// Initialize the exepected section number to zero
|
|
//
|
|
pStream->bExpectedSection = 0;
|
|
|
|
|
|
//
|
|
// Retain a private copy of the HwDevExt and StreamObject in the stream extension
|
|
// so we can use a timer
|
|
//
|
|
pStream->pFilter = pFilter; // For timer use
|
|
pStream->pStreamObject = pSrb->StreamObject; // For timer use
|
|
|
|
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
else
|
|
{
|
|
pSrb->Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pSrb->Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
pSrb->Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOLEAN
|
|
VerifyFormat(
|
|
IN KSDATAFORMAT *pKSDataFormat,
|
|
UINT StreamNumber,
|
|
PKSDATARANGE pMatchedFormat
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
BOOLEAN bResult = FALSE;
|
|
ULONG FormatCount = 0;
|
|
PKS_DATARANGE_VIDEO pThisFormat = NULL;
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Verify Format\n"));
|
|
|
|
for (FormatCount = 0; !bResult && FormatCount < Streams[StreamNumber].hwStreamInfo.NumberOfFormatArrayEntries;
|
|
FormatCount++ )
|
|
{
|
|
|
|
|
|
pThisFormat = (PKS_DATARANGE_VIDEO) Streams [StreamNumber].hwStreamInfo.StreamFormatsArray [FormatCount];
|
|
|
|
if (CompareGUIDsAndFormatSize( pKSDataFormat, &pThisFormat->DataRange, FALSE ) )
|
|
{
|
|
bResult = FALSE;
|
|
|
|
if (pThisFormat->DataRange.SampleSize >= pKSDataFormat->SampleSize)
|
|
{
|
|
bResult = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: VerifyFormat: Data range Sample Sizes don't match\n"));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bResult == TRUE && pMatchedFormat)
|
|
{
|
|
*pMatchedFormat = pThisFormat->DataRange;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
NTSTATUS
|
|
GetOutputBuffer (
|
|
PMPE_FILTER pFilter,
|
|
PHW_STREAM_REQUEST_BLOCK *ppSrb,
|
|
PUCHAR *ppBuffer,
|
|
PULONG pulSize
|
|
)
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
|
|
PKSSTREAM_HEADER pStreamHdr = NULL;
|
|
PHW_STREAM_REQUEST_BLOCK pSrb = NULL;
|
|
|
|
|
|
|
|
if (QueueRemove( &pSrb, &pFilter->IpV4StreamDataSpinLock, &pFilter->IpV4StreamDataQueue))
|
|
{
|
|
|
|
pStreamHdr = pSrb->CommandData.DataBufferArray;
|
|
|
|
*ppSrb = pSrb;
|
|
*ppBuffer = pStreamHdr->Data;
|
|
*pulSize = pStreamHdr->FrameExtent;
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
STREAMAPI
|
|
ReceiveDataPacket (
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
PMPE_FILTER pFilter = (PMPE_FILTER) pSrb->HwDeviceExtension;
|
|
PSTREAM pStream = (PSTREAM)pSrb->StreamObject->HwStreamExtension;
|
|
int iStream = (int) pSrb->StreamObject->StreamNumber;
|
|
PKSSTREAM_HEADER pStreamHdr = pSrb->CommandData.DataBufferArray;
|
|
PKSDATAFORMAT pKSDataFormat = (PKSDATAFORMAT) &pStream->MatchedFormat;
|
|
ULONG ul = 0;
|
|
PHW_STREAM_REQUEST_BLOCK pOutSrb = NULL;
|
|
SECTION_HEADER Section = {0};
|
|
PSECTION_HEADER pSection = NULL;
|
|
PUCHAR pIn = NULL;
|
|
PLLC_SNAP pSnap = NULL;
|
|
ULONG ulSize = 0;
|
|
ULONG ulLength = 0;
|
|
|
|
PHEADER_IP pIP = NULL;
|
|
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Data packet handler called\n"));
|
|
|
|
//
|
|
// Default to success, disable timeouts
|
|
//
|
|
pSrb->TimeoutCounter = 0;
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Check for last buffer
|
|
//
|
|
if (pStreamHdr->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_ENDOFSTREAM)
|
|
{
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Data packet is LAST PACKET\n"));
|
|
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 18Completed SRB %08X\n", pSrb));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
if (pStreamHdr->OptionsFlags != 0)
|
|
{
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: OptionsFlags: %08X\n", pStreamHdr->OptionsFlags));
|
|
}
|
|
|
|
|
|
//
|
|
// determine the type of packet.
|
|
//
|
|
switch (pSrb->Command)
|
|
{
|
|
case SRB_WRITE_DATA:
|
|
|
|
|
|
if (pStream->KSState == KSSTATE_STOP)
|
|
{
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_WRITE STOP SRB Status returned: %08X\n", pSrb->Status));
|
|
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb );
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 19Completed SRB %08X\n", pSrb));
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Update the total number of packets written statistic
|
|
//
|
|
pFilter->Stats.ulTotalSectionsWritten += 1;
|
|
|
|
|
|
//
|
|
// Handle data input, output requests differently.
|
|
//
|
|
switch (iStream)
|
|
{
|
|
//
|
|
// Frame input stream
|
|
//
|
|
case MPE_STREAM:
|
|
{
|
|
ULONG ulBuffers = pSrb->NumberOfBuffers;
|
|
ULONG ulSkip = 0;
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Data packet handler - SRB_WRITE - MPE_STREAM\n"));
|
|
|
|
//
|
|
// Initialize SRB Status to success
|
|
//
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// copy the contents of all buffers into one big buffer
|
|
//
|
|
ASSERT( ulBuffers == 1);
|
|
{
|
|
//ASSERT( pStreamHdr);
|
|
//ASSERT( pStreamHdr->DataUsed <= (sizeof(SECTION_HEADER) + 4096));
|
|
if ( pStreamHdr
|
|
&& (pStreamHdr->DataUsed <= (sizeof(SECTION_HEADER) + 4096))
|
|
)
|
|
{
|
|
// Copy the data
|
|
RtlCopyMemory (pStream->pTransformBuffer,
|
|
pStreamHdr->Data,
|
|
pStreamHdr->DataUsed
|
|
);
|
|
}
|
|
else
|
|
{
|
|
pFilter->Stats.ulTotalInvalidSections += 1;
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
pStream->bExpectedSection = 0;
|
|
pStream->pOut = NULL;
|
|
pOutSrb = NULL;
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 20Completed SRB %08X\n - Invalid TableID", pSrb));
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Process the transform buffer
|
|
//
|
|
pSection = (PSECTION_HEADER) pStream->pTransformBuffer;
|
|
NormalizeSection (pStream->pTransformBuffer, &Section);
|
|
|
|
//
|
|
// Do a quick check of the section header to confirm it looks valid
|
|
//
|
|
if (! ValidSection (&Section))
|
|
{
|
|
// Ignore non-MPE sections
|
|
//
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
pStream->bExpectedSection = 0;
|
|
|
|
pFilter->Stats.ulTotalInvalidSections += 1;
|
|
|
|
//
|
|
// Since we're discarding the data at this point, we'll re-queue the output
|
|
// SRB and re-use it when we get re-synched.
|
|
//
|
|
if (pOutSrb)
|
|
{
|
|
//$REVIEW - Can this cause out of order completion of sections.
|
|
//
|
|
QueuePush (pOutSrb, &pFilter->IpV4StreamDataSpinLock, &pFilter->IpV4StreamDataQueue);
|
|
}
|
|
pStream->pOut = NULL;
|
|
pOutSrb = NULL;
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 20Completed SRB %08X\n - Invalid TableID", pSrb));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Update our UnNormalized section header with our normalized one.
|
|
//
|
|
RtlCopyMemory (pStream->pTransformBuffer, &Section, sizeof (SECTION_HEADER));
|
|
|
|
//
|
|
// Check our section number and see if it's what we expect
|
|
//
|
|
if (pSection->section_number != pStream->bExpectedSection)
|
|
{
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
pStream->bExpectedSection = 0;
|
|
|
|
pFilter->Stats.ulTotalUnexpectedSections += 1;
|
|
|
|
//
|
|
// Since we're discarding the data at this point, we'll re-queue the output
|
|
// SRB and re-use it when we get re-synched.
|
|
//
|
|
if (pOutSrb)
|
|
{
|
|
//$REVIEW - Can this cause out of order completion of sections.
|
|
//
|
|
QueuePush (pOutSrb, &pFilter->IpV4StreamDataSpinLock, &pFilter->IpV4StreamDataQueue);
|
|
}
|
|
pStream->pOut = NULL;
|
|
pOutSrb = NULL;
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 20Completed SRB %08X\n - Invalid section_number", pSrb));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Process the 1st section
|
|
//
|
|
if (pSection->section_number == 0)
|
|
{
|
|
PMAC_Address pMAC = NULL;
|
|
|
|
//
|
|
// Initialize packet length to zero
|
|
//
|
|
ulLength = 0;
|
|
|
|
//
|
|
//
|
|
//
|
|
if (GetOutputBuffer (pFilter, &pOutSrb, &pStream->pOut, &ulSize) != STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Failure....no buffers available most likely
|
|
//
|
|
pFilter->Stats.ulTotalUnavailableOutputBuffers += 1;
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 20Completed SRB %08X\n - Can't get SRB for output pin", pSrb));
|
|
break;
|
|
}
|
|
|
|
if (ulSize < (pSection->section_length - (sizeof (SECTION_HEADER) - 3)))
|
|
{
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
pStream->bExpectedSection = 0;
|
|
pFilter->Stats.ulTotalOutputBuffersTooSmall += 1;
|
|
|
|
//
|
|
// Since we're discarding the data at this point, we'll re-queue the output
|
|
// SRB and re-use it when we get re-synched.
|
|
//
|
|
if (pOutSrb)
|
|
{
|
|
//$REVIEW - Can this cause out of order completion of sections.
|
|
//
|
|
QueuePush (pOutSrb, &pFilter->IpV4StreamDataSpinLock, &pFilter->IpV4StreamDataQueue);
|
|
}
|
|
pStream->pOut = NULL;
|
|
pOutSrb = NULL;
|
|
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 20Completed SRB %08X\n - Section too big", pSrb));
|
|
break;
|
|
}
|
|
|
|
pIP = (PHEADER_IP) pSection->Data;
|
|
if (pSection->LLC_SNAP_flag == 0x1)
|
|
{
|
|
pSnap = (PLLC_SNAP) pSection->Data;
|
|
pIP = (PHEADER_IP) pSnap->Data;
|
|
ulSkip = sizeof( LLC_SNAP);
|
|
}
|
|
|
|
//
|
|
// Add the MAC address to the buffer. The MAC address prefix's the IP packet
|
|
//
|
|
pMAC = (PMAC_Address) pStream->pOut;
|
|
pMAC->MAC_Dest_Address [0] = pSection->MAC_address_1;
|
|
pMAC->MAC_Dest_Address [1] = pSection->MAC_address_2;
|
|
pMAC->MAC_Dest_Address [2] = pSection->MAC_address_3;
|
|
pMAC->MAC_Dest_Address [3] = pSection->MAC_address_4;
|
|
pMAC->MAC_Dest_Address [4] = pSection->MAC_address_5;
|
|
pMAC->MAC_Dest_Address [5] = pSection->MAC_address_6;
|
|
|
|
pMAC->MAC_Src_Address [0] = 0x00;
|
|
pMAC->MAC_Src_Address [1] = 0x00;
|
|
pMAC->MAC_Src_Address [2] = 0x00;
|
|
pMAC->MAC_Src_Address [3] = 0x00;
|
|
pMAC->MAC_Src_Address [4] = 0x00;
|
|
pMAC->MAC_Src_Address [5] = 0x00;
|
|
|
|
pMAC->usLength = 0x0008;
|
|
|
|
//
|
|
// Adjust pointer to output buffer where we'll put data
|
|
//
|
|
pStream->pOut += sizeof (MAC_Address);
|
|
|
|
pIn = pSection->Data;
|
|
|
|
if (pSection->LLC_SNAP_flag == 0x1)
|
|
{
|
|
pSnap = (PLLC_SNAP) pSection->Data;
|
|
|
|
if (pSnap->type != 0x0008)
|
|
{
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
|
|
//
|
|
// Next expected Section should be zero
|
|
//
|
|
pStream->bExpectedSection = 0;
|
|
pFilter->Stats.ulTotalInvalidIPSnapHeaders += 1;
|
|
|
|
//
|
|
// Since we're discarding the data at this point, we'll re-queue the output
|
|
// SRB and re-use it when we get re-synched.
|
|
//
|
|
if (pOutSrb)
|
|
{
|
|
//$REVIEW - Can this cause out of order completion of sections.
|
|
//
|
|
QueuePush (pOutSrb, &pFilter->IpV4StreamDataSpinLock, &pFilter->IpV4StreamDataQueue);
|
|
}
|
|
pStream->pOut = NULL;
|
|
pOutSrb = NULL;
|
|
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 20Completed SRB %08X\n - Bad Snap Type", pSrb));
|
|
break;
|
|
}
|
|
|
|
pIn = pSnap->Data;
|
|
|
|
}
|
|
|
|
ulLength = sizeof (MAC_Address);
|
|
}
|
|
|
|
//
|
|
// pOut should be NULL unless we've found the 1st section.
|
|
//
|
|
if (pStream->pOut)
|
|
{
|
|
ULONG ulTmp = 0;
|
|
PKSSTREAM_HEADER pOutStreamHdr;
|
|
|
|
//
|
|
// Update the datasize field of the Output SRB
|
|
//
|
|
pOutStreamHdr = (PKSSTREAM_HEADER) pOutSrb->CommandData.DataBufferArray;
|
|
|
|
|
|
//
|
|
// Copy data from transform section to output SRB buffer
|
|
//
|
|
// Compute the number of bytes to copy. We subtract of 9 bytes
|
|
// only if this is a LLSNAP packet.
|
|
//
|
|
ulTmp = pSection->section_length;
|
|
ulTmp -= ulSkip;
|
|
|
|
|
|
ASSERT(pIn);
|
|
ASSERT(pStream->pOut);
|
|
|
|
|
|
if (ulSize < (ulTmp +sizeof (MAC_Address) +3))
|
|
{
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
pStream->bExpectedSection = 0;
|
|
pFilter->Stats.ulTotalOutputBuffersTooSmall += 1;
|
|
|
|
//
|
|
// Since we're discarding the data at this point, we'll re-queue the output
|
|
// SRB and re-use it when we get re-synched.
|
|
//
|
|
if (pOutSrb)
|
|
{
|
|
//$REVIEW - Can this cause out of order completion of sections.
|
|
//
|
|
QueuePush (pOutSrb, &pFilter->IpV4StreamDataSpinLock, &pFilter->IpV4StreamDataQueue);
|
|
}
|
|
pStream->pOut = NULL;
|
|
pOutSrb = NULL;
|
|
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 20Completed SRB %08X\n - Section too big", pSrb));
|
|
break;
|
|
}
|
|
|
|
|
|
RtlCopyMemory (pStream->pOut, pIn, ulTmp);
|
|
ulLength += ulTmp;
|
|
pOutStreamHdr->DataUsed += ulLength;
|
|
|
|
ulLength = 0;
|
|
}
|
|
|
|
if (pSection->section_number == pSection->last_section_number)
|
|
{
|
|
|
|
pFilter->Stats.ulTotalIPPacketsWritten += 1;
|
|
|
|
pOutSrb->Status = STATUS_SUCCESS;
|
|
StreamClassStreamNotification (StreamRequestComplete, pOutSrb->StreamObject, pOutSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 20Completed SRB %08X\n", pSrb));
|
|
|
|
pOutSrb = NULL;
|
|
pStream->pOut = NULL;
|
|
ulSize = 0;
|
|
}
|
|
else
|
|
{
|
|
if (pOutSrb)
|
|
{
|
|
//$REVIEW - Can this cause out of order completion of sections.
|
|
//
|
|
QueuePush (pOutSrb, &pFilter->IpV4StreamDataSpinLock, &pFilter->IpV4StreamDataQueue);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 20Completed SRB %08X\n - Packet Sent", pSrb));
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Data packet handler called - SRB_WRITE - Default\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
//
|
|
// Update stats for Unkown packet count
|
|
//
|
|
pFilter->Stats.ulTotalUnknownPacketsWritten += 1;
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: DEFAULT SRB Status returned: %08X\n", pSrb->Status));
|
|
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 22Completed SRB %08X\n", pSrb));
|
|
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
case SRB_READ_DATA:
|
|
|
|
if (pStream->KSState == KSSTATE_STOP)
|
|
{
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_READ STOP SRB Status returned: %08X\n", pSrb->Status));
|
|
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb );
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 23Completed SRB %08X\n", pSrb));
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Update stats for Unkown packet count
|
|
//
|
|
pFilter->Stats.ulTotalPacketsRead += 1;
|
|
|
|
switch (iStream)
|
|
{
|
|
#ifdef OLD
|
|
|
|
case MPE_NET_CONTROL:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Data packet handler called - SRB_READ - STREAM_NET_CONTROL\n"));
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: MPE_NET_CONTROL SRB Status returned: %08X\n", pSrb->Status));
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 24Completed SRB %08X\n", pSrb));
|
|
break;
|
|
|
|
#endif
|
|
|
|
case MPE_IPV4:
|
|
{
|
|
ULONG ulBuffers = pSrb->NumberOfBuffers;
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Data packet handler called - SRB_READ - MPE_IPV4\n"));
|
|
|
|
if (pSrb->CommandData.DataBufferArray->FrameExtent < pKSDataFormat->SampleSize)
|
|
{
|
|
pSrb->Status = STATUS_BUFFER_TOO_SMALL;
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: MPE_IPV4 SRB Buffer too small.... Status returned: %08X\n", pSrb->Status));
|
|
StreamClassStreamNotification(StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 25Completed SRB %08X\n", pSrb));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Take the SRB we get and queue it up. These Queued SRB's will be filled with data on a WRITE_DATA
|
|
// request, at which point they will be completed.
|
|
//
|
|
QueueAdd (pSrb, &pFilter->IpV4StreamDataSpinLock, &pFilter->IpV4StreamDataQueue);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE Queuing IPv4 SRB %08X\n", pSrb));
|
|
|
|
|
|
//
|
|
// Since the stream state may have changed while we were adding the SRB to the queue
|
|
// we'll check it again, and cancel it if necessary
|
|
//
|
|
if (pStream->KSState == KSSTATE_STOP)
|
|
{
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB_READ STOP SRB Status returned: %08X\n", pSrb->Status));
|
|
|
|
if (QueueRemoveSpecific (pSrb, &pFilter->IpV4StreamDataSpinLock, &pFilter->IpV4StreamDataQueue))
|
|
{
|
|
pSrb->Status = STATUS_CANCELLED;
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb );
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 26Completed SRB %08X\n", pSrb));
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Data packet handler called - SRB_READ - Default\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: DEFAULT SRB Status returned: %08X\n", pSrb->Status));
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 27Completed SRB %08X\n", pSrb));
|
|
break;
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// invalid / unsupported command. Fail it as such
|
|
//
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Data packet handler called - Unsupported Command\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: DEFAULT SRB Status returned: %08X\n", pSrb->Status));
|
|
StreamClassStreamNotification( StreamRequestComplete, pSrb->StreamObject, pSrb );
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 28Completed SRB %08X\n", pSrb));
|
|
ASSERT (FALSE);
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Data packet handler called...status: %08X\n", pSrb->Status));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
MpeGetProperty (
|
|
PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;
|
|
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
if (IsEqualGUID (&KSPROPSETID_Connection, &pSPD->Property->Set))
|
|
{
|
|
MpeGetConnectionProperty (pSrb);
|
|
}
|
|
else
|
|
{
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: MpeGetProperty Status: %08X\n", pSrb->Status));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
IndicateMasterClock(
|
|
PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
PSTREAM pStream = (PSTREAM) pSrb->StreamObject->HwStreamExtension;
|
|
|
|
pStream->hClock = pSrb->CommandData.MasterClockHandle;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
STREAMAPI
|
|
ReceiveCtrlPacket(
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
PMPE_FILTER pFilter = (PMPE_FILTER) pSrb->HwDeviceExtension;
|
|
PSTREAM pStream = (PSTREAM) pSrb->StreamObject->HwStreamExtension;
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Control packet handler called\n"));
|
|
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
QueueAdd (pSrb, &pFilter->StreamControlSpinLock, &pFilter->StreamControlQueue);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE Queuing Control Packet SRB %08X\n", pSrb));
|
|
|
|
while (QueueRemove (&pSrb, &pFilter->StreamControlSpinLock, &pFilter->StreamControlQueue))
|
|
{
|
|
//
|
|
// determine the type of packet.
|
|
//
|
|
switch (pSrb->Command)
|
|
{
|
|
case SRB_PROPOSE_DATA_FORMAT:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Control packet handler - Propose data format\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case SRB_SET_STREAM_STATE:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Control packet handler - Set Stream State\n"));
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
MpeSetState (pSrb);
|
|
break;
|
|
|
|
case SRB_GET_STREAM_STATE:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Control packet handler - Get Stream State\n"));
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
pSrb->CommandData.StreamState = pStream->KSState;
|
|
pSrb->ActualBytesTransferred = sizeof (KSSTATE);
|
|
break;
|
|
|
|
case SRB_GET_STREAM_PROPERTY:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Control packet handler - Get Stream Property\n"));
|
|
MpeGetProperty(pSrb);
|
|
break;
|
|
|
|
case SRB_SET_STREAM_PROPERTY:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Control packet handler - Set Stream Property\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case SRB_INDICATE_MASTER_CLOCK:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Control packet handler - Indicate Master Clock\n"));
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
IndicateMasterClock (pSrb);
|
|
break;
|
|
|
|
case SRB_SET_STREAM_RATE:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Control packet handler - Set Stream Rate\n"));
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case SRB_PROPOSE_STREAM_RATE:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Control packet handler - Propose Stream Rate\n"));
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Receive Control packet handler - Default case\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
}
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: SRB Status returned: %08X\n", pSrb->Status));
|
|
|
|
StreamClassStreamNotification (StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 29Completed SRB %08X\n", pSrb));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
MpeSetState(
|
|
PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
PMPE_FILTER pFilter = ((PMPE_FILTER) pSrb->HwDeviceExtension);
|
|
PSTREAM pStream = (PSTREAM) pSrb->StreamObject->HwStreamExtension;
|
|
PHW_STREAM_REQUEST_BLOCK pCurrentSrb = NULL;
|
|
|
|
//
|
|
// For each stream, the following states are used:
|
|
//
|
|
// Stop: Absolute minimum resources are used. No outstanding IRPs.
|
|
// Acquire: KS only state that has no DirectShow correpondence
|
|
// Acquire needed resources.
|
|
// Pause: Getting ready to run. Allocate needed resources so that
|
|
// the eventual transition to Run is as fast as possible.
|
|
// Read SRBs will be queued at either the Stream class
|
|
// or in your driver (depending on when you send "ReadyForNext")
|
|
// Run: Streaming.
|
|
//
|
|
// Moving to Stop to Run always transitions through Pause.
|
|
//
|
|
// But since a client app could crash unexpectedly, drivers should handle
|
|
// the situation of having outstanding IRPs cancelled and open streams
|
|
// being closed WHILE THEY ARE STREAMING!
|
|
//
|
|
// Note that it is quite possible to transition repeatedly between states:
|
|
// Stop -> Pause -> Stop -> Pause -> Run -> Pause -> Run -> Pause -> Stop
|
|
//
|
|
switch (pSrb->CommandData.StreamState)
|
|
{
|
|
case KSSTATE_STOP:
|
|
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Set Stream State KSSTATE_STOP\n"));
|
|
|
|
pStream->KSState = pSrb->CommandData.StreamState;
|
|
//
|
|
// If transitioning to STOP state, then complete any outstanding IRPs
|
|
//
|
|
while (QueueRemove(&pCurrentSrb, &pFilter->IpV4StreamDataSpinLock, &pFilter->IpV4StreamDataQueue))
|
|
{
|
|
pCurrentSrb->Status = STATUS_CANCELLED;
|
|
pCurrentSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
|
|
StreamClassStreamNotification(StreamRequestComplete, pCurrentSrb->StreamObject, pCurrentSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 30Completed SRB %08X\n", pCurrentSrb));
|
|
}
|
|
while (QueueRemove(&pCurrentSrb, &pFilter->StreamControlSpinLock, &pFilter->StreamControlQueue))
|
|
{
|
|
pCurrentSrb->Status = STATUS_CANCELLED;
|
|
pCurrentSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
|
|
StreamClassStreamNotification(StreamRequestComplete, pCurrentSrb->StreamObject, pCurrentSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 30Completed SRB %08X\n", pCurrentSrb));
|
|
}
|
|
|
|
while (QueueRemove(&pCurrentSrb, &pFilter->StreamDataSpinLock, &pFilter->StreamDataQueue))
|
|
{
|
|
pCurrentSrb->Status = STATUS_CANCELLED;
|
|
pCurrentSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
|
|
StreamClassStreamNotification(StreamRequestComplete, pCurrentSrb->StreamObject, pCurrentSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 30Completed SRB %08X\n", pCurrentSrb));
|
|
}
|
|
|
|
while (QueueRemove(&pCurrentSrb, &pFilter->StreamUserSpinLock, &pFilter->StreamContxList))
|
|
{
|
|
pCurrentSrb->Status = STATUS_CANCELLED;
|
|
pCurrentSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
|
|
StreamClassStreamNotification(StreamRequestComplete, pCurrentSrb->StreamObject, pCurrentSrb);
|
|
TEST_DEBUG( TEST_DBG_SRB, ("MPE 30Completed SRB %08X\n", pCurrentSrb));
|
|
}
|
|
|
|
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
|
|
case KSSTATE_ACQUIRE:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Set Stream State KSSTATE_ACQUIRE\n"));
|
|
pStream->KSState = pSrb->CommandData.StreamState;
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case KSSTATE_PAUSE:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Set Stream State KSSTATE_PAUSE\n"));
|
|
pStream->KSState = pSrb->CommandData.StreamState;
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case KSSTATE_RUN:
|
|
TEST_DEBUG (TEST_DBG_TRACE, ("MPE: Set Stream State KSSTATE_RUN\n"));
|
|
pStream->KSState = pSrb->CommandData.StreamState;
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
} // end switch (pSrb->CommandData.StreamState)
|
|
|
|
return;
|
|
}
|
|
|