/*
 * Copyright 1988, 1989, 1990, 1991 Massachusetts Institute of Technology
 */

/* pioneer.c : routines for Pioneer LD-V4200 videodisc player */

/* 
	Russell Sasnett
	GTE Laboratories / MIT Project Athena
	russ@athena.mit.edu
	4/2/90
*/

/* *** TUNABLES *** */

/* if following is defined, audio is heard at all speeds */
#define PIONEER_DONT_SQUELCH

/* *** end tunables *** */

#include "structs.h"
#include "pioneer.h"
#define MAXRETRYS 0		/* the number of times we try before giving up */

typedef unsigned char   UBYTE;

/* define a couple of bit-twiddling macros */

#define BITS_ON(b,m)            ((b) |= (m))
#define BITS_OFF(b,m)           ((b) &= ~(m))
#define BITS_TOGGLE(b,m)        ((b) ^= (m))


#define RPD_STOP_MARKER(rpd) ((pioneer_info_ptr)rpd->extension)->stop_marker


int		pioneer_debug = 0;
static	UBYTE	inbytes[32];
static	UBYTE	outbytes[32];

static  int     hours,mins,secs;  /* for CLV address conversion */
static  int     little_disc = 0;   /* is disc 8-inch instead of 12? */

typedef struct 
{
  int  needs_squelch;  /* if true, squelch audio when you get a chance */
  int  stop_marker;    /* if non-zero, the stop marker is to this frame;
			  need to send 'clear' to get rid of it */
} pioneer_info, *pioneer_info_ptr;

static struct cmdtbl
{
	int 	cmd_id;		/* from .h file */
	char *	format;		/* used for sprintf'ing */
	int 	nargs;		/* number of arguments */
	int 	resptype; 	/* type of response expected */
	int 	timeout;	/* msecs; error if resp takes longer than this */
} pioneer_cmdtbl[] = 
{

PIONEER_CLEAR_CMD,		"CL\r",	0, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,

PIONEER_DOOR_OPEN_CMD, 		"OP\r",	0, PIONEER_ACK_RESP,	PIONEER_OPEN_TIMEOUT,
PIONEER_REJECT_CMD,		"RJ\r",	0, PIONEER_ACK_RESP,	PIONEER_UNLOAD_TIMEOUT,
PIONEER_START_CMD,		"SA\r",	0, PIONEER_ACK_RESP,	PIONEER_LOAD_TIMEOUT,

PIONEER_PLAY_CMD,		"%dPL\r",1, PIONEER_ACK_RESP,	PIONEER_SPECIAL_TIMEOUT,
PIONEER_PAUSE_CMD,		"PA\r",	0, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_STILL_CMD,		"ST\r",	0, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,

PIONEER_STEP_FWD_CMD,		"SF\r",	0, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_STEP_REV_CMD,		"SR\r",	0, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,

PIONEER_SCAN_FWD_CMD,		"NF\r",	0, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_SCAN_REV_CMD,		"NR\r",	0, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,

PIONEER_MULTI_FWD_CMD,		"%dMF\r",1, PIONEER_ACK_RESP,	PIONEER_SPECIAL_TIMEOUT,
PIONEER_MULTI_REV_CMD,		"%dMR\r",1, PIONEER_ACK_RESP,	PIONEER_SPECIAL_TIMEOUT,

PIONEER_SPEED_CMD,		"%dSP\r",1, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_SEARCH_CMD,		"%dSE\r",1, PIONEER_ACK_RESP,	PIONEER_SEARCH_TIMEOUT,
PIONEER_STOP_MARKER_CMD,	"%dSM\r",1, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,

PIONEER_FRAME_MODE_CMD,		"FR\r",	0, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_TIME_MODE_CMD,		"TM\r",	0, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_CHAPTER_MODE_CMD,	"CH\r",	0, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,

PIONEER_AUDIO_CONTROL_CMD,	"%dAD\r",1, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_VIDEO_CONTROL_CMD,	"%dVD\r", 1, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,

PIONEER_FRAME_NO_CMD,		"?F\r",	0, PIONEER_ADDR_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_TIME_NO_CMD,		"?T\r",	0, PIONEER_ADDR_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_CHAPTER_NO_CMD,		"?C\r",	0, PIONEER_ADDR_RESP,	PIONEER_STD_TIMEOUT,

PIONEER_MODEL_CMD,		"?X\r",	0, PIONEER_MODEL_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_PLAYER_STATUS_CMD,	"?P\r",	0, PIONEER_PLAYER_STATUS_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_DISC_STATUS_CMD,	"?D\r",	0, PIONEER_DISC_STATUS_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_COMM_STATUS_CMD,	"?M\r",	0, PIONEER_COMM_STATUS_RESP,	PIONEER_STD_TIMEOUT,

PIONEER_KEY_LOCK_CMD,		"%dKL\r",1, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_COMM_MODE_CMD,		"%dCM\r",1, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,

PIONEER_REG_A_CMD,		"%dRA\r",1, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_REG_B_CMD,		"%dRB\r",1, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_REG_C_CMD,		"%dRC\r",1, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,

PIONEER_DISPLAY_CONTROL_CMD,	"%dDS\r",1, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_CLEAR_SCREEN_CMD,	"CS\r",	1, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_PRINT_STRING_CMD,	"%dPR\r%s\r", 2, PIONEER_PRINT_RESP,	PIONEER_STD_TIMEOUT,

PIONEER_MULTI_FWD_NO_ADDR_CMD,	"MF\r",	0, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_MULTI_REV_NO_ADDR_CMD,	"MR\r",	0, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,
PIONEER_PLAY_NO_ADDR_CMD,	"PL\r",	0, PIONEER_ACK_RESP,	PIONEER_STD_TIMEOUT,

PIONEER_FIND_LAST_ADDR_CMD,	"LOSE\r", 0, PIONEER_ACK_RESP,	PIONEER_SEARCH_TIMEOUT,

};

#define NUM_PIONEER_CMDS	sizeof(pioneer_cmdtbl) / sizeof(struct cmdtbl)

static struct resptbl
{
	int resp_id;  		/* from .h file */
	int nbytes;		/* bytes in response */
} pioneer_resptbl[] =
{
	PIONEER_ACK_RESP,		2,	/* "R\r" */
	PIONEER_ADDR_RESP,		6,	/* "00000\r */
	PIONEER_PLAYER_STATUS_RESP,	4,	/* "P00\r" */
	PIONEER_DISC_STATUS_RESP,	6,	/* "XXXXX\r" */
	PIONEER_COMM_STATUS_RESP,	4,	/* "CMn\r" */
	PIONEER_MODEL_RESP,		8,	/* "P1502xx\r" */
	PIONEER_PRINT_RESP,		4,	/* "R\rR\r" */
	PIONEER_ERR_RESP,		4,	/* "Enn\r" */
};

#define NUM_PIONEER_RESPS	sizeof(pioneer_resptbl) / sizeof(struct resptbl)

static struct errtbl
{
	char *errstr;
	char *explanation;
} pioneer_errtbl[] = 
{
	PIONEER_COMM_ERR,	"basic communications error",
	PIONEER_FUNC_ERR,	"illegal or impossible request",
	PIONEER_ARG_ERR,	"missing argument",
	PIONEER_NODISC_ERR,	"disc is not loaded",
	PIONEER_SEARCH_ERR,	"search address not found",
	PIONEER_FOCUS_ERR,	"player can't focus on disc",
	PIONEER_PICSTOP_ERR,	"player hit picture stop code on disc",
	PIONEER_PANIC_ERR,	"panic condition; unrecoverable error",
};

#define NUM_PIONEER_ERRS	sizeof(pioneer_errtbl) / sizeof(struct errtbl)


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

static int
pioneer_SetAudioState( rpd, argp )

	RPD_ptr	rpd;
	int *argp;
{
  *argp = 0;
  if( rpd->state.audio1_on )
    *argp += PIONEER_CH1_MASK;

  if( rpd->state.audio2_on )
    *argp += PIONEER_CH2_MASK;
    return 0;
}

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

pioneer_cmd(rpd,num)
     RPD_ptr	rpd;
     int 	num;
{
  static char *funcname = "pioneer_cmd";
  int	success = 0;
  int	args[4];	/* assumes these are all 0 */
  int	frame;
  int forked = 0;
  
  /* note that with the audio, must set the bits corresponding
     to the current state of the software */
  
  switch(num)
    {
    case INDEX_ON:
      args[0] = PIONEER_DISPLAY_ON;
      if( !pioneer_ttyio( rpd->fd, PIONEER_DISPLAY_CONTROL_CMD, args, 1 ) )
	{
	  rpd->state.indexon = 1;
	  success = 1;
	}
      break;
    case INDEX_OFF:
      args[0] = PIONEER_DISPLAY_OFF;
      if( !pioneer_ttyio( rpd->fd, PIONEER_DISPLAY_CONTROL_CMD, args, 1 ) )
	{
	  rpd->state.indexon = 0;
	  success = 1;
	}
      break;
    case INDEX_TOGGLE:
      if (rpd->state.indexon) {
	if( !pioneer_cmd( rpd, INDEX_OFF ) )
		success = 1;
      }
      else {
	if( !pioneer_cmd( rpd, INDEX_ON ) )
		success = 1;
      }
      break;

    case A1_ON:
      args[0] = 0;
      rpd->state.audio1_on = 1;
      pioneer_SetAudioState( rpd, &args[0] );
      if( !pioneer_ttyio( rpd->fd, PIONEER_AUDIO_CONTROL_CMD, args, 1 ) )
	{
	  success = 1;
	}
      break;
    case A1_OFF:
      args[0] = 0;
      rpd->state.audio1_on = 0;
      pioneer_SetAudioState( rpd, &args[0] );
      if( !pioneer_ttyio( rpd->fd, PIONEER_AUDIO_CONTROL_CMD, args, 1 ) )
	{
	  success = 1;
	}
      break;
    case A2_ON:
      args[0] = 0;
      rpd->state.audio2_on = 1;
      pioneer_SetAudioState( rpd, &args[0] );
      if( !pioneer_ttyio( rpd->fd, PIONEER_AUDIO_CONTROL_CMD, args, 1 ) )
	{
	  success = 1;
	}
      break;
    case A2_OFF:
      args[0] = 0;
      rpd->state.audio2_on = 0;
      pioneer_SetAudioState( rpd, &args[0] );
      if( !pioneer_ttyio( rpd->fd, PIONEER_AUDIO_CONTROL_CMD, args, 1 ) )
	{
	  success = 1;
	}
      break;
    case SQUELCH_ON:
      args[0] = PIONEER_AV_SQUELCH_ON;
      if( !pioneer_ttyio( rpd->fd, PIONEER_REG_B_CMD, args, 1 ) )
	{
	  success = 1;
	}
      break;
    case SQUELCH_OFF:
      args[0] = PIONEER_AV_SQUELCH_OFF;
      if( !pioneer_ttyio( rpd->fd, PIONEER_REG_B_CMD, args, 1 ) )
	{
	  success = 1;
	}
      break;
    case STARTLOAD:
      if( pioneer_getstatus(rpd) ) {
	bsdsyslog(LOG_NOTICE,"%s: can't get status\n",funcname);
	return -1;
      }
      if( rpd->state.ejected )  /* don't load if door is open */
	return -1;
      pioneer_ttyio( rpd->fd, PIONEER_START_CMD, args, 0 );
      return(PIONEER_LOAD_TIMEOUT);  /* returns milliseconds */
      break;
    case ENDLOAD:
      if( !rpd->state.ejected ) {
	if (ttyutil_read(rpd->fd, inbytes,
			 pioneer_resptbl[PIONEER_ACK_RESP].nbytes,
			 PIONEER_STD_TIMEOUT) == -1) {
	  bsdsyslog(LOG_NOTICE,"%s: i/o timeout",funcname);
	  rpd_error(rpd);
	  return(-1);
	}
	if( inbytes[0] != 'R' ) {
	  bsdsyslog(LOG_NOTICE,"%s: error on spinup response",funcname);
	  rpd_error(rpd);
	  return(-1);
	}
      }

      if(pioneer_getstatus(rpd))
	    return -1;

      if( !rpd->state.volume_loaded || rpd->state.ejected ) {
	bsdsyslog(LOG_NOTICE,"%s: error on spinup; still not loaded",funcname);
	rpd_error(rpd);
	return(-1);
      }

      rpd->state.volume_loaded = 1;

      if( rpd->state.CLV ) {
	if( pioneer_ttyio( rpd->fd, PIONEER_TIME_MODE_CMD, args, 1) )
	  {
	    bsdsyslog(LOG_NOTICE,"%s: error setting CLV time mode",funcname);
	    rpd_error(rpd);
	  }
      }
      else if(pioneer_ttyio( rpd->fd, PIONEER_FRAME_MODE_CMD, args, 1))
	{
	  bsdsyslog(LOG_NOTICE,"%s: error setting CAV frame mode",funcname);
	  rpd_error(rpd);
	}

#ifdef OBSOLETE
      /* lock the front-panel keys */

      args[0] = PIONEER_LOCK;
      if( pioneer_ttyio( rpd->fd, PIONEER_KEY_LOCK_CMD, args, 1 ))
	{
	  bsdsyslog(LOG_NOTICE,"%s: error locking front panel buttons",funcname);
	  rpd_error(rpd);
	}
#endif

      /* on pioneer, looks like you must search to home frame after load
         in order to initiate playback of home frame */

      rpd_setframe(rpd,-1);
      rpd->firstframe = pioneer_getframe(rpd);
      args[0] = rpd->firstframe;
      pioneer_search(rpd,rpd->firstframe,1);
      rpd_setspeed(rpd,0);
      rpd_setframe(rpd, rpd->firstframe);
      success = 1;
      return(2);  /* returns seconds */
      break;
    case FORKLOAD:
      if (pioneer_getstatus(rpd) && pioneer_getstatus(rpd)) return -1;
      if( rpd->state.ejected ) return -1;
      if (rpd->state.volume_loaded == 1) return(-1);
      forked = 1;
      if (fork() > 0) return(0);
    case LOAD:
      if (pioneer_getstatus(rpd) && pioneer_getstatus(rpd)) return -1;
      if( rpd->state.ejected ) return -1;
      if (rpd->state.volume_loaded == 1) 
	return(0);
      if( !pioneer_ttyio( rpd->fd, PIONEER_START_CMD, args, 1 ) )
	{

	  if(pioneer_getstatus(rpd) && pioneer_getstatus(rpd))
	    return -1;

	  if( !rpd->state.volume_loaded || rpd->state.ejected ) {
	    bsdsyslog(LOG_NOTICE,"%s: error on spinup; still not loaded",funcname);
	    rpd_error(rpd);
	    return(-1);
	  }

	  rpd->state.volume_loaded = 1;

	  if( rpd->state.CLV ) {
	    if( pioneer_ttyio( rpd->fd, PIONEER_TIME_MODE_CMD, args, 1) )
	      {
		bsdsyslog(LOG_NOTICE,"%s: error setting CLV time mode",funcname);
		rpd_error(rpd);
	      }
	  }
	  else if(pioneer_ttyio( rpd->fd, PIONEER_FRAME_MODE_CMD, args, 1))
	    {
	      bsdsyslog(LOG_NOTICE,"%s: error setting CAV frame mode",funcname);
	      rpd_error(rpd);
	    }

	  /* lock the front-panel keys */

	  args[0] = PIONEER_LOCK;
	  if( pioneer_ttyio( rpd->fd, PIONEER_KEY_LOCK_CMD, args, 1 ))
	    {
	      bsdsyslog(LOG_NOTICE,"%s: error locking front panel buttons",funcname);
	      rpd_error(rpd);
	    }

	  /* on pioneer, looks like you must search to home frame after load
	     in order to initiate playback of home frame */

	  rpd_setframe(rpd,-1);
	  rpd_setspeed(rpd,0);
#ifdef OBSOLETE
	  rpd->firstframe = pioneer_getframe(rpd);
	  args[0] = rpd->firstframe;
	  pioneer_search(rpd,rpd->firstframe,1);
	  rpd_setspeed(rpd,0);
	  rpd_setframe(rpd, rpd->firstframe);
	  success = 1;
	  sleep(2);
	  if( pioneer_cmd(rpd,INDEX_OFF) )
	    success = 0;
	  if( pioneer_varspeed(rpd,0) )
	    success = 0;
	  if( pioneer_cmd(rpd,A1_ON) )
	    success = 0;
	  if( pioneer_cmd(rpd,A2_ON) )
	    success = 0; 
#endif /* OBSOLETE */
	}
      else
	{
	  bsdsyslog(LOG_NOTICE,"%s, %s: load failure\n",rpd->devname, rpd->port);
	  rpd->state.volume_loaded = 0;
	  break;
	}
      break;
    case UNLOAD:
      /* on pioneer, an UNLOAD command is processed as an EJECT if
	 the disc is already spun down; so get current status first */
      if( pioneer_getstatus(rpd) ) {
	success = 0;
	break;
      }
      if( !rpd->state.volume_loaded || rpd->state.ejected ) {
	success = 1;
	break;
      }
      if( !pioneer_ttyio( rpd->fd, PIONEER_REJECT_CMD, args, 1 ))
	{
	  rpd->state.volume_loaded = 0;
	  rpd->volume[0] = 0;
	  success = 1;
	  rpd_setspeed (rpd, 0);
	  rpd_setframe (rpd, -1);
	}
      else
	{
	  bsdsyslog(LOG_NOTICE,"%s, %s: unload failure\n",rpd->devname,rpd->port);
	}
      break;
    case EJECT:
      if( pioneer_getstatus(rpd) ) {
	success = 0;
	break;
      }
      if( rpd->state.ejected ) {
	success = 1;
	break;
      }
      if( pioneer_ttyio( rpd->fd, PIONEER_DOOR_OPEN_CMD, args, 1 ))
	{
	  bsdsyslog(LOG_NOTICE,"%s, %s: eject failure\n",rpd->devname, rpd->port);
	}
      else
	{
	      rpd->state.ejected = 1;
	      rpd->state.volume_loaded = 0;
	      rpd->lastframe = rpd->firstframe = -1;
	      success = 1;
	      rpd_setspeed (rpd, 0);
	      rpd_setframe (rpd, -1);
	}
      break;
      
    default:
      bsdsyslog(LOG_NOTICE,"%s, %s: %s: illegal request %d\n",
		rpd->devname, rpd->port,funcname,num);
      break;
    }
  if (forked) _exit(0);
  if( success ) {
    rpd_clear_error(rpd);
    return(0);
  }
  else {
    rpd_error(rpd);
    /* need_to_rebuild_list = 1; */
    return -1;
  }
}

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

/* in pioneer_varspeed, forget the scan mode; it takes too long, and
   asynch galatea packets can force it to get a long series of scans,
   which is really not what you want */

pioneer_varspeed(rpd,num)

	RPD_ptr	rpd;
	int	num;
{
  static char *funcname = "pioneer_varspeed";
  int	success = 0;
  int	args[4];
  int	range;
  int	speed;
  int	dir;
  int   realspeed;
  int   fps;
#ifdef notdef
  int   doscan = 0;
#endif

  /* global ugliness here gets around the problem of a STOP_MARKER which
     gets left over by a segplay which doesn't wait; the next command
     affecting the player's speed or frame should get rid of it with
     the CLEAR command */

  if(RPD_STOP_MARKER(rpd))
    {
      if(pioneer_ttyio(rpd->fd,PIONEER_CLEAR_CMD,args,0))
	{
	  bsdsyslog(LOG_NOTICE,"%s, %s: %s: can't clear old STOP_MARKER\n",
		    rpd->devname,rpd->port,funcname);
	  /* need_to_rebuild_list = 1; */
	  rpd_error(rpd);
	  return -1;
	}    
      RPD_STOP_MARKER(rpd) = 0;
    }

  if(rpd->state.CLV && num) 
    num = (num <= 0) ? 0 : 30;
  
  if(num) {
    speed = abs(num);
    realspeed = PIONEER_fps_to_speed_arg(speed);
    if(realspeed > 255)
      {
      realspeed = 255;
#ifdef notdef
      doscan = 1;
#endif
    }
    else if( realspeed < 1)
      realspeed = 1;

    if(num < 0)
      dir = -1;
    else
      dir = 1;

    fps = PIONEER_speed_arg_to_fps(realspeed);
    fps *= dir;

  } else {
    if (!rpd->state.CLV) {
      if(pioneer_ttyio(rpd->fd,PIONEER_STILL_CMD,args,1))
      {
	bsdsyslog(LOG_NOTICE,"%s, %s: %s: can't stop\n",
		  rpd->devname,rpd->port,funcname);
	/* need_to_rebuild_list = 1; */
	rpd_error(rpd);
	return -1;
      }
    }
    else if(pioneer_ttyio(rpd->fd,PIONEER_PAUSE_CMD,args,1))
      {
	bsdsyslog(LOG_NOTICE,"%s, %s: %s: can't pause CLV disc\n",
		  rpd->devname,rpd->port,funcname);
	/* need_to_rebuild_list = 1; */
	rpd_error(rpd);
	return -1;
      }
    rpd_setspeed (rpd, -1);
    pioneer_getframe (rpd);
    rpd_setspeed (rpd, 0);
    rpd_clear_error(rpd);
    return(0);
  }

#ifdef OBSOLETE
  if( ((pioneer_info_ptr)rpd->extension)->needs_squelch )
    pioneer_set_squelch(rpd);
#endif /* OBSOLETE */
  
  rpd_setframe (rpd, -1);

  if(!rpd->state.CLV) {
    args[0] = realspeed;
    if(pioneer_ttyio(rpd->fd,PIONEER_SPEED_CMD,args,1))
      {
	bsdsyslog(LOG_NOTICE,"%s, %s: %s: can't set speed\n",
		  rpd->devname,rpd->port,funcname);
	/* need_to_rebuild_list = 1; */
	rpd_error(rpd);
	return -1;
      }
  }

  if( dir > 0 ) {
    if(num == 30) {
      if( pioneer_ttyio(rpd->fd,PIONEER_PLAY_NO_ADDR_CMD,args,1))
	{
	  bsdsyslog(LOG_NOTICE,"%s, %s: %s: failed play cmd\n",
		    rpd->devname,rpd->port,funcname);
	  /* need_to_rebuild_list = 1; */
	  rpd_error(rpd);
	  return COULDNT_CHANGE_SPEED;
	}
    } else 
      {
	if(pioneer_ttyio(rpd->fd,PIONEER_MULTI_FWD_NO_ADDR_CMD,args,1))
	  {
	    bsdsyslog(LOG_NOTICE,"%s, %s: %s: failed multi-speed fwd cmd\n",
		      rpd->devname,rpd->port,funcname);
	    /* need_to_rebuild_list = 1; */
	    rpd_error(rpd);
	    return -1;
	  }
#ifdef notdef
	if( doscan )
	  if(pioneer_ttyio(rpd->fd,PIONEER_SCAN_FWD_CMD,args,1))
	    {
	      bsdsyslog(LOG_NOTICE,"%s, %s: %s: failed fwd scan cmd\n",
		      rpd->devname,rpd->port,funcname);
	      /* need_to_rebuild_list = 1; */
	      rpd_error(rpd);
	      return -1;
	    }
#endif
      }
  } else {
    if(pioneer_ttyio(rpd->fd,PIONEER_MULTI_REV_NO_ADDR_CMD,args,1))
      {
	bsdsyslog(LOG_NOTICE,"%s, %s: %s: failed multi-speed rev cmd\n",
		  rpd->devname,rpd->port,funcname);
	/* need_to_rebuild_list = 1; */
	rpd_error(rpd);
	return -1;
      }
#ifdef notdef
    if( doscan )
      if(pioneer_ttyio(rpd->fd,PIONEER_SCAN_REV_CMD,args,1))
	{
	  bsdsyslog(LOG_NOTICE,"%s, %s: %s: failed rev scan cmd\n",
		    rpd->devname,rpd->port,funcname);
	  /* need_to_rebuild_list = 1; */
	  rpd_error(rpd);
	  return -1;
	}
#endif
  }

  rpd_clear_error(rpd);
  rpd_setspeed(rpd,fps);
  return fps;
}

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

pioneer_jog(rpd,num)

	RPD_ptr	rpd;
	int	num;
{
  int	success = 0;
  int	args[4];
  int	i;
  int	dir;

  if(rpd->speed)
    pioneer_varspeed(rpd,0);
  
  if( rpd->state.CLV )
    return -1;  /* can't step a CLV disc */

  if( num == 0)
    return 0;

  if( num<0 ) {
      dir = PIONEER_STEP_REV_CMD;
      num = -num;
    }
  else
    dir = PIONEER_STEP_FWD_CMD;
  
  for( i=0; i<num; i++ )
    {
      if( !pioneer_ttyio(rpd->fd, dir, args, 1) )
	    ++success;
    }
  
  if( success == num) {
    if (rpd_getframe(rpd) < 0)
      rpd_setframe (rpd, pioneer_getframe(rpd));
    else {
      if( dir == PIONEER_STEP_FWD_CMD )
	rpd_setframe(rpd, rpd_getframe(rpd) + num );
      else
	rpd_setframe(rpd, rpd_getframe(rpd) - num );
    }
    rpd_setspeed (rpd,0);
    rpd_clear_error(rpd);
    return(0);
  } else {
    /* need_to_rebuild_list = 1; */
    rpd_error(rpd);
    return -1;
  }
  
}

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

pioneer_getframe(rpd)

	RPD_ptr	rpd;
{
  static char *funcname = "pioneer_getframe";
  int	success = 0;
  int	args[4];
  int	frame;

  if (rpd_getspeed (rpd) == 0 && rpd_getframe(rpd) >= 0) 
    return (rpd_getframe(rpd));

  if( rpd->state.CLV ) {
    if( pioneer_ttyio(rpd->fd, PIONEER_TIME_NO_CMD, args, 1) )
      bsdsyslog(LOG_NOTICE,"%s, %s: %s: can't get CLV time\n",
		rpd->devname, rpd->port, funcname);
    else
      success = 1;
  } else {
    if( pioneer_ttyio(rpd->fd, PIONEER_FRAME_NO_CMD, args, 1) )
      bsdsyslog(LOG_NOTICE,"%s, %s: %s: can't get frame number\n",
		rpd->devname, rpd->port, funcname);    
    else
      success = 1;
  }

  if(success) {
    inbytes[5] = 0;
    if( rpd->state.CLV ) {
      hours = inbytes[0] - '0';
      mins  = (inbytes[1] - '0') * 10 + inbytes[2] - '0';
      secs  = (inbytes[3] - '0') * 10 + inbytes[4] - '0';
      frame = HMS_TO_FRAMES(hours,mins,secs);
    }
    else 
      frame = atoi(inbytes);
    if (rpd_getspeed(rpd) == 0)
      rpd_setframe (rpd, frame);
    else
      rpd_setframe(rpd, -1);
    rpd_clear_error(rpd);
    return(frame);
  } else {
    /* need_to_rebuild_list = 1; */
    rpd_error(rpd);
    rpd_setframe(rpd, -1);
    return -1;
  }
}

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

pioneer_getstatus(rpd)

	RPD_ptr	rpd;
{
  static char *funcname = "pioneer_getstatus";
  int	success = 0;
  int	args[4];

  if( pioneer_ttyio(rpd->fd, PIONEER_PLAYER_STATUS_CMD, args, 1) )
    bsdsyslog(LOG_NOTICE,"%s, %s: %s: can't get player status\n",
	      rpd->devname,rpd->port,funcname);
  else if( inbytes[0] == 'P' ) {
    success = 1;
    if( inbytes[2] > '1' )
      rpd->state.volume_loaded = 1;
    else
      rpd->state.volume_loaded = 0;
    if( inbytes[2] == '0' )
	rpd->state.ejected = 1;
    else
	rpd->state.ejected = 0;
    if( pioneer_ttyio(rpd->fd, PIONEER_DISC_STATUS_CMD, args, 1) )
      bsdsyslog(LOG_NOTICE,"%s, %s: %s: can't get disc status\n",
		rpd->devname,rpd->port,funcname);
    else {
      if( inbytes[1] == '1' ) {
	/* disc is CLV mode; can only do forward play
	   and search */
	rpd->state.CLV = 1;

	if( rpd->state.volume_loaded && 
	   pioneer_ttyio( rpd->fd, PIONEER_TIME_MODE_CMD, args, 1) )
	  {
	    bsdsyslog(LOG_NOTICE,"%s: error setting CLV time mode",funcname);
	    rpd_error(rpd);
	  }
      }
      else if( inbytes[1] == '0' ) {
	rpd->state.CLV = 0;

	if( rpd->state.volume_loaded && 
	   pioneer_ttyio( rpd->fd, PIONEER_FRAME_MODE_CMD, args, 1) )
	  {
	    bsdsyslog(LOG_NOTICE,"%s: error setting CAV frame mode",funcname);
	    rpd_error(rpd);
	  }
      }
      if( inbytes[2] != '1' )
	little_disc = 0;  /* 12-inch */
      else
	little_disc = 1;
    }
  }
  else
    bsdsyslog(LOG_NOTICE,"%s, %s: %s: can't get player status, (2)\n",
	      rpd->devname,rpd->port,funcname);
  if( success ) {
    rpd_clear_error(rpd);
    return(0);
  }
  else {
    /* need_to_rebuild_list = 1; */
    rpd_error(rpd);
    return -1;
  }
}	

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

pioneer_search(rpd,frame,wait)
	RPD_ptr	rpd;
	int	frame;
	int	wait;		/* if true, hangs until it gets there 
					or times out */
{
  static char *funcname = "pioneer_search";
  int	success = 0;
  int	args[4];
  char  hms_str[10];

  if( rpd->lastframe == -1 )
    pioneer_findlastframe(rpd);

  if (frame < rpd->firstframe || frame > rpd->lastframe) {
    if (DEBUG) printf("pioneer_search: frame %d outside of range %d-%d\n",
		      frame, rpd->firstframe, rpd->lastframe);
    return -1;
  }

  if(rpd->state.CLV) {
    FRAMES_TO_HMS(frame,hours,mins,secs);
    sprintf(hms_str,"%1d%02d%02d",hours,mins,secs);
    frame = atoi(hms_str);
  }

  args[0] = frame;
  if( !pioneer_ttyio(rpd->fd, PIONEER_SEARCH_CMD, args, wait) ) {
    rpd_setframe (rpd, -1);
    rpd_setspeed (rpd, 0);
    pioneer_getframe (rpd);
    rpd_clear_error(rpd);
    return(0);
  } else {
    bsdsyslog(LOG_NOTICE,"pioneer_search: unable to search to frame %d",
	      frame);
    rpd_error(rpd);
    rpd_setframe (rpd, -1);
    return -1;
  }
}

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

pioneer_reset(rpd)

	RPD_ptr	rpd;
{
  int	ret = 0;
  int   args[4];

  if( pioneer_ttyio(rpd->fd,PIONEER_CLEAR_CMD,args,1))
	ret = -1;

  if( pioneer_getstatus(rpd) )
    {
      rpd->state.not_responding = 1;
      return -1;
    }
  if( rpd->state.volume_loaded ) {

    if( pioneer_cmd(rpd,INDEX_OFF) )
      ret = -1;
    if( pioneer_varspeed(rpd,0) )
      ret = -1;
    if( pioneer_cmd(rpd,A1_ON) )
      ret = -1;
    if( pioneer_cmd(rpd,A2_ON) )
      ret = -1;       

    if (pioneer_cmd(rpd, SQUELCH_ON))
	ret = -1;



#ifdef OBSOLETE
#ifdef PIONEER_DONT_SQUELCH
    if( !rpd->state.CLV ) {
      args[0] = PIONEER_AUDIO_SQUELCH_OFF;
      if( pioneer_ttyio( rpd->fd, PIONEER_REG_B_CMD, args, 1 ) )
	ret = -1;
    } else {
      args[0] = PIONEER_AV_SQUELCH_ON;
      if( pioneer_ttyio( rpd->fd, PIONEER_REG_B_CMD, args, 1 ) )
	ret = -1;
    }
#else
    args[0] = PIONEER_AV_SQUELCH_ON;
    if( pioneer_ttyio( rpd->fd, PIONEER_REG_B_CMD, args, 1 ) )
      ret = -1;
#endif
#endif /* OBSOLETE */

  }

  rpd_setspeed(rpd, 0);
  rpd_setframe(rpd, -1);

  if( ret < 0 )
    {
      rpd->state.not_responding = 1;
      bsdsyslog(LOG_NOTICE,"%s, %s: not responding\n",rpd->devname, rpd->port);
    }
  else {
    rpd->state.not_responding = 0;
    rpd_clear_error(rpd);
    rpd->state.inited = 1;
  }
  return ret;
}

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

pioneer_segplay(rpd,f1,f2,speed,wait)
	RPD_ptr	rpd;
	int	f1,f2;
        int     speed;
	int	wait;		/* if true, hangs until done */
{
  static char *funcname = "pioneer_segplay";
  int success = 0;
  int	args[4];
  int timeout;
  int res;
  int len;
  int readnum;
  int i;
  int realspeed;
  int range;
  int dir;
  int fps;

  /* f1 can be CURRENT_FRAME (0), indicating that the current frame is used,
     and no search should be made */

  if( f1 && speed < 0 && (f1 <= f2) ) {
    if (DEBUG) 
      printf("pioneer_segplay: illegal speed: f1 = %d, f2 = %d, speed = %d\n",
	     f1, f2, speed);
    return -1;
  }
  else if( f1 && speed > 0 && (f2 <= f1) ) {
    if (DEBUG) 
      printf("pioneer_segplay: illegal speed: f1 = %d, f2 = %d, speed = %d\n",
	     f1, f2, speed);
    return -1;
  }
  if (!speed || f1 == f2) {
    res += pioneer_varspeed(rpd,0);
    if (f1)
      res += pioneer_search(rpd,f1,1);
    rpd_setframe(rpd, pioneer_getframe(rpd));
    rpd_setspeed(rpd, 0);
#ifdef OBSOLETE
    rpd_clear_error(rpd);
#endif /* OBSOLETE */
    return(0);
  }

  /* if there's a stop marker lying around, clear it */

  if(RPD_STOP_MARKER(rpd) && RPD_STOP_MARKER(rpd) != f2)
    {
      if(pioneer_ttyio(rpd->fd,PIONEER_CLEAR_CMD,args,0))
	{
	  bsdsyslog(LOG_NOTICE,"%s, %s: %s: can't clear old stop marker\n",
		    rpd->devname,rpd->port,funcname);
	  /* need_to_rebuild_list = 1; */
	  rpd_error(rpd);
	  return -1;
	}    
      RPD_STOP_MARKER(rpd) = 0;
    }

  if(rpd->state.CLV && speed) {
    speed = 30;
    if( f2 < f1 )
      {
	int temp;

	temp = f1;
	f1 = f2;
	f2 = temp;
      }
  }

  if(f1 == CURRENT_FRAME)
    pioneer_getframe(rpd);

  /* if disc is in motion, and CURRENT_FRAME is specified, 
     may have to stop it momentarily to determine the
     proper direction to go in (by getting an exact current frame) */

  if(f1 == CURRENT_FRAME && rpd->speed)
    {      
      /* disc is already moving; see if we're inside the 'danger zone'; 
	 if so, stop disc and get current frame before changing rate;
	 otherwise, we might have passed the target and be going in
	 the wrong direction; note that rpd->frame has just been set
	 by DoPlaySeg() in dofuncs.c, if CURRENT_FRAME is specified */

      if( abs(f2 - rpd->frame) <= MAX_GETFRAME_ERROR(abs(rpd->speed)) )
	{
	  pioneer_varspeed(rpd, 0);
	  rpd_setframe(rpd, rpd_getframe(rpd));
	  /* reverse direction if need to */
	  if(f2 < rpd->frame && speed > 0)
	    speed = -1 * speed;
	  else if(f2 > rpd->frame && speed < 0)
	    speed = abs(speed);
	  else if(f2 == rpd->frame)
	    return (0);
	}
    }
  else if(f1 == CURRENT_FRAME && !rpd->speed && f2 == rpd->frame)
    {
      /* we're not moving and the target is where we already are */
      return 0;
    }

  realspeed = abs(speed);
  realspeed = PIONEER_fps_to_speed_arg(realspeed);
  if(realspeed > 255)
    realspeed = 255;
  else if( realspeed < 1)
    realspeed = 1;

  if(speed < 0)
    dir = -1;
  else
    dir = 1;

  fps = PIONEER_speed_arg_to_fps(realspeed);
  fps *= dir;
  
  if (f1) {
    if( pioneer_search(rpd,f1,1) )
      return -1;
  }

  rpd_setframe (rpd, -1);

  if(!wait)
    {
      /* set the stop marker if not waiting */

      args[0] = f2;
      if( pioneer_ttyio(rpd->fd,PIONEER_STOP_MARKER_CMD,args,1))
	{
	  bsdsyslog(LOG_NOTICE,"%s, %s: %s: can't set stop marker\n",
		    rpd->devname,rpd->port,funcname);
	  /* need_to_rebuild_list = 1; */
	  rpd_error(rpd);
	  return -1;
	}

      RPD_STOP_MARKER(rpd) = 0;  /* if this is non-zero, varspeed will 
				    immediately clear it */

      rpd_setspeed(rpd, pioneer_varspeed(rpd,speed));

      RPD_STOP_MARKER(rpd) = f2;

      return 0;
    }
  else   /* block */
    {
      args[0] = f2;

      if(speed == 30)
	{
	  if(pioneer_ttyio(rpd->fd,PIONEER_PLAY_CMD,args,1))
	    {
	      bsdsyslog(LOG_NOTICE,"%s, %s: %s: failed play cmd\n",
			rpd->devname,rpd->port,funcname);
	      /* need_to_rebuild_list = 1; */
	      rpd_error(rpd);
	      return -1;
	    }
	  else
	    success = 1;
	}
      else
	{
	  args[0] = realspeed;
	  if(pioneer_ttyio(rpd->fd,PIONEER_SPEED_CMD,args,1))
	    {
	      bsdsyslog(LOG_NOTICE,"%s, %s: %s: can't set speed\n",
			rpd->devname,rpd->port,funcname);
	      /* need_to_rebuild_list = 1; */
	      rpd_error(rpd);
	      return -1;
	    }
	  args[0] = f2;
	  if(dir > 0)
	    {
	      if(pioneer_ttyio(rpd->fd,PIONEER_MULTI_FWD_CMD,args,1))
		{
		  bsdsyslog(LOG_NOTICE,"%s, %s: %s: failed fwd cmd\n",
			    rpd->devname,rpd->port,funcname);
		  /* need_to_rebuild_list = 1; */
		  rpd_error(rpd);
		  return -1;
		}
	      else
		success = 1;
	    }
	  else
	    {
	      if(pioneer_ttyio(rpd->fd,PIONEER_MULTI_REV_CMD,args,1))
		{
		  bsdsyslog(LOG_NOTICE,"%s, %s: %s: failed rev cmd\n",
			    rpd->devname,rpd->port,funcname);
		  /* need_to_rebuild_list = 1; */
		  rpd_error(rpd);
		  return -1;
		}
	      else
		success = 1;
	    }
	}
    }
  if( success ) {
    rpd_setframe (rpd, f2);
    rpd_setspeed (rpd, 0);
    rpd_clear_error(rpd);
    return(0);
  } else {
    rpd_setframe (rpd, -1);
    rpd_setspeed( rpd, 0);
    rpd_error(rpd);
    return -1;
  }
}

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

pioneer_ttyio( fd, cmdnum, args, wait )

	int	fd;
	int	cmdnum;
	int *	args;		/* array of ints */
	int	wait;		/* if true, wait for the reply */
{
static char *funcname = "pioneer_ttyio";
static int	retry = 0;
int	writenum, readnum;
int	timeout;
int	num = 0;
int respnum = 0;

/*	ttyutil_debug = pioneer_debug;*/

	if( cmdnum < 0 || cmdnum >= NUM_PIONEER_CMDS )
	{
		bsdsyslog(LOG_NOTICE, "%s: given bad cmd number %d", 
		    funcname,cmdnum);
		return -1;
	}

	outbytes[0] = 0;


	if( pioneer_cmdtbl[cmdnum].nargs )
		sprintf(outbytes,pioneer_cmdtbl[cmdnum].format,args[0],args[1]);
	else
		strcpy(outbytes,pioneer_cmdtbl[cmdnum].format);

/*        if (DEBUG) printf("pioneer_ttyio: output = %s\n",outbytes);*/


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

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

	if(!wait)
		return 0;

	respnum = pioneer_cmdtbl[cmdnum].resptype;
	if( respnum < 0 || respnum >= NUM_PIONEER_RESPS )
	{
		bsdsyslog(LOG_NOTICE, "%s: bad resp index %d in cmd table index %d", 
		    funcname,respnum,cmdnum);
		return -1;
	}

	readnum = pioneer_resptbl[respnum].nbytes;
	timeout = pioneer_cmdtbl[cmdnum].timeout;

	num=ttyutil_read(fd,inbytes,readnum,timeout);
	if( num == -1 ) {
	  bsdsyslog(LOG_NOTICE, "%s: i/o timeout", 
		    funcname);
	  /* need_to_rebuild_list = 1; */
	  return -1;
	} else if( num==-2 )	/* timeout condition */
	{
		if( pioneer_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 = pioneer_ttyio( fd, cmdnum, args, wait );
			retry = 0;
			return (rv);
		}
		else
		{
			retry = 0;
			/* need_to_rebuild_list = 1; */
			bsdsyslog(LOG_NOTICE,"%s: i/o timeout\n",
				  funcname);
			return -1;
		}
	}

	if( num != readnum || inbytes[0] == 'E' )
	{
	  /* need_to_rebuild_list = 1; */
	  if(num && inbytes[0] == 'E')		/* check error list */
	  {
	  int i;
	  int nwaiting;
	  int temp;

		/* on error, make sure whole message is read in */

		nwaiting = ttyutil_testinput(fd);
		if(nwaiting)
		{
			temp = ttyutil_read(fd,&inbytes[num],nwaiting,PIONEER_STD_TIMEOUT);
			if(temp != nwaiting)
			{
				bsdsyslog(LOG_NOTICE,"%s: can't decipher error response\n",
					  funcname);
				return -1;
			}
			num += temp;
			inbytes[num] = 0;
		}
		
		/* check for match in errtbl */
		
		for(i=0;i<NUM_PIONEER_ERRS;i++)
			if(!strncmp(inbytes,pioneer_errtbl[i].errstr,num))
			{
				bsdsyslog(LOG_NOTICE,"%s: ERROR: %s\n",
					funcname,
					pioneer_errtbl[i].explanation);
				return -1;
			}
	  }

	  bsdsyslog(LOG_NOTICE,"%s: unknown error; expected %d bytes, got %d\n",
		    funcname,readnum,num);
	  return -1;
	}

	/* do minor sanity checks on resp type */

	switch(respnum)
	{
	case PIONEER_ACK_RESP:
	case PIONEER_PRINT_RESP:
		if(inbytes[0] != 'R')
		{
			bsdsyslog(LOG_NOTICE,"%s: ack response begins with '%c' not 'R'\n",
					funcname,inbytes[0]);
			return -1;
		}
		break;
	case PIONEER_PLAYER_STATUS_RESP:
	case PIONEER_MODEL_RESP:
		if(inbytes[0] != 'P')
		{
			bsdsyslog(LOG_NOTICE,"%s: ack response begins with '%c' not 'R'\n",
					funcname,inbytes[0]);
			return -1;
		}
		break;
	case PIONEER_COMM_STATUS_RESP:
		if(inbytes[0] != 'C')
		{
			bsdsyslog(LOG_NOTICE,"%s: ack response begins with '%c' not 'R'\n",
					funcname,inbytes[0]);
			return -1;
		}
		break;
	default:
		break;
	}

	return 0;
}


pioneer_proddev(rpd)

     RPD_ptr rpd;
{
  int args[4];
  static char *funcname = "pioneer_proddev";

	/* there's no way to query the device's state with
	regards to audio settings; so the first contact with
	each device should set the player to a known state */

#ifdef OBSOLETE
#ifdef PIONEER_DONT_SQUELCH
  ((pioneer_info_ptr)rpd->extension)->needs_squelch = 1;
#endif
#endif /* OBSOLETE */

  if( pioneer_getstatus(rpd) )
    return -1;
  if (rpd->state.ejected) {
    bsdsyslog(LOG_NOTICE,"%s, %s: lid open\n",
	      rpd->devname,rpd->port);
    return -1;
  }
#ifdef OBSOLETE
  if( !rpd->state.inited ) {
    pioneer_cmd(rpd,A1_ON);
    pioneer_cmd(rpd,A2_ON);
    pioneer_cmd(rpd,INDEX_OFF);

    pioneer_set_squelch(rpd);

    rpd->state.inited = 1;
  }
#endif /* OBSOLETE */
  rpd->state.inited = 1;
  return(0);
}

pioneer_set_squelch(rpd)

     RPD_ptr rpd;
{
int args[4];
static char *funcname = "pioneer_set_squelch";

    if(pioneer_getstatus(rpd))
      return -1;
    if( !((pioneer_info_ptr)rpd->extension)->needs_squelch )
      return -1;

#ifdef PIONEER_DONT_SQUELCH
    if( !rpd->state.volume_loaded ) {   /* can't tell what kind of disc yet */
      args[0] = PIONEER_AV_SQUELCH_ON;
      if( pioneer_ttyio( rpd->fd, PIONEER_REG_B_CMD, args, 1 ) )
	bsdsyslog(LOG_NOTICE,"%s, %s: %s: squelch enable failed\n",
		  rpd->devname,rpd->port,funcname);
    } else {
      if( !rpd->state.CLV ) {
	args[0] = PIONEER_AUDIO_SQUELCH_OFF;
	if( pioneer_ttyio( rpd->fd, PIONEER_REG_B_CMD, args, 1 ) )
	  bsdsyslog(LOG_NOTICE,"%s, %s: %s: squelch disable failed\n",
		    rpd->devname,rpd->port,funcname);
	else
	  ((pioneer_info_ptr)rpd->extension)->needs_squelch = 0;
      } else {
	args[0] = PIONEER_AV_SQUELCH_ON;
	if( pioneer_ttyio( rpd->fd, PIONEER_REG_B_CMD, args, 1 ) )
	  bsdsyslog(LOG_NOTICE,"%s, %s: %s: squelch enable failed\n",
		    rpd->devname,rpd->port,funcname);
	else
	  ((pioneer_info_ptr)rpd->extension)->needs_squelch = 0;
      }
    }
#else
    args[0] = PIONEER_AV_SQUELCH_ON;
    if( pioneer_ttyio( rpd->fd, PIONEER_REG_B_CMD, args, 1 ) )
      bsdsyslog(LOG_NOTICE,"%s, %s: %s: squelch enable failed\n",
		rpd->devname,rpd->port,funcname);
    else
      ((pioneer_info_ptr)rpd->extension)->needs_squelch = 0;
#endif

    return 0;
}

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

pioneer_setfuncs( disc )

	RPD_ptr	disc;
{
int i;

	/* perform basic sanity checks on i/o tables */

	for(i=0;i<NUM_PIONEER_CMDS;i++)
		if(pioneer_cmdtbl[i].cmd_id != i)
			  bsdsyslog(LOG_NOTICE,
				    "pioneer_setfuncs: corrupted command table\n");

	for(i=0;i<NUM_PIONEER_RESPS;i++)
		if(pioneer_resptbl[i].resp_id != i)
			  bsdsyslog(LOG_NOTICE,
				    "pioneer_setfuncs: corrupted response table\n");

	disc->reset = pioneer_reset;
	disc->proddev = pioneer_proddev;
	disc->cmd = pioneer_cmd;
	disc->search = pioneer_search;
	disc->segplay = pioneer_segplay;
	disc->getspeed = rpd_getspeed_f;
	disc->getframe = pioneer_getframe;
	disc->varspeed = pioneer_varspeed;
	disc->jog = pioneer_jog;
	disc->buildfreelist = NULL;
	disc->record = NULL;
	disc->firstframe = -1;
	disc->lastframe = -1;

        /* default state */
        disc->state.audio1_on = disc->state.audio2_on = 1;
        disc->state.indexon = 0;
        disc->state.inited = 0;
        /* rpd struct is calloc'ed, so can tell if initialized or not */
        if(!disc->extension)
	  disc->extension = calloc(1,sizeof(pioneer_info));
}

pioneer_findlastframe(rpd)
     
     RPD_ptr rpd;
{
int args[4];
int success = 0;

  if( rpd->lastframe != -1 )
    return -1;

  /* XXX */
  /* driver used to actually search for the last frame; but things got
     very wacky if you had some bad or unreadable frames near the leadout, 
     which would cause the driver to set a very low lastframe, like 5800;
     thereafter, you couldn't search past the lastframe, making the rest
     of the volume inaccessible; from now on, just do a simple calculation */
  
#ifdef notdef  /* old way */

  if( pioneer_ttyio( rpd->fd, PIONEER_FIND_LAST_ADDR_CMD, args, 1 ) )
    {
      /* well, we couldn't find it; either a comm. err or a bad disc;
	 instead of forcing the error to keep recurring, just set it
	 to a default */

      bsdsyslog(LOG_NOTICE,"pioneer_findlastframe() failed\n");

      if(rpd->firstframe != -1)
	{
	  if(!rpd->state.CLV)
	  {  /* This is buggy!  Would have to do a getstatus() first */
	    if( little_disc )
	      rpd->lastframe = 36000;
	    else
	      rpd->lastframe = 54000;
	  }
	  else
	  {
	    /* should calc from firstframe for CLV case */
	    rpd->lastframe = rpd->firstframe + HMS_TO_FRAMES(1,0,0);
	  }
	}
    }
  else {

    rpd->lastframe = pioneer_getframe(rpd);
    
    bsdsyslog(LOG_NOTICE,"pioneer_findlastframe() found %ld\n",rpd->lastframe);

    /* XXX */
    /* if the end of the disc is bad, you may get a bogus 
       end-of-disc address; try to detect this */

    if( rpd->lastframe < 0 || rpd->lastframe <= rpd->firstframe  )
      if(!rpd->state.CLV) {
	if( little_disc )
	  rpd->lastframe = 36000;
	else
	  rpd->lastframe = 54000;
      }
      else
	{
	  /* should calc from firstframe for CLV case */
	  rpd->lastframe = rpd->firstframe + HMS_TO_FRAMES(1,0,0);
	}
  }

#endif

   if(pioneer_getstatus(rpd))
     return -1;

   if(!rpd->state.CLV) {
     if( little_disc )
       rpd->lastframe = 36000;
     else
       rpd->lastframe = 54000;
   }
   else {
     /* should calc from firstframe for CLV case */
     rpd->lastframe = rpd->firstframe + HMS_TO_FRAMES(1,0,0);
   }

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



