📄 dcampkt.c
字号:
//===========================================================================
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1996 - 2000 Microsoft Corporation. All Rights Reserved.
//
//===========================================================================
/*++
Module Name:
dcampkt.c
Abstract:
Stream class based WDM driver for 1934 Desktop Camera.
This file contains code to handle the stream class packets.
Author:
Shaun Pierce 25-May-96
Modified:
Yee J. Wu 15-Oct-97
Environment:
Kernel mode only
Revision History:
--*/
#include "strmini.h"
#include "ksmedia.h"
#include "1394.h"
#include "wdm.h" // for DbgBreakPoint() defined in dbg.h
#include "dbg.h"
#include "dcamdef.h"
#include "dcampkt.h"
#include "strmdata.h" // stream format and data ranges; static data
#include "capprop.h" // Video and camera property function prototype
#define WAIT_FOR_SLOW_DEVICE
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, DCamProcessPnpIrp)
#pragma alloc_text(PAGE, DCamGetStreamInfo)
#pragma alloc_text(PAGE, DCamFreeIsochResource)
#pragma alloc_text(PAGE, InitializeStreamExtension)
#pragma alloc_text(PAGE, DCamOpenStream)
#pragma alloc_text(PAGE, DCamCloseStream)
#pragma alloc_text(PAGE, AdapterCompareGUIDsAndFormatSize)
#pragma alloc_text(PAGE, AdapterVerifyFormat)
#pragma alloc_text(PAGE, AdapterFormatFromRange)
#pragma alloc_text(PAGE, VideoGetProperty)
#pragma alloc_text(PAGE, VideoGetState)
#pragma alloc_text(PAGE, VideoStreamGetConnectionProperty)
#pragma alloc_text(PAGE, VideoStreamGetDroppedFramesProperty)
#pragma alloc_text(PAGE, VideoIndicateMasterClock)
#pragma alloc_text(PAGE, DCamReceivePacket)
#pragma alloc_text(PAGE, DCamChangePower)
#endif
void
tmGetStreamTime(
IN PHW_STREAM_REQUEST_BLOCK Srb,
PSTREAMEX pStrmEx,
ULONGLONG * ptmStream)
/*++
Routine Description:
Query the current time used to timestamp the frame or calculating the dropped frame.
This is used in IsochCallback so must be paged in always.
Arguments:
Srb - Pointer to Stream request block
Return Value:
Nothing
--*/
{
HW_TIME_CONTEXT TimeContext;
TimeContext.HwDeviceExtension = (PVOID) Srb->HwDeviceExtension;
TimeContext.HwStreamObject = Srb->StreamObject;
TimeContext.Function = TIME_GET_STREAM_TIME;
TimeContext.Time = 0;
TimeContext.SystemTime = 0;
StreamClassQueryMasterClockSync(
pStrmEx->hMasterClock,
&TimeContext);
*ptmStream = TimeContext.Time;
}
BOOL
DCamAllocateIrbAndIrp(
PIRB * ppIrb,
PIRP * ppIrp,
CCHAR StackSize
)
{
// Allocate Irb and Irp
*ppIrb = ExAllocatePoolWithTag(NonPagedPool, sizeof(IRB), 'macd');
if(!*ppIrb) {
return FALSE;
}
*ppIrp = IoAllocateIrp(StackSize, FALSE);
if(!*ppIrp) {
ExFreePool(*ppIrb);
*ppIrb = NULL;
return FALSE;
}
// Initialize IRB
RtlZeroMemory(*ppIrb, sizeof(IRB));
return TRUE;
}
BOOL
DCamAllocateIrbIrpAndContext(
PDCAM_IO_CONTEXT * ppDCamIoContext,
PIRB * ppIrb,
PIRP * ppIrp,
CCHAR StackSize
)
{
// Allocate DCamIoContext
*ppDCamIoContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(DCAM_IO_CONTEXT), 'macd');
if(!*ppDCamIoContext) {
return FALSE;
}
// Allocate Irb and Irp
*ppIrb = ExAllocatePoolWithTag(NonPagedPool, sizeof(IRB), 'macd');
if(!*ppIrb) {
ExFreePool(*ppDCamIoContext);
*ppDCamIoContext = NULL;
return FALSE;
}
*ppIrp = IoAllocateIrp(StackSize, FALSE);
if(!*ppIrp) {
ExFreePool(*ppDCamIoContext);
*ppDCamIoContext = NULL;
ExFreePool(*ppIrb);
*ppIrb = NULL;
return FALSE;
}
// Initialize this context
RtlZeroMemory(*ppDCamIoContext, sizeof(DCAM_IO_CONTEXT));
(*ppDCamIoContext)->dwSize = sizeof(DCAM_IO_CONTEXT);
(*ppDCamIoContext)->pIrb = *ppIrb;
// Initialize IRB
RtlZeroMemory(*ppIrb, sizeof(IRB));
return TRUE;
}
void
DCamFreeIrbIrpAndContext(
PDCAM_IO_CONTEXT pDCamIoContext,
PIRB pIrb,
PIRP pIrp
)
{
if(pIrp)
IoFreeIrp(pIrp);
if(pIrb)
ExFreePool(pIrb);
if(pDCamIoContext)
ExFreePool(pDCamIoContext);
}
BOOL
DCamIsoEnable(
PIRB pIrb,
PDCAM_EXTENSION pDevExt,
BOOL Enable
)
/*
Start or start isoch transmission by setting the ISOEnable bit.
TRUE: Start transmission;
FALSE: Stop transmission.
*/
{
BOOL EnableVerify;
DCamRegArea RegArea;
NTSTATUS Status;
LARGE_INTEGER stableTime;
LONG lRetries = MAX_READ_REG_RETRIES;
do {
RegArea.AsULONG = (Enable ? START_ISOCH_TRANSMISSION : STOP_ISOCH_TRANSMISSION);
Status = DCamWriteRegister(pIrb, pDevExt, FIELDOFFSET(CAMERA_REGISTER_MAP, IsoEnable), RegArea.AsULONG);
EnableVerify = DCamDeviceInUse(pIrb, pDevExt);
if(!NT_SUCCESS(Status) || EnableVerify != Enable) {
ERROR_LOG(("\'DCAmIsoEnable: St:%x; Enable:%d vs EnableVerify:%d\n", Status, Enable, EnableVerify));
if(lRetries >= 1) {
stableTime.LowPart = DCAM_REG_STABLE_DELAY;
stableTime.HighPart = -1;
KeDelayExecutionThread(KernelMode, TRUE, &stableTime);
ERROR_LOG(("\'DCamIsoEnable: delayed and try again...\n"))
}
}
} while (--lRetries > 0 && (!NT_SUCCESS(Status) || (EnableVerify != Enable)) );
return (EnableVerify == Enable);
}
void
DCamProcessPnpIrp(
IN PHW_STREAM_REQUEST_BLOCK Srb,
PIO_STACK_LOCATION IrpStack,
PDCAM_EXTENSION pDevExt
)
/*++
Routine Description:
Process PnP Irp.
Arguments:
Srb - Pointer to Stream request block
Return Value:
Nothing
--*/
{
NTSTATUS Status, StatusWait;
PIRB pIrb;
PIRP pIrp;
PSTREAMEX pStrmEx;
PAGED_CODE();
switch (IrpStack->MinorFunction) {
#if 1
case IRP_MN_QUERY_POWER:
pStrmEx = (PSTREAMEX) pDevExt->pStrmEx;
ERROR_LOG(("IRP_MN_QUERY_POWER: pStrmEx:%x\n", pStrmEx));
if(!pStrmEx) {
Srb->Status = STATUS_SUCCESS;
break;
}
if(pStrmEx->KSState == KSSTATE_PAUSE || pStrmEx->KSState == KSSTATE_RUN) {
ERROR_LOG(("Does not support hibernation while streaming!\n"));
Srb->Status = STATUS_NOT_SUPPORTED;
} else {
ERROR_LOG(("OK to hibernation if not streaming\n"));
Srb->Status = STATUS_SUCCESS;
}
break;
#endif
case IRP_MN_BUS_RESET:
//
// We will realocate the resource (bandwith and channel) in IRQL PASSIVE level.
//
Srb->Status = STATUS_SUCCESS;
Status = STATUS_SUCCESS;
//
// The generation count is updated in the bus reset callback notification only.
// Continue iff the generation count has been updated.
// Else, we are assuming another bus reset has occurred,
// and we will pass to us later.
//
if(pDevExt->CurrentGeneration != *((PULONG) &IrpStack->Parameters.Others.Argument4)) {
ERROR_LOG(("DCamProcessPnpIrp: Generation count old (%d) != new (%d); STOP!\n",
pDevExt->CurrentGeneration, *((PULONG) &IrpStack->Parameters.Others.Argument4)) );
break;
}
pStrmEx = (PSTREAMEX) pDevExt->pStrmEx;
DbgMsg2(("\'%d:%s) SonyDCamProcessPnpIrp: pDevExt %x; pStrmEx %x; CurGen %d\n",
pDevExt->idxDev, pDevExt->pchVendorName, pDevExt, pStrmEx, pDevExt->CurrentGeneration));
//
// If the stream was open (pStrmEx != NULL && pStrmEx->pVideoInfoHeader != NULL);
// We need to ask controller to allocate bandwidth and channel.
//
if(pStrmEx &&
pStrmEx->pVideoInfoHeader != NULL) {
DbgMsg2(("\'%d:%s) DCamProcessPnpIrp: Stream was open so re-allocate resource.\n", pDevExt->idxDev, pDevExt->pchVendorName));
// Allocate Irb
pIrb = ExAllocatePoolWithTag(NonPagedPool, sizeof(IRB), 'macd');
if(!pIrb) {
ERROR_LOG(("\'DCamProcessPnpIrp: allocate IRB failed; insufficient resource.\n"));
Srb->Status = STATUS_INSUFFICIENT_RESOURCES;
break;
} else {
ULONG ulChannel;
HANDLE hResource;
pIrp = IoAllocateIrp(pDevExt->BusDeviceObject->StackSize, FALSE);
if(!pIrp) {
ExFreePool(pIrb);
Srb->Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlZeroMemory(pIrb, sizeof(IRB));
//
// Bus reset will free the bandwidth but not the bandwidth structure allocated by the lower driver
//
if (pDevExt->hBandwidth) {
DbgMsg2(("\'DCamProcessPnpIrp: Attempt to free ->hBandwidth\n"));
pIrb->FunctionNumber = REQUEST_ISOCH_FREE_BANDWIDTH;
pIrb->Flags = 0;
pIrb->u.IsochFreeBandwidth.hBandwidth = pDevExt->hBandwidth;
Status = DCamSubmitIrpSynch(pDevExt, pIrp, pIrb);
if (Status) {
ERROR_LOG(("DCamProcessPnpIrp: Error %x while trying to free Isoch bandwidth\n", Status));
ASSERT(Status == STATUS_SUCCESS || Status == STATUS_INVALID_GENERATION);
}
pDevExt->hBandwidth = NULL;
}
//
// Before we assign the new hResource, we wait for it attaching buffer to complete.
// For buffer that completed with previous hResource,
// It will complete with error ?
//
StatusWait = KeWaitForSingleObject( &pStrmEx->hMutex, Executive, KernelMode, FALSE, 0 );
//
// Reallocate bandwidth and channel, and resource if necessary.
// IF THIS FAIL, we are consider illegally streaming, and need to STOP streaming.
//
ulChannel = pDevExt->IsochChannel;
hResource = pDevExt->hResource;
Status = DCamAllocateIsochResource(pDevExt, pIrb, FALSE);
if(Status) {
ERROR_LOG(("\'%d:%s) DCamProcessPnpIrp: Re-AllocateIsochResource failed! Status=%x; Treat as device removed.\n\n",
pDevExt->idxDev, pDevExt->pchVendorName, Status));
ASSERT(Status == STATUS_SUCCESS);
//
// No resource so let's treat this situation as
// Device has been removed because there is no
// way to restart this.
// This will stop future SRB_READ until stream is STOP and RUN again.
//
pDevExt->bDevRemoved = TRUE;
Srb->Status = STATUS_INSUFFICIENT_RESOURCES;
//
// Stop tranmission so it will not send data to the old channel,
// which might be "owned" by other device.
//
if(pStrmEx->KSState == KSSTATE_RUN) {
// Disable EnableISO
DCamIsoEnable(pIrb, pDevExt, FALSE);
}
KeReleaseMutex(&pStrmEx->hMutex, FALSE);
ExFreePool(pIrb);
IoFreeIrp(pIrp);
return;
}
//
// If channel number change due to bus reset, we must
// - continue to blocking incoming SRB_READ (with mutex)
// - if RUN state, stop transmission
// - detach all pending buffer(s)
// - free "stale" isoch resource
// - if RUN state, program device to use the new channel
// - if RUN state, restart transmission
//
if(pDevExt->IsochChannel != ISOCH_ANY_CHANNEL &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -