aboutsummaryrefslogtreecommitdiff
path: root/drivers/isdn/hardware/eicon/message.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/hardware/eicon/message.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/isdn/hardware/eicon/message.c')
-rw-r--r--drivers/isdn/hardware/eicon/message.c15047
1 files changed, 15047 insertions, 0 deletions
diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
new file mode 100644
index 00000000000..f9b00f19afd
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/message.c
@@ -0,0 +1,15047 @@
+
+/*
+ *
+ Copyright (c) Eicon Networks, 2002.
+ *
+ This source file is supplied for the use with
+ Eicon Networks range of DIVA Server Adapters.
+ *
+ Eicon File Revision : 2.1
+ *
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+ *
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+ *
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+
+
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "capi20.h"
+#include "divacapi.h"
+#include "mdm_msg.h"
+#include "divasync.h"
+
+
+
+#define FILE_ "MESSAGE.C"
+#define dprintf
+
+
+
+
+
+
+
+
+
+/*------------------------------------------------------------------*/
+/* This is options supported for all adapters that are server by */
+/* XDI driver. Allo it is not necessary to ask it from every adapter*/
+/* and it is not necessary to save it separate for every adapter */
+/* Macrose defined here have only local meaning */
+/*------------------------------------------------------------------*/
+static dword diva_xdi_extended_features = 0;
+
+#define DIVA_CAPI_USE_CMA 0x00000001
+#define DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR 0x00000002
+#define DIVA_CAPI_XDI_PROVIDES_NO_CANCEL 0x00000004
+#define DIVA_CAPI_XDI_PROVIDES_RX_DMA 0x00000008
+
+/*
+ CAPI can request to process all return codes self only if:
+ protocol code supports this && xdi supports this
+ */
+#define DIVA_CAPI_SUPPORTS_NO_CANCEL(__a__) (((__a__)->manufacturer_features&MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)&& ((__a__)->manufacturer_features & MANUFACTURER_FEATURE_OK_FC_LABEL) && (diva_xdi_extended_features & DIVA_CAPI_XDI_PROVIDES_NO_CANCEL))
+
+/*------------------------------------------------------------------*/
+/* local function prototypes */
+/*------------------------------------------------------------------*/
+
+static void group_optimization(DIVA_CAPI_ADAPTER * a, PLCI * plci);
+static void set_group_ind_mask (PLCI *plci);
+static void clear_group_ind_mask_bit (PLCI *plci, word b);
+static byte test_group_ind_mask_bit (PLCI *plci, word b);
+void AutomaticLaw(DIVA_CAPI_ADAPTER *);
+word CapiRelease(word);
+word CapiRegister(word);
+word api_put(APPL *, CAPI_MSG *);
+static word api_parse(byte *, word, byte *, API_PARSE *);
+static void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out);
+static void api_load_msg(API_SAVE *in, API_PARSE *out);
+
+word api_remove_start(void);
+void api_remove_complete(void);
+
+static void plci_remove(PLCI *);
+static void diva_get_extended_adapter_features (DIVA_CAPI_ADAPTER * a);
+static void diva_ask_for_xdi_sdram_bar (DIVA_CAPI_ADAPTER *, IDI_SYNC_REQ *);
+
+void callback(ENTITY *);
+
+static void control_rc(PLCI *, byte, byte, byte, byte, byte);
+static void data_rc(PLCI *, byte);
+static void data_ack(PLCI *, byte);
+static void sig_ind(PLCI *);
+static void SendInfo(PLCI *, dword, byte * *, byte);
+static void SendSetupInfo(APPL *, PLCI *, dword, byte * *, byte);
+static void SendSSExtInd(APPL *, PLCI * plci, dword Id, byte * * parms);
+
+static void VSwitchReqInd(PLCI *plci, dword Id, byte **parms);
+
+static void nl_ind(PLCI *);
+
+static byte connect_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte connect_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte connect_a_res(dword,word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte disconnect_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte disconnect_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte listen_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte info_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte info_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte alert_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte facility_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte facility_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte connect_b3_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte connect_b3_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte connect_b3_a_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte disconnect_b3_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte disconnect_b3_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte data_b3_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte data_b3_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte reset_b3_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte reset_b3_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte connect_b3_t90_a_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte select_b_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte manufacturer_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+static byte manufacturer_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+
+static word get_plci(DIVA_CAPI_ADAPTER *);
+static void add_p(PLCI *, byte, byte *);
+static void add_s(PLCI * plci, byte code, API_PARSE * p);
+static void add_ss(PLCI * plci, byte code, API_PARSE * p);
+static void add_ie(PLCI * plci, byte code, byte * p, word p_length);
+static void add_d(PLCI *, word, byte *);
+static void add_ai(PLCI *, API_PARSE *);
+static word add_b1(PLCI *, API_PARSE *, word, word);
+static word add_b23(PLCI *, API_PARSE *);
+static word add_modem_b23 (PLCI * plci, API_PARSE* bp_parms);
+static void sig_req(PLCI *, byte, byte);
+static void nl_req_ncci(PLCI *, byte, byte);
+static void send_req(PLCI *);
+static void send_data(PLCI *);
+static word plci_remove_check(PLCI *);
+static void listen_check(DIVA_CAPI_ADAPTER *);
+static byte AddInfo(byte **, byte **, byte *, byte *);
+static byte getChannel(API_PARSE *);
+static void IndParse(PLCI *, word *, byte **, byte);
+static byte ie_compare(byte *, byte *);
+static word find_cip(DIVA_CAPI_ADAPTER *, byte *, byte *);
+static word CPN_filter_ok(byte *cpn,DIVA_CAPI_ADAPTER *,word);
+
+/*
+ XON protocol helpers
+ */
+static void channel_flow_control_remove (PLCI * plci);
+static void channel_x_off (PLCI * plci, byte ch, byte flag);
+static void channel_x_on (PLCI * plci, byte ch);
+static void channel_request_xon (PLCI * plci, byte ch);
+static void channel_xmit_xon (PLCI * plci);
+static int channel_can_xon (PLCI * plci, byte ch);
+static void channel_xmit_extended_xon (PLCI * plci);
+
+static byte SendMultiIE(PLCI * plci, dword Id, byte * * parms, byte ie_type, dword info_mask, byte setupParse);
+static word AdvCodecSupport(DIVA_CAPI_ADAPTER *, PLCI *, APPL *, byte);
+static void CodecIdCheck(DIVA_CAPI_ADAPTER *, PLCI *);
+static void SetVoiceChannel(PLCI *, byte *, DIVA_CAPI_ADAPTER * );
+static void VoiceChannelOff(PLCI *plci);
+static void adv_voice_write_coefs (PLCI *plci, word write_command);
+static void adv_voice_clear_config (PLCI *plci);
+
+static word get_b1_facilities (PLCI * plci, byte b1_resource);
+static byte add_b1_facilities (PLCI * plci, byte b1_resource, word b1_facilities);
+static void adjust_b1_facilities (PLCI *plci, byte new_b1_resource, word new_b1_facilities);
+static word adjust_b_process (dword Id, PLCI *plci, byte Rc);
+static void adjust_b1_resource (dword Id, PLCI *plci, API_SAVE *bp_msg, word b1_facilities, word internal_command);
+static void adjust_b_restore (dword Id, PLCI *plci, byte Rc);
+static void reset_b3_command (dword Id, PLCI *plci, byte Rc);
+static void select_b_command (dword Id, PLCI *plci, byte Rc);
+static void fax_connect_ack_command (dword Id, PLCI *plci, byte Rc);
+static void fax_edata_ack_command (dword Id, PLCI *plci, byte Rc);
+static void fax_connect_info_command (dword Id, PLCI *plci, byte Rc);
+static void fax_adjust_b23_command (dword Id, PLCI *plci, byte Rc);
+static void fax_disconnect_command (dword Id, PLCI *plci, byte Rc);
+static void hold_save_command (dword Id, PLCI *plci, byte Rc);
+static void retrieve_restore_command (dword Id, PLCI *plci, byte Rc);
+static void init_b1_config (PLCI *plci);
+static void clear_b1_config (PLCI *plci);
+
+static void dtmf_command (dword Id, PLCI *plci, byte Rc);
+static byte dtmf_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg);
+static void dtmf_confirmation (dword Id, PLCI *plci);
+static void dtmf_indication (dword Id, PLCI *plci, byte *msg, word length);
+static void dtmf_parameter_write (PLCI *plci);
+
+
+static void mixer_set_bchannel_id_esc (PLCI *plci, byte bchannel_id);
+static void mixer_set_bchannel_id (PLCI *plci, byte *chi);
+static void mixer_clear_config (PLCI *plci);
+static void mixer_notify_update (PLCI *plci, byte others);
+static void mixer_command (dword Id, PLCI *plci, byte Rc);
+static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg);
+static void mixer_indication_coefs_set (dword Id, PLCI *plci);
+static void mixer_indication_xconnect_from (dword Id, PLCI *plci, byte *msg, word length);
+static void mixer_indication_xconnect_to (dword Id, PLCI *plci, byte *msg, word length);
+static void mixer_remove (PLCI *plci);
+
+
+static void ec_command (dword Id, PLCI *plci, byte Rc);
+static byte ec_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg);
+static void ec_indication (dword Id, PLCI *plci, byte *msg, word length);
+
+
+static void rtp_connect_b3_req_command (dword Id, PLCI *plci, byte Rc);
+static void rtp_connect_b3_res_command (dword Id, PLCI *plci, byte Rc);
+
+
+static int diva_get_dma_descriptor (PLCI *plci, dword *dma_magic);
+static void diva_free_dma_descriptor (PLCI *plci, int nr);
+
+/*------------------------------------------------------------------*/
+/* external function prototypes */
+/*------------------------------------------------------------------*/
+
+extern byte MapController (byte);
+extern byte UnMapController (byte);
+#define MapId(Id) (((Id) & 0xffffff00L) | MapController ((byte)(Id)))
+#define UnMapId(Id) (((Id) & 0xffffff00L) | UnMapController ((byte)(Id)))
+
+void sendf(APPL *, word, dword, word, byte *, ...);
+void * TransmitBufferSet(APPL * appl, dword ref);
+void * TransmitBufferGet(APPL * appl, void * p);
+void TransmitBufferFree(APPL * appl, void * p);
+void * ReceiveBufferGet(APPL * appl, int Num);
+
+int fax_head_line_time (char *buffer);
+
+
+/*------------------------------------------------------------------*/
+/* Global data definitions */
+/*------------------------------------------------------------------*/
+extern byte max_adapter;
+extern byte max_appl;
+extern DIVA_CAPI_ADAPTER * adapter;
+extern APPL * application;
+
+
+
+
+
+
+
+static byte remove_started = FALSE;
+static PLCI dummy_plci;
+
+
+static struct _ftable {
+ word command;
+ byte * format;
+ byte (* function)(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
+} ftable[] = {
+ {_DATA_B3_R, "dwww", data_b3_req},
+ {_DATA_B3_I|RESPONSE, "w", data_b3_res},
+ {_INFO_R, "ss", info_req},
+ {_INFO_I|RESPONSE, "", info_res},
+ {_CONNECT_R, "wsssssssss", connect_req},
+ {_CONNECT_I|RESPONSE, "wsssss", connect_res},
+ {_CONNECT_ACTIVE_I|RESPONSE, "", connect_a_res},
+ {_DISCONNECT_R, "s", disconnect_req},
+ {_DISCONNECT_I|RESPONSE, "", disconnect_res},
+ {_LISTEN_R, "dddss", listen_req},
+ {_ALERT_R, "s", alert_req},
+ {_FACILITY_R, "ws", facility_req},
+ {_FACILITY_I|RESPONSE, "ws", facility_res},
+ {_CONNECT_B3_R, "s", connect_b3_req},
+ {_CONNECT_B3_I|RESPONSE, "ws", connect_b3_res},
+ {_CONNECT_B3_ACTIVE_I|RESPONSE, "", connect_b3_a_res},
+ {_DISCONNECT_B3_R, "s", disconnect_b3_req},
+ {_DISCONNECT_B3_I|RESPONSE, "", disconnect_b3_res},
+ {_RESET_B3_R, "s", reset_b3_req},
+ {_RESET_B3_I|RESPONSE, "", reset_b3_res},
+ {_CONNECT_B3_T90_ACTIVE_I|RESPONSE, "ws", connect_b3_t90_a_res},
+ {_CONNECT_B3_T90_ACTIVE_I|RESPONSE, "", connect_b3_t90_a_res},
+ {_SELECT_B_REQ, "s", select_b_req},
+ {_MANUFACTURER_R, "dws", manufacturer_req},
+ {_MANUFACTURER_I|RESPONSE, "dws", manufacturer_res},
+ {_MANUFACTURER_I|RESPONSE, "", manufacturer_res}
+};
+
+static byte * cip_bc[29][2] = {
+ { "", "" }, /* 0 */
+ { "\x03\x80\x90\xa3", "\x03\x80\x90\xa2" }, /* 1 */
+ { "\x02\x88\x90", "\x02\x88\x90" }, /* 2 */
+ { "\x02\x89\x90", "\x02\x89\x90" }, /* 3 */
+ { "\x03\x90\x90\xa3", "\x03\x90\x90\xa2" }, /* 4 */
+ { "\x03\x91\x90\xa5", "\x03\x91\x90\xa5" }, /* 5 */
+ { "\x02\x98\x90", "\x02\x98\x90" }, /* 6 */
+ { "\x04\x88\xc0\xc6\xe6", "\x04\x88\xc0\xc6\xe6" }, /* 7 */
+ { "\x04\x88\x90\x21\x8f", "\x04\x88\x90\x21\x8f" }, /* 8 */
+ { "\x03\x91\x90\xa5", "\x03\x91\x90\xa5" }, /* 9 */
+ { "", "" }, /* 10 */
+ { "", "" }, /* 11 */
+ { "", "" }, /* 12 */
+ { "", "" }, /* 13 */
+ { "", "" }, /* 14 */
+ { "", "" }, /* 15 */
+
+ { "\x03\x80\x90\xa3", "\x03\x80\x90\xa2" }, /* 16 */
+ { "\x03\x90\x90\xa3", "\x03\x90\x90\xa2" }, /* 17 */
+ { "\x02\x88\x90", "\x02\x88\x90" }, /* 18 */
+ { "\x02\x88\x90", "\x02\x88\x90" }, /* 19 */
+ { "\x02\x88\x90", "\x02\x88\x90" }, /* 20 */
+ { "\x02\x88\x90", "\x02\x88\x90" }, /* 21 */
+ { "\x02\x88\x90", "\x02\x88\x90" }, /* 22 */
+ { "\x02\x88\x90", "\x02\x88\x90" }, /* 23 */
+ { "\x02\x88\x90", "\x02\x88\x90" }, /* 24 */
+ { "\x02\x88\x90", "\x02\x88\x90" }, /* 25 */
+ { "\x03\x91\x90\xa5", "\x03\x91\x90\xa5" }, /* 26 */
+ { "\x03\x91\x90\xa5", "\x03\x91\x90\xa5" }, /* 27 */
+ { "\x02\x88\x90", "\x02\x88\x90" } /* 28 */
+};
+
+static byte * cip_hlc[29] = {
+ "", /* 0 */
+ "", /* 1 */
+ "", /* 2 */
+ "", /* 3 */
+ "", /* 4 */
+ "", /* 5 */
+ "", /* 6 */
+ "", /* 7 */
+ "", /* 8 */
+ "", /* 9 */
+ "", /* 10 */
+ "", /* 11 */
+ "", /* 12 */
+ "", /* 13 */
+ "", /* 14 */
+ "", /* 15 */
+
+ "\x02\x91\x81", /* 16 */
+ "\x02\x91\x84", /* 17 */
+ "\x02\x91\xa1", /* 18 */
+ "\x02\x91\xa4", /* 19 */
+ "\x02\x91\xa8", /* 20 */
+ "\x02\x91\xb1", /* 21 */
+ "\x02\x91\xb2", /* 22 */
+ "\x02\x91\xb5", /* 23 */
+ "\x02\x91\xb8", /* 24 */
+ "\x02\x91\xc1", /* 25 */
+ "\x02\x91\x81", /* 26 */
+ "\x03\x91\xe0\x01", /* 27 */
+ "\x03\x91\xe0\x02" /* 28 */
+};
+
+/*------------------------------------------------------------------*/
+
+#define V120_HEADER_LENGTH 1
+#define V120_HEADER_EXTEND_BIT 0x80
+#define V120_HEADER_BREAK_BIT 0x40
+#define V120_HEADER_C1_BIT 0x04
+#define V120_HEADER_C2_BIT 0x08
+#define V120_HEADER_FLUSH_COND (V120_HEADER_BREAK_BIT | V120_HEADER_C1_BIT | V120_HEADER_C2_BIT)
+
+static byte v120_default_header[] =
+{
+
+ 0x83 /* Ext, BR , res, res, C2 , C1 , B , F */
+
+};
+
+static byte v120_break_header[] =
+{
+
+ 0xc3 | V120_HEADER_BREAK_BIT /* Ext, BR , res, res, C2 , C1 , B , F */
+
+};
+
+
+/*------------------------------------------------------------------*/
+/* API_PUT function */
+/*------------------------------------------------------------------*/
+
+word api_put(APPL * appl, CAPI_MSG * msg)
+{
+ word i, j, k, l, n;
+ word ret;
+ byte c;
+ byte controller;
+ DIVA_CAPI_ADAPTER * a;
+ PLCI * plci;
+ NCCI * ncci_ptr;
+ word ncci;
+ CAPI_MSG *m;
+ API_PARSE msg_parms[MAX_MSG_PARMS+1];
+
+ if (msg->header.length < sizeof (msg->header) ||
+ msg->header.length > MAX_MSG_SIZE) {
+ dbug(1,dprintf("bad len"));
+ return _BAD_MSG;
+ }
+
+ controller = (byte)((msg->header.controller &0x7f)-1);
+
+ /* controller starts with 0 up to (max_adapter - 1) */
+ if ( controller >= max_adapter )
+ {
+ dbug(1,dprintf("invalid ctrl"));
+ return _BAD_MSG;
+ }
+
+ a = &adapter[controller];
+ plci = NULL;
+ if ((msg->header.plci != 0) && (msg->header.plci <= a->max_plci) && !a->adapter_disabled)
+ {
+ dbug(1,dprintf("plci=%x",msg->header.plci));
+ plci = &a->plci[msg->header.plci-1];
+ ncci = GET_WORD(&msg->header.ncci);
+ if (plci->Id
+ && (plci->appl
+ || (plci->State == INC_CON_PENDING)
+ || (plci->State == INC_CON_ALERT)
+ || (msg->header.command == (_DISCONNECT_I|RESPONSE)))
+ && ((ncci == 0)
+ || (msg->header.command == (_DISCONNECT_B3_I|RESPONSE))
+ || ((ncci < MAX_NCCI+1) && (a->ncci_plci[ncci] == plci->Id))))
+ {
+ i = plci->msg_in_read_pos;
+ j = plci->msg_in_write_pos;
+ if (j >= i)
+ {
+ if (j + msg->header.length + MSG_IN_OVERHEAD <= MSG_IN_QUEUE_SIZE)
+ i += MSG_IN_QUEUE_SIZE - j;
+ else
+ j = 0;
+ }
+ else
+ {
+
+ n = (((CAPI_MSG *)(plci->msg_in_queue))->header.length + MSG_IN_OVERHEAD + 3) & 0xfffc;
+
+ if (i > MSG_IN_QUEUE_SIZE - n)
+ i = MSG_IN_QUEUE_SIZE - n + 1;
+ i -= j;
+ }
+
+ if (i <= ((msg->header.length + MSG_IN_OVERHEAD + 3) & 0xfffc))
+
+ {
+ dbug(0,dprintf("Q-FULL1(msg) - len=%d write=%d read=%d wrap=%d free=%d",
+ msg->header.length, plci->msg_in_write_pos,
+ plci->msg_in_read_pos, plci->msg_in_wrap_pos, i));
+
+ return _QUEUE_FULL;
+ }
+ c = FALSE;
+ if ((((byte *) msg) < ((byte *)(plci->msg_in_queue)))
+ || (((byte *) msg) >= ((byte *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
+ {
+ if (plci->msg_in_write_pos != plci->msg_in_read_pos)
+ c = TRUE;
+ }
+ if (msg->header.command == _DATA_B3_R)
+ {
+ if (msg->header.length < 20)
+ {
+ dbug(1,dprintf("DATA_B3 REQ wrong length %d", msg->header.length));
+ return _BAD_MSG;
+ }
+ ncci_ptr = &(a->ncci[ncci]);
+ n = ncci_ptr->data_pending;
+ l = ncci_ptr->data_ack_pending;
+ k = plci->msg_in_read_pos;
+ while (k != plci->msg_in_write_pos)
+ {
+ if (k == plci->msg_in_wrap_pos)
+ k = 0;
+ if ((((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[k]))->header.command == _DATA_B3_R)
+ && (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[k]))->header.ncci == ncci))
+ {
+ n++;
+ if (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[k]))->info.data_b3_req.Flags & 0x0004)
+ l++;
+ }
+
+ k += (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[k]))->header.length +
+ MSG_IN_OVERHEAD + 3) & 0xfffc;
+
+ }
+ if ((n >= MAX_DATA_B3) || (l >= MAX_DATA_ACK))
+ {
+ dbug(0,dprintf("Q-FULL2(data) - pending=%d/%d ack_pending=%d/%d",
+ ncci_ptr->data_pending, n, ncci_ptr->data_ack_pending, l));
+
+ return _QUEUE_FULL;
+ }
+ if (plci->req_in || plci->internal_command)
+ {
+ if ((((byte *) msg) >= ((byte *)(plci->msg_in_queue)))
+ && (((byte *) msg) < ((byte *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
+ {
+ dbug(0,dprintf("Q-FULL3(requeue)"));
+
+ return _QUEUE_FULL;
+ }
+ c = TRUE;
+ }
+ }
+ else
+ {
+ if (plci->req_in || plci->internal_command)
+ c = TRUE;
+ else
+ {
+ plci->command = msg->header.command;
+ plci->number = msg->header.number;
+ }
+ }
+ if (c)
+ {
+ dbug(1,dprintf("enqueue msg(0x%04x,0x%x,0x%x) - len=%d write=%d read=%d wrap=%d free=%d",
+ msg->header.command, plci->req_in, plci->internal_command,
+ msg->header.length, plci->msg_in_write_pos,
+ plci->msg_in_read_pos, plci->msg_in_wrap_pos, i));
+ if (j == 0)
+ plci->msg_in_wrap_pos = plci->msg_in_write_pos;
+ m = (CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[j]);
+ for (i = 0; i < msg->header.length; i++)
+ ((byte *)(plci->msg_in_queue))[j++] = ((byte *) msg)[i];
+ if (m->header.command == _DATA_B3_R)
+ {
+
+ m->info.data_b3_req.Data = (dword)(TransmitBufferSet (appl, m->info.data_b3_req.Data));
+
+ }
+
+ j = (j + 3) & 0xfffc;
+
+ *((APPL * *)(&((byte *)(plci->msg_in_queue))[j])) = appl;
+ plci->msg_in_write_pos = j + MSG_IN_OVERHEAD;
+ return 0;
+ }
+ }
+ else
+ {
+ plci = NULL;
+ }
+ }
+ dbug(1,dprintf("com=%x",msg->header.command));
+
+ for(j=0;j<MAX_MSG_PARMS+1;j++) msg_parms[j].length = 0;
+ for(i=0, ret = _BAD_MSG;
+ i<(sizeof(ftable)/sizeof(struct _ftable));
+ i++) {
+
+ if(ftable[i].command==msg->header.command) {
+ /* break loop if the message is correct, otherwise continue scan */
+ /* (for example: CONNECT_B3_T90_ACT_RES has two specifications) */
+ if(!api_parse(msg->info.b,(word)(msg->header.length-12),ftable[i].format,msg_parms)) {
+ ret = 0;
+ break;
+ }
+ for(j=0;j<MAX_MSG_PARMS+1;j++) msg_parms[j].length = 0;
+ }
+ }
+ if(ret) {
+ dbug(1,dprintf("BAD_MSG"));
+ if(plci) plci->command = 0;
+ return ret;
+ }
+
+
+ c = ftable[i].function(GET_DWORD(&msg->header.controller),
+ msg->header.number,
+ a,
+ plci,
+ appl,
+ msg_parms);
+
+ channel_xmit_extended_xon (plci);
+
+ if(c==1) send_req(plci);
+ if(c==2 && plci) plci->req_in = plci->req_in_start = plci->req_out = 0;
+ if(plci && !plci->req_in) plci->command = 0;
+ return 0;
+}
+
+
+/*------------------------------------------------------------------*/
+/* api_parse function, check the format of api messages */
+/*------------------------------------------------------------------*/
+
+word api_parse(byte * msg, word length, byte * format, API_PARSE * parms)
+{
+ word i;
+ word p;
+
+ for(i=0,p=0; format[i]; i++) {
+ if(parms)
+ {
+ parms[i].info = &msg[p];
+ }
+ switch(format[i]) {
+ case 'b':
+ p +=1;
+ break;
+ case 'w':
+ p +=2;
+ break;
+ case 'd':
+ p +=4;
+ break;
+ case 's':
+ if(msg[p]==0xff) {
+ parms[i].info +=2;
+ parms[i].length = msg[p+1] + (msg[p+2]<<8);
+ p +=(parms[i].length +3);
+ }
+ else {
+ parms[i].length = msg[p];
+ p +=(parms[i].length +1);
+ }
+ break;
+ }
+
+ if(p>length) return TRUE;
+ }
+ if(parms) parms[i].info = NULL;
+ return FALSE;
+}
+
+void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out)
+{
+ word i, j, n = 0;
+ byte *p;
+
+ p = out->info;
+ for (i = 0; format[i] != '\0'; i++)
+ {
+ out->parms[i].info = p;
+ out->parms[i].length = in[i].length;
+ switch (format[i])
+ {
+ case 'b':
+ n = 1;
+ break;
+ case 'w':
+ n = 2;
+ break;
+ case 'd':
+ n = 4;
+ break;
+ case 's':
+ n = in[i].length + 1;
+ break;
+ }
+ for (j = 0; j < n; j++)
+ *(p++) = in[i].info[j];
+ }
+ out->parms[i].info = NULL;
+ out->parms[i].length = 0;
+}
+
+void api_load_msg(API_SAVE *in, API_PARSE *out)
+{
+ word i;
+
+ i = 0;
+ do
+ {
+ out[i].info = in->parms[i].info;
+ out[i].length = in->parms[i].length;
+ } while (in->parms[i++].info);
+}
+
+
+/*------------------------------------------------------------------*/
+/* CAPI remove function */
+/*------------------------------------------------------------------*/
+
+word api_remove_start(void)
+{
+ word i;
+ word j;
+
+ if(!remove_started) {
+ remove_started = TRUE;
+ for(i=0;i<max_adapter;i++) {
+ if(adapter[i].request) {
+ for(j=0;j<adapter[i].max_plci;j++) {
+ if(adapter[i].plci[j].Sig.Id) plci_remove(&adapter[i].plci[j]);
+ }
+ }
+ }
+ return 1;
+ }
+ else {
+ for(i=0;i<max_adapter;i++) {
+ if(adapter[i].request) {
+ for(j=0;j<adapter[i].max_plci;j++) {
+ if(adapter[i].plci[j].Sig.Id) return 1;
+ }
+ }
+ }
+ }
+ api_remove_complete();
+ return 0;
+}
+
+
+/*------------------------------------------------------------------*/
+/* internal command queue */
+/*------------------------------------------------------------------*/
+
+static void init_internal_command_queue (PLCI *plci)
+{
+ word i;
+
+ dbug (1, dprintf ("%s,%d: init_internal_command_queue",
+ (char *)(FILE_), __LINE__));
+
+ plci->internal_command = 0;
+ for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS; i++)
+ plci->internal_command_queue[i] = NULL;
+}
+
+
+static void start_internal_command (dword Id, PLCI *plci, t_std_internal_command command_function)
+{
+ word i;
+
+ dbug (1, dprintf ("[%06lx] %s,%d: start_internal_command",
+ UnMapId (Id), (char *)(FILE_), __LINE__));
+
+ if (plci->internal_command == 0)
+ {
+ plci->internal_command_queue[0] = command_function;
+ (* command_function)(Id, plci, OK);
+ }
+ else
+ {
+ i = 1;
+ while (plci->internal_command_queue[i] != 0)
+ i++;
+ plci->internal_command_queue[i] = command_function;
+ }
+}
+
+
+static void next_internal_command (dword Id, PLCI *plci)
+{
+ word i;
+
+ dbug (1, dprintf ("[%06lx] %s,%d: next_internal_command",
+ UnMapId (Id), (char *)(FILE_), __LINE__));
+
+ plci->internal_command = 0;
+ plci->internal_command_queue[0] = NULL;
+ while (plci->internal_command_queue[1] != 0)
+ {
+ for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS - 1; i++)
+ plci->internal_command_queue[i] = plci->internal_command_queue[i+1];
+ plci->internal_command_queue[MAX_INTERNAL_COMMAND_LEVELS - 1] = NULL;
+ (*(plci->internal_command_queue[0]))(Id, plci, OK);
+ if (plci->internal_command != 0)
+ return;
+ plci->internal_command_queue[0] = NULL;
+ }
+}
+
+
+/*------------------------------------------------------------------*/
+/* NCCI allocate/remove function */
+/*------------------------------------------------------------------*/
+
+static dword ncci_mapping_bug = 0;
+
+static word get_ncci (PLCI *plci, byte ch, word force_ncci)
+{
+ DIVA_CAPI_ADAPTER *a;
+ word ncci, i, j, k;
+
+ a = plci->adapter;
+ if (!ch || a->ch_ncci[ch])
+ {
+ ncci_mapping_bug++;
+ dbug(1,dprintf("NCCI mapping exists %ld %02x %02x %02x-%02x",
+ ncci_mapping_bug, ch, force_ncci, a->ncci_ch[a->ch_ncci[ch]], a->ch_ncci[ch]));
+ ncci = ch;
+ }
+ else
+ {
+ if (force_ncci)
+ ncci = force_ncci;
+ else
+ {
+ if ((ch < MAX_NCCI+1) && !a->ncci_ch[ch])
+ ncci = ch;
+ else
+ {
+ ncci = 1;
+ while ((ncci < MAX_NCCI+1) && a->ncci_ch[ncci])
+ ncci++;
+ if (ncci == MAX_NCCI+1)
+ {
+ ncci_mapping_bug++;
+ i = 1;
+ do
+ {
+ j = 1;
+ while ((j < MAX_NCCI+1) && (a->ncci_ch[j] != i))
+ j++;
+ k = j;
+ if (j < MAX_NCCI+1)
+ {
+ do
+ {
+ j++;
+ } while ((j < MAX_NCCI+1) && (a->ncci_ch[j] != i));
+ }
+ } while ((i < MAX_NL_CHANNEL+1) && (j < MAX_NCCI+1));
+ if (i < MAX_NL_CHANNEL+1)
+ {
+ dbug(1,dprintf("NCCI mapping overflow %ld %02x %02x %02x-%02x-%02x",
+ ncci_mapping_bug, ch, force_ncci, i, k, j));
+ }
+ else
+ {
+ dbug(1,dprintf("NCCI mapping overflow %ld %02x %02x",
+ ncci_mapping_bug, ch, force_ncci));
+ }
+ ncci = ch;
+ }
+ }
+ a->ncci_plci[ncci] = plci->Id;
+ a->ncci_state[ncci] = IDLE;
+ if (!plci->ncci_ring_list)
+ plci->ncci_ring_list = ncci;
+ else
+ a->ncci_next[ncci] = a->ncci_next[plci->ncci_ring_list];
+ a->ncci_next[plci->ncci_ring_list] = (byte) ncci;
+ }
+ a->ncci_ch[ncci] = ch;
+ a->ch_ncci[ch] = (byte) ncci;
+ dbug(1,dprintf("NCCI mapping established %ld %02x %02x %02x-%02x",
+ ncci_mapping_bug, ch, force_ncci, ch, ncci));
+ }
+ return (ncci);
+}
+
+
+static void ncci_free_receive_buffers (PLCI *plci, word ncci)
+{
+ DIVA_CAPI_ADAPTER *a;
+ APPL *appl;
+ word i, ncci_code;
+ dword Id;
+
+ a = plci->adapter;
+ Id = (((dword) ncci) << 16) | (((word)(plci->Id)) << 8) | a->Id;
+ if (ncci)
+ {
+ if (a->ncci_plci[ncci] == plci->Id)
+ {
+ if (!plci->appl)
+ {
+ ncci_mapping_bug++;
+ dbug(1,dprintf("NCCI mapping appl expected %ld %08lx",
+ ncci_mapping_bug, Id));
+ }
+ else
+ {
+ appl = plci->appl;
+ ncci_code = ncci | (((word) a->Id) << 8);
+ for (i = 0; i < appl->MaxBuffer; i++)
+ {
+ if ((appl->DataNCCI[i] == ncci_code)
+ && (((byte)(appl->DataFlags[i] >> 8)) == plci->Id))
+ {
+ appl->DataNCCI[i] = 0;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for (ncci = 1; ncci < MAX_NCCI+1; ncci++)
+ {
+ if (a->ncci_plci[ncci] == plci->Id)
+ {
+ if (!plci->appl)
+ {
+ ncci_mapping_bug++;
+ dbug(1,dprintf("NCCI mapping no appl %ld %08lx",
+ ncci_mapping_bug, Id));
+ }
+ else
+ {
+ appl = plci->appl;
+ ncci_code = ncci | (((word) a->Id) << 8);
+ for (i = 0; i < appl->MaxBuffer; i++)
+ {
+ if ((appl->DataNCCI[i] == ncci_code)
+ && (((byte)(appl->DataFlags[i] >> 8)) == plci->Id))
+ {
+ appl->DataNCCI[i] = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+static void cleanup_ncci_data (PLCI *plci, word ncci)
+{
+ NCCI *ncci_ptr;
+
+ if (ncci && (plci->adapter->ncci_plci[ncci] == plci->Id))
+ {
+ ncci_ptr = &(plci->adapter->ncci[ncci]);
+ if (plci->appl)
+ {
+ while (ncci_ptr->data_pending != 0)
+ {
+ if (!plci->data_sent || (ncci_ptr->DBuffer[ncci_ptr->data_out].P != plci->data_sent_ptr))
+ TransmitBufferFree (plci->appl, ncci_ptr->DBuffer[ncci_ptr->data_out].P);
+ (ncci_ptr->data_out)++;
+ if (ncci_ptr->data_out == MAX_DATA_B3)
+ ncci_ptr->data_out = 0;
+ (ncci_ptr->data_pending)--;
+ }
+ }
+ ncci_ptr->data_out = 0;
+ ncci_ptr->data_pending = 0;
+ ncci_ptr->data_ack_out = 0;
+ ncci_ptr->data_ack_pending = 0;
+ }
+}
+
+
+static void ncci_remove (PLCI *plci, word ncci, byte preserve_ncci)
+{
+ DIVA_CAPI_ADAPTER *a;
+ dword Id;
+ word i;
+
+ a = plci->adapter;
+ Id = (((dword) ncci) << 16) | (((word)(plci->Id)) << 8) | a->Id;
+ if (!preserve_ncci)
+ ncci_free_receive_buffers (plci, ncci);
+ if (ncci)
+ {
+ if (a->ncci_plci[ncci] != plci->Id)
+ {
+ ncci_mapping_bug++;
+ dbug(1,dprintf("NCCI mapping doesn't exist %ld %08lx %02x",
+ ncci_mapping_bug, Id, preserve_ncci));
+ }
+ else
+ {
+ cleanup_ncci_data (plci, ncci);
+ dbug(1,dprintf("NCCI mapping released %ld %08lx %02x %02x-%02x",
+ ncci_mapping_bug, Id, preserve_ncci, a->ncci_ch[ncci], ncci));
+ a->ch_ncci[a->ncci_ch[ncci]] = 0;
+ if (!preserve_ncci)
+ {
+ a->ncci_ch[ncci] = 0;
+ a->ncci_plci[ncci] = 0;
+ a->ncci_state[ncci] = IDLE;
+ i = plci->ncci_ring_list;
+ while ((i != 0) && (a->ncci_next[i] != plci->ncci_ring_list) && (a->ncci_next[i] != ncci))
+ i = a->ncci_next[i];
+ if ((i != 0) && (a->ncci_next[i] == ncci))
+ {
+ if (i == ncci)
+ plci->ncci_ring_list = 0;
+ else if (plci->ncci_ring_list == ncci)
+ plci->ncci_ring_list = i;
+ a->ncci_next[i] = a->ncci_next[ncci];
+ }
+ a->ncci_next[ncci] = 0;
+ }
+ }
+ }
+ else
+ {
+ for (ncci = 1; ncci < MAX_NCCI+1; ncci++)