/* SCCSID = "src/dev/usb/USBAUDIO/AUDIOCOM.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:  AUDIOCOM.C                                            */
/*                                                                            */
/*   DESCRIPTIVE NAME:  PDD`s Comunicator                                     */
/*                                                                            */
/*                                                                            */
/*   FUNCTION: Consists of functions to comunicate with others USB            */
/*                stack drivers                                               */
/*                                                                            */
/*                                                                            */
/*   NOTES:                                                                   */
/*      DEPENDENCIES: None                                                    */
/*      RESTRICTIONS: None                                                    */
/*                                                                            */
/*   ENTRY POINTS:                                                            */
/*                     USBAUDIOProcessIRQ                                     */
/*                     USBSetInterface                                        */
/*                     SetUnitControl                                         */
/*                     GetUnitControl                                         */
/*                     CTXReportBuffer                                        */
/*                     ISOOpen                                                */
/*                     ISOClose                                               */
/*                     ISOCancel                                              */
/*                     ISOStatus                                              */
/*                                                                            */
/*   EXTERNAL REFERENCES:													               */
/*                      DevHelp_AttachDD                                      */
/*                      USBCallIDC                                            */
/*                      SetChannelsCapabilities                               */
/*                      GetChannelCount                                       */
/*                      StartDevicePlay                                       */
/*                      ReportFreeBuffer                                      */
/*                                                                            */
/* Change Log                                                                 */
/*                                                                            */
/*  Mark    yy/mm/dd  Programmer          Comment                             */
/*  ----    --------  ----------          -------                             */
/*          98/10/17  Vjacheslav Chibis   Original developer.                 */
/*                                                                            */
/**************************** END OF SPECIFICATIONS ***************************/


#include "usbaud.h"

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  GetUSBDIDC                                       */
/*                                                                    */
/* DESCRIPTIVE NAME:  Retrieves USBD driver IDC routine address & ds  */
/*                                                                    */
/* FUNCTION:  Retrieves USBD driver IDC routine address & data        */
/*            segment value.                                          */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  GetUSBDIDC                                           */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  none                                                       */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: Sets gpUSBDIDC and gUSBDds with USBD driver IDC ref data*/
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
VOID GetUSBDIDC(VOID)
{
   setmem((PSZ)&gDDTable, 0, sizeof(gDDTable));

   gpUSBDIDC   =  NULL;
   gUSBDds   =  0;

   if( DevHelp_AttachDD( gUSBDName, (NPBYTE)&gDDTable) )
      return;      /* Couldn't find USBD's IDC */

   gpUSBDIDC = (PUSBIDCEntry)gDDTable.ProtIDCEntry;
   gUSBDds = gDDTable.ProtIDC_DS;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  RegisterClass                                    */
/*                                                                    */
/* DESCRIPTIVE NAME:                                                  */
/*                                                                    */
/* FUNCTION:                                                          */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:                                                       */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  none                                                       */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/


USHORT RegisterClass(VOID)
{
   RP_GENIOCTL    rp_USBDReg;
   USBDClass      classRegData;


   setmem((PSZ)&rp_USBDReg, 0, sizeof(rp_USBDReg));
   rp_USBDReg.rph.Cmd    = CMDGenIOCTL;   // IOCTL
   rp_USBDReg.Category   = USB_IDC_CATEGORY_USBD;
   rp_USBDReg.Function   = USB_IDC_FUNCTION_REGISTER;
   rp_USBDReg.ParmPacket = (PVOID)&classRegData;
   classRegData.usbIDC   = (PUSBIDCEntry)&USBDIDCEntry;//IDCEntryPoint;

   classRegData.usbDS=GetDS();

   USBCallIDC( gpUSBDIDC, gUSBDds, (RP_GENIOCTL FAR *)&rp_USBDReg );

   #ifdef DEBUG 
   if( rp_USBDReg.rph.Status!=STATUS_DONE )
      dsPrint1(DBG_CRITICAL, "USBAUD: Error registering USBD. Status = %x\r\n", 
      rp_USBDReg.rph.Status);
   else
      dsPrint(DBG_IRQFLOW, "USBAUD: Register USBD ok.\r\n");
   #endif
   return(rp_USBDReg.rph.Status);

}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  USBDIDCEntry                                     */
/*                                                                    */
/* DESCRIPTIVE NAME:  PDD-PDD IDC entry point and request router      */
/*                                                                    */
/* FUNCTION:  This routine is the PDD-PDD IDC entry point and         */
/*            request router..  IDC function requests are routed      */
/*            to the appropriate worker routine.  The address of      */
/*            this routine is returned to other device drivers via    */
/*            the DevHelp AttachDD call.                              */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  USBDIDCEntry                                        */
/*    LINKAGE  :  CALL FAR                                            */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP_GENIOCTL                                  */
/*                                                                    */
/* EXIT-NORMAL:  n/a                                                  */
/*                                                                    */
/* EXIT-ERROR:  n/a                                                   */
/*                                                                    */
/* EFFECTS:  sets error code in pRP_GENIOCTL->rph.Status              */
/*           USB_IDC_RC_PARMERR - 1) request command code is not      */
/*                                CMDGenIOCTL; 2) parameter packet    */
/*                                address is NULL;                    */
/*           USB_IDC_RC_WRONGFUNC - wrong function requested          */
/*           USB_IDC_RC_WRONGCAT - wrong request category             */
/*                                                                    */
/* INTERNAL REFERENCES:                             */
/*    ROUTINES:                                     */
/*                                                  */
/*                                                  */
/*                                                                    */
/* EXTERNAL REFERENCES:  USBCallIDC                                   */
/*    ROUTINES:                                                       */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


VOID FAR USBDIDCEntry( PRP_GENIOCTL pRP_GENIOCTL )
{
   USHORT   status;

   if( !pRP_GENIOCTL )
      return;

   #ifdef   DEBUG
   dsPrint3(DBG_IRQFLOW, "USBAUDIO : USBDIDCEntry started: Category=%x, Function=%x, Status=%x\r\n",
   pRP_GENIOCTL->Category,pRP_GENIOCTL->Function,pRP_GENIOCTL->rph.Status);
   #endif


   status = pRP_GENIOCTL->rph.Status; // save old status for future use

   pRP_GENIOCTL->rph.Status = USB_IDC_RC_OK; // set new status

   // check for parameters errors
   if( pRP_GENIOCTL->rph.Cmd!=CMDGenIOCTL || !pRP_GENIOCTL->ParmPacket )
      pRP_GENIOCTL->rph.Status=USB_IDC_RC_PARMERR;

   if( pRP_GENIOCTL->rph.Status==USB_IDC_RC_OK )
      switch( pRP_GENIOCTL->Category )
      {
         case USB_IDC_CATEGORY_CLASS:
            switch( pRP_GENIOCTL->Function )
            {
               case USB_IDC_FUNCTION_DETDEV:
                  pRP_GENIOCTL->rph.Status=DetachDevice( pRP_GENIOCTL )?STERR|STATUS_DONE:STATUS_DONE;
                  break;
               case USB_IDC_FUNCTION_CHKSERV:
                  CheckForService( pRP_GENIOCTL );
                #ifdef DEBUG
                  if( pRP_GENIOCTL->rph.Status==USB_IDC_RC_SERVREJCTD )
                     dsPrint(DBG_CRITICAL, "USBAUD: Not USB Audio Device.\r\n");
                #endif
                  break;
               case USB_IDC_FUNCTION_PRCIRQ:
                  pRP_GENIOCTL->rph.Status = status; // restore status
                  USBAUDIOProcessIRQ( pRP_GENIOCTL );
                  break;
               default:
                  pRP_GENIOCTL->rph.Status=USB_IDC_RC_WRONGFUNC;
                  break;
            }
            break;
         default:
            pRP_GENIOCTL->rph.Status=USB_IDC_RC_WRONGCAT;
            break;
      }

   pRP_GENIOCTL->rph.Status|=STATUS_DONE;   // set up status to show complete

   #ifdef   DEBUG
   dsPrint3(DBG_IRQFLOW, "USBAUDIO : USBIDCEntry finished: Category=%x, Function=%x, Status=%x\r\n",
   pRP_GENIOCTL->Category,pRP_GENIOCTL->Function,pRP_GENIOCTL->rph.Status);
   #endif
   return;
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  CheckForService                                  */
/*                                                                    */
/* DESCRIPTIVE NAME:  Check for service                               */
/*                                                                    */
/* FUNCTION:  The function of this routine is to chack new attached   */
/*            USB device for service                                  */
/*                                                                    */
/* NOTES:  none                                                       */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  CheckForService                                      */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP_GENIOCTL  - pointer to request packet     */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR: N/A                                                    */
/*                                                                    */
/* EFFECTS:                                                           */  
/*                                                                    */
/* INTERNAL REFERENCES:  none                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  SearchConfiguration                          */
/*                       GetPipeAddr                                  */
/*                       GetMaxAltIntf                                */
/*                       GetFeatureUnitDesc                           */
/*                       SetChannelsCapabilities                      */
/*                       GetDS                                        */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/



VOID CheckForService(PRP_GENIOCTL pRP_GENIOCTL)
{
   USBCDServe FAR    *serviceData = (USBCDServe FAR *)pRP_GENIOCTL->ParmPacket;
   DeviceConfiguration FAR    *devConf;
   USHORT            deviceIndex;
   USBSetConf        setConfiguration;
   RP_GENIOCTL       rp_USBReq;
   UCHAR             controlInterface, featureUnitID=0, controlConfiguration;
   USHORT            controlConfData;
   FUnitDescriptor FAR     *featureUDesc=NULL;
   UCHAR             bNumConfigurations, sc;
   USHORT            confData, usMIDIConfData;
   UCHAR             ucStreamingPipe, ucMIDIPipe;
   UCHAR             ucStreamingInterface, ucMIDIInterface;


   // checks for proper device type
   if( serviceData->pDeviceInfo->descriptor.bDeviceClass    ||
   serviceData->pDeviceInfo->descriptor.bDeviceSubClass ||
   serviceData->pDeviceInfo->descriptor.bDeviceProtocol
   )
   {
      pRP_GENIOCTL->rph.Status = USB_IDC_RC_SERVREJCTD;
      return;
   }

   bNumConfigurations = serviceData->pDeviceInfo->descriptor.bNumConfigurations;
   devConf = (DeviceConfiguration FAR *)serviceData->pDeviceInfo->configurationData;

   confData = SearchConfiguration(( UCHAR FAR *)devConf, // UCHAR FAR *configurationData
   bNumConfigurations,   // UCHAR bNumConfigurations
   AUDIO,                // UCHAR interfaceClass,
   AUDIOSTREAMING,       // UCHAR interfaceSubClass
   PR_PROTOCOL_UNDEFINED // UCHAR interfaceProtocol
   );
   sc=LOBYTE(confData);

   ucStreamingInterface=HIBYTE(confData);

   if( !sc||(!bNumConfigurations&&(bNumConfigurations!=sc)) )
   {
      pRP_GENIOCTL->rph.Status=USB_IDC_RC_SERVREJCTD;
      return;
   }

   {
      UCHAR altMax, altIndex;

      ucStreamingPipe=0;
      ucStreamingInterface=HIBYTE(confData);

      altMax=GetMaxAltIntf(( UCHAR FAR *)devConf, bNumConfigurations,
      sc, ucStreamingInterface);
      for( altIndex=0; altIndex<=altMax && !ucStreamingPipe; altIndex++ )
      {
         ucStreamingPipe=GetPipeAddr(( UCHAR FAR *)devConf, bNumConfigurations, sc,
         ucStreamingInterface, altIndex, DEV_ENDPT_DIROUT, DEV_ENDPT_DIRMASK, DEV_ENDPT_ISOHR);
      }
#ifdef   DEBUG
      dsPrint4(DBG_DETAILED, "USBAUD : conf %d, Intf %d, AltCount %d, pipe %d\r\n",
      (ULONG)sc, (ULONG)ucStreamingInterface,(ULONG)altMax, (ULONG)ucStreamingPipe);
#endif
      if( !ucStreamingPipe )
      {
         pRP_GENIOCTL->rph.Status=USB_IDC_RC_SERVREJCTD;
         return;
      }
   }


/*********************** MIDI ***********************************************/

   usMIDIConfData = SearchConfiguration(( UCHAR FAR *)devConf, // UCHAR FAR *configurationData
   bNumConfigurations,   // UCHAR bNumConfigurations
   AUDIO,                // UCHAR interfaceClass,
   MIDISTREAMING,        // UCHAR interfaceSubClass
   PR_PROTOCOL_UNDEFINED // UCHAR interfaceProtocol
   );

   ucMIDIInterface=HIBYTE(usMIDIConfData);
   if( !ucMIDIInterface )
   {
      UCHAR altMIDIMax, altMIDIIndex;


      altMIDIMax=GetMaxAltIntf(( UCHAR FAR *)devConf, bNumConfigurations,
      sc, ucMIDIInterface);

      for( altMIDIIndex=0; altMIDIIndex<=altMIDIMax && !ucMIDIPipe; altMIDIIndex++ )
      {
         ucMIDIPipe=GetPipeAddr(( UCHAR FAR *)devConf, bNumConfigurations, LOBYTE(usMIDIConfData),
         ucMIDIInterface, altMIDIIndex, DEV_ENDPT_DIROUT, DEV_ENDPT_DIRMASK, DEV_ENDPT_ISOHR);
      }
   };



/*************************************************************************/



   controlConfData = SearchConfiguration(( UCHAR FAR *)devConf, // UCHAR FAR *configurationData
   bNumConfigurations,   // UCHAR bNumConfigurations
   AUDIO,                // UCHAR interfaceClass,
   AUDIOCONTROL,         // UCHAR interfaceSubClass
   PR_PROTOCOL_UNDEFINED // UCHAR interfaceProtocol
   );

   controlConfiguration =  LOBYTE(controlConfData);
   controlInterface     =  HIBYTE(controlConfData);

   if( controlConfiguration && controlConfiguration==LOBYTE(sc) )
   {
      featureUDesc = GetFeatureUnitDesc(( UCHAR FAR *)devConf, // UCHAR FAR *configurationData
      bNumConfigurations,   // UCHAR bNumConfigurations
      controlConfiguration, // UCHAR interfaceClass,
      controlInterface      // UCHAR interfaceSubClass
      );
      if( featureUDesc )
         featureUnitID=featureUDesc->bUnitID;
   }

   #ifdef   DEBUG
   dsPrint4(DBG_DETAILED, "USBAUD : Control conf %d, Intf %d, Feature UnitID %d, Desc=%lx\r\n",
   (ULONG)controlConfiguration, (ULONG)controlInterface,(ULONG)featureUnitID,(ULONG)featureUDesc);
   #endif

/* device belongs to Audio class - allocate new servicable device entry */
   for( deviceIndex=0; deviceIndex<gNoOfActiveAudioDevices; deviceIndex++ )
      if( !gAudioDevices[deviceIndex].pDeviceInfo )
         break;
   if( deviceIndex+1>=MAX_AUDIO_DEVICES )
   {  /* no space in Hub data entry table - set error return code */
      pRP_GENIOCTL->rph.Status=USB_IDC_RC_EXCEEDSMAX;
   #ifdef   DEBUG
      dsPrint(DBG_DETAILED, "USBAUD : CheckForService: Can not allocate device entry\r\n");
   #endif
      return;
   }

   gNoOfActiveAudioDevices++;  // now we have one more USB Audio device :)

   // set up index, if there was not any device attached
   if( GlobalTable.ucActiveDeviceIndex==0xFF )
      GlobalTable.ucActiveDeviceIndex=0;

   #ifdef DEBUG
   dsPrint1(DBG_SPECIFIC, "USBAUD: gNoOfActiveAudioDevices=%d\r\n", gNoOfActiveAudioDevices);
   #endif

   // sets up new  device global data
   gAudioDevices[deviceIndex].ucControlInterface   =  controlInterface;
   gAudioDevices[deviceIndex].ucStreamingPipe      =  ucStreamingPipe;
   gAudioDevices[deviceIndex].ucStreamingInterface =  ucStreamingInterface;
   gAudioDevices[deviceIndex].ucMIDIInterface      =  ucMIDIInterface;
   gAudioDevices[deviceIndex].ucMIDIPipe           =  ucMIDIPipe;
   gAudioDevices[deviceIndex].ucFeatureUnitID      =  featureUnitID;
   gAudioDevices[deviceIndex].bNumConfigurations   =  bNumConfigurations;
   gAudioDevices[deviceIndex].ucChannels           =  GetChannelCount(featureUDesc);

   // sets capablities for the new device channels
   SetChannelsCapabilities(deviceIndex, featureUDesc);

   #ifdef DEBUG
   dsPrint3(DBG_DETAILED, "USBAUD: PCM Interface=%d MIDI Interface=%d ControlInterface=%d\r\n",
   gAudioDevices[deviceIndex].ucStreamingInterface,
   gAudioDevices[deviceIndex].ucMIDIInterface,
   gAudioDevices[deviceIndex].ucControlInterface);
   dsPrint2(DBG_DETAILED, "USBAUD: PCM Pipe=%d MIDI Pipe=%d \r\n",
   gAudioDevices[deviceIndex].ucStreamingPipe,
   gAudioDevices[deviceIndex].ucMIDIPipe);
   #endif

   gAudioDevices[deviceIndex].pDeviceInfo       =  serviceData->pDeviceInfo;   // far pointer to device data
   gAudioDevices[deviceIndex].devConf           =  devConf;       // far pointer to device cinfiguration data

   // set up all requered data and call setconfiguration for the new device
   setConfiguration.controllerId       =  serviceData->pDeviceInfo->ctrlID;        // controller ID, not used, should be set to 0
   setConfiguration.deviceAddress      =  serviceData->pDeviceInfo->deviceAddress;       // USB device address
   setConfiguration.classDriverDS = GetDS();// class driver data segment value (used to identify driver)
   setConfiguration.configurationValue =  devConf->bConfigurationValue;  // desired configuration value (type depends on call function)
   setConfiguration.irqSwitchValue     =  USBAUD_IRQ_STATUS_SETCONF;      // value used in class driver IRQ processor worker switch
   setConfiguration.category           =  USB_IDC_CATEGORY_CLASS;            // IRQ processor category
   setConfiguration.setConfiguration   =  &gAudioDevices[deviceIndex].stdPacket;

   setmem(  (PSZ)&rp_USBReq, 0, sizeof(rp_USBReq)  );
   rp_USBReq.rph.Cmd    =  CMDGenIOCTL;   // IOCTL
   rp_USBReq.Category   =  USB_IDC_CATEGORY_USBD;  // target is USB Driver 
   rp_USBReq.Function   =  USB_IDC_FUNCTION_SETCONF; // functionn identificator
   rp_USBReq.ParmPacket =  (PVOID)&setConfiguration;

   USBCallIDC( gpUSBDIDC, gUSBDds, (PRP_GENIOCTL)&rp_USBReq );

   return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  GetFeatureUnitDesc                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  Get audio feature unit descriptor address       */
/*                                                                    */
/* FUNCTION:  The function of this routine is find audio feature unit */
/*            device descriptor address.                              */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  GetFeatureUnitDesc                                   */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  UCHAR FAR *configurationData - far pointer to device       */
/*                      configuration data buffer                     */
/*         UCHAR bNumConfigurations - number of configurations for    */
/*                      device                                        */
/*         UCHAR configurationValue - current configuration           */
/*         UCHAR interface - interface                                */
/*                                                                    */
/* EXIT-NORMAL: non-NULL feature unit descriptor address              */
/*                                                                    */
/* EXIT-ERROR: NULL if failed to locate feature unnit descriptor      */
/*                                                                    */
/* EFFECTS: none                                                      */
/*                                                                    */
/* INTERNAL REFERENCES:  GetNextDescriptor                            */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
static FUnitDescriptor FAR * GetFeatureUnitDesc( UCHAR FAR *configurationData,
UCHAR bNumConfigurations,
UCHAR bConfigurationValue,
UCHAR interface)
{
   DeviceConfiguration FAR *devConf;
   UCHAR                   configIndex;
   UCHAR FAR               *currBytePtr, FAR *lastBytePtr;
   DeviceDescHead FAR      *descHead;
   DeviceInterface FAR     *interfaceDesc;
   FUnitDescriptor FAR     *featureUDesc=NULL;
   BOOL                    interfaceFound=FALSE;

   devConf=(DeviceConfiguration FAR *)configurationData;
   for( configIndex=0; configIndex<bNumConfigurations;
   configIndex++ )
   {
      currBytePtr=(UCHAR FAR *)devConf;
      lastBytePtr=currBytePtr+devConf->wTotalLength;
      descHead=(DeviceDescHead FAR *)(currBytePtr+devConf->bLength);
      if( devConf->bConfigurationValue==bConfigurationValue )
      {
         for( descHead=(DeviceDescHead FAR *)(currBytePtr+devConf->bLength); descHead && !featureUDesc;
         descHead=GetNextDescriptor( descHead, lastBytePtr) )
         {
            switch( descHead->bDescriptorType )
            {
               case DESC_INTERFACE:
                  interfaceDesc=(DeviceInterface FAR *)descHead;
                  interfaceFound= interfaceDesc->bInterfaceNumber==interface;
                  break;
               case CS_INTERFACE:
                  if( !interfaceFound )
                     break;
                  switch( descHead->bDescriptorSubtype )
                  {
                     case FEATURE_UNIT:
                        featureUDesc=(FUnitDescriptor FAR *)descHead;
                        break;
                     default:
                        break;
                  }
                  break;
               default:
                  break;
            }
         }
         break;
      }
      devConf=(DeviceConfiguration FAR *)lastBytePtr; // point to next configuration block
   }
   return(featureUDesc);
}


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  USBAUDIOProcessIRQ                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  IRQ procesing extension routine                 */
/*                                                                    */
/* FUNCTION:  This function process IRQ IDC calls                     */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  USBAUDIOProcessIRQ                                  */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP                                           */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */  
/*                                                                    */
/*    ROUTINES:   USBAUDIOClearStalled                                */
/*                GenerateDetach                                      */
/*                SetConf                                             */
/*                GetUnitControl                                      */
/*                SetUnitControl                                      */
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:   InitNewDevice                                       */
/*                StartDevicePlay                                     */
/*                ReportFreeBuffer                                    */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


VOID USBAUDIOProcessIRQ( PRP_GENIOCTL pRP )
{
   USBRB FAR *pRB = (USBRB FAR *)pRP->ParmPacket;
   PSTREAM   pStream;
   USHORT usIOBufIndex;


   if( pRB->status&USRB_STATUS_STALLED )
   {
   #ifdef DEBUG
      dsPrint(DBG_CRITICAL,"USBAUD: IRQ: CLEARSTALLED!\r\n");
   #endif
      // call clear stalled once only //
      if( pRB->requestData1!=IRQ_CLEARSTALLED )
      {
         USBAUDIOClearStalled( pRP );
      }
      else
      {
         GenerateDetach( pRB->controllerId, pRB->deviceAddress);
      }
   }

   switch( pRB->requestData1 )
   {
      case USBAUD_IRQ_STATUS_SETCONF:
         {

            UCHAR ucNewDeviceIndex=0; 


            for( ucNewDeviceIndex=0;ucNewDeviceIndex<MAX_AUDIO_DEVICES;ucNewDeviceIndex++ )
            {
               if( gAudioDevices[ucNewDeviceIndex].pDeviceInfo!=NULL )
               {
                  if( gAudioDevices[ucNewDeviceIndex].pDeviceInfo->deviceAddress==pRB->deviceAddress )
                     break;
               }
               if( ucNewDeviceIndex==MAX_AUDIO_DEVICES-1 )
               {
            #ifdef DEBUG
                  dsPrint1(DBG_CRITICAL, "USBAUD : IRQ : SetConf : Cannot find the device addr=%d \r\n", pRB->deviceAddress);
            #endif
                  pRP->rph.Status=USB_IDC_RC_ALLOCERR;
                  return;
               }

            }
            gAudioDevices[ucNewDeviceIndex].ucOldAltInterface = 0xFF; // show that we have to set up the interface next time

            SetConf(pRP);  // sets configuration for the device


            // checks if setconf is ok
            if( pRP->rph.Status!=USB_IDC_RC_OK )
            {
            #ifdef DEBUG
               dsPrint1(DBG_CRITICAL, "USBAUD : IRQ : SetConf Failed status=%lxh\r\n", pRP->rph.Status);
            #endif
               return;
            }

            // get channel capabilities for the neew attached device //

            {
               register UCHAR ucChannel;
               for( ucChannel=0; ucChannel<=gAudioDevices[ucNewDeviceIndex].ucChannels;  ucChannel++ )
               {

                  if( gAudioDevices[ucNewDeviceIndex].ulDevCh[ucChannel]&CHANNEL_FEATURE_VOLUME )
                  {
                     GetUnitControl(ucNewDeviceIndex, VOLUME_CONTROL, ucChannel, sizeof(USHORT), (PUCHAR)&gAudioDevices[ucNewDeviceIndex].usMinVolume[ucChannel], GET_MIN);
                     GetUnitControl(ucNewDeviceIndex, VOLUME_CONTROL, ucChannel, sizeof(USHORT), (PUCHAR)&gAudioDevices[ucNewDeviceIndex].usMaxVolume[ucChannel], GET_MAX);
                  }
                  if( gAudioDevices[ucNewDeviceIndex].ulDevCh[ucChannel]&CHANNEL_FEATURE_BASS )
                  {
                     GetUnitControl(ucNewDeviceIndex, BASS_CONTROL, ucChannel, sizeof(UCHAR), (PUCHAR)&gAudioDevices[ucNewDeviceIndex].ucMinBass[ucChannel], GET_MIN);
                     GetUnitControl(ucNewDeviceIndex, BASS_CONTROL, ucChannel, sizeof(UCHAR), (PUCHAR)&gAudioDevices[ucNewDeviceIndex].ucMaxBass[ucChannel], GET_MAX);
                  }

                  if( gAudioDevices[ucNewDeviceIndex].ulDevCh[ucChannel]&CHANNEL_FEATURE_TREBLE )
                  {
                     GetUnitControl(ucNewDeviceIndex, TREBLE_CONTROL, ucChannel, sizeof(UCHAR), (PUCHAR)&gAudioDevices[ucNewDeviceIndex].ucMinTreble[ucChannel], GET_MIN);
                     GetUnitControl(ucNewDeviceIndex, TREBLE_CONTROL, ucChannel, sizeof(UCHAR), (PUCHAR)&gAudioDevices[ucNewDeviceIndex].ucMaxTreble[ucChannel], GET_MAX);
                  }

               }
            }

            // if new device is active and initialize it for playback 
            if( ucNewDeviceIndex==GlobalTable.ucActiveDeviceIndex )
            {
            #ifdef DEBUG
               dsPrint(DBG_CRITICAL, "USBAUD : IRQ : SetConf : New device is active\r\n");
            #endif

               //try to init new device with the current stream data format
               gbActiveDeviceSupport = InitNewDevice() ? FALSE : TRUE;
            #ifdef DEBUG
               dsPrint1(DBG_CRITICAL, "USBAUD : IRQ : SetConf : New Device support=%d\r\n", gbActiveDeviceSupport);
            #endif
               // if new device can suuport current stream format, initialize it
               if( gbActiveDeviceSupport )
                  USBSetInterface(ucNewDeviceIndex, gAudioDevices[ucNewDeviceIndex].ucAltInterface, GlobalTable.paStream, FALSE, NO_BYPASS);
            }
         }
         break;


      case USBAUD_IRQ_STATUS_GETUNITCTRL:

         #ifdef DEBUG
         {
            USHORT usValue;
            UCHAR ucChannel=(UCHAR)HIUSHORT(pRB->requestData3);

            switch( HIUSHORT(pRB->requestData2) )
            {
               case TREBLE_CONTROL:
                  if( LOUSHORT(pRB->requestData3)==GET_MIN )
                     usValue=(USHORT)gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucMinTreble[ucChannel];

                  if( LOUSHORT(pRB->requestData3)==GET_MAX )
                     usValue=(USHORT)gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucMaxTreble[ucChannel];

                  break;
               case VOLUME_CONTROL:
                  if( LOUSHORT(pRB->requestData3)==GET_MIN )
                     usValue=gAudioDevices[GlobalTable.ucActiveDeviceIndex].usMinVolume[ucChannel];

                  if( LOUSHORT(pRB->requestData3)==GET_MAX )
                     usValue=gAudioDevices[GlobalTable.ucActiveDeviceIndex].usMaxVolume[ucChannel];

                  break;
               case BASS_CONTROL:
                  if( LOUSHORT(pRB->requestData3)==GET_MIN )
                     usValue=(USHORT)gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucMinBass[ucChannel];

                  if( LOUSHORT(pRB->requestData3)==GET_MAX )
                     usValue=(USHORT)gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucMaxBass[ucChannel];

                  break;

            }

            dsPrint4(DBG_SPECIFIC, "USBAUD: Value =%xh Req=%xh Ch=%xh sel=%xh\r\n", usValue,LOUSHORT(pRB->requestData3),ucChannel,HIUSHORT(pRB->requestData2));
         }
         #endif

         break;

      case USBAUD_IRQ_STATUS_SETUNITCTRL:
         #ifdef DEBUG
         dsPrint2(DBG_CRITICAL, "USBAUD: IRQ: SETUNITCONTROL: bSel=%lxh status=%lx\r\n", HIUSHORT(pRB->requestData2), pRB->status);
         #endif
         break;

      case  USBAUD_IRQ_STATUS_SETINTF:

         // get the stream pointer
         pStream = (PSTREAM)pRB->requestData3;

         #ifdef DEBUG
         dsPrint(DBG_SPECIFIC, "USBAUD: IRQ : USBAUD_IRQ_STATUS_SETINTF OK \r\n");
         #endif     

         if( pStream==NULL )
         {
            #ifdef DEBUG
            dsPrint(DBG_CRITICAL, "USBAUD : SetInterface OK : pStream==NULL\r\n");
            #endif
         }
         else
         {
            UCHAR ucDeviceIndex=0, ucChannel=0; 


            // serach for the device
            for( ucDeviceIndex=0; ucDeviceIndex<MAX_AUDIO_DEVICES; ucDeviceIndex++ )
            {

               if( gAudioDevices[ucDeviceIndex].pDeviceInfo!=NULL )
                  if( gAudioDevices[ucDeviceIndex].pDeviceInfo->deviceAddress==pRB->deviceAddress )
                     break;

               if( ucDeviceIndex==MAX_AUDIO_DEVICES-1 )
               {
                  #ifdef DEBUG
                  dsPrint1(DBG_CRITICAL, "USBAUD : IRQ : SetInterface : Cannot find the device=%d\r\n", pRB->deviceAddress);
                  #endif
                  pRP->rph.Status=USB_IDC_RC_ALLOCERR;
                  return;
               }

            }

            // Set up sound control values for the device //

            for( ucChannel=0; ucChannel<=gAudioDevices[ucDeviceIndex].ucChannels;  ucChannel++ )
            {

               // set up volume, if possible
               if( gOLDAC.lVolume != AUDIO_IGNORE )
               {
                  if( gAudioDevices[ucDeviceIndex].ulDevCh[ucChannel]&CHANNEL_FEATURE_VOLUME )
                  {
                     gUSBAC.usLeftVolume  = GetUnitControlValue(HIUSHORT(gOLDAC.lVolume)*2-USB_MAX_VOLUME,
                     gAudioDevices[ucDeviceIndex].usMinVolume[ucChannel],    
                     gAudioDevices[ucDeviceIndex].usMaxVolume[ucChannel]);
                     #ifdef DEBUG
                     dsPrint4(DBG_CRITICAL, "USBAUD : IRQ : SetIntf :  Set USB chan #%d Volume to %xh (min=%xh max=%xh)\r\n", ucChannel, gUSBAC.usLeftVolume, gAudioDevices[ucDeviceIndex].usMinVolume[ucChannel], gAudioDevices[ucDeviceIndex].usMaxVolume[ucChannel]);
                     #endif
                     SetUnitControl(ucDeviceIndex, VOLUME_CONTROL, ucChannel, sizeof(gUSBAC.usLeftVolume), (PUCHAR)&gUSBAC.usLeftVolume);
                  }

               }

               // set up bass, if possible
               if( gOLDAC.lBass != AUDIO_IGNORE )
                  if( gAudioDevices[ucDeviceIndex].ulDevCh[ucChannel]&CHANNEL_FEATURE_BASS )
                  {
                     gUSBAC.ucLeftBass = HIBYTE(GetUnitControlValue( HIUSHORT(gOLDAC.lBass)*2-USB_MAX_BASS,
                     MAKEUSHORT(0, gAudioDevices[ucDeviceIndex].ucMinBass[ucChannel]),    
                     MAKEUSHORT(0, gAudioDevices[ucDeviceIndex].ucMaxBass[ucChannel]))); 

                     #ifdef DEBUG
                     dsPrint4(DBG_SPECIFIC, "USBAUD : IRQ : SetIntf : Set USB ch=%d Bass to %xh (min=%xh max=%xh)\r\n",ucChannel, gUSBAC.ucLeftBass, gAudioDevices[ucDeviceIndex].ucMinBass[ucChannel], gAudioDevices[ucDeviceIndex].ucMaxBass[ucChannel]);
                     #endif
                     SetUnitControl(ucDeviceIndex, BASS_CONTROL, ucChannel, sizeof(gUSBAC.ucLeftBass), (PUCHAR)&gUSBAC.ucLeftBass);
                  }

                  // set up treble. if possible
               if( gOLDAC.lTreble != AUDIO_IGNORE )
                  if( gAudioDevices[ucDeviceIndex].ulDevCh[ucChannel]&CHANNEL_FEATURE_TREBLE )
                  {
                     gUSBAC.ucLeftTreble  =  HIBYTE(GetUnitControlValue((HIUSHORT(gOLDAC.lTreble)*2-USB_MAX_TREBLE),
                     MAKEUSHORT(0, gAudioDevices[ucDeviceIndex].ucMinTreble[ucChannel]),    
                     MAKEUSHORT(0, gAudioDevices[ucDeviceIndex].ucMaxTreble[ucChannel])));
                     #ifdef DEBUG
                     dsPrint4(DBG_SPECIFIC, "USBAUD : IRQ : SetIntf :  Set USB ch=%d treble to %xh (min=%xh max=%xh\r\n",ucChannel, gUSBAC.ucLeftTreble, gAudioDevices[ucDeviceIndex].ucMinTreble[ucChannel], gAudioDevices[ucDeviceIndex].ucMaxTreble[ucChannel]);
                     #endif
                     SetUnitControl(ucDeviceIndex, TREBLE_CONTROL, ucChannel, sizeof(gUSBAC.ucLeftTreble), (PUCHAR)&gUSBAC.ucLeftTreble);
                  }
            }

            // start playback with new attached device 
            SendFirstBuffers(pStream, NO_BYPASS);

         }
         break;


      case USBAUD_IRQ_STATUS_SENDDATA:

         // get saved stream data
         pStream = (PSTREAM)pRB->requestData3;
         usIOBufIndex = LOUSHORT(pRB->requestData2);
         pStream->usLastIOBuffIndex = usIOBufIndex;
         pStream->ucRemained--;

         #ifdef DEBUG
         dsPrint3(DBG_SPECIFIC, "USBAUD: ISOBufferDone \tindex=%d \tpBuffer=%lxh Remained=%d\r\n", usIOBufIndex, (ULONG)pStream->IOBuff[usIOBufIndex].pBuffer, , pStream->ucRemained);
         #endif

         if( !pStream->IOBuff[pStream->usLastIOBuffIndex].bEmpty )
            ReportFreeBuffer(pStream);

         break;

      case USBAUD_IRQ_STATUS_SETFREQ:
         #ifdef DEBUG
         dsPrint1(DBG_DETAILED, "USBAUD: IRQ: USBAUD_IRQ_STATUS_SETFREQ received status=%lxh\r\n", pRB->status);
         #endif
         break;

      default:
         break;
   }
}
/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  SetConf                                          */
/*                                                                    */
/* DESCRIPTIVE NAME: Set configuration                                */
/*                                                                    */
/* FUNCTION: The function of this routine is to set configuration to  */
/*                   new attached USB Audio device                    */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  SetConf                                             */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP                                           */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  pRP->rph.Status                                          */
/*                                                                    */
/* INTERNAL REFERENCES: NONE                                          */  
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:   NONE                                        */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

VOID SetConf( PRP_GENIOCTL pRP )
{
   USBRB FAR  *pRB=(USBRB FAR *)pRP->ParmPacket;
   register USHORT usDevIndex;

   if( pRP->rph.Status!=USB_IDC_RC_OK )
   {  // stop processing if failed to set configuration
      #ifdef   DEBUG
      dsPrint1(DBG_CRITICAL, "USBAUD : ConfigurationSet failed. Status=%x\r\n", pRP->rph.Status);
      #endif
      return;
   }
   #ifdef   DEBUG
   dsPrint3(DBG_IRQFLOW, "USBAUD : ConfigurationSet Status=%x, devaddr=%d pRB->status=%lx\r\n", pRP->rph.Status, pRB->deviceAddress, pRB->status);
   #endif
   // find active device data row based on device address
   for( usDevIndex=0; usDevIndex<gNoOfActiveAudioDevices; usDevIndex++ )
   {
      if( !gAudioDevices[usDevIndex].pDeviceInfo )
         continue;
      if( gAudioDevices[usDevIndex].pDeviceInfo->ctrlID!=pRB->controllerId )
         continue;
      if( gAudioDevices[usDevIndex].pDeviceInfo->deviceAddress==pRB->deviceAddress )
         break;
   }

   if( usDevIndex>=gNoOfActiveAudioDevices )
   {  // entry not found - set error return code
      #ifdef   DEBUG
      dsPrint2(DBG_CRITICAL, "USBAUD : ConfigurationSet failed to locate device ctrlidd=%d,addr=%d\r\n",pRB->controllerId, pRB->deviceAddress);
      #endif
      pRP->rph.Status=USB_IDC_RC_ALLOCERR;      
      return;
   }

}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  DetachDevice                                     */
/*                                                                    */
/* DESCRIPTIVE NAME:  Detach device                                   */
/*                                                                    */
/* FUNCTION:  The function of this routine is to process detzh idc    */
/*              call for the specified audio device                   */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  DetachDevice                                        */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP                                           */
/*                                                                    */
/* EXIT-NORMAL:  0                                                    */
/*                                                                    */
/* EXIT-ERROR:  STECODE                                               */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */  
/*                                                                    */
/*    ROUTINES:    ISOCancel                                          */
/*                 ISOClose                                           */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:  ReportFreeBuffer                                     */
/*               InitNewDevice                                        */
/*               USBSetInterface                                      */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

USHORT DetachDevice(PRP_GENIOCTL pRP)
{
   USBDetach FAR *pDetachDevData=(USBDetach FAR *)pRP->ParmPacket;  /* pointer to parameters packet */
   register UCHAR  i;
   register USHORT rc = STECODE;
   PSTREAM pStream = GlobalTable.paStream;  // active stream //

   if( !gNoOfActiveAudioDevices )
      return(STECODE); // if we have no one active device //

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

   // search specified device in list and deletes it, if found //
   for( i=0;  i<MAX_AUDIO_DEVICES; i++ )
   {
      if( gAudioDevices[i].pDeviceInfo )
         if( gAudioDevices[i].pDeviceInfo->deviceAddress==pDetachDevData->deviceAddress )
         {  // device found
            gNoOfActiveAudioDevices--;  /* decrement active speakers counter */
            rc = 0;
            break;
         }
      if( i == MAX_AUDIO_DEVICES-1 )
         return(STECODE);
   }

   // check, if detached device was active //
   if( i==GlobalTable.ucActiveDeviceIndex )
   {

      #ifdef DEBUG
      dsPrint(DBG_CRITICAL, "USBAUD : DetachDevice : Active device detached\r\n");
      #endif

      if( gNoOfActiveAudioDevices )
      {
         CHAR FAR * pBuffer = pStream->IOBuff[pStream->usCurrIOBuffIndex].pBuffer;
         USHORT usProcBytes = 0;

         if( gbISOOpened )
         {
            // deinitialize isohronous interface //
            if( ISOCancel((CHAR FAR * FAR *)&pBuffer, (USHORT FAR *)&usProcBytes)== USB_IDC_RC_OK )
            {
            #ifdef DEBUG
               dsPrint2(DBG_SPECIFIC, "USBAUD: DetachDevice : pbuf=%lxh bytes=%xh\r\n", (ULONG)pBuffer, usProcBytes);
            #endif

               // set up stream data for correct playing next time //
               pStream->usLastIOBuffIndex=pStream->usCurrIOBuffIndex;
               pStream->IOBuff[pStream->usCurrIOBuffIndex].bEmpty=FALSE;
            }

            if( ISOClose()==USB_IDC_RC_OK )
               gbISOOpened=FALSE;
         }
      }
      else
      {
         if( !gNoOfActiveAudioDevices || !gbActiveDeviceSupport )
         {
            #ifdef DEBUG
            dsPrint1(DBG_CRITICAL, "USBAUD: DetachDevice: ucBuffers=%d\r\n", pStream->ucBuffers);
            #endif

            if( gbISOOpened )
            {
               // deinitialize isohronous interface //
               if( ISOClose()==USB_IDC_RC_OK )
                  gbISOOpened=FALSE;
            }

            if( pStream )
            {
               if( pStream->ucBuffers )
               {
                  pStream->usLastIOBuffIndex=pStream->usCurrIOBuffIndex;
                  if( ++pStream->usCurrIOBuffIndex==MAXIOBUFFS )
                     pStream->usCurrIOBuffIndex=0;

                  ReportFreeBuffer(pStream);
               }

               if( pStream->ucBuffers )
               {
                  pStream->usLastIOBuffIndex=pStream->usCurrIOBuffIndex;
                  if( ++pStream->usCurrIOBuffIndex==MAXIOBUFFS )
                     pStream->usCurrIOBuffIndex=0;
                  ReportFreeBuffer(pStream);
               }
            }
         }
      }
      gbActiveDeviceSupport=FALSE;
      // show that the node, where the detached device data was, is clear  //
      gAudioDevices[i].pDeviceInfo=NULL;

      // if still there are attached devices //
      if( gNoOfActiveAudioDevices )
      {
         // set up next device as active //
         for( i=0; i<MAX_AUDIO_DEVICES; i++ )
            if( gAudioDevices[i].pDeviceInfo )
            {
               GlobalTable.ucActiveDeviceIndex = i;
               #ifdef DEBUG
               dsPrint1(DBG_CRITICAL, "USBAUD : DetachDevice: New Active Device Index=%d\r\n", i);
               #endif
               break;
            }

         if( InitNewDevice() == ERROR ) // new initiated devices cannnot play data of the current stream format 
         {
            #ifdef DEBUG
            dsPrint(DBG_CRITICAL, "USBAUD: InitNewDevice error! Can not play such type of stream\r\n");
            #endif
            gbActiveDeviceSupport=FALSE; // current active device supports the active stream data format //
         }
         else
         {
            gbActiveDeviceSupport=TRUE; // current active device does not support the active stream data format //

            // decrement current buffer index to start playing it with new device //
            if( pStream )
            {
               if( !pStream->usCurrIOBuffIndex )
                  pStream->usCurrIOBuffIndex=MAXIOBUFFS-1;
               else
                  pStream->usCurrIOBuffIndex--;

               // set interface for new active device //
               USBSetInterface(GlobalTable.ucActiveDeviceIndex, gAudioDevices[GlobalTable.ucActiveDeviceIndex].ucAltInterface, GlobalTable.paStream, TRUE, NO_BYPASS);
            }
         }
      }
      else
         GlobalTable.ucActiveDeviceIndex = 0xFF;
   }
   else
   {
      gAudioDevices[i].pDeviceInfo=NULL;

      #ifdef DEBUG
      dsPrint(DBG_DETAILED, "USBAUD : DetachDevice : Not active device detached\r\n");
      #endif
   }

   #ifdef DEBUG
   dsPrint1(DBG_SPECIFIC, "USBAUD : DetachDevice active idx=%d\r\n", GlobalTable.ucActiveDeviceIndex);
   #endif

   return(rc); 
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  SetUnitControl                                   */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set Unit Control Value                          */
/*                                                                    */
/* FUNCTION:  Set Unit Control Value  for the specified devices       */
/*                e.g. bass, volume, treble                           */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  SetUnitControl                                      */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  USHORT deviceIndex                                         */
/*         UCHAR  bControlSelector                                    */
/*         UCHAR  ucChannelNo                                         */
/*         USHORT wBufferSize                                         */
/*         PUCHAR pData                                               */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: NONE                                          */  
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:    USBCallIDC                                         */
/*                 MAKEUSHORT                                         */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

VOID SetUnitControl( USHORT deviceIndex, UCHAR  bControlSelector, UCHAR  ucChannelNo, USHORT wBufferSize, PUCHAR pData)
{
   USBRB        rb;
   RP_GENIOCTL  rp_USBReq;

   if( gSPIdx++==MAX_SETUP_PACKETS-1 )
      gSPIdx=0;

   // set up device data //
   rb.controllerId   = gAudioDevices[deviceIndex].pDeviceInfo->ctrlID;
   rb.deviceAddress  = gAudioDevices[deviceIndex].pDeviceInfo->deviceAddress;
   rb.endPointId     = USB_DEFAULT_CTRL_ENDPT;    // 0, default control endpoint
   rb.status         = 0;
   rb.flags          = USRB_FLAGS_TTYPE_SETUP;

   // set up request data 
   gSetupPacket[gSPIdx].bmRequestType =  REQTYPE_XFERDIR_HOSTTODEV|REQTYPE_TYPE_CLASS|REQTYPE_RECIPIENT_INTERFACE;    // Characteristics of request
   gSetupPacket[gSPIdx].bRequest      =  SET_CUR;         // Specific Request
   gSetupPacket[gSPIdx].wValue        =  MAKEUSHORT(ucChannelNo, bControlSelector);
   gSetupPacket[gSPIdx].wIndex        =  MAKEUSHORT(gAudioDevices[deviceIndex].ucControlInterface, gAudioDevices[deviceIndex].ucFeatureUnitID); // typically Index or Offset
   gSetupPacket[gSPIdx].wLength       =  wBufferSize;  

   // set up remained request block data
   rb.buffer1        = (PUCHAR)&gSetupPacket[gSPIdx]; // pointer to set device address setup packet
   rb.buffer1Length  = sizeof(gSetupPacket[gSPIdx]);  // setup packet size

   rb.buffer2        = pData;     
   rb.buffer2Length  = wBufferSize; 

   rb.serviceTime    = 0; // Required service frequency for requests in ms. Valid range - [1,1024].
   rb.maxPacketSize  = USB_DEFAULT_PKT_SIZE;  // max packet size to be sent at once
   rb.maxErrorCount  = USB_MAX_ERROR_COUNT;  // 
   rb.usbIDC         = (PUSBIDCEntry)USBDIDCEntry;          // Address of IRQ processing routine to be called for this request

   rb.usbDS=GetDS(); //set data segment value

   rb.category    =  USB_IDC_CATEGORY_CLASS;        // set USBD layer as IRQ processor

   rb.requestData1   =  USBAUD_IRQ_STATUS_SETUNITCTRL;  // USBD I/O call type ID - set device address
   rb.requestData2   =  MAKEULONG(deviceIndex,bControlSelector);        // index in device table to current device
   rb.requestData3   =  MAKEULONG(*((USHORT FAR*)pData), ucChannelNo);                        // not used

   setmem((PSZ)&rp_USBReq, 0, sizeof(rp_USBReq));
   rp_USBReq.rph.Cmd    =  CMDGenIOCTL;   // IOCTL
   rp_USBReq.Category   =  USB_IDC_CATEGORY_USBD;
   rp_USBReq.Function   =  USB_IDC_FUNCTION_ACCIO;
   rp_USBReq.ParmPacket =  (PVOID)&rb;

   USBCallIDC( gpUSBDIDC, gUSBDds, (RP_GENIOCTL FAR *)&rp_USBReq );

   return;
}


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  GetUnitControl                                   */
/*                                                                    */
/* DESCRIPTIVE NAME:   GetUnitControl Value                           */
/*                                                                    */
/* FUNCTION:  The function of this routive is to get current unit     */
/*         control value setting from the device                      */
/*         e.g. volume, bass, treble                                  */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  GetUnitControl                                      */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  USHORT deviceIndex                                         */
/*         UCHAR  bControlSelector                                    */
/*         UCHAR  ucChannelNo                                         */
/*         USHORT wBufferSize                                         */
/*         PUCHAR pData                                               */
/*         UCHAR ucRequest                                            */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  NONE                                         */  
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:   MAKEUSHORT                                          */
/*                GetDS                                               */
/*                USBCallIDC                                          */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


VOID GetUnitControl( USHORT deviceIndex, UCHAR  bControlSelector, UCHAR  ucChannelNo, USHORT wBufferSize, PUCHAR pData, UCHAR ucRequest)
{
   USBRB        rb;
   RP_GENIOCTL  rp_USBReq;

   if( gReadSPIdx++ == MAX_READ_SETUP_PACKETS-1 )
      gReadSPIdx=0;

   // set up device data
   rb.controllerId   = gAudioDevices[deviceIndex].pDeviceInfo->ctrlID;
   rb.deviceAddress  = gAudioDevices[deviceIndex].pDeviceInfo->deviceAddress;
   rb.endPointId     = USB_DEFAULT_CTRL_ENDPT;    // 0, default control endpoint
   rb.status         = 0;
   rb.flags          = USRB_FLAGS_TTYPE_SETUP;

   // set up request data
   gReadSetupPacket[gReadSPIdx].bmRequestType =  REQTYPE_XFERDIR_DEVTOHOST|REQTYPE_TYPE_CLASS|REQTYPE_RECIPIENT_INTERFACE;    // Characteristics of request
   gReadSetupPacket[gReadSPIdx].bRequest      =  ucRequest;         // Specific Request
   gReadSetupPacket[gReadSPIdx].wValue  =  MAKEUSHORT(ucChannelNo, bControlSelector);
   gReadSetupPacket[gReadSPIdx].wIndex  =  MAKEUSHORT(gAudioDevices[deviceIndex].ucControlInterface, gAudioDevices[deviceIndex].ucFeatureUnitID); // typically Index or Offset
   gReadSetupPacket[gReadSPIdx].wLength =  wBufferSize;  

   // set up remained request block data
   rb.buffer1        = (PUCHAR)&gReadSetupPacket[gReadSPIdx];  // pointer to set device address setup packet
   rb.buffer1Length  = sizeof(gReadSetupPacket[gReadSPIdx]); // setup packet size

   rb.buffer2        = pData;     
   rb.buffer2Length  = wBufferSize; 

   rb.serviceTime    = 0; // Required service frequency for requests in ms. Valid range - [1,1024].
   rb.maxPacketSize  = USB_DEFAULT_PKT_SIZE;  // max packet size to be sent at once
   rb.maxErrorCount  = USB_MAX_ERROR_COUNT;  // 
   rb.usbIDC         = (PUSBIDCEntry)USBDIDCEntry;          // Address of IRQ processing routine to be called for this request
   rb.usbDS =   GetDS(); //set data segment value

   rb.category    =  USB_IDC_CATEGORY_CLASS;        // set USBD layer as IRQ processor

   rb.requestData1 = USBAUD_IRQ_STATUS_GETUNITCTRL;  // USBD I/O call type ID - set device address
   rb.requestData2 = MAKEULONG(deviceIndex,bControlSelector);        // index in device table to current device
   rb.requestData3 = MAKEULONG(ucRequest, ucChannelNo);                        // not used

   // set up request packet and call USBD
   setmem((PSZ)&rp_USBReq, 0, sizeof(rp_USBReq));
   rp_USBReq.rph.Cmd    =  CMDGenIOCTL; // IOCTL
   rp_USBReq.Category   =  USB_IDC_CATEGORY_USBD; // call to USBD
   rp_USBReq.Function   =  USB_IDC_FUNCTION_ACCIO; // function ID
   rp_USBReq.ParmPacket =  (PVOID)&rb;

   USBCallIDC( gpUSBDIDC, gUSBDds, (RP_GENIOCTL FAR *)&rp_USBReq );

   return;
}


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  USBSetInterface                                  */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set interface                                   */
/*                                                                    */
/* FUNCTION: The function of this routine is to set up the interface  */
/*                      for the specified device                      */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  USBSetInterface                                     */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  USHORT deviceIndex                                         */
/*         USHORT altInterface                                        */
/*         PSTREAM pStream                                            */
/*         BOOL bEnablePlay                                           */
/*         USHORT usByPass                                            */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  NONE                                         */  
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:   GetDS                                               */
/*                USBCallIDC                                          */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


VOID USBSetInterface( USHORT deviceIndex, USHORT altInterface, PSTREAM pStream, BOOL bEnablePlay, USHORT usByPass)
{

   USBRB             RB;
   RP_GENIOCTL       rp_USBReq;

   gsp.bmRequestType = REQTYPE_RECIPIENT_INTERFACE;//REQTYPE_TYPE_STANDARD;   // standard request
   gsp.bRequest      = REQ_SET_INTERFACE;            // Set interface Request
   gsp.wValue        = altInterface; //alternate setting                             // not used
   gsp.wLength       = 0;// not used, must be set to zerro


   // setup interface value
   switch( pStream->usMode )
   {
      case PCM:
      case ADPCM:
         gsp.wIndex  = gAudioDevices[deviceIndex].ucStreamingInterface;//interface
         break;
      case MIDI:
      case DATATYPE_MIDI:
         gsp.wIndex  = gAudioDevices[deviceIndex].ucMIDIInterface;//interface
         break;
      default:
      #ifdef DEBUG
         dsPrint1(DBG_CRITICAL, "USBAUD: USBSetInterface : Invalid mode =%d\r\n", pStream->usMode);
      #endif
         return;
         break;
   }

   // fill in request block to set device configuration interface

   RB.controllerId  = gAudioDevices[deviceIndex].pDeviceInfo->ctrlID;
   RB.deviceAddress = gAudioDevices[deviceIndex].pDeviceInfo->deviceAddress;
   RB.endPointId    = USB_DEFAULT_CTRL_ENDPT;    // default control endpoint
   RB.status        = 0;        // not used
   RB.flags         = USRB_FLAGS_TTYPE_SETUP;
   RB.buffer1       = (PUCHAR)&gsp;            // pointer to set interface setup packet
   RB.buffer1Length = sizeof(gsp);     // setup packet size
   RB.buffer2       = NULL;        // not used for this request
   RB.buffer2Length = 0;     // not used for this request
   RB.serviceTime   = 0;   // use default service interval
   RB.maxPacketSize = USB_DEFAULT_PKT_SIZE; // use defualt packet size
   RB.maxErrorCount = USB_MAX_ERROR_COUNT;  // maximum error retries
   RB.usbIDC        = (PUSBIDCEntry)USBDIDCEntry;       // USBD IDC routine will be called to process finished requests
   RB.category      = USB_IDC_CATEGORY_CLASS;        // set USBD layer as IRQ processor
   RB.requestData1  = USBAUD_IRQ_STATUS_SETINTF; // request type
   RB.requestData2  = (ULONG)altInterface; // altInterface
   if( bEnablePlay )
      RB.requestData3  = (ULONG)pStream; // Stream Handler
   else
      RB.requestData3=NULL;

   RB.usbDS=GetDS(); // set data segment value


   //set up request packet and call USB Driver
   setmem((PSZ)&rp_USBReq, 0, sizeof(rp_USBReq));

   rp_USBReq.rph.Cmd    =  CMDGenIOCTL;   // IOCTL
   rp_USBReq.Category   =  USB_IDC_CATEGORY_USBD; // call USBD
   rp_USBReq.Function   =  USB_IDC_FUNCTION_ACCIO; // IDC function ID
   rp_USBReq.ParmPacket =  (PVOID)&RB;

   #ifdef DEBUG
   dsPrint1(DBG_SPECIFIC, "USBAUD : SetInterface alt=%d\r\n", altInterface);
   #endif
   USBCallIDC( gpUSBDIDC, gUSBDds, (RP_GENIOCTL FAR *)&rp_USBReq ); //calls USBD

}


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  USBAUDIOClearStalled                             */
/*                                                                    */
/* DESCRIPTIVE NAME:  USB Audio Clear Stalled                         */
/*                                                                    */
/* FUNCTION: The function of this routine is to process errors        */
/*             occured during  USB isohrounoud playback               */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  USBAUDIOClearStalled                                */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  RP_GENIOCTL FAR *pRP                                       */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  pRB->status                                              */
/*                                                                    */
/* INTERNAL REFERENCES:  NONE                                         */  
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:    USBCallIDC                                         */
/*                   setmem                                           */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


VOID USBAUDIOClearStalled( RP_GENIOCTL FAR *pRP )
{
   USBRB FAR            *pRB = (USBRB FAR *)pRP->ParmPacket;
   RP_GENIOCTL          rp_USBReq;
   USBClearStalled      clearRB;
   register USHORT      deviceIndex=GlobalTable.ucActiveDeviceIndex;

 #ifdef   DEBUG
   dsPrint3(DBG_CRITICAL, "USBAUD : USBAUDIOClearStalled: clearing ctrlid=%d,address=%d,endpoint=%d\r\n",
   pRB->controllerId, pRB->deviceAddress, pRB->endPointId);
 #endif

   clearRB.controllerId    =  pRB->controllerId;        // controller ID, not used, should be set to 0
   clearRB.deviceAddress   =  pRB->deviceAddress;       // USB device address
   clearRB.endPointId      =  pRB->endPointId;          // stalled endpoint ID

   if( pRB->category==USB_IDC_CATEGORY_CLASS )
   {
      clearRB.clientIDCAddr=NULL;       // no irq notification for this request
      clearRB.clientDS=0;              //  no irq notification for this request
   }
   else
   {  // fill in request block packet
      clearRB.clientIDCAddr   =  pRB->usbIDC;       // no irq notification for this request
      clearRB.clientDS        =  pRB->usbDS;            //  no irq notification for this request}
      clearRB.irqSwitchValue  =  IRQ_CLEARSTALLED;// pRB->requestData1;      //  no irq notification for this request
      clearRB.requestData2    =  pRB->requestData2;      //  no irq notification for this request
      clearRB.requestData3    =  pRB->requestData3;      //  no irq notification for this request
      clearRB.category        =  pRB->category;            // IRQ processor category
      clearRB.clearStalled    =  NULL;       // clear stalled pipe request packet buffer

      // find active device data row based on device address
      for( deviceIndex=0; deviceIndex<gNoOfActiveAudioDevices; deviceIndex++ )
      {
         if( !gAudioDevices[deviceIndex].pDeviceInfo )
            continue;
         if( gAudioDevices[deviceIndex].pDeviceInfo->ctrlID!=pRB->controllerId )
            continue;
         if( gAudioDevices[deviceIndex].pDeviceInfo->deviceAddress==pRB->deviceAddress )
         {
            clearRB.clearStalled=(SetupPacket FAR *)&gAudioDevices[deviceIndex].cstPacket;
            break;
         }
      }

      if( !clearRB.clearStalled )  // device not exists
         return;

      #ifdef   DEBUG
      dsPrint3(DBG_DETAILED, "USBAUD : USBAUDIOClearStalled: idcAddr=%lx,ds=%x,category=%x\r\n", (LONG)clearRB.clientIDCAddr, clearRB.clientDS, pRB->category);
      dsPrint4(DBG_DETAILED, "USBAUD : USBAUDIOClearStalled: r1=%lx,r2=%lx,r3=%lx, sAddr=%lx\r\n", clearRB.irqSwitchValue, clearRB.requestData2, clearRB.requestData3,(LONG)clearRB.clearStalled);
      #endif

      setmem((PSZ)&rp_USBReq, 0, sizeof(rp_USBReq));
      rp_USBReq.rph.Cmd=CMDGenIOCTL;   // IOCTL
      rp_USBReq.Category=USB_IDC_CATEGORY_USBD;
      rp_USBReq.Function=USB_IDC_FUNCTION_CLRSTALL;
      rp_USBReq.ParmPacket=(PVOID)&clearRB;


      USBCallIDC( gpUSBDIDC, gUSBDds, (RP_GENIOCTL FAR *)&rp_USBReq );

      // check for status and set up variable
      if( rp_USBReq.rph.Status==USB_IDC_RC_OK )
         pRB->status&=~USRB_STATUS_STALLED;
   }
}


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  CTXReportBuffer                                  */
/*                                                                    */
/* DESCRIPTIVE NAME:    CTXReportBuffer                               */
/*                                                                    */
/* FUNCTION:   Calls routine to report  buffer                        */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  CTXReportBuffer                                     */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP                                           */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  NONE                                         */  
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:     ReportFreeBuffer                                  */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

#pragma optimize("eglt", off)
VOID FAR PASCAL CTXReportBuffer( VOID )
{
//   save the registers
   _asm
   {
      _emit  66h
      push  si

      _emit  66h
      push  di

      _emit  66h
      push  bx
   }


   ReportFreeBuffer(GlobalTable.paStream);

   // restore the registers
   _asm
   {
      _emit  66h
      pop   bx

      _emit  66h
      pop   di

      _emit  66h
      pop   si
   }
}
#pragma optimize("", on)


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  ISOOpen                                          */
/*                                                                    */
/* DESCRIPTIVE NAME:  Open isohrounous transfer  pipe                 */
/*                                                                    */
/* FUNCTION:  The function of this routine is to                      */  
/*             open isohrounous transfer  pipe                        */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  ISOOpen                                             */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PSTREAM pStream                                            */
/*         USHORT usFrameLength                                       */
/*                                                                    */
/* EXIT-NORMAL:  USB_IDC_RC_OK                                        */
/*                                                                    */
/* EXIT-ERROR:  USB_IDC_RC_PARMERR                                    */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: NONE                                          */  
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:    setmem                                             */
/*                 GetDS                                              */
/*                 USBCallIDC                                         */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


RC ISOOpen(PSTREAM pStream, USHORT usFrameLength)
{

   USBRB         isoRB;
   RP_GENIOCTL   ioRB;
   AudioDevice  *paDevice=&gAudioDevices[GlobalTable.ucActiveDeviceIndex];

   #ifdef DEBUG
   dsPrint3(DBG_SPECIFIC, "USBAUD: ISOOpen entry : Freq=%ld Bits=%ld Chan=%d\r\n", pStream->ulSamplingFreq, pStream->ulBitsPerSample, pStream->usChannels); 
   #endif


   if( pStream->ulSamplingFreq>44100 )
      pStream->ulSamplingFreq=44100;

   usFrameLength = pStream->usFrameSize = (USHORT)((pStream->ulSamplingFreq*pStream->ulBitsPerSample*pStream->usChannels) /8000); 

   #ifdef DEBUG
   dsPrint2(DBG_CRITICAL, "USBAUD: ISOOpen : FrameSize=%xh altInt=%xh\r\n", usFrameLength, paDevice->ucAltInterface);
   dsPrint3(DBG_CRITICAL, "USBAUD: ISOOpen : Freq=%ld Bits=%ld Chan=%d\r\n", pStream->ulSamplingFreq, pStream->ulBitsPerSample, pStream->usChannels); 
   #endif

   // set up endpoint ID
   setmem((PSZ)&isoRB, 0, sizeof(isoRB));

   switch( pStream->usMode )
   {
      case PCM:
      case ADPCM:
         isoRB.endPointId = paDevice->ucStreamingPipe;
         break;
      case MIDI:
      case DATATYPE_MIDI:
         isoRB.endPointId = paDevice->ucMIDIPipe;
         break;
      default:
         #ifdef DEBUG
         dsPrint1(DBG_CRITICAL, "USBAUD: ISOOpen : Invalid usMode=%d\r\n", pStream->usMode);
         #endif
         return(USB_IDC_RC_PARMERR);
         break ;
   }

   // set up device data
   isoRB.controllerId   = paDevice->pDeviceInfo->ctrlID;
   isoRB.deviceAddress  = paDevice->pDeviceInfo->deviceAddress; 

   isoRB.flags          = USRB_FLAGS_TTYPE_OUT|USRB_FLAGS_DET_ISOHR|USRB_FLAGS_ALT_INTF;
   isoRB.usbIDC         = (PUSBIDCEntry)USBDIDCEntry;       // USBD IDC routine will be called to process finished requests
   isoRB.category       = USB_IDC_CATEGORY_CLASS;        // set USBD layer as IRQ processor
   isoRB.altInterface   = paDevice->ucAltInterface;

   isoRB.usbDS =  GetDS();// set data segment value

   isoRB.requestData1   = USBAUD_IRQ_STATUS_SENDDATA;
   isoRB.requestData2   = 0;
   isoRB.requestData3   = (ULONG)pStream;
   isoRB.isoFrameLength = usFrameLength;
   isoRB.isoBuffers     = MAXIOBUFFS-1;  
   isoRB.isoFlags       = USRB_ISOFLAGS_OPEN;

   isoRB.buffer1       = (PVOID)pStream->IOBuff[pStream->usCurrIOBuffIndex].pBuffer;
   isoRB.buffer1Length = (USHORT)pStream->IOBuff[pStream->usCurrIOBuffIndex].lSize;
   isoRB.maxPacketSize  = 0;

   setmem((PSZ)&ioRB, 0, sizeof(ioRB));
   ioRB.rph.Cmd    = CMDGenIOCTL;   // IOCTL 0x10
   ioRB.Category   = USB_IDC_CATEGORY_USBD;
   ioRB.Function   = USB_IDC_FUNCTION_ACCIO;
   ioRB.ParmPacket = (PVOID)&isoRB;


   USBCallIDC( gpUSBDIDC, gUSBDds, (RP_GENIOCTL FAR *)&ioRB );

   #ifdef DEBUG
   dsPrint1(DBG_SPECIFIC, "USBAUD: ISOOpen : Status=%lxh\r\n",  ioRB.rph.Status);
   #endif

   if( ioRB.rph.Status != USB_IDC_RC_OK )
   {
      #ifdef  DEBUG
      dsPrint1(DBG_CRITICAL, "USBAUD: ISOOpen : ERROR : status=%lxh\r\n",  ioRB.rph.Status);
      #endif

      switch( ioRB.rph.Status )
      {
         case USB_IDC_RC_ADDRINV: 
         #ifdef DEBUG
            dsPrint(DBG_CRITICAL, "USBAUD: ISOOpen : ERROR :Device or endpoint does not exist\r\n");
         #endif
            break;
         default:
            break;
      }
   }
   return(ioRB.rph.Status);

}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  ISOSendBuffer                                    */
/*                                                                    */
/* DESCRIPTIVE NAME:  Send data buffer                                */
/*                                                                    */
/* FUNCTION: The function of this routine is to send audio data       */  
/*             buffer to USB isohronous pipe                          */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  ISOSendBuffer                                       */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PSTREAM paStream                                           */
/*         USHORT usByPass                                            */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  USB_IDC_RC_PARMERR                                    */
/*              USB_IDC_RC_IOFAILED                                   */
/*              USB_IDC_RC_OK                                         */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  NONE                                         */  
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:   ReportFreeBuffer                                    */
/*                SignConverter                                       */
/*                MAKEULONG                                           */
/*                setmem                                              */
/*                USBCallIDC                                          */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


RC ISOSendBuffer( PSTREAM paStream, USHORT usByPass )
{
   USBRB             isoRB;
   RP_GENIOCTL       ioRB;
   AudioDevice *paDevice=&gAudioDevices[GlobalTable.ucActiveDeviceIndex];

   // if we have no USb Audio devices attached, then report buffer
   if( !gNoOfActiveAudioDevices )
   {
      paStream->usLastIOBuffIndex=paStream->usCurrIOBuffIndex;
      ReportFreeBuffer(paStream);
      return(USB_IDC_RC_IOFAILED);
   }

   switch( paStream->usMode )
   {
      case PCM:
      case ADPCM:
         isoRB.endPointId=paDevice->ucStreamingPipe;
         break;
      case MIDI:
      case DATATYPE_MIDI:
         isoRB.endPointId=paDevice->ucMIDIPipe;
         break;
      default:
         #ifdef DEBUG
         dsPrint1(DBG_CRITICAL, "USBAUD: ISOSendBuffer : Invalid usMode=%d\r\n", paStream->usMode);
         #endif
         return(USB_IDC_RC_PARMERR);
         break;
   }

   #ifdef CONVERTER
   if( paStream->ulBitsPerSample==8 )
   {
      #ifdef DEBUG
      dsPrint2(DBG_SPECIFIC, "USBAUD: Calling SignConverter %lxh %xh\r\n", (ULONG)paStream->IOBuff[paStream->usCurrIOBuffIndex].pHead, (USHORT)paStream->IOBuff[paStream->usCurrIOBuffIndex].lSize);
      #endif

      {
         ULONG ulTemp = paStream->IOBuff[paStream->usCurrIOBuffIndex].lSize%sizeof(ULONG);

         if( ulTemp )
            paStream->IOBuff[paStream->usCurrIOBuffIndex].lSize-=ulTemp;
      }

      SignConverter((ULONG FAR *)paStream->IOBuff[paStream->usCurrIOBuffIndex].pHead, (USHORT)paStream->IOBuff[paStream->usCurrIOBuffIndex].lSize);

      #ifdef DEBUG
      dsPrint2(DBG_SPECIFIC, "USBAUD: SignConverter complete%lxh %xh\r\n", (ULONG)paStream->IOBuff[paStream->usCurrIOBuffIndex].pHead, (USHORT)paStream->IOBuff[paStream->usCurrIOBuffIndex].lSize);
      #endif
   }
   #endif


   isoRB.buffer1       = (PVOID)paStream->IOBuff[paStream->usCurrIOBuffIndex].pHead;
   isoRB.buffer1Length = (USHORT)paStream->IOBuff[paStream->usCurrIOBuffIndex].lSize;
   isoRB.controllerId  = paDevice->pDeviceInfo->ctrlID;
   isoRB.deviceAddress = paDevice->pDeviceInfo->deviceAddress; 
   isoRB.status        = 0;        // not used
   isoRB.flags         = USRB_FLAGS_TTYPE_OUT|USRB_FLAGS_DET_ISOHR|USRB_FLAGS_ALT_INTF;
   isoRB.maxErrorCount = USB_MAX_ERROR_COUNT;  // 
   isoRB.usbIDC        = (PUSBIDCEntry)USBDIDCEntry;       // USBD IDC routine will be called to process finished requests
   isoRB.category      = USB_IDC_CATEGORY_CLASS;        // set USBD layer as IRQ processor
   isoRB.requestData1  = USBAUD_IRQ_STATUS_SENDDATA;  // USBD I/O call type ID - set device address
   isoRB.maxPacketSize = 0;
   isoRB.altInterface  = paDevice->ucAltInterface;
   isoRB.isoFlags      = 0;

   isoRB.requestData1   = USBAUD_IRQ_STATUS_SENDDATA;
   isoRB.requestData2   = MAKEULONG(paStream->usCurrIOBuffIndex, usByPass);
   isoRB.requestData3   = (ULONG)paStream;

   isoRB.usbDS=GetDS();


   if( paStream->IOBuff[paStream->usCurrIOBuffIndex].bEmpty )
   {
   #ifdef DEBUG
      dsPrint3(DBG_CRITICAL, "USBAUD: Trap 3  pStream=%lxh Curr=%d pBuff=%lxh\r\n", (ULONG)paStream, paStream->usCurrIOBuffIndex, (ULONG)paStream->IOBuff[paStream->usCurrIOBuffIndex].pBuffer);
   #endif
      return(USB_IDC_RC_IOFAILED);
   }


   setmem((PSZ)&ioRB, 0, sizeof(ioRB));
   ioRB.rph.Cmd    = CMDGenIOCTL;   // IOCTL 0x10
   ioRB.Category   = USB_IDC_CATEGORY_USBD;
   ioRB.Function   = USB_IDC_FUNCTION_ACCIO;
   ioRB.ParmPacket = (PVOID)&isoRB;

   #ifdef DEBUG
   dsPrint3(DBG_CRITICAL, "USBAUD: ISOSendBuffer: pBuf=%lxh BufSize=%xh FrameSize=%xh \r\n", (ULONG)isoRB.buffer1, isoRB.buffer1Length, paStream->usFrameSize);
   dsPrint2(DBG_SPECIFIC, "USBAUD: ISOSendBuffer \tindex=%d \tpBuffer=%lxh\r\n", paStream->usCurrIOBuffIndex, (ULONG)paStream->IOBuff[paStream->usCurrIOBuffIndex].pBuffer);
   #endif

   USBCallIDC( gpUSBDIDC, gUSBDds, (RP_GENIOCTL FAR *)&ioRB );


   if( ioRB.rph.Status != USB_IDC_RC_OK )
   {
      #ifdef  DEBUG
      dsPrint1(DBG_CRITICAL, "USBAUD: ISOSendBuffer status=%lxh\r\n",  ioRB.rph.Status);
      #endif
   }
   else
   {
      paStream->ucRemained++;
   }

   if( ioRB.rph.Status != USB_IDC_RC_OK )
   {
      #ifdef  DEBUG
      dsPrint1(DBG_CRITICAL, "USBAUD: ISOSendBuffer : ERROR : status=%lxh\r\n",  ioRB.rph.Status);
      #endif

      switch( ioRB.rph.Status )
      {
         case USB_IDC_RC_ADDRINV: 
         #ifdef DEBUG
            dsPrint(DBG_CRITICAL, "USBAUD: ISOSendBuffer : ERROR :Device or endpoint does not exist\r\n");
         #endif
            break;
         default:
            break;
      }


   }
   return(ioRB.rph.Status);

}
/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  ISOClose                                         */
/*                                                                    */
/* DESCRIPTIVE NAME:   Close isohronous pipe                          */
/*                                                                    */
/* FUNCTION:  The function of this routine is to close isohrounouse   */
/*             data transferring pipe                                 */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  ISOClose                                            */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  NONE                                                       */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */  
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:   setmem                                              */
/*                USBCallIDC                                          */
/*                                                                    */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/



RC ISOClose(VOID)
{
   USBRB         isoRB;
   RP_GENIOCTL   ioRB;
   AudioDevice *paDevice=&gAudioDevices[GlobalTable.ucActiveDeviceIndex];


   setmem((PSZ)&isoRB, 0, sizeof(isoRB));
   switch( GlobalTable.paStream->usMode )
   {
      case PCM:
      case ADPCM:
         isoRB.endPointId=paDevice->ucStreamingPipe;
         break;
      case MIDI:
      case DATATYPE_MIDI:
         isoRB.endPointId=paDevice->ucMIDIPipe;
         break;
      default:
         #ifdef DEBUG
         dsPrint1(DBG_CRITICAL, "USBAUD: ISOClose : Invalid usMode=%d\r\n", GlobalTable.paStream->usMode);
         #endif
         return(USB_IDC_RC_PARMERR);
         break;
   }

   isoRB.controllerId  = paDevice->pDeviceInfo->ctrlID;
   isoRB.deviceAddress = paDevice->pDeviceInfo->deviceAddress; 
   isoRB.flags         = USRB_FLAGS_TTYPE_OUT|USRB_FLAGS_DET_ISOHR|USRB_FLAGS_ALT_INTF;
   isoRB.altInterface  = paDevice->ucAltInterface;
   isoRB.isoFlags      = USRB_ISOFLAGS_CLOSE;

   setmem((PSZ)&ioRB, 0, sizeof(ioRB));
   ioRB.rph.Cmd    = CMDGenIOCTL;   // IOCTL 0x10
   ioRB.Category   = USB_IDC_CATEGORY_USBD;
   ioRB.Function   = USB_IDC_FUNCTION_ACCIO;
   ioRB.ParmPacket = (PVOID)&isoRB;


   USBCallIDC( gpUSBDIDC, gUSBDds, (RP_GENIOCTL FAR *)&ioRB );

  #ifdef DEBUG
   dsPrint1(DBG_SPECIFIC, "USBAUD: ISOClose : Status=%lxh\r\n",  ioRB.rph.Status);
  #endif

   if( ioRB.rph.Status != USB_IDC_RC_OK )
   {
   #ifdef  DEBUG
      dsPrint1(DBG_CRITICAL, "USBAUD: ISOClose : ERROR : status=%lxh\r\n",  ioRB.rph.Status);
   #endif

      switch( ioRB.rph.Status )
      {
         case USB_IDC_RC_ADDRINV: 
         #ifdef DEBUG
            dsPrint(DBG_CRITICAL, "USBAUD: ISOClose : ERROR :Device or endpoint does not exist\r\n");
         #endif
            break;
         default:
            break;
      }
   }
   return(ioRB.rph.Status);
}
/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  ISOCancel                                        */
/*                                                                    */
/* DESCRIPTIVE NAME: Cancel isohronous data playback                  */
/*                                                                    */
/* FUNCTION:  The function of this routine is to                      */
/*             cancel isohronous data playback                        */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  ISOCancel                                           */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:   CHAR FAR * FAR* ppBuffer                                  */
/*          USHORT FAR *usBytes                                       */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: NONE                                          */  
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:   setmem                                              */
/*                USBCallIDC                                          */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


RC ISOCancel( CHAR FAR * FAR* ppBuffer, USHORT FAR *usBytes)
{
   USBRB         isoRB;
   RP_GENIOCTL   ioRB;
   AudioDevice *paDevice=&gAudioDevices[GlobalTable.ucActiveDeviceIndex];

   setmem((PSZ)&isoRB, 0, sizeof(isoRB));
   switch( GlobalTable.paStream->usMode )
   {
      case PCM:
      case ADPCM:
         isoRB.endPointId = paDevice->ucStreamingPipe;
         break;
      case MIDI:
      case DATATYPE_MIDI:
         isoRB.endPointId = paDevice->ucMIDIPipe;
         break;
      default:
         #ifdef DEBUG
         dsPrint1(DBG_CRITICAL, "USBAUD: ISOCancel : Invalid usMode=%d\r\n", GlobalTable.paStream->usMode);
         #endif
         return(USB_IDC_RC_PARMERR);
         break;
   }

   isoRB.controllerId  = paDevice->pDeviceInfo->ctrlID;
   isoRB.deviceAddress = paDevice->pDeviceInfo->deviceAddress; 
   isoRB.flags         = USRB_FLAGS_TTYPE_OUT|USRB_FLAGS_DET_ISOHR|USRB_FLAGS_ALT_INTF;
   isoRB.altInterface  = paDevice->ucAltInterface;
   isoRB.isoFlags      = USRB_ISOFLAGS_CANCEL;

   setmem((PSZ)&ioRB, 0, sizeof(ioRB));
   ioRB.rph.Cmd        = CMDGenIOCTL;   // IOCTL 0x10
   ioRB.Category       = USB_IDC_CATEGORY_USBD;
   ioRB.Function       = USB_IDC_FUNCTION_ACCIO;
   ioRB.ParmPacket     = (PVOID)&isoRB;


   USBCallIDC( gpUSBDIDC, gUSBDds, (RP_GENIOCTL FAR *)&ioRB );

   #ifdef DEBUG
   dsPrint1(DBG_SPECIFIC, "USBAUD: ISOCancel : Status=%lxh\r\n",  ioRB.rph.Status);
   #endif

   if( ioRB.rph.Status != USB_IDC_RC_OK )
   {
      #ifdef  DEBUG
      dsPrint1(DBG_CRITICAL, "USBAUD: ISOCancel : ERROR : status=%lxh\r\n",  ioRB.rph.Status);
      #endif

      switch( ioRB.rph.Status )
      {
         case USB_IDC_RC_ADDRINV: 
        #ifdef DEBUG
            dsPrint(DBG_CRITICAL, "USBAUD: ISOCancel : ERROR :Device or endpoint does not exist\r\n");
        #endif
            break;
         default:
            break;
      }
   }

   *usBytes=isoRB.buffer1Length;
   *ppBuffer=(CHAR FAR *)isoRB.buffer1;

   #ifdef DEBUG
   dsPrint2(0, "USBAUD: ISOCancel : pBuffer = %lxh Length=%lxh \r\n", (ULONG)isoRB.buffer1, isoRB.buffer1Length);
   #endif

   return(ioRB.rph.Status);

}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  ISOStatus                                        */
/*                                                                    */
/* DESCRIPTIVE NAME:  Status                                          */
/*                                                                    */
/* FUNCTION:  The function of this routine is to request current      */
/*               isohrounous playback status                          */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  ISOStatus                                           */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  UCHAR FAR * FAR *ppBuffer - ptr to ptr to data buffer      */
/*         USHORT FAR *usBytes  - bytes count played                  */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  USB_IDC_RC_PARMERR                                    */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  NONE                                         */  
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES: setmem                                                */
/*              USBCallIDC                                            */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

RC ISOStatus(UCHAR FAR * FAR *ppBuffer, USHORT FAR *usBytes)
{
   USBRB          isoRB;
   RP_GENIOCTL    ioRB;
   AudioDevice    *paDevice = &gAudioDevices[GlobalTable.ucActiveDeviceIndex];
   PSTREAM        paStream = GlobalTable.paStream;

   setmem((PSZ)&isoRB, 0, sizeof(isoRB));

   switch( paStream->usMode )
   {
      case PCM:
      case ADPCM:
         isoRB.endPointId=paDevice->ucStreamingPipe;
         break;
      case MIDI:
      case DATATYPE_MIDI:
         isoRB.endPointId=paDevice->ucMIDIPipe;
         break;
      default:
         #ifdef DEBUG
         dsPrint1(DBG_CRITICAL, "USBAUD: ISOStatus : Invalid usMode=%d\r\n", paStream->usMode);
         #endif
         return(USB_IDC_RC_PARMERR);

         break;
   }

   isoRB.controllerId  = paDevice->pDeviceInfo->ctrlID;
   isoRB.deviceAddress = paDevice->pDeviceInfo->deviceAddress; 
   isoRB.flags         = USRB_FLAGS_TTYPE_OUT|USRB_FLAGS_DET_ISOHR|USRB_FLAGS_ALT_INTF;
   isoRB.altInterface  = paDevice->ucAltInterface;
   isoRB.isoFlags      = USRB_ISOFLAGS_INFO; 

   setmem((PSZ)&ioRB, 0, sizeof(ioRB));
   ioRB.rph.Cmd    = CMDGenIOCTL;   // IOCTL 0x10
   ioRB.Category   = USB_IDC_CATEGORY_USBD;
   ioRB.Function   = USB_IDC_FUNCTION_ACCIO;
   ioRB.ParmPacket = (PVOID)&isoRB;


   USBCallIDC( gpUSBDIDC, gUSBDds, (RP_GENIOCTL FAR *)&ioRB );

   #ifdef DEBUG
   dsPrint1(DBG_SPECIFIC, "USBAUD: ISOStatus : Status=%lxh\r\n",  ioRB.rph.Status);
   #endif

   if( ioRB.rph.Status != USB_IDC_RC_OK )
   {
      #ifdef DEBUG
      dsPrint1(DBG_CRITICAL, "USBAUD: ISOStatus : ERROR : status=%lxh\r\n",  ioRB.rph.Status);
      #endif
      switch( ioRB.rph.Status )
      {
         case USB_IDC_RC_ADDRINV: 
            #ifdef DEBUG
            dsPrint(DBG_CRITICAL, "USBAUD: ISOStatus : ERROR : Device or endpoint does not exist\r\n");
            #endif
            break;
         default:
            break;
      }
   }


   *ppBuffer = (CHAR FAR *)isoRB.buffer1;
   *usBytes  = isoRB.buffer1Length;


   #ifdef DEBUG
   dsPrint2(DBG_CRITICAL, "USBAUD: ISOStatus : pBuffer = %lxh Length=%lxh \r\n", (ULONG)isoRB.buffer1, isoRB.buffer1Length);
   #endif

   return(ioRB.rph.Status);

}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  GenerateDetach                                   */
/*                                                                    */
/* DESCRIPTIVE NAME: Generate detach                                  */
/*                                                                    */
/* FUNCTION:    Generates detach procedure for specified device       */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  GenerateDetach                                      */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  UCHAR  controllerId                                        */
/*         UCHAR  deviceAddress                                       */
/*                                                                    */
/* EXIT-NORMAL:  N/A                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  NONE                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */  
/*                                                                    */
/*    ROUTINES:  DetachDevice                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:  setmem                                               */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


VOID GenerateDetach(UCHAR  controllerId,  UCHAR  deviceAddress)
{

   gDetachData.controllerId  = controllerId;
   gDetachData.deviceAddress = deviceAddress;

   setmem((PSZ)&gRP, 0, sizeof(gRP));

   gpRP = &gRP;
   gpRP->ParmLen = sizeof(gDetachData);   
   gpRP->ParmPacket = (PUCHAR)&gDetachData;

   #ifdef DEBUG
   dsPrint2(DBG_CRITICAL, "USBAUD: GenerateDetach ctrl=%xh addr=%xh\r\n", controllerId, deviceAddress);
   #endif

   DetachDevice(gpRP);

   return;
}


