⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 callback.c

📁 1394 摄像头驱动程序源代码,学习驱动程序的人可以看看
💻 C
📖 第 1 页 / 共 2 页
字号:
//===========================================================================
//
// 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 + -