/**
 * @file i4bcmgr_global.h
 *
 * I4BCMgr-Global - Common definitions for all i4bcapi modules.
 *
 * Copyright: 2000-2004 Thomas Wintergerst. All rights reserved.
 *
 * $FreeBSD$
 * $Id: i4bcmgr_var.h,v 1.1.2.1 2006/02/28 21:35:30 thomas Exp $
 * $Project:    CAPI for BSD $
 * $Target:     i4bcapimgr - The I4B driver for CAPI manager driven controllers $
 * @date        01.01.2000
 * @author      "Thomas Wintergerst" <twinterg@gmx.de>
 * <p>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * </p>
 */

#ifndef __I4BCMGR_GLOBAL_H
#define __I4BCMGR_GLOBAL_H

#include <sys/types.h>
#include <sys/lock.h>
#include <sys/sema.h>
#include <i4b_ioctl.h>

#include <i4b/include/i4b_global.h>
#include <i4b/include/i4b_l3l4.h>

#include <opt_i4bcapimgr.h>





/* === public declarations =============================================== */





/* Note: The partly necessary definitions for these declarations are made in
 *       i4bcapimgr.c.
 */



/* --- some constants --- */

/** The name of this kernel module. */
#define I4BCMGR_MODULE_NAME             "i4bcapimgr"

/** The version number of this kernel module, major part. */
#define I4BCMGR_MODULE_VERSION_MAJOR     0

/** The version number of this kernel module, minor part. */
#define I4BCMGR_MODULE_VERSION_MINOR     9

/** The name for the logging mask as a tunable kernel parameter. */
#define I4BCMGR_TUNABLE_LOGLEVEL \
   "capi." I4BCMGR_MODULE_NAME ".loglevel"

/** Request a CAPI receive window of size of 7 unconfirmed blocks. */
#define I4BCMGR_MAX_BDATA_BLOCKS        7



/* --- registering data for CAPI --- */

extern int      e_fCapiRegistered;
extern unsigned e_uCapiApplID;
extern unsigned e_uMaxCapiConnections;



/* --- mapping between i4b and CAPI controller numbers --- */

/* I4b is at maximum capable of handling MAX_CONTROLLERS controllers */
/* 0 means no CAPI controller exists for corresponding i4b controller no. */
extern unsigned e_auMapI4bToCapiCtlr [MAX_CONTROLLERS];



/* --- some definitions for the CAPI state machines --- */

/* Important: These values are used to index some arrays for translation into
 *            strings. If the enum definition is modified, the mentioned arrays
 *            must be modified, too.
 */
 
/* the PLCI states */
typedef enum
{
   PLCI_STATE_P0,       /* idle state */
   PLCI_STATE_P0_1,     /* connect-req sent, wait for connect-conf */
   PLCI_STATE_P1,       /* connect-conf received, wait for connect-active-ind
                         */
   PLCI_STATE_P2,       /* connect-ind received; wait for extension numbers,
                         * decide wether to go to P4 or P5, must send
                         * connect-resp
                         */
   PLCI_STATE_P3,       /* handset support, not implemented */
   PLCI_STATE_P4,       /* connect-resp sent, wait for connect-active-ind */
   PLCI_STATE_PACT,     /* active state, B-channel switched */
   PLCI_STATE_P5,       /* disconnect-req sent, wait for disconnect-ind */
   PLCI_STATE_P6,       /* got disconnect-ind, next state is P0 */
   NUM_PLCI_STATES      /* number of PLCI states */
} I4bCapiPlciState_t;

/* the NCCI states */
typedef enum
{
   NCCI_STATE_N0,       /* idle state */
   NCCI_STATE_N0_1,     /* connect-b3-req sent, wait for connect-b3-conf to go
                         * to N2
                         */
   NCCI_STATE_N1,       /* got connect-b3-ind, next state is N2 */
   NCCI_STATE_N2,       /* wait for connect-b3-active-ind */
   NCCI_STATE_NACT,     /* active state, connection established */
   NCCI_STATE_N3,       /* resetting B3 connection, not implmented */
   NCCI_STATE_N4,       /* disconnect-b3-req sent, wait for disconnect-b3-ind
                         */
   NCCI_STATE_N5,       /* got disconnect-b3-ind, next state is N0 */
   NUM_NCCI_STATES      /* number of NCCI states */
} I4bCapiNcciState_t;



/* --- data for available CAPI controllers --- */

struct i4bcapimgr_ctlr_data;

/* data for each possible connection */
typedef struct
{
   /* the link to the corresponding CAPI controller */
   struct i4bcapimgr_ctlr_data *pCtlrData;

   /* our own channel number (index in connection array for controller) */
   unsigned uBChn;
   
   /* the address of the i4b call descriptor used for the connection; if NULL,
    * there is currently no connection for this (virtual) B-channel
    */
   call_desc_t *pI4bCd;
   u_int        uCdId;
   
   /* flag if someone is waiting for this connection to finish */
   int fDisconnectSleeping;
   
   /* data for communication with i4b layer 4 */
   struct mbuf    *pmbInBuf;            /* input buffer for raw HDLC B-channel
                                         * protocol; mbuf is handled directly
                                         * after receiving a data block, thus
                                         * no queue necessary
                                         */
   struct ifqueue  rxQueue;             /* queue for incoming data for
                                         * telephony (no B-channel protocol)
                                         */
   unsigned        uRxCount;            /* no. of bytes received since last
                                         * call for channel state
                                         */
   struct ifqueue  txQueue;             /* queue for data to send */
   unsigned        uTxCount;            /* no. of bytes sent since last call to
                                         * for channel state
                                         */
   struct mbuf    *pmbOutCapiMsg;       /* if not NULL: there is still a
                                         * Data-B3-Req pending (last
                                         * kcapi_put_message failed due to full
                                         * CAPI send queue), the mbuf is the
                                         * Data-B3-Req CAPI message
                                         */
   isdn_link_t     isdnLinkTab;         /* our side of the link to the layer 4
                                         * driver
                                         */
   drvr_link_t    *pDrvrLinkTab;        /* the other side of the link to the
                                         * layer 4 driver
                                         */
   unsigned        uLastDataHandle;     /* the data handle (i.e. running block
                                         * number) for the last data block sent
                                         */
   unsigned        uConfirmedDataHandle;/* the data handle for the last data
                                         * block confirmed; is equal to
                                         * uLastDataHandle if all blocks are
                                         * confirmed, else must wait for
                                         * outstanding Data-B3-Conf
                                         */
   unsigned        uDataBlockRetries;   /* no. of attempts to send the current
                                         * data block; if at most
                                         * NCCI_MAX_DATA_SEND_RETRIES failed,
                                         * the connection will be aborted
                                         */
   
   /* data for the PLCI state machine */
   I4bCapiPlciState_t    plciState;     /* the current PLCI state */
   u_int32_t             dwPlci;        /* the current connection identifier */
#if (defined (__FreeBSD_version) && __FreeBSD_version >= 300001) || \
     (! defined (__FreeBSD_version) &&                            \
      defined (__FreeBSD__) && __FreeBSD__ >= 3)
   struct callout_handle calloutPlci;   /* handle for PLCI layer timeouts */
#endif
#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
   struct callout        calloutPlci;   /* handle for PLCI layer timeouts */
#endif
   int                   fPlciCalloutInitOk;
                                        /* 0: timeout handle not initialized
                                         * 1: timeout handle initialized, is
                                         *    usable
                                         */
   int                   fPlciTimerRunning;
                                        /* 0: timer is not running
                                         * 1: timer is currently running
                                         */
   unsigned              uLastIndMsgNum;/* the message number for a CAPI
                                         * indication message; is currently
                                         * used to save the message number of a
                                         * Connect-Ind until the Connect-Resp
                                         * must be sent
                                         */
   size_t                nNumDiscReq;   /* the number of Disconnect-Reqs sent
                                         * for the current connection; if one
                                         * Disconnect-Req failed, a second is
                                         * tried, but a third would make no
                                         * sense
                                         */
   
   /* data for the NCCI state machine */
   I4bCapiNcciState_t    ncciState;     /* the current NCCI state */
   u_int32_t             dwNcci;        /* the current connection identifier */
   int                   fActiveConnectB3;
                                        /* 0: passive connection establishment
                                         *    (wait for Connect-B3-Ind)
                                         * 1: B3-connection must actively
                                         *    established (send Connect-B3-Req)
                                         */
   int                   fActiveDisconnectB3;
                                        /* 0: passive disconnecting (got
                                         *    Disconnect-B3-Ind, wait for
                                         *    Disconnect-Ind)
                                         * 1: active disconnecting
                                         *    (Disconnect-B3-Req sent, send
                                         *    Disconnect-Req)
                                         */
#if (defined (__FreeBSD_version) && __FreeBSD_version >= 300001) || \
     (! defined (__FreeBSD_version) &&                            \
      defined (__FreeBSD__) && __FreeBSD__ >= 3)
   struct callout_handle calloutNcci;   /* handle for NCCI layer timeouts */
#endif
#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
   struct callout        calloutNcci;   /* handle for NCCI layer timeouts */
#endif
   int                   fNcciCalloutInitOk;
                                        /* 0: timeout handle not initialized
                                         * 1: timeout handle initialized, is
                                         *    usable
                                         */
   int                   fNcciTimerRunning;
                                        /* 0: timer is not running
                                         * 1: timre is currently running
                                         */
   
} I4bCapiConnectionData_t;

/* flags for supported controller features */
#define I4BCMGR_FEATURE_FLAG_HDLC          0x00000001
#define I4BCMGR_FEATURE_FLAG_TRANSPARENT   0x00000002

/* the data structure for a CAPI controller */
typedef struct i4bcapimgr_ctlr_data
{
   int                      fEntryUsed; /* flag for used controller entry */
   unsigned                 uCapiCtlrNum;
                                        /* CAPI controller no. for this entry,
                                         * is equal to the array index into
                                         * e_aI4bCapiCtlrData
                                         */
   int                      iI4bCtlrNum;/* i4b controller no. if registered, -1
                                         * if not (yet) registered
                                         */
   unsigned                 uFeatureFlags;
                                        /* flags of supported features, values
                                         * from I4BCMGR_FEATURE_FLAG_*
                                         */
   size_t                   nNumBChannels;
                                        /* the number of B-channels, lenght of
                                         * array paConnData
                                         */
   I4bCapiConnectionData_t *paConnData; /* connection data for each B-channel,
                                         * indexed by B-channel no. starting at
                                         * 0; only valid if iI4bCtlrNum >= 0
                                         * (controller registered at i4b)
                                         */
} I4bCapiCtlrData_t;

/* For CAPI a maximum number of 127 controllers is defined, starting at 1. */
extern I4bCapiCtlrData_t e_aI4bCapiCtlrData [128];



/* --- messages for the message queue to i4bcapimgr from i4b layer 4 --- */

/* Important: The values are used to index an array of strings for the
 *            identifiers in i4bcapimgr.c!
 */
typedef enum
{
   I4BCMGR_EVENT_CONN_REQ = 0,
   I4BCMGR_EVENT_CONN_RESP,
   I4BCMGR_EVENT_DISC_REQ,
   I4BCMGR_EVENT_ALERT_REQ,
   I4BCMGR_EVENT_BCH_CONFIG_UP,
   I4BCMGR_EVENT_BCH_CONFIG_DOWN,
   I4BCMGR_EVENT_BCH_TX_START,
   I4BCMGR_EVENT_NCCI_TIMEOUT,
   I4BCMGR_EVENT_PLCI_TIMEOUT,
   NUM_I4BCMGR_EVENTS
} I4bCapiEventType_t;

/* additional data for i4b event NConnectResponse */
typedef struct
{
   int iResponse;
   int iCause;
} I4bCEventConnectRespData_t;

/* additional data for i4b event NDisconnectRequest */
typedef struct
{
   int iCause;
} I4bCEventDisconnectReqData_t;

/* additional data for i4b event bch_config_up */
typedef struct
{
   int iBProt;
} I4bCEventBChConfigUpData_t;

/* accumulation of additional data for i4b event */
typedef union
{
   I4bCEventConnectRespData_t   connResp;
   I4bCEventDisconnectReqData_t discReq;
   I4bCEventBChConfigUpData_t   bchConfigUp;
} I4bCapiEventData_t;



/* --- the event queue to communicate with i4bcapimgr from i4b layer 4 --- */

typedef struct I4bCEventQueueEntry
{
   /* the links for the event queue and the free list */
   union
   {
      TAILQ_ENTRY (I4bCEventQueueEntry) tqe;
      SLIST_ENTRY (I4bCEventQueueEntry) sle;
   } links;
   
   /* if CAPI ctlr. no. and B-channel no. are known, they should be filled in
    * to speed determining the connection data entry; otherwise UINT_MAX must
    * be entered and uCdId must contain the call descriptor no.
    */
   unsigned           uCapiCtlrNum;
   unsigned           uBChn;
   u_int              uCdId;
   I4bCapiEventType_t event;
   I4bCapiEventData_t data;
} I4bCEventQueueEntry_t;

/* the queue of messages to handle */
TAILQ_HEAD (I4bCEventQueue, I4bCEventQueueEntry);
extern struct I4bCEventQueue e_eventQueue;

/* the list of unused message objects */
SLIST_HEAD (I4bCEventFreeList, I4bCEventQueueEntry);
extern struct I4bCEventFreeList e_eventFreeList;

/** Semaphore to signal a new message in the queue. */
extern struct sema e_semMsgAvail;



/* --- the logging functionality --- */

/** The logging levels supported. */
#define LOG_ALWAYS      0
#define LOG_ERROR       1
#define LOG_INFO        2
#define LOG_TRACE       3
#define LOG_DEBUG       4
#define LOG_DATAMSG     5

/**
 * Characters to mark log messages with their severity.
 *
 * @note The array-string is indexed by the log level.
 */
#define LOG_CHARS       "AEMTDD"

/** The current logging level. */
extern int e_iI4bCapiLogLevel;

/** The macro for log output with no unit number available. */
#define DBG( level, fmt, args... )                        \
   if ((level) <= e_iI4bCapiLogLevel)                     \
   {                                                      \
      printf ("i4bcapimgr: %c %s: " fmt "\n",             \
              LOG_CHARS [level], __FUNCTION__ , ## args); \
   }



/* --- Compatibility macros / functions --- */

/* only for historical reasons (to be removed) */
#define IF_VAR



/* --- some helper macros --- */

#define ARRAY_COUNT( a )        (sizeof (a) / sizeof (a [0]))





/* === prototypes of interface functions ================================= */





/* --- driver entry functions for i4b layer 4 --- */

/* start new outgoing connection */
extern void I4bCmgr_NConnectRequest
   (u_int uCdId);
   
/* answer new incoming call */
extern void I4bCmgr_NConnectResponse
   (u_int uCdId,
    int   iResponse,
    int   iCause);
    
/* do an active disconnect for a call */
extern void I4bCmgr_NDisconnectRequest
   (u_int uCdId,
    int   iCause);

/* tell the switch to wait with expiring new incoming call */
extern void I4bCmgr_NAlertRequest
   (u_int uCdId);
   
/* download firmware to controller */
extern int I4bCmgr_NDownload
   (int                  iUnit,
    int                  iNumProtocols,
    struct isdn_dr_prot *pProtocols);

/* handle layer 4 management commands */
extern void I4bCmgr_NMgmtCommand
   (int   iUnit,
    int   iCmd,
    void *pParam);




/* --- driver entry functions for data transfer control (linktabs) --- */

/* read the linktab to the i4bcapimgr connection handler */
extern isdn_link_t *I4bCmgr_GetLinkTab  /* the link to i4bcapimgr conn. handler,
                                         * NULL if parameters do not identify a
                                         * valid B-channel connection
                                         */
   (int iUnit,                          /* I: unit no. of the ctlr. driver;
                                         *    for i4bcapimgr it is equal to the
                                         *    CAPI controller number
                                         */
    int iChannel);                      /* I: B-channel no., starting at 0 */

/* store linktab to the app. driver into i4bcapimgr connection data */
extern void I4bCmgr_SetLinkTab
   (int          iUnit,                 /* I: unit no. of the ctlr. driver;
                                         *    for i4bcapimgr it es equal to the
                                         *    CAPI controller number
                                         */
    int          iChannel,              /* I: B-channel no., starting at 0 */
    drvr_link_t *pDrvrLinkTab);         /* I: link to the i4b app. driver */

/* configure the B-channel settings */
extern void I4bCmgr_BChConfig
   (int iUnit,                          /* I: unit no. of the ctlr. driver;
                                         *    for i4bcapimgr it es equal to the
                                         *    CAPI controller number
                                         */
    int iChannel,                       /* I: B-channel no., starting at 0 */
    int iBProt,                         /* I: B-channel protocol, values from
                                         *    BPROT_* (i4b_ioctl.h)
                                         */
    int fUp);                           /* I: 0: switch B-channel off
                                         *    1: switch B-channel on
                                         */

/* start transmission of B-channel data */
extern void I4bCmgr_BchTxStart
   (int iUnit,                          /* I: unit no. of the ctlr. driver;
                                         *    for i4bcapimgr it es equal to the
                                         *    CAPI controller number
                                         */
    int iChannel);                      /* I: B-channel no., starting at 0 */

/* read status of B-channel data transmission */
extern void I4bCmgr_Stat
   (int                 iUnit,          /* I: unit no. of the ctlr. driver;
                                         *    for i4bcapimgr it es equal to the
                                         *    CAPI controller number
                                         */
    int                 iChannel,       /* I: B-channel no., starting at 0 */
    bchan_statistics_t *pBChnStat);     /* O: requested statistic data (bytes
                                         *    received and bytes sent)
                                         */



/* --- functions for CAPI events --- */

/* handle the signal for an incoming CAPI message */
#if defined(__alpha__) || defined (__ia64__) || defined (__amd64__) || defined (__sparc64__)
void I4bCmgr_CapiCallback
   (unsigned  uApplID,
    u_int64_t qwParam);
#else /* __alpha__ || __ia64__ || __amd64__ || __sparc64__ */
void I4bCmgr_CapiCallback
   (unsigned  uApplID,
    u_int32_t dwParam);
#endif /* __alpha__ || __ia64__ || __amd64__ || __sparc64__ */



/* --- mapping between i4b data to connection data entries --- */

/* get connection data entry from i4b call descriptor id */
extern I4bCapiConnectionData_t *I4bCmgr_GetConnDataByCdId
   (u_int uCdId);

/* get connection data entry from unit and channel number */
extern I4bCapiConnectionData_t *I4bCmgr_GetConnDataByUnitAndChannel
   (int iUnit,
    int iChannel);



/* --- some helper functions --- */

/* get memory for a new i4bcapimgr message */
extern I4bCEventQueueEntry_t *I4bCmgr_GetFreeEventQueueEntry (void);

/* translate i4bcapimgr event to string */
extern const char *I4bCmgr_GetI4bCEventName
   (I4bCapiEventType_t event);





/* === definition of inline functions ==================================== */





#endif /* __I4BCMGR_GLOBAL_H */
