/*
 * This file I did not write (just modified) and apparently
 * rusty@belch.berkeley.edu did. I pulled this file from
 * xcdplayer-NEC.tar.Z from tsx-11.mit.edu. I hold
 * no rights to it and take no responsibility for it
 * operation. Check the readme's with xcdplayer-NEC.tar.Z
 * for more information.
 *
 * For version 1.1, added #ifdef LINUX lines to allow Cohernet
 * (and other OS) compatibility.
 *
 * Mark Buckaway (mark@datasoft.com)
 */

#include <sys/types.h>

#ifdef LINUX
#include <linux/cdrom.h>
#else
#include <sys/cdrom.h>
#endif

#define SCSI_IOCTL_SEND_COMMAND 1

void dump( void *buffer, unsigned int length )
{
  unsigned int i;

  for (i=0; i<length; i++)
  {
    printf( "%02x ", (unsigned int) ((unsigned char *) buffer)[i] );
    if (i%16 == 15) { printf( "\n" ); }
  }
  printf( "\n" );

}

#define FROMBCD(X) (((X) >> 4)*10 + ((X)&0x0f))
#define TOBCD(X) (((X)/10 << 4) | ((X) % 10))

static   unsigned char min, sec, frame;

int nec_ioctl(int i, int j, char * c){
  unsigned char buffer[64];
  unsigned char *cmd;
  int status;

  memset(buffer, 0, sizeof(buffer));
  *( (int *)  buffer )		= 0;	/* length of input data */
  *( ((int *) buffer) + 1 )	= 0;	/* length of output buffer */

  cmd = (char *) ( ((int *) buffer) + 2 );

  switch(j){
  case CDROMVOLCTRL:
    return -1;
  case CDROMREADMODE2:
    return -1;
  case CDROMREADMODE1:
    return -1;
  case CDROMPLAYMSF:
    return -1;
  case CDROMSTART:
  case CDROMRESUME:
    cmd[0] = 0xd9;			/* INQUIRY */
    cmd[1] = 3;
    cmd[2] = min;
    cmd[3] = sec;
    cmd[4] = frame;
    cmd[9] = 1 << 6;			/* control */
    status = ioctl(i, SCSI_IOCTL_SEND_COMMAND, buffer );
    return status;
  case CDROMPAUSE:
    cmd[0] = 0xda;			/* INQUIRY */
    status = ioctl(i, SCSI_IOCTL_SEND_COMMAND, buffer );
    return status;
  case CDROMSTOP:
    cmd[0] = 0xdd;
    cmd[1] = 10;
    *( ((int *) buffer) + 1 )	= 10;	/* length of output buffer */
    status = ioctl(i, SCSI_IOCTL_SEND_COMMAND, buffer );
    if(status) return status;
    min = buffer[15];
    sec = buffer[16];
    frame = buffer[17];
    memset(buffer, 0, sizeof(buffer));
    cmd[0] = 0xd9;			/* INQUIRY */
    cmd[1] = 0;
    cmd[2] = min;
    cmd[3] = sec;
    cmd[4] = frame;
    cmd[9] = 1 << 6;			/* control */
    status = ioctl(i, SCSI_IOCTL_SEND_COMMAND, buffer );
    return status;
    return 0;
  case CDROMPLAYTRKIND:
    cmd[0] = 0xd8;			/* INQUIRY */
    cmd[2] = TOBCD(c[0]);
    cmd[9] = 2 << 6;			/* control */
    status = ioctl(i, SCSI_IOCTL_SEND_COMMAND, buffer );
    if(status) return status;
    memset(buffer, 0, sizeof(buffer));
    cmd[0] = 0xd9;			/* INQUIRY */
    cmd[1] = 3;
    cmd[2] = TOBCD(c[2]);
    cmd[9] = 2 << 6;			/* control */
    status = ioctl(i, SCSI_IOCTL_SEND_COMMAND, buffer );
    return status;
  case CDROMEJECT:
    cmd[0] = 0xdc;
    status = ioctl(i, SCSI_IOCTL_SEND_COMMAND, buffer );
    return status;
  case CDROMREADTOCHDR:
    cmd[0] = 0xde;
    *( ((int *) buffer) + 1 )	= 4;	/* length of output buffer */
    status = ioctl(i, SCSI_IOCTL_SEND_COMMAND, buffer );
    if(status) return status;
    c[0] = FROMBCD(buffer[8]);
    c[1] = FROMBCD(buffer[9]);
    return 0;
  case CDROMSUBCHNL:
    {
      struct cdrom_subchnl *subchnl;

      subchnl = (struct cdrom_subchnl *) c;

      cmd[0] = 0xdd;
      cmd[1] = 10;
      *( ((int *) buffer) + 1 )	= 10;	/* length of output buffer */
      status = ioctl(i, SCSI_IOCTL_SEND_COMMAND, buffer );
      if(status) return status;
      switch(buffer[8]){
      case 0:
	subchnl->cdsc_audiostatus = CDROM_AUDIO_PLAY; 
	break;
      case 1:
      case 2:
	subchnl->cdsc_audiostatus = CDROM_AUDIO_PAUSED; 
	break;
      case 3:
	subchnl->cdsc_audiostatus = CDROM_AUDIO_COMPLETED; 
	break;
      default:
	subchnl->cdsc_audiostatus = CDROM_AUDIO_INVALID;
	break;
      };
      subchnl->cdsc_format = CDROM_MSF;
      subchnl->cdsc_ctrl = buffer[9];
      subchnl->cdsc_trk = FROMBCD(buffer[10]);
      subchnl->cdsc_ind = FROMBCD(buffer[11]);

      subchnl->cdsc_reladdr.msf.minute = FROMBCD(buffer[12]);
      subchnl->cdsc_reladdr.msf.second = FROMBCD(buffer[13]);
      subchnl->cdsc_reladdr.msf.frame = FROMBCD(buffer[14]);
      subchnl->cdsc_absaddr.msf.minute = FROMBCD(buffer[15]);
      subchnl->cdsc_absaddr.msf.second = FROMBCD(buffer[16]);
      subchnl->cdsc_absaddr.msf.frame = FROMBCD(buffer[17]);
      return 0;
    };
  case CDROMREADTOCENTRY:
    {
      struct cdrom_tocentry *tocentry;

      tocentry = (struct cdrom_tocentry *) c;

      cmd[0] = 0xde;
      cmd[1] = 2;
      if(tocentry->cdte_track != 0xaa)
	cmd[2] = TOBCD(tocentry->cdte_track);
      else 
	cmd[1] = 1;

      *( ((int *) buffer) + 1 )	= 4;	/* length of output buffer */
      status = ioctl(i, SCSI_IOCTL_SEND_COMMAND, buffer );
      if(status) return status;

      if(tocentry->cdte_format == CDROM_MSF){
	tocentry->cdte_addr.msf.minute = FROMBCD(buffer[8]);
	tocentry->cdte_addr.msf.second = FROMBCD(buffer[9]);
	tocentry->cdte_addr.msf.frame = FROMBCD(buffer[10]);
	tocentry->cdte_ctrl = buffer[11];
      } else {
	tocentry->cdte_addr.lba = *( ((int *) buffer) + 8 );
      };
      return 0;
    };
  default:
  };

  return 0;
}
