//==========================================================================;
//
//  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) 1992 - 1997  Microsoft Corporation.  All Rights Reserved.
//
//==========================================================================;

#include "strmini.h"
#include "ksmedia.h"
#include "capmain.h"
#include "mediums.h"
#include "capstrm.h"
#include "capprop.h"
#include "capdebug.h"
#ifdef  TOSHIBA
#include "bert.h"

ULONG   CurrentOSType;  // 0:Win98 1:NT5.0
#endif//TOSHIBA

#ifdef  TOSHIBA
VOID
DevicePowerON (
    IN OUT PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
    DWORD                   dwAddr;

    CameraChkandON(pHwDevExt, MODE_VFW);
    VC_Delay(100);
    ImageSetInputImageSize(pHwDevExt, &(pHwDevExt->SrcRect));
    ImageSetOutputImageSize(pHwDevExt, pHwDevExt->ulWidth, pHwDevExt->ulHeight);
    BertFifoConfig(pHwDevExt, pHwDevExt->Format);
    ImageSetHueBrightnessContrastSat(pHwDevExt);
    if ( pHwDevExt->ColorEnable ) {
        if ( get_AblFilter( pHwDevExt ) ) {
            set_filtering( pHwDevExt, TRUE );
        } else {
            set_filtering( pHwDevExt, FALSE );
            pHwDevExt->ColorEnable = 0;
        }
    } else {
        set_filtering( pHwDevExt, FALSE );
    }
    dwAddr = (DWORD)pHwDevExt->pPhysRpsDMABuf.LowPart;
#if 0
    dwAddr = (dwAddr + 0x1FFF) & 0xFFFFE000;
#endif
    pHwDevExt->s_physDmaActiveFlag = dwAddr + 0X1860;

    if( pHwDevExt->dblBufflag ){
        BertTriBuildNodes(pHwDevExt); // Add 97-04-08(Tue)
    }
    else{
        BertBuildNodes(pHwDevExt);  // Add 97-04-08(Tue)
    }
    pHwDevExt->IsRPSReady = TRUE;
    BertInterruptEnable(pHwDevExt, TRUE);
    BertDMARestart(pHwDevExt);
}

VOID
CameraPowerON (
    IN OUT PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);

    CameraChkandON(pHwDevExt, MODE_VFW);
    VC_Delay(100);
}

VOID
CameraPowerOFF (
    IN OUT PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);

    CameraChkandOFF(pHwDevExt, MODE_VFW);
}

VOID
QueryOSTypeFromRegistry()
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    LONG     RegVals[2];
    PLONG    pRegVal;
    WCHAR    BasePath[] = L"\\Registry\\MACHINE\\SOFTWARE\\Toshiba\\Tsbvcap";
    RTL_QUERY_REGISTRY_TABLE Table[2];
    UNICODE_STRING RegPath;

    //
    // Get the actual values for the controls
    //

    RtlZeroMemory (Table, sizeof(Table));

    CurrentOSType = 1;  // Assume NT5.0
    RegVals[0] = CurrentOSType;

    pRegVal = RegVals;  // for convenience sake
    RegPath.Buffer = BasePath;
#ifdef  TOSHIBA // '99-01-08 Modified
    RegPath.MaximumLength = sizeof(BasePath) + (32 * sizeof(WCHAR)); //32 chars for keys
#else //TOSHIBA
    RegPath.MaximumLength = sizeof(BasePath + 32); //32 chars for keys
#endif//TOSHIBA
    RegPath.Length = 0;

    Table[0].Name = L"CurrentOSType";
    Table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
    Table[0].EntryContext = pRegVal++;

    ntStatus = RtlQueryRegistryValues(
                       RTL_REGISTRY_ABSOLUTE,
                       RegPath.Buffer,
                       Table,
                       NULL,
                       NULL );

    if( NT_SUCCESS(ntStatus))
    {
        CurrentOSType = RegVals[0];
    }
}

VOID
QueryControlsFromRegistry(
    PHW_DEVICE_EXTENSION pHwDevExt
    )
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    LONG     RegVals[6];
    PLONG    pRegVal;
    WCHAR    BasePath[] = L"\\Registry\\MACHINE\\SOFTWARE\\Toshiba\\Tsbvcap";
    RTL_QUERY_REGISTRY_TABLE Table[6];
    UNICODE_STRING RegPath;

    //
    // Get the actual values for the controls
    //

    RtlZeroMemory (Table, sizeof(Table));

    RegVals[0] = pHwDevExt->Brightness;
    RegVals[1] = pHwDevExt->Contrast;
    RegVals[2] = pHwDevExt->Hue;
    RegVals[3] = pHwDevExt->Saturation;
    RegVals[4] = pHwDevExt->ColorEnable;

    pRegVal = RegVals;   // for convenience sake
    RegPath.Buffer = BasePath;
#ifdef  TOSHIBA // '99-01-08 Modified
    RegPath.MaximumLength = sizeof(BasePath) + (32 * sizeof(WCHAR)); //32 chars for keys
#else //TOSHIBA
    RegPath.MaximumLength = sizeof(BasePath + 32); //32 chars for keys
#endif//TOSHIBA
    RegPath.Length = 0;

    Table[0].Name = L"Brightness";
    Table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
    Table[0].EntryContext = pRegVal++;

    Table[1].Name = L"Contrast";
    Table[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
    Table[1].EntryContext = pRegVal++;

    Table[2].Name = L"Hue";
    Table[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
    Table[2].EntryContext = pRegVal++;

    Table[3].Name = L"Saturation";
    Table[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
    Table[3].EntryContext = pRegVal++;

    Table[4].Name = L"FilterEnable";
    Table[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
    Table[4].EntryContext = pRegVal++;

    ntStatus = RtlQueryRegistryValues(
                       RTL_REGISTRY_ABSOLUTE,
                       RegPath.Buffer,
                       Table,
                       NULL,
                       NULL );

    if( NT_SUCCESS(ntStatus))
    {
        pHwDevExt->Brightness  = RegVals[0];
        pHwDevExt->Contrast    = RegVals[1];
        pHwDevExt->Hue         = RegVals[2];
        pHwDevExt->Saturation  = RegVals[3];
        pHwDevExt->ColorEnable = RegVals[4];
    }
}

VOID
SaveControlsToRegistry(
    PHW_DEVICE_EXTENSION pHwDevExt
    )
{
    LONG Value;
    WCHAR BasePath[] = L"\\Registry\\MACHINE\\SOFTWARE\\Toshiba\\Tsbvcap";
    UNICODE_STRING RegPath;


    RegPath.Buffer = BasePath;
#ifdef  TOSHIBA // '99-01-08 Modified
    RegPath.MaximumLength = sizeof(BasePath) + (32 * sizeof(WCHAR)); //32 chars for keys
#else //TOSHIBA
    RegPath.MaximumLength = sizeof(BasePath + 32); //32 chars for keys
#endif//TOSHIBA
    RegPath.Length = 0;

    Value = pHwDevExt->Brightness;
    RtlWriteRegistryValue(
                          RTL_REGISTRY_ABSOLUTE,
                          RegPath.Buffer,
                          L"Brightness",
                          REG_DWORD,
                          &Value,
                          sizeof (ULONG));

    Value = pHwDevExt->Contrast;
    RtlWriteRegistryValue(
                          RTL_REGISTRY_ABSOLUTE,
                          RegPath.Buffer,
                          L"Contrast",
                          REG_DWORD,
                          &Value,
                          sizeof (ULONG));

    Value = pHwDevExt->Hue;
    RtlWriteRegistryValue(
                          RTL_REGISTRY_ABSOLUTE,
                          RegPath.Buffer,
                          L"Hue",
                          REG_DWORD,
                          &Value,
                          sizeof (ULONG));

    Value = pHwDevExt->Saturation;
    RtlWriteRegistryValue(
                          RTL_REGISTRY_ABSOLUTE,
                          RegPath.Buffer,
                          L"Saturation",
                          REG_DWORD,
                          &Value,
                          sizeof (ULONG));

    Value = pHwDevExt->ColorEnable;
    RtlWriteRegistryValue(
                          RTL_REGISTRY_ABSOLUTE,
                          RegPath.Buffer,
                          L"FilterEnable",
                          REG_DWORD,
                          &Value,
                          sizeof (ULONG));
}
#endif//TOSHIBA

/*
** DriverEntry()
**
**   This routine is called when the driver is first loaded by PnP.
**   It in turn, calls upon the stream class to perform registration services.
**
** Arguments:
**
**   DriverObject -
**          Driver object for this driver
**
**   RegistryPath -
**          Registry path string for this driver's key
**
** Returns:
**
**   Results of StreamClassRegisterAdapter()
**
** Side Effects:  none
*/

ULONG
DriverEntry (
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
{

    HW_INITIALIZATION_DATA      HwInitData;
    ULONG                       ReturnValue;


    KdPrint(("TsbVcap: DriverEntry\n"));

    RtlZeroMemory(&HwInitData, sizeof(HwInitData));

    HwInitData.HwInitializationDataSize = sizeof(HwInitData);

    //
    // Set the Adapter entry points for the driver
    //

#ifdef  TOSHIBA
    QueryOSTypeFromRegistry();

    HwInitData.HwInterrupt              = HwInterrupt;
#else //TOSHIBA
    HwInitData.HwInterrupt              = NULL; // HwInterrupt;
#endif//TOSHIBA

    HwInitData.HwReceivePacket          = AdapterReceivePacket;
    HwInitData.HwCancelPacket           = AdapterCancelPacket;
    HwInitData.HwRequestTimeoutHandler  = AdapterTimeoutPacket;

    HwInitData.DeviceExtensionSize      = sizeof(HW_DEVICE_EXTENSION);
    HwInitData.PerRequestExtensionSize  = sizeof(SRB_EXTENSION);
    HwInitData.FilterInstanceExtensionSize = 0;
    HwInitData.PerStreamExtensionSize   = sizeof(STREAMEX);
    HwInitData.BusMasterDMA             = FALSE;
    HwInitData.Dma24BitAddresses        = FALSE;
    HwInitData.BufferAlignment          = 3;
#ifdef  TOSHIBA
    if ( CurrentOSType ) {  // NT5.0
        HwInitData.DmaBufferSize = 8192 * 2;
    } else {
        HwInitData.DmaBufferSize = 8192 * 2 + MAX_CAPTURE_BUFFER_SIZE;
    }
#else //TOSHIBA
    HwInitData.DmaBufferSize            = 0;
#endif//TOSHIBA

    // Don't rely on the stream class using raised IRQL to synchronize
    // execution.  This single paramter most affects the overall structure
    // of the driver.

    HwInitData.TurnOffSynchronization   = TRUE;

    ReturnValue = StreamClassRegisterAdapter(DriverObject, RegistryPath, &HwInitData);

    KdPrint(("TsbVcap: StreamClassRegisterAdapter = %x\n", ReturnValue));

    return ReturnValue;
}

//==========================================================================;
//                   Adapter Based Request Handling Routines
//==========================================================================;

/*
** HwInitialize()
**
**   This routine is called when an SRB_INITIALIZE_DEVICE request is received
**
** Arguments:
**
**   pSrb - pointer to stream request block for the Initialize command
**
** Returns:
**
** Side Effects:  none
*/

BOOL
STREAMAPI
HwInitialize (
    IN OUT PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    STREAM_PHYSICAL_ADDRESS     adr;
    ULONG                       Size;
    PUCHAR                      pDmaBuf;
    int                         j;

    PPORT_CONFIGURATION_INFORMATION ConfigInfo = pSrb->CommandData.ConfigInfo;

    PHW_DEVICE_EXTENSION pHwDevExt =
        (PHW_DEVICE_EXTENSION)ConfigInfo->HwDeviceExtension;

    KdPrint(("TsbVcap: HwInitialize()\n"));

#ifdef  TOSHIBA
    if (ConfigInfo->NumberOfAccessRanges == 0) {
#else //TOSHIBA
    if (ConfigInfo->NumberOfAccessRanges != 0) {
#endif//TOSHIBA
        KdPrint(("TsbVcap: illegal config info\n"));

        pSrb->Status = STATUS_NO_SUCH_DEVICE;
        return (FALSE);
    }

    KdPrint(("TsbVcap: Number of access ranges = %lx\n", ConfigInfo->NumberOfAccessRanges));
    KdPrint(("TsbVcap: Memory Range = %lx\n", pHwDevExt->ioBaseLocal));
    KdPrint(("TsbVcap: IRQ = %lx\n", ConfigInfo->BusInterruptLevel));

    if (ConfigInfo->NumberOfAccessRanges != 0) {
        pHwDevExt->ioBaseLocal
                = (PULONG)(ConfigInfo->AccessRanges[0].RangeStart.LowPart);
    }

    pHwDevExt->Irq  = (USHORT)(ConfigInfo->BusInterruptLevel);

    ConfigInfo->StreamDescriptorSize = sizeof (HW_STREAM_HEADER) +
                DRIVER_STREAM_COUNT * sizeof (HW_STREAM_INFORMATION);

    pDmaBuf = StreamClassGetDmaBuffer(pHwDevExt);

    adr = StreamClassGetPhysicalAddress(pHwDevExt,
            NULL, pDmaBuf, DmaBuffer, &Size);

#ifdef  TOSHIBA
    if ( CurrentOSType ) {  // NT5.0
        pHwDevExt->pRpsDMABuf = pDmaBuf;
        pHwDevExt->pPhysRpsDMABuf = adr;
        pHwDevExt->pCaptureBufferY = NULL;
        pHwDevExt->pCaptureBufferU = NULL;
        pHwDevExt->pCaptureBufferV = NULL;
        pHwDevExt->pPhysCaptureBufferY.LowPart = 0;
        pHwDevExt->pPhysCaptureBufferY.HighPart = 0;
        pHwDevExt->pPhysCaptureBufferU.LowPart = 0;
        pHwDevExt->pPhysCaptureBufferU.HighPart = 0;
        pHwDevExt->pPhysCaptureBufferV.LowPart = 0;
        pHwDevExt->pPhysCaptureBufferV.HighPart = 0;
        pHwDevExt->BufferSize = 0;
    } else {
        pHwDevExt->pRpsDMABuf = pDmaBuf;
        pHwDevExt->pCaptureBufferY = pDmaBuf + (8192 * 2);
        pHwDevExt->pPhysRpsDMABuf = adr;
        adr.LowPart += 8192 * 2;
        pHwDevExt->pPhysCaptureBufferY = adr;
        pHwDevExt->BufferSize = 0;
    }

    InitializeConfigDefaults(pHwDevExt);
    pHwDevExt->NeedHWInit = TRUE;
    if(!SetupPCILT(pHwDevExt))
    {
        pSrb->Status = STATUS_NO_SUCH_DEVICE;
        return (FALSE);
    }
    pHwDevExt->dblBufflag=FALSE;
    BertInitializeHardware(pHwDevExt);
    if(SetASICRev(pHwDevExt) != TRUE )
    {
        pSrb->Status = STATUS_NO_SUCH_DEVICE;
        return (FALSE);
    }
    BertSetDMCHE(pHwDevExt);
#if 0   // move to CameraPowerON()
    if( !CameraChkandON(pHwDevExt, MODE_VFW) )
    {
        pSrb->Status = STATUS_NO_SUCH_DEVICE;
        return (FALSE);
    }
#endif
    HWInit(pHwDevExt);
#endif//TOSHIBA

#ifdef  TOSHIBA
    // Init VideoProcAmp properties
    pHwDevExt->Brightness = 0x80;
    pHwDevExt->BrightnessFlags = KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL;
    pHwDevExt->Contrast = 0x80;
    pHwDevExt->ContrastFlags = KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL;
    pHwDevExt->Hue = 0x80;
    pHwDevExt->HueFlags = KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL;
    pHwDevExt->Saturation = 0x80;
    pHwDevExt->SaturationFlags = KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL;
    pHwDevExt->ColorEnable = ColorEnableDefault;
    pHwDevExt->ColorEnableFlags = KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL;

#ifdef  TOSHIBA // '98-12-09 Added, for Bug-Report 253529
    pHwDevExt->BrightnessRange = BrightnessRangeAndStep[0].Bounds;
    pHwDevExt->ContrastRange   = ContrastRangeAndStep[0].Bounds;
    pHwDevExt->HueRange        = HueRangeAndStep[0].Bounds;
    pHwDevExt->SaturationRange = SaturationRangeAndStep[0].Bounds;
#endif//TOSHIBA

    // Init VideoControl properties
    pHwDevExt->VideoControlMode = 0;
#else //TOSHIBA
    // Init Crossbar properties
    pHwDevExt->VideoInputConnected = 0;     // TvTuner video is the default
    pHwDevExt->AudioInputConnected = 5;     // TvTuner audio is the default

    // Init VideoProcAmp properties
    pHwDevExt->Brightness = BrightnessDefault;
    pHwDevExt->BrightnessFlags = KSPROPERTY_VIDEOPROCAMP_FLAGS_AUTO;
    pHwDevExt->Contrast = ContrastDefault;
    pHwDevExt->ContrastFlags = KSPROPERTY_VIDEOPROCAMP_FLAGS_AUTO;
    pHwDevExt->ColorEnable = ColorEnableDefault;
    pHwDevExt->ColorEnableFlags = KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL;

    // Init CameraControl properties
    pHwDevExt->Focus = FocusDefault;
    pHwDevExt->FocusFlags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
    pHwDevExt->Zoom = ZoomDefault;
    pHwDevExt->ZoomFlags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;

    // Init TvTuner properties
    pHwDevExt->TunerInput = 0;
    pHwDevExt->Busy = 0;

    // Init TvAudio properties
    pHwDevExt->TVAudioMode = KS_TVAUDIO_MODE_MONO   |
                             KS_TVAUDIO_MODE_LANG_A ;

    // Init AnalogVideoDecoder properties
    pHwDevExt->VideoDecoderVideoStandard = KS_AnalogVideo_NTSC_M;
    pHwDevExt->VideoDecoderOutputEnable = FALSE;
    pHwDevExt->VideoDecoderVCRTiming = FALSE;

    // Init VideoControl properties
    pHwDevExt->VideoControlMode = 0;
#endif//TOSHIBA

    // Init VideoCompression properties
    pHwDevExt->CompressionSettings.CompressionKeyFrameRate = 15;
    pHwDevExt->CompressionSettings.CompressionPFramesPerKeyFrame = 3;
    pHwDevExt->CompressionSettings.CompressionQuality = 5000;

    pHwDevExt->PDO = ConfigInfo->PhysicalDeviceObject;
    KdPrint(("TsbVcap: Physical Device Object = %lx\n", pHwDevExt->PDO));

#ifdef  TOSHIBA
    IoInitializeDpcRequest(pHwDevExt->PDO, DeferredRoutine);
#endif//TOSHIBA

    for (j = 0; j < MAX_TSBVCAP_STREAMS; j++){

        // For each stream, maintain a separate queue for data and control
        InitializeListHead (&pHwDevExt->StreamSRBList[j]);
        InitializeListHead (&pHwDevExt->StreamControlSRBList[j]);
        KeInitializeSpinLock (&pHwDevExt->StreamSRBSpinLock[j]);
        pHwDevExt->StreamSRBListSize[j] = 0;
    }


    KdPrint(("TsbVcap: Exit, HwInitialize()\n"));

    pSrb->Status = STATUS_SUCCESS;

    return (TRUE);

}

/*
** HwUnInitialize()
**
**   This routine is called when an SRB_UNINITIALIZE_DEVICE request is received
**
** Arguments:
**
**   pSrb - pointer to stream request block for the UnInitialize command
**
** Returns:
**
** Side Effects:  none
*/

BOOL
STREAMAPI
HwUnInitialize (
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
#ifdef  TOSHIBA
    PHW_DEVICE_EXTENSION    pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);

    if ( CurrentOSType ) {  // NT5.0
        if ( pHwDevExt->pCaptureBufferY )
        {
            // free frame buffer
            MmFreeContiguousMemory(pHwDevExt->pCaptureBufferY);
            pHwDevExt->pCaptureBufferY = NULL;
            pHwDevExt->pPhysCaptureBufferY.LowPart = 0;
            pHwDevExt->pPhysCaptureBufferY.HighPart = 0;
        }
        if ( pHwDevExt->pCaptureBufferU )
        {
            // free frame buffer
            MmFreeContiguousMemory(pHwDevExt->pCaptureBufferU);
            pHwDevExt->pCaptureBufferU = NULL;
            pHwDevExt->pPhysCaptureBufferU.LowPart = 0;
            pHwDevExt->pPhysCaptureBufferU.HighPart = 0;
        }
        if ( pHwDevExt->pCaptureBufferV )
        {
            // free frame buffer
            MmFreeContiguousMemory(pHwDevExt->pCaptureBufferV);
            pHwDevExt->pCaptureBufferV = NULL;
            pHwDevExt->pPhysCaptureBufferV.LowPart = 0;
            pHwDevExt->pPhysCaptureBufferV.HighPart = 0;
        }
    }
#endif//TOSHIBA

    pSrb->Status = STATUS_SUCCESS;

    return TRUE;
}

/*
** AdapterPowerState()
**
**   This routine is called when an SRB_CHANGE_POWER_STATE request is received
**
** Arguments:
**
**   pSrb - pointer to stream request block for the Change Power state command
**
** Returns:
**
** Side Effects:  none
*/

BOOLEAN
STREAMAPI
AdapterPowerState (
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    PHW_DEVICE_EXTENSION    pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
#ifdef  TOSHIBA
    int                     Counter;
    PSTREAMEX               pStrmEx;
#endif//TOSHIBA

    pHwDevExt->DeviceState = pSrb->CommandData.DeviceState;

#ifdef  TOSHIBA
    for (Counter = 0; Counter < DRIVER_STREAM_COUNT; Counter++) {
        if ( pStrmEx = (PSTREAMEX)pHwDevExt->pStrmEx[Counter] ) {
            //
            // Only when it is not streaming, its power state can be changed.
            // We have "DontSuspendIfStreamsAreRunning" turn on in the INF.
            //
            if (pStrmEx->KSState == KSSTATE_PAUSE ||
                pStrmEx->KSState == KSSTATE_RUN) {
                if (pHwDevExt->DeviceState == PowerDeviceD3) {
                    if (pHwDevExt->bVideoIn == TRUE) {
                      // disable the RPS_INT and field interrupts
                      BertInterruptEnable(pHwDevExt, FALSE);
                      BertDMAEnable(pHwDevExt, FALSE);
                      // wait for the current data xfer to complete
                      pHwDevExt->bVideoIn = FALSE;
                    }
                    VideoQueueCancelAllSRBs (pStrmEx);
                    break;
                } else if (pHwDevExt->DeviceState == PowerDeviceD0) {
                    pHwDevExt->bVideoIn = TRUE;
#ifdef  TOSHIBA // '99-01-20 Modified
                    DevicePowerON( pSrb );
#else //TOSHIBA
                    StreamClassCallAtNewPriority(
                            NULL,
                            pSrb->HwDeviceExtension,
                            Low,
                            (PHW_PRIORITY_ROUTINE) DevicePowerON,
                            pSrb
                    );
#endif//TOSHIBA
                }
            }
        }
    }
#endif//TOSHIBA

    return TRUE;
}

/*
** AdapterSetInstance()
**
**   This routine is called to set all of the Medium instance fields
**
** Arguments:
**
**   pSrb - pointer to stream request block
**
** Returns:
**
** Side Effects:  none
*/

VOID
STREAMAPI
AdapterSetInstance (
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    int j;
    PHW_DEVICE_EXTENSION    pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);

    // Use our HwDevExt as the instance data on the Mediums
    // This allows multiple instances to be uniquely identified and
    // connected.  The value used in .Id is not important, only that
    // it is unique for each hardware connection

#ifdef  TOSHIBA
    for (j = 0; j < SIZEOF_ARRAY (CaptureMediums); j++) {
        CaptureMediums[j].Id = 0; //(ULONG) pHwDevExt;
    }
#else //TOSHIBA
    for (j = 0; j < SIZEOF_ARRAY (TVTunerMediums); j++) {
        TVTunerMediums[j].Id = 0; //(ULONG) pHwDevExt;
    }
    for (j = 0; j < SIZEOF_ARRAY (TVAudioMediums); j++) {
        TVAudioMediums[j].Id = 0; //(ULONG) pHwDevExt;
    }
    for (j = 0; j < SIZEOF_ARRAY (CrossbarMediums); j++) {
        CrossbarMediums[j].Id = 0; //(ULONG) pHwDevExt;
    }
    for (j = 0; j < SIZEOF_ARRAY (CaptureMediums); j++) {
        CaptureMediums[j].Id = 0; //(ULONG) pHwDevExt;
    }

    pHwDevExt->AnalogVideoInputMedium = CaptureMediums[2];
#endif//TOSHIBA
}

/*
** AdapterCompleteInitialization()
**
**   This routine is called when an SRB_COMPLETE_INITIALIZATION request is received
**
** Arguments:
**
**   pSrb - pointer to stream request block
**
** Returns:
**
** Side Effects:  none
*/

VOID
STREAMAPI
AdapterCompleteInitialization (
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    NTSTATUS                Status;
    PHW_DEVICE_EXTENSION    pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
    KIRQL                   KIrql;

    KIrql = KeGetCurrentIrql();

    // The following allows multiple instance of identical hardware
    // to be installed
    AdapterSetInstance (pSrb);

    // Create the Registry blobs that DShow uses to create
    // graphs via Mediums

#ifndef TOSHIBA
    // Register the TVTuner
    Status = StreamClassRegisterFilterWithNoKSPins (
                    pHwDevExt->PDO,                 // IN PDEVICE_OBJECT   DeviceObject,
                    &KSCATEGORY_TVTUNER,            // IN GUID           * InterfaceClassGUID,
                    SIZEOF_ARRAY (TVTunerMediums),  // IN ULONG            PinCount,
                    TVTunerPinDirection,            // IN ULONG          * Flags,
                    TVTunerMediums,                 // IN KSPIN_MEDIUM   * MediumList,
                    NULL                            // IN GUID           * CategoryList
            );

    // Register the Crossbar
    Status = StreamClassRegisterFilterWithNoKSPins (
                    pHwDevExt->PDO,                 // IN PDEVICE_OBJECT   DeviceObject,
                    &KSCATEGORY_CROSSBAR,           // IN GUID           * InterfaceClassGUID,
                    SIZEOF_ARRAY (CrossbarMediums), // IN ULONG            PinCount,
                    CrossbarPinDirection,           // IN ULONG          * Flags,
                    CrossbarMediums,                // IN KSPIN_MEDIUM   * MediumList,
                    NULL                            // IN GUID           * CategoryList
            );

    // Register the TVAudio decoder
    Status = StreamClassRegisterFilterWithNoKSPins (
                    pHwDevExt->PDO,                 // IN PDEVICE_OBJECT   DeviceObject,
                    &KSCATEGORY_TVAUDIO,            // IN GUID           * InterfaceClassGUID,
                    SIZEOF_ARRAY (TVAudioMediums),  // IN ULONG            PinCount,
                    TVAudioPinDirection,            // IN ULONG          * Flags,
                    TVAudioMediums,                 // IN KSPIN_MEDIUM   * MediumList,
                    NULL                            // IN GUID           * CategoryList
            );

    // Register the Capture filter
    // Note:  This should be done automatically be MSKsSrv.sys,
    // when that component comes on line (if ever) ...
    Status = StreamClassRegisterFilterWithNoKSPins (
                    pHwDevExt->PDO,                 // IN PDEVICE_OBJECT   DeviceObject,
                    &KSCATEGORY_CAPTURE,            // IN GUID           * InterfaceClassGUID,
                    SIZEOF_ARRAY (CaptureMediums),  // IN ULONG            PinCount,
                    CapturePinDirection,            // IN ULONG          * Flags,
                    CaptureMediums,                 // IN KSPIN_MEDIUM   * MediumList,
                    NULL                            // IN GUID           * CategoryList
            );
#endif//TOSHIBA

}


/*
** AdapterOpenStream()
**
**   This routine is called when an OpenStream SRB request is received.
**   A stream is identified by a stream number, which indexes an array
**   of KSDATARANGE structures.  The particular KSDATAFORMAT format to
**   be used is also passed in, which should be verified for validity.
**
** Arguments:
**
**   pSrb - pointer to stream request block for the Open command
**
** Returns:
**
** Side Effects:  none
*/

VOID
STREAMAPI
AdapterOpenStream (
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    //
    // the stream extension structure is allocated by the stream class driver
    //

    PSTREAMEX               pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension;
    PHW_DEVICE_EXTENSION    pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
    int                     StreamNumber = pSrb->StreamObject->StreamNumber;
    PKSDATAFORMAT           pKSDataFormat = pSrb->CommandData.OpenFormat;
#ifdef  TOSHIBA
    int                     Counter;
    BOOL                    First = TRUE;
#endif//TOSHIBA


    RtlZeroMemory(pStrmEx, sizeof(STREAMEX));

    KdPrint(("TsbVcap: ------- ADAPTEROPENSTREAM ------- StreamNumber=%d\n", StreamNumber));

    //
    // check that the stream index requested isn't too high
    // or that the maximum number of instances hasn't been exceeded
    //

    if (StreamNumber >= DRIVER_STREAM_COUNT || StreamNumber < 0) {

        pSrb->Status = STATUS_INVALID_PARAMETER;

        return;
    }

    //
    // Check that we haven't exceeded the instance count for this stream
    //

    if (pHwDevExt->ActualInstances[StreamNumber] >=
        Streams[StreamNumber].hwStreamInfo.NumberOfPossibleInstances) {

        pSrb->Status = STATUS_INVALID_PARAMETER;

        return;
    }

    //
    // Check the validity of the format being requested
    //

    if (!AdapterVerifyFormat (pKSDataFormat, StreamNumber)) {

        pSrb->Status = STATUS_INVALID_PARAMETER;

        return;
    }

#ifdef  TOSHIBA
    QueryControlsFromRegistry(pHwDevExt);
#endif//TOSHIBA

    //
    // And set the format for the stream
    //

    if (!VideoSetFormat (pSrb)) {

        return;
    }

    ASSERT (pHwDevExt->pStrmEx [StreamNumber] == NULL);

#ifdef  TOSHIBA
    for (Counter = 0; Counter < DRIVER_STREAM_COUNT; Counter++) {
        if ( pHwDevExt->pStrmEx[Counter] ) {
            First = FALSE;
            break;
        }
    } // for all streams
#endif//TOSHIBA

    // Maintain an array of all the StreamEx structures in the HwDevExt
    // so that we can cancel IRPs from any stream

    pHwDevExt->pStrmEx [StreamNumber] = (PSTREAMX) pStrmEx;

    // Set up pointers to the handlers for the stream data and control handlers

    pSrb->StreamObject->ReceiveDataPacket =
            (PVOID) Streams[StreamNumber].hwStreamObject.ReceiveDataPacket;
    pSrb->StreamObject->ReceiveControlPacket =
            (PVOID) Streams[StreamNumber].hwStreamObject.ReceiveControlPacket;

    //
    // The DMA flag must be set when the device will be performing DMA directly
    // to the data buffer addresses passed in to the ReceiceDataPacket routines.
    //

    pSrb->StreamObject->Dma = Streams[StreamNumber].hwStreamObject.Dma;

    //
    // The PIO flag must be set when the mini driver will be accessing the data
    // buffers passed in using logical addressing
    //

    pSrb->StreamObject->Pio = Streams[StreamNumber].hwStreamObject.Pio;

    //
    // How many extra bytes will be passed up from the driver for each frame?
    //

    pSrb->StreamObject->StreamHeaderMediaSpecific =
                Streams[StreamNumber].hwStreamObject.StreamHeaderMediaSpecific;

    pSrb->StreamObject->StreamHeaderWorkspace =
                Streams[StreamNumber].hwStreamObject.StreamHeaderWorkspace;

    //
    // Indicate the clock support available on this stream
    //

    pSrb->StreamObject->HwClockObject =
                Streams[StreamNumber].hwStreamObject.HwClockObject;

    //
    // Increment the instance count on this stream
    //
    pHwDevExt->ActualInstances[StreamNumber]++;


    // Retain a private copy of the HwDevExt and StreamObject in the stream extension
    // so we can use a timer

    pStrmEx->pHwDevExt = pHwDevExt;                     // For timer use
    pStrmEx->pStreamObject = pSrb->StreamObject;        // For timer use

    // Initialize the compression settings
    // These may have been changed from the default values in the HwDevExt
    // before the stream was opened
    pStrmEx->CompressionSettings.CompressionKeyFrameRate =
        pHwDevExt->CompressionSettings.CompressionKeyFrameRate;
    pStrmEx->CompressionSettings.CompressionPFramesPerKeyFrame =
        pHwDevExt->CompressionSettings.CompressionPFramesPerKeyFrame;
    pStrmEx->CompressionSettings.CompressionQuality =
        pHwDevExt->CompressionSettings.CompressionQuality;

    // Init VideoControl properties
    pStrmEx->VideoControlMode = pHwDevExt->VideoControlMode;

#ifdef  TOSHIBA
    if ( First ) {
#ifdef  TOSHIBA // '99-01-20 Modified
        CameraPowerON( pSrb );
#else //TOSHIBA
        StreamClassCallAtNewPriority(
                NULL,
                pSrb->HwDeviceExtension,
                Low,
                (PHW_PRIORITY_ROUTINE) CameraPowerON,
                pSrb
        );
#endif//TOSHIBA
    }
#endif//TOSHIBA

    KdPrint(("TsbVcap: AdapterOpenStream Exit\n"));

}

/*
** AdapterCloseStream()
**
**   Close the requested data stream.
**
**   Note that a stream could be closed arbitrarily in the midst of streaming
**   if a user mode app crashes.  Therefore, you must release all outstanding
**   resources, disable interrupts, complete all pending SRBs, and put the
**   stream back into a quiescent condition.
**
** Arguments:
**
**   pSrb the request block requesting to close the stream
**
** Returns:
**
** Side Effects:  none
*/

VOID
STREAMAPI
AdapterCloseStream (
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    PSTREAMEX               pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension;
    PHW_DEVICE_EXTENSION    pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
    int                     StreamNumber = pSrb->StreamObject->StreamNumber;
    PKSDATAFORMAT           pKSDataFormat = pSrb->CommandData.OpenFormat;
    KS_VIDEOINFOHEADER      *pVideoInfoHdr = pStrmEx->pVideoInfoHeader;
#ifdef  TOSHIBA
    int                     Counter;
    BOOL                    ClosedAll = TRUE;
#endif//TOSHIBA


    KdPrint(("TsbVcap: -------- ADAPTERCLOSESTREAM ------ StreamNumber=%d\n", StreamNumber));

    if (pHwDevExt->StreamSRBListSize > 0) {
        VideoQueueCancelAllSRBs (pStrmEx);
        KdPrint(("TsbVcap: Outstanding SRBs at stream close!!!\n"));
    }

    pHwDevExt->ActualInstances[StreamNumber]--;

    ASSERT (pHwDevExt->pStrmEx [StreamNumber] != 0);

    pHwDevExt->pStrmEx [StreamNumber] = 0;

    //
    // the minidriver should free any resources that were allocate at
    // open stream time etc.
    //

    // Free the variable length VIDEOINFOHEADER

    if (pVideoInfoHdr) {
        ExFreePool(pVideoInfoHdr);
        pStrmEx->pVideoInfoHeader = NULL;
    }

    // Make sure we no longer reference the clock
    pStrmEx->hMasterClock = NULL;

    // Make sure the state is reset to stopped,
    pStrmEx->KSState = KSSTATE_STOP;

#ifdef  TOSHIBA
    for (Counter = 0; Counter < DRIVER_STREAM_COUNT; Counter++) {
        if ( pHwDevExt->pStrmEx[Counter] ) {
            ClosedAll = FALSE;
            break;
        }
    } // for all streams
    if ( ClosedAll ) {
        if( pHwDevExt->dblBufflag ){
                Free_TriBuffer(pHwDevExt);
                pHwDevExt->IsRPSReady = FALSE;
                pHwDevExt->dblBufflag = FALSE;
        }
#ifdef  TOSHIBA // '99-01-20 Modified
        CameraPowerOFF( pSrb );
#else //TOSHIBA
        StreamClassCallAtNewPriority(
                NULL,
                pSrb->HwDeviceExtension,
                Low,
                (PHW_PRIORITY_ROUTINE) CameraPowerOFF,
                pSrb
        );
#endif//TOSHIBA
        SaveControlsToRegistry(pHwDevExt);
    }
#endif//TOSHIBA

}


/*
** AdapterStreamInfo()
**
**   Returns the information of all streams that are supported by the
**   mini-driver
**
** Arguments:
**
**   pSrb - Pointer to the STREAM_REQUEST_BLOCK
**        pSrb->HwDeviceExtension - will be the hardware device extension for
**                                  as initialised in HwInitialise
**
** Returns:
**
** Side Effects:  none
*/

VOID
STREAMAPI
AdapterStreamInfo (
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    int j;

    PHW_DEVICE_EXTENSION pHwDevExt =
        ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);

    //
    // pick up the pointer to header which preceeds the stream info structs
    //

    PHW_STREAM_HEADER pstrhdr =
            (PHW_STREAM_HEADER)&(pSrb->CommandData.StreamBuffer->StreamHeader);

     //
     // pick up the pointer to the array of stream information data structures
     //

     PHW_STREAM_INFORMATION pstrinfo =
            (PHW_STREAM_INFORMATION)&(pSrb->CommandData.StreamBuffer->StreamInfo);


    //
    // verify that the buffer is large enough to hold our return data
    //

    DEBUG_ASSERT (pSrb->NumberOfBytesToTransfer >=
            sizeof (HW_STREAM_HEADER) +
            sizeof (HW_STREAM_INFORMATION) * DRIVER_STREAM_COUNT);

#ifndef TOSHIBA
    // Ugliness.  To allow mulitple instances, modify the pointer to the
    // AnalogVideoMedium and save it in our device extension

    Streams[STREAM_AnalogVideoInput].hwStreamInfo.Mediums =
           &pHwDevExt->AnalogVideoInputMedium;
    pHwDevExt->AnalogVideoInputMedium = CrossbarMediums[9];
    pHwDevExt->AnalogVideoInputMedium.Id = 0; //(ULONG) pHwDevExt;
#endif//TOSHIBA

     //
     // Set the header
     //

     StreamHeader.NumDevPropArrayEntries = NUMBER_OF_ADAPTER_PROPERTY_SETS;
     StreamHeader.DevicePropertiesArray = (PKSPROPERTY_SET) AdapterPropertyTable;
     *pstrhdr = StreamHeader;

     //
     // stuff the contents of each HW_STREAM_INFORMATION struct
     //

     for (j = 0; j < DRIVER_STREAM_COUNT; j++) {
        *pstrinfo++ = Streams[j].hwStreamInfo;
     }

}


/*
** AdapterReceivePacket()
**
**   Main entry point for receiving adapter based request SRBs.  This routine
**   will always be called at Passive level.
**
**   Note: This is an asyncronous entry point.  The request does not necessarily
**         complete on return from this function, the request only completes when a
**         StreamClassDeviceNotification on this request block, of type
**         DeviceRequestComplete, is issued.
**
** Arguments:
**
**   pSrb - Pointer to the STREAM_REQUEST_BLOCK
**        pSrb->HwDeviceExtension - will be the hardware device extension for
**                                  as initialised in HwInitialise
**
** Returns:
**
** Side Effects:  none
*/

VOID
STREAMAPI
AdapterReceivePacket(
    IN PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    PHW_DEVICE_EXTENSION    pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
    BOOL                    Busy;

    DEBUG_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

    KdPrint(("TsbVcap: Receiving Adapter  SRB %8x, %x\n", pSrb, pSrb->Command));

    // The very first time through, we need to initialize the adapter spinlock
    // and queue
    if (!pHwDevExt->AdapterQueueInitialized) {
        InitializeListHead (&pHwDevExt->AdapterSRBList);
        KeInitializeSpinLock (&pHwDevExt->AdapterSpinLock);
        pHwDevExt->AdapterQueueInitialized = TRUE;
        pHwDevExt->ProcessingAdapterSRB = FALSE;
    }

    //
    // If we're already processing an SRB, add it to the queue
    //
    Busy = AddToListIfBusy (
                    pSrb,
                    &pHwDevExt->AdapterSpinLock,
                    &pHwDevExt->ProcessingAdapterSRB,
                    &pHwDevExt->AdapterSRBList);

    if (Busy) {
        return;
    }

    //
    // This will run until the queue is empty
    //
    while (TRUE) {
        //
        // Assume success
        //
        pSrb->Status = STATUS_SUCCESS;

        //
        // determine the type of packet.
        //

        switch (pSrb->Command)
        {

        case SRB_INITIALIZE_DEVICE:

            // open the device

            HwInitialize(pSrb);

            break;

        case SRB_UNINITIALIZE_DEVICE:

            // close the device.

            HwUnInitialize(pSrb);

            break;

        case SRB_OPEN_STREAM:

            // open a stream

            AdapterOpenStream(pSrb);

            break;

        case SRB_CLOSE_STREAM:

            // close a stream

            AdapterCloseStream(pSrb);

            break;

        case SRB_GET_STREAM_INFO:

            //
            // return a block describing all the streams
            //

            AdapterStreamInfo(pSrb);

            break;

        case SRB_GET_DATA_INTERSECTION:

            //
            // Return a format, given a range
            //

            AdapterFormatFromRange(pSrb);

            break;

        case SRB_OPEN_DEVICE_INSTANCE:
        case SRB_CLOSE_DEVICE_INSTANCE:

            //
            // We should never get these since this is a single instance device
            //

            TRAP
            pSrb->Status = STATUS_NOT_IMPLEMENTED;
            break;

        case SRB_GET_DEVICE_PROPERTY:

            //
            // Get adapter wide properties
            //

            AdapterGetProperty (pSrb);
            break;

        case SRB_SET_DEVICE_PROPERTY:

            //
            // Set adapter wide properties
            //

            AdapterSetProperty (pSrb);
            break;

        case SRB_PAGING_OUT_DRIVER:

            //
            // The driver is being paged out
            // Disable Interrupts if you have them!
            //
            KdPrint(("'TsbVcap: Receiving SRB_PAGING_OUT_DRIVER -- SRB=%x\n", pSrb));
            break;

        case SRB_CHANGE_POWER_STATE:

            //
            // Changing the device power state, D0 ... D3
            //
            KdPrint(("'TsbVcap: Receiving SRB_CHANGE_POWER_STATE ------ SRB=%x\n", pSrb));
            AdapterPowerState(pSrb);
            break;

        case SRB_INITIALIZATION_COMPLETE:

            //
            // Stream class has finished initialization.
            // Now create DShow Medium interface BLOBs.
            // This needs to be done at low priority since it uses the registry
            //
            KdPrint(("'TsbVcap: Receiving SRB_INITIALIZATION_COMPLETE-- SRB=%x\n", pSrb));

            AdapterCompleteInitialization (pSrb);
            break;


        case SRB_UNKNOWN_DEVICE_COMMAND:
        default:

            //
            // this is a request that we do not understand.  Indicate invalid
            // command and complete the request
            //
            pSrb->Status = STATUS_NOT_IMPLEMENTED;

        }

        //
        // Indicate back to the Stream Class that we're done with this SRB
        //
        CompleteDeviceSRB (pSrb);

        //
        // See if there's anything else on the queue
        //
        Busy = RemoveFromListIfAvailable (
                &pSrb,
                &pHwDevExt->AdapterSpinLock,
                &pHwDevExt->ProcessingAdapterSRB,
                &pHwDevExt->AdapterSRBList);

        if (!Busy) {
            break;
        }
    } // end of while there's anything in the queue
}

/*
** AdapterCancelPacket ()
**
**   Request to cancel a packet that is currently in process in the minidriver
**
** Arguments:
**
**   pSrb - pointer to request packet to cancel
**
** Returns:
**
** Side Effects:  none
*/

VOID
STREAMAPI
AdapterCancelPacket(
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    PHW_DEVICE_EXTENSION        pHwDevExt = (PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension;
    PSTREAMEX                   pStrmEx;
    int                         StreamNumber;
    BOOL                        Found = FALSE;

    //
    // Run through all the streams the driver has available
    //

    for (StreamNumber = 0; !Found && (StreamNumber < DRIVER_STREAM_COUNT); StreamNumber++) {

        //
        // Check to see if the stream is in use
        //

        if (pStrmEx = (PSTREAMEX) pHwDevExt->pStrmEx[StreamNumber]) {

            Found = VideoQueueCancelOneSRB (
                pStrmEx,
                pSrb
                );

        } // if the stream is open
    } // for all streams

    KdPrint(("TsbVcap: Cancelling SRB %8x Succeeded=%d\n", pSrb, Found));
}

/*
** AdapterTimeoutPacket()
**
**   This routine is called when a packet has been in the minidriver for
**   too long.  The adapter must decide what to do with the packet
**
** Arguments:
**
**   pSrb - pointer to the request packet that timed out
**
** Returns:
**
** Side Effects:  none
*/

VOID
STREAMAPI
AdapterTimeoutPacket(
    PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    //
    // Unlike most devices, we need to hold onto data SRBs indefinitely,
    // since the graph could be in a pause state indefinitely
    //

    KdPrint(("TsbVcap: Timeout    Adapter SRB %8x\n", pSrb));

    pSrb->TimeoutCounter = pSrb->TimeoutOriginal;

}

/*
** CompleteDeviceSRB ()
**
**   This routine is called when a packet is being completed.
**   The optional second notification type is used to indicate ReadyForNext
**
** Arguments:
**
**   pSrb - pointer to the request packet that timed out
**
** Returns:
**
** Side Effects:
**
*/

VOID
STREAMAPI
CompleteDeviceSRB (
     IN PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    KdPrint(("TsbVcap: Completing Adapter SRB %8x\n", pSrb));

    StreamClassDeviceNotification( DeviceRequestComplete, pSrb->HwDeviceExtension, pSrb);
}

/*
** AdapterCompareGUIDsAndFormatSize()
**
**   Checks for a match on the three GUIDs and FormatSize
**
** Arguments:
**
**         IN DataRange1
**         IN DataRange2
**         BOOL fCompareFormatSize - TRUE when comparing ranges
**                                 - FALSE when comparing formats
**
** Returns:
**
**   TRUE if all elements match
**   FALSE if any are different
**
** Side Effects:  none
*/

BOOL
STREAMAPI
AdapterCompareGUIDsAndFormatSize(
    IN PKSDATARANGE DataRange1,
    IN PKSDATARANGE DataRange2,
    BOOL fCompareFormatSize
    )
{
    return (
        IsEqualGUID (
            &DataRange1->MajorFormat,
            &DataRange2->MajorFormat) &&
        IsEqualGUID (
            &DataRange1->SubFormat,
            &DataRange2->SubFormat) &&
        IsEqualGUID (
            &DataRange1->Specifier,
            &DataRange2->Specifier) &&
        (fCompareFormatSize ?
                (DataRange1->FormatSize == DataRange2->FormatSize) : TRUE ));
}


/*
** AdapterVerifyFormat()
**
**   Checks the validity of a format request by walking through the
**       array of supported KSDATA_RANGEs for a given stream.
**
** Arguments:
**
**   pKSDataFormat - pointer of a KSDATAFORMAT structure.
**   StreamNumber - index of the stream being queried / opened.
**
** Returns:
**
**   TRUE if the format is supported
**   FALSE if the format cannot be suppored
**
** Side Effects:  none
*/

BOOL
STREAMAPI
AdapterVerifyFormat(
    PKSDATAFORMAT pKSDataFormatToVerify,
    int StreamNumber
    )
{
    BOOL                        fOK = FALSE;
    ULONG                       j;
    ULONG                       NumberOfFormatArrayEntries;
    PKSDATAFORMAT               *pAvailableFormats;


    //
    // Check that the stream number is valid
    //

    if (StreamNumber >= DRIVER_STREAM_COUNT) {
        TRAP;
        return FALSE;
    }

    NumberOfFormatArrayEntries =
            Streams[StreamNumber].hwStreamInfo.NumberOfFormatArrayEntries;

    //
    // Get the pointer to the array of available formats
    //

    pAvailableFormats = Streams[StreamNumber].hwStreamInfo.StreamFormatsArray;


    KdPrint(("TsbVcap: AdapterVerifyFormat, Stream=%d\n", StreamNumber));
    KdPrint(("TsbVcap: FormatSize=%d\n",  pKSDataFormatToVerify->FormatSize));
    KdPrint(("TsbVcap: MajorFormat=%x\n", pKSDataFormatToVerify->MajorFormat));

    //
    // Walk the formats supported by the stream
    //

    for (j = 0; j < NumberOfFormatArrayEntries; j++, pAvailableFormats++) {

        // Check for a match on the three GUIDs and format size

        if (!AdapterCompareGUIDsAndFormatSize(
                        pKSDataFormatToVerify,
                        *pAvailableFormats,
                        FALSE /* CompareFormatSize */ )) {
            continue;
        }

        //
        // Now that the three GUIDs match, switch on the Specifier
        // to do a further type-specific check
        //

        // -------------------------------------------------------------------
        // Specifier FORMAT_VideoInfo for VIDEOINFOHEADER
        // -------------------------------------------------------------------

        if (IsEqualGUID (&pKSDataFormatToVerify->Specifier,
                &KSDATAFORMAT_SPECIFIER_VIDEOINFO)) {

            PKS_DATAFORMAT_VIDEOINFOHEADER  pDataFormatVideoInfoHeader =
                    (PKS_DATAFORMAT_VIDEOINFOHEADER) pKSDataFormatToVerify;
            PKS_VIDEOINFOHEADER  pVideoInfoHdrToVerify =
                     (PKS_VIDEOINFOHEADER) &pDataFormatVideoInfoHeader->VideoInfoHeader;
            PKS_DATARANGE_VIDEO             pKSDataRangeVideo = (PKS_DATARANGE_VIDEO) *pAvailableFormats;
            KS_VIDEO_STREAM_CONFIG_CAPS    *pConfigCaps = &pKSDataRangeVideo->ConfigCaps;
            RECT                            rcImage;

            KdPrint(("TsbVcap: AdapterVerifyFormat\n"));
            KdPrint(("TsbVcap: pVideoInfoHdrToVerify=%x\n", pVideoInfoHdrToVerify));
            KdPrint(("TsbVcap: KS_VIDEOINFOHEADER size=%d\n",
                    KS_SIZE_VIDEOHEADER (pVideoInfoHdrToVerify)));
            KdPrint(("TsbVcap: Width=%d  Height=%d  BitCount=%d\n",
            pVideoInfoHdrToVerify->bmiHeader.biWidth,
            pVideoInfoHdrToVerify->bmiHeader.biHeight,
            pVideoInfoHdrToVerify->bmiHeader.biBitCount));
            KdPrint(("TsbVcap: biSizeImage=%d\n",
                pVideoInfoHdrToVerify->bmiHeader.biSizeImage));

            /*
            **  HOW BIG IS THE IMAGE REQUESTED (pseudocode follows)
            **
            **  if (IsRectEmpty (&rcTarget) {
            **      SetRect (&rcImage, 0, 0,
            **              BITMAPINFOHEADER.biWidth,
                            BITMAPINFOHEADER.biHeight);
            **  }
            **  else {
            **      // Probably rendering to a DirectDraw surface,
            **      // where biWidth is used to expressed the "stride"
            **      // in units of pixels (not bytes) of the destination surface.
            **      // Therefore, use rcTarget to get the actual image size
            **
            **      rcImage = rcTarget;
            **  }
            */

            if ((pVideoInfoHdrToVerify->rcTarget.right -
                 pVideoInfoHdrToVerify->rcTarget.left <= 0) ||
                (pVideoInfoHdrToVerify->rcTarget.bottom -
                 pVideoInfoHdrToVerify->rcTarget.top <= 0)) {

                 rcImage.left = rcImage.top = 0;
                 rcImage.right = pVideoInfoHdrToVerify->bmiHeader.biWidth;
                 rcImage.bottom = pVideoInfoHdrToVerify->bmiHeader.biHeight;
            }
            else {
                 rcImage = pVideoInfoHdrToVerify->rcTarget;
            }

            //
            // TODO, perform all other verification tests here!!!
            //

            //
            // HOORAY, the format passed all of the tests, so we support it
            //

            fOK = TRUE;
            break;

        } // End of VIDEOINFOHEADER specifier

#ifndef TOSHIBA
        // -------------------------------------------------------------------
        // Specifier FORMAT_AnalogVideo for KS_ANALOGVIDEOINFO
        // -------------------------------------------------------------------

        else if (IsEqualGUID (&pKSDataFormatToVerify->Specifier,
                &KSDATAFORMAT_SPECIFIER_ANALOGVIDEO)) {

            //
            // For analog video, the DataRange and DataFormat
            // are identical, so just copy the whole structure
            //

            PKS_DATARANGE_ANALOGVIDEO DataRangeVideo =
                    (PKS_DATARANGE_ANALOGVIDEO) *pAvailableFormats;

            //
            // TODO, perform all other verification tests here!!!
            //

            fOK = TRUE;
            break;

        } // End of KS_ANALOGVIDEOINFO specifier
#endif//TOSHIBA

    } // End of loop on all formats for this stream

    return fOK;
}

/*
** AdapterFormatFromRange()
**
**   Produces a DATAFORMAT given a DATARANGE.
**
**   Think of a DATARANGE as a multidimensional space of all of the possible image
**       sizes, cropping, scaling, and framerate possibilities.  Here, the caller
**       is saying "Out of this set of possibilities, could you verify that my
**       request is acceptable?".  The resulting singular output is a DATAFORMAT.
**       Note that each different colorspace (YUV vs RGB8 vs RGB24)
**       must be represented as a separate DATARANGE.
**
**   Generally, the resulting DATAFORMAT will be immediately used to open a stream
**       in that format.
**
** Arguments:
**
**         IN PHW_STREAM_REQUEST_BLOCK pSrb
**
** Returns:
**
**   TRUE if the format is supported
**   FALSE if the format cannot be suppored
**
** Side Effects:  none
*/

BOOL
STREAMAPI
AdapterFormatFromRange(
    IN PHW_STREAM_REQUEST_BLOCK pSrb
    )
{
    PSTREAM_DATA_INTERSECT_INFO IntersectInfo;
    PKSDATARANGE                DataRange;
    BOOL                        OnlyWantsSize;
    BOOL                        MatchFound = FALSE;
    ULONG                       FormatSize;
    ULONG                       StreamNumber;
    ULONG                       j;
    ULONG                       NumberOfFormatArrayEntries;
    PKSDATAFORMAT               *pAvailableFormats;

    IntersectInfo = pSrb->CommandData.IntersectInfo;
    StreamNumber = IntersectInfo->StreamNumber;
    DataRange = IntersectInfo->DataRange;

    //
    // Check that the stream number is valid
    //

    if (StreamNumber >= DRIVER_STREAM_COUNT) {
        pSrb->Status = STATUS_NOT_IMPLEMENTED;
        TRAP;
        return FALSE;
    }

    NumberOfFormatArrayEntries =
            Streams[StreamNumber].hwStreamInfo.NumberOfFormatArrayEntries;

    //
    // Get the pointer to the array of available formats
    //

    pAvailableFormats = Streams[StreamNumber].hwStreamInfo.StreamFormatsArray;

    //
    // Is the caller trying to get the format, or the size of the format?
    //

    OnlyWantsSize = (IntersectInfo->SizeOfDataFormatBuffer == sizeof(ULONG));

    //
    // Walk the formats supported by the stream searching for a match
    // of the three GUIDs which together define a DATARANGE
    //

    for (j = 0; j < NumberOfFormatArrayEntries; j++, pAvailableFormats++) {

        if (!AdapterCompareGUIDsAndFormatSize(
                        DataRange,
                        *pAvailableFormats,
                        TRUE /* CompareFormatSize */)) {
            continue;
        }

        //
        // Now that the three GUIDs match, switch on the Specifier
        // to do a further type-specific check
        //

        // -------------------------------------------------------------------
        // Specifier FORMAT_VideoInfo for VIDEOINFOHEADER
        // -------------------------------------------------------------------

        if (IsEqualGUID (&DataRange->Specifier,
                &KSDATAFORMAT_SPECIFIER_VIDEOINFO)) {

            PKS_DATARANGE_VIDEO DataRangeVideoToVerify =
                    (PKS_DATARANGE_VIDEO) DataRange;
            PKS_DATARANGE_VIDEO DataRangeVideo =
                    (PKS_DATARANGE_VIDEO) *pAvailableFormats;
            PKS_DATAFORMAT_VIDEOINFOHEADER DataFormatVideoInfoHeaderOut;

            //
            // Check that the other fields match
            //
            if ((DataRangeVideoToVerify->bFixedSizeSamples != DataRangeVideo->bFixedSizeSamples) ||
                (DataRangeVideoToVerify->bTemporalCompression != DataRangeVideo->bTemporalCompression) ||
                (DataRangeVideoToVerify->StreamDescriptionFlags != DataRangeVideo->StreamDescriptionFlags) ||
                (DataRangeVideoToVerify->MemoryAllocationFlags != DataRangeVideo->MemoryAllocationFlags) ||
                (RtlCompareMemory (&DataRangeVideoToVerify->ConfigCaps,
                        &DataRangeVideo->ConfigCaps,
                        sizeof (KS_VIDEO_STREAM_CONFIG_CAPS)) !=
                        sizeof (KS_VIDEO_STREAM_CONFIG_CAPS))) {
                continue;
            }

            // MATCH FOUND!
            MatchFound = TRUE;
            FormatSize = sizeof (KSDATAFORMAT) +
                KS_SIZE_VIDEOHEADER (&DataRangeVideoToVerify->VideoInfoHeader);

            if (OnlyWantsSize) {
                break;
            }

            // Caller wants the full data format
            if (IntersectInfo->SizeOfDataFormatBuffer < FormatSize) {
                pSrb->Status = STATUS_BUFFER_TOO_SMALL;
                return FALSE;
            }

            // Copy over the KSDATAFORMAT, followed by the
            // actual VideoInfoHeader

            DataFormatVideoInfoHeaderOut = (PKS_DATAFORMAT_VIDEOINFOHEADER) IntersectInfo->DataFormatBuffer;

            // Copy over the KSDATAFORMAT
            RtlCopyMemory(
                &DataFormatVideoInfoHeaderOut->DataFormat,
                &DataRangeVideoToVerify->DataRange,
                sizeof (KSDATARANGE));

            DataFormatVideoInfoHeaderOut->DataFormat.FormatSize = FormatSize;

            // Copy over the callers requested VIDEOINFOHEADER

            RtlCopyMemory(
                &DataFormatVideoInfoHeaderOut->VideoInfoHeader,
                &DataRangeVideoToVerify->VideoInfoHeader,
                KS_SIZE_VIDEOHEADER (&DataRangeVideoToVerify->VideoInfoHeader));

            // Calculate biSizeImage for this request, and put the result in both
            // the biSizeImage field of the bmiHeader AND in the SampleSize field
            // of the DataFormat.
            //
            // Note that for compressed sizes, this calculation will probably not
            // be just width * height * bitdepth

            DataFormatVideoInfoHeaderOut->VideoInfoHeader.bmiHeader.biSizeImage =
                DataFormatVideoInfoHeaderOut->DataFormat.SampleSize =
                KS_DIBSIZE(DataFormatVideoInfoHeaderOut->VideoInfoHeader.bmiHeader);

            //
            // TODO Perform other validation such as cropping and scaling checks
            //

            break;

        } // End of VIDEOINFOHEADER specifier

#ifndef TOSHIBA
        // -------------------------------------------------------------------
        // Specifier FORMAT_AnalogVideo for KS_ANALOGVIDEOINFO
        // -------------------------------------------------------------------

        else if (IsEqualGUID (&DataRange->Specifier,
                &KSDATAFORMAT_SPECIFIER_ANALOGVIDEO)) {

            //
            // For analog video, the DataRange and DataFormat
            // are identical, so just copy the whole structure
            //

            PKS_DATARANGE_ANALOGVIDEO DataRangeVideo =
                    (PKS_DATARANGE_ANALOGVIDEO) *pAvailableFormats;

            // MATCH FOUND!
            MatchFound = TRUE;
            FormatSize = sizeof (KS_DATARANGE_ANALOGVIDEO);

            if (OnlyWantsSize) {
                break;
            }

            // Caller wants the full data format
            if (IntersectInfo->SizeOfDataFormatBuffer < FormatSize) {
                pSrb->Status = STATUS_BUFFER_TOO_SMALL;
                return FALSE;
            }

            RtlCopyMemory(
                IntersectInfo->DataFormatBuffer,
                DataRangeVideo,
                sizeof (KS_DATARANGE_ANALOGVIDEO));

            ((PKSDATAFORMAT)IntersectInfo->DataFormatBuffer)->FormatSize = FormatSize;

            break;

        } // End of KS_ANALOGVIDEOINFO specifier
#endif//TOSHIBA

        else {
            pSrb->Status = STATUS_NO_MATCH;
            return FALSE;
        }

    } // End of loop on all formats for this stream

    if (OnlyWantsSize) {
        *(PULONG) IntersectInfo->DataFormatBuffer = FormatSize;
        pSrb->ActualBytesTransferred = sizeof(ULONG);
        return TRUE;
    }
    pSrb->ActualBytesTransferred = FormatSize;
    return TRUE;
}