diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /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.c | 15047 |
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++) |