home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional Developers Kit 1992 November / Disc01 / Disc01.mdf / runnable / mmos2 / mmtoolkt / samples / audiodd / mmddcmds.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-06  |  34.4 KB  |  978 lines

  1. /**************************START OF SPECIFICATIONS **************************/
  2. /*                                                                          */
  3. /* SOURCE FILE NAME:  MMDDCMDS.C        (TEMPLATE SAMPLE)                   */
  4. /*                                                                          */
  5. /* DISCRIPTIVE NAME: Audio device driver IDC routines for MMPM/2            */
  6. /*                                                                          */
  7. /* LINKAGE: near calls                                                      */
  8. /*                                                                          */
  9. /* DESCRIPTION: Process IOCTLS received from the Amp Mixer and stream data  */
  10. /*              to/from the stream handler.                                 */
  11. /************************** END OF SPECIFICATIONS ***************************/
  12.  
  13.  
  14. //****************************************************************************
  15. //                     I N C L U D E S
  16. //****************************************************************************
  17.  
  18. #define         INCL_NOPMAPI
  19. #define         INCL_BASE
  20. #define         INCL_DOS
  21. #define         INCL_DOSDEVICES
  22. #define         INCL_ERRORS
  23. #include        <os2.h>
  24.  
  25. #include        <os2medef.h>
  26. #include        <meerror.h>     // Multimedia error return codes
  27. #include        <ssm.h>         // Sync Stream Manager
  28. #include        <shdd.h>        // IDC interface
  29. #include        <audio.h>
  30. #include        "audiodd.h"
  31. #include        "audsubs.h"
  32. #include        "cdevhlp.h"
  33.  
  34. //**************************************************
  35. //      IDC MMPM/2 routines
  36. //**************************************************
  37.  
  38. VOID    ShdReportInt (ULONG);
  39.  
  40. RC  FAR DDCMDInternalEntryPoint(PDDCMDCOMMON pCommon);  // Called from stream handler
  41. RC      DDCmdSetup( PDDCMDSETUP pSetup );
  42. RC      DDCmdRead( PDDCMDREADWRITE pRead );
  43. RC      DDCmdWrite( PDDCMDREADWRITE pWrite );
  44. RC      DDCmdStatus( PDDCMDSTATUS pStatus );
  45. RC      DDCmdControl( PDDCMDCONTROL pControl );
  46. RC      DDCmdRegister( PDDCMDREGISTER pRegister );
  47. RC      DDCmdDeRegister( PDDCMDDEREGISTER pDeRegister );
  48. RC      GetStreamEntry(PSTREAM far *ppStream, HSTREAM hStream);
  49. /*****************************************************************************
  50. *                       E X T E R N S
  51. ******************************************************************************/
  52.  
  53. extern  GLOBAL GlobalTable;
  54. extern  ULONG   operation[];    // Holds operation that we are prepared for
  55. extern  ULONG trk_array[];      // Number of supported tracks is
  56. extern  USHORT trk;             // device dependent field.
  57. extern  SHORT mode[];
  58.  
  59. extern MCI_AUDIO_IOBUFFER xmitio;
  60. extern MCI_AUDIO_IOBUFFER recio;
  61. extern PROTOCOLTABLE ProtocolTable[NPROTOCOLS];
  62.  
  63. /*****************************************************************************
  64. *                          D A T A
  65. ******************************************************************************/
  66.  
  67. //*******************************************************
  68. // IDC Command function jump table                      *
  69. //*******************************************************
  70. ULONG   (*DDCMDFuncs[])(PVOID pCommon) = {
  71.                 DDCmdSetup,                         // 0
  72.                 DDCmdRead,                          // 1
  73.                 DDCmdWrite,                         // 2
  74.                 DDCmdStatus,                        // 3
  75.                 DDCmdControl,                       // 4
  76.                 DDCmdRegister,                      // 5
  77.                 DDCmdDeRegister                     // 6
  78.                 };
  79. USHORT  MaxDDCMDFuncs = sizeof(DDCMDFuncs)/sizeof(USHORT);
  80. /*****************************************************************************
  81. *                          C O D E
  82. ******************************************************************************/
  83.  
  84.  
  85. /********************* START OF SPECIFICATIONS *********************
  86. *
  87. * SUBROUTINE NAME:          DDCMDInternalEntryPoint
  88. *
  89. * DESCRIPTIVE NAME: IDC Entry point enabling Audio Stream Handler to
  90. *                   communicate with the Audio PDD.
  91. *
  92. * FUNCTION: To execute the command requested by Audio Stream Handler
  93. *
  94. * NOTES:    This routine is called from the IDCEntry routine located
  95. *           in the  STARTUP.ASM  file.
  96. *
  97. * ENTRY POINTS:     DDCmdInternalEntryPoint()
  98. *     LINKAGE:      CALL FAR
  99. *
  100. * INPUT:        Pointer to command-dependent parameter structure.
  101. *
  102. * EXIT-NORMAL:  NO_ERROR
  103. *
  104. * EXIT_ERROR:   ERROR_INVALID_FUNCTION
  105. *               ERROR_INVALID_BLOCK
  106. * EFFECTS:
  107. *
  108. * INTERNAL REFERENCES: DDCMD functions
  109. *
  110. * EXTERNAL REFERENCES: None
  111. *
  112. *********************** END OF SPECIFICATIONS **********************/
  113.  
  114. RC  far DDCMDInternalEntryPoint( PDDCMDCOMMON pCommon )
  115. {
  116.  
  117.         if (pCommon==NULL)
  118.                 return (ERROR_INVALID_BLOCK) ;
  119.  
  120.         //*********************************
  121.         // Process DDCMD requested by stream handler
  122.         //*********************************
  123.         if (pCommon->ulFunction > (ULONG)MaxDDCMDFuncs)    // check for valid function
  124.                 return(ERROR_INVALID_FUNCTION);
  125.  
  126.         return(DDCMDFuncs[pCommon->ulFunction](pCommon));  // call DDCMD function
  127.  
  128.  
  129. }
  130.  
  131.  
  132. /********************* START OF SPECIFICATIONS *********************
  133. *
  134. * SUBROUTINE NAME:              DDCmdSetup
  135. *
  136. * DESCRIPTIVE NAME:     Sets up the audio device
  137. *
  138. * NOTES:        Match hStream parameter that Stream Handler will pass.
  139. *               Ensure that the PDD is set up with the
  140. *               correct DSP module, using the operation field
  141.                 of the structure matching hStream.
  142. *
  143. *
  144. * EXIT-NORMAL:  NO_ERROR
  145. *
  146. * EXIT_ERROR:   ERROR_INVALID_STREAM
  147. *               ERROR_INVALID_REQUEST
  148. *               ERROR_INVALID_FUNCTION
  149. *
  150. * INPUTS:
  151. *               ulFunction              DDCMD_SETUP
  152. *               hStream                 Stream handle to set up
  153. *               pSetupParm              Not used
  154. *               ulSetupParmSize         Not used
  155. *
  156. *********************** END OF SPECIFICATIONS **********************/
  157.  
  158. RC      DDCmdSetup( PDDCMDSETUP pSetup )
  159. {
  160.     PSTREAM pStream;    // pointer to Stream table
  161.     RC      rc;
  162.     USHORT  i;
  163.  
  164.     //***********************************************
  165.     // Search stream table for matching stream handle
  166.     //***********************************************
  167.     pStream = GlobalTable.paStream;
  168.     if (rc = GetStreamEntry(&pStream, pSetup->hStream))
  169.         return(rc);
  170.  
  171.     //***********************************************
  172.     // Ensure that this stream opertaion matches the
  173.     // operation that the PDD is set to perform.
  174.     // Put another way.  If we were setup for a operation
  175.     // different than that which the stream handler is
  176.     // asking us to perform, then we are not prepared.
  177.     // In this case, return error to stream handler.
  178.     //***********************************************
  179.     switch (operation[trk])     {
  180.  
  181.         case OPERATION_PLAY:
  182.             if (pStream->ulOperation != STREAM_OPERATION_CONSUME)      {
  183.                 return (ERROR_INVALID_REQUEST) ;
  184.             }
  185.  
  186.             break ;
  187.  
  188.  
  189.         case OPERATION_RECORD:
  190.             if (pStream->ulOperation != STREAM_OPERATION_PRODUCE)    {
  191.                 return (ERROR_INVALID_REQUEST) ;
  192.             }
  193.  
  194.             break ;
  195.  
  196.  
  197.         case PLAY_AND_RECORD:       /* Do nothing for now */
  198.             break ;
  199.  
  200.  
  201.         default:
  202.             return (ERROR_INVALID_FUNCTION) ;       /* Stream not initialized */
  203.     }
  204.  
  205.     /*
  206.     ** Set up tables to have right information
  207.     ** for the requested function.
  208.     */
  209.     for (i=0; i<GlobalTable.usMaxNumStreams; i++) {
  210.             if (GlobalTable.paStream[i].hStream != -1) {                              // check for only valid streams
  211.                     if ((GlobalTable.paStream[i].ulFlags & STREAM_STREAMING)          // is stream running?
  212.                        && (GlobalTable.paStream[i].hStream != pStream->hStream)       // is running stream the stream to context switch?
  213.                        && (GlobalTable.paStream[i].usTrackNum == pStream->usTrackNum))  // is running stream using the same channel as the context switch stream?
  214.                             return(ERROR_STREAM_NOT_STOP);                        // yes, so return error
  215.             }
  216.     }
  217.  
  218.     //************************************************************************
  219.     // Stream handler needs to adjust our CumTime when doing a setup, this is
  220.     // because the stream handler might have been seeked and all events that he sends will
  221.     // be relative to the seeked time.
  222.     //*************************************************************************
  223.     SetStreamTime (pStream, *((unsigned long far *)pSetup->pSetupParm) );
  224.  
  225.     return (NO_ERROR);
  226. }
  227.  
  228. /********************* START OF SPECIFICATIONS *********************
  229. *
  230. * SUBROUTINE NAME:          DDCmdRead
  231. *
  232. * DESCRIPTIVE NAME:     Read from the audio device (Recording Mode)
  233. *
  234. * FUNCTION:     Allows the Audio Stream Handler to read buffers from the audio device.
  235. *
  236. * NOTES:
  237. *               This routine chains the incoming buffers from the stream
  238. *               handler into Iobuf packets and updates the next index buffer
  239. *               packet.  The current index is only updated during
  240. *               interrupt time in the get_next_rbuf routine.
  241. *
  242. *               This routine is called at interrupt and non-interrupt time.
  243. *
  244. *
  245. * ENTRY POINTS: DDCmdRead()
  246. *     LINKAGE:  near
  247. *
  248. * INPUT:        Parm pointer
  249. *
  250. * EXIT-NORMAL:  NO_ERROR
  251. *
  252. * EXIT_ERROR:   ERROR_INVALID_STREAM
  253. *               ERROR_INVALID_BLOCK
  254. *               ERROR_STREAM_NOT_ACTIVE
  255. *
  256. *
  257. * INPUTS:
  258. *               ulFunction              DDCMD_READ
  259. *               hStream                 Stream handle
  260. *               pBuffer                 Address of buffer to record data to
  261. *               ulBufferSize            Size of pBuffer
  262. *
  263. *********************** END OF SPECIFICATIONS **********************/
  264.  
  265. RC      DDCmdRead( PDDCMDREADWRITE pRead )
  266. {
  267.     USHORT  Current, Next, Previous;
  268.     PSTREAM pStream;
  269.     RC      rc;
  270.  
  271.  
  272.     //*********************************
  273.     // Validate data buffer pointer
  274.     // that was passed in from stream handler
  275.     //*********************************
  276.  
  277.     if (pRead->pBuffer==NULL)   {
  278.             return (ERROR_INVALID_BLOCK) ;
  279.     }
  280.  
  281.     pStream = GlobalTable.paStream;
  282.     if (rc = GetStreamEntry(&pStream, pRead->hStream))
  283.         return(rc);
  284.  
  285.     //************
  286.     // Set indexes that point to IOBuff packets
  287.     //************
  288.     Current = pStream->usCurrIOBuffIndex;
  289.     Next = pStream->usNextIOBuffIndex;
  290.  
  291.     /**************************************************
  292.     **  Copy buffer pointer to "next"
  293.     **
  294.     **  pBufPhys - Physical address
  295.     **
  296.     **  Buffer   - Physical address to virtual
  297.     **  Head     - beginning of buffer   (VIRTUAL)
  298.     **  Tail     - end of buffer         (VIRTUAL)
  299.     ***************************************************/
  300.  
  301.     //*************************************************
  302.     // Fill IOBuff packet with data from pRead - size of data,
  303.     // address, usRunFlags, and place it in the queue.
  304.     // If there's a previous buffer in the queue, the
  305.     // new packet will be filled in with the previous
  306.     // buffer's values for position and delay.
  307.     // Otherwise these values will be set to zero.
  308.     //*************************************************
  309.  
  310.     pStream->IOBuff[Next].lSize   = pRead->ulBufferSize;
  311.     pStream->IOBuff[Next].lCount  = 0;
  312.     pStream->IOBuff[Next].pBuffer = pRead->pBuffer;
  313.     pStream->IOBuff[Next].lSize   = pRead->ulBufferSize;
  314.     pStream->IOBuff[Next].pHead   = pStream->IOBuff[Next].pBuffer;
  315.     pStream->IOBuff[Next].pTail   =
  316.        pStream->IOBuff[Next].pHead + pRead->ulBufferSize;
  317.     pStream->IOBuff[Next].usRunFlags  =
  318.        pStream->IOBuff[Current].usRunFlags & (USHORT)~IOB_OVERRUN;
  319.  
  320.     if (Current!=Next) {        /* There is a previous buffer */
  321.  
  322.         if (Next == 0)  Previous = MAXIOBUFFS - 1 ;
  323.         else    Previous = Next - 1 ;
  324.  
  325.         pStream->IOBuff[Next].ulposition  = pStream->IOBuff[Previous].ulposition;
  326.         pStream->IOBuff[Next].lDelay     = pStream->IOBuff[Previous].lDelay;
  327.         // Do not set count when recording
  328.     }
  329.  
  330.     else {                      /* Set ulposition, lDelay to 0 */
  331.  
  332.         pStream->IOBuff[Next].ulposition  = 0;
  333.         pStream->IOBuff[Next].lDelay     = 0;
  334.     }
  335.  
  336.  
  337.  
  338.     //***********************************************
  339.     // Increment next buffer index and check for wrap
  340.     //***********************************************
  341.     if ((++Next == MAXIOBUFFS))
  342.         Next = 0 ;
  343.     pStream->usNextIOBuffIndex = Next;
  344.  
  345.     return( NO_ERROR );
  346. }
  347.  
  348.  
  349. /********************* START OF SPECIFICATIONS *********************
  350. *
  351. * SUBROUTINE NAME:              DDCmdWrite
  352. *
  353. * DESCRIPTIVE NAME:     Write to the audio device using AUDIO_HPI
  354. *                       (Playback Mode)
  355. *
  356. * FUNCTION:     Allows the Audio Stream Handlerto write buffers to
  357. *               the audio device by passing buffers (IOBuffs) to
  358. *               the physical hardware device.
  359. *
  360. * NOTES:        StreamNumber is set at the IDC entry point
  361. *               This routine chains the incoming buffers from the stream handler
  362. *               into Iobuf packets and updates the next index buffer
  363. *               packet.  The current index is only updated during
  364. *               interrupt time in the get_next_xbuf routine.
  365. *
  366. *               This routine is called at interrupt and non-interrupt time.
  367. *
  368. * ENTRY POINTS: DDCmdWrite()
  369. *     LINKAGE: near
  370. *
  371. * INPUT:       Parm pointer
  372. *
  373. * EXIT-NORMAL:  NO_ERROR
  374. *
  375. * EXIT_ERROR:   ERROR_INVALID_STREAM
  376. *               ERROR_INVALID_BLOCK
  377. *
  378. * INPUTS:
  379. *               ulFunction              DDCMD_WRITE
  380. *               hStream                 Stream handle
  381. *               pBuffer                 Address of buffer to play data from
  382. *               ulBufferSize            Size of pBuffer
  383. *
  384. *********************** END OF SPECIFICATIONS **********************/
  385.  
  386. RC  DDCmdWrite( PDDCMDREADWRITE pWrite )
  387. {
  388.     USHORT  Current, Next, Previous ;
  389.     PSTREAM pStream;
  390.     RC      rc;
  391.  
  392.     //**********************************
  393.     // Validate data buffer pointer
  394.     //**********************************
  395.  
  396.     if (pWrite->pBuffer==NULL)  {
  397.             return (ERROR_INVALID_BLOCK) ;
  398.     }
  399.  
  400.     //***********************************************
  401.     // Search stream table for matching stream handle
  402.     //***********************************************
  403.     pStream = GlobalTable.paStream;
  404.     if (rc = GetStreamEntry(&pStream, pWrite->hStream))
  405.         return(rc);
  406.  
  407.     //*************
  408.     // Set indexes
  409.     //*************
  410.     Current = pStream->usCurrIOBuffIndex;
  411.     Next = pStream->usNextIOBuffIndex;
  412.  
  413.     /**************************************************
  414.         Copy buffer pointer to "next"
  415.  
  416.         pBufPhys - Physical address is sent from stream handler
  417.  
  418.         Buffer   - Physical address to virtual
  419.         Tail     - beginning of buffer   (VIRTUAL)
  420.         Head     - end of buffer         (VIRTUAL)
  421.      **************************************************/
  422.  
  423.     //**************************************************
  424.     // Fill buffer with data from pWrite - size of data,
  425.     // address, usRunFlags, and place it in the queue.
  426.     // If there's a previous buffer in the queue, the
  427.     // new buffer will be filled in with the previous
  428.     // buffer's values for ulposition and lDelay. Other-
  429.     // wise ulposition will be set to zero, lDelay to 1.
  430.     //**************************************************
  431.     pStream->IOBuff[Next].lSize   = pWrite->ulBufferSize;
  432.     pStream->IOBuff[Next].lCount  = pWrite->ulBufferSize;
  433.     pStream->IOBuff[Next].pBuffer = pWrite->pBuffer;
  434.     pStream->IOBuff[Next].pTail      = pStream->IOBuff[Next].pBuffer;
  435.     pStream->IOBuff[Next].pHead      =
  436.             pStream->IOBuff[Next].pTail + pWrite->ulBufferSize;
  437.     pStream->IOBuff[Next].usRunFlags  = pStream->IOBuff[Current].usRunFlags &
  438.                                         (USHORT)~IOB_UNDERRUN;
  439.  
  440.     if (Current!=Next) {        /* There is a previous buffer */
  441.  
  442.         if (Next == 0)
  443.                 Previous = MAXIOBUFFS - 1 ;
  444.         else
  445.                 Previous = Next - 1 ;
  446.  
  447.         pStream->IOBuff[Previous].lCount += pWrite->ulBufferSize;
  448.     }
  449.  
  450.     pStream->IOBuff[Next].ulposition  = 0;
  451.     pStream->IOBuff[Next].lDelay     = 1;
  452.  
  453.  
  454.     //***********************************************
  455.     // Increment next buffer index and check for wrap
  456.     //***********************************************
  457.     if ((++Next == MAXIOBUFFS))
  458.         Next = 0 ;
  459.     pStream->usNextIOBuffIndex = Next;
  460.  
  461.     return( NO_ERROR );
  462. }
  463.  
  464.  
  465. /********************* START OF SPECIFICATIONS *********************
  466. *
  467. * SUBROUTINE NAME:          DDCmdStatus
  468. *
  469. * DESCRIPTIVE NAME:     Query current ulposition (stream time)
  470. *
  471. * FUNCTION:     Allows the Audio stream handler to get the current
  472. *               stream time ulposition value in milliseconds.
  473. *
  474. * NOTES:
  475. *               This routine will return the current real-time
  476. *               "stream-time" for the stream.
  477. *
  478. *               This routine is called at non-interrupt time.
  479. *
  480. * ENTRY POINTS: DDCmdStatus()
  481. *     LINKAGE: near
  482. *
  483. * INPUT:
  484. *
  485. * EXIT-NORMAL:  NO_ERROR
  486. *
  487. * EXIT_ERROR:   ERROR_INVALID_STREAM
  488. *
  489. * INPUTS:
  490. *               ulFunction              DDCMD_STATUS
  491. *               hStream                 Stream handle
  492. *
  493. *********************** END OF SPECIFICATIONS **********************/
  494.  
  495. RC      DDCmdStatus(PDDCMDSTATUS pStatus )
  496. {
  497.     PSTREAM pStream;
  498.     RC      rc;
  499.  
  500.     pStream = GlobalTable.paStream;
  501.     if (rc = GetStreamEntry(&pStream, pStatus->hStream))
  502.         return(rc);
  503.  
  504.     /* Get the current ulposition */
  505.     GetStreamTime (pStream);
  506.  
  507.     //********************************************************
  508.     // Return far pointer containing real-time position to stream handler
  509.     //********************************************************
  510.     pStatus->ulStatusSize = sizeof(recio.ulposition);
  511.     pStatus->pStatus = &pStream->ulCumTime;
  512.  
  513.     return( NO_ERROR );
  514. }
  515.  
  516.  
  517. /********************* START OF SPECIFICATIONS *********************
  518. *
  519. * SUBROUTINE NAME:          DDCmdControl
  520. *
  521. * DESCRIPTIVE NAME:
  522. *
  523. * FUNCTION:     Maps the AUDIO_CONTROL IDC commands to their IOCTL
  524. *               equilivent.
  525. *
  526. * NOTES:    Since the entire routine uses the AUDIO_HPI calls,
  527. *           Just set the current buffer's usRunFlags to the right command
  528. *           Command from stream handler comes in pControl->ulCmd.
  529. *           This routine sets flags, IOBuff and pStream structures.
  530. *           These will be referenced at interrupt time for command execution.
  531. *           For some operations, we will call stream handler directly.
  532. *
  533. * ENTRY POINTS: DDCmdControl()
  534. *     LINKAGE: near
  535. *
  536. * INPUT:       Parm pointer
  537. *
  538. * EXIT-NORMAL:  NO_ERROR
  539. *
  540. * EXIT_ERROR:   ERROR_INVALID_FUNCTION
  541. *               ERROR_STREAM_NOT_STARTED
  542. *               ERROR_INVALID_SEQUENCE
  543. *               ERROR_INVALID_STREAM
  544. *               ERROR_TOO_MANY_EVENTS
  545. *
  546. * INPUTS:
  547. *               ulFunction              DDCMD_CONTROL
  548. *               hStream                 Stream handle
  549. *               ulCmd                   Specific control command
  550. *               pParm                   Not used
  551. *               ulParmSize              Not used
  552. *
  553. *********************** END OF SPECIFICATIONS **********************/
  554.  
  555. RC  DDCmdControl(PDDCMDCONTROL pControl)
  556. {
  557.     USHORT Current, i ;
  558.     PSTREAM pStream;
  559.     RC      rc;
  560.     ULONG   ulCuePoint;
  561.  
  562.  
  563.     pStream = GlobalTable.paStream;
  564.     if (rc = GetStreamEntry(&pStream, pControl->hStream))
  565.         return(rc);
  566.     Current = pStream->usCurrIOBuffIndex;
  567.  
  568.  
  569.     //****************************************
  570.     // Perform specific DDCMD_CONTROL function
  571.     //****************************************
  572.     switch (pControl->ulCmd)    {
  573.         case    DDCMD_START:
  574.  
  575.                 //*********************************************
  576.                 // ... PAUSE - START ... is an invalid sequence
  577.                 //*********************************************
  578.                 if (pStream->IOBuff[Current].usRunFlags & IOB_PAUSED) {
  579.                         return (ERROR_INVALID_SEQUENCE);
  580.                 }
  581.  
  582.  
  583.                 //*******************************************
  584.                 // stream handler told us to start and we have enough
  585.                 // full buffers, so send this buffer to the
  586.                 // audio card.  If operation is PLAY, the
  587.                 // routine will output the contents of the
  588.                 // buffer to the card.  If operation is RECORD
  589.                 // the routine will fill the buffer with data
  590.                 // from the card's input jack.
  591.                 //******************************************** */
  592.                 pStream->ulFlags |= STREAM_STREAMING;
  593.                 pStream->ulFlags &= ~STREAM_STOPPED;
  594.                 if (operation[trk] == OPERATION_PLAY) {
  595.                         Audio_IOCTL_Hpi (pControl->pParm);
  596.                 }
  597.                 else    Audio_IOCTL_Hpi (pControl->pParm);
  598.  
  599.  
  600.                 //*************************
  601.                 // Set all IOBuffs to START
  602.                 //*************************
  603.                 for (i=0; i<MAXIOBUFFS; i++) {
  604.                         pStream->IOBuff[i].usRunFlags |= IOB_STARTED;
  605.                 }
  606.                 break ;
  607.  
  608.  
  609.            case DDCMD_STOP:
  610.                 //********************************************************
  611.                 // because we always write to the "next" buffer and play
  612.                 // from the "current" buffer, reset the indexes to point
  613.                 // at the same packet. So when a re-start comes in we will
  614.                 // not play a null buffer.
  615.                 //********************************************************
  616.  
  617.                 Current = pStream->usCurrIOBuffIndex = pStream->usNextIOBuffIndex = 0;
  618.  
  619.                 pStream->ulFlags |= STREAM_STOPPED;
  620.                 pStream->ulFlags &= ~STREAM_STREAMING;
  621.                 pStream->ulFlags &= ~STREAM_PAUSED;
  622.  
  623.                 /************************************************
  624.                  Do this so that PDD does not return an old buffer
  625.                  to handler after handler received a STOP-DISCARD.
  626.                  ************************************************/
  627.                 for ( i=0; i<MAXIOBUFFS; i++ )  {
  628.                     pStream->IOBuff[i].usRunFlags &= ~IOB_RUNNING;
  629.                     pStream->IOBuff[i].usRunFlags &= ~IOB_STARTED;
  630.                     pStream->IOBuff[i].usRunFlags &= ~IOB_PAUSED;
  631.                     pStream->IOBuff[i].usRunFlags |= IOB_STOPPED;
  632.                     pStream->IOBuff[i].lSize      = 0;
  633.                     pStream->IOBuff[i].pBuffer   = NULL;
  634.                     pStream->IOBuff[i].lCount    = 0;
  635.                     pStream->IOBuff[i].ulposition  = 0;
  636.                     pStream->IOBuff[i].lDelay     = 0;
  637.                     pStream->IOBuff[i].pBuffer    = NULL;
  638.                 }
  639.  
  640.                 // Always return stream time when
  641.                 // stopping or pausing device.
  642.                 pControl->pParm = GetStreamTime(pStream);
  643.  
  644.                 pControl->ulParmSize = sizeof(recio.ulposition);
  645.  
  646.                 break ;
  647.  
  648.  
  649.         case    DDCMD_PAUSE:
  650.  
  651.                 //********************************************
  652.                 // trying to PAUSE a non-started stream = error
  653.                 //********************************************
  654.                 if (!(pStream->IOBuff[Current].usRunFlags & IOB_STARTED))     {
  655.                         return (ERROR_STREAM_NOT_STARTED);
  656.                 }
  657.  
  658.                 pStream->IOBuff[Current].usRunFlags |= IOB_PAUSED;
  659.                 pStream->ulFlags |= STREAM_PAUSED;
  660.                 pStream->ulFlags &= ~STREAM_STREAMING;
  661.  
  662.                 // Always return stream time when
  663.                 // stopping or pausing device.
  664.                 pControl->pParm = GetStreamTime(pStream);
  665.                 pControl->ulParmSize = sizeof(recio.ulposition);
  666.                 break ;
  667.  
  668.         case    DDCMD_RESUME:
  669.  
  670.                 //*********************************************
  671.                 // trying to RESUME a stoped/non-paused stream = error
  672.                 //*********************************************
  673.                 if (!(pStream->IOBuff[Current].usRunFlags & IOB_STARTED))    {
  674.                         return (ERROR_INVALID_SEQUENCE);
  675.                 }
  676.  
  677.                 if (operation[trk] == OPERATION_PLAY) {
  678.                         Audio_IOCTL_Hpi (pControl->pParm);
  679.                 }
  680.                 else    Audio_IOCTL_Hpi (pControl->pParm);
  681.  
  682.                 pStream->IOBuff[Current].usRunFlags &= ~IOB_PAUSED;
  683.                 pStream->ulFlags |= STREAM_STREAMING;
  684.  
  685.                 break ;
  686.  
  687.  
  688.         case    DDCMD_ENABLE_EVENT:
  689.                 // Create an event with specific cuepoint.
  690.                 // This PDD will detect the cuepoint and report
  691.                 // its occurance to the stream handler via
  692.                 // SHD_REPORT_EVENT
  693.  
  694.                 ulCuePoint = *((unsigned long far *)pControl->pParm);
  695.                 rc = Enqueue_Event (pControl->hEvent, ulCuePoint);
  696.                 if (rc)
  697.                    {
  698.                    return (ERROR_TOO_MANY_EVENTS);
  699.                    }
  700.                 break ;
  701.  
  702.         case    DDCMD_DISABLE_EVENT:
  703.  
  704.                 rc = Dequeue_Event (pControl->hEvent);
  705.  
  706.                 break ;
  707.  
  708.         default:
  709.                 return (ERROR_INVALID_FUNCTION) ;
  710.  
  711.     }     /* switch */
  712.  
  713.     return( NO_ERROR );
  714. }
  715.  
  716.  
  717. /********************* START OF SPECIFICATIONS *********************
  718. *
  719. * SUBROUTINE NAME:          DDCmdRegister
  720. *
  721. * DESCRIPTIVE NAME: Register stream with this PDD
  722. *
  723. * FUNCTION: Initialize stream.
  724. *
  725. * NOTES:    Will receive the handler ID, handle of stream instance,
  726. *           address of entry point from stream handler.
  727. *           Set waiting flag (waiting for data)
  728. *           Set usRunFlags = 0
  729. *           Set No_circular_buffer flag (0x80)
  730. *           Set protocol info for stream handler
  731. *           Set Address type to Physical
  732. *
  733. * ENTRY POINTS:DDCmdRegister()
  734. *     LINKAGE: near
  735. *
  736. * EXIT-NORMAL:  NO_ERROR
  737. *
  738. * EXIT-ERROR:   ERROR_INVALID_STREAM
  739. *               ERROR_HNDLR_REGISTERED
  740. *               ERROR_INVALID_FUNCTION
  741. *               ERROR_INVALID_SPCBKEY
  742. *
  743. * INPUTS:
  744. *               ulFunction              DDCMD_REG_STREAM
  745. *               hStream                 Stream handle
  746. *               ulSysFileNum            Device handle so PDD can map device instance to hStream
  747. *               pSHDEntryPoint          Stream handler entry point
  748. *               ulStreamOperation       Record (PRODUCE) or Play (CONSUME)
  749. *               spcbkey                 Protocol info which determines outputs
  750. *
  751. * OUTPUTS:
  752. *               ulBufSize               Buffer size in bytes for SPCB
  753. *               ulNumBufs               # of buffers for SPCB
  754. *               ulAddressType           Address type of data buffer
  755. *               ulBytesPerUnit          Bytes per unit
  756. *               mmtimePerUnit           MMTIME per unit
  757. *
  758. *********************** END OF SPECIFICATIONS **********************/
  759.  
  760. RC  DDCmdRegister(PDDCMDREGISTER pRegister)
  761. {
  762.  
  763.     USHORT      i;
  764.     PSTREAM     pStream;
  765.     BOOL        bFound;
  766.     RC          rc;
  767.  
  768.     if (pRegister->hStream == -1)
  769.         return (ERROR_INVALID_STREAM) ;    /*   Stream handle invalid   */
  770.  
  771.     if (pRegister->ulSysFileNum == DATATYPE_NULL)
  772.         return(ERROR_INITIALIZATION);
  773.  
  774.     if ((pRegister->ulStreamOperation != STREAM_OPERATION_CONSUME) &&
  775.         (pRegister->ulStreamOperation != STREAM_OPERATION_PRODUCE))
  776.                 return (ERROR_INVALID_FUNCTION);
  777.  
  778.  
  779.     //******************************************
  780.     // Do protocol table lookup, using DataType,
  781.     // DataSubType as keys and return ulBufSize,
  782.     // ulNumBufs, ulAddressType, mmtimePerUnit;
  783.     // Verify requested stream characteristics
  784.     // match our capabilities.
  785.     //******************************************
  786.     for ( i=0; i<NPROTOCOLS; i++ )  {
  787.  
  788.         if (ProtocolTable[i].ulDataType == pRegister->spcbkey.ulDataType) {
  789.             if (ProtocolTable[i].ulDataSubType == pRegister->spcbkey.ulDataSubType) {
  790.                 //**********************************************
  791.                 // We found a match for data type, data sub type
  792.                 //**********************************************
  793.                 break ;
  794.             }
  795.         }
  796.     }
  797.  
  798.  
  799.     //***************
  800.     // No match found
  801.     //***************
  802.     if (i==NPROTOCOLS) {
  803.         return (ERROR_INVALID_SPCBKEY) ;
  804.     }
  805.  
  806.     //***************************
  807.     // Match found:
  808.     //   Pass back protocol ("stream characteristics")
  809.     //   to stream handler.
  810.     //***************************
  811.     else {                                  /* Match found */
  812.         pRegister->ulBufSize       = ProtocolTable[i].ulBufSize ;
  813.         pRegister->ulNumBufs       = ProtocolTable[i].ulNumBufs ;
  814.         pRegister->mmtimePerUnit   = 1;
  815.  
  816.         //****************************************************
  817.         // Bytes per unit =
  818.         //
  819.         //  Samples     Channels     Bits      Byte     Sec
  820.         //  -------  *           *  ------  *  ---- *  ------
  821.         //    Sec                   Sample     Bits    MMTIME
  822.         //****************************************************
  823.         pRegister->ulBytesPerUnit  = ((ProtocolTable[i].ulSampleRate * ProtocolTable[i].usChannels
  824.                                      * ProtocolTable[i].usBitsPerSample) / 8) /3;
  825.  
  826.     }
  827.     //********************************************************************
  828.     // Tell stream handler what type of data buffer pointer to reference
  829.     //********************************************************************
  830.     pRegister->ulAddressType = ADDRESS_TYPE_PHYSICAL ;
  831.  
  832.     bFound = FALSE;
  833.     for (i=0; i<NUM_TRACKS; i++)
  834.             if (trk_array[i] == pRegister->ulSysFileNum) {
  835.                 bFound = TRUE;
  836.                 trk = i;
  837.             }
  838.     if (!bFound)
  839.         return(ERROR_INVALID_STREAM);
  840.  
  841.     //*************************************************************
  842.     // Initialize pStream to point at the first entry for track trk
  843.     //************************************************************* */
  844.     pStream = GlobalTable.paStream;
  845.     if (!(rc = GetStreamEntry(&pStream, pRegister->hStream)))
  846.                 return(ERROR_HNDLR_REGISTERED);
  847.     pStream = GlobalTable.paStream;                         // no match, so create stream
  848.     i=0;
  849.     while(pStream->hStream != -1) {                     // find an empty stream entry
  850.                 if (++i >= GlobalTable.usMaxNumStreams)
  851.                         return(ERROR_STREAM_CREATION);
  852.                 pStream++;
  853.         }
  854.  
  855.     //**************************************
  856.     // Found empty stream entry, so use it
  857.     // Fill Stream structure
  858.     //**************************************
  859.     for ( i=0; i<MAXIOBUFFS; i++ )  {
  860.         pStream->IOBuff[i].lSize      = 0;
  861.         pStream->IOBuff[i].pHead      = NULL;
  862.         pStream->IOBuff[i].pTail      = NULL;
  863.         pStream->IOBuff[i].lCount     = 0;
  864.         pStream->IOBuff[i].ulposition  = 0;
  865.         pStream->IOBuff[i].lDelay     = 0;
  866.         pStream->IOBuff[i].usRunFlags |= IOB_CHAIN_BUFFERS;
  867.         pStream->IOBuff[i].pBuffer    = NULL;
  868.     }
  869.  
  870.     //********************************
  871.     // Save register info in structure
  872.     //********************************
  873.     pStream->hStream        = pRegister->hStream;
  874.     pStream->ulFlags        = STREAM_REGISTERED;
  875.     pStream->ulOperation    = pRegister->ulStreamOperation;
  876.     pStream->ulSysFileNum   = trk_array[trk];
  877.     pStream->usTrackNum     = trk;
  878.     pStream->usCurrIOBuffIndex = 0;
  879.     pStream->usNextIOBuffIndex = 0;
  880.     (PSHDFN)pStream->ADSHEntry = pRegister->pSHDEntryPoint;
  881.  
  882.     return( NO_ERROR );
  883. }
  884.  
  885.  
  886. /********************* START OF SPECIFICATIONS *********************
  887. *
  888. * SUBROUTINE NAME:          DDCmdDeRegister
  889. *
  890. * DESCRIPTIVE NAME: Deregister this stream
  891. *
  892. * FUNCTION:     Remove stream instance from this PDD
  893. *
  894. * NOTES:        Done by setting table handle to value -1
  895. *
  896. * ENTRY POINTS:
  897. *     LINKAGE:
  898. *
  899. * EXIT-NORMAL:  NO_ERROR
  900. *
  901. * EXIT_ERROR:   ERROR_INVALID_STREAM
  902. *
  903. * INPUTS:
  904. *               ulFunction              DDCMD_DEREG_STREAM
  905. *               hStream                 Stream handle
  906. *
  907. *********************** END OF SPECIFICATIONS **********************/
  908.  
  909. RC  DDCmdDeRegister(PDDCMDDEREGISTER pDeRegister)
  910. {
  911.     USHORT  i ;
  912.     PSTREAM pStream;
  913.     RC          rc;
  914.  
  915.  
  916.     //**************************************************************
  917.     // Check table to see if stream is registered and a valid handle
  918.     //**************************************************************
  919.     pStream = GlobalTable.paStream;
  920.     if (rc = GetStreamEntry(&pStream, pDeRegister->hStream))
  921.                 return(rc);
  922.  
  923.     //************************
  924.     // De-activate this stream
  925.     // and clear all flags
  926.     //************************
  927.  
  928.     pStream->hStream = -1;                      // make stream available
  929.     pStream->ulFlags = 0;                       // clear flags
  930.  
  931.     for (i=0; i<MAXIOBUFFS; i++)    {
  932.             pStream->IOBuff[i].usRunFlags = 0;
  933.     }
  934.  
  935.     return( NO_ERROR );
  936. }
  937.  
  938.  
  939. /********************* START OF SPECIFICATIONS *********************
  940. * SUBROUTINE NAME: GetStreamEntry
  941. *
  942. * DESCRIPTIVE NAME: Get the stream table entry.
  943. *
  944. * FUNCTION: To search the stream table finding a match with the given parm.
  945. *
  946. * NOTES: This routine is called internally.
  947. *
  948. * ENTRY POINTS:
  949. *
  950. *     LINKAGE:   CALL near
  951. *
  952. * INPUT: pointer to stream table, stream handle to find
  953. *
  954. * EXIT-NORMAL: NO_ERROR
  955. *
  956. * EXIT_ERROR: ERROR_INVALID_STREAM if stream not found in table
  957. *
  958. * INTERNAL REFERENCES: none
  959. *
  960. * EXTERNAL REFERENCES: none
  961. *
  962. *********************** END OF SPECIFICATIONS **********************/
  963. RC      GetStreamEntry(PSTREAM far *ppStream, HSTREAM hStream)
  964. {
  965.         USHORT  i;
  966.         PSTREAM pStream;
  967.  
  968.         i=0;
  969.         pStream = *ppStream;
  970.         while(pStream->hStream != hStream) {            // find stream entry
  971.                 if (++i >= GlobalTable.usMaxNumStreams)
  972.                         return(ERROR_INVALID_STREAM);
  973.                 pStream++;
  974.         };
  975.         *ppStream = pStream;
  976.         return(NO_ERROR);
  977. }
  978.