/*
Directory
---------

Assumptions

CDTV_RESET
CDTV_READ
CDTV_MOTOR
CDTV_SEEK
CDTV_CHANGENUM
CDTV_CHANGESTATE
CDTV_ADDCHANGEINT
CDTV_REMCHANGEINT
CDTV_QUICKSTATUS
CDTV_INFO
CDTV_ISROM
CDTV_FRONTPANEL
CDTV_FRAMECALL
CDTV_FRAMECOUNT
CDTV_READXL
CDTV_PLAYTRACK
CDTV_PLAYLSN
CDTV_PLAYMSF
CDTV_PLAYSEGSLSN
CDTV_PLAYSEGSMSF
CDTV_TOCLSN
CDTV_TOCMSF
CDTV_SUBQLSN
CDTV_SUBQMSF
CDTV_PAUSE
CDTV_STOPPLAY
CDTV_POKESEGLSN
CDTV_POKESEGMSF
CDTV_MUTE
CDTV_FADE
CDTV_POKEPLAYLSN
CDTV_POKEPLAYMSF
CDTV_GENLOCK
*/


/*************************
 Assumptions
 *************************/

	{
	struct MsgPort *IOPort;
	struct IOStdReq *IOReq;
	BYTE Err;

	// Init: Create request
	IOPort = CreatePort( 0, 0 );
	if ( ! IOPort )
		Error( NO_PORT );

	IOReq = CreateStdIO( IOPort );
	if ( ! IOReq )
		Error( NO_REQUEST );

	if ( OpenDevice( CDTV_NAME, 0, IOReq, 0 ) )
		{
		IOReq->io_Device = NULL;
		Error( OPEN_DEV );
		}

	// Example code here...

	// Quit: Remove request (Error() must call this)
	if ( IOReq )
		{
		if ( IOReq->io_Device )
			CloseDevice( (struct IORequest *) IOReq );

		DeleteStdIO( IOReq );
		}

	if ( IOPort )
		DeletePort( IOPort );
	}


/*************************
 CDTV_RESET
 *************************/

	{
	IOReq->io_Command = CDTV_RESET;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );
	}


/*************************
 CDTV_READ
 *************************/


	{
	static UBYTE Buffer[ 2048 + READ_PAD_BYTES ];
	ULONG Sector;
	ULONG Position;
	ULONG Length;

	// - Remember to add READ_PAD_BYTES to read's (and allow
	//   for the extra room in the Buffer).
	Sector		  = 112;
	Position	  = ( Sector * 2048 );
	Length		  = 2048;

	IOReq->io_Command = CDTV_READ;
	IOReq->io_Offset  = Position;
	IOReq->io_Length  = ( Length + READ_PAD_BYTES );
	IOReq->io_Data    = Buffer;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );
	}


/*************************
 CDTV_MOTOR
 *************************/

	{
	ULONG PreviousState;

	IOReq->io_Command = CDTV_MOTOR;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = FALSE;	// Turn motor off
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );

	PreviousState	  = IOReq->io_Actual;
	}


/*************************
 CDTV_SEEK
 *************************/

	{
	ULONG Position	  = ( 16 * 2048 );

	IOReq->io_Command = CDTV_SEEK;
	IOReq->io_Offset  = Position;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );
	}


/*************************
 CDTV_CHANGENUM
 *************************/

	{
	IOReq->io_Command = CDTV_CHANGENUM;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );

	printf( "%ld disk changes\n", IOReq->io_Actual );
	}


/*************************
 CDTV_CHANGESTATE
 *************************/

	{
	IOReq->io_Command = CDTV_CHANGESTATE;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );

	if ( IOReq->io_Actual )
		printf( "CD is not in drive\n" );
	else
		printf( "CD is in drive\n" );
	}


/*************************
 CDTV_ADDCHANGEINT
 *************************/

struct Interrupt ChangeInt;

void __interrupt __saveds InterruptCode(
	void
	)
	{
	// Do something
	}

	{
	ChangeInt.is_Node.ln_Type = NT_INTERRUPT;
	ChangeInt.is_Code	  = InterruptCode;

	IOReq->io_Command = CDTV_ADDCHANGEINT;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = (APTR) &ChangeInt;
	SendIO( (struct IORequest *) IOReq );

	// Refer to CDTV_REMCHANGEINT for removal
	}


/*************************
 CDTV_REMCHANGEINT
 *************************/

struct Interrupt ChangeInt;

void __interrupt __saveds InterruptCode(
	void
	)
	{
	// Do something
	}

	{
	// Refer to CDTV_ADDCHANGEINT for adding
	// ChangeInt

	// (do not need WaitIO()).
	IOReq->io_Command = CDTV_REMCHANGEINT;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = (APTR) &ChangeInt;
	DoIO( (struct IORequest *) IOReq );
	}


/*************************
 CDTV_QUICKSTATUS
 *************************/

	{
	IOReq->io_Command = CDTV_QUICKSTATUS;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );

	// Valid flags:
	if ( IOReq->io_Actual & QSF_AUDIO )
		printf( "Audio playing\n" );

	if ( IOReq->io_Actual & QSF_SPIN )
		printf( "CD is spinning\n" );

	if ( IOReq->io_Actual & QSF_DISK )
		printf( "CD in drive\n" );
	}


/*************************
 CDTV_INFO
 *************************/

	{
	IOReq->io_Command = CDTV_INFO;
	IOReq->io_Offset  = CDTV_INFO_FRAME_RATE;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );

	printf( "Frame rate: %ld frames/second\n", IOReq->Actual );
	}


/*************************
 CDTV_ISROM
 *************************/

	{
	IOReq->io_Command = CDTV_ISROM;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );

	if ( IOReq->io_Actual )
		printf( "CD is a CD-ROM\n" );
	else
		printf( "CD is an audio CD\n" );
	}


/*************************
 CDTV_FRONTPANEL
 *************************/

	{
	IOReq->io_Command = CDTV_FRONTPANEL;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = FALSE;	// to disable front panel
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );
	}


/*************************
 CDTV_FRAMECALL
 *************************/

void __interrupt __saveds __asm InterruptCode(
	register __a2 struct IOStdReq *Request
	)
	{
	// Do something
	return( 0 );
	}

	{
	ULONG Frames = ( 2 * 75 );	// every 2 seconds

	IOReq->io_Command = CDTV_FRAMECALL;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = Frames;
	IOReq->io_Data    = (APTR) InterruptCode;
	SendIO( (struct IORequest *) IOReq );

	/*
	 *
	 * Body of code goes here
	 *
	 */

	// Cleanup:
	// Proper way to terminate
	AbortIO( (struct IORequest *) IOReq );
	WaitIO( (struct IORequest *) IOReq );
	}


/*************************
 CDTV_FRAMECOUNT
 *************************/

	{
	IOReq->io_Command = CDTV_FRAMECOUNT;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );

	printf( "%ld frames since start\n", IOReq->io_Actual );
	}


/*************************
 CDTV_READXL
 *************************/

void __interrupt __saveds __asm InterruptCode(
	register __a2 CDXL *NodeCompleted
	)
	{
	// Do something
	return( 0 );
	}

	{
	static UBYTE Buffer[ 4 ][ 2048 ];
	struct MinList	CDXLList;
	struct CDXL	CDXLNode[ 4 ];
	ULONG Sector	 = 16;
	ULONG NumSectors = 4;
	ULONG i;

	// Prepare list
	NewList( (struct List *) &CDXLList );

	for ( i = 0; i < 4; i++ )
		{
		AddTail( (struct List *) &CDXLList, (struct Node *) &CDXLNode[ i ] );
		CDXLNode[ i ].Buffer   = Buffer[ i ];
		CDXLNode[ i ].Length   = 2048;
		CDXLNode[ i ].DoneFunc = InterruptCode;
		}

	// Start CDXL
	IOReq->io_Command = CDTV_READXL;
	IOReq->io_Offset  = Sector;
	IOReq->io_Length  = NumSectors;
	IOReq->io_Data    = (APTR) CDXLList.mlh_Head;
	SendIO( (struct IORequest *) IOReq );

	/*
	 *
	 * Body of code goes here
	 *
	 */

	// Cleanup:
	// Proper way to terminate
	AbortIO( (struct IORequest *) IOReq );
	WaitIO( (struct IORequest *) IOReq );

	// Then a SEEK is required to force the drive to stop (sometimes necessary)
	IOReq->io_Command = CDTV_SEEK;
	IOReq->io_Offset  = 0;		// or next position
	IOReq->io_Length  = 0;
	IOReq->io_Data    = NULL;

	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );
	}


/*************************
 CDTV_PLAYTRACK
 *************************/

	{
	ULONG StartTrack = 4;
	ULONG StopTrack	 = 6;

	IOReq->io_Command = CDTV_PLAYTRACK;
	IOReq->io_Offset  = StartTrack;
	IOReq->io_Length  = StopTrack;
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );
	}


/*************************
 CDTV_PLAYLSN
 *************************/

	{
	CDPOS StartSector;
	CDPOS SectorsLength;

	StartSector.LSN   = 16;
	SectorsLength.LSN = 300;

	IOReq->io_Command = CDTV_PLAYLSN;
	IOReq->io_Offset  = StartSector;
	IOReq->io_Length  = SectorsLength;
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );
	}


/*************************
 CDTV_PLAYMSF
 *************************/

	{
	CDPOS StartMSF;
	CDPOS StopMSF;

	StartMSF.Raw	  = TOMSF( 5,  0,  0 );
	StopMSF.Raw	  = TOMSF( 5, 10, 25 );

	IOReq->io_Command = CDTV_PLAYMSF;
	IOReq->io_Offset  = (ULONG) StartMSF;
	IOReq->io_Length  = (ULONG) StopMSF;
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );
	}


/*************************
 CDTV_PLAYSEGSLSN
 *************************/

void __interrupt __saveds __asm InterruptCode(
	register __a2 CDAudioSeg *CompletedSeg
	)
	{
	// Do something
	return( 0 );
	}

	{
	struct MinList    SegList;
	struct CDAudioSeg SegNode;

	// Prepare list
	NewList( (struct List *) &SegList );

	AddTail( (struct List *) &SegList, (struct Node *) &SegNode );
	SegNode.Start.LSN = 16;
	SegNode.Stop.LSN  = 300;
	SegNode.StartFunc = InterruptCode;

	IOReq->io_Command = CDTV_PLAYSEGSLSN;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = (APTR) SegList.mlh_Head;
	SendIO( (struct IORequest *) IOReq );

	/*
	 *
	 * Body of code goes here
	 *
	 */

	// Cleanup:
	WaitIO( (struct IORequest *) IOReq );
	}


/*************************
 CDTV_PLAYSEGSMSF
 *************************/

void __interrupt __saveds __asm InterruptCode(
	register __a2 CDAudioSeg *CompletedSeg
	)
	{
	// Do something
	return( 0 );
	}

	{
	struct MinList    SegList;
	struct CDAudioSeg SegNode;

	// Prepare list
	NewList( (struct List *) &SegList );

	AddTail( (struct List *) &SegList, (struct Node *) &SegNode );
	SegNode.Start.Raw = TOMSF( 5,  0,  0 );
	SegNode.Stop.Raw  = TOMSF( 5, 10, 25 );
	SegNode.StartFunc = InterruptCode;

	IOReq->io_Command = CDTV_PLAYSEGSMSF;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = (APTR) SegList.mlh_Head;
	SendIO( (struct IORequest *) IOReq );

	/*
	 *
	 * Body of code goes here
	 *
	 */

	// Cleanup:
	WaitIO( (struct IORequest *) IOReq );
	}


/*************************
 CDTV_TOCLSN
 *************************/

	{
	static struct CDTOC TOCArray[ 100 ];
	LONG i;

	IOReq->io_Command = CDTV_TOCLSN;
	IOReq->io_Offset  = 0;			// 0=Summary, or #
	IOReq->io_Length  = 100;
	IOReq->io_Data    = (APTR) TOCArray;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );

	// Disk summary
	printf( "Tracks %d to %d\n",
		TOCArray[ 0 ].Track,
		TOCArray[ 0 ].LastTrack );

	// TOC
	for ( i = 1; i <= CDTVIOReq->io_Actual; i++ )
		printf( "Track %d starts at sector %d\n",
			i,
			TOCArray[ 1 ].Position.LSN );
	}


/*************************
 CDTV_TOCMSF
 *************************/

	{
	static struct CDTOC TOCArray[ 100 ];
	LONG i;

	IOReq->io_Command = CDTV_TOCMSF;
	IOReq->io_Offset  = 0;			// 0=Summary, or #
	IOReq->io_Length  = 100;
	IOReq->io_Data    = (APTR) TOCArray;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );

	// Disk summary
	printf( "Tracks %d to %d\n",
		TOCArray[ 0 ].Track,
		TOCArray[ 0 ].LastTrack );

	// TOC
	for ( i = 1; i <= CDTVIOReq->io_Actual; i++ )
		printf( "Track %d starts at Minute:Second:Frame %d:%d:%d\n",
			i,
			TOCArray[ 1 ].Position.MSF.Minute,
			TOCArray[ 1 ].Position.MSF.Second,
			TOCArray[ 1 ].Position.MSF.Frame );
	}


/*************************
 CDTV_SUBQLSN
 *************************/

	{
	struct CDSubQ ReqSubQ;
	UBYTE AddrInfo;

	IOReq->io_Command = CDTV_SUBQLSN;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = (APTR) ReqSubQ;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );

	// First check that it is valid
	AddrInfo = ( ReqSubQ.AddrCtrl & ADRCTL_MASK );
	if ( AddrInfo == ADRCTL_NOMODE )
		return;		// INVALID SUBQ

	switch ( ReqSubQ.Status )
		{
		case ( SQSTAT_NOTVALID ):
		case ( SQSTAT_NOSTAT   ):
			return;		// INVALID SUBQ

		case ( SQSTAT_PLAYING  ):
			printf( "CD Playing\n" );
			break;

		case ( SQSTAT_PAUSED   ):
			printf( "CD Paused\n" );
			break;

		case ( SQSTAT_DONE     ):
			printf( "Last Play finished normally\n" );
			break;

		case ( SQSTAT_ERROR    ):
			printf( "Last Play finished with error\n" );
			break;
		}

	// Position
	if ( AddrInfo == ADRCTL_POSITION )
		{
		printf( "Current track %d, index %d\n",
			ReqSubQ.Track,
			ReqSubQ.Index );

		printf( "Sector %d into CD, sector %d into track\n",
			ReqSubQ.DiskPosition.LSN,
			ReqSubQ.TrackPosition.LSN );
		}
	}


/*************************
 CDTV_SUBQMSF
 *************************/

	{
	struct CDSubQ ReqSubQ;
	UBYTE AddrInfo;

	IOReq->io_Command = CDTV_SUBQMSF;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = (APTR) ReqSubQ;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );

	// First check that it is valid
	AddrInfo = ( ReqSubQ.AddrCtrl & ADRCTL_MASK );
	if ( AddrInfo == ADRCTL_NOMODE )
		return;		// INVALID SUBQ

	switch ( ReqSubQ.Status )
		{
		case ( SQSTAT_NOTVALID ):
		case ( SQSTAT_NOSTAT   ):
			return;		// INVALID SUBQ

		case ( SQSTAT_PLAYING  ):
			printf( "CD Playing\n" );
			break;

		case ( SQSTAT_PAUSED   ):
			printf( "CD Paused\n" );
			break;

		case ( SQSTAT_DONE     ):
			printf( "Last Play finished normally\n" );
			break;

		case ( SQSTAT_ERROR    ):
			printf( "Last Play finished with error\n" );
			break;
		}

	// Position
	if ( AddrInfo == ADRCTL_POSITION )
		{
		printf( "Current track %d, index %d\n",
			ReqSubQ.Track,
			ReqSubQ.Index );

		printf( "Minute:Second:Frame %d:%d:%d into CD, %d:%d:%d into track\n",
			ReqSubQ.DiskPosition.MSF.Minute,
			ReqSubQ.DiskPosition.MSF.Second,
			ReqSubQ.DiskPosition.MSF.Frame,
			ReqSubQ.TrackPosition.MSF.Minute,
			ReqSubQ.TrackPosition.MSF.Second,
			ReqSubQ.TrackPosition.MSF.Frame );
		}
	}


/*************************
 CDTV_PAUSE
 *************************/

	{
	IOReq->io_Command = CDTV_PAUSE;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = TRUE;
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );
	}


/*************************
 CDTV_STOPPLAY
 *************************/

	{
	// Remember to AbortIO the current play command first
	IOReq->io_Command = CDTV_STOPPLAY;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );
	}


/*************************
 CDTV_POKESEGLSN
 *************************/

	{
	struct IOStdReq   PokeIOReq;
	struct MinList    SegList;
	struct CDAudioSeg SegNode;
	CDPOS NewSector;

	// Use a copy of our IOReq
	PokeIOReq = *IOReq;

	// Prepare list
	NewList( (struct List *) &SegList );

	AddTail( (struct List *) &SegList, (struct Node *) &SegNode );
	SegNode.Start.LSN = 16;
	SegNode.Stop.LSN  = 300;

	IOReq->io_Command = CDTV_PLAYSEGSLSN;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = (APTR) SegList.mlh_Head;
	SendIO( (struct IORequest *) IOReq );

	// Actual "poke"
	NewSector.LSN	      = 480;

	PokeIOReq->io_Command = CDTV_POKESEGLSN;
	PokeIOReq->io_Offset  = (ULONG) NewSector;
	PokeIOReq->io_Length  = 0;
	PokeIOReq->io_Data    = (APTR) SegList.mlh_Head;
	if ( Err = DoIO( (struct IORequest *) PokeIOReq ) )
		printf( "IO Error %ld\n", Err );

	// Cleanup:
	WaitIO( (struct IORequest *) IOReq );
	}


/*************************
 CDTV_POKESEGMSF
 *************************/


	{
	struct IOStdReq   PokeIOReq;
	struct MinList    SegList;
	struct CDAudioSeg SegNode;
	CDPOS NewMSF;

	// Use a copy of our IOReq
	PokeIOReq = *IOReq;

	// Prepare list
	NewList( (struct List *) &SegList );

	AddTail( (struct List *) &SegList, (struct Node *) &SegNode );
	SegNode.Start.Raw = TOMSF( 5,  0,  0 );
	SegNode.Stop.Raw  = TOMSF( 5, 10, 25 );

	IOReq->io_Command = CDTV_PLAYSEGSLSN;
	IOReq->io_Offset  = 0;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = (APTR) SegList.mlh_Head;
	SendIO( (struct IORequest *) IOReq );

	// Actual "poke"
	NewMSF.Raw	      = TOMSF( 6, 10, 20 );

	PokeIOReq->io_Command = CDTV_POKESEGMSF;
	PokeIOReq->io_Offset  = (ULONG) NewSector;
	PokeIOReq->io_Length  = 0;
	PokeIOReq->io_Data    = (APTR) SegList.mlh_Head;
	if ( Err = DoIO( (struct IORequest *) PokeIOReq ) )
		printf( "IO Error %ld\n", Err );

	// Cleanup:
	WaitIO( (struct IORequest *) IOReq );
	}


/*************************
 CDTV_MUTE
 *************************/

	{
	IOReq->io_Command = CDTV_MUTE;
	IOReq->io_Offset  = 0;		// Volume 0-0x7FFF
	IOReq->io_Length  = 1;		// 0=check, 1=next play stop, 2=now
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );
	}


/*************************
 CDTV_FADE
 *************************/

	{
	ULONG Seconds	  = 2;

	IOReq->io_Command = CDTV_FADE;
	IOReq->io_Offset  = 0x7FFF;	// Volume 0-0x7FFF
	IOReq->io_Length  = ( Seconds * 75 );
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );
	}


/*************************
 CDTV_POKEPLAYLSN
 *************************/

	{
	struct IOStdReq PokeIOReq;
	CDPOS StartSector;
	CDPOS SecondSector;
	CDPOS SectorsLength;

	// Use a copy of our IOReq
	PokeIOReq = *IOReq;

	StartSector.LSN   = 16;
	SectorsLength.LSN = 300;

	IOReq->io_Command = CDTV_PLAYLSN;
	IOReq->io_Offset  = StartSector;
	IOReq->io_Length  = SectorsLength;
	IOReq->io_Data    = NULL;
	SendIO( (struct IORequest *) IOReq );

	// Actual "poke"
	SecondSector.LSN  = 480;

	PokeIOReq->io_Command = CDTV_POKEPLAYLSN;
	PokeIOReq->io_Offset  = SecondSector;
	PokeIOReq->io_Length  = SectorsLength;
	PokeIOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) PokeIOReq ) )
		printf( "IO Error %ld\n", Err );

	// Cleanup:
	WaitIO( (struct IORequest *) IOReq );
	}


/*************************
 CDTV_POKEPLAYMSF
 *************************/

	{
	struct IOStdReq PokeIOReq;
	CDPOS StartMSF;
	CDPOS SecondMSF;
	CDPOS StopMSF;

	// Use a copy of our IOReq
	PokeIOReq = *IOReq;

	StartMSF.Raw	  = TOMSF( 5,  0,  0 );
	SecondMSF.Raw	  = TOMSF( 5, 40,  0 );

	IOReq->io_Command = CDTV_PLAYMSF;
	IOReq->io_Offset  = (ULONG) StartMSF;
	IOReq->io_Length  = (ULONG) StopMSF;
	IOReq->io_Data    = NULL;
	SendIO( (struct IORequest *) IOReq );

	// Actual "poke"
	StopMSF.Raw	  = TOMSF( 5, 10, 25 );

	PokeIOReq->io_Command = CDTV_POKEPLAYMSF;
	PokeIOReq->io_Offset  = (ULONG) SecondMSF;
	PokeIOReq->io_Length  = (ULONG) StopMSF;
	PokeIOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) PokeIOReq ) )
		printf( "IO Error %ld\n", Err );

	// Cleanup:
	WaitIO( (struct IORequest *) IOReq );
	}


/*************************
 CDTV_GENLOCK
 *************************/

	{
	IOReq->io_Command = CDTV_GENLOCK;
	IOReq->io_Offset  = CDTV_GENLOCK_MIXED;
	IOReq->io_Length  = 0;
	IOReq->io_Data    = NULL;
	if ( Err = DoIO( (struct IORequest *) IOReq ) )
		printf( "IO Error %ld\n", Err );
	}
                                                                                                                        