/*
 ****************************************************************************
 * Copyright (c) 1990-99 Digi International Inc., All Rights Reserved
 *
 * This software contains proprietary and confidential information of Digi
 * International Inc.  By accepting transfer of this copy, Recipient agrees
 * to retain this software in confidence, to prevent disclosure to others,
 * and to make no use of this software other than that for which it was
 * delivered.  This is an unpublished copyrighted work of Digi International
 * Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 * prohibited.
 *
 * Restricted Rights Legend
 *
 * Use, duplication, or disclosure by the Government is subject to
 * restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 * Technical Data and Computer Software clause at DFARS 252.227-7031 or
 * subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 * Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 ****************************************************************************
 */

/*
 *----------------------------------------------------------------------
 * Module File    : asyn.h
 *
 * Author         : P.Donovan
 *
 * Purpose        :
 *
 *      Asyn data structures and defines.
 *
 *----------------------------------------------------------------------
 */

extern PDRIVER_OBJECT gpDriverObject;

/*
 * ----------------------------------------------------------------------
 *  Event Log Definitions.
 *----------------------------------------------------------------------
 */
#include "asyn_msg.h"                /* Generated error message defines. */

/*
 *----------------------------------------------------------------------
 * Macro Definitions.
 *----------------------------------------------------------------------
 */

/*
 *----------------------------------------------------------------------
 *  Definitions.
 *----------------------------------------------------------------------
 */
#define ASYN_REVISION            0x0101   // Major 1, Minor 1

#ifndef MAX
# define MAX(x,y)	(x > y ? x : y)
#endif

// ISDN CC Message encasulation size 
#define ISDN_MESSAGE_ENCAP_SIZE  4
// Maximum ports per line
#define MAX_PORT_PER_POTS_LINE   1
#define MAX_PORT_PER_BRI_LINE    2
#define MAX_PORT_PER_PRI_LINE    23
#define MAX_PORT_PER_T1_LINE     24
#define MAX_PORT_PER_E1_LINE     30
#define MAX_PORT_NUMBER          (MAX_PORT_PER_E1_LINE)

// Maximum lines per adapter
#define MAX_LINE_NUMBER          8        // The POTS adapter

// Number of messages on the put message queue
#define DEF_PUT_EVENT_PER_PORT   2

// Number of messages on the get message queue
#define DEF_GET_EVENT_PER_PORT   1

// Number of read buffers per adapter
#define MAX_RX_BUF_PER_PORT      3
#define DEF_RX_BUF_PER_PORT      1
#define DEF_RX_BUF_SIZE          (SDXB_RMAX_DEF*32)

// number of ioctl's with SDXB message associated with it
// that can be outstanding per port
#define MAX_SDXB_IOCTL           10


/*
 *----------------------------------------------------------------------
 * PORT_EXT eventFlag values.
 *----------------------------------------------------------------------
 */
#define ASYN_OPEN_STREAM        0x01    // Open DXB Stream
#define ASYN_CLOSE_STREAM       0x02    // Close DXB Stream

/*
 *----------------------------------------------------------------------
 * PORT_EXT dataState values.
 *----------------------------------------------------------------------
 */
#define STATE_BAUD_SET         0x01        // Baud Rate
#define STATE_CFLAG_SET        0x02        // Control flags.
#define STATE_IFLAG_SET        0x04        // Input flags.
#define STATE_OFLAG_SET        0x08        // Output flags.
#define STATE_XFLAG_SET        0x10        // Miscellaneous flags.
#define STATE_WINDOW_SET       0x20        // RWIN RMAX RTIME TMAX TTIME set.
#define STATE_TX_SUSPENDED     0x40        // Transmit has been suspended!
#define STATE_DROPPED_CONN     0x80        // Connection has been dropped!

#define STATE_DATA_ENABLED     (STATE_BAUD_SET | STATE_CFLAG_SET | STATE_WINDOW_SET)

#ifdef DBG
//
// Pool Entry Debugging state
//
typedef enum
{
   EntryFree = 0xaa,
   EntryAllocated = 0x55,
} ENTRY_STATE;
#endif

typedef struct _ASYN_LIST {
   LIST_ENTRY  Entry;                  // Allow queueing of descriptors
#ifdef DBG
   ENTRY_STATE EntryState;             // For debugging purposes
#endif
} ASYN_LIST, *PASYN_LIST;

/*
 *----------------------------------------------------------------------
 *  Type Definitions.
 *----------------------------------------------------------------------
 */

/*
 * XN_GETMSG list structure.
 */
typedef struct
{
	LIST_ENTRY	List;					// List Queue head
	PXN_GET		XnGetEntry ;			// 	XN_GET Packet.
} XN_GET_LIST, *PXN_GET_LIST ;

/*
 * Pool list structure.
 */
typedef struct
{
   LIST_ENTRY  List;                   // List Queue head
   USHORT      Count;                  // Number of elements in list
   USHORT      LowTide;                // Record of minimum available
   USHORT      HighTide;               // Record of maximum available
   USHORT      Size;                   // Size of each element in list
   KSPIN_LOCK  PoolLock;               // Spinlock protecting pool elements
} POOL_LIST, *PPOOL_LIST;
 
/*
 * Registry Port Value structure.
 */
typedef struct
{
   UNICODE_STRING
               SymbolicName;           // User device name of the form: COM##
   WCHAR       SymbolicNameBuffer[ASYN_REG_PATH_LENGTH]; // Buffer to place the above.
   ULONG       CloseTimeOut;
   ULONG       CompleteWhenSent;
   ULONG       QWritesInAdapter;
	ULONG       IsModem;						// Port is really a modem (HLC)
} REGISTRY_PORT_VALUES;

typedef struct CARD_EXT *PCARD_EXT;
typedef struct PUT_MSG_EV *PPUT_MSG_EV;
typedef struct RX_BUF *PRX_BUF;

/*
 * Port State variable State transition values.
 */
typedef enum
{
   IdleState,
   OpeningState,
   OpenState,
   ClosingState,
   ClosingAwaitingCompleteState,
   ShutdownState,
	IdleState_PowerD3,
	OpenState_PowerD3,
} PORT_STATE;

typedef enum 
{
	PNPSTATE_OK				= 0x00,
	PNPSTATE_STOPPING		= 0x01,
	PNPSTATE_STOPPED 		= 0x02,
	PNPSTATE_REMOVING  	= 0x04,
	PNPSTATE_ADDED       = 0x08,
} ASYN_PNP_STATE;

//
// Port Open State mask
// NOTE: These are individual bit masks.
//
typedef enum
{
   BreakOnMask             = 0x01,
   ImmWriteMask            = 0x02,

   // Special Char Rxed signal from S/DXB, waiting on S/DXB to pass the DATA 
   // block with this special char.
   SpecialCharRxedMask     = 0x04,

   // S/DXB is currently Purging Rx, awaiting SYNC response
   RxDataPurgeMask         = 0x08,

   // This port has used up it's share of Rx Buffers
   RxDataFullMask          = 0x10,

   // S/DXB is currently Purging Tx, awaiting SYNC response
   TxDataPurgeMask         = 0x20,
   
   // Stop us pre-empting a Write which is about to take place
   TxingMask               = 0x40,
} OPEN_STATE;

//
// NT 4.0 DDK additions not present in 3.51 DDK.
//
#ifndef IOCTL_SERIAL_GET_STATS
#define IOCTL_SERIAL_GET_STATS          CTL_CODE(FILE_DEVICE_SERIAL_PORT,35,METHOD_BUFFERED,FILE_ANY_ACCESS)
#endif
#ifndef IOCTL_SERIAL_CLEAR_STATS
#define IOCTL_SERIAL_CLEAR_STATS        CTL_CODE(FILE_DEVICE_SERIAL_PORT,36,METHOD_BUFFERED,FILE_ANY_ACCESS)
#endif

typedef struct _ASYN_SERIALPERF_STATS {
    ULONG ReceivedCount;
    ULONG TransmittedCount;
    ULONG FrameErrorCount;
    ULONG SerialOverrunErrorCount;
    ULONG BufferOverrunErrorCount;
    ULONG ParityErrorCount;
} ASYN_SERIALPERF_STATS, *PASYN_SERIALPERF_STATS;

/*
 * Definition of a single ASYN port.  This structure is attached
 * to the device object's extension field.
 */
typedef struct
{
   // Spin-lock to protect this port from re-entrancy.
   //
   // In general this spin-lock is held while processing an event for a port.
   // The exception is that the spin-lock needs to be released when talking 
   // to the DXB driver using the DsAPi's Asynchronous calls (Ds*Ex() functions),
   // and completing IRPs (IoCompleteRequest()).
   // When a port is in use and the spin-lock is not held the PortBusy 
   // semaphore is used to block a new event pre-empting the current event 
   // being processed.
   //
   KSPIN_LOCK  PortLock;

   //
   // This semaphore indicates the Port is in use.
   // It should only be examined/modified while holding the port spin lock.
   ULONG       PortBusy;

   PDEVICE_OBJECT
               Card;                   // DigiAsyn OBJECT.
   PCARD_EXT   CardExt;                // DigiAsyn card extension OBJECT.

   ULONG       Port;                   // Port number [0..29].
   ULONG       ComNumber;              // The "##" part of the "COM##" name.
   ULONG       Line;                   // Line number [0..7].

   LIST_ENTRY  PortEntry;              // Allow linking of ports.

   PORT_STATE  State;                  // Opening, Open, Closing, Idle.
   
   //
   // Details on the state of the Port. Only meaningful if port is OpenState.
   //
   OPEN_STATE  OpenStateMask;          

   HANDLE      DsPortHandle;           // Handle returned from DsOpen

   // Next sequence number to use in S/DXB sync commands.
   USHORT      SyncOutSequence;

   // Last sequence number received in sync response from S/DXB.
   USHORT      SyncInSequence;

#ifdef DBG
   //
   // Debug variable and fields used for sanity checks
   struct {
      PVOID       LastGetMsgData;
      ULONG       LastGetMsgLen;
      ULONG       LastRxStart;
      ULONG       LastRxLen;
   } Debug;
#endif   // DBG

   struct {
      //
      // Port Speed and Processing Flags
      //
      ULONG       Speed;                  // BAUD
      USHORT      Cflags;                 // COM control flags.
      USHORT      Iflags;                 // Input processing flags.
      USHORT      Oflags;                 // Output processing flags.
      USHORT      Xflags;                 // Extended control flags.
   
      //
      // Sequence Parameters
      //
   
      // Sequence of the next byte of data to be read from the port and placed in
      // the local buffer.
      ULONG       Rin;
   
      // Sequence of the next byte to be sent to the driver.
      ULONG       Rout;
   
      // Max. input bytes required before data is sent to the host (Trigger).
      ULONG       Rmax;
   
      // Receive trigger time.
      ULONG       Rtime;
   
      // Sequence of the next byte to be placed in the output.
      ULONG       Tin;
   
      // Sequence of the next byte to be sent out the port as reported by the
      // adapter.  This value is updated on Sequence-Number SDXB indications
      // the update rate being a function of Tmax and Ttime, hence it can have
      // the granularity of Tmax.
      ULONG       Tout;
   
      // Value of Tout last reported to driver.
      ULONG       Tpos;
   
      // Max. output bytes before data is flow controlled from the host.
      ULONG       Tmax;
   
      // Tout report time (milliseconds).
      ULONG       Ttime;
   
      ULONG       RinLast;                // Last Rin reported by S/DXB
      ULONG       ToutLast;               // Last Tout reported by S/DXB
   
      ULONG       Insize;                 // Reported in Buffer Size Response
      ULONG       Outsize;                // Reported in Buffer Size Response
   
      ULONG       Maxlen;

      //
      // Event Reporting
      //
      USHORT      Estat;                  // Active Event conditions.
      USHORT      Eint;                   // Async event notification.
      USHORT      Elast;                  // Last state of the event conditions.
   
      //
      // Modem Control Variables
      //
      UCHAR       Mout;                   // Modem active signals.
      UCHAR       Mflow;                  // Modem flow control.
      UCHAR       Mctrl;                  // Modem flow control for out-of-band data.
      UCHAR       Mstat;                  // Current Modem status.
      UCHAR       Mlast;                  // Last Modem status value.
      UCHAR       Mint;                   // Modem notification events.
      UCHAR       Mflags;                 // Value of Flags field in MODEM command.
   
      //
      // Line Error Counters
      //
      USHORT      Ltime;                  // Line error report time (milliseconds)
      UCHAR       LerrFlags;              // SDXB_LERR flags
      ULONG       Norun;                  // Number of UART Overrun errors.
      ULONG       Noflow;                 // Number of buffer Overflow errors.
      ULONG       Nframe;                 // Number of Framing errors.
      ULONG       Nparity;                // Number of Parity errors.
      ULONG       Nbreak;                 // Number of Breaks received.
      ULONG       NorunLast;              // Last number of UART Overrun errors.
      ULONG       NoflowLast;             // Last number of buffer Overflow errors.
      ULONG       NframeLast;             // Last number of Framing errors.
      ULONG       NparityLast;            // Last number of Parity errors.
      ULONG       NbreakLast;             // Last number of Breaks received.
   
      // Flush Flag to use on an SDXB-FLUSH
      UCHAR       FlushFlags;
   
      //
      // Values in S/DXB PAUSE commands
      UCHAR       Pset;
      UCHAR       Preset;

   } SdxbValues;

   // Number of pending transmit bytes.
   ULONG       TxBytesPending;

   // Prior IRQL level, save it in the port stucture so that we can
   // Acquire and Release from different routines without having to pass it
   // as a parameter.
   KIRQL       PortIrql;
   UCHAR       Filler[1];              // Align to 4 byte address.

   UCHAR       SyncSeqNbr;             // Control synchronization number.
   UCHAR       EscapeChar;             // NT error escape character; analogous
                                       // to Digi's DOSMODE.
   // Immediate char to send
   UCHAR       SendImmChar;

   // Tally of errors for CommStatus reporting
   struct {
      USHORT      Break;           // Number of Break signals received.
      USHORT      Framing;         // Framing errors.
      USHORT      Overrun;         // Buffer overflow.
      USHORT      Parity;          // Parity errors.
   } CommErr;

   ULONG       SyncActive;             // 0 inactive; 1 active.

   // Number of Port errors encountered during driver instance.
#define PORT_ERROR_FILE_SIZE           13
   struct {
      // Total number of Port Errors
      ULONG       Total;
      // Line number where last port error occured
      ULONG       LineNumber;
      // Abbreviated file namer where last port error occured
      UCHAR       FileName[PORT_ERROR_FILE_SIZE];
   } PortError;


   // Total Read bytes available
   ULONG       TotalRxBytesBuffered;

   LIST_ENTRY  RxQ;                    // List of Receive Buffers
   USHORT      RxBufCount;             // Count of Receive Buffers

   ULONG       TotalReadBytes;         // Keep track of bytes read.

   // Keep track of bytes successfully written.
   ULONG       TotalWriteBytes;

   LIST_ENTRY  ActivePort;             // Queue of active Ports.

   // Queue of IRPs pending processing by Dispatch Routines.
   LIST_ENTRY  DispatchQ;

   // Queue of Dispatch Elements containing IRPs which are awaiting 
   // Dispatch Status reporting.
   // The entries in this queue are allocated off the stack in the 
   // DispatchEntry() routine.
   LIST_ENTRY  DispatchStatusQ;

   // Queue of SDXB-Responses pending processing by SDXB Routines
   LIST_ENTRY  SdxbRspQ;          

   // Queue of Cancels and Write Timeout IRPs pending processing
   LIST_ENTRY  CancelledAndTimedoutIrpQ;

   // Queue of IRPs ready to complete.
   LIST_ENTRY  CompleteIrpQ;

   LIST_ENTRY  ReadQueue;              // Queue of Read IRPs.
   LIST_ENTRY  WriteQueue;             // Queue of Write IRPs.

   LIST_ENTRY  XnGetQueue;			   // Queue of Xn Get IRPs.
   LIST_ENTRY  XnGetPktQueue ;		   // Queue of Xn Get Packets
   KSPIN_LOCK  XnGetLock ;			   // spin lock for the xn get queue

   PIRP        OpenIrp;                // Open IRP in progress.
   PIRP        CloseIrp;               // Close IRP in progress.
   PIRP        TimedReadIrp;           // Read IRP being timed.
   PIRP        WaitMaskIrp;            // IRP waiting on waitMask events.

   // Write work item (including IRP) being timed.
   PPUT_MSG_EV TimedWritePutEvent;

   ULONG       WaitMask;               // NT wait events.
   // Wait events which occurred but which are still unreported.
   // This includes events which we may or may not be monitored by WaitMask.
   ULONG       HistoryMask;

   ULONG       ReadIntervalActive;     // Read interval timer is active.
   ULONG       ReadIntervalCount;      // Interval timer prior byte count.


   // Read and Write Timers and DPCs.
   struct {
      KDPC        IntervalReadDpc;     // Read Interval IRP timeout DPC d.s.
      KTIMER      IntervalRead;        // Read Interval IRP Timer d.s.
      KDPC        ReadDpc;             // Read IRP timeout DPC structure.
      KTIMER      Read;                // Read IRP Kernel Timer structure.
      KDPC        WriteDpc;            // Write IRP timeout DPC structure.
      KTIMER      Write;               // Write IRP Kernel Timer structure.

      KTIMER      Close;
      KDPC        CloseDpc;            // Close IRP timeout DPC structure.
   } Timer;

   //
   // This points the the delta time that we should use to
   // delay for interval timing as per the serial DDK sample code.
   //
   LARGE_INTEGER IntervalTimeToUse;

   //
   // This value is set by the read code to hold the time value
   // used for read interval timing as per the serial DDK sample code.
   //
   LARGE_INTEGER IntervalTime;

   SERIAL_HANDFLOW
               Handflow;               // Flow control.
   SERIAL_TIMEOUTS
               TimeoutValues;          // NT provided read/write timeout
                                       // values.

   UNICODE_STRING
               SymbolicName;           // User device name of the form:
                                       // \DosDevices\COM##
   WCHAR       SymbolicNameBuffer[48]; // Buffer to place the above.
   UNICODE_STRING
               DeviceMapName;          // "DigiAsyn##Module#Port##"
   WCHAR       DeviceMapNameBuffer[34];// Buffer to place the above.
	UNICODE_STRING
					DeviceName;					

   PDEVICE_OBJECT
               PortDevice;             // The Device Object for this Port.

   SERIAL_CHARS
               SpecialChars;           // Eof Error Break Event Xon Xoff

   // Normally wait until all pending transmit data is sent before closing a
   // port.  However, if we are using flow control and the flow control window
   // is closed we may never send the data.  Thus without a timeout the close
   // may never complete.
   // This value specifies a timeout in Seconds to allow transmits to complete.
   // If after that timeout the transmit is not complete, close the port anyway.
   ULONG       CloseTimeOut;

   // The Win32 COMM API poorly defines when a IRP_MJ_WRITE completes.
   // If this value is set; then complete the IRP when the last byte has left
   // the hardware FIFO.
   // Otherwise complete when the data has been off-loaded to the adapter.
   BOOLEAN     CompleteWhenSent;

   // When FALSE there is at most one pending Write sent to the adapter. 
   // The driver will queue subsequent Writes locally and empties this queue 
   // one Write at a time as the Writes in the adapter complete.
   // When TRUE the driver does not hold back sending Writes to the adapter.
   // Instead the adapter (or the DXB driver if there is not enough credits) 
   // will have to queue them.  This latter method is somewhat faster but 
   // means we cannot necessarily purge the adapters output queue on Write 
   // timeouts.
   BOOLEAN     QWritesInAdapter;

   // The Output queue
   // This is the queue for all PutMsg data and commands, both High and Low
   // priority.
   LIST_ENTRY  PutQ;

   struct {
      LIST_ENTRY     Queue;
      KTIMER         Timer;
      KDPC           Dpc;
      LARGE_INTEGER  Timeout;
      BOOLEAN        TimeoutPending;
   } Trace;

   //
   // Maintain a copy of statistics for IOCTL_SERIAL_GET_STATS and 
   // IOCTL_SERIAL_CLEAR_STATS calls.
   //
   ASYN_SERIALPERF_STATS  PerfStats;

   // Pre-allocated Free Pool of PUT_MSG_EV elements.
   POOL_LIST   PutEventPool;

   // Pre-allocated Free Pool of GET_MSG_EV elements.
   POOL_LIST   GetEventPool;

   // Pre-allocated Free Pool of RX_BUF elements.
   POOL_LIST   ReadBufferPool;

   // Free Pool of variable size receive buffers, allocated on an as need 
   // basis.  Typically these are large buffers.
   POOL_LIST   VariableReadBufferPool;

#if NT5_BUILD
	PDEVICE_OBJECT   pPdo; 	// Physical Device object created by PCI bus enumerator
	PDEVICE_OBJECT   pNextDeviceObject;	// Could be different than Pdo if filter 
   HANDLE      DsHandle;               // Handle to DStreams service provider.
	ASYN_PNP_STATE		PnpState;
	DEVICE_POWER_STATE PowerState;		// PNP Power state: D0 (on) or D3 (off).
	UNICODE_STRING		DxbDevice;
#endif

	// Used for Pnp Modem Detection.
	// TRUE signals that this port is actually a modem on an HLC adapter.
	// FALSE signals that it is a traditional serial port (i.e. AccelePort 2000 )
	BOOLEAN		IsModem;

	HANDLE    	PnpModemDetectHandle;

   SHORT      DxbCount;               // number of DXB messages outstanding

} PORT_EXT, *PPORT_EXT;

/*
 * Commands sent to S/DXB.
 * But not just standard commands, also includes DATA represented as a cmd.
 * Used to describe what's in our outbound queue, both high and low priority.
 */
typedef enum _SDXB_PUT_CMD
{
   CMD_NONE,	
   DATA_CMD,
   SYNC_CMD,
   BUFFER_SIZE_CMD,
   MODEM_CTRL_CMD,
   EVENT_CMD,
   LINE_ERR_CMD,
   PORT_CAP_CMD,
   PORT_PARAM_CMD,
   WATERMARKS_CMD,
   SEQ_NUM_CMD,
   CHAR_IMMED_CMD,
   BREAK_CMD,
   FLUSH_CMD,
   PAUSE_CMD
} SDXB_PUT_CMD, *PSDXB_PUT_CMD;

/*
 * Responses from S/DXB.
 * Not just standard command responses, also includes DATA represented as a rsp.
 * Used to describe what's in our inbound queue.
 */
typedef enum _SDXB_GET_RSP
{
   DATA_RSP,
   SYNC_RSP,
   BUFFER_SIZE_RSP,
   MODEM_CTRL_RSP,
   EVENT_RSP,
   LINE_ERR_RSP,
   PORT_CAP_RSP,
   PORT_PARAM_RSP,
   SEQ_NUM_RSP,
   CHAR_IMMED_RSP,
   SPX_CHAR_RSP,
   PROTOCOL_ERR_RSP
} SDXB_GET_RSP, *PSDXB_GET_RSP;

/*
 * Reason codes.
 * These codes are just a handy way of representing what an IRP is trying to do.
 * Thus they represent the IRP MajorFunction code and/or the IRP parameters
 * in the case of MJ_IOCTL IRPs
 */
typedef enum _IRP_REASON
{
   REASON_NONE,	
   REASON_OPEN,
   REASON_CLOSE,
   REASON_WRITE,
   REASON_SET_DTR,
   REASON_CLR_DTR,
   REASON_SET_RTS,
   REASON_CLR_RTS,
   REASON_SET_BREAK,
   REASON_CLR_BREAK,
   REASON_PAUSE,
   REASON_UNPAUSE,
   REASON_SET_WAIT,
   REASON_SET_CHARS,
   REASON_SET_HANDFLOW,
   REASON_GEN_IOCTL,
   REASON_FLUSH,
   REASON_PURGE,
   REASON_CLEANUP,
   REASON_SET_LSRMST,
   REASON_SEND_IMMED,
   REASON_LERR,
} IRP_REASON, *PIRP_REASON;

/*
 * Put Event States
 */
typedef enum
{
   // The work order is being composed, still generating DsPutMsg's for this
   // descriptor.
   PutBuilding,

   // The work order is fully composed, the PutMsg Completion routines have
   // not been called yet.
   PutAwaitingCompletion,

   // The work order is fully composed, the PutMsg Completion routines have
   // not been called yet.  Despite this an associated response has already
   // been received.  This is an extremely unlikely race condition.
   PutAwaitingCompletionResponseRxed,

   // All associated PutMsg Completion routines have been called.
   // Awaiting response from S/DXB to complete work order and/or associated IRP.
   PutAwaitingResponse,

   // The work order has fully completed.  Return the descriptor to the
   // free pool.
   PutEnded,

   // The PutMsg Completion routines have not been called yet and the user has
   // aborted.
   PutAborted,
} PUT_EV_STATE;

/*
 * Outbound work order item.
 * Descriptor to keep track of messages which have been put in the DStreams
 * PutMsg queue.  Used for both Hi and Low priority queues.
 */
typedef struct PUT_MSG_EV
{
   LIST_ENTRY  ListEntry;     // Allow queueing of messages
#ifdef DBG
   ENTRY_STATE EntryState;    // For debugging purposes
#endif
   PIRP        Irp;           // Associated IRP.
   NTSTATUS    Status;        // Track progress.
   PPORT_EXT   PortExt;       // Port being used.

   // Indicates the final SDXB Command in a chain of SDXB Commands.
   SDXB_PUT_CMD Command;

   //
   // Running count of the number of Tx Bytes awaiting transmission on this 
   // work order.
   // As Sequence numbers are received this running count is decremented.
   // When the Sync associated with this Write is received this value will be 
   // set to zero.
   ULONG       PendingTxBytes;

   USHORT      Sequence;      // Sequence number, only for SYNC/DATA cmds

   // Reference count of pending Completion routine calls.
   USHORT      PutMsgRef;

   PUT_EV_STATE State;        // State of work order.

   IRP_REASON  Reason;        // MajorFunction in IRP
   LARGE_INTEGER
               Timeout;       // Timeout value for WRITEs
} PUT_MSG_EV, *PPUT_MSG_EV;

/*
 * Descriptor of the S/DXB response event, read from the DStreams GetMsg queue.
 */
typedef struct
{
   LIST_ENTRY  ListEntry;              // Allow queueing of messages
#ifdef DBG
   ENTRY_STATE EntryState;             // For debugging purposes
#endif
   PPORT_EXT   PortExt;
   SDXB_GET_RSP
               Response;               // GetMsg response type
   USHORT      Sequence;               // Sequence number, optional
   ULONG       DataLength;             // Data block length
   PVOID       PData;                  // Pointer to the Data block
   ULONG       RspLength;              // Response length.
   SDXB_COMP_RSP
               Rsp;                    // Command Response in compressed form.
   NTSTATUS    Status;                 // Track progress.
} GET_MSG_EV, *PGET_MSG_EV;

/*
 * Receive Buffer structure.
 */
typedef struct RX_BUF
{
   LIST_ENTRY  ListEntry;              // Allow queueing of buffers
#ifdef DBG
   ENTRY_STATE EntryState;             // For debugging purposes
#endif
   ULONG       Size;                   // Maximum size of data buffer
   ULONG       Len;                    // Amount of data in data buffer
   ULONG       Start;                  // Starting offset of Data, usually 0
   UCHAR       Data[DEF_RX_BUF_SIZE];  // Data buffer
} RX_BUF, *PRX_BUF;

/*
 * Receive Buffer header structure.
 */
typedef struct RX_BUF_HEADER
{
   LIST_ENTRY  ListEntry;              // Allow queueing of buffers
#ifdef DBG
   ENTRY_STATE EntryState;             // For debugging purposes
#endif
   ULONG       Size;                   // Maximum size of data buffer
   ULONG       Len;                    // Amount of data in data buffer
   ULONG       Start;                  // Starting offset of Data, usually 0
} RX_BUF_HEADER, *PRX_BUF_HEADER;

/*
 * Dispatch Function element structure
 */
typedef struct _DISPATCH_ELE
{
   LIST_ENTRY  ListEntry;              // Allow queueing of elements
   PIRP        Irp;                    // Dispatch IRP
   NTSTATUS    Status;                 // Dispatch IRP status
} DISPATCH_ELE, *PDISPATCH_ELE;

/*
 * Definition of a Houston device.  This structure is attached
 * to the adapter object's extension field.
 */
typedef struct CARD_EXT
{
   KSPIN_LOCK  CardLock;               // Covers all structures.

   PORT_STATE  State;                  // Opening, Open, Closing, Idle.
   HANDLE      DsHandle;               // Handle to DStreams service provider.


   // Self imposed DStreams Packet size for outbound data.
   // The optimum value will be found thru experimentation.
   // We may also wish to allow this value to be configured in the registry.
   ULONG       DstreamsPayload;

   USHORT      PhysicalPorts;          // DigiAsyn controlled ports.

   ULONG       NbrActivePorts;         // Count of active ports.
   LIST_ENTRY  ActivePorts;            // Queue of opened DigiAsyn ports.
   LIST_ENTRY  PendedOpens;            // Queue of COM_EXTs waiting to be
                                       // opened.

   //
   // Run-time configurable options.
   //
   ULONG       RunTimeOptions;

   //
   // This is the ISDN Call Control flag.  This indicates whether ISDN
   // call control is used on this card.  (This is for Acotec.)
   //
   ULONG	   IsdnCC ;

   PDEVICE_OBJECT
               CardDevice;             // The Device Object for this Adapter.
   DEVICE_OBJECT
               *Next;                  // Next DigiAsync adapter

   LIST_ENTRY  PortList;               // List of Ports on this adapter

   UNICODE_STRING
               DeviceName;             // "\Device\DigiAsyn##"
   WCHAR       DeviceNameBuffer[32];

   //
   // These two values hold the "constant" time that we should use
   // to delay for the read interval time as per the serial DDK sample code.
   //
   LARGE_INTEGER ShortIntervalAmount;
   LARGE_INTEGER LongIntervalAmount;

   //
   // This holds the value that we use to determine if we should use
   // the long interval delay or the short interval delay as per the serial 
   // DDK sample code.
   //
   LARGE_INTEGER CutOverAmount;

   UNICODE_STRING
               SymbolicName;           // User device name of the form:
                                       // \DosDevices\DigiAsynDxb##
   WCHAR       SymbolicNameBuffer[48]; // Buffer to place the above.
} CARD_EXT;



//
// Common structures shared between trace applications and driver
//
typedef enum
{
   TIMEOUT_NONE,
   TIMEOUT_INTERVAL,
   TIMEOUT_TOTAL
} TimeoutType;

//
// Configurable run-time behavior for driver.
//
// In general use the defaults, however the defaults may be overridden by 
// setting the registry "RunTimeOptions".  The defaults are set using 
// RunTimeOptions in the init.c file.
//
// Most of these run-options deal with whether IOCTLs IRPs are completed
// immediately, or marked with STATUS_PENDING and later completed based on 
// DXB or S/DXB responses.
// Completing the IRPs immediately makes the driver (from applications view 
// point) look like the standard serial driver.  On the other hand there is 
// a definite time lag (since we are dealing with intelligent cards) between
// issueing an S/DXB command and having the command take effect.  If it's 
// necessary that the driver guarantees the S/DXB command has been acting upon 
// then it's appropriate to set the "*_PENDING_IRP" option.

#define RUNTIME_SET_BAUD_USE_PENDING_IRP        0x00000001
#define RUNTIME_SET_LINE_USE_PENDING_IRP        0x00000002
#define RUNTIME_SET_BREAK_USE_PENDING_IRP       0x00000004
#define RUNTIME_SET_SIGNALS_USE_PENDING_IRP     0x00000008
#define RUNTIME_SET_XONXOFF_USE_PENDING_IRP     0x00000010
#define RUNTIME_FLUSH_USE_PENDING_IRP           0x00000020
#define RUNTIME_SET_CHARS_USE_PENDING_IRP       0x00000040
#define RUNTIME_SET_HANDFLOW_USE_PENDING_IRP    0x00000080
#define RUNTIME_SET_LSMSR_USE_PENDING_IRP       0x00000100

// RAS/TapiSrv in NT4.0/SP3 doesn't like this setting too much.
// If this is set and RAS is heavily stressed with multiple simultaneous 
// Connects/Disconnects NT4.0/SP3 will eventually blue-screen.
#define RUNTIME_SET_WAIT_MASK_USE_PENDING_IRP   0x00000200

// Detect Special Character reporting in driver instead of in S/DXB
// S/DXB appears to report the Special Character without any problem, if 
// in doubt use this setting to have the driver detect the Character.
#define RUNTIME_RXFLAG_IN_DRIVER                0x00000400


// Special IOCTL invented by Microsoft to aid Digi optimise Fep5 driver with RAS
#define IOCTL_FAST_RAS     CTL_CODE(FILE_DEVICE_SERIAL_PORT,4000,METHOD_BUFFERED,FILE_ANY_ACCESS)

#define IOCTL_DIGI_SPECIAL CTL_CODE(FILE_DEVICE_SERIAL_PORT,2048,METHOD_BUFFERED,FILE_ANY_ACCESS)
// NOTE: FILE_DEVICE_SERIAL_PORT 2049-2050 reserved (See sdxbisdn.h)

#define IOCTL_DIGI_CONTROLLER_SPECIAL        CTL_CODE(FILE_DEVICE_CONTROLLER, 2048,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define IOCTL_DIGI_GET_CONTROLLER_PERF_DATA  CTL_CODE(FILE_DEVICE_CONTROLLER, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_DIGI_GET_PORT_PERF_DATA        CTL_CODE(FILE_DEVICE_CONTROLLER, 2050, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_DIGI_GET_CONTROLLER_DATA       CTL_CODE(FILE_DEVICE_CONTROLLER, 2051, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_DIGI_REPORT_CONTROLLER_STATUS  CTL_CODE(FILE_DEVICE_CONTROLLER, 2054, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_DIGI_GET_PORT_STATUS  CTL_CODE(FILE_DEVICE_CONTROLLER, 2055, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_DIGI_GET_PORT_TRACE  CTL_CODE(FILE_DEVICE_CONTROLLER, 2056, METHOD_BUFFERED, FILE_ANY_ACCESS)

#define MAX_IRPS 64
#if 0
typedef struct _PORT_STATUS
{
   ULONG Version;
   ULONG ComPort;
   PVOID DeviceExt;
   ULONG State;

   USHORT Tin, Tout, Tmax;
   USHORT Rin, Rout, Rmax;
   USHORT Edelay, Iflag, Oflag, Cflag;
   UCHAR  Iempty, Ilow, Idata;
   UCHAR  Xon, Xoff, Hflow;
   UCHAR Tbusy, Mstat, Mint;
   UCHAR Buffer[3];
   struct {
      ULONG  Bin, Bout, Bmax, ScannedBytes, InsertCount;
      BOOLEAN  ScanForSpecialChar;
      PUCHAR Buffer;
      PVOID   ActiveIrp;
      PVOID   Irp[MAX_IRPS];
      NTSTATUS IrpStatus[MAX_IRPS];
      struct {
         LARGE_INTEGER  StartTime;
         LARGE_INTEGER  Time;
         ULONG          Interval;
         ULONG          Multiplier;
         ULONG          Total;
         TimeoutType    Type;
         PVOID           Irp;
      } Timeout;
   } Read;

   struct {
      PVOID ActiveIrp;
      PVOID Irp[MAX_IRPS];
      NTSTATUS IrpStatus[MAX_IRPS];
      PVOID CompletedIrp[MAX_IRPS];
      NTSTATUS CompletedIrpStatus[MAX_IRPS];
      struct {
         // This is the kernel timer structure used to handle
         // total time request timing.
         LARGE_INTEGER  StartTime;
         ULONG    Total;
         ULONG    Multiplier;
         TimeoutType    Type;
         // This field is meant to be a record for tracking the irp associated
         // with the timeout, and not a means to reference it directly.
         PVOID     Irp;
      } Timeout;

   }  Write;
   struct {
      ULONG History, Mask, Active, Status;
      PVOID Irp;
   }  Wait;
} PORT_STATUS, *PPORT_STATUS;
#else

#define MAX_DMODE_PORTS       256

typedef struct _CARD_STATUS
{
   ULONG State;
   ULONG Type;
   PVOID DeviceExt;
   ULONG NumberOfPorts;
   struct {
      USHORT Count;
      USHORT LowTide;
      USHORT HighTide;
      USHORT Size;
   } PutPool;
   struct {
      USHORT Count;
      USHORT LowTide;
      USHORT HighTide;
      USHORT Size;
   } GetPool;
   struct {
      USHORT Count;
      USHORT LowTide;
      USHORT HighTide;
      USHORT Size;
   } RxPool;
   struct {
      USHORT Count;
      USHORT LowTide;
      USHORT HighTide;
      USHORT Size;
   } ExtRxPool;
   UCHAR OpenPorts[MAX_DMODE_PORTS];
} CARD_STATUS, *PCARD_STATUS;

#define MAX_DMODE_RX_BUFFER   5
#define MAX_DMODE_PUT_EVENT   10

typedef struct _PORT_STATUS
{
   ULONG Version;
   ULONG ComPort;
   PVOID DeviceExt;
   ULONG State;
   ULONG Busy;

   USHORT SyncOutNum, SyncInNum;
   ULONG  Speed;
   USHORT Rmax;
   USHORT Iflag, Oflag, Cflag, Xflag;
   UCHAR  Iempty, Ilow, Idata;
   UCHAR  Xon, Xoff, Mflow;
   USHORT Ttime, Tmax;
   UCHAR  Rtime;
   USHORT Estat, Eint;
   UCHAR  Mstat, Mint;
   USHORT Ltime;
   USHORT OpenStateMask;
   USHORT Norun, Noflow, Nframe, Nparity, Nbreak;
   struct {
      USHORT   Total;
      USHORT   LineNumber;
      UCHAR    FileName[PORT_ERROR_FILE_SIZE];
   } PortError;
   ULONG  TotalRxBytesBuffered;
   ULONG  TotalWriteBytes, TotalReadBytes;
   ULONG  Tout, TxBytesPending;
   USHORT RxBufCount;
   ULONG  TimedWritePutEvent;
   UCHAR  Buffer[3];
   struct {
      PVOID   Ptr[MAX_DMODE_RX_BUFFER];
      USHORT  Size[MAX_DMODE_RX_BUFFER];
      USHORT  Start[MAX_DMODE_RX_BUFFER];
      USHORT  Len[MAX_DMODE_RX_BUFFER];
   } RxQ;
   struct {
      PVOID   Put[MAX_DMODE_PUT_EVENT];
      USHORT  Command[MAX_DMODE_PUT_EVENT];
      PVOID   Irp[MAX_DMODE_PUT_EVENT];
      USHORT  Reason[MAX_DMODE_PUT_EVENT];
      USHORT  State[MAX_DMODE_PUT_EVENT];
   } PutQ;
   struct {
      PVOID   Irp[MAX_IRPS];
      NTSTATUS IrpStatus[MAX_IRPS];
   } DispatchQ;
   struct {
      PVOID   Irp[MAX_IRPS];
      NTSTATUS IrpStatus[MAX_IRPS];
      struct {
         ULONG          Interval;
         ULONG          Multiplier;
         ULONG          Total;
         PVOID          Irp;
      } Timeout;
   } Read;
   
   struct {
      PVOID Irp[MAX_IRPS];
      NTSTATUS IrpStatus[MAX_IRPS];
      struct {
         ULONG    Total;
         ULONG    Multiplier;
         // This field is meant to be a record for tracking the irp associated
         // with the timeout, and not a means to reference it directly.
         PVOID     Irp;
      } Timeout;
      
   }  Write;
   struct {
      ULONG History, Mask, Active, Status;
      PVOID Irp;
   }  Wait;
   struct {
      PVOID Irp[MAX_IRPS];
      NTSTATUS IrpStatus[MAX_IRPS];
   } CompleteOutboundIrp;
} PORT_STATUS, *PPORT_STATUS;

#endif

typedef enum {
   TRACETYPE_READ,
   TRACETYPE_WRITE,
   TRACETYPE_IOCTL,
   TRACETYPE_MODEM_STATUS
} TRACE_TYPE;

typedef struct {
   TRACE_TYPE     FunctionType;
   LARGE_INTEGER  Time;
   UCHAR          ModemStatus;
   ULONG          Length;
} TRACE_HEADER;

typedef struct {
   ULONG          Irp;
   ULONG          Status;
} READ_TRACE, WRITE_TRACE;

typedef struct {
   ULONG          Irp;
   ULONG          Status;
   ULONG          IoctlType;
} IOCTL_TRACE;

#define DIGI_IOCTL_DBGOUT     0x00000001
#define DIGI_IOCTL_TRACE      0x00000002
#define DIGI_IOCTL_DBGBREAK   0x00000003

typedef struct _DIGI_IOCTL_
{
   ULONG dwCommand;
   ULONG dwBufferLength;
   CHAR Char[1024];
} DIGI_IOCTL, *PDIGI_IOCTL;



/*
 *----------------------------------------------------------------------
 *  Data Structure Definitions.
 *----------------------------------------------------------------------
 */

/*
 *----------------------------------------------------------------------
 *  Type Structure Definitions LOCAL to Module.
 *----------------------------------------------------------------------
 */
typedef struct
{
   NTSTATUS    Status;                 // Thread creation status.
   PCARD_EXT   Card;                   // Card Extension.
   WORK_QUEUE_ITEM
                WorkQueueItem;         // Work queue data structure.
   KEVENT      Event;                  // Synchronization device.
} THREAD_INFO;

/*
 * Read interval states.
 */
enum
{
   ReadIntervalIdle,
   ReadIntervalTimeout,
   ReadDurationTimeout
} RP_READ_INTERVAL_STATES;

//
// Port Error stuff.
// This is similar to an assert, but is present even in non-debug builds,
// and the driver can recover/continue in spite of the error.
//
#define PORT_ERROR(pPortExt) \
   { \
      ULONG    Size = 0; \
      PUCHAR   pStr = __FILE__; \
      pPortExt->PortError.Total++; \
      pPortExt->PortError.LineNumber = __LINE__; \
      while (*pStr) \
      { \
         Size++; \
         pStr++; \
      } \
      if (Size < PORT_ERROR_FILE_SIZE) \
      { \
         pStr = __FILE__; \
      } \
      else \
      { \
         Size++; \
         pStr++; \
         Size = PORT_ERROR_FILE_SIZE; \
         pStr -= PORT_ERROR_FILE_SIZE; \
      } \
      RtlCopyMemory( pPortExt->PortError.FileName, pStr, Size); \
      DigiDump(DIGIALL, ("*** PORT Error on Port=0x%x %s Line %d\n", \
                          pPortExt->Port, __FILE__, __LINE__)); \
   } 
/*
 * Debug Stuff
 */
#define DIGIINIT               DEBUG_00000001
#define DIGIINIT1              DEBUG_00000002
#define DIGIUNLOAD             DEBUG_00000004
#define DIGISDXB1              DEBUG_00000008

#define DIGIOPEN               DEBUG_00000010
#define DIGICLOSE              DEBUG_00000020
#define DIGICANCEL             DEBUG_00000040
#define DIGISDXB               DEBUG_00000080

#define DIGIDISPATCH           DEBUG_00000100
#define DIGITIMEOUT            DEBUG_00000200
#define DIGIPURGE              DEBUG_00000400
#define DIGIPNP	             DEBUG_00000800

#define DIGIEVENT              DEBUG_00001000
#define DIGITHREAD             DEBUG_00002000
#define DIGIIOCTL1             DEBUG_00004000
#define DIGIIRP                DEBUG_00008000

#define DIGIREAD               DEBUG_00010000
#define DIGIWRITE              DEBUG_00020000
#define DIGIIOCTL              DEBUG_00040000
#define DIGIWAIT               DEBUG_00080000

#define DIGIRXTRACE            DEBUG_00100000
#define DIGITXTRACE            DEBUG_00200000
#define DIGITIMEOUT1           DEBUG_00400000
#define DIGIPOWER              DEBUG_00800000

#define DIGIFLOW               DEBUG_01000000
#define DIGIFLOW1              DEBUG_02000000

#define DIGIERRORS             DEBUG_ERROR
#define DIGIALL                (~DEBUG_BREAK)

