928 lines
28 KiB
C
928 lines
28 KiB
C
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1999 - 2000
|
|
|
|
Module Name:
|
|
|
|
MSTpUppr.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 "MsTpFmt.h"
|
|
#include "MsTpDef.h"
|
|
#include "MsTpGuts.h" // Function prototypes
|
|
#include "MsTpAvc.h"
|
|
|
|
#include "EDevCtrl.h"
|
|
|
|
#ifdef TIME_BOMB
|
|
#include "..\..\inc\timebomb.c"
|
|
#endif
|
|
|
|
#if DBG
|
|
LONG MSDVCRMutextUseCount = 0;
|
|
#endif
|
|
|
|
|
|
// global flag for debugging. Inlines are defined in dbg.h. The debug level is set for
|
|
// minimal amount of messages.
|
|
#if DBG
|
|
|
|
#define TraceMaskCheckIn TL_PNP_ERROR | TL_STRM_ERROR
|
|
|
|
#define TraceMaskDefault 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 TraceMaskDebug 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
|
|
|
|
|
|
ULONG TapeTraceMask = TraceMaskCheckIn;
|
|
ULONG TapeAssertLevel = 1;
|
|
|
|
#endif
|
|
|
|
|
|
extern AVCSTRM_FORMAT_INFO AVCStrmFormatInfoTable[];
|
|
|
|
//
|
|
// 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
|
|
);
|
|
BOOL
|
|
DVSignalEOStream(
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb,
|
|
IN PSTREAMEX pStrmExt,
|
|
IN FMT_INDEX ulVideoFormatIndex,
|
|
IN ULONG ulOptionFlags
|
|
);
|
|
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, AVCTapeRcvControlPacket)
|
|
#pragma alloc_text(PAGE, AVCTapeRcvDataPacket)
|
|
// #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,("StreamDevicePacket: 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 =
|
|
AVCTapeInitialize(
|
|
(PDVCR_EXTENSION) ((PPORT_CONFIGURATION_INFORMATION)pSrb->CommandData.ConfigInfo)->HwDeviceExtension,
|
|
pSrb->CommandData.ConfigInfo,
|
|
pAVReq
|
|
);
|
|
break;
|
|
|
|
|
|
|
|
case SRB_INITIALIZATION_COMPLETE:
|
|
|
|
//
|
|
// Stream class has finished initialization.
|
|
// Now create DShow Medium interface BLOBs.
|
|
// This needs to be done at low priority since it uses the registry, so use a callback
|
|
//
|
|
pSrb->Status =
|
|
AVCTapeInitializeCompleted(
|
|
pDevExt
|
|
);
|
|
break;
|
|
|
|
|
|
case SRB_GET_STREAM_INFO:
|
|
|
|
//
|
|
// this is a request for the driver to enumerate requested streams
|
|
//
|
|
pSrb->Status =
|
|
AVCTapeGetStreamInfo(
|
|
pDevExt,
|
|
pSrb->NumberOfBytesToTransfer,
|
|
&pSrb->CommandData.StreamBuffer->StreamHeader,
|
|
&pSrb->CommandData.StreamBuffer->StreamInfo
|
|
);
|
|
break;
|
|
|
|
|
|
|
|
case SRB_GET_DATA_INTERSECTION:
|
|
|
|
pSrb->Status =
|
|
AVCTapeGetDataIntersection(
|
|
pDevExt->NumOfPins,
|
|
pSrb->CommandData.IntersectInfo->StreamNumber,
|
|
pSrb->CommandData.IntersectInfo->DataRange,
|
|
pSrb->CommandData.IntersectInfo->DataFormatBuffer,
|
|
pSrb->CommandData.IntersectInfo->SizeOfDataFormatBuffer,
|
|
AVCStrmFormatInfoTable[pDevExt->VideoFormatIndex].FrameSize,
|
|
&pSrb->ActualBytesTransferred,
|
|
pDevExt->pStreamInfoObject
|
|
#ifdef SUPPORT_NEW_AVC
|
|
,
|
|
pDevExt->hPlugLocalOut,
|
|
pDevExt->hPlugLocalIn
|
|
#endif
|
|
);
|
|
break;
|
|
|
|
|
|
|
|
case SRB_OPEN_STREAM:
|
|
|
|
//
|
|
// Serialize SRB_OPEN_STREAMs
|
|
//
|
|
|
|
KeWaitForMutexObject(&pDevExt->hMutex, Executive, KernelMode, FALSE, NULL);
|
|
|
|
pSrb->Status =
|
|
AVCTapeOpenStream(
|
|
pSrb->StreamObject,
|
|
pSrb->CommandData.OpenFormat,
|
|
pAVReq
|
|
);
|
|
|
|
KeReleaseMutex(&pDevExt->hMutex, FALSE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SRB_CLOSE_STREAM:
|
|
|
|
KeWaitForMutexObject(&pDevExt->hMutex, Executive, KernelMode, FALSE, NULL);
|
|
pSrb->Status =
|
|
AVCTapeCloseStream(
|
|
pSrb->StreamObject,
|
|
pSrb->CommandData.OpenFormat,
|
|
pAVReq
|
|
);
|
|
KeReleaseMutex(&pDevExt->hMutex, FALSE);
|
|
break;
|
|
|
|
|
|
|
|
case SRB_GET_DEVICE_PROPERTY:
|
|
|
|
pSrb->Status =
|
|
AVCTapeGetDeviceProperty(
|
|
pDevExt,
|
|
pSrb->CommandData.PropertyInfo,
|
|
&pSrb->ActualBytesTransferred
|
|
);
|
|
break;
|
|
|
|
|
|
case SRB_SET_DEVICE_PROPERTY:
|
|
|
|
pSrb->Status =
|
|
AVCTapeSetDeviceProperty(
|
|
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 Supported POWER_STATE MinorFunc:%d\n", pIrpStack->MinorFunction));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED; // STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
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) {
|
|
|
|
AVCTapeProcessPnPBusReset(
|
|
pDevExt
|
|
);
|
|
|
|
// Always success
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
TRACE(TL_PNP_TRACE,("StreamDevicePacket: NOT_IMPL; IRP_MJ_PNP Min:%x\n",
|
|
pIrpStack->MinorFunction
|
|
));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED; // SUPPORTED;
|
|
}
|
|
}
|
|
else
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED; // SUPPORTED;
|
|
break;
|
|
|
|
|
|
case SRB_SURPRISE_REMOVAL:
|
|
|
|
TRACE(TL_PNP_WARNING,("#SURPRISE_REMOVAL# pSrb %x, pDevExt %x\n", pSrb, pDevExt));
|
|
pSrb->Status =
|
|
AVCTapeSurpriseRemoval(
|
|
pDevExt,
|
|
pAVReq
|
|
);
|
|
break;
|
|
|
|
|
|
|
|
case SRB_UNINITIALIZE_DEVICE:
|
|
|
|
TRACE(TL_PNP_WARNING,("#UNINITIALIZE_DEVICE# pSrb %x, pDevExt %x\n", pSrb, pDevExt));
|
|
pSrb->Status =
|
|
AVCTapeUninitialize(
|
|
(PDVCR_EXTENSION) pSrb->HwDeviceExtension
|
|
);
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
TRACE(TL_PNP_WARNING,("StreamDevicePacket: Unknown or unprocessed SRB cmd %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;
|
|
}
|
|
|
|
//
|
|
// 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
|
|
) {
|
|
TRACE(TL_PNP_WARNING,("StreamDevicePacket:pSrb->Command(0x%x) does not return STATUS_SUCCESS or NOT_IMPLEMENTED but 0x%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
|
|
TRACE(TL_PNP_WARNING,("ReceiveDevicePacket:Pending pSrb %x\n", pSrb));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AVCTapeRcvControlPacket(
|
|
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 =
|
|
AVCTapeGetStreamState(
|
|
pStrmExt,
|
|
pDevExt->pBusDeviceObject,
|
|
&(pSrb->CommandData.StreamState),
|
|
&(pSrb->ActualBytesTransferred)
|
|
);
|
|
break;
|
|
|
|
case SRB_SET_STREAM_STATE:
|
|
|
|
pSrb->Status =
|
|
AVCTapeSetStreamState(
|
|
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 =
|
|
AVCTapeOpenCloseMasterClock(
|
|
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 =
|
|
AVCTapeIndicateMasterClock(
|
|
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.
|
|
//
|
|
|
|
if(!AVCTapeVerifyDataFormat(
|
|
pDevExt->NumOfPins,
|
|
pSrb->CommandData.OpenFormat,
|
|
pSrb->StreamObject->StreamNumber,
|
|
AVCStrmFormatInfoTable[pDevExt->VideoFormatIndex].FrameSize,
|
|
pDevExt->pStreamInfoObject
|
|
)) {
|
|
TRACE(TL_PNP_WARNING,("RcvControlPacket: AdapterVerifyFormat failed.\n"));
|
|
pSrb->Status = STATUS_NO_MATCH;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// invalid / unsupported command. Fail it as such
|
|
//
|
|
TRACE(TL_PNP_WARNING,("RcvControlPacket: unknown cmd = %x\n",pSrb->Command));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
TRACE(TL_PNP_TRACE,("RcvControlPacket: pSrb:%x, Command %x, ->Status %x, ->CommandData %x\n",
|
|
pSrb, pSrb->Command, pSrb->Status, &(pSrb->CommandData.StreamState) ));
|
|
|
|
StreamClassStreamNotification(
|
|
StreamRequestComplete,
|
|
pSrb->StreamObject,
|
|
pSrb);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AVCTapeRcvDataPacket(
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called with video data packet commands
|
|
|
|
--*/
|
|
|
|
{
|
|
PSTREAMEX pStrmExt;
|
|
PDVCR_EXTENSION pDevExt;
|
|
PAVC_STREAM_REQUEST_BLOCK pAVCStrmReq;
|
|
PIRP pIrpReq;
|
|
PIO_STACK_LOCATION NextIrpStack;
|
|
NTSTATUS Status;
|
|
PDRIVER_REQUEST pDriverReq;
|
|
KIRQL oldIrql;
|
|
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
pStrmExt = (PSTREAMEX) pSrb->StreamObject->HwStreamExtension;
|
|
pDevExt = (PDVCR_EXTENSION) pSrb->HwDeviceExtension;
|
|
|
|
#if DBG
|
|
if(pDevExt->PowerState != PowerDeviceD0) {
|
|
TRACE(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_TRACE,("RcvDataPacket: 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;
|
|
}
|
|
|
|
|
|
TRACE(TL_PNP_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,
|
|
AVCStrmFormatInfoTable[pDevExt->VideoFormatIndex].FrameSize
|
|
));
|
|
|
|
// If we has asked to stopped, we should not receive data request.
|
|
ASSERT(pStrmExt->StreamState != KSSTATE_STOP);
|
|
|
|
//
|
|
// determine the type of packet.
|
|
//
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
switch (pSrb->Command) {
|
|
|
|
|
|
case SRB_WRITE_DATA:
|
|
|
|
// ********************************
|
|
// Take care of some special cases:
|
|
// ********************************
|
|
|
|
// Can signal this when the last is transmitted or sigal it immediately like
|
|
// what is done here.
|
|
if(pSrb->CommandData.DataBufferArray->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_ENDOFSTREAM) {
|
|
// Optional, wait a fix time and can be signalled when the last one has returned.
|
|
// And then signal the completion.
|
|
|
|
TRACE(TL_STRM_WARNING,("RcvDataPacket: EndOfStream is signalled!\n"));
|
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Send this flag down to AVCStrm.sys so it will wait until
|
|
// all attach buffers are completed.
|
|
//
|
|
|
|
} else if (pSrb->CommandData.DataBufferArray->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TYPECHANGED) {
|
|
TRACE(TL_PNP_WARNING,("RcvDataPacket: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;
|
|
}
|
|
|
|
case SRB_READ_DATA:
|
|
|
|
//
|
|
// If removed, cancel the request with STATUS_DEVICE_REMOVED.
|
|
// (apply to both SRB_READ_DATA and SRB_WRITE_DATA)
|
|
//
|
|
if(pDevExt->bDevRemoved) {
|
|
TRACE(TL_STRM_WARNING,("SRB_READ/WRITE; DevRemoved!\n", pSrb));
|
|
pSrb->Status = STATUS_DEVICE_REMOVED;
|
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// A true data request must has a MdlAddress unless it is a know
|
|
// optional flag.
|
|
//
|
|
if(pSrb->Irp->MdlAddress == NULL) {
|
|
if((pSrb->CommandData.DataBufferArray->OptionsFlags &
|
|
(KSSTREAM_HEADER_OPTIONSF_ENDOFSTREAM | KSSTREAM_HEADER_OPTIONSF_TYPECHANGED) )) {
|
|
//
|
|
// Known optional flags
|
|
//
|
|
} else {
|
|
TRACE(TL_STRM_ERROR,("pSrb:%x, unknown OptionsFlags:%x\n",pSrb, pSrb->CommandData.DataBufferArray->OptionsFlags));
|
|
ASSERT(pSrb->Irp->MdlAddress);
|
|
break;
|
|
|
|
//
|
|
// We do not know how to handle this option flag so we will quit on this data request.
|
|
//
|
|
}
|
|
}
|
|
|
|
//
|
|
// Serialize with setting state
|
|
//
|
|
EnterAVCStrm(pStrmExt->hMutexReq);
|
|
|
|
//
|
|
// Get a context to send this request down
|
|
//
|
|
KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
|
|
|
|
pStrmExt->cntSRBReceived++;
|
|
|
|
if(IsListEmpty(&pStrmExt->DataDetachedListHead)) {
|
|
TRACE(TL_STRM_ERROR,("**** DataDetachList is empty! ****\n"));
|
|
ASSERT(!IsListEmpty(&pStrmExt->DataDetachedListHead));
|
|
|
|
//
|
|
// Note: The alternative to the failure is to expand the pre-allocated list.
|
|
//
|
|
|
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
|
LeaveAVCStrm(pStrmExt->hMutexReq);
|
|
pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
break;
|
|
} else {
|
|
|
|
pDriverReq = (PDRIVER_REQUEST) RemoveHeadList(&pStrmExt->DataDetachedListHead); pStrmExt->cntDataDetached--;
|
|
#if DBG
|
|
pDriverReq->cntDataRequestReceived = pStrmExt->cntSRBReceived; // For verification
|
|
#endif
|
|
InsertTailList(&pStrmExt->DataAttachedListHead, &pDriverReq->ListEntry); pStrmExt->cntDataAttached++;
|
|
|
|
pAVCStrmReq = &pDriverReq->AVCStrmReq;
|
|
pIrpReq = pDriverReq->pIrp;
|
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
|
}
|
|
|
|
RtlZeroMemory(pAVCStrmReq, sizeof(AVC_STREAM_REQUEST_BLOCK));
|
|
INIT_AVCSTRM_HEADER(pAVCStrmReq, (pSrb->Command == SRB_READ_DATA) ? AVCSTRM_READ : AVCSTRM_WRITE);
|
|
pAVCStrmReq->AVCStreamContext = pStrmExt->AVCStreamContext;
|
|
// Need these context when this IRP is completed.
|
|
pDriverReq->Context1 = (PVOID) pSrb;
|
|
pDriverReq->Context2 = (PVOID) pStrmExt;
|
|
|
|
// We are the clock provide if hMasterClock is not NULL.
|
|
pAVCStrmReq->CommandData.BufferStruct.ClockProvider = (pStrmExt->hMasterClock != NULL);
|
|
pAVCStrmReq->CommandData.BufferStruct.ClockHandle = pStrmExt->hClock; // Used only if !ClockProvider
|
|
|
|
pAVCStrmReq->CommandData.BufferStruct.StreamHeader = pSrb->CommandData.DataBufferArray;
|
|
|
|
//
|
|
// This could be a data or just flag that need to be processed.
|
|
// Get its system address only if there is an MdlAddress.
|
|
//
|
|
if(pSrb->Irp->MdlAddress) {
|
|
|
|
pAVCStrmReq->CommandData.BufferStruct.FrameBuffer =
|
|
#ifdef USE_WDM110 // Win2000, XP
|
|
MmGetSystemAddressForMdlSafe(pSrb->Irp->MdlAddress, NormalPagePriority);
|
|
if(!pAVCStrmReq->CommandData.BufferStruct.FrameBuffer) {
|
|
|
|
//
|
|
// Reclaim the data entry from attach (busy) to detach (free)
|
|
//
|
|
KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
|
|
RemoveEntryList(&pDriverReq->ListEntry); pStrmExt->cntDataAttached--;
|
|
InsertHeadList(&pStrmExt->DataAttachedListHead, &pDriverReq->ListEntry); pStrmExt->cntDataAttached++;
|
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
|
|
|
pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
ASSERT(pAVCStrmReq->CommandData.BufferStruct.FrameBuffer);
|
|
break;
|
|
}
|
|
#else // Win9x
|
|
MmGetSystemAddressForMdl (pSrb->Irp->MdlAddress);
|
|
#endif
|
|
}
|
|
|
|
// This is a Async command
|
|
NextIrpStack = IoGetNextIrpStackLocation(pIrpReq);
|
|
NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_AVCSTRM_CLASS;
|
|
NextIrpStack->Parameters.Others.Argument1 = pAVCStrmReq;
|
|
|
|
// Not cancellable!
|
|
IoSetCancelRoutine(
|
|
pIrpReq,
|
|
NULL
|
|
);
|
|
|
|
IoSetCompletionRoutine(
|
|
pIrpReq,
|
|
AVCTapeReqReadDataCR,
|
|
pDriverReq,
|
|
TRUE, // Success
|
|
TRUE, // Error
|
|
TRUE // or Cancel
|
|
);
|
|
|
|
pSrb->Status = STATUS_PENDING;
|
|
pStrmExt->cntDataSubmitted++;
|
|
|
|
Status =
|
|
IoCallDriver(
|
|
pDevExt->pBusDeviceObject,
|
|
pIrpReq
|
|
);
|
|
|
|
LeaveAVCStrm(pStrmExt->hMutexReq);
|
|
|
|
if(Status == STATUS_PENDING) {
|
|
// Normal case.
|
|
return; // Will complete asychronousely (Success, Error, or Cancel)
|
|
} else {
|
|
//
|
|
// Complete the data request synchronousely (no pending)
|
|
//
|
|
if(pDriverReq->Context1 == NULL || pDriverReq->Context2 == NULL) {
|
|
TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("pSrb:%x; SRB_READ_DATA/WRITE IRP completed with Status;%x\n", pSrb, Status));
|
|
return;
|
|
} else {
|
|
TRACE(TL_STRM_WARNING,("AVCSTRM_READ/WRITE: pSrb %x; failed or completed with ST:%x; pAVCStrmReq:%x\n", pSrb, Status, pAVCStrmReq));
|
|
ASSERT(FALSE);
|
|
// Complete the SRB if not pending
|
|
pSrb->Status = pDevExt->bDevRemoved ? STATUS_DEVICE_REMOVED : STATUS_UNSUCCESSFUL;
|
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// invalid / unsupported command. Fail it as such
|
|
//
|
|
pSrb->Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
|
|
ASSERT(pSrb->Status != STATUS_PENDING);
|
|
|
|
// Finally, send the srb back up ...
|
|
StreamClassStreamNotification(
|
|
StreamRequestComplete,
|
|
pSrb->StreamObject,
|
|
pSrb );
|
|
}
|
|
|
|
|
|
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,("<<<<<<< MSTape.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,("TapeTraceMask=0x%.8x = 0x[7][6][5][4][3][2][1][0] where\n", TapeTraceMask));
|
|
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 mstape!TapeTraceMask L1\n"));
|
|
TRACE(TL_PNP_ERROR,("e mstape!TapeTraceMask <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 = DVCRCancelOnePacket;
|
|
HwInitData.DeviceExtensionSize = sizeof(DVCR_EXTENSION) +
|
|
sizeof(AVC_DEV_PLUGS) * 2;
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
|