/* SCCSID = "src/dev/usb/USBAUDIO/AUDIODD.C, usb, c.basedd 98/07/10" */
/*
*   Licensed Material -- Property of IBM
*
*   (c) Copyright IBM Corp. 1998  All Rights Reserved
*/
/************************** START OF SPECIFICATIONS ***************************/
/*                                                                            */
/*   SOURCE FILE NAME:  AUDIODD.C                                             */
/*                                                                            */
/*   DESCRIPTIVE NAME: Audio device driver strategy and IOCTL routines        */
/*                                                                            */
/*                                                                            */
/*   FUNCTION: Contains Audio device driver strategy and IOCTL routines       */
/*                                                                            */
/*                                                                            */
/*   NOTES:                                                                   */
/*      DEPENDENCIES: None                                                    */
/*      RESTRICTIONS: None                                                    */
/*                                                                            */
/*        This audio device driver is an OS/2 16-bit Physical Device driver   */
/*        designed to demonstrate audio device communication with the         */
/*        MMPM/2 stream handler.                                              */
/*        Information on OS/2 Physical Device Drivers architecture and        */
/*        programming is in the "OS/2 2.0 Physical Device Driver reference"   */
/*                                                                            */
/*        MMPM/2 streaming architecture is outlined in                        */
/*        "MMPM/2 Programmers Reference"                                      */
/*           - Data Streaming & synchronization chapter                       */
/*        Specifix information on interdevice communication is in the         */
/*        same document in the "Stream Handler" Chapter in the section on     */
/*        "Interdevice-driver-communication                                   */
/*                                                                            */
/*   ENTRY POINTS:                                                            */
/*                  StrategyEntry()                                           */
/*                  StartDevicePlay()                                         */
/*                  ResumeDevicePlay()                                        */
/*                  SendFirstBuffers()                                        */
/*                                                                            */         
/*                                                                            */
/*   EXTERNAL REFERENCES:													               */
/*                                                                            */
/*                    RegisterClass()                                         */
/*                    DevOpen()                                               */
/*                    DevClose()                                              */
/*                    DevChange()                                             */
/*                    SetSystemTimer()                                         */
/*                    SetStreamState()                                        */
/*                    USBSetInterface()                                       */
/*                    DevHlp_PhysToGDTSelector()                              */
/*                    DevHlp_AllocGDTSelector()                               */
/*                    DevHlp_AllocPhys()                                      */
/*                    DevHlp_PhysToVirt()                                     */
/*				                                                                  */
/*                                                                            */
/* Change Log                                                                 */
/*                                                                            */
/*  Mark    yy/mm/dd  Programmer          Comment                             */
/*  ----    --------  ----------          -------                             */
/*          98/10/17  Vjacheslav Chibis   Original developer.                 */
/*                                                                            */
/**************************** END OF SPECIFICATIONS ***************************/


#include <string.h>

#define  INCL_DOSINFOSEG


#include "usbaud.h"
#include "audsubs.h"

extern  RC (*gIOCTLFuncs[])(PREQPACKET pRP);
extern  gMaxIOCTLFuncs;
extern  VOID FAR  *DevHlp;
extern  GLOBAL GlobalTable;
extern  DEVHDR gDevHdr[];
extern  usGDT[];
extern  ULONG ulActiveSysFileNum;
extern  USHORT usInUse;
extern  ATTACHAREA      AttachArea;
extern  SZ  szDevName[9];
extern  ULONG trk;


unsigned long flags = 0;
ULONG gDevOperation;
int   position_type;
USHORT   usNumOS2Opens=0;  


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  StrategyEntry                                    */
/*                                                                    */
/* DESCRIPTIVE NAME:  Strategy entry                                  */
/*                                                                    */
/* FUNCTION: The function of this routine is to process strategy      */
/*                                calls from OS/2                     */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  StrategyEntry                                       */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PREQPACKET pRP                                             */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: NONE                                          */
/*                                                                    */
/*    ROUTINES:                                                       */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:   RegisterClass                                       */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

ULONG    StrategyEntry(PREQPACKET pRP)
{
   RC rc = RPERR;                          

   #ifdef DEBUG
   dsPrint1(DBG_IRQFLOW,"USBAUD : Strategy entry : CMD=%x\r\n", pRP->RPcommand);
   #endif

   if( !GlobalTable.bFirstEntry&&!GlobalTable.bRegistered )
   {
      rc = RegisterClass();

      if( rc != RPDONE )
         return( rc );

      GlobalTable.bRegistered = TRUE;
   }


   GlobalTable.bFirstEntry = FALSE;

   if( pRP->RPcommand > (UCHAR)gMaxIOCTLFuncs ) // check for valid function
      return(RPDONE | RPERR | RPBADCMD);

   rc = gIOCTLFuncs[pRP->RPcommand](pRP);

   #ifdef DEBUG
   dsPrint1(DBG_IRQFLOW, "USBAUD : Strategy exit : status=%lx\r\n", rc);
   #endif

   return( rc ); 
}


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  IOCTL_Invalid                                    */
/*                                                                    */
/* DESCRIPTIVE NAME:  IOCTL Invalid                                   */
/*                                                                    */
/* FUNCTION:  Process IOCTl call with invalid  function               */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  IOCTL_Invalid                                       */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP                                           */
/*                                                                    */
/* EXIT-NORMAL:  RPDONE | RPERR | RPBADCMD                            */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  NONE                                         */  
/*                                                                    */
/*    ROUTINES:                                                       */
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:                                                       */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
ULONG   IOCTL_Invalid(PREQPACKET rp)
{
   return(RPDONE | RPERR | RPBADCMD);
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  IOCTL_Open                                       */
/*                                                                    */
/* DESCRIPTIVE NAME:                                                  */
/*                                                                    */
/* FUNCTION:  Process IOCTL driver OPEN call                          */
/*                                                                    */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  IOCTL_Open                                          */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP                                           */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  NONE                                         */  
/*                                                                    */
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:     DevOpen                                           */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

ULONG   IOCTL_Open(PREQPACKET rp)
{
   if( DevOpen((ULONG)rp->s.open.sys_file_num) )
   {
      usNumOS2Opens++; // set inuse flag so that a VDM can't use us
      return(RPDONE);
   }
   else
      return(RPDONE|RPERR);
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  IOCTL_Close                                      */
/*                                                                    */
/* DESCRIPTIVE NAME:   IOCTL Close                                    */
/*                                                                    */
/* FUNCTION:  The function of this routine is to process  IOCTL device*/
/*             driver Close call                                      */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  IOCTL_Close                                         */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP                                           */
/*                                                                    */
/* EXIT-NORMAL: always RPDONE                                         */
/*                                                                    */
/* EXIT-ERROR:  Never                                                 */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: NONE                                          */  
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES: DevClose                                              */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
RC   IOCTL_Close(PREQPACKET rp)
{

   usNumOS2Opens--;
   if( !usNumOS2Opens )
      // Only call VDD when
      DevClose((ULONG)rp->s.close.sys_file_num);               // all OS2 processes are closed

   return(RPDONE);

}


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  IOCTL_GenIOCtl                                   */
/*                                                                    */
/* DESCRIPTIVE NAME:  IOCTL Generic IOCTL                             */
/*                                                                    */
/* FUNCTION: Processes Audio specific IOCTl functions                 */
/*                                                                    */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  IOCTL_GenIOCtl                                      */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PREQPACKET pRP                                             */
/*                                                                    */
/* EXIT-NORMAL:  RPDONE                                               */
/*                                                                    */
/* EXIT-ERROR:  RPDONE | RPERR | RPBADCMD - invalid functions         */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:   NONE                                        */  
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:   gAudioIOCTLFuncs[]                                  */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
RC   IOCTL_GenIOCtl(PREQPACKET pRP)                   // GENERAL IOCTL (OS/2)
{

   // Valid category : 0x80
   //  Valid functions: 0x40 - 0x5f 

   #ifdef DEBUG
   dsPrint2(DBG_DETAILED, "USBAUD: IOCTL_Generic : category=%lx, function=%lx\r\n", pRP->s.IOCtl.category, pRP->s.IOCtl.function);
   #endif

   if( pRP->s.IOCtl.category == 0x80 )
   {       // must be proper category
      if( (pRP->s.IOCtl.function < (UCHAR)0x40) ||
      (pRP->s.IOCtl.function >= ((UCHAR)0x40+(UCHAR)gMaxAudioIOCTLFuncs)) )
         return(RPDONE | RPERR | RPBADCMD);

      gAudioIOCTLFuncs[pRP->s.IOCtl.function-0x40](pRP);  // call request function
   }

   return(RPDONE);
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  Audio_IOCTL_Update                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  Audio IOCTL Update                              */
/*                                                                    */
/* FUNCTION: The function of this routine is to update audio          */
/*                buffers status                                      */
/*                                                                    */
/*                                                                    */
/* NOTES: This function is not requried for MMPM/2                    */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  Audio_IOCTL_Update                                  */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PREQPACKET pParm                                           */
/*                                                                    */
/* EXIT-NORMAL: always RPDONE | RPERR | RPBADCMD                      */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:   NONE                                        */  
/*                                                                    */
/* EXTERNAL REFERENCES:   NONE                                        */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

RC   Audio_IOCTL_Update(PREQPACKET pParm)
{
   return(RPDONE | RPERR | RPBADCMD);
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  Audio_IOCTL_Invalid                              */
/*                                                                    */
/* DESCRIPTIVE NAME:  Audio IOCTL Update                              */
/*                                                                    */
/* FUNCTION: The function of this routine is to update audio          */
/*                buffers status                                      */
/*                                                                    */
/*                                                                    */
/* NOTES: This function is not requried for MMPM/2                    */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  Audio_IOCTL_Invalid                                 */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PREQPACKET pParm                                           */
/*                                                                    */
/* EXIT-NORMAL: always RPDONE | RPERR | RPBADCMD                      */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:   NONE                                        */  
/*                                                                    */
/* EXTERNAL REFERENCES:   NONE                                        */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
RC Audio_IOCTL_Invalid(PREQPACKET pParm)
{
   return(RPDONE | RPERR | RPBADCMD);
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  Audio_IOCTL_Init                                 */
/*                                                                    */
/* DESCRIPTIVE NAME:  Audio Init                                      */
/*                                                                    */
/* FUNCTION: Initialize device for the playback                       */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  Audio_IOCTL_Init                                    */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP                                           */
/*                                                                    */
/* EXIT-NORMAL:  RPDONE                                               */
/*                                                                    */
/* EXIT-ERROR:  RPDONE|RPERR                                          */
/*              RPDONE|RPERR|INVALID_REQUEST                          */
/*              RPDONE|RPERR|NO_RECORD_AND_PLAY                       */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  NONE                                         */  
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*   ROUTINES:                                                        */
/*            SetSystemTimer                                          */
/*            GetBestFit                                              */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

RC   Audio_IOCTL_Init(PREQPACKET pParm)
{
   MCI_AUDIO_INIT FAR *pInit= (MCI_AUDIO_INIT FAR *)pParm->s.IOCtl.buffer;
   ULONG   ulFlags = 0;
   ULONG   func_offset;
   PSTREAM pStream = GlobalTable.paStream;


   if( !gNoOfActiveAudioDevices )
   {
      #ifdef DEBUG
      dsPrint(DBG_CRITICAL, "USBAUD: AUDIO_INIT Error : No USB Audio devices attached!\r\n");
      #endif
      return(RPDONE|RPERR);
   }

   gOLDAC.lVolume  = 0;
   gOLDAC.lBass    = 0;
   gOLDAC.lTreble  = 0;


   // pStream = GetFileStream((ULONG)((PREQPACKET) pParm)->s.IOCtl.sysfilenum);

   /* Copy parameters to our global variables in case any of them have changed. */

   {
      gDevOperation   = pInit->ulOperation;

      pStream->ulOperation     = pInit->ulOperation;
      pStream->ulFlags         = pInit->ulFlags;
      pStream->usMode          = pInit->sMode;
      pStream->ulSamplingFreq  = pInit->lSRate;
      pStream->ulBitsPerSample = pInit->lBitsPerSRate;
      pStream->ulBSize         = pInit->lBsize;
      pStream->usChannels      = pInit->sChannels;

   }


   if( !gbTimerIntHooked )
   {
      // Hook the system timer
      func_offset = (ULONG) TimerInterruptHandler;
      if( SetSystemTimer((USHORT) func_offset) )
      {
         
      }
      else
         // turn on the flag
         gbTimerIntHooked = TRUE;

      gTicks=32;
   }


   #ifdef DEBUG
   dsPrint3(DBG_SPECIFIC, "USBAUD: AudioInit: Original values : freq=%ld bits=%ld chan=%d\r\n",pInit->lSRate,pInit->lBitsPerSRate,pInit->sChannels);
   #endif

   {
      ULONG 

      ulMode = (ULONG)pInit->sMode,        
      ulFreq = (ULONG)pInit->lSRate,       
      ulChan = (ULONG)pInit->sChannels,    
      ulBits = (ULONG)pInit->lBitsPerSRate;

      //check device capabilities
      if( !GetBestFit((UCHAR FAR *)&gAudioDevices[GlobalTable.ucActiveDeviceIndex].pDeviceInfo->configurationData,
      gAudioDevices[GlobalTable.ucActiveDeviceIndex].bNumConfigurations,
      gAudioDevices[GlobalTable.ucActiveDeviceIndex].devConf->bConfigurationValue,
      gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucStreamingInterface,
      (ULONG FAR *)&ulMode,
      (ULONG FAR *)&ulFreq,
      (ULONG FAR *)&ulChan,
      (ULONG FAR *)&ulBits,
      (UCHAR FAR *)&gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucAltInterface) )
      {
         #ifdef DEBUG
         dsPrint(DBG_CRITICAL, "USBAUD : AudioIOCTLInit GetBestFit Error!\r\n");
         #endif
         return(RPDONE|RPERR);
      }

      gusChannels=(USHORT)ulChan;
      gulBitsPerSample=ulBits;
      gulSamplingFreq=ulFreq;

      if( ((pStream->ulSamplingFreq+pStream->ulSamplingFreq/10)>ulFreq)||
      ((pStream->ulSamplingFreq-pStream->ulSamplingFreq/10)<ulFreq) )
      {
         
      }
      else
         pStream->ulSamplingFreq=ulFreq;

   #ifdef DEBUG
      dsPrint3(DBG_SPECIFIC, "USBAUD: AudioInit: GetBestFit : freq=%ld bits=%ld chan=%d\r\n",
      ulFreq,ulBits , ulChan);
   #endif

   }
   /* retrieve system file number from request packet and stuff it into audio_init struct.
    Also, store it so PDD knows who is the active stream. */

   pInit->pvReserved  = (VOID FAR *)((PREQPACKET) pParm)->s.IOCtl.sysfilenum;
   ulActiveSysFileNum = (ULONG)pInit->pvReserved; // this is now the active instance
   trk = ulActiveSysFileNum;

   switch( pInit->sMode )
   {
      case PCM:                       // Pulse Coded Modulation //
      case DATATYPE_WAVEFORM:
         if( !gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucStreamingInterface )
         {
            pInit->sReturnCode= NO_RECORD_AND_PLAY;
            return(RPDONE|RPERR);
         }
         break;

      case MIDI:                      // MIDI data //
      case DATATYPE_MIDI:
         if( !gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucMIDIInterface )
         {
            pInit->sReturnCode= NO_RECORD_AND_PLAY;
            return(RPDONE|RPERR);
         }
         #ifdef DEBUG
         dsPrint(DBG_SPECIFIC, "USBAUD: AUDIO_INIT: sMode==MIDI\r\n");
         #endif 
         break;

      case IDLE:
         #ifdef DEBUG
         dsPrint(DBG_SPECIFIC, "USBAUD: AUDIO_INIT: sMode==IDLE\r\n");
         #endif 

         // set stream to be stopped   call DevPause()
         // De-init this stream 
         break;

      default:
         #ifdef DEBUG
         dsPrint1(DBG_CRITICAL, "USBAUD: AUDIO_INIT: sMode==%d (invalid)\r\n", pInit->sMode);
         #endif 
         /*
         pInit->sReturnCode= NO_RECORD_AND_PLAY;
         return(RPDONE|RPERR);
         */
         break;
   }



   if( pInit->ulOperation == PLAY_AND_RECORD )
      return(RPDONE|RPERR|NO_RECORD_AND_PLAY);

   if( (pInit->ulOperation != OPERATION_PLAY ) &&
   (pInit->ulOperation != OPERATION_RECORD ) )
      return(RPDONE|RPERR|INVALID_REQUEST );

   #ifdef DEBUG
   dsPrint3(DBG_DETAILED, "USBAUD: Audio Init SRate=%d Bits=%d Channels=%d\r\n",(USHORT)pInit->lSRate,(USHORT)pInit->lBitsPerSRate,pInit->sChannels);
   #endif
   /*
   if( FALSE )
   {
      if( (pInit->lSRate!=(LONG)grate) )
      {
         #ifdef DEBUG
         dsPrint2(DBG_CRITICAL, "USBAUD: AudioInit freq :%ld %ld\r\n", pInit->lSRate, grate);
         #endif
         pInit->lSRate=(LONG)grate;
         pInit->ulFlags|=BESTFIT_PROVIDED;
      }
      if( pInit->lBitsPerSRate!=(LONG)gbits )
      {
         #ifdef DEBUG
         dsPrint2(DBG_CRITICAL, "USBAUD: AudioInit bits: %ld %ld\r\n", pInit->lBitsPerSRate,gbits);
         #endif
         pInit->lBitsPerSRate=(LONG)gbits;
         pInit->ulFlags|=BESTFIT_PROVIDED;
      }
      if( pInit->sChannels!=(SHORT)gchan )
      {
         #ifdef DEBUG
         dsPrint2(DBG_CRITICAL, "USBAUD: AudioInit channels: %ld %ld\r\n", pInit->sChannels, gchan);
         #endif
         pInit->sChannels=(SHORT)gchan;
         pInit->ulFlags|=BESTFIT_PROVIDED;
      }

   }
     */

   if( pInit->lBitsPerSRate<9 )
      pInit->ulFlags|=SIGNED|TWOS_COMPLEMENT;

   pInit->sReturnCode = 0;

   #ifdef DEBUG
   dsPrint(DBG_IRQFLOW, "USBAUD : AudioInit : Exit No_Error\r\n");
   #endif

   return(RPDONE);

}                                                                               


///******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  Audio_IOCTL_Status                               */
/*                                                                    */
/* DESCRIPTIVE NAME:   Audio Buffer Status                            */
/*                                                                    */
/* FUNCTION:  The function of this routine is to obtain current       */
/*             audio buffer status                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  Audio_IOCTL_Status                                  */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PREQPACKET pRP                                             */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: NONE                                          */  
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES: NONE                                          */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
ULONG   Audio_IOCTL_Status(PREQPACKET pRP)
{
   PSTREAM pStream = GlobalTable.paStream;
   MCI_AUDIO_STATUS FAR *pStatus = (MCI_AUDIO_STATUS FAR *)pRP->s.IOCtl.buffer;

   pStatus->lSRate         =  pStream->ulSamplingFreq;
   pStatus->lBitsPerSRate  =  pStream->ulBitsPerSample;
   pStatus->lBsize         =  pStream->ulBSize;
   pStatus->sMode          =  pStream->usMode;
   pStatus->sChannels      =  (SHORT)pStream->usChannels;
   pStatus->ulFlags        =  pStream->ulFlags;
   pStatus->ulOperation    =  pStream->ulOperation;

   pStatus->rAudioChange.lInput   = 0L;
   pStatus->rAudioChange.lOutput  = 0L;
   pStatus->rAudioChange.lMonitor = 0L;
   pStatus->rAudioChange.lVolume  = gAudioDevices[GlobalTable.ucActiveDeviceIndex].ulVolume;
   pStatus->rAudioChange.lBalance = gAudioDevices[GlobalTable.ucActiveDeviceIndex].ulBalance;
   pStatus->rAudioChange.lTreble  = gAudioDevices[GlobalTable.ucActiveDeviceIndex].ulTreble;
   pStatus->rAudioChange.lBass    = gAudioDevices[GlobalTable.ucActiveDeviceIndex].ulBass;

   return(RPDONE);
}


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  Audio_IOCTL_Control                              */
/*                                                                    */
/* DESCRIPTIVE NAME: Audio Control                                    */
/*                                                                    */
/* FUNCTION:  The function of this routine is to process device       */
/*             specific controls operations                           */
/*                                                                    */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  Audio_IOCTL_Control                                 */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PREQPACKET pRP                                             */
/*                                                                    */
/* EXIT-NORMAL:  Always - RPDONE                                      */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */  
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*    ROUTINES:                                                       */
/*      DevChange                                                     */
/*      SetStreamState                                                */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


ULONG   Audio_IOCTL_Control(PREQPACKET pRP)
{
   MCI_AUDIO_CONTROL FAR *pControl= (MCI_AUDIO_CONTROL FAR *)pRP->s.IOCtl.buffer;
   ULONG   ulFlags=0;
   PSTREAM pStream=GlobalTable.paStream;


   switch( pControl->usIOCtlRequest )
   {
      case AUDIO_CHANGE:  /* Required */  
         DevChange ((MCI_AUDIO_CHANGE FAR *)pControl->pbRequestInfo);               /* characteristics */
         pControl->sReturnCode = 0;
         break;

      case AUDIO_START:                /*    Start new gDevOperation    */
         SetStreamState(pStream, STREAM_STATE_START);
         break;

      case AUDIO_STOP:                 /* Stop current operation        */
         SetStreamState(pStream, STREAM_STATE_STOP);
         break;

      case AUDIO_PAUSE:                /* suspend current operation     */
         SetStreamState(pStream, STREAM_STATE_PAUSE);
         break;

      case AUDIO_RESUME:               /* resume a suspended operation  */
         SetStreamState(pStream, STREAM_STATE_RESUME);
         break;

      default:                         /* Unknown control               */
         return(-1);             /* return an error */
         break;
   }
   return(RPDONE);
}
/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  Audio_IOCTL_Load                                 */
/*                                                                    */
/* DESCRIPTIVE NAME:  Audio IOCTL Load                                */
/*                                                                    */
/* FUNCTION:  Audio IOCTL Load                                        */
/*                                                                    */
/*                                                                    */
/* NOTES:  This function is not required by MMPM/2                    */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  Audio_IOCTL_Load                                    */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP                                           */
/*                                                                    */
/* EXIT-NORMAL: always - RPDONE|RPERR|RPBADCMD                        */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: NONE                                          */  
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:  NONE                                         */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


RC   Audio_IOCTL_Load(PREQPACKET pRP)   /* AUDIO_LOAD IOCTL */
{
   return(RPDONE|RPERR|RPBADCMD);
}



/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  Audio_IOCTL_Hpi                                  */
/*                                                                    */
/* DESCRIPTIVE NAME:  Audio IOCTL Hpi                                 */
/*                                                                    */
/* FUNCTION:  Audio IOCTL Load                                        */
/*                                                                    */
/*                                                                    */
/* NOTES:  This function is not required by MMPM/2                    */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  Audio_IOCTL_Hpi                                     */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP                                           */
/*                                                                    */
/* EXIT-NORMAL: always - RPDONE|RPERR|RPBADCMD                        */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: NONE                                          */  
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:  NONE                                         */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

RC   Audio_IOCTL_Hpi(PREQPACKET pRP)   /* AUDIO_HPI IOCTL */
{
   return(RPDONE|RPERR|RPBADCMD);

}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  Audio_IOCTL_Buffer                               */
/*                                                                    */
/* DESCRIPTIVE NAME:    Audio IOCTL Buffer                            */
/*                                                                    */
/* FUNCTION:   The functioon of this routine is to obtaion from       */
/*             Audio DD current audio buffer status                   */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  Audio_IOCTL_Buffer                                  */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP                                           */
/*                                                                    */
/* EXIT-NORMAL:  always RPDONE                                        */
/*                                                                    */
/* EXIT-ERROR:  never                                                 */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: NONE                                          */  
/*                                                                    */
/* EXTERNAL REFERENCES:  NONE                                         */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

RC   Audio_IOCTL_Buffer(PREQPACKET pRP)   /* AUDIO_BUFFER IOCTL */
{
   MCI_AUDIO_BUFFER FAR *pBuffer = (MCI_AUDIO_BUFFER FAR *)pRP->s.IOCtl.buffer;
   PSTREAM pStream   =  GlobalTable.paStream;

   pBuffer->ulFlags        = 0L;
   pBuffer->ulReadBufSize  = 0L;
   pBuffer->ulWriteBufSize = pStream->IOBuff[pStream->usCurrIOBuffIndex].lSize; 
   pBuffer->ulReadBufTime  = -1;
   pBuffer->ulWriteBufTime = -1;
   pBuffer->ulReadBufMax   = 0L;
   pBuffer->ulWriteBufMax  = MAXIOBUFFSIZE;
   pBuffer->ulPosition     = pStream->ulCumTime;
   pBuffer->ulPositionType = POS_MSECS;
   pBuffer->lReadBufCap    = 0L;
   pBuffer->lWriteBufCap   = MAXIOBUFFS;
   pBuffer->lRequestBufCap = 1L;

   return(RPDONE);
}


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  Audio_IOCTL_Wait                                 */
/*                                                                    */
/* DESCRIPTIVE NAME:  Audio IOCTL Wait                                */
/*                                                                    */
/* FUNCTION:  Audio IOCTL Wait                                        */
/*                                                                    */
/*                                                                    */
/* NOTES:  This function is not required by MMPM/2                    */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  Audio_IOCTL_Wait                                    */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP                                           */
/*                                                                    */
/* EXIT-NORMAL: always - RPDONE|RPERR|RPBADCMD                        */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: NONE                                          */  
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:  NONE                                         */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

RC   Audio_IOCTL_Wait(PREQPACKET pRP)   /* AUDIO_WAIT */
{
   return(RPDONE);
}


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  Audio_IOCTL_Capability                           */
/*                                                                    */
/* DESCRIPTIVE NAME:  Audio Capability                                */
/*                                                                    */
/* FUNCTION:  The function of this routine is to obtain capability    */
/*                of Audio device to check if the device              */
/*                   can paly specified data format                   */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  Audio_IOCTL_Capability                              */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP                                           */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  pCaps->ulFlags                                           */
/*           pCaps->ulSupport                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  NONE                                         */
/*                                                                    */  
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:   GetBestFit                                          */
/*                FindMatchingSampleRate                              */
/*                SetControlCapabilities                              */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


RC   Audio_IOCTL_Capability(PREQPACKET pRP)
{
   MCI_AUDIO_CAPS FAR *pCaps = (MCI_AUDIO_CAPS FAR *)pRP->s.IOCtl.buffer;  // get pointer to data buffer
   USHORT usSampleRateIndex;
   ULONG ulChannels=pCaps->ulChannels; // get channels count
   ULONG ulSamplingRate=pCaps->ulSamplingRate; // get sampling freq
   ULONG ulBitsPerSample=pCaps->ulBitsPerSample; // get bits per sample
   ULONG ulDataType=pCaps->ulDataType; // get data type

   pCaps->ulFlags = 0L;

   #ifdef DEBUG
   dsPrint4(DBG_SPECIFIC, "USBAUD: Capability Entry: \tBits=%ld\tFreq=%ld\tCh=%ld\tDataSubTypew=%d\r\n",pCaps->ulBitsPerSample,pCaps->ulSamplingRate,pCaps->ulChannels,pCaps->ulDataSubType);
   #endif

   if( !gNoOfActiveAudioDevices )
   {
      pCaps->ulSupport = UNSUPPORTED_OPERATION;
      return(RPDONE);
   }

   if( pCaps->ulOperation!=OPERATION_PLAY )
   {
      #ifdef DEBUG
      dsPrint1(DBG_CRITICAL, "USBAUD: Audio_Capability UNSUPPORTED_OPERATION=%lxh\r\n", pCaps->ulOperation);
      #endif
      pCaps->ulSupport=UNSUPPORTED_OPERATION;
      return(RPDONE);
   }
   else
      if( pCaps->ulChannels!=1&&pCaps->ulChannels!=2 )
   {
      #ifdef DEBUG
      dsPrint1(DBG_CRITICAL, "USBAUD: Audio_Capability UNSUPPORTED_CHANNELS=%lxh\r\n", pCaps->ulChannels);
      #endif
      pCaps->ulSupport=UNSUPPORTED_CHANNELS;
      return(RPDONE);
   }

   else
      if( pCaps->ulBitsPerSample!=8 && pCaps->ulBitsPerSample!=16 )
   {
         // only 8 and 16 bits are supported
    #ifdef DEBUG
      dsPrint1(DBG_CRITICAL, "USBAUD: Audio_Capability UNSUPPORTED_BPS=%lxh\r\n", pCaps->ulBitsPerSample);
    #endif 

      pCaps->ulSupport=UNSUPPORTED_BPS;
      return(RPDONE);
   }

   // check for device capabilities
   if( !GetBestFit((UCHAR FAR *)&gAudioDevices[GlobalTable.ucActiveDeviceIndex].pDeviceInfo->configurationData,
   gAudioDevices[GlobalTable.ucActiveDeviceIndex].bNumConfigurations,
   gAudioDevices[GlobalTable.ucActiveDeviceIndex].devConf->bConfigurationValue,
   gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucStreamingInterface,
   (ULONG FAR *)&ulDataType,
   (ULONG FAR *)&ulSamplingRate,
   (ULONG FAR *)&ulChannels,
   (ULONG FAR *)&ulBitsPerSample,
   (UCHAR FAR *)&gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucAltInterface) )
   {
      #ifdef DEBUG
      dsPrint(DBG_CRITICAL, "USBAUD : AudioIOCTLCapability : GetBestFit Error!\r\n");
      #endif
      pCaps->ulSupport=UNSUPPORTED_DATATYPE;
      return(RPDONE);

   }

   #ifdef DEBUG
   dsPrint2(DBG_DETAILED, "USBAUD: GetBestFit dev=%d AltInt=%d\r\n", GlobalTable.ucActiveDeviceIndex, gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucAltInterface);
   dsPrint3(DBG_DETAILED, "USBAUD: after rate=%ld ulChannels=%ld ulBitsPerSample=%ld\r\n",ulSamplingRate,ulChannels,ulBitsPerSample);
   dsPrint2(DBG_DETAILED, "ulDataType=%lxh pcaps->ulDataType=%lxh\r\n", ulDataType, pCaps->ulDataType);
   #endif

   if( ulDataType != pCaps->ulDataType )
   {
      pCaps->ulDataType=(USHORT)ulDataType;
      pCaps->ulSupport=UNSUPPORTED_DATATYPE;
      return(RPDONE);
   }


   gbActiveDeviceSupport=TRUE; // Current USB device can support this data type //

   if( (ulChannels   != pCaps->ulChannels )||
   (ulSamplingRate   != pCaps->ulSamplingRate)||
   (ulBitsPerSample  != pCaps->ulBitsPerSample) )
   {
      pCaps->ulFlags|=BESTFIT_PROVIDED;
      pCaps->ulChannels=ulChannels;
      pCaps->ulSamplingRate=ulSamplingRate;
      pCaps->ulBitsPerSample=ulBitsPerSample;
   }

   // save stream data types
   gusChannels=(USHORT) ulChannels;
   gulBitsPerSample=ulBitsPerSample;
   gulSamplingFreq=ulSamplingRate;

   // Search for appropriate data sub type for the current data type
   switch( pCaps->ulDataType )
   {
      case DATATYPE_WAVEFORM:
         usSampleRateIndex = FindMatchingSampleRate(&pCaps->ulSamplingRate);
         pCaps->ulDataSubType=gPCMTable[usSampleRateIndex][(pCaps->ulBitsPerSample-8)/8][pCaps->ulChannels-1];
         break;
      case DATATYPE_MULAW:
         usSampleRateIndex = FindMatchingSampleRate(&pCaps->ulSamplingRate);
         pCaps->ulDataSubType = gMuLaw[usSampleRateIndex][pCaps->ulChannels-1];
         break;
      case DATATYPE_ALAW:
         usSampleRateIndex = FindMatchingSampleRate(&pCaps->ulSamplingRate);
         pCaps->ulDataSubType = gALaw[usSampleRateIndex][pCaps->ulChannels-1];  
         break;
      case DATATYPE_MIDI:
         pCaps->ulDataSubType = SUBTYPE_NONE; // Required for MIDI //
         break;
      default:
         pCaps->ulSupport=UNSUPPORTED_DATATYPE;
         return(RPDONE);
         break;

   }

   #ifdef DEBUG
   dsPrint4(DBG_SPECIFIC, "USBAUD: Capability Exit: \tBits=%ld\tFreq=%ld Ch=%ld\tDataSubType=%d\r\n", ulBitsPerSample, ulSamplingRate, ulChannels, pCaps->ulDataSubType);
   #endif

   if( ulBitsPerSample<9 )
      pCaps->ulFlags|=SIGNED|TWOS_COMPLEMENT;


   pCaps->ulFlags|= OUTPUT |// Output select is supported   //
   MONITOR;  // Monitor is supported         //

   // sets capability flag according to device abilities
   SetControlCapabilities(GlobalTable.ucActiveDeviceIndex, &pCaps->ulFlags);

   pCaps->ulFlags |= FIXED;
   pCaps->ulFlags |= LEFT_ALIGNED;
   pCaps->ulResourceUnits  =  1L;
   pCaps->ulResourceClass  =  1L;
   pCaps->fCanRecord       =  0;
   pCaps->ulBlockAlign     =  1L;
   pCaps->ulCapability     =  SUPPORT_CAP;
   pCaps->ulSupport        =  SUPPORT_SUCCESS;  
   return(RPDONE);

}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  StartDevicePlay                                  */
/*                                                                    */
/* DESCRIPTIVE NAME:   Start Device Play                              */  
/*                                                                    */
/* FUNCTION:  The function of this routine is to start playback       */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  StartDevicePlay                                     */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PSTREAM pStream, BOOL bSetInterface, USHORT usByPass       */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */  
/*                                                                    */
/*    ROUTINES:  SendFirstBuffers                                     */
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:   USBSetInterface                                     */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


RC StartDevicePlay(PSTREAM pStream, BOOL bSetInterface, USHORT usByPass)
{
   if( !gNoOfActiveAudioDevices||pStream==NULL||!gbActiveDeviceSupport )
   {
     #ifdef DEBUG
      dsPrint3(DBG_CRITICAL, "USBAUD: gNo=%d pStream=%lxh Support=%d\r\n", gNoOfActiveAudioDevices, (ULONG)pStream, gbActiveDeviceSupport);
     #endif
      return(ERROR);
   }

   // set interface, if nessesary, else starts playback
   if( (gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucOldAltInterface!=gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucAltInterface) && bSetInterface )
   {
      USBSetInterface(GlobalTable.ucActiveDeviceIndex, gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucAltInterface, pStream, TRUE, NO_BYPASS);
      gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucOldAltInterface=gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucAltInterface;
   }
   else
      if( SendFirstBuffers(pStream, usByPass)!=STATUS_DONE )
      return(ERROR);

   return(NO_ERROR);
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  SendFirstBuffers                                 */
/*                                                                    */
/* DESCRIPTIVE NAME:  Send First Buffers                              */
/*                                                                    */
/* FUNCTION:    Sends to USB device first 2 buffers of audio data     */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  SendFirstBuffers                                    */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PSTREAM pStream, USHORT usByPass                           */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  NONE                                         */  
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:    ISOClose                                           */
/*                 ISOOpen                                            */
/*                 ISOSendBuffer                                      */
/*                 GetNextBuffer                                      */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

USHORT SendFirstBuffers(PSTREAM pStream, USHORT usByPass)
{
   // set up isohrounous pipe
   if( gbISOOpened )
      if( ISOClose()==USB_IDC_RC_OK )
         gbISOOpened=FALSE;
      else
      {
         #ifdef DEBUG
         dsPrint(DBG_CRITICAL, "USBAUD: SendFirstBuffers :ISOClose Failed\r\n");
         #endif
      }

   if( ISOOpen(pStream, 0) != USB_IDC_RC_OK )
   {
      #ifdef DEBUG
      dsPrint(DBG_CRITICAL, "USBAUD: SendFirstBuffers :ISOOpen Failed!\r\n");
      #endif
      return(ERROR_NOT_READY);
   }
   else
      gbISOOpened=TRUE;

  // send first buffer
   ISOSendBuffer(pStream, NO_BYPASS);

   // if there is one buffer, send it
   if( GetNextBuffer (pStream)==STATUS_DONE )
      ISOSendBuffer(pStream, usByPass);

   return(STATUS_DONE);

}
/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  ResumeDevicePlay                                 */
/*                                                                    */
/* DESCRIPTIVE NAME: Resume Device Play                               */
/*                                                                    */
/* FUNCTION: The function of this routine is to resume device         */
/*       playback with active stream after PAUSE-RESUME events        */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  ResumeDevicePlay                                    */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PSTREAM pStream                                            */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: NONE                                          */  
/*                                                                    */
/*    ROUTINES:                                                       */
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:  ISOSendBuffer                                        */
/*               GetNextBuffer                                        */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

RC ResumeDevicePlay(PSTREAM pStream)
{

   #ifdef DEBUG
   dsPrint3(DBG_SPECIFIC, "USBAUD: ResumeDevicePlay : pbuf=%lxh Size=%lxh Buffs=%xh\r\n", (ULONG)pStream->IOBuff[pStream->usCurrIOBuffIndex].pBuffer,pStream->IOBuff[pStream->usCurrIOBuffIndex].lSize,pStream->ucBuffers);
   #endif

   // send first buffer
   ISOSendBuffer(pStream, NO_BYPASS);
   // send second buffer, if it exists
   if( GetNextBuffer (pStream)==STATUS_DONE )
      ISOSendBuffer(pStream, NO_BYPASS);

   return(NO_ERROR);
}


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  InitEventQueue                                   */
/*                                                                    */
/* DESCRIPTIVE NAME: Initialize Event Queue                           */
/*                                                                    */
/* FUNCTION: The function of this routine is to set up start values   */
/*          for stream events                                         */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  InitEventQueue                                      */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  N/A                                                        */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: NONE                                          */  
/*                                                                    */
/* EXTERNAL REFERENCES: NONE                                          */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
VOID InitEventQueue(VOID)
{
   register USHORT  i, j;


   /* Initialize event queues */
   for( i = 0; i < DEFAULTSTREAMS; i++ )
   {
      for( j = 0; j < MAX_EVENT_QUEUE; j++ )
      {
         aEventQueue[i][j].hEvent = (HEVENT)(-1);
         aEventQueue[i][j].ulCuePoint = 0L;
      }
   }
   /* set up event queue header pointers for each stream. */
   for( i = 0; i < DEFAULTSTREAMS; i++ )
   {
      /* pStreamVirt is a virtual address for the stream table saved in InitStream() */
      pStreamVirt->pEventQueue = &aEventQueue[i][0];
      pStreamVirt++;
   }

   return;
}
/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  IOCTL_InitComplete                               */
/*                                                                    */
/* DESCRIPTIVE NAME: IOCTL  INIT Complete                             */
/*                                                                    */
/* FUNCTION:     Provides processing of OS/2 IOCTL INITCOMPLETE command */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  IOCTL_Init                                          */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PREQPACKET rp - apointer to standard OS/2 IOCTL            */
/*                         request packet                             */
/*                                                                    */
/* EXIT-NORMAL:  RPDONE                                               */
/*                                                                    */
/* EXIT-ERROR:  error specific return code                            */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  NONE                                         */  
/*                                                                    */
/* EXTERNAL REFERENCES:  NONE                                         */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
RC   IOCTL_InitComplete(PREQPACKET rp)
{
   return(RPDONE);
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  IOCTL_Init                                       */
/*                                                                    */
/* DESCRIPTIVE NAME: IOCTL  INIT                                      */
/*                                                                    */
/* FUNCTION:     Provides processing of OS/2 IOCTL INIT command       */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  IOCTL_Init                                          */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PREQPACKET rp - apointer to standard OS/2 IOCTL            */
/*                         request packet                             */
/*                                                                    */
/* EXIT-NORMAL:  RPDONE                                               */
/*                                                                    */
/* EXIT-ERROR:  error specific return code                            */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */  
/*                                                                    */
/*    ROUTINES:  NONE                                                 */
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:  ProcessConfigString                                  */
/*               RMHELP_CreateDriver                                  */
/*               GetUSBDIDC                                           */
/*               AddToMsgArray                                        */
/*               DevHelp_AllocateCtxHook                              */
/*               SetLongValue                                         */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


RC   IOCTL_Init(PREQPACKET rp)
{
   PRPINITOUT      pRPO;  /* output request packet far pointer */
   PRPINITIN       pRPI;  /* input request packet far pointer */
   PSZ             pszCmdLine; /* pointer to command line */
   ULONG           cmdRStatus, errColumn;  
   USHORT          cmdRc;
   RC  rc=RPDONE;

   /* Command line parameters */
   KeyData         keyData[1]={"V",CFSTR_TYPE_DEC,0,0}; // allow verbose during init //


   pRPI = (PRPINITIN) rp;
   pRPO = (PRPINITOUT) rp;


   // get pointer to USB AUDIO  command line in config.sys
   pszCmdLine=(PSZ) MAKEP( SELECTOROF(pRPI->InitArgs), 
   OFFSETOF(((PDDD_PARM_LIST)pRPI->InitArgs)) );

   cmdRStatus  =  ProcessConfigString(pszCmdLine, 1, (KeyData FAR *)&keyData); // process command line to serach specified values and mistakes
   cmdRc       =  LOUSHORT(cmdRStatus); // get command line processing status
   errColumn   =  (ULONG)HIUSHORT(cmdRStatus);// get error column no

   gVerbose = keyData[0].keyStatus!=CFSTR_STATUS_NOTFOUND; // set  verbose variable //

   switch( cmdRc )
   {  // set cmd line processing errors
      case CFSTR_UNKWN_KEYS: /* invalid keys found in command line */
         SetLongValue( gVMessages[INIT_MESSAGE_UNKNOWNKWD], errColumn );
         gMessageCount=AddToMsgArray( gMessageIDs, INIT_MESSAGE_UNKNOWNKWD, gMessageCount, MAX_INIT_MESSAGE_COUNT );
         break;
      case CFSTR_CONVERR:  /* invalid key value found */
         SetLongValue( gVMessages[INIT_MESSAGE_INVNUMERIC], errColumn );
         gMessageCount=AddToMsgArray( gMessageIDs, INIT_MESSAGE_INVNUMERIC, gMessageCount, MAX_INIT_MESSAGE_COUNT );
         break;
      default:
         break;
   }

   if( !GlobalTable.fInited )            // don't init both headers
      GlobalTable.fInited = TRUE;
   else
   {
      rp->s.InitExit.finalCS = (USHORT)&LastCode; // set up end of code mark (all code below this offset will be destroyed aftrer initialization
      rp->s.InitExit.finalDS = (USHORT)&EndOfData; // set up end of data mark (all data below this offset will be destroyed aftrer initialization
      rc=RPDONE;
   }

   Device_Help=(PFN)(CHAR FAR *) rp->s.Init.DevHlp; // get devhelp entry point
   /*
   ** Set varable in data segement to point to the
   ** OS/2 DevHlp entry point.  The address of this
   ** routine is in the gDevHdr data structure.
   ** This address will be referenced on later calls
   ** to DevHlp.
   */

   DevHlp = (CHAR FAR*) rp->s.Init.DevHlp; // get devhelp entry point

   if( rc==RPDONE )
   {

      GetUSBDIDC();  //  get USB Driver IDC entry point address


      if( !gpUSBDIDC || !gUSBDds )
      {
         #ifdef DEBUG
         dsPrint(DBG_CRITICAL, "USBAUD : Unable to attach USBD driver\r\n");
         #endif
         gMessageCount = AddToMsgArray( gMessageIDs, INIT_MESSAGE_NO_USBD, gMessageCount, MAX_INIT_MESSAGE_COUNT );
         rc = RPDONE | RPERR | RPGENFAIL;
      }
      // Create driver within Resource Manager
      if( RMHELP_CreateDriver("USBAUDIO.SYS") != RMRC_SUCCESS )
      {
         rp->s.InitExit.finalCS = 0;
         rp->s.InitExit.finalDS = 0;
         #ifdef DEBUG 
         dsPrint(DBG_CRITICAL,"USBAUD: RMCreateDriver failed! \r\n");
         #endif
         rc= RPDONE | RPERR | RPGENFAIL;
      }

      // Create USB Audio specific Adapter within Resource Manager 
      if( rc==RPDONE )
      {
         if( RMHELP_CreateAdapter() != RMRC_SUCCESS )
         {
            // failed to create adapter
            rp->s.InitExit.finalCS = 0;
            rp->s.InitExit.finalDS = 0;
            RMHELP_DestroyDriver();
            #ifdef DEBUG 
            dsPrint(DBG_CRITICAL,"USBAUD : RMCreateAdapter failed! \r\n");
            #endif
            rc= RPDONE | RPERR | RPGENFAIL;
         }
      }

      
      if( rc==RPDONE )
      {
      // Registration within Resource Manager routines succefull

         /* As return values, tell the operating system the
          address (offset) of the end of the code and data segments.*/
         rp->s.InitExit.finalCS = (USHORT)&LastCode;
         rp->s.InitExit.finalDS = (USHORT)&EndOfData;


         // Call routine to get streaming initialized with MMPM/2
         // and then return to the kernel via our assembler code. 


         // initialize streams global data structure
         if( InitStreams() & RPERR )
         {
            #ifdef DEBUG
            dsPrint(DBG_CRITICAL, "USBAUD: InitStreams failed!\r\n");
            #endif
            RMHELP_DestroyDriver();
            rc= RPERR | RPDONE;
         }

         // initialize events structure
         if( rc==RPDONE )
            InitEventQueue();
         {
            USHORT ctxOffset=(USHORT)(LONG)(CTXReportBuffer);  
            DevHelp_AllocateCtxHook((NPFN)ctxOffset, &gRBHandle);
         }
         // Initialize "verbose" print messages
         SetLongValue( gVMessages[INIT_MESSAGE_LOADED], (ULONG)gDriverStruct.MajorVer );   
         SetLongValue( gVMessages[INIT_MESSAGE_LOADED], (ULONG)gDriverStruct.MinorVer );   
         gMessageCount = AddToMsgArray( gMessageIDs, INIT_MESSAGE_LOADED, gMessageCount, MAX_INIT_MESSAGE_COUNT );
      }
   }


   TTYWrite(gVMessages, gMessageIDs, gMessageCount); // output verbose messages 

   return(rc);
}

/********************* START OF SPECIFICATIONS *********************
*
* SUBROUTINE NAME:          InitStreams
*
* DESCRIPTIVE NAME:
*
* FUNCTION:         Initializes the stream table at device init time.
*
* NOTES: This routine is removed from the code segment after boot time.
*
*
* ENTRY POINTS:
*     LINKAGE:  Near from IOCTL_Init()
*
* INPUT: NONE
*
* EXIT-NORMAL:  NO_ERROR
*
* EXIT_ERROR:  RPERR 
*
* EFFECTS:
*
* INTERNAL REFERENCES: none
*
* EXTERNAL REFERENCES: DevHlps
*
*********************** END OF SPECIFICATIONS **********************/


ULONG InitStreams(VOID)
{
   register USHORT  i, j;
   ULONG           BlkSize;
   PVOID           PhysAddress;
   BOOL            bErrFlg = FALSE;
   PSTREAM         pStream;


   /* Allocate memory for stream table, */
   BlkSize = sizeof(STREAM) * GlobalTable.usMaxNumStreams;

   /* Allocate in high memory first.  If it fails allocate in low mem */
   if( DevHlp_AllocPhys(BlkSize, 0, &PhysAddress) ) // Allocate high
   {
      /* If that fails, allocate low 
      If that fails, installation fails */
      if( DevHlp_AllocPhys(BlkSize, 1, &PhysAddress) )
         return(RPDONE | RPERR);
   }

   /*********************************************************/
   /* allocate GDTs                                         */
   /* The GDT addresses are copied from7 the local variable  */
   /* into the GlobalTable so they can be used when running */
   /* at ring 0 (after initialization).                     */
   /* Set up a temporary virtual address.                   */
   /* Note, cannot use GDT at init time as init is ring 3.  */
   /* The GDT is allocated during init, but cannot be used  */
   /* until executing at ring 0.                            */
   /*********************************************************/

   if( DevHlp_AllocGDTSelector(NUMGDTS, &usGDT[GDT_PSTREAM])||DevHlp_PhysToVirt(PhysAddress,BlkSize,&GlobalTable.paStream) )
      return(RPDONE | RPERR);

   /* Initialize stream table */
   pStream = GlobalTable.paStream;
   pStreamVirt = pStream; // save for use later on in InitEventQueue()

   // clear up stream nodes
   for( i=0; i<GlobalTable.usMaxNumStreams; i++ )
   {
      pStream->hStream      = -1;
      pStream->ulSysFileNum = -1;
      pStream->ulFlags      =  0L;

      for( j=0; j<MAXIOBUFFS; j++ )
      {
         pStream->IOBuff[j].usRunFlags = 0;
         pStream->IOBuff[j].lCount     = 0L;
         pStream->IOBuff[j].pBuffer    = NULL;
         pStream->IOBuff[j].pHead      = NULL;

      }
      pStream++;
   }

   /* Map to GDT selector to address of stream table */
   if( DevHlp_PhysToGDTSelector(PhysAddress,  // Physical address
   BlkSize,          // Length
   usGDT[GDT_PSTREAM]) )        // Selector to map
      bErrFlg = TRUE;

   else
      GlobalTable.paStream = MAKEP(usGDT[GDT_PSTREAM],0);  /* set to virtual GDT pointer */

   return(bErrFlg?RPERR|RPDONE:RPDONE);
}





