2678 lines
78 KiB
C
2678 lines
78 KiB
C
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1999 - 2000
|
|
|
|
Module Name:
|
|
|
|
MSDVUtil.c
|
|
|
|
Abstract:
|
|
|
|
Provide utility functions for MSDV.
|
|
|
|
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 "MsdvAvc.h"
|
|
#include "MsdvUtil.h"
|
|
|
|
#include "XPrtDefs.h"
|
|
|
|
#if 0 // Enable later
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, DVDelayExecutionThread)
|
|
#pragma alloc_text(PAGE, DVGetUnitCapabilities)
|
|
// Local variables might paged out but the called might use it in DISPATCH level!
|
|
// #pragma alloc_text(PAGE, DVGetDevModeOfOperation)
|
|
// #pragma alloc_text(PAGE, DVGetDevIsItDVCPro)
|
|
// #pragma alloc_text(PAGE, DVGetDevSignalFormat)
|
|
#pragma alloc_text(PAGE, DvAllocatePCResource)
|
|
#pragma alloc_text(PAGE, DvFreePCResource)
|
|
#pragma alloc_text(PAGE, DVGetPlugState)
|
|
#pragma alloc_text(PAGE, DVConnect)
|
|
#pragma alloc_text(PAGE, DVDisconnect)
|
|
#endif
|
|
#endif
|
|
|
|
extern DV_FORMAT_INFO DVFormatInfoTable[];
|
|
|
|
VOID
|
|
DVDelayExecutionThread(
|
|
ULONG ulDelayMSec
|
|
)
|
|
/*
|
|
Device might need a "wait" in between AV/C commands.
|
|
*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (ulDelayMSec)
|
|
{
|
|
LARGE_INTEGER tmDelay;
|
|
|
|
TRACE(TL_PNP_TRACE,("\'DelayExeThrd: %d MSec\n", ulDelayMSec));
|
|
|
|
tmDelay.LowPart = (ULONG) (-1 * ulDelayMSec * 10000);
|
|
tmDelay.HighPart = -1;
|
|
KeDelayExecutionThread(KernelMode, FALSE, &tmDelay);
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DVIrpSynchCR(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP pIrp,
|
|
IN PKEVENT Event
|
|
)
|
|
{
|
|
KeSetEvent(Event, 0, FALSE);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
} // DVIrpSynchCR
|
|
|
|
|
|
NTSTATUS
|
|
DVSubmitIrpSynch(
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
IN PIRP pIrp,
|
|
IN PAV_61883_REQUEST pAVReq
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
KEVENT Event;
|
|
PIO_STACK_LOCATION NextIrpStack;
|
|
|
|
|
|
Status = STATUS_SUCCESS;;
|
|
|
|
NextIrpStack = IoGetNextIrpStackLocation(pIrp);
|
|
NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_61883_CLASS;
|
|
NextIrpStack->Parameters.Others.Argument1 = pAVReq;
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
IoSetCompletionRoutine(
|
|
pIrp,
|
|
DVIrpSynchCR,
|
|
&Event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
Status =
|
|
IoCallDriver(
|
|
pDevExt->pBusDeviceObject,
|
|
pIrp
|
|
);
|
|
|
|
if (Status == STATUS_PENDING) {
|
|
|
|
TRACE(TL_PNP_TRACE,("\'Irp is pending...\n"));
|
|
|
|
if(KeGetCurrentIrql() < DISPATCH_LEVEL) {
|
|
KeWaitForSingleObject(
|
|
&Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
TRACE(TL_PNP_TRACE,("\'Irp has returned; IoStatus==Status %x\n", pIrp->IoStatus.Status));
|
|
Status = pIrp->IoStatus.Status; // Final status
|
|
|
|
}
|
|
else {
|
|
ASSERT(FALSE && "Pending but in DISPATCH_LEVEL!");
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
} // DVSubmitIrpSynchAV
|
|
|
|
|
|
|
|
BOOL
|
|
DVGetDevModeOfOperation(
|
|
IN PDVCR_EXTENSION pDevExt
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
BYTE bAvcBuf[MAX_FCP_PAYLOAD_SIZE];
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Use ConnectAV STATUS cmd to determine mode of operation,
|
|
// except for some Canon DVs that it requires its vendor specific command
|
|
//
|
|
|
|
Status =
|
|
DVIssueAVCCommand(
|
|
pDevExt,
|
|
AVC_CTYPE_STATUS,
|
|
DV_CONNECT_AV_MODE,
|
|
(PVOID) bAvcBuf
|
|
);
|
|
|
|
TRACE(TL_FCP_TRACE,("\'DV_CONNECT_AV_MODE: St:%x, %x %x %x %x : %x %x %x %x\n",
|
|
Status, bAvcBuf[0], bAvcBuf[1], bAvcBuf[2], bAvcBuf[3], bAvcBuf[4], bAvcBuf[5], bAvcBuf[6], bAvcBuf[7]));
|
|
|
|
if(Status == STATUS_SUCCESS) {
|
|
if(bAvcBuf[0] == 0x0c) {
|
|
if(bAvcBuf[1] == 0x00 &&
|
|
bAvcBuf[2] == 0x38 &&
|
|
bAvcBuf[3] == 0x38) {
|
|
pDevExt->ulDevType = ED_DEVTYPE_CAMERA;
|
|
} else {
|
|
pDevExt->ulDevType = ED_DEVTYPE_VCR;
|
|
}
|
|
}
|
|
} else if(pDevExt->ulVendorID == VENDORID_CANON) {
|
|
// Try a vendor dependent command if it is a Canon AV device.
|
|
Status =
|
|
DVIssueAVCCommand(
|
|
pDevExt,
|
|
AVC_CTYPE_STATUS,
|
|
DV_VEN_DEP_CANON_MODE,
|
|
(PVOID) bAvcBuf
|
|
);
|
|
|
|
TRACE(TL_FCP_WARNING,("\'DV_VEN_DEP_CANON_MODE: Status %x, %x %x %x %x : %x %x %x %x %x %x\n",
|
|
Status, bAvcBuf[0], bAvcBuf[1], bAvcBuf[2], bAvcBuf[3], bAvcBuf[4], bAvcBuf[5], bAvcBuf[6], bAvcBuf[7], bAvcBuf[8], bAvcBuf[9]));
|
|
|
|
if(Status == STATUS_SUCCESS) {
|
|
if(bAvcBuf[0] == 0x0c) {
|
|
if(bAvcBuf[7] == 0x38) {
|
|
pDevExt->ulDevType = ED_DEVTYPE_CAMERA;
|
|
} else
|
|
if(bAvcBuf[7] == 0x20) {
|
|
pDevExt->ulDevType = ED_DEVTYPE_VCR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(Status != STATUS_SUCCESS) {
|
|
pDevExt->ulDevType = ED_DEVTYPE_UNKNOWN;
|
|
TRACE(TL_FCP_ERROR,("\'DV_CONNECT_AV_MODE: Status %x, DevType %x, %x %x %x %x : %x %x %x %x : %x %x\n",
|
|
Status, pDevExt->ulDevType, bAvcBuf[0], bAvcBuf[1], bAvcBuf[2], bAvcBuf[3], bAvcBuf[4], bAvcBuf[5], bAvcBuf[6], bAvcBuf[7], bAvcBuf[8], bAvcBuf[9]));
|
|
}
|
|
|
|
TRACE(TL_FCP_WARNING,("\'%s; NumOPlg:%d; NumIPlg:%d\n",
|
|
pDevExt->ulDevType == ED_DEVTYPE_CAMERA ? "Camera" : pDevExt->ulDevType == ED_DEVTYPE_VCR ? "VTR" : "Unknown",
|
|
pDevExt->NumOutputPlugs, pDevExt->NumInputPlugs));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
DVGetDevIsItDVCPro(
|
|
IN PDVCR_EXTENSION pDevExt
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
BYTE bAvcBuf[MAX_FCP_PAYLOAD_SIZE];
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Use Panasnoic's vendor dependent command to determine if the system support DVCPro
|
|
//
|
|
|
|
Status =
|
|
DVIssueAVCCommand(
|
|
pDevExt,
|
|
AVC_CTYPE_STATUS,
|
|
DV_VEN_DEP_DVCPRO,
|
|
(PVOID) bAvcBuf
|
|
);
|
|
|
|
pDevExt->bDVCPro = Status == STATUS_SUCCESS;
|
|
|
|
TRACE(TL_FCP_WARNING,("\'DVGetDevIsItDVCPro? %s; Status %x, %x %x %x %x : %x %x %x %x\n",
|
|
pDevExt->bDVCPro ? "Yes":"No",
|
|
Status, bAvcBuf[0], bAvcBuf[1], bAvcBuf[2], bAvcBuf[3], bAvcBuf[4], bAvcBuf[5], bAvcBuf[6], bAvcBuf[7]));
|
|
|
|
return pDevExt->bDVCPro;
|
|
}
|
|
|
|
|
|
// The retries might be redundant since AVC.sys and 1394.sys retries.
|
|
// For device that TIMEOUT an AVC command, we will only try it once.
|
|
#define GET_MEDIA_FMT_MAX_RETRIES 10
|
|
|
|
BOOL
|
|
DVGetDevSignalFormat(
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
IN KSPIN_DATAFLOW DataFlow,
|
|
IN PSTREAMEX pStrmExt
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
BYTE bAvcBuf[MAX_FCP_PAYLOAD_SIZE];
|
|
LONG lRetries = GET_MEDIA_FMT_MAX_RETRIES;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Respone of Input/output signal mode is used to determine plug signal format:
|
|
//
|
|
// FMT:
|
|
// DVCR 10:00 0000 = 0x80; Canon returns 00:100000 (0x20)
|
|
// 50/60: 0:NTSC/60; 1:PAL/50
|
|
// STYPE:
|
|
// SD: 00000 (DVCPRO:11110)
|
|
// HD: 00010
|
|
// SDL:00001
|
|
// 00:
|
|
// SYT:
|
|
// MPEG 10:10 0000 = 0xa0
|
|
// TSF:0:NotTimeShifted; 1:Time shifted
|
|
// 000 0000 0000 0000 0000 0000
|
|
//
|
|
// If this command failed, we can use Input/Output Signal Mode subunit command
|
|
// to determine signal format.
|
|
//
|
|
|
|
do {
|
|
RtlZeroMemory(bAvcBuf, sizeof(bAvcBuf));
|
|
Status =
|
|
DVIssueAVCCommand(
|
|
pDevExt,
|
|
AVC_CTYPE_STATUS,
|
|
pStrmExt == NULL ? DV_OUT_PLUG_SIGNAL_FMT : (DataFlow == KSPIN_DATAFLOW_OUT ? DV_OUT_PLUG_SIGNAL_FMT : DV_IN_PLUG_SIGNAL_FMT),
|
|
(PVOID) bAvcBuf
|
|
);
|
|
|
|
//
|
|
// Camcorders that has problem with this command:
|
|
//
|
|
// Panasonic's DVCPRO: if power on while connected to PC, it will
|
|
// reject this command with (STATUS_REQUEST_NOT_ACCEPTED)
|
|
// so we will retry up to 10 time with .5 second wait between tries.
|
|
//
|
|
// JVC: returns STATUS_NOT_SUPPORTED.
|
|
//
|
|
// SONY DV Decoder Box: return STATUS_TIMEOUT or STATUS_REQUEST_ABORTED
|
|
//
|
|
|
|
if(STATUS_REQUEST_ABORTED == Status)
|
|
return FALSE;
|
|
else if(STATUS_SUCCESS == Status)
|
|
break; // Normal case.
|
|
else if(STATUS_NOT_SUPPORTED == Status || STATUS_TIMEOUT == Status) {
|
|
TRACE(TL_FCP_WARNING | TL_PNP_WARNING,("SignalFormat: Encountered a known failed status:%x; no more retry\n", Status));
|
|
break; // No need to retry
|
|
} else {
|
|
if(Status == STATUS_REQUEST_NOT_ACCEPTED) {
|
|
// If device is not accepting command and return this status, retry.
|
|
if(lRetries > 0) {
|
|
TRACE(TL_FCP_WARNING | TL_PNP_WARNING,("\'ST:%x; Retry getting signal mode; wait...\n", Status));
|
|
DVDelayExecutionThread(DV_AVC_CMD_DELAY_DVCPRO);
|
|
}
|
|
}
|
|
}
|
|
|
|
} while (--lRetries >= 0);
|
|
|
|
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
switch(bAvcBuf[0]) {
|
|
|
|
case FMT_DVCR:
|
|
case FMT_DVCR_CANON: // Workaround for buggy Canon Camcorders
|
|
switch(bAvcBuf[1] & FDF0_STYPE_MASK) {
|
|
case FDF0_STYPE_SD_DVCR:
|
|
case FDF0_STYPE_SD_DVCPRO:
|
|
pDevExt->VideoFormatIndex = ((bAvcBuf[1] & FDF0_50_60_MASK) ? FMT_IDX_SD_DVCR_PAL : FMT_IDX_SD_DVCR_NTSC);
|
|
if(pStrmExt)
|
|
RtlCopyMemory(&pStrmExt->cipQuad2[0], &bAvcBuf[0], 4);
|
|
break;
|
|
#ifdef MSDV_SUPPORT_HD_DVCR
|
|
case FDF0_STYPE_HD_DVCR:
|
|
pDevExt->VideoFormatIndex = ((bAvcBuf[1] & FDF0_50_60_MASK) ? FMT_IDX_HD_DVCR_PAL : FMT_IDX_HD_DVCR_NTSC);
|
|
if(pStrmExt)
|
|
RtlCopyMemory(&pStrmExt->cipQuad2[0], &bAvcBuf[0], 4);
|
|
break;
|
|
#endif
|
|
#ifdef MSDV_SUPPORT_SDL_DVCR
|
|
case FDF0_STYPE_SDL_DVCR:
|
|
pDevExt->VideoFormatIndex = ((bAvcBuf[1] & FDF0_50_60_MASK) ? FMT_IDX_SDL_DVCR_PAL : FMT_IDX_SDL_DVCR_NTSC);
|
|
if(pStrmExt)
|
|
RtlCopyMemory(&pStrmExt->cipQuad2[0], &bAvcBuf[0], 4);
|
|
break;
|
|
#endif
|
|
default: // Unknown format
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
break;
|
|
#ifdef MSDV_SUPPORT_MPEG2TS
|
|
case FMT_MPEG:
|
|
pDevExt->VideoFormatIndex = FMT_IDX_MPEG2TS;
|
|
if(pStrmExt)
|
|
RtlCopyMemory(&pStrmExt->cipQuad2[0], &bAvcBuf[0], 4);
|
|
break;
|
|
#endif
|
|
default:
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
TRACE(TL_FCP_WARNING,("\'ST:%x; PlugSignal:FMT[%x %x %x %x]; VideoFormatIndex;%d\n", Status, bAvcBuf[0], bAvcBuf[1], bAvcBuf[2] , bAvcBuf[3], pDevExt->VideoFormatIndex));
|
|
return TRUE; // Success
|
|
}
|
|
}
|
|
TRACE(TL_FCP_WARNING,("\'ST:%x; PlugSignal:FMT[%x %x %x %x]\n", Status, bAvcBuf[0], bAvcBuf[1], bAvcBuf[2] , bAvcBuf[3], pDevExt->VideoFormatIndex));
|
|
|
|
//
|
|
// If "recommended" unit input/output plug signal status command fails,
|
|
// try "manadatory" input/output signal mode status command.
|
|
// This command may failed some device if its tape is not playing for
|
|
// output signal mode command.
|
|
//
|
|
|
|
Status =
|
|
DVIssueAVCCommand(
|
|
pDevExt,
|
|
AVC_CTYPE_STATUS,
|
|
DataFlow == KSPIN_DATAFLOW_OUT ? VCR_OUTPUT_SIGNAL_MODE : VCR_INPUT_SIGNAL_MODE,
|
|
(PVOID) bAvcBuf
|
|
);
|
|
|
|
if(STATUS_SUCCESS == Status) {
|
|
|
|
PKSPROPERTY_EXTXPORT_S pXPrtProperty;
|
|
|
|
pXPrtProperty = (PKSPROPERTY_EXTXPORT_S) bAvcBuf;
|
|
TRACE(TL_FCP_WARNING,("\'** MediaFormat: Retry %d mSec; ST:%x; SignalMode:%dL\n",
|
|
(GET_MEDIA_FMT_MAX_RETRIES - lRetries) * DV_AVC_CMD_DELAY_DVCPRO, Status, pXPrtProperty->u.SignalMode - ED_BASE));
|
|
|
|
switch(pXPrtProperty->u.SignalMode) {
|
|
case ED_TRANSBASIC_SIGNAL_525_60_SD:
|
|
pDevExt->VideoFormatIndex = FMT_IDX_SD_DVCR_NTSC;
|
|
if(pStrmExt) {
|
|
pStrmExt->cipQuad2[0] = FMT_DVCR; // 0x80
|
|
if(pDevExt->bDVCPro)
|
|
pStrmExt->cipQuad2[1] = FDF0_50_60_NTSC | FDF0_STYPE_SD_DVCPRO; // 0x78 = NTSC(0):STYPE(11110):RSV(00)
|
|
else
|
|
pStrmExt->cipQuad2[1] = FDF0_50_60_NTSC | FDF0_STYPE_SD_DVCR; // 0x00 = NTSC(0):STYPE(00000):RSV(00)
|
|
}
|
|
break;
|
|
case ED_TRANSBASIC_SIGNAL_625_50_SD:
|
|
pDevExt->VideoFormatIndex = FMT_IDX_SD_DVCR_PAL;
|
|
if(pStrmExt) {
|
|
pStrmExt->cipQuad2[0] = FMT_DVCR; // 0x80
|
|
if(pDevExt->bDVCPro)
|
|
pStrmExt->cipQuad2[1] = FDF0_50_60_PAL | FDF0_STYPE_SD_DVCPRO; // 0xf8 = PAL(1):STYPE(11110):RSV(00)
|
|
else
|
|
pStrmExt->cipQuad2[1] = FDF0_50_60_PAL | FDF0_STYPE_SD_DVCR; // 0x80 = PAL(1):STYPE(00000):RSV(00)
|
|
}
|
|
break;
|
|
#ifdef MSDV_SUPPORT_SDL_DVCR
|
|
case ED_TRANSBASIC_SIGNAL_525_60_SDL:
|
|
pDevExt->VideoFormatIndex = FMT_IDX_SDL_DVCR_NTSC;
|
|
if(pStrmExt) {
|
|
pStrmExt->cipQuad2[0] = FMT_DVCR; // 0x80
|
|
pStrmExt->cipQuad2[1] = FDF0_50_60_NTSC | FDF0_STYPE_SDL_DVCR;
|
|
}
|
|
break;
|
|
case ED_TRANSBASIC_SIGNAL_625_50_SDL:
|
|
pDevExt->VideoFormatIndex = FMT_IDX_SDL_DVCR_PAL;
|
|
if(pStrmExt) {
|
|
pStrmExt->cipQuad2[0] = FMT_DVCR; // 0x80
|
|
pStrmExt->cipQuad2[1] = FDF0_50_60_PAL | FDF0_STYPE_SDL_DVCR;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
TRACE(TL_FCP_ERROR,("\'Unsupported SignalMode:%dL", pXPrtProperty->u.SignalMode - ED_BASE));
|
|
ASSERT(FALSE && "Unsupported IoSignal! Refuse to load.");
|
|
return FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// WORKITEM Sony HW CODEC does not response to any AVC command.
|
|
// We are making an exception here to load it.
|
|
if(Status == STATUS_TIMEOUT) {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
// We must know the signal format!! If this failed, the driver will either:
|
|
// fail to load, or fail to open an stream
|
|
ASSERT(Status == STATUS_SUCCESS && "Failed to get media signal format!\n");
|
|
|
|
#if DBG
|
|
if(pStrmExt) {
|
|
// Note: bAvcBuf[0] is operand[1] == 10:fmt
|
|
TRACE(TL_FCP_WARNING,("\'** MediaFormat: St:%x; idx:%d; CIP:[FMT:%.2x(%s); FDF:[%.2x(%s,%s):SYT]\n",
|
|
Status,
|
|
pDevExt->VideoFormatIndex,
|
|
pStrmExt->cipQuad2[0],
|
|
pStrmExt->cipQuad2[0] == FMT_DVCR ? "DVCR" : pStrmExt->cipQuad2[0] == FMT_MPEG ? "MPEG" : "Fmt:???",
|
|
pStrmExt->cipQuad2[1],
|
|
(pStrmExt->cipQuad2[1] & FDF0_50_60_MASK) == FDF0_50_60_PAL ? "PAL" : "NTSC",
|
|
(pStrmExt->cipQuad2[1] & FDF0_STYPE_MASK) == FDF0_STYPE_SD_DVCR ? "SD" : \
|
|
(pStrmExt->cipQuad2[1] & FDF0_STYPE_MASK) == FDF0_STYPE_SDL_DVCR ? "SDL" : \
|
|
(pStrmExt->cipQuad2[1] & FDF0_STYPE_MASK) == FDF0_STYPE_HD_DVCR ? "HD" : \
|
|
(pStrmExt->cipQuad2[1] & FDF0_STYPE_MASK) == FDF0_STYPE_SD_DVCPRO ? "DVCPRO" : "DV:????"
|
|
));
|
|
} else
|
|
TRACE(TL_FCP_WARNING|TL_CIP_WARNING,("\'** MediaFormat: St:%x; use idx:%d\n", Status, pDevExt->VideoFormatIndex));
|
|
|
|
#endif
|
|
|
|
return STATUS_SUCCESS == Status;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
DVCmpGUIDsAndFormatSize(
|
|
IN PKSDATARANGE pDataRange1,
|
|
IN PKSDATARANGE pDataRange2,
|
|
IN BOOL fCompareSubformat,
|
|
IN BOOL fCompareFormatSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks for a match on the three GUIDs and FormatSize
|
|
|
|
Arguments:
|
|
|
|
IN pDataRange1
|
|
IN pDataRange2
|
|
|
|
Return Value:
|
|
|
|
TRUE if all elements match
|
|
FALSE if any are different
|
|
|
|
--*/
|
|
|
|
{
|
|
return (
|
|
IsEqualGUID (
|
|
&pDataRange1->MajorFormat,
|
|
&pDataRange2->MajorFormat) &&
|
|
(fCompareSubformat ?
|
|
IsEqualGUID (
|
|
&pDataRange1->SubFormat,
|
|
&pDataRange2->SubFormat) : TRUE) &&
|
|
IsEqualGUID (
|
|
&pDataRange1->Specifier,
|
|
&pDataRange2->Specifier) &&
|
|
(fCompareFormatSize ?
|
|
(pDataRange1->FormatSize == pDataRange2->FormatSize) : TRUE ));
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DvAllocatePCResource(
|
|
IN KSPIN_DATAFLOW DataFlow,
|
|
IN PSTREAMEX pStrmExt // Note that pStrmExt can be NULL!
|
|
)
|
|
{
|
|
|
|
PSRB_DATA_PACKET pSrbDataPacket;
|
|
PDVCR_EXTENSION pDevExt;
|
|
ULONG i, j;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
//
|
|
// Pre-allcoate PC resource
|
|
//
|
|
pDevExt = pStrmExt->pDevExt;
|
|
for(i=0; i < (DataFlow == KSPIN_DATAFLOW_OUT ? \
|
|
DVFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfRcvBuffers : \
|
|
DVFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfXmtBuffers); i++) {
|
|
|
|
if(!(pSrbDataPacket = ExAllocatePool(NonPagedPool, sizeof(SRB_DATA_PACKET)))) {
|
|
|
|
for(j = 0; j < i; j++) {
|
|
pSrbDataPacket = (PSRB_DATA_PACKET) \
|
|
RemoveHeadList(&pStrmExt->DataDetachedListHead); pStrmExt->cntDataDetached--;
|
|
ExFreePool(pSrbDataPacket->Frame); pSrbDataPacket->Frame = NULL;
|
|
IoFreeIrp(pSrbDataPacket->pIrp); pSrbDataPacket->pIrp = NULL;
|
|
ExFreePool(pSrbDataPacket); pSrbDataPacket = NULL;
|
|
ASSERT(pStrmExt->cntDataDetached >= 0);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
RtlZeroMemory(pSrbDataPacket, sizeof(SRB_DATA_PACKET));
|
|
pSrbDataPacket->State = DE_IRP_SRB_COMPLETED; // Initial state.
|
|
|
|
if(!(pSrbDataPacket->Frame = ExAllocatePool(NonPagedPool, sizeof(CIP_FRAME)))) {
|
|
ExFreePool(pSrbDataPacket); pSrbDataPacket = NULL;
|
|
|
|
for(j = 0; j < i; j++) {
|
|
pSrbDataPacket = (PSRB_DATA_PACKET) \
|
|
RemoveHeadList(&pStrmExt->DataDetachedListHead); pStrmExt->cntDataDetached--;
|
|
ExFreePool(pSrbDataPacket->Frame); pSrbDataPacket->Frame = NULL;
|
|
IoFreeIrp(pSrbDataPacket->pIrp); pSrbDataPacket->pIrp = NULL;
|
|
ExFreePool(pSrbDataPacket); pSrbDataPacket = NULL;
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
if(!(pSrbDataPacket->pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE))) {
|
|
ExFreePool(pSrbDataPacket->Frame); pSrbDataPacket->Frame = NULL;
|
|
ExFreePool(pSrbDataPacket); pSrbDataPacket = NULL;
|
|
|
|
for(j = 0; j < i; j++) {
|
|
pSrbDataPacket = (PSRB_DATA_PACKET) \
|
|
RemoveHeadList(&pStrmExt->DataDetachedListHead); pStrmExt->cntDataDetached--;
|
|
ExFreePool(pSrbDataPacket->Frame); pSrbDataPacket->Frame = NULL;
|
|
IoFreeIrp(pSrbDataPacket->pIrp); pSrbDataPacket->pIrp = NULL;
|
|
ExFreePool(pSrbDataPacket); pSrbDataPacket = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
InsertTailList(&pStrmExt->DataDetachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataDetached++;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DvFreePCResource(
|
|
IN PSTREAMEX pStrmExt
|
|
)
|
|
{
|
|
PSRB_DATA_PACKET pSrbDataPacket;
|
|
KIRQL oldIrql;
|
|
|
|
PAGED_CODE();
|
|
|
|
KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
|
|
while(!IsListEmpty(&pStrmExt->DataDetachedListHead)) {
|
|
pSrbDataPacket = (PSRB_DATA_PACKET)
|
|
RemoveHeadList(
|
|
&pStrmExt->DataDetachedListHead
|
|
);
|
|
|
|
ExFreePool(pSrbDataPacket->Frame);
|
|
pSrbDataPacket->Frame = NULL;
|
|
IoFreeIrp(pSrbDataPacket->pIrp);
|
|
pSrbDataPacket->pIrp = NULL;
|
|
ExFreePool(pSrbDataPacket);
|
|
|
|
pStrmExt->cntDataDetached--;
|
|
|
|
ASSERT(pStrmExt->cntDataDetached >= 0);
|
|
}
|
|
ASSERT(pStrmExt->cntDataDetached == 0);
|
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
DVGetUnitCapabilities(
|
|
IN PDVCR_EXTENSION pDevExt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the targe device's unit capabilities
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_INSUFFICIENT_RESOURCES
|
|
status return from 61883.
|
|
|
|
--*/
|
|
{
|
|
PIRP pIrp;
|
|
PAV_61883_REQUEST pAVReq;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
GET_UNIT_IDS * pUnitIds;
|
|
GET_UNIT_CAPABILITIES * pUnitCaps;
|
|
|
|
PAGED_CODE();
|
|
|
|
if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE)))
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if(!(pAVReq = (AV_61883_REQUEST *) ExAllocatePool(NonPagedPool, sizeof(AV_61883_REQUEST)))) {
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Query device's capability
|
|
//
|
|
if(!(pUnitIds = (GET_UNIT_IDS *) ExAllocatePool(NonPagedPool, sizeof(GET_UNIT_IDS)))) {
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
ExFreePool(pAVReq); pAVReq = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Query device's capability
|
|
//
|
|
if(!(pUnitCaps = (GET_UNIT_CAPABILITIES *) ExAllocatePool(NonPagedPool, sizeof(GET_UNIT_CAPABILITIES)))) {
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
ExFreePool(pAVReq); pAVReq = NULL;
|
|
ExFreePool(pUnitIds); pUnitIds = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
|
|
INIT_61883_HEADER(pAVReq, Av61883_GetUnitInfo);
|
|
pAVReq->GetUnitInfo.nLevel = GET_UNIT_INFO_IDS;
|
|
|
|
RtlZeroMemory(pUnitIds, sizeof(GET_UNIT_IDS));
|
|
pAVReq->GetUnitInfo.Information = (PVOID) pUnitIds;
|
|
|
|
Status =
|
|
DVSubmitIrpSynch(
|
|
pDevExt,
|
|
pIrp,
|
|
pAVReq
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
TRACE(TL_61883_ERROR,("\'Av61883_GetUnitInfo (IDS) Failed = 0x%x\n", Status));
|
|
pDevExt->UniqueID.QuadPart = 0;
|
|
pDevExt->ulVendorID = 0;
|
|
pDevExt->ulModelID = 0;
|
|
}
|
|
else {
|
|
pDevExt->UniqueID = pUnitIds->UniqueID;
|
|
pDevExt->ulVendorID = pUnitIds->VendorID;
|
|
pDevExt->ulModelID = pUnitIds->ModelID;
|
|
|
|
TRACE(TL_61883_WARNING,("\'UniqueId:(%x:%x); VID:%x; MID:%x\n",
|
|
pDevExt->UniqueID.LowPart, pDevExt->UniqueID.HighPart,
|
|
pUnitIds->VendorID,
|
|
pUnitIds->ModelID
|
|
));
|
|
}
|
|
|
|
|
|
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
|
|
INIT_61883_HEADER(pAVReq, Av61883_GetUnitInfo);
|
|
pAVReq->GetUnitInfo.nLevel = GET_UNIT_INFO_CAPABILITIES;
|
|
|
|
RtlZeroMemory(pUnitCaps, sizeof(GET_UNIT_CAPABILITIES));
|
|
pAVReq->GetUnitInfo.Information = (PVOID) pUnitCaps;
|
|
|
|
Status =
|
|
DVSubmitIrpSynch(
|
|
pDevExt,
|
|
pIrp,
|
|
pAVReq
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
TRACE(TL_61883_ERROR,("Av61883_GetUnitInfo (CAPABILITIES) Failed = 0x%x\n", Status));
|
|
pDevExt->MaxDataRate = 0;
|
|
pDevExt->NumOutputPlugs = 0;
|
|
pDevExt->NumInputPlugs = 0;
|
|
pDevExt->HardwareFlags = 0;
|
|
}
|
|
else {
|
|
pDevExt->MaxDataRate = pUnitCaps->MaxDataRate;
|
|
pDevExt->NumOutputPlugs = pUnitCaps->NumOutputPlugs;
|
|
pDevExt->NumInputPlugs = pUnitCaps->NumInputPlugs;
|
|
pDevExt->HardwareFlags = pUnitCaps->HardwareFlags;
|
|
}
|
|
|
|
#if DBG
|
|
if( pDevExt->NumOutputPlugs == 0
|
|
|| pDevExt->NumInputPlugs == 0)
|
|
{
|
|
TRACE(TL_PNP_WARNING|TL_61883_WARNING,("\'Watch out! NumOPlug:%d; NumIPlug:%d\n", pDevExt->NumOutputPlugs, pDevExt->NumInputPlugs));
|
|
}
|
|
#endif
|
|
|
|
TRACE(TL_61883_WARNING,("\'UnitCaps:%s OutP:%d; InP:%d; MDRt:%s; HWFlg:%x; CtsF:%x; HwF:%x\n",
|
|
(pUnitCaps->HardwareFlags & AV_HOST_DMA_DOUBLE_BUFFERING_ENABLED) ? "*PAE*;":"",
|
|
pUnitCaps->NumOutputPlugs,
|
|
pUnitCaps->NumInputPlugs,
|
|
pUnitCaps->MaxDataRate == 0 ? "S100": pUnitCaps->MaxDataRate == 1? "S200" : "S400 or +",
|
|
pUnitCaps->HardwareFlags,
|
|
pUnitCaps->CTSFlags,
|
|
pUnitCaps->HardwareFlags
|
|
));
|
|
|
|
ExFreePool(pUnitIds); pUnitIds = NULL;
|
|
ExFreePool(pUnitCaps); pUnitCaps = NULL;
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
ExFreePool(pAVReq); pAVReq = NULL;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DVGetDVPlug(
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
IN CMP_PLUG_TYPE PlugType,
|
|
IN ULONG PlugNum,
|
|
OUT HANDLE *pPlugHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the targe device's plug handle
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_INSUFFICIENT_RESOURCES
|
|
status return from 61883.
|
|
|
|
--*/
|
|
{
|
|
PIRP pIrp;
|
|
PAV_61883_REQUEST pAVReq;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE)))
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if(!(pAVReq = (AV_61883_REQUEST *) ExAllocatePool(NonPagedPool, sizeof(AV_61883_REQUEST)))) {
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
|
|
INIT_61883_HEADER(pAVReq, Av61883_GetPlugHandle);
|
|
pAVReq->GetPlugHandle.PlugNum = PlugNum;
|
|
pAVReq->GetPlugHandle.hPlug = 0;
|
|
pAVReq->GetPlugHandle.Type = PlugType;
|
|
|
|
if(NT_SUCCESS(
|
|
Status = DVSubmitIrpSynch(
|
|
pDevExt,
|
|
pIrp,
|
|
pAVReq
|
|
))) {
|
|
*pPlugHandle = pAVReq->GetPlugHandle.hPlug;
|
|
TRACE(TL_61883_WARNING,("\'Created h%sPlugDV[%d]=%x\n", PlugType == CMP_PlugIn ? "I" : "O", PlugNum, *pPlugHandle));
|
|
} else {
|
|
TRACE(TL_61883_ERROR,("\'Created h%sPlugDV[%d] failed; Status:%x\n", PlugType == CMP_PlugIn ? "I" : "O", PlugNum, Status));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
ExFreePool(pAVReq); pAVReq = NULL;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
#ifdef NT51_61883
|
|
|
|
NTSTATUS
|
|
DVSetAddressRangeExclusive(
|
|
IN PDVCR_EXTENSION pDevExt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set this mode so that our local plug will be created in address exclusive mode.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_INSUFFICIENT_RESOURCES
|
|
|
|
--*/
|
|
{
|
|
PIRP pIrp;
|
|
PAV_61883_REQUEST pAVReq;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
SET_CMP_ADDRESS_TYPE SetCmpAddress;
|
|
|
|
PAGED_CODE();
|
|
|
|
if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE)))
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if(!(pAVReq = (AV_61883_REQUEST *) ExAllocatePool(NonPagedPool, sizeof(AV_61883_REQUEST)))) {
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
|
|
INIT_61883_HEADER(pAVReq, Av61883_SetUnitInfo);
|
|
pAVReq->SetUnitInfo.nLevel = SET_CMP_ADDRESS_RANGE_TYPE;
|
|
SetCmpAddress.Type = CMP_ADDRESS_TYPE_EXCLUSIVE;
|
|
pAVReq->SetUnitInfo.Information = (PVOID) &SetCmpAddress;
|
|
|
|
if(!NT_SUCCESS(
|
|
Status = DVSubmitIrpSynch(
|
|
pDevExt,
|
|
pIrp,
|
|
pAVReq
|
|
))) {
|
|
TRACE(TL_61883_ERROR,("\'SET_CMP_ADDRESS_RANGE_TYPE Failed:%x\n", Status));
|
|
} else {
|
|
TRACE(TL_61883_TRACE,("\'SET_CMP_ADDRESS_RANGE_TYPE suceeded.\n"));
|
|
}
|
|
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
ExFreePool(pAVReq); pAVReq = NULL;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DVGetUnitIsochParam(
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
OUT UNIT_ISOCH_PARAMS * pUnitIoschParams
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create an enumated local PC PCR
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_INSUFFICIENT_RESOURCES
|
|
|
|
--*/
|
|
{
|
|
PIRP pIrp;
|
|
PAV_61883_REQUEST pAVReq;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE)))
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if(!(pAVReq = (AV_61883_REQUEST *) ExAllocatePool(NonPagedPool, sizeof(AV_61883_REQUEST)))) {
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
//
|
|
// Get Unit isoch parameters
|
|
//
|
|
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
|
|
INIT_61883_HEADER(pAVReq, Av61883_GetUnitInfo);
|
|
pAVReq->GetUnitInfo.nLevel = GET_UNIT_INFO_ISOCH_PARAMS;
|
|
|
|
RtlZeroMemory(pUnitIoschParams, sizeof(UNIT_ISOCH_PARAMS));
|
|
pAVReq->GetUnitInfo.Information = (PVOID) pUnitIoschParams;
|
|
|
|
Status =
|
|
DVSubmitIrpSynch(
|
|
pDevExt,
|
|
pIrp,
|
|
pAVReq
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
TRACE(TL_61883_ERROR,("Av61883_GetUnitInfo Failed:%x\n", Status));
|
|
Status = STATUS_UNSUCCESSFUL; // Cannot stream without this!
|
|
}
|
|
|
|
TRACE(TL_61883_WARNING,("\'IsochParam: RxPkt:%d, RxDesc:%d; XmPkt:%d, XmDesc:%d\n",
|
|
pUnitIoschParams->RX_NumPackets,
|
|
pUnitIoschParams->RX_NumDescriptors,
|
|
pUnitIoschParams->TX_NumPackets,
|
|
pUnitIoschParams->TX_NumDescriptors
|
|
));
|
|
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
ExFreePool(pAVReq); pAVReq = NULL;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DVSetUnitIsochParams(
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
IN UNIT_ISOCH_PARAMS *pUnitIoschParams
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set AV unit's isoch parameters via 61883.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_INSUFFICIENT_RESOURCES
|
|
|
|
--*/
|
|
{
|
|
PIRP pIrp;
|
|
PAV_61883_REQUEST pAVReq;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE)))
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if(!(pAVReq = (AV_61883_REQUEST *) ExAllocatePool(NonPagedPool, sizeof(AV_61883_REQUEST)))) {
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
|
|
INIT_61883_HEADER(pAVReq, Av61883_SetUnitInfo);
|
|
pAVReq->SetUnitInfo.nLevel = SET_UNIT_INFO_ISOCH_PARAMS;
|
|
pAVReq->SetUnitInfo.Information = (PVOID) pUnitIoschParams;
|
|
if(!NT_SUCCESS(
|
|
Status = DVSubmitIrpSynch(
|
|
pDevExt,
|
|
pIrp,
|
|
pAVReq
|
|
))) {
|
|
TRACE(TL_61883_ERROR,("DVSetUnitIsochParams: Av61883_SetUnitInfo Failed:%x\n", Status));
|
|
}
|
|
|
|
TRACE(TL_61883_WARNING,("\'UnitIsochParams: Set: RxPkt:%d, RxDesc:%d; XmPkt:%d, XmDesc:%d\n",
|
|
pUnitIoschParams->RX_NumPackets,
|
|
pUnitIoschParams->RX_NumDescriptors,
|
|
pUnitIoschParams->TX_NumPackets,
|
|
pUnitIoschParams->TX_NumDescriptors
|
|
));
|
|
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
ExFreePool(pAVReq); pAVReq = NULL;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DVMakeP2PConnection(
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
IN KSPIN_DATAFLOW DataFlow,
|
|
IN PSTREAMEX pStrmExt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Make a point to point connection .
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_INSUFFICIENT_RESOURCES
|
|
|
|
--*/
|
|
{
|
|
PIRP pIrp;
|
|
PAV_61883_REQUEST pAVReq;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE)))
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if(!(pAVReq = (AV_61883_REQUEST *) ExAllocatePool(NonPagedPool, sizeof(AV_61883_REQUEST)))) {
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
|
|
INIT_61883_HEADER(pAVReq, Av61883_Connect);
|
|
pAVReq->Connect.Type = CMP_PointToPoint; // !!
|
|
|
|
pAVReq->Connect.hOutputPlug = pStrmExt->hOutputPcr;
|
|
pAVReq->Connect.hInputPlug = pStrmExt->hInputPcr;
|
|
|
|
// see which way we the data will flow...
|
|
if(DataFlow == KSPIN_DATAFLOW_OUT) {
|
|
|
|
// Other parameters !!
|
|
|
|
} else {
|
|
|
|
pAVReq->Connect.Format.FMT = pStrmExt->cipQuad2[0]; // From AV/C in/outpug plug signal format status cmd
|
|
// 00 for NTSC, 80 for PAL; set the 50/60 bit
|
|
pAVReq->Connect.Format.FDF_hi = pStrmExt->cipQuad2[1]; // From AV/C in/outpug plug signal format status cmd
|
|
|
|
//
|
|
// 16bit SYT field = 4BitCycleCount:12BitCycleOffset;
|
|
// Will be set by 61883
|
|
//
|
|
pAVReq->Connect.Format.FDF_mid = 0;
|
|
pAVReq->Connect.Format.FDF_lo = 0;
|
|
|
|
//
|
|
// Constants depend on the A/V data format (in or out plug format)
|
|
//
|
|
pAVReq->Connect.Format.bHeader = (BOOL) DVFormatInfoTable[pDevExt->VideoFormatIndex].SrcPktHeader;
|
|
pAVReq->Connect.Format.Padding = (UCHAR) DVFormatInfoTable[pDevExt->VideoFormatIndex].QuadPadCount;
|
|
pAVReq->Connect.Format.BlockSize = (UCHAR) DVFormatInfoTable[pDevExt->VideoFormatIndex].DataBlockSize;
|
|
pAVReq->Connect.Format.Fraction = (UCHAR) DVFormatInfoTable[pDevExt->VideoFormatIndex].FractionNumber;
|
|
}
|
|
|
|
// Set this so that 61883 can know it is NTSC or PAL;
|
|
// For read: It is needed so 61883 can preallocate just-enough packets
|
|
// so that data can return in a much regular interval.
|
|
if( pDevExt->VideoFormatIndex == FMT_IDX_SD_DVCR_NTSC
|
|
|| pDevExt->VideoFormatIndex == FMT_IDX_SDL_DVCR_NTSC)
|
|
pAVReq->Connect.Format.BlockPeriod = 133466800; // nano-sec
|
|
else
|
|
pAVReq->Connect.Format.BlockPeriod = 133333333; // nano-sec
|
|
|
|
TRACE(TL_61883_WARNING,("\'cipQuad2[0]:%x, cipQuad2[1]:%x, cipQuad2[2]:%x, cipQuad2[3]:%x\n",
|
|
pStrmExt->cipQuad2[0],
|
|
pStrmExt->cipQuad2[1],
|
|
pStrmExt->cipQuad2[2],
|
|
pStrmExt->cipQuad2[3]
|
|
));
|
|
|
|
|
|
TRACE(TL_61883_WARNING,("\'Connect:oPcr:%x->iPcr:%x; cipQuad2[%.2x:%.2x:%.2x:%.2x]\n",
|
|
pAVReq->Connect.hOutputPlug,
|
|
pAVReq->Connect.hInputPlug,
|
|
pAVReq->Connect.Format.FMT,
|
|
pAVReq->Connect.Format.FDF_hi,
|
|
pAVReq->Connect.Format.FDF_mid,
|
|
pAVReq->Connect.Format.FDF_lo
|
|
));
|
|
|
|
TRACE(TL_61883_WARNING,("\' BlkSz %d; SrcPkt %d; AvgTm %d, BlkPrd %d\n",
|
|
pAVReq->Connect.Format.BlockSize,
|
|
DVFormatInfoTable[pDevExt->VideoFormatIndex].ulSrcPackets,
|
|
DVFormatInfoTable[pDevExt->VideoFormatIndex].ulAvgTimePerFrame,
|
|
(DWORD) pAVReq->Connect.Format.BlockPeriod
|
|
));
|
|
|
|
if(NT_SUCCESS(
|
|
Status = DVSubmitIrpSynch(
|
|
pDevExt,
|
|
pIrp,
|
|
pAVReq
|
|
))) {
|
|
TRACE(TL_61883_WARNING,("\'hConnect:%x\n", pAVReq->Connect.hConnect));
|
|
ASSERT(pAVReq->Connect.hConnect != NULL);
|
|
pStrmExt->hConnect = pAVReq->Connect.hConnect;
|
|
}
|
|
else {
|
|
TRACE(TL_61883_ERROR,("Av61883_Connect Failed; Status:%x\n", Status));
|
|
ASSERT(!NT_SUCCESS(Status) && "DisConnect failed");
|
|
pStrmExt->hConnect = NULL;
|
|
}
|
|
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
ExFreePool(pAVReq); pAVReq = NULL;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DVCreateLocalPlug(
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
IN CMP_PLUG_TYPE PlugType,
|
|
IN ULONG PlugNum,
|
|
OUT HANDLE *pPlugHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create an enumated local PC PCR
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_INSUFFICIENT_RESOURCES
|
|
|
|
--*/
|
|
{
|
|
PIRP pIrp;
|
|
PAV_61883_REQUEST pAVReq;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE)))
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if(!(pAVReq = (AV_61883_REQUEST *) ExAllocatePool(NonPagedPool, sizeof(AV_61883_REQUEST)))) {
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Need to correctly update Overhead_ID and payload fields of PC's own oPCR
|
|
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
|
|
INIT_61883_HEADER(pAVReq, Av61883_CreatePlug);
|
|
|
|
pAVReq->CreatePlug.PlugNum = PlugNum;
|
|
pAVReq->CreatePlug.hPlug = NULL;
|
|
|
|
pAVReq->CreatePlug.Context = NULL;
|
|
pAVReq->CreatePlug.pfnNotify = NULL;
|
|
pAVReq->CreatePlug.PlugType = PlugType;
|
|
|
|
//
|
|
// Initialize oPCR values to default values using SDDV signal mode
|
|
// with speed of 100Mbps data rate
|
|
//
|
|
|
|
pAVReq->CreatePlug.Pcr.oPCR.OnLine = 0; // We are not online so we cannot be programmed.
|
|
pAVReq->CreatePlug.Pcr.oPCR.BCCCounter = 0;
|
|
pAVReq->CreatePlug.Pcr.oPCR.PPCCounter = 0;
|
|
pAVReq->CreatePlug.Pcr.oPCR.Channel = 0;
|
|
|
|
pAVReq->CreatePlug.Pcr.oPCR.DataRate = CMP_SPEED_S100;
|
|
pAVReq->CreatePlug.Pcr.oPCR.OverheadID = PCR_OVERHEAD_ID_SDDV;
|
|
pAVReq->CreatePlug.Pcr.oPCR.Payload = PCR_PAYLOAD_SDDV;
|
|
|
|
if(NT_SUCCESS(
|
|
Status = DVSubmitIrpSynch(
|
|
pDevExt,
|
|
pIrp,
|
|
pAVReq
|
|
))) {
|
|
*pPlugHandle = pAVReq->CreatePlug.hPlug;
|
|
TRACE(TL_61883_WARNING,("\'Created h%sPlugPC[%d]=%x\n", PlugType == CMP_PlugIn ? "I" : "O", PlugNum, *pPlugHandle));
|
|
} else {
|
|
TRACE(TL_61883_ERROR,("\'Created h%sPlugPC[%d] failed; Status:%x\n", pAVReq->CreatePlug.PlugType == CMP_PlugIn ? "I" : "O", PlugNum, Status));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES; // No plug!
|
|
}
|
|
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
ExFreePool(pAVReq); pAVReq = NULL;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DVDeleteLocalPlug(
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
IN HANDLE PlugHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete an enumated local PC PCR
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
PIRP pIrp;
|
|
PAV_61883_REQUEST pAVReq;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE)))
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if(!(pAVReq = (AV_61883_REQUEST *) ExAllocatePool(NonPagedPool, sizeof(AV_61883_REQUEST)))) {
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Delete our local oPCR
|
|
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
|
|
INIT_61883_HEADER(pAVReq, Av61883_DeletePlug);
|
|
pAVReq->DeletePlug.hPlug = PlugHandle;
|
|
|
|
Status =
|
|
DVSubmitIrpSynch(
|
|
pDevExt,
|
|
pIrp,
|
|
pAVReq
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
TRACE(TL_61883_ERROR,("Av61883_DeletePlug Failed = 0x%x\n", Status));
|
|
// Do not care if this result in error.
|
|
} else {
|
|
TRACE(TL_61883_WARNING,("\'Av61883_DeletePlug: Deleted!\n", pDevExt->hOPcrPC));
|
|
}
|
|
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
ExFreePool(pAVReq); pAVReq = NULL;
|
|
|
|
return Status;
|
|
}
|
|
#endif
|
|
|
|
NTSTATUS
|
|
DVGetPlugState(
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
IN PSTREAMEX pStrmExt,
|
|
IN PAV_61883_REQUEST pAVReq
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ask 61883.sys for the plug state.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
PIRP pIrp;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE)))
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
//
|
|
// Query oPCR plug state
|
|
//
|
|
if(pStrmExt->hOutputPcr) {
|
|
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
|
|
INIT_61883_HEADER(pAVReq, Av61883_GetPlugState);
|
|
pAVReq->GetPlugState.hPlug = pStrmExt->hOutputPcr;
|
|
|
|
Status =
|
|
DVSubmitIrpSynch(
|
|
pDevExt,
|
|
pIrp,
|
|
pAVReq
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
TRACE(TL_61883_ERROR,("Av61883_GetPlugState Failed %x\n", Status));
|
|
goto ExitGetState;
|
|
}
|
|
else {
|
|
|
|
TRACE(TL_61883_WARNING,("\'PlgState:(oPCR:%x): State %x; DRate %d; Payld %d; BCCnt %d; PPCnt %d\n",
|
|
pAVReq->GetPlugState.hPlug,
|
|
pAVReq->GetPlugState.State,
|
|
pAVReq->GetPlugState.DataRate,
|
|
pAVReq->GetPlugState.Payload,
|
|
pAVReq->GetPlugState.BC_Connections,
|
|
pAVReq->GetPlugState.PP_Connections
|
|
));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Query iPCR plug state
|
|
//
|
|
if(pStrmExt->hInputPcr) {
|
|
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
|
|
INIT_61883_HEADER(pAVReq, Av61883_GetPlugState);
|
|
pAVReq->GetPlugState.hPlug = pStrmExt->hInputPcr;
|
|
|
|
Status =
|
|
DVSubmitIrpSynch(
|
|
pDevExt,
|
|
pIrp,
|
|
pAVReq
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
|
|
TRACE(TL_61883_ERROR,("Av61883_GetPlugState Failed %x\n", Status));
|
|
goto ExitGetState;
|
|
}
|
|
else {
|
|
|
|
TRACE(TL_61883_WARNING,("\'PlugState(iPCR:%x): State %x; DRate %d; Payld %d; BCCnt %d; PPCnt %d\n",
|
|
pAVReq->GetPlugState.hPlug,
|
|
pAVReq->GetPlugState.State,
|
|
pAVReq->GetPlugState.DataRate,
|
|
pAVReq->GetPlugState.Payload,
|
|
pAVReq->GetPlugState.BC_Connections,
|
|
pAVReq->GetPlugState.PP_Connections
|
|
));
|
|
}
|
|
}
|
|
|
|
ExitGetState:
|
|
IoFreeIrp(pIrp);
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DVCreateAttachFrameThread(
|
|
PSTREAMEX pStrmExt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a system thread for attaching data (for transmiut to DV only).
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS or
|
|
return status from PsCreateSystemThread
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
HANDLE hAttachFrameThread;
|
|
|
|
Status =
|
|
PsCreateSystemThread(
|
|
&hAttachFrameThread,
|
|
(ACCESS_MASK) 0,
|
|
NULL,
|
|
(HANDLE) 0,
|
|
NULL,
|
|
DVAttachFrameThread,
|
|
pStrmExt
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
pStrmExt->bTerminateThread = TRUE;
|
|
TRACE(TL_CIP_ERROR|TL_FCP_ERROR,("\'PsCreateSystemThread() failed %x\n", Status));
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
}
|
|
else {
|
|
pStrmExt->bTerminateThread = FALSE; // Just started!
|
|
Status =
|
|
ObReferenceObjectByHandle(
|
|
hAttachFrameThread,
|
|
THREAD_ALL_ACCESS,
|
|
NULL,
|
|
KernelMode,
|
|
&pStrmExt->pAttachFrameThreadObject,
|
|
NULL
|
|
);
|
|
|
|
TRACE(TL_CIP_WARNING|TL_PNP_WARNING,("\'ObReferenceObjectByHandle() St %x; Obj %x\n", Status, pStrmExt->pAttachFrameThreadObject));
|
|
ZwClose(hAttachFrameThread);
|
|
|
|
// To signl end of an event
|
|
KeInitializeEvent(&pStrmExt->hThreadEndEvent, NotificationEvent, FALSE); // Non-signal
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DVConnect(
|
|
IN KSPIN_DATAFLOW ulDataFlow,
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
IN PSTREAMEX pStrmExt,
|
|
IN PAV_61883_REQUEST pAVReq
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ask 61883.sys to allocate isoch bandwidth and program PCR.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
other Status from calling other routine.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(pStrmExt->hConnect == NULL);
|
|
|
|
//
|
|
// Do not reconnect. 61883 should handle all the necessary CMP reconnect.
|
|
//
|
|
if(pStrmExt->hConnect) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
#ifdef SUPPORT_NEW_AVC
|
|
//
|
|
// For Device to device connection, we only connect if we are the data producer (oPCR)
|
|
//
|
|
|
|
TRACE(TL_61883_WARNING,("\'[pStrmExt:%x]: %s PC (oPCR:%x, iPCR:%x); DV (oPCR:%x; iPCR:%x)\n",
|
|
pStrmExt,
|
|
ulDataFlow == KSPIN_DATAFLOW_OUT ? "OutPin" : "InPin",
|
|
pDevExt->hOPcrPC, 0,
|
|
pDevExt->hOPcrDV, pDevExt->hIPcrDV
|
|
));
|
|
|
|
if(
|
|
pStrmExt->bDV2DVConnect &&
|
|
(pStrmExt->hOutputPcr != pDevExt->hOPcrDV)) {
|
|
TRACE(TL_61883_WARNING,("\'** pStrmExt:%x not data producer!\n\n", pStrmExt));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef NT51_61883
|
|
//
|
|
// Set Unit isoch parameters:
|
|
// The number of packets is depending on two factors:
|
|
// For a PAE system, number of packets cannnot be bigger than 64k/480 = 133
|
|
// For capture, number of packets should not be bigger than max packets to construct a DV buffer.
|
|
// This is needed to avoid completing two buffers in the same descriptor and can cause glitched
|
|
// in the "real time" playback of the data, esp the audio.
|
|
//
|
|
if(pDevExt->HardwareFlags & AV_HOST_DMA_DOUBLE_BUFFERING_ENABLED) {
|
|
// PAE system
|
|
pDevExt->UnitIoschParams.RX_NumPackets =
|
|
// pDevExt->UnitIoschParams.TX_NumPackets = // Use the default set by 61883
|
|
((pDevExt->VideoFormatIndex == FMT_IDX_SD_DVCR_NTSC || pDevExt->VideoFormatIndex == FMT_IDX_SDL_DVCR_NTSC) ?
|
|
MAX_SRC_PACKETS_PER_NTSC_FRAME_PAE : MAX_SRC_PACKETS_PER_PAL_FRAME_PAE);
|
|
} else {
|
|
pDevExt->UnitIoschParams.RX_NumPackets =
|
|
// pDevExt->UnitIoschParams.TX_NumPackets = // Use the default set by 61883
|
|
((pDevExt->VideoFormatIndex == FMT_IDX_SD_DVCR_NTSC || pDevExt->VideoFormatIndex == FMT_IDX_SDL_DVCR_NTSC) ?
|
|
MAX_SRC_PACKETS_PER_NTSC_FRAME : MAX_SRC_PACKETS_PER_PAL_FRAME);
|
|
}
|
|
|
|
if(!NT_SUCCESS(
|
|
Status = DVSetUnitIsochParams(
|
|
pDevExt,
|
|
&pDevExt->UnitIoschParams
|
|
))) {
|
|
return Status;
|
|
}
|
|
|
|
#endif // NT51_61883
|
|
|
|
//
|
|
// Make a point to point connection
|
|
//
|
|
Status =
|
|
DVMakeP2PConnection(
|
|
pDevExt,
|
|
ulDataFlow,
|
|
pStrmExt
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
DVDisconnect(
|
|
IN KSPIN_DATAFLOW ulDataFlow,
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
IN PSTREAMEX pStrmExt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ask 61883.sys to free isoch bandwidth and program PCR.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
PIRP pIrp;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PAV_61883_REQUEST pAVReq;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Use the hPlug to disconnect
|
|
//
|
|
if(pStrmExt->hConnect) {
|
|
|
|
if(!(pAVReq = (AV_61883_REQUEST *) ExAllocatePool(NonPagedPool, sizeof(AV_61883_REQUEST))))
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE))) {
|
|
ExFreePool(pAVReq); pAVReq = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
|
|
INIT_61883_HEADER(pAVReq, Av61883_Disconnect);
|
|
pAVReq->Disconnect.hConnect = pStrmExt->hConnect;
|
|
ASSERT(pStrmExt->hConnect);
|
|
|
|
if(!NT_SUCCESS(
|
|
Status = DVSubmitIrpSynch(
|
|
pDevExt,
|
|
pIrp,
|
|
pAVReq
|
|
))) {
|
|
// This could be caused that the connection was not P2P, and
|
|
// it tried to disconnect.
|
|
TRACE(TL_61883_ERROR,("\'Disconnect hConnect:%x failed; ST %x; AvReq->ST %x\n", pStrmExt->hConnect, Status, pAVReq->Flags ));
|
|
// ASSERT(NT_SUCCESS(Status) && "DisConnect failed");
|
|
} else {
|
|
TRACE(TL_61883_TRACE,("\'Disconnect suceeded; ST %x; AvReq->ST %x\n", Status, pAVReq->Flags ));
|
|
}
|
|
|
|
IoFreeIrp(pIrp); pIrp = NULL;
|
|
ExFreePool(pAVReq); pAVReq = NULL;
|
|
|
|
TRACE(TL_61883_WARNING,("\'DisConn %s St:%x; Stat: SRBCnt:%d; [Pic# =? Prcs:Drp:Cncl:Rpt] [%d ?=%d+%d+%d+%d]\n",
|
|
ulDataFlow == KSPIN_DATAFLOW_OUT ? "[OutPin]" : "[InPin]",
|
|
Status,
|
|
(DWORD) pStrmExt->cntSRBReceived,
|
|
(DWORD) pStrmExt->PictureNumber,
|
|
(DWORD) pStrmExt->FramesProcessed,
|
|
(DWORD) pStrmExt->FramesDropped,
|
|
(DWORD) pStrmExt->cntSRBCancelled, // number of SRB_READ/WRITE_DATA cancelled
|
|
(DWORD) (pStrmExt->PictureNumber - pStrmExt->FramesProcessed - pStrmExt->FramesDropped - pStrmExt->cntSRBCancelled)
|
|
));
|
|
#if DBG
|
|
if(DVFormatInfoTable[pDevExt->VideoFormatIndex].SrcPktHeader) {
|
|
ULONG ulElapsed = (DWORD) ((GetSystemTime() - pStrmExt->tmStreamStart)/(ULONGLONG) 10000);
|
|
TRACE(TL_61883_WARNING,("\'****-* TotalSrcPkt:%d; DisCont:%d; Elapse:%d msec; DataRate:%d bps *-****\n", \
|
|
pStrmExt->lTotalCycleCount, pStrmExt->lDiscontinuityCount,
|
|
ulElapsed,
|
|
pStrmExt->lTotalCycleCount * 188 * 1000 / ulElapsed * 8
|
|
));
|
|
}
|
|
#endif
|
|
|
|
// We will not have another chance to reconnect it so we assume it is disconnected.
|
|
pStrmExt->hConnect = NULL;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// GetSystemTime in 100 nS units
|
|
//
|
|
|
|
ULONGLONG GetSystemTime()
|
|
{
|
|
|
|
LARGE_INTEGER rate, ticks;
|
|
|
|
ticks = KeQueryPerformanceCounter(&rate);
|
|
|
|
return (KSCONVERT_PERFORMANCE_TIME(rate.QuadPart, ticks));
|
|
}
|
|
|
|
|
|
|
|
|
|
#define DIFBLK_SIZE 12000
|
|
|
|
#define PACK_NO_INFO 0xff
|
|
|
|
// Subcode header identifier
|
|
#define SC_HDR_TIMECODE 0x13
|
|
#define SC_HDR_BINARYGROUP 0x14
|
|
|
|
// header identifier
|
|
|
|
#define AAUX_HDR_SOURCE 0x50
|
|
#define AAUX_HDR_SOURCE_CONTROL 0x51
|
|
#define AAUX_HDR_REC_DATE 0x52
|
|
#define AAUX_HDR_REC_TIME 0x53
|
|
#define AAUX_HDR_BINARY_GROUP 0x54
|
|
#define AAUX_HDR_CC 0x55
|
|
#define AAUX_HDR_TR 0x56
|
|
|
|
#define VAUX_HDR_SOURCE 0x60
|
|
#define VAUX_HDR_SOURCE_CONTROL 0x61
|
|
#define VAUX_HDR_REC_DATE 0x62
|
|
#define VAUX_HDR_REC_TIME 0x63
|
|
#define VAUX_HDR_BINARY_GROUP 0x64
|
|
#define VAUX_HDR_CC 0x65
|
|
#define VAUX_HDR_TR 0x66
|
|
|
|
// Determine section type (MS 3 bits); Fig.66; Table 36.
|
|
#define ID0_SCT_MASK 0xe0
|
|
#define ID0_SCT_HEADER 0x00
|
|
#define ID0_SCT_SUBCODE 0x20
|
|
#define ID0_SCT_VAUX 0x40
|
|
#define ID0_SCT_AUDIO 0x60
|
|
#define ID0_SCT_VIDEO 0x80
|
|
|
|
// A pack is consisted of one byte of header identifier and 4 bytes of data; Part2, annex D.
|
|
typedef struct _DV_PACK {
|
|
UCHAR Header;
|
|
UCHAR Data[4];
|
|
} DV_PACK, *PDV_PACK;
|
|
|
|
typedef struct _DV_H0 {
|
|
UCHAR ID0;
|
|
UCHAR ID1;
|
|
UCHAR ID2;
|
|
|
|
UCHAR DSF;
|
|
UCHAR DFTIA;
|
|
UCHAR TF1;
|
|
UCHAR TF2;
|
|
UCHAR TF3;
|
|
|
|
UCHAR Reserved[72];
|
|
} DV_H0, *PDV_H0;
|
|
|
|
typedef struct _DV_SC {
|
|
UCHAR ID0;
|
|
UCHAR ID1;
|
|
UCHAR ID2;
|
|
|
|
struct {
|
|
UCHAR SID0;
|
|
UCHAR SID1;
|
|
UCHAR Reserved;
|
|
DV_PACK Pack;
|
|
} SSyb0;
|
|
struct {
|
|
UCHAR SID0;
|
|
UCHAR SID1;
|
|
UCHAR Reserved;
|
|
DV_PACK Pack;
|
|
} SSyb1;
|
|
struct {
|
|
UCHAR SID0;
|
|
UCHAR SID1;
|
|
UCHAR Reserved;
|
|
DV_PACK Pack;
|
|
} SSyb2;
|
|
struct {
|
|
UCHAR SID0;
|
|
UCHAR SID1;
|
|
UCHAR Reserved;
|
|
DV_PACK Pack;
|
|
} SSyb3;
|
|
struct {
|
|
UCHAR SID0;
|
|
UCHAR SID1;
|
|
UCHAR Reserved;
|
|
DV_PACK Pack;
|
|
} SSyb4;
|
|
struct {
|
|
UCHAR SID0;
|
|
UCHAR SID1;
|
|
UCHAR Reserved;
|
|
DV_PACK Pack;
|
|
} SSyb5;
|
|
|
|
UCHAR Reserved[29];
|
|
} DV_SC, *PDV_SC;
|
|
|
|
#define MAX_VAUX_PACK 15
|
|
|
|
typedef struct _DV_VAUX {
|
|
UCHAR ID0;
|
|
UCHAR ID1;
|
|
UCHAR ID2;
|
|
|
|
DV_PACK Pack[MAX_VAUX_PACK];
|
|
|
|
UCHAR Reserved[2];
|
|
} DV_VAUX, *PDV_VAUX;
|
|
|
|
typedef struct _DV_A {
|
|
UCHAR ID0;
|
|
UCHAR ID1;
|
|
UCHAR ID2;
|
|
DV_PACK Pack;
|
|
UCHAR Data[72];
|
|
} DV_A, *PDV_A;
|
|
|
|
typedef struct _DV_V {
|
|
UCHAR ID0;
|
|
UCHAR ID1;
|
|
UCHAR ID2;
|
|
UCHAR Data[77]; // 3..79
|
|
} DV_V, *PDV_V;
|
|
|
|
// Two source packets
|
|
#define V_BLOCKS 15
|
|
typedef struct _DV_AV {
|
|
DV_A A;
|
|
DV_V V[V_BLOCKS];
|
|
} DV_AV, *PDV_AV;
|
|
|
|
|
|
#define SC_SECTIONS 2
|
|
#define VAUX_SECTIONS 3
|
|
#define AV_SECTIONS 9
|
|
|
|
typedef struct _DV_DIF_SEQ {
|
|
DV_H0 H0;
|
|
DV_SC SC[SC_SECTIONS];
|
|
DV_VAUX VAux[VAUX_SECTIONS];
|
|
DV_AV AV[AV_SECTIONS];
|
|
} DV_DIF_SEQ, *PDV_DIF_SEQ;
|
|
|
|
|
|
typedef struct _DV_FRAME_NTSC {
|
|
DV_DIF_SEQ DifSeq[10];
|
|
} DV_FRAME_NTSC, *PDV_FRAME_NTSC;
|
|
|
|
typedef struct _DV_FRAME_PAL {
|
|
DV_DIF_SEQ DifSeq[12];
|
|
} DV_FRAME_PAL, *PDV_FRAME_PAL;
|
|
|
|
// By setting REC MODE to 111b (invalid recording) can
|
|
// cause DV to mute the audio
|
|
#define AAUX_REC_MODE_INVALID_MASK 0x38 // xx11:1xxx
|
|
#define AAUX_REC_MODE_ORIGINAL 0x08 // xx00:1xxx
|
|
|
|
|
|
#ifdef MSDV_SUPPORT_MUTE_AUDIO
|
|
// #define SHOW_ONE_FIELD_TWICE
|
|
|
|
BOOL
|
|
DVMuteDVFrame(
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
IN OUT PUCHAR pFrameBuffer,
|
|
IN BOOL bMuteAudio
|
|
)
|
|
{
|
|
PDV_DIF_SEQ pDifSeq;
|
|
#ifdef SHOW_ONE_FIELD_TWICE
|
|
PDV_VAUX pVAux;
|
|
ULONG k;
|
|
#endif
|
|
ULONG i, j;
|
|
#ifdef SHOW_ONE_FIELD_TWICE
|
|
BOOL bFound1 = FALSE;
|
|
#endif
|
|
BOOL bFound2 = FALSE;
|
|
|
|
pDifSeq = (PDV_DIF_SEQ) pFrameBuffer;
|
|
|
|
// find the VVAX Source pack
|
|
for (i=0; i < DVFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfDIFSequences; i++) {
|
|
|
|
#ifdef SHOW_ONE_FIELD_TWICE // Advise by Adobe that we may want to show bothj field but mute audio
|
|
// Make the field2 output twice, FrameChange to 0 (same as previous frame)
|
|
for (j=0; j < VAUX_SECTIONS; j++) {
|
|
pVAux = &pDifSeq->VAux[j];
|
|
if((pVAux->ID0 & ID0_SCT_MASK) != ID0_SCT_VAUX) {
|
|
TRACE(TL_CIP_WARNING,("\'Invalid ID0:%.2x for pVAUX:%x (Dif:%d;V%d;S%d)\n", pVAux->ID0, pVAux, i, j, k));
|
|
continue;
|
|
}
|
|
|
|
for (k=0; k< MAX_VAUX_PACK; k++) {
|
|
if(pVAux->Pack[k].Header == VAUX_HDR_SOURCE_CONTROL) {
|
|
if(bMuteAudio) {
|
|
TRACE(TL_CIP_WARNING,("\'Mute Audio; pDifSeq:%x; pVAux:%x; (Dif:%d,V%d,S%d); %.2x,[%.2x,%.2x,%.2x,%.2x]; pack[2]->%.2x\n", \
|
|
pDifSeq, pVAux, i, j, k, \
|
|
pVAux->Pack[k].Header, pVAux->Pack[k].Data[0], pVAux->Pack[k].Data[1], pVAux->Pack[k].Data[2], pVAux->Pack[k].Data[3], \
|
|
(pVAux->Pack[k].Data[2] & 0x1F) ));
|
|
pVAux->Pack[k].Data[2] &= 0x1f; // 0x1F; // set FF, FS and FC to 0
|
|
TRACE(TL_CIP_TRACE,("\'pVAux->Pack[k].Data[2] = %.2x\n", pVAux->Pack[k].Data[2]));
|
|
} else {
|
|
TRACE(TL_CIP_TRACE,("\'un-Mute Audio; pack[2]: %.2x ->%.2x\n", pVAux->Pack[k].Data[2], (pVAux->Pack[k].Data[2] | 0xc0) ));
|
|
pVAux->Pack[k].Data[2] |= 0xe0; // set FF, FS and FCto 1; Show both fields in field 1,2 order
|
|
}
|
|
bFound1 = TRUE;
|
|
break; // Set only the 1st occurrence
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (j=0; j < AV_SECTIONS; j++) {
|
|
if(pDifSeq->AV[j].A.Pack.Header == AAUX_HDR_SOURCE_CONTROL) {
|
|
TRACE(TL_CIP_TRACE,("\'A0Aux %.2x,[%.2x,%.2x,%.2x,%.2x] %.2x->%.2x\n", \
|
|
pDifSeq->AV[j].A.Pack.Header, pDifSeq->AV[j].A.Pack.Data[0], \
|
|
pDifSeq->AV[j].A.Pack.Data[1], pDifSeq->AV[j].A.Pack.Data[2], pDifSeq->AV[j].A.Pack.Data[3], \
|
|
pDifSeq->AV[j].A.Pack.Data[1], pDifSeq->AV[j].A.Pack.Data[1] | AAUX_REC_MODE_INVALID_MASK
|
|
));
|
|
if(bMuteAudio)
|
|
pDifSeq->AV[j].A.Pack.Data[1] |= AAUX_REC_MODE_INVALID_MASK; // Cause DV to mute this.
|
|
else
|
|
pDifSeq->AV[j].A.Pack.Data[1] = \
|
|
(pDifSeq->AV[j].A.Pack.Data[1] & ~AAUX_REC_MODE_INVALID_MASK) | AAUX_REC_MODE_ORIGINAL;
|
|
bFound2 = TRUE;
|
|
break; // Set only the 1st occurrence
|
|
}
|
|
}
|
|
|
|
// Must do the 1st occurance of all Dif sequences;
|
|
pDifSeq++; // Next DIF sequence
|
|
}
|
|
#ifdef SHOW_ONE_FIELD_TWICE
|
|
return (bFound1 && bFound2);
|
|
#else
|
|
return bFound2;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#ifdef MSDV_SUPPORT_EXTRACT_SUBCODE_DATA
|
|
|
|
VOID
|
|
DVCRExtractTimecodeFromFrame(
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
IN PSTREAMEX pStrmExt,
|
|
IN PUCHAR pFrameBuffer
|
|
)
|
|
{
|
|
PUCHAR pDIFBlk;
|
|
PUCHAR pS0, pS1, pSID0;
|
|
ULONG i, j;
|
|
BYTE LastTimecode[4], Timecode[4]; // hh:mm:ss,ff
|
|
DWORD LastAbsTrackNumber, AbsTrackNumber;
|
|
PUCHAR pSID1;
|
|
BYTE Timecode2[4]; // hh:mm:ss,ff
|
|
DWORD AbsTrackNumber2;
|
|
BOOL bGetAbsT = TRUE, bGetTimecode = TRUE;
|
|
|
|
|
|
// Can be called at DISPATCH_LEVEL
|
|
|
|
pDIFBlk = (PUCHAR) pFrameBuffer;
|
|
|
|
// Save the last timecode so we will now if it has
|
|
|
|
LastTimecode[0] = pStrmExt->Timecode[0];
|
|
LastTimecode[1] = pStrmExt->Timecode[1];
|
|
LastTimecode[2] = pStrmExt->Timecode[2];
|
|
LastTimecode[3] = pStrmExt->Timecode[3];
|
|
|
|
LastAbsTrackNumber = pStrmExt->AbsTrackNumber;
|
|
|
|
//
|
|
// Traverse thru every DIF BLOCK looking for VA0,1 and 2
|
|
for(i=0; i < DVFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfDIFSequences; i++) {
|
|
|
|
pS0 = pDIFBlk + 80;
|
|
pS1 = pS0 + 80;
|
|
|
|
|
|
//
|
|
// Is this Subcode source packet? See Table 36 (P.111) of the Blue Book
|
|
//
|
|
if ((pS0[0] & 0xe0) == 0x20 && (pS1[0] & 0xe0) == 0x20) {
|
|
|
|
if(bGetAbsT) {
|
|
//
|
|
// See Figure 42 (p. 94) of the Blue book
|
|
// SID0(Low nibble),1 (high nibble) of every three subcode sync block can form the ATN
|
|
//
|
|
pSID0 = &pS0[3];
|
|
AbsTrackNumber = 0;
|
|
for (j = 0 ; j < 3; j++) {
|
|
AbsTrackNumber = (( ( (pSID0[0] & 0x0f) << 4) | (pSID0[1] >> 4) ) << (j * 8)) | AbsTrackNumber;
|
|
pSID0 += 8;
|
|
bGetAbsT = FALSE;
|
|
}
|
|
|
|
pSID1 = &pS1[3];
|
|
AbsTrackNumber2 = 0;
|
|
for (j = 0 ; j < 3; j++) {
|
|
AbsTrackNumber2 = (( ( (pSID1[0] & 0x0f) << 4) | (pSID1[1] >> 4) ) << (j * 8)) | AbsTrackNumber2;
|
|
pSID1 += 8;
|
|
}
|
|
|
|
// Verify that the track number is the same!
|
|
if(AbsTrackNumber == AbsTrackNumber2) {
|
|
|
|
bGetAbsT = FALSE;
|
|
} else {
|
|
bGetAbsT = TRUE;
|
|
TRACE(TL_CIP_TRACE,("\'%d Sequence; AbsT (%d,%d) != AbsT2 (%d,%d)\n",
|
|
i,
|
|
AbsTrackNumber / 2, AbsTrackNumber & 0x01,
|
|
AbsTrackNumber2 / 2, AbsTrackNumber2 & 0x01
|
|
));
|
|
}
|
|
}
|
|
|
|
|
|
if(bGetTimecode) {
|
|
// See Figure 68 (p. 114) of the Blue Book
|
|
// Subcode sync block number 3, 4 and 5
|
|
for(j = 3; j <= 5; j++) {
|
|
// 3 bytes of IDs and follow by sequence of 8 bytes SyncBlock (3:5);
|
|
// 0x13 == TIMECODE
|
|
if(pS0[3+3+j*8] == 0x13
|
|
&& pS0[3+3+j*8+4] != 0xff
|
|
&& pS0[3+3+j*8+3] != 0xff
|
|
&& pS0[3+3+j*8+2] != 0xff
|
|
&& pS0[3+3+j*8+1] != 0xff) {
|
|
|
|
Timecode[0] = pS0[3+3+j*8+4]&0x3f; // hh
|
|
Timecode[1] = pS0[3+3+j*8+3]&0x7f; // mm
|
|
Timecode[2] = pS0[3+3+j*8+2]&0x7f; // ss
|
|
Timecode[3] = pS0[3+3+j*8+1]&0x3f; // ff
|
|
|
|
bGetTimecode = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Subcode sync block number 9, 10 and 11
|
|
for(j = 3; j <= 5; j++) {
|
|
// 3 bytes of IDs and follow by sequence of 8 bytes SyncBlock (3:5);
|
|
// 0x13 == TIMECODE
|
|
if(pS1[3+3+j*8] == 0x13
|
|
&& pS1[3+3+j*8+4] != 0xff
|
|
&& pS1[3+3+j*8+3] != 0xff
|
|
&& pS1[3+3+j*8+2] != 0xff
|
|
&& pS1[3+3+j*8+1] != 0xff) {
|
|
|
|
Timecode2[0] = pS1[3+3+j*8+4]&0x3f; // hh
|
|
Timecode2[1] = pS1[3+3+j*8+3]&0x7f; // mm
|
|
Timecode2[2] = pS1[3+3+j*8+2]&0x7f; // ss
|
|
Timecode2[3] = pS1[3+3+j*8+1]&0x3f; // ff
|
|
|
|
bGetTimecode = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Verify
|
|
//
|
|
if(!bGetTimecode) {
|
|
|
|
if( Timecode[0] == Timecode2[0]
|
|
&& Timecode[1] == Timecode2[1]
|
|
&& Timecode[2] == Timecode2[2]
|
|
&& Timecode[3] == Timecode2[3]) {
|
|
|
|
} else {
|
|
bGetTimecode = TRUE;
|
|
TRACE(TL_CIP_TRACE,("\'%d Sequence; %.2x:%.2x:%.2x,%.2x != %.2x:%.2x:%.2x,%.2x\n",
|
|
i,
|
|
Timecode[0], Timecode[1], Timecode[2], Timecode[3],
|
|
Timecode2[0], Timecode2[1], Timecode2[2], Timecode2[3]
|
|
));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!bGetAbsT && !bGetTimecode)
|
|
break;
|
|
|
|
pDIFBlk += DIFBLK_SIZE; // Get to next block
|
|
|
|
}
|
|
|
|
if(!bGetAbsT && pStrmExt->AbsTrackNumber != AbsTrackNumber) {
|
|
pStrmExt->AbsTrackNumber = AbsTrackNumber; // BF is the LSB
|
|
pStrmExt->bATNUpdated = TRUE;
|
|
TRACE(TL_CIP_TRACE,("\'Extracted TrackNum:%d; DicontBit:%d\n", AbsTrackNumber / 2, AbsTrackNumber & 0x01));
|
|
}
|
|
|
|
if(!bGetTimecode &&
|
|
(
|
|
Timecode[0] != LastTimecode[0] ||
|
|
Timecode[1] != LastTimecode[1] ||
|
|
Timecode[2] != LastTimecode[2] ||
|
|
Timecode[3] != LastTimecode[3]
|
|
)
|
|
) {
|
|
pStrmExt->Timecode[0] = Timecode[0]; // hh
|
|
pStrmExt->Timecode[1] = Timecode[1]; // mm
|
|
pStrmExt->Timecode[2] = Timecode[2]; // mm
|
|
pStrmExt->Timecode[3] = Timecode[3]; // ff
|
|
pStrmExt->bTimecodeUpdated = TRUE;
|
|
|
|
TRACE(TL_CIP_TRACE,("\'Extracted Timecode %.2x:%.2x:%.2x,%.2x\n", Timecode[0], Timecode[1], Timecode[2], Timecode[3]));
|
|
}
|
|
}
|
|
|
|
#endif // MSDV_SUPPORT_EXTRACT_SUBCODE_DATA
|
|
|
|
|
|
#ifdef MSDV_SUPPORT_EXTRACT_DV_DATE_TIME
|
|
|
|
VOID
|
|
DVCRExtractRecDateAndTimeFromFrame(
|
|
IN PDVCR_EXTENSION pDevExt,
|
|
IN PSTREAMEX pStrmExt,
|
|
IN PUCHAR pFrameBuffer
|
|
)
|
|
{
|
|
PUCHAR pDIFBlk;
|
|
PUCHAR pS0, pS1;
|
|
ULONG i, j;
|
|
BOOL bGetRecDate = TRUE, bGetRecTime = TRUE;
|
|
|
|
// Can be called at DISPATCH_LEVEL
|
|
|
|
|
|
pDIFBlk = (PUCHAR) pFrameBuffer + DIFBLK_SIZE * DVFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfDIFSequences/2;
|
|
|
|
|
|
//
|
|
// REC Data (VRD) and Time (VRT) on in the 2nd half oa a video frame
|
|
//
|
|
for(i=DVFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfDIFSequences/2; i < DVFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfDIFSequences; i++) {
|
|
|
|
pS0 = pDIFBlk + 80;
|
|
pS1 = pS0 + 80;
|
|
|
|
|
|
//
|
|
// Find SC0 and SC1. See Table 36 (P.111) of the Blue Book
|
|
//
|
|
// SC0/1: ID(0,1,2), Data (3,50), Reserved(51-79)
|
|
// SC0:Data: SSYB0(3..10), SSYB1(11..18), SSYB2(19..26), SSYB3(27..34), SSYB4(35..42), SSYB5(43..50)
|
|
// SC1:Data: SSYB6(3..10), SSYB7(11..18), SSYB8(19..26), SSYB9(27..34), SSYB10(35..42), SSYB11(43..50)
|
|
// SSYBx(SubCodeId0, SubcodeID1, Reserved, Pack(3,4,5,6,7))
|
|
//
|
|
// TTC are in the 1st half: SSYB0..11 (every)
|
|
// TTC are in the 2nd half: SSYB0,3,6,9
|
|
// VRD are in the 2nd half of a video frame, SSYB1,4,7,10
|
|
// VRT are in the 2nd half of a video frame, SSYB2,5,8,11
|
|
//
|
|
|
|
// Subcode data ?
|
|
if ((pS0[0] & 0xe0) == 0x20 && (pS1[0] & 0xe0) == 0x20) {
|
|
|
|
//
|
|
// RecDate: VRD
|
|
//
|
|
if(bGetRecDate) {
|
|
// go thru 6 sync blocks (8 bytes per block) per Subcode; idx 1(SSYB1),4(SSYB4) for SC0
|
|
for(j=0; j <= 5 ; j++) {
|
|
if(j == 1 || j == 4) {
|
|
// 0x62== RecDate
|
|
if(pS0[3+3+j*8] == 0x62) {
|
|
pStrmExt->RecDate[0] = pS0[3+3+j*8+4]; // Year
|
|
pStrmExt->RecDate[1] = pS0[3+3+j*8+3]&0x1f; // Month
|
|
pStrmExt->RecDate[2] = pS0[3+3+j*8+2]&0x3f; // Day
|
|
pStrmExt->RecDate[3] = pS0[3+3+j*8+1]&0x3f; // TimeZone
|
|
bGetRecDate = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(bGetRecDate) {
|
|
// go thru 6 sync blocks (8 bytes per block) per Subcode; idx 1 (SSYB7),4(SSYB10) for SC1
|
|
for(j=0; j <= 5; j++) {
|
|
if(j == 1 || j == 4) {
|
|
// 0x62== RecDate
|
|
if(pS1[3+3+j*8] == 0x62) {
|
|
pStrmExt->RecDate[0] = pS1[3+3+j*8+4]; // Year
|
|
pStrmExt->RecDate[1] = pS1[3+3+j*8+3]&0x1f; // Month
|
|
pStrmExt->RecDate[2] = pS1[3+3+j*8+2]&0x3f; // Day
|
|
pStrmExt->RecDate[3] = pS1[3+3+j*8+1]&0x3f; // TimeZone
|
|
bGetRecDate = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// RecTime: VRT
|
|
//
|
|
if(bGetRecTime) {
|
|
// go thru 6 sync blocks (8 bytes per block) per Subcode; idx 2(SSYB2),5(SSYB5) for SC0
|
|
for(j=0; j <= 5 ; j++) {
|
|
if(j == 2 || j == 5) {
|
|
// 0x63== RecTime
|
|
if(pS0[3+3+j*8] == 0x63) {
|
|
pStrmExt->RecTime[0] = pS0[3+3+j*8+4]&0x3f;
|
|
pStrmExt->RecTime[1] = pS0[3+3+j*8+3]&0x7f;
|
|
pStrmExt->RecTime[2] = pS0[3+3+j*8+2]&0x7f;
|
|
pStrmExt->RecTime[3] = pS0[3+3+j*8+1]&0x3f;
|
|
bGetRecTime = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(bGetRecTime) {
|
|
// go thru 6 sync blocks (8 bytes per block) per Subcode; idx 2 (SSYB8),5(SSYB11) for SC1
|
|
for(j=0; j <= 5; j++) {
|
|
if(j == 2 || j == 5) {
|
|
// 0x63== RecTime
|
|
if(pS1[3+3+j*8] == 0x63) {
|
|
pStrmExt->RecTime[0] = pS1[3+3+j*8+4]&0x3f;
|
|
pStrmExt->RecTime[1] = pS1[3+3+j*8+3]&0x7f;
|
|
pStrmExt->RecTime[2] = pS1[3+3+j*8+2]&0x7f;
|
|
pStrmExt->RecTime[3] = pS1[3+3+j*8+1]&0x3f;
|
|
bGetRecTime = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if(!bGetRecDate && !bGetRecTime)
|
|
break;
|
|
|
|
pDIFBlk += DIFBLK_SIZE; // Next sequence
|
|
|
|
}
|
|
|
|
TRACE(TL_CIP_TRACE,("\'Frame# %.5d, Date %s %x-%.2x-%.2x, Time %s %.2x:%.2x:%.2x,%.2x\n",
|
|
(ULONG) pStrmExt->FramesProcessed,
|
|
bGetRecDate ? "NF:" : "Found:", pStrmExt->RecDate[0], pStrmExt->RecDate[1] & 0x1f, pStrmExt->RecDate[2] & 0x3f,
|
|
bGetRecTime ? "NF:" : "Found:",pStrmExt->RecTime[0], pStrmExt->RecTime[1], pStrmExt->RecTime[2], pStrmExt->RecTime[3]
|
|
));
|
|
}
|
|
|
|
#endif // MSDV_SUPPORT_EXTRACT_DV_DATE_TIME
|
|
|
|
#ifdef READ_CUTOMIZE_REG_VALUES
|
|
|
|
NTSTATUS
|
|
CreateRegistryKeySingle(
|
|
IN HANDLE hKey,
|
|
IN ACCESS_MASK desiredAccess,
|
|
PWCHAR pwszSection,
|
|
OUT PHANDLE phKeySection
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING ustr;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
|
|
RtlInitUnicodeString(&ustr, pwszSection);
|
|
InitializeObjectAttributes(
|
|
&objectAttributes,
|
|
&ustr,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hKey,
|
|
NULL
|
|
);
|
|
|
|
status =
|
|
ZwCreateKey(
|
|
phKeySection,
|
|
desiredAccess,
|
|
&objectAttributes,
|
|
0,
|
|
NULL, /* optional*/
|
|
REG_OPTION_NON_VOLATILE,
|
|
NULL
|
|
);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CreateRegistrySubKey(
|
|
IN HANDLE hKey,
|
|
IN ACCESS_MASK desiredAccess,
|
|
PWCHAR pwszSection,
|
|
OUT PHANDLE phKeySection
|
|
)
|
|
{
|
|
UNICODE_STRING ustr;
|
|
USHORT usPos = 1; // Skip first backslash
|
|
static WCHAR wSep = '\\';
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
RtlInitUnicodeString(&ustr, pwszSection);
|
|
|
|
while(usPos < ustr.Length) {
|
|
if(ustr.Buffer[usPos] == wSep) {
|
|
|
|
// NULL terminate our partial string
|
|
ustr.Buffer[usPos] = UNICODE_NULL;
|
|
status =
|
|
CreateRegistryKeySingle(
|
|
hKey,
|
|
desiredAccess,
|
|
ustr.Buffer,
|
|
phKeySection
|
|
);
|
|
ustr.Buffer[usPos] = wSep;
|
|
|
|
if(NT_SUCCESS(status)) {
|
|
ZwClose(*phKeySection);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
usPos++;
|
|
}
|
|
|
|
// Create the full key
|
|
if(NT_SUCCESS(status)) {
|
|
status =
|
|
CreateRegistryKeySingle(
|
|
hKey,
|
|
desiredAccess,
|
|
ustr.Buffer,
|
|
phKeySection
|
|
);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetRegistryKeyValue (
|
|
IN HANDLE Handle,
|
|
IN PWCHAR KeyNameString,
|
|
IN ULONG KeyNameStringLength,
|
|
IN PVOID Data,
|
|
IN PULONG DataLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets the specified value out of the registry
|
|
|
|
Arguments:
|
|
|
|
Handle - Handle to location in registry
|
|
|
|
KeyNameString - registry key we're looking for
|
|
|
|
KeyNameStringLength - length of registry key we're looking for
|
|
|
|
Data - where to return the data
|
|
|
|
DataLength - how big the data is
|
|
|
|
Return Value:
|
|
|
|
status is returned from ZwQueryValueKey
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
|
|
UNICODE_STRING keyName;
|
|
ULONG length;
|
|
PKEY_VALUE_FULL_INFORMATION fullInfo;
|
|
|
|
|
|
RtlInitUnicodeString(&keyName, KeyNameString);
|
|
|
|
length = sizeof(KEY_VALUE_FULL_INFORMATION) +
|
|
KeyNameStringLength + *DataLength;
|
|
|
|
fullInfo = ExAllocatePool(PagedPool, length);
|
|
|
|
if (fullInfo) {
|
|
|
|
status = ZwQueryValueKey(
|
|
Handle,
|
|
&keyName,
|
|
KeyValueFullInformation,
|
|
fullInfo,
|
|
length,
|
|
&length
|
|
);
|
|
|
|
if (NT_SUCCESS(status)){
|
|
|
|
ASSERT(fullInfo->DataLength <= *DataLength);
|
|
|
|
RtlCopyMemory(
|
|
Data,
|
|
((PUCHAR) fullInfo) + fullInfo->DataOffset,
|
|
fullInfo->DataLength
|
|
);
|
|
|
|
}
|
|
|
|
*DataLength = fullInfo->DataLength;
|
|
ExFreePool(fullInfo);
|
|
|
|
}
|
|
|
|
return (status);
|
|
|
|
}
|
|
|
|
|
|
#if 0 // Not used
|
|
NTSTATUS
|
|
SetRegistryKeyValue(
|
|
HANDLE hKey,
|
|
PWCHAR pwszEntry,
|
|
LONG nValue
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING ustr;
|
|
|
|
RtlInitUnicodeString(&ustr, pwszEntry);
|
|
|
|
status =
|
|
ZwSetValueKey(
|
|
hKey,
|
|
&ustr,
|
|
0, /* optional */
|
|
REG_DWORD,
|
|
&nValue,
|
|
sizeof(nValue)
|
|
);
|
|
|
|
return status;
|
|
}
|
|
#endif // Not used
|
|
|
|
//
|
|
// Registry subky and values wide character strings.
|
|
//
|
|
WCHAR wszSettings[] = L"Settings";
|
|
|
|
WCHAR wszATNSearch[] = L"bSupportATNSearch";
|
|
WCHAR wszSyncRecording[] = L"bSyncRecording";
|
|
WCHAR wszMaxDataSync[] = L"tmMaxDataSync";
|
|
WCHAR wszPlayPs2RecPs[] = L"fmPlayPause2RecPause";
|
|
WCHAR wszStop2RecPs[] = L"fmStop2RecPause";
|
|
WCHAR wszRecPs2Rec[] = L"tmRecPause2Rec";
|
|
WCHAR wszXprtStateChangeWait[] = L"tmXprtStateChangeWait";
|
|
|
|
BOOL
|
|
DVGetPropertyValuesFromRegistry(
|
|
IN PDVCR_EXTENSION pDevExt
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE hPDOKey, hKeySettings;
|
|
ULONG ulLength;
|
|
|
|
|
|
//
|
|
// Registry key:
|
|
// Windows 2000:
|
|
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\
|
|
// {6BDD1FC6-810F-11D0-BEC7-08002BE2092F\000x
|
|
//
|
|
// Win98:
|
|
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Class\Image\000x
|
|
//
|
|
Status =
|
|
IoOpenDeviceRegistryKey(
|
|
pDevExt->pPhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DRIVER,
|
|
STANDARD_RIGHTS_READ,
|
|
&hPDOKey
|
|
);
|
|
|
|
// PDO might be deleted when it was removed.
|
|
if(! pDevExt->bDevRemoved) {
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// loop through our table of strings,
|
|
// reading the registry for each.
|
|
//
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
// Create or open the settings key
|
|
Status =
|
|
CreateRegistrySubKey(
|
|
hPDOKey,
|
|
KEY_ALL_ACCESS,
|
|
wszSettings,
|
|
&hKeySettings
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
// Note: we can be more selective by checking
|
|
// pDevExt->ulDevType
|
|
#if 0 // Not supported yet!
|
|
// ATNSearch
|
|
ulLength = sizeof(LONG);
|
|
Status = GetRegistryKeyValue(
|
|
hKeySettings,
|
|
wszATNSearch,
|
|
sizeof(wszATNSearch),
|
|
(PVOID) &pDevExt->bATNSearch,
|
|
&ulLength);
|
|
TRACE(TL_PNP_WARNING,("\'GetRegVal: St:%x, Len:%d, bATNSearch:%d (1:Yes)\n", Status, ulLength, pDevExt->bATNSearch));
|
|
if(!NT_SUCCESS(Status)) pDevExt->bATNSearch = FALSE;
|
|
|
|
// bSyncRecording
|
|
ulLength = sizeof(LONG);
|
|
Status = GetRegistryKeyValue(
|
|
hKeySettings,
|
|
wszSyncRecording,
|
|
sizeof(wszSyncRecording),
|
|
(PVOID) &pDevExt->bSyncRecording,
|
|
&ulLength);
|
|
TRACE(TL_PNP_WARNING,("\'GetRegVal: St:%x, Len:%d, bSyncRecording:%d (1:Yes)\n", Status, ulLength, pDevExt->bSyncRecording));
|
|
if(!NT_SUCCESS(Status)) pDevExt->bSyncRecording = FALSE;
|
|
|
|
// tmMaxDataSync
|
|
ulLength = sizeof(LONG);
|
|
Status = GetRegistryKeyValue(
|
|
hKeySettings,
|
|
wszMaxDataSync,
|
|
sizeof(wszMaxDataSync),
|
|
(PVOID) &pDevExt->tmMaxDataSync,
|
|
&ulLength);
|
|
TRACE(TL_PNP_WARNING,("\'GetRegVal: St:%x, Len:%d, tmMaxDataSync:%d (msec)\n", Status, ulLength, pDevExt->tmMaxDataSync));
|
|
|
|
// fmPlayPs2RecPs
|
|
ulLength = sizeof(LONG);
|
|
Status = GetRegistryKeyValue(
|
|
hKeySettings,
|
|
wszPlayPs2RecPs,
|
|
sizeof(wszPlayPs2RecPs),
|
|
(PVOID) &pDevExt->fmPlayPs2RecPs,
|
|
&ulLength);
|
|
TRACE(TL_PNP_WARNING,("\'GetRegVal: St:%x, Len:%d, fmPlayPs2RecPs:%d (frames)\n", Status, ulLength, pDevExt->fmPlayPs2RecPs));
|
|
|
|
// fmStop2RecPs
|
|
ulLength = sizeof(LONG);
|
|
Status = GetRegistryKeyValue(
|
|
hKeySettings,
|
|
wszStop2RecPs,
|
|
sizeof(wszStop2RecPs),
|
|
(PVOID) &pDevExt->fmStop2RecPs,
|
|
&ulLength);
|
|
TRACE(TL_PNP_WARNING,("\'GetRegVal: St:%x, Len:%d, fmStop2RecPs:%d (frames)\n", Status, ulLength, pDevExt->fmStop2RecPs));
|
|
|
|
// tmRecPs2Rec
|
|
ulLength = sizeof(LONG);
|
|
Status = GetRegistryKeyValue(
|
|
hKeySettings,
|
|
wszRecPs2Rec,
|
|
sizeof(wszRecPs2Rec),
|
|
(PVOID) &pDevExt->tmRecPs2Rec,
|
|
&ulLength);
|
|
TRACE(TL_PNP_WARNING,("\'GetRegVal: St:%x, Len:%d, tmRecPs2Rec:%d (msec)\n", Status, ulLength, pDevExt->tmRecPs2Rec));
|
|
#endif
|
|
ulLength = sizeof(LONG);
|
|
Status = GetRegistryKeyValue(
|
|
hKeySettings,
|
|
wszXprtStateChangeWait,
|
|
sizeof(wszXprtStateChangeWait),
|
|
(PVOID) &pDevExt->XprtStateChangeWait, // in msec
|
|
&ulLength);
|
|
TRACE(TL_PNP_WARNING,("\'GetRegVal: St:%x, Len:%d, XprtStateChangeWait:%d msec\n", Status, ulLength, pDevExt->XprtStateChangeWait));
|
|
if(!NT_SUCCESS(Status)) pDevExt->XprtStateChangeWait = 0;
|
|
|
|
ZwClose(hKeySettings);
|
|
ZwClose(hPDOKey);
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
TRACE(TL_PNP_ERROR,("\'GetPropertyValuesFromRegistry: CreateRegistrySubKey failed with Status=%x\n", Status));
|
|
|
|
}
|
|
|
|
ZwClose(hPDOKey);
|
|
|
|
} else {
|
|
|
|
TRACE(TL_PNP_ERROR,("\'GetPropertyValuesFromRegistry: IoOpenDeviceRegistryKey failed with Status=%x\n", Status));
|
|
|
|
}
|
|
|
|
// Not implemented so always return FALSE to use the defaults.
|
|
return FALSE;
|
|
}
|
|
|
|
#if 0 // Not used
|
|
BOOL
|
|
DVSetPropertyValuesToRegistry(
|
|
PDVCR_EXTENSION pDevExt
|
|
)
|
|
{
|
|
// Set the default to :
|
|
// HLM\Software\DeviceExtension->pchVendorName\1394DCam
|
|
|
|
NTSTATUS Status;
|
|
HANDLE hPDOKey, hKeySettings;
|
|
|
|
TRACE(TL_PNP_TRACE,("\'SetPropertyValuesToRegistry: pDevExt=%x; pDevExt->pBusDeviceObject=%x\n", pDevExt, pDevExt->pBusDeviceObject));
|
|
|
|
|
|
//
|
|
// Registry key:
|
|
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\
|
|
// {6BDD1FC6-810F-11D0-BEC7-08002BE2092F\000x
|
|
//
|
|
Status =
|
|
IoOpenDeviceRegistryKey(
|
|
pDevExt->pPhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DRIVER,
|
|
STANDARD_RIGHTS_WRITE,
|
|
&hPDOKey);
|
|
|
|
// PDO might be deleted when it was removed.
|
|
if(! pDevExt->bDevRemoved) {
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// loop through our table of strings,
|
|
// reading the registry for each.
|
|
//
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
// Create or open the settings key
|
|
Status =
|
|
CreateRegistrySubKey(
|
|
hPDOKey,
|
|
KEY_ALL_ACCESS,
|
|
wszSettings,
|
|
&hKeySettings
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
#if 0 // Note used, just an example:
|
|
// Brightness
|
|
Status = SetRegistryKeyValue(
|
|
hKeySettings,
|
|
wszBrightness,
|
|
pDevExt->XXXX);
|
|
TRACE(TL_PNP_TRACE,("\'SetPropertyValuesToRegistry: Status %x, Brightness %d\n", Status, pDevExt->Brightness));
|
|
|
|
#endif
|
|
ZwClose(hKeySettings);
|
|
ZwClose(hPDOKey);
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
TRACE(TL_PNP_ERROR,("\'GetPropertyValuesToRegistry: CreateRegistrySubKey failed with Status=%x\n", Status));
|
|
|
|
}
|
|
|
|
ZwClose(hPDOKey);
|
|
|
|
} else {
|
|
|
|
TRACE(TL_PNP_TRACE,("\'GetPropertyValuesToRegistry: IoOpenDeviceRegistryKey failed with Status=%x\n", Status));
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
#endif // Not used
|
|
#endif // READ_CUTOMIZE_REG_VALUES
|