|
|
// $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<VBIChannel> )); 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<VideoChannel> ), VideoStream( st -1 ) ) == Success ) { videochannels[st] = new( addr ) AlterVideoChannel<VideoChannel>( 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 <stdarg.h>
#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
|