928 lines
27 KiB
C
928 lines
27 KiB
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:
|
|
|
|
CtrlPkt.c
|
|
|
|
Abstract:
|
|
|
|
Stream class based WDM driver for 1934 Desktop Camera.
|
|
This file contains code to handle the stream class control 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"
|
|
|
|
#define WAIT_FOR_SLOW_DEVICE
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, DCamSetKSStateSTOP)
|
|
#pragma alloc_text(PAGE, DCamSetKSStatePAUSE)
|
|
#pragma alloc_text(PAGE, DCamReceiveCtrlPacket)
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
DCamToStopStateCR(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP pIrp,
|
|
IN PDCAM_IO_CONTEXT pDCamIoContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
This is the state machine to set the streaming state to STOP.
|
|
It start at PASSIVE_LEVEL and the lower driver may have raised it to DISPATCH_LEVEL.
|
|
|
|
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;
|
|
NTSTATUS Status;
|
|
PIRB pIrb;
|
|
PIO_STACK_LOCATION NextIrpStack;
|
|
|
|
|
|
if(!pDCamIoContext) {
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
pIrb = pDCamIoContext->pIrb;
|
|
pDevExt = pDCamIoContext->pDevExt;
|
|
pStrmEx = (PSTREAMEX) pDevExt->pStrmEx;
|
|
|
|
DbgMsg2(("\'DCamToStopStateCR: completed DeviceState=%d; pIrp->IoStatus.Status=%x\n",
|
|
pDCamIoContext->DeviceState, pIrp->IoStatus.Status));
|
|
|
|
// Free MDL
|
|
if(pIrb->FunctionNumber == REQUEST_ASYNC_WRITE) {
|
|
DbgMsg3(("DCamToStopStateCR: IoFreeMdl\n"));
|
|
IoFreeMdl(pIrb->u.AsyncWrite.Mdl);
|
|
}
|
|
|
|
|
|
// Return error status and free resoruce.
|
|
if(pIrp->IoStatus.Status != STATUS_SUCCESS) {
|
|
if(pDCamIoContext->pSrb) {
|
|
ERROR_LOG(("DCamToStopStateCR: pIrp->IoStatus.Status %x; cancel all packets\n", pIrp->IoStatus.Status));
|
|
// In order to stop streaming, we must cancel all pending IRPs
|
|
// Cancel pending IRPS and complete SRB.
|
|
DCamCancelAllPackets(
|
|
pDCamIoContext->pSrb,
|
|
pDevExt,
|
|
&pDevExt->PendingReadCount
|
|
);
|
|
}
|
|
DCamFreeIrbIrpAndContext(pDCamIoContext, pDCamIoContext->pIrb, pIrp);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
switch (pDCamIoContext->DeviceState) {
|
|
|
|
case DCAM_STOPSTATE_SET_REQUEST_ISOCH_STOP:
|
|
//
|
|
// Now stop the stream at the device itself
|
|
//
|
|
// Next state:
|
|
pDCamIoContext->DeviceState = DCAM_STOPSTATE_SET_STOP_ISOCH_TRANSMISSION; // Keep track of device state that we just set.
|
|
|
|
pDCamIoContext->RegisterWorkArea.AsULONG = STOP_ISOCH_TRANSMISSION;
|
|
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, IsoEnable);
|
|
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);
|
|
|
|
// Set once and used again in the completion routine.
|
|
NextIrpStack = IoGetNextIrpStackLocation(pIrp);
|
|
NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS;
|
|
NextIrpStack->Parameters.Others.Argument1 = pIrb;
|
|
|
|
IoSetCompletionRoutine(
|
|
pIrp,
|
|
DCamToStopStateCR,
|
|
pDCamIoContext,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
Status =
|
|
IoCallDriver(
|
|
pDevExt->BusDeviceObject,
|
|
pIrp
|
|
);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
|
|
case DCAM_STOPSTATE_SET_STOP_ISOCH_TRANSMISSION:
|
|
//
|
|
// Detach all buffers that might still be attached.
|
|
//
|
|
DbgMsg2(("\'DCamToStopStateCR: IsListEmpty()=%s; PendingRead=%d\n",
|
|
IsListEmpty(&pDevExt->IsochDescriptorList) ? "Yes" : "No", pDevExt->PendingReadCount));
|
|
|
|
if(pDCamIoContext->pSrb) {
|
|
//
|
|
// Cancel all pending and waiting buffers;
|
|
// and Complete DCamSetKSStateSTOP's SRB
|
|
//
|
|
DCamCancelAllPackets(
|
|
pDCamIoContext->pSrb,
|
|
pDevExt,
|
|
&pDevExt->PendingReadCount
|
|
);
|
|
|
|
// This pDCamIoContext->pSrb will be completed in DCamCancelPacket()
|
|
// But its Irb and Irp and context are freed here.
|
|
DCamFreeIrbIrpAndContext(pDCamIoContext, pDCamIoContext->pIrb, pIrp);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
} else {
|
|
ERROR_LOG(("DCamToStopStateCR:CanNOT call DCamCancelPacket() with a null pSrb\n"));
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
ERROR_LOG(("\'DCamToStopStateCR: Unknown pDCamIoContext->DeviceState=%d\n", pDCamIoContext->DeviceState));
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
if(pDCamIoContext->pSrb) {
|
|
pDCamIoContext->pSrb->Status = pIrp->IoStatus.Status == STATUS_SUCCESS ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
|
COMPLETE_SRB(pDCamIoContext->pSrb)
|
|
}
|
|
DCamFreeIrbIrpAndContext(pDCamIoContext, pDCamIoContext->pIrb, pIrp);
|
|
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
DCamSetKSStateSTOP(
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Into STOP streaming state.
|
|
(1) Stop device from steaming (!ISO_ENABLE)
|
|
(2) Stop listening (controller)
|
|
(3) Detach pending read buffer and return with Cancel, and
|
|
start the waiting read to be put into the pengin read and then Cancel.
|
|
|
|
Arguments:
|
|
|
|
pSrb - Pointer to Stream request block
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PDCAM_EXTENSION pDevExt;
|
|
PSTREAMEX pStrmEx;
|
|
PIRB pIrb;
|
|
PIRP pIrp;
|
|
PDCAM_IO_CONTEXT pDCamIoContext;
|
|
PIO_STACK_LOCATION NextIrpStack;
|
|
NTSTATUS Status, StatusWait;
|
|
|
|
PAGED_CODE();
|
|
|
|
pDevExt = (PDCAM_EXTENSION) pSrb->HwDeviceExtension;
|
|
ASSERT(pDevExt);
|
|
pStrmEx = (PSTREAMEX) pDevExt->pStrmEx;
|
|
ASSERT(pStrmEx);
|
|
|
|
|
|
DbgMsg1(("\'DCamSetKSStateSTOP: Frame captured:%d\n", (DWORD) pStrmEx->FrameCaptured));
|
|
//
|
|
// After this, no more read will be accepted.
|
|
//
|
|
pStrmEx->KSState = KSSTATE_STOP;
|
|
|
|
|
|
//
|
|
// First stop the stream internally inside the PC's 1394
|
|
// stack
|
|
//
|
|
if(!pDevExt->hResource) {
|
|
pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
COMPLETE_SRB(pSrb)
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Wait for last read to complete.
|
|
// After KState == KSSTATE_STOP, we will return all SRB_READ.
|
|
//
|
|
StatusWait = KeWaitForSingleObject( &pStrmEx->hMutex, Executive, KernelMode, FALSE, 0 );
|
|
KeReleaseMutex(&pStrmEx->hMutex, FALSE);
|
|
|
|
|
|
if(!DCamAllocateIrbIrpAndContext(&pDCamIoContext, &pIrb, &pIrp, pDevExt->BusDeviceObject->StackSize)) {
|
|
pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
COMPLETE_SRB(pSrb)
|
|
return;
|
|
}
|
|
|
|
pDCamIoContext->DeviceState = DCAM_STOPSTATE_SET_REQUEST_ISOCH_STOP;
|
|
pDCamIoContext->pSrb = pSrb; // To do StreamClassStreamNotification()
|
|
pDCamIoContext->pDevExt = pDevExt;
|
|
pIrb->FunctionNumber = REQUEST_ISOCH_STOP;
|
|
pIrb->Flags = 0;
|
|
pIrb->u.IsochStop.hResource = pDevExt->hResource;
|
|
pIrb->u.IsochStop.fulFlags = 0;
|
|
|
|
NextIrpStack = IoGetNextIrpStackLocation(pIrp);
|
|
NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS;
|
|
NextIrpStack->Parameters.Others.Argument1 = pIrb;
|
|
|
|
IoSetCompletionRoutine(
|
|
pIrp,
|
|
DCamToStopStateCR,
|
|
pDCamIoContext,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
Status =
|
|
IoCallDriver(
|
|
pDevExt->BusDeviceObject,
|
|
pIrp
|
|
);
|
|
|
|
ASSERT(Status == STATUS_SUCCESS || Status == STATUS_PENDING);
|
|
|
|
return; // Do StreamClassStreamNotification() in IoCompletionRoutine
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
DCamToPauseStateCR(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP pIrp,
|
|
IN PDCAM_IO_CONTEXT pDCamIoContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is for use with synchronous IRP processing.
|
|
All it does is signal an event, so the driver knows it
|
|
can continue.
|
|
|
|
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;
|
|
pStrmEx = (PSTREAMEX) pDevExt->pStrmEx;
|
|
ASSERT(pStrmEx);
|
|
|
|
DbgMsg2(("\'DCamToPauseStateCR: completed DeviceState=%d; pIrp->IoStatus.Status=%x\n",
|
|
pDCamIoContext->DeviceState, pIrp->IoStatus.Status));
|
|
|
|
// No reason it would failed.
|
|
ASSERT(pIrp->IoStatus.Status == STATUS_SUCCESS);
|
|
|
|
switch (pDCamIoContext->DeviceState) {
|
|
|
|
case DCAM_PAUSESTATE_SET_REQUEST_ISOCH_STOP:
|
|
break;
|
|
default:
|
|
ERROR_LOG(("DCamToPauseStateCompletionRoutine: Unknown or unexpected pDCamIoContext->DeviceState=%d\n", pDCamIoContext->DeviceState));
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We are here only if switching from RUN->PAUSE,
|
|
// It is alreay set to PAUSE state in DCamSetKSStatePAUSE
|
|
//
|
|
|
|
|
|
|
|
if(pDCamIoContext->pSrb) {
|
|
pDCamIoContext->pSrb->Status = pIrp->IoStatus.Status == STATUS_SUCCESS ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
|
COMPLETE_SRB(pDCamIoContext->pSrb)
|
|
}
|
|
|
|
DCamFreeIrbIrpAndContext(pDCamIoContext, pDCamIoContext->pIrb, pIrp);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
DCamSetKSStatePAUSE(
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set KSSTATE to KSSTATE_PAUSE.
|
|
|
|
Arguments:
|
|
|
|
Srb - Pointer to Stream request block
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
PDCAM_EXTENSION pDevExt;
|
|
PSTREAMEX pStrmEx;
|
|
PIRB pIrb;
|
|
PIRP pIrp;
|
|
PDCAM_IO_CONTEXT pDCamIoContext;
|
|
PIO_STACK_LOCATION NextIrpStack;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
pDevExt = (PDCAM_EXTENSION) pSrb->HwDeviceExtension;
|
|
ASSERT(pDevExt);
|
|
pStrmEx = (PSTREAMEX) pDevExt->pStrmEx;
|
|
ASSERT(pStrmEx);
|
|
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
switch(pStrmEx->KSState) {
|
|
case KSSTATE_ACQUIRE:
|
|
case KSSTATE_STOP:
|
|
//
|
|
// Out of STOP state,
|
|
// initialize frame and timestamp information.
|
|
// (Master's clock's stream time is also reset.)
|
|
//
|
|
pStrmEx->FrameCaptured = 0; // Actual count
|
|
pStrmEx->FrameInfo.DropCount = 0;
|
|
pStrmEx->FrameInfo.PictureNumber = 0;
|
|
pStrmEx->FrameInfo.dwFrameFlags = 0;
|
|
|
|
// Advanced one frame.
|
|
pStrmEx->FirstFrameTime = pStrmEx->pVideoInfoHeader->AvgTimePerFrame;
|
|
DbgMsg2(("\'DCamSetKSStatePAUSE: FirstFrameTime(%d)\n", pStrmEx->FirstFrameTime));
|
|
break;
|
|
|
|
case KSSTATE_RUN:
|
|
//
|
|
// Will ask controll to stop listening.
|
|
// All the pening buffer(s) are kept in the controller.
|
|
// Before it completely stop (some latency here),
|
|
// we might get some IsochCallback() with data.
|
|
//
|
|
if(!pDevExt->hResource) {
|
|
pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
if(!DCamAllocateIrbIrpAndContext(&pDCamIoContext, &pIrb, &pIrp, pDevExt->BusDeviceObject->StackSize)) {
|
|
pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
// Set to KSSTATE_PAUSE at the beginning to prvent CancelPacket being processed thinking
|
|
// it is still in KSSTATE_RUN state.
|
|
pStrmEx->KSState = KSSTATE_PAUSE;
|
|
pDCamIoContext->DeviceState = DCAM_PAUSESTATE_SET_REQUEST_ISOCH_STOP;
|
|
pDCamIoContext->pSrb = pSrb; // To do StreamClassStreamNotification()
|
|
pDCamIoContext->pDevExt = pDevExt;
|
|
pIrb->FunctionNumber = REQUEST_ISOCH_STOP;
|
|
pIrb->Flags = 0;
|
|
pIrb->u.IsochStop.hResource = pDevExt->hResource;
|
|
pIrb->u.IsochStop.fulFlags = 0;
|
|
|
|
NextIrpStack = IoGetNextIrpStackLocation(pIrp);
|
|
NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS;
|
|
NextIrpStack->Parameters.Others.Argument1 = pIrb;
|
|
|
|
IoSetCompletionRoutine(
|
|
pIrp,
|
|
DCamToPauseStateCR,
|
|
pDCamIoContext,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
Status =\
|
|
IoCallDriver(
|
|
pDevExt->BusDeviceObject,
|
|
pIrp
|
|
);
|
|
return; // Do StreamClassStreamNotification() in IoCompletionRoutine
|
|
|
|
case KSSTATE_PAUSE:
|
|
ERROR_LOG(("DCamSetKSStatePAUSE: Already in KSSTATE_PAUSE state.\n"));
|
|
ASSERT(pStrmEx->KSState != KSSTATE_PAUSE);
|
|
break;
|
|
}
|
|
|
|
pStrmEx->KSState = KSSTATE_PAUSE;
|
|
|
|
COMPLETE_SRB(pSrb)
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
DCamToRunStateCR(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP pIrp,
|
|
IN PDCAM_IO_CONTEXT pDCamIoContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is for use with synchronous IRP processing.
|
|
All it does is signal an event, so the driver knows it
|
|
can continue.
|
|
|
|
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;
|
|
NTSTATUS Status;
|
|
PIRB pIrb;
|
|
PIO_STACK_LOCATION NextIrpStack;
|
|
|
|
if(!pDCamIoContext) {
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
pIrb = pDCamIoContext->pIrb;
|
|
pDevExt = pDCamIoContext->pDevExt;
|
|
|
|
DbgMsg2(("\'DCamToRunStateCR: completed DeviceState=%d; pIrp->IoStatus.Status=%x\n",
|
|
pDCamIoContext->DeviceState, pIrp->IoStatus.Status));
|
|
|
|
// Free MDL
|
|
if(pIrb->FunctionNumber == REQUEST_ASYNC_WRITE) {
|
|
DbgMsg3(("DCamToRunStateCR: IoFreeMdl\n"));
|
|
IoFreeMdl(pIrb->u.AsyncWrite.Mdl);
|
|
}
|
|
|
|
//
|
|
// CAUTION:
|
|
// STATUS_TIMEOUT can be a valid return that we may to try again.
|
|
// But should it be a HW issue that it is not responding to our write.
|
|
// Controller should have made many reties before return STATUS_TIMEOUT.
|
|
//
|
|
if(pIrp->IoStatus.Status != STATUS_SUCCESS) {
|
|
if(DCAM_RUNSTATE_SET_REQUEST_ISOCH_LISTEN != pDCamIoContext->DeviceState ||
|
|
STATUS_INSUFFICIENT_RESOURCES != pIrp->IoStatus.Status ) {
|
|
|
|
ERROR_LOG(("DCamToRunStateCR: pIrp->IoStatus.Status=%x; free resoruce and STOP\n", pIrp->IoStatus.Status));
|
|
if(pDCamIoContext->pSrb) {
|
|
pDCamIoContext->pSrb->Status = pIrp->IoStatus.Status == STATUS_SUCCESS ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
|
COMPLETE_SRB(pDCamIoContext->pSrb);
|
|
}
|
|
DCamFreeIrbIrpAndContext(pDCamIoContext, pDCamIoContext->pIrb, pIrp);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
} else {
|
|
//
|
|
// This is OK:
|
|
// If we get an insufficient resources error that means
|
|
// we don't have any Reads down yet. Set flag to TRUE
|
|
// indicating that when we do get a Read down we'll
|
|
// actually need to begin the listening process.
|
|
//
|
|
pDevExt->bNeedToListen = TRUE;
|
|
DbgMsg1(("DCamToRunStateCR: ##### no read yet! set pDevExt->bNeedToListen = TRUE\n"));
|
|
}
|
|
}
|
|
|
|
#ifdef WAIT_FOR_SLOW_DEVICE
|
|
KeStallExecutionProcessor(5000); // 5 msec
|
|
#endif
|
|
|
|
|
|
switch (pDCamIoContext->DeviceState) {
|
|
|
|
case DCAM_RUNSTATE_SET_REQUEST_ISOCH_LISTEN:
|
|
//
|
|
// Bit[24..26]0:0000 = CurrentFrameRate
|
|
//
|
|
pDCamIoContext->RegisterWorkArea.AsULONG = pDevExt->FrameRate << 5;
|
|
DbgMsg2(("\'DCamToRunState: FrameRate %x\n", pDCamIoContext->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, CurrentVFrmRate);
|
|
pIrb->u.AsyncWrite.nNumberOfBytesToWrite = sizeof(ULONG);
|
|
pIrb->u.AsyncWrite.nBlockSize = 0;
|
|
pIrb->u.AsyncWrite.fulFlags = 0;
|
|
InterlockedExchange(&pIrb->u.AsyncWrite.ulGeneration, pDevExt->CurrentGeneration);
|
|
break;
|
|
|
|
case DCAM_RUNSTATE_SET_FRAME_RATE:
|
|
//
|
|
// Bit[24..26]0:0000 = CurrentVideoMode
|
|
//
|
|
pDCamIoContext->RegisterWorkArea.AsULONG = pDevExt->CurrentModeIndex << 5;
|
|
DbgMsg2(("\'DCamToRunState: CurrentVideoMode %x\n", pDCamIoContext->RegisterWorkArea.AsULONG));
|
|
pIrb->u.AsyncWrite.DestinationAddress.IA_Destination_Offset.Off_Low =
|
|
pDevExt->BaseRegister + FIELDOFFSET(CAMERA_REGISTER_MAP, CurrentVMode);
|
|
break;
|
|
|
|
case DCAM_RUNSTATE_SET_CURRENT_VIDEO_MODE:
|
|
pDCamIoContext->RegisterWorkArea.AsULONG = FORMAT_VGA_NON_COMPRESSED;
|
|
DbgMsg2(("\'DCamToRunState: VideoFormat %x\n", pDCamIoContext->RegisterWorkArea.AsULONG));
|
|
pIrb->u.AsyncWrite.DestinationAddress.IA_Destination_Offset.Off_Low =
|
|
pDevExt->BaseRegister + FIELDOFFSET(CAMERA_REGISTER_MAP, CurrentVFormat);
|
|
break;
|
|
|
|
case DCAM_RUNSTATE_SET_CURRENT_VIDEO_FORMAT:
|
|
//
|
|
// Bit [24..27]:00[30..31] = IsoChannel:00SpeedCode
|
|
//
|
|
pDCamIoContext->RegisterWorkArea.AsULONG = (pDevExt->IsochChannel << 4) | pDevExt->SpeedCode;
|
|
DbgMsg2(("\'DCamToRunState: pDevExt->SpeedCode 0x%x, Channel+SpeedCode %x\n", pDevExt->SpeedCode, pDCamIoContext->RegisterWorkArea.AsULONG));
|
|
pIrb->u.AsyncWrite.DestinationAddress.IA_Destination_Offset.Off_Low =
|
|
pDevExt->BaseRegister + FIELDOFFSET(CAMERA_REGISTER_MAP, IsoChannel);
|
|
break;
|
|
|
|
case DCAM_RUNSTATE_SET_SPEED:
|
|
//
|
|
// Bit[24]000:0000 = start ? 1 : 0;
|
|
//
|
|
|
|
pDCamIoContext->RegisterWorkArea.AsULONG = START_ISOCH_TRANSMISSION;
|
|
pIrb->u.AsyncWrite.DestinationAddress.IA_Destination_Offset.Off_Low =
|
|
pDevExt->BaseRegister + FIELDOFFSET(CAMERA_REGISTER_MAP, IsoEnable);
|
|
break;
|
|
|
|
|
|
case DCAM_RUNSTATE_SET_START:
|
|
pStrmEx = (PSTREAMEX) pDevExt->pStrmEx;
|
|
ASSERT(pStrmEx);
|
|
pStrmEx->KSState = KSSTATE_RUN;
|
|
|
|
// If this is called from a SRB, then completed it.
|
|
if(pDCamIoContext->pSrb) {
|
|
pDCamIoContext->pSrb->Status = pIrp->IoStatus.Status == STATUS_SUCCESS ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
|
COMPLETE_SRB(pDCamIoContext->pSrb);
|
|
}
|
|
|
|
//
|
|
// This is last stop; so
|
|
// we free what we allocated.
|
|
//
|
|
DbgMsg2(("\'DCamToRunStateCR: DONE!\n"));
|
|
DCamFreeIrbIrpAndContext(pDCamIoContext, pDCamIoContext->pIrb, pIrp);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
default:
|
|
ERROR_LOG(("DCamToRunStateCR:DeviceState(%d) is not defined!\n\n", pDCamIoContext->DeviceState));
|
|
ASSERT(FALSE);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
}
|
|
|
|
pDCamIoContext->DeviceState++; // Keep track of device state that we just set.
|
|
|
|
if(pIrb->FunctionNumber == REQUEST_ASYNC_WRITE) {
|
|
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,
|
|
DCamToRunStateCR,
|
|
pDCamIoContext,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
Status =
|
|
IoCallDriver(
|
|
pDevExt->BusDeviceObject,
|
|
pIrp
|
|
);
|
|
|
|
DbgMsg2(("\'DCamToRunStateCR: IoCallDriver, Status=%x; STATUS_PENDING(%x)\n", Status, STATUS_PENDING));
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
DCamSetKSStateRUN(
|
|
PDCAM_EXTENSION pDevExt,
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb // Needed only to complete the SRB; for bus reset, there is no SRB.
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set KSSTATE to KSSTATE_RUN.
|
|
Can be called at DISPATCH level for initializing the device after a bus reset.
|
|
|
|
Arguments:
|
|
|
|
pSrb - Pointer to Stream request block
|
|
|
|
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;
|
|
ASSERT(pStrmEx);
|
|
|
|
|
|
if(!DCamAllocateIrbIrpAndContext(&pDCamIoContext, &pIrb, &pIrp, pDevExt->BusDeviceObject->StackSize)) {
|
|
if(pSrb) {
|
|
pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
COMPLETE_SRB(pSrb);
|
|
}
|
|
return;
|
|
}
|
|
|
|
pStrmEx->KSStateFinal = KSSTATE_RUN;
|
|
pDCamIoContext->DeviceState = DCAM_RUNSTATE_SET_REQUEST_ISOCH_LISTEN;
|
|
pDCamIoContext->pSrb = pSrb; // To do StreamClassStreamNotification()
|
|
pDCamIoContext->pDevExt = pDevExt;
|
|
pIrb->FunctionNumber = REQUEST_ISOCH_LISTEN;
|
|
pIrb->Flags = 0;
|
|
pIrb->u.IsochStop.hResource = pDevExt->hResource;
|
|
pIrb->u.IsochStop.fulFlags = 0;
|
|
|
|
NextIrpStack = IoGetNextIrpStackLocation(pIrp);
|
|
NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS;
|
|
NextIrpStack->Parameters.Others.Argument1 = pIrb;
|
|
|
|
// In case we time out, we will try again; apply only to start listen;
|
|
// With little change, it can work with other operation as well.
|
|
pDevExt->lRetries = 0;
|
|
|
|
IoSetCompletionRoutine(
|
|
pIrp,
|
|
DCamToRunStateCR,
|
|
pDCamIoContext,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
Status =
|
|
IoCallDriver(
|
|
pDevExt->BusDeviceObject,
|
|
pIrp
|
|
);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
DCamReceiveCtrlPacket(
|
|
IN PHW_STREAM_REQUEST_BLOCK pSrb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called with packet commands that control the video stream
|
|
|
|
Arguments:
|
|
|
|
pSrb - Pointer to Stream request block
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PDCAM_EXTENSION pDevExt;
|
|
PSTREAMEX pStrmEx;
|
|
|
|
|
|
//
|
|
// determine the type of packet.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
pSrb->Status = STATUS_SUCCESS; // default; called functions depends on this.
|
|
pDevExt = (PDCAM_EXTENSION) pSrb->HwDeviceExtension;
|
|
ASSERT(pDevExt);
|
|
pStrmEx = (PSTREAMEX) pDevExt->pStrmEx;
|
|
ASSERT(pStrmEx);
|
|
|
|
switch (pSrb->Command) {
|
|
case SRB_GET_STREAM_STATE:
|
|
VideoGetState (pSrb);
|
|
break;
|
|
|
|
case SRB_SET_STREAM_STATE:
|
|
if(pStrmEx == NULL) {
|
|
ERROR_LOG(("\'DCamReceiveCtrlPacket: SRB_SET_STREAM_STATE but pStrmEx is NULL.\n"));
|
|
ASSERT(pStrmEx);
|
|
pSrb->Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
DbgMsg2(("\'DCamReceiveCtrlPacket: Setting state from %d to %d; PendingRead %d\n",
|
|
pStrmEx->KSState, pSrb->CommandData.StreamState, pDevExt->PendingReadCount));
|
|
|
|
|
|
//
|
|
// The control packet and data packet are not serialized by the stream class.
|
|
// We need to watch for PAUSE->STOP transition.
|
|
// In this transition, SRB_READ can still come in in a separate thread if
|
|
// the client application has separate threads for setting state and read data.
|
|
//
|
|
// A "stop data packet" flag and a mutex is used for this synchronization.
|
|
// So we set "stop data packet" flag to stop future read, and
|
|
// wait to own the mutex (if read is in progress) and then set stream to STOP state.
|
|
// This "stop data packet" flag can be the stream state.
|
|
//
|
|
switch (pSrb->CommandData.StreamState) {
|
|
case KSSTATE_STOP:
|
|
DCamSetKSStateSTOP(pSrb);
|
|
return; // Complete Asynchronously in IoCompletionRoutine*
|
|
|
|
case KSSTATE_PAUSE:
|
|
DCamSetKSStatePAUSE(pSrb);
|
|
return; // Complete Asynchronously in IoCompletionRoutine*
|
|
|
|
case KSSTATE_RUN:
|
|
DCamSetKSStateRUN(pDevExt, pSrb);
|
|
return; // Complete Asynchronously in IoCompletionRoutine*
|
|
|
|
case KSSTATE_ACQUIRE:
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
ERROR_LOG(("\'DCamReceiveCtrlPacket: Error unknown state\n"));
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
pStrmEx->KSState = pSrb->CommandData.StreamState;
|
|
break;
|
|
|
|
case SRB_GET_STREAM_PROPERTY:
|
|
DbgMsg3(("\'DCamReceiveCtrlPacket: SRB_GET_STREAM_PROPERTY\n"));
|
|
VideoGetProperty(pSrb);
|
|
break;
|
|
|
|
case SRB_INDICATE_MASTER_CLOCK:
|
|
//
|
|
// Assigns a clock to a stream
|
|
//
|
|
VideoIndicateMasterClock (pSrb);
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// invalid / unsupported command. Fail it as such
|
|
//
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
StreamClassStreamNotification(StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
}
|