// $Header: G:/SwDev/WDM/Video/bt848/rcs/Capmain.c 1.19 1998/05/11 23:59:54 tomz Exp $ //==========================================================================; // // 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 - 1996 Microsoft Corporation. All Rights Reserved. // //==========================================================================; #define INITGUID #define BT848_MEDIUMS #ifdef __cplusplus extern "C" { #endif #include "strmini.h" #include "ksmedia.h" #ifdef __cplusplus } #endif #include "device.h" #include "capmain.h" #include "capstrm.h" #include "capdebug.h" #include "capprop.h" LONG PinTypes_ [MaxInpPins]; // just allocate maximum possible DWORD xtals_ [2]; // no more than 2 xtals extern PsDevice *gpPsDevice; extern BYTE *gpjBaseAddr; extern VOID *gpHwDeviceExtension; void AdapterFormatFromRange( IN PHW_STREAM_REQUEST_BLOCK pSrb ); VOID ReadRegistryValues( IN PDEVICE_OBJECT PhysicalDeviceObject ); inline void CompleteDeviceSRB( IN OUT PHW_STREAM_REQUEST_BLOCK pSrb ); extern DWORD GetSizeHwDeviceExtension( ); extern DWORD GetSizeStreamEx( ); extern PsDevice *GetCurrentDevice( ); extern void SetCurrentDevice( PsDevice *dev ); extern BYTE *GetBase(); extern void SetBase(BYTE *base); PHW_STREAM_REQUEST_BLOCK StreamIdxToSrb[4]; void CheckSrbStatus( PHW_STREAM_REQUEST_BLOCK pSrb ) { VideoStream StreamNumber = (VideoStream)pSrb->StreamObject->StreamNumber; DebugOut((1, " *** completing pSrb(%x) strm(%d) status(%x)\n", pSrb, StreamNumber, pSrb->Status )); switch ( pSrb->Status ) { case STATUS_SUCCESS: case STATUS_CANCELLED: break; default: DebugOut((0, "*** pSrb->Status = %x\n", pSrb->Status )); DEBUG_BREAKPOINT(); } } /* Function: GetRequestedSize * Purpose: Figures out what the image size should be * Input: vidHdr: KS_VIDEOINFOHEADER & * size: MSize & * Output: None */ void GetRequestedSize2( const KS_VIDEOINFOHEADER2 &vidHdr, MSize &size ) { Trace t("GetRequestedSize()"); size.Set( vidHdr.bmiHeader.biWidth, abs(vidHdr.bmiHeader.biHeight) ); MRect dst( vidHdr.rcTarget ); // if writing to a DD surface maybe ? if ( !dst.IsNull() && !dst.IsEmpty() ) size.Set( dst.Width(), dst.Height() ); } void GetRequestedSize( const KS_VIDEOINFOHEADER &vidHdr, MSize &size ) { Trace t("GetRequestedSize()"); size.Set( vidHdr.bmiHeader.biWidth, abs(vidHdr.bmiHeader.biHeight) ); MRect dst( vidHdr.rcTarget ); // if writing to a DD surface maybe ? if ( !dst.IsNull() && !dst.IsEmpty() ) size.Set( dst.Width(), dst.Height() ); } /* Function: VerifyVideoStream * Purpose: Checks the paramaters passed in for opening steam * Input: vidHDR: KS_DATAFORMAT_VIDEOINFOHEADER * Output: Success or Fail */ ErrorCode VerifyVideoStream( const KS_DATAFORMAT_VIDEOINFOHEADER &vidHDR ) { Trace t("VerifyVideoStream()"); // [WRK] - add guid for VideoInfoHeader2 // simply verify that major and format are of video nature... if ( IsEqualGUID( vidHDR.DataFormat.MajorFormat, KSDATAFORMAT_TYPE_VIDEO ) && IsEqualGUID( vidHDR.DataFormat.Specifier, KSDATAFORMAT_SPECIFIER_VIDEOINFO ) ) { MSize size; GetRequestedSize( vidHDR.VideoInfoHeader, size ); // ... and here see if the subtype is one of those supported by us ColorSpace tmpCol( vidHDR.DataFormat.SubFormat ); MRect dst( vidHDR.VideoInfoHeader.rcTarget ); // make sure the dimentions are acceptable if ( tmpCol.IsValid() && tmpCol.CheckDimentions( size ) && tmpCol.CheckLeftTop( dst.TopLeft() ) ) { DebugOut((1, "VerifyVideoStream succeeded\n")); return Success; } } DebugOut((0, "VerifyVideoStream failed\n")); return Fail; } ErrorCode VerifyVideoStream2( const KS_DATAFORMAT_VIDEOINFOHEADER2 &vidHDR ) { Trace t("VerifyVideoStream2()"); // [WRK] - add guid for VideoInfoHeader2 // simply verify that major and format are of video nature... if ( IsEqualGUID( vidHDR.DataFormat.MajorFormat, KSDATAFORMAT_TYPE_VIDEO ) && IsEqualGUID( vidHDR.DataFormat.Specifier, KSDATAFORMAT_SPECIFIER_VIDEOINFO2 ) ) { MSize size; GetRequestedSize2( vidHDR.VideoInfoHeader2, size ); // ... and here see if the subtype is one of those supported by us ColorSpace tmpCol( vidHDR.DataFormat.SubFormat ); MRect dst( vidHDR.VideoInfoHeader2.rcTarget ); // make sure the dimentions are acceptable if ( tmpCol.IsValid() && tmpCol.CheckDimentions( size ) && tmpCol.CheckLeftTop( dst.TopLeft() ) ) { DebugOut((1, "VerifyVideoStream2 succeeded\n")); return Success; } } DebugOut((0, "VerifyVideoStream2 failed\n")); return Fail; } /* Function: VerifyVBIStream * Purpose: Checks that VBI stream info during open is correct * Input: rKSDataFormat: KS_DATAFORMAT & * Output: ErrorCode */ ErrorCode VerifyVBIStream( const KS_DATAFORMAT_VBIINFOHEADER &rKSDataFormat ) { Trace t("VerifyVBIStream()"); if ( IsEqualGUID( rKSDataFormat.DataFormat.MajorFormat, KSDATAFORMAT_TYPE_VBI ) && IsEqualGUID( rKSDataFormat.DataFormat.Specifier, KSDATAFORMAT_SPECIFIER_VBI ) && rKSDataFormat.VBIInfoHeader.StartLine == VBIStart && rKSDataFormat.VBIInfoHeader.EndLine == VBIEnd && rKSDataFormat.VBIInfoHeader.SamplesPerLine == VBISamples ) return Success; return Fail; } /* ** DriverEntry() ** ** This routine is called when an SRB_INITIALIZE_DEVICE request is received ** ** Arguments: ** ** Context1 and Context2 ** ** Returns: ** ** Results of StreamClassRegisterAdapter() ** ** Side Effects: none */ extern "C" ULONG DriverEntry( PVOID Arg1, PVOID Arg2 ) { Trace t("DriverEntry()"); // // Entry points for Port Driver // HW_INITIALIZATION_DATA HwInitData; RtlZeroMemory( &HwInitData, sizeof( HwInitData )); HwInitData.HwInitializationDataSize = sizeof( HwInitData ); HwInitData.HwInterrupt = (PHW_INTERRUPT)&HwInterrupt; HwInitData.HwReceivePacket = &AdapterReceivePacket; HwInitData.HwCancelPacket = &AdapterCancelPacket; HwInitData.HwRequestTimeoutHandler = &AdapterTimeoutPacket; HwInitData.DeviceExtensionSize = GetSizeHwDeviceExtension( ); HwInitData.PerRequestExtensionSize = sizeof(SRB_EXTENSION); HwInitData.FilterInstanceExtensionSize = 0; // double to support alternating/interleaved HwInitData.PerStreamExtensionSize = GetSizeStreamEx( ); HwInitData.BusMasterDMA = true; HwInitData.Dma24BitAddresses = FALSE; HwInitData.BufferAlignment = 4; HwInitData.TurnOffSynchronization = FALSE; HwInitData.DmaBufferSize = RISCProgramsSize; return (StreamClassRegisterAdapter(Arg1, Arg2,&HwInitData)); } /****************************************************************************** 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 */ BOOLEAN HwInitialize( IN OUT PHW_STREAM_REQUEST_BLOCK pSrb ) { Trace t("HwInitialize()"); DebugOut((1, "HwInitialize()\n")); // initialize ourselves PPORT_CONFIGURATION_INFORMATION ConfigInfo = pSrb->CommandData.ConfigInfo; gpHwDeviceExtension = ConfigInfo->HwDeviceExtension; DebugOut((0, "*** gpHwDeviceExtension = %x\n", gpHwDeviceExtension)); PHW_DEVICE_EXTENSION HwDeviceExtension = (PHW_DEVICE_EXTENSION) gpHwDeviceExtension; DWORD dwBase = ConfigInfo->AccessRanges[0].RangeStart.LowPart; SetBase((BYTE *)dwBase); if ( ConfigInfo->NumberOfAccessRanges != 1 ) { DebugOut((1, "illegal config info\n")); pSrb->Status = STATUS_NO_SUCH_DEVICE; } // read info from the registry ReadXBarRegistryValues( ConfigInfo->PhysicalDeviceObject ); ReadXTalRegistryValues( ConfigInfo->PhysicalDeviceObject ); ReadTunerRegistryValues( ConfigInfo->PhysicalDeviceObject ); HwDeviceExtension->psdevice = new ( &(HwDeviceExtension->psdevicemem) ) PsDevice( dwBase ); DebugOut((0, "psdevice = %x\n", HwDeviceExtension->psdevice )); DebugOut((0, "&psdevicemem = %x\n", &HwDeviceExtension->psdevicemem )); PsDevice *adapter = HwDeviceExtension->psdevice; // save for later use when phys address if obtained SetCurrentDevice( adapter ); // make sure initialization is successful if ( !adapter->InitOK() ) { DebugOut((1, "Error initializing\n")); pSrb->Status = STATUS_INSUFFICIENT_RESOURCES; } // save our PDO adapter->PDO = ConfigInfo->PhysicalDeviceObject; ConfigInfo->StreamDescriptorSize = sizeof( HW_STREAM_HEADER ) + DRIVER_STREAM_COUNT * sizeof( HW_STREAM_INFORMATION ); DebugOut((1, "Exit : HwInitialize()\n")); // go to usual priority, completing the SRB at the same time StreamClassCallAtNewPriority( pSrb->StreamObject, HwDeviceExtension, LowToHigh, PHW_PRIORITY_ROUTINE( CompleteDeviceSRB ), pSrb ); 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 */ void HwUnInitialize( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { Trace t("HwUnInitialize()"); PHW_DEVICE_EXTENSION HwDeviceExtension = (PHW_DEVICE_EXTENSION) pSrb->HwDeviceExtension; DebugOut((0, "HwUnInitialize - pSrb(%x)\n", pSrb)); PsDevice *adapter = HwDeviceExtension->psdevice; adapter->~PsDevice(); } /* ** AdapterOpenStream() ** ** This routine is called when an OpenStream SRB request is received ** ** Arguments: ** ** pSrb - pointer to stream request block for the Open command ** ** Returns: ** ** Side Effects: none */ VOID AdapterOpenStream( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { Trace t("AdapterOpenStream()"); // // the stream extension structure is allocated by the stream class driver // // retrieve the device object pointer PHW_DEVICE_EXTENSION HwDeviceExtension = (PHW_DEVICE_EXTENSION) pSrb->HwDeviceExtension; PsDevice *adapter = HwDeviceExtension->psdevice; VideoStream StreamNumber = (VideoStream)pSrb->StreamObject->StreamNumber; StreamIdxToSrb[StreamNumber] = pSrb; DebugOut((1, "AdapterOpenStream(%d) - pSrb(%x)\n", StreamNumber, pSrb)); // [STRM] [!!!] //if ( !( StreamNumber >= VS_Field1 && StreamNumber <= DRIVER_STREAM_COUNT ) ) { // pSrb->Status = STATUS_INVALID_PARAMETER; // ?change to the proper error code? // return; //} if ( StreamNumber == STREAM_IDX_ANALOG ) // [TMZ] [!!] was 3 { pSrb->StreamObject->ReceiveDataPacket = AnalogReceiveDataPacket; pSrb->StreamObject->ReceiveControlPacket = AnalogReceiveCtrlPacket; return; // nothing to do for the analog stream } PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; RtlZeroMemory( &pStrmEx->FrameInfo, sizeof( pStrmEx->FrameInfo ) ); pStrmEx->StreamNumber = StreamNumber; // size of the media specific data UINT MediaSpecific = sizeof( KS_FRAME_INFO ); // Always open VBI stream as Alternating fields if ( StreamNumber == STREAM_IDX_VBI ) { const KS_DATAFORMAT_VBIINFOHEADER &rKSVBIDataFormat = *(PKS_DATAFORMAT_VBIINFOHEADER) pSrb->CommandData.OpenFormat; if ( VerifyVBIStream( rKSVBIDataFormat ) != Success ) { DebugOut((0, "*** VerifyVBIStream failed - aborting\n")); pSrb->Status = STATUS_INVALID_PARAMETER; // ?change to the proper error code? return; } if ( adapter->OpenVBIChannel( pStrmEx ) != Success ) { DebugOut((0, "*** OpenVBIChannel failed - aborting\n")); pSrb->Status = STATUS_INVALID_PARAMETER; // ?change to the proper error code? return; } VBIAlterChannel *chan = (VBIAlterChannel *)pStrmEx->videochannel; //chan->pStrmEx = pStrmEx; chan->SetVidHdr( rKSVBIDataFormat ); MediaSpecific = sizeof( KS_VBI_FRAME_INFO ); } else { // is it where the size, fourcc, etc. are specified ? they should be settable // via properies sets const KS_DATAFORMAT_VIDEOINFOHEADER &rKSDataFormat = *(PKS_DATAFORMAT_VIDEOINFOHEADER) pSrb->CommandData.OpenFormat; const KS_VIDEOINFOHEADER &rVideoInfoHdrRequested = rKSDataFormat.VideoInfoHeader; const KS_DATAFORMAT_VIDEOINFOHEADER2 &rKSDataFormat2 = *(PKS_DATAFORMAT_VIDEOINFOHEADER2) pSrb->CommandData.OpenFormat; const KS_VIDEOINFOHEADER2 &rVideoInfoHdrRequested2 = rKSDataFormat2.VideoInfoHeader2; DebugOut((1, "AdapterOpenStream\n")); if ( IsEqualGUID( rKSDataFormat.DataFormat.Specifier, KSDATAFORMAT_SPECIFIER_VIDEOINFO ) ) { DebugOut((1, "StreamNumber=%d\n", pSrb->StreamObject->StreamNumber)); DebugOut((1, "FormatSize=%d\n", rKSDataFormat.DataFormat.FormatSize)); DebugOut((1, "MajorFormat=%x\n", rKSDataFormat.DataFormat.MajorFormat)); DebugOut((1, "pVideoInfoHdrRequested=%x\n", &rVideoInfoHdrRequested)); DebugOut((1, "Bpp =%d\n", rVideoInfoHdrRequested.bmiHeader.biBitCount ) ); DebugOut((1, "Width =%d\n", rVideoInfoHdrRequested.bmiHeader.biWidth)); DebugOut((1, "Height =%d\n", rVideoInfoHdrRequested.bmiHeader.biHeight)); DebugOut((1, "biSizeImage =%d\n", rVideoInfoHdrRequested.bmiHeader.biSizeImage)); if ( VerifyVideoStream( rKSDataFormat ) != Success ) { pSrb->Status = STATUS_INVALID_PARAMETER; // ?change to the proper error code? return; } } else { DebugOut((1, "StreamNumber=%d\n", pSrb->StreamObject->StreamNumber)); DebugOut((1, "FormatSize=%d\n", rKSDataFormat2.DataFormat.FormatSize)); DebugOut((1, "MajorFormat=%x\n", rKSDataFormat2.DataFormat.MajorFormat)); DebugOut((1, "pVideoInfoHdrRequested2=%x\n", &rVideoInfoHdrRequested2)); DebugOut((1, "Bpp =%d\n", rVideoInfoHdrRequested2.bmiHeader.biBitCount ) ); DebugOut((1, "Width =%d\n", rVideoInfoHdrRequested2.bmiHeader.biWidth)); DebugOut((1, "Height =%d\n", rVideoInfoHdrRequested2.bmiHeader.biHeight)); DebugOut((1, "biSizeImage =%d\n", rVideoInfoHdrRequested2.bmiHeader.biSizeImage)); if ( VerifyVideoStream2( rKSDataFormat2 ) != Success ) { pSrb->Status = STATUS_INVALID_PARAMETER; // ?change to the proper error code? return; } } // at this point have to see what type of channel is to be opened: // single field, alternating or interleaved // algorithm is like this: // 1. look at the video format Specifier guid. If it's a infoheader2, it // will tell us type of stream to open. // 2. else look at the vertical size to decide single field vs. interleaved if ( IsEqualGUID( rKSDataFormat.DataFormat.Specifier, KSDATAFORMAT_SPECIFIER_VIDEOINFO ) ) { MSize size; GetRequestedSize( rVideoInfoHdrRequested, size ); // different video standards have different vertical sizes int threshold = adapter->GetFormat() == VFormat_NTSC ? 240 : 288; if ( size.cy > threshold ) { if ( adapter->OpenInterChannel( pStrmEx, StreamNumber ) != Success ) { pSrb->Status = STATUS_INVALID_PARAMETER; // ?change to the proper error code? return; } } else { if ( adapter->OpenChannel( pStrmEx, StreamNumber ) != Success ) { pSrb->Status = STATUS_INVALID_PARAMETER; // ?change to the proper error code? return; } } VideoChannel *chan = (VideoChannel *)pStrmEx->videochannel; //chan->pStrmEx = pStrmEx; chan->SetVidHdr( rVideoInfoHdrRequested ); } else if ( IsEqualGUID( rKSDataFormat2.DataFormat.Specifier, KSDATAFORMAT_SPECIFIER_VIDEOINFO2 ) ) { MSize size; GetRequestedSize2( rVideoInfoHdrRequested2, size ); // different video standards have different vertical sizes int threshold = adapter->GetFormat() == VFormat_NTSC ? 240 : 288; if ( size.cy > threshold ) { if ( adapter->OpenInterChannel( pStrmEx, StreamNumber ) != Success ) { pSrb->Status = STATUS_INVALID_PARAMETER; // ?change to the proper error code? return; } } else { if ( adapter->OpenChannel( pStrmEx, StreamNumber ) != Success ) { pSrb->Status = STATUS_INVALID_PARAMETER; // ?change to the proper error code? return; } } VideoChannel *chan = (VideoChannel *)pStrmEx->videochannel; //chan->pStrmEx = pStrmEx; chan->SetVidHdr2( rVideoInfoHdrRequested2 ); } else { if ( adapter->OpenInterChannel( pStrmEx, StreamNumber ) != Success ) { pSrb->Status = STATUS_INVALID_PARAMETER; // ?change to the proper error code? return; } if ( adapter->OpenAlterChannel( pStrmEx, StreamNumber ) != Success ) { pSrb->Status = STATUS_INVALID_PARAMETER; // ?change to the proper error code? return; } // [WRK] - check the height of the image for alter channel !> threshold VideoChannel *chan = (VideoChannel *)pStrmEx->videochannel; //chan->pStrmEx = pStrmEx; chan->SetVidHdr( rVideoInfoHdrRequested ); } } #ifdef ENABLE_DDRAW_STUFF //TODO: should we check to see what kind of stream type this is? if( OpenKernelDirectDraw( pSrb ) ) { OpenKernelDDrawSurfaceHandle( pSrb ); RegisterForDirectDrawEvents( pSrb ); } #endif // the structure of the driver is such that a single callback could be used // for all stream requests. But the code below could be used to supply // different entry points for different streams pSrb->StreamObject->ReceiveDataPacket = VideoReceiveDataPacket; pSrb->StreamObject->ReceiveControlPacket = VideoReceiveCtrlPacket; pSrb->StreamObject->Dma = true; pSrb->StreamObject->Allocator = Streams[StreamNumber].hwStreamObject.Allocator; // // The PIO flag must be set when the mini driver will be accessing the data // buffers passed in using logical addressing // pSrb->StreamObject->Pio = true; pSrb->StreamObject->StreamHeaderMediaSpecific = MediaSpecific; pSrb->StreamObject->HwClockObject.ClockSupportFlags = 0; pSrb->StreamObject->HwClockObject.HwClockFunction = 0; DebugOut((1, "AdapterOpenStream Exit\n")); } /* ** AdapterCloseStream() ** ** Close the requested data stream ** ** Arguments: ** ** pSrb the request block requesting to close the stream ** ** Returns: ** ** Side Effects: none */ VOID AdapterCloseStream( PHW_STREAM_REQUEST_BLOCK pSrb ) { Trace t("AdapterCloseStream()"); PHW_DEVICE_EXTENSION HwDeviceExtension = (PHW_DEVICE_EXTENSION) pSrb->HwDeviceExtension; PsDevice *adapter = HwDeviceExtension->psdevice; VideoChannel *chan = (VideoChannel *)((PSTREAMEX)pSrb->StreamObject->HwStreamExtension)->videochannel; VideoStream StreamNumber = (VideoStream)pSrb->StreamObject->StreamNumber; DebugOut((1, "AdapterCloseStream(%d) - pSrb(%x)\n", StreamNumber, pSrb)); if ( !( StreamNumber >= 0 && StreamNumber < DRIVER_STREAM_COUNT ) ) { DebugOut((0, " AdapterCloseStream - failed to close stream %d\n", StreamNumber)); DEBUG_BREAKPOINT(); pSrb->Status = STATUS_INVALID_PARAMETER; // ?change to the proper error code? return; } if ( StreamNumber == STREAM_IDX_ANALOG ) // nothing to close for analog { DebugOut((1, " AdapterCloseStream - doing nothing, stream (%d) was assumed to be analog\n", StreamNumber)); return; } #ifdef ENABLE_DDRAW_STUFF //TODO: should we check to see what kind of stream type this is? UnregisterForDirectDrawEvents( pSrb ); CloseKernelDDrawSurfaceHandle( pSrb ); CloseKernelDirectDraw( pSrb ); #endif // CloseChannel() has a bit of ugly code to take care of paired channels adapter->CloseChannel( chan ); } /* ** 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 AdapterStreamInfo( PHW_STREAM_REQUEST_BLOCK pSrb ) { Trace t("AdapterStreamInfo()"); // // 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 stream information data structure // 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 ); // // 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 ( int j = 0; j < DRIVER_STREAM_COUNT; j++ ) { *pstrinfo++ = Streams[j].hwStreamInfo; } } #ifdef HAUPPAUGEI2CPROVIDER // new private members of PsDevice for Hauppauge I2C Provider: // LARGE_INTEGER LastI2CAccessTime; // DWORD dwExpiredCookie = 0; // // /* Method: PsDevice::I2COpen * Purpose: Tries to allocate I2C port to the caller */ NTSTATUS STDMETHODCALLTYPE PsDevice::I2COpen( PDEVICE_OBJECT pdo, ULONG ToOpen, PI2CControl ctrl ) { Trace t("PsDevice::I2COpen()"); DebugOut((1, "*** pdo->DeviceExtension = %x\n", pdo->DeviceExtension)); LARGE_INTEGER CurTime; // need a way to obtain the device pointer PsDevice *adapter = GetCurrentDevice(); KeQuerySystemTime( &CurTime ); ctrl->Status = I2C_STATUS_NOERROR; // cookie is not NULL if I2C is open if ( ToOpen && adapter->dwCurCookie_ ) { // Check time stamp against current time to detect if current Cookie has timed out. // If it has remember the last timed out cookie and grant the new requestor access. if ( ( adapter->dwI2CClientTimeout != 0 ) && ( (CurTime - adapter->LastI2CAccessTime) > adapter->dwI2CClientTimeout ) ) { adapter->dwExpiredCookie = adapter->dwCurCookie_; } else { ctrl->dwCookie = 0; return STATUS_INVALID_HANDLE; } } // want to close ? if ( !ToOpen ) { if ( adapter->dwCurCookie_ == ctrl->dwCookie ) { adapter->dwCurCookie_ = 0; ctrl->dwCookie = 0; return STATUS_SUCCESS; } else { if ( (adapter->dwExpiredCookie != 0 ) && (adapter->dwExpiredCookie == ctrl->dwCookie ) ) { ctrl->Status = I2C_STATUS_ERROR; } else { ctrl->dwCookie = 0; ctrl->Status = I2C_STATUS_NOERROR; } return STATUS_INVALID_HANDLE; } } adapter->dwCurCookie_ = CurTime.LowPart; adapter->LastI2CAccessTime = CurTime; ctrl->dwCookie = adapter->dwCurCookie_; ctrl->ClockRate = 100000; return STATUS_SUCCESS; } NTSTATUS STDMETHODCALLTYPE PsDevice::I2CAccess( PDEVICE_OBJECT pdo, PI2CControl ctrl ) { Trace t("PsDevice::I2CAccess()"); DebugOut((1, "*** pdo->DeviceExtension = %x\n", pdo->DeviceExtension)); ErrorCode error; PsDevice *adapter = GetCurrentDevice(); ctrl->Status = I2C_STATUS_NOERROR; if ( ctrl->dwCookie != adapter->dwCurCookie_ ) { if ( (adapter->dwExpiredCookie != 0 ) && (adapter->dwExpiredCookie == ctrl->dwCookie ) ) ctrl->Status = I2C_STATUS_ERROR; else ctrl->Status = I2C_STATUS_NOERROR; return STATUS_INVALID_HANDLE; } // Record time of this transaction to enable checking for timeout KeQuerySystemTime( &adapter->LastI2CAccessTime ); // Check for valid combinations of I2C command & flags switch( ctrl->Command ) { case I2C_COMMAND_NULL: if ( ( ctrl->Flags & ~(I2C_FLAGS_START | I2C_FLAGS_STOP) ) || ( ( ctrl->Flags & (I2C_FLAGS_START | I2C_FLAGS_STOP) ) == (I2C_FLAGS_START | I2C_FLAGS_STOP) ) ) { // Illegal combination of Command & Flags return STATUS_INVALID_PARAMETER; } if ( ctrl->Flags & I2C_FLAGS_START ) { if ( adapter->I2CSWStart() ) { ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } } if ( ctrl->Flags & I2C_FLAGS_STOP ) { if ( adapter->I2CSWStop() ) { ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } } break; case I2C_COMMAND_READ: if ( ctrl->Flags & ~(I2C_FLAGS_STOP | I2C_FLAGS_ACK) ) { // Illegal combination of Command & Flags return STATUS_INVALID_PARAMETER; } if ( adapter->I2CSWRead( &ctrl->Data ) ) { ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } if ( ctrl->Flags & I2C_FLAGS_ACK ) { if ( adapter->I2CSWSendACK() ) { ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } } else { if ( adapter->I2CSWSendNACK() ) { ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } } if ( ctrl->Flags & I2C_FLAGS_STOP ) { if ( adapter->I2CSWStop() ) { ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } } break; case I2C_COMMAND_WRITE: if ( ctrl->Flags & ~(I2C_FLAGS_START | I2C_FLAGS_STOP | I2C_FLAGS_ACK | I2C_FLAGS_DATACHAINING) ) { // Illegal combination of Command & Flags return STATUS_INVALID_PARAMETER; } if ( ctrl->Flags & I2C_FLAGS_DATACHAINING ) { if ( adapter->I2CSWStop() ) { ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } if ( adapter->I2CSWStart() ) { ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } } if ( ctrl->Flags & I2C_FLAGS_START ) { if ( adapter->I2CSWStart() ) { ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } } error = adapter->I2CSWWrite(ctrl->Data); switch ( error ) { case I2CERR_NOACK: if ( ctrl->Flags & I2C_FLAGS_ACK ) { ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } break; case I2CERR_OK: if ( ( ctrl->Flags & I2C_FLAGS_ACK ) == 0 ) { ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } break; default: ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } if ( ctrl->Flags & I2C_FLAGS_STOP ) { if ( adapter->I2CSWStop() ) { ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } } break; case I2C_COMMAND_STATUS: // Flags are ignored return STATUS_NOT_IMPLEMENTED; case I2C_COMMAND_RESET: // Flags are ignored if ( adapter->I2CSWStart() ) { ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } if ( adapter->I2CSWStop() ) { ctrl->Status = I2C_STATUS_ERROR; return STATUS_SUCCESS; } break; default: return STATUS_INVALID_PARAMETER; } return STATUS_SUCCESS; } #else /* Method: PsDevice::I2COpen * Purpose: Tries to allocate I2C port to the caller */ NTSTATUS STDMETHODCALLTYPE PsDevice::I2COpen( PDEVICE_OBJECT pdo, ULONG ToOpen, PI2CControl ctrl ) { Trace t("PsDevice::I2COpen()"); DebugOut((1, "*** pdo->DeviceExtension = %x\n", pdo->DeviceExtension)); // need a way to obtain the device pointer PsDevice *adapter = GetCurrentDevice(); // cookie is not NULL if I2C is open if ( ToOpen && adapter->dwCurCookie_ ) { ctrl->Flags = I2C_STATUS_BUSY; return STATUS_DEVICE_BUSY; } // want to close ? if ( !ToOpen ) if ( adapter->dwCurCookie_ == ctrl->dwCookie ) { adapter->dwCurCookie_ = 0; return STATUS_SUCCESS; } else { ctrl->Flags = I2C_STATUS_BUSY; return STATUS_DEVICE_BUSY; } // now we are opening LARGE_INTEGER CurTime; KeQuerySystemTime( &CurTime ); adapter->dwCurCookie_ = CurTime.LowPart; ctrl->dwCookie = adapter->dwCurCookie_; ctrl->ClockRate = 100000; return STATUS_SUCCESS; } NTSTATUS STDMETHODCALLTYPE PsDevice::I2CAccess( PDEVICE_OBJECT pdo , PI2CControl ctrl ) { Trace t("PsDevice::I2CAccess()"); DebugOut((1, "*** pdo->DeviceExtension = %x\n", pdo->DeviceExtension)); PsDevice *adapter = GetCurrentDevice(); if ( ctrl->dwCookie != adapter->dwCurCookie_ ) { ctrl->Flags = I2C_STATUS_BUSY; return I2C_STATUS_BUSY; } ctrl->Flags = I2C_STATUS_NOERROR; // 848 I2C API currently needs to have an address for both write and read // commands. So, if START flag is set an address is passed. Cache it and use // later switch ( ctrl->Command ) { case I2C_COMMAND_READ: // got 'write' command first ( with the address ) if ( adapter->I2CHWRead( adapter->GetI2CAddress(), &ctrl->Data ) != Success ) ctrl->Flags = I2C_STATUS_ERROR; break; case I2C_COMMAND_WRITE: if ( ctrl->Flags & I2C_FLAGS_START ) { adapter->StoreI2CAddress( ctrl->Data ); } else adapter->I2CHWWrite2( adapter->GetI2CAddress(), ctrl->Data ); break; case I2C_COMMAND_STATUS: if ( adapter->I2CGetLastError() != I2CERR_OK ) ctrl->Flags = I2C_STATUS_ERROR; break; case I2C_COMMAND_RESET: adapter->I2CInitHWMode( 100000 ); // assume frequency = 100Khz break; } return STATUS_SUCCESS; } #endif void HandleIRP( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { Trace t("HandleIRP()"); DebugOut((1, "HandleIRP(%x)\n", pSrb)); PHW_DEVICE_EXTENSION HwDeviceExtension = (PHW_DEVICE_EXTENSION) pSrb->HwDeviceExtension; PsDevice *adapter = HwDeviceExtension->psdevice; PIRP Irp = pSrb->Irp; PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation( Irp ); switch ( IrpStack->MajorFunction ) { case IRP_MJ_PNP: if ( IrpStack->MinorFunction == IRP_MN_QUERY_INTERFACE ) { if ( IsEqualGUID( *IrpStack->Parameters.QueryInterface.InterfaceType, GUID_I2C_INTERFACE ) && IrpStack->Parameters.QueryInterface.Size >= sizeof( I2CINTERFACE ) ) { IrpStack->Parameters.QueryInterface.InterfaceType = &GUID_I2C_INTERFACE; IrpStack->Parameters.QueryInterface.Size = sizeof( I2CINTERFACE ); IrpStack->Parameters.QueryInterface.Version = 1; I2CINTERFACE *i2ciface = (I2CINTERFACE *)IrpStack->Parameters.QueryInterface.Interface; i2ciface->i2cOpen = &PsDevice::I2COpen; i2ciface->i2cAccess = &PsDevice::I2CAccess; IrpStack->Parameters.QueryInterface.InterfaceSpecificData = 0; // complete the irp Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest( Irp, IO_NO_INCREMENT ); break; } else { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER_1; IoCompleteRequest( Irp, IO_NO_INCREMENT ); } } default: pSrb->Status = STATUS_NOT_SUPPORTED; } } /** CompleteInitialization() ** ** This routine is called when an SRB_COMPLETE_INITIALIZATION request is received ** ** Arguments: ** ** pSrb - pointer to stream request block ** ** Returns: ** ** Side Effects: none */ void STDMETHODCALLTYPE CompleteInitialization( IN OUT PHW_STREAM_REQUEST_BLOCK pSrb ) { Trace t("CompleteInitialization()"); NTSTATUS Status; PHW_DEVICE_EXTENSION HwDeviceExtension = (PHW_DEVICE_EXTENSION) pSrb->HwDeviceExtension; PsDevice *adapter = HwDeviceExtension->psdevice; // Create the Registry blobs that DShow uses to create // graphs via Mediums Status = StreamClassRegisterFilterWithNoKSPins ( adapter->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 ); Status = StreamClassRegisterFilterWithNoKSPins ( adapter->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 ( adapter->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 ( adapter->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, CaptureCategories // IN GUID * CategoryList ); // go to usual priority, completing the SRB at the same time StreamClassCallAtNewPriority( pSrb->StreamObject, HwDeviceExtension, LowToHigh, PHW_PRIORITY_ROUTINE( CompleteDeviceSRB ), pSrb ); } /* ** AdapterReceivePacket() ** ** Main entry point for receiving adapter based request SRBs. This routine ** will always be called at High Priority. ** ** Note: This is an asyncronous entry point. The request does not 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 ) { Trace t("AdapterReceivePacket()"); BOOL CompleteRequestSynchronously = TRUE; //default to success pSrb->Status = STATUS_SUCCESS; PHW_DEVICE_EXTENSION HwDeviceExtension = (PHW_DEVICE_EXTENSION) pSrb->HwDeviceExtension; PsDevice *adapter = HwDeviceExtension->psdevice; // // determine the type of packet. // DebugOut((1, "'AdapterReceivePacket(%x) cmd(%x)\n", pSrb, pSrb->Command)); switch ( pSrb->Command ) { case SRB_INITIALIZE_DEVICE: DebugOut((1, " SRB_INITIALIZE_DEVICE\n")); CompleteRequestSynchronously = FALSE; // have to schedule a low priority call to open the device because // registry functions are used during initialization StreamClassCallAtNewPriority( pSrb->StreamObject, pSrb->HwDeviceExtension, Low, PHW_PRIORITY_ROUTINE( HwInitialize ), pSrb ); break; case SRB_UNINITIALIZE_DEVICE: DebugOut((1, " SRB_UNINITIALIZE_DEVICE\n")); // close the device. HwUnInitialize(pSrb); break; case SRB_OPEN_STREAM: DebugOut((1, " SRB_OPEN_STREAM\n")); // open a stream AdapterOpenStream( pSrb ); break; case SRB_CLOSE_STREAM: DebugOut((1, " SRB_CLOSE_STREAM\n")); // close a stream AdapterCloseStream( pSrb ); break; case SRB_GET_STREAM_INFO: DebugOut((1, " SRB_GET_STREAM_INFO\n")); // // return a block describing all the streams // AdapterStreamInfo(pSrb); break; case SRB_GET_DEVICE_PROPERTY: DebugOut((1, " SRB_GET_DEVICE_PROPERTY\n")); AdapterGetProperty( pSrb ); break; case SRB_SET_DEVICE_PROPERTY: DebugOut((1, " SRB_SET_DEVICE_PROPERTY\n")); AdapterSetProperty( pSrb ); break; case SRB_GET_DATA_INTERSECTION: DebugOut((1, " SRB_GET_DATA_INTERSECTION\n")); // // Return a format, given a range // AdapterFormatFromRange( pSrb ); break; case SRB_INITIALIZATION_COMPLETE: DebugOut((1, " SRB_INITIALIZATION_COMPLETE\n")); // // Stream class has finished initialization. // Now create DShow Medium interface BLOBs. // This needs to be done at low priority since it uses the registry, so use a callback // CompleteRequestSynchronously = FALSE; StreamClassCallAtNewPriority( NULL /*pSrb->StreamObject*/, pSrb->HwDeviceExtension, Low, PHW_PRIORITY_ROUTINE( CompleteInitialization), pSrb ); break; case SRB_PAGING_OUT_DRIVER: if ( (*(DWORD*)(gpjBaseAddr+0x10c) & 3) || (*(DWORD*)(gpjBaseAddr+0x104)) ) { DebugOut((0, " ****** SRB_PAGING_OUT_DRIVER ENB(%x) MSK(%x)\n", *(DWORD*)(gpjBaseAddr+0x10c) & 3, *(DWORD*)(gpjBaseAddr+0x104) )); *(DWORD*)(gpjBaseAddr+0x10c) &= ~3; // disable interrupts [TMZ] [!!!] *(DWORD*)(gpjBaseAddr+0x104) = 0; // disable interrupts [TMZ] [!!!] } break; case SRB_UNKNOWN_DEVICE_COMMAND: DebugOut((1, " SRB_UNKNOWN_DEVICE_COMMAND\n")); HandleIRP( pSrb ); break; // We should never get the following 2 since this is a single instance // device case SRB_OPEN_DEVICE_INSTANCE: case SRB_CLOSE_DEVICE_INSTANCE: default: // // this is a request that we do not understand. Indicate invalid // command and complete the request // DebugOut((0, "SRB(%x) not recognized by this driver\n", pSrb->Command)); pSrb->Status = STATUS_NOT_IMPLEMENTED; } // // Most, but not all SRBs are handled synchronously here // if ( CompleteRequestSynchronously ) { CompleteDeviceSRB( pSrb ); } } /* ** 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 ) { Trace t("AdapterCancelPacket()"); VideoStream StreamNumber = (VideoStream)pSrb->StreamObject->StreamNumber; DebugOut((1, "AdapterCancelPacket - pSrb(%x) strm(%d)\n", pSrb, StreamNumber)); VideoChannel *chan = (VideoChannel *)((PSTREAMEX)pSrb->StreamObject->HwStreamExtension)->videochannel; pSrb->Status = STATUS_CANCELLED; // // it is necessary to call the request back correctly. Determine which // type of command it is // switch ( pSrb->Flags & (SRB_HW_FLAGS_DATA_TRANSFER | SRB_HW_FLAGS_STREAM_REQUEST ) ) { // // find all stream commands, and do stream notifications // case SRB_HW_FLAGS_STREAM_REQUEST | SRB_HW_FLAGS_DATA_TRANSFER: DebugOut((1, " Canceling data SRB\n" ) ); // adapter->Stop( *chan ); [!!!] [TMZ] [???] why is this commented out??? if (!chan->RemoveSRB( pSrb )) { DebugOut((0, " Canceling data SRB failed\n")); DEBUG_BREAKPOINT(); } break; case SRB_HW_FLAGS_STREAM_REQUEST: DebugOut((1, " Canceling control SRB\n" ) ); CheckSrbStatus( pSrb ); StreamClassStreamNotification( ReadyForNextStreamControlRequest, pSrb->StreamObject ); StreamClassStreamNotification( StreamRequestComplete, pSrb->StreamObject, pSrb ); break; default: // // this must be a device request. Use device notifications // DebugOut((1, " Canceling SRB per device request\n" ) ); StreamClassDeviceNotification( ReadyForNextDeviceRequest, pSrb->HwDeviceExtension ); StreamClassDeviceNotification( DeviceRequestComplete, pSrb->HwDeviceExtension, pSrb ); } } /* ** 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 ) { Trace t("AdapterTimeoutPacket()"); DebugOut((0, "AdapterTimeoutPacket (incomplete) - pSrb(%x)\n", pSrb)); // [TMZ] Fix this #if SHOW_BUILD_MSGS #pragma message("*** AdapterTimeoutPacket needs to be completed") #endif DebugOut((0, " pSrb->Flags = %x\n", pSrb->Flags)); if ( pSrb->Flags & SRB_HW_FLAGS_STREAM_REQUEST ) { DebugOut((0, " SRB_HW_FLAGS_STREAM_REQUEST\n")); } if ( pSrb->Flags & SRB_HW_FLAGS_DATA_TRANSFER ) { DebugOut((0, " SRB_HW_FLAGS_DATA_TRANSFER\n")); } // // if we timeout while playing, then we need to consider this // condition an error, and reset the hardware, and reset everything // as well as cancelling this and all requests // // // if we are not playing, and this is a CTRL request, we still // need to reset everything as well as cancelling this and all requests // // // if this is a data request, and the device is paused, we probably have // run out of data buffer, and need more time, so just reset the timer, // and let the packet continue // pSrb->TimeoutCounter = pSrb->TimeoutOriginal; } /* ** HwInterrupt() ** ** Routine is called when an interrupt at the IRQ level specified by the ** ConfigInfo structure passed to the HwInitialize routine is received. ** ** Note: IRQs may be shared, so the device should ensure the IRQ received ** was expected ** ** Arguments: ** ** pHwDevEx - the device extension for the hardware interrupt ** ** Returns: ** ** Side Effects: none */ BOOLEAN HwInterrupt( IN PHW_DEVICE_EXTENSION HwDeviceExtension ) { Trace t("HwInterrupt()"); DebugOut((1, "HwInterrupt called by system\n")); PsDevice *adapter = (PsDevice *)(HwDeviceExtension->psdevice); BOOLEAN b = adapter->Interrupt(); return( b ); } /* Function: CompleteDeviceSRB * Purpose: Called to complete a device SRB * Input: pSrb */ inline void CompleteDeviceSRB( IN OUT PHW_STREAM_REQUEST_BLOCK pSrb ) { Trace t("CompleteDeviceSRB()"); StreamClassDeviceNotification( DeviceRequestComplete, pSrb->HwDeviceExtension, pSrb ); StreamClassDeviceNotification( ReadyForNextDeviceRequest, pSrb->HwDeviceExtension ); } /* ** AdapterCompareGUIDsAndFormatSize() ** ** Checks for a match on the three GUIDs and FormatSize ** ** Arguments: ** ** IN DataRange1 ** IN DataRange2 ** ** Returns: ** ** TRUE if all elements match ** FALSE if any are different ** ** Side Effects: none */ bool AdapterCompareGUIDsAndFormatSize( IN const PKSDATARANGE DataRange1, IN const PKSDATARANGE DataRange2 ) { Trace t("AdapterCompareGUIDsAndFormatSize()"); bool bCheckSize = false; #if 1 // use old guid verify return ( IsEqualGUID( DataRange1->MajorFormat, DataRange2->MajorFormat ) && IsEqualGUID( DataRange1->SubFormat, DataRange2->SubFormat ) && IsEqualGUID( DataRange1->Specifier, DataRange2->Specifier ) && ( DataRange1->FormatSize == DataRange2->FormatSize ) ); #else // use new guid verify from cc decoder bool rval = false; if ( IsEqualGUID(DataRange1->MajorFormat, KSDATAFORMAT_TYPE_WILDCARD) || IsEqualGUID(DataRange2->MajorFormat, KSDATAFORMAT_TYPE_WILDCARD) || IsEqualGUID(DataRange1->MajorFormat, DataRange2->MajorFormat) ) { if ( !IsEqualGUID(DataRange1->MajorFormat, DataRange2->MajorFormat) ) { DebugOut((0, "Match 1\n" )); } if ( IsEqualGUID(DataRange1->SubFormat, KSDATAFORMAT_SUBTYPE_WILDCARD) || IsEqualGUID(DataRange2->SubFormat, KSDATAFORMAT_SUBTYPE_WILDCARD) || IsEqualGUID(DataRange1->SubFormat, DataRange2->SubFormat) ) { if ( !IsEqualGUID(DataRange1->SubFormat, DataRange2->SubFormat) ) { DebugOut((0, "Match 2\n" )); } if ( IsEqualGUID(DataRange1->Specifier, KSDATAFORMAT_SPECIFIER_WILDCARD) || IsEqualGUID(DataRange2->Specifier, KSDATAFORMAT_SPECIFIER_WILDCARD) || IsEqualGUID(DataRange1->Specifier, DataRange2->Specifier) ) { if ( !IsEqualGUID(DataRange1->Specifier, DataRange2->Specifier) ) { DebugOut((0, "Match 3\n" )); } if ( !bCheckSize || DataRange1->FormatSize == DataRange2->FormatSize) { DebugOut((0, "Victory !!!\n" )); rval = true; } else { DebugOut((0, "FormatSize Mismatch\n" )); } } else { DebugOut((0, "Specifier Mismatch\n" )); } } else { DebugOut((0, "SubFormat Mismatch\n" )); } } else { DebugOut((0, "MajorFormat Mismatch\n" )); } DebugOut((0, "CompareGUIDsAndFormatSize(\n")); DebugOut((0, " DataRange1=%x\n", DataRange1)); DebugOut((0, " DataRange2=%x\n", DataRange2)); DebugOut((0, " bCheckSize=%s\n", bCheckSize ? "TRUE":"FALSE")); DebugOut((0, ")\n")); DebugOut((0, "returning %s\n", rval? "TRUE":"FALSE")); return rval; #endif } /* ** AdapterFormatFromRange() ** ** Returns a DATAFORMAT from a DATARANGE ** ** Arguments: ** ** IN PHW_STREAM_REQUEST_BLOCK pSrb ** ** Returns: ** ** TRUE if the format is supported ** FALSE if the format cannot be suppored ** ** Side Effects: none */ void AdapterFormatFromRange( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { Trace t("AdapterFormatFromRange()"); PSTREAM_DATA_INTERSECT_INFO IntersectInfo; PKSDATARANGE DataRange; ULONG FormatSize=0; 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; return; } 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? // bool 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 ) ) { 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; // // 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 ) ) ) { DebugOut(( 1, "AdapterFormatFromRange(): at least one field does not match\n" )); continue; } // MATCH FOUND! FormatSize = sizeof( KSDATAFORMAT ) + KS_SIZE_VIDEOHEADER( &DataRangeVideoToVerify->VideoInfoHeader ); if ( OnlyWantsSize ) { break; } // Caller wants the full data format if ( IntersectInfo->SizeOfDataFormatBuffer < FormatSize ) { DebugOut(( 1, "AdapterFormatFromRange(): STATUS_BUFFER_TOO_SMALL\n" )); pSrb->Status = STATUS_BUFFER_TOO_SMALL; return; } // Copy over the KSDATAFORMAT, followed by the // actual VideoInfoHeader PKS_DATAFORMAT_VIDEOINFOHEADER InterVidHdr = (PKS_DATAFORMAT_VIDEOINFOHEADER)IntersectInfo->DataFormatBuffer; RtlCopyMemory( &InterVidHdr->DataFormat, &DataRangeVideoToVerify->DataRange, sizeof( KSDATARANGE ) ); ((PKSDATAFORMAT)IntersectInfo->DataFormatBuffer)->FormatSize = FormatSize; RtlCopyMemory( &InterVidHdr->VideoInfoHeader, &DataRangeVideoToVerify->VideoInfoHeader, KS_SIZE_VIDEOHEADER( &DataRangeVideoToVerify->VideoInfoHeader ) ); // report back the omage size as we know it KS_VIDEOINFOHEADER &vidHDR = DataRangeVideoToVerify->VideoInfoHeader; #ifdef HACK_FUDGE_RECTANGLES // [!!!] [TMZ] - hack if( vidHDR.rcTarget.bottom == 0 ) { vidHDR.rcTarget.left = 0; vidHDR.rcTarget.top = 0; vidHDR.rcTarget.right = vidHDR.bmiHeader.biWidth; vidHDR.rcTarget.bottom = abs(vidHDR.bmiHeader.biHeight); } if( InterVidHdr->VideoInfoHeader.rcTarget.bottom == 0 ) { InterVidHdr->VideoInfoHeader.rcTarget.left = 0; InterVidHdr->VideoInfoHeader.rcTarget.top = 0; InterVidHdr->VideoInfoHeader.rcTarget.right = vidHDR.bmiHeader.biWidth; InterVidHdr->VideoInfoHeader.rcTarget.bottom = abs(vidHDR.bmiHeader.biHeight); } #endif MSize size; GetRequestedSize( vidHDR, size ); ColorSpace tmpCol( DataRange->SubFormat ); MRect dst( vidHDR.rcTarget ); // make sure the dimentions are acceptable if ( tmpCol.IsValid() && tmpCol.CheckDimentions( size ) && tmpCol.CheckLeftTop( dst.TopLeft() ) ) { // if width is different, use it ( in bytes ) to calculate the size if ( vidHDR.bmiHeader.biWidth != size.cx ) { InterVidHdr->VideoInfoHeader.bmiHeader.biSizeImage = vidHDR.bmiHeader.biWidth * abs(vidHDR.bmiHeader.biHeight); } else { InterVidHdr->VideoInfoHeader.bmiHeader.biSizeImage = size.cx * tmpCol.GetBitCount() * abs(vidHDR.bmiHeader.biHeight) / 8; } DebugOut((1, "InterVidHdr->VideoInfoHeader.bmiHeader.biSizeImage = %d\n", InterVidHdr->VideoInfoHeader.bmiHeader.biSizeImage)); break; } else { pSrb->Status = STATUS_BUFFER_TOO_SMALL; DebugOut((1, "AdapterFormatFromRange: Buffer too small\n")); return; } } // End of VIDEOINFOHEADER specifier // ------------------------------------------------------------------- // Specifier FORMAT_VideoInfo2 for VIDEOINFOHEADER2 // ------------------------------------------------------------------- else if ( IsEqualGUID( DataRange->Specifier, KSDATAFORMAT_SPECIFIER_VIDEOINFO2 ) ) { PKS_DATARANGE_VIDEO2 DataRangeVideoToVerify = (PKS_DATARANGE_VIDEO2) DataRange; PKS_DATARANGE_VIDEO2 DataRangeVideo = (PKS_DATARANGE_VIDEO2) *pAvailableFormats; // // 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 ) ) ) { DebugOut(( 1, "AdapterFormatFromRange(): at least one field does not match\n" )); continue; } // MATCH FOUND! FormatSize = sizeof( KSDATAFORMAT ) + KS_SIZE_VIDEOHEADER2( &DataRangeVideoToVerify->VideoInfoHeader ); if ( OnlyWantsSize ) { break; } // Caller wants the full data format if ( IntersectInfo->SizeOfDataFormatBuffer < FormatSize ) { DebugOut(( 1, "AdapterFormatFromRange(): STATUS_BUFFER_TOO_SMALL\n" )); pSrb->Status = STATUS_BUFFER_TOO_SMALL; return; } // Copy over the KSDATAFORMAT, followed by the // actual VideoInfoHeader PKS_DATAFORMAT_VIDEOINFOHEADER2 InterVidHdr = (PKS_DATAFORMAT_VIDEOINFOHEADER2)IntersectInfo->DataFormatBuffer; RtlCopyMemory( &InterVidHdr->DataFormat, &DataRangeVideoToVerify->DataRange, sizeof( KSDATARANGE ) ); ((PKSDATAFORMAT)IntersectInfo->DataFormatBuffer)->FormatSize = FormatSize; RtlCopyMemory( &InterVidHdr->VideoInfoHeader2, &DataRangeVideoToVerify->VideoInfoHeader, KS_SIZE_VIDEOHEADER2( &DataRangeVideoToVerify->VideoInfoHeader ) ); // report back the omage size as we know it KS_VIDEOINFOHEADER2 &vidHDR = DataRangeVideoToVerify->VideoInfoHeader; #ifdef HACK_FUDGE_RECTANGLES // [!!!] [TMZ] - hack if( vidHDR.rcTarget.bottom == 0 ) { vidHDR.rcTarget.left = 0; vidHDR.rcTarget.top = 0; vidHDR.rcTarget.right = vidHDR.bmiHeader.biWidth; vidHDR.rcTarget.bottom = abs(vidHDR.bmiHeader.biHeight); } if( InterVidHdr->VideoInfoHeader.rcTarget.bottom == 0 ) { InterVidHdr->VideoInfoHeader.rcTarget.left = 0; InterVidHdr->VideoInfoHeader.rcTarget.top = 0; InterVidHdr->VideoInfoHeader.rcTarget.right = vidHDR.bmiHeader.biWidth; InterVidHdr->VideoInfoHeader.rcTarget.bottom = abs(vidHDR.bmiHeader.biHeight); } #endif MSize size; GetRequestedSize2( vidHDR, size ); ColorSpace tmpCol( DataRange->SubFormat ); MRect dst( vidHDR.rcTarget ); // make sure the dimentions are acceptable if ( tmpCol.IsValid() && tmpCol.CheckDimentions( size ) && tmpCol.CheckLeftTop( dst.TopLeft() ) ) { // if width is different, use it ( in bytes ) to calculate the size if ( vidHDR.bmiHeader.biWidth != size.cx ) { InterVidHdr->VideoInfoHeader2.bmiHeader.biSizeImage = vidHDR.bmiHeader.biWidth * abs(vidHDR.bmiHeader.biHeight); } else { InterVidHdr->VideoInfoHeader2.bmiHeader.biSizeImage = size.cx * tmpCol.GetBitCount() * abs(vidHDR.bmiHeader.biHeight) / 8; } DebugOut((1, "InterVidHdr->VideoInfoHeader2.bmiHeader.biSizeImage = %d\n", InterVidHdr->VideoInfoHeader2.bmiHeader.biSizeImage)); break; } else { pSrb->Status = STATUS_BUFFER_TOO_SMALL; DebugOut((1, "AdapterFormatFromRange: Buffer too small\n")); return; } } // End of VIDEOINFOHEADER2 specifier // ------------------------------------------------------------------- // 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 pDataRangeVideo = (PKS_DATARANGE_ANALOGVIDEO) *pAvailableFormats; // MATCH FOUND! FormatSize = sizeof( KS_DATARANGE_ANALOGVIDEO ); if ( OnlyWantsSize ) { break; } // Caller wants the full data format if ( IntersectInfo->SizeOfDataFormatBuffer < FormatSize ) { pSrb->Status = STATUS_BUFFER_TOO_SMALL; DebugOut((1, "AdapterFormatFromRange: Buffer too small\n")); return; } RtlCopyMemory( IntersectInfo->DataFormatBuffer, pDataRangeVideo, sizeof( KS_DATARANGE_ANALOGVIDEO ) ); ((PKSDATAFORMAT)IntersectInfo->DataFormatBuffer)->FormatSize = FormatSize; break; } else { if ( IsEqualGUID( DataRange->Specifier, KSDATAFORMAT_SPECIFIER_VBI ) ) { PKS_DATARANGE_VIDEO_VBI pDataRangeVBI = (PKS_DATARANGE_VIDEO_VBI)*pAvailableFormats; FormatSize = sizeof( KS_DATAFORMAT_VBIINFOHEADER ); if ( OnlyWantsSize ) { break; } // Caller wants the full data format if ( IntersectInfo->SizeOfDataFormatBuffer < FormatSize ) { pSrb->Status = STATUS_BUFFER_TOO_SMALL; DebugOut((1, "AdapterFormatFromRange: Buffer too small\n")); return; } // Copy over the KSDATAFORMAT, followed by the // actual VideoInfoHeader PKS_DATAFORMAT_VBIINFOHEADER InterVBIHdr = (PKS_DATAFORMAT_VBIINFOHEADER)IntersectInfo->DataFormatBuffer; RtlCopyMemory( &InterVBIHdr->DataFormat, &pDataRangeVBI->DataRange, sizeof( KSDATARANGE ) ); ((PKSDATAFORMAT)IntersectInfo->DataFormatBuffer)->FormatSize = FormatSize; RtlCopyMemory( &InterVBIHdr->VBIInfoHeader, &pDataRangeVBI->VBIInfoHeader, sizeof( KS_VBIINFOHEADER ) ); break; } else { DebugOut(( 0, "AdapterFormatFromRange: STATUS_NO_MATCH\n" )); pSrb->Status = STATUS_NO_MATCH; return; } } } // End of loop on all formats for this stream if ( OnlyWantsSize ) { DebugOut(( 2, "AdapterFormatFromRange: only wants size\n" )); *(PULONG) IntersectInfo->DataFormatBuffer = FormatSize; pSrb->ActualBytesTransferred = sizeof( ULONG ); return; } pSrb->ActualBytesTransferred = FormatSize; DebugOut(( 2, "AdapterFormatFromRange: done\n" )); return; }