windows-nt/Source/XPSP1/NT/drivers/wdm/capture/mini/mstape/mstputil.c
2020-09-26 16:20:57 +08:00

3047 lines
91 KiB
C

/*++
Copyright (C) Microsoft Corporation, 1999 - 2000
Module Name:
MsTpUtil.c
Abstract:
Provide utility functions for MSTAPE.
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 "MsTpAvc.h"
#include "MsTpUtil.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)
#endif
#endif
extern AVCSTRM_FORMAT_INFO AVCStrmFormatInfoTable[];
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 completed; 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
#ifdef SUPPORT_LOCAL_PLUGS
BOOL
AVCTapeCreateLocalPlug(
IN PDVCR_EXTENSION pDevExt,
IN AV_61883_REQUEST * pAVReq,
IN CMP_PLUG_TYPE PlugType,
IN AV_PCR *pPCR,
OUT ULONG *pPlugNumber,
OUT HANDLE *pPlugHandle
)
/*
To be a compliant device, we need to have both input and output
plugs in order to do isoch streaming. These plug is belong to
the device and is part of the device extension. In theory, the
lugs belong to the unit (ei.e. avc.sys) and not this subunit
Driver; however, in this case, we create directly from 61883.sys.
*/
{
NTSTATUS Status = STATUS_SUCCESS;
PIRP pIrp;
pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE);
if(!pIrp)
return FALSE;
// Create a local oPCR
// 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.Context = NULL;
pAVReq->CreatePlug.pfnNotify = NULL;
pAVReq->CreatePlug.PlugType = PlugType;
if(PlugType == CMP_PlugOut)
pAVReq->CreatePlug.Pcr.oPCR = pPCR->oPCR;
else
pAVReq->CreatePlug.Pcr.iPCR = pPCR->iPCR;
Status = DVSubmitIrpSynch(pDevExt, pIrp, pAVReq);
if(!NT_SUCCESS(Status)) {
*pPlugNumber = 0xffffffff;
*pPlugHandle = 0;
TRACE(TL_61883_ERROR,("Av61883_CreatePlug (%s) Failed:%x\n",
PlugType == CMP_PlugOut ? "oPCR":"iPCR", Status));
} else {
*pPlugNumber = pAVReq->CreatePlug.PlugNum;
*pPlugHandle = pAVReq->CreatePlug.hPlug;
TRACE(TL_61883_TRACE,("Av61883_CreatePlug (%s): PlugNum:%d, hPlug:%x\n",
PlugType == CMP_PlugOut ? "oPCR":"iPCR", *pPlugNumber, *pPlugHandle));
#if DBG
if(PlugType == CMP_PlugOut) {
TRACE(TL_61883_WARNING,("Av61883_CreatePlug: oPCR DataRate:%d (%s); Payload:%d, Overhead_ID:0x%x\n",
pPCR->oPCR.DataRate,
(pPCR->oPCR.DataRate == CMP_SPEED_S100) ? "S100" :
(pPCR->oPCR.DataRate == CMP_SPEED_S200) ? "S200" :
(pPCR->oPCR.DataRate == CMP_SPEED_S400) ? "S400" : "Sxxx",
pPCR->oPCR.Payload,
pPCR->oPCR.OverheadID
));
}
#endif
}
IoFreeIrp(pIrp);
pIrp = NULL;
return NT_SUCCESS(Status);
}
BOOL
AVCTapeDeleteLocalPlug(
IN PDVCR_EXTENSION pDevExt,
IN AV_61883_REQUEST * pAVReq,
OUT ULONG *pPlugNumber,
OUT HANDLE *pPlugHandle
)
/*
Delete a local plug.
*/
{
NTSTATUS Status = STATUS_SUCCESS;
PIRP pIrp;
TRACE(TL_61883_TRACE,("Deleting hPlug[%d]:%x\n", *pPlugNumber, *pPlugHandle));
pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE);
if(!pIrp)
return FALSE;
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
INIT_61883_HEADER(pAVReq, Av61883_DeletePlug);
pAVReq->DeletePlug.hPlug = *pPlugHandle;
Status = DVSubmitIrpSynch(pDevExt, pIrp, pAVReq);
if(!NT_SUCCESS(Status)) {
TRACE(TL_61883_ERROR,("Av61883_DeletePlug Failed; ST:%x\n", Status));
// Do not care if this result in error.
} else {
*pPlugNumber = 0xffffffff;
*pPlugHandle = 0;
TRACE(TL_61883_TRACE,("Av61883_DeltePlug suceeded.\n"));
}
IoFreeIrp(pIrp);
pIrp = NULL;
return NT_SUCCESS(Status);
}
BOOL
AVCTapeSetLocalPlug(
IN PDVCR_EXTENSION pDevExt,
IN AV_61883_REQUEST * pAVReq,
IN HANDLE *pPlugHandle,
IN AV_PCR *pPCR
)
/*
Set the content of a local plug.
*/
{
NTSTATUS Status = STATUS_SUCCESS;
PIRP pIrp;
pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE);
if(!pIrp)
return FALSE;
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
INIT_61883_HEADER(pAVReq, Av61883_SetPlug);
pAVReq->SetPlug.hPlug = *pPlugHandle;
pAVReq->SetPlug.Pcr = *pPCR;
TRACE(TL_61883_TRACE,("Av61883_SetPlug hPlug:%x to %x.\n", *pPlugHandle, pPCR->ulongData));
Status = DVSubmitIrpSynch(pDevExt, pIrp, pAVReq);
#if DBG
if(!NT_SUCCESS(Status)) {
TRACE(TL_61883_ERROR,("Av61883_SetPlug to %x Failed; ST:%x\n", pPCR->ulongData, Status));
}
#endif
IoFreeIrp(pIrp);
pIrp = NULL;
return NT_SUCCESS(Status);
}
#endif // SUPPORT_LOCAL_PLUGS
//
// Get device plug and query its state
//
NTSTATUS
AVCDevGetDevPlug(
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;
}
NTSTATUS
AVCDevGetPlugState(
IN PDVCR_EXTENSION pDevExt,
IN HANDLE hPlug,
OUT CMP_GET_PLUG_STATE *pPlugState
)
/*++
Routine Description:
Ask 61883.sys for the plug state.
Arguments:
Return Value:
Nothing
--*/
{
PIRP pIrp;
PAV_61883_REQUEST pAVReq;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
if(!hPlug || !pPlugState)
return STATUS_INVALID_PARAMETER;
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_GetPlugState);
pAVReq->GetPlugState.hPlug = hPlug;
if(NT_SUCCESS(
Status = DVSubmitIrpSynch(
pDevExt,
pIrp,
pAVReq
))) {
//
// Transfer plug state (note: these are dynamic values)
//
*pPlugState = pAVReq->GetPlugState;
TRACE(TL_61883_WARNING,("GetPlugState: ST %x; State %x; DRate %d (%s); Payld %d; BCCnt %d; PPCnt %d\n",
pAVReq->Flags ,
pAVReq->GetPlugState.State,
pAVReq->GetPlugState.DataRate,
(pAVReq->GetPlugState.DataRate == CMP_SPEED_S100) ? "S100" :
(pAVReq->GetPlugState.DataRate == CMP_SPEED_S200) ? "S200" :
(pAVReq->GetPlugState.DataRate == CMP_SPEED_S400) ? "S400" : "Sxxx",
pAVReq->GetPlugState.Payload,
pAVReq->GetPlugState.BC_Connections,
pAVReq->GetPlugState.PP_Connections
));
}
else {
TRACE(TL_61883_ERROR,("GetPlugState Failed %x\n", Status));
}
IoFreeIrp(pIrp); pIrp = NULL;
ExFreePool(pAVReq); pAVReq = NULL;
return Status;
}
#ifndef NT51_61883
NTSTATUS
AVCDevSubmitIrpSynch1394(
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp,
IN PIRB pIrb
)
{
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_1394_CLASS;
NextIrpStack->Parameters.Others.Argument1 = pIrb;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
IoSetCompletionRoutine(
pIrp,
DVIrpSynchCR,
&Event,
TRUE,
TRUE,
TRUE
);
Status =
IoCallDriver(
pDevObj,
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 completed; 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;
} // AVCDevSubmitIrpSynch1394
NTSTATUS
Av1394_GetGenerationCount(
IN PDVCR_EXTENSION pDevExt,
OUT PULONG pGenerationCount
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PIRP pIrp = NULL;
PIRB p1394Irb = NULL;
CCHAR StackSize;
PAGED_CODE();
StackSize = pDevExt->pBusDeviceObject->StackSize;
pIrp = IoAllocateIrp(StackSize, FALSE);
p1394Irb = ExAllocatePool(NonPagedPool, sizeof(IRB));
if ((pIrp == NULL) || (p1394Irb == NULL)) {
TRACE(TL_PNP_ERROR, ("Failed to allocate pIrp (%x) or p1394Irb (%x)", pIrp, p1394Irb));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Exit_GetGenerationCount;
}
//
// Get the current generation count first
//
p1394Irb->FunctionNumber = REQUEST_GET_GENERATION_COUNT;
p1394Irb->Flags = 0;
ntStatus = AVCDevSubmitIrpSynch1394(pDevExt->pBusDeviceObject, pIrp, p1394Irb);
if (!NT_SUCCESS(ntStatus)) {
TRACE(TL_PNP_ERROR, ("REQUEST_GET_GENERATION_COUNT Failed %x", ntStatus));
goto Exit_GetGenerationCount;
}
*pGenerationCount = p1394Irb->u.GetGenerationCount.GenerationCount;
Exit_GetGenerationCount:
if(pIrp) {
IoFreeIrp(pIrp); pIrp = NULL;
}
if(p1394Irb) {
ExFreePool(p1394Irb); p1394Irb = NULL;
}
return(ntStatus);
} // Av1394_GetGenerationCount
#define RETRY_COUNT 4
//
// IEEE 1212 Directory definition
//
typedef struct _DIRECTORY_INFO {
union {
USHORT DI_CRC;
USHORT DI_Saved_Length;
} u;
USHORT DI_Length;
} DIRECTORY_INFO, *PDIRECTORY_INFO;
//
// IEEE 1212 Immediate entry definition
//
typedef struct _IMMEDIATE_ENTRY {
ULONG IE_Value:24;
ULONG IE_Key:8;
} IMMEDIATE_ENTRY, *PIMMEDIATE_ENTRY;
NTSTATUS
Av1394_QuadletRead(
IN PDVCR_EXTENSION pDevExt,
IN OUT PULONG pData,
IN ULONG Address
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PIRP pIrp;
PIRB p1394Irb;
PMDL Mdl = NULL;
ULONG Retries = RETRY_COUNT;
CCHAR StackSize;
PAGED_CODE();
StackSize = pDevExt->pBusDeviceObject->StackSize;
pIrp = IoAllocateIrp(StackSize, FALSE);
p1394Irb = ExAllocatePool(NonPagedPool, sizeof(IRB));
if ((pIrp == NULL) || (p1394Irb == NULL)) {
TRACE(TL_PNP_ERROR, ("Failed to allocate Irp (0x%x) or Irb (0x%x)", pIrp, p1394Irb));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Exit_Av1394_QuadletRead;
}
Mdl = IoAllocateMdl(pData, sizeof(ULONG), FALSE, FALSE, NULL);
if (!Mdl) {
TRACE(TL_PNP_ERROR, ("Failed to allocate Mdl!"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Exit_Av1394_QuadletRead;
}
MmBuildMdlForNonPagedPool(Mdl);
do {
p1394Irb->FunctionNumber = REQUEST_ASYNC_READ;
p1394Irb->Flags = 0;
p1394Irb->u.AsyncRead.DestinationAddress.IA_Destination_Offset.Off_High = (USHORT)0xffff;
p1394Irb->u.AsyncRead.DestinationAddress.IA_Destination_Offset.Off_Low = Address;
p1394Irb->u.AsyncRead.nNumberOfBytesToRead = 4;
p1394Irb->u.AsyncRead.nBlockSize = 0;
p1394Irb->u.AsyncRead.fulFlags = 0;
p1394Irb->u.AsyncRead.Mdl = Mdl;
p1394Irb->u.AsyncRead.ulGeneration = pDevExt->GenerationCount;
p1394Irb->u.AsyncRead.chPriority = 0;
p1394Irb->u.AsyncRead.nSpeed = 0;
p1394Irb->u.AsyncRead.tCode = 0;
p1394Irb->u.AsyncRead.Reserved = 0;
ntStatus = AVCDevSubmitIrpSynch1394(pDevExt->pBusDeviceObject, pIrp, p1394Irb);
if (ntStatus == STATUS_INVALID_GENERATION) {
TRACE(TL_PNP_WARNING, ("QuadletRead: Invalid GenerationCount = %d", pDevExt->GenerationCount));
Av1394_GetGenerationCount(pDevExt, &pDevExt->GenerationCount);
}
else if (!NT_SUCCESS(ntStatus)) {
TRACE(TL_PNP_ERROR, ("Av1394_QuadletRead Failed = 0x%x Address = 0x%x", ntStatus, Address));
}
else {
goto Exit_Av1394_QuadletRead;
}
} while ((ntStatus == STATUS_INVALID_GENERATION) || (Retries--));
Exit_Av1394_QuadletRead:
if(pIrp) {
IoFreeIrp(pIrp); pIrp = NULL;
}
if(p1394Irb) {
ExFreePool(p1394Irb); p1394Irb = NULL;
}
if(Mdl) {
IoFreeMdl(Mdl); Mdl = NULL;
}
return(ntStatus);
} // Av1394_QuadletRead
#define KEY_ModuleVendorId (0x03)
#define KEY_ModuleHwVersion (0x04)
#define KEY_UnitSwVersion (0x13)
#define KEY_ModelId (0x17)
#define DEVICE_NAME_MAX_CHARS 100*sizeof(WCHAR)
NTSTATUS
Av1394_ReadTextualDescriptor(
IN PDVCR_EXTENSION pDevExt,
IN OUT PUNICODE_STRING uniString,
IN ULONG Address
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PULONG pData = NULL;
ULONG DataLength, i, n;
ULONG ulUnicode;
ULONG ulQuadlet;
union {
ULONG asUlong;
UCHAR asUchar[4];
DIRECTORY_INFO DirectoryHeader;
} u;
PAGED_CODE();
TRACE(TL_PNP_TRACE, ("Address = 0x%x", Address));
// read the first quadlet of leaf, this is the header
ntStatus = Av1394_QuadletRead(pDevExt, &ulQuadlet, Address);
if (!NT_SUCCESS(ntStatus)) {
TRACE(TL_PNP_ERROR, ("GetUnitInfo: QuadletRead Error = 0x%x", ntStatus));
goto Exit_Av1394_ReadTextualDescriptor;
}
// number of entries
u.asUlong = bswap(ulQuadlet);
DataLength = u.DirectoryHeader.DI_Length-2; // one extra for the header
// read the second quadlet of leaf to determine unicode
Address += 4;
ntStatus = Av1394_QuadletRead(pDevExt, &ulQuadlet, Address);
if (!NT_SUCCESS(ntStatus)) {
TRACE(TL_PNP_ERROR, ("GetUnitInfo: QuadletRead Error = 0x%x", ntStatus));
goto Exit_Av1394_ReadTextualDescriptor;
}
// save spec type
ulUnicode = bswap(ulQuadlet);
pData = ExAllocatePool(NonPagedPool, DataLength*sizeof(ULONG)+2);
if (pData == NULL) {
TRACE(TL_PNP_ERROR, ("Failed to allocate pData"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Exit_Av1394_ReadTextualDescriptor;
}
RtlZeroMemory(pData, DataLength*sizeof(ULONG)+2);
// lets read in each quad
Address += 8;
for (i=0; i<DataLength; i++) {
ntStatus = Av1394_QuadletRead(pDevExt, &u.asUlong, Address+(sizeof(ULONG)*i));
if (!NT_SUCCESS(ntStatus)) {
TRACE(TL_PNP_ERROR, ("GetUnitInfo: QuadletRead Error = 0x%x", ntStatus));
goto Exit_Av1394_ReadTextualDescriptor;
}
// need to make sure we have valid characters...
for (n=0; n<4; n++) {
// we should be done if the char equals 0x00
if (u.asUchar[n] == 0x00)
break;
if ((u.asUchar[n] == 0x2C) || (u.asUchar[n] < 0x20) || (u.asUchar[n] > 0x7F)) {
TRACE(TL_PNP_WARNING, ("Invalid Character = 0x%x", u.asUchar[n]));
// set it to space
u.asUchar[n] = 0x20;
}
if (ulUnicode & 0x80000000)
n++;
}
RtlCopyMemory((PULONG)pData+i, &u.asUlong, sizeof(ULONG));
}
// if there's a vendor leaf, then convert it to unicode
{
ANSI_STRING ansiString;
uniString->Length = 0;
uniString->MaximumLength = DEVICE_NAME_MAX_CHARS;
uniString->Buffer = ExAllocatePool(NonPagedPool, uniString->MaximumLength);
if (!uniString->Buffer) {
TRACE(TL_PNP_ERROR, ("Failed to allocate uniString.Buffer!"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Exit_Av1394_ReadTextualDescriptor;
}
RtlZeroMemory(uniString->Buffer, uniString->MaximumLength);
// unicode??
if (ulUnicode & 0x80000000) {
RtlAppendUnicodeToString(uniString, ((PWSTR)pData));
}
else {
RtlInitAnsiString(&ansiString, (PUCHAR)pData);
RtlAnsiStringToUnicodeString(uniString, &ansiString, FALSE);
}
}
Exit_Av1394_ReadTextualDescriptor:
if (pData)
ExFreePool(pData);
return(ntStatus);
} // ReadTextualLeaf
NTSTATUS
AVCDevGetModelText(
IN PDVCR_EXTENSION pDevExt,
PUNICODE_STRING pUniRootModelString,
PUNICODE_STRING pUniUnitModelString
)
{
CCHAR StackSize;
PIRP pIrp = NULL;
PIRB p1394Irb = NULL;
NTSTATUS ntStatus = STATUS_SUCCESS;
CONFIG_ROM ConfigRom;
ULONG ulQuadlet = 0;
ULONG CurrAddress;
PULONG UnitDir = NULL, UnitDirToFree = NULL;
ULONG i;
ULONG LastKey;
union {
ULONG asUlong;
DIRECTORY_INFO DirInfo;
IMMEDIATE_ENTRY Entry;
} u, u2; //, u3;
PAGED_CODE();
StackSize = pDevExt->pBusDeviceObject->StackSize;
pIrp = IoAllocateIrp(StackSize, FALSE);
p1394Irb = ExAllocatePool(NonPagedPool, sizeof(IRB));
if ((pIrp == NULL) || (p1394Irb == NULL)) {
TRACE(TL_PNP_ERROR, ("Failed to allocate pIrp (%x) or p1394Irb (%x)", pIrp, p1394Irb));
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Get the current generation count (used to read config rom)
//
Av1394_GetGenerationCount(pDevExt, &pDevExt->GenerationCount);
//
// Get Model Text from the Root directory
//
CurrAddress = 0xF0000414;
// root directory
ntStatus = Av1394_QuadletRead(pDevExt, &ulQuadlet, CurrAddress);
if (!NT_SUCCESS(ntStatus)) {
TRACE(TL_PNP_ERROR, ("GetUnitInfo: QuadletRead Error = 0x%x", ntStatus));
goto Exit_GetUnitInfo;
}
u.asUlong = bswap(ulQuadlet);
TRACE(TL_PNP_TRACE, ("RootDir: Length = %d", u.DirInfo.DI_Length));
// process the root directory
for (i=0; i<u.DirInfo.DI_Length; i++) {
CurrAddress += sizeof(ULONG);
ntStatus = Av1394_QuadletRead(pDevExt, &ulQuadlet, CurrAddress);
if (!NT_SUCCESS(ntStatus)) {
TRACE(TL_PNP_ERROR, ("GetUnitInfo: QuadletRead Error = 0x%x", ntStatus));
goto Exit_GetUnitInfo;
}
u2.asUlong = bswap(ulQuadlet);
TRACE(TL_PNP_TRACE, ("CurrAddress = 0x%x Key = 0x%x Value = 0x%x",
CurrAddress, u2.Entry.IE_Key, u2.Entry.IE_Value));
// ModelId Textual Descriptor
if ((u2.Entry.IE_Key == 0x81) && (LastKey == KEY_ModelId)) {
// get the first entry of the textual descriptor
Av1394_ReadTextualDescriptor( pDevExt,
pUniRootModelString,
CurrAddress+(u2.Entry.IE_Value*sizeof(ULONG))
);
}
#if 0
// ModelId Textual Descriptor Layer
if ((u2.Entry.IE_Key == 0xC1) && (LastKey == KEY_ModelId)) {
ULONG DescAddress;
DescAddress = CurrAddress+(u2.Entry.IE_Value*sizeof(ULONG));
Av1394_QuadletRead(pDevExt, &ulQuadlet, DescAddress);
u3.asUlong = bswap(ulQuadlet);
// get the first entry of the textual descriptor
Av1394_ReadTextualDescriptor( pDevExt,
pUniRootModelString,
DescAddress+(u3.Entry.IE_Value*sizeof(ULONG))
);
}
#endif
LastKey = u2.Entry.IE_Key;
}
//
// Get Configuration Info
//
p1394Irb->FunctionNumber = REQUEST_GET_CONFIGURATION_INFO;
p1394Irb->Flags = 0;
p1394Irb->u.GetConfigurationInformation.ConfigRom = NULL;
p1394Irb->u.GetConfigurationInformation.UnitDirectoryBufferSize = 0;
p1394Irb->u.GetConfigurationInformation.UnitDirectory = NULL;
p1394Irb->u.GetConfigurationInformation.UnitDependentDirectoryBufferSize = 0;
p1394Irb->u.GetConfigurationInformation.UnitDependentDirectory = NULL;
p1394Irb->u.GetConfigurationInformation.VendorLeafBufferSize = 0;
p1394Irb->u.GetConfigurationInformation.VendorLeaf = NULL;
p1394Irb->u.GetConfigurationInformation.ModelLeafBufferSize = 0;
p1394Irb->u.GetConfigurationInformation.ModelLeaf = NULL;
ntStatus = AVCDevSubmitIrpSynch1394(pDevExt->pBusDeviceObject, pIrp, p1394Irb);
if (!NT_SUCCESS(ntStatus)) {
TRACE(TL_PNP_ERROR, ("REQUEST_GET_CONFIGURATION_INFO Failed %x", ntStatus));
goto Exit_GetUnitInfo;
}
//
// Allocate buffer in order retrieve unit directory of a config rom
//
if (p1394Irb->u.GetConfigurationInformation.UnitDirectoryBufferSize) {
UnitDir = UnitDirToFree =
p1394Irb->u.GetConfigurationInformation.UnitDirectory =
ExAllocatePool(NonPagedPool, p1394Irb->u.GetConfigurationInformation.UnitDirectoryBufferSize);
if (!p1394Irb->u.GetConfigurationInformation.UnitDirectory) {
TRACE(TL_PNP_ERROR, ("Couldn't allocate memory for the UnitDirectory"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Exit_GetUnitInfo;
}
}
else {
TRACE(TL_PNP_ERROR, ("No Unit directory. Bad Device."));
ntStatus = STATUS_BAD_DEVICE_TYPE;
goto Exit_GetUnitInfo;
}
p1394Irb->u.GetConfigurationInformation.ConfigRom = &ConfigRom;
p1394Irb->u.GetConfigurationInformation.UnitDependentDirectoryBufferSize = 0;
p1394Irb->u.GetConfigurationInformation.VendorLeafBufferSize = 0;
p1394Irb->u.GetConfigurationInformation.ModelLeafBufferSize = 0;
ntStatus = AVCDevSubmitIrpSynch1394(pDevExt->pBusDeviceObject, pIrp, p1394Irb);
if (!NT_SUCCESS(ntStatus)) {
TRACE(TL_PNP_ERROR, ("2nd REQUEST_GET_CONFIGURATION_INFO Failed = 0x%x", ntStatus));
goto Exit_GetUnitInfo;
}
//
// Process unit directory; see this doc for detail:
// 1394TA specification: Configuration ROM for AV/C device 1.0 (AVWG)
//
u.asUlong = bswap(*UnitDir++); // Get length, and dkip first quadlet
TRACE(TL_PNP_TRACE, ("UnitDir: Length = %d", u.DirInfo.DI_Length));
CurrAddress = p1394Irb->u.GetConfigurationInformation.UnitDirectoryLocation.IA_Destination_Offset.Off_Low;
for (i=0; i<u.DirInfo.DI_Length; i++) {
TRACE(TL_PNP_TRACE, ("i = %d UnitDir = 0x%x *UnitDir = 0x%x", i, UnitDir, *UnitDir));
u2.asUlong = bswap(*UnitDir++);
CurrAddress += sizeof(ULONG);
TRACE(TL_PNP_TRACE, ("UnitDir Quadlet = 0x%x", u2.asUlong));
//
// ModelId Textual Descriptor
//
if ((u2.Entry.IE_Key == 0x81) && (LastKey == KEY_ModelId)) {
// get the first entry of the textual descriptor
Av1394_ReadTextualDescriptor(
pDevExt,
pUniUnitModelString,
CurrAddress+(u2.Entry.IE_Value*sizeof(ULONG))
);
}
#if 0
//
// UnitModelId Textual Descriptor Layer
//
if ((u2.Entry.IE_Key == 0xC1) && (LastKey == KEY_ModelId)) {
ULONG DescAddress;
DescAddress = CurrAddress+(u2.Entry.IE_Value*sizeof(ULONG));
Av1394_QuadletRead(pDevExt, &ulQuadlet, DescAddress);
u3.asUlong = bswap(ulQuadlet);
// get the first entry of the textual descriptor
Av1394_ReadTextualDescriptor(
pDevExt,
pUniUnitModelString,
DescAddress+(u3.Entry.IE_Value*sizeof(ULONG))
);
}
#endif
LastKey = u2.Entry.IE_Key;
}
Exit_GetUnitInfo:
if (UnitDirToFree) {
ExFreePool(UnitDirToFree); UnitDirToFree = NULL;
}
if(pIrp) {
IoFreeIrp(pIrp); pIrp = NULL;
}
if(p1394Irb) {
ExFreePool(p1394Irb); p1394Irb = NULL;
}
return ntStatus;
}
#endif
NTSTATUS
DVGetUnitCapabilities(
IN PDVCR_EXTENSION pDevExt,
IN PIRP pIrp,
IN PAV_61883_REQUEST pAVReq
)
{
NTSTATUS Status;
GET_UNIT_IDS * pUnitIds;
GET_UNIT_CAPABILITIES * pUnitCaps;
PAGED_CODE();
//
// Query device's capability
//
pUnitCaps = (GET_UNIT_CAPABILITIES *) ExAllocatePool(NonPagedPool, sizeof(GET_UNIT_CAPABILITIES));
if(!pUnitCaps) {
TRACE(TL_61883_ERROR,("DVGetUnitCapabilities: Allocate pUnitCaps (%d bytes) failed\n", sizeof(GET_UNIT_CAPABILITIES)));
return STATUS_INSUFFICIENT_RESOURCES;
}
// UnitIDS is cached in DevExt.
pUnitIds = &pDevExt->UnitIDs;
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)); // Initialize pointers.
pAVReq->GetUnitInfo.Information = (PVOID) pUnitIds;
Status =
DVSubmitIrpSynch(
pDevExt,
pIrp,
pAVReq
);
if(!NT_SUCCESS(Status)) {
TRACE(TL_61883_ERROR,("Av61883_GetUnitCapabilities 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_TRACE,("UniqueId:(Low)%x:(High)%x; VendorID:%x; ModelID:%x\n",
pDevExt->UniqueID.LowPart, pDevExt->UniqueID.HighPart, pDevExt->ulVendorID, pDevExt->ulModelID));
//
// Allocate memory needed for the text string for VendorText,
// ModelText and UntiModelText.
//
if(pUnitIds->ulVendorLength) {
pUnitIds->VendorText = (PWSTR) ExAllocatePool(NonPagedPool, pUnitIds->ulVendorLength);
if(!pUnitIds->VendorText)
goto AbortGetUnitCapabilities;
}
if(pUnitIds->ulModelLength) {
pUnitIds->ModelText = (PWSTR) ExAllocatePool(NonPagedPool, pUnitIds->ulModelLength);
if(!pUnitIds->ModelText)
goto AbortGetUnitCapabilities;
}
#ifdef NT51_61883
if(pUnitIds->ulUnitModelLength) {
pUnitIds->UnitModelText = (PWSTR) ExAllocatePool(NonPagedPool, pUnitIds->ulUnitModelLength);
if(!pUnitIds->UnitModelText)
goto AbortGetUnitCapabilities;
}
#else
//
// 1st version of 61883.sys does not retrieve Root and Unit model text
// the same way as in WinXP; so we retieve them directly using 1394 API
//
if(!NT_SUCCESS(AVCDevGetModelText(
pDevExt,
&pDevExt->UniRootModelString,
&pDevExt->UniUnitModelString
))) {
goto AbortGetUnitCapabilities;
}
#endif
Status =
DVSubmitIrpSynch(
pDevExt,
pIrp,
pAVReq
);
}
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)); // Initialize pointers.
pAVReq->GetUnitInfo.Information = (PVOID) pUnitCaps;
Status =
DVSubmitIrpSynch(
pDevExt,
pIrp,
pAVReq
);
if(!NT_SUCCESS(Status)) {
TRACE(TL_61883_ERROR,("Av61883_GetUnitCapabilities Failed = 0x%x\n", Status));
pDevExt->pDevOutPlugs->MaxDataRate = 0;
pDevExt->pDevOutPlugs->NumPlugs = 0;
pDevExt->pDevInPlugs->MaxDataRate = 0;
pDevExt->pDevInPlugs->NumPlugs = 0;
}
else {
//
// There can never be more than MAX_NUM_PCR (= 31) of plugs
//
ASSERT(pUnitCaps->NumOutputPlugs <= MAX_NUM_PCR);
ASSERT(pUnitCaps->NumInputPlugs <= MAX_NUM_PCR);
pDevExt->pDevOutPlugs->MaxDataRate = pUnitCaps->MaxDataRate;
pDevExt->pDevOutPlugs->NumPlugs = (pUnitCaps->NumOutputPlugs > MAX_NUM_PCR ? MAX_NUM_PCR : pUnitCaps->NumOutputPlugs);
pDevExt->pDevInPlugs->MaxDataRate = pUnitCaps->MaxDataRate;
pDevExt->pDevInPlugs->NumPlugs = (pUnitCaps->NumInputPlugs > MAX_NUM_PCR ? MAX_NUM_PCR : pUnitCaps->NumInputPlugs);
}
TRACE(TL_61883_TRACE,("** UnitCaps: OutP:%d; InP:%d; MDRate:%s; CtsF:%x; HwF:%x; VID:%x; MID:%x\n",
pUnitCaps->NumOutputPlugs,
pUnitCaps->NumInputPlugs,
pUnitCaps->MaxDataRate == 0 ? "S100": pUnitCaps->MaxDataRate == 1? "S200" : "S400 or +",
pUnitCaps->CTSFlags,
pUnitCaps->HardwareFlags,
pUnitIds->VendorID,
pUnitIds->ModelID
));
AbortGetUnitCapabilities:
if(pUnitIds->ulVendorLength && pUnitIds->VendorText) {
TRACE(TL_61883_TRACE,("Vendor: Len:%d; \"%S\"\n", pUnitIds->ulVendorLength, pUnitIds->VendorText));
if(!NT_SUCCESS(Status)) {
ExFreePool(pUnitIds->VendorText); pUnitIds->VendorText = NULL;
}
}
if(pUnitIds->ulModelLength && pUnitIds->ModelText) {
TRACE(TL_61883_TRACE,("Model: Len:%d; \"%S\"\n", pUnitIds->ulModelLength, pUnitIds->ModelText));
if(!NT_SUCCESS(Status)) {
ExFreePool(pUnitIds->ModelText); pUnitIds->ModelText = NULL;
}
}
#ifdef NT51_61883
if(pUnitIds->ulUnitModelLength && pUnitIds->UnitModelText) {
TRACE(TL_61883_TRACE,("UnitModel (61883): Len:%d; \"%S\"\n", pUnitIds->ulUnitModelLength, pUnitIds->UnitModelText));
if(!NT_SUCCESS(Status)) {
ExFreePool(pUnitIds->UnitModelText); pUnitIds->UnitModelText = NULL;
}
}
#else
if(pDevExt->UniRootModelString.Length && pDevExt->UniRootModelString.Buffer) {
TRACE(TL_61883_TRACE,("RootModel (MSTape): Len:%d; \"%S\"\n", pDevExt->UniRootModelString.Length, pDevExt->UniRootModelString.Buffer));
if(!NT_SUCCESS(Status)) {
ExFreePool(pDevExt->UniRootModelString.Buffer); pDevExt->UniRootModelString.Buffer = NULL;
}
}
if(pDevExt->UniUnitModelString.Length && pDevExt->UniUnitModelString.Buffer) {
TRACE(TL_61883_TRACE,("UnitModel (MSTape): Len:%d; \"%S\"\n", pDevExt->UniUnitModelString.Length, pDevExt->UniUnitModelString.Buffer));
if(!NT_SUCCESS(Status)) {
ExFreePool(pDevExt->UniUnitModelString.Buffer); pDevExt->UniUnitModelString.Buffer = NULL;
}
}
#endif
ExFreePool(pUnitCaps); pUnitCaps = NULL;
return Status;
}
#ifdef SUPPORT_NEW_AVC_CMD
BOOL
InitializeAVCCommand (
PAVC_CMD pAVCCmd,
AvcCommandType CmdType,
AvcSubunitType SubunitType,
UCHAR SubunitID,
AVC_COMMAND_OP_CODE Opcode
)
{
switch(Opcode) {
case OPC_UNIT_CONNECT_AV_20:
pAVCCmd->DataLen = 8;
pAVCCmd->ConnectAV.AudSrc = 3;
pAVCCmd->ConnectAV.VidSrc = 3;
pAVCCmd->ConnectAV.AudDst = 0; // subunit
pAVCCmd->ConnectAV.VidDst = 0; // subunit
pAVCCmd->ConnectAV.VidSrc = 0xff;
pAVCCmd->ConnectAV.AudSrc = 0xff;
pAVCCmd->ConnectAV.VidDst = 0x20;
pAVCCmd->ConnectAV.AudDst = 0x20;
break;
case OPC_TAPE_PLAY_C3:
pAVCCmd->DataLen = 4;
// pAVCCmd->TapePlay.PlaybackMode =
break;
default:
return FALSE;
}
pAVCCmd->CmdFrame.CmdHeader.CTS = 0;
pAVCCmd->CmdFrame.CmdHeader.CmdType = CmdType;
pAVCCmd->CmdFrame.CmdHeader.SubunitTypeID.SubunitType = SubunitType;
pAVCCmd->CmdFrame.CmdHeader.SubunitTypeID.SubunitID = SubunitID;
pAVCCmd->CmdFrame.CmdHeader.Opcode = Opcode;
return TRUE;
}
#endif // SUPPORT_NEW_AVC_CMD
BOOL
DVGetDevModeOfOperation(
IN PDVCR_EXTENSION pDevExt
)
{
NTSTATUS Status;
BYTE bAvcBuf[MAX_FCP_PAYLOAD_SIZE];
#ifdef SUPPORT_NEW_AVC_CMD
AVC_CMD AVCCmd;
#endif
PAGED_CODE();
#ifdef SUPPORT_NEW_AVC_CMD
InitializeAVCCommand(&AVCCmd, AVC_CTYPE_STATUS, AVC_SUBUNITTYPE_UNIT, 0, OPC_UNIT_CONNECT_AV_20);
InitializeAVCCommand(&AVCCmd, AVC_CTYPE_CONTROL, AVC_SUBUNITTYPE_TAPE_PLAYER, 0, OPC_TAPE_PLAY_C3);
AVCCmd.TapePlay.PlaybackMode = NEXT_FRAME; // Testing...
#endif
//
// 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_61883_TRACE,("GetDevModeOfOperation(DV_CONNECT_AV_MODE): Status %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
if(bAvcBuf[1] == 0xa0 &&
bAvcBuf[2] == 0x00 &&
bAvcBuf[3] == 0x00) {
pDevExt->ulDevType = ED_DEVTYPE_VCR;
}
}
} else if(pDevExt->ulVendorID == VENDORID_CANON) {
// If this is a Canon, we can try this:
Status = DVIssueAVCCommand(pDevExt, AVC_CTYPE_STATUS, DV_VEN_DEP_CANON_MODE, (PVOID) bAvcBuf);
TRACE(TL_61883_TRACE,("GetDevModeOfOperation(DV_VEN_DEP_CANON_MODE): Status %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[7] == 0x38) {
pDevExt->ulDevType = ED_DEVTYPE_CAMERA;
} else
if(bAvcBuf[7] == 0x20) {
pDevExt->ulDevType = ED_DEVTYPE_VCR;
}
}
}
}
//
// Connect AV is an optional command, a device may not support it.
// If this device support a tape subunit, we will assume we are in that device type.
//
if(Status != STATUS_SUCCESS) {
// We are the subunit driver so if any of the device type is a
// tape subunit, we are in that device type.
if( pDevExt->Subunit_Type[0] == AVC_DEVICE_TAPE_REC
|| pDevExt->Subunit_Type[1] == AVC_DEVICE_TAPE_REC
|| pDevExt->Subunit_Type[2] == AVC_DEVICE_TAPE_REC
|| pDevExt->Subunit_Type[3] == AVC_DEVICE_TAPE_REC) {
pDevExt->ulDevType = ED_DEVTYPE_VCR;
} else {
pDevExt->ulDevType = ED_DEVTYPE_UNKNOWN; // Such as MediaConverter box.
}
TRACE(TL_PNP_ERROR|TL_FCP_ERROR,("GetDevModeOfOperation: failed but we choose DevType:%x\n", pDevExt->ulDevType));
}
TRACE(TL_61883_TRACE,("** Mode of operation: %s (%x); NumOPlg:%d; NumIPlg:%d\n",
pDevExt->ulDevType == ED_DEVTYPE_CAMERA ? "Camera" : pDevExt->ulDevType == ED_DEVTYPE_VCR ? "Tape" : "Unknown",
pDevExt->ulDevType, pDevExt->pDevOutPlugs->NumPlugs, pDevExt->pDevInPlugs->NumPlugs));
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_61883_TRACE,("GetDevIsItDVCPro? %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;
}
#define GET_MEDIA_FMT_MAX_RETRIES 10 // AVC.sys will retry so we may rey just once.
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 : pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_OUT ? DV_OUT_PLUG_SIGNAL_FMT : DV_IN_PLUG_SIGNAL_FMT,
(PVOID) bAvcBuf
);
--lRetries;
//
// 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
//
if(Status == STATUS_SUCCESS ||
Status == STATUS_NOT_SUPPORTED ||
Status == STATUS_TIMEOUT) {
break; // No need to retry
} else
if(Status == STATUS_REQUEST_NOT_ACCEPTED) {
if(lRetries >= 0)
DVDelayExecutionThread(DV_AVC_CMD_DELAY_DVCPRO);
}
// else retry.
} 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) ? AVCSTRM_FORMAT_SDDV_PAL : AVCSTRM_FORMAT_SDDV_NTSC);
break;
case FDF0_STYPE_HD_DVCR:
pDevExt->VideoFormatIndex = ((bAvcBuf[1] & FDF0_50_60_MASK) ? AVCSTRM_FORMAT_HDDV_PAL : AVCSTRM_FORMAT_HDDV_NTSC);
break;
case FDF0_STYPE_SDL_DVCR:
pDevExt->VideoFormatIndex = ((bAvcBuf[1] & FDF0_50_60_MASK) ? AVCSTRM_FORMAT_SDLDV_PAL : AVCSTRM_FORMAT_SDLDV_NTSC);
break;
default: // Unknown format
Status = STATUS_UNSUCCESSFUL;
break;
}
break;
case FMT_MPEG:
pDevExt->VideoFormatIndex = AVCSTRM_FORMAT_MPEG2TS;
break;
default:
Status = STATUS_UNSUCCESSFUL;
}
if(NT_SUCCESS(Status)) {
TRACE(TL_PNP_ERROR|TL_FCP_ERROR,("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_TRACE,("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.
//
RtlZeroMemory(bAvcBuf, sizeof(bAvcBuf));
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_STRM_TRACE|TL_FCP_TRACE,("** 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 = AVCSTRM_FORMAT_SDDV_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 = AVCSTRM_FORMAT_SDDV_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;
case ED_TRANSBASIC_SIGNAL_MPEG2TS:
pDevExt->VideoFormatIndex = AVCSTRM_FORMAT_MPEG2TS;
break;
default:
TRACE(TL_PNP_ERROR|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_STRM_TRACE|TL_CIP_TRACE,("** 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_STRM_TRACE|TL_CIP_TRACE,("** 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 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) &&
IsEqualGUID (
&pDataRange1->SubFormat,
&pDataRange2->SubFormat) &&
IsEqualGUID (
&pDataRange1->Specifier,
&pDataRange2->Specifier) &&
(fCompareFormatSize ?
(pDataRange1->FormatSize == pDataRange2->FormatSize) : TRUE ));
}
//
// GetSystemTime in 100 nS units
//
ULONGLONG GetSystemTime()
{
LARGE_INTEGER rate, ticks;
ticks = KeQueryPerformanceCounter(&rate);
return (KSCONVERT_PERFORMANCE_TIME(rate.QuadPart, ticks));
}
VOID
DvFreeTextualString(
PDVCR_EXTENSION pDevExt,
GET_UNIT_IDS * pUnitIds
)
{
if(pUnitIds->ulVendorLength && pUnitIds->VendorText) {
ExFreePool(pUnitIds->VendorText); pUnitIds->VendorText = NULL;
}
if(pUnitIds->ulModelLength && pUnitIds->ModelText) {
ExFreePool(pUnitIds->ModelText); pUnitIds->ModelText = NULL;
}
#ifdef NT51_61883
if(pUnitIds->ulUnitModelLength && pUnitIds->UnitModelText) {
ExFreePool(pUnitIds->UnitModelText); pUnitIds->UnitModelText = NULL;
}
#else
if(pDevExt->UniRootModelString.Length && pDevExt->UniRootModelString.Buffer) {
ExFreePool(pDevExt->UniRootModelString.Buffer); pDevExt->UniRootModelString.Buffer = NULL;
}
if(pDevExt->UniUnitModelString.Length && pDevExt->UniUnitModelString.Buffer) {
ExFreePool(pDevExt->UniUnitModelString.Buffer); pDevExt->UniUnitModelString.Buffer = NULL;
}
#endif
}
#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
BOOL
DVMuteDVFrame(
IN PDVCR_EXTENSION pDevExt,
IN OUT PUCHAR pFrameBuffer,
IN BOOL bMuteAudio
)
{
PDV_DIF_SEQ pDifSeq;
#if 0
PDV_VAUX pVAux;
ULONG k;
#endif
ULONG i, j;
#if 0
BOOL bFound1 = FALSE;
#endif
BOOL bFound2 = FALSE;
pDifSeq = (PDV_DIF_SEQ) pFrameBuffer;
// find the VVAX Source pack
for (i=0; i < AVCStrmFormatInfoTable[pDevExt->VideoFormatIndex].FrameSize/DIFBLK_SIZE; i++) {
// #define SHOW_ONE_FIELD_TWICE
#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_TRACE,("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_TRACE,("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_INFO,("pVAux->Pack[k].Data[2] = %.2x\n", pVAux->Pack[k].Data[2]));
} else {
TRACE(TL_CIP_INFO,("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_INFO,("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
}
#if 0
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 < AVCStrmFormatInfoTable[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_INFO,("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_INFO,("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 * AVCStrmFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfDIFSequences/2;
//
// REC Data (VRD) and Time (VRT) on in the 2nd half oa a video frame
//
for(i=AVCStrmFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfDIFSequences/2; i < AVCStrmFormatInfoTable[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_PNP_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);
}
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;
}
//
// 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";
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
// ATNSearch
ulLength = sizeof(LONG);
Status = GetRegistryKeyValue(
hKeySettings,
wszATNSearch,
sizeof(wszATNSearch),
(PVOID) &pDevExt->bATNSearch,
&ulLength);
TRACE(TL_PNP_TRACE,("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_TRACE,("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_TRACE,("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_TRACE,("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_TRACE,("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_TRACE,("GetRegVal: St:%x, Len:%d, tmRecPs2Rec:%d (msec)\n", Status, ulLength, pDevExt->tmRecPs2Rec));
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;
}
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 // READ_CUTOMIZE_REG_VALUES
#ifdef SUPPORT_ACCESS_DEVICE_INTERFACE
#if DBG
NTSTATUS
DVGetRegistryValue(
IN HANDLE Handle,
IN PWCHAR KeyNameString,
IN ULONG KeyNameStringLength,
IN PVOID Data,
IN ULONG DataLength
)
/*++
Routine Description:
Reads the specified registry value
Arguments:
Handle - handle to the registry key
KeyNameString - value to read
KeyNameStringLength - length of string
Data - buffer to read data into
DataLength - length of data buffer
Return Value:
NTSTATUS returned as appropriate
--*/
{
NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
UNICODE_STRING KeyName;
ULONG Length;
PKEY_VALUE_FULL_INFORMATION FullInfo;
PAGED_CODE();
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)) {
if (DataLength >= FullInfo->DataLength) {
RtlCopyMemory(Data, ((PUCHAR) FullInfo) + FullInfo->DataOffset, FullInfo->DataLength);
} else {
Status = STATUS_BUFFER_TOO_SMALL;
} // buffer right length
} // if success
else {
TRACE(TL_PNP_ERROR,("ReadRegValue failed; ST:%x\n", Status));
}
ExFreePool(FullInfo);
} // if fullinfo
return Status;
}
#endif
#ifdef NT51_61883
static const WCHAR DeviceTypeName[] = L"GLOBAL";
#endif
static const WCHAR UniqueID_Low[] = L"UniqueID_Low";
static const WCHAR UniqueID_High[] = L"UniqueID_High";
static const WCHAR VendorID[] = L"VendorID";
static const WCHAR ModelID[] = L"ModelID";
static const WCHAR VendorText[] = L"VendorText";
static const WCHAR ModelText[] = L"ModelText";
static const WCHAR UnitModelText[] = L"UnitModelText";
static const WCHAR DeviceOPcr0Payload[] = L"DeviceOPcr0Payload";
static const WCHAR DeviceOPcr0DataRate[] = L"DeviceOPcr0DataRate";
#if DBG
static const WCHAR FriendlyName[] = L"FriendlyName";
#endif
BOOL
DVAccessDeviceInterface(
IN PDVCR_EXTENSION pDevExt,
IN const ULONG ulNumCategories,
IN GUID DVCategories[]
)
/*++
Routine Description:
Access to the device's interface section and update the VendorText,
ModelText and UnitModelText.
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
HANDLE hDevIntfKey;
UNICODE_STRING *aSymbolicLinkNames,
#ifdef NT51_61883
RefString,
#endif
TempUnicodeString;
ULONG i;
#ifdef NT51_61883
#if DBG
WCHAR DataBuffer[MAX_PATH];
#endif
#endif
//
// allocate space for the array of catagory names
//
if (!(aSymbolicLinkNames = ExAllocatePool(PagedPool,
sizeof(UNICODE_STRING) * ulNumCategories))) {
return FALSE;
}
//
// zero the array in case we're unable to fill it in below. the Destroy
// routine below will then correctly handle this case.
//
RtlZeroMemory(aSymbolicLinkNames, sizeof(UNICODE_STRING) * ulNumCategories);
#ifdef NT51_61883
//
// loop through each of the catagory GUID's for each of the pins,
// creating a symbolic link for each one.
//
RtlInitUnicodeString(&RefString, DeviceTypeName);
#endif
for (i = 0; i < ulNumCategories; i++) {
// Register our Device Interface
ntStatus = IoRegisterDeviceInterface(
pDevExt->pPhysicalDeviceObject,
&DVCategories[i],
#ifdef NT51_61883
&RefString,
#else
NULL,
#endif
&aSymbolicLinkNames[i]
);
if(!NT_SUCCESS(ntStatus)) {
//
// Can't register device interface
//
TRACE(TL_PNP_WARNING,("Cannot register device interface! ST:%x\n", ntStatus));
goto Exit;
}
TRACE(TL_PNP_TRACE,("AccessDeviceInterface:%d) Cateogory (Len:%d; MaxLen:%d); Name:\n%S\n", i,
aSymbolicLinkNames[i].Length, aSymbolicLinkNames[i].MaximumLength, aSymbolicLinkNames[i].Buffer));
//
// Get deice interface
//
hDevIntfKey = 0;
ntStatus = IoOpenDeviceInterfaceRegistryKey(&aSymbolicLinkNames[i],
STANDARD_RIGHTS_ALL,
&hDevIntfKey);
if (NT_SUCCESS(ntStatus)) {
#ifdef NT51_61883
#if DBG
// Get DeviceInstance
ntStatus = DVGetRegistryValue(hDevIntfKey,
(PWCHAR) FriendlyName,
sizeof(FriendlyName),
&DataBuffer,
MAX_PATH);
if(NT_SUCCESS(ntStatus)) {
TRACE(TL_PNP_TRACE,("AccessDeviceInterface:%S:%S\n", FriendlyName, DataBuffer));
} else {
TRACE(TL_PNP_WARNING,("Get %S failed; ST:%x\n", FriendlyName, ntStatus));
}
#endif
#endif
//
// Update ConfigROM info read from an AV/C device:
// UniqueID, VendorID, ModelID,
// VendorText, ModelText and UnitModelText
//
if(pDevExt->UniqueID.LowPart || pDevExt->UniqueID.HighPart) {
RtlInitUnicodeString(&TempUnicodeString, UniqueID_High);
ZwSetValueKey(hDevIntfKey,
&TempUnicodeString,
0,
REG_DWORD,
&pDevExt->UniqueID.HighPart,
sizeof(pDevExt->UniqueID.HighPart));
RtlInitUnicodeString(&TempUnicodeString, UniqueID_Low);
ZwSetValueKey(hDevIntfKey,
&TempUnicodeString,
0,
REG_DWORD,
&pDevExt->UniqueID.LowPart,
sizeof(pDevExt->UniqueID.LowPart));
TRACE(TL_PNP_TRACE,("Reg: %S = (Low)%x:(High)%x\n", TempUnicodeString.Buffer, pDevExt->UniqueID.LowPart, pDevExt->UniqueID.HighPart));
}
if(pDevExt->ulVendorID) {
RtlInitUnicodeString(&TempUnicodeString, VendorID);
ZwSetValueKey(hDevIntfKey,
&TempUnicodeString,
0,
REG_DWORD,
&pDevExt->ulVendorID,
sizeof(pDevExt->ulVendorID));
TRACE(TL_PNP_TRACE,("Reg: %S = %x\n", TempUnicodeString.Buffer, pDevExt->ulVendorID));
}
if(pDevExt->ulModelID) {
RtlInitUnicodeString(&TempUnicodeString, ModelID);
ZwSetValueKey(hDevIntfKey,
&TempUnicodeString,
0,
REG_DWORD,
&pDevExt->ulModelID,
sizeof(pDevExt->ulModelID));
TRACE(TL_PNP_TRACE,("Reg: %S = %x\n", TempUnicodeString.Buffer, pDevExt->ulModelID));
}
if(pDevExt->UnitIDs.ulVendorLength && pDevExt->UnitIDs.VendorText) {
RtlInitUnicodeString(&TempUnicodeString, VendorText);
ZwSetValueKey(hDevIntfKey,
&TempUnicodeString,
0,
REG_SZ,
pDevExt->UnitIDs.VendorText,
pDevExt->UnitIDs.ulVendorLength);
TRACE(TL_PNP_TRACE,("Reg: %S = %S\n", TempUnicodeString.Buffer, pDevExt->UnitIDs.VendorText));
}
#ifdef NT51_61883
if(pDevExt->UnitIDs.ulModelLength && pDevExt->UnitIDs.ModelText) {
RtlInitUnicodeString(&TempUnicodeString, ModelText);
ZwSetValueKey(hDevIntfKey,
&TempUnicodeString,
0,
REG_SZ,
pDevExt->UnitIDs.ModelText,
pDevExt->UnitIDs.ulModelLength);
TRACE(TL_PNP_WARNING,("Reg: %S = %S\n", TempUnicodeString.Buffer, pDevExt->UnitIDs.ModelText));
}
#else
if(pDevExt->UniRootModelString.Length && pDevExt->UniRootModelString.Buffer) {
RtlInitUnicodeString(&TempUnicodeString, ModelText);
ZwSetValueKey(hDevIntfKey,
&TempUnicodeString,
0,
REG_SZ,
pDevExt->UniRootModelString.Buffer,
pDevExt->UniRootModelString.Length);
TRACE(TL_PNP_WARNING,("Reg: %S = %S\n", TempUnicodeString.Buffer, pDevExt->UniRootModelString.Buffer));
}
#endif
#ifdef NT51_61883
if(pDevExt->UnitIDs.ulUnitModelLength && pDevExt->UnitIDs.UnitModelText) {
RtlInitUnicodeString(&TempUnicodeString, UnitModelText);
ZwSetValueKey(hDevIntfKey,
&TempUnicodeString,
0,
REG_SZ,
pDevExt->UnitIDs.UnitModelText,
pDevExt->UnitIDs.ulUnitModelLength);
TRACE(TL_PNP_WARNING,("Reg: %S = %S\n", TempUnicodeString.Buffer, pDevExt->UnitIDs.UnitModelText));
}
#else
if(pDevExt->UniUnitModelString.Length && pDevExt->UniUnitModelString.Buffer) {
RtlInitUnicodeString(&TempUnicodeString, UnitModelText);
ZwSetValueKey(hDevIntfKey,
&TempUnicodeString,
0,
REG_SZ,
pDevExt->UniUnitModelString.Buffer,
pDevExt->UniUnitModelString.Length);
TRACE(TL_PNP_WARNING,("Reg: %S = %S\n", TempUnicodeString.Buffer, pDevExt->UniUnitModelString.Buffer));
}
#endif
//
// Cache cache device's payload field of the oPCR[0];
// The valid range is 0 to 1023 where 0 is 1024.
// This value is needed for an application figure out
// max data rate. However, if this payload is
// dynamically changing, it will not be accurate.
//
if(pDevExt->pDevOutPlugs->NumPlugs) {
//
// 98 and 146 are two known valid payloads
//
ASSERT(pDevExt->pDevOutPlugs->DevPlug[0].PlugState.Payload <= MAX_PAYLOAD-1); // 0..MAX_PAYLOAD-1 is the valid range; "0" is MAX_PAYLOAD (1024) quadlets.
RtlInitUnicodeString(&TempUnicodeString, DeviceOPcr0Payload);
ZwSetValueKey(hDevIntfKey,
&TempUnicodeString,
0,
REG_DWORD,
&pDevExt->pDevOutPlugs->DevPlug[0].PlugState.Payload,
sizeof(pDevExt->pDevOutPlugs->DevPlug[0].PlugState.Payload));
TRACE(TL_PNP_TRACE,("Reg: %S = %d quadlets\n", TempUnicodeString.Buffer, pDevExt->pDevOutPlugs->DevPlug[0].PlugState.Payload));
//
// 0 (S100), 1(S200) and 2(S400) are the only three valid data rates.
//
ASSERT(pDevExt->pDevOutPlugs->DevPlug[0].PlugState.DataRate <= CMP_SPEED_S400);
RtlInitUnicodeString(&TempUnicodeString, DeviceOPcr0DataRate);
ZwSetValueKey(hDevIntfKey,
&TempUnicodeString,
0,
REG_DWORD,
&pDevExt->pDevOutPlugs->DevPlug[0].PlugState.DataRate,
sizeof(pDevExt->pDevOutPlugs->DevPlug[0].PlugState.DataRate));
TRACE(TL_PNP_TRACE,("Reg: %S = %d (0:S100,1:S200,2:S400)\n", TempUnicodeString.Buffer,
pDevExt->pDevOutPlugs->DevPlug[0].PlugState.DataRate));
}
ZwClose(hDevIntfKey);
} else {
TRACE(TL_PNP_ERROR,("IoOpenDeviceInterfaceRegistryKey failed; ST:%x\n", ntStatus));
}
RtlFreeUnicodeString(&aSymbolicLinkNames[i]);
}
Exit:
ExFreePool(aSymbolicLinkNames); aSymbolicLinkNames = NULL;
return ntStatus == STATUS_SUCCESS;
}
#endif