939 lines
30 KiB
C
939 lines
30 KiB
C
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1999 - 2000
|
|
|
|
Module Name:
|
|
|
|
MSDVUppr.c
|
|
|
|
Abstract:
|
|
|
|
Interface code with stream class driver.
|
|
|
|
Last changed by:
|
|
|
|
Author: Yee J. Wu
|
|
|
|
Environment:
|
|
|
|
Kernel mode only
|
|
|
|
Revision History:
|
|
|
|
$Revision:: $
|
|
$Date:: $
|
|
|
|
--*/
|
|
|
|
#include "strmini.h"
|
|
#include "ksmedia.h"
|
|
#include "1394.h"
|
|
#include "61883.h"
|
|
#include "avc.h"
|
|
#include "dbg.h"
|
|
#include "msdvfmt.h"
|
|
#include "msdvdef.h"
|
|
#include "MsdvGuts.h" // Function prototypes
|
|
#include "MsdvAvc.h"
|
|
#include "MsdvUtil.h"
|
|
|
|
#include "EDevCtrl.h"
|
|
|
|
#ifdef TIME_BOMB
|
|
#include "..\..\inc\timebomb.c"
|
|
#endif
|
|
|
|
// global flag for debugging. Inlines are defined in dbg.h. The debug level is set for
|
|
// minimal amount of messages.
|
|
#if DBG
|
|
|
|
#define DVTraceMaskCheckIn TL_PNP_ERROR | TL_STRM_ERROR | TL_61883_ERROR
|
|
|
|
#define DVTraceMaskDefault TL_PNP_ERROR | TL_PNP_WARNING \
|
|
| TL_61883_ERROR | TL_61883_WARNING \
|
|
| TL_CIP_ERROR \
|
|
| TL_FCP_ERROR \
|
|
| TL_STRM_ERROR | TL_STRM_WARNING \
|
|
| TL_CLK_ERROR
|
|
|
|
#define DVTraceMaskDebug TL_PNP_ERROR | TL_PNP_WARNING \
|
|
| TL_61883_ERROR| TL_61883_WARNING \
|
|
| TL_CIP_ERROR \
|
|
| TL_FCP_ERROR | TL_FCP_WARNING \
|
|
| TL_STRM_ERROR | TL_STRM_WARNING \
|
|
| TL_CLK_ERROR
|
|
|
|
|
|
#ifdef USE_WDM110 // Win2000 code base
|
|
ULONG DVTraceMask = DVTraceMaskCheckIn | TL_FCP_ERROR;
|
|
#else
|
|
ULONG DVTraceMask = DVTraceMaskCheckIn;
|
|
#endif
|
|
|
|
ULONG DVAssertLevel = 1; // Turn on assert (>0)
|
|
ULONG DVDebugXmt = 0; // Debug data transfer flag; (> 0) to turn it on.
|
|
|
|
#endif
|
|
|
|
|
|
extern DV_FORMAT_INFO DVFormatInfoTable[];
|
|
|
|
//
|
|
// Function prototypes
|
|
//
|
|
VOID
|
|
DVRcvStreamDevicePacket(
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb
|
|
);
|
|
VOID
|
|
DVSRBRead(
|
|
IN PKSSTREAM_HEADER pStrmHeader,
|
|
IN ULONG ulFrameSize,
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
IN PSTREAMEX pStrmExt,
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb // needs Srb->Status
|
|
);
|
|
NTSTATUS
|
|
DVAttachWriteFrame(
|
|
IN PSTREAMEX pStrmExt
|
|
);
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
#if 0 // Enable later
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, DVRcvStreamDevicePacket)
|
|
#pragma alloc_text(PAGE, DVRcvControlPacket)
|
|
#pragma alloc_text(PAGE, DVRcvDataPacket)
|
|
// #pragma alloc_text(INIT, DriverEntry)
|
|
#endif
|
|
#endif
|
|
|
|
|
|
VOID
|
|
DVRcvStreamDevicePacket(
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is where most of the interesting Stream requests come to us
|
|
|
|
--*/
|
|
{
|
|
PDVCR_EXTENSION pDevExt;
|
|
PAV_61883_REQUEST pAVReq;
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
//
|
|
// Get these extensions from a SRB
|
|
//
|
|
pDevExt = (PDVCR_EXTENSION) pSrb->HwDeviceExtension;
|
|
pAVReq = (PAV_61883_REQUEST) pSrb->SRBExtension; // Use in IrpSync is OK,
|
|
|
|
#if DBG
|
|
if(pSrb->Command != SRB_INITIALIZE_DEVICE && // PowerState is initialize in this SRB so ignore it.
|
|
pDevExt->PowerState != PowerDeviceD0) {
|
|
TRACE(TL_PNP_WARNING,("RcvDevPkt; pSrb:%x; Cmd:%x; Dev is OFF state\n", pSrb, pSrb->Command));
|
|
}
|
|
#endif
|
|
|
|
TRACE(TL_PNP_TRACE,("\'DVRcvStreamDevicePacket: pSrb %x, Cmd %d, pdevExt %x\n", pSrb, pSrb->Command, pDevExt));
|
|
|
|
//
|
|
// Assume success
|
|
//
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
switch (pSrb->Command) {
|
|
|
|
case SRB_INITIALIZE_DEVICE:
|
|
|
|
ASSERT(((PPORT_CONFIGURATION_INFORMATION) pSrb->CommandData.ConfigInfo)->HwDeviceExtension == pDevExt);
|
|
pSrb->Status =
|
|
DVInitializeDevice(
|
|
(PDVCR_EXTENSION) ((PPORT_CONFIGURATION_INFORMATION)pSrb->CommandData.ConfigInfo)->HwDeviceExtension,
|
|
pSrb->CommandData.ConfigInfo,
|
|
pAVReq
|
|
);
|
|
break;
|
|
|
|
|
|
|
|
case SRB_INITIALIZATION_COMPLETE:
|
|
|
|
//
|
|
// Stream class has finished initialization. Get device interface registry value/
|
|
//
|
|
DVInitializeCompleted(
|
|
(PDVCR_EXTENSION) pSrb->HwDeviceExtension);
|
|
break;
|
|
|
|
|
|
case SRB_GET_STREAM_INFO:
|
|
|
|
//
|
|
// this is a request for the driver to enumerate requested streams
|
|
//
|
|
pSrb->Status =
|
|
DVGetStreamInfo(
|
|
pDevExt,
|
|
pSrb->NumberOfBytesToTransfer,
|
|
&pSrb->CommandData.StreamBuffer->StreamHeader,
|
|
&pSrb->CommandData.StreamBuffer->StreamInfo
|
|
);
|
|
break;
|
|
|
|
|
|
|
|
case SRB_GET_DATA_INTERSECTION:
|
|
|
|
// Since format can dynamically change, we will query new format here.
|
|
// Note: during data intersection, we compare FrameSize and that is
|
|
// format related.
|
|
|
|
if((GetSystemTime() - pDevExt->tmLastFormatUpdate) > FORMAT_UPDATE_INTERVAL) {
|
|
|
|
// Get mode of operation (Camera or VCR)
|
|
DVGetDevModeOfOperation(pDevExt);
|
|
|
|
if(!DVGetDevSignalFormat(pDevExt, KSPIN_DATAFLOW_OUT,0)) {
|
|
// If querying its format has failed, we cannot open this stream.
|
|
TRACE(TL_STRM_WARNING,("SRB_GET_DATA_INTERSECTION:Failed getting signal format.\n"));
|
|
}
|
|
|
|
// Update system time to reflect last update
|
|
pDevExt->tmLastFormatUpdate = GetSystemTime();
|
|
}
|
|
|
|
pSrb->Status =
|
|
DVGetDataIntersection(
|
|
pSrb->CommandData.IntersectInfo->StreamNumber,
|
|
pSrb->CommandData.IntersectInfo->DataRange,
|
|
pSrb->CommandData.IntersectInfo->DataFormatBuffer,
|
|
pSrb->CommandData.IntersectInfo->SizeOfDataFormatBuffer,
|
|
DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize,
|
|
&pSrb->ActualBytesTransferred,
|
|
pDevExt->paCurrentStrmInfo
|
|
#ifdef SUPPORT_NEW_AVC
|
|
,pDevExt->paCurrentStrmInfo[pSrb->CommandData.IntersectInfo->StreamNumber].DataFlow == KSPIN_DATAFLOW_OUT ? pDevExt->hOPcrDV : pDevExt->hIPcrDV
|
|
#endif
|
|
);
|
|
break;
|
|
|
|
|
|
|
|
case SRB_OPEN_STREAM:
|
|
|
|
//
|
|
// Serialize SRB_OPEN/CLOSE_STREAMs
|
|
//
|
|
KeWaitForSingleObject( &pDevExt->hMutex, Executive, KernelMode, FALSE, 0 );
|
|
|
|
pSrb->Status =
|
|
DVOpenStream(
|
|
pSrb->StreamObject,
|
|
pSrb->CommandData.OpenFormat,
|
|
pAVReq
|
|
);
|
|
|
|
KeReleaseMutex(&pDevExt->hMutex, FALSE);
|
|
break;
|
|
|
|
|
|
|
|
case SRB_CLOSE_STREAM:
|
|
|
|
//
|
|
// Serialize SRB_OPEN/CLOSE_STREAMs
|
|
//
|
|
KeWaitForSingleObject( &pDevExt->hMutex, Executive, KernelMode, FALSE, 0 );
|
|
|
|
pSrb->Status =
|
|
DVCloseStream(
|
|
pSrb->StreamObject,
|
|
pSrb->CommandData.OpenFormat,
|
|
pAVReq
|
|
);
|
|
KeReleaseMutex(&pDevExt->hMutex, FALSE);
|
|
break;
|
|
|
|
|
|
|
|
case SRB_GET_DEVICE_PROPERTY:
|
|
|
|
pSrb->Status =
|
|
DVGetDeviceProperty(
|
|
pDevExt,
|
|
pSrb->CommandData.PropertyInfo,
|
|
&pSrb->ActualBytesTransferred
|
|
);
|
|
break;
|
|
|
|
|
|
case SRB_SET_DEVICE_PROPERTY:
|
|
|
|
pSrb->Status =
|
|
DVSetDeviceProperty(
|
|
pDevExt,
|
|
pSrb->CommandData.PropertyInfo,
|
|
&pSrb->ActualBytesTransferred
|
|
);
|
|
break;
|
|
|
|
|
|
|
|
case SRB_CHANGE_POWER_STATE:
|
|
|
|
pIrpStack = IoGetCurrentIrpStackLocation(pSrb->Irp);
|
|
|
|
if(pIrpStack->MinorFunction == IRP_MN_SET_POWER) {
|
|
pSrb->Status =
|
|
DVChangePower(
|
|
(PDVCR_EXTENSION) pSrb->HwDeviceExtension,
|
|
pAVReq,
|
|
pSrb->CommandData.DeviceState
|
|
);
|
|
} else
|
|
if(pIrpStack->MinorFunction == IRP_MN_QUERY_POWER) {
|
|
TRACE(TL_PNP_WARNING,("IRP_MN_QUERY_POWER: PwrSt:%d\n", pDevExt->PowerState));
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
TRACE(TL_PNP_WARNING,("NOT_IMPL POWER_STATE MinorFunc:%d\n", pIrpStack->MinorFunction));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case SRB_UNKNOWN_DEVICE_COMMAND:
|
|
|
|
//
|
|
// We might be interested in unknown commands if they pertain
|
|
// to bus resets. Bus resets are important cuz we need to know
|
|
// what the current generation count is.
|
|
//
|
|
pIrpStack = IoGetCurrentIrpStackLocation(pSrb->Irp);
|
|
|
|
if(pIrpStack->MajorFunction == IRP_MJ_PNP) {
|
|
if(pIrpStack->MinorFunction == IRP_MN_BUS_RESET) {
|
|
|
|
DVProcessPnPBusReset(
|
|
pDevExt
|
|
);
|
|
|
|
// Always success
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
/* Known: IRP_MN_QUERY_PNP_DEVICE_STATE */
|
|
TRACE(TL_PNP_WARNING,("\'DVRcvStreamDevicePacket: NOT_IMPL; IRP_MJ_PNP IRP_MN_:%x\n",
|
|
pIrpStack->MinorFunction
|
|
));
|
|
// Canot return STATUS_NOT_SUPPORTED for PNP irp or device will not load.
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
}
|
|
else {
|
|
TRACE(TL_PNP_WARNING,("\'DVRcvStreamDevicePacket: NOT_IMPL; IRP_MJ_ %x; IRP_MN_:%x\n",
|
|
pIrpStack->MajorFunction,
|
|
pIrpStack->MinorFunction
|
|
));
|
|
// Canot return STATUS_NOT_SUPPORTED for PNP irp or device will not load.
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
break;
|
|
|
|
|
|
case SRB_SURPRISE_REMOVAL:
|
|
|
|
TRACE(TL_PNP_WARNING,("\' #SURPRISE_REMOVAL# pSrb %x, pDevExt %x\n", pSrb, pDevExt));
|
|
pSrb->Status =
|
|
DVSurpriseRemoval(
|
|
pDevExt,
|
|
pAVReq
|
|
);
|
|
break;
|
|
|
|
|
|
|
|
case SRB_UNINITIALIZE_DEVICE:
|
|
|
|
TRACE(TL_PNP_WARNING,("\' #UNINITIALIZE_DEVICE# pSrb %x, pDevExt %x\n", pSrb, pDevExt));
|
|
pSrb->Status =
|
|
DVUninitializeDevice(
|
|
(PDVCR_EXTENSION) pSrb->HwDeviceExtension
|
|
);
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
TRACE(TL_PNP_WARNING,("\'DVRcvStreamDevicePacket: Unknown or unprocessed SRB cmd 0x%x\n", pSrb->Command));
|
|
|
|
//
|
|
// this is a request that we do not understand. Indicate invalid
|
|
// command and complete the request
|
|
//
|
|
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED; // SUPPORTED;
|
|
}
|
|
|
|
//
|
|
// NOTE:
|
|
//
|
|
// all of the commands that we do, or do not understand can all be completed
|
|
// synchronously at this point, so we can use a common callback routine here.
|
|
// If any of the above commands require asynchronous processing, this will
|
|
// have to change
|
|
//
|
|
#if DBG
|
|
if (pSrb->Status != STATUS_SUCCESS &&
|
|
pSrb->Status != STATUS_NOT_SUPPORTED &&
|
|
pSrb->Status != STATUS_NOT_IMPLEMENTED &&
|
|
pSrb->Status != STATUS_BUFFER_TOO_SMALL &&
|
|
pSrb->Status != STATUS_BUFFER_OVERFLOW &&
|
|
pSrb->Status != STATUS_NO_MATCH
|
|
&& pSrb->Status != STATUS_TIMEOUT
|
|
) {
|
|
TRACE(TL_PNP_WARNING,("\'pSrb->Command (%x) ->Status:%x\n", pSrb->Command, pSrb->Status));
|
|
}
|
|
#endif
|
|
|
|
if(STATUS_PENDING != pSrb->Status) {
|
|
|
|
StreamClassDeviceNotification(
|
|
DeviceRequestComplete,
|
|
pSrb->HwDeviceExtension,
|
|
pSrb
|
|
);
|
|
}
|
|
else {
|
|
|
|
// Pending pSrb which will be completed asynchronously
|
|
// Does StreamClass allow device SRB to be in the pending state?
|
|
TRACE(TL_PNP_WARNING,("\'DVReceiveDevicePacket:Pending pSrb %x\n", pSrb));
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DVRcvControlPacket(
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called with packet commands that control the video stream
|
|
|
|
--*/
|
|
{
|
|
PAV_61883_REQUEST pAVReq;
|
|
PSTREAMEX pStrmExt;
|
|
PDVCR_EXTENSION pDevExt;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Get these three extension from SRB
|
|
//
|
|
pAVReq = (PAV_61883_REQUEST) pSrb->SRBExtension; // This is OK to be used us IrpSync operation
|
|
pDevExt = (PDVCR_EXTENSION) pSrb->HwDeviceExtension;
|
|
pStrmExt = (PSTREAMEX) pSrb->StreamObject->HwStreamExtension; // Only valid in SRB_OPEN/CLOSE_STREAM
|
|
|
|
ASSERT(pStrmExt && pDevExt && pAVReq);
|
|
|
|
//
|
|
// Default to success
|
|
//
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
switch (pSrb->Command) {
|
|
|
|
case SRB_GET_STREAM_STATE:
|
|
|
|
pSrb->Status =
|
|
DVGetStreamState(
|
|
pStrmExt,
|
|
&(pSrb->CommandData.StreamState),
|
|
&(pSrb->ActualBytesTransferred)
|
|
);
|
|
break;
|
|
|
|
case SRB_SET_STREAM_STATE:
|
|
|
|
pSrb->Status =
|
|
DVSetStreamState(
|
|
pStrmExt,
|
|
pDevExt,
|
|
pAVReq,
|
|
pSrb->CommandData.StreamState // Target KSSTATE
|
|
);
|
|
break;
|
|
|
|
|
|
case SRB_GET_STREAM_PROPERTY:
|
|
|
|
pSrb->Status =
|
|
DVGetStreamProperty(
|
|
pSrb
|
|
);
|
|
break;
|
|
|
|
|
|
case SRB_SET_STREAM_PROPERTY:
|
|
|
|
pSrb->Status =
|
|
DVSetStreamProperty(
|
|
pSrb
|
|
);
|
|
break;
|
|
|
|
case SRB_OPEN_MASTER_CLOCK:
|
|
case SRB_CLOSE_MASTER_CLOCK:
|
|
|
|
//
|
|
// This stream is being selected to provide a Master clock.
|
|
//
|
|
pSrb->Status =
|
|
DVOpenCloseMasterClock(
|
|
pStrmExt,
|
|
pSrb->Command == SRB_OPEN_MASTER_CLOCK ? pSrb->CommandData.MasterClockHandle: NULL);
|
|
break;
|
|
|
|
case SRB_INDICATE_MASTER_CLOCK:
|
|
|
|
//
|
|
// Assigns a clock to a stream.
|
|
//
|
|
pSrb->Status =
|
|
DVIndicateMasterClock(
|
|
pStrmExt,
|
|
pSrb->CommandData.MasterClockHandle);
|
|
break;
|
|
|
|
case SRB_PROPOSE_DATA_FORMAT:
|
|
|
|
//
|
|
// The SRB_PROPOSE_DATA_FORMAT command queries the minidriver
|
|
// to determine if the minidriver can change the format of a
|
|
// particular stream. If the minidriver is able to switch the
|
|
// stream to the specified format, STATUS_SUCCESS is returned.
|
|
// Note that this function only proposes a new format, but does
|
|
// not change it.
|
|
//
|
|
// The CommandData.OpenFormat passes the format to validate.
|
|
// If the minidriver is able to accept the new format, at some
|
|
// later time the class driver may send the minidriver a format
|
|
// change, which is indicated by an OptionsFlags flag in a
|
|
// KSSTREAM_HEADER structure.
|
|
//
|
|
|
|
TRACE(TL_STRM_INFO,("\'DVRcvControlPacket: SRB_PROPOSE_DATA_FORMAT\n"));
|
|
if(!DVVerifyDataFormat(
|
|
pSrb->CommandData.OpenFormat,
|
|
pSrb->StreamObject->StreamNumber,
|
|
DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize,
|
|
pDevExt->paCurrentStrmInfo
|
|
)) {
|
|
TRACE(TL_STRM_WARNING,("\'DVRcvControlPacket: AdapterVerifyFormat failed.\n"));
|
|
pSrb->Status = STATUS_NO_MATCH;
|
|
}
|
|
break;
|
|
|
|
case SRB_PROPOSE_STREAM_RATE:
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED; // if returned STATUS_NOT_SUPPORTED, it will send EOStream.
|
|
TRACE(TL_STRM_TRACE,("\'SRB_PROPOSE_STREAM_RATE: NOT_IMPLEMENTED!\n"));
|
|
break;
|
|
case SRB_BEGIN_FLUSH:
|
|
pSrb->Status = STATUS_NOT_SUPPORTED;
|
|
TRACE(TL_STRM_TRACE,("\'SRB_BEGIN_FLUSH: NOT_SUPPORTED!\n"));
|
|
break;
|
|
case SRB_END_FLUSH:
|
|
pSrb->Status = STATUS_NOT_SUPPORTED;
|
|
TRACE(TL_STRM_TRACE,("\'SRB_END_FLUSH: NOT_SUPPORTED!\n"));
|
|
break;
|
|
default:
|
|
|
|
//
|
|
// invalid / unsupported command. Fail it as such
|
|
//
|
|
TRACE(TL_STRM_WARNING,("\'DVRcvControlPacket: unknown cmd = %x\n",pSrb->Command));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED; // SUPPORTED;
|
|
}
|
|
|
|
TRACE(TL_STRM_TRACE,("\'DVRcvControlPacket: Command %x, ->Status %x, ->CommandData %x\n",
|
|
pSrb->Command, pSrb->Status, &(pSrb->CommandData.StreamState) ));
|
|
|
|
StreamClassStreamNotification(
|
|
StreamRequestComplete,
|
|
pSrb->StreamObject,
|
|
pSrb);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
DVRcvDataPacket(
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called with video data packet commands
|
|
|
|
--*/
|
|
|
|
{
|
|
PSTREAMEX pStrmExt;
|
|
PDVCR_EXTENSION pDevExt;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
pStrmExt = (PSTREAMEX) pSrb->StreamObject->HwStreamExtension;
|
|
pDevExt = (PDVCR_EXTENSION) pSrb->HwDeviceExtension;
|
|
|
|
#if DBG
|
|
if(pDevExt->PowerState != PowerDeviceD0) {
|
|
TRACE(TL_STRM_WARNING|TL_PNP_WARNING,("\'SRB_READ/WRITE; PowerSt:OFF; pSrb:%x\n", pSrb));
|
|
}
|
|
#endif
|
|
|
|
// The stream has to be open before we can do anything.
|
|
if (pStrmExt == NULL) {
|
|
TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("DVRcvDataPacket: stream not opened for SRB %x. kicking out...\n", pSrb->Command));
|
|
pSrb->Status = STATUS_UNSUCCESSFUL;
|
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
StreamClassStreamNotification(StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Serialize attach, cancel and state change
|
|
//
|
|
KeWaitForSingleObject( pStrmExt->hStreamMutex, Executive, KernelMode, FALSE, 0 );
|
|
|
|
|
|
TRACE(TL_CIP_TRACE,("\'XXX_DATA(%d, %d);Srb:%x;Flg:%x;FExt:%d:%d\n",
|
|
(DWORD) pStrmExt->cntSRBReceived,
|
|
(DWORD) pSrb->CommandData.DataBufferArray->PresentationTime.Time/10000,
|
|
pSrb,
|
|
pSrb->CommandData.DataBufferArray->OptionsFlags,
|
|
pSrb->CommandData.DataBufferArray->FrameExtent,
|
|
DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize
|
|
));
|
|
|
|
//
|
|
// determine the type of packet.
|
|
//
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
#if DBG
|
|
pStrmExt->cntSRBPending++;
|
|
#endif
|
|
|
|
switch (pSrb->Command) {
|
|
|
|
case SRB_READ_DATA:
|
|
|
|
// Rule:
|
|
// Only accept read requests when in either the Pause or Run
|
|
// States. If Stopped, immediately return the SRB.
|
|
|
|
if (pStrmExt->lCancelStateWorkItem) {
|
|
// TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("\'SRB_READ_DATA: Abort while getting SRB_READ_DATA!\n"));
|
|
// ASSERT(pStrmExt->lCancelStateWorkItem == 0 && "Encounter SRB_READ_DATA while aborting or aborted.\n");
|
|
pSrb->Status = (pDevExt->bDevRemoved ? STATUS_DEVICE_REMOVED : STATUS_CANCELLED);
|
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
break;
|
|
|
|
} else if( pStrmExt->StreamState == KSSTATE_STOP ||
|
|
pStrmExt->StreamState == KSSTATE_ACQUIRE ||
|
|
pStrmExt->hConnect == NULL ||
|
|
pDevExt->bDevRemoved
|
|
) {
|
|
TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("\'SRB_READ_DATA: (DV->) State %d, bDevRemoved %d\n", pStrmExt->StreamState, pDevExt->bDevRemoved));
|
|
pSrb->Status = (pDevExt->bDevRemoved ? STATUS_DEVICE_REMOVED : STATUS_CANCELLED);
|
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
TRACE(TL_STRM_INFO|TL_CIP_INFO,("\'SRB_READ_DATA pSrb %x, pStrmExt %x\n", pSrb, pStrmExt));
|
|
pStrmExt->cntSRBReceived++;
|
|
|
|
// Set state thread in halt while while Read/Write SRB is being processed
|
|
DVSRBRead(
|
|
pSrb->CommandData.DataBufferArray,
|
|
DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize,
|
|
pDevExt,
|
|
pStrmExt,
|
|
pSrb
|
|
);
|
|
|
|
KeReleaseMutex(pStrmExt->hStreamMutex, FALSE);
|
|
|
|
// Note: This SRB will be completed asynchronously.
|
|
|
|
return;
|
|
}
|
|
|
|
break;
|
|
|
|
case SRB_WRITE_DATA:
|
|
|
|
if( pStrmExt->StreamState == KSSTATE_STOP ||
|
|
pStrmExt->StreamState == KSSTATE_ACQUIRE ||
|
|
#ifdef SUPPORT_NEW_AVC
|
|
(pStrmExt->hConnect == NULL && !pStrmExt->bDV2DVConnect) ||
|
|
#else
|
|
pStrmExt->hConnect == NULL ||
|
|
#endif
|
|
pDevExt->bDevRemoved
|
|
) {
|
|
pSrb->Status = (pDevExt->bDevRemoved ? STATUS_DEVICE_REMOVED : STATUS_CANCELLED);
|
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\'SRB_WRITE_DATA: (DV->) State %d, bDevRemoved %d; Status:%x\n", pStrmExt->StreamState, pDevExt->bDevRemoved, pSrb->Status));
|
|
break; // Complete SRB with error status
|
|
|
|
} else {
|
|
|
|
KIRQL oldIrql;
|
|
PLONG plSrbUseCount; // When this count is 0, it can be completed.
|
|
|
|
TRACE(TL_STRM_INFO|TL_CIP_INFO,("\'SRB_WRITE_DATA pSrb %x, pStrmExt %x\n", pSrb, pStrmExt));
|
|
|
|
//
|
|
// Process EOSream frame separately
|
|
//
|
|
if(pSrb->CommandData.DataBufferArray->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_ENDOFSTREAM) {
|
|
KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
|
|
TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\'*** EOStream: ST:%d; bIsochIsActive:%d; Wait (cndAttached:%d+cndSRQ:%d) to complete......\n", \
|
|
pStrmExt->StreamState, pStrmExt->bIsochIsActive, pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued));
|
|
pStrmExt->bEOStream = TRUE;
|
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
} else if(pSrb->CommandData.DataBufferArray->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TYPECHANGED) {
|
|
TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\'DVRcvDataPacket:KSSTREAM_HEADER_OPTIONSF_TYPECHANGED.\n"));
|
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
// May need to compare the data format; instead of return STATUS_SUCCESS??
|
|
pSrb->Status = STATUS_SUCCESS; // May need to check the format when dynamic format change is allowed.
|
|
break;
|
|
|
|
#ifdef SUPPORT_NEW_AVC
|
|
} else if(pStrmExt->bDV2DVConnect) {
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\'SRB_WRITE_DATA: [DV2DV] (pStrmExt:%x), pSrb:%x, FrameExt:%d\n",
|
|
pStrmExt, pSrb, pSrb->CommandData.DataBufferArray->FrameExtent));
|
|
break;
|
|
#endif
|
|
} else {
|
|
|
|
PSRB_ENTRY pSrbEntry;
|
|
|
|
//
|
|
// Validation
|
|
//
|
|
if(pSrb->CommandData.DataBufferArray->FrameExtent < DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize) {
|
|
TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("\' FrameExt %d < FrameSize %d\n", pSrb->CommandData.DataBufferArray->FrameExtent, DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize));
|
|
ASSERT(pSrb->CommandData.DataBufferArray->FrameExtent >= DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize);
|
|
pSrb->Status = STATUS_INVALID_PARAMETER;
|
|
break; // Complete SRB with error status
|
|
}
|
|
|
|
//
|
|
// Dynamically allocate a SRB_ENTRY and append it to SRBQueue
|
|
//
|
|
if(!(pSrbEntry = ExAllocatePool(NonPagedPool, sizeof(SRB_ENTRY)))) {
|
|
pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
break; // Complete SRB with error status
|
|
}
|
|
|
|
#if DBG
|
|
if(pStrmExt->bEOStream) {
|
|
TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\'SRB_WRITE_DATA: pSrb:%x after EOStream!\n", pSrb));
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// For statistics
|
|
//
|
|
pStrmExt->cntSRBReceived++;
|
|
|
|
//
|
|
// Save SRB and add it to SRB queue
|
|
// No need for spin lock since StreamClass will serialize it for us.
|
|
//
|
|
pSrb->Status = STATUS_PENDING;
|
|
pSrbEntry->pSrb = pSrb; pSrbEntry->bStale = FALSE; pSrbEntry->bAudioMute = FALSE;
|
|
#if DBG
|
|
pSrbEntry->SrbNum = (ULONG) pStrmExt->cntSRBReceived -1;
|
|
#endif
|
|
//
|
|
// Note: plSrbUseCount is initialize to 1
|
|
// When it is insert: ++
|
|
// When it is removed: --
|
|
// when this count is 0; it can be completed.
|
|
//
|
|
plSrbUseCount = (PLONG) pSrb->SRBExtension; *plSrbUseCount = 1; // Can be completed if this is 0
|
|
|
|
KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
|
|
InsertTailList(&pStrmExt->SRBQueuedListHead, &pSrbEntry->ListEntry); pStrmExt->cntSRBQueued++;
|
|
TRACE(TL_CIP_INFO,("\'%d) Fresh Srb:%x; RefCnt:%d; cntSrbQ:%d\n", (DWORD) pStrmExt->cntSRBReceived, pSrb, *plSrbUseCount, pStrmExt->cntSRBQueued));
|
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
|
|
|
|
|
#ifdef SUPPORT_PREROLL_AT_RUN_STATE
|
|
// We can operate "smoothly" if we hace N number of media sample.
|
|
if(pStrmExt->cntSRBReceived == NUM_BUFFER_BEFORE_TRANSMIT_BEGIN) {
|
|
KeSetEvent(&pStrmExt->hPreRollEvent, 0, FALSE);
|
|
}
|
|
#endif
|
|
if(pStrmExt->pAttachFrameThreadObject) {
|
|
// Signal that a new frame has arrived.
|
|
KeSetEvent(&pStrmExt->hSrbArriveEvent, 0, FALSE);
|
|
}
|
|
else {
|
|
TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("\'No thread to attach frame ?\n"));
|
|
}
|
|
}
|
|
|
|
KeReleaseMutex(pStrmExt->hStreamMutex, FALSE);
|
|
|
|
return; // Note: This SRB will be completed asynchronously.
|
|
}
|
|
|
|
break; // Complete SRB with error status
|
|
|
|
default:
|
|
//
|
|
// invalid / unsupported command. Fail it as such
|
|
//
|
|
pSrb->Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
KeReleaseMutex(pStrmExt->hStreamMutex, FALSE);
|
|
|
|
|
|
ASSERT(pSrb->Status != STATUS_PENDING);
|
|
|
|
// Finally, send the srb back up ...
|
|
StreamClassStreamNotification(
|
|
StreamRequestComplete,
|
|
pSrb->StreamObject,
|
|
pSrb );
|
|
#if DBG
|
|
pStrmExt->cntSRBPending--;
|
|
#endif
|
|
}
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This where life begins for a driver. The stream class takes care
|
|
of alot of stuff for us, but we still need to fill in an initialization
|
|
structure for the stream class and call it.
|
|
|
|
Arguments:
|
|
|
|
Context1 - DriverObject
|
|
Context2 - RegistryPath
|
|
|
|
Return Value:
|
|
|
|
The function value is the final status from the initialization operation.
|
|
|
|
--*/
|
|
{
|
|
|
|
HW_INITIALIZATION_DATA HwInitData;
|
|
|
|
|
|
TRACE(TL_PNP_ERROR,("<<<<<<< MSDV.sys: %s; %s; %x %x >>>>>>>>\n",
|
|
__DATE__, __TIME__, DriverObject, RegistryPath));
|
|
|
|
#ifdef TIME_BOMB
|
|
if (HasEvaluationTimeExpired()) {
|
|
TRACE(TL_PNP_ERROR, ("Evaluation period expired!") );
|
|
return STATUS_EVALUATION_EXPIRATION;
|
|
}
|
|
#endif
|
|
|
|
TRACE(TL_PNP_ERROR,("===================================================================\n"));
|
|
TRACE(TL_PNP_ERROR,("DVTraceMask=0x%.8x = 0x[7][6][5][4][3][2][1][0] where\n", DVTraceMask));
|
|
TRACE(TL_PNP_ERROR,("\n"));
|
|
TRACE(TL_PNP_ERROR,("PNP: [0]:Loading, power state, surprise removal, device SRB..etc.\n"));
|
|
TRACE(TL_PNP_ERROR,("61883: [1]:Plugs, connection, CMP info and call to 61883.\n"));
|
|
TRACE(TL_PNP_ERROR,("CIP: [2]:Isoch data transfer.\n"));
|
|
TRACE(TL_PNP_ERROR,("AVC: [3]:AVC commands.\n"));
|
|
TRACE(TL_PNP_ERROR,("Stream:[4]:Data intersec, open/close,.state, property etc.\n"));
|
|
TRACE(TL_PNP_ERROR,("Clock: [5]:Clock (event and signal)etc.\n"));
|
|
TRACE(TL_PNP_ERROR,("===================================================================\n"));
|
|
TRACE(TL_PNP_ERROR,("dd msdv!DVTraceMask L1\n"));
|
|
TRACE(TL_PNP_ERROR,("e msdv!DVTraceMask <new value> <enter>\n"));
|
|
TRACE(TL_PNP_ERROR,("<for each nibble: ERROR:8, WARNING:4, TRACE:2, INFO:1, MASK:f>\n"));
|
|
TRACE(TL_PNP_ERROR,("===================================================================\n\n"));
|
|
|
|
|
|
//
|
|
// Fill in the HwInitData structure
|
|
//
|
|
RtlZeroMemory( &HwInitData, sizeof(HW_INITIALIZATION_DATA) );
|
|
|
|
HwInitData.HwInitializationDataSize = sizeof(HwInitData);
|
|
HwInitData.HwInterrupt = NULL;
|
|
|
|
HwInitData.HwReceivePacket = DVRcvStreamDevicePacket;
|
|
HwInitData.HwRequestTimeoutHandler = DVTimeoutHandler;
|
|
HwInitData.HwCancelPacket = DVCancelOnePacket;
|
|
HwInitData.DeviceExtensionSize = sizeof(DVCR_EXTENSION); // Per device
|
|
|
|
//
|
|
// The ULONG is used in SRB_WRITE_DATA to keep track of
|
|
// number of times the same SRB was attached for transmit.
|
|
//
|
|
// Data SRB: ULONG is used (< sizeof(AV_61883_REQ)
|
|
// DeviceControl or StreamControl Srb: AV_61883_REQ is used.
|
|
HwInitData.PerRequestExtensionSize = sizeof(AV_61883_REQUEST); // Per SRB
|
|
HwInitData.PerStreamExtensionSize = sizeof(STREAMEX); // Per pin/stream
|
|
HwInitData.FilterInstanceExtensionSize = 0;
|
|
|
|
HwInitData.BusMasterDMA = FALSE;
|
|
HwInitData.Dma24BitAddresses = FALSE;
|
|
HwInitData.BufferAlignment = sizeof(ULONG) - 1;
|
|
HwInitData.TurnOffSynchronization = TRUE;
|
|
HwInitData.DmaBufferSize = 0;
|
|
|
|
return StreamClassRegisterAdapter(DriverObject, RegistryPath, &HwInitData);
|
|
}
|
|
|