/*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 = HIIORB.C
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION
 *
 *
 * FUNCTIONS   Filters SCSI-2 Command Descriptor Blocks and conters
 *             them to the vendor unique Hitachi Command Descriptor
 *             Blocks.
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#include <flthdr.h>

/*
** FUNCTION PROTOTYPES
*/

USHORT NotifyRead6 (PIORB_CDB pIORB);
USHORT NotifyDiskInfo (PIORB_CDB pIORB);
USHORT NotifyGetTOC (PIORB_CDB pIORB);
USHORT NotifyPlayAudio (PIORB_CDB pIORB);
USHORT NotifyReadSubChannel (PIORB_CDB pIORB);


/*
** CODE STARTS HERE
*/

/****************************************************************************
 *
 * FUNCTION NAME = Filter_Read_6
 *
 * DESCRIPTION   = This routine checks for Read requests for LBA of 0 with a
 *                 length of 1.  This tells us that a new media has been
 *                 inserted into the drive so that we can read and store the
 *                 table of contents.
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_Read_6 (PIORB_CDB pIORB)
{
   USHORT   i;

   struct CDB_Read_6    FAR *pCDB1;
   pHIT_CDB_DiskInfo    pCDB2;
   PIORB_FLTWORK        pFilter_workspace;
   NPUNITCB             pUnitCB;

   pCDB1 = (struct CDB_Read_6 FAR *) pIORB->apt.pControllerCmd;
   pCDB2 = (pHIT_CDB_DiskInfo)  pIORB->apt.pControllerCmd;
   pFilter_workspace = (PIORB_FLTWORK) pIORB->filter_workspace;
   pUnitCB = pFilter_workspace->pUnitCB;

   if ( pCDB1->LBA.word != 0 || pCDB1->transfer_length != 1 )
      return CALL_ADD_AND_RET;

   /*
   ** Need to store the data pointer until we are ready to send the
   ** Read request.
   */
   pUnitCB->transfer_buffer = pIORB->apt.pSGList->ppXferBuf;
   pIORB->apt.pSGList->ppXferBuf =
               (ULONG)(ppDataSeg+(ULONG)((USHORT)&(pUnitCB->HitDiskInfo)));

   /*
   ** Build Disk Info command block.
   */
   pIORB->apt.ControllerCmdLen = sizeof (HIT_CDB_DiskInfo);
   pIORB->apt.pSGList->XferBufLen = 6;

   pCDB2->OpCode = HIT_DISK_INFO;       /* get table of contents.  */

   pCDB2->alloc_length_msb = 0;
   pCDB2->alloc_length_lsb = 6;
   pCDB2->control = 0;

   for (i=1;i<9;i++)
      *((PBYTE) pCDB2+i) = 0;

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

   return CALL_ADD_AND_NOTIFY_FILTER;
}

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

USHORT NotifyDiskInfo (PIORB_CDB pIORB)
{
   USHORT   i;
   UCHAR    last_track;
   USHORT   req_length;

   pHIT_CDB_DiskInfo          pCDB1;
   PIORB_FLTWORK              pFilter_workspace;
   NPUNITCB                   pUnitCB;

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

   pIORB->apt.cSGList = 1;

   last_track = pUnitCB->HitDiskInfo.max_tno;

   req_length = last_track * 3 + 6;

   pIORB->apt.ControllerCmdLen = sizeof (HIT_CDB_DiskInfo);
   pIORB->apt.pSGList->XferBufLen = req_length;

   pCDB1->OpCode = HIT_DISK_INFO;       /* get table of contents.         */
   pCDB1->UPC    = 0;                   /* do not want UPC information.   */
   pCDB1->alloc_length_msb = 0;
   pCDB1->alloc_length_lsb = req_length;
   pCDB1->control = 0;

   pCDB1->reserved_1 = 0;

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

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

   return CALL_ADD_AND_NOTIFY_FILTER;
}


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

USHORT NotifyRead6 (PIORB_CDB pIORB)
{
   USHORT   i;
   struct CDB_Read_6    FAR *pCDB1;
   PIORB_FLTWORK        pFilter_workspace;
   NPUNITCB             pUnitCB;

   pCDB1 = (struct CDB_Read_6 FAR *) pIORB->apt.pControllerCmd;
   pFilter_workspace = (PIORB_FLTWORK) pIORB->filter_workspace;
   pUnitCB = pFilter_workspace->pUnitCB;

   /*
   ** If the disc contains no data, do not bother sending down the
   ** Read request.
   */
   if ( pUnitCB->HitDiskInfo.data == 0 )
      return NOTIFY_CDM_WITH_ERROR;

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

   /*
   ** Restore original data pointer.
   */
   pIORB->apt.pSGList->ppXferBuf = pUnitCB->transfer_buffer;

   pIORB->apt.ControllerCmdLen = sizeof (struct CDB_Read_6);
   pIORB->apt.pSGList->XferBufLen = 0x800;

   pCDB1->OpCode = SCSI_READ_6;
   pCDB1->transfer_length = 1;

   return CALL_ADD_AND_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)
{
   /*
   ** No conversion needed, pass along to ADD.
   */

   return CALL_ADD_AND_RET;
}


/****************************************************************************
 *
 * FUNCTION NAME = Filter_ModeSelect
 *
 * DESCRIPTION   = This routine converts the Audio Control Mode Page to a
 *                 Hitachi Play Audio command.  (audio channel control is
 *                 changed by setting the play mode bits in the Hitachi 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;
   UCHAR    block_length_lsb, block_length_msb;
   USHORT   i, rc;

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

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

   *((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 )
   {
      pCDB2->parm_length = 12;

      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.
      */
      if ( !(block_length_msb == 0x08 && block_length_lsb == 0x00) &&
           !(block_length_msb == 0x09 && block_length_lsb == 0x24) )
      {
         return NOTIFY_CDM_WITH_ERROR;
      }

      /*
      ** Density Code and Block Count must be set to zero.
      */
      pCDBData2->Descriptors.BlockDescriptor.density_code   = 0;
      pCDBData2->Descriptors.BlockDescriptor.block_count_0  = 0;
      pCDBData2->Descriptors.BlockDescriptor.block_count_1  = 0;
      pCDBData2->Descriptors.BlockDescriptor.block_count_2  = 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) )
   {
      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 == 0 || out_vol0 == PCS_MUTED )
         left_off = TRUE;

      if ( out_chan1 == 0 || out_vol1 == PCS_MUTED )
         right_off = TRUE;

      /*
      ** Check for audio channel redirection.
      */
      if ( out_chan0 != 0 && out_chan0 == 2 )
         left_off = TRUE;

      if ( out_chan1 != 0 && out_chan1 == 1 )
         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;

      if ( left_off & right_off )
         play_mode = HIT_PLAY_MUTE;
      else if ( left_off )
         play_mode = HIT_PLAY_RIGHT;
      else if ( right_off )
         play_mode = HIT_PLAY_LEFT;
      else
         play_mode = HIT_PLAY_STEREO;

      pUnitCB = pFilter_workspace->pUnitCB;
      pUnitCB->play_mode = play_mode;
   }

   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 a Hitachi eject command.
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_StartStopUnit (PIORB_CDB pIORB)

{
   USHORT   i;

   pHIT_CDB_Eject           pCDB1;
   struct CDB_StartStopUnit FAR *pCDB2;

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

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

      pCDB1->OpCode = HIT_EJECT;

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

      pCDB1->eject   = 1;     /* set eject bit */
      pCDB1->mode    = 0;     /* we do not want check up status */
      pCDB1->control = 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_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
 *                 a Hitachi Audio Status command.
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

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

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

   pCDB1 = (pHIT_CDB_AudioStatus) 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 (HIT_CDB_AudioStatus);
      pIORB->apt.pSGList->XferBufLen = sizeof (HIT_DATA_AudioStatus);

      pCDB1->OpCode = HIT_AUDIO_STATUS;

      for (i=1;i<12;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;

   pHIT_DATA_AudioStatus      pCDBData1;
   struct SubChannel_Position FAR *pCDBData2;

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

   /*
   ** convert Hitachi play status byte to SCSI-2
   */
   if ( pCDBData1->play_status )
      audio_status = AS_PLAY_IN_PROGRESS;
   else
      audio_status = AS_PLAY_COMPLETE;

   control = pCDBData1->control;
   track_number = pCDBData1->tno;
   index = pCDBData1->point;

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

   pCDBData2->abs_address.redbook.frame = pCDBData1->aframe;
   pCDBData2->abs_address.redbook.sec   = pCDBData1->asec;
   pCDBData2->abs_address.redbook.min   = 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 gets the requested information form the SCSI-2
 *                 Read TOC command and obtains the necessary data from the
 *                 Hitachi TOC data table.
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Filter_ReadTOC (PIORB_CDB pIORB)
{
   USHORT   i, rc;
   UCHAR    track_number, trk_index;

   struct CDB_ReadTOC   FAR *pCDB1;
   struct ReadTOC_Data  FAR *pCDBData1;
   PIORB_FLTWORK        pFilter_workspace;
   NPUNITCB             pUnitCB;

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

   track_number = pCDB1->starting_track;

   pCDBData1->toc_hdr.toc_datalength.usbytes.byte_0 = 0;
   pCDBData1->toc_hdr.toc_datalength.usbytes.byte_1 =
                                    sizeof (struct ReadTOC_Data) - 2;
   pCDBData1->toc_hdr.first_track = pUnitCB->HitDiskInfo.min_tno;
   pCDBData1->toc_hdr.last_track  = pUnitCB->HitDiskInfo.max_tno;


   pCDBData1->toc_descriptor[0].track_num  = track_number;
   pCDBData1->toc_descriptor[0].reserved_1 = 0;
   pCDBData1->toc_descriptor[0].reserved_3 = 0;

   /*
   ** we first want to get the track information
   */
   if ( track_number == 0xAA )
   {
      pCDBData1->toc_descriptor[0].control = 0;
      pCDBData1->toc_descriptor[0].ADR     = ADR_CURRENT_POSITION;


      pCDBData1->toc_descriptor[0].abs_address.redbook.zero = 0;
      pCDBData1->toc_descriptor[0].abs_address.redbook.min =
                                             pUnitCB->HitDiskInfo.lead_min;
      pCDBData1->toc_descriptor[0].abs_address.redbook.sec =
                                             pUnitCB->HitDiskInfo.lead_sec;
      pCDBData1->toc_descriptor[0].abs_address.redbook.frame =
                                             pUnitCB->HitDiskInfo.lead_frame;
   }
   else
   {
      trk_index = track_number - 1;

      if ( pUnitCB->HitDiskInfo.track_info[trk_index].data )
         pCDBData1->toc_descriptor[0].control = 4;
      else
         pCDBData1->toc_descriptor[0].control = 0;

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


      pCDBData1->toc_descriptor[0].abs_address.redbook.zero = 0;
      pCDBData1->toc_descriptor[0].abs_address.redbook.min =
                       pUnitCB->HitDiskInfo.track_info[trk_index].amin;
      pCDBData1->toc_descriptor[0].abs_address.redbook.sec =
                       pUnitCB->HitDiskInfo.track_info[trk_index].asec;
      pCDBData1->toc_descriptor[0].abs_address.redbook.frame =
                       pUnitCB->HitDiskInfo.track_info[trk_index].aframe;
   }

   pIORB->apt.iorbh.Status = 0;  /* return with no error condition */

   return NOTIFY_CDM;
}


/****************************************************************************
 *
 * FUNCTION NAME = Filter_ReadHeader
 *
 * DESCRIPTION   = Because the Hitachi 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
 *                 Hitachi Play Audio command.
 *
 * INPUT         = pIORB - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

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

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

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

   pCDB1->OpCode = HIT_PLAY_AUDIO;

   pCDB1->immed = 1;
   pCDB1->play_mode = pUnitCB->play_mode;
   pCDB1->reserved_1 = 0;

   pCDB1->start_min   = pCDB2->starting_M;
   pCDB1->start_sec   = pCDB2->starting_S;
   pCDB1->start_frame = pCDB2->starting_F;

   pCDB1->end_frame   = pCDB2->ending_F;
   pCDB1->end_sec     = pCDB2->ending_S;
   pCDB1->end_min     = pCDB2->ending_M;

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

   pCDB1->control = 0;

   pUnitCB->end_play_address.redbook.min   = pCDB1->end_min;
   pUnitCB->end_play_address.redbook.sec   = pCDB1->end_sec;
   pUnitCB->end_play_address.redbook.frame = pCDB1->end_frame;

   return CALL_ADD_AND_RET;
}


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

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

   pHIT_CDB_Pause          pCDB1;
   struct CDB_PauseResume  FAR *pCDB2;
   PIORB_FLTWORK           pFilter_workspace;

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

   /*
   ** We should only get a pause request.
   */
   if ( !(pCDB2->resume) )
   {
      /*
      ** Convert SCSI-2 Pause to Hitachi Still command.
      */
      pIORB->apt.cSGList = 1;
      pIORB->apt.pSGList->XferBufLen = 3;
      pIORB->apt.Flags |= PT_DIRECTION_IN;

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

      pCDB1->OpCode = HIT_PAUSE;

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

      rc = CALL_ADD_AND_RET;
   }
   else
   {
      rc = NOTIFY_CDM_WITH_ERROR;
   }

   return rc;
}
