|
|
//===========================================================================
//
// 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:
DataPkt.c
Abstract:
Stream class based WDM driver for 1934 Desktop Camera. This file contains code to handle the stream class packets.
Author:
Yee J. Wu 24-Jun-98
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"
extern CAMERA_ISOCH_INFO IsochInfoTable[];
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, DCamSurpriseRemoval)
#pragma alloc_text(PAGE, DCamReceiveDataPacket)
#endif
NTSTATUS DCamCancelOnePacketCR( IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, PISOCH_DESCRIPTOR IsochDescriptor ) /*++
Routine Description:
Completion routine for detach an isoch descriptor associate with a pending read SRB. Will cancel the pending SRB here if detaching descriptor has suceeded.
Arguments:
DriverObject - Pointer to driver object created by system. pIrp - Allocated locally, need to be free here. IsochDescriptor - Isoch descriptor containing the SRB to be cancelled.
Return Value:
None.
--*/ { PHW_STREAM_REQUEST_BLOCK pSrbToCancel; PISOCH_DESCRIPTOR_RESERVED IsochDescriptorReserved; PDCAM_EXTENSION pDevExt;
if(STATUS_SUCCESS != pIrp->IoStatus.Status) { ERROR_LOG(("DCamCancelOnePacketCR: Detach buffer failed with pIrp->IoStatus.Status= %x (! STATUS_SUCCESS) \n", pIrp->IoStatus.Status)); ASSERT(STATUS_SUCCESS == pIrp->IoStatus.Status);
} else { IsochDescriptorReserved = (PISOCH_DESCRIPTOR_RESERVED) &IsochDescriptor->DeviceReserved[0]; pSrbToCancel = IsochDescriptorReserved->Srb; pDevExt = (PDCAM_EXTENSION) pSrbToCancel->HwDeviceExtension;
IsochDescriptorReserved->Flags |= STATE_SRB_IS_COMPLETE;
pSrbToCancel->CommandData.DataBufferArray->DataUsed = 0; pSrbToCancel->ActualBytesTransferred = 0; pSrbToCancel->Status = pDevExt->bDevRemoved ? STATUS_DEVICE_REMOVED : STATUS_CANCELLED;
DbgMsg2(("DCamCancelOnePacketCR: SRB %x, Status %x, IsochDesc %x, Reserved %x cancelled\n", pSrbToCancel, pSrbToCancel->Status, IsochDescriptor, IsochDescriptorReserved));
StreamClassStreamNotification( StreamRequestComplete, pSrbToCancel->StreamObject, pSrbToCancel);
ExFreePool(IsochDescriptor); }
// Allocated locally so free it.
IoFreeIrp(pIrp);
return STATUS_MORE_PROCESSING_REQUIRED; }
VOID DCamDetachAndCancelOnePacket( IN PHW_STREAM_REQUEST_BLOCK pSrbToCancel, PISOCH_DESCRIPTOR IsochDescriptorToDetach, HANDLE hResource, PDEVICE_OBJECT pBusDeviceObject ) /*++
Routine Description:
Detach an isoch descriptor and then cancel pending SRB in the completion routine.
Arguments:
pSrbToCancel - Pointer to SRB to cancel IsochDescriptorToDetach - Iosch descriptor to detach hResource - isoch resource allocated hBusDeviceObject - bus device object
Return Value:
None.
--*/ { PDCAM_EXTENSION pDevExt; PIO_STACK_LOCATION NextIrpStack; NTSTATUS Status; PIRB pIrb; PIRP pIrp;
DbgMsg2(("\'DCamDetachAndCancelOnePacket: pSrbTocancel %x, detaching IsochDescriptorToDetach %x\n", pSrbToCancel, IsochDescriptorToDetach));
pDevExt = (PDCAM_EXTENSION) pSrbToCancel->HwDeviceExtension; pIrp = IoAllocateIrp(pDevExt->BusDeviceObject->StackSize, FALSE); ASSERT(pIrp); if(!pIrp) return;
pIrb = pSrbToCancel->SRBExtension;
pIrb->Flags = 0; pIrb->FunctionNumber = REQUEST_ISOCH_DETACH_BUFFERS; pIrb->u.IsochDetachBuffers.hResource = hResource; pIrb->u.IsochDetachBuffers.nNumberOfDescriptors = 1; pIrb->u.IsochDetachBuffers.pIsochDescriptor = IsochDescriptorToDetach;
NextIrpStack = IoGetNextIrpStackLocation(pIrp); NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS; NextIrpStack->Parameters.Others.Argument1 = pIrb;
IoSetCompletionRoutine( pIrp, DCamCancelOnePacketCR, IsochDescriptorToDetach, TRUE, TRUE, TRUE );
Status = IoCallDriver( pBusDeviceObject, pIrp );
ASSERT(Status == STATUS_SUCCESS || Status == STATUS_PENDING); }
VOID DCamCancelOnePacket( IN PHW_STREAM_REQUEST_BLOCK pSrbToCancel ) /*++
Routine Description:
This routine is called to cancel a pending streaming SRB. This is likely to happen when transitioning from PAUSE to STOP state. Note: This routine is called at DISPATCH_LEVEL !!
Arguments:
pSrbToCancel - Pointer to SRB to cancel
Return Value:
None.
--*/ { PHW_STREAM_REQUEST_BLOCK pSrbInQ; PISOCH_DESCRIPTOR IsochDescriptorToDetach;
PDCAM_EXTENSION pDevExt; PSTREAMEX pStrmEx; PLIST_ENTRY pEntry; // Pointer to an isoch decriptor reserved structure
KIRQL oldIrql; BOOL Found;
pDevExt = (PDCAM_EXTENSION) pSrbToCancel->HwDeviceExtension; ASSERT(pDevExt); pStrmEx = (PSTREAMEX) pDevExt->pStrmEx; ASSERT(pStrmEx);
// Nothing to cancel
if(pStrmEx == NULL) { return; }
//
// We only expect stream SRB, but not device SRB.
//
if ( (pSrbToCancel->Flags & SRB_HW_FLAGS_STREAM_REQUEST) != SRB_HW_FLAGS_STREAM_REQUEST) { ERROR_LOG(("DCamCancelOnePacket: Cannot cancel Device SRB %x\n", pSrbToCancel)); ASSERT( (pSrbToCancel->Flags & SRB_HW_FLAGS_STREAM_REQUEST) == SRB_HW_FLAGS_STREAM_REQUEST ); return; }
//
// Loop through the linked list from the beginning to end,
// trying to find the SRB to cancel
//
KeAcquireSpinLock(&pDevExt->IsochDescriptorLock, &oldIrql);
Found = FALSE; pEntry = pDevExt->IsochDescriptorList.Flink;
while (pEntry != &pDevExt->IsochDescriptorList) {
pSrbInQ = ((PISOCH_DESCRIPTOR_RESERVED)pEntry)->Srb; IsochDescriptorToDetach = \ (PISOCH_DESCRIPTOR) ( ((PUCHAR) pEntry) - FIELDOFFSET(ISOCH_DESCRIPTOR, DeviceReserved[0]));
if(pSrbToCancel == pSrbInQ) { // If we are in RUN state, we could be competing with IsochCallback;
// Whichever grabs and change STATE_DETACHING_BUFFERS will detach.
if(((PISOCH_DESCRIPTOR_RESERVED) pEntry)->Flags & (STATE_SRB_IS_COMPLETE | STATE_DETACHING_BUFFERS)) { Found = FALSE; // IsochCallback are detaching it (we lost our chance).
ERROR_LOG(("DCamCancelOnePacket: pSrbToCancel %x, Descriptor %x, Reserved %x already detaching or completed\n", pSrbToCancel, IsochDescriptorToDetach, pEntry));
} else { ((PISOCH_DESCRIPTOR_RESERVED) pEntry)->Flags |= STATE_DETACHING_BUFFERS; #if DBG
// Should not have been detached.
ASSERT((IsochDescriptorToDetach->DeviceReserved[7] == 0x87654321)); IsochDescriptorToDetach->DeviceReserved[7]++; #endif
RemoveEntryList(pEntry); InterlockedDecrement(&pDevExt->PendingReadCount); Found = TRUE; } break; }
pEntry = pEntry->Flink; // Next
} KeReleaseSpinLock (&pDevExt->IsochDescriptorLock, oldIrql);
//
// Since we are in DISPATCH level, we cannot do sync operation;
// so we will complete this asynchronously in the completion routine.
//
if (Found) {
DCamDetachAndCancelOnePacket( pSrbToCancel, IsochDescriptorToDetach, pDevExt->hResource, pDevExt->BusDeviceObject);
} else { ERROR_LOG(("DCamCancelOnePacket: pSrbToCancel %x is not in our list!\n", pSrbToCancel)); ASSERT(Found); } }
VOID DCamCancelAllPackets( PHW_STREAM_REQUEST_BLOCK pSrb, PDCAM_EXTENSION pDevExt, LONG *plPendingReadCount ) /*++
Routine Description:
This routine is use to cancel all pending IRP. Can be called at DISPATCH_LEVEL.
Arguments:
pSrbToCancel - Pointer to SRB to cancel pDevExt - Device's contect plPendingReadCount - Number of pending read
Return Value:
None.
--*/ { PHW_STREAM_REQUEST_BLOCK pSrbToCancel; PISOCH_DESCRIPTOR IsochDescriptorToDetach; PLIST_ENTRY pEntry; KIRQL oldIrql;
PSTREAMEX pStrmEx;
pStrmEx = pDevExt->pStrmEx;
// Nothing to cancel
if(pStrmEx == NULL) { return; }
//
// Loop through the linked list from the beginning to end,
// trying to find the SRB to cancel
//
KeAcquireSpinLock(&pDevExt->IsochDescriptorLock, &oldIrql); pEntry = pDevExt->IsochDescriptorList.Flink;
while (pEntry != &pDevExt->IsochDescriptorList) {
pSrbToCancel = ((PISOCH_DESCRIPTOR_RESERVED)pEntry)->Srb; IsochDescriptorToDetach = \ (PISOCH_DESCRIPTOR) ( ((PUCHAR) pEntry) - FIELDOFFSET(ISOCH_DESCRIPTOR, DeviceReserved[0]));
if(((PISOCH_DESCRIPTOR_RESERVED) pEntry)->Flags & (STATE_SRB_IS_COMPLETE | STATE_DETACHING_BUFFERS)) { // Skip this one since it is already in detaching phase or completed.
ERROR_LOG(("DCamCancelAllPacket: pSrbToCancel %x, Descriptor %x, Reserved %x already detaching or completed\n", pSrbToCancel, IsochDescriptorToDetach, pEntry));
pEntry = pEntry->Flink; // next
} else { ((PISOCH_DESCRIPTOR_RESERVED) pEntry)->Flags |= STATE_DETACHING_BUFFERS; #if DBG
// Should not have been detached.
ASSERT((IsochDescriptorToDetach->DeviceReserved[7] == 0x87654321)); IsochDescriptorToDetach->DeviceReserved[7]++; #endif
RemoveEntryList(pEntry); InterlockedDecrement(plPendingReadCount); DbgMsg2(("DCamCancelAllPackets: pSrbToCancel %x, Descriptor %x, Reserved %x\n", pSrbToCancel, IsochDescriptorToDetach, pEntry));
pEntry = pEntry->Flink; // pEntry is deleted in DCamDetachAndCancelOnePacket(); so get next here.
DCamDetachAndCancelOnePacket( pSrbToCancel, IsochDescriptorToDetach, pDevExt->hResource, pDevExt->BusDeviceObject); } }
KeReleaseSpinLock (&pDevExt->IsochDescriptorLock, oldIrql);
pSrb->Status = STATUS_SUCCESS; DbgMsg1(("DCamCancelAllPackets: Complete pSrb %x, Status %x\n", pSrb, pSrb->Status));
COMPLETE_SRB(pSrb) }
VOID DCamSurpriseRemoval( IN PHW_STREAM_REQUEST_BLOCK pSrb )
/*++
Routine Description:
Response to SRB_SURPRISE_REMOVAL.
Arguments:
pSrb - Pointer to the stream request block
Return Value:
None.
--*/
{
PIRP pIrp; PIRB pIrb; PDCAM_EXTENSION pDevExt; PSTREAMEX pStrmEx; NTSTATUS Status, StatusWait;
PAGED_CODE();
pIrb = (PIRB) pSrb->SRBExtension; ASSERT(pIrb); pDevExt = (PDCAM_EXTENSION) pSrb->HwDeviceExtension; ASSERT(pDevExt);
//
// Set this to stop accepting incoming read.
//
pDevExt->bDevRemoved = TRUE;
//
// Wait for currect read to be attached so we cancel them all.
//
pStrmEx = pDevExt->pStrmEx; if(pStrmEx) { // Make sure that this structure is still valid.
if(pStrmEx->pVideoInfoHeader) { StatusWait = KeWaitForSingleObject( &pStrmEx->hMutex, Executive, KernelMode, FALSE, 0 ); KeReleaseMutex(&pStrmEx->hMutex, FALSE); } }
pIrp = IoAllocateIrp(pDevExt->BusDeviceObject->StackSize, FALSE); if(!pIrp) { ERROR_LOG(("DCamSurpriseRemovalPacket: faile to get resource; pIrb=%x, pDevExt=%x, pIrp\n", pIrb, pDevExt, pIrp)); pSrb->Status = STATUS_INSUFFICIENT_RESOURCES; StreamClassDeviceNotification(DeviceRequestComplete, pSrb->HwDeviceExtension, pSrb); return; }
//
// un-register a bus reset callback notification
//
pIrb->FunctionNumber = REQUEST_BUS_RESET_NOTIFICATION; pIrb->Flags = 0; pIrb->u.BusResetNotification.fulFlags = DEREGISTER_NOTIFICATION_ROUTINE; pIrb->u.BusResetNotification.ResetRoutine = (PBUS_BUS_RESET_NOTIFICATION) DCamBusResetNotification; pIrb->u.BusResetNotification.ResetContext = 0; Status = DCamSubmitIrpSynch(pDevExt, pIrp, pIrb); if(Status) { ERROR_LOG(("DCamSurpriseRemoval: Status %x while trying to deregister bus reset notification.\n", Status)); }
//
// Get new generation number
//
pIrb->FunctionNumber = REQUEST_GET_GENERATION_COUNT; pIrb->Flags = 0; Status = DCamSubmitIrpSynch(pDevExt, pIrp, pIrb); if(Status) { ERROR_LOG(("DCamSurpriseRemoval: Status %x while trying to get generation number.\n", Status)); } else { DbgMsg1(("DCamSurpriseRemoval: pDevExt %x, Generation number from %d to %d\n", pDevExt, pDevExt->CurrentGeneration, pIrb->u.GetGenerationCount.GenerationCount)); InterlockedExchange(&pDevExt->CurrentGeneration, pIrb->u.GetGenerationCount.GenerationCount); }
if(pStrmEx) { //
// Stop isoch transmission so we can detach buffers and cancel pending SRBs
//
pIrb->FunctionNumber = REQUEST_ISOCH_STOP; pIrb->Flags = 0; pIrb->u.IsochStop.hResource = pDevExt->hResource; pIrb->u.IsochStop.fulFlags = 0; Status = DCamSubmitIrpSynch(pDevExt, pIrp, pIrb); if(Status) { ERROR_LOG(("DCamSurpriseRemoval: Status %x while trying to ISOCH_STOP.\n", Status)); } IoFreeIrp(pIrp);
DCamCancelAllPackets( pSrb, pDevExt, &pDevExt->PendingReadCount );
} else { IoFreeIrp(pIrp); StreamClassDeviceNotification(DeviceRequestComplete, pSrb->HwDeviceExtension, pSrb); }
}
NTSTATUS DCamAttachBufferCR( IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PISOCH_DESCRIPTOR IsochDescriptor ) /*++
Routine Description:
This routine is the completion routine from attaching a bufffer to lower driver.
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.
--*/
{ PHW_STREAM_REQUEST_BLOCK pSrb; PDCAM_EXTENSION pDevExt; PSTREAMEX pStrmEx; NTSTATUS Status; PIRB pIrb; PISOCH_DESCRIPTOR_RESERVED IsochDescriptorReserved; KIRQL oldIrql;
pDevExt = (PDCAM_EXTENSION) IsochDescriptor->Context1; ASSERT(pDevExt); pStrmEx = (PSTREAMEX) pDevExt->pStrmEx; ASSERT(pStrmEx); IsochDescriptorReserved = (PISOCH_DESCRIPTOR_RESERVED) &IsochDescriptor->DeviceReserved[0]; ASSERT(IsochDescriptorReserved); pSrb = IsochDescriptorReserved->Srb; ASSERT(pSrb); pIrb = (PIRB) pSrb->SRBExtension;
DbgMsg3(("\'DCamAttachBufferCR: completed KSSTATE=%d; pIrp->IoStatus.Status=%x; pSrb=%x\n", pStrmEx->KSState, pIrp->IoStatus.Status, pSrb));
//
// Attaching a buffer return with error.
//
if(pIrp->IoStatus.Status) {
ERROR_LOG(("DCamAttachBufferCR: pIrp->IoStatus.Status=%x (STATUS_PENDING=%x); complete SRB with this status.\n", pIrp->IoStatus.Status, STATUS_PENDING)); ASSERT(pIrp->IoStatus.Status == STATUS_SUCCESS);
if(!(IsochDescriptorReserved->Flags & STATE_SRB_IS_COMPLETE)) {
ASSERT(((IsochDescriptorReserved->Flags & STATE_SRB_IS_COMPLETE) != STATE_SRB_IS_COMPLETE));
IsochDescriptorReserved->Flags |= STATE_SRB_IS_COMPLETE; pSrb->Status = pIrp->IoStatus.Status; // Read is completed with error status.
KeAcquireSpinLock(&pDevExt->IsochDescriptorLock, &oldIrql); RemoveEntryList(&IsochDescriptorReserved->DescriptorList); InterlockedDecrement(&pDevExt->PendingReadCount); KeReleaseSpinLock(&pDevExt->IsochDescriptorLock, oldIrql);
ExFreePool(IsochDescriptor); StreamClassStreamNotification(StreamRequestComplete, pSrb->StreamObject, pSrb);
KeAcquireSpinLock(&pDevExt->IsochWaitingLock, &oldIrql);
//
// If we failed to attach (rtn with failed status),
// removed this entry, and
// pull one out of the waiting list if not yet exceeded out limit.
//
if (!IsListEmpty(&pDevExt->IsochWaitingList) && pDevExt->PendingReadCount >= MAX_BUFFERS_SUPPLIED) {
//
// We had someone blocked waiting for us to complete. Pull
// them off the waiting list and get them running
//
DbgMsg3(("\'DCamAttachBufferCR: Dequeueing request - Read Count=%d\n", pDevExt->PendingReadCount)); IsochDescriptorReserved = \ (PISOCH_DESCRIPTOR_RESERVED) RemoveHeadList( &pDevExt->IsochWaitingList );
KeReleaseSpinLock(&pDevExt->IsochWaitingLock, oldIrql);
IsochDescriptor = \ (PISOCH_DESCRIPTOR) (((PUCHAR) IsochDescriptorReserved) - FIELDOFFSET(ISOCH_DESCRIPTOR, DeviceReserved[0])); DCamReadStreamWorker(IsochDescriptorReserved->Srb, IsochDescriptor); } else { KeReleaseSpinLock(&pDevExt->IsochWaitingLock, oldIrql); }
} else {
// Race condition ? or a valid error code?
ERROR_LOG(("DCamAttachBufferCR: IsochDescriptorReserved->Flags contain STATE_SRB_IS_COMPLETE\n")); ASSERT(FALSE); }
}
//
// Ealier when we set to RUN state, it might have failed with
// STATUS_INSUFFICIENT_RESOURCE due to no buffer attached;
// we have at least one now, ask controll to start listen and
// fill and return our buffer.
//
if(pDevExt->bNeedToListen) { PIRB pIrb2; PIRP pIrp2; PDCAM_IO_CONTEXT pDCamIoContext; PIO_STACK_LOCATION NextIrpStack;
if(!DCamAllocateIrbIrpAndContext(&pDCamIoContext, &pIrb2, &pIrp2, pDevExt->BusDeviceObject->StackSize)) { ERROR_LOG(("DCamAttachBufferCR: Want to stat Listening but no resource !!\n")); return STATUS_MORE_PROCESSING_REQUIRED; } pDevExt->bNeedToListen = FALSE; DbgMsg2(("\'DCamAttachBufferCR: ##### pDevExt->bNeedToListen\n")); pDCamIoContext->pDevExt = pDevExt; pDCamIoContext->pIrb = pIrb2;
pIrb2->FunctionNumber = REQUEST_ISOCH_LISTEN; pIrb2->Flags = 0; pIrb2->u.IsochListen.hResource = pDevExt->hResource; pIrb2->u.IsochListen.fulFlags = 0;
NextIrpStack = IoGetNextIrpStackLocation(pIrp2); NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS; NextIrpStack->Parameters.Others.Argument1 = pIrb2;
pDevExt->lRetries = RETRY_COUNT;
IoSetCompletionRoutine( pIrp2, DCamStartListenCR, pDCamIoContext, TRUE, TRUE, TRUE );
Status = IoCallDriver( pDevExt->BusDeviceObject, pIrp2); }
// No resource to freed.
// Resource (pIrb is from original SRB)
return STATUS_MORE_PROCESSING_REQUIRED;
//
// The attached SRB read will be completed in IoschCallback().
//
}
NTSTATUS DCamReSubmitPacketCR( IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PISOCH_DESCRIPTOR IsochDescriptor ) /*++
Routine Description:
This routine is called after a packet is detach and will be attached here to complete the resubmission of packet after a isoch. resource change.
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.
--*/
{ PIRB pIrb; PIO_STACK_LOCATION NextIrpStack; PDCAM_EXTENSION pDevExt; PISOCH_DESCRIPTOR_RESERVED IsochDescriptorReserved; NTSTATUS Status;
pDevExt = IsochDescriptor->Context1; ASSERT(pDevExt);
pIrb = (PIRB) IsochDescriptor->DeviceReserved[6]; ASSERT(pIrb);
IsochDescriptorReserved = (PISOCH_DESCRIPTOR_RESERVED) &IsochDescriptor->DeviceReserved[0];
//
// Detached, so unmark it.
//
IsochDescriptorReserved->Flags &= ~STATE_DETACHING_BUFFERS;
DbgMsg2(("\'DCamReSubmitPacketCR: ReSubmit pDevExt %x, pIrb %x, hResource %x, IsochDescriptor %x, IsochDescriptorReserved %x\n", pDevExt, pIrb, pDevExt->hResource, IsochDescriptor, IsochDescriptorReserved));
#if DBG
//
// Put signatures and use these count to track if the IsochDescriptor
// has been attached or detached unexpectely.
//
// When attach, [4]++ (DCamReadStreamWorker(), DCamReSumbitPacketCR())
// detach, [7]++ (DCamIsochcallback(), DCamCancelPacketCR(), DCamResubmitPacket())
//
IsochDescriptor->DeviceReserved[4] = 0x12345678; IsochDescriptor->DeviceReserved[7] = 0x87654321; #endif
//
// Attach descriptor onto our pending descriptor list
//
ExInterlockedInsertTailList( &pDevExt->IsochDescriptorList, &IsochDescriptorReserved->DescriptorList, &pDevExt->IsochDescriptorLock );
pIrb->FunctionNumber = REQUEST_ISOCH_ATTACH_BUFFERS; pIrb->Flags = 0; pIrb->u.IsochAttachBuffers.hResource = pDevExt->hResource; pIrb->u.IsochAttachBuffers.nNumberOfDescriptors = 1; pIrb->u.IsochAttachBuffers.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, DCamAttachBufferCR, IsochDescriptor, TRUE, TRUE, TRUE );
Status = IoCallDriver( pDevExt->BusDeviceObject, pIrp );
ASSERT(Status == STATUS_SUCCESS || Status == STATUS_PENDING);
return STATUS_MORE_PROCESSING_REQUIRED; // Complete Asynchronously in DCamAttachBufferCR
}
NTSTATUS DCamReSubmitPacket( HANDLE hStaleResource, PDCAM_EXTENSION pDevExt, PSTREAMEX pStrmEx, LONG cntPendingRead )
/*++
Routine Description:
Due to a bus reset, if a channel number has changed (subsequently, iso resource change too), we must detach and re-attach pending packet(s). While this function is executed, incoming SRB_READ is blocked and isoch callback are returned and not processed (we are resubmiting them).
Arguments:
hStaleResource - staled isoch resource pDevExt - Device's Extension pStrmEx - Stremaing extension cntPendingRead - Number of pending packets
Return Value:
NTSTATUS.
--*/
{ PIRB pIrb; PIRP pIrp; PIO_STACK_LOCATION NextIrpStack; PISOCH_DESCRIPTOR IsochDescriptor; PISOCH_DESCRIPTOR_RESERVED IsochDescriptorReserved; NTSTATUS Status = STATUS_SUCCESS; KIRQL oldIrql;
DbgMsg1(("DCamReSubmitPacket: pDevExt %x, pStrmEx %x, PendingCount %d\n", pDevExt, pStrmEx, cntPendingRead));
for(; cntPendingRead > 0; cntPendingRead--) {
if(!IsListEmpty(&pDevExt->IsochDescriptorList)) {
//
// 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); IsochDescriptorReserved = (PISOCH_DESCRIPTOR_RESERVED) RemoveHeadList(&pDevExt->IsochDescriptorList);
if((IsochDescriptorReserved->Flags & (STATE_SRB_IS_COMPLETE | STATE_DETACHING_BUFFERS))) { ERROR_LOG(("DCamReSubmitPacket: Flags %x aleady mark STATE_SRB_IS_COMPLETE | STATE_DETACHING_BUFFERS\n", IsochDescriptorReserved->Flags)); ASSERT(( !(IsochDescriptorReserved->Flags & (STATE_SRB_IS_COMPLETE | STATE_DETACHING_BUFFERS))));\ //Put it back since it has been detached.
InsertTailList(&pDevExt->IsochDescriptorList, &IsochDescriptorReserved->DescriptorList);
KeReleaseSpinLock(&pDevExt->IsochDescriptorLock, oldIrql); continue; } IsochDescriptorReserved->Flags |= STATE_DETACHING_BUFFERS; KeReleaseSpinLock(&pDevExt->IsochDescriptorLock, oldIrql);
IsochDescriptor = (PISOCH_DESCRIPTOR) (((PUCHAR) IsochDescriptorReserved) - FIELDOFFSET(ISOCH_DESCRIPTOR, DeviceReserved[0]));
pIrp = (PIRP) IsochDescriptor->DeviceReserved[5]; ASSERT(pIrp); pIrb = (PIRB) IsochDescriptor->DeviceReserved[6]; ASSERT(pIrb);
DbgMsg1(("DCamReSubmitPacket: detaching IsochDescriptor %x IsochDescriptorReserved %x, pSrb %x\n", IsochDescriptor, IsochDescriptorReserved, IsochDescriptorReserved->Srb));
#if DBG
// Should not have been detached
ASSERT((IsochDescriptor->DeviceReserved[7] == 0x87654321)); IsochDescriptor->DeviceReserved[7]++; #endif
pIrb->FunctionNumber = REQUEST_ISOCH_DETACH_BUFFERS; pIrb->Flags = 0; pIrb->u.IsochDetachBuffers.hResource = hStaleResource; 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, DCamReSubmitPacketCR, IsochDescriptor, TRUE, TRUE, TRUE );
Status = IoCallDriver( pDevExt->BusDeviceObject, pIrp );
ASSERT(Status == STATUS_SUCCESS || Status == STATUS_PENDING);
} else { ERROR_LOG(("PendingCount %d, but list is empty!!\n", cntPendingRead)); ASSERT(cntPendingRead == 0); }
} // for()
return Status; }
VOID DCamReadStreamWorker( IN PHW_STREAM_REQUEST_BLOCK pSrb, IN PISOCH_DESCRIPTOR IsochDescriptor )
/*++
Routine Description:
Does most of the work for handling reads via Attach buffers
Arguments:
Srb - Pointer to Stream request block
IsochDescriptor - Pointer to IsochDescriptor to be used
Return Value:
Nothing
--*/
{
PIRB pIrb; PIRP pIrp; PIO_STACK_LOCATION NextIrpStack; PDCAM_EXTENSION pDevExt; PISOCH_DESCRIPTOR_RESERVED IsochDescriptorReserved; NTSTATUS Status;
pDevExt = (PDCAM_EXTENSION) pSrb->HwDeviceExtension; pIrp = (PIRP) IsochDescriptor->DeviceReserved[5]; ASSERT(pIrp); pIrb = (PIRB) IsochDescriptor->DeviceReserved[6]; ASSERT(pIrb); #if DBG
// track number time the same IsochDescriptor are attaching; should only be one.
IsochDescriptor->DeviceReserved[4]++; #endif
//
// It is pending and will be completed in isoch callback or cancelled.
//
pSrb->Status = STATUS_PENDING;
IsochDescriptorReserved = (PISOCH_DESCRIPTOR_RESERVED) &IsochDescriptor->DeviceReserved[0];
DbgMsg3(("\'DCamReadStreamWorker: enter with pSrb = %x, pDevExt=0x%x\n", pSrb, pDevExt));
//
// Attach descriptor onto our pending descriptor list
//
ExInterlockedInsertTailList( &pDevExt->IsochDescriptorList, &IsochDescriptorReserved->DescriptorList, &pDevExt->IsochDescriptorLock );
pIrb->FunctionNumber = REQUEST_ISOCH_ATTACH_BUFFERS; pIrb->Flags = 0; pIrb->u.IsochAttachBuffers.hResource = pDevExt->hResource; pIrb->u.IsochAttachBuffers.nNumberOfDescriptors = 1; pIrb->u.IsochAttachBuffers.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, DCamAttachBufferCR, IsochDescriptor, TRUE, TRUE, TRUE );
Status = IoCallDriver( pDevExt->BusDeviceObject, pIrp );
ASSERT(Status == STATUS_SUCCESS || Status == STATUS_PENDING);
return; // Complete Asynchronously in IoCompletionRoutine*
}
VOID DCamReadStream( IN PHW_STREAM_REQUEST_BLOCK Srb )
/*++
Routine Description:
Called when an Read Data Srb request is received
Arguments:
Srb - Pointer to Stream request block
Return Value:
Nothing
--*/
{
PIRB pIrb; PIRP pIrp; KIRQL oldIrql; PDCAM_EXTENSION pDevExt; PSTREAMEX pStrmEx; PISOCH_DESCRIPTOR IsochDescriptor; PISOCH_DESCRIPTOR_RESERVED IsochDescriptorReserved; NTSTATUS StatusWait;
pIrb = (PIRB) Srb->SRBExtension; pDevExt = (PDCAM_EXTENSION) Srb->HwDeviceExtension; ASSERT(pDevExt != NULL);
pStrmEx = (PSTREAMEX) pDevExt->pStrmEx; ASSERT(pStrmEx);
if(pDevExt->bDevRemoved || pStrmEx == NULL) {
Srb->Status = pDevExt->bDevRemoved ? STATUS_DEVICE_REMOVED : STATUS_UNSUCCESSFUL; Srb->ActualBytesTransferred = 0; Srb->CommandData.DataBufferArray->DataUsed = 0; ERROR_LOG(("DCamReadStream: Failed with Status %x or pStrmEx %x\n", Srb->Status, pStrmEx));
StreamClassStreamNotification(StreamRequestComplete, Srb->StreamObject, Srb); return; }
//
// Mutext for either StreamIo (SRB_READ) ControlIo (SRB_SET_STREAM_STATE)
//
// Non-alertable; wait infinite
StatusWait = KeWaitForSingleObject( &pStrmEx->hMutex, Executive, KernelMode, FALSE, 0 ); ASSERT(StatusWait == STATUS_SUCCESS);
DbgMsg3(("\'%d:%s) DCamReadStream: enter with Srb %x, DevExt %x\n", pDevExt->idxDev, pDevExt->pchVendorName, Srb, pDevExt));
// Rule:
// Only accept read requests when in either the Pause or Run
// States. If Stopped, immediately return the SRB.
if (pStrmEx->KSState == KSSTATE_STOP || pStrmEx->KSState == KSSTATE_ACQUIRE) {
DbgMsg2(("\'%d:%s)DCamReadStream: Current KSState(%d) < (%d)=KSSTATE_PAUSE; Srb=0x%x; DevExt=0x%x", pDevExt->idxDev, pDevExt->pchVendorName, pStrmEx->KSState, KSSTATE_PAUSE, Srb, pDevExt));
DbgMsg2(("\'DCamReadStream: PendingRead=%d, IsochDescriptorList(%s)\n", pDevExt->PendingReadCount, IsListEmpty(&pDevExt->IsochDescriptorList)?"Empty":"!Empty"));
Srb->Status = STATUS_UNSUCCESSFUL; Srb->CommandData.DataBufferArray->DataUsed = 0; StreamClassStreamNotification(StreamRequestComplete, Srb->StreamObject, Srb);
KeReleaseMutex(&pStrmEx->hMutex, FALSE);
return; }
// Buffer need to be big enough
if (IsochInfoTable[pStrmEx->idxIsochTable].CompletePictureSize > Srb->CommandData.DataBufferArray->FrameExtent) {
ASSERT(IsochInfoTable[pStrmEx->idxIsochTable].CompletePictureSize <= Srb->CommandData.DataBufferArray->FrameExtent); Srb->Status = STATUS_INVALID_PARAMETER; StreamClassStreamNotification(StreamRequestComplete, Srb->StreamObject, Srb);
KeReleaseMutex(&pStrmEx->hMutex, FALSE);
return; }
//
// Use our own IRP
//
pIrp = IoAllocateIrp(pDevExt->BusDeviceObject->StackSize, FALSE); if(!pIrp) { ASSERT(pIrp); Srb->Status = STATUS_INSUFFICIENT_RESOURCES; return; }
//
// This structure (IsochDescriptor) has (ULONG) DeviceReserved[8];
// Its first 4 ULONGs are used by IsochDescriptorReserved,
// The 6th (index[5]), is used to keep pIrp
// 7th (index[6]), is used to keep pIrb
//
IsochDescriptor = ExAllocatePoolWithTag(NonPagedPool, sizeof(ISOCH_DESCRIPTOR), 'macd'); if (!IsochDescriptor) {
ASSERT(FALSE); Srb->Status = STATUS_INSUFFICIENT_RESOURCES; StreamClassStreamNotification(StreamRequestComplete, Srb->StreamObject, Srb);
KeReleaseMutex(&pStrmEx->hMutex, FALSE);
return; }
DbgMsg3(("\'DCamReadStream: IsochDescriptor = %x\n", IsochDescriptor)); IsochDescriptor->fulFlags = SYNCH_ON_SY;
DbgMsg3(("\'DCamReadStream: Incoming Mdl = %x\n", Srb->Irp->MdlAddress)); IsochDescriptor->Mdl = Srb->Irp->MdlAddress;
// Use size match what we originally requested in AllocateIsoch
IsochDescriptor->ulLength = IsochInfoTable[pStrmEx->idxIsochTable].CompletePictureSize; IsochDescriptor->nMaxBytesPerFrame = IsochInfoTable[pStrmEx->idxIsochTable].QuadletPayloadPerPacket << 2;
IsochDescriptor->ulSynch = START_OF_PICTURE; IsochDescriptor->ulTag = 0; IsochDescriptor->Callback = DCamIsochCallback; IsochDescriptor->Context1 = pDevExt; IsochDescriptor->Context2 = IsochDescriptor;
//
// IsochDescriptorReserved is pointed to the DeviceReserved[0];
// The entire, except the links, are kept in the DeviceReserved[]
//
IsochDescriptorReserved = (PISOCH_DESCRIPTOR_RESERVED) &IsochDescriptor->DeviceReserved[0]; IsochDescriptorReserved->Srb = Srb; IsochDescriptorReserved->Flags = 0;
IsochDescriptor->DeviceReserved[5] = (ULONG_PTR) pIrp; IsochDescriptor->DeviceReserved[6] = (ULONG_PTR) pIrb;
#if DBG
//
// Put signatures and use these count to track if the IsochDescriptor
// has been attached or detached unexpectely.
//
// When attach, [4]++ (DCamReadStreamWorker(), DCamReSumbitPacketCR())
// detach, [7]++ (DCamIsochcallback(), DCamCancelPacketCR(), DCamResubmitPacket())
//
IsochDescriptor->DeviceReserved[4] = 0x12345678; IsochDescriptor->DeviceReserved[7] = 0x87654321; #endif
//
// Checking here to see if we have enuff resources to put this read
// down right away. Since we only allocated N amount of resources
// from the 1394 stack beneath us, we'll have to stay within that
// limit and do some of the throttling ourself.
//
KeAcquireSpinLock(&pDevExt->IsochWaitingLock, &oldIrql); if (InterlockedIncrement(&pDevExt->PendingReadCount) > MAX_BUFFERS_SUPPLIED) {
//
// don't have enuff resources to do an attach buffers right now.
// we'll queue this request and pull it off later when another
// read completes.
//
DbgMsg2(("\'DCamReadStream: Queueing request - Read Count = %x\n", pDevExt->PendingReadCount)); InsertTailList( &pDevExt->IsochWaitingList, &IsochDescriptorReserved->DescriptorList );
KeReleaseSpinLock(&pDevExt->IsochWaitingLock, oldIrql);
KeReleaseMutex(&pStrmEx->hMutex, FALSE);
return;
}
if(pStrmEx->KSState == KSSTATE_PAUSE) { DbgMsg2(("\'DCamReadStream: Doing Pre-read in _PAUSE state; Srb %x, pDevExt %x, PendingCount %d\n", Srb, pDevExt, pDevExt->PendingReadCount)); }
//
// Do actual read work here via our Read worker function
//
KeReleaseSpinLock(&pDevExt->IsochWaitingLock, oldIrql); DCamReadStreamWorker(Srb, IsochDescriptor);
KeReleaseMutex(&pStrmEx->hMutex, FALSE);
}
VOID DCamReceiveDataPacket( IN PHW_STREAM_REQUEST_BLOCK Srb )
/*++
Routine Description:
Called with video data packet commands
Arguments:
Srb - Pointer to Stream request block
Return Value:
Nothing
--*/
{ PAGED_CODE();
//
// determine the type of packet.
//
switch (Srb->Command) {
case SRB_READ_DATA:
DbgMsg3(("\'DCamReceiveDataPacket: SRB_READ_DATA\n")); DCamReadStream(Srb);
// This request will be completed asynchronously...
break;
case SRB_WRITE_DATA:
DbgMsg3(("\'DCamReceiveDataPacket: SRB_WRITE_DATA, not used for digital camera.\n")); ASSERT(FALSE);
default:
//
// invalid / unsupported command. Fail it as such
//
Srb->Status = STATUS_NOT_IMPLEMENTED;
StreamClassStreamNotification(StreamRequestComplete, Srb->StreamObject, Srb);
}
}
|