📄 callback.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:
This file contains code to handle callback from the bus/class driver.
They might be running in DISPATCH level.
Author:
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 "sonydcam.h"
#include "capprop.h"
IO_COMPLETION_ROUTINE DCamToInitializeStateCompletionRoutine;
NTSTATUS
DCamToInitializeStateCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrp,
IN PDCAM_IO_CONTEXT pDCamIoContext
)
/*++
Routine Description:
Completion routine called after the device is initialize to a known state.
Arguments:
DriverObject - Pointer to driver object created by system.
pIrp - Irp that just completed
pDCamIoContext - A structure that contain the context of this IO completion routine.
Return Value:
None.
--*/
{
PDCAM_EXTENSION pDevExt;
PSTREAMEX pStrmEx;
PIRB pIrb;
if(!pDCamIoContext) {
return STATUS_MORE_PROCESSING_REQUIRED;
}
pIrb = pDCamIoContext->pIrb;
pDevExt = pDCamIoContext->pDevExt;
DbgMsg2(("\'DCamToInitializeStateCompletionRoutine: completed DeviceState=%d; pIrp->IoStatus.Status=%x\n",
pDCamIoContext->DeviceState, pIrp->IoStatus.Status));
// Free MDL
if(pIrb->FunctionNumber == REQUEST_ASYNC_WRITE) {
DbgMsg3(("DCamToInitializeStateCompletionRoutine: IoFreeMdl\n"));
IoFreeMdl(pIrb->u.AsyncWrite.Mdl);
}
// CAUTION:
// Do we need to retry if the return is STATUS_TIMEOUT or invalid generation number ?
//
if(pIrp->IoStatus.Status != STATUS_SUCCESS) {
ERROR_LOG(("DCamToInitializeStateCompletionRoutine: Status=%x != STATUS_SUCCESS; cannot restart its state.\n", pIrp->IoStatus.Status));
if(pDCamIoContext->pSrb) {
pDCamIoContext->pSrb->Status = STATUS_UNSUCCESSFUL;
StreamClassStreamNotification(StreamRequestComplete, pDCamIoContext->pSrb->StreamObject, pDCamIoContext->pSrb);
}
DCamFreeIrbIrpAndContext(pDCamIoContext, pDCamIoContext->pIrb, pIrp);
return STATUS_MORE_PROCESSING_REQUIRED;
}
//
// Done here if we are in STOP or PAUSE state;
// else setting to RUN state.
//
pStrmEx = (PSTREAMEX) pDevExt->pStrmEx;
//
// No stream is open, job is done.
//
if(!pStrmEx) {
if(pDCamIoContext->pSrb) {
pDCamIoContext->pSrb->Status = STATUS_SUCCESS;
StreamClassStreamNotification(StreamRequestComplete, pDCamIoContext->pSrb->StreamObject, pDCamIoContext->pSrb);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
switch(pStrmEx->KSStateFinal) {
case KSSTATE_STOP:
case KSSTATE_PAUSE:
pStrmEx->KSState = pStrmEx->KSStateFinal;
if(pDCamIoContext->pSrb) {
pDCamIoContext->pSrb->Status = STATUS_SUCCESS;
StreamClassStreamNotification(StreamRequestComplete, pDCamIoContext->pSrb->StreamObject, pDCamIoContext->pSrb);
}
DCamFreeIrbIrpAndContext(pDCamIoContext, pDCamIoContext->pIrb, pIrp);
break;
case KSSTATE_RUN:
if(pDCamIoContext->pSrb) {
pDCamIoContext->pSrb->Status = STATUS_SUCCESS;
StreamClassStreamNotification(StreamRequestComplete, pDCamIoContext->pSrb->StreamObject, pDCamIoContext->pSrb);
}
// Restart the stream.
DCamSetKSStateRUN(pDevExt, pDCamIoContext->pSrb);
// Need pDCamIoContext->pSrb; so free it after DCamSetKSStateRUN().
DCamFreeIrbIrpAndContext(pDCamIoContext, pDCamIoContext->pIrb, pIrp);
break;
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
DCamSetKSStateInitialize(
PDCAM_EXTENSION pDevExt
)
/*++
Routine Description:
Set KSSTATE to KSSTATE_RUN.
Arguments:
pDevExt -
Return Value:
Nothing
--*/
{
PSTREAMEX pStrmEx;
PIRB pIrb;
PIRP pIrp;
PDCAM_IO_CONTEXT pDCamIoContext;
PIO_STACK_LOCATION NextIrpStack;
NTSTATUS Status;
ASSERT(pDevExt);
pStrmEx = (PSTREAMEX) pDevExt->pStrmEx;
if(!DCamAllocateIrbIrpAndContext(&pDCamIoContext, &pIrb, &pIrp, pDevExt->BusDeviceObject->StackSize)) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Initialize the device to a known state
// may need to do this due to power down??
//
pDCamIoContext->DeviceState = DCAM_SET_INITIALIZE; // Keep track of device state that we just set.
pDCamIoContext->pDevExt = pDevExt;
pDCamIoContext->RegisterWorkArea.AsULONG = 0;
pDCamIoContext->RegisterWorkArea.Initialize.Initialize = TRUE;
pDCamIoContext->RegisterWorkArea.AsULONG = bswap(pDevExt->RegisterWorkArea.AsULONG);
pIrb->FunctionNumber = REQUEST_ASYNC_WRITE;
pIrb->Flags = 0;
pIrb->u.AsyncWrite.DestinationAddress.IA_Destination_Offset.Off_High = INITIAL_REGISTER_SPACE_HI;
pIrb->u.AsyncWrite.DestinationAddress.IA_Destination_Offset.Off_Low =
pDevExt->BaseRegister + FIELDOFFSET(CAMERA_REGISTER_MAP, Initialize);
pIrb->u.AsyncWrite.nNumberOfBytesToWrite = sizeof(ULONG);
pIrb->u.AsyncWrite.nBlockSize = 0;
pIrb->u.AsyncWrite.fulFlags = 0;
InterlockedExchange(&pIrb->u.AsyncWrite.ulGeneration, pDevExt->CurrentGeneration);
pIrb->u.AsyncWrite.Mdl =
IoAllocateMdl(&pDCamIoContext->RegisterWorkArea, sizeof(ULONG), FALSE, FALSE, NULL);
MmBuildMdlForNonPagedPool(pIrb->u.AsyncWrite.Mdl);
NextIrpStack = IoGetNextIrpStackLocation(pIrp);
NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS;
NextIrpStack->Parameters.Others.Argument1 = pIrb;
IoSetCompletionRoutine(
pIrp,
DCamToInitializeStateCompletionRoutine,
pDCamIoContext,
TRUE,
TRUE,
TRUE
);
Status =
IoCallDriver(
pDevExt->BusDeviceObject,
pIrp
);
return STATUS_SUCCESS;
}
VOID
DCamBusResetWorkItem(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context
)
/*++
Routine Description:
This work item routine react to a busreset while there is an active stream. It performs
1. REQUEST_ISOCH_FREE_BANDWIDTH (Must be at PASSIVE_LEVEL) to free the Bandwidth structure
2. REQUEST_ISOCH_ALLOCATE_CHANNEL (reclaim the original channel first, then any channel)
3. REQUEST_ISOCH_ALLOCATE_BANDWIDTH
4. If same channel and has sufficient BW to continue, done!
Only if lost the original isoch channel:
5. REQUEST_ISOCH_ALLOCATE_RESOURCES
6. Stop isoch and rEsubmit the attached buffers
7. Restart isoch
--*/
{
NTSTATUS ntStatus, ntStatusWait;
DCAM_EXTENSION *pDevExt = (DCAM_EXTENSION *) Context;
STREAMEX *pStrmEx;
IRB *pIrb = NULL;
IRP *pIrp = NULL;
ULONG ulChannel;
HANDLE hResource;
PAGED_CODE();
DbgMsg1(( "%d:%s) %s enter\n", pDevExt->idxDev, pDevExt->pchVendorName, __FUNCTION__ ));
pStrmEx = ( STREAMEX * ) pDevExt->pStrmEx;
if( !pStrmEx ) goto Exit; // Stream has stopped!
// Allocate 1394 IRB and IRP
pIrb = ExAllocatePoolWithTag(NonPagedPool, sizeof(IRB), 'macd');
if( !pIrb ) goto Exit;
pIrp = IoAllocateIrp(pDevExt->BusDeviceObject->StackSize, FALSE);
if( !pIrp ) {
goto Exit;
}
RtlZeroMemory( pIrb, sizeof( IRB ) );
//
// Bus reset will free the bandwidth but not the bandwidth structure allocated by the lower driver
//
if( pDevExt->hBandwidth ) {
pIrb->FunctionNumber = REQUEST_ISOCH_FREE_BANDWIDTH;
pIrb->Flags = 0;
pIrb->u.IsochFreeBandwidth.hBandwidth = pDevExt->hBandwidth;
ntStatus = DCamSubmitIrpSynch(pDevExt, pIrp, pIrb);
ASSERT( ntStatus == STATUS_SUCCESS || ntStatus == STATUS_INVALID_GENERATION );
pDevExt->hBandwidth = NULL;
}
//
// NO need to restart streaming if the device has been removed!
//
if( pDevExt->bDevRemoved ) goto Exit;
//
// Synchronize read request and other work item
//
ntStatusWait = 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; // Cache it so we know if it is changed after the new allocation.
hResource = pDevExt->hResource;
ntStatus = DCamAllocateIsochResource( pDevExt, pIrb, FALSE );
if( ntStatus ) {
ERROR_LOG(( "%d:%s) Reclaim isoch resource failed! ntStatus %x; Treat as device removed.\n\n",
pDevExt->idxDev, pDevExt->pchVendorName, ntStatus));
ASSERT( ntStatus == STATUS_SUCCESS && "Failed to allocate isoch resource after busret!" );
//
// 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;
//
// 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);
goto Exit;
}
//
// 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 &&
ulChannel != pDevExt->IsochChannel) {
ERROR_LOG(( "%d:%s) Lost our channel so resubmit and the restart.\n\n", pDevExt->idxDev, pDevExt->pchVendorName ));
//
// Stop tranmission on the channel we no longer own!
//
if( pStrmEx->KSState == KSSTATE_RUN ) {
// Disable EnableISO
DCamIsoEnable(pIrb, pDevExt, FALSE);
}
//
// Detach pending packets using the hOldRources and reattached using the new hResource
// Note: incoming SRB_READ is block right now.
// free old resource after all pending reads are detached.
//
if( pDevExt->PendingReadCount > 0 ) {
ntStatus = DCamReSubmitPacket( hResource, pDevExt, pStrmEx, pDevExt->PendingReadCount );
}
//
// Free "stale" isoch resource
//
if( pDevExt->hResource != hResource ) {
pIrb->FunctionNumber = REQUEST_ISOCH_FREE_RESOURCES;
pIrb->Flags = 0;
pIrb->u.IsochFreeResources.hResource = hResource;
ntStatus = DCamSubmitIrpSynch(pDevExt, pIrp, pIrb);
if( ntStatus ) {
ERROR_LOG(("Failed REQUEST_ISOCH_FREE_RESOURCES ntStatus %x\n", ntStatus));
ASSERT(ntStatus == STATUS_SUCCESS);
}
}
//
// Getting ready to accept callback
//
pDevExt->bStopIsochCallback = FALSE;
//
// Restore to its initial Streaming state
// mainly, programming device.
//
DCamSetKSStateInitialize( pDevExt );
}
KeReleaseMutex(&pStrmEx->hMutex, FALSE);
Exit:
if( pIrb ) {
ExFreePool( pIrb );
pIrb = NULL;
}
if( pIrp ) {
IoFreeIrp( pIrp );
pIrp = NULL;
}
//
// Decrement work item count and signal the event only if there is no more work item.
//
if( InterlockedDecrement( &pDevExt->PendingWorkItemCount ) == 0 )
KeSetEvent( &pDevExt->PendingWorkItemEvent, 0, FALSE );
ERROR_LOG(( "%d:%s) %s exit\n", pDevExt->idxDev, pDevExt->pchVendorName, __FUNCTION__ ));
return;
}
VOID
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -