Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1968 lines
58 KiB

//==========================================================================;
//
// 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;
}