home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cset21v6.zip / MMPM2TK / TK / CDMCT / IBMCDPRO.C < prev    next >
C/C++ Source or Header  |  1993-03-16  |  67KB  |  1,422 lines

  1. /****************************************************************************/
  2. /*                                                                          */
  3. /* SOURCE FILE NAME:  IBMCDPRO.C                                            */
  4. /*                                                                          */
  5. /* DESCRIPTIVE NAME:  IBM CD-ROMs PROCESS                                   */
  6. /*                                                                          */
  7. /* COPYRIGHT:  (c) IBM Corp. 1990 - 1993                                    */
  8. /*                                                                          */
  9. /* FUNCTION:  This file contains the functions that require hardware        */
  10. /*            processing.                                                   */
  11. /*                                                                          */
  12. /*                                                                          */
  13. /* OTHER FUNCTIONS:                                                         */
  14. /*       CD01_Cue           - Preroll a drive.                              */
  15. /*       CD01_CuePoint      - Set up a cue point.                           */
  16. /*       CD01_GetCaps       - Get device capabilities.                      */
  17. /*       CD01_GetDiscInfo   - Get status info of the disc.                  */
  18. /*       CD01_GetID         - Get the CD ID from the disc.                  */
  19. /*       CD01_GetPosition   - Get the position of the head.                 */
  20. /*       CD01_GetState      - Get the state of the device.                  */
  21. /*       CD01_GetTOC        - Returns table of contents (MMTOC form) of CD. */
  22. /*       CD01_GetVolume     - Get the volume settings of the drive.         */
  23. /*       CD01_LockDoor      - Lock/Unlock the drive door.                   */
  24. /*       CD01_Open          - Open specified device/drive.                  */
  25. /*       CD01_Play          - Initiate a play operation.                    */
  26. /*       CD01_PlayCont      - Continue a play operation.                    */
  27. /*       CD01_PosAdvise     - Set up a position advise command.             */
  28. /*       CD01_RegTracks     - Register tracks on the disc.                  */
  29. /*       CD01_Restore       - Restore the saved instance.                   */
  30. /*       CD01_Resume        - Unpause a CD Play operation.                  */
  31. /*       CD01_Save          - Save the current instance.                    */
  32. /*       CD01_Seek          - Seek to a particular redbook address.         */
  33. /*       CD01_SetVolume     - Set the volume of the drive.                  */
  34. /*       CD01_Stop          - Stop a CD Play operation.                     */
  35. /*                                                                          */
  36. /*       NOTE:  CD01_... refers to commands that are compatible with the    */
  37. /*              IBM 3510 CD-ROM drive.  CD02_... may refer to commands      */
  38. /*              that are compatible with the CD02 drives, which are         */
  39. /*              not compatible with the CD01_... commands.  This way        */
  40. /*              different hardware can share the same VSD.                  */
  41. /*                                                                          */
  42. /*                                                                          */
  43. /****************************************************************************/
  44.  
  45. #define INCL_DOSERRORS
  46. #define INCL_DOSDEVICES
  47. #define INCL_DOSPROCESS
  48. #define INCL_DOSFILEMGR
  49. #define INCL_DOSSEMAPHORES
  50. #include <os2.h>
  51. #include <string.h>
  52. #include <stdlib.h>
  53. #define INCL_MCIOS2
  54. #include <os2me.h>
  55. #include <cdaudos2.h>
  56. #include "ibmcdrom.h"
  57.  
  58.  
  59. /****************************************************************************/
  60. /*                                                                          */
  61. /* SUBROUTINE NAME:  CD01_Cue                                               */
  62. /*                                                                          */
  63. /* DESCRIPTIVE NAME:  CD Cue.                                               */
  64. /*                                                                          */
  65. /* FUNCTION:  Cue up or preroll the drive.  To do this we seek to the       */
  66. /*            current position.                                             */
  67. /*                                                                          */
  68. /* PARAMETERS:                                                              */
  69. /*      PINST pInst      -- Instance structure.                             */
  70. /*                                                                          */
  71. /* EXIT CODES:                                                              */
  72. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  73. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  74. /*                                                                          */
  75. /* NOTES:                                                                   */
  76. /*                                                                          */
  77. /****************************************************************************/
  78. ULONG CD01_Cue(PINST pInst)
  79. {
  80.    ULONG rc, ulPos;
  81.  
  82.    /* test is disk is still present and get current position */
  83.    rc = CD01_GetPosition(pInst, &ulPos);
  84.  
  85.    /* seek to current position to spin disc */
  86.    if (!rc)                              // if no error
  87.       rc = CD01_Seek(pInst, ulPos);
  88.  
  89.    return(rc);
  90.  
  91. }  /* of CD01_Cue() */
  92.  
  93.  
  94.  
  95. /****************************************************************************/
  96. /*                                                                          */
  97. /* SUBROUTINE NAME:  CD01_CuePoint                                          */
  98. /*                                                                          */
  99. /* DESCRIPTIVE NAME:  CD Cue Point                                          */
  100. /*                                                                          */
  101. /* FUNCTION:  Set up the desired cuepoint.  To do this the cue point        */
  102. /*            arrays will need to be updated.                               */
  103. /*                                                                          */
  104. /* PARAMETERS:                                                              */
  105. /*      PINST pInst      -- Instance structure.                             */
  106. /*      ULONG ulParam1   -- Flag set for this message.                      */
  107. /*      MCI_CUEPOINT_PARMS *pParam2 -- Pointer to data record structure.    */
  108. /*                                                                          */
  109. /* EXIT CODES:                                                              */
  110. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  111. /*      MCIERR_CUEPOINT_LIMIT_REACHED -- no more room to add events.        */
  112. /*      MCIERR_INVALID_CUEPOINT       -- unable to locate event.            */
  113. /*                                                                          */
  114. /* NOTES:                                                                   */
  115. /*                                                                          */
  116. /****************************************************************************/
  117. ULONG CD01_CuePoint(PINST pInst, ULONG ulParam1, MCI_CUEPOINT_PARMS *pParam2)
  118. {
  119.    ULONG rc = MCIERR_SUCCESS;
  120.    int i;
  121.  
  122.    if (ulParam1 & MCI_SET_CUEPOINT_ON)
  123.    {
  124.       /* valid cuepoint, find first available entry,  */
  125.       /* CD Audio MCD will make sure that we have room  */
  126.       /* and that cuepoint is unique */
  127.       for (i=0; i < CDMCD_CUEPOINT_MAX; i++)
  128.          if (pInst->arrCuePoint[i].ulEvent == (ULONG) -1L)
  129.             break;
  130.  
  131.       if (i == CDMCD_CUEPOINT_MAX)
  132.          rc = MCIERR_CUEPOINT_LIMIT_REACHED;
  133.       else
  134.       {
  135.          pInst->arrCuePoint[i].ulEvent = pParam2->ulCuepoint;
  136.          pInst->arrCuePoint[i].hwndCallback = pParam2->hwndCallback;
  137.          pInst->arrCuePoint[i].usUserParm = pParam2->usUserParm;
  138.       }
  139.    }  /* of if setting cuepoint */
  140.    else
  141.    {
  142.       for (i=0; i < CDMCD_CUEPOINT_MAX; i++)
  143.       {
  144.          if (pInst->arrCuePoint[i].ulEvent == pParam2->ulCuepoint)
  145.             break;
  146.       }
  147.       if (i == CDMCD_CUEPOINT_MAX)
  148.          rc = MCIERR_INVALID_CUEPOINT;
  149.       else
  150.          pInst->arrCuePoint[i].ulEvent = (ULONG) -1L;
  151.  
  152.    }   /* of else MCI_SET_CUEPOINT_OFF */
  153.  
  154.    return(rc);
  155.  
  156. }  /* of CD01_CuePoint() */
  157.  
  158.  
  159.  
  160. /****************************************************************************/
  161. /*                                                                          */
  162. /* SUBROUTINE NAME:  CD01_GetCaps                                           */
  163. /*                                                                          */
  164. /* DESCRIPTIVE NAME:  CD Get Capabilities.                                  */
  165. /*                                                                          */
  166. /* FUNCTION:  Get information about the capabilities of the device and the  */
  167. /*            VSD.                                                          */
  168. /*                                                                          */
  169. /* PARAMETERS:                                                              */
  170. /*      ULONG ulParam1   -- Flag set for this message.                      */
  171. /*      MCI_GETDEVCAPS_PARMS *pParam2   -- Pointer to data record structure.*/
  172. /*                                                                          */
  173. /* EXIT CODES:                                                              */
  174. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  175. /*      MCIERR_FLAGS_NOT_COMPATIBLE  -- Mis-match in flags.                 */
  176. /*      MCIERR_INVALID_FLAG          -- Unknown flag.                       */
  177. /*      MCIERR_INVALID_ITEM_FLAG     -- Unknown item specified.             */
  178. /*                                                                          */
  179. /* NOTES:  Most of the capabilities are processed in the general MCI Driver.*/
  180. /*      The messages supported need to be listed in the VSD because VSDs    */
  181. /*      may support different messages.                                     */
  182. /*                                                                          */
  183. /*                                                                          */
  184. /****************************************************************************/
  185. ULONG CD01_GetCaps(ULONG ulParam1, MCI_GETDEVCAPS_PARMS *pParam2)
  186. {
  187.    ULONG rc = MCIERR_SUCCESS;
  188.  
  189.    ulParam1 &= WAIT_NOTIFY_MASK;
  190.  
  191.    switch (ulParam1)
  192.    {
  193.       case MCI_GETDEVCAPS_MESSAGE :
  194.          switch (pParam2->usMessage)
  195.          {
  196.             case MCI_CLOSE :                  case MCI_CUE :
  197.             case MCI_GETDEVCAPS :             case MCI_GETTOC :
  198.             case MCI_INFO :                   case MCI_OPEN :
  199.             case MCI_PAUSE :                  case MCI_PLAY :
  200.                                               case MCI_RESUME :
  201.             case MCI_SEEK :                   case MCI_SET :
  202.             case MCI_SET_CUEPOINT :           case MCI_SET_POSITION_ADVISE :
  203.             case MCI_STATUS :                 case MCI_STOP :
  204.             case MCIDRV_SAVE :                case MCIDRV_RESTORE :
  205.             case MCIDRV_SYNC :
  206.             case MCIDRV_REGISTER_DISC :       case MCIDRV_REGISTER_DRIVE :
  207.             case MCIDRV_REGISTER_TRACKS :
  208.             case MCIDRV_CD_SET_VERIFY :       case MCIDRV_CD_STATUS_CVOL :
  209.                pParam2->ulReturn = MCI_TRUE;
  210.                break;
  211.             default :
  212.                pParam2->ulReturn = MCI_FALSE;
  213.          }  /* of switch */
  214.          break;
  215.       case MCI_GETDEVCAPS_ITEM :            // MCD does all that VSD supports
  216.          rc = MCIERR_INVALID_ITEM_FLAG;
  217.          break;
  218.       default :
  219.          rc = MCIERR_INVALID_FLAG;
  220.          break;
  221.    }   /* of switch */
  222.  
  223.    return(rc);
  224.  
  225. }  /* of CD01_GetCaps() */
  226.  
  227.  
  228.  
  229. /****************************************************************************/
  230. /*                                                                          */
  231. /* SUBROUTINE NAME:  CD01_GetDiscInfo                                       */
  232. /*                                                                          */
  233. /* DESCRIPTIVE NAME:  CD Get Disc Information                               */
  234. /*                                                                          */
  235. /* FUNCTION:  Get information contained on the compact disc.                */
  236. /*                                                                          */
  237. /* PARAMETERS:                                                              */
  238. /*      PINST pInst      -- Instance structure.                             */
  239. /*      ULONG ulType     -- Type flag for this message.                     */
  240. /*      MCI_STATUS_PARMS *pParam2   -- Pointer to data record structure.    */
  241. /*                                                                          */
  242. /* EXIT CODES:                                                              */
  243. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  244. /*      MCIERR_FLAGS_NOT_COMPATIBLE  -- Mis-match in flags.                 */
  245. /*                                                                          */
  246. /* NOTES:  The function supports the MCI_STATUS_MEDIA_PRESENT,              */
  247. /*      MCI_STATUS_MODE and MCI_STATUS_READY flags for the MCI_STATUS       */
  248. /*      command message.                                                    */
  249. /*                                                                          */
  250. /****************************************************************************/
  251. ULONG CD01_GetDiscInfo(PINST pInst, ULONG ulType, MCI_STATUS_PARMS *pParam2)
  252. {
  253.    ULONG rc = MCIERR_SUCCESS;
  254.    BYTE data[SEEKSTATDMAX];
  255.    ULONG ulDataLen = SEEKSTATDMAX, ulParamLen = STANDRD_PMAX;
  256.  
  257.    switch(ulType)
  258.    {
  259.       case MCI_STATUS_MEDIA_PRESENT :
  260.          if (CallIOCtl(pInst, CDDRIVE_CAT, DEV__STATUS,
  261.                        "CD01", ulParamLen, &ulParamLen,
  262.                        data,   ulDataLen,  &ulDataLen))
  263.             pParam2->ulReturn = MCI_FALSE;
  264.          else
  265.             if (data[STATAUDFLD] & NO_MEDIA)     // if No disc is present
  266.                pParam2->ulReturn = MCI_FALSE;
  267.             else
  268.                pParam2->ulReturn = MCI_TRUE;
  269.          break;
  270.       case MCI_STATUS_MODE :
  271.          CD01_GetState(pInst, pParam2);
  272.          break;
  273.       case MCI_STATUS_READY :
  274.          CD01_GetState(pInst, pParam2);
  275.          if (pParam2->ulReturn == MCI_MODE_NOT_READY)
  276.             pParam2->ulReturn = MCI_FALSE;
  277.          else
  278.             pParam2->ulReturn = MCI_TRUE;
  279.          break;
  280.       default : rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  281.  
  282.    }  /* of switch */
  283.  
  284.    return(rc);
  285.  
  286. }  /* of CD01_GetDiscInfo() */
  287.  
  288.  
  289.  
  290. /****************************************************************************/
  291. /*                                                                          */
  292. /* SUBROUTINE NAME:  CD01_GetID                                             */
  293. /*                                                                          */
  294. /* DESCRIPTIVE NAME:  CD Get Disc ID.                                       */
  295. /*                                                                          */
  296. /* FUNCTION:  Get the Disc ID.  The disc ID is 8 bytes and format is:       */
  297. /*            ┌────────┬───┬───┬──────┬───┬───┬───┬───┐                     */
  298. /*            │   01   │Addr of│Num of│Address of the │                     */
  299. /*            │UPC = 00│Track 1│Tracks│Lead Out Track │                     */
  300. /*            └────────┴───┴───┴──────┴───┴───┴───┴───┘                     */
  301. /*                                                                          */
  302. /* PARAMETERS:                                                              */
  303. /*      PINST pInst      -- Instance structure.                             */
  304. /*      MCI_CD_DISC_ID *pDiscID  -- Pointer to data record structure.       */
  305. /*      BYTE  *LowTrack  -- Lowest track number.                            */
  306. /*      BYTE  *HighTrack -- Highest track number.                           */
  307. /*                                                                          */
  308. /* EXIT CODES:                                                              */
  309. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  310. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  311. /*                                                                          */
  312. /* NOTES:                                                                   */
  313. /*                                                                          */
  314. /****************************************************************************/
  315. ULONG CD01_GetID(PINST pInst, MCI_CD_ID *pDiscID,
  316.                  BYTE *LowTrack, BYTE *HighTrack)
  317. {
  318.    ULONG rc;
  319.    BYTE data[DSKTRCK_DMAX], param[DSKTRCK_PMAX] = "CD01";
  320.    ULONG ulDataLen = DSKTRCK_DMAX, ulParamLen = STANDRD_PMAX;
  321.  
  322.    /* set mode */
  323.    pDiscID->Mode = 1;
  324.  
  325.    /* get rest of data */
  326.    rc = CallIOCtl(pInst, CDAUDIO_CAT, DISK___INFO,
  327.                   "CD01", ulParamLen, &ulParamLen,
  328.                   data,   ulDataLen,  &ulDataLen);
  329.  
  330.    if (!rc)
  331.    {
  332.       /* set number of tracks */
  333.       pDiscID->NumTracks = data[TRCKHI_FLD];
  334.       *HighTrack = data[TRCKHI_FLD];
  335.  
  336.       /* set leadout track */
  337.       pDiscID->ulLeadOut = REDBOOK2TOMM(*(ULONG *)&data[TRCKENDADR]);
  338.  
  339.       /* set first track */
  340.       param[TRACKFIELD] = data[TRCKLOWFLD];
  341.       *LowTrack = data[TRCKLOWFLD];
  342.  
  343.       /* get track information to get address of the first track */
  344.       ulDataLen = DSKTRCK_DMAX;
  345.       ulParamLen = DSKTRCK_PMAX;
  346.       rc = CallIOCtl(pInst, CDAUDIO_CAT, TRACK__INFO,
  347.                      param, ulParamLen, &ulParamLen,
  348.                      data,  ulDataLen,  &ulDataLen);
  349.  
  350.       if (!rc)
  351.          pDiscID->usTrack1 = (USHORT) REDBOOK2TOMM(*(ULONG *)&data[TRACKFFFLD]);
  352.  
  353.    }   /* of if no error on IOCTL */
  354.  
  355.    return(rc);
  356.  
  357. }  /* of CD01_GetID() */
  358.  
  359.  
  360.  
  361. /****************************************************************************/
  362. /*                                                                          */
  363. /* SUBROUTINE NAME:  CD01_GetPosition                                       */
  364. /*                                                                          */
  365. /* DESCRIPTIVE NAME:  CD Get Position.                                      */
  366. /*                                                                          */
  367. /* FUNCTION:  Get the current position of the CD-ROM drive.                 */
  368. /*                                                                          */
  369. /* PARAMETERS:                                                              */
  370. /*      PINST pInst        -- Instance structure.                           */
  371. /*      ULONG *pulPosition -- ptr of the current position.                  */
  372. /*                                                                          */
  373. /* EXIT CODES:                                                              */
  374. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  375. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  376. /*      MCIERR_MEDIA_CHANGED         -- A disc change was reported.         */
  377. /*                                                                          */
  378. /* NOTES:  It is important to return the above three return codes because   */
  379. /*         MCDs and Applications may rely on MCI_STATUS POSITION to verify  */
  380. /*         that the same disc is still there.                               */
  381. /*                                                                          */
  382. /****************************************************************************/
  383. ULONG CD01_GetPosition(PINST pInst, ULONG *pulPosition)
  384. {
  385.    ULONG rc;
  386.    BYTE data[LOCATON_DMAX], param[LOCATON_PMAX] = {'C', 'D', '0', '1', RBMODE};
  387.    ULONG ulDataLen = LOCATON_DMAX, ulParamLen = LOCATON_PMAX;
  388.  
  389.    /* get location of head in disc */
  390.    rc = CallIOCtl(pInst, CDDRIVE_CAT, Q__LOCATION,
  391.                   param, ulParamLen, &ulParamLen,
  392.                   data,  ulDataLen,  &ulDataLen);
  393.  
  394.    if (!rc)
  395.       if (pInst->usPlayFlag == TIMER_PLAYING)
  396.       {
  397.          *pulPosition = REDBOOK2TOMM(*(ULONG *)data);
  398.          pInst->ulCurPos = *pulPosition;
  399.       }  /* of if playing */
  400.       else           /* if not playing then use logical location */
  401.          *pulPosition = pInst->ulCurPos;
  402.  
  403.    return(rc);
  404.  
  405. }  /* of CD01_GetPosition() */
  406.  
  407.  
  408.  
  409. /****************************************************************************/
  410. /*                                                                          */
  411. /* SUBROUTINE NAME:  CD01_GetState                                          */
  412. /*                                                                          */
  413. /* DESCRIPTIVE NAME:  CD Get State.                                         */
  414. /*                                                                          */
  415. /* FUNCTION:  Get the state (playing, stopped, paused, etc.) of the device. */
  416. /*                                                                          */
  417. /* PARAMETERS:                                                              */
  418. /*      PINST pInst      -- Instance structure.                             */
  419. /*      MCI_STATUS_PARMS *pParam2   -- Pointer to data record structure.    */
  420. /*                                                                          */
  421. /* EXIT CODES:                                                              */
  422. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  423. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  424. /*                                                                          */
  425. /* NOTES:                                                                   */
  426. /*                                                                          */
  427. /****************************************************************************/
  428. ULONG CD01_GetState(PINST pInst, MCI_STATUS_PARMS *pParam2)
  429. {
  430.    ULONG rc;
  431.    BYTE data[AUDSTAT_DMAX];      //values for the audio status command
  432.    ULONG ulDataLen = AUDSTAT_DMAX, ulParamLen = STANDRD_PMAX;
  433.  
  434.    /* query the status */
  435.    rc = CallIOCtl(pInst, CDDRIVE_CAT, DEV__STATUS,
  436.                   "CD01", ulParamLen, &ulParamLen,
  437.                   data,   ulDataLen,  &ulDataLen);
  438.  
  439.    if (rc)    /* error, manual eject */
  440.       pParam2->ulReturn = MCI_MODE_NOT_READY;
  441.    else
  442.    {
  443.       if (data[STATAUDFLD] & NO_MEDIA)               // if no disc
  444.          pParam2->ulReturn = MCI_MODE_NOT_READY;
  445.       else if (data[STATAUDFLD] & IS_PLAYING)        // if Playing
  446.          pParam2->ulReturn = MCI_MODE_PLAY;
  447.       else
  448.          pParam2->ulReturn = MCI_MODE_STOP;
  449.  
  450.    }  /* of else no IOCTL error */
  451.  
  452.    return(rc);
  453.  
  454. }  /* of CD01_GetState() */
  455.  
  456.  
  457.  
  458. /****************************************************************************/
  459. /*                                                                          */
  460. /* SUBROUTINE NAME:  CD01_GetTOC                                            */
  461. /*                                                                          */
  462. /* DESCRIPTIVE NAME:  CD Get Table of Contents.                             */
  463. /*                                                                          */
  464. /* FUNCTION:  Get the Table of Contents of the playable portion of the CD.  */
  465. /*                                                                          */
  466. /* PARAMETERS:                                                              */
  467. /*      PINST pInst      -- Instance structure.                             */
  468. /*      MCI_TOC_PARMS *pParam2   -- Pointer to data record structure.       */
  469. /*                                                                          */
  470. /* EXIT CODES:                                                              */
  471. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  472. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  473. /*      MCIERR_INVALID_BUFFER        -- Buffer too small.                   */
  474. /*      MCIERR_INVALID_MEDIA_TYPE    -- No audio tracks were found.         */
  475. /*                                                                          */
  476. /* NOTES:                                                                   */
  477. /*                                                                          */
  478. /****************************************************************************/
  479. ULONG CD01_GetTOC(PINST pInst, MCI_TOC_PARMS *pParam2)
  480. {
  481.    ULONG rc;
  482.    BYTE data[DSKTRCK_DMAX], param[DSKTRCK_PMAX] = "CD01";
  483.    BYTE low, hi;             // low and high track values
  484.    BYTE cnt = 0, check = 0;  // audio track counters
  485.    ULONG end_adr, cur_adr;
  486.    ULONG ulDataLen = DSKTRCK_DMAX, ulParamLen = DSKTRCK_PMAX;
  487.  
  488.    /*** GET DISK INFORMATION ***/
  489.    /* get disk information */
  490.    rc = CallIOCtl(pInst, CDAUDIO_CAT, DISK___INFO,
  491.                   param, ulParamLen, &ulParamLen,
  492.                   data,  ulDataLen,  &ulDataLen);
  493.  
  494.    if (!rc)
  495.       if (pParam2->ulBufSize < sizeof(MCI_TOC_REC))
  496.          rc = MCIERR_INVALID_BUFFER;
  497.  
  498.    low = data[TRCKLOWFLD];
  499.    hi  = data[TRCKHI_FLD];
  500.  
  501.    if (!rc)
  502.    {                                            // okay, extract data
  503.       /* get ending address */
  504.       end_adr = REDBOOK2TOMM(*(ULONG *)&data[TRENDFFFLD]);
  505.  
  506.       /*** LOOP TO FILL TABLE ***/
  507.       /******************************************************************
  508.        *  CNT is a counter of audio tracks, LOW starts with the lowest  *
  509.        *  track number and increments with each track, CHECK is a flag  *
  510.        *  marking the previous audio track so that the ending address   *
  511.        *  may be assigned.                                              *
  512.        ******************************************************************/
  513.  
  514.       for (; low <= hi; low++)
  515.       {
  516.          param[TRACKFIELD] = low;
  517.  
  518.          ulDataLen = DSKTRCK_DMAX;
  519.          ulParamLen = DSKTRCK_PMAX;
  520.          rc = CallIOCtl(pInst, CDAUDIO_CAT, TRACK__INFO,
  521.                         param, ulParamLen, &ulParamLen,
  522.                         data,  ulDataLen,  &ulDataLen);
  523.  
  524.          if (rc)
  525.             break;
  526.  
  527.          cur_adr = REDBOOK2TOMM(*(ULONG *)&data[TRACKFFFLD]);
  528.  
  529.          /* Enter address as ending address of previous track */
  530.          if (cnt != check)                     // skip first and data tracks
  531.          {                                     // add ending address
  532.             (pParam2->pBuf + cnt-1)->ulEndAddr = cur_adr;
  533.             check = cnt;
  534.          }
  535.  
  536.          if (!(data[TRKSTATFLD] & IS_DATA_TRK))         // if audio track
  537.          {  /* audio track has been found, is there room for it in buffer */
  538.             /* check for valid buffer size */
  539.             if (pParam2->ulBufSize < (ULONG)(cnt + 1) * sizeof(MCI_TOC_REC))
  540.             {
  541.                rc = MCIERR_INVALID_BUFFER;
  542.                break;
  543.             }
  544.  
  545.             (pParam2->pBuf + cnt)->TrackNum = low;            // track number
  546.             (pParam2->pBuf + cnt)->ulStartAddr = cur_adr;     // add start loc
  547.             (pParam2->pBuf + cnt)->Control = data[TRKSTATFLD];   // Control
  548.             (pParam2->pBuf + cnt)->usCountry = 0;                // Country
  549.             (pParam2->pBuf + cnt)->ulOwner = 0L;                 // Owner
  550.             (pParam2->pBuf + cnt)->ulSerialNum = 0L;             // S/N
  551.  
  552.             if (low == hi)                       // last addr if last track
  553.                (pParam2->pBuf + cnt)->ulEndAddr = end_adr;
  554.             cnt++;
  555.  
  556.          }  /* of if not data track */
  557.  
  558.       }   /* of for loop */
  559.  
  560.       if (!cnt)
  561.          rc = MCIERR_INVALID_MEDIA_TYPE;     // No audio tracks were found.
  562.  
  563.    }   /* of if no error getting audio disc information */
  564.  
  565.    /* find needed buffer size */
  566.    if (rc == MCIERR_INVALID_BUFFER)
  567.    {
  568.       for (; low <= hi; low++)
  569.       {
  570.          param[TRACKFIELD] = low;
  571.  
  572.          ulDataLen = DSKTRCK_DMAX;
  573.          ulParamLen = DSKTRCK_PMAX;
  574.          if (CallIOCtl(pInst, CDAUDIO_CAT, TRACK__INFO,
  575.                        param, ulParamLen, &ulParamLen,
  576.                        data,  ulDataLen,  &ulDataLen))
  577.          {
  578.             rc = MCIERR_DEVICE_NOT_READY;
  579.             break;
  580.          }
  581.  
  582.          if (!(data[TRKSTATFLD] & IS_DATA_TRK))         // if audio track
  583.             cnt++;
  584.  
  585.       }   /* of for loop */
  586.  
  587.    }  /* of if buffer too small */
  588.  
  589.    /* return buffer size */
  590.    pParam2->ulBufSize = sizeof(MCI_TOC_REC) * cnt;
  591.  
  592.    return(rc);
  593.  
  594. }  /* of CD01_GetTOC() */
  595.  
  596.  
  597.  
  598. /****************************************************************************/
  599. /*                                                                          */
  600. /* SUBROUTINE NAME:  CD01_GetVolume                                         */
  601. /*                                                                          */
  602. /* DESCRIPTIVE NAME:  CD Get Volume for the IBM 3510.                       */
  603. /*                                                                          */
  604. /* FUNCTION:  Get the left and right volume levels.                         */
  605. /*                                                                          */
  606. /* PARAMETERS:                                                              */
  607. /*      PINST pInst      -- Instance structure.                             */
  608. /*      ULONG *pulVolume -- Retrieved volume.                               */
  609. /*                                                                          */
  610. /* EXIT CODES:                                                              */
  611. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  612. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  613. /*                                                                          */
  614. /* NOTES:                                                                   */
  615. /*                                                                          */
  616. /****************************************************************************/
  617. ULONG CD01_GetVolume(PINST pInst, ULONG *pulVolume)
  618. {
  619.    ULONG rc;
  620.    BYTE data[QVOLUME_DMAX];
  621.    ULONG ulDataLen = QVOLUME_DMAX, ulParamLen = STANDRD_PMAX;
  622.  
  623.    /* audio channel information */
  624.    rc = CallIOCtl(pInst, CDAUDIO_CAT, AUD_CH_INFO,
  625.                   "CD01", ulParamLen, &ulParamLen,
  626.                   data,   ulDataLen,  &ulDataLen);
  627.  
  628.    if (!rc)
  629.       /* convert volume levels from 0-FF to 0-100% */
  630.       *pulVolume = (data[VOL_LT_FLD] * 100 / 0xFF) |        // Left Channel
  631.                    (data[VOL_RT_FLD] * 100 / 0xFF << 16);   // Right Chan
  632.  
  633.    return(rc);
  634.  
  635. }  /* of CD01_GetVolume() */
  636.  
  637.  
  638.  
  639. /****************************************************************************/
  640. /*                                                                          */
  641. /* SUBROUTINE NAME:  CD01_LockDoor                                          */
  642. /*                                                                          */
  643. /* DESCRIPTIVE NAME:  CD Lock Door                                          */
  644. /*                                                                          */
  645. /* FUNCTION:  Disable or enable the manual eject button.                    */
  646. /*                                                                          */
  647. /* PARAMETERS:                                                              */
  648. /*      PINST  pInst     -- Instance structure.                             */
  649. /*      USHORT Lockit    -- Is To Be LOCK flag.                             */
  650. /*                                                                          */
  651. /* EXIT CODES:                                                              */
  652. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  653. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  654. /*                                                                          */
  655. /* NOTES:                                                                   */
  656. /*                                                                          */
  657. /****************************************************************************/
  658. ULONG CD01_LockDoor(PINST pInst, USHORT LockIt)
  659. {
  660.    ULONG rc;
  661.    BYTE param[LOCKDOR_PMAX] = "CD01";
  662.    ULONG ulDataLen = STANDRD_DMAX, ulParamLen = LOCKDOR_PMAX;
  663.  
  664.    if (LockIt == MCI_TRUE)
  665.       param[LOCKDORFLD] = 1;             //Eject button is disabled
  666.    else
  667.       param[LOCKDORFLD] = 0;             //Eject button is enabled
  668.  
  669.    rc = CallIOCtl(pInst, CDDRIVE_CAT, LOCK___DOOR,
  670.                   param, ulParamLen, &ulParamLen,
  671.                   NULL,  ulDataLen,  &ulDataLen);
  672.  
  673.    /* Drive cannot lock the first time after a disc is mounted. */
  674.    /* Device driver reset hardware on first call, try again.    */
  675.    if (rc)
  676.    {
  677.       ulDataLen = STANDRD_DMAX;
  678.       ulParamLen = LOCKDOR_PMAX;
  679.  
  680.       rc = CallIOCtl(pInst, CDDRIVE_CAT, LOCK___DOOR,
  681.                      param, ulParamLen, &ulParamLen,
  682.                      NULL,  ulDataLen,  &ulDataLen);
  683.  
  684.    }  /* of if needed second try */
  685.  
  686.    return(rc);
  687.  
  688. }  /* of CD01_LockDoor() */
  689.  
  690.  
  691.  
  692. /****************************************************************************/
  693. /*                                                                          */
  694. /* SUBROUTINE NAME:  CD01_Open                                              */
  695. /*                                                                          */
  696. /* DESCRIPTIVE NAME:  CD Open.                                              */
  697. /*                                                                          */
  698. /* FUNCTION:  Open the CD-ROM drive.                                        */
  699. /*                                                                          */
  700. /* PARAMETERS:                                                              */
  701. /*      PINST pInst      -- Instance structure.                             */
  702. /*                                                                          */
  703. /* EXIT CODES:                                                              */
  704. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  705. /*      MCIERR_INI_FILE  -- corrupted INI file, drive is not CD-ROM drive.  */
  706. /*      MCIERR_DEVICE_LOCKED -- CD-ROM drive, previously opened exclusively.*/
  707. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  708. /*      MCIERR_MEDIA_CHANGED         -- different disc was inserted.        */
  709. /*                                                                          */
  710. /* NOTES:                                                                   */
  711. /*                                                                          */
  712. /****************************************************************************/
  713. ULONG CD01_Open(PINST pInst)
  714. {
  715.    ULONG rc;
  716.  
  717.    CHAR drive[] = "A:";
  718.    ULONG ulAction;
  719.    HFILE hDev;
  720.    MCI_CD_REGDISC_PARMS recParam2;
  721.    BYTE data[LOCATON_DMAX], param[LOCATON_PMAX] = {'C', 'D', '0', '1', RBMODE};
  722.    ULONG ulDataLen, ulParamLen;
  723.  
  724.    drive[0] = pInst->Drive;               /* Get drive letter */
  725.  
  726.    /* open device */
  727.    rc = DosOpen(drive, &hDev, &ulAction, 0L, 0L, OPENFLAG, OPENMODE, 0L);
  728.  
  729.    if (rc)
  730.    {
  731.       switch (rc)
  732.       {
  733.          case ERROR_PATH_NOT_FOUND :     //network drive
  734.          case ERROR_INVALID_DRIVE :      //invalid drive, not reg in boot-up(?)
  735.             rc = MCIERR_INI_FILE;
  736.             break;
  737.          case ERROR_SHARING_VIOLATION :  //drive opened exclusively
  738.             rc = MCIERR_DEVICE_LOCKED;
  739.             break;
  740.          case ERROR_NOT_READY :          //disc not in drive, drive powered off
  741.          default :
  742.             /* resume timer loop so that it can exit */
  743.             DosPostEventSem(pInst->hTimeLoopSem);
  744.             /* make play completed before returning */
  745.             while (pInst->usPlayFlag != TIMER_AVAIL)
  746.                DosSleep(HALF_TIME_MIN);
  747.             rc = MCIERR_DEVICE_NOT_READY;
  748.       }  /* of switch() */
  749.    }  /* of if error */
  750.    else                                   /* open was successful */
  751.    {
  752.       pInst->hDrive = hDev;
  753.  
  754.       if (pInst->DiscID.ulLeadOut == 0L)            // if New Open
  755.          rc = OpenFirstTime(pInst);
  756.       else
  757.       {
  758.          /** Previous Open, register separately and compare with old  *
  759.            * disc.  If the same, pretend nothing happened, otherwise  *
  760.            * return code to make general MCI Driver do a re-register  */
  761.          rc = CDAudRegDisc(pInst, REG_PARAM2, &recParam2);
  762.  
  763.          if (!rc)
  764.             if (memcmp(&pInst->DiscID, &recParam2.DiscID, sizeof(MCI_CD_ID)))
  765.             {
  766.                CD01_Stop(pInst, TIMER_EXIT_CHANGED);
  767.                rc = MCIERR_MEDIA_CHANGED;           /* Different disc */
  768.             }
  769.       }  /* of else not a new open */
  770.    }  /* of else device is opened */
  771.  
  772.    return(rc);
  773.  
  774. }  /* of CD01_Open() */
  775.  
  776.  
  777.  
  778. /****************************************************************************/
  779. /*                                                                          */
  780. /* SUBROUTINE NAME:  CD01_Play                                              */
  781. /*                                                                          */
  782. /* DESCRIPTIVE NAME:  CD Play.                                              */
  783. /*                                                                          */
  784. /* FUNCTION:  Initiate playing audio data to internal DAC(s).               */
  785. /*                                                                          */
  786. /* PARAMETERS:                                                              */
  787. /*      PINST  pInst        -- Instance pointer.                            */
  788. /*      ULONG  *pulParam1   -- Flag for this message.                       */
  789. /*      ULONG  ulFrom       -- From address.                                */
  790. /*      ULONG  ulTo         -- To address in MMTIME.                        */
  791. /*      USHORT usUserParm   -- User Parameter.                              */
  792. /*      HWND   hwndCallback -- Call back handle.                            */
  793. /*                                                                          */
  794. /* EXIT CODES:                                                              */
  795. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  796. /*      MCIERR_DEVICE_NOT_READY  -- device was not ready, no disc.          */
  797. /*      MCIERR_MEDIA_CHANGED     -- Disc changed.                           */
  798. /*                                                                          */
  799. /* NOTES:                                                                   */
  800. /*                                                                          */
  801. /****************************************************************************/
  802. ULONG CD01_Play(PINST pInst, ULONG *pulParam1, ULONG ulFrom, ULONG ulTo,
  803.                 USHORT usUserParm, HWND hwndCallback)
  804. {
  805.    ULONG rc;
  806.    ULONG ulThreadID;
  807.    ULONG cnt;
  808.  
  809.    /* Stop drive before issuing next play command */
  810.    if ((pInst->usPlayFlag == TIMER_PLAYING) ||
  811.        (pInst->usPlayFlag == TIMER_PLAY_SUSPEND) ||
  812.        (pInst->usPlayFlag == TIMER_PLAY_SUSP_2))
  813.       if (*pulParam1 & MCI_NOTIFY)
  814.          CD01_Stop(pInst, TIMER_EXIT_SUPER);
  815.       else
  816.          CD01_Stop(pInst, TIMER_EXIT_ABORTED);
  817.  
  818.    /* prepare for play call */
  819.    pInst->ulCurPos = ulFrom;
  820.    pInst->ulEndPos = ulTo;
  821.    pInst->usPlayNotify = (USHORT)(*pulParam1 & (MCI_WAIT | MCI_NOTIFY));
  822.    if (*pulParam1 & MCI_NOTIFY)
  823.    {
  824.       pInst->usPlayUserParm = usUserParm;
  825.       pInst->hwndPlayCallback = hwndCallback;
  826.       *pulParam1 ^= MCI_NOTIFY;
  827.    }  /* notify flag was used */
  828.  
  829.    if (*pulParam1 & MCI_WAIT)
  830.       rc = CD01_Timer(pInst);      /* returns when play commands end */
  831.    else
  832.    {
  833.       DosResetEventSem(pInst->hReturnSem, &cnt);  //force a wait
  834.       rc = DosCreateThread(&ulThreadID, (PFNTHREAD)CD01_Timer,
  835.                            (ULONG)pInst, 0L, THREAD_STACK_SZ);
  836.       if (rc)
  837.       {
  838.          rc = MCIERR_OUT_OF_MEMORY;
  839.          DosPostEventSem(pInst->hReturnSem);
  840.       }
  841.       else  /* wait for new thread to process enough */
  842.       {
  843.          /* Let MCD know not to send notification by returning wait */
  844.          *pulParam1 = (*pulParam1 & ~MCI_NOTIFY) | MCI_WAIT;
  845.  
  846.          /* wait for new thread to process enough */
  847.          DosWaitEventSem(pInst->hReturnSem, WAIT_FOREVER);
  848.       }
  849.  
  850.       DosReleaseMutexSem(pInst->hInstSem);
  851.  
  852.    }  /* else no wait flag was used */
  853.  
  854.    return(rc);
  855.  
  856. }  /* of CD01_Play() */
  857.  
  858.  
  859.  
  860. /****************************************************************************/
  861. /*                                                                          */
  862. /* SUBROUTINE NAME:  CD01_PlayCont                                          */
  863. /*                                                                          */
  864. /* DESCRIPTIVE NAME:  CD Play Continue.                                     */
  865. /*                                                                          */
  866. /* FUNCTION:  Continue to play audio data to internal DAC(s) from a         */
  867. /*            MCIDRV_RESTORE or MCIDRV_SYNC command.                        */
  868. /*                                                                          */
  869. /* PARAMETERS:                                                              */
  870. /*      PINST pInst       -- Instance pointer.                              */
  871. /*      ULONG ulFrom      -- From address.                                  */
  872. /*      ULONG ulTo        -- To address in MMTIME.                          */
  873. /*                                                                          */
  874. /* EXIT CODES:                                                              */
  875. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  876. /*      MCIERR_DEVICE_NOT_READY  -- device was not ready, no disc.          */
  877. /*      MCIERR_MEDIA_CHANGED     -- Disc changed.                           */
  878. /*                                                                          */
  879. /* NOTES:                                                                   */
  880. /*                                                                          */
  881. /****************************************************************************/
  882. ULONG CD01_PlayCont(PINST pInst, ULONG ulFrom, ULONG ulTo)
  883. {
  884.    ULONG rc;
  885.    BYTE param[PLAYAUD_PMAX] = {'C', 'D', '0', '1', RBMODE};
  886.    ULONG ulDataLen = STANDRD_DMAX, ulParamLen = PLAYAUD_PMAX;
  887.  
  888.    /* convert starting MM Time into Redbook 2 format */
  889.    * (ULONG *)¶m[STARTFFFLD] = REDBOOK2FROMMM(ulFrom);
  890.  
  891.    /* convert ending MM Time into Redbook 2 format */
  892.    * (ULONG *)¶m[END_FF_FLD] = REDBOOK2FROMMM(ulTo);
  893.  
  894.    /* Stop drive before issuing next play command */
  895.    CD01_Stop(pInst, TIMER_PLAY_SUSPEND);
  896.  
  897.    /* play drive */
  898.    rc = CallIOCtl(pInst, CDAUDIO_CAT, PLAY__AUDIO,
  899.                   param, ulParamLen, &ulParamLen,
  900.                   NULL,  ulDataLen,  &ulDataLen);
  901.  
  902.    if (!rc)
  903.       pInst->ulCurPos = ulFrom;
  904.  
  905.    /* if Timer was stopped, continue timer loop */
  906.    if (pInst->usPlayFlag == TIMER_PLAY_SUSPEND)
  907.       pInst->usPlayFlag = TIMER_PLAYING;
  908.    DosPostEventSem(pInst->hTimeLoopSem);
  909.  
  910.    return(rc);
  911.  
  912. }  /* of CD01_PlayCont() */
  913.  
  914.  
  915.  
  916. /****************************************************************************/
  917. /*                                                                          */
  918. /* SUBROUTINE NAME:  CD01_PosAdvise                                         */
  919. /*                                                                          */
  920. /* DESCRIPTIVE NAME:  CD Position Advise                                    */
  921. /*                                                                          */
  922. /* FUNCTION:  Set up the desired position advise.                           */
  923. /*                                                                          */
  924. /* PARAMETERS:                                                              */
  925. /*      PINST pInst      -- Instance structure.                             */
  926. /*      ULONG ulParam1   -- Flag set for this message.                      */
  927. /*      MCI_POSITION_PARMS *pParam2 -- Pointer to data record structure.    */
  928. /*                                                                          */
  929. /* EXIT CODES:                                                              */
  930. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  931. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Flags are mutually exclusive.        */
  932. /*                                                                          */
  933. /* NOTES:                                                                   */
  934. /*                                                                          */
  935. /****************************************************************************/
  936. ULONG CD01_PosAdvise(PINST pInst, ULONG ulParam1, MCI_POSITION_PARMS *pParam2)
  937. {
  938.    ULONG rc = MCIERR_SUCCESS;
  939.  
  940.    if (ulParam1 & MCI_SET_POSITION_ADVISE_ON)
  941.    {
  942.       if (ulParam1 & MCI_SET_POSITION_ADVISE_OFF)
  943.          rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  944.       else
  945.       {
  946.          pInst->qptPosAdvise.ulEvent = pParam2->ulUnits;
  947.          pInst->qptPosAdvise.hwndCallback = pParam2->hwndCallback;
  948.          pInst->qptPosAdvise.usUserParm = pParam2->usUserParm;
  949.       }
  950.    }  /* of if on */
  951.    else
  952.       if (ulParam1 & MCI_SET_POSITION_ADVISE_OFF)
  953.          pInst->qptPosAdvise.ulEvent = 0L;
  954.  
  955.    return(rc);
  956.  
  957. }  /* of CD01_PosAdvise() */
  958.  
  959.  
  960.  
  961. /****************************************************************************/
  962. /*                                                                          */
  963. /* SUBROUTINE NAME:  CD01_RegTracks                                         */
  964. /*                                                                          */
  965. /* DESCRIPTIVE NAME:  CD Audio Register Compact Disc.                       */
  966. /*                                                                          */
  967. /* FUNCTION:  Register a CD media so that the disc may be recognized by     */
  968. /*            the calling MCD.                                              */
  969. /*                                                                          */
  970. /* PARAMETERS:                                                              */
  971. /*      PINST pInst      -- Instance structure.                             */
  972. /*      MCI_CD_REGTRACKS_PARMS *pParam2 -- Pointer to data record.          */
  973. /*                                                                          */
  974. /* EXIT CODES:                                                              */
  975. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  976. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  977. /*      MCIERR_INVALID_BUFFER        -- Buffer size is too small.           */
  978. /*                                                                          */
  979. /* NOTES:                                                                   */
  980. /*                                                                          */
  981. /****************************************************************************/
  982. ULONG CD01_RegTracks(PINST pInst, MCI_CD_REGTRACKS_PARMS *pParam2)
  983. {
  984.    ULONG rc;
  985.    BYTE data[DSKTRCK_DMAX], param[DSKTRCK_PMAX] = "CD01";
  986.    BYTE low, hi, cnt;       // low and high track values
  987.    ULONG end_adr, cur_adr;
  988.    ULONG ulDataLen = DSKTRCK_DMAX, ulParamLen = DSKTRCK_PMAX;
  989.  
  990.  
  991.    /*** GET DISK INFORMATION ***/
  992.  
  993.    /* get disk information */
  994.    rc = CallIOCtl(pInst, CDAUDIO_CAT, DISK___INFO,
  995.                   param, ulParamLen, &ulParamLen,
  996.                   data,  ulDataLen,  &ulDataLen);
  997.  
  998.    if (!rc)
  999.    {                                            // okay, extract data
  1000.       low = data[TRCKLOWFLD];
  1001.       hi  = data[TRCKHI_FLD];
  1002.  
  1003.       /* get ending address */
  1004.       end_adr = REDBOOK2TOMM(*(ULONG *)&data[TRENDFFFLD]);
  1005.  
  1006.       /* check for valid buffer size */
  1007.       if (pParam2->ulBufSize <
  1008.              (ULONG)(hi - low + 1) * sizeof(MCI_CD_REGTRACK_REC))
  1009.          rc = MCIERR_INVALID_BUFFER;
  1010.       else
  1011.       {
  1012.          rc = MCIERR_SUCCESS;
  1013.  
  1014.          /*** LOOP TO FILL TABLE ***/
  1015.  
  1016.          for (cnt = 0; low <= hi; cnt++, low++)
  1017.          {
  1018.             param[TRACKFIELD] = low;
  1019.  
  1020.             ulDataLen  = DSKTRCK_DMAX;
  1021.             ulParamLen = DSKTRCK_PMAX;
  1022.             if (CallIOCtl(pInst, CDAUDIO_CAT, TRACK__INFO,
  1023.                           param, ulParamLen, &ulParamLen,
  1024.                           data,  ulDataLen,  &ulDataLen))
  1025.             {
  1026.                rc = MCIERR_DEVICE_NOT_READY;
  1027.                break;
  1028.             }
  1029.  
  1030.             /* get track number */
  1031.             (pParam2->TrackRecArr + cnt)->TrackNum = low;
  1032.  
  1033.             /* get control byte */
  1034.             (pParam2->TrackRecArr + cnt)->TrackControl = data[TRKSTATFLD];
  1035.  
  1036.             /* get starting address */
  1037.             cur_adr = REDBOOK2TOMM(*(ULONG *)&data[TRACKFFFLD]);
  1038.             (pParam2->TrackRecArr + cnt)->ulStartAddr = cur_adr;
  1039.  
  1040.             if (cnt)
  1041.                /* get ending address */
  1042.                (pParam2->TrackRecArr + cnt-1)->ulEndAddr = cur_adr;
  1043.  
  1044.             /* get ending address if it is the last track */
  1045.             if (low == hi)
  1046.                (pParam2->TrackRecArr + cnt)->ulEndAddr = end_adr;
  1047.  
  1048.          }   /* of for loop */
  1049.       }   /* of else valid buffer size */
  1050.    }   /* of if no error getting audio disc information */
  1051.  
  1052.    /* return buffer size */
  1053.    if (rc)
  1054.       pParam2->ulBufSize = 0;
  1055.    else
  1056.       pParam2->ulBufSize = sizeof(MCI_CD_REGTRACK_REC) * cnt;
  1057.  
  1058.    return(rc);
  1059.  
  1060. }  /* of CD01_RegTracks() */
  1061.  
  1062.  
  1063.  
  1064. /****************************************************************************/
  1065. /*                                                                          */
  1066. /* SUBROUTINE NAME:  CD01_Restore                                           */
  1067. /*                                                                          */
  1068. /* DESCRIPTIVE NAME:  CD Restore.                                           */
  1069. /*                                                                          */
  1070. /* FUNCTION:  The device context or instance is being restored.  Restore    */
  1071. /*            the drive as listed in pParams.                               */
  1072. /*                                                                          */
  1073. /* PARAMETERS:                                                              */
  1074. /*      PINST pInst      -- Pointer to instance.                            */
  1075. /*      MCIDRV_CD_SAVE_PARMS *pParam2 -- pointer to save structure.         */
  1076. /*                                                                          */
  1077. /* EXIT CODES:                                                              */
  1078. /*      MCIERR_SUCCESS   -- action completed.                               */
  1079. /*                                                                          */
  1080. /* NOTES:                                                                   */
  1081. /*                                                                          */
  1082. /****************************************************************************/
  1083. ULONG CD01_Restore(PINST pInst, MCIDRV_CD_SAVE_PARMS *pParam2)
  1084. {
  1085.    ULONG rc;
  1086.  
  1087.    /* reset volume */
  1088.    rc = CD01_SetVolume(pInst, pParam2->ulLevel);
  1089.  
  1090.    /* reset position and mode */
  1091.    if (!rc)
  1092.    {
  1093.       switch (pParam2->ulMode)
  1094.       {
  1095.          case MCI_MODE_STOP :
  1096.             rc = CD01_Seek(pInst, pParam2->ulPosition);
  1097.             break;
  1098.          case MCI_MODE_PLAY :
  1099.             rc = CD01_PlayCont(pInst, pParam2->ulPosition, pParam2->ulEndPlay);
  1100.             DosPostEventSem(pInst->hTimeLoopSem);  //continue timer loop
  1101.             break;
  1102.          case MCI_MODE_PAUSE :
  1103.             rc = CD01_Stop(pInst, TIMER_PLAY_SUSP_2);
  1104.             if (!rc)
  1105.             {
  1106.                pInst->ulCurPos = pParam2->ulPosition;
  1107.                pInst->ulEndPos = pParam2->ulEndPlay;
  1108.             }
  1109.             break;
  1110.          case MCI_MODE_NOT_READY :                /* disc changed on restore */
  1111.             rc = CD01_Stop(pInst, TIMER_EXIT_CHANGED);
  1112.             break;
  1113.          default :   /* error in saved state, try to accept current position */
  1114.             break;
  1115.       }  /* of switch */
  1116.    }  /* if no error setting volume */
  1117.  
  1118.    return(rc);
  1119.  
  1120. }  /* of CD01_Restore() */
  1121.  
  1122.  
  1123.  
  1124. /****************************************************************************/
  1125. /*                                                                          */
  1126. /* SUBROUTINE NAME:  CD01_Resume                                            */
  1127. /*                                                                          */
  1128. /* DESCRIPTIVE NAME:  CD Resume Playing.                                    */
  1129. /*                                                                          */
  1130. /* FUNCTION:  Unpause or resume the play command.                           */
  1131. /*                                                                          */
  1132. /* PARAMETERS:                                                              */
  1133. /*      PINST pInst      -- Instance structure.                             */
  1134. /*                                                                          */
  1135. /* EXIT CODES:                                                              */
  1136. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1137. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  1138. /*                                                                          */
  1139. /* NOTES:                                                                   */
  1140. /*                                                                          */
  1141. /****************************************************************************/
  1142. ULONG CD01_Resume(PINST pInst)
  1143. {
  1144.    ULONG rc;
  1145.    ULONG ulDataLen = STANDRD_DMAX, ulParamLen = STANDRD_PMAX;
  1146.  
  1147.    if (pInst->usPlayFlag == TIMER_PLAY_SUSP_2)
  1148.    {
  1149.       rc = CD01_PlayCont(pInst, pInst->ulCurPos, pInst->ulEndPos);
  1150.       DosPostEventSem(pInst->hTimeLoopSem);
  1151.    }
  1152.    else
  1153.    {
  1154.       /* resume audio */
  1155.       rc = CallIOCtl(pInst, CDAUDIO_CAT, RESUMEAUDIO,
  1156.                      "CD01", ulParamLen, &ulParamLen,
  1157.                      NULL,   ulDataLen,  &ulDataLen);
  1158.  
  1159.       /* check if resume failed, a disc was ejected and reinserted */
  1160.       if (rc == MCIERR_OUTOFRANGE)
  1161.          rc = CD01_PlayCont(pInst, pInst->ulCurPos, pInst->ulEndPos);
  1162.  
  1163.       if (!rc)
  1164.       {
  1165.          if (pInst->usPlayFlag == TIMER_PLAY_SUSPEND)
  1166.             pInst->usPlayFlag = TIMER_PLAYING;
  1167.          DosPostEventSem(pInst->hTimeLoopSem);
  1168.       }
  1169.    }   /* of else resuming paused audio */
  1170.  
  1171.    return(rc);
  1172.  
  1173. }  /* of CD01_Resume() */
  1174.  
  1175.  
  1176.  
  1177. /****************************************************************************/
  1178. /*                                                                          */
  1179. /* SUBROUTINE NAME:  CD01_Save                                              */
  1180. /*                                                                          */
  1181. /* DESCRIPTIVE NAME:  CD Save.                                              */
  1182. /*                                                                          */
  1183. /* FUNCTION:  The device context or instance is being saved.  Stop the      */
  1184. /*            drive and the play timer if needed.  Save the current state.  */
  1185. /*                                                                          */
  1186. /* PARAMETERS:                                                              */
  1187. /*      PINST pInst      -- Pointer to instance.                            */
  1188. /*      MCIDRV_CD_SAVE_PARMS *pParam2 -- pointer to save structure.         */
  1189. /*                                                                          */
  1190. /* EXIT CODES:                                                              */
  1191. /*      MCIERR_SUCCESS   -- action completed.                               */
  1192. /*                                                                          */
  1193. /* NOTES:                                                                   */
  1194. /*                                                                          */
  1195. /****************************************************************************/
  1196. ULONG CD01_Save(PINST pInst, MCIDRV_CD_SAVE_PARMS *pParam2)
  1197. {
  1198.    ULONG rc;
  1199.  
  1200.    /* cheek to see if it is playing. If it is, stop drive */
  1201.    if (pInst->usPlayFlag == TIMER_PLAYING)
  1202.       CD01_Stop(pInst, TIMER_PLAY_SUSPEND);     // Don't care about return code
  1203.    else
  1204.       if (pInst->usPlayFlag == TIMER_PLAY_SUSP_2)
  1205.          pInst->usPlayFlag = TIMER_PLAY_SUSPEND;
  1206.  
  1207.    /* get volume */
  1208.    CDAudStatCVol(&pParam2->ulLevel);
  1209.  
  1210.    /* get position */
  1211.    rc = CD01_GetPosition(pInst, &pParam2->ulPosition);
  1212.  
  1213.    return(rc);
  1214.  
  1215. }  /* of CD01_Save() */
  1216.  
  1217.  
  1218.  
  1219. /****************************************************************************/
  1220. /*                                                                          */
  1221. /* SUBROUTINE NAME:  CD01_Seek                                              */
  1222. /*                                                                          */
  1223. /* DESCRIPTIVE NAME:  CD Seek.                                              */
  1224. /*                                                                          */
  1225. /* FUNCTION:  Seek to the specified position.                               */
  1226. /*                                                                          */
  1227. /* PARAMETERS:                                                              */
  1228. /*      PINST pInst      -- Instance pointer.                               */
  1229. /*      ULONG ulTo       -- address to seek.                                */
  1230. /*                                                                          */
  1231. /* EXIT CODES:                                                              */
  1232. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1233. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  1234. /*                                                                          */
  1235. /* NOTES:                                                                   */
  1236. /*                                                                          */
  1237. /****************************************************************************/
  1238. ULONG CD01_Seek(PINST pInst, ULONG ulTo)
  1239. {
  1240.    ULONG rc;
  1241.    BYTE data[SEEKSTATDMAX], param[SEEKSTATPMAX] = {'C', 'D', '0', '1', RBMODE};
  1242.    ULONG ulDataLen = SEEKSTATDMAX, ulParamLen = SEEKSTATPMAX;
  1243.  
  1244.    /* Stop drive before issuing SEEK command,         *
  1245.     *    drive will not SEEK Command if it is playing */
  1246.    rc = CallIOCtl(pInst, CDDRIVE_CAT, DEV__STATUS,
  1247.                   "CD01", ulParamLen, &ulParamLen,
  1248.                    data,  ulDataLen,  &ulDataLen);
  1249.  
  1250.    if (!rc)        /* stop drive even if it thinks that its playing */
  1251.       if ((data[STATAUDFLD] & IS_PLAYING) ||
  1252.           (pInst->usPlayFlag == TIMER_PLAYING) ||
  1253.           (pInst->usPlayFlag == TIMER_PLAY_SUSPEND) ||
  1254.           (pInst->usPlayFlag == TIMER_PLAY_SUSP_2))
  1255.          rc = CD01_Stop(pInst, TIMER_EXIT_ABORTED);
  1256.  
  1257.    /* issue hardware seek if no errors */
  1258.    if (!rc)
  1259.    {
  1260.       /* convert MM Time into Redbook 2 format */
  1261.       * (ULONG *)¶m[SEEK_FFFLD] = REDBOOK2FROMMM(ulTo);
  1262.  
  1263.       /* Seek to new location */
  1264.       ulDataLen  = STANDRD_DMAX;
  1265.       ulParamLen = SEEKSTATPMAX;
  1266.       rc = CallIOCtl(pInst, CDDRIVE_CAT, SEEK_POSITN,
  1267.                      param, ulParamLen, &ulParamLen,
  1268.                      NULL,  ulDataLen,  &ulDataLen);
  1269.  
  1270.       /* Some drives cannot seek to some/all audio address, */
  1271.       /* the IBM 3510-001 can so a true VSD would not need these lines */
  1272.       if (rc == MCIERR_OUTOFRANGE)         // MCD makes sure address is correct
  1273.          rc = MCIERR_SUCCESS;              //    Mask CD & PDD errors
  1274.  
  1275.       if (!rc)
  1276.          pInst->ulCurPos = ulTo;
  1277.  
  1278.    }  /* of if no error preparing disk for seek */
  1279.  
  1280.    return(rc);
  1281.  
  1282. }  /* of CD01_Seek() */
  1283.  
  1284.  
  1285.  
  1286. /****************************************************************************/
  1287. /*                                                                          */
  1288. /* SUBROUTINE NAME:  CD01_SetVolume                                         */
  1289. /*                                                                          */
  1290. /* DESCRIPTIVE NAME:  CD Set Volume.                                        */
  1291. /*                                                                          */
  1292. /* FUNCTION:  Set the left and right volume levels on the CD-ROM drive.     */
  1293. /*                                                                          */
  1294. /* PARAMETERS:                                                              */
  1295. /*      PINST pInst      -- Instance structure.                             */
  1296. /*      ULONG ulVolume   -- Volume Level.                                   */
  1297. /*                                                                          */
  1298. /* EXIT CODES:                                                              */
  1299. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1300. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  1301. /*                                                                          */
  1302. /* NOTES:                                                                   */
  1303. /*                                                                          */
  1304. /****************************************************************************/
  1305. ULONG CD01_SetVolume(PINST pInst, ULONG ulVolume)
  1306. {
  1307.  
  1308.    ULONG rc;
  1309.    BYTE data[QVOLUME_DMAX], left, right;
  1310.    ULONG ulDataLen = QVOLUME_DMAX, ulParamLen = STANDRD_PMAX;
  1311.  
  1312.    /* get current audio channel information */
  1313.    rc = CallIOCtl(pInst, CDAUDIO_CAT, AUD_CH_INFO,
  1314.                   "CD01", ulParamLen, &ulParamLen,
  1315.                   data,   ulDataLen,  &ulDataLen);
  1316.  
  1317.    /* get requested volume levels */
  1318.    left  = (BYTE) ulVolume;
  1319.    right = (BYTE) (ulVolume >> 16);
  1320.  
  1321.    if (!rc)
  1322.    {
  1323.       /* Since this is the IBM 3510, reset left and right to 0 or FF */
  1324.       if (left)
  1325.          left = 0xFF;
  1326.  
  1327.       if (right)
  1328.          right = 0xFF;
  1329.  
  1330.       /* Save an IOCLT call by only resetting if a change occurred */
  1331.  
  1332.       if (data[VOL_LT_FLD] != left || data[VOL_RT_FLD] != right)
  1333.       {
  1334.          data[VOL_LT_FLD] = left;
  1335.          data[VOL_RT_FLD] = right;
  1336.          /* set volume */
  1337.          ulDataLen = QVOLUME_DMAX;
  1338.          ulParamLen = STANDRD_PMAX;
  1339.          rc = CallIOCtl(pInst, CDAUDIO_CAT, AUD_CH_CTRL,
  1340.                         "CD01", ulParamLen, &ulParamLen,
  1341.                         data,   ulDataLen,  &ulDataLen);
  1342.  
  1343.       } /* of if volume had changed */
  1344.  
  1345.    }  /* of else Audio Channel Info DevIOCtl worked */
  1346.  
  1347.    return(rc);
  1348.  
  1349. }  /* of CD01_SetVolume() */
  1350.  
  1351.  
  1352.  
  1353. /****************************************************************************/
  1354. /*                                                                          */
  1355. /* SUBROUTINE NAME:  CD01_Stop                                              */
  1356. /*                                                                          */
  1357. /* DESCRIPTIVE NAME:  CD Stop.                                              */
  1358. /*                                                                          */
  1359. /* FUNCTION:  Stop the play command.                                        */
  1360. /*                                                                          */
  1361. /* PARAMETERS:                                                              */
  1362. /*      PINST  pInst       -- Instance pointer.                             */
  1363. /*      USHORT usTimerFlag -- Set timer to this flag, if playing.           */
  1364. /*                                                                          */
  1365. /* EXIT CODES:                                                              */
  1366. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1367. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  1368. /*                                                                          */
  1369. /* NOTES:                                                                   */
  1370. /*                                                                          */
  1371. /****************************************************************************/
  1372. ULONG CD01_Stop(PINST pInst, USHORT usTimerFlag)
  1373. {
  1374.    ULONG rc;
  1375.    USHORT StopTimer = TRUE;
  1376.    ULONG ulDataLen = STANDRD_DMAX, ulParamLen = STANDRD_PMAX;
  1377.  
  1378.    /* stop timer if one is going */
  1379.    if (pInst->usPlayFlag == TIMER_PLAYING ||
  1380.        pInst->usPlayFlag == TIMER_PLAY_SUSPEND ||
  1381.        pInst->usPlayFlag == TIMER_PLAY_SUSP_2)
  1382.    {
  1383.       pInst->usPlayFlag = usTimerFlag;
  1384.  
  1385.       switch(usTimerFlag)
  1386.       {
  1387.          case TIMER_PLAY_SUSPEND :
  1388.          case TIMER_PLAY_SUSP_2 :
  1389.             StopTimer = FALSE;
  1390.       }  /* of switch */
  1391.  
  1392.       if (StopTimer)
  1393.       {
  1394.          if (DosWaitThread(&pInst->ulPlayTID, 1L) ==
  1395.                            ERROR_THREAD_NOT_TERMINATED)
  1396.          {
  1397.             /* resume timer loop so that it can exit */
  1398.             DosPostEventSem(pInst->hTimeLoopSem);
  1399.  
  1400.             /* make play completed before returning, race condition. */
  1401.             while (pInst->usPlayFlag != TIMER_AVAIL)
  1402.                DosSleep(HALF_TIME_MIN);
  1403.  
  1404.          }  /* of if thread exists */
  1405.          else
  1406.             pInst->usPlayFlag = TIMER_AVAIL;     //play thread doesn't exist
  1407.  
  1408.      }   /* of if Play Time needs to be stopped */
  1409.    }  /* of if timer is being used */
  1410.  
  1411.    /* stop drive */
  1412.    rc = CallIOCtl(pInst, CDAUDIO_CAT, STOP__AUDIO,
  1413.                   "CD01", ulParamLen, &ulParamLen,
  1414.                    NULL,  ulDataLen,  &ulDataLen);
  1415.  
  1416.    return(rc);
  1417.  
  1418. }  /* of CD01_Stop() */
  1419.  
  1420.  
  1421.  
  1422.