home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / viscobv6.zip / vac22os2 / ibmcobol / samples / toolkit / mm / cdmcidrv / cdaudpro.c < prev    next >
C/C++ Source or Header  |  1996-11-19  |  96KB  |  2,199 lines

  1. /****************************************************************************/
  2. /*                                                                          */
  3. /* SOURCE FILE NAME:  CDAUDPRO.C                                            */
  4. /*                                                                          */
  5. /* DESCRIPTIVE NAME:  CD AUDIO MCI DRIVER PROCESS COMMANDS                  */
  6. /*                                                                          */
  7. /* COPYRIGHT:  (c) IBM Corp. 1991 - 1993                                    */
  8. /*                                                                          */
  9. /* FUNCTION:  This file contains the hardware independent code that         */
  10. /*            PROCESS commands for the CD Audio MCI Driver uses.            */
  11. /*            The entry point to the DLL is CDAUDIO.C                       */
  12. /*                                                                          */
  13. /* NOTES:  The hardware dependent code is found in file IBMCDROM.C.         */
  14. /*                                                                          */
  15. /* OTHER FUNCTIONS:                                                         */
  16. /*       ProcClose     - process MCI_CLOSE command.                         */
  17. /*       ProcConnector - process MCI_CONNECTOR command.                     */
  18. /*       ProcCue       - process MCI_CUE command.                           */
  19. /*       ProcCuePoint  - process MCI_SET_CUEPOINT command.                  */
  20. /*       ProcGeneral   - process pass through MCI commands.                 */
  21. /*       ProcCaps      - process MCI_GETDEVCAPS command.                    */
  22. /*       ProcInfo      - process MCI_INFO command.                          */
  23. /*       ProcMAudio    - process MCI_MASTERAUDIO command.                   */
  24. /*       ProcOpen      - process MCI_OPEN command.                          */
  25. /*       ProcPause     - process MCI_PAUSE command.                         */
  26. /*       ProcPlay      - process MCI_PLAY command.                          */
  27. /*       ProcPosAdvise - process MCI_SET_POSITION_ADVISE command.           */
  28. /*       ProcRestore   - process MCIDRV_RESTORE command.                    */
  29. /*       ProcResume    - process MCI_RESUME command.                        */
  30. /*       ProcSave      - process MCIDRV_SAVE command.                       */
  31. /*       ProcSeek      - process MCI_SEEK command.                          */
  32. /*       ProcSet       - process MCI_SET command.                           */
  33. /*       ProcSetSync   - process MCI_SET_SYNC_OFFSET command.               */
  34. /*       ProcStatus    - process MCI_STATUS command.                        */
  35. /*       ProcStop      - process MCI_STOP command.                          */
  36. /*       ProcSync      - process MCIDRV_SYNC command.                       */
  37. /*                                                                          */
  38. /*                                                                          */
  39. /****************************************************************************/
  40.  
  41. #define INCL_DOSERRORS
  42. #define INCL_DOSPROCESS
  43. #define INCL_DOSMEMMGR
  44. #define INCL_DOSMODULEMGR
  45. #define INCL_DOSSEMAPHORES
  46. #include <os2.h>
  47. #include <string.h>
  48. #define INCL_MCIOS2
  49. #include <os2me.h>
  50. #include <cdaudos2.h>
  51. #include "cdaudibm.h"
  52. #include <ctype.h>
  53. #include "hhpheap.h"
  54.  
  55. extern PVOID          CDMC_hHeap;
  56.  
  57. /****************************************************************************/
  58. /*                                                                          */
  59. /* SUBROUTINE NAME:  ProcClose                                              */
  60. /*                                                                          */
  61. /* DESCRIPTIVE NAME:  Process Close.                                        */
  62. /*                                                                          */
  63. /* FUNCTION:  Process MCI_CLOSE command.                                    */
  64. /*                                                                          */
  65. /* PARAMETERS:                                                              */
  66. /*      PINST  pInst      -- pointer to instance.                           */
  67. /*      ULONG  *pulParam1 -- flag for this message.                         */
  68. /*      PVOID  pParam2    -- pointer to structure (message dependent).      */
  69. /*      USHORT usUserParm -- User Parameter for mciDriverNotify.            */
  70. /*                                                                          */
  71. /* EXIT CODES:                                                              */
  72. /*      MCIERR_SUCCESS    -- action completed without error.                */
  73. /*                                                                          */
  74. /* NOTES:                                                                   */
  75. /*                                                                          */
  76. /****************************************************************************/
  77.  
  78. ULONG ProcClose(PINST pInst, ULONG *pulParam1, PVOID pParam2, USHORT usUserParm)
  79. {
  80.    ULONG rc, ulP1Temp;
  81.  
  82.    /* send close command to VSD, remove non-VSD flags */
  83.    ulP1Temp = (*pulParam1 & ~(MCI_NOTIFY | MCI_CLOSE_EXIT)) | MCI_WAIT;
  84.    rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_CLOSE, &ulP1Temp, pParam2, 0);
  85.  
  86.    if (!rc)
  87.    {
  88.       pInst->valid[0] = ' ';               //invalidate instance
  89.  
  90.       /* free up memory */
  91.       DosCloseMutexSem(pInst->hInstSem);
  92.  
  93.       if (pInst->ulTrackInfoSize)
  94.          HhpFreeMem(CDMC_hHeap, pInst->pTrackInfo);
  95.  
  96.       /* send notification before destroying device context information */
  97.       if (*pulParam1 & MCI_NOTIFY)
  98.       {
  99.          *pulParam1 ^= MCI_NOTIFY;
  100.          *pulParam1 |= MCI_WAIT;
  101.          mdmDriverNotify(pInst->usDeviceID,
  102.                   ((MCI_GENERIC_PARMS *)pParam2)->hwndCallback, MM_MCINOTIFY,
  103.                   usUserParm, MAKEULONG(MCI_CLOSE, MCI_NOTIFY_SUCCESSFUL));
  104.       }  /* of if notify */
  105.  
  106.       HhpFreeMem(CDMC_hHeap, pInst);
  107.    }  /* of if no error from VSD */
  108.  
  109.    return(rc);
  110.  
  111. }  /* of ProcClose() */
  112.  
  113.  
  114. /****************************************************************************/
  115. /*                                                                          */
  116. /* SUBROUTINE NAME:  ProcConnector                                          */
  117. /*                                                                          */
  118. /* DESCRIPTIVE NAME:  Process Connector.                                    */
  119. /*                                                                          */
  120. /* FUNCTION:  Process MCI_CONNECTOR command.                                */
  121. /*                                                                          */
  122. /* PARAMETERS:                                                              */
  123. /*      PINST pInst    -- pointer to instance.                              */
  124. /*      ULONG ulParam1 -- flag for this message.                            */
  125. /*      PVOID pParam2  -- pointer to structure (message dependent).         */
  126. /*                                                                          */
  127. /* EXIT CODES:                                                              */
  128. /*      MCIERR_SUCCESS    -- action completed without error.                */
  129. /*      MCIERR_DEVICE_NOT_READY  -- No Disc is present.                     */
  130. /*      MCIERR_INSTANCE_INACTIVE -- Instance is suspended.                  */
  131. /*      MCIERR_INVALID_CONNECTOR_INDEX -- Invalid connector specified.      */
  132. /*      MCIERR_INVALID_CONNECTOR_TYPE  -- Invalid connector specified.      */
  133. /*      MCIERR_UNSUPPORTED_CONN_TYPE   -- Unsupported connector specified.  */
  134. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Invalid flag combinations.           */
  135. /*      MCIERR_INVALID_FLAG         -- Unknown or unsupported flag.         */
  136. /*      MCIERR_MISSING_FLAG         -- Flag is needed.                      */
  137. /*      MCIERR_CANNOT_LOAD_DRIVER -- Unable to load VSD.                    */
  138. /*                                                                          */
  139. /* NOTES:                                                                   */
  140. /*                                                                          */
  141. /****************************************************************************/
  142.  
  143. ULONG ProcConnector(PINST pInst, ULONG ulParam1, MCI_CONNECTOR_PARMS *pParam2)
  144. {
  145.    ULONG rc;
  146.    USHORT cnt = 0;
  147.    ULONG ulType, ulIndex;
  148.  
  149.    rc = ValState(pInst);
  150.    if ((rc != MCIERR_INSTANCE_INACTIVE) &&
  151.           (ulParam1 & MCI_DISABLE_CONNECTOR ||
  152.            ulParam1 & MCI_QUERY_CONNECTOR_STATUS))
  153.       rc = MCIERR_SUCCESS;
  154.  
  155.    /********* check flags **********/
  156.    if (!rc)
  157.    {
  158.       /* check exclusive flags */
  159.       if (ulParam1 & MCI_ENABLE_CONNECTOR)
  160.          cnt++;
  161.       if (ulParam1 & MCI_DISABLE_CONNECTOR)
  162.          cnt++;
  163.       if (ulParam1 & MCI_QUERY_CONNECTOR_STATUS)
  164.          cnt++;
  165.  
  166.       /* validate flags */
  167.       if (!cnt)
  168.          rc = MCIERR_MISSING_FLAG;
  169.       else if (cnt > 1)
  170.          rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  171.       else
  172.       {
  173.          ulType = ulParam1 & WAIT_NOTIFY_MASK;
  174.          if (ulType & (0xFFFFFFFF ^
  175.                     (MCI_ENABLE_CONNECTOR | MCI_DISABLE_CONNECTOR |
  176.                      MCI_QUERY_CONNECTOR_STATUS |
  177.                      MCI_CONNECTOR_TYPE | MCI_CONNECTOR_INDEX)))
  178.             rc = MCIERR_INVALID_FLAG;
  179.       }
  180.    }   /* of if no error */
  181.  
  182.    /********* get connector index **********/
  183.    if (!rc)
  184.    {
  185.       if (ulType & MCI_CONNECTOR_INDEX)
  186.          ulIndex = pParam2->ulConnectorIndex;
  187.       else
  188.          ulIndex = 1;                  // set default
  189.  
  190.       /* get type of channel */
  191.       /* This example assumes that there is only one connector, */
  192.       /* the internal DAC or headphone.                         */
  193.       if (ulParam1 & MCI_CONNECTOR_TYPE)
  194.          if (pParam2->ulConnectorType == MCI_HEADPHONES_CONNECTOR)
  195.          {
  196.             if (ulIndex != 1)
  197.                rc = MCIERR_INVALID_CONNECTOR_INDEX;
  198.          }
  199.          else
  200.             if (pParam2->ulConnectorType > MCI_UNIVERSAL_CONNECTOR)
  201.                rc = MCIERR_INVALID_CONNECTOR_TYPE;
  202.             else
  203.                rc = MCIERR_UNSUPPORTED_CONN_TYPE;
  204.       else             /* no type is declared, use absolute numbers */
  205.          if (ulIndex != 1)
  206.             rc = MCIERR_INVALID_CONNECTOR_INDEX;
  207.    }  /* of if no error */
  208.  
  209.    /******  process request  ********/
  210.    if (!rc)
  211.    {
  212.       if (ulType & MCI_QUERY_CONNECTOR_STATUS)
  213.       {
  214.          if (pInst->ulMode & CDMC_INTDAC)
  215.             pParam2->ulReturn = MCI_TRUE;
  216.          else
  217.             pParam2->ulReturn = MCI_FALSE;
  218.          ULONG_HIWD(rc) = MCI_TRUE_FALSE_RETURN;   // Adjust rc type
  219.       }
  220.       else
  221.          rc = SetConnector(pInst, ulType);
  222.    }  /* of if no error */
  223.  
  224.    return(rc);
  225.  
  226. }  /* of ProcConnector() */
  227.  
  228.  
  229.  
  230. /****************************************************************************/
  231. /*                                                                          */
  232. /* SUBROUTINE NAME:  ProcCue                                                */
  233. /*                                                                          */
  234. /* DESCRIPTIVE NAME:  Process Cue.                                          */
  235. /*                                                                          */
  236. /* FUNCTION:  Process MCI_CUE command.                                      */
  237. /*                                                                          */
  238. /* PARAMETERS:                                                              */
  239. /*      PINST pInst    -- pointer to instance.                              */
  240. /*      ULONG ulParam1 -- flag for this message.                            */
  241. /*                                                                          */
  242. /* EXIT CODES:                                                              */
  243. /*      MCIERR_SUCCESS    -- action completed without error.                */
  244. /*      MCIERR_DEVICE_NOT_READY   -- No Disc is present.                    */
  245. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  246. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  247. /*      MCIERR_PARAM_OVERFLOW     -- Invalid PARMS pointer.                 */
  248. /*      MCIERR_INVALID_FLAG       -- Unknown flag.                          */
  249. /*      MCIERR_UNSUPPORTED_FLAG   -- Flag not supported by this MCD.        */
  250. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Invalid flag combinations.           */
  251. /*                                                                          */
  252. /* NOTES:                                                                   */
  253. /*                                                                          */
  254. /****************************************************************************/
  255.  
  256. ULONG ProcCue(PINST pInst, ULONG ulParam1)
  257. {
  258.    ULONG rc, ulFlags;
  259.  
  260.    rc = ValState(pInst);
  261.  
  262.    if (!rc)
  263.    {
  264.       /* The CD Audio MCI Driver does not support MCI_RECORD */
  265.  
  266.       ulFlags = ulParam1 & WAIT_NOTIFY_MASK;
  267.  
  268.       switch (ulFlags)
  269.       {
  270.          case MCI_CUE_OUTPUT :
  271.             /* call VSD (Vendor Specific Driver), *
  272.              * the hardware specific MCI Driver   */
  273.             pInst->usStatus = STOPPED;
  274.             rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_CUE, 0L, 0L, 0);
  275.             if (rc)
  276.                rc = vsdResponse(pInst, rc);
  277.  
  278.             break;
  279.          case MCI_CUE_OUTPUT | MCI_CUE_INPUT :
  280.             rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  281.             break;
  282.          case MCI_CUE_INPUT :       // CD MCI Driver doesn't support MCI_RECORD
  283.             rc = MCIERR_UNSUPPORTED_FLAG;
  284.             break;
  285.          case 0 :
  286.             rc = MCIERR_MISSING_FLAG;
  287.             break;
  288.          default :
  289.             rc = MCIERR_INVALID_FLAG;
  290.  
  291.       }  /* of switch */
  292.    }  /* if drive is ready for command */
  293.  
  294.    return(rc);
  295.  
  296. }  /* of ProcCue() */
  297.  
  298.  
  299. /****************************************************************************/
  300. /*                                                                          */
  301. /* SUBROUTINE NAME:  ProcCuePoint                                           */
  302. /*                                                                          */
  303. /* DESCRIPTIVE NAME:  Process Cue Point                                     */
  304. /*                                                                          */
  305. /* FUNCTION:  Process MCI_SET_CUEPOINT command.                             */
  306. /*                                                                          */
  307. /* PARAMETERS:                                                              */
  308. /*      PINST pInst    -- pointer to instance.                              */
  309. /*      ULONG ulParam1 -- flag for this message.                            */
  310. /*      PVOID pParam2  -- pointer to structure (message dependent).         */
  311. /*                                                                          */
  312. /* EXIT CODES:                                                              */
  313. /*      MCIERR_SUCCESS    -- action completed without error.                */
  314. /*      MCIERR_OUTOFRANGE -- event does not exist.                          */
  315. /*      MCIERR_DEVICE_NOT_READY   -- No Disc is present.                    */
  316. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  317. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  318. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Invalid flag combinations.           */
  319. /*      MCIERR_INVALID_FLAG         -- Unknown or unsupported flag.         */
  320. /*      MCIERR_INVALID_CUEPOINT       --  unable to locate event.           */
  321. /*      MCIERR_CUEPOINT_LIMIT_REACHED --  no more room to add events.       */
  322. /*      MCIERR_DUPLICATE_CUEPOINT     --  duplicate cuepoint.               */
  323. /*      MCIERR_INVALID_CALLBACK_HANDLE -- invalid call back handle.         */
  324. /*                                                                          */
  325. /* NOTES:                                                                   */
  326. /*                                                                          */
  327. /****************************************************************************/
  328.  
  329. ULONG ProcCuePoint(PINST pInst, ULONG ulParam1, MCI_CUEPOINT_PARMS *pParam2)
  330. {
  331.    ULONG rc, ulTime, ulFlags;
  332.    MCI_CUEPOINT_PARMS recCuePoint;
  333.    MCI_STATUS_PARMS recStatus;
  334.    int i;
  335.    PID pid;
  336.    TID tid;
  337.  
  338.    rc = ValState(pInst);
  339.  
  340.    /* Make sure disc is present before you rely on cache */
  341.    if (!rc)
  342.    {
  343.       recStatus.ulItem = MCI_STATUS_POSITION;
  344.       ulFlags = MCI_STATUS_ITEM | MCI_WAIT;
  345.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STATUS,
  346.                              &ulFlags, &recStatus, 0);
  347.       if (ULONG_LOWD(rc))
  348.          rc = vsdResponse(pInst, rc);
  349.    }  /* of if no error */
  350.  
  351.    /* if flag doesn't require an active/ready state, process it */
  352.    if (!(ulParam1 & MCI_SET_CUEPOINT_ON) && rc != MCIERR_INSTANCE_INACTIVE)
  353.       rc = MCIERR_SUCCESS;
  354.  
  355.    /* validate callback handle */
  356.    if (!rc && !(ulParam1 & MCI_NOTIFY))
  357.       if (!WinQueryWindowProcess(pParam2->hwndCallback, &pid, &tid))
  358.          rc = MCIERR_INVALID_CALLBACK_HANDLE;
  359.  
  360.    if (!ULONG_LOWD(rc))
  361.    {
  362.       ulParam1 &= WAIT_NOTIFY_MASK;
  363.       memcpy(&recCuePoint, pParam2, sizeof(MCI_CUEPOINT_PARMS));
  364.  
  365.       switch(ulParam1)
  366.       {
  367.          case MCI_SET_CUEPOINT_ON :
  368.             rc = SetCuePoint(pInst, &recCuePoint);
  369.             break;
  370.          case MCI_SET_CUEPOINT_OFF :
  371.             /* get time */
  372.             ulTime = GetTimeAddr(pInst, pParam2->ulCuepoint, TRUE);
  373.             if (ulTime == (ULONG) -1L)
  374.                rc = MCIERR_OUTOFRANGE;         // invalid track number
  375.             else
  376.             {
  377.                ulTime += pInst->ulOffset;
  378.  
  379.                /* find requested cuepoint and disable */
  380.                for (i=0; i < CDMCD_CUEPOINT_MAX; i++)
  381.                   if (pInst->arrCuePoint[i] == ulTime)
  382.                      break;
  383.  
  384.                if (i == CDMCD_CUEPOINT_MAX)
  385.                   rc = MCIERR_INVALID_CUEPOINT;
  386.                else
  387.                {
  388.                   pInst->arrCuePoint[i] = (ULONG) -1L;
  389.                   recCuePoint.ulCuepoint = ulTime;
  390.                   ulFlags = MCI_SET_CUEPOINT_OFF | MCI_WAIT;
  391.                   rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_SET_CUEPOINT,
  392.                                          &ulFlags, &recCuePoint, 0);
  393.  
  394.                }  /* of else found cuepoint */
  395.             }  /* of else no error, find cuepoint */
  396.             break;
  397.          case MCI_SET_CUEPOINT_ON | MCI_SET_CUEPOINT_OFF :
  398.             rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  399.             break;
  400.          case 0 :
  401.             rc = MCIERR_MISSING_FLAG;
  402.             break;
  403.          default :
  404.             rc = MCIERR_INVALID_FLAG;
  405.  
  406.       }  /* of switch */
  407.    }  /* of if no error */
  408.  
  409.    if (rc)
  410.       rc = vsdResponse(pInst, rc);
  411.  
  412.    return(rc);
  413.  
  414. }  /* of ProcCuePoint() */
  415.  
  416.  
  417. /****************************************************************************/
  418. /*                                                                          */
  419. /* SUBROUTINE NAME:  ProcGeneral                                            */
  420. /*                                                                          */
  421. /* DESCRIPTIVE NAME:  Process General commands.                             */
  422. /*                                                                          */
  423. /* FUNCTION:  Process any MCI command messages that the MCI does not        */
  424. /*            handle but are completely handled by the hardware specific    */
  425. /*            MCI Driver.                                                   */
  426. /*                                                                          */
  427. /* PARAMETERS:                                                              */
  428. /*      PINST  pInst      -- pointer to instance.                           */
  429. /*      USHORT usMessage  -- requested action to be performed.              */
  430. /*      ULONG  *pulParam1 -- flag for this message.                         */
  431. /*      PVOID  pParam2    -- pointer to structure (message dependent).      */
  432. /*      USHORT usUserParm -- User Parameter for mciDriverNotify.            */
  433. /*                                                                          */
  434. /* EXIT CODES:                                                              */
  435. /*      MCIERR_SUCCESS    -- action completed without error.                */
  436. /*      MCIERR_DEVICE_NOT_READY   -- No Disc is present.                    */
  437. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  438. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  439. /*                                                                          */
  440. /* NOTES:                                                                   */
  441. /*                                                                          */
  442. /****************************************************************************/
  443.  
  444. ULONG ProcGeneral(PINST pInst, USHORT usMessage, ULONG *pulParam1,
  445.                   PVOID pParam2, USHORT usUserParm)
  446. {
  447.    ULONG rc = MCIERR_SUCCESS;
  448.    ULONG ulP1Temp;
  449.    PVOID pTemp;
  450.  
  451.    /* validate pointers within the pParam2 structure, if known */
  452.    switch (usMessage)
  453.    {
  454.       case MCI_ESCAPE :
  455.          /* check string pointer for validity */
  456.          rc = ValPointer(((MCI_ESCAPE_PARMS *)pParam2)->pszCommand,
  457.                         sizeof(BYTE));
  458.          break;
  459.       case MCI_GETTOC :
  460.          /* validate TOC buffer pointer for existence & space for 1 entry */
  461.          if (ValPointer(((MCI_TOC_PARMS *)pParam2)->pBuf,
  462.                           sizeof(MCI_TOC_REC)))
  463.             ((MCI_TOC_PARMS *)pParam2)->ulBufSize = 0L;   //invalid pointer
  464.          ulP1Temp   = *pulParam1;
  465.          *pulParam1 = (*pulParam1 & WAIT_NOTIFY_MASK) | MCI_WAIT;
  466.          break;
  467.       case MCI_LOAD :
  468.          pTemp = ((MCI_LOAD_PARMS *)pParam2)->pszElementName;
  469.          if (pTemp != NULL)
  470.             rc = ValPointer(pTemp, sizeof(BYTE));
  471.          break;
  472.    }  /* of switch */
  473.  
  474.    /* validate state for message */
  475.    if (!rc)
  476.    {
  477.       rc = ValState(pInst);
  478.       /* protect GET TOC, let others slip by */
  479.       if (rc == MCIERR_DEVICE_NOT_READY && usMessage != MCI_GETTOC)
  480.          rc = MCIERR_SUCCESS;
  481.    }
  482.  
  483.    if (!rc)
  484.    {
  485.       /* call VSD (Vendor Specific Driver), the hardware specific MCI Driver */
  486.       rc = pInst->pMCIDriver(pInst->hHWMCID, usMessage, pulParam1,
  487.                              pParam2, usUserParm);
  488.       if (ULONG_LOWD(rc))
  489.          rc = vsdResponse(pInst, rc);
  490.  
  491.    }  /* if drive is ready for command */
  492.  
  493.    if (usMessage == MCI_GETTOC)
  494.       *pulParam1 = ulP1Temp;      // Restore original flags
  495.  
  496.    return(rc);
  497.  
  498. }  /* of ProcGeneral() */
  499.  
  500.  
  501. /****************************************************************************/
  502. /*                                                                          */
  503. /* SUBROUTINE NAME:  ProcCaps                                               */
  504. /*                                                                          */
  505. /* DESCRIPTIVE NAME:  Process Capabilities                                  */
  506. /*                                                                          */
  507. /* FUNCTION:  Process MCI_GETDEVCAPS command.                               */
  508. /*                                                                          */
  509. /* PARAMETERS:                                                              */
  510. /*      PINST pInst    -- pointer to instance.                              */
  511. /*      ULONG ulParam1 -- flag for this message.                            */
  512. /*      PVOID pParam2  -- pointer to structure (message dependent).         */
  513. /*                                                                          */
  514. /* EXIT CODES:                                                              */
  515. /*      MCIERR_SUCCESS    -- action completed without error.                */
  516. /*      MCIERR_DEVICE_NOT_READY     -- No Disc is present.                  */
  517. /*      MCIERR_INSTANCE_INACTIVE    -- Instance is suspended.               */
  518. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- invalid combinations.                */
  519. /*      MCIERR_PARAM_OVERFLOW       -- Invalid PARMS pointer.               */
  520. /*      MCIERR_INVALID_FLAG         -- No message value.                    */
  521. /*      MCIERR_INVALID_ITEM_FLAG    -- Invalid capability item.             */
  522. /*                                                                          */
  523. /* NOTES:  This function returns the drives capabilities, not those of the  */
  524. /*         component nor of the instance.                                   */
  525. /*                                                                          */
  526. /****************************************************************************/
  527.  
  528. ULONG ProcCaps(PINST pInst, ULONG ulParam1, MCI_GETDEVCAPS_PARMS *pParam2)
  529. {
  530.    ULONG rc;
  531.  
  532.    ulParam1 &= WAIT_NOTIFY_MASK;
  533.    rc = MCIERR_SUCCESS;       /* assume the best */
  534.    ULONG_HIWD(rc) = MCI_TRUE_FALSE_RETURN;  //Most will be T/F, adjust later
  535.  
  536.    switch(ulParam1)
  537.    {
  538.       case MCI_GETDEVCAPS_MESSAGE :
  539.          switch(pParam2->usMessage)
  540.          {  /* check empty case */
  541.             case 0 :
  542.                pParam2->ulReturn = MCI_FALSE;
  543.                rc = MCIERR_INVALID_FLAG;
  544.                break;
  545.             /* return true on those commands that the MCI Driver Does */
  546.             case MCI_CLOSE :                  case MCI_CONNECTOR :
  547.             case MCI_GETDEVCAPS :             case MCI_INFO :
  548.             case MCI_MASTERAUDIO :            case MCI_OPEN :
  549.             case MCI_SET :                    case MCI_SET_SYNC_OFFSET :
  550.             case MCI_STATUS :
  551.                pParam2->ulReturn = MCI_TRUE;
  552.                break;
  553.             /* return false on commands that the MCI Driver cannot do */
  554.             case MCI_RECORD :
  555.                pParam2->ulReturn = MCI_FALSE;
  556.                break;
  557.             /* return true on commands MCD does when streaming */
  558.             case MCI_CUE :                    case MCI_PLAY :
  559.             case MCI_PAUSE :                  case MCI_RESUME :
  560.             case MCI_SEEK :                   case MCI_SET_CUEPOINT :
  561.             case MCI_SET_POSITION_ADVISE :    case MCI_STOP :
  562.                if (pInst->ulMode & CDMC_CAN_STREAM)
  563.                {
  564.                   pParam2->ulReturn = MCI_TRUE;
  565.                   break;
  566.                }
  567.                /* else drop down to default and ask VSD */
  568.             default :       /* ask VSD */
  569.                ulParam1 |= MCI_WAIT;
  570.                rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_GETDEVCAPS,
  571.                                       &ulParam1, pParam2, 0);
  572.                if (!ULONG_LOWD(rc))
  573.                   ULONG_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  574.          }  /* of message switch */
  575.          break;
  576.       case MCI_GETDEVCAPS_ITEM :
  577.          switch(pParam2->ulItem)
  578.          {  /* check empty case */
  579.             case 0 :
  580.                pParam2->ulReturn = MCI_FALSE;
  581.                rc = MCIERR_INVALID_ITEM_FLAG;
  582.                break;
  583.             /* list the always TRUE */
  584.             case MCI_GETDEVCAPS_CAN_PLAY :
  585.                   pParam2->ulReturn = MCI_TRUE;
  586.                break;
  587.             /* list the always FALSE */
  588.             case MCI_GETDEVCAPS_CAN_RECORD :
  589.             case MCI_GETDEVCAPS_CAN_RECORD_INSERT :
  590.             case MCI_GETDEVCAPS_CAN_SAVE :
  591.             case MCI_GETDEVCAPS_USES_FILES :
  592.             case MCI_GETDEVCAPS_HAS_VIDEO :
  593.                   pParam2->ulReturn = MCI_FALSE;
  594.                break;
  595.             /* list the conditionals */
  596.             case MCI_GETDEVCAPS_CAN_EJECT :
  597.                if (pInst->usCaps & CDVSD_CAP_CAN_EJECT)
  598.                   pParam2->ulReturn = MCI_TRUE;
  599.                else
  600.                   pParam2->ulReturn = MCI_FALSE;
  601.                break;
  602.             case MCI_GETDEVCAPS_HAS_AUDIO :
  603.                if (pInst->usCaps & CDVSD_CAP_HAS_AUDIO)
  604.                   pParam2->ulReturn = MCI_TRUE;
  605.                else
  606.                   pParam2->ulReturn = MCI_FALSE;
  607.                break;
  608.             case MCI_GETDEVCAPS_DEVICE_TYPE :
  609.                pParam2->ulReturn = MCI_DEVTYPE_CD_AUDIO;
  610.                ULONG_HIWD(rc) = MCI_DEVICENAME_RETURN;
  611.                break;
  612.             case MCI_GETDEVCAPS_CAN_LOCKEJECT :
  613.                if (pInst->usCaps & CDVSD_CAP_CAN_LOCK)
  614.                   pParam2->ulReturn = MCI_TRUE;
  615.                else
  616.                   pParam2->ulReturn = MCI_FALSE;
  617.                break;
  618.             case MCI_GETDEVCAPS_CAN_PROCESS_INTERNAL :
  619.                if (pInst->usCaps & CDVSD_CAP_HAS_DAC)
  620.                   pParam2->ulReturn = MCI_TRUE;
  621.                else
  622.                   pParam2->ulReturn = MCI_FALSE;
  623.                break;
  624.             case MCI_GETDEVCAPS_CAN_SETVOLUME :
  625.                if (pInst->usCaps & CDVSD_CAP_CAN_VOLUME)
  626.                   pParam2->ulReturn = MCI_TRUE;
  627.                else
  628.                   pParam2->ulReturn = MCI_FALSE;
  629.                break;
  630.             case MCI_GETDEVCAPS_CAN_STREAM :
  631.                if (pInst->usCaps & CDVSD_CAP_CAN_STREAM)
  632.                   pParam2->ulReturn = MCI_TRUE;
  633.                else
  634.                   pParam2->ulReturn = MCI_FALSE;
  635.                break;
  636.             case MCI_GETDEVCAPS_PREROLL_TYPE :
  637.                pParam2->ulReturn = pInst->ulPrerollType;
  638.                ULONG_HIWD(rc) = MCI_INTEGER_RETURNED;
  639.                break;
  640.             case MCI_GETDEVCAPS_PREROLL_TIME :
  641.                pParam2->ulReturn = pInst->ulPrerollTime;
  642.                ULONG_HIWD(rc) = MCI_INTEGER_RETURNED;
  643.                break;
  644.             default :               // unknown flag, call VSD
  645.                ulParam1 |= MCI_WAIT;
  646.                rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_GETDEVCAPS,
  647.                                       &ulParam1, pParam2, 0);
  648.  
  649.          }  /* of item switch */
  650.          break;
  651.       case MCI_GETDEVCAPS_MESSAGE | MCI_GETDEVCAPS_ITEM :
  652.          rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  653.          break;
  654.       case 0 :
  655.          rc = MCIERR_MISSING_FLAG;
  656.          break;
  657.       default :               // unknown flag, call VSD
  658.          ulParam1 |= MCI_WAIT;
  659.          rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_GETDEVCAPS,
  660.                                 &ulParam1, pParam2, 0);
  661.  
  662.    }  /* of ulParam1 switch */
  663.  
  664.    return(rc);
  665.  
  666. }  /* of ProcCaps() */
  667.  
  668.  
  669. /****************************************************************************/
  670. /*                                                                          */
  671. /* SUBROUTINE NAME:  ProcInfo                                               */
  672. /*                                                                          */
  673. /* DESCRIPTIVE NAME:  Process device Information.                           */
  674. /*                                                                          */
  675. /* FUNCTION:  Process MCI_INFO command.                                     */
  676. /*                                                                          */
  677. /* PARAMETERS:                                                              */
  678. /*      PINST pInst    -- pointer to instance.                              */
  679. /*      ULONG ulParam1 -- flag for this message.                            */
  680. /*      PVOID pParam2  -- pointer to structure (message dependent).         */
  681. /*                                                                          */
  682. /* EXIT CODES:                                                              */
  683. /*      MCIERR_SUCCESS    -- action completed without error.                */
  684. /*      MCIERR_DEVICE_NOT_READY   -- No Disc is present.                    */
  685. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  686. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  687. /*      MCIERR_INVALID_BUFFER     -- Buffer size was too small.             */
  688. /*      MCIERR_PARAM_OVERFLOW     -- Invalid PARMS pointer.                 */
  689. /*                                                                          */
  690. /* NOTES:                                                                   */
  691. /*                                                                          */
  692. /****************************************************************************/
  693.  
  694. ULONG ProcInfo(PINST pInst, ULONG ulParam1, MCI_INFO_PARMS *pParam2)
  695. {
  696.    ULONG rc, ulFlags;
  697.    USHORT len=UPC_SIZE+1;
  698.    BYTE  buf[UPC_SIZE+1], cnt = 0;
  699.    MCI_CD_ID *ptr;
  700.    MCI_STATUS_PARMS recStatus;
  701.  
  702.    /* validate buffer pointer */
  703.    if (ValPointer(pParam2->pszReturn, sizeof(BYTE)))
  704.       pParam2->ulRetSize = 0L;        //invalid pointer
  705.  
  706.    /* validate flags */
  707.    rc = MCIERR_SUCCESS;
  708.    ulParam1 &= WAIT_NOTIFY_MASK;
  709.  
  710.    if (ulParam1 & MCI_CD_INFO_ID)
  711.       cnt++;
  712.    if (ulParam1 & MCI_CD_INFO_UPC)
  713.       cnt++;
  714.    if (ulParam1 & MCI_INFO_PRODUCT)
  715.       cnt++;
  716.    if (cnt > 1)
  717.       rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  718.  
  719.    if (!rc)
  720.    {
  721.       /* If it is something that can be handled internally,  */
  722.       /*    find the minimum length to return                */
  723.       if (ulParam1 == MCI_CD_INFO_ID || ulParam1 == MCI_CD_INFO_UPC)
  724.       {
  725.          if (pInst->usStatus < REGDISC)
  726.             rc = MCIERR_DEVICE_NOT_READY;
  727.  
  728.          /* Make sure disc is present before you rely on cache */
  729.          else
  730.          {
  731.             recStatus.ulItem = MCI_STATUS_POSITION;
  732.             ulFlags = MCI_STATUS_ITEM | MCI_WAIT;
  733.             rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STATUS,
  734.                                    &ulFlags, &recStatus, 0);
  735.             if (ULONG_LOWD(rc))
  736.                rc = vsdResponse(pInst, rc);
  737.          }  /* of else disc was registered */
  738.  
  739.          if (pParam2->ulRetSize < UPC_SIZE+1)
  740.             len = (USHORT) pParam2->ulRetSize;
  741.          else
  742.             len = UPC_SIZE+1;
  743.       }  /* of if internal process flag */
  744.    }  /* of if no error */
  745.  
  746.    if (!rc)
  747.       /* process flag */
  748.       switch(ulParam1)
  749.       {
  750.          case MCI_CD_INFO_ID :
  751.             /* formulate in the buffer */
  752.             ptr = (MCI_CD_ID *)buf;
  753.             ptr->Mode = 1;                                   // ID = 1
  754.             ptr->usTrack1 = (USHORT) pInst->recTrack.TrackRecArr->ulStartAddr;
  755.             ptr->NumTracks = (BYTE) (pInst->recDisc.HighestTrackNum -
  756.                              pInst->recDisc.LowestTrackNum + 1);
  757.                 /* lead-out track is end address for last track */
  758.             ptr->ulLeadOut = (pInst->recTrack.TrackRecArr +
  759.                              (ptr->NumTracks - 1))->ulEndAddr;
  760.  
  761.             if (len)
  762.                memcpy(pParam2->pszReturn, buf, len);
  763.  
  764.             if (len == UPC_SIZE+1)
  765.                rc = MCIERR_SUCCESS;
  766.             else
  767.                rc = MCIERR_INVALID_BUFFER;
  768.             pParam2->ulRetSize = UPC_SIZE+1;
  769.  
  770.             break;
  771.          case MCI_CD_INFO_UPC :
  772.             if (len)   //if zero then invalid buffer
  773.             {
  774.                buf[0] = 0;
  775.                memcpy(buf+1, pInst->recDisc.UPC, UPC_SIZE);
  776.                memcpy(pParam2->pszReturn, buf, len);
  777.             }
  778.  
  779.             if (len == UPC_SIZE+1)
  780.                rc = MCIERR_SUCCESS;
  781.             else
  782.                rc = MCIERR_INVALID_BUFFER;
  783.             pParam2->ulRetSize = UPC_SIZE+1;
  784.             break;
  785.          case 0 :
  786.             rc = MCIERR_MISSING_FLAG;
  787.             break;
  788.          default :
  789.             ulParam1 |= MCI_WAIT;
  790.             rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_INFO, &ulParam1,
  791.                                    pParam2, 0);
  792.             if (ULONG_LOWD(rc))
  793.                rc = vsdResponse(pInst, rc);
  794.  
  795.       }  /* of switch */
  796.  
  797.    return(rc);
  798.  
  799. }  /* of ProcInfo() */
  800.  
  801.  
  802. /****************************************************************************/
  803. /*                                                                          */
  804. /* SUBROUTINE NAME:  ProcMAudio                                             */
  805. /*                                                                          */
  806. /* DESCRIPTIVE NAME:  Process Master Audio                                  */
  807. /*                                                                          */
  808. /* FUNCTION:  Process MCI_MASTERAUDIO command.                              */
  809. /*                                                                          */
  810. /* PARAMETERS:                                                              */
  811. /*      PINST pInst    -- pointer to instance.                              */
  812. /*      ULONG ulParam1 -- flag for this message.                            */
  813. /*      MCI_MASTERAUDIO_PARMS *pParam2 -- pointer to structure.             */
  814. /*                                                                          */
  815. /* EXIT CODES:                                                              */
  816. /*      MCIERR_SUCCESS    -- action completed without error.                */
  817. /*      MCIERR_DEVICE_NOT_READY   -- No Disc is present.                    */
  818. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  819. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  820. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Flags not compatible.                */
  821. /*                                                                          */
  822. /* NOTES:                                                                   */
  823. /*                                                                          */
  824. /****************************************************************************/
  825.  
  826. ULONG ProcMAudio(PINST pInst, ULONG ulParam1, MCI_MASTERAUDIO_PARMS *pParam2)
  827. {
  828.    ULONG rc = MCIERR_SUCCESS;
  829.    ULONG ulSetParam1;
  830.    ULONG ulType;
  831.    MCI_SET_PARMS recSet;
  832.  
  833.    /* eliminate general reserved flags */
  834.    ulType = ulParam1 & WAIT_NOTIFY_MASK;
  835.  
  836.    switch(ulType)
  837.    {
  838.       case MCI_MASTERVOL:
  839.          if (pParam2->ulMasterVolume > 100)
  840.             pInst->ulMasterVolume = 100;
  841.          else
  842.             pInst->ulMasterVolume = pParam2->ulMasterVolume;
  843.          break;
  844.       case MCI_SPEAKERS | MCI_ON:
  845.          pInst->ulMode |= CDMC_SPEAKER;
  846.          break;
  847.       case MCI_SPEAKERS | MCI_OFF:
  848.          if (pInst->ulMode & CDMC_SPEAKER)
  849.             pInst->ulMode ^= CDMC_SPEAKER;
  850.          break;
  851.       case MCI_HEADPHONES | MCI_ON:
  852.          pInst->ulMode |= CDMC_HEADPHONE;
  853.          break;
  854.       case MCI_HEADPHONES | MCI_OFF:
  855.          if (pInst->ulMode & CDMC_HEADPHONE)
  856.             pInst->ulMode ^= CDMC_HEADPHONE;
  857.          break;
  858.       default :
  859.          if (ulType & MCI_ON && ulType & MCI_OFF)
  860.             rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  861.          else
  862.             rc = MCIERR_INVALID_FLAG;
  863.    }  /* of switch */
  864.  
  865.    /* update volume settings if needed */
  866.    if (!rc)
  867.    {
  868.       rc = ValState(pInst);
  869.       if (!rc || rc == MCIERR_INVALID_MEDIA_TYPE)
  870.       {
  871.          /* fill in Set record structure so that ProcSet() will respond */
  872.          recSet.ulAudio = MCI_SET_AUDIO_LEFT;
  873.          recSet.ulLevel = (ULONG) VOL_LEFT(pInst->ulLevel);
  874.          recSet.ulOver  = 0L;
  875.          ulSetParam1 = MCI_SET_AUDIO | MCI_SET_VOLUME | MCI_WAIT;
  876.  
  877.          ProcSet(pInst, &ulSetParam1, &recSet);
  878.  
  879.       }  /* is state is such that volume can be adjusted */
  880.       else
  881.          rc = MCIERR_SUCCESS;      // okay if not setting hardware
  882.    }  /* no error from validating flags */
  883.  
  884.    return(rc);
  885.  
  886. }  /* of ProcMAudio() */
  887.  
  888.  
  889. /****************************************************************************/
  890. /*                                                                          */
  891. /* SUBROUTINE NAME:  ProcOpen                                               */
  892. /*                                                                          */
  893. /* DESCRIPTIVE NAME:  Process Open.                                         */
  894. /*                                                                          */
  895. /* FUNCTION:  Process MCI_OPEN command.                                     */
  896. /*                                                                          */
  897. /* PARAMETERS:                                                              */
  898. /*      ULONG  *pulParam1 -- flag for this message.                         */
  899. /*      PVOID  pParam2    -- pointer to structure (message dependent).      */
  900. /*      USHORT usUserParm -- user defined parameter.                        */
  901. /*                                                                          */
  902. /* EXIT CODES:                                                              */
  903. /*      MCIERR_SUCCESS    -- Action completed without error.                */
  904. /*      MCIERR_OUTOFRANGE -- Cannot stream on stream only hardware.         */
  905. /*      MCIERR_INI_FILE   -- Corrupted INI file, drive is not CD-ROM drive. */
  906. /*      MCIERR_OUT_OF_MEMORY -- Could not create instance or semaphore.     */
  907. /*      MCIERR_INVALID_DEVICE_NAME -- Illegal drive name.                   */
  908. /*      MCIERR_PARAM_OVERFLOW      -- Invalid PARMS pointer.                */
  909. /*      MCIERR_CANNOT_LOAD_DRIVER  -- Unable to load VSD.                   */
  910. /*      MCIERR_INVALID_FLAG  -- Flag not supported by the VSD.              */
  911. /*      MCIERR_DEVICE_LOCKED -- CD-ROM drive, previously opened exclusively.*/
  912. /*                                                                          */
  913. /* NOTES:                                                                   */
  914. /*                                                                          */
  915. /****************************************************************************/
  916.  
  917. ULONG ProcOpen(ULONG *pulParam1, MMDRV_OPEN_PARMS *pParam2, USHORT usUserParm)
  918. {
  919.    ULONG rc;
  920.    ULONG rsp, ulDevParmLen, usNotify = FALSE;
  921.    PINST pInst = NULL;
  922.    CHAR  buf[LOAD_MOD_BUF_LEN];
  923.    CHAR  *pMCDToken, *pDummy, CDDrive;
  924.    PVOID pMCDParm;
  925.    int i;
  926.  
  927.    /* validate pointers */
  928.    rc = ValPointer(pParam2->pDevParm, sizeof(BYTE));
  929.  
  930.    /* MCI_OPEN is from MDM, accept all flags as valid */
  931.  
  932.    /* get memory and pointer to instance structure */
  933.    if (!rc)
  934.    {
  935.       pInst = HhpAllocMem(CDMC_hHeap, sizeof(struct instance_state));
  936.  
  937.       /* create semaphore so only one command will access instance table */
  938.       if (pInst == NULL)
  939.          rc = MCIERR_OUT_OF_MEMORY;
  940.       else
  941.          if (DosCreateMutexSem((PSZ) NULL, &pInst->hInstSem, 0L, FALSE))
  942.             rc = MCIERR_OUT_OF_MEMORY;
  943.    }  /* of if no error to get memory */
  944.  
  945.    if (!rc)
  946.    {  /* instance entry created */
  947.       pInst->usDeviceID = pParam2->usDeviceID;
  948.       pInst->ulMasterVolume = (ULONG) -1L;
  949.       pInst->usStatus = UNLOADED;
  950.       /* set all fields in ulMode */
  951.       pInst->ulMode = CDMC_MMTIME | CDMC_ALL_CH;
  952.       pInst->hHWMCID = NULL;
  953.       pInst->ulOffset = 0L;
  954.       pInst->ulLevel = 0x00640064;                   /* set to 100% volume */
  955.       pInst->ulTrackInfoSize = 0L;
  956.       pInst->usDeviceOrd = pParam2->usDeviceOrd;
  957.       pInst->recDisc.DiscID.Mode = (BYTE) -1;     /* used as first time flag */
  958.       CDDrive = 0;
  959.       memcpy(pInst->valid, "CDDA", VALLEN);
  960.  
  961.       /* process shareable flag */
  962.       if (*pulParam1 & MCI_OPEN_SHAREABLE)
  963.       {
  964.          pInst->ulMode |= CDMC_SHAREABLE;
  965.          *pulParam1 ^= MCI_OPEN_SHAREABLE;       // remove non-VSD flag
  966.       }
  967.  
  968.       /* init cuepoint array */
  969.       for (i=0; i < CDMCD_CUEPOINT_MAX; i++)
  970.          pInst->arrCuePoint[i] = (ULONG) -1L;   //clear flag
  971.  
  972.       /* Get and Validate drive letter */
  973.       /* copy string so that it doesn't get disturb for the VSD */
  974.       ulDevParmLen = strlen(pParam2->pDevParm) + 2;
  975.       pMCDParm = (PSZ)   HhpAllocMem(CDMC_hHeap, ulDevParmLen);
  976.       strcpy((CHAR *)pMCDParm, pParam2->pDevParm);
  977.       parse_DevParm((CHAR *)pMCDParm, &pMCDToken, &pDummy);
  978.       if (*(pMCDToken + 1) == '\0' || *(pMCDToken + 1) == ':')
  979.          CDDrive = *pMCDToken;
  980.       HhpFreeMem(CDMC_hHeap, pMCDParm);
  981.  
  982.       if (CDDrive < 'A' || CDDrive >'Z')
  983.          rc = MCIERR_INVALID_DEVICE_NAME;      /* of if invalid drive letter */
  984.       else
  985.       {
  986.          /* load hardware specific MCI Driver (VSD -- Vendor Specific Driver)*/
  987.          /* fail if does not load */
  988.          rsp = DosLoadModule(buf, LOAD_MOD_BUF_LEN,
  989.                              pParam2->szDevDLLName, &pInst->hMod);
  990.          if (!rsp)
  991.             rsp = DosQueryProcAddr(pInst->hMod, 0L, "vsdDriverEntry",
  992.                                    (PFN *) &pInst->pMCIDriver);
  993.          if (rsp)
  994.             rc = MCIERR_CANNOT_LOAD_DRIVER;
  995.          else
  996.          {
  997.             /* open Vendor Specific Driver */
  998.             if (*pulParam1 & MCI_NOTIFY)
  999.             {
  1000.                usNotify = TRUE;
  1001.                *pulParam1 ^= MCI_NOTIFY; //remove flag, don't send notify twice
  1002.             }
  1003.  
  1004.             *pulParam1 |= MCI_WAIT;
  1005.             rc = pInst->pMCIDriver(NULL, MCI_OPEN, pulParam1, pParam2, 0);
  1006.  
  1007.          }  /* of else VSD loaded */
  1008.       }  /* of else valid drive letter */
  1009.  
  1010.       if (!rc)
  1011.       {
  1012.          /* get and pass instance handles */
  1013.          pInst->hHWMCID = pParam2->pInstance;
  1014.          pParam2->pInstance = (PVOID) pInst;
  1015.          pInst->usStatus = OPENED;
  1016.  
  1017.          /* Register Hardware & streaming capabilities */
  1018.          rc = Register(pInst);
  1019.  
  1020.       }
  1021.    }   /* of if no memory problem creating instance structure */
  1022.  
  1023.    if (rc)
  1024.    {
  1025.       if (pInst != NULL)      // if memory was created
  1026.       {
  1027.          DosCloseMutexSem(pInst->hInstSem);
  1028.          HhpFreeMem(CDMC_hHeap, pInst);
  1029.       }
  1030.    }  /* of if error */
  1031.    else
  1032.    {
  1033.       pInst->usStatus += SUSPEND;  // go inactive until MDM issues a restore
  1034.  
  1035.       /*****************************************************************/
  1036.       /* If successful and notify is requested then send notification. */
  1037.       /* This is needed because the instance pointer (lpInstance)      */
  1038.       /* in mciDriverEntry() is not valid on MCI_OPEN.                 */
  1039.       /*****************************************************************/
  1040.       if (usNotify)
  1041.          mdmDriverNotify(pInst->usDeviceID, pParam2->hwndCallback,
  1042.                          MM_MCINOTIFY, usUserParm,
  1043.                          MAKEULONG(MCI_OPEN, MCI_NOTIFY_SUCCESSFUL));
  1044.  
  1045.    }  /* of else no error */
  1046.  
  1047.    return(rc);
  1048.  
  1049. }  /* of ProcOpen() */
  1050.  
  1051.  
  1052. /****************************************************************************/
  1053. /*                                                                          */
  1054. /* SUBROUTINE NAME:  ProcPause                                              */
  1055. /*                                                                          */
  1056. /* DESCRIPTIVE NAME:  Process Pause.                                        */
  1057. /*                                                                          */
  1058. /* FUNCTION:  Process MCI_PAUSE command.                                    */
  1059. /*                                                                          */
  1060. /* PARAMETERS:                                                              */
  1061. /*      PINST pInst    -- pointer to instance.                              */
  1062. /*      ULONG ulParam1 -- flag for this message.                            */
  1063. /*                                                                          */
  1064. /* EXIT CODES:                                                              */
  1065. /*      MCIERR_SUCCESS    -- action completed without error.                */
  1066. /*      MCIERR_DEVICE_NOT_READY   -- No Disc is present.                    */
  1067. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  1068. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  1069. /*                                                                          */
  1070. /* NOTES:                                                                   */
  1071. /*                                                                          */
  1072. /****************************************************************************/
  1073.  
  1074. ULONG ProcPause(PINST pInst, ULONG ulParam1)
  1075. {
  1076.    ULONG rc;
  1077.  
  1078.    rc = ValState(pInst);
  1079.  
  1080.    /* if drive is not ready, ignore call */
  1081.    if (rc == MCIERR_DEVICE_NOT_READY)
  1082.       if (ulParam1 & WAIT_NOTIFY_MASK)
  1083.          return(MCIERR_INVALID_FLAG);
  1084.       else
  1085.          return(MCIERR_SUCCESS);
  1086.  
  1087.    /* validate flags */
  1088.    if (!rc && ulParam1 & WAIT_NOTIFY_MASK)
  1089.       rc = MCIERR_INVALID_FLAG;
  1090.  
  1091.    if (!rc)
  1092.    {
  1093.       switch(pInst->usStatus)
  1094.       {
  1095.          case PLAYING:
  1096.             pInst->usStatus = PAUSED;
  1097.  
  1098.             /* call VSD (Vendor Specific Driver) */
  1099.             rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_PAUSE, 0L, 0L, 0);
  1100.             if (rc)
  1101.             {
  1102.                pInst->usStatus = STOPPED;
  1103.                rc = vsdResponse(pInst, rc);    //if error, process response
  1104.             }
  1105.             break;
  1106.          case PAUSED:
  1107.             /* already pausing */
  1108.             rc = MCIERR_SUCCESS;
  1109.             break;
  1110.          default : rc = MCIERR_SUCCESS;    //pretend that we paused
  1111.  
  1112.       }   /* of switch */
  1113.    }  /* if drive is ready for command */
  1114.  
  1115.    return(rc);
  1116.  
  1117. }  /* of ProcPause() */
  1118.  
  1119.  
  1120. /****************************************************************************/
  1121. /*                                                                          */
  1122. /* SUBROUTINE NAME:  ProcPlay                                               */
  1123. /*                                                                          */
  1124. /* DESCRIPTIVE NAME:  Process Play.                                         */
  1125. /*                                                                          */
  1126. /* FUNCTION:  Process MCI_PLAY command.                                     */
  1127. /*                                                                          */
  1128. /* PARAMETERS:                                                              */
  1129. /*      PINST  pInst      -- pointer to instance.                           */
  1130. /*      ULONG  *pulParam1 -- flag for this message.                         */
  1131. /*      PVOID  pParam2    -- pointer to structure (message dependent).      */
  1132. /*      USHORT usUserParm -- User Parameter for mciDriverNotify.            */
  1133. /*                                                                          */
  1134. /* EXIT CODES:                                                              */
  1135. /*      MCIERR_SUCCESS    -- action completed without error.                */
  1136. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  1137. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  1138. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  1139. /*      MCIERR_OUTOFRANGE         -- invalid track, or cannot reverse.      */
  1140. /*      MCIERR_PARAM_OVERFLOW     -- Invalid PARMS pointer.                 */
  1141. /*      MCIERR_NO_CONNECTION      -- no way to play, no stream/DAC.         */
  1142. /*                                                                          */
  1143. /* NOTES:                                                                   */
  1144. /*                                                                          */
  1145. /****************************************************************************/
  1146.  
  1147. ULONG ProcPlay(PINST pInst, ULONG *pulParam1,
  1148.                MCI_PLAY_PARMS *pParam2, USHORT usUserParm)
  1149. {
  1150.    ULONG rc, ulFlags;
  1151.    MCI_STATUS_PARMS recStatus;
  1152.    MCI_PLAY_PARMS recPlay;
  1153.  
  1154.    rc = ValState(pInst);
  1155.  
  1156.    /* validate flags */
  1157.    if (!rc && *pulParam1 & (0xFFFFFFFF ^
  1158.                          (MCI_WAIT | MCI_NOTIFY | MCI_FROM | MCI_TO)))
  1159.       rc = MCIERR_INVALID_FLAG;
  1160.  
  1161.    if (!rc)
  1162.    {
  1163.       /* Make sure disc is present before you rely on cache */
  1164.       recStatus.ulItem = MCI_STATUS_POSITION;
  1165.       ulFlags = MCI_STATUS_ITEM | MCI_WAIT;
  1166.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STATUS,
  1167.                              &ulFlags, &recStatus, 0);
  1168.       if (ULONG_LOWD(rc))
  1169.       {
  1170.          rc = vsdResponse(pInst, rc);
  1171.          if (!rc)                    //Disc Change, get starting address
  1172.             recStatus.ulReturn = pInst->ulStart_disk;
  1173.       }
  1174.    }  /* of if no error */
  1175.  
  1176.    if (!rc)
  1177.    {
  1178.       /* get starting address */
  1179.       if (*pulParam1 & MCI_FROM)
  1180.       {
  1181.          recPlay.ulFrom = GetTimeAddr(pInst, pParam2->ulFrom, TRUE);
  1182.          if (recPlay.ulFrom == (ULONG) -1L)
  1183.             rc = MCIERR_OUTOFRANGE;            // invalid track number
  1184.          else
  1185.             recPlay.ulFrom += pInst->ulOffset;
  1186.       }  /* of if FROM */
  1187.       else
  1188.       {   /* start at current position */
  1189.          recPlay.ulFrom = recStatus.ulReturn;
  1190.       }
  1191.  
  1192.       if (!rc)
  1193.       {
  1194.          /* get ending address */
  1195.          if (*pulParam1 & MCI_TO)
  1196.          {
  1197.             recPlay.ulTo = GetTimeAddr(pInst, pParam2->ulTo, TRUE);
  1198.             if (recPlay.ulTo == (ULONG) -1L)
  1199.                rc = MCIERR_OUTOFRANGE;            // invalid track number
  1200.             else
  1201.                recPlay.ulTo += pInst->ulOffset;
  1202.          }
  1203.          else
  1204.             recPlay.ulTo = pInst->ulEnd_disk;         /* no TO flag, goto end */
  1205.  
  1206.          /* check hardware start limitations */
  1207.          if (recPlay.ulFrom < pInst->ulMinStartTime)
  1208.             recPlay.ulFrom = pInst->ulMinStartTime;
  1209.          if (recPlay.ulTo < pInst->ulMinStartTime)
  1210.             recPlay.ulTo = pInst->ulMinStartTime;
  1211.  
  1212.          /* validate address */
  1213.          rc = ValAddress(pInst, &recPlay.ulFrom, &recPlay.ulTo, TRUE);
  1214.  
  1215.       }  /* of if no error after getting starting address */
  1216.    }  /* of if no error from validating state */
  1217.  
  1218.    /* Call the play command */
  1219.    if (rc)
  1220.       DosReleaseMutexSem(pInst->hInstSem);
  1221.    else
  1222.    {
  1223.       pInst->ulEnd_play = recPlay.ulTo;
  1224.       pInst->ulCur_pos  = recPlay.ulFrom;  //update current position
  1225.  
  1226.       if (pInst->ulMode & CDMC_INTDAC)
  1227.       {
  1228.          /* update instance prior to call */
  1229.          pInst->usStatus = PLAYING;
  1230.          recPlay.hwndCallback = pParam2->hwndCallback;
  1231.          DosReleaseMutexSem(pInst->hInstSem);
  1232.          rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_PLAY, pulParam1,
  1233.                                 &recPlay, usUserParm);
  1234.          if (ULONG_LOWD(rc))
  1235.             rc = vsdResponse(pInst, rc);  //if error, process response
  1236.       }
  1237.       else
  1238.       {
  1239.          rc = MCIERR_NO_CONNECTION;       //no internal DAC
  1240.          DosReleaseMutexSem(pInst->hInstSem);
  1241.       }
  1242.  
  1243.       /* if play terminated with an error then set to STOP */
  1244.       if (ULONG_LOWD(rc) && pInst->usStatus > NODISC)
  1245.          pInst->usStatus = STOPPED;
  1246.  
  1247.    }  /* of else no error after validating addresses */
  1248.  
  1249.    return(rc);
  1250.  
  1251. }  /* of ProcPlay() */
  1252.  
  1253.  
  1254. /****************************************************************************/
  1255. /*                                                                          */
  1256. /* SUBROUTINE NAME:  ProcPosAdvise                                          */
  1257. /*                                                                          */
  1258. /* DESCRIPTIVE NAME:  Process Position Advise                               */
  1259. /*                                                                          */
  1260. /* FUNCTION:  Process MCI_SET_POSITION_ADVISE command.                      */
  1261. /*                                                                          */
  1262. /* PARAMETERS:                                                              */
  1263. /*      PINST  pInst      -- pointer to instance.                           */
  1264. /*      ULONG  ulParam1   -- flag for this message.                         */
  1265. /*      PVOID  pParam2    -- pointer to structure (message dependent).      */
  1266. /*      USHORT usUserParm -- User passthru value.                           */
  1267. /*                                                                          */
  1268. /* EXIT CODES:                                                              */
  1269. /*      MCIERR_SUCCESS    -- action completed without error.                */
  1270. /*      MCIERR_DEVICE_NOT_READY   -- No Disc is present.                    */
  1271. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  1272. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  1273. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Invalid flag combinations.           */
  1274. /*      MCIERR_INVALID_FLAG         -- Unknown or unsupported flag.         */
  1275. /*                                                                          */
  1276. /* NOTES:                                                                   */
  1277. /*                                                                          */
  1278. /****************************************************************************/
  1279.  
  1280. ULONG ProcPosAdvise(PINST pInst, ULONG ulParam1, MCI_POSITION_PARMS *pParam2)
  1281. {
  1282.    ULONG rc, ulTime, ulFlags;
  1283.    MCI_POSITION_PARMS recPosition;
  1284.    MCI_STATUS_PARMS recStatus;
  1285.    PID pid;
  1286.    TID tid;
  1287.  
  1288.    rc = ValState(pInst);
  1289.  
  1290.    /* Make sure disc is present before you rely on cache */
  1291.    if (!rc)
  1292.    {
  1293.       recStatus.ulItem = MCI_STATUS_POSITION;
  1294.       ulFlags = MCI_STATUS_ITEM | MCI_WAIT;
  1295.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STATUS,
  1296.                              &ulFlags, &recStatus, 0);
  1297.       if (ULONG_LOWD(rc))
  1298.          rc = vsdResponse(pInst, rc);
  1299.    }  /* of if no error */
  1300.  
  1301.    /* if flag doesn't require an active/ready state, process it */
  1302.    if (!(ulParam1 & MCI_SET_POSITION_ADVISE_ON) &&
  1303.          rc != MCIERR_INSTANCE_INACTIVE)
  1304.       rc = MCIERR_SUCCESS;
  1305.  
  1306.    /* validate callback handle */
  1307.    if (!rc && !(ulParam1 & MCI_NOTIFY))
  1308.       if (!WinQueryWindowProcess(pParam2->hwndCallback, &pid, &tid))
  1309.          rc = MCIERR_INVALID_CALLBACK_HANDLE;
  1310.  
  1311.    if (!rc)
  1312.    {
  1313.       ulParam1 &= WAIT_NOTIFY_MASK;
  1314.  
  1315.       switch(ulParam1)
  1316.       {
  1317.          case MCI_SET_POSITION_ADVISE_ON :
  1318.             /* validate time */
  1319.             ulTime = GetTimeAddr(pInst, pParam2->ulUnits, TRUE);
  1320.  
  1321.             /* check for invalid track number or no position specified */
  1322.             if ((ulTime == (ULONG) -1L) || (ulTime == 0L))
  1323.                rc = MCIERR_OUTOFRANGE;
  1324.             else
  1325.                if (ulTime > pInst->ulEnd_disk)
  1326.                   rc = MCIERR_OUTOFRANGE;
  1327.  
  1328.             /* enable position advise */
  1329.             if (!rc)
  1330.             {
  1331.                memcpy(&recPosition, pParam2, sizeof(MCI_POSITION_PARMS));
  1332.                recPosition.ulUnits = ulTime;
  1333.                ulParam1 |= MCI_WAIT;
  1334.                rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_SET_POSITION_ADVISE,
  1335.                                       &ulParam1, &recPosition, 0);
  1336.  
  1337.             }   /* of if no error, enable it */
  1338.             break;
  1339.          case MCI_SET_POSITION_ADVISE_OFF :
  1340.             ulParam1 |= MCI_WAIT;
  1341.             rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_SET_POSITION_ADVISE,
  1342.                                    &ulParam1, 0L, 0);
  1343.             break;
  1344.          case MCI_SET_POSITION_ADVISE_ON | MCI_SET_POSITION_ADVISE_OFF :
  1345.             rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  1346.             break;
  1347.          case 0 :
  1348.             rc = MCIERR_MISSING_FLAG;
  1349.             break;
  1350.          default :
  1351.             rc = MCIERR_INVALID_FLAG;
  1352.  
  1353.       }  /* of switch */
  1354.    }  /* of if no error */
  1355.  
  1356.    if (rc)
  1357.       rc = vsdResponse(pInst, rc);
  1358.  
  1359.    return(rc);
  1360.  
  1361. }  /* of ProcPosAdvise() */
  1362.  
  1363.  
  1364. /****************************************************************************/
  1365. /*                                                                          */
  1366. /* SUBROUTINE NAME:  ProcRestore                                            */
  1367. /*                                                                          */
  1368. /* DESCRIPTIVE NAME:  Process Restore.                                      */
  1369. /*                                                                          */
  1370. /* FUNCTION:  Process MCIDRV_RESTORE command.                               */
  1371. /*                                                                          */
  1372. /* PARAMETERS:                                                              */
  1373. /*      PINST pInst    -- pointer to instance.                              */
  1374. /*                                                                          */
  1375. /* EXIT CODES:                                                              */
  1376. /*      MCIERR_SUCCESS    -- action completed without error.                */
  1377. /*      MCIERR_FILE_NOT_FOUND -- improper disc not loaded.                  */
  1378. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  1379. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  1380. /*      MCIERR_OUT_OF_MEMORY      -- Out of memory for thread.              */
  1381. /*                                                                          */
  1382. /* NOTES:                                                                   */
  1383. /*                                                                          */
  1384. /****************************************************************************/
  1385.  
  1386. ULONG ProcRestore(PINST pInst)
  1387. {
  1388.    ULONG rc;
  1389.    MCI_CD_REGDISC_PARMS recDisc;
  1390.    USHORT usSameDisc = TRUE, usOldStatus;
  1391.  
  1392.    /* Set player the way it was */
  1393.    pInst->usStatus -= SUSPEND;
  1394.  
  1395.    if (pInst->usStatus <= NODISC)
  1396.    {
  1397.       rc = MCIERR_SUCCESS;
  1398.       pInst->usStatus = REGDRIVE;         //reset because position is not known
  1399.  
  1400.       /* check if disc was inserted */
  1401.       ReRegister(pInst);
  1402.    }
  1403.    else         // there was a disc when we saved
  1404.    {
  1405.       usOldStatus = pInst->usStatus;      // retain original status
  1406.  
  1407.       /* Validate disc as same as old state */
  1408.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCIDRV_REGISTER_DISC,
  1409.                              0L, &recDisc, 0);
  1410.       if (rc)
  1411.          usSameDisc = FALSE;
  1412.       else
  1413.          if (memcmp(&pInst->recDisc.DiscID, &recDisc.DiscID, IDSIZE))
  1414.             usSameDisc = FALSE;
  1415.  
  1416.       /* get current master volume settings */
  1417.       QMAudio(pInst);
  1418.  
  1419.       /* set parameters on restore */
  1420.       pInst->recSave.ulEndPlay = pInst->ulEnd_play;
  1421.  
  1422.       /* set volume */
  1423.       if (pInst->ulMode & CDMC_LFT_CH && pInst->ulMode & CDMC_HEADPHONE)
  1424.          VOL_LEFT(pInst->recSave.ulLevel) = (USHORT)
  1425.             ((ULONG)VOL_LEFT(pInst->ulLevel) * pInst->ulMasterVolume / 100);
  1426.       else
  1427.          VOL_LEFT(pInst->recSave.ulLevel) = 0;
  1428.  
  1429.       if (pInst->ulMode & CDMC_RGT_CH && pInst->ulMode & CDMC_HEADPHONE)
  1430.          VOL_RIGHT(pInst->recSave.ulLevel) = (USHORT)
  1431.             ((ULONG)VOL_RIGHT(pInst->ulLevel) * pInst->ulMasterVolume / 100);
  1432.       else
  1433.          VOL_RIGHT(pInst->recSave.ulLevel) = 0;
  1434.  
  1435.       /* set restoring mode */
  1436.       if (!usSameDisc)
  1437.          pInst->recSave.ulMode = MCI_MODE_NOT_READY;
  1438.       else if (pInst->ulMode & CDMC_STREAM)
  1439.          pInst->recSave.ulMode = MCI_MODE_STOP;
  1440.       else
  1441.          switch (usOldStatus)
  1442.          {
  1443.             case PLAYING:
  1444.                pInst->recSave.ulMode = MCI_MODE_PLAY;
  1445.                break;
  1446.             case PAUSED:
  1447.                pInst->recSave.ulMode = MCI_MODE_PAUSE;
  1448.                break;
  1449.             default :                           // must be status = STOPPED
  1450.                pInst->recSave.ulMode = MCI_MODE_STOP;
  1451.  
  1452.          }  /* of switch */
  1453.  
  1454.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCIDRV_RESTORE, 0L,
  1455.                              &pInst->recSave, 0);
  1456.  
  1457.       if (rc)
  1458.          rc = vsdResponse(pInst, rc);       //if error, process response
  1459.  
  1460.       if (!usSameDisc)
  1461.          rc = ReRegister(pInst);            //accept and load new disc
  1462.  
  1463.    }  /* of else there was a disc when we saved */
  1464.  
  1465.    return(MCIERR_SUCCESS);
  1466.  
  1467. }  /* of ProcRestore() */
  1468.  
  1469.  
  1470. /****************************************************************************/
  1471. /*                                                                          */
  1472. /* SUBROUTINE NAME:  ProcResume                                             */
  1473. /*                                                                          */
  1474. /* DESCRIPTIVE NAME:  Process Resume                                        */
  1475. /*                                                                          */
  1476. /* FUNCTION:  Process MCI_RESUME command.  Unpause after a Pause.           */
  1477. /*                                                                          */
  1478. /* PARAMETERS:                                                              */
  1479. /*      PINST pInst    -- pointer to instance.                              */
  1480. /*      ULONG ulParam1 -- flag for this message.                            */
  1481. /*                                                                          */
  1482. /* EXIT CODES:                                                              */
  1483. /*      MCIERR_SUCCESS    -- action completed without error.                */
  1484. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  1485. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  1486. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  1487. /*                                                                          */
  1488. /* NOTES:                                                                   */
  1489. /*                                                                          */
  1490. /****************************************************************************/
  1491.  
  1492. ULONG ProcResume(PINST pInst, ULONG ulParam1)
  1493. {
  1494.    ULONG rc, ulFlags;
  1495.    MCI_STATUS_PARMS recStatus;
  1496.  
  1497.    rc = ValState(pInst);
  1498.  
  1499.    /* if drive is not ready, ignore call */
  1500.    if (rc == MCIERR_DEVICE_NOT_READY)
  1501.       if (ulParam1 & WAIT_NOTIFY_MASK)
  1502.          return(MCIERR_INVALID_FLAG);
  1503.       else
  1504.          return(MCIERR_SUCCESS);
  1505.  
  1506.    /* validate flags */
  1507.    if (!rc && ulParam1 & WAIT_NOTIFY_MASK)
  1508.       rc = MCIERR_INVALID_FLAG;
  1509.  
  1510.    if (!rc)   /* make sure we are in a PAUSED state */
  1511.       if (pInst->usStatus != PAUSED)
  1512.          return(MCIERR_SUCCESS);     // ignore call,
  1513.  
  1514.    if (!rc)   /* Make sure disc is valid before resuming */
  1515.    {
  1516.       recStatus.ulItem = MCI_STATUS_POSITION;
  1517.       ulFlags = MCI_STATUS_ITEM | MCI_WAIT;
  1518.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STATUS,
  1519.                              &ulFlags, &recStatus, 0);
  1520.       if (ULONG_LOWD(rc))
  1521.       {
  1522.          rc = vsdResponse(pInst, rc);
  1523.          return(rc);                //if rc==MCIERR_SUCCESS means Disc Change
  1524.       }  /* of if VSD reported an error */
  1525.    }  /* if no error */
  1526.  
  1527.    if (!rc)
  1528.    {
  1529.       pInst->usStatus = PLAYING;
  1530.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_RESUME, 0L, 0L, 0);
  1531.       if (ULONG_LOWD(rc))
  1532.       {
  1533.          pInst->usStatus = STOPPED;
  1534.          rc = vsdResponse(pInst, rc);       //if error, process response
  1535.       }
  1536.    }  /* of if no error */
  1537.  
  1538.    return(rc);
  1539.  
  1540. }  /* of ProcResume() */
  1541.  
  1542.  
  1543. /****************************************************************************/
  1544. /*                                                                          */
  1545. /* SUBROUTINE NAME:  ProcSave                                               */
  1546. /*                                                                          */
  1547. /* DESCRIPTIVE NAME:  Process Save.                                         */
  1548. /*                                                                          */
  1549. /* FUNCTION:  Process MCI_SAVE command.                                     */
  1550. /*                                                                          */
  1551. /* PARAMETERS:                                                              */
  1552. /*      PINST pInst    -- pointer to instance.                              */
  1553. /*                                                                          */
  1554. /* EXIT CODES:                                                              */
  1555. /*      MCIERR_SUCCESS    -- action completed without error.                */
  1556. /*                                                                          */
  1557. /* NOTES:                                                                   */
  1558. /*                                                                          */
  1559. /****************************************************************************/
  1560.  
  1561. ULONG ProcSave(PINST pInst)
  1562. {
  1563.    ULONG rc;
  1564.  
  1565.    pInst->usStatus += SUSPEND;
  1566.  
  1567.    /* tell the VSD that it is being saved and get values */
  1568.    pInst->recSave.ulLevel = pInst->ulLevel;
  1569.    rc = pInst->pMCIDriver(pInst->hHWMCID, MCIDRV_SAVE, 0L, &pInst->recSave, 0);
  1570.  
  1571.    pInst->ulCur_pos = pInst->recSave.ulPosition;
  1572.  
  1573.    if (rc)             /* info was not saved, restore will re-register */
  1574.       pInst->usStatus = NODISC + SUSPEND;
  1575.  
  1576.    return(MCIERR_SUCCESS);
  1577.  
  1578. }  /* of ProcSave() */
  1579.  
  1580.  
  1581. /****************************************************************************/
  1582. /*                                                                          */
  1583. /* SUBROUTINE NAME:  ProcSeek                                               */
  1584. /*                                                                          */
  1585. /* DESCRIPTIVE NAME:  Process Seek.                                         */
  1586. /*                                                                          */
  1587. /* FUNCTION:  Process MCI_SEEK command.                                     */
  1588. /*                                                                          */
  1589. /* PARAMETERS:                                                              */
  1590. /*      PINST pInst    -- pointer to instance.                              */
  1591. /*      ULONG ulParam1 -- flag for this message.                            */
  1592. /*      PVOID pParam2  -- pointer to structure (message dependent).         */
  1593. /*                                                                          */
  1594. /* EXIT CODES:                                                              */
  1595. /*      MCIERR_SUCCESS    -- action completed without error.                */
  1596. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  1597. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  1598. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  1599. /*      MCIERR_OUTOFRANGE         -- invalid track or address.              */
  1600. /*      MCIERR_PARAM_OVERFLOW     -- Invalid PARMS pointer.                 */
  1601. /*                                                                          */
  1602. /* NOTES:                                                                   */
  1603. /*                                                                          */
  1604. /****************************************************************************/
  1605.  
  1606. ULONG ProcSeek(PINST pInst, ULONG ulParam1, MCI_SEEK_PARMS *pParam2)
  1607. {
  1608.    ULONG rc = MCIERR_SUCCESS, ulFlags;
  1609.    MCI_SEEK_PARMS recSeek;
  1610.    MCI_STATUS_PARMS recStatus;
  1611.    ULONG ulType;
  1612.  
  1613.    rc = ValState(pInst);
  1614.  
  1615.    /* validate flags */
  1616.    if (!rc)
  1617.       if (ulParam1 & (0xFFFFFFFF ^
  1618.                  (MCI_WAIT | MCI_NOTIFY | MCI_TO | MCI_TO_START | MCI_TO_END)))
  1619.          rc = MCIERR_INVALID_FLAG;
  1620.       else
  1621.       {
  1622.          /* Make sure disc is present before you rely on cache */
  1623.          recStatus.ulItem = MCI_STATUS_POSITION;
  1624.          ulFlags = MCI_STATUS_ITEM | MCI_WAIT;
  1625.          rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STATUS,
  1626.                                 &ulFlags, &recStatus, 0);
  1627.          if (ULONG_LOWD(rc))
  1628.             rc = vsdResponse(pInst, rc);
  1629.       }
  1630.  
  1631.    if (!rc)
  1632.    {
  1633.       ulType = ulParam1 & WAIT_NOTIFY_MASK;
  1634.       switch (ulType)
  1635.       {
  1636.          case MCI_TO_START :            /* seek to first position */
  1637.             recSeek.ulTo = pInst->ulStart_disk;
  1638.             break;
  1639.          case MCI_TO_END :              /* seek to last position */
  1640.             recSeek.ulTo = pInst->ulEnd_disk - MMT_FRAME;
  1641.             break;
  1642.          case 0L :                      /* No address specified, error */
  1643.             rc = MCIERR_MISSING_FLAG;
  1644.             break;
  1645.          case MCI_TO :                  /* seek to specified address */
  1646.             /*    make sure it is a playable address */
  1647.             recSeek.ulTo = GetTimeAddr(pInst, pParam2->ulTo, TRUE);
  1648.             if (recSeek.ulTo == (ULONG) -1L)
  1649.                rc = MCIERR_OUTOFRANGE;            // invalid track number
  1650.             else
  1651.             {
  1652.                recSeek.ulTo += pInst->ulOffset;
  1653.                rc = ValAddress(pInst, NULL, &recSeek.ulTo, FALSE);
  1654.             }
  1655.             break;
  1656.          default :                      /* unknown flag combination */
  1657.             rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  1658.       }  /* of switch() */
  1659.  
  1660.       if (!rc)
  1661.       {                                          /* No error, set it up */
  1662.          /* check hardware start limitations */
  1663.          if (recSeek.ulTo < pInst->ulMinStartTime)
  1664.             recSeek.ulTo = pInst->ulMinStartTime;
  1665.  
  1666.          /* call VSD (Vendor Specific Driver) */
  1667.          rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_SEEK, 0L, &recSeek, 0);
  1668.  
  1669.          pInst->usStatus = STOPPED;
  1670.  
  1671.          if (ULONG_LOWD(rc))
  1672.              rc = vsdResponse(pInst, rc);      //if error, process response
  1673.  
  1674.       }   /* of if no error */
  1675.    }  /* of if no error from validating state */
  1676.  
  1677.    return(rc);
  1678.  
  1679. }  /* of ProcSeek() */
  1680.  
  1681.  
  1682. /****************************************************************************/
  1683. /*                                                                          */
  1684. /* SUBROUTINE NAME:  ProcSet                                                */
  1685. /*                                                                          */
  1686. /* DESCRIPTIVE NAME:  Process Set.                                          */
  1687. /*                                                                          */
  1688. /* FUNCTION:  Process MCI_SET command.                                      */
  1689. /*                                                                          */
  1690. /* PARAMETERS:                                                              */
  1691. /*      PINST pInst      -- pointer to instance.                            */
  1692. /*      ULONG *pulParam1 -- flag for this message.                          */
  1693. /*      PVOID pParam2    -- pointer to structure (message dependent).       */
  1694. /*                                                                          */
  1695. /* EXIT CODES:                                                              */
  1696. /*      MCIERR_SUCCESS    -- action completed without error.                */
  1697. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  1698. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  1699. /*      MCIERR_PARAM_OVERFLOW     -- Invalid PARMS pointer.                 */
  1700. /*      MCIERR_UNSUPPORTED_FLAG   -- Flag not supported by this MCD.        */
  1701. /*      MCIERR_INVALID_FLAG       -- Unknown flag or value used.            */
  1702. /*      MCIERR_SPEED_FORMAT_FLAG  -- Unknown speed type specified.          */
  1703. /*      MCIERR_OUT_OF_MEMORY      -- Could not create thread.               */
  1704. /*      MCIERR_INVALID_AUDIO_FLAG -- Unknown audio flag specified.          */
  1705. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Conflicting Flags.                   */
  1706. /*      MCIERR_INVALID_TIME_FORMAT_FLAG  -- Unknown time type specified.    */
  1707. /*                                                                          */
  1708. /* NOTES:  Flags needing a valid pParam2 are checked in verify_entry()      */
  1709. /*                                                                          */
  1710. /****************************************************************************/
  1711.  
  1712. ULONG ProcSet(PINST pInst, ULONG *pulParam1, MCI_SET_PARMS *pParam2)
  1713. {
  1714.    ULONG rc, ulLevel, ulP1Temp;
  1715.    USHORT SemHolding = TRUE;
  1716.    ULONG ulMode;
  1717.    MCI_SET_PARMS recSet;
  1718.  
  1719.    rc = ValState(pInst);
  1720.    if (rc == MCIERR_INVALID_MEDIA_TYPE)
  1721.       rc = MCIERR_SUCCESS;
  1722.  
  1723.    /* validate flags */
  1724.    if (!rc)
  1725.    {
  1726.       ulP1Temp = *pulParam1 & WAIT_NOTIFY_MASK;          //mask off N/W flags
  1727.       if (ulP1Temp & MCI_SET_VIDEO || ulP1Temp & MCI_SET_ITEM)
  1728.          rc = MCIERR_UNSUPPORTED_FLAG;
  1729.       else
  1730.          if (!(ulP1Temp) ||                              // no flags,
  1731.               (!(ulP1Temp & MCI_SET_AUDIO) &&            // check flags needing
  1732.                 (ulP1Temp & MCI_SET_VOLUME ||            //   MCI_SET_AUDIO
  1733.                  ulP1Temp & MCI_SET_ON || ulP1Temp & MCI_SET_OFF)))
  1734.             rc = MCIERR_MISSING_FLAG;
  1735.    }  /* of if no error to validate first set of flags */
  1736.  
  1737.    if (!rc)
  1738.    {
  1739.       ulMode = pInst->ulMode;
  1740.       ulLevel = pInst->ulLevel;
  1741.  
  1742.       /* copy pParam2 structure to make changes */
  1743.       if (pParam2 != NULL)
  1744.          memcpy(&recSet, pParam2, sizeof(MCI_SET_PARMS));
  1745.  
  1746.       if (ulP1Temp & MCI_SET_SPEED_FORMAT)
  1747.       {
  1748.          ulP1Temp ^= MCI_SET_SPEED_FORMAT;        // remove non VSD flag
  1749.          switch (pParam2->ulSpeedFormat)
  1750.          {
  1751.             case MCI_FORMAT_PERCENTAGE :
  1752.                ulMode |= CDMC_PERCENT;
  1753.                break;
  1754.             case MCI_FORMAT_FPS :
  1755.                if (ulMode & CDMC_PERCENT)
  1756.                   ulMode ^= CDMC_PERCENT;
  1757.                break;
  1758.             default : rc = MCIERR_SPEED_FORMAT_FLAG;
  1759.  
  1760.          }  /* of switch time format */
  1761.       }  /* of if speed format */
  1762.  
  1763.       if (!rc && ulP1Temp & MCI_SET_TIME_FORMAT)
  1764.       {
  1765.          ulP1Temp ^= MCI_SET_TIME_FORMAT;        // remove non VSD flag
  1766.          switch (pParam2->ulTimeFormat)
  1767.          {
  1768.             case MCI_FORMAT_MILLISECONDS :
  1769.                ulMode = ulMode & TIME_MODE_SET | CDMC_MILLSEC;
  1770.                break;
  1771.             case MCI_FORMAT_MMTIME :
  1772.                ulMode = ulMode & TIME_MODE_SET | CDMC_MMTIME;
  1773.                break;
  1774.             case MCI_FORMAT_MSF :
  1775.                ulMode = ulMode & TIME_MODE_SET | CDMC_REDBOOK;
  1776.                break;
  1777.             case MCI_FORMAT_TMSF :
  1778.                ulMode = ulMode & TIME_MODE_SET | CDMC_TMSF;
  1779.                break;
  1780.             default : rc = MCIERR_INVALID_TIME_FORMAT_FLAG;
  1781.  
  1782.          }  /* of switch time format */
  1783.       }  /* of if time format */
  1784.  
  1785.       if (!rc && ulP1Temp & MCI_SET_DOOR_LOCK && ulP1Temp & MCI_SET_DOOR_UNLOCK)
  1786.          rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  1787.  
  1788.       if (!rc && ulP1Temp & MCI_SET_DOOR_OPEN && ulP1Temp & MCI_SET_DOOR_CLOSED)
  1789.          rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  1790.  
  1791.       if (!rc && ulP1Temp & MCI_SET_AUDIO)
  1792.          rc = SetAudio(pInst, &ulP1Temp, &recSet, &ulMode, &ulLevel);
  1793.  
  1794.       /* process VSD flags, if they exist */
  1795.       if (!rc && ulP1Temp)
  1796.       {
  1797.          ulP1Temp |= MCI_WAIT;
  1798.          rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_SET, &ulP1Temp,
  1799.                                 &recSet, 0);
  1800.          if (rc)
  1801.             rc = vsdResponse(pInst, rc);      //if error, process response
  1802.       }
  1803.    }  /* of if valid state */
  1804.  
  1805.    if (!rc)
  1806.    {
  1807.       pInst->ulMode = ulMode;
  1808.       pInst->ulLevel = ulLevel;
  1809.    }  /* of else no error */
  1810.  
  1811.    if (SemHolding)             //Release semaphore if not already done
  1812.       DosReleaseMutexSem(pInst->hInstSem);
  1813.  
  1814.    return(rc);
  1815.  
  1816. }  /* of ProcSet() */
  1817.  
  1818.  
  1819. /****************************************************************************/
  1820. /*                                                                          */
  1821. /* SUBROUTINE NAME:  ProcSetSync                                            */
  1822. /*                                                                          */
  1823. /* DESCRIPTIVE NAME:  Process Set Synchronization Offset                    */
  1824. /*                                                                          */
  1825. /* FUNCTION:  Process MCI_SET_SYNC_OFFSET command.                          */
  1826. /*                                                                          */
  1827. /* PARAMETERS:                                                              */
  1828. /*      PINST pInst    -- pointer to instance.                              */
  1829. /*      ULONG ulParam1 -- flag for this message.                            */
  1830. /*      PVOID pParam2  -- pointer to structure (message dependent).         */
  1831. /*                                                                          */
  1832. /* EXIT CODES:                                                              */
  1833. /*      MCIERR_SUCCESS      -- action completed without error.              */
  1834. /*      MCIERR_INVALID_FLAG -- Unknown flag or value used.                  */
  1835. /*      MCIERR_OUTOFRANGE   -- invalid track specified.                     */
  1836. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  1837. /*                                                                          */
  1838. /* NOTES:                                                                   */
  1839. /*                                                                          */
  1840. /****************************************************************************/
  1841.  
  1842. ULONG ProcSetSync(PINST pInst, ULONG ulParam1, MCI_SYNC_OFFSET_PARMS *pParam2)
  1843. {
  1844.    ULONG rc = MCIERR_SUCCESS;
  1845.    USHORT temp;
  1846.  
  1847.    ulParam1 &= WAIT_NOTIFY_MASK;
  1848.  
  1849.    if (ulParam1)
  1850.       rc = MCIERR_INVALID_FLAG;
  1851.    else
  1852.    {
  1853.       /* check if disc is needed, track info is needed for TMSF mode */
  1854.       if (pInst->ulMode & TIME_MODE == CDMC_TMSF)
  1855.       {
  1856.          temp = (USHORT)(pInst->usStatus % SUSPEND);
  1857.          if (temp <= NODISC)
  1858.             rc = MCIERR_DEVICE_NOT_READY;
  1859.       }
  1860.  
  1861.       if (!rc)
  1862.       {
  1863.          pInst->ulOffset = GetTimeAddr(pInst, pParam2->ulOffset, TRUE);
  1864.          if (pInst->ulOffset == (ULONG) -1)
  1865.          {                              // Invalid track specified for TMSF
  1866.             pInst->ulOffset = 0L;
  1867.             rc = MCIERR_OUTOFRANGE;
  1868.          }
  1869.       }  /* of if no error */
  1870.    }  /* no invalid flags */
  1871.  
  1872.    return(rc);
  1873.  
  1874. }  /* of ProcSetSync() */
  1875.  
  1876.  
  1877. /****************************************************************************/
  1878. /*                                                                          */
  1879. /* SUBROUTINE NAME:  ProcStatus                                             */
  1880. /*                                                                          */
  1881. /* DESCRIPTIVE NAME:  Process Status.                                       */
  1882. /*                                                                          */
  1883. /* FUNCTION:  Process MCI_STATUS command.                                   */
  1884. /*                                                                          */
  1885. /* PARAMETERS:                                                              */
  1886. /*      PINST pInst    -- pointer to instance.                              */
  1887. /*      ULONG ulParam1 -- flag for this message.                            */
  1888. /*      PVOID pParam2  -- pointer to structure (message dependent).         */
  1889. /*                                                                          */
  1890. /* EXIT CODES:                                                              */
  1891. /*      MCIERR_SUCCESS    -- action completed without error.                */
  1892. /*      MCIERR_OUTOFRANGE -- invalid track supplied.                        */
  1893. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  1894. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  1895. /*      MCIERR_INVALID_ITEM_FLAG  -- Invalid item specified.                */
  1896. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  1897. /*      MCIERR_PARAM_OVERFLOW     -- Invalid PARMS pointer.                 */
  1898. /*                                                                          */
  1899. /* NOTES:                                                                   */
  1900. /*                                                                          */
  1901. /****************************************************************************/
  1902.  
  1903. ULONG ProcStatus(PINST pInst, ULONG ulParam1, MCI_STATUS_PARMS *pParam2)
  1904. {
  1905.    ULONG rc, rsp;
  1906.  
  1907.    rsp = ValState(pInst);
  1908.  
  1909.    /* validate flags */
  1910.    ulParam1 &= WAIT_NOTIFY_MASK;
  1911.    pParam2->ulReturn = 0L;
  1912.  
  1913.    switch(ulParam1)
  1914.    {
  1915.       case MCI_STATUS_ITEM :
  1916.          rc = MCIERR_SUCCESS;
  1917.          switch(pParam2->ulItem)
  1918.          {
  1919.             /* process items that the MCI Driver can do */
  1920.  
  1921.             case MCI_STATUS_AUDIO :
  1922.                ULONG_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  1923.                switch (pParam2->ulValue)
  1924.                {
  1925.                   case MCI_STATUS_AUDIO_LEFT :
  1926.                      if (pInst->ulMode & CDMC_LFT_CH)
  1927.                         pParam2->ulReturn = MCI_TRUE;
  1928.                      else
  1929.                         pParam2->ulReturn = MCI_FALSE;
  1930.                      break;
  1931.                   case MCI_STATUS_AUDIO_RIGHT :
  1932.                      if (pInst->ulMode & CDMC_RGT_CH)
  1933.                         pParam2->ulReturn = MCI_TRUE;
  1934.                      else
  1935.                         pParam2->ulReturn = MCI_FALSE;
  1936.                      break;
  1937.                   case MCI_STATUS_AUDIO_ALL :
  1938.                      if (pInst->ulMode & CDMC_ALL_CH)
  1939.                         pParam2->ulReturn = MCI_TRUE;
  1940.                      else
  1941.                         pParam2->ulReturn = MCI_FALSE;
  1942.                      break;
  1943.                   default : rc = MCIERR_INVALID_AUDIO_FLAG;
  1944.                }  /* of switch */
  1945.                break;
  1946.             case MCI_STATUS_SPEED_FORMAT :
  1947.                ULONG_HIWD(rc) = MCI_SPEED_FORMAT_RETURN;
  1948.                if (pInst->ulMode & CDMC_PERCENT)
  1949.                   pParam2->ulReturn = MCI_FORMAT_PERCENTAGE;
  1950.                else
  1951.                   pParam2->ulReturn = MCI_FORMAT_FPS;
  1952.                break;
  1953.             case MCI_STATUS_TIME_FORMAT :
  1954.                ULONG_HIWD(rc) = MCI_TIME_FORMAT_RETURN;
  1955.                switch (pInst->ulMode & TIME_MODE)
  1956.                {
  1957.                   case CDMC_MILLSEC :
  1958.                      pParam2->ulReturn = MCI_FORMAT_MILLISECONDS;
  1959.                      break;
  1960.                   case CDMC_REDBOOK :
  1961.                      pParam2->ulReturn = MCI_FORMAT_MSF;
  1962.                      break;
  1963.                   case CDMC_TMSF :
  1964.                      pParam2->ulReturn = MCI_FORMAT_TMSF;
  1965.                      break;
  1966.                   default :              // must be CDMC_MMTIME
  1967.                      pParam2->ulReturn = MCI_FORMAT_MMTIME;
  1968.                }  /* of switch */
  1969.                break;
  1970.  
  1971.             /* Process commands that the MCD can do with the VSD */
  1972.  
  1973.             case MCI_STATUS_LENGTH :
  1974.             case MCI_STATUS_NUMBER_OF_TRACKS :
  1975.                rc = StatusMCD(pInst, ulParam1, pParam2, rsp, TRUE);
  1976.                break;
  1977.             case MCI_STATUS_POSITION :
  1978.             case MCI_STATUS_POSITION_IN_TRACK :
  1979.             case MCI_STATUS_CURRENT_TRACK :
  1980.             case MCI_CD_STATUS_TRACK_TYPE :
  1981.             case MCI_CD_STATUS_TRACK_COPYPERMITTED :
  1982.             case MCI_CD_STATUS_TRACK_CHANNELS :
  1983.             case MCI_CD_STATUS_TRACK_PREEMPHASIS :
  1984.                rc = StatusMCD(pInst, ulParam1, pParam2, rsp, FALSE);
  1985.                break;
  1986.  
  1987.             /* Process commands that the VSD can only do   */
  1988.             /* MCI_STATUS_MEDIA_PRESENT, MCI_STATUS_VOLUME */
  1989.             /* MCI_STATUS_MODE, MCI_STATUS_READY, others   */
  1990.             default :
  1991.                rc = StatusVSD(pInst, ulParam1, pParam2, rsp);
  1992.  
  1993.          }  /* of item switch */
  1994.          break;
  1995.       case MCI_STATUS_ITEM | MCI_TRACK :
  1996.          switch(pParam2->ulItem)
  1997.          {
  1998.             case MCI_STATUS_LENGTH :
  1999.             case MCI_CD_STATUS_TRACK_TYPE :
  2000.             case MCI_CD_STATUS_TRACK_COPYPERMITTED :
  2001.             case MCI_STATUS_POSITION :
  2002.             case MCI_CD_STATUS_TRACK_CHANNELS :
  2003.             case MCI_CD_STATUS_TRACK_PREEMPHASIS :
  2004.                rc = StatusMCD(pInst, ulParam1, pParam2, rsp, TRUE);
  2005.                break;
  2006.             default :
  2007.                rc = StatusVSD(pInst, ulParam1, pParam2, rsp);
  2008.          }  /* of item switch */
  2009.          break;
  2010.       case MCI_STATUS_ITEM | MCI_STATUS_START :
  2011.          switch(pParam2->ulItem)
  2012.          {
  2013.             case MCI_STATUS_POSITION :
  2014.                rc = StatusMCD(pInst, ulParam1, pParam2, rsp, FALSE);
  2015.                break;
  2016.             default :
  2017.                rc = MCIERR_INVALID_ITEM_FLAG;
  2018.          }  /* of item switch */
  2019.          break;
  2020.       case 0 :
  2021.          rc = MCIERR_MISSING_FLAG;
  2022.          break;
  2023.       default :
  2024.          if (rsp)
  2025.          {
  2026.             if (rsp == MCIERR_INSTANCE_INACTIVE)
  2027.                if (pInst->usStatus - SUSPEND <= NODISC)
  2028.                   rc = MCIERR_DEVICE_NOT_READY;
  2029.                else
  2030.                   rsp = MCIERR_SUCCESS;    //clear flag and let VSD process it
  2031.             else
  2032.                rc = rsp;
  2033.          }
  2034.  
  2035.          if (!rsp)        // unknown flag, query VSD
  2036.          {
  2037.             ulParam1 |= MCI_WAIT;
  2038.             rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STATUS,
  2039.                                    &ulParam1, pParam2, 0);
  2040.             if (ULONG_LOWD(rc))
  2041.                rc = vsdResponse(pInst, rc);      //if error, process response
  2042.          }
  2043.    }  /* of switch on flags */
  2044.  
  2045.    return(rc);
  2046.  
  2047. }  /* of ProcStatus() */
  2048.  
  2049.  
  2050. /****************************************************************************/
  2051. /*                                                                          */
  2052. /* SUBROUTINE NAME:  ProcStop                                               */
  2053. /*                                                                          */
  2054. /* DESCRIPTIVE NAME:  Process Stop.                                         */
  2055. /*                                                                          */
  2056. /* FUNCTION:  Process MCI_STOP command.                                     */
  2057. /*                                                                          */
  2058. /* PARAMETERS:                                                              */
  2059. /*      PINST pInst    -- pointer to instance.                              */
  2060. /*      ULONG ulParam1 -- flag for this message.                            */
  2061. /*                                                                          */
  2062. /* EXIT CODES:                                                              */
  2063. /*      MCIERR_SUCCESS    -- action completed without error.                */
  2064. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  2065. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  2066. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  2067. /*                                                                          */
  2068. /* NOTES:                                                                   */
  2069. /*                                                                          */
  2070. /****************************************************************************/
  2071.  
  2072. ULONG ProcStop(PINST pInst, ULONG ulParam1)
  2073. {
  2074.    ULONG rc;
  2075.  
  2076.    rc = ValState(pInst);
  2077.  
  2078.    /* if drive is not ready, ignore call */
  2079.    if (rc == MCIERR_DEVICE_NOT_READY)
  2080.       if (ulParam1 & WAIT_NOTIFY_MASK)
  2081.          return(MCIERR_INVALID_FLAG);
  2082.       else
  2083.          return(MCIERR_SUCCESS);
  2084.  
  2085.    /* validate flags */
  2086.    if (!rc && ulParam1 & WAIT_NOTIFY_MASK)
  2087.       rc = MCIERR_INVALID_FLAG;
  2088.  
  2089.    if (!rc)
  2090.    {
  2091.       /* call VSD (Vendor Specific Driver) */
  2092.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STOP, 0L, 0L, 0);
  2093.       if (rc)
  2094.           rc = vsdResponse(pInst, rc);          //if error, process response
  2095.  
  2096.       pInst->usStatus = STOPPED;
  2097.  
  2098.    }  /* if drive is ready for command */
  2099.  
  2100.    return(rc);
  2101.  
  2102. }  /* of ProcStop() */
  2103.  
  2104.  
  2105. /****************************************************************************/
  2106. /*                                                                          */
  2107. /* SUBROUTINE NAME:  ProcSync                                               */
  2108. /*                                                                          */
  2109. /* DESCRIPTIVE NAME:  Process Synchronization                               */
  2110. /*                                                                          */
  2111. /* FUNCTION:  Process MCIDRV_SYNC command.                                  */
  2112. /*                                                                          */
  2113. /* PARAMETERS:                                                              */
  2114. /*      PINST pInst    -- pointer to instance.                              */
  2115. /*      ULONG ulParam1 -- flag for this message.                            */
  2116. /*      PVOID pParam2  -- pointer to structure (message dependent).         */
  2117. /*                                                                          */
  2118. /* EXIT CODES:                                                              */
  2119. /*      MCIERR_SUCCESS    -- action completed without error.                */
  2120. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  2121. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  2122. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  2123. /*      MCIERR_NO_CONNECTION      -- no way to play, no stream/DAC.         */
  2124. /*                                                                          */
  2125. /* NOTES:                                                                   */
  2126. /*                                                                          */
  2127. /****************************************************************************/
  2128.  
  2129. ULONG ProcSync(PINST pInst, ULONG ulParam1, MCIDRV_SYNC_PARMS *pParam2)
  2130. {
  2131.    ULONG rc;
  2132.    USHORT cnt=0;
  2133.  
  2134.    rc = ValState(pInst);
  2135.  
  2136.    if (rc != MCIERR_INSTANCE_INACTIVE)
  2137.    {
  2138.       /* validate flags */
  2139.       ulParam1 &= WAIT_NOTIFY_MASK;
  2140.       if (ulParam1 & MCIDRV_SYNC_ENABLE)
  2141.          cnt++;
  2142.       if (ulParam1 & MCIDRV_SYNC_DISABLE)
  2143.          cnt++;
  2144.       if (ulParam1 & MCIDRV_SYNC_SET_MASTER)
  2145.          cnt++;
  2146.       if (ulParam1 & MCIDRV_SYNC_REC_PULSE)
  2147.          cnt++;
  2148.       if (cnt > 1)
  2149.          return(MCIERR_FLAGS_NOT_COMPATIBLE);
  2150.  
  2151.       switch (ulParam1)
  2152.       {
  2153.          case MCIDRV_SYNC_ENABLE :
  2154.             rc = MCIERR_SUCCESS;
  2155.  
  2156.             if (pInst->ulMode & CDMC_INTDAC)
  2157.             {
  2158.                ulParam1 |= MCI_WAIT;
  2159.                rc = pInst->pMCIDriver(pInst->hHWMCID, MCIDRV_SYNC,
  2160.                                       &ulParam1, pParam2, 0);
  2161.             }
  2162.             else
  2163.                rc = MCIERR_NO_CONNECTION;   //no internal DAC
  2164.             break;
  2165.          case MCIDRV_SYNC_DISABLE :
  2166.          case MCIDRV_SYNC_MASTER :
  2167.             rc = MCIERR_SUCCESS;
  2168.          case MCIDRV_SYNC_REC_PULSE :
  2169.             if (!rc)
  2170.                if (pInst->ulMode & CDMC_INTDAC)
  2171.                {
  2172.                   ulParam1 |= MCI_WAIT;
  2173.                   rc = pInst->pMCIDriver(pInst->hHWMCID, MCIDRV_SYNC,
  2174.                                          &ulParam1, pParam2, 0);
  2175.                }
  2176.                else
  2177.                   if (!(pInst->ulMode & CDMC_STREAM))
  2178.                      rc = MCIERR_NO_CONNECTION;   //not streaming either
  2179.             break;
  2180.          case 0L :
  2181.             if (!rc)
  2182.                rc = MCIERR_MISSING_FLAG;
  2183.             break;
  2184.          default :
  2185.             if (!rc)
  2186.                rc = MCIERR_INVALID_FLAG;
  2187.       }  /* of switch */
  2188.  
  2189.       if (rc)
  2190.           rc = vsdResponse(pInst, rc);          //if error, process response
  2191.  
  2192.    }  /* if drive is ready for command */
  2193.  
  2194.    return(rc);
  2195.  
  2196. }  /* of ProcSync() */
  2197.  
  2198.  
  2199.