home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tolkit45.zip / os2tk45 / samples / mm / cdmcidrv / cdaudio.c < prev    next >
C/C++ Source or Header  |  1999-05-11  |  46KB  |  958 lines

  1. /****************************************************************************/
  2. /*                                                                          */
  3. /* SOURCE FILE NAME:  CDAUDIO.C                                             */
  4. /*                                                                          */
  5. /* DESCRIPTIVE NAME:  CD AUDIO MCI DRIVER                                   */
  6. /*                                                                          */
  7. /* COPYRIGHT:  (c) IBM Corp. 1991 - 1993                                    */
  8. /*                                                                          */
  9. /* FUNCTION:  This file contains the hardware independent code that the     */
  10. /*            CD Audio MCI Driver uses.  This includes the entry point for  */
  11. /*            the MDM/MCI calls to the DLL and the global structures,       */
  12. /*            utilities and parameter checking.  The Process Command        */
  13. /*            functions are in CDAUDPRO.C                                   */
  14. /*                                                                          */
  15. /*                                                                          */
  16. /* NOTES:  The hardware dependent code is found in file IBMCDROM.C.         */
  17. /*         This MCD (MCI Driver) is an example of a non-streaming MCD       */
  18. /*         with simple support.                                             */
  19. /*                                                                          */
  20. /* ENTRY POINTS:                                                            */
  21. /*       mciDriverEntry - performs component specific messages of this MCI  */
  22. /*                        Driver.                                           */
  23. /*                                                                          */
  24. /* OTHER FUNCTIONS:                                                         */
  25. /*       pre_process_msg - Pre-Process the requested command message.       */
  26. /*       process_msg   - Process the requested command message.             */
  27. /*       verify_entry  - Verify that entry parameters are valid.            */
  28. /*       QMAudio       - Query master audio's current settings.             */
  29. /*       Register      - Register drive.                                    */
  30. /*       ReRegister    - Register disc and tracks.                          */
  31. /*       VSDReturn     - Process return information from VSD.               */
  32. /*       SetTrackInst  - Set Track info in Instance, seek to start.         */
  33. /*       ValPointer    - Validate address to record structures.             */
  34. /*                                                                          */
  35. /*                                                                          */
  36. /****************************************************************************/
  37.  
  38. #define INCL_DOSERRORS
  39. #define INCL_DOSPROCESS
  40. #define INCL_DOSMEMMGR
  41. #define INCL_DOSMODULEMGR
  42. #define INCL_DOSSEMAPHORES
  43. #include <os2.h>
  44. #include <string.h>
  45. #define INCL_MCIOS2
  46. #include <os2me.h>
  47. #include <cdaudos2.h>
  48. #include "cdaudibm.h"
  49. #include "hhpheap.h"
  50.  
  51. extern PVOID          CDMC_hHeap;
  52.  
  53. /****************************************************************************/
  54. /*                                                                          */
  55. /* SUBROUTINE NAME:  mciDriverEntry                                         */
  56. /*                                                                          */
  57. /* DESCRIPTIVE NAME:  MCI Driver Entry                                      */
  58. /*                                                                          */
  59. /* FUNCTION:  Processes the CD Audio component commands.                    */
  60. /*                                                                          */
  61. /* PARAMETERS:                                                              */
  62. /*      PVOID  lpInstance -- Pointer to device handle.                      */
  63. /*      USHORT usMessage  -- Command message.                               */
  64. /*      ULONG  ulParam1   -- Flag for this message.                         */
  65. /*      PVOID  pParam2    -- Pointer to data record structure.              */
  66. /*      USHORT usUserParm -- User Parameter for mciDriverNotify.            */
  67. /*                                                                          */
  68. /* EXIT CODES:                                                              */
  69. /*      MCIERR_SUCCESS    -- Action completed without error.                */
  70. /*      MCIERR_INI_FILE   -- Corrupted file, invalid open or connection.    */
  71. /*      MCIERR_DEVICE_NOT_READY   -- Device was not ready, no disc.         */
  72. /*      MCIERR_DEVICE_OPEN        -- Error on open.                         */
  73. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  74. /*      MCIERR_INVALID_BUFFER     -- Buffer size was too small.             */
  75. /*      MCIERR_OUTOFRANGE         -- Invalid value or stream error.         */
  76. /*      MCIERR_NO_CONNECTION      -- No way to play, no stream/DAC          */
  77. /*      MCIERR_OUT_OF_MEMORY      -- Out of memory.                         */
  78. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  79. /*      MCIERR_PARAM_OVERFLOW     -- Invalid pointer in Parms.              */
  80. /*      MCIERR_MISSING_PARAMETER  -- Invalid PARMS pointer.                 */
  81. /*      MCIERR_INVALID_DEVICE_NAME  -- Illegal drive name.                  */
  82. /*      MCIERR_UNSUPPORTED_FUNCTION -- Invalid command message.             */
  83. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Invalid flag combinations.           */
  84. /*      MCIERR_INVALID_FLAG         -- Unknown or unsupported flag.         */
  85. /*      MCIERR_CANNOT_LOAD_DRIVER -- Unable to load VSD.                    */
  86. /*      MCIERR_INVALID_CUEPOINT       --  Unable to locate event.           */
  87. /*      MCIERR_CUEPOINT_LIMIT_REACHED --  No more room to add events.       */
  88. /*      MCIERR_DUPLICATE_CUEPOINT     --  Duplicate cuepoint.               */
  89. /*      MCIERR_INVALID_ITEM_FLAG  -- Invalid item specified.                */
  90. /*      MCIERR_INVALID_SPEED_FORMAT_FLAG -- Unknown speed type specified.   */
  91. /*      MCIERR_INVALID_TIME_FORMAT_FLAG  -- Unknown time type specified.    */
  92. /*      MCIERR_INVALID_CONNECTOR_INDEX -- Invalid connector specified.      */
  93. /*      MCIERR_INVALID_CONNECTOR_TYPE  -- Invalid connector specified.      */
  94. /*      MCIERR_UNSUPPORTED_CONN_TYPE   -- Unsupported connector specified.  */
  95. /*      MCIERR_INVALID_CALLBACK_HANDLE -- Invalid call back handle.         */
  96. /*      MCIERR_INVALID_AUDIO_FLAG -- Unknown audio flag specified.          */
  97. /*      MCIERR_DEVICE_LOCKED -- CD-ROM drive, previously opened exclusively.*/
  98. /*                                                                          */
  99. /* NOTES:  Assumes that if NOT MCI_WAIT then it is MCI_NOTIFY, no check     */
  100. /*         if no flag is passed.                                            */
  101. /*                                                                          */
  102. /****************************************************************************/
  103.  
  104. ULONG APIENTRY mciDriverEntry(PVOID lpInstance, USHORT usMessage,
  105.                               ULONG ulParam1, PVOID pParam2, USHORT usUserParm)
  106. {
  107.    ULONG rc;
  108.  
  109.    /* verify inputs */
  110.    rc = verify_entry((PINST)lpInstance, usMessage, ulParam1, &pParam2);
  111.  
  112.    if (!rc)
  113.       rc = process_msg((PINST)lpInstance, usMessage, &ulParam1,
  114.                        pParam2, usUserParm);
  115.  
  116.    /* if successful and notify is requested then send notification */
  117.    if (!(ULONG_LOWD(rc)) && ulParam1 & MCI_NOTIFY)
  118.    {
  119.       mdmDriverNotify(((struct instance_state *)lpInstance)->usDeviceID,
  120.                ((MCI_GENERIC_PARMS *)pParam2)->hwndCallback, MM_MCINOTIFY,
  121.                usUserParm, MAKEULONG(usMessage, MCI_NOTIFY_SUCCESSFUL));
  122.  
  123.    }  /* of if no error and NOTIFY is set */
  124.  
  125.    return(rc);
  126.  
  127. }  /* of mciDriverEntry() */
  128.  
  129.  
  130. /****************************************************************************/
  131. /*                                                                          */
  132. /* SUBROUTINE NAME:  pre_process_msg                                        */
  133. /*                                                                          */
  134. /* DESCRIPTIVE NAME:  Pre-process messages.                                 */
  135. /*                                                                          */
  136. /* FUNCTION:  The code for this function was in process_msg but was         */
  137. /*            placed here to make it neater.                                */
  138. /*                                                                          */
  139. /* PARAMETERS:                                                              */
  140. /*      PINST  pInst       -- instance pointer.                             */
  141. /*      USHORT *pusMessage -- requested action to be performed.             */
  142. /*      ULONG  ulParam1    -- flag for this message.                        */
  143. /*                                                                          */
  144. /* EXIT CODES:                                                              */
  145. /*      MCIERR_SUCCESS       -- action completed without error.             */
  146. /*                                                                          */
  147. /* NOTES:                                                                   */
  148. /*                                                                          */
  149. /****************************************************************************/
  150.  
  151. ULONG pre_process_msg(PINST pInst, USHORT *pusMessage, ULONG ulParam1)
  152. {
  153.    ULONG rc = MCIERR_SUCCESS;
  154.  
  155.    if (*pusMessage == MCIDRV_RESTORE)
  156.    {
  157.       /* process shareable flag */
  158.       if (ulParam1 & MCI_OPEN_SHAREABLE)
  159.          pInst->ulMode |= CDMC_SHAREABLE;
  160.       else
  161.          pInst->ulMode &= ~CDMC_SHAREABLE;
  162.  
  163.       if (pInst->usStatus < SUSPEND)
  164.          *pusMessage = 0;                  //ignore restores without a save
  165.    }  /* of id message is RESTORE */
  166.  
  167.    /* re-register if necessary */
  168.    if (pInst->usStatus <= NODISC)       //try registering disc and tracks
  169.       ReRegister(pInst);                //ignore RC, let message process state
  170.  
  171.    /* re-restore if necessary */
  172.    if (pInst->usStatus >= SUSPEND && *pusMessage == MCIDRV_SAVE)
  173.       *pusMessage = 0;                  //ignore saves when saved
  174.  
  175.    return(rc);
  176.  
  177. }  /* of pre_process_msg() */
  178.  
  179.  
  180. /****************************************************************************/
  181. /*                                                                          */
  182. /* SUBROUTINE NAME:  process_msg                                            */
  183. /*                                                                          */
  184. /* DESCRIPTIVE NAME:  Process Control Message                               */
  185. /*                                                                          */
  186. /* FUNCTION:  Processes the CD Audio commands.                              */
  187. /*                                                                          */
  188. /* PARAMETERS:                                                              */
  189. /*      PINST  pInst      -- instance pointer.                              */
  190. /*      USHORT usMessage  -- requested action to be performed.              */
  191. /*      ULONG  *pulParam1 -- pointer to flag for this message.              */
  192. /*      PVOID  pParam2    -- pointer to structure (message dependent).      */
  193. /*      USHORT usUserParm -- User Parameter for mciDriverNotify.            */
  194. /*                                                                          */
  195. /* EXIT CODES:                                                              */
  196. /*      MCIERR_SUCCESS    -- action completed without error.                */
  197. /*      MCIERR_INI_FILE   -- corrupted file, invalid open or connection.    */
  198. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  199. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  200. /*      MCIERR_OUTOFRANGE         -- Invalid value.                         */
  201. /*      MCIERR_NO_CONNECTION      -- No way to play, no stream/DAC.         */
  202. /*      MCIERR_OUT_OF_MEMORY      -- Out of memory.                         */
  203. /*      MCIERR_INSTANCE_INACTIVE  -- Instance is suspended.                 */
  204. /*      MCIERR_PARAM_OVERFLOW     -- Invalid PARMS pointer.                 */
  205. /*      MCIERR_INVALID_DEVICE_ID  -- invalid instance handle.               */
  206. /*      MCIERR_INVALID_BUFFER       -- Buffer size was too small.           */
  207. /*      MCIERR_UNSUPPORTED_FUNCTION -- Invalid command message.             */
  208. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Invalid flag combinations.           */
  209. /*      MCIERR_INVALID_FLAG         -- Unknown or unsupported flag.         */
  210. /*      MCIERR_INVALID_DEVICE_NAME  -- Illegal drive name.                  */
  211. /*      MCIERR_INVALID_CUEPOINT       --  unable to locate event.           */
  212. /*      MCIERR_CUEPOINT_LIMIT_REACHED --  no more room to add events.       */
  213. /*      MCIERR_DUPLICATE_CUEPOINT     --  duplicate cuepoint.               */
  214. /*      MCIERR_INVALID_ITEM_FLAG  -- Invalid item specified.                */
  215. /*      MCIERR_INVALID_SPEED_FORMAT_FLAG -- Unknown speed type specified.   */
  216. /*      MCIERR_INVALID_TIME_FORMAT_FLAG  -- Unknown time type specified.    */
  217. /*      MCIERR_INVALID_CONNECTOR_INDEX -- Invalid connector specified.      */
  218. /*      MCIERR_INVALID_CONNECTOR_TYPE  -- Invalid connector specified.      */
  219. /*      MCIERR_UNSUPPORTED_CONN_TYPE   -- Unsupported connector specified.  */
  220. /*      MCIERR_INVALID_CALLBACK_HANDLE -- invalid call back handle.         */
  221. /*      MCIERR_INVALID_AUDIO_FLAG  -- Unknown audio flag specified.         */
  222. /*      MCIERR_CANNOT_LOAD_DRIVER  -- Unable to load VSD.                   */
  223. /*      MCIERR_DEVICE_LOCKED -- CD-ROM drive, previously opened exclusively.*/
  224. /*                                                                          */
  225. /* NOTES:                                                                   */
  226. /*                                                                          */
  227. /*                                                                          */
  228. /****************************************************************************/
  229.  
  230. ULONG process_msg(PINST pInst, USHORT usMessage, ULONG *pulParam1,
  231.                   PVOID pParam2, USHORT usUserParm)
  232. {
  233.    ULONG rc;
  234.  
  235.    if (usMessage != MCI_OPEN)
  236.       DosRequestMutexSem(pInst->hInstSem, WAIT_FOREVER);
  237.  
  238.    /* bypass restores if opening or closing */
  239.    if (usMessage == MCI_CLOSE || usMessage == MCI_OPEN)
  240.       rc = MCIERR_SUCCESS;
  241.    else
  242.    {
  243.       if (rc = pre_process_msg(pInst, &usMessage, *pulParam1))
  244.       {
  245.          DosReleaseMutexSem(pInst->hInstSem);
  246.          return(rc);
  247.       }
  248.    }  /* of else not close */
  249.  
  250.    switch(usMessage)
  251.    {
  252.       case 0 :                /* save or restore when already in that state */
  253.          DosReleaseMutexSem(pInst->hInstSem);
  254.          break;
  255.       case MCI_CLOSE :
  256.          rc = ProcClose(pInst, pulParam1, pParam2, usUserParm);
  257.          break;
  258.       case MCI_CONNECTOR :
  259.          rc = ProcConnector(pInst, *pulParam1, (MCI_CONNECTOR_PARMS *)pParam2);
  260.          DosReleaseMutexSem(pInst->hInstSem);
  261.          break;
  262.       case MCI_CUE :
  263.          rc = ProcCue(pInst, *pulParam1);
  264.          DosReleaseMutexSem(pInst->hInstSem);
  265.          break;
  266.       case MCI_ESCAPE :
  267.          DosReleaseMutexSem(pInst->hInstSem);  /* can't provide protection */
  268.          rc = ProcGeneral(pInst, usMessage, pulParam1, pParam2, usUserParm);
  269.          break;
  270.       case MCI_GETDEVCAPS :
  271.          DosReleaseMutexSem(pInst->hInstSem);  /* doesn't need protection */
  272.          rc = ProcCaps(pInst, *pulParam1, (MCI_GETDEVCAPS_PARMS *) pParam2);
  273.          break;
  274.       case MCI_GETTOC :
  275.          DosReleaseMutexSem(pInst->hInstSem);  /* doesn't need protection */
  276.          rc = ProcGeneral(pInst, usMessage, pulParam1, pParam2, usUserParm);
  277.          break;
  278.       case MCI_INFO :
  279.          DosReleaseMutexSem(pInst->hInstSem);  /* doesn't need protection */
  280.          rc = ProcInfo(pInst, *pulParam1, (MCI_INFO_PARMS *)pParam2);
  281.          break;
  282.       case MCI_MASTERAUDIO :
  283.          rc = ProcMAudio(pInst, *pulParam1, (MCI_MASTERAUDIO_PARMS *)pParam2);
  284.          DosReleaseMutexSem(pInst->hInstSem);
  285.          break;
  286.       case MCI_OPEN :
  287.          rc = ProcOpen(pulParam1, (MMDRV_OPEN_PARMS *)pParam2, usUserParm);
  288.          break;
  289.       case MCI_PAUSE :
  290.          rc = ProcPause(pInst, *pulParam1);
  291.          DosReleaseMutexSem(pInst->hInstSem);
  292.          break;
  293.       case MCI_PLAY :
  294.          rc = ProcPlay(pInst, pulParam1, (MCI_PLAY_PARMS *)pParam2,
  295.                            usUserParm);
  296.          break;
  297.       case MCIDRV_RESTORE :
  298.          ProcRestore(pInst);      //from MDM, return success
  299.          DosReleaseMutexSem(pInst->hInstSem);
  300.          break;
  301.       case MCI_RESUME :
  302.          rc = ProcResume(pInst, *pulParam1);
  303.          DosReleaseMutexSem(pInst->hInstSem);
  304.          break;
  305.       case MCIDRV_SAVE :
  306.          ProcSave(pInst);         //from MDM, return success
  307.          DosReleaseMutexSem(pInst->hInstSem);
  308.          break;
  309.       case MCI_SEEK :
  310.          rc = ProcSeek(pInst, *pulParam1, (MCI_SEEK_PARMS *) pParam2);
  311.          DosReleaseMutexSem(pInst->hInstSem);
  312.          break;
  313.       case MCI_SET :
  314.          rc = ProcSet(pInst, pulParam1, (MCI_SET_PARMS *) pParam2);
  315.          break;
  316.       case MCI_SET_CUEPOINT :
  317.          rc = ProcCuePoint(pInst, *pulParam1, (MCI_CUEPOINT_PARMS *) pParam2);
  318.          DosReleaseMutexSem(pInst->hInstSem);
  319.          break;
  320.       case MCI_SET_POSITION_ADVISE :
  321.          rc = ProcPosAdvise(pInst, *pulParam1, (MCI_POSITION_PARMS *) pParam2);
  322.          DosReleaseMutexSem(pInst->hInstSem);
  323.          break;
  324.       case MCI_SET_SYNC_OFFSET :
  325.          rc = ProcSetSync(pInst, *pulParam1, (MCI_SYNC_OFFSET_PARMS *) pParam2);
  326.          DosReleaseMutexSem(pInst->hInstSem);
  327.          break;
  328.       case MCI_STATUS :
  329.          rc = ProcStatus(pInst, *pulParam1, (MCI_STATUS_PARMS *) pParam2);
  330.          DosReleaseMutexSem(pInst->hInstSem);
  331.          break;
  332.       case MCI_STOP :
  333.          rc = ProcStop(pInst, *pulParam1);
  334.          DosReleaseMutexSem(pInst->hInstSem);
  335.          break;
  336.       case MCIDRV_SYNC :
  337.          rc = ProcSync(pInst, *pulParam1, (MCIDRV_SYNC_PARMS *) pParam2);
  338.          DosReleaseMutexSem(pInst->hInstSem);
  339.          break;
  340.       default :
  341.          DosReleaseMutexSem(pInst->hInstSem);  /* can't provide protection */
  342.          rc = ProcGeneral(pInst, usMessage, pulParam1, pParam2, usUserParm);
  343.    }  /* of switch */
  344.  
  345.    return(rc);
  346.  
  347. }  /* of process_msg() */
  348.  
  349.  
  350. /****************************************************************************/
  351. /*                                                                          */
  352. /* SUBROUTINE NAME:  verify_entry                                           */
  353. /*                                                                          */
  354. /* DESCRIPTIVE NAME:  Verify Entry.                                         */
  355. /*                                                                          */
  356. /* FUNCTION:  Verifies the input parameters from the mciDriverEntry         */
  357. /*            point of entry.  The handle or instance pointer is verified   */
  358. /*            to be a valid open instance.  Also the PARMS record pointer   */
  359. /*            is validated to be in a writable data segment.                */
  360. /*                                                                          */
  361. /* PARAMETERS:                                                              */
  362. /*      PINST  pInst     -- instance pointer.                               */
  363. /*      USHORT usMessage -- requested action to be performed.               */
  364. /*      ULONG  ulParam1  -- flag for this message.                          */
  365. /*      PVOID  pParam2   -- pointer to structure (message dependent).       */
  366. /*                                                                          */
  367. /* EXIT CODES:                                                              */
  368. /*      MCIERR_SUCCESS    -- action completed without error.                */
  369. /*      MCIERR_INI_FILE   -- open device type is not CD Audio.              */
  370. /*      MCIERR_INVALID_DEVICE_ID -- invalid instance handle.                */
  371. /*      MCIERR_INVALID_BUFFER    -- invalid pointer in o/p buffer.          */
  372. /*      MCIERR_MISSING_PARAMETER -- invalid PARMS pointer, or i/p buffer.   */
  373. /*      MCIERR_OUT_OF_MEMORY     -- out of memory.                          */
  374. /*      MCIERR_UNSUPPORTED_FUNCTION -- Invalid command message.             */
  375. /*                                                                          */
  376. /* NOTES:                                                                   */
  377. /*                                                                          */
  378. /****************************************************************************/
  379.  
  380. ULONG verify_entry(PINST pInst, USHORT usMessage,
  381.                    ULONG ulParam1, PVOID *pParam2)
  382. {
  383.    ULONG rc = MCIERR_SUCCESS;
  384.    USHORT usFlag;
  385.  
  386.    if (usMessage == MCI_OPEN)      /* make sure correct device type is used */
  387.    {
  388.       if (((MMDRV_OPEN_PARMS *)*pParam2)->usDeviceType != MCI_DEVTYPE_CD_AUDIO)
  389.          rc = MCIERR_INI_FILE;
  390.    }
  391.    else          /* verify that component handle exists and is valid */
  392.    {
  393.       if (!usMessage)
  394.          rc = MCIERR_UNSUPPORTED_FUNCTION;
  395.  
  396.       if (ValPointer(pInst, VALLEN))                // is it a real pointer?
  397.          rc = MCIERR_INVALID_DEVICE_ID;
  398.       else
  399.          if (strncmp(pInst->valid, VALIDID, VALLEN))   // does it point to
  400.             rc = MCIERR_INVALID_DEVICE_ID;             // an instance?
  401.  
  402.       if (rc && (usMessage == MCI_DEVICESETTINGS))     // DevSets don't need an
  403.          rc = MCIERR_UNSUPPORTED_FUNCTION;             // instance ptr
  404.  
  405.    }  /* of if not open */
  406.  
  407.    /* test *pParam2 is a valid pointer */
  408.    if (!rc)
  409.    {
  410.       switch (usMessage)       /* does message require pParam2 ? */
  411.       {
  412.          case MCI_DEVICESETTINGS :
  413.          case MCI_ESCAPE :       case MCI_GETDEVCAPS :
  414.          case MCI_GETTOC :       case MCI_INFO :         case MCI_LOAD :
  415.          case MCI_MASTERAUDIO :  case MCI_OPEN :         case MCI_RECORD :
  416.          case MCI_SAVE:          case MCI_SET_CUEPOINT :
  417.          case MCI_SET_POSITION_ADVISE :          case MCI_SET_SYNC_OFFSET :
  418.          case MCI_STATUS :       case MCI_STEP :         case MCI_SYSINFO :
  419.             usFlag = TRUE;
  420.             break;
  421.          case MCI_CONNECTOR :
  422.             if (ulParam1 & (MCI_QUERY_CONNECTOR_STATUS |
  423.                             MCI_CONNECTOR_TYPE | MCI_CONNECTOR_INDEX))
  424.                usFlag = TRUE;
  425.             else
  426.                usFlag = FALSE;
  427.             break;
  428.          case MCI_PLAY :
  429.             if (ulParam1 & MCI_FROM || ulParam1 & MCI_TO)
  430.                usFlag = TRUE;
  431.             else
  432.                usFlag = FALSE;
  433.             break;
  434.          case MCI_SEEK :
  435.             if (ulParam1 & MCI_TO)
  436.                usFlag = TRUE;
  437.             else
  438.                usFlag = FALSE;
  439.             break;
  440.          case MCI_SET :
  441.             if (ulParam1 & MCI_SET_AUDIO || ulParam1 & MCI_SET_SPEED_FORMAT ||
  442.                 ulParam1 & MCI_SET_TIME_FORMAT || ulParam1 & MCI_SET_VOLUME ||
  443.                 ulParam1 & MCI_OVER)
  444.                usFlag = TRUE;
  445.             else
  446.                usFlag = FALSE;
  447.             break;
  448.          default :                       /* other commands are on their own */
  449.             usFlag = FALSE;
  450.       }  /* of switch */
  451.  
  452.       /* Verify that pParam2 is a valid pointer if necessary */
  453.       rc = ValPointer(*pParam2, sizeof(ULONG));
  454.       if (rc && (!(ulParam1 & MCI_NOTIFY) && !usFlag))
  455.       {
  456.          rc = MCIERR_SUCCESS;   //pParam2 not required
  457.          *pParam2 = NULL;
  458.       }
  459.    }  /* of if no error */
  460.  
  461.    return(rc);
  462.  
  463. }  /* of verify_entry() */
  464.  
  465.  
  466. /****************************************************************************/
  467. /*                                                                          */
  468. /* SUBROUTINE NAME:  QMAudio                                                */
  469. /*                                                                          */
  470. /* DESCRIPTIVE NAME:  Query Master Audio                                    */
  471. /*                                                                          */
  472. /* FUNCTION:  Query current volume and headphone/speaker settings from      */
  473. /*            Master Audio.                                                 */
  474. /*                                                                          */
  475. /* PARAMETERS:                                                              */
  476. /*      PINST pInst    -- pointer to instance.                              */
  477. /*                                                                          */
  478. /* EXIT CODES:   None                                                       */
  479. /*                                                                          */
  480. /* NOTES:                                                                   */
  481. /*                                                                          */
  482. /****************************************************************************/
  483.  
  484. VOID QMAudio(PINST pInst)
  485. {
  486.    ULONG rc;
  487.    USHORT ulChanType = 0L;
  488.    MCI_MASTERAUDIO_PARMS recMasterAudio;
  489.  
  490.    /* get current master volume */
  491.    rc = mciSendCommand(pInst->usDeviceID, MCI_MASTERAUDIO,
  492.                       MCI_WAIT | MCI_QUERYCURRENTSETTING | MCI_MASTERVOL,
  493.                       &recMasterAudio, 0);
  494.    if (ULONG_LOWD(rc))
  495.    {
  496.       if (pInst->ulMasterVolume == (ULONG) -1L)
  497.          pInst->ulMasterVolume = 75L;     //if first time error set to default
  498.    }
  499.    else
  500.       pInst->ulMasterVolume = recMasterAudio.ulReturn;
  501.  
  502.    /* get current speaker status */
  503.    rc = mciSendCommand(pInst->usDeviceID, MCI_MASTERAUDIO,
  504.                        MCI_WAIT | MCI_QUERYCURRENTSETTING | MCI_SPEAKERS,
  505.                        &recMasterAudio, 0);
  506.    if (ULONG_LOWD(rc))
  507.       ulChanType = CDMC_SPEAKER;          //if error set to default
  508.    else
  509.       if (recMasterAudio.ulReturn)
  510.          ulChanType = CDMC_SPEAKER;       //SPEAKERS are turned on
  511.  
  512.    /* get current headphone status */
  513.    rc = mciSendCommand(pInst->usDeviceID, MCI_MASTERAUDIO,
  514.                        MCI_WAIT | MCI_QUERYCURRENTSETTING | MCI_HEADPHONES,
  515.                        &recMasterAudio, 0);
  516.    if (ULONG_LOWD(rc))
  517.       ulChanType |= CDMC_HEADPHONE;       //if error set to default
  518.    else
  519.       if (recMasterAudio.ulReturn)
  520.          ulChanType |= CDMC_HEADPHONE;    //HEADPHONES are turned on
  521.  
  522.    pInst->ulMode = (pInst->ulMode & CHAN_TYPE_SET) | ulChanType;
  523.  
  524. }  /* of QMAudio() */
  525.  
  526.  
  527. /****************************************************************************/
  528. /*                                                                          */
  529. /* SUBROUTINE NAME:  Register                                               */
  530. /*                                                                          */
  531. /* DESCRIPTIVE NAME:  Register.                                             */
  532. /*                                                                          */
  533. /* FUNCTION:  Register the CD-ROM Drive for the MCI Driver.                 */
  534. /*                                                                          */
  535. /* PARAMETERS:                                                              */
  536. /*      PINST pInst    -- pointer to instance.                              */
  537. /*                                                                          */
  538. /* EXIT CODES:                                                              */
  539. /*      MCIERR_SUCCESS    -- action completed without error.                */
  540. /*      MCIERR_OUT_OF_MEMORY  -- couldn't allocate memory for semaphore.    */
  541. /*                                                                          */
  542. /* NOTES:                                                                   */
  543. /*                                                                          */
  544. /****************************************************************************/
  545.  
  546. ULONG Register(PINST pInst)
  547. {
  548.    ULONG rc;
  549.    MCI_CD_REGDRIVE_PARMS recDrive;
  550.  
  551.    /* register drive */
  552.    recDrive.ulCDMCDID = (ULONG) pInst;
  553.    recDrive.pCDMCDReturn = VSDReturn;
  554.    rc = pInst->pMCIDriver(pInst->hHWMCID, MCIDRV_REGISTER_DRIVE, 0L,
  555.                           &recDrive, 0);
  556.    if (!rc)
  557.    {
  558.       pInst->usStatus = REGDRIVE;
  559.       pInst->usCaps = recDrive.usCaps;
  560.       pInst->ulPrerollType  = recDrive.ulPrerollType;
  561.       pInst->ulPrerollTime  = recDrive.ulPrerollTime;
  562.       pInst->ulMinStartTime = recDrive.ulMinStartTime;
  563.  
  564.       /* STREAM_CAP field in ulMode was cleared in ProcOpen() */
  565.       if (recDrive.usCaps & CDVSD_CAP_HAS_DAC)
  566.       {
  567.          pInst->ulMode |= CDMC_CAN_DAC;
  568.          pInst->ulMode |= CDMC_INTDAC;
  569.       }
  570.  
  571.       if (recDrive.usCaps & CDVSD_CAP_CAN_STREAM)
  572.          pInst->ulMode |= CDMC_CAN_STREAM;
  573.          /* just set potential to stream, don't go into stream mode until */
  574.          /* the MCI_CONNECTOR command message is sent.                    */
  575.  
  576.       if (rc)         /* if error, clear stream mode */
  577.          pInst->ulMode &= STREAM_MODE_SET;
  578.  
  579.    }  /* of if no error registering drive */
  580.  
  581.    return(rc);
  582.  
  583. }  /* of Register() */
  584.  
  585.  
  586. /****************************************************************************/
  587. /*                                                                          */
  588. /* SUBROUTINE NAME:  ReRegister                                             */
  589. /*                                                                          */
  590. /* DESCRIPTIVE NAME:  Re-Register.                                          */
  591. /*                                                                          */
  592. /* FUNCTION:  Register the discs and tracks for the MCI Driver.             */
  593. /*                                                                          */
  594. /* PARAMETERS:                                                              */
  595. /*      PINST pInst    -- pointer to instance.                              */
  596. /*                                                                          */
  597. /* EXIT CODES:                                                              */
  598. /*      MCIERR_SUCCESS    -- action completed without error.                */
  599. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  600. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  601. /*                                                                          */
  602. /* NOTES:                                                                   */
  603. /*                                                                          */
  604. /****************************************************************************/
  605.  
  606. ULONG ReRegister(PINST pInst)
  607. {
  608.    ULONG rc = MCIERR_SUCCESS;                 // assume the best
  609.    ULONG ulSetParam1;
  610.    ULONG ulInfoSize;
  611.    USHORT usTemp, usChange = TRUE;
  612.    MCI_SET_PARMS recSet;
  613.    MCI_CD_ID DiscID;
  614.  
  615.    memcpy(&DiscID, &pInst->recDisc.DiscID, IDSIZE);
  616.    /* Get new disk information */
  617.    rc = pInst->pMCIDriver(pInst->hHWMCID, MCIDRV_REGISTER_DISC, 0L,
  618.                           &pInst->recDisc, 0);
  619.  
  620.    if (rc == MCIERR_MEDIA_CHANGED)    // Get it again to make sure
  621.       pInst->pMCIDriver(pInst->hHWMCID, MCIDRV_REGISTER_DISC, 0L,
  622.                         &pInst->recDisc, 0);
  623.  
  624.    /* if no error and previous disc check to see if it's the same */
  625.    if (!rc && DiscID.Mode != (BYTE) -1)
  626.       if (memcmp(&pInst->recDisc.DiscID, &DiscID, IDSIZE))
  627.          rc = MCIERR_MEDIA_CHANGED;
  628.       else
  629.          usChange = FALSE;     //same disc perhaps
  630.  
  631.    if (rc && rc != MCIERR_MEDIA_CHANGED)
  632.       pInst->usStatus = REGDRIVE;          //Reg Disc, failed
  633.    else
  634.    {  /* Disc was registered */
  635.  
  636.       /* set initial volume */
  637.       if (pInst->ulMasterVolume == (ULONG) -1L)
  638.       {
  639.          /* if mastervolume is not set then set it */
  640.          /* get current master volume */
  641.          QMAudio(pInst);
  642.  
  643.          /* set local volume */
  644.          usTemp = pInst->usStatus;
  645.          pInst->usStatus = STOPPED;
  646.          recSet.ulAudio = MCI_SET_AUDIO_LEFT;
  647.          recSet.ulLevel = (ULONG) VOL_LEFT(pInst->ulLevel);
  648.          recSet.ulOver  = 0L;
  649.          ulSetParam1 = MCI_SET_AUDIO | MCI_SET_VOLUME | MCI_WAIT;
  650.          ProcSet(pInst, &ulSetParam1, &recSet);
  651.          pInst->usStatus = usTemp;
  652.  
  653.       }  /* of setting the device with initial volume setting */
  654.  
  655.       ulInfoSize = (pInst->recDisc.HighestTrackNum -
  656.                     pInst->recDisc.LowestTrackNum + 1) *
  657.                     sizeof(MCI_CD_REGTRACK_REC);
  658.  
  659.       /* make sure we have enough memory to hold new disc */
  660.       if (ulInfoSize > pInst->ulTrackInfoSize)
  661.       {
  662.          /* free old pointer if one existed */
  663.          if (pInst->ulTrackInfoSize)
  664.             HhpFreeMem(CDMC_hHeap, pInst->pTrackInfo);
  665.          pInst->pTrackInfo = HhpAllocMem(CDMC_hHeap, (size_t)ulInfoSize);
  666.  
  667.          if (pInst->pTrackInfo == NULL)
  668.          {
  669.             pInst->ulTrackInfoSize = 0;
  670.             pInst->usStatus = REGDISC;          //No memory to reg tracks
  671.          }
  672.          else
  673.             pInst->ulTrackInfoSize = ulInfoSize;
  674.       }  /* of if need more memory */
  675.  
  676.       /* Get ready to get track info */
  677.       pInst->recTrack.ulBufSize = pInst->ulTrackInfoSize;
  678.       pInst->recTrack.TrackRecArr = (MCI_CD_REGTRACK_REC *)pInst->pTrackInfo;
  679.  
  680.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCIDRV_REGISTER_TRACKS, 0L,
  681.                              &pInst->recTrack, 0);
  682.  
  683.       if (rc)
  684.          pInst->usStatus = REGDRIVE;     //Reg Tracks failed
  685.       else
  686.       {
  687.          /* Set Track Info into instance & Seek to start of first audio track */
  688.          pInst->usStatus = REGTRACK;
  689.          rc = SetTrackInst(pInst, usChange);
  690.  
  691.          /* report change only if there was a previous disc */
  692.          if (!rc && usChange && DiscID.Mode != (BYTE) -1)
  693.             rc = MCIERR_MEDIA_CHANGED;
  694.  
  695.       }   /* of else no error registering tracks */
  696.    }   /* of else no error registering disc */
  697.  
  698.    if (rc == MCIERR_MEDIA_CHANGED || rc == MCIERR_INVALID_MEDIA_TYPE)
  699.       DisableEvents(pInst);
  700.    if (rc == MCIERR_MEDIA_CHANGED)
  701.       rc = MCIERR_SUCCESS;
  702.  
  703.    return(rc);
  704.  
  705. }  /* of ReRegister() */
  706.  
  707.  
  708. /****************************************************************************/
  709. /*                                                                          */
  710. /* SUBROUTINE NAME:  VSDReturn                                              */
  711. /*                                                                          */
  712. /* DESCRIPTIVE NAME:  VSD Return                                            */
  713. /*                                                                          */
  714. /* FUNCTION:  Process return information from VSDs.  This function is       */
  715. /*            called by the VSD to inform the MCD of changes in the         */
  716. /*            component mode or state.  This is needed when the VSD         */
  717. /*            creates a thread to process a command (ie MCI_PLAY with       */
  718. /*            MCI_NOTIFY) and needs to inform the MCD of the results        */
  719. /*            (ie PLAY terminated because of an error or PLAY completed     */
  720. /*            and the MCD must now be in a STOPPED state).  This function   */
  721. /*            is called also by the VSD when a non-standard message or      */
  722. /*            MCI_ESCAPE alters the mode of the device (ie it stops is).    */
  723. /*                                                                          */
  724. /* PARAMETERS:                                                              */
  725. /*      ULONG pInst     -- MCD Instance ID / pointer to instance.           */
  726. /*      ULONG ulMsgParm -- Message Parm, same format as in mdmDriverNotify()*/
  727. /*      ULONG ulMode    -- Mode the component is in.                        */
  728. /*                                                                          */
  729. /* EXIT CODES: None                                                         */
  730. /*                                                                          */
  731. /* NOTES:                                                                   */
  732. /*                                                                          */
  733. /****************************************************************************/
  734.  
  735. VOID VSDReturn(ULONG pInst, ULONG ulMsgParm, ULONG ulMode)
  736. {
  737.    USHORT usMessage, usErrorCode, usChange = FALSE;
  738.  
  739.    /* extract error and message codes */
  740.    usMessage   = LOUSHORT(ulMsgParm);
  741.    usErrorCode = HIUSHORT(ulMsgParm);
  742.  
  743.    switch(usMessage)
  744.    {
  745.       case MCI_PLAY :
  746.          if (usErrorCode != MCI_NOTIFY_SUPERSEDED &&
  747.              usErrorCode != MCI_NOTIFY_ABORTED)
  748.          {
  749.             usChange = TRUE;                   //PLAY completed or had error
  750.             ulMode = MCI_MODE_STOP;
  751.          }
  752.          break;
  753.       case MCI_CONNECTOR :    case MCI_GETDEVCAPS :   case MCI_GETTOC :
  754.       case MCI_INFO :         case MCI_MASTERAUDIO :  case MCI_OPEN :
  755.       case MCI_RECORD :       case MCI_SAVE:          case MCI_SEEK :
  756.       case MCI_SET_CUEPOINT :
  757.       case MCI_SET_POSITION_ADVISE :          case MCI_SET_SYNC_OFFSET :
  758.       case MCI_STATUS :       case MCI_STEP :         case MCI_SYSINFO :
  759.          break;                          // messages processed by MCD
  760.       case MCI_LOAD :         case MCI_SET :
  761.          usChange = TRUE;                // possible change, listen to VSD
  762.          break;
  763.       default :                          // unknown message, listen to VSD
  764.          usChange = TRUE;
  765.  
  766.    }  /* of switch */
  767.  
  768.    if (usChange)
  769.    {
  770.       switch (ulMode)
  771.       {
  772.          case MCI_MODE_NOT_READY :
  773.             ((PINST) pInst)->usStatus = NODISC;
  774.             break;
  775.          case MCI_MODE_PAUSE :
  776.             ((PINST) pInst)->usStatus = PAUSED;
  777.             break;
  778.          case MCI_MODE_PLAY :
  779.             ((PINST) pInst)->usStatus = PLAYING;
  780.             break;
  781.          case MCI_MODE_STOP :
  782.             ((PINST) pInst)->usStatus = STOPPED;
  783.             break;
  784.  
  785.       }  /* of switch */
  786.    }  /* of if change was needed */
  787. }  /* of VSDReturn() */
  788.  
  789.  
  790. /****************************************************************************/
  791. /*                                                                          */
  792. /* SUBROUTINE NAME:  SetTrackInst                                           */
  793. /*                                                                          */
  794. /* DESCRIPTIVE NAME:  Set Track Information of Instance.                    */
  795. /*                                                                          */
  796. /* FUNCTION:  Sets the Track related information in the instance structure. */
  797. /*            It also seeks to the start of the first audio track.          */
  798. /*            If any error occurs, it will update the usStatus field        */
  799. /*            as an extension of the registration portion.                  */
  800. /*                                                                          */
  801. /* PARAMETERS:                                                              */
  802. /*      PINST  pInst    -- pointer to instance.                             */
  803. /*      USHORT usChange -- Change Disc flag.                                */
  804. /*                                                                          */
  805. /* EXIT CODES:                                                              */
  806. /*      MCIERR_SUCCESS    -- action completed without error.                */
  807. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  808. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  809. /*      MCIERR_MEDIA_CHANGED      -- different disc was inserted.           */
  810. /*                                                                          */
  811. /* NOTES:  MCIERR_MEDIA_CHANGED is returned when usChange is FALSE and      */
  812. /*         a difference was found, otherwise it expects that the            */
  813. /*         calling function is aware of the change and will return          */
  814. /*         MCIERR_MEDIA_CHANGED if needed.                                  */
  815. /*                                                                          */
  816. /****************************************************************************/
  817.  
  818. ULONG SetTrackInst(PINST pInst, USHORT usChange)
  819. {
  820.    ULONG rc = MCIERR_SUCCESS;          // assume the best
  821.    int i, cnt;
  822.    MCI_SEEK_PARMS recSeek;
  823.    MCI_STATUS_PARMS recStatus;
  824.    ULONG ulParam1, ulDirt = FALSE, ulFlags;
  825.  
  826.    cnt =  (BYTE) (pInst->recDisc.HighestTrackNum -
  827.                   pInst->recDisc.LowestTrackNum + 1);
  828.  
  829.    /* find the start of the audio section */
  830.    for (i = 0; i < cnt; i++)
  831.    {
  832.       if (!((pInst->recTrack.TrackRecArr + i)->TrackControl & IS_DATA_TRK))
  833.       {
  834.          pInst->ulStart_disk = (pInst->recTrack.TrackRecArr + i)->ulStartAddr;
  835.          break;
  836.       }
  837.    }   /* of for loop, finding first audio track */
  838.  
  839.    /* Did we get it ? */
  840.    if (i == cnt)
  841.    {
  842.       pInst->ulStart_disk = 0L;
  843.       pInst->ulEnd_disk = 0L;
  844.       pInst->ulCur_pos = 0L;
  845.       rc = MCIERR_INVALID_MEDIA_TYPE;
  846.    }
  847.    else
  848.    {
  849.       /* find last audio track */
  850.       for (i = cnt-1; ; i--)
  851.       {
  852.          if (!((pInst->recTrack.TrackRecArr + i)->TrackControl & IS_DATA_TRK))
  853.          {
  854.             pInst->ulEnd_disk = (pInst->recTrack.TrackRecArr + i)->ulEndAddr;
  855.             break;
  856.          }
  857.       }   /* of for loop, finding last audio track */
  858.  
  859.       if (usChange)
  860.          /* now seek to start of playable disc */
  861.          recSeek.ulTo = pInst->ulStart_disk;
  862.       else   // we think its the same disc, reseek to current position
  863.       {
  864.          recStatus.ulItem = MCI_STATUS_POSITION;
  865.          ulFlags = MCI_STATUS_ITEM | MCI_WAIT;
  866.          rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STATUS,
  867.                                 &ulFlags, &recStatus, 0);
  868.          if (ULONG_LOWD(rc))
  869.             rc = vsdResponse(pInst, rc);
  870.          else
  871.             recSeek.ulTo = recStatus.ulReturn;
  872.  
  873.          if (rc)  //error getting current position, try last known position
  874.          {
  875.             rc = MCIERR_SUCCESS;
  876.             recSeek.ulTo = pInst->ulCur_pos;
  877.             ulDirt = TRUE;
  878.          }
  879.  
  880.          if (ValAddress(pInst, NULL, &recSeek.ulTo, FALSE))
  881.          {
  882.             recSeek.ulTo = pInst->ulStart_disk;
  883.             ulDirt = TRUE;
  884.          }
  885.       }  /* of else assuming same disc */
  886.  
  887.       /* check hardware start limitations */
  888.       if (recSeek.ulTo < pInst->ulMinStartTime)
  889.          recSeek.ulTo = pInst->ulMinStartTime;
  890.  
  891.       ulParam1 = MCI_TO | MCI_WAIT;
  892.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_SEEK, &ulParam1, &recSeek, 0);
  893.  
  894.       /* just incase they changed the disc again, check it */
  895.       if (rc)
  896.          rc = vsdResponse(pInst, rc);
  897.       else
  898.       {
  899.          pInst->usStatus = STOPPED;
  900.          pInst->ulCur_pos = recSeek.ulTo;
  901.          if (ulDirt)
  902.             rc = MCIERR_MEDIA_CHANGED;
  903.  
  904.       }  /* of else no error seeking */
  905.    }  /* of else disc contains playable tracks */
  906.  
  907.    return(rc);
  908.  
  909. }  /* of SetTrackInst() */
  910.  
  911.  
  912.  
  913. /****************************************************************************/
  914. /*                                                                          */
  915. /* SUBROUTINE NAME:  ValPointer                                             */
  916. /*                                                                          */
  917. /* DESCRIPTIVE NAME:  Validate Pointer                                      */
  918. /*                                                                          */
  919. /* FUNCTION:  Validate Pointers as writable addresses.                      */
  920. /*                                                                          */
  921. /* PARAMETERS:                                                              */
  922. /*      PVOID  ptr     -- pointer, address to be checked.                   */
  923. /*      ULONG  usLen   -- length to be checked.                             */
  924. /*                                                                          */
  925. /* EXIT CODES:                                                              */
  926. /*      MCIERR_SUCCESS    -- action completed without error.                */
  927. /*      MCIERR_MISSING_PARAMETER -- invalid pointer.                        */
  928. /*                                                                          */
  929. /* NOTES:   If interrupted, pretend that it was successful.                 */
  930. /*                                                                          */
  931. /*                                                                          */
  932. /****************************************************************************/
  933.  
  934. ULONG ValPointer(PVOID ptr, ULONG ulLen)
  935. {
  936.    ULONG rc = MCIERR_SUCCESS;          // assume the best
  937.    ULONG ulFlags;
  938.  
  939.    if (ptr == 0L)
  940.       rc = MCIERR_MISSING_PARAMETER;
  941.    else
  942.    {
  943.       rc = DosQueryMem(ptr, &ulLen, &ulFlags);
  944.  
  945.       if (rc != ERROR_INTERRUPT)            // ignore interruptions
  946.          if (rc)
  947.             rc = MCIERR_MISSING_PARAMETER;
  948.          else
  949.             if (!(ulFlags & PAG_WRITE))
  950.                rc = MCIERR_MISSING_PARAMETER;
  951.    }
  952.  
  953.    return(rc);
  954.  
  955. }  /* of ValPointer() */
  956.  
  957.  
  958.