home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional Developers Kit 1992 November / Disc01 / Disc01.mdf / mmpm2tk / mmpmtlk2 / cdmct / ibmcdrom.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-06  |  129.4 KB  |  2,818 lines

  1. /*static char *SCCSID = "@(#)ibmcdrom.c    13.8 92/04/23";*/
  2. /****************************************************************************/
  3. /*                                                                          */
  4. /* SOURCE FILE NAME:  IBMCDROM.C                                            */
  5. /*                                                                          */
  6. /* DESCRIPTIVE NAME:  IBM CD-ROMs                                           */
  7. /*                                                                          */
  8. /* COPYRIGHT:  (c) IBM Corp. 1990 - 1992                                    */
  9. /*                                                                          */
  10. /* FUNCTION:  This file contains the device dependent code for the CD Audio */
  11. /*            Vendor Specific Driver (VSD).  This file is called by         */
  12. /*            CDAUDIO.DLL  -- the generic CD Audio MCI Driver.              */
  13. /*                                                                          */
  14. /* NOTES:  The hardware independent code is found in file CDAUDIO.C.  As    */
  15. /*         more and more CD ROM drives are supported, hardware dependent    */
  16. /*         files can be made into DLLs and register be registered in the    */
  17. /*         MMPM2.INI file upon installation to be recognized.               */
  18. /*                                                                          */
  19. /* ENTRY POINTS:                                                            */
  20. /*       vsdDriverEntry     - entry point to the VSD                        */
  21. /*                                                                          */
  22. /*                                                                          */
  23. /* OTHER FUNCTIONS:                                                         */
  24. /*       process_msg        - Process the requested command message.        */
  25. /*       CDAudErrRecov      - Error recovery routine.                       */
  26. /*       CDAudClose         - Close an instance.                            */
  27. /*       CDAudInfo          - Returns information about the component.      */
  28. /*       CDAudOpen          - Open an instance.                             */
  29. /*       CDAudRegDisc       - Register a disc for the multimedia component. */
  30. /*       CDAudRegDrive      - Register a drive for the multimedia component.*/
  31. /*       CDAudSet           - Set various attributes of the device.         */
  32. /*       CDAudSetVerify     - Tests flags for the set command.              */
  33. /*       CDAudStatus        - Returns the requested attribute.              */
  34. /*       CDAudStatCVol      - Returns mapped volume levels for volume given.*/
  35. /*       CD01_Cue           - Preroll a drive.                              */
  36. /*       CD01_CuePoint      - Set up a cue point.                           */
  37. /*       CD01_GetCaps       - Get device capabilities.                      */
  38. /*       CD01_GetDiscInfo   - Get status info of the disc.                  */
  39. /*       CD01_GetID         - Get the CD ID from the disc.                  */
  40. /*       CD01_GetPosition   - Get the position of the head.                 */
  41. /*       CD01_GetState      - Get the state of the device.                  */
  42. /*       CD01_GetTOC        - Returns table of contents (MMTOC form) of CD. */
  43. /*       CD01_GetVolume     - Get the volume settings of the drive.         */
  44. /*       CD01_LockDoor      - Lock/Unlock the drive door.                   */
  45. /*       CD01_Open          - Open specified device/drive.                  */
  46. /*       CD01_Play          - Initiate a play operation.                    */
  47. /*       CD01_PlayCont      - Continue a play operation.                    */
  48. /*       CD01_PosAdvise     - Set up a position advise command.             */
  49. /*       CD01_RegTracks     - Register tracks on the disc.                  */
  50. /*       CD01_Restore       - Restore the saved instance.                   */
  51. /*       CD01_Resume        - Unpause a CD Play operation.                  */
  52. /*       CD01_Save          - Save the current instance.                    */
  53. /*       CD01_Seek          - Seek to a particular redbook address.         */
  54. /*       CD01_SetVolume     - Set the volume of the drive.                  */
  55. /*       CD01_StartPlay     - Start the play operation.                     */
  56. /*       CD01_Stop          - Stop a CD Play operation.                     */
  57. /*       CD01_Sync          - Sync to MDM request.                          */
  58. /*       CD01_Timer         - Timer routine for play operation.             */
  59. /*       CD01_TimerNotify   - Timer routine to setup and notify events.     */
  60. /*       CallIOCtl          - Call the hardware via IOCTLs.                 */
  61. /*                                                                          */
  62. /*       NOTE:  CD01_... refers to commands that are compatible with the    */
  63. /*              IBM 3510 CD-ROM drive.  CD02_... may refers to commands     */
  64. /*              that are compatible with the CD02 drives, which are         */
  65. /*              not compatible with the CD01_... commands.  This way        */
  66. /*              different hardware can share the same VSD.                  */
  67. /*                                                                          */
  68. /*                                                                          */
  69. /****************************************************************************/
  70.  
  71. #define INCL_DOSERRORS
  72. #define INCL_DOSDEVICES
  73. #define INCL_DOSPROCESS
  74. #define INCL_DOSFILEMGR
  75. #define INCL_DOSSEMAPHORES
  76. #include <os2.h>
  77. #include <string.h>
  78. #include <stdlib.h>
  79. #include <os2me.h>
  80. #include <cdaudio.h>
  81. #include "ibmcdrom.h"
  82. #include <hhpheap.h>
  83.  
  84. extern PVOID          CDMC_hHeap;
  85.  
  86. /****************************************************************************/
  87. /*                                                                          */
  88. /* SUBROUTINE NAME:  vsdDriverEntry                                         */
  89. /*                                                                          */
  90. /* DESCRIPTIVE NAME:  Hardware specific code entry point.                   */
  91. /*                                                                          */
  92. /* FUNCTION:  Receive command message from the generic MCI Driver for CD    */
  93. /*            Audio (CDAUDIO.DLL).                                          */
  94. /*                                                                          */
  95. /* PARAMETERS:                                                              */
  96. /*      LPTR  lpInstance -- Pointer to device handle.                       */
  97. /*      WORD  wMessage   -- Command message.                                */
  98. /*      DWORD dwParam1   -- Pointer to flag for this message.               */
  99. /*      DWORD dwParam2   -- Pointer to data record structure.               */
  100. /*      WORD  wUserParm  -- User Parameter.                                 */
  101. /*                                                                          */
  102. /* EXIT CODES:                                                              */
  103. /*      MCIERR_SUCCESS    -- action completed without error.                */
  104. /*      MCIERR_INI_FILE   -- corrupted INI file, drive is not CD-ROM drive. */
  105. /*      MCIERR_DEVICE_NOT_READY      -- device was closed from an error.    */
  106. /*      MCIERR_MEDIA_CHANGED         -- device was reopened, waiting for    */
  107. /*                                      MCIDRV_REGISTER message.            */
  108. /*      MCIERR_FLAGS_NOT_COMPATIBLE  -- missing or multiple flags.          */
  109. /*      MCIERR_UNRECOGNIZED_COMMAND  -- unknown command.                    */
  110. /*      MCIERR_UNSUPPORTED_FUNCTION  -- unsupported command.                */
  111. /*      MCIERR_UNSUPPORTED_FLAG      -- unsupported flag.                   */
  112. /*      MCIERR_INVALID_FLAG          -- flag not supported by this VSD.     */
  113. /*      MCIERR_OUT_OF_MEMORY         -- couldn't allocate instance.         */
  114. /*      MCIERR_INVALID_ITEM_FLAG     -- Unknown item specified.             */
  115. /*      MCIERR_INVALID_MEDIA_TYPE    -- No audio tracks were found.         */
  116. /*      MCIERR_CUEPOINT_LIMIT_REACHED -- no more room to add events.        */
  117. /*      MCIERR_INVALID_CUEPOINT       -- unable to locate event.            */
  118. /*      MCIERR_DEVICE_LOCKED -- CD-ROM drive, previously opened exclusively.*/
  119. /*                                                                          */
  120. /* NOTES:                                                                   */
  121. /*                                                                          */
  122. /****************************************************************************/
  123. DWORD APIENTRY vsdDriverEntry(LPTR lpInstance, WORD wMessage, DWORD dwParam1,
  124.                               DWORD dwParam2, WORD wUserParm)
  125. {
  126.    DWORD  rc, dwP1Temp = MCI_WAIT;
  127.    USHORT try = 1;
  128.  
  129.    if (dwParam1 == 0L)
  130.       dwParam1 = (DWORD) &dwP1Temp;
  131.  
  132.    /* check to see if the drive is open, unless it is an Open message */
  133.    if (wMessage == MCI_OPEN)
  134.       rc = CDAudOpen(*(DWORD *)dwParam1, (MMDRV_OPEN_PARMS *)dwParam2);
  135.    else
  136.    {
  137.       /* if the device is closed try reopening it unless you are closing */
  138.       if (((PINST) lpInstance)->hDrive == 0 && wMessage != MCI_CLOSE)
  139.       {
  140.          rc = CD01_Open((PINST) lpInstance);
  141.          /* Clear commands not needing an open hardware device */
  142.          if (rc == MCIERR_DEVICE_NOT_READY)
  143.             if ((wMessage == MCI_GETDEVCAPS) ||
  144.                 (wMessage == MCI_INFO) ||
  145.                 (wMessage == MCIDRV_REGISTER_DRIVE) ||
  146.                 (wMessage == MCI_SET_CUEPOINT) ||
  147.                 (wMessage == MCI_SET_POSITION_ADVISE) ||
  148.                 (wMessage == MCIDRV_CD_STATUS_CVOL) ||
  149.                 (wMessage == MCIDRV_SYNC &&
  150.                    !(*(DWORD *)dwParam1 & MCIDRV_SYNC_REC_PULSE)))
  151.                rc = MCIERR_SUCCESS;
  152.  
  153.       }  /* of if drive needs to be open */
  154.       else      /* drive was opened */
  155.          rc = MCIERR_SUCCESS;
  156.  
  157.       if (!rc)
  158.          do
  159.          {
  160.             /* process message */
  161.             rc = process_msg((PINST) lpInstance, wMessage,
  162.                               (DWORD *)dwParam1, dwParam2, wUserParm);
  163.  
  164.             if (rc == MCIERR_DEVICE_NOT_READY ||       /* ERROR RECOVERY */
  165.                 rc == MCIERR_MEDIA_CHANGED)
  166.             {
  167.                if (((PINST)lpInstance)->Drive == '0')     /* drive is closed */
  168.                {                                   /* don't reissue commands */
  169.                   rc = MCIERR_SUCCESS;
  170.                   break;
  171.                }
  172.                else
  173.                   if (try == 2)
  174.                      break;                         /* quit after 2 tries. */
  175.                   else
  176.                   {
  177.                      rc = CDAudErrRecov((PINST) lpInstance);
  178.                      if (rc)                   /* error is still there, exit */
  179.                         break;
  180.                      else
  181.                         try++;
  182.                   }  /* of else only tried the command once (try == 1) */
  183.  
  184.             }  /* of if the drive was not ready */
  185.             else
  186.                break;                          /* clear flag to exit */
  187.  
  188.          } while (try);  /* end of do loop and if no open error */
  189.  
  190.    } /* of else command was not MCI_OPEN */
  191.  
  192.    return(rc);
  193.  
  194. }  /* of vsdDriverEntry() */
  195.  
  196.  
  197.  
  198. /****************************************************************************/
  199. /*                                                                          */
  200. /* SUBROUTINE NAME:  process_msg                                            */
  201. /*                                                                          */
  202. /* DESCRIPTIVE NAME:  Process message command.                              */
  203. /*                                                                          */
  204. /* FUNCTION:  Process the command message received by vsdDriverEntry().     */
  205. /*                                                                          */
  206. /* PARAMETERS:                                                              */
  207. /*      PINST pInst      -- Pointer to instance structure.                  */
  208. /*      WORD  wMessage   -- Command message.                                */
  209. /*      DWORD *pParam1   -- Pointer to flag for this message.               */
  210. /*      DWORD dwParam2   -- Pointer to data record structure.               */
  211. /*      WORD  wUserParm  -- User Parameter.                                 */
  212. /*                                                                          */
  213. /* EXIT CODES:                                                              */
  214. /*      MCIERR_SUCCESS    -- action completed without error.                */
  215. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  216. /*      MCIERR_MEDIA_CHANGED         -- device was reopened, waiting for    */
  217. /*                                      MCIDRV_REGISTER message.            */
  218. /*      MCIERR_FLAGS_NOT_COMPATIBLE  -- missing or multiple flags.          */
  219. /*      MCIERR_UNRECOGNIZED_COMMAND  -- unknown command.                    */
  220. /*      MCIERR_UNSUPPORTED_FUNCTION  -- unsupported command.                */
  221. /*      MCIERR_UNSUPPORTED_FLAG      -- unsupported flag.                   */
  222. /*      MCIERR_INVALID_BUFFER        -- Buffer size was too small.          */
  223. /*      MCIERR_INVALID_FLAG          -- Unknown flag.                       */
  224. /*      MCIERR_INVALID_MEDIA_TYPE    -- No audio tracks were found.         */
  225. /*      ERROR_TOO_MANY_EVENTS --  no more room to add events.               */
  226. /*      ERROR_INVALID_EVENT   --  unable to locate event.                   */
  227. /*      ERROR_INVALID_MMTIME  --  duplicate cuepoint.                       */
  228. /*                                                                          */
  229. /* NOTES:                                                                   */
  230. /*                                                                          */
  231. /****************************************************************************/
  232. static DWORD process_msg(PINST pInst, WORD wMessage,
  233.                          DWORD *pParam1, DWORD dwParam2, WORD wUserParm)
  234. {
  235.    DWORD rc;
  236.  
  237.    DosRequestMutexSem(pInst->hInstSem, WAIT_FOREVER);
  238.    if (wMessage != MCI_PLAY)
  239.       DosReleaseMutexSem(pInst->hInstSem);       // No protection needed
  240.  
  241.    /* process message */
  242.    switch(wMessage)
  243.    {
  244.       case MCI_CLOSE :
  245.          rc = CDAudClose(pInst, *pParam1);
  246.          break;
  247.       case MCI_CUE :                           /* Pre-roll */
  248.          rc = CD01_Cue(pInst);
  249.          break;
  250.       case MCI_GETDEVCAPS :                    /* Get Device Capabilities */
  251.          rc = CD01_GetCaps(*pParam1, (MCI_GETDEVCAPS_PARMS *)dwParam2);
  252.          break;
  253.       case MCI_GETTOC :                        /* Get Table of Contents */
  254.          if (*pParam1 & WAIT_NOTIFY_MASK)
  255.             rc = MCIERR_INVALID_FLAG;
  256.          else
  257.             rc = CD01_GetTOC(pInst, (MCI_TOC_PARMS *)dwParam2);
  258.          break;
  259.       case MCI_INFO :
  260.          rc = CDAudInfo(pInst, *pParam1, (MCI_INFO_PARMS *)dwParam2);
  261.          break;
  262.       /* case MCI_OPEN :          open was already done in vsdDriverEntry() */
  263.  
  264.       case MCI_PAUSE :
  265.          rc = CD01_Stop(pInst, TIMER_PLAY_SUSPEND);
  266.          break;
  267.       case MCI_PLAY :
  268.          rc = CD01_Play(pInst, pParam1,
  269.                         ((MCI_PLAY_PARMS *)dwParam2)->dwFrom,
  270.                         ((MCI_PLAY_PARMS *)dwParam2)->dwTo, wUserParm,
  271.                         (HWND) ((MCI_PLAY_PARMS *)dwParam2)->dwCallback);
  272.          break;
  273.       case MCIDRV_REGISTER_DISC :                  /* Register Disc */
  274.          rc = CDAudRegDisc(pInst, REG_BOTH, (MCI_CD_REGDISC_PARMS *)dwParam2);
  275.          break;
  276.       case MCIDRV_REGISTER_DRIVE :                 /* Register Drive */
  277.          rc = CDAudRegDrive(pInst, (MCI_CD_REGDRIVE_PARMS *)dwParam2);
  278.          break;
  279.       case MCIDRV_REGISTER_TRACKS :                /* Register Tracks */
  280.          rc = CD01_RegTracks(pInst, (MCI_CD_REGTRACKS_PARMS *)dwParam2);
  281.          break;
  282.       case MCIDRV_RESTORE :
  283.          rc = CD01_Restore(pInst, (MCIDRV_CD_SAVE_PARMS *)dwParam2);
  284.          break;
  285.       case MCI_RESUME :                            /* Unpause */
  286.          rc = CD01_Resume(pInst);
  287.          break;
  288.       case MCIDRV_SAVE :
  289.          rc = CD01_Save(pInst, (MCIDRV_CD_SAVE_PARMS *)dwParam2);
  290.          break;
  291.       case MCI_SEEK :
  292.          rc = CD01_Seek(pInst, ((MCI_SEEK_PARMS *)dwParam2)->dwTo);
  293.          break;
  294.       case MCI_SET :
  295.          rc = CDAudSet(pInst, pParam1, (MCI_SET_PARMS *)dwParam2);
  296.          break;
  297.       case MCI_SET_CUEPOINT :
  298.          rc = CD01_CuePoint(pInst, *pParam1, (MCI_CUEPOINT_PARMS *)dwParam2);
  299.          break;
  300.       case MCI_SET_POSITION_ADVISE :
  301.          rc = CD01_PosAdvise(pInst, *pParam1, (MCI_POSITION_PARMS *)dwParam2);
  302.          break;
  303.       case MCIDRV_CD_SET_VERIFY :
  304.          rc = CDAudSetVerify(*pParam1);
  305.          break;
  306.       case MCI_STATUS :
  307.          rc = CDAudStatus(pInst, *pParam1, (MCI_STATUS_PARMS *)dwParam2);
  308.          break;
  309.       case MCIDRV_CD_STATUS_CVOL :
  310.          rc = CDAudStatCVol(&((MCI_STATUS_PARMS *)dwParam2)->dwReturn);
  311.          break;
  312.       case MCI_STOP :
  313.          rc = CD01_Stop(pInst, TIMER_EXIT_ABORTED);
  314.          break;
  315.       case MCIDRV_SYNC :
  316.          rc = CD01_Sync(pInst, *pParam1, (MCIDRV_SYNC_PARMS *)dwParam2);
  317.          break;
  318.  
  319.       /* List unsupported functions */
  320.  
  321.       case MCI_ACQUIREDEVICE :  case MCI_CONNECTION :     case MCI_CONNECTOR :
  322.       case MCI_CONNECTORINFO :  case MCI_DEVICESETTINGS :
  323.       case MCI_DEFAULT_CONNECTION:                        case MCI_ESCAPE :
  324.       case MCI_LOAD:            case MCI_MASTERAUDIO :    case MCI_RECORD :
  325.       case MCI_RELEASEDEVICE :  case MCI_SAVE :           case MCI_SPIN :
  326.       case MCI_STEP :           case MCI_SYSINFO :        case MCI_UPDATE :
  327.          rc = MCIERR_UNSUPPORTED_FUNCTION;
  328.          break;
  329.       default : rc = MCIERR_UNRECOGNIZED_COMMAND;
  330.  
  331.    }  /* of switch */
  332.  
  333.    return(rc);
  334.  
  335. }  /* of process_msg() */
  336.  
  337.  
  338.  
  339. /****************************************************************************/
  340. /*                                                                          */
  341. /* SUBROUTINE NAME:  CDAudErrRecov                                          */
  342. /*                                                                          */
  343. /* DESCRIPTIVE NAME:  CD Audio Information.                                 */
  344. /*                                                                          */
  345. /* FUNCTION:  Returns string information from a device driver.              */
  346. /*                                                                          */
  347. /* PARAMETERS:                                                              */
  348. /*      PINST pInst      -- Instance structure.                             */
  349. /*                                                                          */
  350. /* EXIT CODES:                                                              */
  351. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  352. /*      MCIERR_INI_FILE  -- corrupted INI file, drive is not CD-ROM drive.  */
  353. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  354. /*      MCIERR_MEDIA_CHANGED         -- device was reopened.                */
  355. /*                                                                          */
  356. /* NOTES:                                                                   */
  357. /*                                                                          */
  358. /****************************************************************************/
  359. static DWORD CDAudErrRecov(PINST pInst)
  360. {
  361.    DWORD rc;
  362.  
  363.    /* Close the device */
  364.    DosClose(pInst->hDrive);
  365.    pInst->hDrive = 0;                    /* mark the instance structure */
  366.  
  367.    /* Try to reopen the device */
  368.    rc = CD01_Open(pInst);
  369.  
  370.    return(rc);
  371.  
  372. }  /* of CDAudErrRecov() */
  373.  
  374.  
  375.  
  376. /****************************************************************************/
  377. /*                                                                          */
  378. /* SUBROUTINE NAME:  CDAudClose                                             */
  379. /*                                                                          */
  380. /* DESCRIPTIVE NAME:  CD Audio Close                                        */
  381. /*                                                                          */
  382. /* FUNCTION:  Close a device dependent instance.                            */
  383. /*                                                                          */
  384. /* PARAMETERS:                                                              */
  385. /*      MMDRV_OPEN_PARMS *pParam2 -- Pointer to data record structure.      */
  386. /*                                                                          */
  387. /* EXIT CODES:                                                              */
  388. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  389. /*      MCIERR_INVALID_FLAG -- flag not supported by this VSD.              */
  390. /*                                                                          */
  391. /* NOTES:                                                                   */
  392. /*                                                                          */
  393. /****************************************************************************/
  394. static DWORD CDAudClose(PINST pInst, DWORD dwParam1)
  395. {
  396.    DWORD rc;
  397.  
  398.    if (dwParam1 & WAIT_NOTIFY_MASK)
  399.       rc = MCIERR_INVALID_FLAG;
  400.    else
  401.    {
  402.       pInst->Drive = '0';              /* destroy drive to prevent reopening */
  403.  
  404.       /* stop play & timer if one is going */
  405.       switch(pInst->usPlayFlag)
  406.       {
  407.          case TIMER_PLAY_SUSPEND :                 //suspended, stop only timer
  408.          case TIMER_PLAY_SUSP_2  :
  409.             if (DosWaitThread(&pInst->ulPlayTID, 1L) ==
  410.                                          ERROR_THREAD_NOT_TERMINATED)
  411.             {
  412.                pInst->usPlayFlag = TIMER_EXIT_ABORTED;
  413.                DosPostEventSem(pInst->hTimeLoopSem);  //continue timer loop
  414.             }
  415.             else
  416.                pInst->usPlayFlag = TIMER_AVAIL;
  417.             break;
  418.          case TIMER_PLAYING :                      //playing, stop device
  419.             if (DosWaitThread(&pInst->ulPlayTID, 1L) !=
  420.                                          ERROR_THREAD_NOT_TERMINATED)
  421.                pInst->usPlayFlag = TIMER_AVAIL;     //play thread doesn't exist
  422.             CD01_Stop(pInst, TIMER_EXIT_ABORTED);
  423.             break;
  424.       }  /* of switch() */
  425.  
  426.       /* wait for commands to terminate */
  427.       while (pInst->usPlayFlag != TIMER_AVAIL)
  428.          DosSleep(HALF_TIME_MIN);
  429.  
  430.       DosClose(pInst->hDrive);
  431.       DosCloseMutexSem(pInst->hIOSem);
  432.       DosCloseMutexSem(pInst->hInstSem);
  433.       DosCloseEventSem(pInst->hTimeLoopSem);
  434.       DosCloseEventSem(pInst->hReturnSem);
  435.       HhpFreeMem(CDMC_hHeap, pInst);
  436.       rc = MCIERR_SUCCESS;                  /* assume all will work right */
  437.    }  /* of else flags were okay */
  438.  
  439.    return(rc);
  440.  
  441. }  /* of CDAudClose() */
  442.  
  443.  
  444.  
  445. /****************************************************************************/
  446. /*                                                                          */
  447. /* SUBROUTINE NAME:  CDAudInfo                                              */
  448. /*                                                                          */
  449. /* DESCRIPTIVE NAME:  CD Audio Information.                                 */
  450. /*                                                                          */
  451. /* FUNCTION:  Returns string information from a device driver.              */
  452. /*                                                                          */
  453. /* PARAMETERS:                                                              */
  454. /*      PINST pInst      -- Instance structure.                             */
  455. /*      DWORD dwParam1   -- Flag for this message.                          */
  456. /*      MCI_INFO_PARMS *pParam2 -- Pointer to data record structure.        */
  457. /*                                                                          */
  458. /* EXIT CODES:                                                              */
  459. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  460. /*      MCIERR_FLAGS_NOT_COMPATIBLE  -- Mis-match in flags.                 */
  461. /*      MCIERR_INVALID_BUFFER        -- Buffer too small.                   */
  462. /*      MCIERR_INVALID_FLAG          -- Unknown flag.                       */
  463. /*                                                                          */
  464. /* NOTES:                                                                   */
  465. /*                                                                          */
  466. /****************************************************************************/
  467. static DWORD CDAudInfo(PINST pInst, DWORD dwParam1, MCI_INFO_PARMS *pParam2)
  468. {
  469.    DWORD rc, dwLen;
  470.    CHAR szInfo[INFO_SIZE];
  471.    USHORT i;
  472.  
  473.    dwParam1 &= WAIT_NOTIFY_MASK;
  474.  
  475.    if (dwParam1 == MCI_INFO_PRODUCT)
  476.    {
  477.       if (pParam2->dwRetSize >= INFO_SIZE)
  478.       {
  479.          dwLen = INFO_SIZE;
  480.          rc = MCIERR_SUCCESS;
  481.       }
  482.       else
  483.       {
  484.          dwLen = pParam2->dwRetSize;
  485.          rc = MCIERR_INVALID_BUFFER;
  486.       }
  487.  
  488.       /* fill in product information */
  489.  
  490.       if (pInst->usHWType / HW_TYPE < HW_TYPE)
  491.          strcpy(szInfo, "IBMCD0");
  492.       else
  493.          strcpy(szInfo, "IBMCD");
  494.  
  495.       /* complete string with ID number */
  496.       i = (USHORT) strlen(szInfo);
  497.       _itoa((int)pInst->usHWType, (PSZ)&szInfo[i], 10);
  498.  
  499.       if (dwLen)   //if 0, it may be an invalid address
  500.          strncpy((CHAR *)pParam2->lpstrReturn, szInfo, dwLen);
  501.       pParam2->dwRetSize = INFO_SIZE;
  502.  
  503.    }
  504.    else
  505.       rc = MCIERR_INVALID_FLAG;
  506.  
  507.    if (rc && rc != MCIERR_INVALID_BUFFER)
  508.       pParam2->dwRetSize = 0L;
  509.  
  510.    return(rc);
  511.  
  512. }  /* of CDAudInfo() */
  513.  
  514.  
  515.  
  516. /****************************************************************************/
  517. /*                                                                          */
  518. /* SUBROUTINE NAME:  CDAudOpen                                              */
  519. /*                                                                          */
  520. /* DESCRIPTIVE NAME:  CD Audio Open.                                        */
  521. /*                                                                          */
  522. /* FUNCTION:  Open a device dependent instance.                             */
  523. /*                                                                          */
  524. /* PARAMETERS:                                                              */
  525. /*      DWORD dwParam1   -- Flag for this message.                          */
  526. /*      MMDRV_OPEN_PARMS *pParam2 -- Pointer to data record structure.      */
  527. /*                                                                          */
  528. /* EXIT CODES:                                                              */
  529. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  530. /*      MCIERR_INI_FILE  -- corrupted INI file, drive is not CD-ROM drive.  */
  531. /*      MCIERR_OUT_OF_MEMORY       -- couldn't allocate memory for instance.*/
  532. /*      MCIERR_INVALID_FLAG -- flag not supported by this VSD.              */
  533. /*      MCIERR_DEVICE_LOCKED -- CD-ROM drive, previously opened exclusively.*/
  534. /*                                                                          */
  535. /* NOTES:                                                                   */
  536. /*                                                                          */
  537. /****************************************************************************/
  538. static DWORD CDAudOpen(DWORD dwParam1, MMDRV_OPEN_PARMS *pParam2)
  539. {
  540.    DWORD rc;
  541.    PINST pInst;
  542.    BYTE i;
  543.    ULONG ulDevParmLen;
  544.    PVOID pVSDParm;
  545.    CHAR *pDrive, *pModel;
  546.  
  547.    /* validate flags */
  548.    /* this VSD will only support standard flags */
  549.    dwParam1 &= WAIT_NOTIFY_MASK;
  550.    if (dwParam1)
  551.       rc = MCIERR_INVALID_FLAG;
  552.    else
  553.    {
  554.       /* get memory */
  555.       pInst = HhpAllocMem(CDMC_hHeap, sizeof(struct instance_state));
  556.       if (pInst == NULL)
  557.          rc = MCIERR_OUT_OF_MEMORY;
  558.       else
  559.       {
  560.          /* create semaphore so only one IOCLT call will be made at a time */
  561.          rc = DosCreateMutexSem((PSZ) NULL, &pInst->hIOSem, 0L, FALSE);
  562.          if (!rc)
  563.             rc = DosCreateEventSem((PSZ) NULL, &pInst->hTimeLoopSem, 0L, FALSE);
  564.          if (!rc)
  565.             rc = DosCreateMutexSem((PSZ) NULL, &pInst->hInstSem, 0L, FALSE);
  566.          if (!rc)
  567.             rc = DosCreateEventSem((PSZ) NULL, &pInst->hReturnSem, 0L, FALSE);
  568.          if (rc)
  569.          {
  570.             DosCloseMutexSem(pInst->hIOSem);
  571.             DosCloseMutexSem(pInst->hInstSem);
  572.             DosCloseEventSem(pInst->hTimeLoopSem);
  573.             DosCloseEventSem(pInst->hReturnSem);
  574.             rc = MCIERR_OUT_OF_MEMORY;
  575.  
  576.          }  /* of if error creating semaphores */
  577.       }  /* else no error creating instance structure's memory */
  578.  
  579.       /* init instance */
  580.       if (!rc)
  581.       {  /* instance entry created */
  582.          /* init instance */
  583.          pInst->hDrive = 0;                     // drive handle
  584.          pInst->dwCurPos = 0L;                  // set current position;
  585.          pInst->wDeviceID = pParam2->wDeviceID;
  586.          for (i=0; i < CDMCD_CUEPOINT_MAX; i++)          // init arrays
  587.             pInst->arrCuePoint[i].dwEvent = (DWORD) -1L;
  588.  
  589.          pInst->qptPosAdvise.dwEvent = 0L;
  590.          pInst->StreamMaster = FALSE;
  591.  
  592.          /* validate and get drive & hardware type */
  593.          /* copy string so that it doesn't get disturb */
  594.          ulDevParmLen = strlen(pParam2->pDevParm) + 1;
  595.          pVSDParm = HhpAllocMem(CDMC_hHeap, ulDevParmLen);
  596.          strcpy(pVSDParm, pParam2->pDevParm);
  597.          parse_DevParm((CHAR *)pVSDParm, &pDrive, &pModel);
  598.          pInst->Drive = *pDrive;
  599.  
  600.          if (stricmp(pModel, "IBMCD010"))
  601.             pInst->usHWType = IBMCD019;       /* assume 3510 */
  602.          else
  603.             pInst->usHWType = IBMCD010;
  604.  
  605.          HhpFreeMem(CDMC_hHeap, pVSDParm);
  606.  
  607.          pInst->usPlayFlag = TIMER_AVAIL;
  608.          pInst->ulPlayTID  = 0L;
  609.          pInst->DiscID.dwLeadOut = 0L;
  610.  
  611.          /* Try opening the device.  Ignore things like disc not present, */
  612.          /* but report errors involving the INI file or that the drive    */
  613.          /* was previously opened in an exclusive mode.                   */
  614.          rc = CD01_Open(pInst);
  615.          if (rc != MCIERR_INI_FILE && rc != MCIERR_DEVICE_LOCKED)
  616.             rc = MCIERR_SUCCESS;        /* pretend that all went well */
  617.  
  618.       }  /* of if no errors getting memory */
  619.  
  620.       if (rc)                                  /* if error, free memory */
  621.          HhpFreeMem(CDMC_hHeap, pInst);
  622.       else
  623.          pParam2->pInstance = pInst;           /* pass pointer back */
  624.  
  625.    }  /* of else no invalid flags */
  626.  
  627.    return(rc);
  628.  
  629. }  /* of CDAudOpen() */
  630.  
  631.  
  632.  
  633. /****************************************************************************/
  634. /*                                                                          */
  635. /* SUBROUTINE NAME:  CDAudRegDisc                                           */
  636. /*                                                                          */
  637. /* DESCRIPTIVE NAME:  CD Audio Register Compact Disc.                       */
  638. /*                                                                          */
  639. /* FUNCTION:  Register a CD media so that the disc may be recognized by     */
  640. /*            CDAUDIO.DLL.                                                  */
  641. /*                                                                          */
  642. /* PARAMETERS:                                                              */
  643. /*      PINST pInst      -- Instance structure.                             */
  644. /*      USHORT usFlag    -- Action Flag to copy into pParam2.               */
  645. /*      MCI_CD_REGDISC_PARMS *pParam2 -- Pointer to data record.            */
  646. /*                                                                          */
  647. /* EXIT CODES:                                                              */
  648. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  649. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  650. /*                                                                          */
  651. /* NOTES:                                                                   */
  652. /*                                                                          */
  653. /****************************************************************************/
  654. static DWORD CDAudRegDisc(PINST pInst, USHORT usFlag,
  655.                           MCI_CD_REGDISC_PARMS *pParam2)
  656. {
  657.    DWORD rc;
  658.    USHORT i;
  659.    BYTE lowest, highest;
  660.    ULONG ulDataLen = STANDRD_DMAX, ulParamLen = STANDRD_PMAX;
  661.    MCI_CD_ID DiscID;
  662.  
  663.    memcpy(&DiscID, &pInst->DiscID, sizeof(MCI_CD_ID));  //save original
  664.  
  665.    if (usFlag == REG_BOTH || usFlag == REG_INST)
  666.    {   /* register with the internal instance */
  667.       rc = CD01_GetID(pInst, &pInst->DiscID, &lowest, &highest);
  668.       if (!rc && usFlag == REG_BOTH)
  669.          /* copy information to external source */
  670.          memcpy(&pParam2->DiscID, &pInst->DiscID, sizeof(MCI_CD_ID));
  671.    }   /* of if update instance structure */
  672.    else      /* the flag is REG_PARAM2 */
  673.       rc = CD01_GetID(pInst, &pParam2->DiscID, &lowest, &highest);
  674.  
  675.    /* complete registration for param2 */
  676.    if (!rc && (usFlag == REG_BOTH || usFlag == REG_PARAM2))
  677.    {
  678.       /* get low and high track numbers */
  679.       pParam2->LowestTrackNum  = lowest;
  680.       pParam2->HighestTrackNum = highest;
  681.  
  682.       /* get upc code -- device cannot do this so set this to zero */
  683.       for (i=0; i < UPC_SIZE; i++)
  684.          pParam2->UPC[i] = 0;
  685.  
  686.    }  /* of if need to complete Param2 */
  687.  
  688.    return(rc);
  689.  
  690. }  /* of CDAudRegDisc() */
  691.  
  692.  
  693.  
  694. /****************************************************************************/
  695. /*                                                                          */
  696. /* SUBROUTINE NAME:  CDAudRegDrive                                          */
  697. /*                                                                          */
  698. /* DESCRIPTIVE NAME:  CD Audio Register CD-ROM Drive and its capabilities.  */
  699. /*                                                                          */
  700. /* FUNCTION:  Register a CD media so that the disc may be recognized by     */
  701. /*            CDAUDIO.DLL.                                                  */
  702. /*                                                                          */
  703. /* PARAMETERS:                                                              */
  704. /*      PINST pInst      -- Instance structure.                             */
  705. /*      MCI_CD_REGDRIVE_PARMS *pParam2 -- Pointer to data record.           */
  706. /*                                                                          */
  707. /* EXIT CODES:                                                              */
  708. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  709. /*                                                                          */
  710. /* NOTES:                                                                   */
  711. /*                                                                          */
  712. /****************************************************************************/
  713. static DWORD CDAudRegDrive(PINST pInst, MCI_CD_REGDRIVE_PARMS *pParam2)
  714. {
  715.    /* get the CD MCD return function information */
  716.    pInst->dwCDMCDID    = pParam2->dwCDMCDID;
  717.    pInst->pCDMCDReturn = pParam2->pCDMCDReturn;
  718.  
  719.    /* fill in capabilities */
  720.    pParam2->wCaps = CD01_CAPS;        //This sample supports on the IBM 3510
  721.  
  722.    /* fill in preroll information */
  723.    pParam2->dwPrerollType  = MCI_PREROLL_NONE;
  724.    pParam2->dwPrerollTime  = 0L;
  725.    pParam2->dwMinStartTime = SPEC_START;
  726.  
  727.    return(MCIERR_SUCCESS);
  728. }  /* of CDAudRegDrive() */
  729.  
  730.  
  731.  
  732. /****************************************************************************/
  733. /*                                                                          */
  734. /* SUBROUTINE NAME:  CDAudSet                                               */
  735. /*                                                                          */
  736. /* DESCRIPTIVE NAME:  CD Audio Set.                                         */
  737. /*                                                                          */
  738. /* FUNCTION:  Set features and attributes of the CD-ROM drive.              */
  739. /*                                                                          */
  740. /* PARAMETERS:                                                              */
  741. /*      PINST pInst      -- Instance structure.                             */
  742. /*      DWORD *pParam1   -- Flag for this message.                          */
  743. /*      MCI_SET_PARMS *pParam2   -- Pointer to data record structure.       */
  744. /*                                                                          */
  745. /* EXIT CODES:                                                              */
  746. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  747. /*      MCIERR_UNSUPPORTED_FLAG      -- unsupported flag.                   */
  748. /*      MCIERR_INVALID_FLAG          -- Unknown flag.                       */
  749. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  750. /*                                                                          */
  751. /* NOTES:  Mutual Exclusive flags (LOCK/UNLOCK & OPEN/CLOSE DOOR) are       */
  752. /*         tested in the MCD.                                               */
  753. /*                                                                          */
  754. /****************************************************************************/
  755. static DWORD CDAudSet(PINST pInst, DWORD *pParam1, MCI_SET_PARMS *pParam2)
  756. {
  757.    DWORD rc;
  758.    ULONG ulDataLen = STANDRD_DMAX, ulParamLen = STANDRD_PMAX;
  759.    ULONG ulType;
  760.  
  761.    /* validate flags */
  762.    rc = CDAudSetVerify(*pParam1);
  763.  
  764.    if (!rc)
  765.    {
  766.       ulType = *pParam1 & WAIT_NOTIFY_MASK;
  767.  
  768.       if (ulType & MCI_SET_DOOR_OPEN)
  769.       {
  770.          /* hardware does not support eject if playing, so stop it. */
  771.          if (pInst->usPlayFlag == TIMER_PLAYING)
  772.             rc = CD01_Stop(pInst, TIMER_EXIT_ABORTED);
  773.  
  774.          if (!rc)             // no error, proceed, else disc is already out
  775.          {
  776.             /* make sure that door is unlocked so eject can be successful */
  777.             CD01_LockDoor(pInst, MCI_FALSE);
  778.             CallIOCtl(pInst, CDDRIVE_CAT, EJECT__DISK,
  779.                        "CD01", ulParamLen, &ulParamLen,
  780.                         NULL,  ulDataLen,  &ulDataLen);
  781.          }
  782.          rc = MCIERR_SUCCESS;
  783.  
  784.       }  /* of if EJECTing disc */
  785.  
  786.       if (ulType & MCI_SET_DOOR_LOCK)
  787.          rc = CD01_LockDoor(pInst, MCI_TRUE);
  788.       else if (ulType & MCI_SET_DOOR_UNLOCK)
  789.          rc = CD01_LockDoor(pInst, MCI_FALSE);
  790.  
  791.       if (ulType & MCI_SET_VOLUME)
  792.          /* Hardware for example cannot support vectored volume */
  793.          rc = CD01_SetVolume(pInst, pParam2->dwLevel);
  794.  
  795.    }  /* of if no error */
  796.  
  797.    return(rc);
  798.  
  799. }  /* of CDAudSet() */
  800.  
  801.  
  802.  
  803. /****************************************************************************/
  804. /*                                                                          */
  805. /* SUBROUTINE NAME:  CDAudSetVerify                                         */
  806. /*                                                                          */
  807. /* DESCRIPTIVE NAME:  CD Audio Set Verify                                   */
  808. /*                                                                          */
  809. /* FUNCTION:  Verify flags for SET command.  This function is called by     */
  810. /*            the MCD to validate flags prior to calling other components,  */
  811. /*            like the Amp/Mixer or SSM, to process their flags.            */
  812. /*                                                                          */
  813. /* PARAMETERS:                                                              */
  814. /*      DWORD dwParam1   -- Flag for this message.                          */
  815. /*                                                                          */
  816. /* EXIT CODES:                                                              */
  817. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  818. /*      MCIERR_UNSUPPORTED_FLAG      -- unsupported flag.                   */
  819. /*      MCIERR_INVALID_FLAG          -- Unknown flag.                       */
  820. /*                                                                          */
  821. /* NOTES:  Mutual Exclusive flags (LOCK/UNLOCK & OPEN/CLOSE DOOR) are       */
  822. /*         tested in the MCD.                                               */
  823. /*                                                                          */
  824. /****************************************************************************/
  825. static DWORD CDAudSetVerify(DWORD dwParam1)
  826. {
  827.    DWORD rc = MCIERR_SUCCESS;
  828.  
  829.    /* check unsupported flags */
  830.    if (dwParam1 & MCI_SET_DOOR_CLOSED)
  831.       rc = MCIERR_UNSUPPORTED_FLAG;
  832.    else
  833.       /* check unknown flags */
  834.       if (dwParam1 & ~(MCI_SET_DOOR_OPEN   | MCI_SET_DOOR_LOCK |
  835.                        MCI_SET_DOOR_UNLOCK | MCI_SET_VOLUME | MCI_OVER |
  836.                        MCI_NOTIFY | MCI_WAIT))
  837.          rc = MCIERR_INVALID_FLAG;
  838.  
  839.    return(rc);
  840.  
  841. }  /* of CDAudSetVerify() */
  842.  
  843.  
  844.  
  845. /****************************************************************************/
  846. /*                                                                          */
  847. /* SUBROUTINE NAME:  CDAudStatus                                            */
  848. /*                                                                          */
  849. /* DESCRIPTIVE NAME:  CD Audio Status.                                      */
  850. /*                                                                          */
  851. /* FUNCTION:  Query and return the status of the features and attributes    */
  852. /*            of the CD-ROM drive.                                          */
  853. /*                                                                          */
  854. /* PARAMETERS:                                                              */
  855. /*      PINST pInst      -- Instance structure.                             */
  856. /*      DWORD dwParam1   -- Flag for this message.                          */
  857. /*      MCI_STATUS_PARMS *pParam2   -- Pointer to data record structure.    */
  858. /*                                                                          */
  859. /* EXIT CODES:                                                              */
  860. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  861. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  862. /*      MCIERR_FLAGS_NOT_COMPATIBLE  -- Mis-match in flags.                 */
  863. /*      MCIERR_UNSUPPORTED_FUNCTION  -- Flags not supported.                */
  864. /*      MCIERR_INVALID_FLAG          -- Unknown flag.                       */
  865. /*      MCIERR_INVALID_ITEM_FLAG     -- Unknown item specified.             */
  866. /*                                                                          */
  867. /* NOTES:                                                                   */
  868. /*                                                                          */
  869. /****************************************************************************/
  870. static DWORD CDAudStatus(PINST pInst,
  871.                          DWORD dwParam1, MCI_STATUS_PARMS *pParam2)
  872. {
  873.    DWORD rc;
  874.  
  875.    dwParam1 &= WAIT_NOTIFY_MASK;
  876.  
  877.    /* verify flags */
  878.    if (dwParam1 & MCI_STATUS_ITEM)
  879.       if (dwParam1 != MCI_STATUS_ITEM)
  880.          if (dwParam1 & MCI_STATUS_START && dwParam1 & MCI_TRACK)
  881.             rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  882.          else
  883.             rc = MCIERR_INVALID_FLAG;
  884.       else
  885.          rc = MCIERR_SUCCESS;
  886.    else                                      // no ITEM flag
  887.       if (dwParam1 & MCI_TRACK)
  888.          rc = MCIERR_MISSING_FLAG;
  889.       else if (dwParam1 & MCI_STATUS_START)
  890.          rc = MCIERR_MISSING_FLAG;
  891.       else
  892.          rc = MCIERR_INVALID_FLAG;
  893.  
  894.    if (!rc)                         // dwParam1 == MCI_STATUS_ITEM only
  895.    {
  896.       switch(pParam2->dwItem)
  897.       {
  898.          case MCI_STATUS_POSITION :
  899.             rc = CD01_GetPosition(pInst, &pParam2->dwReturn);
  900.             break;
  901.          case MCI_STATUS_VOLUME :
  902.             rc = CD01_GetVolume(pInst, &pParam2->dwReturn);
  903.             break;
  904.          case MCI_STATUS_MEDIA_PRESENT :
  905.          case MCI_STATUS_MODE :
  906.          case MCI_STATUS_READY :
  907.             rc = CD01_GetDiscInfo(pInst, pParam2->dwItem, pParam2);
  908.             break;
  909.          default :
  910.             rc = MCIERR_INVALID_ITEM_FLAG;
  911.  
  912.       }  /* of item switch */
  913.    }  /* of if valid flag */
  914.  
  915.    return(rc);
  916.  
  917. }  /* of CDAudStatus() */
  918.  
  919.  
  920.  
  921. /****************************************************************************/
  922. /*                                                                          */
  923. /* SUBROUTINE NAME:  CDAudStatCVol                                          */
  924. /*                                                                          */
  925. /* DESCRIPTIVE NAME:  CD Audio Status Component Volume.                     */
  926. /*                                                                          */
  927. /* FUNCTION:  Remaps the component volume to what it would be from the      */
  928. /*            hardware if master audio was at 100%.                         */
  929. /*                                                                          */
  930. /* PARAMETERS:                                                              */
  931. /*      DWORD *dwLevel   -- Pointer to volume level.                        */
  932. /*                                                                          */
  933. /* EXIT CODES:                                                              */
  934. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  935. /*                                                                          */
  936. /* NOTES:                                                                   */
  937. /*                                                                          */
  938. /****************************************************************************/
  939. DWORD CDAudStatCVol(DWORD *dwLevel)
  940. {
  941.    WORD wLeft, wRight;
  942.  
  943.    wLeft  = LOUSHORT(*dwLevel);
  944.    wRight = HIUSHORT(*dwLevel);
  945.  
  946.    if (wLeft)  wLeft  = 100; else wLeft  = 0;
  947.    if (wRight) wRight = 100; else wRight = 0;
  948.  
  949.    /* Adjust for hardware limitations, VOL = MAX(Left, Right) */
  950.    if (wLeft && wRight)
  951.       if (wLeft > wRight)
  952.          wRight = wLeft;
  953.       else
  954.          wLeft = wRight;
  955.  
  956.    *dwLevel = MAKEULONG(wLeft, wRight);
  957.  
  958.    return(MCIERR_SUCCESS);
  959.  
  960. }  /* of CDAudStatCVol() */
  961.  
  962.  
  963.  
  964. /****************************************************************************/
  965. /*                                                                          */
  966. /* SUBROUTINE NAME:  CD01_Cue                                               */
  967. /*                                                                          */
  968. /* DESCRIPTIVE NAME:  CD Cue.                                               */
  969. /*                                                                          */
  970. /* FUNCTION:  Cue up or preroll the drive.  To do this we seek to the       */
  971. /*            current position.                                             */
  972. /*                                                                          */
  973. /* PARAMETERS:                                                              */
  974. /*      PINST pInst      -- Instance structure.                             */
  975. /*                                                                          */
  976. /* EXIT CODES:                                                              */
  977. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  978. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  979. /*                                                                          */
  980. /* NOTES:                                                                   */
  981. /*                                                                          */
  982. /****************************************************************************/
  983. static DWORD CD01_Cue(PINST pInst)
  984. {
  985.    DWORD rc, dwPos;
  986.  
  987.    /* test is disk is still present and get current position */
  988.    rc = CD01_GetPosition(pInst, &dwPos);
  989.  
  990.    /* seek to current position to spin disc */
  991.    if (!rc)                              // if no error
  992.       rc = CD01_Seek(pInst, dwPos);
  993.  
  994.    return(rc);
  995.  
  996. }  /* of CD01_Cue() */
  997.  
  998.  
  999.  
  1000. /****************************************************************************/
  1001. /*                                                                          */
  1002. /* SUBROUTINE NAME:  CD01_CuePoint                                          */
  1003. /*                                                                          */
  1004. /* DESCRIPTIVE NAME:  CD Cue Point                                          */
  1005. /*                                                                          */
  1006. /* FUNCTION:  Set up the desired cuepoint.  To do this the cue point        */
  1007. /*            arrays will need to be updated.                               */
  1008. /*                                                                          */
  1009. /* PARAMETERS:                                                              */
  1010. /*      PINST pInst      -- Instance structure.                             */
  1011. /*      DWORD dwParam1   -- Flag set for this message.                      */
  1012. /*      MCI_CUEPOINT_PARMS *pParam2 -- Pointer to data record structure.    */
  1013. /*                                                                          */
  1014. /* EXIT CODES:                                                              */
  1015. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1016. /*      MCIERR_CUEPOINT_LIMIT_REACHED -- no more room to add events.        */
  1017. /*      MCIERR_INVALID_CUEPOINT       -- unable to locate event.            */
  1018. /*                                                                          */
  1019. /* NOTES:                                                                   */
  1020. /*                                                                          */
  1021. /****************************************************************************/
  1022. static DWORD CD01_CuePoint(PINST pInst,
  1023.                            DWORD dwParam1, MCI_CUEPOINT_PARMS *pParam2)
  1024. {
  1025.    DWORD rc = MCIERR_SUCCESS;
  1026.    int i;
  1027.  
  1028.    if (dwParam1 & MCI_SET_CUEPOINT_ON)
  1029.    {
  1030.       /* valid cuepoint, find first available entry,  */
  1031.       /* CD Audio MCD will make sure that we have room  */
  1032.       /* and that cuepoint is unique */
  1033.       for (i=0; i < CDMCD_CUEPOINT_MAX; i++)
  1034.          if (pInst->arrCuePoint[i].dwEvent == (DWORD) -1L)
  1035.             break;
  1036.  
  1037.       if (i == CDMCD_CUEPOINT_MAX)
  1038.          rc = MCIERR_CUEPOINT_LIMIT_REACHED;
  1039.       else
  1040.       {
  1041.          pInst->arrCuePoint[i].dwEvent = pParam2->dwCuepoint;
  1042.          pInst->arrCuePoint[i].dwCallback = pParam2->dwCallback;
  1043.          pInst->arrCuePoint[i].wUserParm = pParam2->wUserParm;
  1044.       }
  1045.    }  /* of if setting cuepoint */
  1046.    else
  1047.    {
  1048.       for (i=0; i < CDMCD_CUEPOINT_MAX; i++)
  1049.       {
  1050.          if (pInst->arrCuePoint[i].dwEvent == pParam2->dwCuepoint)
  1051.             break;
  1052.       }
  1053.       if (i == CDMCD_CUEPOINT_MAX)
  1054.          rc = MCIERR_INVALID_CUEPOINT;
  1055.       else
  1056.          pInst->arrCuePoint[i].dwEvent = (DWORD) -1L;
  1057.  
  1058.    }   /* of else MCI_SET_CUEPOINT_OFF */
  1059.  
  1060.    return(rc);
  1061.  
  1062. }  /* of CD01_CuePoint() */
  1063.  
  1064.  
  1065.  
  1066. /****************************************************************************/
  1067. /*                                                                          */
  1068. /* SUBROUTINE NAME:  CD01_GetCaps                                           */
  1069. /*                                                                          */
  1070. /* DESCRIPTIVE NAME:  CD Get Capabilities.                                  */
  1071. /*                                                                          */
  1072. /* FUNCTION:  Get information about the capabilities of the device and the  */
  1073. /*            VSD.                                                          */
  1074. /*                                                                          */
  1075. /* PARAMETERS:                                                              */
  1076. /*      DWORD dwParam1   -- Flag set for this message.                      */
  1077. /*      MCI_GETDEVCAPS_PARMS *pParam2   -- Pointer to data record structure.*/
  1078. /*                                                                          */
  1079. /* EXIT CODES:                                                              */
  1080. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1081. /*      MCIERR_FLAGS_NOT_COMPATIBLE  -- Mis-match in flags.                 */
  1082. /*      MCIERR_INVALID_FLAG          -- Unknown flag.                       */
  1083. /*      MCIERR_INVALID_ITEM_FLAG     -- Unknown item specified.             */
  1084. /*                                                                          */
  1085. /* NOTES:  Most of the capabilities are processed in the general MCI Driver.*/
  1086. /*      The messages supported need to be listed in the VSD because VSDs    */
  1087. /*      may support different messages.                                     */
  1088. /*                                                                          */
  1089. /*                                                                          */
  1090. /****************************************************************************/
  1091. static DWORD CD01_GetCaps(DWORD dwParam1, MCI_GETDEVCAPS_PARMS *pParam2)
  1092. {
  1093.    DWORD rc = MCIERR_SUCCESS;
  1094.  
  1095.    dwParam1 &= WAIT_NOTIFY_MASK;
  1096.  
  1097.    switch (dwParam1)
  1098.    {
  1099.       case MCI_GETDEVCAPS_MESSAGE :
  1100.          switch (pParam2->wMessage)
  1101.          {
  1102.             case MCI_CLOSE :                  case MCI_CUE :
  1103.             case MCI_GETDEVCAPS :             case MCI_GETTOC :
  1104.             case MCI_INFO :                   case MCI_OPEN :
  1105.             case MCI_PAUSE :                  case MCI_PLAY :
  1106.                                               case MCI_RESUME :
  1107.             case MCI_SEEK :                   case MCI_SET :
  1108.             case MCI_SET_CUEPOINT :           case MCI_SET_POSITION_ADVISE :
  1109.             case MCI_STATUS :                 case MCI_STOP :
  1110.             case MCIDRV_SAVE :                case MCIDRV_RESTORE :
  1111.             case MCIDRV_REGISTER_DISC :       case MCIDRV_REGISTER_DRIVE :
  1112.             case MCIDRV_REGISTER_TRACKS :     case MCIDRV_CD_STATUS_CVOL :
  1113.                pParam2->dwReturn = MCI_TRUE;
  1114.                break;
  1115.             default :
  1116.                pParam2->dwReturn = MCI_FALSE;
  1117.          }  /* of switch */
  1118.          break;
  1119.       case MCI_GETDEVCAPS_ITEM :            // MCD does all that VSD supports
  1120.          rc = MCIERR_INVALID_ITEM_FLAG;
  1121.          break;
  1122.       default :
  1123.          rc = MCIERR_INVALID_FLAG;
  1124.          break;
  1125.    }   /* of switch */
  1126.  
  1127.    return(rc);
  1128.  
  1129. }  /* of CD01_GetCaps() */
  1130.  
  1131.  
  1132.  
  1133. /****************************************************************************/
  1134. /*                                                                          */
  1135. /* SUBROUTINE NAME:  CD01_GetDiscInfo                                       */
  1136. /*                                                                          */
  1137. /* DESCRIPTIVE NAME:  CD Get Disc Information                               */
  1138. /*                                                                          */
  1139. /* FUNCTION:  Get information contained on the compact disc.                */
  1140. /*                                                                          */
  1141. /* PARAMETERS:                                                              */
  1142. /*      PINST pInst      -- Instance structure.                             */
  1143. /*      ULONG ulType     -- Type flag for this message.                     */
  1144. /*      MCI_STATUS_PARMS *pParam2   -- Pointer to data record structure.    */
  1145. /*                                                                          */
  1146. /* EXIT CODES:                                                              */
  1147. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1148. /*      MCIERR_FLAGS_NOT_COMPATIBLE  -- Mis-match in flags.                 */
  1149. /*                                                                          */
  1150. /* NOTES:  The function supports the MCI_STATUS_MEDIA_PRESENT,              */
  1151. /*      MCI_STATUS_MODE and MCI_STATUS_READY flags for the MCI_STATUS       */
  1152. /*      command message.                                                    */
  1153. /*                                                                          */
  1154. /****************************************************************************/
  1155. static DWORD CD01_GetDiscInfo(PINST pInst, ULONG ulType,
  1156.                                MCI_STATUS_PARMS *pParam2)
  1157. {
  1158.    DWORD rc = MCIERR_SUCCESS;
  1159.    BYTE data[SEEKSTATDMAX];
  1160.    ULONG ulDataLen = SEEKSTATDMAX, ulParamLen = STANDRD_PMAX;
  1161.  
  1162.    switch(ulType)
  1163.    {
  1164.       case MCI_STATUS_MEDIA_PRESENT :
  1165.          if (CallIOCtl(pInst, CDDRIVE_CAT, DEV__STATUS,
  1166.                       "CD01", ulParamLen, &ulParamLen,
  1167.                        data,  ulDataLen,  &ulDataLen))
  1168.             pParam2->dwReturn = MCI_FALSE;
  1169.          else
  1170.             if (data[STATAUDFLD] & NO_MEDIA)     // if No disc is present
  1171.                pParam2->dwReturn = MCI_FALSE;
  1172.             else
  1173.                pParam2->dwReturn = MCI_TRUE;
  1174.          break;
  1175.       case MCI_STATUS_MODE :
  1176.          CD01_GetState(pInst, pParam2);
  1177.          break;
  1178.       case MCI_STATUS_READY :
  1179.          CD01_GetState(pInst, pParam2);
  1180.          if (pParam2->dwReturn == MCI_MODE_NOT_READY)
  1181.             pParam2->dwReturn = MCI_FALSE;
  1182.          else
  1183.             pParam2->dwReturn = MCI_TRUE;
  1184.          break;
  1185.       default : rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  1186.  
  1187.    }  /* of switch */
  1188.  
  1189.    return(rc);
  1190.  
  1191. }  /* of CD01_GetDiscInfo() */
  1192.  
  1193.  
  1194.  
  1195. /****************************************************************************/
  1196. /*                                                                          */
  1197. /* SUBROUTINE NAME:  CD01_GetID                                             */
  1198. /*                                                                          */
  1199. /* DESCRIPTIVE NAME:  CD Get Disc ID.                                       */
  1200. /*                                                                          */
  1201. /* FUNCTION:  Get the Disc ID.  The disc ID is 8 bytes and format is:       */
  1202. /*            ┌────────┬───┬───┬──────┬───┬───┬───┬───┐                     */
  1203. /*            │   01   │Addr of│Num of│Address of the │                     */
  1204. /*            │UPC = 00│Track 1│Tracks│Lead Out Track │                     */
  1205. /*            └────────┴───┴───┴──────┴───┴───┴───┴───┘                     */
  1206. /*                                                                          */
  1207. /* PARAMETERS:                                                              */
  1208. /*      PINST pInst      -- Instance structure.                             */
  1209. /*      MCI_CD_DISC_ID *pDiscID  -- Pointer to data record structure.       */
  1210. /*      BYTE  *LowTrack  -- Lowest track number.                            */
  1211. /*      BYTE  *HighTrack -- Highest track number.                           */
  1212. /*                                                                          */
  1213. /* EXIT CODES:                                                              */
  1214. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1215. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  1216. /*                                                                          */
  1217. /* NOTES:                                                                   */
  1218. /*                                                                          */
  1219. /****************************************************************************/
  1220. static DWORD CD01_GetID(PINST pInst, MCI_CD_ID *pDiscID,
  1221.                  BYTE *LowTrack, BYTE *HighTrack)
  1222. {
  1223.    DWORD rc;
  1224.    BYTE data[DSKTRCK_DMAX], param[DSKTRCK_PMAX] = "CD01";
  1225.    ULONG ulDataLen = DSKTRCK_DMAX, ulParamLen = STANDRD_PMAX;
  1226.  
  1227.    /* set mode */
  1228.    pDiscID->Mode = 1;
  1229.  
  1230.    /* get rest of data */
  1231.    rc = CallIOCtl(pInst, CDAUDIO_CAT, DISK___INFO,
  1232.                    "CD01", ulParamLen, &ulParamLen,
  1233.                     data,  ulDataLen,  &ulDataLen);
  1234.  
  1235.    if (!rc)
  1236.    {
  1237.       /* set number of tracks */
  1238.       pDiscID->NumTracks = data[TRCKHI_FLD];
  1239.       *HighTrack = data[TRCKHI_FLD];
  1240.  
  1241.       /* set leadout track */
  1242.       pDiscID->dwLeadOut = REDBOOK2TOMM(*(DWORD *)&data[TRCKENDADR]);
  1243.  
  1244.       /* set first track */
  1245.       param[TRACKFIELD] = data[TRCKLOWFLD];
  1246.       *LowTrack = data[TRCKLOWFLD];
  1247.  
  1248.       /* get track information to get address of the first track */
  1249.       ulDataLen = DSKTRCK_DMAX;
  1250.       ulParamLen = DSKTRCK_PMAX;
  1251.       rc = CallIOCtl(pInst, CDAUDIO_CAT, TRACK__INFO,
  1252.                       param, ulParamLen, &ulParamLen,
  1253.                       data,  ulDataLen,  &ulDataLen);
  1254.  
  1255.       if (!rc)
  1256.          pDiscID->wTrack1 = (WORD) REDBOOK2TOMM(*(DWORD *)&data[TRACKFFFLD]);
  1257.  
  1258.    }   /* of if no error on IOCTL */
  1259.  
  1260.    return(rc);
  1261.  
  1262. }  /* of CD01_GetID() */
  1263.  
  1264.  
  1265.  
  1266. /****************************************************************************/
  1267. /*                                                                          */
  1268. /* SUBROUTINE NAME:  CD01_GetPosition                                       */
  1269. /*                                                                          */
  1270. /* DESCRIPTIVE NAME:  CD Get Position.                                      */
  1271. /*                                                                          */
  1272. /* FUNCTION:  Get the current position of the CD-ROM drive.                 */
  1273. /*                                                                          */
  1274. /* PARAMETERS:                                                              */
  1275. /*      PINST pInst      -- Instance structure.                             */
  1276. /*      DWORD *dwPosition -- ptr of the current position.                   */
  1277. /*                                                                          */
  1278. /* EXIT CODES:                                                              */
  1279. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1280. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  1281. /*      MCIERR_MEDIA_CHANGED         -- A disc change was reported.         */
  1282. /*                                                                          */
  1283. /* NOTES:  It is important to return the above three return codes because   */
  1284. /*         MCDs and Applications may rely on MCI_STATUS POSITION to verify  */
  1285. /*         that the same disc is still there.                               */
  1286. /*                                                                          */
  1287. /****************************************************************************/
  1288. static DWORD CD01_GetPosition(PINST pInst, DWORD *dwPosition)
  1289. {
  1290.    DWORD rc;
  1291.    BYTE data[LOCATON_DMAX], param[LOCATON_PMAX] = {'C', 'D', '0', '1', RBMODE};
  1292.    ULONG ulDataLen = LOCATON_DMAX, ulParamLen = LOCATON_PMAX;
  1293.  
  1294.    /* get location of head in disc */
  1295.    rc = CallIOCtl(pInst, CDDRIVE_CAT, Q__LOCATION,
  1296.                    param, ulParamLen, &ulParamLen,
  1297.                    data,  ulDataLen,  &ulDataLen);
  1298.  
  1299.    if (!rc)
  1300.       if (pInst->usPlayFlag == TIMER_PLAYING)
  1301.       {
  1302.          *dwPosition = REDBOOK2TOMM(*(DWORD *)data);
  1303.          pInst->dwCurPos = *dwPosition;
  1304.       }  /* of if playing */
  1305.       else           /* if not playing then use logical location */
  1306.          *dwPosition = pInst->dwCurPos;
  1307.  
  1308.    return(rc);
  1309.  
  1310. }  /* of CD01_GetPosition() */
  1311.  
  1312.  
  1313.  
  1314. /****************************************************************************/
  1315. /*                                                                          */
  1316. /* SUBROUTINE NAME:  CD01_GetState                                          */
  1317. /*                                                                          */
  1318. /* DESCRIPTIVE NAME:  CD Get State.                                         */
  1319. /*                                                                          */
  1320. /* FUNCTION:  Get the state (playing, stopped, paused, etc.) of the device. */
  1321. /*                                                                          */
  1322. /* PARAMETERS:                                                              */
  1323. /*      PINST pInst      -- Instance structure.                             */
  1324. /*      MCI_STATUS_PARMS *pParam2   -- Pointer to data record structure.    */
  1325. /*                                                                          */
  1326. /* EXIT CODES:                                                              */
  1327. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1328. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  1329. /*                                                                          */
  1330. /* NOTES:                                                                   */
  1331. /*                                                                          */
  1332. /****************************************************************************/
  1333. static DWORD CD01_GetState(PINST pInst, MCI_STATUS_PARMS *pParam2)
  1334. {
  1335.    DWORD rc;
  1336.    BYTE data[AUDSTAT_DMAX];      //values for the audio status command
  1337.    ULONG ulDataLen = AUDSTAT_DMAX, ulParamLen = STANDRD_PMAX;
  1338.  
  1339.    /* query the status */
  1340.    rc = CallIOCtl(pInst, CDDRIVE_CAT, DEV__STATUS,
  1341.                    "CD01", ulParamLen, &ulParamLen,
  1342.                    data,   ulDataLen,  &ulDataLen);
  1343.  
  1344.    if (rc)    /* error, manual eject */
  1345.       pParam2->dwReturn = MCI_MODE_NOT_READY;
  1346.    else
  1347.    {
  1348.       if (data[STATAUDFLD] & NO_MEDIA)               // if no disc
  1349.          pParam2->dwReturn = MCI_MODE_NOT_READY;
  1350.       else if (data[STATAUDFLD] & IS_PLAYING)        // if Playing
  1351.          pParam2->dwReturn = MCI_MODE_PLAY;
  1352.       else
  1353.          pParam2->dwReturn = MCI_MODE_STOP;
  1354.  
  1355.    }  /* of else no IOCTL error */
  1356.  
  1357.    return(rc);
  1358.  
  1359. }  /* of CD01_GetState() */
  1360.  
  1361.  
  1362.  
  1363. /****************************************************************************/
  1364. /*                                                                          */
  1365. /* SUBROUTINE NAME:  CD01_GetTOC                                            */
  1366. /*                                                                          */
  1367. /* DESCRIPTIVE NAME:  CD Get Table of Contents.                             */
  1368. /*                                                                          */
  1369. /* FUNCTION:  Get the Table of Contents of the playable portion of the CD.  */
  1370. /*                                                                          */
  1371. /* PARAMETERS:                                                              */
  1372. /*      PINST pInst      -- Instance structure.                             */
  1373. /*      MCI_TOC_PARMS *pParam2   -- Pointer to data record structure.       */
  1374. /*                                                                          */
  1375. /* EXIT CODES:                                                              */
  1376. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1377. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  1378. /*      MCIERR_INVALID_BUFFER        -- Buffer too small.                   */
  1379. /*      MCIERR_INVALID_MEDIA_TYPE    -- No audio tracks were found.         */
  1380. /*                                                                          */
  1381. /* NOTES:                                                                   */
  1382. /*                                                                          */
  1383. /****************************************************************************/
  1384. static DWORD CD01_GetTOC(PINST pInst, MCI_TOC_PARMS *pParam2)
  1385. {
  1386.    DWORD rc;
  1387.    BYTE data[DSKTRCK_DMAX], param[DSKTRCK_PMAX] = "CD01";
  1388.    BYTE low, hi;             // low and high track values
  1389.    BYTE cnt = 0, check = 0;  // audio track counters
  1390.    DWORD end_adr, cur_adr;
  1391.    ULONG ulDataLen = DSKTRCK_DMAX, ulParamLen = DSKTRCK_PMAX;
  1392.  
  1393.    /*** GET DISK INFORMATION ***/
  1394.    /* get disk information */
  1395.    rc = CallIOCtl(pInst, CDAUDIO_CAT, DISK___INFO,
  1396.                     param, ulParamLen, &ulParamLen,
  1397.                     data,  ulDataLen,  &ulDataLen);
  1398.  
  1399.    if (!rc)
  1400.       if (pParam2->dwBufSize < sizeof(MCI_TOC_REC))
  1401.          rc = MCIERR_INVALID_BUFFER;
  1402.  
  1403.    low = data[TRCKLOWFLD];
  1404.    hi  = data[TRCKHI_FLD];
  1405.  
  1406.    if (!rc)
  1407.    {                                            // okay, extract data
  1408.       /* get ending address */
  1409.       end_adr = REDBOOK2TOMM(*(DWORD *)&data[TRENDFFFLD]);
  1410.  
  1411.       /*** LOOP TO FILL TABLE ***/
  1412.       /******************************************************************
  1413.        *  CNT is a counter of audio tracks, LOW starts with the lowest  *
  1414.        *  track number and increments with each track, CHECK is a flag  *
  1415.        *  marking the previous audio track so that the ending address   *
  1416.        *  may be assigned.                                              *
  1417.        ******************************************************************/
  1418.  
  1419.       for (; low <= hi; low++)
  1420.       {
  1421.          param[TRACKFIELD] = low;
  1422.  
  1423.          ulDataLen = DSKTRCK_DMAX;
  1424.          ulParamLen = DSKTRCK_PMAX;
  1425.          rc = CallIOCtl(pInst, CDAUDIO_CAT, TRACK__INFO,
  1426.                    param, ulParamLen, &ulParamLen,
  1427.                    data,  ulDataLen,  &ulDataLen);
  1428.  
  1429.          if (rc)
  1430.             break;
  1431.  
  1432.          cur_adr = REDBOOK2TOMM(*(DWORD *)&data[TRACKFFFLD]);
  1433.  
  1434.          /* Enter address as ending address of previous track */
  1435.          if (cnt != check)                     // skip first and data tracks
  1436.          {                                     // add ending address
  1437.             (pParam2->lpBuf + cnt-1)->dwEndAddr = cur_adr;
  1438.             check = cnt;
  1439.          }
  1440.  
  1441.          if (!(data[TRKSTATFLD] & IS_DATA_TRK))         // if audio track
  1442.          {  /* audio track has been found, is there room for it in buffer */
  1443.             /* check for valid buffer size */
  1444.             if (pParam2->dwBufSize < (DWORD)(cnt + 1) * sizeof(MCI_TOC_REC))
  1445.             {
  1446.                rc = MCIERR_INVALID_BUFFER;
  1447.                break;
  1448.             }
  1449.  
  1450.             (pParam2->lpBuf + cnt)->TrackNum = low;          // track number
  1451.             (pParam2->lpBuf + cnt)->dwStartAddr = cur_adr;   // add start loc
  1452.             (pParam2->lpBuf + cnt)->Control = data[TRKSTATFLD];   // Control
  1453.             (pParam2->lpBuf + cnt)->wCountry = 0;                 // Country
  1454.             (pParam2->lpBuf + cnt)->dwOwner = 0L;                 // Owner
  1455.             (pParam2->lpBuf + cnt)->dwSerialNum = 0L;             // S/N
  1456.  
  1457.             if (low == hi)                       // last addr if last track
  1458.                (pParam2->lpBuf + cnt)->dwEndAddr = end_adr;
  1459.             cnt++;
  1460.  
  1461.          }  /* of if not data track */
  1462.  
  1463.       }   /* of for loop */
  1464.  
  1465.       if (!cnt)
  1466.          rc = MCIERR_INVALID_MEDIA_TYPE;     // No audio tracks were found.
  1467.  
  1468.    }   /* of if no error getting audio disc information */
  1469.  
  1470.    /* find needed buffer size */
  1471.    if (rc == MCIERR_INVALID_BUFFER)
  1472.    {
  1473.       for (; low <= hi; low++)
  1474.       {
  1475.          param[TRACKFIELD] = low;
  1476.  
  1477.          ulDataLen = DSKTRCK_DMAX;
  1478.          ulParamLen = DSKTRCK_PMAX;
  1479.          if (CallIOCtl(pInst, CDAUDIO_CAT, TRACK__INFO,
  1480.                    param, ulParamLen, &ulParamLen,
  1481.                    data,  ulDataLen,  &ulDataLen))
  1482.          {
  1483.             rc = MCIERR_DEVICE_NOT_READY;
  1484.             break;
  1485.          }
  1486.  
  1487.          if (!(data[TRKSTATFLD] & IS_DATA_TRK))         // if audio track
  1488.             cnt++;
  1489.  
  1490.       }   /* of for loop */
  1491.  
  1492.    }  /* of if buffer too small */
  1493.  
  1494.    /* return buffer size */
  1495.    pParam2->dwBufSize = sizeof(MCI_TOC_REC) * cnt;
  1496.  
  1497.    return(rc);
  1498.  
  1499. }  /* of CD01_GetTOC() */
  1500.  
  1501.  
  1502.  
  1503. /****************************************************************************/
  1504. /*                                                                          */
  1505. /* SUBROUTINE NAME:  CD01_GetVolume                                         */
  1506. /*                                                                          */
  1507. /* DESCRIPTIVE NAME:  CD Get Volume for the IBM 3510.                       */
  1508. /*                                                                          */
  1509. /* FUNCTION:  Get the left and right volume levels.                         */
  1510. /*                                                                          */
  1511. /* PARAMETERS:                                                              */
  1512. /*      PINST pInst      -- Instance structure.                             */
  1513. /*      DWORD *dwVolume  -- Retrieved volume.                               */
  1514. /*                                                                          */
  1515. /* EXIT CODES:                                                              */
  1516. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1517. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  1518. /*                                                                          */
  1519. /* NOTES:                                                                   */
  1520. /*                                                                          */
  1521. /****************************************************************************/
  1522. static DWORD CD01_GetVolume(PINST pInst, DWORD *dwVolume)
  1523. {
  1524.    DWORD rc;
  1525.    BYTE data[QVOLUME_DMAX];
  1526.    ULONG ulDataLen = QVOLUME_DMAX, ulParamLen = STANDRD_PMAX;
  1527.  
  1528.    /* audio channel information */
  1529.    rc = CallIOCtl(pInst, CDAUDIO_CAT, AUD_CH_INFO,
  1530.                     "CD01", ulParamLen, &ulParamLen,
  1531.                     data,  ulDataLen,  &ulDataLen);
  1532.  
  1533.    if (!rc)
  1534.       /* convert volume levels from 0-FF to 0-100% */
  1535.       *dwVolume = (data[VOL_LT_FLD] * 100 / 0xFF) |        // Left Channel
  1536.                   (data[VOL_RT_FLD] * 100 / 0xFF << 16);   // Right Chan
  1537.  
  1538.    return(rc);
  1539.  
  1540. }  /* of CD01_GetVolume() */
  1541.  
  1542.  
  1543.  
  1544. /****************************************************************************/
  1545. /*                                                                          */
  1546. /* SUBROUTINE NAME:  CD01_LockDoor                                          */
  1547. /*                                                                          */
  1548. /* DESCRIPTIVE NAME:  CD Lock Door                                          */
  1549. /*                                                                          */
  1550. /* FUNCTION:  Disable or enable the manual eject button.                    */
  1551. /*                                                                          */
  1552. /* PARAMETERS:                                                              */
  1553. /*      PINST pInst      -- Instance structure.                             */
  1554. /*      USHORT Lockit    -- Is To Be LOCK flag.                             */
  1555. /*                                                                          */
  1556. /* EXIT CODES:                                                              */
  1557. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1558. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  1559. /*                                                                          */
  1560. /* NOTES:                                                                   */
  1561. /*                                                                          */
  1562. /****************************************************************************/
  1563. static DWORD CD01_LockDoor(PINST pInst, USHORT LockIt)
  1564. {
  1565.    DWORD rc;
  1566.    BYTE param[LOCKDOR_PMAX] = "CD01";
  1567.    ULONG ulDataLen = STANDRD_DMAX, ulParamLen = LOCKDOR_PMAX;
  1568.  
  1569.    if (LockIt == MCI_TRUE)
  1570.       param[LOCKDORFLD] = 1;             //Eject button is disabled
  1571.    else
  1572.       param[LOCKDORFLD] = 0;             //Eject button is enabled
  1573.  
  1574.    rc = CallIOCtl(pInst, CDDRIVE_CAT, LOCK___DOOR,
  1575.                    param, ulParamLen, &ulParamLen,
  1576.                    NULL,  ulDataLen,  &ulDataLen);
  1577.  
  1578.    /* IBM device driver error, lock or unlock twice */
  1579.    ulDataLen = STANDRD_DMAX;
  1580.    ulParamLen = LOCKDOR_PMAX;
  1581.  
  1582.    rc = CallIOCtl(pInst, CDDRIVE_CAT, LOCK___DOOR,
  1583.                    param, ulParamLen, &ulParamLen,
  1584.                    NULL,  ulDataLen,  &ulDataLen);
  1585.  
  1586.  
  1587.    return(rc);
  1588.  
  1589. }  /* of CD01_LockDoor() */
  1590.  
  1591.  
  1592.  
  1593. /****************************************************************************/
  1594. /*                                                                          */
  1595. /* SUBROUTINE NAME:  CD01_Open                                              */
  1596. /*                                                                          */
  1597. /* DESCRIPTIVE NAME:  CD Open.                                              */
  1598. /*                                                                          */
  1599. /* FUNCTION:  Open the CD-ROM drive.                                        */
  1600. /*                                                                          */
  1601. /* PARAMETERS:                                                              */
  1602. /*      PINST pInst      -- Instance structure.                             */
  1603. /*                                                                          */
  1604. /* EXIT CODES:                                                              */
  1605. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1606. /*      MCIERR_INI_FILE  -- corrupted INI file, drive is not CD-ROM drive.  */
  1607. /*      MCIERR_DEVICE_LOCKED -- CD-ROM drive, previously opened exclusively.*/
  1608. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  1609. /*      MCIERR_MEDIA_CHANGED         -- different disc was inserted.        */
  1610. /*                                                                          */
  1611. /* NOTES:                                                                   */
  1612. /*                                                                          */
  1613. /****************************************************************************/
  1614. static DWORD CD01_Open(PINST pInst)
  1615. {
  1616.    DWORD rc;
  1617.  
  1618.    CHAR drive[] = "A:";
  1619.    ULONG ulAction;
  1620.    HFILE hDev;
  1621.    MCI_CD_REGDISC_PARMS dwParam2;
  1622.    BYTE data[LOCATON_DMAX], param[LOCATON_PMAX] = {'C', 'D', '0', '1', RBMODE};
  1623.    ULONG ulDataLen, ulParamLen;
  1624.  
  1625.    drive[0] = pInst->Drive;               /* Get drive letter */
  1626.  
  1627.    /* open device */
  1628.    rc = DosOpen(drive, &hDev, &ulAction, 0L, 0L, OPENFLAG, OPENMODE, 0L);
  1629.  
  1630.    if (rc)
  1631.    {
  1632.       switch (rc)
  1633.       {
  1634.          case ERROR_PATH_NOT_FOUND :     //network drive
  1635.          case ERROR_INVALID_DRIVE :      //invalid drive, not reg in boot-up(?)
  1636.             rc = MCIERR_INI_FILE;
  1637.             break;
  1638.          case ERROR_SHARING_VIOLATION :  //drive opened exclusively
  1639.             rc = MCIERR_DEVICE_LOCKED;
  1640.             break;
  1641.          case ERROR_NOT_READY :          //disc not in drive, drive powered off
  1642.          default :
  1643.             /* resume timer loop so that it can exit */
  1644.             DosPostEventSem(pInst->hTimeLoopSem);
  1645.             /* make play completed before returning */
  1646.             while (pInst->usPlayFlag != TIMER_AVAIL)
  1647.                DosSleep(HALF_TIME_MIN);
  1648.             rc = MCIERR_DEVICE_NOT_READY;
  1649.       }  /* of switch() */
  1650.    }  /* of if error */
  1651.    else                                   /* open was successful */
  1652.    {
  1653.       pInst->hDrive = hDev;
  1654.  
  1655.       if (pInst->DiscID.dwLeadOut == 0L)            // if New Open
  1656.       {
  1657.          /* test to see if drive is really a CD-ROM Drive */
  1658.          ulDataLen  = IDCDROM_DMAX;
  1659.          ulParamLen = STANDRD_PMAX;
  1660.          if (CallIOCtl(pInst, CDDRIVE_CAT, ID___CD_ROM,
  1661.                         param, ulParamLen, &ulParamLen,
  1662.                         data,  ulDataLen,  &ulDataLen))
  1663.             rc = MCIERR_INI_FILE;
  1664.          else
  1665.             if (memcmp(data, "CD01", IDCDROM_DMAX))
  1666.                rc = MCIERR_INI_FILE;
  1667.             else
  1668.                rc = MCIERR_SUCCESS;
  1669.  
  1670.          if (!rc)
  1671.          {  /** Get current position and let the registration *
  1672.               * insert information to the instance structure. **/
  1673.             ulDataLen  = LOCATON_DMAX;
  1674.             ulParamLen = LOCATON_PMAX;
  1675.             rc = CallIOCtl(pInst, CDDRIVE_CAT, Q__LOCATION,
  1676.                            param, ulParamLen, &ulParamLen,
  1677.                            data,  ulDataLen,  &ulDataLen);
  1678.             pInst->dwCurPos = REDBOOK2TOMM(*(DWORD *)data);
  1679.  
  1680.             rc = CDAudRegDisc(pInst, REG_INST, NULL);
  1681.          }   /* of if no error identifying drive */
  1682.       }
  1683.       else
  1684.       {
  1685.          /** Previous Open, register separately and compare with old  *
  1686.            * disc.  If the same, pretend nothing happened, otherwise  *
  1687.            * return code to make general MCI Driver do a re-register  */
  1688.          rc = CDAudRegDisc(pInst, REG_PARAM2, &dwParam2);
  1689.  
  1690.          if (!rc)
  1691.             if (memcmp(&pInst->DiscID, &dwParam2.DiscID, sizeof(MCI_CD_ID)))
  1692.             {
  1693.                CD01_Stop(pInst, TIMER_EXIT_CHANGED);
  1694.                rc = MCIERR_MEDIA_CHANGED;           /* Different disc */
  1695.             }
  1696.       }  /* of else not a new open */
  1697.    }  /* of else device is opened */
  1698.  
  1699.    return(rc);
  1700.  
  1701. }  /* of CD01_Open() */
  1702.  
  1703.  
  1704.  
  1705. /****************************************************************************/
  1706. /*                                                                          */
  1707. /* SUBROUTINE NAME:  CD01_Play                                              */
  1708. /*                                                                          */
  1709. /* DESCRIPTIVE NAME:  CD Play.                                              */
  1710. /*                                                                          */
  1711. /* FUNCTION:  Initiate playing audio data to internal DAC(s).               */
  1712. /*                                                                          */
  1713. /* PARAMETERS:                                                              */
  1714. /*      PINST pInst       -- Instance pointer.                              */
  1715. /*      DWORD *pParam1    -- Flag for this message.                         */
  1716. /*      DWORD dwFrom      -- From address.                                  */
  1717. /*      DWORD dwTo        -- To address in MMTIME.                          */
  1718. /*      WORD  wUserParm   -- User Parameter.                                */
  1719. /*      HWND  hCallback   -- Call back handle.                              */
  1720. /*                                                                          */
  1721. /* EXIT CODES:                                                              */
  1722. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1723. /*      MCIERR_DEVICE_NOT_READY  -- device was not ready, no disc.          */
  1724. /*      MCIERR_MEDIA_CHANGED     -- Disc changed.                           */
  1725. /*                                                                          */
  1726. /* NOTES:                                                                   */
  1727. /*                                                                          */
  1728. /****************************************************************************/
  1729. static DWORD CD01_Play(PINST pInst, DWORD *pParam1, DWORD dwFrom, DWORD dwTo,
  1730.                        WORD wUserParm, HWND hCallback)
  1731. {
  1732.    DWORD rc;
  1733.    DWORD dwThreadID;
  1734.    ULONG cnt;
  1735.  
  1736.    /* Stop drive before issuing next play command */
  1737.    if ((pInst->usPlayFlag == TIMER_PLAYING) ||
  1738.        (pInst->usPlayFlag == TIMER_PLAY_SUSPEND) ||
  1739.        (pInst->usPlayFlag == TIMER_PLAY_SUSP_2))
  1740.       if (*pParam1 & MCI_WAIT)
  1741.          CD01_Stop(pInst, TIMER_EXIT_ABORTED);
  1742.       else
  1743.          CD01_Stop(pInst, TIMER_EXIT_SUPER);
  1744.  
  1745.    /* prepare for play call */
  1746.    pInst->dwCurPos = dwFrom;
  1747.    pInst->dwEndPos = dwTo;
  1748.    pInst->wPlayNotify = (WORD)(*pParam1 & (MCI_WAIT | MCI_NOTIFY));
  1749.    if (*pParam1 & MCI_NOTIFY)
  1750.    {
  1751.       pInst->wPlayUserParm = wUserParm;
  1752.       pInst->hPlayCallback = hCallback;
  1753.       *pParam1 ^= MCI_NOTIFY;
  1754.    }  /* notify flag was used */
  1755.  
  1756.    if (*pParam1 & MCI_WAIT)
  1757.       rc = CD01_Timer(pInst);      /* returns when play commands end */
  1758.    else
  1759.    {
  1760.       DosResetEventSem(pInst->hReturnSem, &cnt);  //force a wait
  1761.       rc = DosCreateThread(&dwThreadID, (PFNTHREAD)CD01_Timer,
  1762.                    (DWORD)pInst, 0L, THREAD_STACK_SZ);
  1763.       if (rc)
  1764.       {
  1765.          rc = MCIERR_OUT_OF_MEMORY;
  1766.          DosPostEventSem(pInst->hReturnSem);
  1767.       }
  1768.       else  /* wait for new thread to process enough */
  1769.       {
  1770.          /* Let MCD know not to send notification by returning wait */
  1771.          *pParam1 = (*pParam1 & ~MCI_NOTIFY) | MCI_WAIT;
  1772.  
  1773.          /* wait for new thread to process enough */
  1774.          DosWaitEventSem(pInst->hReturnSem, WAIT_FOREVER);
  1775.       }
  1776.  
  1777.       DosReleaseMutexSem(pInst->hInstSem);
  1778.  
  1779.    }  /* else no wait flag was used */
  1780.  
  1781.    return(rc);
  1782.  
  1783. }  /* of CD01_Play() */
  1784.  
  1785.  
  1786.  
  1787. /****************************************************************************/
  1788. /*                                                                          */
  1789. /* SUBROUTINE NAME:  CD01_PlayCont                                          */
  1790. /*                                                                          */
  1791. /* DESCRIPTIVE NAME:  CD Play Continue.                                     */
  1792. /*                                                                          */
  1793. /* FUNCTION:  Continue to play audio data to internal DAC(s) from a         */
  1794. /*            MCIDRV_RESTORE or MCIDRV_SYNC command.                        */
  1795. /*                                                                          */
  1796. /* PARAMETERS:                                                              */
  1797. /*      PINST pInst       -- Instance pointer.                              */
  1798. /*      DWORD dwFrom      -- From address.                                  */
  1799. /*      DWORD dwTo        -- To address in MMTIME.                          */
  1800. /*                                                                          */
  1801. /* EXIT CODES:                                                              */
  1802. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1803. /*      MCIERR_DEVICE_NOT_READY  -- device was not ready, no disc.          */
  1804. /*      MCIERR_MEDIA_CHANGED     -- Disc changed.                           */
  1805. /*                                                                          */
  1806. /* NOTES:                                                                   */
  1807. /*                                                                          */
  1808. /****************************************************************************/
  1809. static DWORD CD01_PlayCont(PINST pInst, DWORD dwFrom, DWORD dwTo)
  1810. {
  1811.    DWORD rc;
  1812.    BYTE param[PLAYAUD_PMAX] = {'C', 'D', '0', '1', RBMODE};
  1813.    ULONG ulDataLen = STANDRD_DMAX, ulParamLen = PLAYAUD_PMAX;
  1814.  
  1815.    /* convert starting MM Time into Redbook 2 format */
  1816.    * (DWORD *)¶m[STARTFFFLD] = REDBOOK2FROMMM(dwFrom);
  1817.  
  1818.    /* convert ending MM Time into Redbook 2 format */
  1819.    * (DWORD *)¶m[END_FF_FLD] = REDBOOK2FROMMM(dwTo);
  1820.  
  1821.    /* Stop drive before issuing next play command */
  1822.    CD01_Stop(pInst, TIMER_PLAY_SUSPEND);
  1823.  
  1824.    /* play drive */
  1825.    rc = CallIOCtl(pInst, CDAUDIO_CAT, PLAY__AUDIO,
  1826.                   param, ulParamLen, &ulParamLen,
  1827.                   NULL,  ulDataLen,  &ulDataLen);
  1828.  
  1829.    if (!rc)
  1830.       pInst->dwCurPos = dwFrom;
  1831.  
  1832.    /* if Timer was stopped, continue timer loop */
  1833.    if (pInst->usPlayFlag == TIMER_PLAY_SUSPEND)
  1834.       pInst->usPlayFlag = TIMER_PLAYING;
  1835.    DosPostEventSem(pInst->hTimeLoopSem);
  1836.  
  1837.    return(rc);
  1838.  
  1839. }  /* of CD01_PlayCont() */
  1840.  
  1841.  
  1842.  
  1843. /****************************************************************************/
  1844. /*                                                                          */
  1845. /* SUBROUTINE NAME:  CD01_PosAdvise                                         */
  1846. /*                                                                          */
  1847. /* DESCRIPTIVE NAME:  CD Position Advise                                    */
  1848. /*                                                                          */
  1849. /* FUNCTION:  Set up the desired position advise.                           */
  1850. /*                                                                          */
  1851. /* PARAMETERS:                                                              */
  1852. /*      PINST pInst      -- Instance structure.                             */
  1853. /*      DWORD dwParam1   -- Flag set for this message.                      */
  1854. /*      MCI_POSITION_PARMS *pParam2 -- Pointer to data record structure.    */
  1855. /*                                                                          */
  1856. /* EXIT CODES:                                                              */
  1857. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1858. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Flags are mutually exclusive.        */
  1859. /*                                                                          */
  1860. /* NOTES:                                                                   */
  1861. /*                                                                          */
  1862. /****************************************************************************/
  1863. static DWORD CD01_PosAdvise(PINST pInst, DWORD dwParam1,
  1864.                             MCI_POSITION_PARMS *pParam2)
  1865. {
  1866.    DWORD rc = MCIERR_SUCCESS;
  1867.  
  1868.    if (dwParam1 & MCI_SET_POSITION_ADVISE_ON)
  1869.    {
  1870.       if (dwParam1 & MCI_SET_POSITION_ADVISE_OFF)
  1871.          rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  1872.       else
  1873.       {
  1874.          pInst->qptPosAdvise.dwEvent = pParam2->dwUnits;
  1875.          pInst->qptPosAdvise.dwCallback = pParam2->dwCallback;
  1876.          pInst->qptPosAdvise.wUserParm = pParam2->wUserParm;
  1877.       }
  1878.    }  /* of if on */
  1879.    else
  1880.       if (dwParam1 & MCI_SET_POSITION_ADVISE_OFF)
  1881.          pInst->qptPosAdvise.dwEvent = 0L;
  1882.  
  1883.    return(rc);
  1884.  
  1885. }  /* of CD01_PosAdvise() */
  1886.  
  1887.  
  1888.  
  1889. /****************************************************************************/
  1890. /*                                                                          */
  1891. /* SUBROUTINE NAME:  CD01_RegTracks                                         */
  1892. /*                                                                          */
  1893. /* DESCRIPTIVE NAME:  CD Audio Register Compact Disc.                       */
  1894. /*                                                                          */
  1895. /* FUNCTION:  Register a CD media so that the disc may be recognized by     */
  1896. /*            CDAUDIO.DLL.                                                  */
  1897. /*                                                                          */
  1898. /* PARAMETERS:                                                              */
  1899. /*      PINST pInst      -- Instance structure.                             */
  1900. /*      MCI_CD_REGTRACKS_PARMS *pParam2 -- Pointer to data record.          */
  1901. /*                                                                          */
  1902. /* EXIT CODES:                                                              */
  1903. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  1904. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  1905. /*      MCIERR_INVALID_BUFFER        -- Buffer size is too small.           */
  1906. /*                                                                          */
  1907. /* NOTES:                                                                   */
  1908. /*                                                                          */
  1909. /****************************************************************************/
  1910. static DWORD CD01_RegTracks(PINST pInst, MCI_CD_REGTRACKS_PARMS *pParam2)
  1911. {
  1912.    DWORD rc;
  1913.    BYTE data[DSKTRCK_DMAX], param[DSKTRCK_PMAX] = "CD01";
  1914.    BYTE low, hi, cnt;       // low and high track values
  1915.    DWORD end_adr, cur_adr;
  1916.    ULONG ulDataLen = DSKTRCK_DMAX, ulParamLen = DSKTRCK_PMAX;
  1917.  
  1918.  
  1919.    /*** GET DISK INFORMATION ***/
  1920.  
  1921.    /* get disk information */
  1922.    rc = CallIOCtl(pInst, CDAUDIO_CAT, DISK___INFO,
  1923.                    param, ulParamLen, &ulParamLen,
  1924.                    data,  ulDataLen,  &ulDataLen);
  1925.  
  1926.    if (!rc)
  1927.    {                                            // okay, extract data
  1928.       low = data[TRCKLOWFLD];
  1929.       hi  = data[TRCKHI_FLD];
  1930.  
  1931.       /* get ending address */
  1932.       end_adr = REDBOOK2TOMM(*(DWORD *)&data[TRENDFFFLD]);
  1933.  
  1934.       /* check for valid buffer size */
  1935.       if (pParam2->dwBufSize <
  1936.              (DWORD)(hi - low + 1) * sizeof(MCI_CD_REGTRACK_REC))
  1937.          rc = MCIERR_INVALID_BUFFER;
  1938.       else
  1939.       {
  1940.          rc = MCIERR_SUCCESS;
  1941.  
  1942.          /*** LOOP TO FILL TABLE ***/
  1943.  
  1944.          for (cnt = 0; low <= hi; cnt++, low++)
  1945.          {
  1946.             param[TRACKFIELD] = low;
  1947.  
  1948.             ulDataLen  = DSKTRCK_DMAX;
  1949.             ulParamLen = DSKTRCK_PMAX;
  1950.             if (CallIOCtl(pInst, CDAUDIO_CAT, TRACK__INFO,
  1951.                             param, ulParamLen, &ulParamLen,
  1952.                             data,  ulDataLen,  &ulDataLen))
  1953.             {
  1954.                rc = MCIERR_DEVICE_NOT_READY;
  1955.                break;
  1956.             }
  1957.  
  1958.             /* get track number */
  1959.             (pParam2->TrackRecArr + cnt)->TrackNum = low;
  1960.  
  1961.             /* get control byte */
  1962.             (pParam2->TrackRecArr + cnt)->TrackControl = data[TRKSTATFLD];
  1963.  
  1964.             /* get starting address */
  1965.             cur_adr = REDBOOK2TOMM(*(DWORD *)&data[TRACKFFFLD]);
  1966.             (pParam2->TrackRecArr + cnt)->dwStartAddr = cur_adr;
  1967.  
  1968.             if (cnt)
  1969.                /* get ending address */
  1970.                (pParam2->TrackRecArr + cnt-1)->dwEndAddr = cur_adr;
  1971.  
  1972.             /* get ending address if it is the last track */
  1973.             if (low == hi)
  1974.                (pParam2->TrackRecArr + cnt)->dwEndAddr = end_adr;
  1975.  
  1976.          }   /* of for loop */
  1977.       }   /* of else valid buffer size */
  1978.    }   /* of if no error getting audio disc information */
  1979.  
  1980.    /* return buffer size */
  1981.    if (rc)
  1982.       pParam2->dwBufSize = 0;
  1983.    else
  1984.       pParam2->dwBufSize = sizeof(MCI_CD_REGTRACK_REC) * cnt;
  1985.  
  1986.    return(rc);
  1987.  
  1988. }  /* of CD01_RegTracks() */
  1989.  
  1990.  
  1991.  
  1992. /****************************************************************************/
  1993. /*                                                                          */
  1994. /* SUBROUTINE NAME:  CD01_Restore                                           */
  1995. /*                                                                          */
  1996. /* DESCRIPTIVE NAME:  CD Restore.                                           */
  1997. /*                                                                          */
  1998. /* FUNCTION:  The device context or instance is being restored.  Restore    */
  1999. /*            the drive as listed in pParams.                               */
  2000. /*                                                                          */
  2001. /* PARAMETERS:                                                              */
  2002. /*      PINST pInst      -- Pointer to instance.                            */
  2003. /*      MCIDRV_CD_SAVE_PARMS *pParam2 -- pointer to save structure.         */
  2004. /*                                                                          */
  2005. /* EXIT CODES:                                                              */
  2006. /*      MCIERR_SUCCESS   -- action completed.                               */
  2007. /*                                                                          */
  2008. /* NOTES:                                                                   */
  2009. /*                                                                          */
  2010. /****************************************************************************/
  2011. static DWORD CD01_Restore(PINST pInst, MCIDRV_CD_SAVE_PARMS *pParam2)
  2012. {
  2013.    DWORD rc;
  2014.  
  2015.    /* reset volume */
  2016.    rc = CD01_SetVolume(pInst, pParam2->dwLevel);
  2017.  
  2018.    /* reset position and mode */
  2019.    if (!rc)
  2020.    {
  2021.       switch (pParam2->dwMode)
  2022.       {
  2023.          case MCI_MODE_STOP :
  2024.             rc = CD01_Seek(pInst, pParam2->dwPosition);
  2025.             break;
  2026.          case MCI_MODE_PLAY :
  2027.             rc = CD01_PlayCont(pInst, pParam2->dwPosition, pParam2->dwEndPlay);
  2028.             DosPostEventSem(pInst->hTimeLoopSem);  //continue timer loop
  2029.             break;
  2030.          case MCI_MODE_PAUSE :
  2031.             rc = CD01_Stop(pInst, TIMER_PLAY_SUSP_2);
  2032.             if (!rc)
  2033.             {
  2034.                pInst->dwCurPos = pParam2->dwPosition;
  2035.                pInst->dwEndPos = pParam2->dwEndPlay;
  2036.             }
  2037.             break;
  2038.          case MCI_MODE_NOT_READY :                /* disc changed on restore */
  2039.             rc = CD01_Stop(pInst, TIMER_EXIT_CHANGED);
  2040.             break;
  2041.          default :   /* error in saved state, try to accept current position */
  2042.             break;
  2043.       }  /* of switch */
  2044.    }  /* if no error setting volume */
  2045.  
  2046.    return(rc);
  2047.  
  2048. }  /* of CD01_Restore() */
  2049.  
  2050.  
  2051.  
  2052. /****************************************************************************/
  2053. /*                                                                          */
  2054. /* SUBROUTINE NAME:  CD01_Resume                                            */
  2055. /*                                                                          */
  2056. /* DESCRIPTIVE NAME:  CD Resume Playing.                                    */
  2057. /*                                                                          */
  2058. /* FUNCTION:  Unpause or resume the play command.                           */
  2059. /*                                                                          */
  2060. /* PARAMETERS:                                                              */
  2061. /*      PINST pInst      -- Instance structure.                             */
  2062. /*                                                                          */
  2063. /* EXIT CODES:                                                              */
  2064. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  2065. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  2066. /*                                                                          */
  2067. /* NOTES:                                                                   */
  2068. /*                                                                          */
  2069. /****************************************************************************/
  2070. static DWORD CD01_Resume(PINST pInst)
  2071. {
  2072.    DWORD rc;
  2073.    ULONG ulDataLen = STANDRD_DMAX, ulParamLen = STANDRD_PMAX;
  2074.  
  2075.    if (pInst->usPlayFlag == TIMER_PLAY_SUSP_2)
  2076.    {
  2077.       rc = CD01_PlayCont(pInst, pInst->dwCurPos, pInst->dwEndPos);
  2078.       DosPostEventSem(pInst->hTimeLoopSem);
  2079.    }
  2080.    else
  2081.    {
  2082.       /* resume audio */
  2083.       rc = CallIOCtl(pInst, CDAUDIO_CAT, RESUMEAUDIO,
  2084.                      "CD01", ulParamLen, &ulParamLen,
  2085.                       NULL,  ulDataLen,  &ulDataLen);
  2086.  
  2087.       /* check if resume failed, a disc was ejected and reinserted */
  2088.       if (rc == MCIERR_OUTOFRANGE)
  2089.          rc = CD01_PlayCont(pInst, pInst->dwCurPos, pInst->dwEndPos);
  2090.  
  2091.       if (!rc)
  2092.       {
  2093.          if (pInst->usPlayFlag == TIMER_PLAY_SUSPEND)
  2094.             pInst->usPlayFlag = TIMER_PLAYING;
  2095.          DosPostEventSem(pInst->hTimeLoopSem);
  2096.       }
  2097.    }   /* of else resuming paused audio */
  2098.  
  2099.    return(rc);
  2100.  
  2101. }  /* of CD01_Resume() */
  2102.  
  2103.  
  2104.  
  2105. /****************************************************************************/
  2106. /*                                                                          */
  2107. /* SUBROUTINE NAME:  CD01_Save                                              */
  2108. /*                                                                          */
  2109. /* DESCRIPTIVE NAME:  CD Save.                                              */
  2110. /*                                                                          */
  2111. /* FUNCTION:  The device context or instance is being saved.  Stop the      */
  2112. /*            drive and the play timer if needed.  Save the current state.  */
  2113. /*                                                                          */
  2114. /* PARAMETERS:                                                              */
  2115. /*      PINST pInst      -- Pointer to instance.                            */
  2116. /*      MCIDRV_CD_SAVE_PARMS *pParam2 -- pointer to save structure.         */
  2117. /*                                                                          */
  2118. /* EXIT CODES:                                                              */
  2119. /*      MCIERR_SUCCESS   -- action completed.                               */
  2120. /*                                                                          */
  2121. /* NOTES:                                                                   */
  2122. /*                                                                          */
  2123. /****************************************************************************/
  2124. static DWORD CD01_Save(PINST pInst, MCIDRV_CD_SAVE_PARMS *pParam2)
  2125. {
  2126.    DWORD rc;
  2127.  
  2128.    /* cheek to see if it is playing. If it is, stop drive */
  2129.    if (pInst->usPlayFlag == TIMER_PLAYING)
  2130.       CD01_Stop(pInst, TIMER_PLAY_SUSPEND);     // Don't care about return code
  2131.    else
  2132.       if (pInst->usPlayFlag == TIMER_PLAY_SUSP_2)
  2133.          pInst->usPlayFlag = TIMER_PLAY_SUSPEND;
  2134.  
  2135.    /* get volume */
  2136.    CDAudStatCVol(&pParam2->dwLevel);
  2137.  
  2138.    /* get position */
  2139.    rc = CD01_GetPosition(pInst, &pParam2->dwPosition);
  2140.  
  2141.    return(rc);
  2142.  
  2143. }  /* of CD01_Save() */
  2144.  
  2145.  
  2146.  
  2147. /****************************************************************************/
  2148. /*                                                                          */
  2149. /* SUBROUTINE NAME:  CD01_Seek                                              */
  2150. /*                                                                          */
  2151. /* DESCRIPTIVE NAME:  CD Seek.                                              */
  2152. /*                                                                          */
  2153. /* FUNCTION:  Seek to the specified position.                               */
  2154. /*                                                                          */
  2155. /* PARAMETERS:                                                              */
  2156. /*      PINST pInst      -- Instance pointer.                               */
  2157. /*      DWORD dwTo       -- address to seek.                                */
  2158. /*                                                                          */
  2159. /* EXIT CODES:                                                              */
  2160. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  2161. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  2162. /*                                                                          */
  2163. /* NOTES:                                                                   */
  2164. /*                                                                          */
  2165. /****************************************************************************/
  2166. static DWORD CD01_Seek(PINST pInst, DWORD dwTo)
  2167. {
  2168.    DWORD rc;
  2169.    BYTE data[SEEKSTATDMAX], param[SEEKSTATPMAX] = {'C', 'D', '0', '1', RBMODE};
  2170.    ULONG ulDataLen = SEEKSTATDMAX, ulParamLen = SEEKSTATPMAX;
  2171.  
  2172.    /* Stop drive before issuing SEEK command,         *
  2173.     *    drive will not SEEK Command if it is playing */
  2174.    rc = CallIOCtl(pInst, CDDRIVE_CAT, DEV__STATUS,
  2175.                    "CD01", ulParamLen, &ulParamLen,
  2176.                     data,  ulDataLen,  &ulDataLen);
  2177.  
  2178.    if (!rc)        /* stop drive even if it thinks that its playing */
  2179.       if ((data[STATAUDFLD] & IS_PLAYING) ||
  2180.           (pInst->usPlayFlag == TIMER_PLAYING) ||
  2181.           (pInst->usPlayFlag == TIMER_PLAY_SUSPEND) ||
  2182.           (pInst->usPlayFlag == TIMER_PLAY_SUSP_2))
  2183.          rc = CD01_Stop(pInst, TIMER_EXIT_ABORTED);
  2184.  
  2185.    if (!rc)
  2186.    {
  2187.       /* convert MM Time into Redbook 2 format */
  2188.       * (DWORD *)¶m[SEEK_FFFLD] = REDBOOK2FROMMM(dwTo);
  2189.  
  2190.       /* Seek to new location */
  2191.       ulDataLen  = STANDRD_DMAX;
  2192.       ulParamLen = SEEKSTATPMAX;
  2193.       rc = CallIOCtl(pInst, CDDRIVE_CAT, SEEK_POSITN,
  2194.                       param, ulParamLen, &ulParamLen,
  2195.                       NULL,  ulDataLen,  &ulDataLen);
  2196.  
  2197.       if (!rc)
  2198.          pInst->dwCurPos = dwTo;
  2199.  
  2200.    }  /* of if no error preparing disk for seek */
  2201.  
  2202.    return(rc);
  2203.  
  2204. }  /* of CD01_Seek() */
  2205.  
  2206.  
  2207.  
  2208. /****************************************************************************/
  2209. /*                                                                          */
  2210. /* SUBROUTINE NAME:  CD01_SetVolume                                         */
  2211. /*                                                                          */
  2212. /* DESCRIPTIVE NAME:  CD Set Volume.                                        */
  2213. /*                                                                          */
  2214. /* FUNCTION:  Set the left and right volume levels on the CD-ROM drive.     */
  2215. /*                                                                          */
  2216. /* PARAMETERS:                                                              */
  2217. /*      PINST pInst      -- Instance structure.                             */
  2218. /*      DWORD dwVolume   -- Volume Level.                                   */
  2219. /*                                                                          */
  2220. /* EXIT CODES:                                                              */
  2221. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  2222. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  2223. /*                                                                          */
  2224. /* NOTES:                                                                   */
  2225. /*                                                                          */
  2226. /****************************************************************************/
  2227. static DWORD CD01_SetVolume(PINST pInst, DWORD dwVolume)
  2228. {
  2229.  
  2230.    DWORD rc;
  2231.    BYTE data[QVOLUME_DMAX], left, right;
  2232.    ULONG ulDataLen = QVOLUME_DMAX, ulParamLen = STANDRD_PMAX;
  2233.  
  2234.    /* get current audio channel information */
  2235.    rc = CallIOCtl(pInst, CDAUDIO_CAT, AUD_CH_INFO,
  2236.                     "CD01", ulParamLen, &ulParamLen,
  2237.                     data,   ulDataLen,  &ulDataLen);
  2238.  
  2239.    /* get requested volume levels */
  2240.    left  = (BYTE) dwVolume;
  2241.    right = (BYTE) (dwVolume >> 16);
  2242.  
  2243.    if (!rc)
  2244.    {
  2245.       /* Since this is the IBM 3510, reset left and right to 0 or FF */
  2246.       if (left)
  2247.          left = 0xFF;
  2248.  
  2249.       if (right)
  2250.          right = 0xFF;
  2251.  
  2252.       /* Save an IOCLT call by only resetting if a change occurred */
  2253.  
  2254.       if (data[VOL_LT_FLD] != left || data[VOL_RT_FLD] != right)
  2255.       {
  2256.          data[VOL_LT_FLD] = left;
  2257.          data[VOL_RT_FLD] = right;
  2258.          /* set volume */
  2259.          ulDataLen = QVOLUME_DMAX;
  2260.          ulParamLen = STANDRD_PMAX;
  2261.          rc = CallIOCtl(pInst, CDAUDIO_CAT, AUD_CH_CTRL,
  2262.                   "CD01", ulParamLen, &ulParamLen,
  2263.                    data,  ulDataLen,  &ulDataLen);
  2264.  
  2265.       } /* of if volume had changed */
  2266.  
  2267.    }  /* of else Audio Channel Info DevIOCtl worked */
  2268.  
  2269.    return(rc);
  2270.  
  2271. }  /* of CD01_SetVolume() */
  2272.  
  2273.  
  2274.  
  2275. /****************************************************************************/
  2276. /*                                                                          */
  2277. /* SUBROUTINE NAME:  CD01_StartPlay                                         */
  2278. /*                                                                          */
  2279. /* DESCRIPTIVE NAME:  CD Start Play.                                        */
  2280. /*                                                                          */
  2281. /* FUNCTION:  Start playing audio data to internal DAC(s).                  */
  2282. /*                                                                          */
  2283. /* PARAMETERS:                                                              */
  2284. /*      PINST pInst       -- Instance pointer.                              */
  2285. /*                                                                          */
  2286. /* EXIT CODES:                                                              */
  2287. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  2288. /*      MCIERR_DEVICE_NOT_READY  -- device was not ready, no disc.          */
  2289. /*      MCIERR_MEDIA_CHANGED     -- Disc changed.                           */
  2290. /*                                                                          */
  2291. /* NOTES:                                                                   */
  2292. /*                                                                          */
  2293. /****************************************************************************/
  2294. static DWORD CD01_StartPlay(PINST pInst)
  2295. {
  2296.    DWORD rc;
  2297.    BYTE param[PLAYAUD_PMAX] = {'C', 'D', '0', '1', RBMODE};
  2298.    ULONG ulDataLen = STANDRD_DMAX, ulParamLen = PLAYAUD_PMAX;
  2299.    ULONG cnt;
  2300.    PTIB ptib;
  2301.    PPIB ppib;
  2302.  
  2303.    /* convert MM Time into Redbook 2 format */
  2304.    * (DWORD *)¶m[STARTFFFLD] = REDBOOK2FROMMM(pInst->dwCurPos);
  2305.    * (DWORD *)¶m[END_FF_FLD] = REDBOOK2FROMMM(pInst->dwEndPos);
  2306.  
  2307.    /* play drive */
  2308.    rc = CallIOCtl(pInst, CDAUDIO_CAT, PLAY__AUDIO,
  2309.                     param, ulParamLen, &ulParamLen,
  2310.                     NULL,  ulDataLen,  &ulDataLen);
  2311.  
  2312.    if (!rc)
  2313.    {
  2314.       /* set timer play flag */
  2315.       pInst->usPlayFlag = TIMER_PLAYING;
  2316.       DosGetInfoBlocks(&ptib, &ppib);
  2317.       pInst->ulPlayTID = ptib->tib_ptib2->tib2_ultid;
  2318.       DosResetEventSem(pInst->hTimeLoopSem, &cnt);  // force a wait in timer
  2319.  
  2320.    }  /* if no error */
  2321.  
  2322.    /* original thread owns Mutex sem,               */
  2323.    /* if not WAIT tell original thead to release it */
  2324.    if (pInst->wPlayNotify == MCI_WAIT)
  2325.       DosReleaseMutexSem(pInst->hInstSem);
  2326.    else
  2327.       DosPostEventSem(pInst->hReturnSem);
  2328.  
  2329.    return(rc);
  2330.  
  2331. }  /* of CD01_StartPlay() */
  2332.  
  2333.  
  2334.  
  2335. /****************************************************************************/
  2336. /*                                                                          */
  2337. /* SUBROUTINE NAME:  CD01_Stop                                              */
  2338. /*                                                                          */
  2339. /* DESCRIPTIVE NAME:  CD Stop.                                              */
  2340. /*                                                                          */
  2341. /* FUNCTION:  Stop the play command.                                        */
  2342. /*                                                                          */
  2343. /* PARAMETERS:                                                              */
  2344. /*      PINST pInst        -- Instance pointer.                             */
  2345. /*      USHORT usTimerFlag -- Set timer to this flag, if playing.           */
  2346. /*                                                                          */
  2347. /* EXIT CODES:                                                              */
  2348. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  2349. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  2350. /*                                                                          */
  2351. /* NOTES:                                                                   */
  2352. /*                                                                          */
  2353. /****************************************************************************/
  2354. static DWORD CD01_Stop(PINST pInst, USHORT usTimerFlag)
  2355. {
  2356.    DWORD rc;
  2357.    USHORT StopTimer = TRUE;
  2358.    ULONG ulDataLen = STANDRD_DMAX, ulParamLen = STANDRD_PMAX;
  2359.  
  2360.    /* stop timer if one is going */
  2361.    if (pInst->usPlayFlag == TIMER_PLAYING ||
  2362.        pInst->usPlayFlag == TIMER_PLAY_SUSPEND ||
  2363.        pInst->usPlayFlag == TIMER_PLAY_SUSP_2)
  2364.    {
  2365.       pInst->usPlayFlag = usTimerFlag;
  2366.  
  2367.       switch(usTimerFlag)
  2368.       {
  2369.          case TIMER_PLAY_SUSPEND :
  2370.          case TIMER_PLAY_SUSP_2 :
  2371.             StopTimer = FALSE;
  2372.       }  /* of switch */
  2373.  
  2374.       if (StopTimer)
  2375.       {
  2376.          /* resume timer loop so that it can exit */
  2377.          DosPostEventSem(pInst->hTimeLoopSem);
  2378.          while (pInst->usPlayFlag != TIMER_AVAIL)  //make play completed before
  2379.             DosSleep(HALF_TIME_MIN);               //returning, race condition.
  2380.       }
  2381.    }  /* of if timer is being used */
  2382.  
  2383.    /* stop drive */
  2384.    rc = CallIOCtl(pInst, CDAUDIO_CAT, STOP__AUDIO,
  2385.                    "CD01", ulParamLen, &ulParamLen,
  2386.                     NULL,  ulDataLen,  &ulDataLen);
  2387.  
  2388.    return(rc);
  2389.  
  2390. }  /* of CD01_Stop() */
  2391.  
  2392.  
  2393.  
  2394. /****************************************************************************/
  2395. /*                                                                          */
  2396. /* SUBROUTINE NAME:  CD01_Sync                                              */
  2397. /*                                                                          */
  2398. /* DESCRIPTIVE NAME:  CD Synchronization.                                   */
  2399. /*                                                                          */
  2400. /* FUNCTION:  Process SYNC messages from MCIDRV_SYNC message.               */
  2401. /*                                                                          */
  2402. /* PARAMETERS:                                                              */
  2403. /*      PINST pInst      -- Instance pointer.                               */
  2404. /*      DWORD dwParam1   -- Flag for this message.                          */
  2405. /*      MCIDRV_SYNC_PARMS *pParam2 -- pointer to record structure.          */
  2406. /*                                                                          */
  2407. /* EXIT CODES:                                                              */
  2408. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  2409. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  2410. /*      MCIERR_INVALID_FLAG          -- Unknown flag.                       */
  2411. /*                                                                          */
  2412. /* NOTES:                                                                   */
  2413. /*                                                                          */
  2414. /****************************************************************************/
  2415. static DWORD CD01_Sync(PINST pInst, DWORD dwParam1, MCIDRV_SYNC_PARMS *pParam2)
  2416. {
  2417.    DWORD rc = MCIERR_SUCCESS;
  2418.    DWORD dwPosition;
  2419.    LONG  lDelta;
  2420.  
  2421.    dwParam1 &= WAIT_NOTIFY_MASK;
  2422.  
  2423.    switch (dwParam1)
  2424.    {
  2425.       case MCIDRV_SYNC_ENABLE | MCIDRV_SYNC_MASTER :
  2426.          pInst->StreamMaster = TRUE;        // continue on
  2427.       case MCIDRV_SYNC_ENABLE :
  2428.          pInst->pSyncInst = pParam2->pInstance;
  2429.          pInst->GroupID = pParam2->GroupID;
  2430.          break;
  2431.       case MCIDRV_SYNC_DISABLE :
  2432.          pInst->StreamMaster = FALSE;
  2433.          break;
  2434.       case MCIDRV_SYNC_REC_PULSE :
  2435.          /* get current position */
  2436.          CD01_GetPosition(pInst, &dwPosition);
  2437.  
  2438.          lDelta = dwPosition - pParam2->mmTime - SYNC_LATENCY;
  2439.          if (lDelta < -SYNC_TOLERANCE || lDelta > SYNC_TOLERANCE)
  2440.             rc = CD01_PlayCont(pInst, (DWORD) pParam2->mmTime, pInst->dwEndPos);
  2441.          break;
  2442.       default :
  2443.          rc = MCIERR_INVALID_FLAG;
  2444.    }  /* of switch */
  2445.  
  2446.    return(rc);
  2447.  
  2448. }  /* of CD01_Sync() */
  2449.  
  2450.  
  2451.  
  2452. /****************************************************************************/
  2453. /*                                                                          */
  2454. /* SUBROUTINE NAME:  CD01_Timer                                             */
  2455. /*                                                                          */
  2456. /* DESCRIPTIVE NAME:  CD Timer                                              */
  2457. /*                                                                          */
  2458. /* FUNCTION:  Queries the device once a second to determine is a play       */
  2459. /*            command is still going on.                                    */
  2460. /*                                                                          */
  2461. /* PARAMETERS:                                                              */
  2462. /*      PINST pInst      -- Instance pointer.                               */
  2463. /*                                                                          */
  2464. /* EXIT CODES:                                                              */
  2465. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  2466. /*      MCIERR_DEVICE_NOT_READY  -- device was not ready, no disc.          */
  2467. /*      MCIERR_MEDIA_CHANGED     -- Disc changed on restore as reported by  */
  2468. /*                                  MCD.  Return error on play thread.      */
  2469. /*                                                                          */
  2470. /* NOTES:                                                                   */
  2471. /*                                                                          */
  2472. /****************************************************************************/
  2473. static DWORD CD01_Timer(PINST pInst)
  2474. {
  2475.    DWORD rc;
  2476.    DWORD dwDelay, dwPrevLimit;
  2477.    DWORD dwPosAdvise = 0L, dwSyncPos = 0L, dwOldPosAdvise = 0L;
  2478.    BYTE dataAud[AUDSTAT_DMAX];    //values for the audio status command
  2479.    BYTE dataPos[LOCATON_DMAX],
  2480.           param[LOCATON_PMAX] = {'C', 'D', '0', '1', RBMODE};
  2481.    ULONG ulDataLen, ulParamLen;
  2482.    ULONG cnt, DoLoop = TRUE;
  2483.    WORD wNotifyType = MCI_NOTIFY_SUCCESSFUL;
  2484.  
  2485.    /* start playing */
  2486.    rc = CD01_StartPlay(pInst);
  2487.    dwPrevLimit = pInst->dwCurPos;
  2488.  
  2489.    if (!rc)
  2490.    do
  2491.    {
  2492.       /* check position advise before calling notification routine. */
  2493.       /* event must be multiple address relative to address 0.      */
  2494.       if (pInst->qptPosAdvise.dwEvent != dwOldPosAdvise)
  2495.       {
  2496.          dwOldPosAdvise = pInst->qptPosAdvise.dwEvent;
  2497.          if (dwOldPosAdvise)
  2498.             if (pInst->dwCurPos % dwOldPosAdvise)    //if past, get next one
  2499.                dwPosAdvise = (pInst->dwCurPos / dwOldPosAdvise + 1)
  2500.                               * dwOldPosAdvise;
  2501.             else
  2502.                dwPosAdvise = pInst->dwCurPos;
  2503.          else
  2504.             dwPosAdvise = 0L;
  2505.       }  /* of if position advise changed */
  2506.  
  2507.       dwDelay = CD01_TimerNotify(pInst, &dwPosAdvise, &dwSyncPos, &dwPrevLimit);
  2508.  
  2509.       /********************************************************************
  2510.        * wait on the semaphore.  If the instance is PAUSED or being SAVED *
  2511.        * (no longer active) then wait until RESUME or RESTORE clears the  *
  2512.        * semaphore.  If a destructive STOP is received, the wait will     *
  2513.        * terminate immediately.  Otherwise, wait as long as dwDelay.      *
  2514.        ********************************************************************/
  2515.  
  2516.       if (!DosWaitEventSem(pInst->hTimeLoopSem, (ULONG) dwDelay))
  2517.          /* semaphore is cleared.  Reset it incase we don't exit loop */
  2518.          DosResetEventSem(pInst->hTimeLoopSem, &cnt);
  2519.  
  2520.       /* get new position */
  2521.       ulDataLen  = LOCATON_DMAX;
  2522.       ulParamLen = LOCATON_PMAX;
  2523.       rc = CallIOCtl(pInst, CDDRIVE_CAT, Q__LOCATION,
  2524.                    param, ulParamLen, &ulParamLen,
  2525.                    dataPos,  ulDataLen,  &ulDataLen);
  2526.  
  2527.       /* The only way to receive a media change rc is when closing   *
  2528.        * an inactive instance after a disc change, process the abort */
  2529.       if (rc)
  2530.          if (rc == MCIERR_MEDIA_CHANGED)
  2531.             rc = MCIERR_SUCCESS;
  2532.          else   // an error occurred, break out of the loop
  2533.             break;
  2534.  
  2535.       switch (pInst->usPlayFlag)
  2536.       {
  2537.          case TIMER_EXIT_SUPER :
  2538.             wNotifyType = MCI_NOTIFY_SUPERSEDED;
  2539.             DoLoop = FALSE;
  2540.             break;
  2541.          case TIMER_EXIT_ABORTED :
  2542.             wNotifyType = MCI_NOTIFY_ABORTED;
  2543.             DoLoop = FALSE;
  2544.             break;
  2545.          case TIMER_EXIT_CHANGED :
  2546.             rc = MCIERR_MEDIA_CHANGED;
  2547.             DoLoop = FALSE;
  2548.             break;
  2549.          case TIMER_AVAIL :
  2550.             rc = MCIERR_DRIVER_INTERNAL;       // abondon ship
  2551.             DoLoop = FALSE;
  2552.             break;
  2553.          case TIMER_PLAY_SUSPEND :             // do nothing
  2554.          case TIMER_PLAY_SUSP_2  :
  2555.             break;
  2556.          case TIMER_PLAYING :
  2557.             /* update current location */
  2558.             pInst->dwCurPos = REDBOOK2TOMM(*(DWORD *)dataPos);
  2559.  
  2560.             DosRequestMutexSem(pInst->hIOSem, (ULONG)-1L);
  2561.  
  2562.             /* check if drive is still playing */
  2563.             ulDataLen  = AUDSTAT_DMAX;
  2564.             ulParamLen = STANDRD_PMAX;
  2565.             if (DosDevIOCtl(pInst->hDrive, CDDRIVE_CAT, DEV__STATUS,
  2566.                             "CD01", ulParamLen, &ulParamLen,
  2567.                             dataAud,   ulDataLen,  &ulDataLen))
  2568.             {                         // Error
  2569.                rc = MCIERR_DEVICE_NOT_READY;
  2570.                DoLoop = FALSE;
  2571.             }  /* of if error calling device */
  2572.             else
  2573.             {
  2574.                if (!(dataAud[STATAUDFLD] & IS_PLAYING))      // if NOT Playing
  2575.                {
  2576.                   /* check to see if PLAY terminated or was STOPPED/PAUSED */
  2577.                   ulDataLen  = AUDSTAT_DMAX;
  2578.                   ulParamLen = STANDRD_PMAX;
  2579.                   if (DosDevIOCtl(pInst->hDrive, CDAUDIO_CAT, AUD__STATUS,
  2580.                                   "CD01", ulParamLen, &ulParamLen,
  2581.                                    dataAud,   ulDataLen,  &ulDataLen))
  2582.                   {
  2583.                      rc = MCIERR_DEVICE_NOT_READY;
  2584.                      DoLoop = FALSE;
  2585.                   }  /* of if error calling device */
  2586.                   else
  2587.                      if (!(dataAud[AUDSTATFLD] & WAS_STOPPED))
  2588.                      {     /* PLAY command finished */
  2589.                         rc = MCIERR_SUCCESS;
  2590.                         DoLoop = FALSE;
  2591.                      }  /* of else PLAY command terminated itself (finished) */
  2592.                      /* else it is paused, continue the clock */
  2593.  
  2594.                }  /* of if NOT Playing */
  2595.             }  /* of else no error querying status */
  2596.  
  2597.             DosReleaseMutexSem(pInst->hIOSem);
  2598.             break;
  2599.          default :
  2600.             rc = MCIERR_DRIVER_INTERNAL;       // unknown play flag
  2601.             DoLoop = FALSE;
  2602.             break;
  2603.  
  2604.       }   /* of switch on play flag */
  2605.    } while(DoLoop);  /* of do loop */
  2606.  
  2607.    if (!rc)         // if no error, report any events
  2608.       CD01_TimerNotify(pInst, &dwPosAdvise, &dwSyncPos, &dwPrevLimit);
  2609.  
  2610.    pInst->ulPlayTID  = 0L;                     // clear before exit or return
  2611.  
  2612.    if (pInst->wPlayNotify != MCI_WAIT)
  2613.    {
  2614.       if (rc)
  2615.          wNotifyType = (WORD) rc;
  2616.  
  2617.       /* inform MDM that play has terminated */
  2618.       if (pInst->wPlayNotify == MCI_NOTIFY)
  2619.          mdmDriverNotify(pInst->wDeviceID, pInst->hPlayCallback, MM_MCINOTIFY,
  2620.                       pInst->wPlayUserParm, MAKEULONG(MCI_PLAY, wNotifyType));
  2621.  
  2622.       /* inform MCD that play has terminated */
  2623.       pInst->pCDMCDReturn(pInst->dwCDMCDID, MAKEULONG(MCI_PLAY, wNotifyType),
  2624.                           0L);               //MCD ignores 3rd field for PLAY
  2625.       pInst->usPlayFlag = TIMER_AVAIL;
  2626.       DosExit(0L, 0L);
  2627.    }  /* of if notify was used */
  2628.  
  2629.    if (!rc && wNotifyType == MCI_NOTIFY_SUCCESSFUL)
  2630.       pInst->dwCurPos = pInst->dwEndPos;
  2631.  
  2632.    pInst->usPlayFlag = TIMER_AVAIL;
  2633.  
  2634.    return(rc);
  2635.  
  2636. }  /* of CD01_Timer() */
  2637.  
  2638.  
  2639.  
  2640. /****************************************************************************/
  2641. /*                                                                          */
  2642. /* SUBROUTINE NAME:  CD01_TimerNotify                                       */
  2643. /*                                                                          */
  2644. /* DESCRIPTIVE NAME:  CD Timer Notify                                       */
  2645. /*                                                                          */
  2646. /* FUNCTION:  Sets up the wait value to suspend the timer thread based on   */
  2647. /*            upcoming events.  It also sends notification of past or soon  */
  2648. /*            to pass events.                                               */
  2649. /*                                                                          */
  2650. /* PARAMETERS:                                                              */
  2651. /*      PINST pInst       -- Instance pointer.                              */
  2652. /*      DWORD *pPosAdvise -- Position for next Position Advise Event.       */
  2653. /*      DWORD *pSyncPos   -- Position for next Sync Pulse if master.        */
  2654. /*      DWORD *pPrevLimit -- Last range checked.                            */
  2655. /*                                                                          */
  2656. /* EXIT CODES:                                                              */
  2657. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  2658. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  2659. /*                                                                          */
  2660. /* NOTES:  It is important to note that events are in MM Time and delay     */
  2661. /*         factors are in milliseconds.                                     */
  2662. /*                                                                          */
  2663. /****************************************************************************/
  2664. static DWORD CD01_TimerNotify(PINST pInst, DWORD *pPosAdvise,
  2665.                               DWORD *pSyncPos, DWORD *pPrevLimit)
  2666. {
  2667.    DWORD dwDelay, dwUpperLimit, dwEvent;
  2668.    LONG lTemp;
  2669.    int i;
  2670.  
  2671.    /* find wait value */
  2672.    if (pInst->usPlayFlag == TIMER_PLAY_SUSPEND ||
  2673.        pInst->usPlayFlag == TIMER_PLAY_SUSP_2)
  2674.       dwDelay = (DWORD) WAIT_FOREVER;
  2675.    else
  2676.    {  /* find minimum event */
  2677.       dwDelay = WAIT_TIME_MAX;
  2678.       dwUpperLimit = pInst->dwCurPos + HALF_TIME_MIN * 3; // *3 is ms to mmtime
  2679.  
  2680.       /* process cuepoints */
  2681.       for (i=0; i < CDMCD_CUEPOINT_MAX; i++)
  2682.       {
  2683.          dwEvent = pInst->arrCuePoint[i].dwEvent;
  2684.  
  2685.          /* skip if no event */
  2686.          if (dwEvent == (DWORD) -1L)
  2687.             continue;
  2688.  
  2689.          /* check to see if event is in window */
  2690.          if (dwEvent >= *pPrevLimit && dwEvent < dwUpperLimit)
  2691.          {
  2692.             mdmDriverNotify(pInst->wDeviceID,
  2693.                             (HWND)pInst->arrCuePoint[i].dwCallback,
  2694.                             MM_MCICUEPOINT,
  2695.                             pInst->arrCuePoint[i].wUserParm, dwEvent);
  2696.             continue;
  2697.          }
  2698.                                              // there is an implied ELSE here
  2699.          lTemp = (LONG)(dwEvent - pInst->dwCurPos) / 3;
  2700.          if (lTemp > 0 && (DWORD)lTemp < dwDelay)
  2701.             dwDelay = (DWORD)lTemp;
  2702.  
  2703.       }  /* of cuepoint for loop */
  2704.  
  2705.       /* process position advise */
  2706.       if (*pPosAdvise)
  2707.       {
  2708.          /* loop for small advise frequencies */
  2709.          do
  2710.          {
  2711.             lTemp = (LONG)(*pPosAdvise - pInst->dwCurPos) / 3;
  2712.             if (lTemp < HALF_TIME_MIN)
  2713.             {
  2714.                mdmDriverNotify(pInst->wDeviceID,
  2715.                                (HWND)pInst->qptPosAdvise.dwCallback,
  2716.                                MM_MCIPOSITIONCHANGE,
  2717.                                pInst->qptPosAdvise.wUserParm,
  2718.                                (DWORD) *pPosAdvise);
  2719.                *pPosAdvise += pInst->qptPosAdvise.dwEvent;
  2720.             }
  2721.          }  while (lTemp < HALF_TIME_MIN);
  2722.  
  2723.          if ((DWORD)lTemp < dwDelay)
  2724.             dwDelay = (DWORD)lTemp;
  2725.       }  /* of if process advise event pending */
  2726.  
  2727.       /* process sync pulse */
  2728.       if (pInst->StreamMaster)
  2729.       {
  2730.          if (*pSyncPos)
  2731.          {
  2732.             lTemp = (LONG)(*pSyncPos - pInst->dwCurPos) / 3;
  2733.             if (lTemp < HALF_TIME_MIN)
  2734.             {
  2735.                mdmSyncNotify(pInst->pSyncInst, pInst->GroupID,
  2736.                              pInst->dwCurPos, 0);
  2737.                *pSyncPos = pInst->dwCurPos + SYNC_TOLERANCE * 2 * 3;
  2738.             }
  2739.          }
  2740.          else      // new event just started
  2741.             *pSyncPos = pInst->dwCurPos + SYNC_TOLERANCE * 2 * 3;
  2742.       }  /* of if position advise is set */
  2743.       else
  2744.          *pSyncPos = 0L;
  2745.  
  2746.       *pPrevLimit = dwUpperLimit;
  2747.  
  2748.    }  /* of else find minimum time to wait */
  2749.  
  2750.    return(dwDelay);
  2751.  
  2752. }  /* of CD01_TimerNotify() */
  2753.  
  2754.  
  2755.  
  2756. /****************************************************************************/
  2757. /*                                                                          */
  2758. /* SUBROUTINE NAME:  CallIOCtl                                              */
  2759. /*                                                                          */
  2760. /* DESCRIPTIVE NAME:  Call DosDevIOCTL()                                    */
  2761. /*                                                                          */
  2762. /* FUNCTION:  Call the DosDevIOCTLM Time to Redbook address.                */
  2763. /*                                                                          */
  2764. /* PARAMETERS:                                                              */
  2765. /*      PINST pInst      -- Instance pointer.                               */
  2766. /*      ULONG ulCat      -- Category.                                       */
  2767. /*      ULONG ulFunction -- Function number.                                */
  2768. /*      PVOID pParam     -- pointer to Parameter array.                     */
  2769. /*      ULONG ulPLen     -- Parameter array length.                         */
  2770. /*      ULONG *pPLen     -- pointer to Parameter array length.              */
  2771. /*      PVOID pData      -- pointer to Data array.                          */
  2772. /*      ULONG ulDLen     -- Data array length.                              */
  2773. /*      ULONG *pDLen     -- pointer to Data array length.                   */
  2774. /*                                                                          */
  2775. /* EXIT CODES:                                                              */
  2776. /*      MCIERR_SUCCESS   -- action completed without error.                 */
  2777. /*      MCIERR_DEVICE_NOT_READY      -- device was not ready, no disc.      */
  2778. /*                                                                          */
  2779. /* NOTES:  DosDevIOCTL sometimes fail when called by a second thread.  To   */
  2780. /*      avoid this, a generated thread should have at least a 16K stack     */
  2781. /*      size.                                                               */
  2782. /*                                                                          */
  2783. /****************************************************************************/
  2784. static DWORD CallIOCtl(PINST pInst,  ULONG ulCat,  ULONG ulFunction,
  2785.                        PVOID pParam, ULONG ulPLen, ULONG *pPLen,
  2786.                        PVOID pData,  ULONG ulDLen, ULONG *pDLen)
  2787. {
  2788.    DWORD rc;
  2789.  
  2790.    DosRequestMutexSem(pInst->hIOSem, (ULONG)-1L);
  2791.    rc = DosDevIOCtl(pInst->hDrive, ulCat, ulFunction,
  2792.                     pParam, ulPLen, pPLen,
  2793.                     pData,  ulDLen, pDLen);
  2794.    DosReleaseMutexSem(pInst->hIOSem);
  2795.  
  2796.    switch(rc)
  2797.    {
  2798.       case 0L :
  2799.          rc = MCIERR_SUCCESS;
  2800.          break;
  2801.       case 0xFF06 :
  2802.       case 0xFF08 :
  2803.          rc = MCIERR_OUTOFRANGE;
  2804.          break;
  2805.       case 0xFF10 :
  2806.          rc = MCIERR_MEDIA_CHANGED;
  2807.          break;
  2808.       default :
  2809.          rc = MCIERR_DEVICE_NOT_READY;
  2810.    }
  2811.  
  2812.    return(rc);
  2813.  
  2814. }  /* of CallIOCtl() */
  2815.  
  2816.  
  2817.  
  2818.