/* SCCSID = "src/dev/usb/COM/COMSTRAT.C, usb, c.basedd 98/10/26" */
/*
*   Licensed Material -- Property of IBM
*
*   (c) Copyright IBM Corp. 1998  All Rights Reserved
*/
/************************** START OF SPECIFICATIONS ***************************/
/*                                                                            */
/*   SOURCE FILE NAME:  COMSTRAT.C                                            */
/*                                                                            */
/*   DESCRIPTIVE NAME:  USB Communication Device Class Driver                 */
/*                      strategy routines                                     */
/*                                                                            */
/*   FUNCTION: These routines handle the task time routines for the strategy  */
/*             entry point of the USB Communication Device Class Driver.      */
/*                                                                            */
/*   NOTES:                                                                   */
/*      DEPENDENCIES: None                                                    */
/*      RESTRICTIONS: None                                                    */
/*                                                                            */
/*   ENTRY POINTS:                                                            */
/*             COMStrategy                                                    */
/*             CmdError                                                       */
/*             COMRead                                                        */
/*             COMInStatus                                                    */
/*             COMIFlush                                                      */
/*             COMWrite                                                       */
/*             COMOutStatus                                                   */
/*             COMOutFlush                                                    */
/*             COMOpen                                                        */
/*             COMClose                                                       */
/*             COMInitComplete                                                */
/*             SendCommand                                                    */
/*             GetResponse                                                    */
/*             SetFeature                                                     */
/*             GetFeature                                                     */
/*             ClearFeature                                                   */
/*             SetLineCoding                                                  */
/*             GetLineCoding                                                  */
/*             SetSignals                                                     */
/*             SendBreak                                                      */
/*             COMRequest                                                     */
/*                                                                            */
/*   EXTERNAL REFERENCES:                                                     */
/*                                                                            */
/* Change Log                                                                 */
/*                                                                            */
/*  Mark    yy/mm/dd  Programmer      Comment                                 */
/*  ----    --------  ----------      -------                                 */
/*          98/10/26  LR                                                      */
/*                                                                            */
/**************************** END OF SPECIFICATIONS ***************************/

#include "usbcom.h"

static void  COMRequest (SetupPacket FAR *pSetPack, PUCHAR pReqData, ULONG comIRQ);

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  COMStrategy                                      */
/*                                                                    */
/* DESCRIPTIVE NAME: Strategy entry point                             */
/*                   for the USB Communication Device Class Driver    */
/*                                                                    */
/* FUNCTION:   The function of this routine is                        */
/*             to call appropriate worker routine                     */
/*             to process the OS/2 kernel request packet.             */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  COMStrategy                                          */
/*    LINKAGE:  CALL FAR                                              */
/*                                                                    */
/* INPUT:  es:bx -> kernel request packet                             */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: None                                                      */
/*                                                                    */
/* INTERNAL REFERENCES:  CmdError                                     */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

#pragma optimize("eglt", off)

void far COMStrategy (void)
{
   PRPH     pRP;  // pointer to Request Packet (Header)
   USHORT   Cmd;  // strategy command

   _asm
   {
      mov   word ptr pRP[0], bx
      mov   word ptr pRP[2], es
   }
   Cmd = pRP->Cmd;

#ifdef DEBUG
   dsPrint1 (DBG_HLVLFLOW, "USBCOM: Strategy Cmd = 0x%x\r\n", Cmd);
#endif

   if (Cmd > MAX_STRAT_CMD)   CmdError (pRP);
   else                       (*gStratList[Cmd])(pRP);

#ifdef DEBUG
   dsPrint1 (DBG_HLVLFLOW, "USBCOM: Strategy S = 0x%x\r\n", pRP->Status);
#endif
}

#pragma optimize("", on)

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  CmdError                                         */
/*                                                                    */
/* DESCRIPTIVE NAME:  Command not supported in the device driver      */
/*                                                                    */
/* FUNCTION:  The function of this routine is to return command not   */
/*            supported for the request.                              */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  CmdError                                             */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status = STDON + STERR + ERROR_I24_BAD_COMMAND       */
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void CmdError (PRPH pRP)
{
#ifdef DEBUG
   dsPrint1 (DBG_CRITICAL, "USBCOM: Unknown Strategy Cmd = 0x%x\r\n", pRP->Cmd);
#endif

   pRP->Status = STDON | STERR | ERROR_I24_BAD_COMMAND;
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  COMRead                                          */
/*                                                                    */
/* DESCRIPTIVE NAME:  USB Communication Device Class Driver Read      */
/*                                                                    */
/* FUNCTION:  This strategy command reads from                        */
/*            USB Communication Device Class Driver                   */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  COMRead                                              */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status                                               */
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void COMRead (PRPH pRP)
{
   PRP_RWV pRPRead = (PRP_RWV)pRP;
   PBYTE   pBuffer;
   USHORT  count, awakeCount;

#ifdef DEBUG
   dsPrint2 (DBG_HLVLFLOW, "USBCOM: Read %d bytes from SFN = %d\r\n",
             pRPRead->NumSectors, pRPRead->sfn);
#endif

   if (gCOM.pRPRead[CURRENT] != NULL) // Current request active?
   {                                  // Yes, link a request packet onto the end of a list
      pRPRead->rph.Link = NULL;
      if (gCOM.pRPRead[FIRST] == NULL)
      {
         gCOM.pRPRead[FIRST] = pRPRead;
         gCOM.pRPRead[LAST]  = pRPRead;
      }
      else
      {
         gCOM.pRPRead[LAST]->rph.Link = (PRPH)pRPRead;
         gCOM.pRPRead[LAST]           = pRPRead;
      }
      DevHelp_ProcBlock ((ULONG)(PUCHAR)pRPRead, -1, WAIT_IS_INTERRUPTABLE);
   }
   else
   {                                // No outstanding read requests
      if (pRPRead->NumSectors == 0) // request is for 0 bytes, done
      {
         pRPRead->rph.Status = STDON;
         return;
      }
      gCOM.pRPRead[CURRENT] = pRPRead;
      do
      {
         if (DevHelp_PhysToGDTSelector (gCOM.pRPRead[CURRENT]->XferAddr,
                                        gCOM.pRPRead[CURRENT]->NumSectors,
                                        gCOM.wGDTSel[READ_SEL]))
         {
            gCOM.pRPRead[CURRENT]->rph.Status = STDON | STERR;
            return;
         }
         pBuffer = MAKEP (gCOM.wGDTSel[READ_SEL], NULL);
         gCOM.wRcount = 0;
         do
         {
            if (!gCOM.inq.wCount)
            {
               if ((gCOM.dcb.bmF3 & F3_READ_TO_MASK) == F3_READ_TO_NW || !(gCOM.bMSR & MSR_DSR)) break;
               else
               {
                  if (DevHelp_ProcBlock ((ULONG)(PUCHAR)&gCOM.inq.bBuffer[0],
                                         (gCOM.dcb.wReadTO + 1)*10,
                                         WAIT_IS_INTERRUPTABLE) == WAIT_TIMED_OUT) break;
                  else
                  {
                     if (gCOM.wDataToggle & INPUT_FLUSH_INPROGRESS) break;
                     else                                           continue;
                  }
               }
            }
            else
            {
               count = (gCOM.inq.wCount <= gCOM.pRPRead[CURRENT]->NumSectors - gCOM.wRcount)?
                        gCOM.inq.wCount :  gCOM.pRPRead[CURRENT]->NumSectors - gCOM.wRcount;
               if (gCOM.inq.iOut + count <= IO_QUEUE_LENGTH)
                  movmem (&pBuffer[gCOM.wRcount], &gCOM.inq.bBuffer[gCOM.inq.iOut], count);
               else
               {
                  movmem (&pBuffer[gCOM.wRcount], &gCOM.inq.bBuffer[gCOM.inq.iOut],
                          IO_QUEUE_LENGTH - gCOM.inq.iOut);
                  movmem (&pBuffer[gCOM.wRcount + IO_QUEUE_LENGTH - gCOM.inq.iOut],
                          &gCOM.inq.bBuffer[0],
                          count - (IO_QUEUE_LENGTH - gCOM.inq.iOut));
               }
               gCOM.inq.wCount -= count;
               gCOM.inq.iOut = (gCOM.inq.iOut + count) % IO_QUEUE_LENGTH;
               if (IO_QUEUE_LENGTH - gCOM.inq.wCount > 0)
                  DevHelp_ProcRun ((ULONG)(PUCHAR)&gCOM.inq.bBuffer[IO_QUEUE_LENGTH-1], &awakeCount);
               gCOM.wRcount += count;
               if ((gCOM.dcb.bmF3 & F3_READ_TO_MASK) == F3_READ_TO_WFS) break;
            }
         }
         while (gCOM.wRcount < gCOM.pRPRead[CURRENT]->NumSectors);

         gCOM.pRPRead[CURRENT]->NumSectors = gCOM.wRcount;
         gCOM.pRPRead[CURRENT]->rph.Status = STDON;
         DevHelp_ProcRun ((ULONG)(PUCHAR)gCOM.pRPRead[CURRENT], &awakeCount);

#ifdef DEBUG
         dsPrint2 (DBG_HLVLFLOW, "USBCOM: %d bytes readed from SFN = %d\r\n",
                   gCOM.pRPRead[CURRENT]->NumSectors, gCOM.pRPRead[CURRENT]->sfn);
#endif

         gCOM.pRPRead[CURRENT] = gCOM.pRPRead[FIRST];
         if (gCOM.pRPRead[FIRST] == gCOM.pRPRead[LAST])
              gCOM.pRPRead[FIRST] = gCOM.pRPRead[LAST] = NULL;
         else gCOM.pRPRead[FIRST] = (PRP_RWV)gCOM.pRPRead[FIRST]->rph.Link;

         if (gCOM.wDataToggle & INPUT_FLUSH_INPROGRESS)
         {
            gCOM.wDataToggle &= ~INPUT_FLUSH_INPROGRESS;
            DevHelp_ProcRun ((ULONG)(PUCHAR)&gCOM.inq.wCount, &awakeCount);
         }
      }
      while (gCOM.pRPRead[CURRENT] != NULL);
   }
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  COMInStatus                                      */
/*                                                                    */
/* DESCRIPTIVE NAME:  USB Communication Device Class Driver           */
/*                    input status                                    */
/*                                                                    */
/* FUNCTION:  This function determines input status on                */
/*            USB Communication Device Class Driver.                  */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  COMInStatus                                          */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status                                               */
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void COMInStatus (PRPH pRP)
{
   if (gCOM.inq.wCount == 0) pRP->Status = STBUI;  // busy bit 9
   pRP->Status |= STDON;

#ifdef DEBUG
   dsPrint1 (DBG_HLVLFLOW, "USBCOM: Input Status = 0x%x\r\n", pRP->Status);
#endif
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  COMInFlush                                       */
/*                                                                    */
/* DESCRIPTIVE NAME:  USB Communication Device Class Driver           */
/*                    input flush                                     */
/*                                                                    */
/* FUNCTION:  This function flushes input queue on                    */
/*            USB Communication Device Class Driver.                  */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  COMInFlush                                           */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status                                               */
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void COMInFlush (PRPH pRP)
{
   USHORT  awakeCount;
   PRP_RWV pRPRead;

#ifdef DEBUG
   dsPrint (DBG_HLVLFLOW, "USBCOM: Input Flush\r\n");
#endif

   gCOM.wDataToggle |= INPUT_FLUSH_INPROGRESS;

   for (pRPRead = gCOM.pRPRead[FIRST]; pRPRead != NULL; pRPRead = (PRP_RWV)pRPRead->rph.Link)
   {
      pRPRead->NumSectors = 0;
      pRPRead->rph.Status = STDON;
      DevHelp_ProcRun ((ULONG)(PUCHAR)pRPRead, &awakeCount);
   }
   gCOM.pRPRead[FIRST] = gCOM.pRPRead[LAST] = NULL;

   DevHelp_ProcRun ((ULONG)(PUCHAR)&gCOM.inq.bBuffer[0], &awakeCount);
   gCOM.inq.iOut = gCOM.inq.iIn;
   gCOM.inq.wCount = 0;
   if (!awakeCount) gCOM.wDataToggle &= ~INPUT_FLUSH_INPROGRESS;
   else
      while (gCOM.wDataToggle & INPUT_FLUSH_INPROGRESS)
         DevHelp_ProcBlock ((ULONG)(PUCHAR)&gCOM.inq.wCount, -1, WAIT_IS_INTERRUPTABLE);
   pRP->Status = STDON;
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  COMWrite                                         */
/*                                                                    */
/* DESCRIPTIVE NAME:  USB Communication Device Class Driver Write     */
/*                                                                    */
/* FUNCTION:  This strategy command writes to                         */
/*            USB Communication Device Class Driver                   */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  COMWrite                                              */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status                                               */
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  SendData                                     */
/*                       TransmitCommand                              */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void COMWrite (PRPH pRP)
{
   PRP_RWV pRPWrite = (PRP_RWV)pRP;
   PBYTE   pBuffer;
   USHORT  count, awakeCount;

#ifdef DEBUG
   dsPrint2 (DBG_HLVLFLOW, "USBCOM: Write %d bytes to SFN = %d\r\n",
             pRPWrite->NumSectors, pRPWrite->sfn);
#endif

   if (gCOM.pRPWrite[CURRENT] != NULL) // Current request active?
   {                                   // Yes, link a request packet onto the end of a list
      pRPWrite->rph.Link = NULL;
      if (gCOM.pRPWrite[FIRST] == NULL)
      {
         gCOM.pRPWrite[FIRST] = pRPWrite;
         gCOM.pRPWrite[LAST]  = pRPWrite;
      }
      else
      {
         gCOM.pRPWrite[LAST]->rph.Link = (PRPH)pRPWrite;
         gCOM.pRPWrite[LAST]           = pRPWrite;
      }
      DevHelp_ProcBlock ((ULONG)(PUCHAR)pRPWrite, -1, WAIT_IS_INTERRUPTABLE);
   }
   else
   {                                      // No outstanding write requests
      if (pRPWrite->NumSectors == 0 ||    // request is for 0 bytes, done
          gCOM.iModem >= MAX_MDMS)
      {
         pRPWrite->NumSectors = 0;
         pRPWrite->rph.Status = STDON;
         return;
      }
      gCOM.pRPWrite[CURRENT] = pRPWrite;
      do
      {
         if (DevHelp_PhysToGDTSelector (gCOM.pRPWrite[CURRENT]->XferAddr,
                                        gCOM.pRPWrite[CURRENT]->NumSectors,
                                        gCOM.wGDTSel[WRITE_SEL]))
         {
            gCOM.pRPWrite[CURRENT]->rph.Status = STDON | STERR;
            return;
         }
         pBuffer = MAKEP (gCOM.wGDTSel[WRITE_SEL], NULL);
         gCOM.wWcount = 0;
         do
         {
            if (IO_QUEUE_LENGTH - gCOM.outq.wCount == 0)
            {
               if (DevHelp_ProcBlock ((ULONG)(PUCHAR)&gCOM.outq.bBuffer[0],
                                      (gCOM.dcb.wWriteTO + 1)*10,
                                      WAIT_IS_INTERRUPTABLE) == WAIT_TIMED_OUT)
               {
                  if (gCOM.dcb.bmF3 & F3_W_INF_TO) continue;
                  else                             break;
               }
               else
               {
                  if (gCOM.wDataToggle & OUTPUT_FLUSH_INPROGRESS) break;
                  else                                            continue;
               }
            }
            else
            {
               count = ((USHORT)IO_QUEUE_LENGTH - gCOM.outq.wCount <= gCOM.pRPWrite[CURRENT]->NumSectors - gCOM.wWcount)?
                                IO_QUEUE_LENGTH - gCOM.outq.wCount :  gCOM.pRPWrite[CURRENT]->NumSectors - gCOM.wWcount;
               if (gCOM.outq.iIn + count <= IO_QUEUE_LENGTH)
                  movmem (&gCOM.outq.bBuffer[gCOM.outq.iIn], &pBuffer[gCOM.wWcount], count);
               else
               {
                  movmem (&gCOM.outq.bBuffer[gCOM.outq.iIn], &pBuffer[gCOM.wWcount],
                          IO_QUEUE_LENGTH - gCOM.outq.iIn);
                  movmem (&gCOM.outq.bBuffer[0], &pBuffer[gCOM.wWcount + IO_QUEUE_LENGTH - gCOM.outq.iIn],
                          count - (IO_QUEUE_LENGTH - gCOM.outq.iIn));
               }
               gCOM.outq.wCount += count;
               gCOM.outq.iIn = (gCOM.outq.iIn + count) % IO_QUEUE_LENGTH;

               if (gMDM[gCOM.iModem].cmCapabilities & CM_DATA_SUPPORT)
               {
                  if (!(gCOM.wDataToggle & (SEND_DATA_INPROGRESS | SEND_BYTE_INPROGRESS))) SendData();
               }
               else
               {
                  if (gCOM.bMSR & MSR_DCD)
                  {
                     if (!(gCOM.wDataToggle & (SEND_DATA_INPROGRESS | SEND_BYTE_INPROGRESS))) SendData();
                  }
                  else
                  {
                     if (!(gCOM.wDataToggle & SEND_CMD_INPROGRESS)) TransmitCommand();
                  }
               }
               gCOM.wWcount += count;
            }
         }
         while (gCOM.wWcount < gCOM.pRPWrite[CURRENT]->NumSectors);

         gCOM.pRPWrite[CURRENT]->NumSectors = gCOM.wWcount;
         gCOM.pRPWrite[CURRENT]->rph.Status = STDON;
         DevHelp_ProcRun ((ULONG)(PUCHAR)gCOM.pRPWrite[CURRENT], &awakeCount);

         gCOM.pRPWrite[CURRENT] = gCOM.pRPWrite[FIRST];
         if (gCOM.pRPWrite[FIRST] == gCOM.pRPWrite[LAST])
              gCOM.pRPWrite[FIRST] = gCOM.pRPWrite[LAST] = NULL;
         else gCOM.pRPWrite[FIRST] = (PRP_RWV)gCOM.pRPWrite[FIRST]->rph.Link;

         if (gCOM.wDataToggle & OUTPUT_FLUSH_INPROGRESS)
         {
            gCOM.wDataToggle &= ~OUTPUT_FLUSH_INPROGRESS;
            DevHelp_ProcRun ((ULONG)(PUCHAR)&gCOM.outq.wCount, &awakeCount);
         }
      }
      while (gCOM.pRPWrite[CURRENT] != NULL);
   }
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  COMOutStatus                                     */
/*                                                                    */
/* DESCRIPTIVE NAME:  USB Communication Device Class Driver           */
/*                    output status                                   */
/*                                                                    */
/* FUNCTION:  This function determines output status on               */
/*            USB Communication Device Class Driver.                  */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  COMOutStatus                                          */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status                                               */
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void COMOutStatus (PRPH pRP)
{
   if (gCOM.pRPWrite[CURRENT] != NULL) pRP->Status = STBUI;
   pRP->Status |= STDON;

#ifdef DEBUG
   dsPrint1 (DBG_HLVLFLOW, "USBCOM: Output Status = 0x%x\r\n", pRP->Status);
#endif
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  COMOutFlush                                      */
/*                                                                    */
/* DESCRIPTIVE NAME:  USB Communication Device Class Driver           */
/*                    output flush                                    */
/*                                                                    */
/* FUNCTION:  This function flushes output queue on                   */
/*            USB Communication Device Class Driver.                  */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  COMOutFlush                                          */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status                                               */
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void COMOutFlush (PRPH pRP)
{
   USHORT  awakeCount;
   PRP_RWV pRPWrite;

#ifdef DEBUG
   dsPrint (DBG_HLVLFLOW, "USBCOM: Output Flush\r\n");
#endif

   gCOM.wDataToggle |= OUTPUT_FLUSH_INPROGRESS;

   for (pRPWrite = gCOM.pRPWrite[FIRST]; pRPWrite != NULL; pRPWrite = (PRP_RWV)pRPWrite->rph.Link)
   {
      pRPWrite->NumSectors = 0;
      pRPWrite->rph.Status = STDON;
      DevHelp_ProcRun ((ULONG)(PUCHAR)pRPWrite, &awakeCount);
   }
   gCOM.pRPWrite[FIRST] = gCOM.pRPWrite[LAST] = NULL;

   DevHelp_ProcRun ((ULONG)(PUCHAR)&gCOM.outq.bBuffer[0], &awakeCount);
   gCOM.outq.iOut = gCOM.outq.iIn;
   gCOM.outq.wCount = 0;
   if (!awakeCount) gCOM.wDataToggle &= ~OUTPUT_FLUSH_INPROGRESS;
   else
      while (gCOM.wDataToggle & OUTPUT_FLUSH_INPROGRESS)
         DevHelp_ProcBlock ((ULONG)(PUCHAR)&gCOM.outq.wCount, -1, WAIT_IS_INTERRUPTABLE);
   pRP->Status = STDON;
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  COMOpen                                          */
/*                                                                    */
/* DESCRIPTIVE NAME:  USB Communication Device Class Driver open      */
/*                                                                    */
/* FUNCTION:  The function of this routine is to open                 */
/*            USB Communication Device Class Driver                   */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  COMOpen                                              */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status                                               */
/*                                                                    */
/* INTERNAL REFERENCES:  SetSignals                                   */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void COMOpen (PRPH pRP)
{
   USHORT awakeCountIn, awakeCountOut;
   PRP_RWV pRPRW;

#ifdef DEBUG
   dsPrint1 (DBG_HLVLFLOW, "USBCOM: Open SFN = %d\r\n", ((PRP_OPENCLOSE)pRP)->sfn);
#endif

   if (gCOM.iModem >= MAX_MDMS)
   {
      pRP->Status = STDON | STERR | ERROR_I24_NOT_READY;
      return;
   }
   if (gCOM.wNOpens++ == 0)            // First Level Open
   {
      gCOM.wDataToggle |= INPUT_FLUSH_INPROGRESS | OUTPUT_FLUSH_INPROGRESS;

      for (pRPRW = gCOM.pRPRead[FIRST]; pRPRW != NULL; pRPRW = (PRP_RWV)pRPRW->rph.Link)
      {
         pRPRW->NumSectors = 0;
         pRPRW->rph.Status = STDON;
         DevHelp_ProcRun ((ULONG)(PUCHAR)pRPRW, &awakeCountIn);
      }
      gCOM.pRPRead[FIRST] = gCOM.pRPRead[LAST] = NULL;
      
      DevHelp_ProcRun ((ULONG)(PUCHAR)&gCOM.inq.bBuffer[0], &awakeCountIn);
      gCOM.inq.iIn = gCOM.inq.iOut = gCOM.inq.wCount = 0;

      for (pRPRW = gCOM.pRPWrite[FIRST]; pRPRW != NULL; pRPRW = (PRP_RWV)pRPRW->rph.Link)
      {
         pRPRW->NumSectors = 0;
         pRPRW->rph.Status = STDON;
         DevHelp_ProcRun ((ULONG)(PUCHAR)pRPRW, &awakeCountOut);
      }
      gCOM.pRPWrite[FIRST] = gCOM.pRPWrite[LAST] = NULL;

      DevHelp_ProcRun ((ULONG)(PUCHAR)&gCOM.outq.bBuffer[0], &awakeCountOut);
      gCOM.outq.iIn = gCOM.outq.iOut = gCOM.outq.wCount = 0;

      gCOM.dcb.wWriteTO = WRITE_TO_INIT;
      gCOM.dcb.wReadTO  = READ_TO_INIT;
                                       // No effect on DCB Flags1
      gCOM.dcb.bmF2 &= ~F2_ERR_CHAR;   // Disable error replacement character processing
      gCOM.dcb.bmF2 &= ~F2_NULL_STRIP; // Disable null stripping
      gCOM.dcb.bmF2 &= ~F2_BRK_CHAR;   // Disable break replacement character processing
      gCOM.dcb.bmF3   = F3_READ_TO_NORM;
      gCOM.dcb.bError = 0;
      gCOM.dcb.bBreak = 0;
      gCOM.dcb.bXON   = XON_INIT;
      gCOM.dcb.bXOFF  = XOFF_INIT;
      
      gCOM.wEvent = gCOM.wError = 0;

      gCOM.wDataToggle &= ~STOP_TRANSMIT;

      if ((gCOM.dcb.bmF1 & F1_DTR_MASK) == F1_DTR_ENABLE) gCOM.bMCR |= MCR_DTR;
      if ((gCOM.dcb.bmF2 & F2_RTS_MASK) == F2_RTS_ENABLE) gCOM.bMCR |= MCR_RTS;
      SetSignals();

      if (!awakeCountIn) gCOM.wDataToggle &= ~INPUT_FLUSH_INPROGRESS;
      else
         while (gCOM.wDataToggle & INPUT_FLUSH_INPROGRESS)
            DevHelp_ProcBlock ((ULONG)(PUCHAR)&gCOM.inq.wCount, -1, WAIT_IS_INTERRUPTABLE);
      if (!awakeCountOut) gCOM.wDataToggle &= ~OUTPUT_FLUSH_INPROGRESS;   
      else
         while (gCOM.wDataToggle & OUTPUT_FLUSH_INPROGRESS)
            DevHelp_ProcBlock ((ULONG)(PUCHAR)&gCOM.outq.wCount, -1, WAIT_IS_INTERRUPTABLE);
   }
   pRP->Status = STDON;
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  COMClose                                         */
/*                                                                    */
/* DESCRIPTIVE NAME:  USB Communication Device Class Driver close     */
/*                                                                    */
/* FUNCTION:  The function of this routine is to close                */
/*            USB Communication Device Class Driver                   */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  COMClose                                             */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status                                               */
/*                                                                    */
/* INTERNAL REFERENCES:  SendBreak                                    */
/*                       SetSignals                                   */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void COMClose (PRPH pRP)
{
   USHORT  awakeCountIn, awakeCountOut;
   PRP_RWV pRPRW;

#ifdef DEBUG
   dsPrint1 (DBG_HLVLFLOW, "USBCOM: Close SFN = %d\r\n", ((PRP_OPENCLOSE)pRP)->sfn);
#endif

   if (--gCOM.wNOpens == 0)  // Last Level Close
   {
      if (gCOM.bTxBreak) SendBreak (SEND_BREAK_OFF, COM_IRQ_BREAKOFF);

      gCOM.wDataToggle |= INPUT_FLUSH_INPROGRESS | OUTPUT_FLUSH_INPROGRESS;

      for (pRPRW = gCOM.pRPRead[FIRST]; pRPRW != NULL; pRPRW = (PRP_RWV)pRPRW->rph.Link)
      {
         pRPRW->NumSectors = 0;
         pRPRW->rph.Status = STDON;
         DevHelp_ProcRun ((ULONG)(PUCHAR)pRPRW, &awakeCountIn);
      }
      gCOM.pRPRead[FIRST] = gCOM.pRPRead[LAST] = NULL;

      DevHelp_ProcRun ((ULONG)(PUCHAR)&gCOM.inq.bBuffer[0], &awakeCountIn);
      gCOM.inq.iIn = gCOM.inq.iOut = gCOM.inq.wCount = 0;

      for (pRPRW = gCOM.pRPWrite[FIRST]; pRPRW != NULL; pRPRW = (PRP_RWV)pRPRW->rph.Link)
      {
         pRPRW->NumSectors = 0;
         pRPRW->rph.Status = STDON;
         DevHelp_ProcRun ((ULONG)(PUCHAR)pRPRW, &awakeCountOut);
      }
      gCOM.pRPWrite[FIRST] = gCOM.pRPWrite[LAST] = NULL;

      DevHelp_ProcRun ((ULONG)(PUCHAR)&gCOM.outq.bBuffer[0], &awakeCountOut);
      gCOM.outq.iIn = gCOM.outq.iOut = gCOM.outq.wCount = 0;

      gCOM.bMCR &= ~MCR_DTR;
      gCOM.bMCR &= ~MCR_RTS;
      if (gCOM.iModem < MAX_MDMS) SetSignals();

      if (!awakeCountIn) gCOM.wDataToggle &= ~INPUT_FLUSH_INPROGRESS;
      else
         while (gCOM.wDataToggle & INPUT_FLUSH_INPROGRESS)
            DevHelp_ProcBlock ((ULONG)(PUCHAR)&gCOM.inq.wCount, -1, WAIT_IS_INTERRUPTABLE);
      if (!awakeCountOut) gCOM.wDataToggle &= ~OUTPUT_FLUSH_INPROGRESS;   
      else
         while (gCOM.wDataToggle & OUTPUT_FLUSH_INPROGRESS)
            DevHelp_ProcBlock ((ULONG)(PUCHAR)&gCOM.outq.wCount, -1, WAIT_IS_INTERRUPTABLE);
   }
   pRP->Status = STDON;
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  COMInitComplete                                  */
/*                                                                    */
/* DESCRIPTIVE NAME:  Initialization complete                         */
/*                                                                    */
/* FUNCTION:  The function of this routine is to finish driver's      */
/*            initialization by registering them to USB driver.       */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Initialization time                                       */
/*                                                                    */
/* ENTRY POINT:  COMInitComplete                                      */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status                                               */
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  USBCallIDC                                   */
/*                       GetDS                                        */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void COMInitComplete (PRPH pRP)
{
   RP_GENIOCTL rp;      // GENeric IOCTL Request Packet
   USBDClass   comData;

#ifdef DEBUG
   dsPrint (DBG_HLVLFLOW, "USBCOM: InitComplete\r\n");
#endif

   setmem ((PSZ)&rp, 0, sizeof(rp));
   rp.rph.Cmd = CMDGenIOCTL;
   rp.Category = USB_IDC_CATEGORY_USBD;
   rp.Function = USB_IDC_FUNCTION_REGISTER;
   rp.ParmPacket = (PVOID)&comData;
   comData.usbIDC = (PUSBIDCEntry)&COMidc;
   comData.usbDS = GetDS();
   USBCallIDC (gpUSBDIDC, gdsUSBDIDC, (RP_GENIOCTL FAR *)&rp);
   pRP->Status = rp.rph.Status;
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  SendCommand                                      */
/*                                                                    */
/* DESCRIPTIVE NAME:  Send Encapsulated Command                       */
/*                                                                    */
/* FUNCTION:  This function is used to issue a command                */
/*            in the format of the supported control protocol         */
/*            of the Communication Class interface.                   */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  SendCommand                                          */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:                                                             */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES:  COMRequest                                   */
/*                                                                    */
/* EXTERNAL REFERENCES:  none                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void  SendCommand (USHORT length)
{
   gCOM.setPack.bmRequestType = REQTYPE_XFERDIR_HOSTTODEV;
   gCOM.setPack.bRequest = SEND_ENCAPSULATED_COMMAND;
   gCOM.setPack.wValue = 0;
   gCOM.setPack.wLength = length;

   COMRequest (&gCOM.setPack, (PUCHAR)&gCOM.outq.bBuffer[gCOM.outq.iOut], COM_IRQ_SENDCMD);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  GetResponse                                      */
/*                                                                    */
/* DESCRIPTIVE NAME:  Get Encapsulated Response                       */
/*                                                                    */
/* FUNCTION:  This function is used to request a response             */
/*            in the format of the supported control protocol         */
/*            of the Communication Class interface.                   */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  GetResponse                                          */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:                                                             */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES:  COMRequest                                   */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void GetResponse (USHORT length)
{
   gCOM.setPack.bmRequestType = REQTYPE_XFERDIR_DEVTOHOST;
   gCOM.setPack.bRequest = GET_ENCAPSULATED_RESPONSE;
   gCOM.setPack.wValue = 0;
   gCOM.setPack.wLength = length;

   COMRequest (&gCOM.setPack, (PUCHAR)&gCOM.inq.bBuffer[gCOM.inq.iIn], COM_IRQ_GETRESP);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  SetFeature                                       */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set Feature Request                             */
/*                                                                    */
/* FUNCTION:  This request controls the settings for a particular     */
/*            communication feature.                                  */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  SetFeature                                           */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:                                                             */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES:  COMRequest                                   */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void SetFeature (USHORT feature)
{
   gCOM.setPack.bmRequestType = REQTYPE_XFERDIR_HOSTTODEV;
   gCOM.setPack.bRequest = SET_COMM_FEATURE;
   gCOM.setPack.wValue = ABSTRACT_STATE;
   gCOM.setPack.wLength = ABSTRACT_STATE_LENGTH;
   
   gCOM.bReqData[FIRST] = LOUCHAR(feature);
   gCOM.bReqData[SECOND] = HIUCHAR(feature);

   COMRequest (&gCOM.setPack, gCOM.bReqData, COM_IRQ_FEATURE);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  GetFeature                                       */
/*                                                                    */
/* DESCRIPTIVE NAME:  Get Communication Feature                       */
/*                                                                    */
/* FUNCTION:  This function returns the current settings for the      */
/*            communication feature.                                  */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  GetFeature                                           */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:                                                             */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES:  COMRequest                                   */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void GetFeature (void)
{
   gCOM.setPack.bmRequestType = REQTYPE_XFERDIR_DEVTOHOST;
   gCOM.setPack.bRequest = GET_COMM_FEATURE;
   gCOM.setPack.wValue = ABSTRACT_STATE;
   gCOM.setPack.wLength = ABSTRACT_STATE_LENGTH;

   COMRequest (&gCOM.setPack, (PUCHAR)&gCOM.wFeature, COM_IRQ_FEATURE);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  ClearFeature                                     */
/*                                                                    */
/* DESCRIPTIVE NAME:  Clear Feature Request                           */
/*                                                                    */
/* FUNCTION:  This request clears the settings for a particular       */
/*            communication feature.                                  */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  ClearFeature                                         */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:                                                             */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES:  COMRequest                                   */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void ClearFeature (void)
{
   gCOM.setPack.bmRequestType = REQTYPE_XFERDIR_HOSTTODEV;
   gCOM.setPack.bRequest = CLEAR_COMM_FEATURE;
   gCOM.setPack.wValue = ABSTRACT_STATE;
   gCOM.setPack.wLength = 0;

   COMRequest (&gCOM.setPack, NULL, COM_IRQ_FEATURE);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  SetLineCoding                                    */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set Line Coding Request                         */
/*                                                                    */
/* FUNCTION:  This request allows to set the required asynchronous    */
/*            line properties.                                        */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  SetLineCoding                                        */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:                                                             */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES:  COMRequest                                   */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void SetLineCoding (void)
{
   ((LineCoding *)gCOM.bReqData)->dwDTERate   = gCOM.line.dwDTERate;
   ((LineCoding *)gCOM.bReqData)->bDataBits   = gCOM.line.bDataBits;
   ((LineCoding *)gCOM.bReqData)->bParityType = gCOM.line.bParityType;
   ((LineCoding *)gCOM.bReqData)->bCharFormat = gCOM.line.bCharFormat;

   gCOM.setPack.bmRequestType = REQTYPE_XFERDIR_HOSTTODEV;
   gCOM.setPack.bRequest = SET_LINE_CODING;
   gCOM.setPack.wValue = 0;
   gCOM.setPack.wLength = sizeof(LineCoding);

   COMRequest (&gCOM.setPack, gCOM.bReqData, COM_IRQ_LINECOD);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  GetLineCoding                                    */
/*                                                                    */
/* DESCRIPTIVE NAME:  Get Line Coding Request                         */
/*                                                                    */
/* FUNCTION:  This request allows to find out the currently           */
/*            configured line coding.                                 */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  GetLineCoding                                        */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:                                                             */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES:  COMRequest                                   */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void GetLineCoding (void)
{
   gCOM.setPack.bmRequestType = REQTYPE_XFERDIR_DEVTOHOST;
   gCOM.setPack.bRequest = GET_LINE_CODING;
   gCOM.setPack.wValue = 0;
   gCOM.setPack.wLength = sizeof(LineCoding);

   COMRequest (&gCOM.setPack, gCOM.bReqData, COM_IRQ_LINECOD);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  SetSignals                                       */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set Control Line State                          */
/*                                                                    */
/* FUNCTION:  This request generates RS-232/V.24 style control        */
/*            signals: DTR/108.2 and RTS/105.                         */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  SetSignals                                           */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:                                                             */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES:  COMRequest                                   */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void  SetSignals (void)
{
   gCOM.setPackS.bmRequestType = REQTYPE_XFERDIR_HOSTTODEV;
   gCOM.setPackS.bRequest = SET_CONTROL_LINE_STATE;
   gCOM.setPackS.wValue = (USHORT)gCOM.bMCR;
   gCOM.setPackS.wLength = 0;

#ifdef DEBUG
   dsPrint1 (DBG_DETAILED, "USBCOM: SetSignals = 0x%x\r\n", gCOM.setPackS.wValue);
#endif

   COMRequest (&gCOM.setPackS, NULL, COM_IRQ_REQUEST);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  SendBreak                                        */
/*                                                                    */
/* DESCRIPTIVE NAME:  Send Break                                      */
/*                                                                    */
/* FUNCTION:  This request sends special carrier modulation used to   */
/*            specify RS-232 style break.                             */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  SendBreak                                            */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:                                                             */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES:  COMRequest                                   */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

void SendBreak (USHORT duration, ULONG comIRQ)
{
   gCOM.setPack.bmRequestType = REQTYPE_XFERDIR_HOSTTODEV;
   gCOM.setPack.bRequest = SEND_BREAK;
   gCOM.setPack.wValue = duration;        // in milliseconds
   gCOM.setPack.wLength = 0;

#ifdef DEBUG
   dsPrint1 (DBG_DETAILED, "USBCOM: SendBreak %d ms\r\n", duration);
#endif

   COMRequest (&gCOM.setPack, NULL, comIRQ);
}

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

static void  COMRequest (SetupPacket FAR *pSetPack, PUCHAR pReqData, ULONG comIRQ)
{
   USBRB          rb;
   RP_GENIOCTL    rp;

   pSetPack->bmRequestType |= REQTYPE_TYPE_CLASS | REQTYPE_RECIPIENT_INTERFACE;
   pSetPack->wIndex = gMDM[gCOM.iModem].bComInterface;

   rb.controllerId = gMDM[gCOM.iModem].pDeviceInfo->ctrlID;
   rb.deviceAddress = gMDM[gCOM.iModem].pDeviceInfo->deviceAddress;
   rb.endPointId = USB_DEFAULT_CTRL_ENDPT;
   rb.status = 0;
   rb.flags = USRB_FLAGS_TTYPE_SETUP;
   rb.buffer1 = (PUCHAR)pSetPack;
   rb.buffer1Length = sizeof(SetupPacket);
   rb.buffer2 = pReqData;
   rb.buffer2Length = pSetPack->wLength;
   rb.serviceTime = USB_DEFAULT_SRV_INTV;
   rb.maxPacketSize = USB_DEFAULT_PKT_SIZE;
   rb.maxErrorCount = USB_MAX_ERROR_COUNT;
   rb.usbIDC = (PUSBIDCEntry)COMidc;
   rb.usbDS = GetDS();
   rb.category = USB_IDC_CATEGORY_CLASS;
   rb.requestData1 = comIRQ;
   rb.requestData2 = 0;
   rb.requestData3 = 0;

   setmem((PSZ)&rp, 0, sizeof(rp));
   rp.rph.Cmd = CMDGenIOCTL;
   rp.Category = USB_IDC_CATEGORY_USBD;
   rp.Function = USB_IDC_FUNCTION_ACCIO;
   rp.ParmPacket = (PVOID)&rb;
   
   USBCallIDC (gpUSBDIDC, gdsUSBDIDC, (PRP_GENIOCTL)&rp);

#ifdef DEBUG
   dsPrint2 (DBG_HLVLFLOW, "USBCOM: Request = 0x%x, S = 0x%x\r\n",
             pSetPack->bRequest, rp.rph.Status);
#endif
}

