📄 callback.c
字号:
DCamBusResetNotification(
IN PVOID Context
)
/*++
Routine Description:
We receive this callback notification after a bus reset and if the device is still attached.
This can happen when a new device is plugged in or an existing one is removed, or due to
awaken from sleep state. We will restore the device to its original streaming state by
(1) Initialize the device to a known state and then
(2) launch a state machine to restart streaming.
We will stop the state machine if previous state has failed. This can happen if the generation
count is changed before the state mahcine is completed.
The freeing and realocation of isoch bandwidth and channel are done in the bus reset irp.
It is passed down by stream class in SRB_UNKNOWN_DEVICE_COMMAND. This IRP is guarantee to
call after this bus reset notification has returned and while the state machine is going on.
This is a callback at IRQL_DPC level; there are many 1394 APIs cannot be called at this level
if it does blocking using KeWaitFor*Object(). Consult 1394 docuement for the list.
Arguments:
Context - Pointer to the context of this registered notification.
Return Value:
Nothing
--*/
{
PDCAM_EXTENSION pDevExt = (PDCAM_EXTENSION) Context;
PSTREAMEX pStrmEx;
NTSTATUS Status;
PIRP pIrp;
PIRB pIrb;
PIO_WORKITEM pIOWorkItem;
if(!pDevExt) {
ERROR_LOG(("DCamBusResetNotification:pDevExt is 0.\n\n"));
ASSERT(pDevExt);
return;
}
//
// Check a field in the context that must be valid to make sure that it is Ok to continue.
//
if(!pDevExt->BusDeviceObject) {
ERROR_LOG(("DCamBusResetNotification:pDevExtBusDeviceObject is 0.\n\n"));
ASSERT(pDevExt->BusDeviceObject);
return;
}
DbgMsg2(("DCamBusResetNotification: pDevExt %x, pDevExt->pStrmEx %x, pDevExt->BusDeviceObject %x\n",
pDevExt, pDevExt->pStrmEx, pDevExt->BusDeviceObject));
//
//
// Get the current generation count first
//
// CAUTION:
// not all 1394 APIs can be called in DCamSubmitIrpSynch() if in DISPATCH_LEVEL;
// Getting generation count require no blocking so it is OK.
if(!DCamAllocateIrbAndIrp(&pIrb, &pIrp, pDevExt->BusDeviceObject->StackSize)) {
ERROR_LOG(("DCamBusResetNotification: DcamAllocateIrbAndIrp has failed!!\n\n\n"));
ASSERT(FALSE);
return;
}
pIrb->FunctionNumber = REQUEST_GET_GENERATION_COUNT;
pIrb->Flags = 0;
Status = DCamSubmitIrpSynch(pDevExt, pIrp, pIrb);
if(Status) {
ERROR_LOG(("\'DCamBusResetNotification: Status=%x while trying to get generation number\n", Status));
// Done with them; free resources.
DCamFreeIrbIrpAndContext(0, pIrb, pIrp);
return;
}
ERROR_LOG(("DCamBusResetNotification: Generation number from %d to %d\n",
pDevExt->CurrentGeneration, pIrb->u.GetGenerationCount.GenerationCount));
InterlockedExchange(&pDevExt->CurrentGeneration, pIrb->u.GetGenerationCount.GenerationCount);
// Done with them; free resources.
DCamFreeIrbIrpAndContext(0, pIrb, pIrp);
pStrmEx = (PSTREAMEX) pDevExt->pStrmEx;
//
// If the stream was open (pStrmEx != NULL && pStrmEx->pVideoInfoHeader != NULL),
// then we need to restore its streaming state.
//
if (pStrmEx &&
pStrmEx->pVideoInfoHeader != NULL) {
DbgMsg2(("\'%d:%s) DCamBusResetNotification: Stream was open; Try allocate them again.\n", pDevExt->idxDev, pDevExt->pchVendorName));
} else {
DbgMsg2(("DCamBusResetNotification:Stream has not open on this device. Done!\n"));
return;
}
//
// We will allow queuing only one work item!
//
if( pDevExt->PendingWorkItemCount )
goto Exit;
//
// Get here only because we have an active stream;
// Start a work item to reclaim isoch resource as a result of busreset; some 1394 request
// like free BW must be exeuted in PASSIVE level.
//
pIOWorkItem = IoAllocateWorkItem( pDevExt -> PhysicalDeviceObject );
if( !pIOWorkItem ) {
ERROR_LOG(("%s failed to alocate work item!\n", __FUNCTION__ ));
// No more resource, there is nothing we can do.
goto Exit;
}
InterlockedIncrement( &pDevExt->PendingWorkItemCount );
KeResetEvent( &pDevExt->PendingWorkItemEvent ); // Non-signal so the device removal can wait!
// Make it critical as we need to reclaim resource ASAP (within 1 sec)
IoQueueWorkItem( pIOWorkItem, DCamBusResetWorkItem, CriticalWorkQueue, pDevExt );
Exit:
DbgMsg2(("\'DCamBusResetNotification: Leaving...; Task complete in the CompletionRoutine.\n"));
return;
}
NTSTATUS
DCamDetachBufferCR(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrp,
IN PIRB pIrb
)
/*++
Routine Description:
Detaching a buffer has completed. Attach next buffer.
Returns more processing required so the IO Manager will leave us alone
Arguments:
DriverObject - Pointer to driver object created by system.
pIrp - Irp that just completed
pIrb - Context set in DCamIsochCallback()
Return Value:
None.
--*/
{
IN PISOCH_DESCRIPTOR IsochDescriptor;
PDCAM_EXTENSION pDevExt;
PISOCH_DESCRIPTOR_RESERVED IsochDescriptorReserved;
KIRQL oldIrql;
if(!pIrb) {
ERROR_LOG(("\'DCamDetachBufferCR: pIrb is NULL\n"));
ASSERT(pIrb);
IoFreeIrp(pIrp);
return (STATUS_MORE_PROCESSING_REQUIRED);
}
// Get IsochDescriptor from the context (pIrb)
IsochDescriptor = pIrb->u.IsochDetachBuffers.pIsochDescriptor;
if(!IsochDescriptor) {
ERROR_LOG(("\'DCamDetachBufferCR: IsochDescriptor is NULL\n"));
ASSERT(IsochDescriptor);
IoFreeIrp(pIrp);
return (STATUS_MORE_PROCESSING_REQUIRED);
}
if(pIrp->IoStatus.Status != STATUS_SUCCESS) {
ERROR_LOG(("\'DCamDetachBufferCR: pIrp->IoStatus.Status(%x) != STATUS_SUCCESS\n", pIrp->IoStatus.Status));
ASSERT(pIrp->IoStatus.Status == STATUS_SUCCESS);
IoFreeIrp(pIrp);
return STATUS_MORE_PROCESSING_REQUIRED;
}
// IsochDescriptorReserved->Srb->Irp->IoStatus = pIrp->IoStatus.Status;
IoFreeIrp(pIrp);
// Freed and should not be referenced again!
IsochDescriptor->DeviceReserved[5] = 0;
IsochDescriptorReserved = (PISOCH_DESCRIPTOR_RESERVED) &IsochDescriptor->DeviceReserved[0];
pDevExt = (PDCAM_EXTENSION) IsochDescriptor->Context1;
DbgMsg3(("\'DCamDetachBufferCR: IsochDescriptorReserved=%x; DevExt=%x\n", IsochDescriptorReserved, pDevExt));
ASSERT(IsochDescriptorReserved);
ASSERT(pDevExt);
if(pDevExt &&
IsochDescriptorReserved) {
//
// Indicate that the Srb should be complete
//
IsochDescriptorReserved->Flags |= STATE_SRB_IS_COMPLETE;
IsochDescriptorReserved->Srb->Status = STATUS_SUCCESS;
IsochDescriptorReserved->Srb->CommandData.DataBufferArray->DataUsed = IsochDescriptor->ulLength;
IsochDescriptorReserved->Srb->ActualBytesTransferred = IsochDescriptor->ulLength;
DbgMsg3(("\'DCamDetachBufferCR: Completing Srb %x\n", IsochDescriptorReserved->Srb));
KeAcquireSpinLock(&pDevExt->IsochDescriptorLock, &oldIrql);
RemoveEntryList(&IsochDescriptorReserved->DescriptorList); InterlockedDecrement(&pDevExt->PendingReadCount);
KeReleaseSpinLock(&pDevExt->IsochDescriptorLock, oldIrql);
ASSERT(IsochDescriptorReserved->Srb->StreamObject);
ASSERT(IsochDescriptorReserved->Srb->Flags & SRB_HW_FLAGS_STREAM_REQUEST);
StreamClassStreamNotification(
StreamRequestComplete,
IsochDescriptorReserved->Srb->StreamObject,
IsochDescriptorReserved->Srb);
// Free it here instead of in DCamCompletionRoutine.
ExFreePool(IsochDescriptor);
}
return (STATUS_MORE_PROCESSING_REQUIRED);
}
VOID
DCamIsochCallback(
IN PDCAM_EXTENSION pDevExt,
IN PISOCH_DESCRIPTOR IsochDescriptor
)
/*++
Routine Description:
Called when an Isoch Descriptor completes
Arguments:
pDevExt - Pointer to our DeviceExtension
IsochDescriptor - IsochDescriptor that completed
Return Value:
Nothing
--*/
{
PIRB pIrb;
PIRP pIrp;
PSTREAMEX pStrmEx;
PIO_STACK_LOCATION NextIrpStack;
PISOCH_DESCRIPTOR_RESERVED IsochDescriptorReserved;
PKSSTREAM_HEADER pDataPacket;
PKS_FRAME_INFO pFrameInfo;
KIRQL oldIrql;
//
// Debug check to make sure we're dealing with a real IsochDescriptor
//
ASSERT ( IsochDescriptor );
IsochDescriptorReserved = (PISOCH_DESCRIPTOR_RESERVED) &IsochDescriptor->DeviceReserved[0];
//
// All Pending read will be either resubmitted, or cancelled (if out of resource).
//
if(pDevExt->bStopIsochCallback) {
ERROR_LOG(("DCamIsochCallback: bStopCallback is set. IsochDescriptor %x (and Reserved %x) is returned and not processed.\n",
IsochDescriptor, IsochDescriptorReserved));
return;
}
//
// Synchronization note:
//
// We are competing with cancel packet routine in the
// event of device removal or setting to STOP state.
// which ever got the spin lock to set DEATCH_BUFFER
// flag take ownership completing the Irp/IsochDescriptor.
//
KeAcquireSpinLock(&pDevExt->IsochDescriptorLock, &oldIrql);
if(pDevExt->bDevRemoved ||
(IsochDescriptorReserved->Flags & (STATE_SRB_IS_COMPLETE | STATE_DETACHING_BUFFERS)) ) {
ERROR_LOG(("DCamIsochCallback: bDevRemoved || STATE_SRB_IS_COMPLETE | STATE_DETACHING_BUFFERS %x %x\n",
IsochDescriptorReserved,IsochDescriptorReserved->Flags));
ASSERT((!pDevExt->bDevRemoved && !(IsochDescriptorReserved->Flags & (STATE_SRB_IS_COMPLETE | STATE_DETACHING_BUFFERS))));
KeReleaseSpinLock(&pDevExt->IsochDescriptorLock, oldIrql);
return;
}
IsochDescriptorReserved->Flags |= STATE_DETACHING_BUFFERS;
KeReleaseSpinLock(&pDevExt->IsochDescriptorLock, oldIrql);
pStrmEx = (PSTREAMEX) pDevExt->pStrmEx;
ASSERT(pStrmEx == (PSTREAMEX)IsochDescriptorReserved->Srb->StreamObject->HwStreamExtension);
pStrmEx->FrameCaptured++;
pStrmEx->FrameInfo.PictureNumber = pStrmEx->FrameCaptured + pStrmEx->FrameInfo.DropCount;
//
// Return the timestamp for the frame
//
pDataPacket = IsochDescriptorReserved->Srb->CommandData.DataBufferArray;
pFrameInfo = (PKS_FRAME_INFO) (pDataPacket + 1);
ASSERT ( pDataPacket );
ASSERT ( pFrameInfo );
//
// Return the timestamp for the frame
//
pDataPacket->PresentationTime.Numerator = 1;
pDataPacket->PresentationTime.Denominator = 1;
pDataPacket->Duration = pStrmEx->pVideoInfoHeader->AvgTimePerFrame;
//
// if we have a master clock
//
if (pStrmEx->hMasterClock) {
ULONGLONG tmStream;
tmGetStreamTime(IsochDescriptorReserved->Srb, pStrmEx, &tmStream);
pDataPacket->PresentationTime.Time = tmStream;
pDataPacket->OptionsFlags = 0;
pDataPacket->OptionsFlags |=
KSSTREAM_HEADER_OPTIONSF_TIMEVALID |
KSSTREAM_HEADER_OPTIONSF_DURATIONVALID |
KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT; // Every frame we generate is a key frame (aka SplicePoint)
DbgMsg3(("\'IsochCallback: Time(%dms); P#(%d)=Cap(%d)+Drp(%d); Pend%d\n",
(ULONG) tmStream/10000,
(ULONG) pStrmEx->FrameInfo.PictureNumber,
(ULONG) pStrmEx->FrameCaptured,
(ULONG) pStrmEx->FrameInfo.DropCount,
pDevExt->PendingReadCount));
} else {
pDataPacket->PresentationTime.Time = 0;
pDataPacket->OptionsFlags &=
~(KSSTREAM_HEADER_OPTIONSF_TIMEVALID |
KSSTREAM_HEADER_OPTIONSF_DURATIONVALID);
}
// Set additional info fields about the data captured such as:
// Frames Captured
// Frames Dropped
// Field Polarity
pStrmEx->FrameInfo.ExtendedHeaderSize = pFrameInfo->ExtendedHeaderSize;
*pFrameInfo = pStrmEx->FrameInfo;
#ifdef SUPPORT_RGB24
// Swaps B and R or BRG24 to RGB24.
// There are 640x480 pixels so 307200 swaps are needed.
if(pDevExt->CurrentModeIndex == VMODE4_RGB24 && pStrmEx->pVideoInfoHeader) {
PBYTE pbFrameBuffer;
BYTE bTemp;
ULONG i, ulLen;
#ifdef USE_WDM110 // Win2000
// Driver verifier flag to use this but if this is used, this driver will not load for any Win9x OS.
pbFrameBuffer = (PBYTE) MmGetSystemAddressForMdlSafe(IsochDescriptorReserved->Srb->Irp->MdlAddress, NormalPagePriority);
#else // Win9x
pbFrameBuffer = (PBYTE) MmGetSystemAddressForMdl (IsochDescriptorReserved->Srb->Irp->MdlAddress);
#endif
if(pbFrameBuffer) {
// calculate number of pixels
ulLen = abs(pStrmEx->pVideoInfoHeader->bmiHeader.biWidth) * abs(pStrmEx->pVideoInfoHeader->bmiHeader.biHeight);
ASSERT(ulLen == pStrmEx->pVideoInfoHeader->bmiHeader.biSizeImage/3);
if(ulLen > pStrmEx->pVideoInfoHeader->bmiHeader.biSizeImage)
ulLen = pStrmEx->pVideoInfoHeader->bmiHeader.biSizeImage/3;
for (i=0; i < ulLen; i++) {
// swap R and B
bTemp = pbFrameBuffer[0];
pbFrameBuffer[0] = pbFrameBuffer[2];
pbFrameBuffer[2] = bTemp;
pbFrameBuffer += 3; // next RGB24 pixel
}
}
}
#endif
// Reuse the Irp and Irb
pIrp = (PIRP) IsochDescriptor->DeviceReserved[5];
ASSERT(pIrp);
pIrb = (PIRB) IsochDescriptor->DeviceReserved[6];
ASSERT(pIrb);
#if DBG
// Same isochdescriptor should only be callback once.
ASSERT((IsochDescriptor->DeviceReserved[7] == 0x87654321));
IsochDescriptor->DeviceReserved[7]++;
#endif
pIrb->FunctionNumber = REQUEST_ISOCH_DETACH_BUFFERS;
pIrb->u.IsochDetachBuffers.hResource = pDevExt->hResource;
pIrb->u.IsochDetachBuffers.nNumberOfDescriptors = 1;
pIrb->u.IsochDetachBuffers.pIsochDescriptor = IsochDescriptor;
NextIrpStack = IoGetNextIrpStackLocation(pIrp);
NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS;
NextIrpStack->Parameters.Others.Argument1 = pIrb;
IoSetCompletionRoutine(
pIrp,
DCamDetachBufferCR, // Detach complete and will attach queued buffer.
pIrb,
TRUE,
TRUE,
TRUE
);
IoCallDriver(pDevExt->BusDeviceObject, pIrp);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -