/*
 * Copyright 2000-5 Digi International, Inc.
 */
													



/*
 *----------------------------------------------------------------------
 * Function:  AsynIoSetBaudRate.
 *
 * Purpose:
 *
 *    Set the BAUD rate.
 *
 *
 * 
 *----------------------------------------------------------------------
 */

#include "header.h"


static NTSTATUS
AsynIoSetBaudRate(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Associated IRP
   IN ULONG             BufferSize,    // Input buffer size.
   IN PSERIAL_BAUD_RATE pBaudRate      // BAUD rate to set.
)
{
   NTSTATUS    status;                 // Call return value.
   
   DigiDump(DIGIIOCTL | DIGIIOCTL1, ("ASYN!IoSetBaudRate: PortNo=0x%x ", pPortExt->port));

   if (BufferSize < sizeof(*pBaudRate))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      goto IoctlExit;
   }
   DigiDump(DIGIIOCTL | DIGIIOCTL1, ("Baud=%d\n", pBaudRate->BaudRate));

   status = STATUS_INVALID_PARAMETER;
   if ((pBaudRate->BaudRate > 1228800) || (pBaudRate->BaudRate < 4))
   {
      DigiDump(DIGIALL, ("ASYN!IoSetBaudRate: PortNo=0x%x InvalidBaud=%d!\n", 
         pPortExt->port, pBaudRate->BaudRate));
      status = STATUS_INVALID_PARAMETER;
      goto IoctlExit;
   }

	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);

   if (pBaudRate->BaudRate == pPortExt->ioctl.Speed)
   {
      status = STATUS_SUCCESS;
	  KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);
      goto IoctlExit;
   }

   
	pPortExt->ioctl.Speed = pBaudRate->BaudRate;
   	pIrp->IoStatus.Information = ++pPortExt->ioctl.sync;
	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);


/*
 *		Parag - TODO
 *		Add interface here fot Sxb interpreter
 *
 */


//	We get here after the SxB interpreter is done.






	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);
	if (pPortExt->ioctl.syncAck >=pIrp->IoStatus.Information)
		status = STATUS_SUCCESS;
	else
		status = STATUS_PENDING;


	if (status == STATUS_PENDING)
	{
		IoMarkIrpPending(pIrp);
		InsertTailList(&pPortExt->ioctl.pendingQueue, &pIrp->Tail.Overlay.ListEntry);
	}
		

	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

	
IoctlExit:

      return (status);
}







/*
 *----------------------------------------------------------------------
 * Function:  AsynIoGetBaudRate.
 *
 * Purpose:
 *
 *    Get the BAUD rate.
 *
 *
 * Method:
 *
 *    o Update the baud rate based on the PortExt structure.
 *
 *
 * Returns:
 *
 *    o STATUS_SUCCESS is returned.
 *    o STATUS_BUFFER_TOO_SMALL on buffer too small.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoGetBaudRate(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Work item.
   IN ULONG             BufferSize,    // Output buffer size.
   OUT PSERIAL_BAUD_RATE pBaudRate     // BAUD rate to set.
)
{
   NTSTATUS    Status;                 // Call return value.

   DigiDump(DIGIIOCTL | DIGIIOCTL1, ("ASYN!IoGetBaudRate: PortNo=0x%x ", 
            pPortExt->port));

   if (BufferSize < sizeof(*pBaudRate))
   {
      Status = STATUS_BUFFER_TOO_SMALL;
      pIrp->IoStatus.Information = 0;
      goto  IoctlExit;
   }
   pBaudRate->BaudRate = pPortExt->ioctl.Speed;
        
   DigiDump(DIGIIOCTL | DIGIIOCTL1, ("%d\n", pBaudRate->BaudRate));

   pIrp->IoStatus.Information = sizeof(*pBaudRate);

   Status = STATUS_SUCCESS;

IoctlExit:
   return (Status);
}


//PARAG TODO - Talk to Sandy


/*
**----------------------------------------------------------------------
**  Function:  AsynSetQueueSize.
**
**  Purpose:
**
**      Verify that NT and PortServer are in sync.
**
**
**  Method:
**
**      o Only error when NT requires more memory than the PortServer
**        provides for a port.
**
**
**  Returns:
**
**      o STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES is returned.
**
**
**  Revision History:
**
**      Date   Revision  Author         Modification Notes
**
**    01/03/97  1.0.0.0  J. Ruf         Initial Release
**    03/21/97  1.0.0.0  J. Ruf         Update rwin to the new buffer size.
**    04/01/97  1.0.0.1  J. Ruf         DOSMODE functionality added.
**    04/25/97  1.0.0.2  J. Ruf         Fixed upgraded buffer.
**    05/27/97  1.0.0.3  J. Ruf         Use SPINLOCK to throttle port access.
**
**----------------------------------------------------------------------
** STATIC
*/





/*
 *----------------------------------------------------------------------
 * Function:  AsynIoSetLineControl
 *
 * Purpose:
 *
 *    Set the parity, word size and stop bit parameters.
 *
 *
 * Method:
 *
 *    o Set the parity, word size and stop bit parameters.
 *
 *
 * Returns:
 *
 *    o STATUS_BUFFER_TOO_SMALL on buffer too small.
 *    o STATUS_INVALID_PARAMETER, Error.
 *    o STATUS_PENDING, DsPutMsgEx called.
 *    o STATUS_SUCCESS, no need to send a command to S/DXB.
 *
 *
 * Notes:
 *    o The associated IRP is already marked as Pending.
 *    o The Port's PortLock Lock is held before calling this function.
 *
 *
 *----------------------------------------------------------------------
 */

NTSTATUS
AsynIoSetLineControl(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Associated IRP
   IN ULONG             BufferSize,    // Input buffer size.
   IN PSERIAL_LINE_CONTROL
                        pLineControl   // Control Information.
)
{
   NTSTATUS    status = STATUS_SUCCESS;// Call return value.
   USHORT      ProposedCflags;
   USHORT      ProposedXflags;
   USHORT      ProposedIflags;
   PIRP        pIrpRecorded = NULL;

   DigiDump(DIGIIOCTL, ("ASYN!IoSetLineControl: PortNo=0x%x\n", pPortExt->port));

   if (BufferSize < sizeof(*pLineControl))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      goto  IoctlExit;
   }

  
   //
   // Reset changeable xflag and cflag bits.
   //
   ProposedCflags = SDXB_CREAD;
   ProposedXflags = pPortExt->ioctl.Xflags & ~(SDXB_XPAR | SDXB_XEDATA);
   ProposedIflags = pPortExt->ioctl.Iflags & ~(SDXB_INPCK);

   switch (pLineControl->Parity)
   {
      case NO_PARITY:
         break;
      case ODD_PARITY:
         ProposedCflags |= SDXB_PARENB | SDXB_PARODD;
         ProposedIflags |= SDXB_INPCK;
         //
         // If not doing Microsoft's LSRMST_INSERT or Line Error 
         // replacement , then receive error chars unaltered.
         if (!(pPortExt->ioctl.Xflags & (SDXB_XMSPAR | SDXB_XMSERC)))
         {
            ProposedXflags |= SDXB_XEDATA;
         }
         break;
      case EVEN_PARITY:
         ProposedCflags |= SDXB_PARENB;
         ProposedIflags |= SDXB_INPCK;
         //
         // If not doing Microsoft's LSRMST_INSERT or Break or Line Error 
         // replacement , then receive error chars unaltered.
         if (!(pPortExt->ioctl.Xflags & (SDXB_XMSPAR | SDXB_XMSERC)))
         {
            ProposedXflags |= SDXB_XEDATA;
         }
         break;
      case MARK_PARITY:
         ProposedCflags |= SDXB_PARENB | SDXB_PARODD;
         ProposedXflags |= SDXB_XPAR;
         ProposedIflags |= SDXB_INPCK;
         //
         // If not doing Microsoft's LSRMST_INSERT or Break or Line Error 
         // replacement , then receive error chars unaltered.
         if (!(pPortExt->ioctl.Xflags & (SDXB_XMSPAR | SDXB_XMSERC)))
         {
            ProposedXflags |= SDXB_XEDATA;
         }
         break;
      case SPACE_PARITY:
         ProposedCflags |= SDXB_PARENB;
         ProposedXflags |= SDXB_XPAR;
         ProposedIflags |= SDXB_INPCK;
         //
         // If not doing Microsoft's LSRMST_INSERT or Break or Line Error 
         // replacement , then receive error chars unaltered.
         if (!(pPortExt->ioctl.Xflags & (SDXB_XMSPAR | SDXB_XMSERC)))
         {
            ProposedXflags |= SDXB_XEDATA;
         }
         break;
      default:
         status = STATUS_INVALID_PARAMETER;
         goto  IoctlExit;
   }

   switch (pLineControl->WordLength)
   {
      case 5:
         ProposedCflags |= SDXB_CS5;
         break;
      case 6:
         ProposedCflags |= SDXB_CS6;
         break;
      case 7:
         ProposedCflags |= SDXB_CS7;
         break;
      case 8:
         ProposedCflags |= SDXB_CS8;
         break;
      default:
         status = STATUS_INVALID_PARAMETER;
         goto  IoctlExit;
   }

   switch (pLineControl->StopBits)
   {
      case STOP_BIT_1:
         break;
      case STOP_BITS_1_5:
         if (pLineControl->WordLength != 5)
         {
            status = STATUS_INVALID_PARAMETER;
            goto  IoctlExit;
         }
         else
            ProposedCflags |= SDXB_CSTOPB;
         break;
      case STOP_BITS_2:
         if (pLineControl->WordLength == 5)
         {
            status = STATUS_INVALID_PARAMETER;
            goto  IoctlExit;
         }
         else
            ProposedCflags |= SDXB_CSTOPB;
         break;
      default:
         status = STATUS_INVALID_PARAMETER;
         goto  IoctlExit;
   }


   //
   // All the setup values have been set, do we need to update S/DXB module?
   //
   if ((ProposedCflags != pPortExt->ioctl.Cflags)
       || (ProposedXflags != pPortExt->ioctl.Xflags)
       || (ProposedIflags != pPortExt->ioctl.Iflags))
   {

      pPortExt->ioctl.Cflags = ProposedCflags;
      pPortExt->ioctl.Xflags = ProposedXflags;
      pPortExt->ioctl.Iflags = ProposedIflags;

      KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);
	  pIrp->IoStatus.Information = ++pPortExt->ioctl.sync;
	  KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);


/*
 *		Parag - TODO
 *		Add interface here fot Sxb interpreter
 *
 */


//	We get here after the SxB interpreter is done.





   }

	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);
	if (pPortExt->ioctl.syncAck >=pIrp->IoStatus.Information)
		status = STATUS_SUCCESS;
	else
		status = STATUS_PENDING;


	if (status == STATUS_PENDING)
	{
		 InsertTailList(&pPortExt->ioctl.pendingQueue, &pIrp->Tail.Overlay.ListEntry);
		 IoMarkIrpPending(pIrp);

	}


	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

	
IoctlExit:

      return (status);
}




/*
 *----------------------------------------------------------------------
 * Function:  AsynIoGetLineControl
 *
 * Purpose:
 *
 *    Return the port's configured parity, data width, and stop bits.
 *
 *
 * Method:
 *
 *    o Return the port's configured parity, data width, and stop bits.
 *
 *
 * Returns:
 *
 *    o STATUS_BUFFER_TOO_SMALL on buffer too small.
 *    o STATUS_SUCCESS is returned.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoGetLineControl(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Ioctl work to perform.
   IN ULONG             BufferSize,    // Output buffer size.
   OUT PSERIAL_LINE_CONTROL
                        pLineControl   // Control information.
)
{
   NTSTATUS    status;                 // Call return value.

   DigiDump(DIGIIOCTL, ("ASYN!IoGetLineControl: PortNo=0x%x\n",
                        pPortExt->port));

   status = STATUS_SUCCESS;

   if (BufferSize < sizeof(*pLineControl))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      pIrp->IoStatus.Information = 0;
      goto  IoctlExit;
   }

   switch (pPortExt->ioctl.Cflags & (SDXB_CSIZE))
   {
      case SDXB_CS5:
           pLineControl->WordLength = 5;
           break;
      case SDXB_CS6:
           pLineControl->WordLength = 6;
           break;
      case SDXB_CS7:
           pLineControl->WordLength = 7;
           break;
      case SDXB_CS8:
           pLineControl->WordLength = 8;
           break;
   }

   switch (pPortExt->ioctl.Cflags & SDXB_CSTOPB)
   {
      case 0x00:
           pLineControl->StopBits = STOP_BIT_1;
           break;
      case SDXB_CSTOPB:
           if (pLineControl->WordLength == 5)
               pLineControl->StopBits = STOP_BITS_1_5;
           else
               pLineControl->StopBits = STOP_BITS_2;
           break;
   }

   if (!(pPortExt->ioctl.Cflags & SDXB_PARENB))
   {
      pLineControl->Parity = NO_PARITY;
   }
   else
   {
      if (!(pPortExt->ioctl.Xflags & SDXB_XPAR))
      {
         if (pPortExt->ioctl.Cflags & SDXB_PARODD)
         {
            pLineControl->Parity = ODD_PARITY;
         }
         else
         {
            pLineControl->Parity = EVEN_PARITY;
         }
      }
      else
      {
         if (pPortExt->ioctl.Cflags & SDXB_PARODD)
         {
            pLineControl->Parity = MARK_PARITY;
         }
         else
         {
            pLineControl->Parity = SPACE_PARITY;
         }
      }
   }
   pIrp->IoStatus.Information = sizeof(*pLineControl);
IoctlExit:
   return (status);
}





/*
 *----------------------------------------------------------------------
 * Function:  AsynIoSetBreak.
 *
 * Purpose:
 *
 *    Set/Clear Break.
 *
 *
 * Method:
 *
 *    o Mark associated IRP as Pending.
 *    o Hold the Port's Spin Lock.
 *    o Generate an S/DXB break command.
 *    o Release the Port's Spin Lock.
 *
 *
 * Returns:
 *
 *    o STATUS_PENDING is returned.
 *    o STATUS_INVALID_PARAMETER on Error.
 *
 *
 * Notes:
 *
 *    o When the DsPutMsgEx completion routine is called the IRP status is
 *      changed from PENDING to SUCCESS and the IRP is completed.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoSetBreak(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Associated IRP
   IN BOOLEAN           BreakOn        // TRUE if Break is on.
)
{
   NTSTATUS    status;                 // Call return value.
   PIRP        pIrpRecorded = NULL;

   DigiDump(DIGIIOCTL, ("ASYN!IoSetBreak: PortNo=0x%x\n", pPortExt->port));

   if ( (BreakOn && (pPortExt->ioctl.state & BreakOnMask)) || 
        (!BreakOn && !(pPortExt->ioctl.state & BreakOnMask)) )
   {
      status = STATUS_SUCCESS;
      goto  IoctlExit;
   }

   
   
   if (BreakOn)
      pPortExt->ioctl.state |= BreakOnMask;
   else
      pPortExt->ioctl.state &= ~BreakOnMask;



	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);
	pIrp->IoStatus.Information = ++pPortExt->ioctl.sync;
	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);


/*
 *		Parag - TODO
 *		Add interface here fot Sxb interpreter
 *
 */


//	We get here after the SxB interpreter is done.









	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);
	if (pPortExt->ioctl.syncAck >= pIrp->IoStatus.Information)
		status = STATUS_SUCCESS;
	else
		status = STATUS_PENDING;


	if (status == STATUS_PENDING)
	{
		 InsertTailList(&pPortExt->ioctl.pendingQueue, &pIrp->Tail.Overlay.ListEntry);
		 IoMarkIrpPending(pIrp);
	}

		

	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

	
IoctlExit:

      return (status);
}



// PARAG TODO --- RETHINK this One



/*
 *----------------------------------------------------------------------
 * Function:  AsynIoSendChar.
 *
 * Purpose:
 *
 *    Sends a single character immediately.
 *
 *
 * Method:
 *
 *    o Mark associated IRP as Pending.
 *    o Hold the Port's Spin Lock.
 *    o Generate an S/DXB SEND_IMMED_CHAR command.
 *    o Release the Port's Spin Lock.
 *
 *
 * Returns:
 *
 *    o STATUS_PENDING is returned.
 *    o STATUS_INVALID_PARAMETER on Error.
 *
 *
 * Notes:
 *
 *    o When the DsPutMsgEx completion routine is called the IRP status is
 *      changed from PENDING to SUCCESS and the IRP is completed.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoSendChar(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Associated IRP
   IN ULONG             BufferSize,    // Input buffer size.
   IN PUCHAR            pChar          // Char to send
)
{
   NTSTATUS    status;                 // Call return value.


   DigiDump(DIGIIOCTL | DIGIIOCTL1 | DIGIALL, ("ASYN!IoSendChar: PortNo=0x%x\n", pPortExt->port));

   if (BufferSize < sizeof(*pChar))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      goto IoctlExit;
   }
   //
   // Illegal request when already processing an immediate character OR
   // a BREAK character write.
   //
   if ((pPortExt->ioctl.state & ImmWriteMask) || 
       (pPortExt->ioctl.state & BreakOnMask))
   {
       status = STATUS_INVALID_PARAMETER;
       goto IoctlExit;
   }


   pIrp->IoStatus.Information = 1;

   pPortExt->ioctl.state |= ImmWriteMask;
   pPortExt->ioctl.sendImmChar = *pChar;





	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);
	pIrp->IoStatus.Information = ++pPortExt->ioctl.sync;
	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);


/*
 *		Parag - TODO
 *		Add interface here fot Sxb interpreter
 *
 */


//	We get here after the SxB interpreter is done.
//
// BUGBUG - Check to see how ImmWrite is completed.
// Parag TODO -BUGBUG
//






	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);
	if (pPortExt->ioctl.syncAck >= pIrp->IoStatus.Information)
		status = STATUS_SUCCESS;
	else
		status = STATUS_PENDING;


	if (status == STATUS_PENDING)
		 InsertTailList(&pPortExt->ioctl.pendingQueue, &pIrp->Tail.Overlay.ListEntry);

		

	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

	
IoctlExit:

      return (status);
}




/*
 *----------------------------------------------------------------------
 * Function:  AsynIoSetTimeouts.
 *
 * Purpose:
 *
 *    Set the Timeout settings
 *
 *
 * Method:
 *
 *    o Set the timeout settings based on the supplied settings.
 *
 *
 * Returns:
 *
 *    o STATUS_SUCCESS is returned.
 *    o STATUS_BUFFER_TOO_SMALL on buffer too small.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoSetTimeouts(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Associated work order.
   IN ULONG             BufferSize,    // Output buffer size.
   IN PSERIAL_TIMEOUTS  pTimeouts      // Set these timeout values.
)
{
   NTSTATUS    status;                 // Call return value.

   DigiDump(DIGIIOCTL, ("ASYN!IoSetTimeouts: PortNo=0x%x\n", pPortExt->port));
   if (BufferSize < sizeof(*pTimeouts))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      goto  IoctlExit;
   }

	KeAcquireSpinLock(&pPortExt->portLock,&pPortExt->portIrql);
#ifdef DBG
   if ( (pTimeouts->ReadIntervalTimeout != pPortExt->timeoutValues.ReadIntervalTimeout) ||
        (pTimeouts->ReadTotalTimeoutMultiplier != pPortExt->timeoutValues.ReadTotalTimeoutMultiplier) ||
        (pTimeouts->ReadTotalTimeoutConstant != pPortExt->timeoutValues.ReadTotalTimeoutConstant) ||
        (pTimeouts->WriteTotalTimeoutMultiplier != pPortExt->timeoutValues.WriteTotalTimeoutMultiplier) ||
        (pTimeouts->WriteTotalTimeoutConstant != pPortExt->timeoutValues.WriteTotalTimeoutConstant) )
   {
      DigiDump(DIGITIMEOUT1, ("ASYN!IoSetTimeouts: PortNo=0x%x Read Int:0x%x Mul:0x%x Con:0x%x - Write Mul:0x%x Con:0x%x\n", 
                             pPortExt->port,
                             pTimeouts->ReadIntervalTimeout,
                             pTimeouts->ReadTotalTimeoutMultiplier,
                             pTimeouts->ReadTotalTimeoutConstant,
                             pTimeouts->WriteTotalTimeoutMultiplier,
                             pTimeouts->WriteTotalTimeoutConstant));
   }
#endif
   pPortExt->timeoutValues = *pTimeouts;
   KeReleaseSpinLock(&pPortExt->portLock,pPortExt->portIrql);

	

   status = STATUS_SUCCESS;

IoctlExit:
   pIrp->IoStatus.Information = 0;
   return (status);
}

/*
 *----------------------------------------------------------------------
 * Function:  AsynIoGetTimeouts.
 *
 * Purpose:
 *
 *    Get the Timeout settings
 *
 *
 * Method:
 *
 *    o Get the timeout settings based on the PortExt structure.
 *
 *
 * Returns:
 *
 *    o STATUS_SUCCESS is returned.
 *    o STATUS_BUFFER_TOO_SMALL on buffer too small.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoGetTimeouts(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Ioctl work to perform.
   IN ULONG             BufferSize,    // Output buffer size.
   OUT PSERIAL_TIMEOUTS pTimeouts      // return timeout values.
)

{
   NTSTATUS    status;                 // Call return value.

   DigiDump(DIGIIOCTL|DIGITIMEOUT, ("ASYN!IoGetTimeouts: PortNo=0x%x\n", pPortExt->port));

   if (BufferSize < sizeof(*pTimeouts))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      pIrp->IoStatus.Information = 0;
      goto  IoctlExit;
   }
   *pTimeouts = pPortExt->timeoutValues;
   pIrp->IoStatus.Information = sizeof(*pTimeouts);
   status = STATUS_SUCCESS;

IoctlExit:
   return (status);
}







/*
 *----------------------------------------------------------------------
 * Function:  AsynIoDtr.
 *
 * Purpose:
 *
 *    Set or Clear the DTR signal.
 *
 *
 * Method:
 *
 *    o Mark associated IRP as Pending.
 *    o Hold the Port's PortLock Lock.
 *    o Set or Clear the DTR signal.
 *
 *
 * Returns:
 *
 *    o STATUS_SUCCESS no signal change necessary.
 *    o STATUS_INVALID_PARAMETER on Error.
 *    o STATUS_PENDING attempting to change signal.
 *
 *
 * Notes:
 *
 *    o When an S/DXB response is received the IRP status is changed from
 *      PENDING to SUCCESS and the IRP is completed.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoDtr(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Associated IRP
   IN BOOLEAN           SetDtr         // TRUE for Set DTR
)
{
   
   NTSTATUS    status;                 // Call return value.
   PIRP        pIrpRecorded = NULL;

   DigiDump(DIGIIOCTL | DIGIIOCTL1, ("ASYN!IoDtr: PortNo=0x%x Dtr=%d\n", 
                         pPortExt->port, SetDtr));

	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);

   if ( (pPortExt->ioctl.handFlow.ControlHandShake & SERIAL_DTR_MASK) ==
         SERIAL_DTR_HANDSHAKE )
   {
      status = STATUS_INVALID_PARAMETER;
	  KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);
      goto IoctlExit;
   }
   if (SetDtr)
   {
         
      if ( (pPortExt->ioctl.Mout & SDXB_DTR) || 
         (pPortExt->ioctl.Mstat & SDXB_DTR))
      {
         pPortExt->ioctl.Mout |= SDXB_DTR;
         status = STATUS_SUCCESS;
		 KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);
         goto IoctlExit;
      }
   }
   else
   {
             
      if ( !(pPortExt->ioctl.Mout & SDXB_DTR) || 
         !(pPortExt->ioctl.Mstat & SDXB_DTR))
      {
         pPortExt->ioctl.Mout &= ~SDXB_DTR;
         status = STATUS_SUCCESS;
		 KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);
         goto IoctlExit;
      }
   }

   if (SetDtr)
   {
      pPortExt->ioctl.Mout |= SDXB_DTR;
      
   }
   else
   {
      pPortExt->ioctl.Mout &= ~SDXB_DTR;
      
   }
  
   
	pIrp->IoStatus.Information = ++pPortExt->ioctl.sync;
	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);


/*
 *		Parag - TODO
 *		Add interface here fot Sxb interpreter
 *
 */


//	We get here after the SxB interpreter is done.









	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);
	if (pPortExt->ioctl.syncAck >= pIrp->IoStatus.Information)
		status = STATUS_SUCCESS;
	else
		status = STATUS_PENDING;


	if (status == STATUS_PENDING)
	{
		 InsertTailList(&pPortExt->ioctl.pendingQueue, &pIrp->Tail.Overlay.ListEntry);
		 IoMarkIrpPending(pIrp);
	 }
		

	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

	
IoctlExit:

      return (status);
}








/*
 *----------------------------------------------------------------------
 * Function:  AsynIoResetDevice
 *
 * Purpose:
 *
 *    Reset the device, this has no meaning for serial ports.
 *
 *
 * Method:
 *
 *    o Just return
 *
 *
 * Returns:
 *
 *    o STATUS_SUCCESS
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoResetDevice( 
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp           // Associated IRP
   )
{
   NTSTATUS    status = STATUS_SUCCESS;

   DigiDump(DIGIIOCTL, ("ASYN!ResetDevice: Port=%d\n", pPortExt->port));

   pIrp->IoStatus.Information = 0;
   return (status);
}





/*
 *----------------------------------------------------------------------
 * Function:  AsynIoRts.
 *
 * Purpose:
 *
 *    Set or Clear the RTS signal.
 *
 *
 * Method:
 *
 *    o Mark associated IRP as Pending.
 *    o Hold the Port's PortLock Lock.
 *    o Set or Clear the RTS signal.
 *
 *
 * Returns:
 *
 *    o STATUS_SUCCESS no signal change necessary.
 *    o STATUS_INVALID_PARAMETER on Error.
 *    o STATUS_PENDING attempting to change signal.
 *
 *
 * Notes:
 *
 *    o When an S/DXB response is received the IRP status is changed from
 *      PENDING to SUCCESS and the IRP is completed.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoRts(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Associated IRP
   IN BOOLEAN           SetRts         // TRUE for Set RTS
)
{

      NTSTATUS    status;                 // Call return value.

   DigiDump(DIGIIOCTL | DIGIIOCTL1, ("ASYN!IoRts: PortNo=0x%x Rts=%d\n", 
                         pPortExt->port, SetRts));
   DigiDump(DIGIIOCTL | DIGIIOCTL1, ("ASYN!IoRts: HandShake=0x%x\n", 
                         pPortExt->ioctl.handFlow.ControlHandShake));

	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);

   if( (pPortExt->ioctl.handFlow.ControlHandShake & SERIAL_RTS_MASK) == 
            SERIAL_RTS_HANDSHAKE ||
       (pPortExt->ioctl.handFlow.ControlHandShake & SERIAL_RTS_MASK) == 
            SERIAL_TRANSMIT_TOGGLE )
   {
      DigiDump( DIGIIOCTL, ("ASYN!IoRts: Returning STATUS_INVALID_PARAMETER\n") );
      status = STATUS_INVALID_PARAMETER;
	  KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

      goto IoctlExit;
   }
   if (SetRts)
   {
                   
   
      if ( (pPortExt->ioctl.Mout & SDXB_RTS) || 
         (pPortExt->ioctl.Mstat & SDXB_RTS))
      {
         pPortExt->ioctl.Mout |= SDXB_RTS;
         status = STATUS_SUCCESS;
		 KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

         goto IoctlExit;
      }
   }
   else
   {
               
      if ( !(pPortExt->ioctl.Mout & SDXB_RTS) || 
         !(pPortExt->ioctl.Mstat & SDXB_RTS))
      {
         pPortExt->ioctl.Mout &= ~SDXB_RTS;
         status = STATUS_SUCCESS;
		 KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

         goto IoctlExit;
      }
   }
   if (SetRts)
   {
      pPortExt->ioctl.Mout |= SDXB_RTS;
     
   }
   else
   {
      pPortExt->ioctl.Mout &= ~SDXB_RTS;
      
   }



   	pIrp->IoStatus.Information = ++pPortExt->ioctl.sync;
	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);


/*
 *		Parag - TODO
 *		Add interface here fot Sxb interpreter
 *
 */


//	We get here after the SxB interpreter is done.



	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);
	if (pPortExt->ioctl.syncAck >= pIrp->IoStatus.Information)
		status = STATUS_SUCCESS;
	else
		status = STATUS_PENDING;


	if (status == STATUS_PENDING)
		 InsertTailList(&pPortExt->ioctl.pendingQueue, &pIrp->Tail.Overlay.ListEntry);

	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

	
IoctlExit:

      return (status);
}
  




/*
 *----------------------------------------------------------------------
 * Function:  AsynIoGetDtrRts
 *
 * Purpose:
 *
 *    Return the current DTR & RTS Modem Signals.
 *
 *
 * Method:
 *
 *    o Return the Port structure's DTR & RTS Mstat values.
 *
 *
 * Returns:
 *
 *    o STATUS_BUFFER_TOO_SMALL on buffer too small.
 *    o STATUS_SUCCESS is normally returned.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoGetDtrRts(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Associated IRP
   IN ULONG             BufferSize,    // Size of output buffer.
   OUT PULONG           pDtrRtsState   // Destination for modem status.
)
{
   NTSTATUS    status;                 // Call return value.

   DigiDump(DIGIIOCTL | DIGIIOCTL1, ("ASYN!IoGetDtrRts: PortNo=0x%x\n", pPortExt->port));

   if (BufferSize < sizeof(*pDtrRtsState))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      pIrp->IoStatus.Information = 0;
      goto  IoctlExit;
   }

   *pDtrRtsState = 0;

   KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);
   if (pPortExt->ioctl.Mstat & SDXB_DTR)
       *pDtrRtsState |= SERIAL_DTR_STATE;

   if (pPortExt->ioctl.Mstat & SDXB_RTS)
       *pDtrRtsState |= SERIAL_RTS_STATE;

	KeReleaseSpinLock( &pPortExt->ioctl.lock, pPortExt->ioctl.irql);

   pIrp->IoStatus.Information = sizeof(*pDtrRtsState);
   status = STATUS_SUCCESS;

IoctlExit:
   return (status);
}




/*
 *----------------------------------------------------------------------
 * Function:  AsynIoXonXoff.
 *
 * Purpose:
 *
 *    Simulate an Xon or an Xoff.
 *
 *
 * Method:
 *
 *    o Mark associated IRP as Pending.
 *    o Hold the Port's PortLock Lock.
 *    o Simulate an Xon or Xoff as appropriate.
 *
 *
 * Returns:
 *
 *    o STATUS_SUCCESS no signal change necessary.
 *    o STATUS_INVALID_PARAMETER on Error.
 *    o STATUS_PENDING attempting to change signal.
 *
 *
 * Notes:
 *
 *    o When an S/DXB response is received the IRP status is changed from
 *      PENDING to SUCCESS and the IRP is completed.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoXonXoff(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Associated IRP
   IN BOOLEAN           SimulateXon    // TRUE for Simulating Xon
)
{
   
   NTSTATUS    status;                 // Call return value.
   
  
   DigiDump(DIGIIOCTL, ("ASYN!IoXonXoff: PortNo=0x%x Xon=%d\n", 
                         pPortExt->port, SimulateXon));

	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);
    
   if (SimulateXon)
   {
      pPortExt->ioctl.Pset &= ~SDXB_OPS;
      pPortExt->ioctl.Preset |= SDXB_OPS;
 
   }
   else
   {
      pPortExt->ioctl.Pset |= SDXB_OPS;
      pPortExt->ioctl.Preset &= ~SDXB_OPS;
   }

  	pIrp->IoStatus.Information = ++pPortExt->ioctl.sync;
	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);


/*
 *		Parag - TODO
 *		Add interface here fot Sxb interpreter
 *
 */


//	We get here after the SxB interpreter is done.









	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);
	if (pPortExt->ioctl.syncAck >= pIrp->IoStatus.Information)
		status = STATUS_SUCCESS;
	else
		status = STATUS_PENDING;


	if (status == STATUS_PENDING)
	{
		 InsertTailList(&pPortExt->ioctl.pendingQueue, &pIrp->Tail.Overlay.ListEntry);
		 IoMarkIrpPending(pIrp);
	}

		

	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

	


      return (status);
}
  

  

/*
 *----------------------------------------------------------------------
 * Function:  AsynIoSetChars.
 *
 * Purpose:
 *
 *    Set the NT special characters.
 *
 *
 * Method:
 *
 *    o If the special characters have not changed; return.
 *    o Mark associated IRP as Pending.
 *    o Hold the Port's PortLock Lock.
 *    o Change the Special characters settings and convey to S/DXB.
 *    o Mark the end of setting Special characters with a SYNC cmd.
 *    o Release the Port's PortLock Lock.
 *
 *
 * Returns:
 *
 *    o STATUS_SUCCESS no change necessary.
 *    o STATUS_BUFFER_TOO_SMALL on supplied buffer is too small.
 *    o STATUS_INVALID_PARAMETER on Error.
 *    o STATUS_PENDING attempting to change characters in S/DXB.
 *
 *
 * Notes:
 *
 *    o When an S/DXB SYNC response is received the IRP status is changed from
 *      PENDING to SUCCESS and the IRP is completed.
 *
 *
 *----------------------------------------------------------------------
 */								 
static NTSTATUS
AsynIoSetChars(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Ioctl request to perform.
   IN ULONG             BufferSize,    // Input buffer size.
   IN PSERIAL_CHARS     pChars         // Eof Error Break Event Xon Xoff
)
{

	NTSTATUS    status;                 // Call return value.
   
   DigiDump(DIGIIOCTL, ("ASYN!IoSetChars: PortNo=0x%x\n", pPortExt->port));

   if (BufferSize < sizeof(*pChars))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      goto IoctlExit;
   }
   if ((pChars->XonChar == pChars->XoffChar) && (pChars->XonChar != 0))
   {
      status = STATUS_INVALID_PARAMETER;
      goto IoctlExit;
   }

  
   //
   // Do not allow a null character to be BOTH the xon and the xoff character.
   //
   if (( pChars->XonChar == pChars->XoffChar) && (pChars->XonChar == 0))
   {
      status = STATUS_SUCCESS;
      goto IoctlExit;
   }

   //
   // Have the special characters changed?
   //

	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);

   if ( (pChars->XonChar == pPortExt->ioctl.specialChars.XonChar) &&
        (pChars->XoffChar == pPortExt->ioctl.specialChars.XoffChar) &&
        (pChars->ErrorChar == pPortExt->ioctl.specialChars.ErrorChar) &&
        (pChars->BreakChar == pPortExt->ioctl.specialChars.BreakChar) &&
        (pChars->EventChar == pPortExt->ioctl.specialChars.EventChar) )
   {
      // Pickup Eof, even though we currently don't do anything with it.
      pPortExt->ioctl.specialChars = *pChars;
      status = STATUS_SUCCESS;
	  KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);
      goto IoctlExit;
   }

      //
   // Parity/Framing error replacement char
   //
   if (pPortExt->ioctl.handFlow.FlowReplace & SERIAL_ERROR_CHAR)
   {
      pPortExt->ioctl.Xflags |= SDXB_XMSERC;
      pPortExt->ioctl.Xflags &= ~SDXB_XEDATA;
   }
   else
   {
      pPortExt->ioctl.Xflags &= ~SDXB_XMSERC;
      pPortExt->ioctl.Xflags |= SDXB_XEDATA;
   }

   //
   // Break replacement char
   //
   if (pPortExt->ioctl.handFlow.FlowReplace & SERIAL_ERROR_BREAK)
   {
      pPortExt->ioctl.Xflags |= SDXB_XMSBRC;
   }
   else
   {
      pPortExt->ioctl.Xflags &= ~SDXB_XMSBRC;
   }

   //
   // We need to tell S/DXB about the new characters.
   //
   pPortExt->ioctl.specialChars = *pChars;

   
	pIrp->IoStatus.Information = ++pPortExt->ioctl.sync;
	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);


/*
 *		Parag - TODO
 *		Add interface here fot Sxb interpreter
 *
 */


//	We get here after the SxB interpreter is done.







	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);


   	if (pPortExt->ioctl.syncAck >= pIrp->IoStatus.Information)
		status = STATUS_SUCCESS;
	else
		status = STATUS_PENDING;


	if (status == STATUS_PENDING)
	{
		 InsertTailList(&pPortExt->ioctl.pendingQueue, &pIrp->Tail.Overlay.ListEntry);
		 IoMarkIrpPending(pIrp);
	}

		

	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

	
IoctlExit:

      return (status);
}
  


/*
 *----------------------------------------------------------------------
 * Function:  AsynIoGetChars
 *
 * Purpose:
 *
 *    Return the current special characters.
 *
 *
 * Method:
 *
 *    o Return the current special characters.
 *
 *
 * Returns:
 *
 *    o STATUS_BUFFER_TOO_SMALL on buffer too small.
 *    o STATUS_SUCCESS is normally returned.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoGetChars(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Ioctl work to perform.
   IN ULONG             BufferSize,    // Size of output buffer.
   OUT PSERIAL_CHARS    pChars         // Special characters
)
{
   NTSTATUS    status;                 // Call return value.

   DigiDump(DIGIIOCTL, ("ASYN!IoGetChars: PortNo=0x%x\n", pPortExt->port));

   if (BufferSize < sizeof(*pChars))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      pIrp->IoStatus.Information = 0;
      goto IoctlExit;
   }
   *pChars = pPortExt->ioctl.specialChars;
   pIrp->IoStatus.Information = sizeof(*pChars);
   status = STATUS_SUCCESS;

IoctlExit:
   return (status);
}



/*
 *----------------------------------------------------------------------
 * Function:  AsynIoSetHandflow.
 *
 * Purpose:
 *
 *    Set the handshaking and flow control parameters.
 *
 *
 * Method:
 *
 *    o Sanity check the handshake and flow control parameters.
 *    o If the special characters have not changed; return.
 *    o Hold the Port's PortLock Lock.
 *    o Mark associated IRP as Pending.
 *    o Change the Handshaking and flow control settings and convey to S/DXB.
 *    o Mark the end of setting Special characters with a SYNC cmd.
 *    o Release the Port's PortLock Lock.
 *
 *
 * Returns:
 *
 *    o STATUS_SUCCESS no change necessary.
 *    o STATUS_BUFFER_TOO_SMALL on supplied buffer is too small.
 *    o STATUS_INVALID_PARAMETER on Error.
 *    o STATUS_PENDING attempting to change characters in S/DXB.
 *
 *
 * Notes:
 *
 *    o When an S/DXB SYNC response is received the IRP status is changed from
 *      PENDING to SUCCESS and the IRP is completed.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoSetHandflow(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Ioctl request to perform.
   IN ULONG             BufferSize,    // Input buffer size.
   IN PSERIAL_HANDFLOW  pHandflow      // Handshaking and Flow control.
)
{
  
   NTSTATUS    status = STATUS_SUCCESS;// Call return value.
   USHORT      Iflags;                 // New iflags value.
   UCHAR       Mflow;                  // Modem flow control.
   UCHAR       Mout;                   // Modem signals.
   BOOLEAN     BuildPortParam = FALSE;
   BOOLEAN     BuildModemCtrl = FALSE;
   ULONG       ProposedFlow, ProposedHandshake;
   ULONG       CurrentFlow, CurrentHandshake;
   PIRP        pIrpRecorded = NULL;

   DigiDump(DIGIIOCTL, ("ASYN!IoSetHandflow: PortNo=0x%x\n", pPortExt->port));

   if (BufferSize < sizeof(*pHandflow))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      goto IoctlExit;
   }

	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);
   if ((pHandflow->ControlHandShake & SERIAL_CONTROL_INVALID) ||
      ((pHandflow->ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_MASK) ||
      (pHandflow->FlowReplace & SERIAL_FLOW_INVALID) ||

      //
      // Insure sane Xon/Xoff limits.
      //
      (pHandflow->XonLimit < 0) || (pHandflow->XoffLimit < 0) ||

      //
      // Don't allow NT's error replacement AND line/modem status insertion.
      //
      ((pPortExt->ioctl.escapeChar) && (pHandflow->FlowReplace & SERIAL_ERROR_CHAR)))
   {
      status = STATUS_INVALID_PARAMETER;
	  KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

      goto IoctlExit;
   }

  
      // Make life a little easier by assigning some shorthand variables.
   ProposedHandshake = pHandflow->ControlHandShake;
   CurrentHandshake = pPortExt->ioctl.handFlow.ControlHandShake;
   ProposedFlow = pHandflow->FlowReplace;
   CurrentFlow = pPortExt->ioctl.handFlow.FlowReplace;

   DigiDump(DIGIIOCTL, ("ASYN!IoSetHandflow: newHand=0x%x curHand=0x%x\n", 
                        ProposedHandshake, CurrentHandshake));
   DigiDump(DIGIIOCTL, ("ASYN!IoSetHandflow: newFlow=0x%x curFlow=0x%x\n", 
                        ProposedFlow, CurrentFlow));
   //
   // Is a PORT-PARAM-CMD necessary ?
   //
   if ( ((ProposedHandshake & SERIAL_DTR_MASK & SERIAL_DTR_HANDSHAKE) !=
          (CurrentHandshake & SERIAL_DTR_MASK & SERIAL_DTR_HANDSHAKE)) ||
        ((ProposedFlow & SERIAL_RTS_MASK & SERIAL_RTS_HANDSHAKE) !=
          (CurrentFlow & SERIAL_RTS_MASK & SERIAL_RTS_HANDSHAKE)) ||
        ((ProposedHandshake & SERIAL_OUT_HANDSHAKEMASK) !=
          (CurrentHandshake & SERIAL_OUT_HANDSHAKEMASK)) ||
        ((ProposedFlow & SERIAL_AUTO_TRANSMIT) !=
          (CurrentFlow & SERIAL_AUTO_TRANSMIT)) ||
        ((ProposedFlow & SERIAL_AUTO_RECEIVE) !=
          (CurrentFlow & SERIAL_AUTO_RECEIVE)) ||
        ((ProposedFlow & SERIAL_ERROR_CHAR) !=
          (CurrentFlow & SERIAL_ERROR_CHAR))  ||
        ((ProposedFlow & SERIAL_NULL_STRIPPING) !=
          (CurrentFlow & SERIAL_NULL_STRIPPING)) 
	)
   {
      BuildPortParam = TRUE;
   }

   //
   // Is a MODEM-CTRL-CMD necessary ?
   //
   if ( ((ProposedHandshake & SERIAL_DTR_MASK & SERIAL_DTR_CONTROL) !=
          (CurrentHandshake & SERIAL_DTR_MASK & SERIAL_DTR_CONTROL)) ||
        ((ProposedFlow & SERIAL_RTS_MASK & SERIAL_RTS_CONTROL) !=
          (CurrentFlow & SERIAL_RTS_MASK & SERIAL_RTS_CONTROL)) )
   {
      BuildModemCtrl = TRUE;
   }
   if ( !BuildPortParam && !BuildModemCtrl)
   {
		KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

      // Nothing to do, we can leave
	    goto IoctlExit;
   }

   //
   // Save the new values
   //
   pPortExt->ioctl.handFlow.ControlHandShake = ProposedHandshake;
   pPortExt->ioctl.handFlow.FlowReplace = ProposedFlow;

   
   //
   // Update the Port settings
   //
   Mflow = 0;
   // Preserve setting which are not being changed.
   Mout = pPortExt->ioctl.Mout;

   Iflags = pPortExt->ioctl.Iflags & ~(SDXB_IXON | SDXB_IXOFF);
   if ((ProposedFlow & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE)
   {
      Mflow |= SDXB_RTS;
   }
   else if ((ProposedFlow & SERIAL_RTS_MASK) == SERIAL_RTS_CONTROL)
   {
      Mout |= SDXB_RTS;
   }

   if ((ProposedHandshake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE)
   {
      Mflow |= SDXB_DTR;
   }
   else if ((ProposedHandshake & SERIAL_DTR_MASK) == SERIAL_DTR_CONTROL)
   {
      Mout |= SDXB_DTR;
   }

   if (ProposedHandshake & SERIAL_CTS_HANDSHAKE)
   {
      Mflow |= SDXB_CTS;
   }

   if (ProposedHandshake & SERIAL_DSR_HANDSHAKE)
   {
      Mflow |= SDXB_DSR;
   }

   if (ProposedHandshake & SERIAL_DCD_HANDSHAKE)
   {
      Mflow |= SDXB_DCD;
   }

   //
   // Turn on software flow control for transmit.
   //
   if (ProposedFlow & SERIAL_AUTO_TRANSMIT)
   {
      Iflags |= SDXB_IXON;
   }

   //
   // Turn on software flow control for receive.
   //
   if (ProposedFlow & SERIAL_AUTO_RECEIVE)
   {
      Iflags |= SDXB_IXOFF;
   }
   //
   // Parity/Framing error replacement char
   //
   if (ProposedFlow & SERIAL_ERROR_CHAR)
   {
      pPortExt->ioctl.Xflags |= SDXB_XMSERC;
      pPortExt->ioctl.Xflags &= ~SDXB_XEDATA;
   }
   else
   {
      pPortExt->ioctl.Xflags &= ~SDXB_XMSERC;
      pPortExt->ioctl.Xflags |= SDXB_XEDATA;
   }
   //
   // Break replacement char
   //
   if (pPortExt->ioctl.handFlow.FlowReplace & SERIAL_ERROR_BREAK)
   {
      pPortExt->ioctl.Xflags |= SDXB_XMSBRC;
   }
   else
   {
      pPortExt->ioctl.Xflags &= ~SDXB_XMSBRC;
   }
   
	//
	// strip NULLs
	//
   if (ProposedFlow & SERIAL_NULL_STRIPPING) {
		pPortExt->ioctl.Xflags |= SDXB_XSTRIP;
	}
	else {
		pPortExt->ioctl.Xflags &= ~SDXB_XSTRIP;
	}
	   
   pPortExt->ioctl.Mflow = Mflow;
   pPortExt->ioctl.Mout = Mout;
   pPortExt->ioctl.Iflags = Iflags;



/*
 *	We might need to send two  requests to the sDxb interpreter
 */   	

   if (BuildPortParam)
   {

	pIrp->IoStatus.Information = ++pPortExt->ioctl.sync;
	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);


/*
 *		Parag - TODO
 *		Add interface here fot Sxb interpreter
 *
 */


//	We get here after the SxB interpreter is done.







	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);



	}
         
   if (BuildModemCtrl)
   {

		pIrp->IoStatus.Information = ++pPortExt->ioctl.sync;
		KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);


/*
 *		Parag - TODO
 *		Add interface here fot Sxb interpreter
 *
 */


//	We get here after the SxB interpreter is done.







		KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);

	}



	

   	if (pPortExt->ioctl.syncAck >= pIrp->IoStatus.Information)
		status = STATUS_SUCCESS;
	else
		status = STATUS_PENDING;


	if (status == STATUS_PENDING)
	{
		 InsertTailList(&pPortExt->ioctl.pendingQueue, &pIrp->Tail.Overlay.ListEntry);
		 IoMarkIrpPending(pIrp);
	}

		

	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

	
IoctlExit:

      return (status);
}
  



/*
 *----------------------------------------------------------------------
 * Function:  AsynIoGetHandflow
 *
 * Purpose:
 *
 *    Return the handshaking and flow control parameters.
 *
 *
 * Method:
 *
 *    o Return the handshaking and flow control parameters.
 *
 *
 * Returns:
 *
 *    o STATUS_BUFFER_TOO_SMALL on buffer too small.
 *    o STATUS_SUCCESS is normally returned.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoGetHandflow(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Ioctl work to perform.
   IN ULONG             BufferSize,    // Size of output buffer.
   OUT PSERIAL_HANDFLOW pHandflow      // Flow control and handshaking.
)
{
   NTSTATUS    status;                 // Call return value.

   DigiDump(DIGIIOCTL, ("ASYN!IoGetHandflow: PortNo=0x%x\n", pPortExt->port));

   if (BufferSize < sizeof(*pHandflow))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      pIrp->IoStatus.Information = 0;
      goto IoctlExit;
   }

   *pHandflow = pPortExt->ioctl.handFlow;

   pIrp->IoStatus.Information = sizeof(*pHandflow);
   status = STATUS_SUCCESS;

IoctlExit:
   return (status);
}

/*
 *----------------------------------------------------------------------
 * Function:  AsynIoGetModemStatus
 *
 * Purpose:
 *
 *    Return the current Modem Signals.
 *
 *
 * Method:
 *
 *    o Return the Port structure's Mstat values.
 *
 *
 * Returns:
 *
 *    o STATUS_BUFFER_TOO_SMALL on buffer too small.
 *    o STATUS_SUCCESS is normally returned.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoGetModemStatus(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Ioctl work to perform.
   IN ULONG             BufferSize,    // Size of output buffer.
   OUT PULONG           pModemStatus   // Destination for modem status.
)
{
   NTSTATUS    status;                 // Call return value.

   DigiDump(DIGIIOCTL | DIGIIOCTL1, ("ASYN!IoGetModemStatus: PortNo=0x%x ", pPortExt->port));

   if (BufferSize < sizeof(*pModemStatus))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      pIrp->IoStatus.Information = 0;
      goto IoctlExit;
   }

   *pModemStatus = 0;

   if (pPortExt->ioctl.Mstat & SDXB_CTS)
       *pModemStatus |= SERIAL_CTS_STATE;

   if (pPortExt->ioctl.Mstat & SDXB_DSR)
       *pModemStatus |= SERIAL_DSR_STATE;

   if (pPortExt->ioctl.Mstat & SDXB_RI)
       *pModemStatus |= SERIAL_RI_STATE;

   if (pPortExt->ioctl.Mstat & SDXB_DCD)
       *pModemStatus |= SERIAL_DCD_STATE;

   DigiDump(DIGIIOCTL | DIGIIOCTL1, ("State=0x%x\n", *pModemStatus));

   pIrp->IoStatus.Information = sizeof(*pModemStatus);
   status = STATUS_SUCCESS;

IoctlExit:
   return (status);
}


/*
 *----------------------------------------------------------------------
 * Function:  AsynIoGetCommStatus
 *
 * Purpose:
 *
 *    Return the most recent comm status.
 *
 *
 * Method:
 *
 *    o Return the Port structure's Communications status.
 *
 *
 * Returns:
 *
 *    o STATUS_BUFFER_TOO_SMALL on buffer too small.
 *    o STATUS_SUCCESS is normally returned.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoGetCommStatus(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Associated request.
   IN ULONG             BufferSize,    // Size of output buffer.
   OUT PSERIAL_STATUS   pCommStatus    // Destination for Comm status.
)
{
   NTSTATUS    status;                 // Call return value.
   

   DigiDump(DIGIIOCTL | DIGIIOCTL1, ("ASYN!IoGetCommStatus: PortNo=0x%x ", pPortExt->port));

   if (BufferSize < sizeof(*pCommStatus))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      pIrp->IoStatus.Information = 0;
      goto IoctlExit;
   }

   pCommStatus->Errors = 0;

   if (pPortExt->commErr.Break)
   {
      pPortExt->commErr.Break = 0;
      pCommStatus->Errors |= SERIAL_ERROR_BREAK;
   }
   if (pPortExt->commErr.Framing)
   {
      pPortExt->commErr.Framing = 0;
      pCommStatus->Errors |= SERIAL_ERROR_FRAMING;
   }
   if (pPortExt->commErr.Overrun)
   {
      pPortExt->commErr.Overrun = 0;
      pCommStatus->Errors |= SERIAL_ERROR_OVERRUN;
   }
   if (pPortExt->commErr.Parity)
   {
      pPortExt->commErr.Parity = 0;
      pCommStatus->Errors |= SERIAL_ERROR_PARITY;
   }
   pCommStatus->HoldReasons = 0;
   if ((pPortExt->ioctl.handFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE) &&
       !(pPortExt->ioctl.Mstat & SDXB_CTS))
   {
      pCommStatus->HoldReasons |= SERIAL_TX_WAITING_FOR_CTS;
   }
   if ((pPortExt->ioctl.handFlow.ControlHandShake & SERIAL_DSR_HANDSHAKE) &&
       !(pPortExt->ioctl.Mstat & SDXB_DSR))
   {
      pCommStatus->HoldReasons |= SERIAL_TX_WAITING_FOR_DSR;
   }
   if ((pPortExt->ioctl.handFlow.ControlHandShake & SERIAL_DCD_HANDSHAKE) &&
       !(pPortExt->ioctl.Mstat & SDXB_DCD))
   {
      pCommStatus->HoldReasons |= SERIAL_TX_WAITING_FOR_DCD;
   }
   if (pPortExt->Estat & SDXB_TXF)
   {
      pCommStatus->HoldReasons |= SERIAL_TX_WAITING_FOR_XON;
   }

   if (pPortExt->Estat & (SDXB_OPS | SDXB_OPH) )
   {
      pCommStatus->HoldReasons |= SERIAL_TX_WAITING_XOFF_SENT;
   }
   if ((pPortExt->WaitMask & SERIAL_EV_BREAK) &&
       (pPortExt->Estat & SDXB_TXB))
   {
      pCommStatus->HoldReasons |= SERIAL_TX_WAITING_ON_BREAK;
   }

   pCommStatus->AmountInInQueue = pPortExt->TotalRxBytesBuffered;
   pCommStatus->AmountInOutQueue = pPortExt->TxBytesPending;


	   //
   // Must include the immediate char (out of band data) in this
   // calculation.
   //
   if (pPortExt->ioctl.state & ImmWriteMask)
   {
      pCommStatus->AmountInOutQueue++;
      pCommStatus->WaitForImmediate = TRUE;
   }
   else
   {
      pCommStatus->WaitForImmediate = FALSE;
   }

   pPortExt->LerrFlags = SDXB_CLEAR;

   //
   // Clear the line error statistics with SDXB_LERR,
   // but only if our SDXB_COUNT isn't too high
   //

   
   pCommStatus->EofReceived = FALSE;

   DigiDump(DIGIIOCTL | DIGIIOCTL1, ("InQ=%d OutQ=%d Hold=0x%x Errors=0x%x\n", 
      pCommStatus->AmountInInQueue, pCommStatus->AmountInOutQueue, 
      pCommStatus->HoldReasons, pCommStatus->Errors));

   pIrp->IoStatus.Information = sizeof(*pCommStatus);
   status = STATUS_SUCCESS;

IoctlExit:
   return (status);
}

/*
 *----------------------------------------------------------------------
 * Function:  AsynIoGetProperties
 *
 * Purpose:
 *
 *    Return the Port capabilities.
 *
 *
 * Method:
 *
 *    o Provide all possible baud rates and configurations.
 *
 *
 * Returns:
 *
 *    o STATUS_BUFFER_TOO_SMALL on buffer too small.
 *    o STATUS_SUCCESS is normally returned.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoGetProperties(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Associated request.
   IN ULONG             BufferSize,    // Size of output buffer.
   OUT PSERIAL_COMMPROP pProperties    // Destination for Comm Properties.
)
{
   NTSTATUS    status;                 // Call return value.

   DigiDump(DIGIIOCTL | DIGIIOCTL1, ("ASYN!IoGetProperties: PortNo=0x%x\n", 
         pPortExt->port));

   if (BufferSize < sizeof(*pProperties))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      pIrp->IoStatus.Information = 0;
      goto IoctlExit;
   }

   RtlZeroMemory( pProperties, sizeof(*pProperties));

   pProperties->PacketLength = sizeof(*pProperties);
   pProperties->PacketVersion = 2;
   pProperties->ServiceMask = SERIAL_SP_SERIALCOMM;
   pProperties->Reserved1 = 0;

   pProperties->MaxTxQueue = pPortExt->writeObj.tsize;

//PARAG - TODO - Talk to Sandy
//	pProperties->MaxRxQueue = pPortExt->readObj.rsize;

   pProperties->CurrentTxQueue = pPortExt->writeObj.tsize;
//PARAG - TODO - Talk to Sandy
//   pProperties->CurrentRxQueue = pPortExt->rsize;

   pProperties->SettableBaud = 0;

   pProperties->MaxBaud = SERIAL_BAUD_USER;

   pProperties->ProvSubType = SERIAL_SP_RS232;
   pProperties->ProvCapabilities = SERIAL_PCF_DTRDSR |
                                   SERIAL_PCF_RTSCTS |
                                   SERIAL_PCF_CD     |
                                   SERIAL_PCF_PARITY_CHECK |
                                   SERIAL_PCF_XONXOFF |
                                   SERIAL_PCF_SETXCHAR |
                                   SERIAL_PCF_TOTALTIMEOUTS |
                                   SERIAL_PCF_INTTIMEOUTS |
                                   SERIAL_PCF_SPECIALCHARS;

   pProperties->SettableParams = SERIAL_SP_PARITY |
                                 SERIAL_SP_BAUD |
                                 SERIAL_SP_DATABITS |
                                 SERIAL_SP_STOPBITS |
                                 SERIAL_SP_HANDSHAKING |
                                 SERIAL_SP_PARITY_CHECK |
                                 SERIAL_SP_CARRIER_DETECT;

   pProperties->SettableBaud |= SERIAL_BAUD_075 |
                                SERIAL_BAUD_110 |
                                SERIAL_BAUD_134_5 |
                                SERIAL_BAUD_150 |
                                SERIAL_BAUD_300 |
                                SERIAL_BAUD_600 |
                                SERIAL_BAUD_1200 |
                                SERIAL_BAUD_1800 |
                                SERIAL_BAUD_2400 |
                                SERIAL_BAUD_4800 |
                                SERIAL_BAUD_7200 |
                                SERIAL_BAUD_9600 |
                                SERIAL_BAUD_14400 |
                                SERIAL_BAUD_19200 |
                                SERIAL_BAUD_38400 |
                                SERIAL_BAUD_57600 |
                                SERIAL_BAUD_115200 |
                                SERIAL_BAUD_USER;

   pProperties->SettableData = SERIAL_DATABITS_5 |
                               SERIAL_DATABITS_6 |
                               SERIAL_DATABITS_7 |
                               SERIAL_DATABITS_8;

   pProperties->SettableStopParity = SERIAL_STOPBITS_10 |
                                     SERIAL_STOPBITS_15 |
                                     SERIAL_STOPBITS_20 |
                                     SERIAL_PARITY_NONE |
                                     SERIAL_PARITY_ODD  |
                                     SERIAL_PARITY_EVEN |
                                     SERIAL_PARITY_MARK |
                                     SERIAL_PARITY_SPACE;

   pIrp->IoStatus.Information = sizeof(*pProperties);
   status = STATUS_SUCCESS;

IoctlExit:
   return (status);
}


/*
 *----------------------------------------------------------------------
 * Function:  AsynIoLsrmstInsert
 *
 * Purpose:
 *
 *    Establish NT's error reporting escape character; similar to Digi's
 *    DOSMODE implementation.
 *
 *
 * Method:
 *
 *    o Send the updated notification events to the PortServer.
 *
 *
 * Returns:
 *
 *    o STATUS_BUFFER_TOO_SMALL on buffer too small.
 *    o STATUS_SUCCESS is normally returned.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoLsrmstInsert( 
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Associated request.
   IN ULONG             BufferSize,    // Size of input buffer.
   OUT PUCHAR           pEscapeChar    // Escape character to use.
)
{
   NTSTATUS    status;        // Call return value.

   DigiDump(DIGIIOCTL, ("ASYN!IoLsrmstInsert: PortNo=0x%x\n", pPortExt->port));

   if (BufferSize < sizeof(*pEscapeChar))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      goto IoctlExit;
   }

	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);
   if (*pEscapeChar)
   {
       if ((*pEscapeChar == pPortExt->ioctl.specialChars.XoffChar) ||
           (*pEscapeChar == pPortExt->ioctl.specialChars.XonChar) ||
           (pPortExt->ioctl.handFlow.FlowReplace & SERIAL_ERROR_CHAR))
       {
          status = STATUS_INVALID_PARAMETER;
		  KeReleaseSpinLock( &pPortExt->ioctl.lock, pPortExt->ioctl.irql);
          goto IoctlExit;

       }
   }

   
   //
   // We need to tell S/DXB about the new escape character.
   //


   //
   // Update the Port settings
   //
   if (*pEscapeChar)
   {
      pPortExt->ioctl.Xflags |= SDXB_XMSPAR | SDXB_XMODEM;
      pPortExt->ioctl.Iflags |= SDXB_PARMRK;

      // Turn off errored-data-placed-in-input-stream-without-modification
      pPortExt->ioctl.Xflags &= ~SDXB_XEDATA;
   }
   else
   {
      pPortExt->ioctl.Xflags &= ~(SDXB_XMSPAR | SDXB_XMODEM);
      pPortExt->ioctl.Iflags &= ~SDXB_PARMRK;

      // Turn on errored-data-placed-in-input-stream-without-modification
      if (!(pPortExt->ioctl.Xflags & (SDXB_XMSPAR | SDXB_XMSERC))) {
         pPortExt->ioctl.Xflags |= SDXB_XEDATA;
      }
   }
   pPortExt->ioctl.escapeChar = *pEscapeChar;
   pPortExt->ioctl.specialChars.BreakChar = *pEscapeChar;



	pIrp->IoStatus.Information = ++pPortExt->ioctl.sync;
	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);


/*
 *		Parag - TODO
 *		Add interface here fot Sxb interpreter
 *
 */


//	We get here after the SxB interpreter is done.







	KeAcquireSpinLock( &pPortExt->ioctl.lock, &pPortExt->ioctl.irql);


   	if (pPortExt->ioctl.syncAck >= pIrp->IoStatus.Information)
		status = STATUS_SUCCESS;
	else
		status = STATUS_PENDING;


	if (status == STATUS_PENDING)
	{
		 InsertTailList(&pPortExt->ioctl.pendingQueue, &pIrp->Tail.Overlay.ListEntry);
		 IoMarkIrpPending(pIrp);
	}

		

	KeReleaseSpinLock(&pPortExt->ioctl.lock, pPortExt->ioctl.irql);

	
IoctlExit:

      return (status);
}
  













    
/*
 *----------------------------------------------------------------------
 * Function:  AsynIoConfigSize
 *
 * Purpose:
 *
 *    Return the Config Size
 *
 *
 * Method:
 *
 *    o Return zero.
 *
 *
 * Returns:
 *
 *    o STATUS_BUFFER_TOO_SMALL on buffer too small.
 *    o STATUS_SUCCESS is normally returned.
 *
 *
 *----------------------------------------------------------------------
 */
static NTSTATUS
AsynIoConfigSize(
   IN PPORT_EXT         pPortExt,      // Port specific information.
   IN PIRP              pIrp,          // Associated request.
   IN ULONG             BufferSize,    // Size of output buffer.
   OUT PULONG           pConfigSize    // Destination for Config Size.
)
{
   NTSTATUS    status = STATUS_SUCCESS;   // Call return value.

   DigiDump(DIGIIOCTL, ("ASYN!IoConfigSize: PortNo=0x%x\n", pPortExt->port));

   if (BufferSize < sizeof(*pConfigSize))
   {
      status = STATUS_BUFFER_TOO_SMALL;
      pIrp->IoStatus.Information = 0;
      goto IoctlExit;
   }
   pIrp->IoStatus.Information = sizeof(ULONG);
   pIrp->IoStatus.Status = STATUS_SUCCESS;

   *pConfigSize = 0;

IoctlExit:
   return (status);
}




/*
 *----------------------------------------------------------------------
 * Function:   AsynIoctl.
 *
 * Purpose:
 *
 *    Perform the IOCTL operation.
 *
 *
 * Method:
 *
 *    o Perform the decode of the IOCTL and call the appropriate function.
 *    o If a DsPutMsgEx is necessary, then mark the IRP as Pending BEFORE
 *      calling DsPutMsgEx.  This is to allow for the case of the PutMsg
 *      completion routine being called in-line and the completion routine
 *      completing the IRP.  Thus when we return from DsPutMsgEx the IRP may
 *      have already completed.
 *
 *
 * Returns:
 *
 *    o Status of the IOCTL result is returned.
 *
 *
 * NOTE:
 *    o If a status other than STATUS_PENDING is returned, the calling
 *      routine will complete the IRP.
 *----------------------------------------------------------------------
 */
NTSTATUS
AsynProcessIoctl(
   IN PPORT_EXT   pPortExt,      // Port specific information.
   IN PIRP        pIrp           // Write request to perform.
)
{
   NTSTATUS       status;        // Called function return value.
   PIO_STACK_LOCATION      pIrpSp;        // Current IRP stack position.

   pIrpSp = IoGetCurrentIrpStackLocation(pIrp);

   // Unfortunately the "Parameters.DeviceIoControl" field is not a defined
   // struct type, thus we use a "#define" instead of a variable.
#define PDEVIO      (pIrpSp->Parameters.DeviceIoControl)

   DigiDump( DIGIIOCTL, ("ASYN!Ioctl: Code req=0x%x\n", PDEVIO.IoControlCode));


   switch (PDEVIO.IoControlCode)
   {
      
      case IOCTL_SERIAL_SET_BAUD_RATE:
         status = 
            AsynIoSetBaudRate( pPortExt, pIrp, PDEVIO.InputBufferLength,
                               (PSERIAL_BAUD_RATE)pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_GET_BAUD_RATE:

         status = 							 
            AsynIoGetBaudRate( pPortExt, pIrp, PDEVIO.OutputBufferLength,
                               (PSERIAL_BAUD_RATE)pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_SET_QUEUE_SIZE:
         DigiDump( DIGIIOCTL, ("ASYN!Ioctl: SET_QUEUE_SIZE Port=%d In=0x%x Out=0x%x\n", 
                  pPortExt->port, 
                  ((PSERIAL_QUEUE_SIZE)pIrp->AssociatedIrp.SystemBuffer)->InSize,
                  ((PSERIAL_QUEUE_SIZE)pIrp->AssociatedIrp.SystemBuffer)->OutSize));
         if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
             sizeof(SERIAL_QUEUE_SIZE))
         {
            status = STATUS_BUFFER_TOO_SMALL;
         }
         else
         {
            status = STATUS_SUCCESS;
         }
         break;

      case IOCTL_SERIAL_SET_LINE_CONTROL:
         status = 
            AsynIoSetLineControl( pPortExt, pIrp, PDEVIO.InputBufferLength,
                                  (PSERIAL_LINE_CONTROL)pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_GET_LINE_CONTROL:
         status = AsynIoGetLineControl( pPortExt, pIrp, PDEVIO.OutputBufferLength,
                                        (PSERIAL_LINE_CONTROL)
                                          pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_SET_BREAK_ON:
         status = AsynIoSetBreak( pPortExt, pIrp, TRUE);
         break;

      case IOCTL_SERIAL_SET_BREAK_OFF:
         status = AsynIoSetBreak( pPortExt, pIrp, FALSE);
         break;
      
      case IOCTL_SERIAL_IMMEDIATE_CHAR:
         status = AsynIoSendChar( pPortExt, pIrp, PDEVIO.InputBufferLength,
                                  pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_SET_TIMEOUTS:
         status = AsynIoSetTimeouts( pPortExt, pIrp, PDEVIO.InputBufferLength,
                                     (PSERIAL_TIMEOUTS)pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_GET_TIMEOUTS:
         status = AsynIoGetTimeouts( pPortExt, pIrp, PDEVIO.OutputBufferLength,
                                     (PSERIAL_TIMEOUTS)pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_SET_DTR:
         status = AsynIoDtr( pPortExt, pIrp, TRUE);
         break;

      case IOCTL_SERIAL_CLR_DTR:
         status = AsynIoDtr( pPortExt, pIrp, FALSE);
         break;

      case IOCTL_SERIAL_RESET_DEVICE:
         status = AsynIoResetDevice( pPortExt, pIrp);
         break;

      case IOCTL_SERIAL_SET_RTS:
         status = AsynIoRts( pPortExt, pIrp, TRUE);
         break;

      case IOCTL_SERIAL_CLR_RTS:
         status = AsynIoRts( pPortExt, pIrp, FALSE);
         break;

      case IOCTL_SERIAL_GET_DTRRTS:
         status = AsynIoGetDtrRts( pPortExt, pIrp, PDEVIO.OutputBufferLength,
                                   (PULONG)pIrp->AssociatedIrp.SystemBuffer);
         break;
      
      case IOCTL_SERIAL_SET_XON:
         status = AsynIoXonXoff( pPortExt, pIrp, TRUE);
         break;

      case IOCTL_SERIAL_SET_XOFF:
         status = AsynIoXonXoff(pPortExt, pIrp, FALSE);
         break;

      


      case IOCTL_SERIAL_SET_CHARS:
         status = AsynIoSetChars( pPortExt, pIrp, PDEVIO.InputBufferLength, 
                                  (PSERIAL_CHARS)pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_GET_CHARS:
         status = AsynIoGetChars( pPortExt, pIrp, PDEVIO.OutputBufferLength,
                                  (PSERIAL_CHARS)pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_SET_HANDFLOW:
         status = AsynIoSetHandflow( pPortExt, pIrp, PDEVIO.InputBufferLength,
                                     (PSERIAL_HANDFLOW)pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_GET_HANDFLOW:
         status = AsynIoGetHandflow( pPortExt, pIrp, PDEVIO.OutputBufferLength,
                                     (PSERIAL_HANDFLOW)pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_GET_MODEMSTATUS:
         status = AsynIoGetModemStatus( pPortExt, pIrp, PDEVIO.OutputBufferLength,
                                        (PULONG)pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_GET_COMMSTATUS:
         status = AsynIoGetCommStatus( pPortExt, pIrp, PDEVIO.OutputBufferLength,
                                       (PSERIAL_STATUS)
                                          pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_GET_PROPERTIES:
         status = AsynIoGetProperties( pPortExt, pIrp, PDEVIO.OutputBufferLength,
                                       (PSERIAL_COMMPROP)
                                          pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_LSRMST_INSERT:
         status = AsynIoLsrmstInsert( pPortExt, pIrp, PDEVIO.InputBufferLength,
                                      (PUCHAR)pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_CONFIG_SIZE:
         status = AsynIoConfigSize( pPortExt, pIrp, PDEVIO.OutputBufferLength,
                                    (PULONG)pIrp->AssociatedIrp.SystemBuffer);
         break;

           
      /*
      case IOCTL_SERIAL_SET_WAIT_MASK:
         status = AsynIoSetWaitMask( pPortExt, pIrp, PDEVIO.InputBufferLength,
                                     (PULONG)pIrp->AssociatedIrp.SystemBuffer);
         break;

      case IOCTL_SERIAL_GET_WAIT_MASK:
         status = AsynIoGetWaitMask( pPortExt, pIrp, PDEVIO.OutputBufferLength,
                                     (PULONG)pIrp->AssociatedIrp.SystemBuffer);

      case IOCTL_SERIAL_WAIT_ON_MASK:
         status = AsynIoWaitOnMask( pPortExt, pIrp,
                                       PDEVIO.OutputBufferLength);
         break;

      case IOCTL_SERIAL_PURGE:
         status = AsynIoPurge( pPortExt, pIrp, PDEVIO.InputBufferLength,
                               (PULONG)pIrp->AssociatedIrp.SystemBuffer);
         break;


      case IOCTL_SERIAL_GET_STATS:
         status = AsynIoGetStats( pPortExt, pIrp, PDEVIO.OutputBufferLength,
                                  (PASYN_SERIALPERF_STATS)
                                       pIrp->AssociatedIrp.SystemBuffer);

	  case IOCTL_SERIAL_CLEAR_STATS:
         status = AsynIoClearStats( pPortExt, pIrp);
         break;


     


*/
         break;

	
         //
         // No idea what this request wants!
         //
      default:
         DigiDump( DIGIALL, ("*** ASYN!Ioctl: Unknown req=0x%x\n",
                   pIrpSp->Parameters.DeviceIoControl.IoControlCode ));
         status = STATUS_INVALID_PARAMETER;
         pIrp->IoStatus.Information = 0;
         break;
   }
   DigiDump( DIGIIOCTL, ("ASYN!Ioctl: Exit ret=0x%x\n", status));

   
#ifdef DBG
   if ( (status != STATUS_SUCCESS) && (status != STATUS_PENDING))
   {
      DigiDump( DIGIALL, ("*** ASYN!Ioctl: Exit ret=0x%x Ioctl=0x%x\n", 
                          status, PDEVIO.IoControlCode));
   }
#endif

#undef PDEVIO

   return (status);
}


// PARAG - TODO  - Fill this up




VOID
AsynCancelIoctl(
   IN PPORT_EXT         pPortExt,   // port 
   IN PIRP              pIrp           // Associated work order.
)


{

	KIRQL	oldCancelIrql;
	KeAcquireSpinLock(&pPortExt->ioctl.lock,&pPortExt->ioctl.irql);
	RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
	IoAcquireCancelSpinLock(&oldCancelIrql);
	IoSetCancelRoutine(pIrp, NULL);
	IoReleaseCancelSpinLock(oldCancelIrql);

//	PARAG - TODO Check the retur status

	pIrp->IoStatus.Status = STATUS_CANCELLED;
	pIrp->IoStatus.Information = 0;


	//PARAG - TODO

	// Cancel Wait Mask IRP
	// Immediate write ??

	
	KeReleaseSpinLock(&pPortExt->ioctl.lock,pPortExt->ioctl.irql);
	IoCompleteRequest(pIrp, IO_SERIAL_INCREMENT);




}







NTSTATUS
AsynIoctl(
    IN DEVICE_OBJECT    *DeviceObject,  /* Specific PortServer Port. */
    IN IRP              *Irp            /* IOCTL request to perform. */
)

{
    PPORT_EXT     pPortExt;               /* Driver specific information. */
    IO_STACK_LOCATION 
                *irpSp;                 /* Current IRP stack position. */
    NTSTATUS    status;                 /* Called function return value. */
    KIRQL       oldCancelIrql;          /* Save prior irq level. */

  
    /*
    ** Get the driver specific data structures.
    */
    pPortExt = DeviceObject->DeviceExtension;

	Irp->IoStatus.Information = 0;

    /*
    ** The status field needs to be set to something to insure correct
    ** operation during RpCancelSerial() in the event a modem function
    ** has been cancelled.
    */
    Irp->IoStatus.Status = STATUS_SUCCESS;

    irpSp = IoGetCurrentIrpStackLocation(Irp);

    /*
    ** Port needs to be OPEN.
    */
    
    if (pPortExt->state != OpenState)
    {
        status = STATUS_UNSUCCESSFUL;
    }

	else
	    status = AsynProcessIoctl(pPortExt, Irp);
    
    Irp->IoStatus.Status = status;

    if (status != STATUS_PENDING)
    {
        IoAcquireCancelSpinLock(&oldCancelIrql);
        IoSetCancelRoutine(Irp, NULL);
        IoReleaseCancelSpinLock(oldCancelIrql);
		IoCompleteRequest(Irp, IO_NO_INCREMENT);
      }
    else
    {
        IoMarkIrpPending(Irp);

        /*
        ** Every pended call needs the cancel function set!
        */
        IoAcquireCancelSpinLock(&oldCancelIrql);
        IoSetCancelRoutine(Irp, AsynCancelIoctl);
        IoReleaseCancelSpinLock(oldCancelIrql);
    }

    return (status);
}




/*
	PARAG  TODO - this will be called from OnSyncResponse or
	putcompletion - Not sure about the parameters. Assuming the
	most convinient.

*/ 



VOID
AsynOnSyncResponse(
	IN PPORT_EXT	pPortExt,        /* Port specific information. */
	ULONG			syncAck
)

{

	PLIST_ENTRY	p;
	PIRP	pIrp ;
	KIRQL	oldCancelIrql;

	KeAcquireSpinLock(&pPortExt->ioctl.lock,&pPortExt->ioctl.irql);
	pPortExt->ioctl.syncAck = syncAck;
	KeReleaseSpinLock(&pPortExt->ioctl.lock,pPortExt->ioctl.irql);

	while (!IsListEmpty(&pPortExt->ioctl.pendingQueue))
	{
		KeAcquireSpinLock(&pPortExt->ioctl.lock,&pPortExt->ioctl.irql);
		p = RemoveHeadList(&pPortExt->ioctl.pendingQueue);
		pIrp = CONTAINING_RECORD(p, IRP, Tail.Overlay.ListEntry);
		if (pIrp->IoStatus.Information > pPortExt->ioctl.syncAck)
		{	
			InsertHeadList(&pPortExt->ioctl.pendingQueue,
				&pIrp->Tail.Overlay.ListEntry);

			pIrp = NULL;
		}
		else
		{
			pIrp->IoStatus.Information = 0;   //PARAG ?? ULONG ?
			pIrp->IoStatus.Status = STATUS_SUCCESS;
			IoAcquireCancelSpinLock(&oldCancelIrql);
			IoSetCancelRoutine(pIrp, NULL);
			IoReleaseCancelSpinLock(oldCancelIrql);

		}
						
		KeReleaseSpinLock(&pPortExt->ioctl.lock,pPortExt->ioctl.irql);
		
		if (pIrp != NULL)
			IoCompleteRequest(pIrp,IO_NO_INCREMENT);
		else
			break;
	}

}
