home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cdrom.zip / DDK / BASE / SRC / DEV / DASD / CDROM / OS2CDROM / cdioc81.c < prev    next >
C/C++ Source or Header  |  1996-06-18  |  29KB  |  1,003 lines

  1. /**************************************************************************
  2.  *
  3.  * SOURCE FILE NAME = CDIOC81.C
  4.  *
  5.  * DESCRIPTIVE NAME = IOCTL handling routines for OS/2 CD-ROM Device Mgr
  6.  *
  7.  * Copyright : COPYRIGHT IBM CORPORATION, 1991, 1992
  8.  *             LICENSED MATERIAL - PROGRAM PROPERTY OF IBM
  9.  *             REFER TO COPYRIGHT INSTRUCTION FORM#G120-2083
  10.  *             RESTRICTED MATERIALS OF IBM
  11.  *             IBM CONFIDENTIAL
  12.  *
  13.  * VERSION = V2.0
  14.  *
  15.  * DATE
  16.  *
  17.  * DESCRIPTION
  18.  *
  19.  *
  20.  * FUNCTIONS
  21.  *
  22.  * ENTRY POINTS:
  23.  *
  24.  * DEPENDENCIES:
  25.  *
  26.  * NOTES
  27.  *
  28.  *
  29.  * STRUCTURES
  30.  *
  31.  * EXTERNAL REFERENCES
  32.  *
  33.  * EXTERNAL FUNCTIONS
  34.  *
  35.  * CHANGE ACTIVITY =
  36.  *  DATE      FLAG        APAR   CHANGE DESCRIPTION
  37.  *  --------  ----------  -----  --------------------------------------
  38.  *  09/08/95  @V135221           Sam Detweiler - CD-ROM changer support
  39.  *
  40.  ****************************************************************************/
  41.  
  42. #include "cdh.h"
  43.  
  44. /****************************************************************************
  45.  *
  46.  * FUNCTION NAME = CD_AudioChannelCtrl
  47.  *
  48.  * DESCRIPTION   = Audio Channel Control.
  49.  *
  50.  *       Provides playback control of audio information on the disk.  This
  51.  *       includes assigning input channels to output channels and controlling
  52.  *       the volume of each output channel.
  53.  *
  54.  *       USHORT CD_ChannelControl (PRP_GENIOCTL pRP, NPUNITCB pUnitCB)
  55.  *
  56.  * INPUT         = pRP              - Request Packet
  57.  *                 pUnitCB          - Pointer to UnitCB
  58.  *
  59.  * OUTPUT        = USHORT           - Packet Status word
  60.  *
  61.  * RETURN-NORMAL =
  62.  * RETURN-ERROR  =
  63.  *
  64.  ****************************************************************************/
  65.  
  66. USHORT CD_AudioChannelCtrl (pRP, pUnitCB)
  67.  
  68. PRP_GENIOCTL pRP;
  69. NPUNITCB     pUnitCB;
  70.  
  71. {
  72.    USHORT rc;
  73.    BOOL   playing;
  74.    NPIORB_CDB pIORB;
  75.  
  76.    struct AudioChannelControl_Data FAR *pDataPkt;
  77.    struct Channel *channel;
  78.    struct Audio   *audio;
  79.    struct Status  *audio_status;
  80.  
  81.    union AddressType start_red, end_red;
  82.  
  83.    pDataPkt = (struct AudioChannelControl_Data FAR *) pRP->DataPacket;
  84.  
  85.    audio = &pUnitCB->DeviceInfo.Audio;
  86.    channel = &audio->channel;
  87.    audio_status = &audio->status;
  88.  
  89.    /*
  90.    ** Copy the data to the UnitCB for channels 0 and 1
  91.    */
  92.    channel->input_0  = pDataPkt->input_0;
  93.    channel->volume_0 = pDataPkt->volume_0;
  94.    channel->input_1  = pDataPkt->input_1;
  95.    channel->volume_1 = pDataPkt->volume_1;
  96.  
  97.    /*
  98.    ** Only 2 channels supported at this time, so check to make sure
  99.    ** channels above 1 are not specified.
  100.    */
  101.    if (channel->input_0 > 1 || channel->input_1 > 1)
  102.    {
  103.       channel->input_0  = 0;
  104.       channel->input_1  = 1;
  105.       channel->volume_0 = 0xFF;
  106.       channel->volume_1 = 0xFF;
  107.       return(STDON + STERR + ERROR_I24_INVALID_PARAMETER);
  108.    }
  109.  
  110.    /*
  111.    ** Set volume setting for both channels the same.
  112.    */
  113. /*
  114. ** if (channel->volume_0 && channel->volume_1)
  115. ** {
  116. **    if (channel->volume_0 > channel->volume_1)
  117. **       channel->volume_1 = channel->volume_0;
  118. **    else
  119. **       channel->volume_0 = channel->volume_1;
  120. ** }
  121. */
  122.    /*
  123.    ** If the drive doesn't support receiving an audio control command
  124.    ** while it's playing, then pause the audio, issue the audio control
  125.    ** command and resume the audio.
  126.    */
  127.    rc = GetPlayStatus (pUnitCB, &playing);
  128.  
  129.    if (rc == STDON && playing &&
  130.                       (audio->capabilities & DCAPS_NO_AUDIO_CTRL_DURING_PLAY))
  131.    {
  132.       /*
  133.       ** Pause the play operation
  134.       */
  135.       rc = CD_Stop (pRP, pUnitCB);
  136.  
  137.       /*
  138.       ** Issue the audio control command
  139.       */
  140.       BuildCDB_AudioControl(pUnitCB, (NPIORB_CDB FAR *) &pIORB);
  141.       pIORB->filter_workspace[0] = (UCHAR) playing;
  142.       rc = SubmitIORB_Wait (pUnitCB, pIORB);
  143.       FreeIORB (pUnitCB, pIORB);
  144.  
  145.       /*
  146.       ** Resume playing
  147.       */
  148.       rc = CD_Resume (pRP, pUnitCB);
  149.    }
  150.    else
  151.    {
  152.       /*
  153.       ** Issue Mode Select to set Audio Control Page info
  154.       */
  155.       BuildCDB_AudioControl(pUnitCB, (NPIORB_CDB FAR *) &pIORB);
  156.       pIORB->filter_workspace[0] = (UCHAR) playing;
  157.       rc = SubmitIORB_Wait (pUnitCB, pIORB);
  158.       FreeIORB (pUnitCB, pIORB);
  159.    }
  160.  
  161.    return(rc);
  162. }
  163.  
  164.  
  165. /****************************************************************************
  166.  *
  167.  * FUNCTION NAME = CD_Play
  168.  *
  169.  * DESCRIPTION   = Play
  170.  *
  171.  *                 Play the selected audio tracks until the selection is done
  172.  *                 or until a stop command is issued.
  173.  *
  174.  *                 USHORT CD_Play (PRP_GENIOCTL pRP, NPUNITCB pUnitCB)
  175.  *
  176.  * INPUT         = pRP              - Request Packet
  177.  *                 pUnitCB          - Pointer to UnitCB
  178.  *
  179.  * OUTPUT        = USHORT           - Packet Status word
  180.  *
  181.  * RETURN-NORMAL =
  182.  * RETURN-ERROR  =
  183.  *
  184.  ****************************************************************************/
  185.  
  186. USHORT CD_Play (pRP, pUnitCB)
  187.  
  188. PRP_GENIOCTL pRP;
  189. NPUNITCB     pUnitCB;
  190.  
  191. {
  192.    USHORT rc;
  193.    BOOL   playing;
  194.    NPIORB_CDB pIORB;
  195.  
  196.    union  AddressType start_red, start_hsg, end_red, end_hsg, last_sector;
  197.    struct PlayAudio FAR *pParmPkt;
  198.    struct Audio *audio;
  199.    struct Status *audio_status;
  200.  
  201.    pParmPkt = (struct PlayAudio FAR *) pRP->ParmPacket;
  202.  
  203.  
  204.    if (pUnitCB->Flags & UCF_UNCERTAIN_MEDIA)
  205.       return (STDON + STERR + ERROR_I24_UNCERTAIN_MEDIA);
  206.  
  207.    if ( (rc = GetPlayStatus (pUnitCB, &playing)) & STERR)
  208.       return(rc);
  209.  
  210.    if (playing)
  211.       return (STDON + STERR + ERROR_I24_DEVICE_IN_USE);
  212.  
  213.  
  214.    switch(pParmPkt->address_mode)
  215.    {
  216.       case CDROM_HSG_MODE:
  217.           start_hsg.dword = pParmPkt->start_sector;
  218.           end_hsg.dword   = pParmPkt->end_sector;
  219.           start_red.dword = HSGtoRedBook (start_hsg.dword);
  220.           end_red.dword   = HSGtoRedBook (end_hsg.dword);
  221.           break;
  222.  
  223.       case CDROM_REDBOOK_MODE:
  224.           start_red.dword = pParmPkt->start_sector;
  225.           end_red.dword   = pParmPkt->end_sector;
  226.           start_hsg.dword = RedBooktoHSG (start_red.dword);
  227.           end_hsg.dword   = RedBooktoHSG (end_red.dword);
  228.           break;
  229.  
  230.       default:
  231.          return(STDON + STERR + ERROR_I24_INVALID_PARAMETER);
  232.    }
  233.  
  234.    if ( (pUnitCB->DeviceInfo.leadout.dword == end_red.dword) &&
  235.         (end_red.dword != 0) )
  236.    {
  237.       if (end_red.ul_redbook.frame != 0)
  238.          end_red.ul_redbook.frame --;
  239.       else if (end_red.ul_redbook.sec != 0)
  240.       {
  241.          end_red.ul_redbook.sec --;
  242.          end_red.ul_redbook.frame = 74;
  243.       }
  244.       else
  245.       {
  246.          end_red.ul_redbook.min--;
  247.          end_red.ul_redbook.sec = 59;
  248.          end_red.ul_redbook.frame = 74;
  249.       }
  250.    }
  251.  
  252.    if ( (ULONG) start_hsg.dword < 0L )
  253.       return (STDON + STERR + ERROR_I24_SECTOR_NOT_FOUND);
  254.  
  255.  
  256.    audio = &pUnitCB->DeviceInfo.Audio;
  257.    audio_status = &audio->status;
  258.  
  259.    /*
  260.    ** Issue Play command
  261.    */
  262.    BuildCDB_PlayAudio_MSF (pUnitCB, start_red, end_red,
  263.                                                (NPIORB_CDB FAR *) &pIORB);
  264.  
  265.    rc = SubmitIORB_Wait (pUnitCB, pIORB);
  266.  
  267.    FreeIORB (pUnitCB, pIORB);
  268.  
  269.    if (rc == STDON)
  270.    {
  271.       pUnitCB->DeviceInfo.playing = TRUE;
  272.       if(pUnitCB->pParentUnitCB)                                        /*SD135221*/
  273.         {                                                               /*SD135221*/
  274.         pUnitCB->pParentUnitCB->DeviceInfo.Parentplaying = TRUE;        /*SD135221*/
  275.         } /* endif */                                                   /*SD135221*/
  276.       audio_status->paused = FALSE;
  277.  
  278.       audio_status->last_start_location.min   = start_red.ul_redbook.min;
  279.       audio_status->last_start_location.sec   = start_red.ul_redbook.sec;
  280.       audio_status->last_start_location.frame = start_red.ul_redbook.frame;
  281.  
  282.       audio_status->last_end_location.min   = end_red.ul_redbook.min;
  283.       audio_status->last_end_location.sec   = end_red.ul_redbook.sec;
  284.       audio_status->last_end_location.frame = end_red.ul_redbook.frame;
  285.    }
  286.    else if (rc == STDON + STERR + ERROR_I24_BAD_COMMAND)
  287.    {
  288.       rc = STDON + STERR + ERROR_I24_SECTOR_NOT_FOUND;
  289.    }
  290.  
  291.    return(rc);
  292. }
  293.  
  294.  
  295. /****************************************************************************
  296.  *
  297.  * FUNCTION NAME = CD_Stop
  298.  *
  299.  * DESCRIPTION   = Stop play
  300.  *
  301.  *                 Cancel any active play request.  It is not an error if the
  302.  *                 drive is not currently playing.  The ending location is
  303.  *                 saved for a subsequent resume operation.
  304.  *
  305.  *                 USHORT CD_Stop (PRP_GENIOCTL pRP, NPUNITCB pUnitCB)
  306.  *
  307.  * INPUT         = pRP              - Request Packet
  308.  *                 pUnitCB          - Pointer to UnitCB
  309.  *
  310.  * OUTPUT        = USHORT           - Packet Status word
  311.  *
  312.  * RETURN-NORMAL =
  313.  * RETURN-ERROR  =
  314.  *
  315.  ****************************************************************************/
  316.  
  317. USHORT CD_Stop (pRP, pUnitCB)
  318.  
  319. PRP_GENIOCTL pRP;
  320. NPUNITCB     pUnitCB;
  321.  
  322. {
  323.    USHORT rc;
  324.    BOOL   playing;
  325.    NPIORB_CDB pIORB;
  326.    struct Status *audio_status;
  327.    struct SubChannel_Position NEAR *pCDBData;
  328.  
  329.    audio_status = &pUnitCB->DeviceInfo.Audio.status;
  330.  
  331.    /*
  332.    ** Simply return without error if not currently playing
  333.    */
  334.    rc = GetPlayStatus (pUnitCB, &playing);
  335.    if ( ! playing)
  336.       return (STDON);
  337.  
  338.    /*
  339.    ** Issue SCSI Pause Command to cancel play operation.
  340.    */
  341.    BuildCDB_PauseResume (pUnitCB, CDBF_PAUSE, (NPIORB_CDB FAR *) &pIORB);
  342.  
  343.    rc = SubmitIORB_Wait (pUnitCB, pIORB);
  344.  
  345.    FreeIORB (pUnitCB, pIORB);
  346.  
  347.    if (rc & STERR)
  348.       return(rc);
  349.  
  350.    /*
  351.    ** Issue SCSI Read SubChannel - Current Position Command
  352.    */
  353.    BuildCDB_ReadSubChannel(pUnitCB, RSC_CURRENT_POSITION,
  354.                                     (NPIORB_CDB FAR *) &pIORB);
  355.  
  356.    rc = SubmitIORB_Wait(pUnitCB, pIORB);
  357.  
  358.  
  359.    if (rc == STDON)
  360.    {
  361.       pCDBData = (struct SubChannel_Position FAR *) pIORB->CDB_data;
  362.  
  363.       if (pUnitCB->DeviceInfo.product_id_code == NEC_260_17B)
  364.       {
  365.          audio_status->last_start_location.frame
  366.                              = BCDtoBinary(pCDBData->abs_address.redbook.frame);
  367.          audio_status->last_start_location.sec
  368.                              = BCDtoBinary(pCDBData->abs_address.redbook.sec);
  369.          audio_status->last_start_location.min
  370.                              = BCDtoBinary(pCDBData->abs_address.redbook.min);
  371.       }
  372.       else
  373.       {
  374.          audio_status->last_start_location.frame
  375.                                          = pCDBData->abs_address.redbook.frame;
  376.          audio_status->last_start_location.sec
  377.                                          = pCDBData->abs_address.redbook.sec;
  378.          audio_status->last_start_location.min
  379.                                          = pCDBData->abs_address.redbook.min;
  380.       }
  381.  
  382.       audio_status->paused = TRUE;
  383.       pUnitCB->DeviceInfo.playing = FALSE;
  384.       if(pUnitCB->pParentUnitCB)                                        /*SD135221*/
  385.         {                                                               /*SD135221*/
  386.         pUnitCB->pParentUnitCB->DeviceInfo.Parentplaying = FALSE;       /*SD135221*/
  387.         } /* endif */                                                   /*SD135221*/
  388.    }
  389.  
  390.    FreeIORB (pUnitCB, pIORB);
  391.  
  392.    return(rc);
  393. }
  394.  
  395.  
  396. /****************************************************************************
  397.  *
  398.  * FUNCTION NAME = CD_Resume
  399.  *
  400.  * DESCRIPTION   = Resume Play
  401.  *
  402.  *                 Resume playing audio tracks after play has been interrupted
  403.  *                 with the Stop Audio command.  An error is returned if there
  404.  *                 was no previous Stop command.  The Resume is converted to a
  405.  *                 Play command from the last play address when paused.
  406.  *
  407.  *                 USHORT CD_Resume (PRP_GENIOCTL pRP, NPUNITCB pUnitCB)
  408.  *
  409.  * INPUT         = pRP              - Request Packet
  410.  *                 pUnitCB          - Pointer to UnitCB
  411.  *
  412.  * OUTPUT        = USHORT           - Packet Status word
  413.  *
  414.  * RETURN-NORMAL =
  415.  * RETURN-ERROR  =
  416.  *
  417.  ****************************************************************************/
  418.  
  419. USHORT CD_Resume (pRP, pUnitCB)
  420.  
  421. PRP_GENIOCTL pRP;
  422. NPUNITCB     pUnitCB;
  423.  
  424. {
  425.    USHORT rc;
  426.    NPIORB_CDB pIORB;
  427.  
  428.    struct Status *audio_status;
  429.    struct Audio  *audio;
  430.  
  431.    union AddressType start_red, end_red;
  432.  
  433.    audio = &pUnitCB->DeviceInfo.Audio;
  434.    audio_status = &audio->status;
  435.  
  436.    if (pUnitCB->Flags & UCF_UNCERTAIN_MEDIA)
  437.       return(STDON + STERR + ERROR_I24_UNCERTAIN_MEDIA);
  438.  
  439.    if ( ! audio_status->paused )
  440.       return (STDON + STERR + ERROR_I24_SECTOR_NOT_FOUND);
  441.  
  442.    /*
  443.    ** Resume is simply a play from the last address when paused to the
  444.    ** last ending play address.
  445.    */
  446.    start_red.ul_redbook.min   = audio_status->last_start_location.min;
  447.    start_red.ul_redbook.sec   = audio_status->last_start_location.sec;
  448.    start_red.ul_redbook.frame = audio_status->last_start_location.frame;
  449.    start_red.ul_redbook.zero  = 0;
  450.  
  451.    end_red.ul_redbook.min   = audio_status->last_end_location.min;
  452.    end_red.ul_redbook.sec   = audio_status->last_end_location.sec;
  453.    end_red.ul_redbook.frame = audio_status->last_end_location.frame;
  454.    end_red.ul_redbook.zero  = 0;
  455.  
  456.    BuildCDB_PlayAudio_MSF (pUnitCB, start_red, end_red,
  457.                                                (NPIORB_CDB FAR *) &pIORB);
  458.  
  459.    rc = SubmitIORB_Wait (pUnitCB, pIORB);
  460.  
  461.    FreeIORB (pUnitCB, pIORB);
  462.  
  463.  
  464.    if ( (rc == STDON) || (rc == STDON + STERR + ERROR_I24_UNCERTAIN_MEDIA) )
  465.       audio_status->paused = FALSE;
  466.  
  467.    pUnitCB->DeviceInfo.playing = TRUE;
  468.    if(pUnitCB->pParentUnitCB)                                   /*SD135221*/
  469.      {                                                          /*SD135221*/
  470.      pUnitCB->pParentUnitCB->DeviceInfo.Parentplaying = TRUE;   /*SD135221*/
  471.      } /* endif */                                              /*SD135221*/
  472.  
  473.    return(rc);
  474. }
  475.  
  476.  
  477. /****************************************************************************
  478.  *
  479.  * FUNCTION NAME = CD_AudioChannelInfo
  480.  *
  481.  * DESCRIPTION   = Return audio channel information
  482.  *
  483.  *       Return the current settings of the audio channel controls.  These
  484.  *       are either the default settings or those set with the Audio Channel
  485.  *       control IOCTL.
  486.  *
  487.  *       USHORT CD_AudioChannelInfo (PRP_GENIOCTL pRP, NPUNITCB pUnitCB)
  488.  *
  489.  * INPUT         = pRP              - Request Packet
  490.  *                 pUnitCB          - Pointer to UnitCB
  491.  *
  492.  * OUTPUT        = USHORT           - Packet Status word
  493.  *
  494.  * RETURN-NORMAL =
  495.  * RETURN-ERROR  =
  496.  *
  497.  ****************************************************************************/
  498.  
  499. USHORT CD_AudioChannelInfo (pRP, pUnitCB)
  500.  
  501. PRP_GENIOCTL pRP;
  502. NPUNITCB     pUnitCB;
  503.  
  504. {
  505.    struct Channel *channel;
  506.  
  507.    channel = &pUnitCB->DeviceInfo.Audio.channel;
  508.  
  509.    * (struct AudioChannelControl_Data FAR *)pRP->DataPacket =
  510.  
  511.    * (struct AudioChannelControl_Data NEAR *) channel;
  512.  
  513.   return(STDON);
  514.  
  515. }
  516.  
  517.  
  518. /****************************************************************************
  519.  *
  520.  * FUNCTION NAME = CD_AudioDiskInfo
  521.  *
  522.  * DESCRIPTION   = Return audio disk information.
  523.  *
  524.  *       Returns the first and last track numbers and the Red Book address
  525.  *       for the lead-out track.  This information is read from the TOC info
  526.  *       on the Q-channel on the lead-in track.  The first and last number are
  527.  *       binary values and not BCD.
  528.  *
  529.  *       USHORT CD_AudioDiskInfo (PRP_GENIOCTL pRP, NPUNITCB pUnitCB)
  530.  *
  531.  * INPUT         = pRP              - Request Packet
  532.  *                 pUnitCB          - Pointer to UnitCB
  533.  *
  534.  * OUTPUT        = USHORT           - Packet Status word
  535.  *
  536.  * RETURN-NORMAL =
  537.  * RETURN-ERROR  =
  538.  *
  539.  ****************************************************************************/
  540.  
  541. USHORT CD_AudioDiskInfo (pRP, pUnitCB)
  542.  
  543. PRP_GENIOCTL pRP;
  544. NPUNITCB     pUnitCB;
  545.  
  546. {
  547.    USHORT rc;
  548.    NPIORB_CDB pIORB;
  549.  
  550.    struct AudioDiskInfo_Data FAR *pDataPkt;
  551.    struct ReadTOC_Data FAR *pCDBData;
  552.  
  553.    pDataPkt = (struct AudioDiskInfo_Data FAR *) pRP->DataPacket;
  554.  
  555.  
  556.    if (pUnitCB->Flags & UCF_UNCERTAIN_MEDIA)
  557.       return (STDON + STERR + ERROR_I24_UNCERTAIN_MEDIA);
  558.  
  559.    /*
  560.    ** Issue a SCSI Read TOC command to retrieve the information.
  561.    */
  562.    BuildCDB_ReadTOC (pUnitCB,LEAD_OUT_TRACK_NUMBER,1,(NPIORB_CDB FAR *) &pIORB);
  563.  
  564.    rc = SubmitIORB_Wait (pUnitCB, pIORB);
  565.  
  566.    if (rc & STERR)
  567.    {
  568.       if (ReadTOC_Leadout (pUnitCB, pIORB) & STERR)
  569.       {
  570.          FreeIORB (pUnitCB, pIORB);
  571.          return(rc);
  572.       }
  573.    }
  574.    /*
  575.    ** Copy the data from the CDB data area to the IOCTL data packet
  576.    */
  577.    pCDBData = (struct ReadTOC_Data FAR *) pIORB->CDB_data;
  578.  
  579.    pDataPkt->lowest_track  = pCDBData->toc_hdr.first_track;
  580.    pDataPkt->highest_track = pCDBData->toc_hdr.last_track;
  581.  
  582.    pDataPkt->frame = pCDBData->toc_descriptor[0].abs_address.redbook.frame;
  583.    pDataPkt->sec   = pCDBData->toc_descriptor[0].abs_address.redbook.sec;
  584.    pDataPkt->min   = pCDBData->toc_descriptor[0].abs_address.redbook.min;
  585.    pDataPkt->zero  = 0;
  586.  
  587.    pUnitCB->DeviceInfo.leadout.ul_redbook.min   = pDataPkt->min;
  588.    pUnitCB->DeviceInfo.leadout.ul_redbook.sec   = pDataPkt->sec;
  589.    pUnitCB->DeviceInfo.leadout.ul_redbook.frame = pDataPkt->frame;
  590.  
  591.    if (pUnitCB->DeviceInfo.product_id_code == NEC_260_17B)
  592.    {
  593.       pDataPkt->frame = BCDtoBinary(pDataPkt->frame);
  594.       pDataPkt->sec   = BCDtoBinary(pDataPkt->sec);
  595.       pDataPkt->min   = BCDtoBinary(pDataPkt->min);
  596.    }
  597.  
  598.  
  599.    FreeIORB (pUnitCB, pIORB);
  600.  
  601.    /*
  602.    ** Some early ATAPI devices with OAK firmware return LEAD_OUT_TRACK_NUMBER
  603.    ** as the first track instead of the true first track.  If we issue the
  604.    ** ReadTOC with a starting track of 0, the correct first track will be
  605.    ** in the data returned.
  606.    */
  607.    if ((pDataPkt->lowest_track == LEAD_OUT_TRACK_NUMBER) &&
  608.        (pUnitCB->DeviceInfo.interface_type == INTERFACE_ATAPI))
  609.    {
  610.       /*
  611.       ** Issue a SCSI Read TOC command to retrieve the information.
  612.       */
  613.       BuildCDB_ReadTOC (pUnitCB,0,1,(NPIORB_CDB FAR *) &pIORB);
  614.  
  615.       rc = SubmitIORB_Wait (pUnitCB, pIORB);
  616.  
  617.       if (!(rc & STERR) )
  618.       {
  619.          pCDBData = (struct ReadTOC_Data FAR *) pIORB->CDB_data;
  620.          pDataPkt->lowest_track = pCDBData->toc_hdr.first_track;
  621.       }
  622.  
  623.       FreeIORB (pUnitCB, pIORB);
  624.    }
  625.  
  626.    return(STDON);
  627. }
  628.  
  629.  
  630. /****************************************************************************
  631.  *
  632.  * FUNCTION NAME = CD_AudioTrackInfo
  633.  *
  634.  * DESCRIPTION   = Return audio track information.
  635.  *
  636.  *      Given a track number, return the Red Book address for the starting
  637.  *      point of the track, and the track control information for that track.
  638.  *
  639.  *      USHORT CD_AudioTrackInfo (PRP_GENIOCTL pRP, NPUNITCB pUnitCB)
  640.  *
  641.  * INPUT         = pRP              - Request Packet
  642.  *                 pUnitCB          - Pointer to UnitCB
  643.  *
  644.  * OUTPUT        = USHORT           - Packet Status word
  645.  *
  646.  * RETURN-NORMAL =
  647.  * RETURN-ERROR  =
  648.  *
  649.  ****************************************************************************/
  650.  
  651. USHORT CD_AudioTrackInfo (pRP, pUnitCB)
  652.  
  653. PRP_GENIOCTL pRP;
  654. NPUNITCB     pUnitCB;
  655.  
  656. {
  657.    USHORT rc;
  658.    NPIORB_CDB pIORB;
  659.  
  660.    struct AudioTrackInfo_Data FAR *pDataPkt;
  661.    struct ReadTOC_Data FAR *pCDBData;
  662.  
  663.    pDataPkt = (struct AudioTrackInfo_Data FAR *) pRP->DataPacket;
  664.  
  665.  
  666.    if (pUnitCB->Flags & UCF_UNCERTAIN_MEDIA)
  667.       return (STDON + STERR + ERROR_I24_UNCERTAIN_MEDIA);
  668.  
  669.    /*
  670.    ** Issue a SCSI Read TOC command to retrieve the information.
  671.    */
  672.    BuildCDB_ReadTOC (pUnitCB,
  673.                  ((struct AudioTrackInfo FAR *)pRP->ParmPacket)->track_number,
  674.                  1,
  675.                  (NPIORB_CDB FAR *) &pIORB);
  676.  
  677.    rc = SubmitIORB_Wait (pUnitCB, pIORB);
  678.  
  679.    /*
  680.    ** If there's an error reading the TOC for the leadout track, then
  681.    ** re-read 2 TOC entries starting with the last valid track number.
  682.    */
  683.    if ( (rc & STERR) &&
  684.         ( ((struct AudioTrackInfo FAR *)pRP->ParmPacket)->track_number
  685.                                                    == LEAD_OUT_TRACK_NUMBER) )
  686.    {
  687.       rc = ReadTOC_Leadout (pUnitCB, pIORB);
  688.    }
  689.  
  690.    /*
  691.    ** Copy the data from the CDB data area to the IOCTL data packet
  692.    */
  693.    if (rc == STDON)
  694.    {
  695.       pCDBData = (struct ReadTOC_Data FAR *) pIORB->CDB_data;
  696.  
  697.       pDataPkt->frame = pCDBData->toc_descriptor[0].abs_address.redbook.frame;
  698.       pDataPkt->sec   = pCDBData->toc_descriptor[0].abs_address.redbook.sec;
  699.       pDataPkt->min   = pCDBData->toc_descriptor[0].abs_address.redbook.min;
  700.       pDataPkt->zero  = 0;
  701.  
  702.       if (pUnitCB->DeviceInfo.Audio.capabilities & DCAPS_NO_ADR_RETURNED)
  703.          pCDBData->toc_descriptor[0].ADR = ADR_CURRENT_POSITION;
  704.  
  705.       pDataPkt->control =  pCDBData->toc_descriptor[0].ADR |
  706.                            (pCDBData->toc_descriptor[0].control << 4);
  707.  
  708.  
  709.       if (pUnitCB->DeviceInfo.product_id_code == NEC_260_17B)
  710.       {
  711.          pDataPkt->frame = BCDtoBinary(pDataPkt->frame);
  712.          pDataPkt->sec   = BCDtoBinary(pDataPkt->sec);
  713.          pDataPkt->min   = BCDtoBinary(pDataPkt->min);
  714.       }
  715.    }
  716.  
  717.    FreeIORB (pUnitCB, pIORB);
  718.  
  719.    return(rc);
  720. }
  721.  
  722.  
  723. /****************************************************************************
  724.  *
  725.  * FUNCTION NAME = ReadTOC_Leadout
  726.  *
  727.  * DESCRIPTION   = Read the TOC for the leadout track;
  728.  *
  729.  *     The Hitachi 3750 returns a check condition if a ReadTOC command is
  730.  *     issued for track_num = 0xAA, the leadout track. Reading the TOC for
  731.  *     the leadout track is valid under SCSI-II.  The workaround is to issue
  732.  *     the ReadTOC command for 2 TOC entries, starting with the last valid
  733.  *     track_num before the lead out track. The last entry is the leadout track.
  734.  *
  735.  *     USHORT RetryTOCRead  (NPUNITCB pUnitCB, NPIORB pIORB)
  736.  *
  737.  * INPUT         = pUnitCB          - Pointer to UnitCB
  738.  *                 pIORB            - Pointer to IORB
  739.  *
  740.  * OUTPUT        = USHORT           - Packet Status word
  741.  *
  742.  * RETURN-NORMAL =
  743.  * RETURN-ERROR  =
  744.  *
  745.  ****************************************************************************/
  746.  
  747. USHORT ReadTOC_Leadout (pUnitCB, pIORB)
  748.  
  749. NPUNITCB   pUnitCB;
  750. NPIORB_CDB pIORB;
  751. {
  752.    NPIORB_CDB pIORB2;
  753.    struct ReadTOC_Data FAR *pCDBData1;
  754.    struct ReadTOC_Data FAR *pCDBData2;
  755.    USHORT rc = STDON + STERR;
  756.  
  757.    if ( (pIORB->status_block.Flags & STATUS_SENSEDATA_VALID) &&
  758.         ((pIORB->sense_data.error_code == 0x70) ||
  759.          (pIORB->sense_data.error_code == 0x71)) &&
  760.  
  761.            pIORB->sense_data.sense_key == SCSI_SK_ILLEGALREQ)
  762. /*      && pIORB->sense_data.additional_sense_code == ASC_INVALID_FIELD)   */
  763.    {
  764.       BuildCDB_ReadTOC (pUnitCB, 1, 1, (NPIORB_CDB FAR *) &pIORB2);
  765.  
  766.       rc = SubmitIORB_Wait (pUnitCB, pIORB2);
  767.  
  768.       if (rc == STDON)
  769.       {
  770.          pCDBData1 = (struct ReadTOC_Data FAR *) pIORB->CDB_data;
  771.          pCDBData2 = (struct ReadTOC_Data FAR *) pIORB2->CDB_data;
  772.  
  773.          FreeIORB(pUnitCB, pIORB2);
  774.  
  775.          BuildCDB_ReadTOC (pUnitCB,
  776.                            pCDBData2->toc_hdr.last_track,
  777.                            2,
  778.                            (NPIORB_CDB FAR *) &pIORB2);
  779.  
  780.          rc = SubmitIORB_Wait (pUnitCB, pIORB2);
  781.  
  782.          if (rc == STDON)
  783.          {
  784.            pCDBData1->toc_hdr = pCDBData2->toc_hdr;
  785.            pCDBData1->toc_descriptor[0] = pCDBData2->toc_descriptor[1];
  786.          }
  787.       }
  788.       FreeIORB(pUnitCB, pIORB2);
  789.    }
  790.    return(rc);
  791. }
  792.  
  793.  
  794. /****************************************************************************
  795.  *
  796.  * FUNCTION NAME = CD_AudioQChannelInfo
  797.  *
  798.  * DESCRIPTION   = Return audio Q-channel information.
  799.  *
  800.  *        Reads and returns the most current address information from the
  801.  *        Q-channel.  This command does not interrupt the present status
  802.  *        of the drive as one of its intended purposes is to monitor the
  803.  *        location of the read head while playing audio tracks.
  804.  *
  805.  *        USHORT CD_QChannelInfo (PRP_GENIOCTL pRP, NPUNITCB pUnitCB)
  806.  *
  807.  * INPUT         = pRP              - Request Packet
  808.  *                 pUnitCB          - Pointer to UnitCB
  809.  *
  810.  * OUTPUT        = USHORT           - Packet Status word
  811.  *
  812.  * RETURN-NORMAL =
  813.  * RETURN-ERROR  =
  814.  *
  815.  ****************************************************************************/
  816.  
  817. USHORT CD_AudioQChannelInfo (pRP, pUnitCB)
  818.  
  819. PRP_GENIOCTL pRP;
  820. NPUNITCB     pUnitCB;
  821.  
  822. {
  823.    USHORT rc;
  824.    NPIORB_CDB pIORB;
  825.  
  826.    struct AudioQChannelInfo_Data FAR *pDataPkt;
  827.    struct SubChannel_Position FAR *pCDBData;
  828.  
  829.    pDataPkt = (struct AudioQChannelInfo_Data FAR *) pRP->DataPacket;
  830.  
  831.    if (pUnitCB->Flags & UCF_UNCERTAIN_MEDIA)
  832.       return (STDON + STERR + ERROR_I24_UNCERTAIN_MEDIA);
  833.  
  834.    if ( (rc = ClearCheckCondition (pUnitCB)) & STERR)
  835.       return(rc);
  836.  
  837.    /*
  838.    ** Issue a SCSI Read TOC command to retrieve the information.
  839.    */
  840.    BuildCDB_ReadSubChannel(pUnitCB, RSC_CURRENT_POSITION,
  841.                                     (NPIORB_CDB FAR *) &pIORB);
  842.  
  843.    rc = SubmitIORB_Wait (pUnitCB, pIORB);
  844.  
  845.    if (rc & STERR)
  846.    {
  847.       FreeIORB (pUnitCB, pIORB);
  848.       return(rc);
  849.    }
  850.    /*
  851.    ** Copy the data from the CDB data area to the IOCTL data packet
  852.    */
  853.    pCDBData = (struct SubChannel_Position FAR *) pIORB->CDB_data;
  854.  
  855.    if (pUnitCB->DeviceInfo.product_id_code == NEC_260_17B)
  856.    {
  857.       pDataPkt->min    = BCDtoBinary(pCDBData->rel_address.redbook.min);
  858.       pDataPkt->sec    = BCDtoBinary(pCDBData->rel_address.redbook.sec);
  859.       pDataPkt->frame  = BCDtoBinary(pCDBData->rel_address.redbook.frame);
  860.  
  861.       pDataPkt->amin   = BCDtoBinary(pCDBData->abs_address.redbook.min);
  862.       pDataPkt->asec   = BCDtoBinary(pCDBData->abs_address.redbook.sec);
  863.       pDataPkt->aframe = BCDtoBinary(pCDBData->abs_address.redbook.frame);
  864.    }
  865.    else
  866.    {
  867.       pDataPkt->min    = pCDBData->rel_address.redbook.min;
  868.       pDataPkt->sec    = pCDBData->rel_address.redbook.sec;
  869.       pDataPkt->frame  = pCDBData->rel_address.redbook.frame;
  870.  
  871.       pDataPkt->amin   = pCDBData->abs_address.redbook.min;
  872.       pDataPkt->asec   = pCDBData->abs_address.redbook.sec;
  873.       pDataPkt->aframe = pCDBData->abs_address.redbook.frame;
  874.    }
  875.  
  876.    pDataPkt->zero   = 0;
  877.  
  878.    if (pUnitCB->DeviceInfo.Audio.capabilities & DCAPS_NO_ADR_RETURNED)
  879.       pCDBData->ADR = ADR_CURRENT_POSITION;
  880.  
  881.    pDataPkt->control = pCDBData->ADR | (pCDBData->control << 4);
  882.  
  883.    pDataPkt->tno   = BinaryToBCD (pCDBData->track_number);
  884.    pDataPkt->point = BinaryToBCD (pCDBData->index_number);
  885.  
  886.    FreeIORB (pUnitCB, pIORB);
  887.  
  888.    return(STDON);
  889. }
  890.  
  891.  
  892. /****************************************************************************
  893.  *
  894.  * FUNCTION NAME = CD_AudioSubChannelInfo
  895.  *
  896.  * DESCRIPTION   = Return subchannel information
  897.  *
  898.  *         Return subchannel information.
  899.  *
  900.  *         USHORT CD_AudioSubChannelInfo (PRP_GENIOCTL pRP, NPUNITCB pUnitCB)
  901.  *
  902.  * INPUT         = pRP              - Request Packet
  903.  *                 pUnitCB          - Pointer to UnitCB
  904.  *
  905.  * OUTPUT        = USHORT           - Packet Status word
  906.  *
  907.  * RETURN-NORMAL =
  908.  * RETURN-ERROR  =
  909.  *
  910.  ****************************************************************************/
  911.  
  912. USHORT CD_AudioSubChannelInfo (pRP, pUnitCB)
  913.  
  914. PRP_GENIOCTL pRP;
  915. NPUNITCB     pUnitCB;
  916.  
  917. {
  918.    return(STDON + STERR + ERROR_I24_BAD_COMMAND);
  919. }
  920.  
  921.  
  922. /****************************************************************************
  923.  *
  924.  * FUNCTION NAME = CD_AudioStatusInfo
  925.  *
  926.  * DESCRIPTION   = Return audio status information.
  927.  *
  928.  *       Returns the Audio Paused bit and the starting and ending locations
  929.  *       of the last play or the next resume.
  930.  *
  931.  *       USHORT CD_AudioStatusInfo (PRP_GENIOCTL pRP, NPUNITCB pUnitCB)
  932.  *
  933.  * INPUT         = pRP              - Request Packet
  934.  *                 pUnitCB          - Pointer to UnitCB
  935.  *
  936.  * OUTPUT        = USHORT           - Packet Status word
  937.  *
  938.  * RETURN-NORMAL =
  939.  * RETURN-ERROR  =
  940.  *
  941.  ****************************************************************************/
  942.  
  943. USHORT CD_AudioStatusInfo (pRP, pUnitCB)
  944.  
  945. PRP_GENIOCTL pRP;
  946. NPUNITCB     pUnitCB;
  947.  
  948. {
  949.    USHORT rc;
  950.    NPIORB_CDB pIORB;
  951.  
  952.    struct AudioStatusInfo_Data FAR *pDataPkt;
  953.    struct SubChannel_Position  FAR *pCDBData;
  954.  
  955.    struct Status *audio_status;
  956.    struct Audio  *audio;
  957.  
  958.    struct ul_RedBookAddress start, end;
  959.  
  960.  
  961.    pDataPkt = (struct AudioStatusInfo_Data FAR *) pRP->DataPacket;
  962.    audio = &pUnitCB->DeviceInfo.Audio;
  963.    audio_status = &audio->status;
  964.  
  965.    /*
  966.    ** Issue a SCSI Read SubChannel command to retrieve the information.
  967.    */
  968.    BuildCDB_ReadSubChannel(pUnitCB, RSC_CURRENT_POSITION,
  969.                                     (NPIORB_CDB FAR *) &pIORB);
  970.  
  971.    rc = SubmitIORB_Wait (pUnitCB, pIORB);
  972.  
  973.    if (rc == STDON)
  974.    {
  975.       /*
  976.       ** Copy the data to the IOCTL data packet
  977.       */
  978.       pCDBData = (struct SubChannel_Position FAR *) pIORB->CDB_data;
  979.  
  980.       start.frame = audio_status->last_start_location.frame;
  981.       start.sec   = audio_status->last_start_location.sec;
  982.       start.min   = audio_status->last_start_location.min;
  983.       start.zero  = 0;
  984.  
  985.       end.frame =  audio_status->last_end_location.frame;
  986.       end.sec   =  audio_status->last_end_location.sec;
  987.       end.min   =  audio_status->last_end_location.min;
  988.       end.zero  =  0;
  989.  
  990.       pDataPkt->audio_status = *(USHORT *) audio_status;
  991.       pDataPkt->last_start_location = *(ULONG FAR *) &start;
  992.       pDataPkt->last_end_location   = *(ULONG FAR *) &end;
  993.  
  994.       if (pUnitCB->Flags & UCF_UNCERTAIN_MEDIA)
  995.          rc = STDON + STERR + ERROR_I24_UNCERTAIN_MEDIA;
  996.    }
  997.  
  998.    FreeIORB (pUnitCB, pIORB);
  999.  
  1000.    return(rc);
  1001. }
  1002.  
  1003.