// $Header: G:/SwDev/WDM/Video/bt848/rcs/Device.cpp 1.18 1998/05/13 14:44:33 tomz Exp $ #include "device.h" #include "capmain.h" const I2C_Offset = 0x110; const GPIO_Cntl_Offset = 0x10D; const GPIO_OutputOffset = 0x118; const GPIO_DataOffset = 0x200; // Global functions/data exposing public class info to the "C" modules PsDevice *gpPsDevice = NULL; BYTE *gpjBaseAddr = NULL; VOID *gpHwDeviceExtension = NULL; DWORD GetSizeHwDeviceExtension( ) { return ( sizeof( HW_DEVICE_EXTENSION ) + sizeof( PsDevice )); } DWORD GetSizeStreamEx( ) { // return the size of the largest possible channel object DWORD dwMax = sizeof( VBIChannel ); dwMax = max( dwMax, sizeof( AlterVideoChannel )); dwMax = max( dwMax, sizeof( InterVideoChannel )); DWORD dwReq = 2 * dwMax; // paired stuff has two of them together dwReq += sizeof( STREAMEX ); return ( dwReq ); } /* Function: GetDeviceExt * Purpose: Used in creation of risc programs to obtain physical addresses */ PsDevice *GetCurrentDevice() { // This is only used for I2C stuff. Remove this ASAP. return gpPsDevice; } /* Function: SetCurrentDevice * Purpose: Remembers the currently active device * Input: PsDevice * * Output: None */ void SetCurrentDevice( PsDevice *dev ) { // This is only used for I2C stuff. Remove this ASAP. gpPsDevice = dev; } /* Function: GetBase * Purpose: Returns the base address of the currently active device * Input: None * Output: LPBYTE */ BYTE *GetBase() { return gpjBaseAddr; } /* Function: SetBase * Purpose: Remembers the base address of the currently active device * Input: None * Output: LPBYTE */ void SetBase(BYTE *base) { gpjBaseAddr = base; } PsDevice::PsDevice( DWORD dwBase ) : BaseAddress_( (LPBYTE)dwBase ), LastFreq_( 0 ), dwCurCookie_( 0 ), I2CAddr_( 0 ), xBar( PinTypes_ ), CaptureContrll_( xtals_ ) { SetCurrentDevice ( this ); for ( int i = 0; i < (sizeof(videochannels)/sizeof(videochannels[0])); i++ ) { videochannels [i] = 0; } I2CIsInitOK(); #ifdef HARDWAREI2C I2CInitHWMode( 100000 ); // assume frequency = 100Khz #else I2CInitSWMode( 100000 ); // assume frequency = 100Khz I2CSWStart(); I2CSWStop(); #endif GPIOIsInitOK(); DebugOut((0, "*** Base Address = %x\n", BaseAddress_)); } PsDevice::~PsDevice() { for ( int i = 0; i < (sizeof(videochannels)/sizeof(videochannels[0])); i++ ) { VideoChannel *pvcTemp = videochannels [i]; videochannels [i] = NULL; delete pvcTemp; } } /* Method: PsDevice::AddBuf * Purpose: Adds next buffer to be used to the queue * Input: VideoChan: VxDVideoChannel & * pBufAddr: PVOID - address of the next buffer * Output: None */ void PsDevice::AddBuffer( VideoChannel &VideoChan, PHW_STREAM_REQUEST_BLOCK pSrb ) { // bogus channel, bye-bye if ( !IsOurChannel( VideoChan ) ) { DebugOut((0, "PsDevice::Addbuffer - not our channel (pSrb=%x) (&VideoChan=%x)\n", pSrb, &VideoChan ) ); return; } DebugOut((1, "PsDevice::Addbuffer - adding (pSrb=%x) (&VideoChan=%x)\n", pSrb, &VideoChan ) ); VideoChan.AddSRB( pSrb ); } void PsDevice::Start( VideoChannel &VidChan ) { VidChan.Start(); } void PsDevice::Pause( VideoChannel &VidChan ) { *(DWORD*)(gpjBaseAddr+0x10c) &= ~3; // disable interrupts [TMZ] [!!!] // [TMZ] [!!!] for ( int i = 0; i < (sizeof(videochannels)/sizeof(videochannels[0])); i++ ) { if ( videochannels[i] == &VidChan ) { DebugOut((1, "'PsDevice::Pause called on videochannels[%d]\n", i)); } } VidChan.Pause(); } /* Method: PsDevice::Create * Purpose: Calls into the channel ( stream ) to create RISC programs for it. * Input: VideoChan: VxDVideoChannel & * Parms: StartParms &, parameters to create stream with * Output: ErrorCode */ ErrorCode PsDevice::Create( VideoChannel &VidChan ) { return VidChan.Create(); } /* Method: PsDevice::Stop * Purpose: Adds next buffer to be used to the queue * Input: VideoChan: VxDVideoChannel & * Output: None */ void PsDevice::Stop( VideoChannel &VidChan ) { *(DWORD*)(gpjBaseAddr+0x10c) &= ~3; // disable interrupts [TMZ] [!!!] VidChan.Stop(); } #if NEED_CLIPPING /* Method: PsDevice::SetClipping * Purpose: Propagates the call down a video channel * Input: VideoChan: VxDVideoChannel & - reference * dwData: DWORD - a pointer to RGNDATA in reality * Output: None */ void PsDevice::SetClipping( VideoChannel &VidChan, const RGNDATA & rgnData ) { if ( !rgnData.rdh.nCount ) return; if ( FullSizeChannel_ ) { // have to decrese hight of all rectangles in half and decrease top in half unsigned i; for ( i = 0; i < rgnData.rdh.nCount; i++ ) { TRect *lpR = (TRect *)rgnData.Buffer + i; // make all even lpR->top++; lpR->top &= ~1; lpR->bottom++; lpR->bottom &= ~1; lpR->top /= 2; lpR->bottom /= 2; } FullSizeChannel_->SetClipping( rgnData ); SlaveChannel_ ->SetClipping( rgnData ); } else VidChan.SetClipping( rgnData ); } #endif /* Method: PsDevice::IsVideoChannel * Purpose: */ bool PsDevice::IsVideoChannel( VideoChannel &aChan ) { return bool( &aChan == videochannels [VS_Field1] || &aChan == videochannels [VS_Field2] ); } /* Method: PsDevice::IsVBIChannel * Purpose: */ bool PsDevice::IsVBIChannel( VideoChannel &aChan ) { return bool( &aChan == videochannels [VS_VBI1] || &aChan == videochannels [VS_VBI2] ); } /* Method: PsDevice::IsOurChannel * Purpose: Verifies the channel * Input: aChan: VideoChannel &, reference to a channel * Output: true if our, false otherwise */ bool PsDevice::IsOurChannel( VideoChannel &aChan ) { return IsVideoChannel( aChan ) || IsVBIChannel( aChan ); } /* Method: PsDevice::DoOpen * Purpose: This function performs opening of a video channel * Input: st: VideoStream, stream to open * Output: ErrorCode */ ErrorCode PsDevice::DoOpen( VideoStream st ) { DebugOut((1, "PsDevice::DoOpen(%d)\n", st)); if ( !videochannels [st] ) { DebugOut((1, " PsDevice::DoOpen(%d) failed - videochannel not created\n", st)); return Fail; } videochannels [st]->Init( &CaptureContrll_ ); if ( videochannels [st]->OpenChannel() != Success ) { DebugOut((1, " PsDevice::DoOpen(%d) failed - videochannel open failed\n", st)); VideoChannel *pvcTemp = videochannels [st]; videochannels [st] = NULL; delete pvcTemp; return Fail; } return Success; } /* Method: PsDevice::OpenChannel * Purpose: This function opens a channel requested by the capture driver * Input: hVM: VMHANDLE - handle of the VM making a call * pRegs: CLIENT_STRUCT * - pointer to the structure with VM's registers * Output: None */ ErrorCode PsDevice::OpenChannel( PVOID pStrmEx, VideoStream st ) { PVOID addr = &((PSTREAMEX)pStrmEx)->videochannelmem[0]; ((PSTREAMEX)pStrmEx)->videochannel = addr; DebugOut((1, "PsDevice::OpenChannel(%x,%d)\n", addr, st)); if ( videochannels [st] ) { DebugOut((1, " PsDevice::OpenChannel(%x,%d) failed - already open\n", addr, st)); return Fail; } videochannels[st] = new( addr ) VideoChannel( st ); videochannels[st]->SetStrmEx( pStrmEx ) ; DebugOut((1, " PsDevice::OpenChannel(%x,%d), videochannels[%d] = %x\n", addr, st, st, videochannels[st])); return DoOpen( st ); } /* Method: PsDevice::OpenInterChannel * Purpose: This function opens video channel that produces interleaved fields * Input: addr: PVOID, address for the palcement new * st: VideoStream, stream to open ( VBI or video ) * Output: None */ ErrorCode PsDevice::OpenInterChannel( PVOID pStrmEx, VideoStream st ) { PVOID addr = &((PSTREAMEX)pStrmEx)->videochannelmem[0]; ((PSTREAMEX)pStrmEx)->videochannel = addr; DebugOut((1, "PsDevice::OpenInterChannel(%x,%d)\n", addr, st)); // only odd channel can be paired if ( !( st & 1 ) || videochannels [st] || videochannels [st-1] ) { DebugOut((1, " PsDevice::OpenInterChannel(%x,%d) failed - stream not odd or already open\n", addr, st)); return Fail; } if ( OpenChannel( (PBYTE)addr + sizeof( InterVideoChannel ), VideoStream( st - 1 ) ) == Success ) { videochannels[st] = new( addr ) InterVideoChannel( st, *videochannels [st-1] ); videochannels[st]->SetStrmEx( pStrmEx ) ; if ( DoOpen( st ) != Success ) { DebugOut((1, " PsDevice::OpenInterChannel(%x,%d) failed - DoOpen failed\n", addr, st)); CloseChannel( videochannels [st-1] ); return Fail; } } else { DebugOut((1, " PsDevice::OpenInterChannel(%x,%d) failed - OpenChannel failed\n", addr, st)); return Fail; } return Success; } /* Method: PsDevice::OpenAlterChannel * Purpose: This function opens video channel that produces alternating fields * Input: addr: PVOID, address for the palcement new * st: VideoStream, stream to open ( VBI or video ) * Output: None */ ErrorCode PsDevice::OpenAlterChannel( PVOID pStrmEx, VideoStream st ) { PVOID addr = &((PSTREAMEX)pStrmEx)->videochannelmem[0]; ((PSTREAMEX)pStrmEx)->videochannel = addr; DebugOut((1, "PsDevice::OpenAlterChannel(%x,%d)\n", addr, st)); // only odd channel can be paired if ( !( st & 1 ) || videochannels [st] || videochannels [st-1] ) { DebugOut((1, " PsDevice::OpenAlterChannel(%x,%d) failed - stream not odd or already open\n", addr, st)); return Fail; } if ( OpenChannel( (PBYTE)addr + sizeof( AlterVideoChannel ), VideoStream( st -1 ) ) == Success ) { videochannels[st] = new( addr ) AlterVideoChannel( st, *videochannels [st-1] ); videochannels[st]->SetStrmEx( pStrmEx ) ; videochannels[st-1]->SetStrmEx( pStrmEx ) ; if ( DoOpen( st ) != Success ) { DebugOut((1, " PsDevice::OpenAlterChannel(%x,%d) failed - DoOpen failed\n", addr, st)); CloseChannel( videochannels [st-1] ); return Fail; } } else { DebugOut((1, " PsDevice::OpenAlterChannel(%x,%d) failed - OpenChannel failed\n", addr, st)); return Fail; } return Success; } /* Method: PsDevice::OpenVBIChannel * Purpose: This function opens video channel that produces alternating fields * Input: addr: PVOID, address for the palcement new * st: VideoStream, stream to open ( VBI or video ) * Output: None */ ErrorCode PsDevice::OpenVBIChannel( PVOID pStrmEx ) { PVOID addr = &((PSTREAMEX)pStrmEx)->videochannelmem[0]; ((PSTREAMEX)pStrmEx)->videochannel = addr; DebugOut((1, "PsDevice::OpenVBIChannel(%x)\n", addr)); if ( videochannels [VS_VBI1] || videochannels [VS_VBI2] ) { DebugOut((1, " PsDevice::OpenVBIChannel(%x) failed - already open\n", addr)); return Fail; } VBIChannel *tmp = new( (PBYTE)addr + sizeof( VBIAlterChannel ) ) VBIChannel( VS_VBI1 ); videochannels [VS_VBI1] = tmp; DebugOut((1, " PsDevice::OpenVBIChannel(%x), videochannels[VS_VBI1(%d)] = %x\n", addr, VS_VBI1, videochannels[VS_VBI1])); if ( !tmp ) { DebugOut((1, " PsDevice::OpenVBIChannel(%x) failed - new VBIChannel failed\n", addr)); return Fail; } if ( DoOpen( VS_VBI1 ) != Success ) { DebugOut((1, " PsDevice::OpenVBIChannel(%x) failed - DoOpen(VS_VBI1) failed\n", addr)); return Fail; } videochannels [VS_VBI2] = new( addr ) VBIAlterChannel( VS_VBI2, *tmp ); DebugOut((1, " PsDevice::OpenVBIChannel(%x), videochannels[VS_VBI2(%d)] = %x\n", addr, VS_VBI2, videochannels[VS_VBI2])); if (!videochannels [VS_VBI2]) { DebugOut((1, " PsDevice::OpenVBIChannel(%x) failed - new VBIAlterChannel failed\n", addr)); return Fail; } if ( DoOpen( VS_VBI2 ) != Success ) { DebugOut((1, " PsDevice::OpenVBIChannel(%x) failed - DoOpen(VS_VBI1) failed\n", addr)); CloseChannel( videochannels [VS_VBI1] ); return Fail; } videochannels[VS_VBI1]->SetStrmEx( pStrmEx ) ; videochannels[VS_VBI2]->SetStrmEx( pStrmEx ) ; return Success; } /* Method: PsDevice::CloseChannel * Purpose: Closes a video channel * Input: ToClose: VideoChannel * * Output: None */ void PsDevice::CloseChannel( VideoChannel *ToClose ) { *(DWORD*)(gpjBaseAddr+0x10c) &= ~3; // disable interrupts [TMZ] [!!!] DebugOut((1, "PsDevice::CloseChannel(%x)\n", ToClose)); if ( IsOurChannel( *ToClose ) ) { // this is a bit ugly solution to make CLOSE_STREAM SRB clean if ( ToClose->GetStreamType() == Single ) { VideoStream st = ToClose->GetStreamID(); DebugOut((1, " PsDevice::CloseChannel(%x) - closing single channel (stream == %d)\n", ToClose, st)); VideoChannel * pvcTemp = videochannels [st]; videochannels [st] = NULL; delete pvcTemp; } else { DebugOut((1, " PsDevice::CloseChannel(%x) - closing paired channel\n", ToClose)); ClosePairedChannel( ToClose ); } } else { DebugOut((1, " PsDevice::CloseChannel(%x) ignored - not our channel\n", ToClose)); } } /* Method: PsDevice::ClosePairedChannel * Purpose: This function opens a channel requested by the capture driver * Input: hVM: VMHANDLE - handle of the VM making a call * pRegs: CLIENT_STRUCT * - pointer to the structure with VM's registers * Output: None */ void PsDevice::ClosePairedChannel( VideoChannel *ToClose ) { *(DWORD*)(gpjBaseAddr+0x10c) &= ~3; // disable interrupts [TMZ] [!!!] DebugOut((1, "PsDevice::ClosePairedChannel(%x)\n", ToClose)); if ( IsOurChannel( *ToClose ) ) { VideoStream st = ToClose->GetStreamID(); DebugOut((1, " PsDevice::ClosePairedChannel(%x) - closing paired channel (stream == %d)\n", ToClose, st)); DebugOut((1, " PsDevice::ClosePairedChannel(%x) - streams[%d] = %x\n", ToClose, st, videochannels[st])); DebugOut((1, " PsDevice::ClosePairedChannel(%x) - streams[%d] = %x\n", ToClose, st-1, videochannels[st-1])); VideoChannel *pvcTemp; pvcTemp = videochannels [st]; videochannels [st] = NULL; delete pvcTemp; pvcTemp = videochannels [st-1]; videochannels [st-1] = NULL; delete pvcTemp; } else { DebugOut((1, " PsDevice::ClosePairedChannel(%x) ignored - not our channel\n", ToClose)); } } /* Method: PsDevice::SetSaturation * Purpose: * Input: * Output: None */ void PsDevice::SetSaturation( LONG Data ) { CaptureContrll_.SetSaturation( Data ); } /* Method: PsDevice::SetHue * Purpose: * Input: * Output: None */ void PsDevice::SetHue( LONG Data ) { CaptureContrll_.SetHue( Data ); } /* Method: PsDevice::SetBrightness * Purpose: * Input: * Output: None */ void PsDevice::SetBrightness( LONG Data ) { CaptureContrll_.SetBrightness( Data ); } /* Method: PsDevice::SetSVideo * Purpose: * Input: * Output: None */ void PsDevice::SetSVideo( LONG Data ) { CaptureContrll_.SetSVideo( Data ); } /* Method: PsDevice::SetContrast * Purpose: * Input: * Output: None */ void PsDevice::SetContrast( LONG Data ) { CaptureContrll_.SetContrast( Data ); } /* Method: PsDevice::SetFormat * Purpose: * Input: * Output: None */ void PsDevice::SetFormat( LONG Data ) { CaptureContrll_.SetFormat( Data ); // notify all video channels that video timing has changed LONG time = Data == KS_AnalogVideo_NTSC_M ? 333667 : 400000; for ( int i = 0; i < (sizeof(videochannels)/sizeof(videochannels[0])); i++ ) { if ( videochannels [i] ) { DebugOut((1, "PsDevice::SetFormat(%d) SetTimePerFrame on videochannels[%d]\n", Data, i)); videochannels [i]->SetTimePerFrame( time ); } } } /* Method: PsDevice::SetConnector * Purpose: * Input: * Output: None */ void PsDevice::SetConnector( LONG Data ) { CaptureContrll_.SetConnector( Data ); } /* Method: PsDevice::GetSaturation * Purpose: * Input: pData: PLONG * Output: None */ LONG PsDevice::GetSaturation() { return CaptureContrll_.GetSaturation(); } /* Method: PsDevice::GetHue * Purpose: * Input: pData: PLONG * Output: None */ LONG PsDevice::GetHue() { return CaptureContrll_.GetHue(); } /* Method: PsDevice::GetBrightness * Purpose: * Input: pData: PLONG * Output: None */ LONG PsDevice::GetBrightness() { return CaptureContrll_.GetBrightness(); } /* Method: PsDevice::GetSVideo * Purpose: * Input: pData: PLONG * Output: None */ LONG PsDevice::GetSVideo() { return CaptureContrll_.GetSVideo(); } /* Method: PsDevice::GetContrast * Purpose: * Input: pData: PLONG * Output: None */ LONG PsDevice::GetContrast() { return CaptureContrll_.GetContrast(); } /* Method: PsDevice::GetFormat * Purpose: * Input: pData: PLONG * Output: None */ LONG PsDevice::GetFormat() { return CaptureContrll_.GetFormat(); } /* Method: PsDevice::GetConnector * Purpose: * Input: pData: PLONG * Output: None */ LONG PsDevice::GetConnector() { return CaptureContrll_.GetConnector(); } /* Method: PsDevice::ChangeNotifyChannels * Purpose: Invoked to notify channels of some global changes */ void PsDevice::ChangeNotifyChannels( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { // We should only do this once per "system" stream. // Video streams don't seem to care. // That just leaves one VBI notification required videochannels [VS_VBI1]->ChangeNotification( pSrb ); } /* Method: PsDevice::GetSupportedStandards * Purpose: Obtains video standards device can support * Input: None * Output: LONG */ LONG PsDevice::GetSupportedStandards() { return CaptureContrll_.GetSupportedStandards(); } bool PsDevice::InitOK() { return CaptureContrll_.InitOK(); } #ifndef HARDWAREI2C //=========================================================================== // Bt848 software I2C stuff //=========================================================================== /* * If we build with software I2C then these routines fake the Hardware I2C routines * so the tuner code keeps working */ ErrorCode PsDevice::I2CHWRead( BYTE address, BYTE *value ) { ErrorCode error; error = I2CSWStart(); if(error) { return error; } error = I2CSWWrite( address | 0x01 ); if(error) { return error; } error = I2CSWRead( value ); if(error) { return error; } error = I2CSWSendNACK(); if(error) { return error; } error = I2CSWStop(); return error; } ErrorCode PsDevice::I2CHWWrite3( BYTE address, BYTE value1, BYTE value2 ) { ErrorCode error; error = I2CSWStart(); if(error) { return error; } error = I2CSWWrite( address ); if(error) { return error; } error = I2CSWWrite( value1 ); if(error) { return error; } error = I2CSWWrite( value2 ); if(error) { return error; } error = I2CSWStop(); return error; } #endif ////////////////////////////////////////////////////////////////// #ifdef __cplusplus extern "C" { #endif #include #ifdef __cplusplus } #endif // #include "capdebug.h" #define DEBUG_PRINT_PREFIX " ---: " // #define DEBUG_PRINT_PREFIX "bt848wdm: " long DebugLevel = 0; BOOL bNewLine = TRUE; extern "C" void MyDebugPrint(long DebugPrintLevel, char * DebugMessage, ... ) { if (DebugPrintLevel <= DebugLevel) { char debugPrintBuffer[256] ; va_list marker; va_start( marker, DebugMessage ); // Initialize variable arguments. vsprintf( debugPrintBuffer, DebugMessage, marker ); if( bNewLine ) { DbgPrint(("%s", DEBUG_PRINT_PREFIX)); } DbgPrint((debugPrintBuffer)); if( debugPrintBuffer[strlen(debugPrintBuffer)-1] == '\n') { bNewLine = TRUE; } else { bNewLine = FALSE; } va_end( marker ); // Reset variable arguments. } } #if TRACE_CALLS #define MAX_TRACE_DEPTH 10 unsigned long ulTraceDepth = 0; char achIndentBuffer[100]; char * IndentStr( ) { unsigned long ul = ulTraceDepth < MAX_TRACE_DEPTH ? ulTraceDepth : MAX_TRACE_DEPTH; unsigned long x; char * lpszBuf = achIndentBuffer; for( x = 0; x < ul; x++) { // indent two spaces per depth increment *lpszBuf++ = ' '; *lpszBuf++ = ' '; } sprintf (lpszBuf, "[%lu]", ulTraceDepth); return( achIndentBuffer ); } Trace::Trace(char *pszFunc) { psz = pszFunc; DebugOut((0, "%s %s\n", IndentStr(), psz)); ulTraceDepth++; } Trace::~Trace() { ulTraceDepth--; // DebugOut((0, "%s %s\n", IndentStr(), psz)); } #endif