
/* vdp50_driver.c : routines for DEC_VDP-50 videodisc player */

#include "vdp50.h"
#include "rpd_driver.h"
#include <stdio.h>

#define MAXRETRYS 0		/* the number of times we try before giving up */

extern int ttyutil_debug;

int		vdp50_debug = 0;
static	UBYTE	inbytes[16];
static	UBYTE	outbytes[16];
static 	int	not_loaded = 0;

/* ------------------------------------------------------------------------ */

static int
vdp50_IntToFrame(n,f)

	int	n;
	UBYTE *	f;
{	
int 	i; 
char 	s[6];

	f[0] = f[1] = f[2] = 0;
	sprintf(s,"%05d",(n));
	for( i=0; i<5; i++ )
	    f[(i+1)/2] |= (s[i]-'0') << (i%2?4:0);
	f[0] |= 0xf0;
	return 0;
}

/* ------------------------------------------------------------------------ */

static int
vdp50_FrameToInt(f)

	UBYTE *	f;
{	
int i; 
char s[6];

	s[5] = 0;
	for( i=0; i<5; i++ )
	    s[i] = ((f[(i+1)/2] >> (i%2?4:0)) & 0x0f) + '0';
	return atoi(s);
}

/* ------------------------------------------------------------------------ */

static int
vdp50_IntToJumpArg(n,j)

	int	n;
	UBYTE *	j;
{
int 	i; 
char 	s[4];

	j[0] = j[1] = 0;
	sprintf(s,"%03d",(n));
	for( i=0; i<3; i++ )
	    j[(i+1)/2] |= ((s[i]-'0') << (i%2?4:0));
	return 0;
}

/* ------------------------------------------------------------------------ */

static int
vdp50_RevisionToInts(r,hn,fn)
	
	UBYTE *	r;
	int *	hn;
	int *	fn;
{	
int i;
	*hn = r[1] * 0xff + r[0];
	*fn = r[3] * 0xff + r[2];
	return 0;
}

/* ------------------------------------------------------------------------ */

static int
vdp50_SetAudioState( rpd, b )

	RPD_ptr	rpd;
	UBYTE *	b;
{
	*b = 0;
	if( rpd->state.audio1_on )
		BITS_ON( *b, VDP50_CH1_ON );
	else
		BITS_OFF( *b, VDP50_CH1_ON );

	if( rpd->state.audio2_on )
		BITS_ON( *b, VDP50_CH2_ON );
	else
		BITS_OFF( *b, VDP50_CH2_ON );
	return 0;
}

/* ------------------------------------------------------------------------ */

vdp50_cmd(rpd,num)

	RPD_ptr	rpd;
	int 	num;
{
static char *funcname = "vdp50_cmd";
int	success = 0;
UBYTE	args[10];	/* assumes these are all 0 */
VDP50_Frame	bcdf;
VDP50_DiscID	id;
int	frame;

	/* note that with the audio, must set the bits corresponding
	   to the current state of the software */

	switch(num)
	{
		case INDEX_ON:
			BITS_ON( args[0], VDP50_INDEX_ON );
			if( !vdp50_ttyio( rpd->fd, VDP50_INDEX_PKT, args, 1 ) )
			{
				rpd->state.indexon = 1;
				success = 1;
			}
			break;
		case INDEX_OFF:
			BITS_OFF( args[0], VDP50_INDEX_ON );
			if( !vdp50_ttyio( rpd->fd, VDP50_INDEX_PKT, args, 1 ) )
			{
				rpd->state.indexon = 0;
				success = 1;
			}
			break;
		case A1_ON:
			vdp50_SetAudioState( rpd, &args[0] );
			BITS_ON( args[0], VDP50_CH1_ON );
			if( !vdp50_ttyio( rpd->fd, VDP50_AUDIO_PKT, args, 1 ) )
			{
				rpd->state.audio1_on = 1;
				success = 1;
			}
			break;
		case A1_OFF:
			vdp50_SetAudioState( rpd, &args[0] );
			BITS_OFF( args[0], VDP50_CH1_ON );
			if( !vdp50_ttyio( rpd->fd, VDP50_AUDIO_PKT, args, 1 ) )
			{
				rpd->state.audio1_on = 0;
				success = 1;
			}
			break;
		case A2_ON:
			vdp50_SetAudioState( rpd, &args[0] );
			BITS_ON( args[0], VDP50_CH2_ON );
			if( !vdp50_ttyio( rpd->fd, VDP50_AUDIO_PKT, args, 1 ) )
			{
				rpd->state.audio2_on = 1;
				success = 1;
			}
			break;
		case A2_OFF:
			vdp50_SetAudioState( rpd, &args[0] );
			BITS_OFF( args[0], VDP50_CH2_ON );
			if( !vdp50_ttyio( rpd->fd, VDP50_AUDIO_PKT, args, 1 ) )
			{
				rpd->state.audio2_on = 0;
				success = 1;
			}
			break;
		case LOAD:
			if( !vdp50_ttyio( rpd->fd, VDP50_LOAD_PKT, args, 1 ) )
			{
				rpd->state.volume_loaded = 1;
				bcopy( &inbytes[1], bcdf, 3 );
				if( !vdp50_LoadIsNormal(bcdf) )
				{
					frame = vdp50_FrameToInt( bcdf );
					fprintf(stderr,"%s: abnormal load: at frame %d\n",
						rpd->devname,frame );
				}
				if( !vdp50_ttyio( rpd->fd, VDP50_ID_PKT, args, 1 ) )
				{
					bcopy( &inbytes[1], id, 3 );
					sprintf(rpd->volume,"#%02x%02x%02x",
						id[0],id[1],id[2] );
					fprintf(stderr,"%s: vdp50 loaded volume id '%s'\n",
						rpd->devname,rpd->volume);
				}
				success = 1;
			}
			else
			{
				fprintf(stderr,"%s: load failure\n",rpd->devname);
				rpd->state.volume_loaded = 0;
			}
			break;
		case UNLOAD:
			if( !vdp50_ttyio( rpd->fd, VDP50_UNLOAD_PKT, args, 1 ) )
			{
				if( inbytes[1] == VDP50_UNLOAD_OK )
				{
					rpd->state.volume_loaded = 0;
					rpd->volume[0] = 0;
					success = 1;
				}
				else
				{
					if( inbytes[1] & VDP50_LASER_ON )
					fprintf(stderr,"%s: laser still on after unload\n",
						rpd->devname);
					if( inbytes[1] & VDP50_MOTOR_ON )
					fprintf(stderr,"%s: motor still on after unload\n",
						rpd->devname);
				}
				if( vdp50_ttyio( rpd->fd, VDP50_EJECT_PKT, args, 1 ) )
				{
					fprintf(stderr,"%s: eject failure\n",rpd->devname);
				}
			}
			else
			{
				fprintf(stderr,"%s: unload failure\n",rpd->devname);
			}
			break;
		default:
			fprintf(stderr,"%s: %s: illegal request %d\n",
				rpd->devname,funcname,num);
			break;
	}

	if( success )
		return(0);
	else
		return -1;
}

/* ------------------------------------------------------------------------ */

static int
vdp50_SendSpeed( rpd, range, speed )

	RPD_ptr	rpd;
	int	range;
	int	speed;
{
VDP50_Speed	s;

	vdp50_IntToSpeedArg(speed,s);
	vdp50_SetSpeedRange(s,range);
	if( vdp50_ttyio( rpd->fd, VDP50_SPEED_PKT, s, 1 ) )
		return -1;
	return 0;
}

/* ------------------------------------------------------------------------ */

vdp50_varspeed(rpd,num)

	RPD_ptr	rpd;
	int	num;
{
static char *funcname = "vdp50_varspeed";
int	success = 0;
UBYTE	args[10];
int	range;
int	speed;
int	dir;

	switch(num)
	{
		case R_MAX:
			range = VDP50_FAST_PLAY;
			speed = VDP50_MAX_FAST_SPEED;
			dir = VDP50_REV;
			break;
		case R_VERY_FAST:
			range = VDP50_FAST_PLAY;
			speed = VDP50_MAX_FAST_SPEED/2;
			dir = VDP50_REV;
			break;
		case R_FAST:
			range = VDP50_FAST_PLAY;
			speed = VDP50_MAX_FAST_SPEED/4;
			dir = VDP50_REV;
			break;
		case R_PLAY:
			range = VDP50_NORMAL_PLAY;
			speed = 1;
			dir = VDP50_REV;
			break;
		case R_SLOW:
			range = VDP50_SLOW_PLAY;
			speed = 5;
			dir = VDP50_REV;
			break;
		case R_VERY_SLOW:
			range = VDP50_SLOW_PLAY;
			speed = 10;
			dir = VDP50_REV;
			break;
		case STOP:
			/* special case */
			if( vdp50_ttyio(rpd->fd,VDP50_HALT_PKT,args,1) )
			{
				fprintf(stderr,"%s: %s: can't stop\n",
					rpd->devname,funcname);
				return -1;
			}
			else
				return 0;
			break;
		case F_VERY_SLOW:
			range = VDP50_SLOW_PLAY;
			speed = 10;
			dir = VDP50_FWD;
			break;
		case F_SLOW:
			range = VDP50_SLOW_PLAY;
			speed = 5;
			dir = VDP50_FWD;
			break;
		case F_PLAY:
			range = VDP50_NORMAL_PLAY;
			speed = 1;
			dir = VDP50_FWD;
			break;
		case F_FAST:
			range = VDP50_FAST_PLAY;
			speed = VDP50_MAX_FAST_SPEED/4;
			dir = VDP50_FWD;
			break;
		case F_VERY_FAST:
			range = VDP50_FAST_PLAY;
			speed = VDP50_MAX_FAST_SPEED/2;
			dir = VDP50_FWD;
			break;
		case F_MAX:
			range = VDP50_FAST_PLAY;
			speed = VDP50_MAX_FAST_SPEED;
			dir = VDP50_FWD;
			break;
		default:
		fprintf(stderr,"%s: %s: illegal cmd %d\n",
			rpd->devname,funcname,num);
			return(-1);
			break;
	}

	if( vdp50_SendSpeed(rpd,range,speed) )
	{
		fprintf(stderr,"%s: %s: can't set speed\n",
			rpd->devname,funcname);
	}
	else
	{
		vdp50_SetPlayDirection(args[0],dir);
		if( vdp50_ttyio(rpd->fd,VDP50_PLAY_PKT,args,1) )
			fprintf(stderr,"%s: %s: can't play\n",
			rpd->devname,funcname);
		else
			success = 1;
	}	
	
	if( success )
		return(0);
	else
		return -1;
}

/* ------------------------------------------------------------------- */

vdp50_jog(rpd,num)

	RPD_ptr	rpd;
	int	num;
{
static char *funcname = "vdp50_jog";
int	success = 0;
UBYTE	args[10];
int	i;
int	dir;

	if( num<0 ) 
	{
		num = (-num);
		dir = VDP50_REV;
	}
	else
		dir = VDP50_FWD;

	vdp50_SetStepDirection( args[0], dir );

	for( i=0; i<abs(num); i++ )
	{
		if( !vdp50_ttyio(rpd->fd, VDP50_STEP_PKT, args, 1) )
		{
			if( !(inbytes[1] && VDP50_FRAME_NOT_FOUND) )
				success = 1;	
		}
	}

	if( success )
		return(0);
	else
		return -1;
}

/* ------------------------------------------------------------------------ */

vdp50_getframe(rpd)

	RPD_ptr	rpd;
{
static char *funcname = "vdp50_getframe";
int	success = 0;
UBYTE	args[10];
VDP50_Status	st;
VDP50_Frame	bcdf;
int		frame;

	if( vdp50_ttyio(rpd->fd, VDP50_STATUS_PKT, args, 1) )
		fprintf(stderr,"%s: %s: can't get player status\n",
			rpd->devname,funcname);
	else
	{
		bcopy( &inbytes[1], st, 2 );
		bcopy( &inbytes[3], bcdf, 3 );
		frame = vdp50_FrameToInt( bcdf );
		success = 1;
	}

	if( success )
		return(frame);
	else
		return -1;
}

/* ------------------------------------------------------------------------ */

vdp50_getstatus(rpd)

	RPD_ptr	rpd;
{
static char *funcname = "vdp50_getstatus";
int	success = 0;
UBYTE	args[10];
VDP50_Status	st;
VDP50_Frame	bcdf;
int		frame;

	if( vdp50_ttyio(rpd->fd, VDP50_STATUS_PKT, args, 1) )
		fprintf(stderr,"%s: %s: can't get player status\n",
			rpd->devname,funcname);
	else
	{
		bcopy( &inbytes[1], st, 2 );
		bcopy( &inbytes[3], bcdf, 3 );
		vdp50_FrameToInt( bcdf );
		success = 1;

		if( !(st[0] & VDP50_ST_LOADED) )
			not_loaded = 1;
/*		
		printf("Status of rpd: <%s>\n",rpd->devname);
		printf("------------------\n");

		if( st[0] & VDP50_ST_LOADED );
		else
			printf("disc NOT loaded!!\n");

		if( st[0] & VDP50_ST_PLAYING )
			printf("disc playing\n");
		else
			printf("disc NOT playing\n");

		if( st[0] & VDP50_ST_SEARCHING )
			printf("disc is searching!!\n");

		if( st[0] & VDP50_ST_CH1_ON )
			printf("channel 1 on\n");
		else
			printf("channel 1 off\n");

		if( st[0] & VDP50_ST_INDEX_ON )
			printf("index is ON\n");

		if( st[0] & VDP50_ST_CH2_ON )
			printf("channel 2 on\n");
		else
			printf("channel 2 off\n");

		if( st[1] & VDP50_ST_GENLOCKED );
		else
			printf("player NOT GENLOCKED!\n");

		success = 1;
*/
	}
	if( success )
		return(0);
	else
		return -1;
}	

/* ------------------------------------------------------------------------ */

vdp50_search(rpd,frame,wait)
	RPD_ptr	rpd;
	int	frame;
	int	wait;		/* if true, hangs until it gets there 
					or times out */
{
static char *funcname = "vdp50_search";
int	success = 0;
UBYTE	args[10];
VDP50_Frame	bcdf;
VDP50_JumpArg	jump;
int	at, last;
int	dir;
int	nframes;
int	readnum;
int	res;

	/* to do the quick jump, see if we're within the
		legal limits */

	at = vdp50_getframe(rpd);
	nframes = frame-at;

	if( nframes > 0 )
		dir = VDP50_FWD;
	else if( nframes < 0 )
		dir = VDP50_REV;
	else
		return 0;	/* already there */

	/* RMS - 11/19/87 changed this to bypass any quick jumps;
		1% to 2% of quick jumps miss by one frame;
		this error rate is deemed not worth the speed gain */

/*	
	nframes = abs(nframes);

	if( at > 0 && nframes <= VDP50_MAX_SINGLE_JUMP )
	{
		vdp50_IntToJumpArg( nframes, jump );
		vdp50_SetJumpDirection( jump, dir );
		bcopy( jump, args, 2 );
		if( !vdp50_ttyio( rpd->fd, VDP50_JUMP_PKT, args, 1) )
			success = 1;
		else
			fprintf(stderr,"%s: %s: failed quick jump\n",
				rpd->devname,funcname );
	}
	else
*/
	/* do a normal search */
	{
		vdp50_IntToFrame( frame, bcdf );
		bcopy( bcdf, args, 3 );
		if( !vdp50_ttyio(rpd->fd, VDP50_SEARCH_PKT, args, wait) )
		{
			if( !wait )
				return 0;

			readnum = vdp50_table[VDP50_ACK_PKT].resp_bytes + 2 +
				vdp50_table[VDP50_SEARCH_PKT].resp_bytes + 2;
			res = ttyutil_read( rpd->fd, inbytes, readnum,
				VDP50_SEARCH_TIMEOUT+1000 );
			if( res == readnum )
			{	
				if( inbytes[0] != 
					vdp50_table[VDP50_ACK_PKT].resp_code
					||
				    inbytes[1] != 
					vdp50_table[VDP50_ACK_PKT].resp_end )
				{
					fprintf(stderr,"%s: %s: ACK packet mis-match\n",
						rpd->devname,funcname);
					return -1;
				}
				if( inbytes[2] != 
					vdp50_table[VDP50_SEARCH_PKT].resp_code
					||
				    inbytes[readnum-1] != 
					vdp50_table[VDP50_SEARCH_PKT].resp_end )
				{
					fprintf(stderr,"%s: %s: SEARCH packet mis-match\n",
						rpd->devname,funcname);
					return -1;
				}
				bcopy( &inbytes[4], bcdf, 3 );
				last = vdp50_FrameToInt(bcdf);
				if( inbytes[3] & VDP50_FRAME_NOT_FOUND )
				{	/* must search back to last valid frame */
					if( !vdp50_search( rpd, last, 1 ) )
					 fprintf(stderr,
					 "%s: %s: frame not found: now at %d, not %d\n",
					 rpd->devname,funcname,at,frame);
					else
					{
						fprintf(stderr,"%s: %s: search failed, resetting rpd\n",
							rpd->devname,funcname);
						if( vdp50_reset(rpd) )
							fprintf(stderr,"%s: %s: RESET FAILED!\n",
							  rpd->devname,funcname);
					}
				}
				else
					success = 1;
			}
		}
		else
			fprintf(stderr,"%s: %s: search error\n",
				rpd->devname,funcname);
	}
	
	if( success )
		return(0);
	else
		return -1;
}

/* ------------------------------------------------------------------------ */

vdp50_reset(rpd)

	RPD_ptr	rpd;
{
static char *funcname = "vdp50_reset";
int	ret = 0;

	if( vdp50_getstatus(rpd) )
	{
		rpd->state.volume_loaded = 0;
		rpd->state.not_responding = 1;
		return -1;
	}
	if( not_loaded )
	{
		if( vdp50_cmd(rpd,LOAD) )
		{
			ret = -1;
			rpd->state.volume_loaded = 0;
		}
		else
			rpd->state.volume_loaded = 1;
	}
	else
	{
		rpd->state.volume_loaded = 1;
	}

	if( vdp50_cmd(rpd,INDEX_OFF) )
		ret = -1;
	if( vdp50_varspeed(rpd,STOP) )
		ret = -1;
	if( vdp50_cmd(rpd,A1_ON) )
		ret = -1;
	if( vdp50_cmd(rpd,A2_ON) )
		ret = -1;

	if( ret < 0 )
	{
		rpd->state.not_responding = 1;
		fprintf(stderr,"rpd '%s' not responding\n",rpd->devname);
	}
	else
		rpd->state.not_responding = 0;
	return ret;
}

/* ------------------------------------------------------------------------ */

vdp50_segplay(rpd,f1,f2,wait)

	RPD_ptr	rpd;
	int	f1,f2;
	int	wait;		/* if true, hangs until done */
{
static char *funcname = "vdp50_segplay";
int	success = 0;
UBYTE	args[10];
VDP50_Frame	endf;
int		timeout;
int		res;
int		len;
int		readnum;
int 		i;

	len = abs(f1-f2);

	/* could take this out for variable-speed play */
	if( vdp50_SendSpeed( rpd,VDP50_NORMAL_PLAY, 1 ) )
	{
		fprintf(stderr,"%s: %s: couldn't set speed\n",
			rpd->devname,funcname);
		return -1;
	}

	if( vdp50_search(rpd,f1,1) )	/* must wait for now */
	{
		fprintf(stderr,"%s: %s: couldn't search to %d\n",
			rpd->devname,funcname,f1);
		return -1;
	}

	vdp50_IntToFrame( f2, endf );
	bcopy( endf, args, 3 );
	for( i=0; i<16; i++ )
		inbytes[i] = 0;
	
	if( !vdp50_ttyio(rpd->fd,VDP50_PLAY_U_PKT,args,wait) )
	{
		if( !wait )
			return 0;
		else
		{	/* since it's a play pkt, we must read the input
				(see vdp50_ttyio() below) */

			readnum = vdp50_table[VDP50_ACK_PKT].resp_bytes + 2 +
				vdp50_table[VDP50_PLAY_U_PKT].resp_bytes + 2;
			timeout = vdp50_TimeToPlay(len,VDP50_NORMAL_PLAY,1);
			res = ttyutil_read(rpd->fd,inbytes,readnum,timeout+1000);

/*	
			printf("segplay response:\n");
			for( i=0; i<readnum; i++ )
				printf("[%02x] ",inbytes[i]);
			printf("\n");
*/
			if( res == -2 )
			{
				fprintf(stderr,"%s: %s: timed out\n",
					rpd->devname, funcname );
			}
			else if( res == -1 )
				fprintf(stderr,"%s: %s: read error\n",
					rpd->devname, funcname );
			else if( res != readnum )
				fprintf(stderr,"%s: %s: read %d chars, not %d\n",
					rpd->devname, funcname,res,readnum );
			else
			{
				if( inbytes[0] != 
					vdp50_table[VDP50_ACK_PKT].resp_code
					||
				    inbytes[1] != 
					vdp50_table[VDP50_ACK_PKT].resp_end )
				{
					fprintf(stderr,"%s: %s: ACK packet mis-match\n",
						rpd->devname,funcname);
					return -1;
				}
				if( inbytes[2] != 
					vdp50_table[VDP50_PLAY_U_PKT].resp_code
					||
				    inbytes[readnum-1] != 
					vdp50_table[VDP50_PLAY_U_PKT].resp_end )
				{
					fprintf(stderr,"%s: %s: PLAY_U packet mis-match\n",
						rpd->devname,funcname);
					return -1;
				}
				/* check for frame-found */
				if( inbytes[3] & VDP50_FRAME_NOT_FOUND )
					fprintf(stderr,"%s: %s: frame not found\n",
						rpd->devname,funcname );
				else
					success = 1;
			}
		}
	}

	if( success )
		return(0);
	else
		return -1;
}

/* ------------------------------------------------------------------------ */

vdp50_ttyio( fd, pkt, args, wait )

	int	fd;
	int	pkt;
	UBYTE *	args;		/* the argument bytes for the packet */
	int	wait;		/* if true, wait for the reply */
{
static char *funcname = "vdp50_ttyio";
static int	retry = 0;
int	writenum, readnum;
int	timeout;
int	num = 0;

	ttyutil_debug = vdp50_debug;

	if( vdp50_table[pkt].cmd_code != VDP50_NO_COMMAND )
	{

		outbytes[0] = vdp50_table[pkt].cmd_code;
		num = vdp50_table[pkt].arg_bytes;
		if( num )
			bcopy( args, &outbytes[1], num );
		outbytes[1+num] = vdp50_table[pkt].cmd_end;

		writenum = num+2;		/* cmd + args + end */

		ttyutil_clear(fd);		/* flush input; maybe a mistake ... */

		if( ttyutil_write( fd,outbytes,writenum,0 ) == -1 )
			return (-1);
	}

	readnum = vdp50_table[pkt].resp_bytes+2;	/* resp + args + end */
	if( readnum == 0 || !wait )
		return (0);
	
	/* caller must pick up the final input on these first four packets;
		this is due to uncertain length of
		timeout (too complicated to do here) */

	if( 	pkt == VDP50_SEARCH_PKT ||
		pkt == VDP50_PLAY_U_PKT ||
		pkt == VDP50_PLAY_US_PKT ||
		pkt == VDP50_SCAN_U_PKT )
	{
		return 0;		/* caller must pick up all data */
	}
	else if( pkt == VDP50_LOAD_PKT || pkt == VDP50_UNLOAD_PKT
			|| pkt == VDP50_EJECT_PKT )
		timeout = VDP50_LOAD_TIMEOUT;
	
	else				/* normal timeout (1/4 second) */
		timeout = 250;

	if( (num=ttyutil_read(fd,inbytes,readnum,timeout)) == -1 )
		return (-1);

	if( num==-2 )	/* timeout condition */
	{
		if( vdp50_debug )
		{
			if( num == -2 )
				printf("%s: NO RESPONSE, try %d\n",
					funcname,retry+1);
			else
				printf("%s: ERROR RESPONSE, try %d\n",
					funcname,retry+1);
		}

		if( retry++ < MAXRETRYS )
		{
		int rv;
			rv = vdp50_ttyio( fd, pkt, args, wait );
			retry = 0;
			return (rv);
		}
		else
		{
			retry = 0;
			fprintf(stderr,"%s: i/o timeout\n",funcname);
			return (-1);
		}
	}

	if( num != readnum )
	{
		fprintf(stderr,"%s: expected %d bytes, got %d\n",
			funcname,readnum,num);
		return -1;
	}

	if( inbytes[0] != vdp50_table[pkt].resp_code )
	{
		fprintf(stderr,"%s: response code does not match command\n",
			funcname );
		return -1;
	}

	if( inbytes[num-1] != vdp50_table[pkt].resp_end )
	{
		fprintf(stderr,"%s: response end code does not match command\n",
			funcname);
		return -1;
	}

	return 0;
}

/* ------------------------------------------------------------------------ */

vdp50_setfuncs( disc )

	RPD_ptr	disc;
{
	disc->reset = vdp50_reset;
	disc->cmd = vdp50_cmd;
	disc->search = vdp50_search;
	disc->segplay = vdp50_segplay;
	disc->getframe = vdp50_getframe;
	disc->varspeed = vdp50_varspeed;
	disc->jog = vdp50_jog;
	disc->record = NULL;
}

