/*++
*******************************************************************************
* Copyright (c) 1999 - 2000 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 Name:

   digiasyn.h


Abstract:

        Serial (async) driver for DXB-based adapters, e.g. Houston or Hercules.  This 
        driver communicates with the S/DXB firmware module.

Author:

   Michael Zarns

--*/

#ifndef DIGIASYN_H
#define DIGIASYN_H

#define UNICODE
#include <ntddk.h>
#include <ntddser.h>                    // Serial port definitions.

// Standard defines required by firmware headers
#include "dxbtypes.h"

// firmware headers
#include "sdxb_prot.h"

#include "digilib.h"
#include "dsapi.h"
#include "dxbreg.h"
#include "asynlog.h"
#include "asynerror.h"
#include "asynrx.h"
#include "asynsdxb.h"

#include "isdn_proto.h"
#include "sdxbisdn.h"

typedef struct ASYN_WRITE *PASYN_WRITE;
typedef struct ASYN_SDXB *PASYN_SDXB;
typedef struct ASYN_PORT_EXT *PASYN_PORT_EXT;

#include "asyncreate.h"
#include "asyninit.h"
#include "asynioctl.h"
#include "asynpnp.h"
#include "asynread.h"
#include "asynrsp.h"
#include "asynwait.h"
#include "asynwrite.h"
#include "pnpmodem.h"
#include "digidga.h"

// Driver Global Data
extern PDRIVER_OBJECT gpDriverObject;
extern LIST_ENTRY     gDeviceExtList;
extern UNICODE_STRING gDriverRegPath;

// Default pool tag for ExAllocatePoolWithTag memory allocations
extern ULONG DefaultPoolTag;

// Debug flags
#define DIGIINIT                        DEBUG_00000001
#define DIGIRXENGINE            DEBUG_00000002
#define DIGIFLOW                        DEBUG_00000004
#define DIGIUNLOAD              DEBUG_00000008

#define DIGICREATE              DEBUG_00000010
#define DIGICLOSE                       DEBUG_00000020
//#define DIGI                  DEBUG_00000040
//#define DIGI                  DEBUG_00000080

#define DIGISDXBRSP             DEBUG_00000100
//#define DIGI                  DEBUG_00000200
//#define DIGI                  DEBUG_00000400
//#define DIGI                  DEBUG_00000800

#define DIGIPNP                 DEBUG_00001000
#define DIGIPOWER                       DEBUG_00002000
//#define DIGI                  DEBUG_00004000
//#define DIGI                  DEBUG_00008000

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

#define DIGITIMEOUT             DEBUG_00100000
#define DIGICANCEL              DEBUG_00200000
//#define DIGI                  DEBUG_00400000
//#define DIGI                  DEBUG_00800000

//#define DIGI                  DEBUG_01000000
//#define DIGI                  DEBUG_02000000
#define DIGIWARN                DEBUG_WARN
#define DIGIERROR               DEBUG_ERROR
#define DIGIBREAK               DEBUG_BREAK

#define                         MILLISECOND  10000L

PDEVICE_OBJECT                  GlobalDgaObject;


typedef enum 
{
    ASYN_TYPE_PORT_EXT = 0xAA000001,
    ASYN_TYPE_RXENGINE,
    ASYN_TYPE_ADAPTER_EXT,
    ASYN_TYPE_COUNT
} ASYN_OBJECT_TYPE;

/*
 * Port State variable State transition values.
 */
typedef enum
{
    IdleState = 0,
    OpenInProgressState,
    OpenState,
    CloseWaitTxDrainState,
    CloseInProgressState,
    CloseOnFinalSyncState,
    ShutdownState,
    OpenState_PowerD3,          // Device was open prior to request to transition to D3 power state
    OpeningState_PowerD3,       // Create IRP received while port was in D3 power state
    IdleState_PowerD3,          // Device was idle prior to request to transition to D3 power state
} PORT_STATE;

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

typedef enum ASYN_POWER_STATE
{
    PWRSTATE_ON,            // power on, device in D0 state
    PWRSTATE_OFF_PENDING,   // power off operation is pending
    PWRSTATE_OFF,           // power off, device in D3 state
    PWRSTATE_OFF_IDLE,      // power off due to idle detection
} ASYN_POWER_STATE, *PASYN_POWER_STATE;

//
// S/DXB Defaults
//

// Adjust these defaults 
#define SDXB_RMAX_DEF                   512
#define SDXB_RTIME_DEF                  100         // MilliSeconds
#define SDXB_TMAX_DEF                   256
#define SDXB_TTIME_DEF                  1000        // MilliSeconds
#define SDXB_ICDTIME_DEF                        0

#define SDXB_RMAX_LOWLATENCY     1
#define SDXB_RTIME_LOWLATENCY    0         // MilliSeconds
#define SDXB_TMAX_LOWLATENCY     1
#define SDXB_TTIME_LOWLATENCY    10        // MilliSeconds
#define SDXB_ICDTIME_LOWLATENCY  10

#define SDXB_MAXLEN_DEF                 1024
#define ASYN_DEF_BAUDRATE               9600
#define ASYN_DEF_XON                    0x11
#define ASYN_DEF_XOFF                   0x13

#define SDXB_LTIME_DEF         100            // Line Error Report time in mSec
#define SDXB_LTIME_OFF         0           // Line Error Report is off

typedef struct ASYN_SDXB
{
    //
    // Port Speed and Processing Flags
    //
    DIGI_SPINLOCK       Lock;           // Spinlock to protect access 

    USHORT              SyncSeqNum;
    USHORT              SyncSeqAck;

    LIST_ENTRY          PendingIrps;    // Queue of pending irps awaiting a SDXB sync response

    UCHAR               PortType;       // Reported in port capabilities response
    ULONG               PortCapabilities;               

    struct sdxb_param_command   
                        PortParams;     // Structure used for SDXB port param requests 

    //
    // Event Reporting
    //
    USHORT              Estat;          // Active Event conditions.

    //
    // Modem Control Variables
    //
    UCHAR               Mout;           // Modem active signals.
    UCHAR               Mint;
    UCHAR               Mflow;          // Modem flow control.
    UCHAR               Mctrl;          // Modem flow control for out-of-band data.
    UCHAR               Mstat;          // Current Modem status.

    //
    // 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               Rmax;           // Max inbound bytes in SDXB's buffer before data is sent to the host
    ULONG               Rtime;          // Receive trigger time
    ULONG               Icdtime;        // Max. inter-character delay

    ULONG               Tmax;           // Outbound trigger level of flow control
    ULONG               Ttime;          // Tout report time (msec)

    SERIAL_HANDFLOW     Handflow;       // Flow control.
    SERIALPERF_STATS    PerfStats;
        
    ULONG               CommErr;        
                                        
    UCHAR               EofChar;        // Driver doesn't use, but keep for reporting
                                        //  on IOCTL_SERIAL_GET_CHARS request.
} ASYN_SDXB;

typedef struct WRITE_TIMER
{
    KTIMER              Timer;          // These are the varibles for the write time out 
    BOOLEAN             TimerOn;
    BOOLEAN             TimerInUse;
    KDPC                TimeOutDPC;
    LARGE_INTEGER       TimerLength;
    ULONG               TimeoutMultiplier;
    ULONG               TimeoutConstant;

} WRITE_TIMER;

typedef struct SEQUENCE
{
    ULONG               WaitTillDone;
    ULONG               CurrentCountOut;
    ULONG               CurrentCountIn;
    ULONG               CurrentCountReference;
                                        // This is user based, when the user wants to clear the stats.
    LIST_ENTRY          WaitTillCompleteQueue;
    DIGI_SPINLOCK       WaitLock;
    KEVENT              FlushEvent;
    LIST_ENTRY          FlushList;
    KEVENT              EmptyEvent;
    KEVENT              CancelEvent;
    BOOLEAN             WaitFlushEvent;
    BOOLEAN             WaitEmptyEvent;
    KEVENT              ClearEvent;
    BOOLEAN             WaitForWrite;

}SEQUENCE;

typedef struct ASYN_WRITE
{
    DIGI_SPINLOCK       Lock;           // Protects fields only in this struct

    BOOLEAN             fQueuing;       // Queue single-byte writes when done enmass

    ULONG               cbMaxPutMsg;    // Max number bytes to send in single PutMsg
    LIST_ENTRY          PendingQueue;   // Irps queued to be sent, not processed yet
    LIST_ENTRY          ActiveQueue;    // Irps in use, probably pending in dxb.

    //  HANDLE          WorkerThread;
    //  KEVENT          ThreadEvent;
    PVOID               pWorkerThread;
    KEVENT              WorkEvent;
    KEVENT              HaltEvent;
    WRITE_TIMER         WriteTimer;     
    SEQUENCE            Sequence;

    PIRP                ActiveIrp;
    BOOLEAN             TimeoutActive;
} ASYN_WRITE;

typedef struct ASYN_CLOSE
{
    KDPC                DPC;            // Close Timeout DPC
    KTIMER              Timer;          // Close Timer
    ULONG               TxDrainTimeout; 
    USHORT              SyncSeq;        // Expected sequence number on sync response
} ASYN_CLOSE;

typedef struct ASYN_ADAPTER_EXT *PASYN_ADAPTER_EXT;

typedef struct _TRACE_IOCTL
{
    LIST_ENTRY          TraceQueue;
    DIGI_SPINLOCK       TraceLock;
    KTIMER              TraceTimer;
    KDPC                TraceDpc;
    LARGE_INTEGER       Timeout;

}TRACE_IOCTL, *PTRACE_IOCTL;

typedef struct ASYN_PORT_EXT
{
    ASYN_OBJECT_TYPE    Type;           // ASYN_TYPE_PORT_EXT
    DIGI_SPINLOCK       Lock;           // Spinlock to protect access 
    LIST_ENTRY          ListEntry;      // Entry on adapter's Portlist (NT4.0) or gDeviceExtList (Win2k)

    PASYN_ADAPTER_EXT   pParentExt;     // Device Extension of parent device
                                                        
    PORT_STATE          State;          // Opening, Open, Closing, Idle.
    PDEVICE_OBJECT      pDevice;        // The Device Object for this Port.

    UNICODE_STRING      PortName;
    UNICODE_STRING      DeviceName;                     
    ULONG               iSdxbPort;
    HANDLE              DsHandle;       // Handle to DStreams service provider.
    HANDLE              DsPortHandle;   // Handle returned from DsOpen

    PIRP                pPendingIrp;    // Used during Create and Close

    ASYN_CLOSE          Close;          // Structure for close specific data    
    ASYN_SDXB           SdxbValues;     

    HANDLE              hRxEngine_HighPriority;
                                        // Self-contained engine which posts GetMsgs to Dxb
    HANDLE              hRxEngine_LowPriority;  

    ASYN_RXENGINE       RxEngine[DS_PRIORITY_COUNT];    

    ASYN_READ           Read;           // Structure for Read specific variables
    ASYN_WRITE          Write;          // Serial write specific data
    ASYN_WAIT           Wait;           // Wait event data

    TRACE_IOCTL         Trace;

#if NT5_BUILD
    PDEVICE_OBJECT      pPdo;           // Physical Device object created by PCI bus enumerator
    PDEVICE_OBJECT      pNextDeviceObject;
                                        // Could be different than Pdo if filter 
    ASYN_PNP_STATE      PnpState;                               
    ASYN_POWER_STATE    PowerState;     // current power state
    DEVICE_POWER_STATE  DevPower;       // current device power state
    SYSTEM_POWER_STATE  SysPower;       // current system power state
    SYSTEM_POWER_STATE  WakeSysPower;   // wakeup system power state
    UNICODE_STRING      DxbDevice;

    UNICODE_STRING      DeviceInterfaceSymbolicName; 
                                        // String returned by PnP manager when device is registered under comm class.
    ULONG               DeviceStateFlags;
                                        // Used to respond to IRP_MN_QUERY_DEVICE_STATE                                                         

#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 Xp )
    ULONG               IsModem;
    HANDLE              PnpModemDetectHandle;
    ULONG               AltPin;
    ULONG               fLowLatency;
} ASYN_PORT_EXT;

__inline VOID SetAsynPendingIrp(PIRP *ppPendingIrp,PIRP Irp) {
    PIRP OldIrp;

    OldIrp = (PIRP)InterlockedExchange((PLONG)ppPendingIrp,(LONG)Irp);

    if (OldIrp != NULL) {
        SRAPRINT(DBGLVL_ALWAYS,
                 ("SetAsynPendingIrp: pending irp %x, new irp %x\n",
                  OldIrp,Irp));
    }

    ASSERT(OldIrp == NULL);
}

__inline PIRP GetAsynPendingIrp(PIRP *ppPendingIrp) {
    return (PIRP)InterlockedExchange((PLONG)ppPendingIrp,(LONG)NULL);
}

typedef struct ASYN_ADAPTER_EXT
{
    ASYN_OBJECT_TYPE    Type;                                           // ASYN_TYPE_ADAPTER_EXT
    DIGI_SPINLOCK       Lock;                  // Covers all structures.
    HANDLE                      DsHandle;            // Handle to DStreams service provider.
    LIST_ENTRY          ListEntry;                              // Entry on gDeviceExtList

    PDEVICE_OBJECT              pDevice;                                        // The Device Object for this Adapter.

    UNICODE_STRING    InstanceName;                     // Adapter instance name. NT4.0: DigiDxb#       
    LIST_ENTRY                  PortList;            // List of Ports on this adapter

} ASYN_ADAPTER_EXT;


VOID  AsynIoCompleteRequest(            IN PIRP                         pIrp,
                                                                                IN NTSTATUS                     Status,
                                                                                IN PASYN_PORT_EXT       pPortExt );


// Function for DGA Requests.

NTSTATUS                DigiDgaIoctl(                   PDEVICE_OBJECT          DeviceObject,
                                                                                PIRP                            Irp );

NTSTATUS                GetControllerData(              PDEVICE_OBJECT          DeviceObject,
                                                                                PIRP                            Irp );

NTSTATUS                GetPortStatus(                  PDEVICE_OBJECT          DeviceObject,
                                                                                PIRP                            Irp );

PDEVICE_OBJECT  GetPortDeviceObject(    PDRIVER_OBJECT          DriverObject,
                                                                            ULONG                               ComPort);

void                    AsynTraceWriteIrp(              PASYN_PORT_EXT          pPortExt,
                                                                                PIRP                            pIrp );

void                    AsynTraceIoctlIrp(              PASYN_PORT_EXT          pPortExt,
                                                                                PIRP                            pIrp,
                                                                                BOOLEAN                         In,
                                                                                BOOLEAN                         Out);

void                    AsynTraceReadIrp(               PASYN_PORT_EXT          pPortExt,
                                                                                PIRP                            pIrp);

void                    AsynTraceTimeout(               IN PKDPC                        Dpc,
                                                                                IN PVOID                        DeferredContext,
                                                                                IN PVOID                        SystemContext1,
                                                                                IN PVOID                        SystemContext2  );

void                    AsynGetDeviceStatus(    PASYN_PORT_EXT          pPortExt,
                                                                                PPORT_STATUS            pPortStatus );

VOID                    AsynDeleteGlobalCardExt();


STATIC __inline BOOLEAN
RemoveIrpFromQueue( 
        IN PLIST_ENTRY  pIrpQ,  
   IN PIRP                      pIrp
)
/*++

Description

        Called to remove the specified irp from the queue.
   
--*/
{       
    PLIST_ENTRY ListEntry;
    BOOLEAN fIrpRemoved = FALSE;
   
    // Look for this Irp on the queue.
    for ( ListEntry = pIrpQ->Flink;
          ListEntry != pIrpQ; 
          ListEntry = ListEntry->Flink)
    {
        if ( pIrp == CONTAINING_RECORD( ListEntry, IRP, Tail.Overlay.ListEntry ))
        {
            // Found it.
            RemoveEntryList( &pIrp->Tail.Overlay.ListEntry );
            fIrpRemoved = TRUE;
            break;
        }
    }
    return fIrpRemoved;
}

#include "asynpower.h"

#endif

