windows-nt/Source/XPSP1/NT/drivers/wdm/capture/mini/bt848/pisces.cpp
2020-09-26 16:20:57 +08:00

1295 lines
36 KiB
C++

// $Header: G:/SwDev/WDM/Video/bt848/rcs/Pisces.cpp 1.15 1998/05/04 23:48:53 tomz Exp $
#include "pisces.h"
#include <stdlib.h>
/*
*/
BtPisces::BtPisces( DWORD *xtals ) : Engine_(), Inited_( false ),
Even_( CAPTURE_EVEN, VF_Even,&COLOR_EVEN, &WSWAP_EVEN, &BSWAP_EVEN ),
Odd_( CAPTURE_ODD, VF_Odd, &COLOR_ODD, &WSWAP_ODD, &BSWAP_ODD ),
VBIE_( CAPTURE_VBI_EVEN ), VBIO_( CAPTURE_VBI_ODD ), Update_( false ),
nSkipped_( 0 ), Paused_( false ),
Starter_( ),
SyncEvenEnd1_( ),
SyncEvenEnd2_( ),
SyncOddEnd1_( ),
SyncOddEnd2_( ),
PsDecoder_( xtals ),
dwPlanarAdjust_( 0 ),
CONSTRUCT_COLORCONTROL,
CONSTRUCT_INTERRUPTSTATUS,
CONSTRUCT_INTERRUPTMASK,
CONSTRUCT_CONTROL,
CONSTRUCT_CAPTURECONTROL,
CONSTRUCT_COLORFORMAT,
CONSTRUCT_GPIOOUTPUTENABLECONTROL,
CONSTRUCT_GPIODATAIO
{
Trace t("BtPisces::BtPisces()");
Init();
}
BtPisces::~BtPisces()
{
Trace t("BtPisces::~BtPisces()");
Engine_.Stop();
InterruptMask = 0;
InterruptStatus = AllFs;
// prevent risc program destructor from gpf-ing
SyncEvenEnd1_.SetParent( NULL );
SyncEvenEnd2_.SetParent( NULL );
SyncOddEnd1_.SetParent( NULL );
SyncOddEnd2_.SetParent( NULL );
// free the association array now
int ArrSize = sizeof( InterruptToIdx_ ) / sizeof( InterruptToIdx_ [0] );
while ( --ArrSize >= 0 )
delete InterruptToIdx_ [ArrSize];
// now is the Skippers_' turn
ArrSize = sizeof( Skippers_ ) / sizeof( Skippers_ [0] );
while ( --ArrSize >= 0 )
delete Skippers_ [ArrSize];
}
/* Method: BtPisces::GetIdxFromStream
* Purpose: Returns starting index in the program array for a field
* Input: aStream: StreamInfo & - reference
* Output: int : Index
*/
int BtPisces::GetIdxFromStream( Field &aStream )
{
Trace t("BtPisces::GetIdxFromStream()");
switch ( aStream.GetStreamID() ) {
case VS_Field1:
return OddStartLocation;
case VS_Field2:
return EvenStartLocation;
case VS_VBI1:
return VBIOStartLocation;
case VS_VBI2:
return VBIEStartLocation;
default:
return 0;
}
}
/* Method: BtPisces::CreateSyncCodes
* Purpose: Creates the risc programs with sync codes needed between data risc
* programs
* Input: None
* Output: ErrorCode
*/
bool BtPisces::CreateSyncCodes()
{
Trace t("BtPisces::CreateSyncCodes()");
bool bRet = SyncEvenEnd1_.Create( SC_VRE ) == Success &&
SyncEvenEnd2_.Create( SC_VRE ) == Success &&
SyncOddEnd1_.Create( SC_VRO ) == Success &&
SyncOddEnd2_.Create( SC_VRO ) == Success &&
Starter_.Create( SC_VRO ) == Success;
DebugOut((1, "*** BtPisces::CreateSyncCodes SyncEvenEnd1_(%x)\n", &SyncEvenEnd1_));
DebugOut((1, "*** BtPisces::CreateSyncCodes SyncEvenEnd2_(%x)\n", &SyncEvenEnd2_));
DebugOut((1, "*** BtPisces::CreateSyncCodes SyncOddEnd1_(%x)\n", &SyncOddEnd1_));
DebugOut((1, "*** BtPisces::CreateSyncCodes SyncOddEnd2_(%x)\n", &SyncOddEnd2_));
DebugOut((1, "*** BtPisces::CreateSyncCodes Starter_(%x)\n", &Starter_));
return( bRet );
}
/* Method: BtPisces::Init
* Purpose: Performs all necessary initialization
* Input: None
* Output: None
*/
void BtPisces::Init()
{
Trace t("BtPisces::Init()");
InterruptStatus = AllFs;
InterruptStatus = 0;
GAMMA = 1;
// initialize the arrays
CreatedProgs_.Clear() ;
ActiveProgs_.Clear() ;
// fill in the skippers array and make each program a 'skipper'
DataBuf buf;
// [!!!] [TMZ]
// Engine_.CreateProgram constants look questionable
for ( int i = 0; i < sizeof( Skippers_ ) / sizeof( Skippers_ [0] ); i++ ) {
if ( i & 1 ) {
MSize s( 10, 10 );
Skippers_ [i] = Engine_.CreateProgram( s, 10 * 2, CF_VBI, buf, true, 0, false );
DebugOut((1, "Creating Skipper[%d] == %x\n", i, Skippers_[i]));
Engine_.Skip( Skippers_ [i] );
} else {
MSize s( 768, 12 );
// now create skippers for the VBI streams
Skippers_ [i] = Engine_.CreateProgram( s, 768 * 2, CF_VBI, buf, true, 0, false );
DebugOut((1, "Creating Skipper[%d] == %x\n", i, Skippers_[i]));
}
if ( !Skippers_ [i] )
return;
}
// create associations between Created and Skippers
int link = 0;
for ( i = 0; i < sizeof( SkipperIdxArr_ ) / sizeof( SkipperIdxArr_ [0] ); i++ ) {
SkipperIdxArr_ [i] = link;
i += link & 1; // advance past the sync program entry
link++;
}
// fill in constant elements; see the table in the .h file
CreatedProgs_ [2] = &SyncOddEnd1_;
CreatedProgs_ [8] = &SyncOddEnd2_;
CreatedProgs_ [5] = &SyncEvenEnd1_;
CreatedProgs_ [11] = &SyncEvenEnd2_;
// set corresponding sync bits
if ( !CreateSyncCodes() )
return;
// initialize association array now
int ArrSize = sizeof( InterruptToIdx_ ) / sizeof( InterruptToIdx_ [0] );
while ( --ArrSize >= 0 ) {
if ( ( InterruptToIdx_ [ArrSize] = new IntrIdxAss() ) == 0 )
return;
}
Even_.SetFrameRate( 333667 );
Odd_. SetFrameRate( 333667 );
VBIE_.SetFrameRate( 333667 );
VBIO_.SetFrameRate( 333667 );
Odd_. SetStreamID( VS_Field1 );
Even_.SetStreamID( VS_Field2 );
VBIO_.SetStreamID( VS_VBI1 );
VBIE_.SetStreamID( VS_VBI2 );
// finally, can wipe out the prespiration from the forehead
Inited_ = true;
}
/* Method: BtPisces::AssignIntNumbers
* Purpose: Assigns numbers to RISC programs that generate interrupt
* Input: None
* Output: None
*/
void BtPisces::AssignIntNumbers()
{
Trace t("BtPisces::AssignIntNumbers()");
int IntrCnt = 0;
int limit = ActiveProgs_.NumElements() ;
int idx;
// initialize InterruptToIdx_ array
for ( idx = 0; idx < limit; idx++ ) {
IntrIdxAss item( idx, -1 );
*InterruptToIdx_ [idx] = item;
}
// assign numbers in front of starting program
bool first = true;
for ( idx = 0; idx < (int) ActiveProgs_.NumElements() ; idx++ ) {
RiscPrgHandle pProg = ActiveProgs_ [idx];
//if not skipped and generates an interrupt assign number
if ( pProg && pProg->IsInterrupting() ) {
if ( first == true ) {
first = false;
pProg->ResetStatus();
Skippers_ [SkipperIdxArr_ [idx] ]->ResetStatus();
} else {
pProg->SetToCount();
Skippers_ [SkipperIdxArr_ [idx] ]->SetToCount();
}
IntrIdxAss item( IntrCnt, idx );
*InterruptToIdx_ [IntrCnt] = item;
IntrCnt++;
}
}
}
/* Method: BtPisces::LinkThePrograms
* Purpose: Creates links between the created programs
* Input: None
* Output: None
*/
void BtPisces::LinkThePrograms()
{
Trace t("BtPisces::LinkThePrograms()");
DebugOut((1, "*** Linking Programs\n"));
RiscPrgHandle hParent = ActiveProgs_.First(),
hChild = NULL,
hVeryFirst = NULL,
hLastChild = NULL ;
if (hParent) {
if ( hParent->IsSkipped() ) {
int idx = ActiveProgs_.GetIndex(hParent) ;
hParent = Skippers_ [SkipperIdxArr_ [idx] ] ;
}
while (hParent) {
if (!hVeryFirst)
hVeryFirst = hParent ;
if ( hChild = ActiveProgs_.Next()) {
if ( hChild->IsSkipped() ) {
int idx = ActiveProgs_.GetIndex(hChild) ;
hChild = Skippers_ [SkipperIdxArr_ [idx] ] ;
}
hLastChild = hChild;
Engine_.Chain( hParent, hChild ) ;
}
hParent = hChild ;
}
// initial jump
Engine_.Chain( &Starter_, hVeryFirst ) ;
// now create the loop
Engine_.Chain( hLastChild ? hLastChild : hVeryFirst, hVeryFirst ) ;
}
}
/* Method: BtPisces::ProcessSyncPrograms()
* Purpose: This function unlinks the helper sync programs
* Input: None
* Output: None
*/
void BtPisces::ProcessSyncPrograms()
{
Trace t("BtPisces::ProcessSyncPrograms()");
for ( int i = 0; i < (int) ActiveProgs_.NumElements(); i += ProgsWithinField ) {
if ( !ActiveProgs_ [i] && !ActiveProgs_ [i+1] ) {
ActiveProgs_ [i+2] = NULL;
} else {
ActiveProgs_ [i+2] = CreatedProgs_ [i+2];
}
}
}
/* Method: BtPisces::ProcessPresentPrograms
* Purpose:
* Input: None
* Output: None
*/
void BtPisces::ProcessPresentPrograms()
{
Trace t("BtPisces::ProcessPresentPrograms()");
// link in/out helper sync programs
ProcessSyncPrograms();
// and now is time to cross link the programs
LinkThePrograms();
// and now figure out the numbers programs use for interrupts
AssignIntNumbers();
}
/* Method: BtPisces::AddProgram
* Purpose: Creates new RISC program and inserts it in the chain at a proper place
* Input: aStream: StreamInfo & - reference to the stream to add a program for
* NumberToAdd: int - number of programs to add
* Output:
* Note: Basically this internal function performs a loop 2 times
* //4. Tries to get another buffer to establish double buffering
* //5. If buffer is available it creates another RISC program with it
* //6. Then it has to link the program in...
*/
RiscPrgHandle BtPisces::AddProgram( Field &ToStart, int NumberToAdd )
{
Trace t("BtPisces::AddProgram()");
DebugOut((1, "BtPisces::AddProgram()\n"));
int StartIdx = GetIdxFromStream( ToStart );
SyncCode Sync;
int SyncIdx;
bool rsync;
if ( StartIdx <= OddStartLocation ) {
Sync = SC_VRO;
SyncIdx = OddSyncStartLoc;
rsync = false;
} else {
Sync = SC_VRE;
SyncIdx = EvenSyncStartLoc;
rsync = bool( StartIdx == EvenStartLocation );
}
// have to know what is the size of the image to produce
MRect r;
ToStart.GetDigitalWindow( r );
// RISC engine operates on absolute sizes, not rectangles
MSize s = r.Size();
int BufCnt = 0;
int Idx = StartIdx;
for ( ; BufCnt < NumberToAdd; BufCnt++ ) {
// init sync programs with a premise tha no data program exists
CreatedProgs_ [SyncIdx]->Create( Sync, true );
// obtain the next buffer from queue ( entry is removed from container )
DataBuf buf = ToStart.GetNextBuffer();
// can create a RISC program now.
RiscPrgHandle hProgram = Engine_.CreateProgram( s, ToStart.GetBufPitch(),
ToStart.GetColorFormat(), buf, ToStart.Interrupt_, dwPlanarAdjust_, rsync );
// store this program
CreatedProgs_ [Idx] = hProgram;
DebugOut((1, "Creating RiscProgram[%d] == %x\n", Idx, CreatedProgs_ [Idx]));
if ( !hProgram ) {
Idx -= DistBetweenProgs;
if ( Idx >= 0 ) {
// clean up previous program
Engine_.DestroyProgram( CreatedProgs_ [Idx] );
CreatedProgs_ [Idx] = NULL;
}
return NULL;
}
// make sure we unskip the program when buffer becomes available
if ( !buf.pData_ ) {
hProgram->SetSkipped(); // do not have enough buffers to support double buffering
nSkipped_++;
}
// assign stream to program; makes it easy during interrupt
hProgram->SetTag( &ToStart );
SyncIdx += DistBetweenProgs;
Idx += DistBetweenProgs; // skip the location intended for the other program
} /* endfor */
return CreatedProgs_ [StartIdx];
}
/* Method: BtPisces::Create
* Purpose: This functions starts the stream.
* Input: aStream: StreamInfo & - reference to a stream to start
* Output: Address of the Starter_
* Note: After the Start 2 entries in the CreatedProgs_ are created. Starting
* location is 4 for even and 1 for odd. Increment is 6. So if it is the first
* invocation and there is enough ( 2 ) buffers present entries [1] and [7]
* or [4] and [10] will be filled with newly created RISC programs. When programs
* exist for one field only they are doubly linked. When programs exist for
* both fields they alternate, i.e. 0->2->1->3->0... When one of the fields
* has 1 program only, programs are linked like this: 0->2->1->0->2...(numbers
* are indexes in the CreatedProgs_ array ). Alternating programs makes for
* maximum frame rate.
*/
ErrorCode BtPisces::Create( Field &ToCreate )
{
Trace t("BtPisces::Create()");
// running full-steam, nothing to create
if ( ToCreate.IsStarted() == true )
return Success;
int StartIdx = GetIdxFromStream( ToCreate );
if ( CreatedProgs_ [StartIdx] )
return Success; // not running yet, but exists
// call into internal function that adds new RISC program
if ( ! AddProgram( ToCreate, MaxProgsForField ) )
return Fail;
return Success;
}
/* Method: BtPisces::Start
* Purpose: Starts given stream ( by putting in in the Active_ array
* Input: ToStart: Field &
*/
void BtPisces::Start( Field & ToStart )
{
Trace t("BtPisces::Start()");
// DebugOut((1, "BtPisces::Start\n"));
if ( ToStart.IsStarted() == true )
return;
// all we need to do at this point is to create a proper starter
// and link the programs in.
int idx = GetIdxFromStream( ToStart );
// this loop will enable LinkThePrograms to see programs for this stream
for ( int i = 0; i < MaxProgsForField; i++, idx += DistBetweenProgs ) {
ActiveProgs_ [idx] = CreatedProgs_ [idx];
}
// all I want to do at this point is call Restart.
// do not signal the buffers
Update_ = false;
Restart();
Update_ = true;
}
/* Method: BtPisces::Stop
* Purpose: This function stops a stream. Called when PAUSE SRB is received
* Input: aStream: StreamInfo & - reference to a stream to start
* Output: None
*/
void BtPisces::Stop( Field &ToStop )
{
Trace t("BtPisces::Stop()");
// DebugOut((1, "BtPisces::Stop\n"));
Engine_.Stop(); // no more interrupts
int StartIdx = GetIdxFromStream( ToStop );
// prevent unneeded syncronization interrupts
IMASK_SCERW = 0;
// it is time to pause the stream now
ToStop.Stop();
bool Need2Restart = false;
// go through the array of programs and killing ones for this field (stream)
for ( int i = 0; i < MaxProgsForField; i++, StartIdx += DistBetweenProgs ) {
RiscPrgHandle ToDie = CreatedProgs_ [StartIdx];
if ( !ToDie ) // this should never happen
continue;
if ( ToDie->IsSkipped() )
nSkipped_--;
DebugOut((1, "about to destroy idx = %d\n", StartIdx ) );
Engine_.DestroyProgram( ToDie );
CreatedProgs_ [StartIdx] = NULL;
ActiveProgs_ [StartIdx] = NULL; // in case Pause wasn't called
Need2Restart = true;
} /* endfor */
// nobody's around anymore
if ( !CreatedProgs_.CountDMAProgs() ) {
Engine_.Stop();
InterruptMask = 0;
InterruptStatus = AllFs;
nSkipped_ = 0;
} else {
if ( Need2Restart ) {
Restart(); // relink the programs and start ones that are alive
IMASK_SCERW = 1; // re-enable the sync error interrupts
}
}
}
/* Method: BtPisces::Pause
* Purpose: This function stops a stream. Called when PAUSE SRB is received
* Input: aStream: Field & - reference to a stream to start
* Output: None
*/
void BtPisces::Pause( Field &ToPause )
{
Trace t("BtPisces::Pause()");
// DebugOut((1, "BtPisces::Pause\n"));
Engine_.Stop(); // no more interrupts
if ( !ToPause.IsStarted() )
return;
int StartIdx = GetIdxFromStream( ToPause );
// prevent unneeded syncronization interrupts
IMASK_SCERW = 0;
// it is time to pause the stream now
// ToPause.Stop(); - done in Restart
// go through the array of programs and killing ones for this field (stream)
for ( int i = 0; i < MaxProgsForField; i++, StartIdx += DistBetweenProgs ) {
ActiveProgs_ [StartIdx] = NULL;
} /* endfor */
Restart(); // relink the programs and start ones that are alive
}
/* Method: BtPisces::PairedPause
* Purpose: This is a hacky function that pauses 2 streams at once
* Input: idx: index of the second program in the second field
* Output: None
*/
void BtPisces::PairedPause( int idx )
{
Trace t("BtPisces::PairedPause()");
// DebugOut((1, "BtPisces::PairedPause\n"));
Engine_.Stop(); // no more interrupts
// go through the array of programs and killing ones for this field (stream)
for ( int i = 0; i < MaxProgsForField; i++, idx -= DistBetweenProgs ) {
ActiveProgs_ [idx] = NULL;
ActiveProgs_ [idx-ProgsWithinField] = NULL;
} /* endfor */
Restart(); // relink the programs and start ones that are alive
}
/* Method: BtPisces::GetStarted
* Purpose: Figures out the channels that are started
* Input:
* Output: None
*/
void BtPisces::GetStarted( bool &EvenWasStarted, bool &OddWasStarted,
bool &VBIEWasStarted, bool &VBIOWasStarted )
{
Trace t("BtPisces::GetStarted()");
VBIEWasStarted = ( ActiveProgs_ [VBIEStartLocation] ? TRUE : FALSE);
EvenWasStarted = ( ActiveProgs_ [EvenStartLocation] ? TRUE : FALSE);
VBIOWasStarted = ( ActiveProgs_ [VBIOStartLocation] ? TRUE : FALSE);
OddWasStarted = ( ActiveProgs_ [OddStartLocation] ? TRUE : FALSE);
}
/* Method: BtPisces::RestartStreams
* Purpose: Restarts streams that were started
* Input:
* Output: None
*/
void BtPisces::RestartStreams( bool EvenWasStarted, bool OddWasStarted,
bool VBIEWasStarted, bool VBIOWasStarted )
{
Trace t("BtPisces::RestartStream()");
// vbi programs are first to execute, so enable them first
if ( VBIOWasStarted )
VBIO_.Start();
if ( OddWasStarted )
Odd_.Start();
if ( VBIEWasStarted )
VBIE_.Start();
if ( EvenWasStarted )
Even_.Start();
}
/* Method: BtPisces::CreateStarter
* Purpose: Creates proper sync code for the bootstrap program
* Input: EvenWasStarted: bool
* Output: None
*/
void BtPisces::CreateStarter( bool EvenWasStarted )
{
Trace t("BtPisces::CreateStarter()");
Starter_.Create( EvenWasStarted ? SC_VRE : SC_VRO, true );
DebugOut((1, "*** BtPisces::CreateStarter(%x) buf(%x)\n", &Starter_ , Starter_.GetPhysProgAddr( )));
}
/* Method: BtPisces::Restart
* Purpose: Restarts the capture process. Called by ISR and Stop()
* Input: None
* Output: None
*/
void BtPisces::Restart()
{
Trace t("BtPisces::Restart()");
bool EvenWasStarted, OddWasStarted, VBIEWasStarted, VBIOWasStarted;
GetStarted( EvenWasStarted, OddWasStarted, VBIEWasStarted, VBIOWasStarted );
DebugOut((2, "BtPisces::Restart - Even WasStarted (%d)\n", EvenWasStarted));
DebugOut((2, "BtPisces::Restart - Odd WasStarted (%d)\n", OddWasStarted));
DebugOut((2, "BtPisces::Restart - VBIE WasStarted (%d)\n", VBIEWasStarted));
DebugOut((2, "BtPisces::Restart - VBIO WasStarted (%d)\n", VBIOWasStarted));
Engine_.Stop(); // No more interrupts!
Odd_.Stop();
Even_.Stop();
VBIE_.Stop();
VBIO_.Stop();
Engine_.Stop(); // No more interrupts!
#if 1
if ( OddWasStarted )
{
Odd_.CancelSrbList();
}
if ( EvenWasStarted )
{
Even_.CancelSrbList();
}
if ( VBIEWasStarted )
{
VBIE_.CancelSrbList();
}
if ( VBIOWasStarted )
{
VBIO_.CancelSrbList();
}
#endif
// this will never happen, probably
if ( !EvenWasStarted && !OddWasStarted && !VBIEWasStarted && !VBIOWasStarted )
return;
InterruptStatus = AllFs; // clear all the status bits
CreateStarter( bool( EvenWasStarted || VBIEWasStarted ) );
ProcessPresentPrograms();
// DumpRiscPrograms();
Engine_.Start( Starter_ );
RestartStreams( EvenWasStarted, OddWasStarted, VBIEWasStarted, VBIOWasStarted );
OldIdx_ = -1;
InterruptMask = RISC_I | FBUS_I | OCERR_I | SCERR_I |
RIPERR_I | PABORT_I | EN_TRITON1_BUG_FIX;
}
/* Method: BtPisces::Skip
* Purpose: Forces a given program to be skipped by the RISC engine
* Input: ToSkip: RiscPrgHandle - program to be skipped
* Output: None
* Note: If the number of skipped programs equals total number of programs, the
* RISC engine is stopped
*/
void BtPisces::Skip( int idx )
{
Trace t("BtPisces::Skip()");
// get the program and skip it
RiscPrgHandle ToSkip = ActiveProgs_ [idx];
if ( ToSkip->IsSkipped() )
return;
ToSkip->SetSkipped();
nSkipped_++;
//skip by linking the Skipper_ in instead of the skippee
RiscPrgHandle SkipeeParent = ToSkip->GetParent();
RiscPrgHandle SkipeeChild = ToSkip->GetChild();
// get the skipper for this program
RiscPrgHandle pSkipper = Skippers_ [SkipperIdxArr_ [idx] ];
Engine_.Chain( pSkipper, SkipeeChild );
Engine_.Chain( SkipeeParent, pSkipper );
DebugOut((1, "BtPisces::Skipped %d Skipper %d\n", idx, SkipperIdxArr_ [idx] ) );
}
inline bool IsFirst( int idx )
{
Trace t("BtPisces::IsFirst()");
return bool( idx == OddStartLocation || idx == VBIOStartLocation ||
idx - DistBetweenProgs == OddStartLocation ||
idx - DistBetweenProgs == VBIOStartLocation );
}
inline bool IsLast( int idx )
{
Trace t("BtPisces::IsLast()");
return bool((idx == (VBIEStartLocation + DistBetweenProgs)) ||
(idx == (EvenStartLocation + DistBetweenProgs)));
}
/* Method: BtPisces::GetPassed
* Purpose: Calculates number of programs that have executed since last interrupt
* Input: None
* Output: int: number of passed
*/
int BtPisces::GetPassed()
{
Trace t("BtPisces::GetPassed()");
// figure out which RISC program caused an interrupt
int ProgCnt = RISCS;
int numActive = ActiveProgs_.CountDMAProgs() ;
if ( ProgCnt >= numActive ) {
DebugOut((1, "ProgCnt = %d, larger than created\n", ProgCnt ) );
}
// now see how many programs have interrupted since last time and process them all
if ( ProgCnt == OldIdx_ ) {
DebugOut((1, "ProgCnt is the same = %d\n", ProgCnt ) );
}
int passed;
if ( ProgCnt < OldIdx_ ) {
passed = numActive - OldIdx_ + ProgCnt; // you spin me like a record, baby - round, round...
} else
passed = ProgCnt - OldIdx_;
// The following line of code was VERY bad !!!
// This caused crashes when the system got busy and had interrupts backed up.
// if ( ProgCnt == OldIdx_ )
// passed = numActive;
OldIdx_ = ProgCnt;
return passed;
}
/* Method: BtPisces::GetProgram
* Purpose: Finds a RISC program based on its position
* Input: None
* Output: None
*/
inline RiscPrgHandle BtPisces::GetProgram( int pos, int &idx )
{
Trace t("BtPisces::GetProgram()");
int nActiveProgs = ActiveProgs_.CountDMAProgs( );
if ( nActiveProgs == 0 )
{
idx = 0;
return ( NULL );
}
IntrIdxAss *item;
item = InterruptToIdx_ [ pos % nActiveProgs ];
idx = item->Idx;
DEBUG_ASSERT( idx != -1 );
return (idx == -1) ? NULL : ActiveProgs_ [idx];
}
/* Method: BtPisces::ProcessRISCIntr
* Purpose: Handles interrupts caused by the RISC programs
* Input: None
* Output: None
*/
void BtPisces::ProcessRISCIntr()
{
PHW_STREAM_REQUEST_BLOCK gpCurSrb = 0;
Trace t("BtPisces::ProcessRISCIntr()");
// this line must be before GetPassed(), as OldIdx_ is changed by that function
int pos = OldIdx_ + 1;
// measure elapsed time
int passed = GetPassed();
DebugOut((1, " passed = %d\n", passed ) );
while ( passed-- > 0 ) {
int idx;
RiscPrgHandle Rspnsbl = GetProgram( pos, idx );
pos++;
// last chance to prevent a disaster...
if ( !Rspnsbl || !Rspnsbl->IsInterrupting() ) {
DebugOut((1, " no resp or not intr\n" ) );
continue;
}
// get conveniently saved stream from the program
Field &Interrupter = *(Field *)Rspnsbl->GetTag();
gpCurSrb = Rspnsbl->pSrb_; // [TMZ] [!!!]
DebugOut((1, "'idx(%d), pSrb(%x)\n", idx, gpCurSrb));
bool paired = Interrupter.GetPaired();
if ( Interrupter.IsStarted() != true ) {
DebugOut((1, " not started %d\n", idx ) );
continue;
}
if ( IsFirst( idx ) && paired ) {
DebugOut((1, " continue pair %d\n", idx ) );
continue;
}
LONGLONG *pL = (LONGLONG *)Rspnsbl->GetDataBuffer();
if ( !pL )
{
DebugOut((1, "null buffer in interrupt, ignore this interrupt\n"));
//continue;
}
else
{
DebugOut((1, "good buffer in interrupt\n"));
}
// now make sure all buffers are written to
if ( !pL || Rspnsbl->IsSkipped() ) {
// want to call notify, so ProcessBufferAtInterrupt is called
DebugOut((1, " skipped %d\n", idx ) );
Interrupter.Notify( (PVOID)idx, true );
Interrupter.SetReady( true );
} else {
BOOL test1 = FALSE;
BOOL test2 = FALSE;
BOOL test3 = FALSE;
if ( 1
//*pL != 0xAAAAAAAA33333333 && (test1 = TRUE) &&
//*(pL + 1) != 0xBBBBBBBB22222222 && (test2 = TRUE) &&
//Interrupter.GetReady() && (test3 = TRUE)
) {
// here buffer is available
DebugOut((1, " notify %d, addr - %x\n", idx,
Rspnsbl->GetDataBuffer() ) );
//#pragma message("*** be very carefull zeroing buffers!!!")
//Rspnsbl->SetDataBuffer( 0 ); // [TMZ] try to fix buffer re-use bug
Interrupter.Notify( (PVOID)idx, false );
Interrupter.SetReady( true );
} else {
// add code for the paired streams here
DebugOut((1, " not time %d (%d, %d, %d)\n", idx , test1, test2, test3));
// this if/else takes care of this cases:
// 1. first buffer for a field is not written to
// 2. second buffer for a field is written to ( this can happen when
// both programs were updated at the same time, but the timing was
// such that first did not start executing, but second was );
// so this if/else prevents sending buffers back out of order
if ( Interrupter.GetReady() ) // it is always true before it is ever false
Interrupter.SetReady( false );
else
// make sure that things are correct when the loop is entered later
// the field must be set to 'ready'
Interrupter.SetReady( true );
}
}
} /* endwhile */
}
/* Method: BtPiscess::ProcessBufferAtInterrupt
* Purpose: Called by a video channel to perform risc program modifications
* if needed
* Input: pTag: PVOID - pointer to some data ( risc program pointer )
* Output: None
*/
void BtPisces::ProcessBufferAtInterrupt( PVOID pTag )
{
Trace t("BtPisces::ProcessBufferAtInterrupt()");
int idx = (int)pTag;
RiscPrgHandle Rspnsbl = ActiveProgs_ [idx];
if ( !Rspnsbl ) {
DebugOut((1, "PBAI: no responsible\n"));
return; // can this really happen ??
}
// get conveniently saved field from the program
Field &Interrupter = *(Field *)Rspnsbl->GetTag();
// see if there is a buffer in the queue and get it
DataBuf buf = Interrupter.GetNextBuffer();
DebugOut((1, "Update %d %x\n", idx, buf.pData_ ) );
// if buffer is not available skip the program
if ( !buf.pData_ ) {
DebugOut((1, "Buffer not available, skipping %d\n", idx ) );
Skip( idx );
} else {
if ( Rspnsbl->IsSkipped() )
nSkipped_--;
Engine_.ChangeAddress( Rspnsbl, buf );
LinkThePrograms();
}
}
/* Method: BtPisces::Interrupt
* Purpose: Called by ISR to initiate the processing of an interrupt
* Input: None
* Output: None
*/
State BtPisces::Interrupt()
{
Trace t("BtPisces::Interrupt()");
DebugOut((2, "BtPisces::Interrupt()\n"));
extern BYTE *gpjBaseAddr;
DWORD IntrStatus = *(DWORD*)(gpjBaseAddr+0x100);
State DidWe = Off;
if ( IntrStatus & RISC_I ) {
DebugOut((2, "RISC_I\n"));
ProcessRISCIntr();
*(DWORD*)(gpjBaseAddr+0x100) = RISC_I; // reset the status bit
DidWe = On;
}
if ( IntrStatus & FBUS_I ) {
DebugOut((2, "FBUS\n"));
*(DWORD*)(gpjBaseAddr+0x100) = FBUS_I; // reset the status bit
DidWe = On;
}
if ( IntrStatus & FTRGT_I ) {
DebugOut((2, "FTRGT\n"));
*(DWORD*)(gpjBaseAddr+0x100) = FTRGT_I; // reset the status bit
DidWe = On; //[TMZ]
}
if ( IntrStatus & FDSR_I ) {
DebugOut((2, "FDSR\n"));
*(DWORD*)(gpjBaseAddr+0x100) = FDSR_I; // reset the status bit
DidWe = On; //[TMZ]
}
if ( IntrStatus & PPERR_I ) {
DebugOut((2, "PPERR\n"));
*(DWORD*)(gpjBaseAddr+0x100) = PPERR_I; // reset the status bit
DidWe = On; //[TMZ]
}
if ( IntrStatus & RIPERR_I ) {
DebugOut((2, "RIPERR\n"));
*(DWORD*)(gpjBaseAddr+0x100) = RIPERR_I; // reset the status bit
Restart();
DidWe = On;
}
if ( IntrStatus & PABORT_I ) {
DebugOut((2, "PABORT\n"));
*(DWORD*)(gpjBaseAddr+0x100) = PABORT_I; // reset the status bit
DidWe = On;
}
if ( IntrStatus & OCERR_I ) {
DebugOut((2, "OCERR\n"));
DidWe = On;
DebugOut((0, "Stopping RiscEngine due to OCERR\n")); // [!!!] [TMZ] why not restart?
Engine_.Stop();
*(DWORD*)(gpjBaseAddr+0x100) = OCERR_I; // reset the status bit
}
if ( IntrStatus & SCERR_I ) {
DebugOut((0, "SCERR\n"));
DidWe = On;
*(DWORD*)(gpjBaseAddr+0x100) = SCERR_I; // reset the status bit
Restart(); // [TMZ] [!!!] this royally screws us over sometimes, figure it out.
*(DWORD*)(gpjBaseAddr+0x100) = SCERR_I; // reset the status bit
}
return DidWe;
}
// resource allocation group
/* Method: BtPisces::AllocateStream
* Purpose: This function allocates a stream for use by a video channel
* Input: StrInf: StreamInfo & - reference to the stream information structure
* Output:
*/
ErrorCode BtPisces::AllocateStream( Field *&ToAllocate, VideoStream st )
{
Trace t("BtPisces::AllocateStream()");
switch ( st ) {
case VS_Field1:
ToAllocate = &Odd_;
break;
case VS_Field2:
ToAllocate = &Even_;
break;
case VS_VBI1:
ToAllocate = &VBIO_;
break;
case VS_VBI2:
ToAllocate = &VBIE_;
break;
}
return Success;
}
/* Method: BtPisces::SetBrightness
* Purpose: Changes brightness of the captured image
* Input:
* Output:
*/
void BtPisces::SetBrightness( DWORD value )
{
Trace t("BtPisces::SetBrightness()");
PsDecoder_.SetBrightness( value );
}
/* Method: BtPisces::SetSaturation
* Purpose:
* Input:
* Output:
*/
void BtPisces::SetSaturation( DWORD value )
{
Trace t("BtPisces::SetSaturation()");
PsDecoder_.SetSaturation( value );
}
/* Method: BtPisces::SetConnector
* Purpose:
* Input:
* Output:
*/
void BtPisces::SetConnector( DWORD value )
{
Trace t("BtPisces::SetConnector()");
PsDecoder_.SetVideoInput( Connector( value ) );
}
/* Method: BtPisces::SetContrast
* Purpose:
* Input:
* Output:
*/
void BtPisces::SetContrast( DWORD value )
{
Trace t("BtPisces::SetContrast()");
PsDecoder_.SetContrast( value );
}
/* Method: BtPisces::SetHue
* Purpose:
* Input:
* Output:
*/
void BtPisces::SetHue( DWORD value )
{
Trace t("BtPisces::SetHue()");
PsDecoder_.SetHue( value );
}
/* Method: BtPisces::SetSVideo
* Purpose:
* Input:
* Output:
*/
void BtPisces::SetSVideo( DWORD )
{
Trace t("BtPisces::SetSVideo()");
}
/* Method: BtPisces::
* Purpose:
* Input: value: DWORD
* Output:
*/
void BtPisces::SetFormat( DWORD value )
{
Trace t("BtPisces::SetFormat()");
PsDecoder_.SetVideoFormat( VideoFormat( value ) );
// let the scaler know format has changed
Even_.VideoFormatChanged( VideoFormat( value ) );
Odd_.VideoFormatChanged( VideoFormat( value ) );
}
/* Method: BtPisces::GetSaturation
* Purpose:
* Input: pData: PLONG
* Output:
*/
LONG BtPisces::GetSaturation()
{
Trace t("BtPisces::GetSaturation()");
return PsDecoder_.GetSaturation();
}
/* Method: BtPisces::GetHue
* Purpose:
* Input: pData: PLONG
* Output:
*/
LONG BtPisces::GetHue()
{
Trace t("BtPisces::GetHue()");
return PsDecoder_.GetHue();
}
/* Method: BtPisces::GetBrightness
* Purpose:
* Input: pData: PLONG
* Output:
*/
LONG BtPisces::GetBrightness()
{
Trace t("BtPisces::GetBrightness()");
return PsDecoder_.GetBrightness();
}
/* Method: BtPisces::GetSVideo
* Purpose:
* Input: pData: PLONG
* Output:
*/
LONG BtPisces::GetSVideo()
{
Trace t("BtPisces::GetSVideo()");
return 0;
}
/* Method: BtPisces::GetContrast
* Purpose:
* Input: pData: PLONG
* Output:
*/
LONG BtPisces::GetContrast()
{
Trace t("BtPisces::GetContrast()");
return PsDecoder_.GetContrast();
}
/* Method: BtPisces::GetFormat
* Purpose:
* Input: pData: PLONG
* Output:
*/
LONG BtPisces::GetFormat()
{
Trace t("BtPisces::GetFormat()");
return PsDecoder_.GetVideoFormat();
}
/* Method: BtPisces::GetConnector
* Purpose:
* Input: pData: PLONG
* Output:
*/
LONG BtPisces::GetConnector()
{
Trace t("BtPisces::GetConnector()");
return PsDecoder_.GetVideoInput();
}
// scaler group
/* Method: BtPisces::SetAnalogWindow
* Purpose:
* Input:
* Output:
*/
ErrorCode BtPisces::SetAnalogWindow( MRect &r, Field &aField )
{
Trace t("BtPisces::SetAnalogWindow()");
return aField.SetAnalogWindow( r );
}
/* Method: BtPisces::SetDigitalWindow
* Purpose:
* Input:
* Output:
*/
ErrorCode BtPisces::SetDigitalWindow( MRect &r, Field &aField )
{
Trace t("BtPisces::SetDigitalWindow()");
return aField.SetDigitalWindow( r );
}
// color space converter group
/* Method: BtPisces::SetPixelFormat
* Purpose:
* Input:
* Output:
*/
void BtPisces::SetPixelFormat( ColFmt aFormat, Field &aField )
{
Trace t("BtPisces::SetPixelFormat()");
aField.SetColorFormat( aFormat );
}
/* Method: BtPisces::GetPixelFormat
* Purpose:
* Input:
* Output:
*/
ColFmt BtPisces::GetPixelFormat( Field &aField )
{
Trace t("BtPisces::GetPixelFormat()");
return aField.GetColorFormat();
}
void BtPisces::TurnVFilter( State s )
{
Trace t("BtPisces::TurnVFilter()");
Even_.TurnVFilter( s );
Odd_.TurnVFilter( s );
}
/* Method:
* Purpose: returns video standards supported by the board
*/
LONG BtPisces::GetSupportedStandards()
{
Trace t("BtPisces::GetSupportedStandards()");
return PsDecoder_.GetSupportedStandards();
}
void BtPisces::DumpRiscPrograms()
{
LONG x;
// Dump the links
DebugOut((0, "------------------------------------------------\n"));
for( x = 0; x < 12; x++ )
{
if ( CreatedProgs_[x] )
{
DebugOut((0, "Created #%02d addr(%x) paddr(%x) jaddr(%x)\n", x, CreatedProgs_[x], CreatedProgs_[x]->GetPhysProgAddr( ), *(CreatedProgs_[x]->pChainAddress_ + 1)));
}
}
for( x = 0; x < 8; x++ )
{
if ( Skippers_[x] )
{
DebugOut((0, "Skipper #%02d addr(%x) paddr(%x) jaddr(%x)\n", x, Skippers_[x], Skippers_[x]->GetPhysProgAddr( ), *(Skippers_[x]->pChainAddress_ + 1)));
}
}
DebugOut((0, "------------------------------------------------\n"));
return ;
/////////////////////////////////////////////////
for( x = 0; x < 12; x++ ) {
DebugOut((0, "Active Program # %d(%x) buf(%x)\n", x, ActiveProgs_[x], ActiveProgs_[x]?ActiveProgs_[x]->GetPhysProgAddr( ):-1));
}
for( x = 0; x < 12; x++ ) {
DebugOut((0, "Created Program # %d(%x) buf(%x)\n", x, CreatedProgs_[x], CreatedProgs_[x]?CreatedProgs_[x]->GetPhysProgAddr( ):-1));
}
for( x = 0; x < 8; x++ ) {
DebugOut((0, "Skipper Program # %d(%x) buf(%x)\n", x, Skippers_[x], Skippers_[x]?Skippers_[x]->GetPhysProgAddr( ):-1));
}
DebugOut((2, "---------------------------------\n"));
DebugOut((2, "Dumping ActiveProgs_\n"));
DebugOut((2, "---------------------------------\n"));
for( x = 0; x < 12; x++ ) {
DebugOut((1, "Active Program # %d\n", x));
ActiveProgs_[x]->Dump();
}
DebugOut((2, "---------------------------------\n"));
DebugOut((2, "Dumping CreatedProgs_\n"));
DebugOut((2, "---------------------------------\n"));
for( x = 0; x < 12; x++ ) {
DebugOut((1, "Created Program # %d\n", x));
CreatedProgs_[x]->Dump();
}
DebugOut((2, "---------------------------------\n"));
DebugOut((2, "Dumping Skippers_\n"));
DebugOut((2, "---------------------------------\n"));
for( x = 0; x < 8; x++ ) {
DebugOut((1, "Skipper Program # %d\n", x));
Skippers_[x]->Dump();
}
}