/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = NEIORB2.C
 *
 * DESCRIPTIVE NAME = IORB handling for NEC Filter
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION
 *
 *
 * FUNCTIONS   Filters SCSI-2 Command Descriptor Blocks and conters
 *             them to the vendor unique NEC Command Descriptor Blocks.
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#include <flthdr.h>

/*
** FUNCTION PROTOTYPES
*/

USHORT NotifyReadSubChannel (PIORB_CDB pIORB);
USHORT NotifyReadTrack (PIORB_CDB pIORB);
USHORT NotifyReadMinMax (PIORB_CDB pIORB);
USHORT NotifyAudioSearch (PIORB_CDB pIORB);
USHORT NotifyResume (PIORB_CDB pIORB);
USHORT NotifySeek6 (PIORB_CDB pIORB);
USHORT NotifyTestUnitReady (PIORB_CDB pIORB);


/*
** CODE STARTS HERE
*/


/****************************************************************************
 *
 * FUNCTION NAME = Filter_TestUnitReady
 *
 * DESCRIPTION   = This routine filters Test Unit Ready. The CDR-35, 77 and 80
 *                 does not generate a media changes check condition for this
 *                 command.  We must issue a Request Sense prior to the
 *                 Test Unit Ready to make sure the check condition is reported.
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_TestUnitReady (PIORB_CDB pIORB)
{

   NPUNITCB pUnitCB;

   struct CDB_RequestSense    FAR *pCDB1;
   PIORB_FLTWORK pFilter_workspace;

   pFilter_workspace = (PIORB_FLTWORK) pIORB->filter_workspace;
   pUnitCB = pFilter_workspace->pUnitCB;

   if ( ( pUnitCB->product_id[12] != ' ' ) &&
        ( pUnitCB->product_id[6] != '2' ) )
   {
      return(CALL_ADD_AND_RET);
   }

   pCDB1 = (struct CDB_RequestSense FAR *) pIORB->apt.pControllerCmd;

   pCDB1->OpCode = SCSI_REQUEST_SENSE;

   pCDB1->reserved_1 = 0;
   pCDB1->reserved_2 = 0;
   pCDB1->reserved_3 = 0;
   pCDB1->alloc_length = sizeof(struct Sense_Data);
   pCDB1->control = 0;

   pIORB->apt.cSGList = 1;
   pIORB->apt.pSGList->XferBufLen = sizeof(struct Sense_Data);
   pIORB->apt.Flags |= PT_DIRECTION_IN;

   /*
   ** Replace callback address with ours.
   */
   pFilter_workspace->completion_address = NotifyTestUnitReady;

   return (CALL_ADD_AND_NOTIFY_FILTER);
}


/****************************************************************************
 *
 * FUNCTION NAME = NotifyTestUnitReady
 *
 * DESCRIPTION   =
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT NotifyTestUnitReady (PIORB_CDB pIORB)
{

   struct Sense_Data FAR *pSense_Data;
   pSense_Data = (struct Sense_Data FAR *) pIORB->CDB_data;

   if ( pSense_Data->sense_key != SK_NO_SENSE )
   {
       pIORB->sense_data = *pSense_Data;
       pIORB->apt.iorbh.Status = IORB_DONE | IORB_ERROR |
                                 IORB_STATUSBLOCK_AVAIL;

       pIORB->status_block.Flags = STATUS_SENSEDATA_VALID;
       NEC_Sense_Fix (pIORB);
   }

   return(NOTIFY_CDM);
}


/****************************************************************************
 *
 * FUNCTION NAME = Filter_Seek_6
 *
 * DESCRIPTION   =
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_Seek_6 (PIORB_CDB pIORB)
{
   PIORB_FLTWORK pFilter_workspace;
   pFilter_workspace = (PIORB_FLTWORK) pIORB->filter_workspace;


   /*
   ** Replace callback address with ours.
   */

   pFilter_workspace->completion_address = NotifySeek6;
   pFilter_workspace->flags |= FWF_SKIP_ERROR_CHECK;

   return CALL_ADD_AND_NOTIFY_FILTER;
}


/****************************************************************************
 *
 * FUNCTION NAME = NotifySeek6
 *
 * DESCRIPTION   =
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT NotifySeek6 (PIORB_CDB pIORB)
{
   pNEC_CDB_AudioTrackSearch  pCDB1;
   struct CDB_Seek_6          FAR *pCDB2;

   if ( (pIORB->apt.iorbh.Status & IORB_ERROR) &&
        ( !(pIORB->apt.iorbh.Status & IORB_RECOV_ERROR) ) &&
        (pIORB->sense_data.sense_key == 3) &&
        pIORB->sense_data.command_specific_info[1] == 0x1D)
   {

      pCDB1 = (pNEC_CDB_AudioTrackSearch) pIORB->apt.pControllerCmd;
      pCDB2 = (struct CDB_Seek_6 FAR *) pCDB1;

      pIORB->apt.ControllerCmdLen = sizeof (NEC_CDB_AudioTrackSearch);

      pCDB1->OpCode = NEC_AUDIO_TRACK_SEARCH;

      pCDB1->play = 0;                  /* pause after search */

      pCDB1->search_zero  = pCDB2->LBA.usbytes.byte_1;
      pCDB1->search_frame = pCDB2->LBA.usbytes.byte_0;
      pCDB1->search_sec   = pCDB2->LBA_msb;
      pCDB1->search_min   = 0;

      pCDB1->addr_type = NEC_ADDR_HSG;

      pCDB1->reserved_1 = 0;
      pCDB1->reserved_2 = 0;
      pCDB1->reserved_3 = 0;
      pCDB1->reserved_4 = 0;
      pCDB1->reserved_5 = 0;
      return CALL_ADD_AND_NOTIFY_CDM;
   }
   else
      return NOTIFY_CDM;
}


/****************************************************************************
 *
 * FUNCTION NAME = Filter_ModeSelect
 *
 * DESCRIPTION   = This routine converts the Audio Control Mode Page to an NEC
 *                 Play Audio command.  (audio channel control is changed by
 *                 setting the play mode bits in the NEC Play Audio command).
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_ModeSelect (PIORB_CDB pIORB)
{
   UCHAR    play_mode, out_chan0, out_chan1, out_vol0, out_vol1;
   UCHAR    left_off, right_off, transfer_length;
   UCHAR    block_length_lsb, block_length_msb;
   USHORT   i, rc;

   pNEC_CDB_PlayAudio         pCDB1;
   struct CDB_ModeSelect      FAR *pCDB2;
   struct ModeSelectParmList  FAR *pCDBData2;
   PIORB_FLTWORK              pFilter_workspace;
   NPUNITCB                   pUnitCB;

   pCDB1 = (pNEC_CDB_PlayAudio) pIORB->apt.pControllerCmd;
   pCDB2 = (struct CDB_ModeSelect FAR *) pCDB1;
   pCDBData2 = (struct ModeSelectParmList FAR *) pIORB->CDB_data;
   pFilter_workspace = (PIORB_FLTWORK) pIORB->filter_workspace;
   pUnitCB = pFilter_workspace->pUnitCB;

   *((PBYTE) pCDB2+1) = 0;    /* Byte 1 of the command block must be zero */

   rc = NOTIFY_CDM;

   /*
   ** Check for Block Descriptor Header.
   */
   if ( pCDBData2->ModeSelectHdr.block_descriptor_len == 8 )
   {
      /*
      ** The NEC CDR-35 drive expects 11 bytes of information.  The last
      ** byte must be zero.
      */
      if ( pUnitCB->product_id[6] == '2' )
         transfer_length = 11;
      else
         transfer_length = 10;

      pCDB2->parm_length = transfer_length;
      pIORB->apt.pSGList->XferBufLen = transfer_length;

      pCDBData2->ModeSelectHdr.block_descriptor_len = 0;

      block_length_lsb = pCDBData2->Descriptors.BlockDescriptor.block_length_2;
      block_length_msb = pCDBData2->Descriptors.BlockDescriptor.block_length_1;

      /*
      ** Test for block size of 2048 or 2340 bytes.  Return an error for
      ** any other block size.
      **
      ** NOTE: The NEC CDR-35 drive only supports a block size of 2048 bytes.
      */
      if ( block_length_msb == 0x08 && block_length_lsb == 0x00 )
      {
         if ( pCDBData2->Descriptors.BlockDescriptor.density_code != 0x81 )
            pCDBData2->Descriptors.BlockDescriptor.density_code = 0;
      }
      else if ( (block_length_msb == 0x09 && block_length_lsb == 0x24) &&
                (pUnitCB->product_id[6] != '2') )
      {
         pCDBData2->Descriptors.BlockDescriptor.density_code = 3;
      }
      else
      {
         return NOTIFY_CDM_WITH_ERROR;
      }

      /*
      ** Remaining 4 bytes should be zero and the last byte should be
      ** set to 5 for the retry count.
      */
      pCDBData2->Descriptors.BlockDescriptor.block_count_0  = 0;
      pCDBData2->Descriptors.BlockDescriptor.block_count_1  = 0;
      pCDBData2->Descriptors.BlockDescriptor.block_count_2  = 0;
      pCDBData2->Descriptors.BlockDescriptor.reserved_1     = 0;

      if ( pUnitCB->product_id[6] != '2' )
         pCDBData2->Descriptors.BlockDescriptor.block_length_0 = 5;
      else
         pCDBData2->Descriptors.BlockDescriptor.block_length_0 = 0;

      pCDBData2->Descriptors.BlockDescriptor.block_length_1 = 0;

      rc = CALL_ADD_AND_RET;
   }


   /*
   ** Check for Audio Channel Control page.
   */


   if ( (pCDBData2->ModeSelectHdr.block_descriptor_len == 0) &&
        (pCDBData2->Descriptors.audio_control.page_code == PAGE_AUDIO_CONTROL) )
   {
      pIORB->apt.ControllerCmdLen = sizeof (NEC_CDB_PlayAudio);
      pIORB->apt.cSGList = 0;
      pIORB->apt.pSGList = 0;
      pIORB->apt.ppSGLIST = 0;

      out_chan0 = pCDBData2->Descriptors.audio_control.output0_select;
      out_vol0  = pCDBData2->Descriptors.audio_control.output0_volume;
      out_chan1 = pCDBData2->Descriptors.audio_control.output1_select;
      out_vol1  = pCDBData2->Descriptors.audio_control.output1_volume;

      left_off = right_off = FALSE;

      /*
      ** Check for volume control of zero and output channel of zero.
      */
      if ( out_chan0 != 1 || out_vol0 == PCS_MUTED )
         left_off = TRUE;

      if ( out_chan1 != 2 || out_vol1 == PCS_MUTED )
         right_off = TRUE;

      /*
      ** If audio channels are switched, continue to play in stereo.
      */
      if ( out_chan0 == 2 && out_chan1 == 1 )
         left_off = right_off = FALSE;

      /*
      ** The NEC CDR-35 drive only supports Stereo & Mute mode.  If only
      ** one channel is muted, we must set the audio mode to Stereo for
      ** this drive.
      */
      if ( pUnitCB->product_id[6] == '2' && !(left_off & right_off) )
         left_off = right_off = FALSE;

      if ( left_off & right_off )
         play_mode = NEC_PLAY_MUTE;
      else if ( left_off )
         play_mode = NEC_PLAY_RIGHT;
      else if ( right_off )
         play_mode = NEC_PLAY_LEFT;
      else
         play_mode = NEC_PLAY_STEREO;

      pUnitCB->play_mode = play_mode;

      /*
      ** issue a play command if drive is in play mode
      */
      if ( pFilter_workspace->input_parm_0 == 1 )
      {
         pIORB->apt.ControllerCmdLen = sizeof (NEC_CDB_PlayAudio);

         pCDB1->OpCode = NEC_PLAY_AUDIO;

         pCDB1->play_mode = play_mode;

         for (i=2;i<9;i++)
            *((PBYTE) pCDB1+i) = 0;

         pCDB1->reserved_5 = 0;

         pCDB1->addr_type = NEC_ADDR_PRV;

         rc = CALL_ADD_AND_RET;
      }
   }

   return rc;
}


/****************************************************************************
 *
 * FUNCTION NAME = Filter_StartStopUnit
 *
 * DESCRIPTION   = This routine checks the SCSI-2 Start/Stop command block for
 *                 for eject bit and if set, sends down an NEC eject command.
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_StartStopUnit (PIORB_CDB pIORB)

{
   USHORT   i;

   pNEC_CDB_Eject           pCDB1;
   struct CDB_StartStopUnit FAR *pCDB2;

   pCDB1 = (pNEC_CDB_Eject) pIORB->apt.pControllerCmd;
   pCDB2 = (struct CDB_StartStopUnit FAR *) pCDB1;

   /*
   ** If eject reqested, build an NEC eject command.
   */
   if ( (pCDB2->LoEj) && !(pCDB2->start) )
   {
      pIORB->apt.ControllerCmdLen = sizeof (NEC_CDB_Eject);

      pCDB1->OpCode = NEC_EJECT;

      for (i=2;i<10;i++)
         *((PBYTE) pCDB1+i) = 0;
   }

   return CALL_ADD_AND_RET;
}


/****************************************************************************
 *
 * FUNCTION NAME = Filter_PreventAllowRemoval
 *
 * DESCRIPTION   =
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_PreventAllowRemoval (PIORB_CDB pIORB)
{
   /*
   ** No conversion needed, pass along to ADD.
   */

   return CALL_ADD_AND_RET;
}


/****************************************************************************
 *
 * FUNCTION NAME = Filter_ReadCapacity
 *
 * DESCRIPTION   = For the NEC-CDR 35, we have to hard code the Read Capcity
 *                 Data since this device does not support this command.
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_ReadCapacity (PIORB_CDB pIORB)
{
   struct ReadCapacity_Data FAR *pCDBData1;
   PIORB_FLTWORK pFilter_workspace;
   NPUNITCB pUnitCB;

   pCDBData1 = (struct ReadCapacity_Data FAR *) pIORB->CDB_data;
   pFilter_workspace = (PIORB_FLTWORK) pIORB->filter_workspace;
   pUnitCB = pFilter_workspace->pUnitCB;

   if ( pUnitCB->product_id[6] != '2' )
      return CALL_ADD_AND_RET;

   /*
   ** Set Total Blocks to 276,480.
   */
   pCDBData1->capacity_LBA.ulbytes.byte_0 = 0x00;
   pCDBData1->capacity_LBA.ulbytes.byte_1 = 0x04;
   pCDBData1->capacity_LBA.ulbytes.byte_2 = 0x38;
   pCDBData1->capacity_LBA.ulbytes.byte_3 = 0x00;

   /*
   ** Set Block Length to 2048.
   */
   pCDBData1->capacity_block_length.ulbytes.byte_0 = 0x00;
   pCDBData1->capacity_block_length.ulbytes.byte_1 = 0x00;
   pCDBData1->capacity_block_length.ulbytes.byte_2 = 0x08;
   pCDBData1->capacity_block_length.ulbytes.byte_3 = 0x00;

   return NOTIFY_CDM;
}


/****************************************************************************
 *
 * FUNCTION NAME = Filter_Seek_10
 *
 * DESCRIPTION   =
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_Seek_10 (PIORB_CDB pIORB)
{
   /*
   ** No conversion needed, pass along to ADD.
   */

   return CALL_ADD_AND_RET;
}


/****************************************************************************
 *
 * FUNCTION NAME = Filter_ReadSubChannel
 *
 * DESCRIPTION   = This routine converts the SCSI-2 Read Sub Channel command to
 *                 an NEC Read Subcode Q command.
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_ReadSubChannel (PIORB_CDB pIORB)
{
   USHORT   i, rc;

   pNEC_CDB_ReadSubQ         pCDB1;
   struct CDB_ReadSubChannel FAR *pCDB2;
   PIORB_FLTWORK             pFilter_workspace;

   pCDB1 = (pNEC_CDB_ReadSubQ) pIORB->apt.pControllerCmd;
   pCDB2 = (struct CDB_ReadSubChannel FAR *) pCDB1;
   pFilter_workspace = (PIORB_FLTWORK) pIORB->filter_workspace;

   if ( pCDB2->data_format == RSC_CURRENT_POSITION )
   {
      pIORB->apt.ControllerCmdLen = sizeof (NEC_CDB_ReadSubQ);
      pIORB->apt.pSGList->XferBufLen = sizeof (NEC_DATA_SubQChannel);

      pCDB1->OpCode = NEC_READ_SUB_Q;

      pCDB1->alloc_length = sizeof (NEC_DATA_SubQChannel);

      for (i=2;i<10;i++)
         *((PBYTE) pCDB1+i) = 0;

      /*
      ** Replace callback address with ours.
      */
      pFilter_workspace->completion_address = NotifyReadSubChannel;

      rc = CALL_ADD_AND_NOTIFY_FILTER;
   }
   else
   {
      rc = NOTIFY_CDM_WITH_ERROR;
   }

   return rc;
}


/****************************************************************************
 *
 * FUNCTION NAME = NotifyReadSubChannel
 *
 * DESCRIPTION   =
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT NotifyReadSubChannel (PIORB_CDB pIORB)
{
   UCHAR    audio_status, control, track_number, index;

   pNEC_DATA_SubQChannel      pCDBData1;
   struct SubChannel_Position FAR *pCDBData2;

   pCDBData1 = (pNEC_DATA_SubQChannel) pIORB->CDB_data;
   pCDBData2 = (struct SubChannel_Position FAR *) pIORB->CDB_data;

   /*
   ** convert NEC play status byte to SCSI-2
   */
   switch (pCDBData1->playback_status )
   {
      case NEC_PLAY_IN_PROGRESS:
         audio_status = AS_PLAY_IN_PROGRESS;
         break;

      case NEC_PLAY_STILL:
         audio_status = AS_PLAY_PAUSED;
         break;

      case NEC_PLAY_PAUSED:
         audio_status = AS_PLAY_PAUSED;
         break;

      case NEC_PLAY_COMPLETE:
         audio_status = AS_PLAY_COMPLETE;
         break;

      default:
         audio_status = AS_NO_STATUS;
         break;
   }

   control = pCDBData1->control;
   track_number = BCDtoBinary(pCDBData1->tno);
   index = BCDtoBinary(pCDBData1->point);

   /*
   ** fill in Current Position data block
   */
   pCDBData2->rel_address.redbook.zero  = 0;
   pCDBData2->rel_address.redbook.min   = BCDtoBinary(pCDBData1->min);
   pCDBData2->rel_address.redbook.sec   = BCDtoBinary(pCDBData1->sec);
   pCDBData2->rel_address.redbook.frame = BCDtoBinary(pCDBData1->frame);

   pCDBData2->abs_address.redbook.frame = BCDtoBinary(pCDBData1->aframe);
   pCDBData2->abs_address.redbook.sec   = BCDtoBinary(pCDBData1->asec);
   pCDBData2->abs_address.redbook.min   = BCDtoBinary(pCDBData1->amin);
   pCDBData2->abs_address.redbook.zero  = 0;

   pCDBData2->data_format_code = 1;
   pCDBData2->control = control;
   pCDBData2->ADR = ADR_CURRENT_POSITION;
   pCDBData2->track_number = track_number;
   pCDBData2->index_number = index;

   /*
   ** fill in sub-channel header
   */
   pCDBData2->sub_channel_hdr.reserved_1 = 0;
   pCDBData2->sub_channel_hdr.audio_status = audio_status;
   pCDBData2->sub_channel_hdr.data_length.usbytes.byte_0 = 0;
   pCDBData2->sub_channel_hdr.data_length.usbytes.byte_1 =
                                       sizeof(struct SubChannel_Position) -
                                       sizeof(struct SubChannel_Hdr);

   return NOTIFY_CDM;
}


/****************************************************************************
 *
 * FUNCTION NAME = Filter_ReadTOC
 *
 * DESCRIPTION   = This routine converts the SCSI-2 Read TOC command to an NEC
 *                 Read TOC.
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_ReadTOC (PIORB_CDB pIORB)
{
   USHORT   i;

   pNEC_CDB_ReadTOC     pCDB1;
   struct CDB_ReadTOC   FAR *pCDB2;
   PIORB_FLTWORK        pFilter_workspace;

   pCDB1 = (pNEC_CDB_ReadTOC) pIORB->apt.pControllerCmd;
   pCDB2 = (struct CDB_ReadTOC FAR *) pCDB1;
   pFilter_workspace = (PIORB_FLTWORK) pIORB->filter_workspace;

   pIORB->apt.ControllerCmdLen = sizeof (NEC_CDB_ReadTOC);
   pIORB->apt.pSGList->XferBufLen = sizeof (NEC_DATA_TrackInfo);

   pCDB1->OpCode = NEC_READ_TOC;

   /*
   ** we first want to get the track information
   */
   if ( pCDB2->starting_track == 0xAA )
      pCDB1->data_type = NEC_LEADOUT_INFO;
   else
      pCDB1->data_type = NEC_TRACK_INFO;

   pCDB1->TNO = BinarytoBCD (pCDB2->starting_track);
   pCDB1->control = 0;

   for (i=3;i<9;i++)
      *((PBYTE) pCDB1+i) = 0;

   /*
   ** Replace callback address with ours.
   */
   pFilter_workspace->completion_address = NotifyReadTrack;

   return CALL_ADD_AND_NOTIFY_FILTER;
}


/****************************************************************************
 *
 * FUNCTION NAME = NotifyReadTrack
 *
 * DESCRIPTION   =
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT NotifyReadTrack (PIORB_CDB pIORB)
{
   USHORT   i;

   pNEC_CDB_ReadTOC     pCDB1;
   pNEC_DATA_TrackInfo  pCDBData1;
   struct CDB_ReadTOC   FAR *pCDB2;
   struct ReadTOC_Data  FAR *pCDBData2;
   PIORB_FLTWORK        pFilter_workspace;

   pCDB1 = (pNEC_CDB_ReadTOC) pIORB->apt.pControllerCmd;
   pCDBData1 = (pNEC_DATA_TrackInfo) pIORB->CDB_data;
   pCDB2 = (struct CDB_ReadTOC FAR *) pCDB1;
   pCDBData2 = (struct ReadTOC_Data FAR *) pIORB->CDB_data;
   pFilter_workspace = (PIORB_FLTWORK) pIORB->filter_workspace;

   pCDBData2->toc_descriptor[0].control = pCDBData1->control;
   pCDBData2->toc_descriptor[0].ADR = ADR_CURRENT_POSITION;

   pCDBData2->toc_descriptor[0].track_num = pCDB1->TNO;

   pCDBData2->toc_descriptor[0].abs_address.redbook.zero  = 0;
   pCDBData2->toc_descriptor[0].abs_address.redbook.min   =
                                          BCDtoBinary(pCDBData1->amin);
   pCDBData2->toc_descriptor[0].abs_address.redbook.sec   =
                                          BCDtoBinary(pCDBData1->asec);
   pCDBData2->toc_descriptor[0].abs_address.redbook.frame =
                                          BCDtoBinary(pCDBData1->aframe);

   pCDB1->data_type = NEC_MINMAX_INFO;

   pFilter_workspace->completion_address = NotifyReadMinMax;

   return CALL_ADD_AND_NOTIFY_FILTER;
}


/****************************************************************************
 *
 * FUNCTION NAME = NotifyReadMinMax
 *
 * DESCRIPTION   =
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT NotifyReadMinMax (PIORB_CDB pIORB)
{
   pNEC_DATA_MinMax     pCDBData1;
   struct ReadTOC_Data  FAR *pCDBData2;

   pCDBData1 = (pNEC_DATA_MinMax) pIORB->CDB_data;
   pCDBData2 = (struct ReadTOC_Data FAR *) pIORB->CDB_data;

   pCDBData2->toc_hdr.first_track = BCDtoBinary(pCDBData1->min_tno);
   pCDBData2->toc_hdr.last_track  = BCDtoBinary(pCDBData1->max_tno);

   pCDBData2->toc_hdr.toc_datalength.usbytes.byte_0 = 0;
   pCDBData2->toc_hdr.toc_datalength.usbytes.byte_1 =
                                    sizeof (struct ReadTOC_Data) - 2;

   pCDBData2->toc_descriptor[0].reserved_1 = 0;
   pCDBData2->toc_descriptor[0].reserved_3 = 0;

   return NOTIFY_CDM;
}


/****************************************************************************
 *
 * FUNCTION NAME = Filter_ReadHeader
 *
 * DESCRIPTION   = Because the NEC drive does not support the Read Header
 *                 command or equevalent, we always return a density code of 1.
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_ReadHeader (PIORB_CDB pIORB)
{
   USHORT   i;

   struct CDB_ReadHeader   FAR *pCDB1;
   struct ReadHeader_Data  FAR *pCDBData1;

   pCDB1 = (struct CDB_ReadHeader FAR *) pIORB->apt.pControllerCmd;
   pCDBData1 = (struct ReadHeader_Data FAR *) pIORB->CDB_data;

   pCDBData1->cdrom_data_mode = 1;

   for (i=1;i<8;i++)
      *((PBYTE) pCDB1+i) = 0;

   return NOTIFY_CDM;
}


/****************************************************************************
 *
 * FUNCTION NAME = Filter_PlayAudio_MSF
 *
 * DESCRIPTION   = This routine converts the SCSI-2 Play MSF command to an NEC
 *                 Audio Search command and then a Audio Play command.
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_PlayAudio_MSF (PIORB_CDB pIORB)
{
   pNEC_CDB_AudioTrackSearch  pCDB1;
   struct CDB_PlayAudio_MSF   FAR *pCDB2;
   PIORB_FLTWORK              pFilter_workspace;

   pCDB1 = (pNEC_CDB_AudioTrackSearch) pIORB->apt.pControllerCmd;
   pCDB2 = (struct CDB_PlayAudio_MSF FAR *) pCDB1;
   pFilter_workspace = (PIORB_FLTWORK) pIORB->filter_workspace;

   pIORB->apt.ControllerCmdLen = sizeof (NEC_CDB_AudioTrackSearch);

   pCDB1->OpCode = NEC_AUDIO_TRACK_SEARCH;

   pCDB1->play = 0;                     /* pause after search */

   pCDB1->search_min   = BinarytoBCD (pCDB2->starting_M);
   pCDB1->search_sec   = BinarytoBCD (pCDB2->starting_S);
   pCDB1->search_frame = BinarytoBCD (pCDB2->starting_F);
   pCDB1->search_zero  = 0;

   pFilter_workspace->end_play_address.redbook.min   =
                                        BinarytoBCD (pCDB2->ending_M);
   pFilter_workspace->end_play_address.redbook.sec   =
                                        BinarytoBCD (pCDB2->ending_S);
   pFilter_workspace->end_play_address.redbook.frame =
                                        BinarytoBCD (pCDB2->ending_F);

   pCDB1->addr_type = NEC_ADDR_MSF;

   pCDB1->reserved_1 = 0;
   pCDB1->reserved_2 = 0;
   pCDB1->reserved_3 = 0;
   pCDB1->reserved_4 = 0;
   pCDB1->reserved_5 = 0;

   /*
   ** Replace callback address with ours.
   */
   pFilter_workspace->completion_address = NotifyAudioSearch;

   return CALL_ADD_AND_NOTIFY_FILTER;
}


/****************************************************************************
 *
 * FUNCTION NAME = NotifyAudioSearch
 *
 * DESCRIPTION   =
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT NotifyAudioSearch (PIORB_CDB pIORB)
{
   pNEC_CDB_PlayAudio   pCDB1;
   PIORB_FLTWORK        pFilter_workspace;
   NPUNITCB             pUnitCB;

   pCDB1 = (pNEC_CDB_PlayAudio) pIORB->apt.pControllerCmd;
   pFilter_workspace = (PIORB_FLTWORK) pIORB->filter_workspace;
   pUnitCB = pFilter_workspace->pUnitCB;

   pIORB->apt.ControllerCmdLen = sizeof (NEC_CDB_PlayAudio);

   pCDB1->OpCode = NEC_PLAY_AUDIO;

   pCDB1->play_mode = pUnitCB->play_mode;

   pCDB1->completion_min   = pFilter_workspace->end_play_address.redbook.min;
   pCDB1->completion_sec   = pFilter_workspace->end_play_address.redbook.sec;
   pCDB1->completion_frame = pFilter_workspace->end_play_address.redbook.frame;
   pCDB1->completion_zero  = 0;

   pCDB1->addr_type = NEC_ADDR_MSF;

   return CALL_ADD_AND_NOTIFY_CDM;
}


/****************************************************************************
 *
 * FUNCTION NAME = Filter_Pause_Resume
 *
 * DESCRIPTION   = This routine converts the SCSI-2 Pause/Resume CDB to a NEC
 *                 Still or Play CDB.
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_Pause_Resume (PIORB_CDB pIORB)
{
   UCHAR    i, rc;

   pNEC_CDB_Still             pCDB1;
   pNEC_CDB_PlayAudio         pCDB1a;
   struct CDB_PauseResume FAR *pCDB2;
   PIORB_FLTWORK              pFilter_workspace;

   pCDB1  = (pNEC_CDB_Still) pIORB->apt.pControllerCmd;
   pCDB1a = (pNEC_CDB_PlayAudio) pIORB->apt.pControllerCmd;
   pCDB2  = (struct CDB_PauseResume FAR *) pCDB1;
   pFilter_workspace = (PIORB_FLTWORK) pIORB->filter_workspace;

   /*
   ** If SCSI-2 resume request, issue Audio Search followed by Play command.
   */

   if ( pCDB2->resume )
   {
      pIORB->apt.ControllerCmdLen = sizeof (NEC_CDB_PlayAudio);

      pCDB1a->OpCode = NEC_PLAY_AUDIO;

      pCDB1a->play_mode = NEC_PLAY_PREVIOUS_MODE;

      pCDB1a->completion_min   = 0;
      pCDB1a->completion_sec   = 0;
      pCDB1a->completion_frame = 0;
      pCDB1a->completion_zero  = 0;

      pCDB1a->addr_type = NEC_ADDR_PRV;

      rc = CALL_ADD_AND_NOTIFY_CDM;
   }
   else
   {
      /*
      ** Convert SCSI-2 Pause to NEC Still command.
      */
      pIORB->apt.ControllerCmdLen = sizeof (NEC_CDB_Still);

      pCDB1->OpCode = NEC_STILL;

      for (i=2;i<10;i++)
         *((PBYTE) pCDB1+i) = 0;

      rc = CALL_ADD_AND_RET;
   }
   return rc;
}

