| /* |
| * |
| 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)(long)(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 < ARRAY_SIZE(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 */ |
| /*------------------------------------------------------------------*/ |
| |
| static 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; |
| } |
| |
| static 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; |
| } |
| |
| static 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] != NULL) |
| 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] != NULL) |
| { |
| 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++) |
| { |
| if (a->ncci_plci[ncci] == plci->Id) |
| { |
| 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; |
| a->ncci_next[ncci] = 0; |
| } |
| } |
| } |
| if (!preserve_ncci) |
| plci->ncci_ring_list = 0; |
| } |
| } |
| |
| |
| /*------------------------------------------------------------------*/ |
| /* PLCI remove function */ |
| /*------------------------------------------------------------------*/ |
| |
| static void plci_free_msg_in_queue(PLCI *plci) |
| { |
| word i; |
| |
| if (plci->appl) |
| { |
| i = plci->msg_in_read_pos; |
| while (i != plci->msg_in_write_pos) |
| { |
| if (i == plci->msg_in_wrap_pos) |
| i = 0; |
| if (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[i]))->header.command == _DATA_B3_R) |
| { |
| |
| TransmitBufferFree(plci->appl, |
| (byte *)(long)(((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[i]))->info.data_b3_req.Data)); |
| |
| } |
| |
| i += (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[i]))->header.length + |
| MSG_IN_OVERHEAD + 3) & 0xfffc; |
| |
| } |
| } |
| plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE; |
| plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE; |
| plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE; |
| } |
| |
| |
| static void plci_remove(PLCI *plci) |
| { |
| |
| if (!plci) { |
| dbug(1, dprintf("plci_remove(no plci)")); |
| return; |
| } |
| init_internal_command_queue(plci); |
| dbug(1, dprintf("plci_remove(%x,tel=%x)", plci->Id, plci->tel)); |
| if (plci_remove_check(plci)) |
| { |
| return; |
| } |
| if (plci->Sig.Id == 0xff) |
| { |
| dbug(1, dprintf("D-channel X.25 plci->NL.Id:%0x", plci->NL.Id)); |
| if (plci->NL.Id && !plci->nl_remove_id) |
| { |
| nl_req_ncci(plci, REMOVE, 0); |
| send_req(plci); |
| } |
| } |
| else |
| { |
| if (!plci->sig_remove_id |
| && (plci->Sig.Id |
| || (plci->req_in != plci->req_out) |
| || (plci->nl_req || plci->sig_req))) |
| { |
| sig_req(plci, HANGUP, 0); |
| send_req(plci); |
| } |
| } |
| ncci_remove(plci, 0, false); |
| plci_free_msg_in_queue(plci); |
| |
| plci->channels = 0; |
| plci->appl = NULL; |
| if ((plci->State == INC_CON_PENDING) || (plci->State == INC_CON_ALERT)) |
| plci->State = OUTG_DIS_PENDING; |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* Application Group function helpers */ |
| /*------------------------------------------------------------------*/ |
| |
| static void set_group_ind_mask(PLCI *plci) |
| { |
| word i; |
| |
| for (i = 0; i < C_IND_MASK_DWORDS; i++) |
| plci->group_optimization_mask_table[i] = 0xffffffffL; |
| } |
| |
| static void clear_group_ind_mask_bit(PLCI *plci, word b) |
| { |
| plci->group_optimization_mask_table[b >> 5] &= ~(1L << (b & 0x1f)); |
| } |
| |
| static byte test_group_ind_mask_bit(PLCI *plci, word b) |
| { |
| return ((plci->group_optimization_mask_table[b >> 5] & (1L << (b & 0x1f))) != 0); |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* c_ind_mask operations for arbitrary MAX_APPL */ |
| /*------------------------------------------------------------------*/ |
| |
| static void clear_c_ind_mask(PLCI *plci) |
| { |
| word i; |
| |
| for (i = 0; i < C_IND_MASK_DWORDS; i++) |
| plci->c_ind_mask_table[i] = 0; |
| } |
| |
| static byte c_ind_mask_empty(PLCI *plci) |
| { |
| word i; |
| |
| i = 0; |
| while ((i < C_IND_MASK_DWORDS) && (plci->c_ind_mask_table[i] == 0)) |
| i++; |
| return (i == C_IND_MASK_DWORDS); |
| } |
| |
| static void set_c_ind_mask_bit(PLCI *plci, word b) |
| { |
| plci->c_ind_mask_table[b >> 5] |= (1L << (b & 0x1f)); |
| } |
| |
| static void clear_c_ind_mask_bit(PLCI *plci, word b) |
| { |
| plci->c_ind_mask_table[b >> 5] &= ~(1L << (b & 0x1f)); |
| } |
| |
| static byte test_c_ind_mask_bit(PLCI *plci, word b) |
| { |
| return ((plci->c_ind_mask_table[b >> 5] & (1L << (b & 0x1f))) != 0); |
| } |
| |
| static void dump_c_ind_mask(PLCI *plci) |
| { |
| word i, j, k; |
| dword d; |
| char *p; |
| char buf[40]; |
| |
| for (i = 0; i < C_IND_MASK_DWORDS; i += 4) |
| { |
| p = buf + 36; |
| *p = '\0'; |
| for (j = 0; j < 4; j++) |
| { |
| if (i + j < C_IND_MASK_DWORDS) |
| { |
| d = plci->c_ind_mask_table[i + j]; |
| for (k = 0; k < 8; k++) |
| { |
| *(--p) = hex_asc_lo(d); |
| d >>= 4; |
| } |
| } |
| else if (i != 0) |
| { |
| for (k = 0; k < 8; k++) |
| *(--p) = ' '; |
| } |
| *(--p) = ' '; |
| } |
| dbug(1, dprintf("c_ind_mask =%s", (char *) p)); |
| } |
| } |
| |
| |
| |
| |
| |
| #define dump_plcis(a) |
| |
| |
| |
| /*------------------------------------------------------------------*/ |
| /* translation function for each message */ |
| /*------------------------------------------------------------------*/ |
| |
| static byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *parms) |
| { |
| word ch; |
| word i; |
| word Info; |
| byte LinkLayer; |
| API_PARSE *ai; |
| API_PARSE *bp; |
| API_PARSE ai_parms[5]; |
| word channel = 0; |
| dword ch_mask; |
| byte m; |
| static byte esc_chi[35] = {0x02, 0x18, 0x01}; |
| static byte lli[2] = {0x01, 0x00}; |
| byte noCh = 0; |
| word dir = 0; |
| byte *p_chi = ""; |
| |
| for (i = 0; i < 5; i++) ai_parms[i].length = 0; |
| |
| dbug(1, dprintf("connect_req(%d)", parms->length)); |
| Info = _WRONG_IDENTIFIER; |
| if (a) |
| { |
| if (a->adapter_disabled) |
| { |
| dbug(1, dprintf("adapter disabled")); |
| Id = ((word)1 << 8) | a->Id; |
| sendf(appl, _CONNECT_R | CONFIRM, Id, Number, "w", 0); |
| sendf(appl, _DISCONNECT_I, Id, 0, "w", _L1_ERROR); |
| return false; |
| } |
| Info = _OUT_OF_PLCI; |
| if ((i = get_plci(a))) |
| { |
| Info = 0; |
| plci = &a->plci[i - 1]; |
| plci->appl = appl; |
| plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE; |
| /* check 'external controller' bit for codec support */ |
| if (Id & EXT_CONTROLLER) |
| { |
| if (AdvCodecSupport(a, plci, appl, 0)) |
| { |
| plci->Id = 0; |
| sendf(appl, _CONNECT_R | CONFIRM, Id, Number, "w", _WRONG_IDENTIFIER); |
| return 2; |
| } |
| } |
| ai = &parms[9]; |
| bp = &parms[5]; |
| ch = 0; |
| if (bp->length)LinkLayer = bp->info[3]; |
| else LinkLayer = 0; |
| if (ai->length) |
| { |
| ch = 0xffff; |
| if (!api_parse(&ai->info[1], (word)ai->length, "ssss", ai_parms)) |
| { |
| ch = 0; |
| if (ai_parms[0].length) |
| { |
| ch = GET_WORD(ai_parms[0].info + 1); |
| if (ch > 4) ch = 0; /* safety -> ignore ChannelID */ |
| if (ch == 4) /* explizit CHI in message */ |
| { |
| /* check length of B-CH struct */ |
| if ((ai_parms[0].info)[3] >= 1) |
| { |
| if ((ai_parms[0].info)[4] == CHI) |
| { |
| p_chi = &((ai_parms[0].info)[5]); |
| } |
| else |
| { |
| p_chi = &((ai_parms[0].info)[3]); |
| } |
| if (p_chi[0] > 35) /* check length of channel ID */ |
| { |
| Info = _WRONG_MESSAGE_FORMAT; |
| } |
| } |
| else Info = _WRONG_MESSAGE_FORMAT; |
| } |
| |
| if (ch == 3 && ai_parms[0].length >= 7 && ai_parms[0].length <= 36) |
| { |
| dir = GET_WORD(ai_parms[0].info + 3); |
| ch_mask = 0; |
| m = 0x3f; |
| for (i = 0; i + 5 <= ai_parms[0].length; i++) |
| { |
| if (ai_parms[0].info[i + 5] != 0) |
| { |
| if ((ai_parms[0].info[i + 5] | m) != 0xff) |
| Info = _WRONG_MESSAGE_FORMAT; |
| else |
| { |
| if (ch_mask == 0) |
| channel = i; |
| ch_mask |= 1L << i; |
| } |
| } |
| m = 0; |
| } |
| if (ch_mask == 0) |
| Info = _WRONG_MESSAGE_FORMAT; |
| if (!Info) |
| { |
| if ((ai_parms[0].length == 36) || (ch_mask != ((dword)(1L << channel)))) |
| { |
| esc_chi[0] = (byte)(ai_parms[0].length - 2); |
| for (i = 0; i + 5 <= ai_parms[0].length; i++) |
| esc_chi[i + 3] = ai_parms[0].info[i + 5]; |
| } |
| else |
| esc_chi[0] = 2; |
| esc_chi[2] = (byte)channel; |
| plci->b_channel = (byte)channel; /* not correct for ETSI ch 17..31 */ |
| add_p(plci, LLI, lli); |
| add_p(plci, ESC, esc_chi); |
| plci->State = LOCAL_CONNECT; |
| if (!dir) plci->call_dir |= CALL_DIR_FORCE_OUTG_NL; /* dir 0=DTE, 1=DCE */ |
| } |
| } |
| } |
| } |
| else Info = _WRONG_MESSAGE_FORMAT; |
| } |
| |
| dbug(1, dprintf("ch=%x,dir=%x,p_ch=%d", ch, dir, channel)); |
| plci->command = _CONNECT_R; |
| plci->number = Number; |
| /* x.31 or D-ch free SAPI in LinkLayer? */ |
| if (ch == 1 && LinkLayer != 3 && LinkLayer != 12) noCh = true; |
| if ((ch == 0 || ch == 2 || noCh || ch == 3 || ch == 4) && !Info) |
| { |
| /* B-channel used for B3 connections (ch==0), or no B channel */ |
| /* is used (ch==2) or perm. connection (3) is used do a CALL */ |
| if (noCh) Info = add_b1(plci, &parms[5], 2, 0); /* no resource */ |
| else Info = add_b1(plci, &parms[5], ch, 0); |
| add_s(plci, OAD, &parms[2]); |
| add_s(plci, OSA, &parms[4]); |
| add_s(plci, BC, &parms[6]); |
| add_s(plci, LLC, &parms[7]); |
| add_s(plci, HLC, &parms[8]); |
| if (a->Info_Mask[appl->Id - 1] & 0x200) |
| { |
| /* early B3 connect (CIP mask bit 9) no release after a disc */ |
| add_p(plci, LLI, "\x01\x01"); |
| } |
| if (GET_WORD(parms[0].info) < 29) { |
| add_p(plci, BC, cip_bc[GET_WORD(parms[0].info)][a->u_law]); |
| add_p(plci, HLC, cip_hlc[GET_WORD(parms[0].info)]); |
| } |
| add_p(plci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| sig_req(plci, ASSIGN, DSIG_ID); |
| } |
| else if (ch == 1) { |
| |
| /* D-Channel used for B3 connections */ |
| plci->Sig.Id = 0xff; |
| Info = 0; |
| } |
| |
| if (!Info && ch != 2 && !noCh) { |
| Info = add_b23(plci, &parms[5]); |
| if (!Info) { |
| if (!(plci->tel && !plci->adv_nl))nl_req_ncci(plci, ASSIGN, 0); |
| } |
| } |
| |
| if (!Info) |
| { |
| if (ch == 0 || ch == 2 || ch == 3 || noCh || ch == 4) |
| { |
| if (plci->spoofed_msg == SPOOFING_REQUIRED) |
| { |
| api_save_msg(parms, "wsssssssss", &plci->saved_msg); |
| plci->spoofed_msg = CALL_REQ; |
| plci->internal_command = BLOCK_PLCI; |
| plci->command = 0; |
| dbug(1, dprintf("Spoof")); |
| send_req(plci); |
| return false; |
| } |
| if (ch == 4)add_p(plci, CHI, p_chi); |
| add_s(plci, CPN, &parms[1]); |
| add_s(plci, DSA, &parms[3]); |
| if (noCh) add_p(plci, ESC, "\x02\x18\xfd"); /* D-channel, no B-L3 */ |
| add_ai(plci, &parms[9]); |
| if (!dir)sig_req(plci, CALL_REQ, 0); |
| else |
| { |
| plci->command = PERM_LIST_REQ; |
| plci->appl = appl; |
| sig_req(plci, LISTEN_REQ, 0); |
| send_req(plci); |
| return false; |
| } |
| } |
| send_req(plci); |
| return false; |
| } |
| plci->Id = 0; |
| } |
| } |
| sendf(appl, |
| _CONNECT_R | CONFIRM, |
| Id, |
| Number, |
| "w", Info); |
| return 2; |
| } |
| |
| static byte connect_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *parms) |
| { |
| word i, Info; |
| word Reject; |
| static byte cau_t[] = {0, 0, 0x90, 0x91, 0xac, 0x9d, 0x86, 0xd8, 0x9b}; |
| static byte esc_t[] = {0x03, 0x08, 0x00, 0x00}; |
| API_PARSE *ai; |
| API_PARSE ai_parms[5]; |
| word ch = 0; |
| |
| if (!plci) { |
| dbug(1, dprintf("connect_res(no plci)")); |
| return 0; /* no plci, no send */ |
| } |
| |
| dbug(1, dprintf("connect_res(State=0x%x)", plci->State)); |
| for (i = 0; i < 5; i++) ai_parms[i].length = 0; |
| ai = &parms[5]; |
| dbug(1, dprintf("ai->length=%d", ai->length)); |
| |
| if (ai->length) |
| { |
| if (!api_parse(&ai->info[1], (word)ai->length, "ssss", ai_parms)) |
| { |
| dbug(1, dprintf("ai_parms[0].length=%d/0x%x", ai_parms[0].length, GET_WORD(ai_parms[0].info + 1))); |
| ch = 0; |
| if (ai_parms[0].length) |
| { |
| ch = GET_WORD(ai_parms[0].info + 1); |
| dbug(1, dprintf("BCH-I=0x%x", ch)); |
| } |
| } |
| } |
| |
| if (plci->State == INC_CON_CONNECTED_ALERT) |
| { |
| dbug(1, dprintf("Connected Alert Call_Res")); |
| if (a->Info_Mask[appl->Id - 1] & 0x200) |
| { |
| /* early B3 connect (CIP mask bit 9) no release after a disc */ |
| add_p(plci, LLI, "\x01\x01"); |
| } |
| add_s(plci, CONN_NR, &parms[2]); |
| add_s(plci, LLC, &parms[4]); |
| add_ai(plci, &parms[5]); |
| plci->State = INC_CON_ACCEPT; |
| sig_req(plci, CALL_RES, 0); |
| return 1; |
| } |
| else if (plci->State == INC_CON_PENDING || plci->State == INC_CON_ALERT) { |
| clear_c_ind_mask_bit(plci, (word)(appl->Id - 1)); |
| dump_c_ind_mask(plci); |
| Reject = GET_WORD(parms[0].info); |
| dbug(1, dprintf("Reject=0x%x", Reject)); |
| if (Reject) |
| { |
| if (c_ind_mask_empty(plci)) |
| { |
| if ((Reject & 0xff00) == 0x3400) |
| { |
| esc_t[2] = ((byte)(Reject & 0x00ff)) | 0x80; |
| add_p(plci, ESC, esc_t); |
| add_ai(plci, &parms[5]); |
| sig_req(plci, REJECT, 0); |
| } |
| else if (Reject == 1 || Reject >= 9) |
| { |
| add_ai(plci, &parms[5]); |
| sig_req(plci, HANGUP, 0); |
| } |
| else |
| { |
| esc_t[2] = cau_t[(Reject&0x000f)]; |
| add_p(plci, ESC, esc_t); |
| add_ai(plci, &parms[5]); |
| sig_req(plci, REJECT, 0); |
| } |
| plci->appl = appl; |
| } |
| else |
| { |
| sendf(appl, _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED); |
| } |
| } |
| else { |
| plci->appl = appl; |
| if (Id & EXT_CONTROLLER) { |
| if (AdvCodecSupport(a, plci, appl, 0)) { |
| dbug(1, dprintf("connect_res(error from AdvCodecSupport)")); |
| sig_req(plci, HANGUP, 0); |
| return 1; |
| } |
| if (plci->tel == ADV_VOICE && a->AdvCodecPLCI) |
| { |
| Info = add_b23(plci, &parms[1]); |
| if (Info) |
| { |
| dbug(1, dprintf("connect_res(error from add_b23)")); |
| sig_req(plci, HANGUP, 0); |
| return 1; |
| } |
| if (plci->adv_nl) |
| { |
| nl_req_ncci(plci, ASSIGN, 0); |
| } |
| } |
| } |
| else |
| { |
| plci->tel = 0; |
| if (ch != 2) |
| { |
| Info = add_b23(plci, &parms[1]); |
| if (Info) |
| { |
| dbug(1, dprintf("connect_res(error from add_b23 2)")); |
| sig_req(plci, HANGUP, 0); |
| return 1; |
| } |
| } |
| nl_req_ncci(plci, ASSIGN, 0); |
| } |
| |
| if (plci->spoofed_msg == SPOOFING_REQUIRED) |
| { |
| api_save_msg(parms, "wsssss", &plci->saved_msg); |
| plci->spoofed_msg = CALL_RES; |
| plci->internal_command = BLOCK_PLCI; |
| plci->command = 0; |
| dbug(1, dprintf("Spoof")); |
| } |
| else |
| { |
| add_b1(plci, &parms[1], ch, plci->B1_facilities); |
| if (a->Info_Mask[appl->Id - 1] & 0x200) |
| { |
| /* early B3 connect (CIP mask bit 9) no release after a disc */ |
| add_p(plci, LLI, "\x01\x01"); |
| } |
| add_s(plci, CONN_NR, &parms[2]); |
| add_s(plci, LLC, &parms[4]); |
| add_ai(plci, &parms[5]); |
| plci->State = INC_CON_ACCEPT; |
| sig_req(plci, CALL_RES, 0); |
| } |
| |
| for (i = 0; i < max_appl; i++) { |
| if (test_c_ind_mask_bit(plci, i)) { |
| sendf(&application[i], _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED); |
| } |
| } |
| } |
| } |
| return 1; |
| } |
| |
| static byte connect_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *msg) |
| { |
| dbug(1, dprintf("connect_a_res")); |
| return false; |
| } |
| |
| static byte disconnect_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *msg) |
| { |
| word Info; |
| word i; |
| |
| dbug(1, dprintf("disconnect_req")); |
| |
| Info = _WRONG_IDENTIFIER; |
| |
| if (plci) |
| { |
| if (plci->State == INC_CON_PENDING || plci->State == INC_CON_ALERT) |
| { |
| clear_c_ind_mask_bit(plci, (word)(appl->Id - 1)); |
| plci->appl = appl; |
| for (i = 0; i < max_appl; i++) |
| { |
| if (test_c_ind_mask_bit(plci, i)) |
| sendf(&application[i], _DISCONNECT_I, Id, 0, "w", 0); |
| } |
| plci->State = OUTG_DIS_PENDING; |
| } |
| if (plci->Sig.Id && plci->appl) |
| { |
| Info = 0; |
| if (plci->Sig.Id != 0xff) |
| { |
| if (plci->State != INC_DIS_PENDING) |
| { |
| add_ai(plci, &msg[0]); |
| sig_req(plci, HANGUP, 0); |
| plci->State = OUTG_DIS_PENDING; |
| return 1; |
| } |
| } |
| else |
| { |
| if (plci->NL.Id && !plci->nl_remove_id) |
| { |
| mixer_remove(plci); |
| nl_req_ncci(plci, REMOVE, 0); |
| sendf(appl, _DISCONNECT_R | CONFIRM, Id, Number, "w", 0); |
| sendf(appl, _DISCONNECT_I, Id, 0, "w", 0); |
| plci->State = INC_DIS_PENDING; |
| } |
| return 1; |
| } |
| } |
| } |
| |
| if (!appl) return false; |
| sendf(appl, _DISCONNECT_R | CONFIRM, Id, Number, "w", Info); |
| return false; |
| } |
| |
| static byte disconnect_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *msg) |
| { |
| dbug(1, dprintf("disconnect_res")); |
| if (plci) |
| { |
| /* clear ind mask bit, just in case of collsion of */ |
| /* DISCONNECT_IND and CONNECT_RES */ |
| clear_c_ind_mask_bit(plci, (word)(appl->Id - 1)); |
| ncci_free_receive_buffers(plci, 0); |
| if (plci_remove_check(plci)) |
| { |
| return 0; |
| } |
| if (plci->State == INC_DIS_PENDING |
| || plci->State == SUSPENDING) { |
| if (c_ind_mask_empty(plci)) { |
| if (plci->State != SUSPENDING) plci->State = IDLE; |
| dbug(1, dprintf("chs=%d", plci->channels)); |
| if (!plci->channels) { |
| plci_remove(plci); |
| } |
| } |
| } |
| } |
| return 0; |
| } |
| |
| static byte listen_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *parms) |
| { |
| word Info; |
| byte i; |
| |
| dbug(1, dprintf("listen_req(Appl=0x%x)", appl->Id)); |
| |
| Info = _WRONG_IDENTIFIER; |
| if (a) { |
| Info = 0; |
| a->Info_Mask[appl->Id - 1] = GET_DWORD(parms[0].info); |
| a->CIP_Mask[appl->Id - 1] = GET_DWORD(parms[1].info); |
| dbug(1, dprintf("CIP_MASK=0x%lx", GET_DWORD(parms[1].info))); |
| if (a->Info_Mask[appl->Id - 1] & 0x200) { /* early B3 connect provides */ |
| a->Info_Mask[appl->Id - 1] |= 0x10; /* call progression infos */ |
| } |
| |
| /* check if external controller listen and switch listen on or off*/ |
| if (Id&EXT_CONTROLLER && GET_DWORD(parms[1].info)) { |
| if (a->profile.Global_Options & ON_BOARD_CODEC) { |
| dummy_plci.State = IDLE; |
| a->codec_listen[appl->Id - 1] = &dummy_plci; |
| a->TelOAD[0] = (byte)(parms[3].length); |
| for (i = 1; parms[3].length >= i && i < 22; i++) { |
| a->TelOAD[i] = parms[3].info[i]; |
| } |
| a->TelOAD[i] = 0; |
| a->TelOSA[0] = (byte)(parms[4].length); |
| for (i = 1; parms[4].length >= i && i < 22; i++) { |
| a->TelOSA[i] = parms[4].info[i]; |
| } |
| a->TelOSA[i] = 0; |
| } |
| else Info = 0x2002; /* wrong controller, codec not supported */ |
| } |
| else{ /* clear listen */ |
| a->codec_listen[appl->Id - 1] = (PLCI *)0; |
| } |
| } |
| sendf(appl, |
| _LISTEN_R | CONFIRM, |
| Id, |
| Number, |
| "w", Info); |
| |
| if (a) listen_check(a); |
| return false; |
| } |
| |
| static byte info_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *msg) |
| { |
| word i; |
| API_PARSE *ai; |
| PLCI *rc_plci = NULL; |
| API_PARSE ai_parms[5]; |
| word Info = 0; |
| |
| dbug(1, dprintf("info_req")); |
| for (i = 0; i < 5; i++) ai_parms[i].length = 0; |
| |
| ai = &msg[1]; |
| |
| if (ai->length) |
| { |
| if (api_parse(&ai->info[1], (word)ai->length, "ssss", ai_parms)) |
| { |
| dbug(1, dprintf("AddInfo wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| } |
| } |
| if (!a) Info = _WRONG_STATE; |
| |
| if (!Info && plci) |
| { /* no fac, with CPN, or KEY */ |
| rc_plci = plci; |
| if (!ai_parms[3].length && plci->State && (msg[0].length || ai_parms[1].length)) |
| { |
| /* overlap sending option */ |
| dbug(1, dprintf("OvlSnd")); |
| add_s(plci, CPN, &msg[0]); |
| add_s(plci, KEY, &ai_parms[1]); |
| sig_req(plci, INFO_REQ, 0); |
| send_req(plci); |
| return false; |
| } |
| |
| if (plci->State && ai_parms[2].length) |
| { |
| /* User_Info option */ |
| dbug(1, dprintf("UUI")); |
| add_s(plci, UUI, &ai_parms[2]); |
| sig_req(plci, USER_DATA, 0); |
| } |
| else if (plci->State && ai_parms[3].length) |
| { |
| /* Facility option */ |
| dbug(1, dprintf("FAC")); |
| add_s(plci, CPN, &msg[0]); |
| add_ai(plci, &msg[1]); |
| sig_req(plci, FACILITY_REQ, 0); |
| } |
| else |
| { |
| Info = _WRONG_STATE; |
| } |
| } |
| else if ((ai_parms[1].length || ai_parms[2].length || ai_parms[3].length) && !Info) |
| { |
| /* NCR_Facility option -> send UUI and Keypad too */ |
| dbug(1, dprintf("NCR_FAC")); |
| if ((i = get_plci(a))) |
| { |
| rc_plci = &a->plci[i - 1]; |
| appl->NullCREnable = true; |
| rc_plci->internal_command = C_NCR_FAC_REQ; |
| rc_plci->appl = appl; |
| add_p(rc_plci, CAI, "\x01\x80"); |
| add_p(rc_plci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| sig_req(rc_plci, ASSIGN, DSIG_ID); |
| send_req(rc_plci); |
| } |
| else |
| { |
| Info = _OUT_OF_PLCI; |
| } |
| |
| if (!Info) |
| { |
| add_s(rc_plci, CPN, &msg[0]); |
| add_ai(rc_plci, &msg[1]); |
| sig_req(rc_plci, NCR_FACILITY, 0); |
| send_req(rc_plci); |
| return false; |
| /* for application controlled supplementary services */ |
| } |
| } |
| |
| if (!rc_plci) |
| { |
| Info = _WRONG_MESSAGE_FORMAT; |
| } |
| |
| if (!Info) |
| { |
| send_req(rc_plci); |
| } |
| else |
| { /* appl is not assigned to a PLCI or error condition */ |
| dbug(1, dprintf("localInfoCon")); |
| sendf(appl, |
| _INFO_R | CONFIRM, |
| Id, |
| Number, |
| "w", Info); |
| } |
| return false; |
| } |
| |
| static byte info_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *msg) |
| { |
| dbug(1, dprintf("info_res")); |
| return false; |
| } |
| |
| static byte alert_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *msg) |
| { |
| word Info; |
| byte ret; |
| |
| dbug(1, dprintf("alert_req")); |
| |
| Info = _WRONG_IDENTIFIER; |
| ret = false; |
| if (plci) { |
| Info = _ALERT_IGNORED; |
| if (plci->State != INC_CON_ALERT) { |
| Info = _WRONG_STATE; |
| if (plci->State == INC_CON_PENDING) { |
| Info = 0; |
| plci->State = INC_CON_ALERT; |
| add_ai(plci, &msg[0]); |
| sig_req(plci, CALL_ALERT, 0); |
| ret = 1; |
| } |
| } |
| } |
| sendf(appl, |
| _ALERT_R | CONFIRM, |
| Id, |
| Number, |
| "w", Info); |
| return ret; |
| } |
| |
| static byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *msg) |
| { |
| word Info = 0; |
| word i = 0; |
| |
| word selector; |
| word SSreq; |
| long relatedPLCIvalue; |
| DIVA_CAPI_ADAPTER *relatedadapter; |
| byte *SSparms = ""; |
| byte RCparms[] = "\x05\x00\x00\x02\x00\x00"; |
| byte SSstruct[] = "\x09\x00\x00\x06\x00\x00\x00\x00\x00\x00"; |
| API_PARSE *parms; |
| API_PARSE ss_parms[11]; |
| PLCI *rplci; |
| byte cai[15]; |
| dword d; |
| API_PARSE dummy; |
| |
| dbug(1, dprintf("facility_req")); |
| for (i = 0; i < 9; i++) ss_parms[i].length = 0; |
| |
| parms = &msg[1]; |
| |
| if (!a) |
| { |
| dbug(1, dprintf("wrong Ctrl")); |
| Info = _WRONG_IDENTIFIER; |
| } |
| |
| selector = GET_WORD(msg[0].info); |
| |
| if (!Info) |
| { |
| switch (selector) |
| { |
| case SELECTOR_HANDSET: |
| Info = AdvCodecSupport(a, plci, appl, HOOK_SUPPORT); |
| break; |
| |
| case SELECTOR_SU_SERV: |
| if (!msg[1].length) |
| { |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| SSreq = GET_WORD(&(msg[1].info[1])); |
| PUT_WORD(&RCparms[1], SSreq); |
| SSparms = RCparms; |
| switch (SSreq) |
| { |
| case S_GET_SUPPORTED_SERVICES: |
| if ((i = get_plci(a))) |
| { |
| rplci = &a->plci[i - 1]; |
| rplci->appl = appl; |
| add_p(rplci, CAI, "\x01\x80"); |
| add_p(rplci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| sig_req(rplci, ASSIGN, DSIG_ID); |
| send_req(rplci); |
| } |
| else |
| { |
| PUT_DWORD(&SSstruct[6], MASK_TERMINAL_PORTABILITY); |
| SSparms = (byte *)SSstruct; |
| break; |
| } |
| rplci->internal_command = GETSERV_REQ_PEND; |
| rplci->number = Number; |
| rplci->appl = appl; |
| sig_req(rplci, S_SUPPORTED, 0); |
| send_req(rplci); |
| return false; |
| break; |
| |
| case S_LISTEN: |
| if (parms->length == 7) |
| { |
| if (api_parse(&parms->info[1], (word)parms->length, "wbd", ss_parms)) |
| { |
| dbug(1, dprintf("format wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| } |
| else |
| { |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| a->Notification_Mask[appl->Id - 1] = GET_DWORD(ss_parms[2].info); |
| if (a->Notification_Mask[appl->Id - 1] & SMASK_MWI) /* MWI active? */ |
| { |
| if ((i = get_plci(a))) |
| { |
| rplci = &a->plci[i - 1]; |
| rplci->appl = appl; |
| add_p(rplci, CAI, "\x01\x80"); |
| add_p(rplci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| sig_req(rplci, ASSIGN, DSIG_ID); |
| send_req(rplci); |
| } |
| else |
| { |
| break; |
| } |
| rplci->internal_command = GET_MWI_STATE; |
| rplci->number = Number; |
| sig_req(rplci, MWI_POLL, 0); |
| send_req(rplci); |
| } |
| break; |
| |
| case S_HOLD: |
| api_parse(&parms->info[1], (word)parms->length, "ws", ss_parms); |
| if (plci && plci->State && plci->SuppState == IDLE) |
| { |
| plci->SuppState = HOLD_REQUEST; |
| plci->command = C_HOLD_REQ; |
| add_s(plci, CAI, &ss_parms[1]); |
| sig_req(plci, CALL_HOLD, 0); |
| send_req(plci); |
| return false; |
| } |
| else Info = 0x3010; /* wrong state */ |
| break; |
| case S_RETRIEVE: |
| if (plci && plci->State && plci->SuppState == CALL_HELD) |
| { |
| if (Id & EXT_CONTROLLER) |
| { |
| if (AdvCodecSupport(a, plci, appl, 0)) |
| { |
| Info = 0x3010; /* wrong state */ |
| break; |
| } |
| } |
| else plci->tel = 0; |
| |
| plci->SuppState = RETRIEVE_REQUEST; |
| plci->command = C_RETRIEVE_REQ; |
| if (plci->spoofed_msg == SPOOFING_REQUIRED) |
| { |
| plci->spoofed_msg = CALL_RETRIEVE; |
| plci->internal_command = BLOCK_PLCI; |
| plci->command = 0; |
| dbug(1, dprintf("Spoof")); |
| return false; |
| } |
| else |
| { |
| sig_req(plci, CALL_RETRIEVE, 0); |
| send_req(plci); |
| return false; |
| } |
| } |
| else Info = 0x3010; /* wrong state */ |
| break; |
| case S_SUSPEND: |
| if (parms->length) |
| { |
| if (api_parse(&parms->info[1], (word)parms->length, "wbs", ss_parms)) |
| { |
| dbug(1, dprintf("format wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| } |
| if (plci && plci->State) |
| { |
| add_s(plci, CAI, &ss_parms[2]); |
| plci->command = SUSPEND_REQ; |
| sig_req(plci, SUSPEND, 0); |
| plci->State = SUSPENDING; |
| send_req(plci); |
| } |
| else Info = 0x3010; /* wrong state */ |
| break; |
| |
| case S_RESUME: |
| if (!(i = get_plci(a))) |
| { |
| Info = _OUT_OF_PLCI; |
| break; |
| } |
| rplci = &a->plci[i - 1]; |
| rplci->appl = appl; |
| rplci->number = Number; |
| rplci->tel = 0; |
| rplci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE; |
| /* check 'external controller' bit for codec support */ |
| if (Id & EXT_CONTROLLER) |
| { |
| if (AdvCodecSupport(a, rplci, appl, 0)) |
| { |
| rplci->Id = 0; |
| Info = 0x300A; |
| break; |
| } |
| } |
| if (parms->length) |
| { |
| if (api_parse(&parms->info[1], (word)parms->length, "wbs", ss_parms)) |
| { |
| dbug(1, dprintf("format wrong")); |
| rplci->Id = 0; |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| } |
| dummy.length = 0; |
| dummy.info = "\x00"; |
| add_b1(rplci, &dummy, 0, 0); |
| if (a->Info_Mask[appl->Id - 1] & 0x200) |
| { |
| /* early B3 connect (CIP mask bit 9) no release after a disc */ |
| add_p(rplci, LLI, "\x01\x01"); |
| } |
| add_p(rplci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| sig_req(rplci, ASSIGN, DSIG_ID); |
| send_req(rplci); |
| add_s(rplci, CAI, &ss_parms[2]); |
| rplci->command = RESUME_REQ; |
| sig_req(rplci, RESUME, 0); |
| rplci->State = RESUMING; |
| send_req(rplci); |
| break; |
| |
| case S_CONF_BEGIN: /* Request */ |
| case S_CONF_DROP: |
| case S_CONF_ISOLATE: |
| case S_CONF_REATTACH: |
| if (api_parse(&parms->info[1], (word)parms->length, "wbd", ss_parms)) |
| { |
| dbug(1, dprintf("format wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| if (plci && plci->State && ((plci->SuppState == IDLE) || (plci->SuppState == CALL_HELD))) |
| { |
| d = GET_DWORD(ss_parms[2].info); |
| if (d >= 0x80) |
| { |
| dbug(1, dprintf("format wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| plci->ptyState = (byte)SSreq; |
| plci->command = 0; |
| cai[0] = 2; |
| switch (SSreq) |
| { |
| case S_CONF_BEGIN: |
| cai[1] = CONF_BEGIN; |
| plci->internal_command = CONF_BEGIN_REQ_PEND; |
| break; |
| case S_CONF_DROP: |
| cai[1] = CONF_DROP; |
| plci->internal_command = CONF_DROP_REQ_PEND; |
| break; |
| case S_CONF_ISOLATE: |
| cai[1] = CONF_ISOLATE; |
| plci->internal_command = CONF_ISOLATE_REQ_PEND; |
| break; |
| case S_CONF_REATTACH: |
| cai[1] = CONF_REATTACH; |
| plci->internal_command = CONF_REATTACH_REQ_PEND; |
| break; |
| } |
| cai[2] = (byte)d; /* Conference Size resp. PartyId */ |
| add_p(plci, CAI, cai); |
| sig_req(plci, S_SERVICE, 0); |
| send_req(plci); |
| return false; |
| } |
| else Info = 0x3010; /* wrong state */ |
| break; |
| |
| case S_ECT: |
| case S_3PTY_BEGIN: |
| case S_3PTY_END: |
| case S_CONF_ADD: |
| if (parms->length == 7) |
| { |
| if (api_parse(&parms->info[1], (word)parms->length, "wbd", ss_parms)) |
| { |
| dbug(1, dprintf("format wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| } |
| else if (parms->length == 8) /* workaround for the T-View-S */ |
| { |
| if (api_parse(&parms->info[1], (word)parms->length, "wbdb", ss_parms)) |
| { |
| dbug(1, dprintf("format wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| } |
| else |
| { |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| if (!msg[1].length) |
| { |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| if (!plci) |
| { |
| Info = _WRONG_IDENTIFIER; |
| break; |
| } |
| relatedPLCIvalue = GET_DWORD(ss_parms[2].info); |
| relatedPLCIvalue &= 0x0000FFFF; |
| dbug(1, dprintf("PTY/ECT/addCONF,relPLCI=%lx", relatedPLCIvalue)); |
| /* controller starts with 0 up to (max_adapter - 1) */ |
| if (((relatedPLCIvalue & 0x7f) == 0) |
| || (MapController((byte)(relatedPLCIvalue & 0x7f)) == 0) |
| || (MapController((byte)(relatedPLCIvalue & 0x7f)) > max_adapter)) |
| { |
| if (SSreq == S_3PTY_END) |
| { |
| dbug(1, dprintf("wrong Controller use 2nd PLCI=PLCI")); |
| rplci = plci; |
| } |
| else |
| { |
| Info = 0x3010; /* wrong state */ |
| break; |
| } |
| } |
| else |
| { |
| relatedadapter = &adapter[MapController((byte)(relatedPLCIvalue & 0x7f)) - 1]; |
| relatedPLCIvalue >>= 8; |
| /* find PLCI PTR*/ |
| for (i = 0, rplci = NULL; i < relatedadapter->max_plci; i++) |
| { |
| if (relatedadapter->plci[i].Id == (byte)relatedPLCIvalue) |
| { |
| rplci = &relatedadapter->plci[i]; |
| } |
| } |
| if (!rplci || !relatedPLCIvalue) |
| { |
| if (SSreq == S_3PTY_END) |
| { |
| dbug(1, dprintf("use 2nd PLCI=PLCI")); |
| rplci = plci; |
| } |
| else |
| { |
| Info = 0x3010; /* wrong state */ |
| break; |
| } |
| } |
| } |
| /* |
| dbug(1, dprintf("rplci:%x", rplci)); |
| dbug(1, dprintf("plci:%x", plci)); |
| dbug(1, dprintf("rplci->ptyState:%x", rplci->ptyState)); |
| dbug(1, dprintf("plci->ptyState:%x", plci->ptyState)); |
| dbug(1, dprintf("SSreq:%x", SSreq)); |
| dbug(1, dprintf("rplci->internal_command:%x", rplci->internal_command)); |
| dbug(1, dprintf("rplci->appl:%x", rplci->appl)); |
| dbug(1, dprintf("rplci->Id:%x", rplci->Id)); |
| */ |
| /* send PTY/ECT req, cannot check all states because of US stuff */ |
| if (!rplci->internal_command && rplci->appl) |
| { |
| plci->command = 0; |
| rplci->relatedPTYPLCI = plci; |
| plci->relatedPTYPLCI = rplci; |
| rplci->ptyState = (byte)SSreq; |
| if (SSreq == S_ECT) |
| { |
| rplci->internal_command = ECT_REQ_PEND; |
| cai[1] = ECT_EXECUTE; |
| |
| rplci->vswitchstate = 0; |
| rplci->vsprot = 0; |
| rplci->vsprotdialect = 0; |
| plci->vswitchstate = 0; |
| plci->vsprot = 0; |
| plci->vsprotdialect = 0; |
| |
| } |
| else if (SSreq == S_CONF_ADD) |
| { |
| rplci->internal_command = CONF_ADD_REQ_PEND; |
| cai[1] = CONF_ADD; |
| } |
| else |
| { |
| rplci->internal_command = PTY_REQ_PEND; |
| cai[1] = (byte)(SSreq - 3); |
| } |
| rplci->number = Number; |
| if (plci != rplci) /* explicit invocation */ |
| { |
| cai[0] = 2; |
| cai[2] = plci->Sig.Id; |
| dbug(1, dprintf("explicit invocation")); |
| } |
| else |
| { |
| dbug(1, dprintf("implicit invocation")); |
| cai[0] = 1; |
| } |
| add_p(rplci, CAI, cai); |
| sig_req(rplci, S_SERVICE, 0); |
| send_req(rplci); |
| return false; |
| } |
| else |
| { |
| dbug(0, dprintf("Wrong line")); |
| Info = 0x3010; /* wrong state */ |
| break; |
| } |
| break; |
| |
| case S_CALL_DEFLECTION: |
| if (api_parse(&parms->info[1], (word)parms->length, "wbwss", ss_parms)) |
| { |
| dbug(1, dprintf("format wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| if (!plci) |
| { |
| Info = _WRONG_IDENTIFIER; |
| break; |
| } |
| /* reuse unused screening indicator */ |
| ss_parms[3].info[3] = (byte)GET_WORD(&(ss_parms[2].info[0])); |
| plci->command = 0; |
| plci->internal_command = CD_REQ_PEND; |
| appl->CDEnable = true; |
| cai[0] = 1; |
| cai[1] = CALL_DEFLECTION; |
| add_p(plci, CAI, cai); |
| add_p(plci, CPN, ss_parms[3].info); |
| sig_req(plci, S_SERVICE, 0); |
| send_req(plci); |
| return false; |
| break; |
| |
| case S_CALL_FORWARDING_START: |
| if (api_parse(&parms->info[1], (word)parms->length, "wbdwwsss", ss_parms)) |
| { |
| dbug(1, dprintf("format wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| |
| if ((i = get_plci(a))) |
| { |
| rplci = &a->plci[i - 1]; |
| rplci->appl = appl; |
| add_p(rplci, CAI, "\x01\x80"); |
| add_p(rplci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| sig_req(rplci, ASSIGN, DSIG_ID); |
| send_req(rplci); |
| } |
| else |
| { |
| Info = _OUT_OF_PLCI; |
| break; |
| } |
| |
| /* reuse unused screening indicator */ |
| rplci->internal_command = CF_START_PEND; |
| rplci->appl = appl; |
| rplci->number = Number; |
| appl->S_Handle = GET_DWORD(&(ss_parms[2].info[0])); |
| cai[0] = 2; |
| cai[1] = 0x70 | (byte)GET_WORD(&(ss_parms[3].info[0])); /* Function */ |
| cai[2] = (byte)GET_WORD(&(ss_parms[4].info[0])); /* Basic Service */ |
| add_p(rplci, CAI, cai); |
| add_p(rplci, OAD, ss_parms[5].info); |
| add_p(rplci, CPN, ss_parms[6].info); |
| sig_req(rplci, S_SERVICE, 0); |
| send_req(rplci); |
| return false; |
| break; |
| |
| case S_INTERROGATE_DIVERSION: |
| case S_INTERROGATE_NUMBERS: |
| case S_CALL_FORWARDING_STOP: |
| case S_CCBS_REQUEST: |
| case S_CCBS_DEACTIVATE: |
| case S_CCBS_INTERROGATE: |
| switch (SSreq) |
| { |
| case S_INTERROGATE_NUMBERS: |
| if (api_parse(&parms->info[1], (word)parms->length, "wbd", ss_parms)) |
| { |
| dbug(0, dprintf("format wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| } |
| break; |
| case S_CCBS_REQUEST: |
| case S_CCBS_DEACTIVATE: |
| if (api_parse(&parms->info[1], (word)parms->length, "wbdw", ss_parms)) |
| { |
| dbug(0, dprintf("format wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| } |
| break; |
| case S_CCBS_INTERROGATE: |
| if (api_parse(&parms->info[1], (word)parms->length, "wbdws", ss_parms)) |
| { |
| dbug(0, dprintf("format wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| } |
| break; |
| default: |
| if (api_parse(&parms->info[1], (word)parms->length, "wbdwws", ss_parms)) |
| { |
| dbug(0, dprintf("format wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| break; |
| } |
| |
| if (Info) break; |
| if ((i = get_plci(a))) |
| { |
| rplci = &a->plci[i - 1]; |
| switch (SSreq) |
| { |
| case S_INTERROGATE_DIVERSION: /* use cai with S_SERVICE below */ |
| cai[1] = 0x60 | (byte)GET_WORD(&(ss_parms[3].info[0])); /* Function */ |
| rplci->internal_command = INTERR_DIVERSION_REQ_PEND; /* move to rplci if assigned */ |
| break; |
| case S_INTERROGATE_NUMBERS: /* use cai with S_SERVICE below */ |
| cai[1] = DIVERSION_INTERROGATE_NUM; /* Function */ |
| rplci->internal_command = INTERR_NUMBERS_REQ_PEND; /* move to rplci if assigned */ |
| break; |
| case S_CALL_FORWARDING_STOP: |
| rplci->internal_command = CF_STOP_PEND; |
| cai[1] = 0x80 | (byte)GET_WORD(&(ss_parms[3].info[0])); /* Function */ |
| break; |
| case S_CCBS_REQUEST: |
| cai[1] = CCBS_REQUEST; |
| rplci->internal_command = CCBS_REQUEST_REQ_PEND; |
| break; |
| case S_CCBS_DEACTIVATE: |
| cai[1] = CCBS_DEACTIVATE; |
| rplci->internal_command = CCBS_DEACTIVATE_REQ_PEND; |
| break; |
| case S_CCBS_INTERROGATE: |
| cai[1] = CCBS_INTERROGATE; |
| rplci->internal_command = CCBS_INTERROGATE_REQ_PEND; |
| break; |
| default: |
| cai[1] = 0; |
| break; |
| } |
| rplci->appl = appl; |
| rplci->number = Number; |
| add_p(rplci, CAI, "\x01\x80"); |
| add_p(rplci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| sig_req(rplci, ASSIGN, DSIG_ID); |
| send_req(rplci); |
| } |
| else |
| { |
| Info = _OUT_OF_PLCI; |
| break; |
| } |
| |
| appl->S_Handle = GET_DWORD(&(ss_parms[2].info[0])); |
| switch (SSreq) |
| { |
| case S_INTERROGATE_NUMBERS: |
| cai[0] = 1; |
| add_p(rplci, CAI, cai); |
| break; |
| case S_CCBS_REQUEST: |
| case S_CCBS_DEACTIVATE: |
| cai[0] = 3; |
| PUT_WORD(&cai[2], GET_WORD(&(ss_parms[3].info[0]))); |
| add_p(rplci, CAI, cai); |
| break; |
| case S_CCBS_INTERROGATE: |
| cai[0] = 3; |
| PUT_WORD(&cai[2], GET_WORD(&(ss_parms[3].info[0]))); |
| add_p(rplci, CAI, cai); |
| add_p(rplci, OAD, ss_parms[4].info); |
| break; |
| default: |
| cai[0] = 2; |
| cai[2] = (byte)GET_WORD(&(ss_parms[4].info[0])); /* Basic Service */ |
| add_p(rplci, CAI, cai); |
| add_p(rplci, OAD, ss_parms[5].info); |
| break; |
| } |
| |
| sig_req(rplci, S_SERVICE, 0); |
| send_req(rplci); |
| return false; |
| break; |
| |
| case S_MWI_ACTIVATE: |
| if (api_parse(&parms->info[1], (word)parms->length, "wbwdwwwssss", ss_parms)) |
| { |
| dbug(1, dprintf("format wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| if (!plci) |
| { |
| if ((i = get_plci(a))) |
| { |
| rplci = &a->plci[i - 1]; |
| rplci->appl = appl; |
| rplci->cr_enquiry = true; |
| add_p(rplci, CAI, "\x01\x80"); |
| add_p(rplci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| sig_req(rplci, ASSIGN, DSIG_ID); |
| send_req(rplci); |
| } |
| else |
| { |
| Info = _OUT_OF_PLCI; |
| break; |
| } |
| } |
| else |
| { |
| rplci = plci; |
| rplci->cr_enquiry = false; |
| } |
| |
| rplci->command = 0; |
| rplci->internal_command = MWI_ACTIVATE_REQ_PEND; |
| rplci->appl = appl; |
| rplci->number = Number; |
| |
| cai[0] = 13; |
| cai[1] = ACTIVATION_MWI; /* Function */ |
| PUT_WORD(&cai[2], GET_WORD(&(ss_parms[2].info[0]))); /* Basic Service */ |
| PUT_DWORD(&cai[4], GET_DWORD(&(ss_parms[3].info[0]))); /* Number of Messages */ |
| PUT_WORD(&cai[8], GET_WORD(&(ss_parms[4].info[0]))); /* Message Status */ |
| PUT_WORD(&cai[10], GET_WORD(&(ss_parms[5].info[0]))); /* Message Reference */ |
| PUT_WORD(&cai[12], GET_WORD(&(ss_parms[6].info[0]))); /* Invocation Mode */ |
| add_p(rplci, CAI, cai); |
| add_p(rplci, CPN, ss_parms[7].info); /* Receiving User Number */ |
| add_p(rplci, OAD, ss_parms[8].info); /* Controlling User Number */ |
| add_p(rplci, OSA, ss_parms[9].info); /* Controlling User Provided Number */ |
| add_p(rplci, UID, ss_parms[10].info); /* Time */ |
| sig_req(rplci, S_SERVICE, 0); |
| send_req(rplci); |
| return false; |
| |
| case S_MWI_DEACTIVATE: |
| if (api_parse(&parms->info[1], (word)parms->length, "wbwwss", ss_parms)) |
| { |
| dbug(1, dprintf("format wrong")); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| if (!plci) |
| { |
| if ((i = get_plci(a))) |
| { |
| rplci = &a->plci[i - 1]; |
| rplci->appl = appl; |
| rplci->cr_enquiry = true; |
| add_p(rplci, CAI, "\x01\x80"); |
| add_p(rplci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| sig_req(rplci, ASSIGN, DSIG_ID); |
| send_req(rplci); |
| } |
| else |
| { |
| Info = _OUT_OF_PLCI; |
| break; |
| } |
| } |
| else |
| { |
| rplci = plci; |
| rplci->cr_enquiry = false; |
| } |
| |
| rplci->command = 0; |
| rplci->internal_command = MWI_DEACTIVATE_REQ_PEND; |
| rplci->appl = appl; |
| rplci->number = Number; |
| |
| cai[0] = 5; |
| cai[1] = DEACTIVATION_MWI; /* Function */ |
| PUT_WORD(&cai[2], GET_WORD(&(ss_parms[2].info[0]))); /* Basic Service */ |
| PUT_WORD(&cai[4], GET_WORD(&(ss_parms[3].info[0]))); /* Invocation Mode */ |
| add_p(rplci, CAI, cai); |
| add_p(rplci, CPN, ss_parms[4].info); /* Receiving User Number */ |
| add_p(rplci, OAD, ss_parms[5].info); /* Controlling User Number */ |
| sig_req(rplci, S_SERVICE, 0); |
| send_req(rplci); |
| return false; |
| |
| default: |
| Info = 0x300E; /* not supported */ |
| break; |
| } |
| break; /* case SELECTOR_SU_SERV: end */ |
| |
| |
| case SELECTOR_DTMF: |
| return (dtmf_request(Id, Number, a, plci, appl, msg)); |
| |
| |
| |
| case SELECTOR_LINE_INTERCONNECT: |
| return (mixer_request(Id, Number, a, plci, appl, msg)); |
| |
| |
| |
| case PRIV_SELECTOR_ECHO_CANCELLER: |
| appl->appl_flags |= APPL_FLAG_PRIV_EC_SPEC; |
| return (ec_request(Id, Number, a, plci, appl, msg)); |
| |
| case SELECTOR_ECHO_CANCELLER: |
| appl->appl_flags &= ~APPL_FLAG_PRIV_EC_SPEC; |
| return (ec_request(Id, Number, a, plci, appl, msg)); |
| |
| |
| case SELECTOR_V42BIS: |
| default: |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } /* end of switch (selector) */ |
| } |
| |
| dbug(1, dprintf("SendFacRc")); |
| sendf(appl, |
| _FACILITY_R | CONFIRM, |
| Id, |
| Number, |
| "wws", Info, selector, SSparms); |
| return false; |
| } |
| |
| static byte facility_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *msg) |
| { |
| dbug(1, dprintf("facility_res")); |
| return false; |
| } |
| |
| static byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *parms) |
| { |
| word Info = 0; |
| byte req; |
| byte len; |
| word w; |
| word fax_control_bits, fax_feature_bits, fax_info_change; |
| API_PARSE *ncpi; |
| byte pvc[2]; |
| |
| API_PARSE fax_parms[9]; |
| word i; |
| |
| |
| dbug(1, dprintf("connect_b3_req")); |
| if (plci) |
| { |
| if ((plci->State == IDLE) || (plci->State == OUTG_DIS_PENDING) |
| || (plci->State == INC_DIS_PENDING) || (plci->SuppState != IDLE)) |
| { |
| Info = _WRONG_STATE; |
| } |
| else |
| { |
| /* local reply if assign unsuccessful |
| or B3 protocol allows only one layer 3 connection |
| and already connected |
| or B2 protocol not any LAPD |
| and connect_b3_req contradicts originate/answer direction */ |
| if (!plci->NL.Id |
| || (((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE)) |
| && ((plci->channels != 0) |
| || (((plci->B2_prot != B2_SDLC) && (plci->B2_prot != B2_LAPD) && (plci->B2_prot != B2_LAPD_FREE_SAPI_SEL)) |
| && ((plci->call_dir & CALL_DIR_ANSWER) && !(plci->call_dir & CALL_DIR_FORCE_OUTG_NL)))))) |
| { |
| dbug(1, dprintf("B3 already connected=%d or no NL.Id=0x%x, dir=%d sstate=0x%x", |
| plci->channels, plci->NL.Id, plci->call_dir, plci->SuppState)); |
| Info = _WRONG_STATE; |
| sendf(appl, |
| _CONNECT_B3_R | CONFIRM, |
| Id, |
| Number, |
| "w", Info); |
| return false; |
| } |
| plci->requested_options_conn = 0; |
| |
| req = N_CONNECT; |
| ncpi = &parms[0]; |
| if (plci->B3_prot == 2 || plci->B3_prot == 3) |
| { |
| if (ncpi->length > 2) |
| { |
| /* check for PVC */ |
| if (ncpi->info[2] || ncpi->info[3]) |
| { |
| pvc[0] = ncpi->info[3]; |
| pvc[1] = ncpi->info[2]; |
| add_d(plci, 2, pvc); |
| req = N_RESET; |
| } |
| else |
| { |
| if (ncpi->info[1] & 1) req = N_CONNECT | N_D_BIT; |
| add_d(plci, (word)(ncpi->length - 3), &ncpi->info[4]); |
| } |
| } |
| } |
| else if (plci->B3_prot == 5) |
| { |
| if (plci->NL.Id && !plci->nl_remove_id) |
| { |
| fax_control_bits = GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low); |
| fax_feature_bits = GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->feature_bits_low); |
| if (!(fax_control_bits & T30_CONTROL_BIT_MORE_DOCUMENTS) |
| || (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS)) |
| { |
| len = offsetof(T30_INFO, universal_6); |
| fax_info_change = false; |
| if (ncpi->length >= 4) |
| { |
| w = GET_WORD(&ncpi->info[3]); |
| if ((w & 0x0001) != ((word)(((T30_INFO *)(plci->fax_connect_info_buffer))->resolution & 0x0001))) |
| { |
| ((T30_INFO *)(plci->fax_connect_info_buffer))->resolution = |
| (byte)((((T30_INFO *)(plci->fax_connect_info_buffer))->resolution & ~T30_RESOLUTION_R8_0770_OR_200) | |
| ((w & 0x0001) ? T30_RESOLUTION_R8_0770_OR_200 : 0)); |
| fax_info_change = true; |
| } |
| fax_control_bits &= ~(T30_CONTROL_BIT_REQUEST_POLLING | T30_CONTROL_BIT_MORE_DOCUMENTS); |
| if (w & 0x0002) /* Fax-polling request */ |
| fax_control_bits |= T30_CONTROL_BIT_REQUEST_POLLING; |
| if ((w & 0x0004) /* Request to send / poll another document */ |
| && (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_MORE_DOCUMENTS)) |
| { |
| fax_control_bits |= T30_CONTROL_BIT_MORE_DOCUMENTS; |
| } |
| if (ncpi->length >= 6) |
| { |
| w = GET_WORD(&ncpi->info[5]); |
| if (((byte) w) != ((T30_INFO *)(plci->fax_connect_info_buffer))->data_format) |
| { |
| ((T30_INFO *)(plci->fax_connect_info_buffer))->data_format = (byte) w; |
| fax_info_change = true; |
| } |
| |
| if ((a->man_profile.private_options & (1L << PRIVATE_FAX_SUB_SEP_PWD)) |
| && (GET_WORD(&ncpi->info[5]) & 0x8000)) /* Private SEP/SUB/PWD enable */ |
| { |
| plci->requested_options_conn |= (1L << PRIVATE_FAX_SUB_SEP_PWD); |
| } |
| if ((a->man_profile.private_options & (1L << PRIVATE_FAX_NONSTANDARD)) |
| && (GET_WORD(&ncpi->info[5]) & 0x4000)) /* Private non-standard facilities enable */ |
| { |
| plci->requested_options_conn |= (1L << PRIVATE_FAX_NONSTANDARD); |
| } |
| fax_control_bits &= ~(T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_SEL_POLLING | |
| T30_CONTROL_BIT_ACCEPT_PASSWORD); |
| if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id - 1]) |
| & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD))) |
| { |
| if (api_parse(&ncpi->info[1], ncpi->length, "wwwwsss", fax_parms)) |
| Info = _WRONG_MESSAGE_FORMAT; |
| else |
| { |
| if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id - 1]) |
| & (1L << PRIVATE_FAX_SUB_SEP_PWD)) |
| { |
| fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_PASSWORD; |
| if (fax_control_bits & T30_CONTROL_BIT_ACCEPT_POLLING) |
| fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SEL_POLLING; |
| } |
| w = fax_parms[4].length; |
| if (w > 20) |
| w = 20; |
| ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = (byte) w; |
| for (i = 0; i < w; i++) |
| ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id[i] = fax_parms[4].info[1 + i]; |
| ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0; |
| len = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH; |
| w = fax_parms[5].length; |
| if (w > 20) |
| w = 20; |
| plci->fax_connect_info_buffer[len++] = (byte) w; |
| for (i = 0; i < w; i++) |
| plci->fax_connect_info_buffer[len++] = fax_parms[5].info[1 + i]; |
| w = fax_parms[6].length; |
| if (w > 20) |
| w = 20; |
| plci->fax_connect_info_buffer[len++] = (byte) w; |
| for (i = 0; i < w; i++) |
| plci->fax_connect_info_buffer[len++] = fax_parms[6].info[1 + i]; |
| if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id - 1]) |
| & (1L << PRIVATE_FAX_NONSTANDARD)) |
| { |
| if (api_parse(&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms)) |
| { |
| dbug(1, dprintf("non-standard facilities info missing or wrong format")); |
| plci->fax_connect_info_buffer[len++] = 0; |
| } |
| else |
| { |
| if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2)) |
| plci->nsf_control_bits = GET_WORD(&fax_parms[7].info[2]); |
| plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length); |
| for (i = 0; i < fax_parms[7].length; i++) |
| plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1 + i]; |
| } |
| } |
| } |
| } |
| else |
| { |
| len = offsetof(T30_INFO, universal_6); |
| } |
| fax_info_change = true; |
| |
| } |
| if (fax_control_bits != GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low)) |
| { |
| PUT_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low, fax_control_bits); |
| fax_info_change = true; |
| } |
| } |
| if (Info == GOOD) |
| { |
| plci->fax_connect_info_length = len; |
| if (fax_info_change) |
| { |
| if (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS) |
| { |
| start_internal_command(Id, plci, fax_connect_info_command); |
| return false; |
| } |
| else |
| { |
| start_internal_command(Id, plci, fax_adjust_b23_command); |
| return false; |
| } |
| } |
| } |
| } |
| else Info = _WRONG_STATE; |
| } |
| else Info = _WRONG_STATE; |
| } |
| |
| else if (plci->B3_prot == B3_RTP) |
| { |
| plci->internal_req_buffer[0] = ncpi->length + 1; |
| plci->internal_req_buffer[1] = UDATA_REQUEST_RTP_RECONFIGURE; |
| for (w = 0; w < ncpi->length; w++) |
| plci->internal_req_buffer[2 + w] = ncpi->info[1 + w]; |
| start_internal_command(Id, plci, rtp_connect_b3_req_command); |
| return false; |
| } |
| |
| if (!Info) |
| { |
| nl_req_ncci(plci, req, 0); |
| return 1; |
| } |
| } |
| } |
| else Info = _WRONG_IDENTIFIER; |
| |
| sendf(appl, |
| _CONNECT_B3_R | CONFIRM, |
| Id, |
| Number, |
| "w", Info); |
| return false; |
| } |
| |
| static byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *parms) |
| { |
| word ncci; |
| API_PARSE *ncpi; |
| byte req; |
| |
| word w; |
| |
| |
| API_PARSE fax_parms[9]; |
| word i; |
| byte len; |
| |
| |
| dbug(1, dprintf("connect_b3_res")); |
| |
| ncci = (word)(Id >> 16); |
| if (plci && ncci) { |
| if (a->ncci_state[ncci] == INC_CON_PENDING) { |
| if (GET_WORD(&parms[0].info[0]) != 0) |
| { |
| a->ncci_state[ncci] = OUTG_REJ_PENDING; |
| channel_request_xon(plci, a->ncci_ch[ncci]); |
| channel_xmit_xon(plci); |
| cleanup_ncci_data(plci, ncci); |
| nl_req_ncci(plci, N_DISC, (byte)ncci); |
| return 1; |
| } |
| a->ncci_state[ncci] = INC_ACT_PENDING; |
| |
| req = N_CONNECT_ACK; |
| ncpi = &parms[1]; |
| if ((plci->B3_prot == 4) || (plci->B3_prot == 5) || (plci->B3_prot == 7)) |
| { |
| |
| if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id - 1]) |
| & (1L << PRIVATE_FAX_NONSTANDARD)) |
| { |
| if (((plci->B3_prot == 4) || (plci->B3_prot == 5)) |
| && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF) |
| && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP)) |
| { |
| len = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH; |
| if (plci->fax_connect_info_length < len) |
| { |
| ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0; |
| ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0; |
| } |
| if (api_parse(&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms)) |
| { |
| dbug(1, dprintf("non-standard facilities info missing or wrong format")); |
| } |
| else |
| { |
| if (plci->fax_connect_info_length <= len) |
| plci->fax_connect_info_buffer[len] = 0; |
| len += 1 + plci->fax_connect_info_buffer[len]; |
| if (plci->fax_connect_info_length <= len) |
| plci->fax_connect_info_buffer[len] = 0; |
| len += 1 + plci->fax_connect_info_buffer[len]; |
| if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2)) |
| plci->nsf_control_bits = GET_WORD(&fax_parms[7].info[2]); |
| plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length); |
| for (i = 0; i < fax_parms[7].length; i++) |
| plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1 + i]; |
| } |
| plci->fax_connect_info_length = len; |
| ((T30_INFO *)(plci->fax_connect_info_buffer))->code = 0; |
| start_internal_command(Id, plci, fax_connect_ack_command); |
| return false; |
| } |
| } |
| |
| nl_req_ncci(plci, req, (byte)ncci); |
| if ((plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT) |
| && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT)) |
| { |
| if (plci->B3_prot == 4) |
| sendf(appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", ""); |
| else |
| sendf(appl, _CONNECT_B3_ACTIVE_I, Id, 0, "S", plci->ncpi_buffer); |
| plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT; |
| } |
| } |
| |
| else if (plci->B3_prot == B3_RTP) |
| { |
| plci->internal_req_buffer[0] = ncpi->length + 1; |
| plci->internal_req_buffer[1] = UDATA_REQUEST_RTP_RECONFIGURE; |
| for (w = 0; w < ncpi->length; w++) |
| plci->internal_req_buffer[2 + w] = ncpi->info[1+w]; |
| start_internal_command(Id, plci, rtp_connect_b3_res_command); |
| return false; |
| } |
| |
| else |
| { |
| if (ncpi->length > 2) { |
| if (ncpi->info[1] & 1) req = N_CONNECT_ACK | N_D_BIT; |
| add_d(plci, (word)(ncpi->length - 3), &ncpi->info[4]); |
| } |
| nl_req_ncci(plci, req, (byte)ncci); |
| sendf(appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", ""); |
| if (plci->adjust_b_restore) |
| { |
| plci->adjust_b_restore = false; |
| start_internal_command(Id, plci, adjust_b_restore); |
| } |
| } |
| return 1; |
| } |
| } |
| return false; |
| } |
| |
| static byte connect_b3_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *parms) |
| { |
| word ncci; |
| |
| ncci = (word)(Id >> 16); |
| dbug(1, dprintf("connect_b3_a_res(ncci=0x%x)", ncci)); |
| |
| if (plci && ncci && (plci->State != IDLE) && (plci->State != INC_DIS_PENDING) |
| && (plci->State != OUTG_DIS_PENDING)) |
| { |
| if (a->ncci_state[ncci] == INC_ACT_PENDING) { |
| a->ncci_state[ncci] = CONNECTED; |
| if (plci->State != INC_CON_CONNECTED_ALERT) plci->State = CONNECTED; |
| channel_request_xon(plci, a->ncci_ch[ncci]); |
| channel_xmit_xon(plci); |
| } |
| } |
| return false; |
| } |
| |
| static byte disconnect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *parms) |
| { |
| word Info; |
| word ncci; |
| API_PARSE *ncpi; |
| |
| dbug(1, dprintf("disconnect_b3_req")); |
| |
| Info = _WRONG_IDENTIFIER; |
| ncci = (word)(Id >> 16); |
| if (plci && ncci) |
| { |
| Info = _WRONG_STATE; |
| if ((a->ncci_state[ncci] == CONNECTED) |
| || (a->ncci_state[ncci] == OUTG_CON_PENDING) |
| || (a->ncci_state[ncci] == INC_CON_PENDING) |
| || (a->ncci_state[ncci] == INC_ACT_PENDING)) |
| { |
| a->ncci_state[ncci] = OUTG_DIS_PENDING; |
| channel_request_xon(plci, a->ncci_ch[ncci]); |
| channel_xmit_xon(plci); |
| |
| if (a->ncci[ncci].data_pending |
| && ((plci->B3_prot == B3_TRANSPARENT) |
| || (plci->B3_prot == B3_T30) |
| || (plci->B3_prot == B3_T30_WITH_EXTENSIONS))) |
| { |
| plci->send_disc = (byte)ncci; |
| plci->command = 0; |
| return false; |
| } |
| else |
| { |
| cleanup_ncci_data(plci, ncci); |
| |
| if (plci->B3_prot == 2 || plci->B3_prot == 3) |
| { |
| ncpi = &parms[0]; |
| if (ncpi->length > 3) |
| { |
| add_d(plci, (word)(ncpi->length - 3), (byte *)&(ncpi->info[4])); |
| } |
| } |
| nl_req_ncci(plci, N_DISC, (byte)ncci); |
| } |
| return 1; |
| } |
| } |
| sendf(appl, |
| _DISCONNECT_B3_R | CONFIRM, |
| Id, |
| Number, |
| "w", Info); |
| return false; |
| } |
| |
| static byte disconnect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *parms) |
| { |
| word ncci; |
| word i; |
| |
| ncci = (word)(Id >> 16); |
| dbug(1, dprintf("disconnect_b3_res(ncci=0x%x", ncci)); |
| if (plci && ncci) { |
| plci->requested_options_conn = 0; |
| plci->fax_connect_info_length = 0; |
| plci->ncpi_state = 0x00; |
| if (((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE)) |
| && ((plci->B2_prot != B2_LAPD) && (plci->B2_prot != B2_LAPD_FREE_SAPI_SEL))) |
| { |
| plci->call_dir |= CALL_DIR_FORCE_OUTG_NL; |
| } |
| for (i = 0; i < MAX_CHANNELS_PER_PLCI && plci->inc_dis_ncci_table[i] != (byte)ncci; i++); |
| if (i < MAX_CHANNELS_PER_PLCI) { |
| if (plci->channels)plci->channels--; |
| for (; i < MAX_CHANNELS_PER_PLCI - 1; i++) plci->inc_dis_ncci_table[i] = plci->inc_dis_ncci_table[i + 1]; |
| plci->inc_dis_ncci_table[MAX_CHANNELS_PER_PLCI - 1] = 0; |
| |
| ncci_free_receive_buffers(plci, ncci); |
| |
| if ((plci->State == IDLE || plci->State == SUSPENDING) && !plci->channels) { |
| if (plci->State == SUSPENDING) { |
| sendf(plci->appl, |
| _FACILITY_I, |
| Id & 0xffffL, |
| 0, |
| "ws", (word)3, "\x03\x04\x00\x00"); |
| sendf(plci->appl, _DISCONNECT_I, Id & 0xffffL, 0, "w", 0); |
| } |
| plci_remove(plci); |
| plci->State = IDLE; |
| } |
| } |
| else |
| { |
| if ((a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS) |
| && ((plci->B3_prot == 4) || (plci->B3_prot == 5)) |
| && (a->ncci_state[ncci] == INC_DIS_PENDING)) |
| { |
| ncci_free_receive_buffers(plci, ncci); |
| |
| nl_req_ncci(plci, N_EDATA, (byte)ncci); |
| |
| plci->adapter->ncci_state[ncci] = IDLE; |
| start_internal_command(Id, plci, fax_disconnect_command); |
| return 1; |
| } |
| } |
| } |
| return false; |
| } |
| |
| static byte data_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *parms) |
| { |
| NCCI *ncci_ptr; |
| DATA_B3_DESC *data; |
| word Info; |
| word ncci; |
| word i; |
| |
| dbug(1, dprintf("data_b3_req")); |
| |
| Info = _WRONG_IDENTIFIER; |
| ncci = (word)(Id >> 16); |
| dbug(1, dprintf("ncci=0x%x, plci=0x%x", ncci, plci)); |
| |
| if (plci && ncci) |
| { |
| Info = _WRONG_STATE; |
| if ((a->ncci_state[ncci] == CONNECTED) |
| || (a->ncci_state[ncci] == INC_ACT_PENDING)) |
| { |
| /* queue data */ |
| ncci_ptr = &(a->ncci[ncci]); |
| i = ncci_ptr->data_out + ncci_ptr->data_pending; |
| if (i >= MAX_DATA_B3) |
| i -= MAX_DATA_B3; |
| data = &(ncci_ptr->DBuffer[i]); |
| data->Number = Number; |
| if ((((byte *)(parms[0].info)) >= ((byte *)(plci->msg_in_queue))) |
| && (((byte *)(parms[0].info)) < ((byte *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue))) |
| { |
| |
| data->P = (byte *)(long)(*((dword *)(parms[0].info))); |
| |
| } |
| else |
| data->P = TransmitBufferSet(appl, *(dword *)parms[0].info); |
| data->Length = GET_WORD(parms[1].info); |
| data->Handle = GET_WORD(parms[2].info); |
| data->Flags = GET_WORD(parms[3].info); |
| (ncci_ptr->data_pending)++; |
| |
| /* check for delivery confirmation */ |
| if (data->Flags & 0x0004) |
| { |
| i = ncci_ptr->data_ack_out + ncci_ptr->data_ack_pending; |
| if (i >= MAX_DATA_ACK) |
| i -= MAX_DATA_ACK; |
| ncci_ptr->DataAck[i].Number = data->Number; |
| ncci_ptr->DataAck[i].Handle = data->Handle; |
| (ncci_ptr->data_ack_pending)++; |
| } |
| |
| send_data(plci); |
| return false; |
| } |
| } |
| if (appl) |
| { |
| if (plci) |
| { |
| if ((((byte *)(parms[0].info)) >= ((byte *)(plci->msg_in_queue))) |
| && (((byte *)(parms[0].info)) < ((byte *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue))) |
| { |
| |
| TransmitBufferFree(appl, (byte *)(long)(*((dword *)(parms[0].info)))); |
| |
| } |
| } |
| sendf(appl, |
| _DATA_B3_R | CONFIRM, |
| Id, |
| Number, |
| "ww", GET_WORD(parms[2].info), Info); |
| } |
| return false; |
| } |
| |
| static byte data_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *parms) |
| { |
| word n; |
| word ncci; |
| word NCCIcode; |
| |
| dbug(1, dprintf("data_b3_res")); |
| |
| ncci = (word)(Id >> 16); |
| if (plci && ncci) { |
| n = GET_WORD(parms[0].info); |
| dbug(1, dprintf("free(%d)", n)); |
| NCCIcode = ncci | (((word) a->Id) << 8); |
| if (n < appl->MaxBuffer && |
| appl->DataNCCI[n] == NCCIcode && |
| (byte)(appl->DataFlags[n] >> 8) == plci->Id) { |
| dbug(1, dprintf("found")); |
| appl->DataNCCI[n] = 0; |
| |
| if (channel_can_xon(plci, a->ncci_ch[ncci])) { |
| channel_request_xon(plci, a->ncci_ch[ncci]); |
| } |
| channel_xmit_xon(plci); |
| |
| if (appl->DataFlags[n] & 4) { |
| nl_req_ncci(plci, N_DATA_ACK, (byte)ncci); |
| return 1; |
| } |
| } |
| } |
| return false; |
| } |
| |
| static byte reset_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *parms) |
| { |
| word Info; |
| word ncci; |
| |
| dbug(1, dprintf("reset_b3_req")); |
| |
| Info = _WRONG_IDENTIFIER; |
| ncci = (word)(Id >> 16); |
| if (plci && ncci) |
| { |
| Info = _WRONG_STATE; |
| switch (plci->B3_prot) |
| { |
| case B3_ISO8208: |
| case B3_X25_DCE: |
| if (a->ncci_state[ncci] == CONNECTED) |
| { |
| nl_req_ncci(plci, N_RESET, (byte)ncci); |
| send_req(plci); |
| Info = GOOD; |
| } |
| break; |
| case B3_TRANSPARENT: |
| if (a->ncci_state[ncci] == CONNECTED) |
| { |
| start_internal_command(Id, plci, reset_b3_command); |
| Info = GOOD; |
| } |
| break; |
| } |
| } |
| /* reset_b3 must result in a reset_b3_con & reset_b3_Ind */ |
| sendf(appl, |
| _RESET_B3_R | CONFIRM, |
| Id, |
| Number, |
| "w", Info); |
| return false; |
| } |
| |
| static byte reset_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *parms) |
| { |
| word ncci; |
| |
| dbug(1, dprintf("reset_b3_res")); |
| |
| ncci = (word)(Id >> 16); |
| if (plci && ncci) { |
| switch (plci->B3_prot) |
| { |
| case B3_ISO8208: |
| case B3_X25_DCE: |
| if (a->ncci_state[ncci] == INC_RES_PENDING) |
| { |
| a->ncci_state[ncci] = CONNECTED; |
| nl_req_ncci(plci, N_RESET_ACK, (byte)ncci); |
| return true; |
| } |
| break; |
| } |
| } |
| return false; |
| } |
| |
| static byte connect_b3_t90_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *parms) |
| { |
| word ncci; |
| API_PARSE *ncpi; |
| byte req; |
| |
| dbug(1, dprintf("connect_b3_t90_a_res")); |
| |
| ncci = (word)(Id >> 16); |
| if (plci && ncci) { |
| if (a->ncci_state[ncci] == INC_ACT_PENDING) { |
| a->ncci_state[ncci] = CONNECTED; |
| } |
| else if (a->ncci_state[ncci] == INC_CON_PENDING) { |
| a->ncci_state[ncci] = CONNECTED; |
| |
| req = N_CONNECT_ACK; |
| |
| /* parms[0]==0 for CAPI original message definition! */ |
| if (parms[0].info) { |
| ncpi = &parms[1]; |
| if (ncpi->length > 2) { |
| if (ncpi->info[1] & 1) req = N_CONNECT_ACK | N_D_BIT; |
| add_d(plci, (word)(ncpi->length - 3), &ncpi->info[4]); |
| } |
| } |
| nl_req_ncci(plci, req, (byte)ncci); |
| return 1; |
| } |
| } |
| return false; |
| } |
| |
| |
| static byte select_b_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *msg) |
| { |
| word Info = 0; |
| word i; |
| byte tel; |
| API_PARSE bp_parms[7]; |
| |
| if (!plci || !msg) |
| { |
| Info = _WRONG_IDENTIFIER; |
| } |
| else |
| { |
| dbug(1, dprintf("select_b_req[%d],PLCI=0x%x,Tel=0x%x,NL=0x%x,appl=0x%x,sstate=0x%x", |
| msg->length, plci->Id, plci->tel, plci->NL.Id, plci->appl, plci->SuppState)); |
| dbug(1, dprintf("PlciState=0x%x", plci->State)); |
| for (i = 0; i < 7; i++) bp_parms[i].length = 0; |
| |
| /* check if no channel is open, no B3 connected only */ |
| if ((plci->State == IDLE) || (plci->State == OUTG_DIS_PENDING) || (plci->State == INC_DIS_PENDING) |
| || (plci->SuppState != IDLE) || plci->channels || plci->nl_remove_id) |
| { |
| Info = _WRONG_STATE; |
| } |
| /* check message format and fill bp_parms pointer */ |
| else if (msg->length && api_parse(&msg->info[1], (word)msg->length, "wwwsss", bp_parms)) |
| { |
| Info = _WRONG_MESSAGE_FORMAT; |
| } |
| else |
| { |
| if ((plci->State == INC_CON_PENDING) || (plci->State == INC_CON_ALERT)) /* send alert tone inband to the network, */ |
| { /* e.g. Qsig or RBS or Cornet-N or xess PRI */ |
| if (Id & EXT_CONTROLLER) |
| { |
| sendf(appl, _SELECT_B_REQ | CONFIRM, Id, Number, "w", 0x2002); /* wrong controller */ |
| return 0; |
| } |
| plci->State = INC_CON_CONNECTED_ALERT; |
| plci->appl = appl; |
| clear_c_ind_mask_bit(plci, (word)(appl->Id - 1)); |
| dump_c_ind_mask(plci); |
| for (i = 0; i < max_appl; i++) /* disconnect the other appls */ |
| { /* its quasi a connect */ |
| if (test_c_ind_mask_bit(plci, i)) |
| sendf(&application[i], _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED); |
| } |
| } |
| |
| api_save_msg(msg, "s", &plci->saved_msg); |
| tel = plci->tel; |
| if (Id & EXT_CONTROLLER) |
| { |
| if (tel) /* external controller in use by this PLCI */ |
| { |
| if (a->AdvSignalAppl && a->AdvSignalAppl != appl) |
| { |
| dbug(1, dprintf("Ext_Ctrl in use 1")); |
| Info = _WRONG_STATE; |
| } |
| } |
| else /* external controller NOT in use by this PLCI ? */ |
| { |
| if (a->AdvSignalPLCI) |
| { |
| dbug(1, dprintf("Ext_Ctrl in use 2")); |
| Info = _WRONG_STATE; |
| } |
| else /* activate the codec */ |
| { |
| dbug(1, dprintf("Ext_Ctrl start")); |
| if (AdvCodecSupport(a, plci, appl, 0)) |
| { |
| dbug(1, dprintf("Error in codec procedures")); |
| Info = _WRONG_STATE; |
| } |
| else if (plci->spoofed_msg == SPOOFING_REQUIRED) /* wait until codec is active */ |
| { |
| plci->spoofed_msg = AWAITING_SELECT_B; |
| plci->internal_command = BLOCK_PLCI; /* lock other commands */ |
| plci->command = 0; |
| dbug(1, dprintf("continue if codec loaded")); |
| return false; |
| } |
| } |
| } |
| } |
| else /* external controller bit is OFF */ |
| { |
| if (tel) /* external controller in use, need to switch off */ |
| { |
| if (a->AdvSignalAppl == appl) |
| { |
| CodecIdCheck(a, plci); |
| plci->tel = 0; |
| plci->adv_nl = 0; |
| dbug(1, dprintf("Ext_Ctrl disable")); |
| } |
| else |
| { |
| dbug(1, dprintf("Ext_Ctrl not requested")); |
| } |
| } |
| } |
| if (!Info) |
| { |
| if (plci->call_dir & CALL_DIR_OUT) |
| plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE; |
| else if (plci->call_dir & CALL_DIR_IN) |
| plci->call_dir = CALL_DIR_IN | CALL_DIR_ANSWER; |
| start_internal_command(Id, plci, select_b_command); |
| return false; |
| } |
| } |
| } |
| sendf(appl, _SELECT_B_REQ | CONFIRM, Id, Number, "w", Info); |
| return false; |
| } |
| |
| static byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *parms) |
| { |
| word command; |
| word i; |
| word ncci; |
| API_PARSE *m; |
| API_PARSE m_parms[5]; |
| word codec; |
| byte req; |
| byte ch; |
| byte dir; |
| static byte chi[2] = {0x01, 0x00}; |
| static byte lli[2] = {0x01, 0x00}; |
| static byte codec_cai[2] = {0x01, 0x01}; |
| static byte null_msg = {0}; |
| static API_PARSE null_parms = { 0, &null_msg }; |
| PLCI *v_plci; |
| word Info = 0; |
| |
| dbug(1, dprintf("manufacturer_req")); |
| for (i = 0; i < 5; i++) m_parms[i].length = 0; |
| |
| if (GET_DWORD(parms[0].info) != _DI_MANU_ID) { |
| Info = _WRONG_MESSAGE_FORMAT; |
| } |
| command = GET_WORD(parms[1].info); |
| m = &parms[2]; |
| if (!Info) |
| { |
| switch (command) { |
| case _DI_ASSIGN_PLCI: |
| if (api_parse(&m->info[1], (word)m->length, "wbbs", m_parms)) { |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| codec = GET_WORD(m_parms[0].info); |
| ch = m_parms[1].info[0]; |
| dir = m_parms[2].info[0]; |
| if ((i = get_plci(a))) { |
| plci = &a->plci[i - 1]; |
| plci->appl = appl; |
| plci->command = _MANUFACTURER_R; |
| plci->m_command = command; |
| plci->number = Number; |
| plci->State = LOCAL_CONNECT; |
| Id = (((word)plci->Id << 8) | plci->adapter->Id | 0x80); |
| dbug(1, dprintf("ManCMD,plci=0x%x", Id)); |
| |
| if ((ch == 1 || ch == 2) && (dir <= 2)) { |
| chi[1] = (byte)(0x80 | ch); |
| lli[1] = 0; |
| plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE; |
| switch (codec) |
| { |
| case 0: |
| Info = add_b1(plci, &m_parms[3], 0, 0); |
| break; |
| case 1: |
| add_p(plci, CAI, codec_cai); |
| break; |
| /* manual 'swich on' to the codec support without signalling */ |
| /* first 'assign plci' with this function, then use */ |
| case 2: |
| if (AdvCodecSupport(a, plci, appl, 0)) { |
| Info = _RESOURCE_ERROR; |
| } |
| else { |
| Info = add_b1(plci, &null_parms, 0, B1_FACILITY_LOCAL); |
| lli[1] = 0x10; /* local call codec stream */ |
| } |
| break; |
| } |
| |
| plci->State = LOCAL_CONNECT; |
| plci->manufacturer = true; |
| plci->command = _MANUFACTURER_R; |
| plci->m_command = command; |
| plci->number = Number; |
| |
| if (!Info) |
| { |
| add_p(plci, LLI, lli); |
| add_p(plci, CHI, chi); |
| add_p(plci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| sig_req(plci, ASSIGN, DSIG_ID); |
| |
| if (!codec) |
| { |
| Info = add_b23(plci, &m_parms[3]); |
| if (!Info) |
| { |
| nl_req_ncci(plci, ASSIGN, 0); |
| send_req(plci); |
| } |
| } |
| if (!Info) |
| { |
| dbug(1, dprintf("dir=0x%x,spoof=0x%x", dir, plci->spoofed_msg)); |
| if (plci->spoofed_msg == SPOOFING_REQUIRED) |
| { |
| api_save_msg(m_parms, "wbbs", &plci->saved_msg); |
| plci->spoofed_msg = AWAITING_MANUF_CON; |
| plci->internal_command = BLOCK_PLCI; /* reject other req meanwhile */ |
| plci->command = 0; |
| send_req(plci); |
| return false; |
| } |
| if (dir == 1) { |
| sig_req(plci, CALL_REQ, 0); |
| } |
| else if (!dir) { |
| sig_req(plci, LISTEN_REQ, 0); |
| } |
| send_req(plci); |
| } |
| else |
| { |
| sendf(appl, |
| _MANUFACTURER_R | CONFIRM, |
| Id, |
| Number, |
| "dww", _DI_MANU_ID, command, Info); |
| return 2; |
| } |
| } |
| } |
| } |
| else Info = _OUT_OF_PLCI; |
| break; |
| |
| case _DI_IDI_CTRL: |
| if (!plci) |
| { |
| Info = _WRONG_IDENTIFIER; |
| break; |
| } |
| if (api_parse(&m->info[1], (word)m->length, "bs", m_parms)) { |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| req = m_parms[0].info[0]; |
| plci->command = _MANUFACTURER_R; |
| plci->m_command = command; |
| plci->number = Number; |
| if (req == CALL_REQ) |
| { |
| plci->b_channel = getChannel(&m_parms[1]); |
| mixer_set_bchannel_id_esc(plci, plci->b_channel); |
| if (plci->spoofed_msg == SPOOFING_REQUIRED) |
| { |
| plci->spoofed_msg = CALL_REQ | AWAITING_MANUF_CON; |
| plci->internal_command = BLOCK_PLCI; /* reject other req meanwhile */ |
| plci->command = 0; |
| break; |
| } |
| } |
| else if (req == LAW_REQ) |
| { |
| plci->cr_enquiry = true; |
| } |
| add_ss(plci, FTY, &m_parms[1]); |
| sig_req(plci, req, 0); |
| send_req(plci); |
| if (req == HANGUP) |
| { |
| if (plci->NL.Id && !plci->nl_remove_id) |
| { |
| if (plci->channels) |
| { |
| for (ncci = 1; ncci < MAX_NCCI + 1; ncci++) |
| { |
| if ((a->ncci_plci[ncci] == plci->Id) && (a->ncci_state[ncci] == CONNECTED)) |
| { |
| a->ncci_state[ncci] = OUTG_DIS_PENDING; |
| cleanup_ncci_data(plci, ncci); |
| nl_req_ncci(plci, N_DISC, (byte)ncci); |
| } |
| } |
| } |
| mixer_remove(plci); |
| nl_req_ncci(plci, REMOVE, 0); |
| send_req(plci); |
| } |
| } |
| break; |
| |
| case _DI_SIG_CTRL: |
| /* signalling control for loop activation B-channel */ |
| if (!plci) |
| { |
| Info = _WRONG_IDENTIFIER; |
| break; |
| } |
| if (m->length) { |
| plci->command = _MANUFACTURER_R; |
| plci->number = Number; |
| add_ss(plci, FTY, m); |
| sig_req(plci, SIG_CTRL, 0); |
| send_req(plci); |
| } |
| else Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| |
| case _DI_RXT_CTRL: |
| /* activation control for receiver/transmitter B-channel */ |
| if (!plci) |
| { |
| Info = _WRONG_IDENTIFIER; |
| break; |
| } |
| if (m->length) { |
| plci->command = _MANUFACTURER_R; |
| plci->number = Number; |
| add_ss(plci, FTY, m); |
| sig_req(plci, DSP_CTRL, 0); |
| send_req(plci); |
| } |
| else Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| |
| case _DI_ADV_CODEC: |
| case _DI_DSP_CTRL: |
| /* TEL_CTRL commands to support non standard adjustments: */ |
| /* Ring on/off, Handset micro volume, external micro vol. */ |
| /* handset+external speaker volume, receiver+transm. gain,*/ |
| /* handsfree on (hookinfo off), set mixer command */ |
| |
| if (command == _DI_ADV_CODEC) |
| { |
| if (!a->AdvCodecPLCI) { |
| Info = _WRONG_STATE; |
| break; |
| } |
| v_plci = a->AdvCodecPLCI; |
| } |
| else |
| { |
| if (plci |
| && (m->length >= 3) |
| && (m->info[1] == 0x1c) |
| && (m->info[2] >= 1)) |
| { |
| if (m->info[3] == DSP_CTRL_OLD_SET_MIXER_COEFFICIENTS) |
| { |
| if ((plci->tel != ADV_VOICE) || (plci != a->AdvSignalPLCI)) |
| { |
| Info = _WRONG_STATE; |
| break; |
| } |
| a->adv_voice_coef_length = m->info[2] - 1; |
| if (a->adv_voice_coef_length > m->length - 3) |
| a->adv_voice_coef_length = (byte)(m->length - 3); |
| if (a->adv_voice_coef_length > ADV_VOICE_COEF_BUFFER_SIZE) |
| a->adv_voice_coef_length = ADV_VOICE_COEF_BUFFER_SIZE; |
| for (i = 0; i < a->adv_voice_coef_length; i++) |
| a->adv_voice_coef_buffer[i] = m->info[4 + i]; |
| if (plci->B1_facilities & B1_FACILITY_VOICE) |
| adv_voice_write_coefs(plci, ADV_VOICE_WRITE_UPDATE); |
| break; |
| } |
| else if (m->info[3] == DSP_CTRL_SET_DTMF_PARAMETERS) |
| { |
| if (!(a->manufacturer_features & MANUFACTURER_FEATURE_DTMF_PARAMETERS)) |
| { |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } |
| |
| plci->dtmf_parameter_length = m->info[2] - 1; |
| if (plci->dtmf_parameter_length > m->length - 3) |
| plci->dtmf_parameter_length = (byte)(m->length - 3); |
| if (plci->dtmf_parameter_length > DTMF_PARAMETER_BUFFER_SIZE) |
| plci->dtmf_parameter_length = DTMF_PARAMETER_BUFFER_SIZE; |
| for (i = 0; i < plci->dtmf_parameter_length; i++) |
| plci->dtmf_parameter_buffer[i] = m->info[4 + i]; |
| if (plci->B1_facilities & B1_FACILITY_DTMFR) |
| dtmf_parameter_write(plci); |
| break; |
| |
| } |
| } |
| v_plci = plci; |
| } |
| |
| if (!v_plci) |
| { |
| Info = _WRONG_IDENTIFIER; |
| break; |
| } |
| if (m->length) { |
| add_ss(v_plci, FTY, m); |
| sig_req(v_plci, TEL_CTRL, 0); |
| send_req(v_plci); |
| } |
| else Info = _WRONG_MESSAGE_FORMAT; |
| |
| break; |
| |
| case _DI_OPTIONS_REQUEST: |
| if (api_parse(&m->info[1], (word)m->length, "d", m_parms)) { |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| if (GET_DWORD(m_parms[0].info) & ~a->man_profile.private_options) |
| { |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } |
| a->requested_options_table[appl->Id - 1] = GET_DWORD(m_parms[0].info); |
| break; |
| |
| |
| |
| default: |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| } |
| |
| sendf(appl, |
| _MANUFACTURER_R | CONFIRM, |
| Id, |
| Number, |
| "dww", _DI_MANU_ID, command, Info); |
| return false; |
| } |
| |
| |
| static byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, |
| PLCI *plci, APPL *appl, API_PARSE *msg) |
| { |
| word indication; |
| |
| API_PARSE m_parms[3]; |
| API_PARSE *ncpi; |
| API_PARSE fax_parms[9]; |
| word i; |
| byte len; |
| |
| |
| dbug(1, dprintf("manufacturer_res")); |
| |
| if ((msg[0].length == 0) |
| || (msg[1].length == 0) |
| || (GET_DWORD(msg[0].info) != _DI_MANU_ID)) |
| { |
| return false; |
| } |
| indication = GET_WORD(msg[1].info); |
| switch (indication) |
| { |
| |
| case _DI_NEGOTIATE_B3: |
| if (!plci) |
| break; |
| if (((plci->B3_prot != 4) && (plci->B3_prot != 5)) |
| || !(plci->ncpi_state & NCPI_NEGOTIATE_B3_SENT)) |
| { |
| dbug(1, dprintf("wrong state for NEGOTIATE_B3 parameters")); |
| break; |
| } |
| if (api_parse(&msg[2].info[1], msg[2].length, "ws", m_parms)) |
| { |
| dbug(1, dprintf("wrong format in NEGOTIATE_B3 parameters")); |
| break; |
| } |
| ncpi = &m_parms[1]; |
| len = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH; |
| if (plci->fax_connect_info_length < len) |
| { |
| ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0; |
| ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0; |
| } |
| if (api_parse(&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms)) |
| { |
| dbug(1, dprintf("non-standard facilities info missing or wrong format")); |
| } |
| else |
| { |
| if (plci->fax_connect_info_length <= len) |
| plci->fax_connect_info_buffer[len] = 0; |
| len += 1 + plci->fax_connect_info_buffer[len]; |
| if (plci->fax_connect_info_length <= len) |
| plci->fax_connect_info_buffer[len] = 0; |
| len += 1 + plci->fax_connect_info_buffer[len]; |
| if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2)) |
| plci->nsf_control_bits = GET_WORD(&fax_parms[7].info[2]); |
| plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length); |
| for (i = 0; i < fax_parms[7].length; i++) |
| plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1 + i]; |
| } |
| plci->fax_connect_info_length = len; |
| plci->fax_edata_ack_length = plci->fax_connect_info_length; |
| start_internal_command(Id, plci, fax_edata_ack_command); |
| break; |
| |
| } |
| return false; |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* IDI callback function */ |
| /*------------------------------------------------------------------*/ |
| |
| void callback(ENTITY *e) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| APPL *appl; |
| PLCI *plci; |
| CAPI_MSG *m; |
| word i, j; |
| byte rc; |
| byte ch; |
| byte req; |
| byte global_req; |
| int no_cancel_rc; |
| |
| dbug(1, dprintf("%x:CB(%x:Req=%x,Rc=%x,Ind=%x)", |
| (e->user[0] + 1) & 0x7fff, e->Id, e->Req, e->Rc, e->Ind)); |
| |
| a = &(adapter[(byte)e->user[0]]); |
| plci = &(a->plci[e->user[1]]); |
| no_cancel_rc = DIVA_CAPI_SUPPORTS_NO_CANCEL(a); |
| |
| /* |
| If new protocol code and new XDI is used then CAPI should work |
| fully in accordance with IDI cpec an look on callback field instead |
| of Rc field for return codes. |
| */ |
| if (((e->complete == 0xff) && no_cancel_rc) || |
| (e->Rc && !no_cancel_rc)) { |
| rc = e->Rc; |
| ch = e->RcCh; |
| req = e->Req; |
| e->Rc = 0; |
| |
| if (e->user[0] & 0x8000) |
| { |
| /* |
| If REMOVE request was sent then we have to wait until |
| return code with Id set to zero arrives. |
| All other return codes should be ignored. |
| */ |
| if (req == REMOVE) |
| { |
| if (e->Id) |
| { |
| dbug(1, dprintf("cancel RC in REMOVE state")); |
| return; |
| } |
| channel_flow_control_remove(plci); |
| for (i = 0; i < 256; i++) |
| { |
| if (a->FlowControlIdTable[i] == plci->nl_remove_id) |
| a->FlowControlIdTable[i] = 0; |
| } |
| plci->nl_remove_id = 0; |
| if (plci->rx_dma_descriptor > 0) { |
| diva_free_dma_descriptor(plci, plci->rx_dma_descriptor - 1); |
| plci->rx_dma_descriptor = 0; |
| } |
| } |
| if (rc == OK_FC) |
| { |
| a->FlowControlIdTable[ch] = e->Id; |
| a->FlowControlSkipTable[ch] = 0; |
| |
| a->ch_flow_control[ch] |= N_OK_FC_PENDING; |
| a->ch_flow_plci[ch] = plci->Id; |
| plci->nl_req = 0; |
| } |
| else |
| { |
| /* |
| Cancel return codes self, if feature was requested |
| */ |
| if (no_cancel_rc && (a->FlowControlIdTable[ch] == e->Id) && e->Id) { |
| a->FlowControlIdTable[ch] = 0; |
| if ((rc == OK) && a->FlowControlSkipTable[ch]) { |
| dbug(3, dprintf("XDI CAPI: RC cancelled Id:0x02, Ch:%02x", e->Id, ch)); |
| return; |
| } |
| } |
| |
| if (a->ch_flow_control[ch] & N_OK_FC_PENDING) |
| { |
| a->ch_flow_control[ch] &= ~N_OK_FC_PENDING; |
| if (ch == e->ReqCh) |
| plci->nl_req = 0; |
| } |
| else |
| plci->nl_req = 0; |
| } |
| if (plci->nl_req) |
| control_rc(plci, 0, rc, ch, 0, true); |
| else |
| { |
| if (req == N_XON) |
| { |
| channel_x_on(plci, ch); |
| if (plci->internal_command) |
| control_rc(plci, req, rc, ch, 0, true); |
| } |
| else |
| { |
| if (plci->nl_global_req) |
| { |
| global_req = plci->nl_global_req; |
| plci->nl_global_req = 0; |
| if (rc != ASSIGN_OK) { |
| e->Id = 0; |
| if (plci->rx_dma_descriptor > 0) { |
| diva_free_dma_descriptor(plci, plci->rx_dma_descriptor - 1); |
| plci->rx_dma_descriptor = 0; |
| } |
| } |
| channel_xmit_xon(plci); |
| control_rc(plci, 0, rc, ch, global_req, true); |
| } |
| else if (plci->data_sent) |
| { |
| channel_xmit_xon(plci); |
| plci->data_sent = false; |
| plci->NL.XNum = 1; |
| data_rc(plci, ch); |
| if (plci->internal_command) |
| control_rc(plci, req, rc, ch, 0, true); |
| } |
| else |
| { |
| channel_xmit_xon(plci); |
| control_rc(plci, req, rc, ch, 0, true); |
| } |
| } |
| } |
| } |
| else |
| { |
| /* |
| If REMOVE request was sent then we have to wait until |
| return code with Id set to zero arrives. |
| All other return codes should be ignored. |
| */ |
| if (req == REMOVE) |
| { |
| if (e->Id) |
| { |
| dbug(1, dprintf("cancel RC in REMOVE state")); |
| return; |
| } |
| plci->sig_remove_id = 0; |
| } |
| plci->sig_req = 0; |
| if (plci->sig_global_req) |
| { |
| global_req = plci->sig_global_req; |
| plci->sig_global_req = 0; |
| if (rc != ASSIGN_OK) |
| e->Id = 0; |
| channel_xmit_xon(plci); |
| control_rc(plci, 0, rc, ch, global_req, false); |
| } |
| else |
| { |
| channel_xmit_xon(plci); |
| control_rc(plci, req, rc, ch, 0, false); |
| } |
| } |
| /* |
| Again: in accordance with IDI spec Rc and Ind can't be delivered in the |
| same callback. Also if new XDI and protocol code used then jump |
| direct to finish. |
| */ |
| if (no_cancel_rc) { |
| channel_xmit_xon(plci); |
| goto capi_callback_suffix; |
| } |
| } |
| |
| channel_xmit_xon(plci); |
| |
| if (e->Ind) { |
| if (e->user[0] & 0x8000) { |
| byte Ind = e->Ind & 0x0f; |
| byte Ch = e->IndCh; |
| if (((Ind == N_DISC) || (Ind == N_DISC_ACK)) && |
| (a->ch_flow_plci[Ch] == plci->Id)) { |
| if (a->ch_flow_control[Ch] & N_RX_FLOW_CONTROL_MASK) { |
| dbug(3, dprintf("XDI CAPI: I: pending N-XON Ch:%02x", Ch)); |
| } |
| a->ch_flow_control[Ch] &= ~N_RX_FLOW_CONTROL_MASK; |
| } |
| nl_ind(plci); |
| if ((e->RNR != 1) && |
| (a->ch_flow_plci[Ch] == plci->Id) && |
| (a->ch_flow_control[Ch] & N_RX_FLOW_CONTROL_MASK)) { |
| a->ch_flow_control[Ch] &= ~N_RX_FLOW_CONTROL_MASK; |
| dbug(3, dprintf("XDI CAPI: I: remove faked N-XON Ch:%02x", Ch)); |
| } |
| } else { |
| sig_ind(plci); |
| } |
| e->Ind = 0; |
| } |
| |
| capi_callback_suffix: |
| |
| while (!plci->req_in |
| && !plci->internal_command |
| && (plci->msg_in_write_pos != plci->msg_in_read_pos)) |
| { |
| j = (plci->msg_in_read_pos == plci->msg_in_wrap_pos) ? 0 : plci->msg_in_read_pos; |
| |
| i = (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[j]))->header.length + 3) & 0xfffc; |
| |
| m = (CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[j]); |
| appl = *((APPL **)(&((byte *)(plci->msg_in_queue))[j + i])); |
| dbug(1, dprintf("dequeue msg(0x%04x) - write=%d read=%d wrap=%d", |
| m->header.command, plci->msg_in_write_pos, plci->msg_in_read_pos, plci->msg_in_wrap_pos)); |
| if (plci->msg_in_read_pos == plci->msg_in_wrap_pos) |
| { |
| plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE; |
| plci->msg_in_read_pos = i + MSG_IN_OVERHEAD; |
| } |
| else |
| { |
| plci->msg_in_read_pos = j + i + MSG_IN_OVERHEAD; |
| } |
| if (plci->msg_in_read_pos == plci->msg_in_write_pos) |
| { |
| plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE; |
| plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE; |
| } |
| else if (plci->msg_in_read_pos == plci->msg_in_wrap_pos) |
| { |
| plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE; |
| plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE; |
| } |
| i = api_put(appl, m); |
| if (i != 0) |
| { |
| if (m->header.command == _DATA_B3_R) |
| |
| TransmitBufferFree(appl, (byte *)(long)(m->info.data_b3_req.Data)); |
| |
| dbug(1, dprintf("Error 0x%04x from msg(0x%04x)", i, m->header.command)); |
| break; |
| } |
| |
| if (plci->li_notify_update) |
| { |
| plci->li_notify_update = false; |
| mixer_notify_update(plci, false); |
| } |
| |
| } |
| send_data(plci); |
| send_req(plci); |
| } |
| |
| |
| static void control_rc(PLCI *plci, byte req, byte rc, byte ch, byte global_req, |
| byte nl_rc) |
| { |
| dword Id; |
| dword rId; |
| word Number; |
| word Info = 0; |
| word i; |
| word ncci; |
| DIVA_CAPI_ADAPTER *a; |
| APPL *appl; |
| PLCI *rplci; |
| byte SSparms[] = "\x05\x00\x00\x02\x00\x00"; |
| byte SSstruct[] = "\x09\x00\x00\x06\x00\x00\x00\x00\x00\x00"; |
| |
| if (!plci) { |
| dbug(0, dprintf("A: control_rc, no plci %02x:%02x:%02x:%02x:%02x", req, rc, ch, global_req, nl_rc)); |
| return; |
| } |
| dbug(1, dprintf("req0_in/out=%d/%d", plci->req_in, plci->req_out)); |
| if (plci->req_in != plci->req_out) |
| { |
| if (nl_rc || (global_req != ASSIGN) || (rc == ASSIGN_OK)) |
| { |
| dbug(1, dprintf("req_1return")); |
| return; |
| } |
| /* cancel outstanding request on the PLCI after SIG ASSIGN failure */ |
| } |
| plci->req_in = plci->req_in_start = plci->req_out = 0; |
| dbug(1, dprintf("control_rc")); |
| |
| appl = plci->appl; |
| a = plci->adapter; |
| ncci = a->ch_ncci[ch]; |
| if (appl) |
| { |
| Id = (((dword)(ncci ? ncci : ch)) << 16) | ((word)plci->Id << 8) | a->Id; |
| if (plci->tel && plci->SuppState != CALL_HELD) Id |= EXT_CONTROLLER; |
| Number = plci->number; |
| dbug(1, dprintf("Contr_RC-Id=%08lx,plci=%x,tel=%x, entity=0x%x, command=0x%x, int_command=0x%x", Id, plci->Id, plci->tel, plci->Sig.Id, plci->command, plci->internal_command)); |
| dbug(1, dprintf("channels=0x%x", plci->channels)); |
| if (plci_remove_check(plci)) |
| return; |
| if (req == REMOVE && rc == ASSIGN_OK) |
| { |
| sig_req(plci, HANGUP, 0); |
| sig_req(plci, REMOVE, 0); |
| send_req(plci); |
| } |
| if (plci->command) |
| { |
| switch (plci->command) |
| { |
| case C_HOLD_REQ: |
| dbug(1, dprintf("HoldRC=0x%x", rc)); |
| SSparms[1] = (byte)S_HOLD; |
| if (rc != OK) |
| { |
| plci->SuppState = IDLE; |
| Info = 0x2001; |
| } |
| sendf(appl, _FACILITY_R | CONFIRM, Id, Number, "wws", Info, 3, SSparms); |
| break; |
| |
| case C_RETRIEVE_REQ: |
| dbug(1, dprintf("RetrieveRC=0x%x", rc)); |
| SSparms[1] = (byte)S_RETRIEVE; |
| if (rc != OK) |
| { |
| plci->SuppState = CALL_HELD; |
| Info = 0x2001; |
| } |
| sendf(appl, _FACILITY_R | CONFIRM, Id, Number, "wws", Info, 3, SSparms); |
| break; |
| |
| case _INFO_R: |
| dbug(1, dprintf("InfoRC=0x%x", rc)); |
| if (rc != OK) Info = _WRONG_STATE; |
| sendf(appl, _INFO_R | CONFIRM, Id, Number, "w", Info); |
| break; |
| |
| case _CONNECT_R: |
| dbug(1, dprintf("Connect_R=0x%x/0x%x/0x%x/0x%x", req, rc, global_req, nl_rc)); |
| if (plci->State == INC_DIS_PENDING) |
| break; |
| if (plci->Sig.Id != 0xff) |
| { |
| if (((global_req == ASSIGN) && (rc != ASSIGN_OK)) |
| || (!nl_rc && (req == CALL_REQ) && (rc != OK))) |
| { |
| dbug(1, dprintf("No more IDs/Call_Req failed")); |
| sendf(appl, _CONNECT_R | CONFIRM, Id & 0xffL, Number, "w", _OUT_OF_PLCI); |
| plci_remove(plci); |
| plci->State = IDLE; |
| break; |
| } |
| if (plci->State != LOCAL_CONNECT) plci->State = OUTG_CON_PENDING; |
| sendf(appl, _CONNECT_R | CONFIRM, Id, Number, "w", 0); |
| } |
| else /* D-ch activation */ |
| { |
| if (rc != ASSIGN_OK) |
| { |
| dbug(1, dprintf("No more IDs/X.25 Call_Req failed")); |
| sendf(appl, _CONNECT_R | CONFIRM, Id & 0xffL, Number, "w", _OUT_OF_PLCI); |
| plci_remove(plci); |
| plci->State = IDLE; |
| break; |
| } |
| sendf(appl, _CONNECT_R | CONFIRM, Id, Number, "w", 0); |
| sendf(plci->appl, _CONNECT_ACTIVE_I, Id, 0, "sss", "", "", ""); |
| plci->State = INC_ACT_PENDING; |
| } |
| break; |
| |
| case _CONNECT_I | RESPONSE: |
| if (plci->State != INC_DIS_PENDING) |
| plci->State = INC_CON_ACCEPT; |
| break; |
| |
| case _DISCONNECT_R: |
| if (plci->State == INC_DIS_PENDING) |
| break; |
| if (plci->Sig.Id != 0xff) |
| { |
| plci->State = OUTG_DIS_PENDING; |
| sendf(appl, _DISCONNECT_R | CONFIRM, Id, Number, "w", 0); |
| } |
| break; |
| |
| case SUSPEND_REQ: |
| break; |
| |
| case RESUME_REQ: |
| break; |
| |
| case _CONNECT_B3_R: |
| if (rc != OK) |
| { |
| sendf(appl, _CONNECT_B3_R | CONFIRM, Id, Number, "w", _WRONG_IDENTIFIER); |
| break; |
| } |
| ncci = get_ncci(plci, ch, 0); |
| Id = (Id & 0xffff) | (((dword) ncci) << 16); |
| plci->channels++; |
| if (req == N_RESET) |
| { |
| a->ncci_state[ncci] = INC_ACT_PENDING; |
| sendf(appl, _CONNECT_B3_R | CONFIRM, Id, Number, "w", 0); |
| sendf(appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", ""); |
| } |
| else |
| { |
| a->ncci_state[ncci] = OUTG_CON_PENDING; |
| sendf(appl, _CONNECT_B3_R | CONFIRM, Id, Number, "w", 0); |
| } |
| break; |
| |
| case _CONNECT_B3_I | RESPONSE: |
| break; |
| |
| case _RESET_B3_R: |
| /* sendf(appl, _RESET_B3_R | CONFIRM, Id, Number, "w", 0);*/ |
| break; |
| |
| case _DISCONNECT_B3_R: |
| sendf(appl, _DISCONNECT_B3_R | CONFIRM, Id, Number, "w", 0); |
| break; |
| |
| case _MANUFACTURER_R: |
| break; |
| |
| case PERM_LIST_REQ: |
| if (rc != OK) |
| { |
| Info = _WRONG_IDENTIFIER; |
| sendf(plci->appl, _CONNECT_R | CONFIRM, Id, Number, "w", Info); |
| plci_remove(plci); |
| } |
| else |
| sendf(plci->appl, _CONNECT_R | CONFIRM, Id, Number, "w", Info); |
| break; |
| |
| default: |
| break; |
| } |
| plci->command = 0; |
| } |
| else if (plci->internal_command) |
| { |
| switch (plci->internal_command) |
| { |
| case BLOCK_PLCI: |
| return; |
| |
| case GET_MWI_STATE: |
| if (rc == OK) /* command supported, wait for indication */ |
| { |
| return; |
| } |
| plci_remove(plci); |
| break; |
| |
| /* Get Supported Services */ |
| case GETSERV_REQ_PEND: |
| if (rc == OK) /* command supported, wait for indication */ |
| { |
| break; |
| } |
| PUT_DWORD(&SSstruct[6], MASK_TERMINAL_PORTABILITY); |
| sendf(appl, _FACILITY_R | CONFIRM, Id, Number, "wws", 0, 3, SSstruct); |
| plci_remove(plci); |
| break; |
| |
| case INTERR_DIVERSION_REQ_PEND: /* Interrogate Parameters */ |
| case INTERR_NUMBERS_REQ_PEND: |
| case CF_START_PEND: /* Call Forwarding Start pending */ |
| case CF_STOP_PEND: /* Call Forwarding Stop pending */ |
| case CCBS_REQUEST_REQ_PEND: |
| case CCBS_DEACTIVATE_REQ_PEND: |
| case CCBS_INTERROGATE_REQ_PEND: |
| switch (plci->internal_command) |
| { |
| case INTERR_DIVERSION_REQ_PEND: |
| SSparms[1] = S_INTERROGATE_DIVERSION; |
| break; |
| case INTERR_NUMBERS_REQ_PEND: |
| SSparms[1] = S_INTERROGATE_NUMBERS; |
| break; |
| case CF_START_PEND: |
| SSparms[1] = S_CALL_FORWARDING_START; |
| break; |
| case CF_STOP_PEND: |
| SSparms[1] = S_CALL_FORWARDING_STOP; |
| break; |
| case CCBS_REQUEST_REQ_PEND: |
| SSparms[1] = S_CCBS_REQUEST; |
| break; |
| case CCBS_DEACTIVATE_REQ_PEND: |
| SSparms[1] = S_CCBS_DEACTIVATE; |
| break; |
| case CCBS_INTERROGATE_REQ_PEND: |
| SSparms[1] = S_CCBS_INTERROGATE; |
| break; |
| } |
| if (global_req == ASSIGN) |
| { |
| dbug(1, dprintf("AssignDiversion_RC=0x%x/0x%x", req, rc)); |
| return; |
| } |
| if (!plci->appl) break; |
| if (rc == ISDN_GUARD_REJ) |
| { |
| Info = _CAPI_GUARD_ERROR; |
| } |
| else if (rc != OK) |
| { |
| Info = _SUPPLEMENTARY_SERVICE_NOT_SUPPORTED; |
| } |
| sendf(plci->appl, _FACILITY_R | CONFIRM, Id & 0x7, |
| plci->number, "wws", Info, (word)3, SSparms); |
| if (Info) plci_remove(plci); |
| break; |
| |
| /* 3pty conference pending */ |
| case PTY_REQ_PEND: |
| if (!plci->relatedPTYPLCI) break; |
| rplci = plci->relatedPTYPLCI; |
| SSparms[1] = plci->ptyState; |
| rId = ((word)rplci->Id << 8) | rplci->adapter->Id; |
| if (rplci->tel) rId |= EXT_CONTROLLER; |
| if (rc != OK) |
| { |
| Info = 0x300E; /* not supported */ |
| plci->relatedPTYPLCI = NULL; |
| plci->ptyState = 0; |
| } |
| sendf(rplci->appl, |
| _FACILITY_R | CONFIRM, |
| rId, |
| plci->number, |
| "wws", Info, (word)3, SSparms); |
| break; |
| |
| /* Explicit Call Transfer pending */ |
| case ECT_REQ_PEND: |
| dbug(1, dprintf("ECT_RC=0x%x/0x%x", req, rc)); |
| if (!plci->relatedPTYPLCI) break; |
| rplci = plci->relatedPTYPLCI; |
| SSparms[1] = S_ECT; |
| rId = ((word)rplci->Id << 8) | rplci->adapter->Id; |
| if (rplci->tel) rId |= EXT_CONTROLLER; |
| if (rc != OK) |
| { |
| Info = 0x300E; /* not supported */ |
| plci->relatedPTYPLCI = NULL; |
| plci->ptyState = 0; |
| } |
| sendf(rplci->appl, |
| _FACILITY_R | CONFIRM, |
| rId, |
| plci->number, |
| "wws", Info, (word)3, SSparms); |
| break; |
| |
| case _MANUFACTURER_R: |
| dbug(1, dprintf("_Manufacturer_R=0x%x/0x%x", req, rc)); |
| if ((global_req == ASSIGN) && (rc != ASSIGN_OK)) |
| { |
| dbug(1, dprintf("No more IDs")); |
| sendf(appl, _MANUFACTURER_R | CONFIRM, Id, Number, "dww", _DI_MANU_ID, _MANUFACTURER_R, _OUT_OF_PLCI); |
| plci_remove(plci); /* after codec init, internal codec commands pending */ |
| } |
| break; |
| |
| case _CONNECT_R: |
| dbug(1, dprintf("_Connect_R=0x%x/0x%x", req, rc)); |
| if ((global_req == ASSIGN) && (rc != ASSIGN_OK)) |
| { |
| dbug(1, dprintf("No more IDs")); |
| sendf(appl, _CONNECT_R | CONFIRM, Id & 0xffL, Number, "w", _OUT_OF_PLCI); |
| plci_remove(plci); /* after codec init, internal codec commands pending */ |
| } |
| break; |
| |
| case PERM_COD_HOOK: /* finished with Hook_Ind */ |
| return; |
| |
| case PERM_COD_CALL: |
| dbug(1, dprintf("***Codec Connect_Pending A, Rc = 0x%x", rc)); |
| plci->internal_command = PERM_COD_CONN_PEND; |
| return; |
| |
| case PERM_COD_ASSIGN: |
| dbug(1, dprintf("***Codec Assign A, Rc = 0x%x", rc)); |
| if (rc != ASSIGN_OK) break; |
| sig_req(plci, CALL_REQ, 0); |
| send_req(plci); |
| plci->internal_command = PERM_COD_CALL; |
| return; |
| |
| /* Null Call Reference Request pending */ |
| case C_NCR_FAC_REQ: |
| dbug(1, dprintf("NCR_FAC=0x%x/0x%x", req, rc)); |
| if (global_req == ASSIGN) |
| { |
| if (rc == ASSIGN_OK) |
| { |
| return; |
| } |
| else |
| { |
| sendf(appl, _INFO_R | CONFIRM, Id & 0xf, Number, "w", _WRONG_STATE); |
| appl->NullCREnable = false; |
| plci_remove(plci); |
| } |
| } |
| else if (req == NCR_FACILITY) |
| { |
| if (rc == OK) |
| { |
| sendf(appl, _INFO_R | CONFIRM, Id & 0xf, Number, "w", 0); |
| } |
| else |
| { |
| sendf(appl, _INFO_R | CONFIRM, Id & 0xf, Number, "w", _WRONG_STATE); |
| appl->NullCREnable = false; |
| } |
| plci_remove(plci); |
| } |
| break; |
| |
| case HOOK_ON_REQ: |
| if (plci->channels) |
| { |
| if (a->ncci_state[ncci] == CONNECTED) |
| { |
| a->ncci_state[ncci] = OUTG_DIS_PENDING; |
| cleanup_ncci_data(plci, ncci); |
| nl_req_ncci(plci, N_DISC, (byte)ncci); |
| } |
| break; |
| } |
| break; |
| |
| case HOOK_OFF_REQ: |
| if (plci->State == INC_DIS_PENDING) |
| break; |
| sig_req(plci, CALL_REQ, 0); |
| send_req(plci); |
| plci->State = OUTG_CON_PENDING; |
| break; |
| |
| |
| case MWI_ACTIVATE_REQ_PEND: |
| case MWI_DEACTIVATE_REQ_PEND: |
| if (global_req == ASSIGN && rc == ASSIGN_OK) |
| { |
| dbug(1, dprintf("MWI_REQ assigned")); |
| return; |
| } |
| else if (rc != OK) |
| { |
| if (rc == WRONG_IE) |
| { |
| Info = 0x2007; /* Illegal message parameter coding */ |
| dbug(1, dprintf("MWI_REQ invalid parameter")); |
| } |
| else |
| { |
| Info = 0x300B; /* not supported */ |
| dbug(1, dprintf("MWI_REQ not supported")); |
| } |
| /* 0x3010: Request not allowed in this state */ |
| PUT_WORD(&SSparms[4], 0x300E); /* SS not supported */ |
| |
| } |
| if (plci->internal_command == MWI_ACTIVATE_REQ_PEND) |
| { |
| PUT_WORD(&SSparms[1], S_MWI_ACTIVATE); |
| } |
| else PUT_WORD(&SSparms[1], S_MWI_DEACTIVATE); |
| |
| if (plci->cr_enquiry) |
| { |
| sendf(plci->appl, |
| _FACILITY_R | CONFIRM, |
| Id & 0xf, |
| plci->number, |
| "wws", Info, (word)3, SSparms); |
| if (rc != OK) plci_remove(plci); |
| } |
| else |
| { |
| sendf(plci->appl, |
| _FACILITY_R | CONFIRM, |
| Id, |
| plci->number, |
| "wws", Info, (word)3, SSparms); |
| } |
| break; |
| |
| case CONF_BEGIN_REQ_PEND: |
| case CONF_ADD_REQ_PEND: |
| case CONF_SPLIT_REQ_PEND: |
| case CONF_DROP_REQ_PEND: |
| case CONF_ISOLATE_REQ_PEND: |
| case CONF_REATTACH_REQ_PEND: |
| dbug(1, dprintf("CONF_RC=0x%x/0x%x", req, rc)); |
| if ((plci->internal_command == CONF_ADD_REQ_PEND) && (!plci->relatedPTYPLCI)) break; |
| rplci = plci; |
| rId = Id; |
| switch (plci->internal_command) |
| { |
| case CONF_BEGIN_REQ_PEND: |
| SSparms[1] = S_CONF_BEGIN; |
| break; |
| case CONF_ADD_REQ_PEND: |
| SSparms[1] = S_CONF_ADD; |
| rplci = plci->relatedPTYPLCI; |
| rId = ((word)rplci->Id << 8) | rplci->adapter->Id; |
| break; |
| case CONF_SPLIT_REQ_PEND: |
| SSparms[1] = S_CONF_SPLIT; |
| break; |
| case CONF_DROP_REQ_PEND: |
| SSparms[1] = S_CONF_DROP; |
| break; |
| case CONF_ISOLATE_REQ_PEND: |
| SSparms[1] = S_CONF_ISOLATE; |
| break; |
| case CONF_REATTACH_REQ_PEND: |
| SSparms[1] = S_CONF_REATTACH; |
| break; |
| } |
| |
| if (rc != OK) |
| { |
| Info = 0x300E; /* not supported */ |
| plci->relatedPTYPLCI = NULL; |
| plci->ptyState = 0; |
| } |
| sendf(rplci->appl, |
| _FACILITY_R | CONFIRM, |
| rId, |
| plci->number, |
| "wws", Info, (word)3, SSparms); |
| break; |
| |
| case VSWITCH_REQ_PEND: |
| if (rc != OK) |
| { |
| if (plci->relatedPTYPLCI) |
| { |
| plci->relatedPTYPLCI->vswitchstate = 0; |
| plci->relatedPTYPLCI->vsprot = 0; |
| plci->relatedPTYPLCI->vsprotdialect = 0; |
| } |
| plci->vswitchstate = 0; |
| plci->vsprot = 0; |
| plci->vsprotdialect = 0; |
| } |
| else |
| { |
| if (plci->relatedPTYPLCI && |
| plci->vswitchstate == 1 && |
| plci->relatedPTYPLCI->vswitchstate == 3) /* join complete */ |
| plci->vswitchstate = 3; |
| } |
| break; |
| |
| /* Call Deflection Request pending (SSCT) */ |
| case CD_REQ_PEND: |
| SSparms[1] = S_CALL_DEFLECTION; |
| if (rc != OK) |
| { |
| Info = 0x300E; /* not supported */ |
| plci->appl->CDEnable = 0; |
| } |
| sendf(plci->appl, _FACILITY_R | CONFIRM, Id, |
| plci->number, "wws", Info, (word)3, SSparms); |
| break; |
| |
| case RTP_CONNECT_B3_REQ_COMMAND_2: |
| if (rc == OK) |
| { |
| ncci = get_ncci(plci, ch, 0); |
| Id = (Id & 0xffff) | (((dword) ncci) << 16); |
| plci->channels++; |
| a->ncci_state[ncci] = OUTG_CON_PENDING; |
| } |
| |
| default: |
| if (plci->internal_command_queue[0]) |
| { |
| (*(plci->internal_command_queue[0]))(Id, plci, rc); |
| if (plci->internal_command) |
| return; |
| } |
| break; |
| } |
| next_internal_command(Id, plci); |
| } |
| } |
| else /* appl==0 */ |
| { |
| Id = ((word)plci->Id << 8) | plci->adapter->Id; |
| if (plci->tel) Id |= EXT_CONTROLLER; |
| |
| switch (plci->internal_command) |
| { |
| case BLOCK_PLCI: |
| return; |
| |
| case START_L1_SIG_ASSIGN_PEND: |
| case REM_L1_SIG_ASSIGN_PEND: |
| if (global_req == ASSIGN) |
| { |
| break; |
| } |
| else |
| { |
| dbug(1, dprintf("***L1 Req rem PLCI")); |
| plci->internal_command = 0; |
| sig_req(plci, REMOVE, 0); |
| send_req(plci); |
| } |
| break; |
| |
| /* Call Deflection Request pending, just no appl ptr assigned */ |
| case CD_REQ_PEND: |
| SSparms[1] = S_CALL_DEFLECTION; |
| if (rc != OK) |
| { |
| Info = 0x300E; /* not supported */ |
| } |
| for (i = 0; i < max_appl; i++) |
| { |
| if (application[i].CDEnable) |
| { |
| if (!application[i].Id) application[i].CDEnable = 0; |
| else |
| { |
| sendf(&application[i], _FACILITY_R | CONFIRM, Id, |
| plci->number, "wws", Info, (word)3, SSparms); |
| if (Info) application[i].CDEnable = 0; |
| } |
| } |
| } |
| plci->internal_command = 0; |
| break; |
| |
| case PERM_COD_HOOK: /* finished with Hook_Ind */ |
| return; |
| |
| case PERM_COD_CALL: |
| plci->internal_command = PERM_COD_CONN_PEND; |
| dbug(1, dprintf("***Codec Connect_Pending, Rc = 0x%x", rc)); |
| return; |
| |
| case PERM_COD_ASSIGN: |
| dbug(1, dprintf("***Codec Assign, Rc = 0x%x", rc)); |
| plci->internal_command = 0; |
| if (rc != ASSIGN_OK) break; |
| plci->internal_command = PERM_COD_CALL; |
| sig_req(plci, CALL_REQ, 0); |
| send_req(plci); |
| return; |
| |
| case LISTEN_SIG_ASSIGN_PEND: |
| if (rc == ASSIGN_OK) |
| { |
| plci->internal_command = 0; |
| dbug(1, dprintf("ListenCheck, new SIG_ID = 0x%x", plci->Sig.Id)); |
| add_p(plci, ESC, "\x02\x18\x00"); /* support call waiting */ |
| sig_req(plci, INDICATE_REQ, 0); |
| send_req(plci); |
| } |
| else |
| { |
| dbug(1, dprintf("ListenCheck failed (assignRc=0x%x)", rc)); |
| a->listen_active--; |
| plci_remove(plci); |
| plci->State = IDLE; |
| } |
| break; |
| |
| case USELAW_REQ: |
| if (global_req == ASSIGN) |
| { |
| if (rc == ASSIGN_OK) |
| { |
| sig_req(plci, LAW_REQ, 0); |
| send_req(plci); |
| dbug(1, dprintf("Auto-Law assigned")); |
| } |
| else |
| { |
| dbug(1, dprintf("Auto-Law assign failed")); |
| a->automatic_law = 3; |
| plci->internal_command = 0; |
| a->automatic_lawPLCI = NULL; |
| } |
| break; |
| } |
| else if (req == LAW_REQ && rc == OK) |
| { |
| dbug(1, dprintf("Auto-Law initiated")); |
| a->automatic_law = 2; |
| plci->internal_command = 0; |
| } |
| else |
| { |
| dbug(1, dprintf("Auto-Law not supported")); |
| a->automatic_law = 3; |
| plci->internal_command = 0; |
| sig_req(plci, REMOVE, 0); |
| send_req(plci); |
| a->automatic_lawPLCI = NULL; |
| } |
| break; |
| } |
| plci_remove_check(plci); |
| } |
| } |
| |
| static void data_rc(PLCI *plci, byte ch) |
| { |
| dword Id; |
| DIVA_CAPI_ADAPTER *a; |
| NCCI *ncci_ptr; |
| DATA_B3_DESC *data; |
| word ncci; |
| |
| if (plci->appl) |
| { |
| TransmitBufferFree(plci->appl, plci->data_sent_ptr); |
| a = plci->adapter; |
| ncci = a->ch_ncci[ch]; |
| if (ncci && (a->ncci_plci[ncci] == plci->Id)) |
| { |
| ncci_ptr = &(a->ncci[ncci]); |
| dbug(1, dprintf("data_out=%d, data_pending=%d", ncci_ptr->data_out, ncci_ptr->data_pending)); |
| if (ncci_ptr->data_pending) |
| { |
| data = &(ncci_ptr->DBuffer[ncci_ptr->data_out]); |
| if (!(data->Flags & 4) && a->ncci_state[ncci]) |
| { |
| Id = (((dword)ncci) << 16) | ((word)plci->Id << 8) | a->Id; |
| if (plci->tel) Id |= EXT_CONTROLLER; |
| sendf(plci->appl, _DATA_B3_R | CONFIRM, Id, data->Number, |
| "ww", data->Handle, 0); |
| } |
| (ncci_ptr->data_out)++; |
| if (ncci_ptr->data_out == MAX_DATA_B3) |
| ncci_ptr->data_out = 0; |
| (ncci_ptr->data_pending)--; |
| } |
| } |
| } |
| } |
| |
| static void data_ack(PLCI *plci, byte ch) |
| { |
| dword Id; |
| DIVA_CAPI_ADAPTER *a; |
| NCCI *ncci_ptr; |
| word ncci; |
| |
| a = plci->adapter; |
| ncci = a->ch_ncci[ch]; |
| ncci_ptr = &(a->ncci[ncci]); |
| if (ncci_ptr->data_ack_pending) |
| { |
| if (a->ncci_state[ncci] && (a->ncci_plci[ncci] == plci->Id)) |
| { |
| Id = (((dword)ncci) << 16) | ((word)plci->Id << 8) | a->Id; |
| if (plci->tel) Id |= EXT_CONTROLLER; |
| sendf(plci->appl, _DATA_B3_R | CONFIRM, Id, ncci_ptr->DataAck[ncci_ptr->data_ack_out].Number, |
| "ww", ncci_ptr->DataAck[ncci_ptr->data_ack_out].Handle, 0); |
| } |
| (ncci_ptr->data_ack_out)++; |
| if (ncci_ptr->data_ack_out == MAX_DATA_ACK) |
| ncci_ptr->data_ack_out = 0; |
| (ncci_ptr->data_ack_pending)--; |
| } |
| } |
| |
| static void sig_ind(PLCI *plci) |
| { |
| dword x_Id; |
| dword Id; |
| dword rId; |
| word i; |
| word cip; |
| dword cip_mask; |
| byte *ie; |
| DIVA_CAPI_ADAPTER *a; |
| API_PARSE saved_parms[MAX_MSG_PARMS + 1]; |
| #define MAXPARMSIDS 31 |
| byte *parms[MAXPARMSIDS]; |
| byte *add_i[4]; |
| byte *multi_fac_parms[MAX_MULTI_IE]; |
| byte *multi_pi_parms[MAX_MULTI_IE]; |
| byte *multi_ssext_parms[MAX_MULTI_IE]; |
| byte *multi_CiPN_parms[MAX_MULTI_IE]; |
| |
| byte *multi_vswitch_parms[MAX_MULTI_IE]; |
| |
| byte ai_len; |
| byte *esc_chi = ""; |
| byte *esc_law = ""; |
| byte *pty_cai = ""; |
| byte *esc_cr = ""; |
| byte *esc_profile = ""; |
| |
| byte facility[256]; |
| PLCI *tplci = NULL; |
| byte chi[] = "\x02\x18\x01"; |
| byte voice_cai[] = "\x06\x14\x00\x00\x00\x00\x08"; |
| byte resume_cau[] = "\x05\x05\x00\x02\x00\x00"; |
| /* ESC_MSGTYPE must be the last but one message, a new IE has to be */ |
| /* included before the ESC_MSGTYPE and MAXPARMSIDS has to be incremented */ |
| /* SMSG is situated at the end because its 0 (for compatibility reasons */ |
| /* (see Info_Mask Bit 4, first IE. then the message type) */ |
| word parms_id[] = |
| {MAXPARMSIDS, CPN, 0xff, DSA, OSA, BC, LLC, HLC, ESC_CAUSE, DSP, DT, CHA, |
| UUI, CONG_RR, CONG_RNR, ESC_CHI, KEY, CHI, CAU, ESC_LAW, |
| RDN, RDX, CONN_NR, RIN, NI, CAI, ESC_CR, |
| CST, ESC_PROFILE, 0xff, ESC_MSGTYPE, SMSG}; |
| /* 14 FTY repl by ESC_CHI */ |
| /* 18 PI repl by ESC_LAW */ |
| /* removed OAD changed to 0xff for future use, OAD is multiIE now */ |
| word multi_fac_id[] = {1, FTY}; |
| word multi_pi_id[] = {1, PI}; |
| word multi_CiPN_id[] = {1, OAD}; |
| word multi_ssext_id[] = {1, ESC_SSEXT}; |
| |
| word multi_vswitch_id[] = {1, ESC_VSWITCH}; |
| |
| byte *cau; |
| word ncci; |
| byte SS_Ind[] = "\x05\x02\x00\x02\x00\x00"; /* Hold_Ind struct*/ |
| byte CF_Ind[] = "\x09\x02\x00\x06\x00\x00\x00\x00\x00\x00"; |
| byte Interr_Err_Ind[] = "\x0a\x02\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; |
| byte CONF_Ind[] = "\x09\x16\x00\x06\x00\x00\x00\x00\x00\x00"; |
| byte force_mt_info = false; |
| byte dir; |
| dword d; |
| word w; |
| |
| a = plci->adapter; |
| Id = ((word)plci->Id << 8) | a->Id; |
| PUT_WORD(&SS_Ind[4], 0x0000); |
| |
| if (plci->sig_remove_id) |
| { |
| plci->Sig.RNR = 2; /* discard */ |
| dbug(1, dprintf("SIG discard while remove pending")); |
| return; |
| } |
| if (plci->tel && plci->SuppState != CALL_HELD) Id |= EXT_CONTROLLER; |
| dbug(1, dprintf("SigInd-Id=%08lx,plci=%x,tel=%x,state=0x%x,channels=%d,Discflowcl=%d", |
| Id, plci->Id, plci->tel, plci->State, plci->channels, plci->hangup_flow_ctrl_timer)); |
| if (plci->Sig.Ind == CALL_HOLD_ACK && plci->channels) |
| { |
| plci->Sig.RNR = 1; |
| return; |
| } |
| if (plci->Sig.Ind == HANGUP && plci->channels) |
| { |
| plci->Sig.RNR = 1; |
| plci->hangup_flow_ctrl_timer++; |
| /* recover the network layer after timeout */ |
| if (plci->hangup_flow_ctrl_timer == 100) |
| { |
| dbug(1, dprintf("Exceptional disc")); |
| plci->Sig.RNR = 0; |
| plci->hangup_flow_ctrl_timer = 0; |
| for (ncci = 1; ncci < MAX_NCCI + 1; ncci++) |
| { |
| if (a->ncci_plci[ncci] == plci->Id) |
| { |
| cleanup_ncci_data(plci, ncci); |
| if (plci->channels)plci->channels--; |
| if (plci->appl) |
| sendf(plci->appl, _DISCONNECT_B3_I, (((dword) ncci) << 16) | Id, 0, "ws", 0, ""); |
| } |
| } |
| if (plci->appl) |
| sendf(plci->appl, _DISCONNECT_I, Id, 0, "w", 0); |
| plci_remove(plci); |
| plci->State = IDLE; |
| } |
| return; |
| } |
| |
| /* do first parse the info with no OAD in, because OAD will be converted */ |
| /* first the multiple facility IE, then mult. progress ind. */ |
| /* then the parameters for the info_ind + conn_ind */ |
| IndParse(plci, multi_fac_id, multi_fac_parms, MAX_MULTI_IE); |
| IndParse(plci, multi_pi_id, multi_pi_parms, MAX_MULTI_IE); |
| IndParse(plci, multi_ssext_id, multi_ssext_parms, MAX_MULTI_IE); |
| |
| IndParse(plci, multi_vswitch_id, multi_vswitch_parms, MAX_MULTI_IE); |
| |
| IndParse(plci, parms_id, parms, 0); |
| IndParse(plci, multi_CiPN_id, multi_CiPN_parms, MAX_MULTI_IE); |
| esc_chi = parms[14]; |
| esc_law = parms[18]; |
| pty_cai = parms[24]; |
| esc_cr = parms[25]; |
| esc_profile = parms[27]; |
| if (esc_cr[0] && plci) |
| { |
| if (plci->cr_enquiry && plci->appl) |
| { |
| plci->cr_enquiry = false; |
| /* d = MANU_ID */ |
| /* w = m_command */ |
| /* b = total length */ |
| /* b = indication type */ |
| /* b = length of all IEs */ |
| /* b = IE1 */ |
| /* S = IE1 length + cont. */ |
| /* b = IE2 */ |
| /* S = IE2 length + cont. */ |
| sendf(plci->appl, |
| _MANUFACTURER_I, |
| Id, |
| 0, |
| "dwbbbbSbS", _DI_MANU_ID, plci->m_command, |
| 2 + 1 + 1 + esc_cr[0] + 1 + 1 + esc_law[0], plci->Sig.Ind, 1 + 1 + esc_cr[0] + 1 + 1 + esc_law[0], ESC, esc_cr, ESC, esc_law); |
| } |
| } |
| /* create the additional info structure */ |
| add_i[1] = parms[15]; /* KEY of additional info */ |
| add_i[2] = parms[11]; /* UUI of additional info */ |
| ai_len = AddInfo(add_i, multi_fac_parms, esc_chi, facility); |
| |
| /* the ESC_LAW indicates if u-Law or a-Law is actually used by the card */ |
| /* indication returns by the card if requested by the function */ |
| /* AutomaticLaw() after driver init */ |
| if (a->automatic_law < 4) |
| { |
| if (esc_law[0]) { |
| if (esc_law[2]) { |
| dbug(0, dprintf("u-Law selected")); |
| a->u_law = 1; |
| } |
| else { |
| dbug(0, dprintf("a-Law selected")); |
| a->u_law = 0; |
| } |
| a->automatic_law = 4; |
| if (plci == a->automatic_lawPLCI) { |
| plci->internal_command = 0; |
| sig_req(plci, REMOVE, 0); |
| send_req(plci); |
| a->automatic_lawPLCI = NULL; |
| } |
| } |
| if (esc_profile[0]) |
| { |
| dbug(1, dprintf("[%06x] CardProfile: %lx %lx %lx %lx %lx", |
| UnMapController(a->Id), GET_DWORD(&esc_profile[6]), |
| GET_DWORD(&esc_profile[10]), GET_DWORD(&esc_profile[14]), |
| GET_DWORD(&esc_profile[18]), GET_DWORD(&esc_profile[46]))); |
| |
| a->profile.Global_Options &= 0x000000ffL; |
| a->profile.B1_Protocols &= 0x000003ffL; |
| a->profile.B2_Protocols &= 0x00001fdfL; |
| a->profile.B3_Protocols &= 0x000000b7L; |
| |
| a->profile.Global_Options &= GET_DWORD(&esc_profile[6]) | |
| GL_BCHANNEL_OPERATION_SUPPORTED; |
| a->profile.B1_Protocols &= GET_DWORD(&esc_profile[10]); |
| a->profile.B2_Protocols &= GET_DWORD(&esc_profile[14]); |
| a->profile.B3_Protocols &= GET_DWORD(&esc_profile[18]); |
| a->manufacturer_features = GET_DWORD(&esc_profile[46]); |
| a->man_profile.private_options = 0; |
| |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_ECHO_CANCELLER) |
| { |
| a->man_profile.private_options |= 1L << PRIVATE_ECHO_CANCELLER; |
| a->profile.Global_Options |= GL_ECHO_CANCELLER_SUPPORTED; |
| } |
| |
| |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_RTP) |
| a->man_profile.private_options |= 1L << PRIVATE_RTP; |
| a->man_profile.rtp_primary_payloads = GET_DWORD(&esc_profile[50]); |
| a->man_profile.rtp_additional_payloads = GET_DWORD(&esc_profile[54]); |
| |
| |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_T38) |
| a->man_profile.private_options |= 1L << PRIVATE_T38; |
| |
| |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_SUB_SEP_PWD) |
| a->man_profile.private_options |= 1L << PRIVATE_FAX_SUB_SEP_PWD; |
| |
| |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_V18) |
| a->man_profile.private_options |= 1L << PRIVATE_V18; |
| |
| |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_DTMF_TONE) |
| a->man_profile.private_options |= 1L << PRIVATE_DTMF_TONE; |
| |
| |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_PIAFS) |
| a->man_profile.private_options |= 1L << PRIVATE_PIAFS; |
| |
| |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS) |
| a->man_profile.private_options |= 1L << PRIVATE_FAX_PAPER_FORMATS; |
| |
| |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_VOWN) |
| a->man_profile.private_options |= 1L << PRIVATE_VOWN; |
| |
| |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_NONSTANDARD) |
| a->man_profile.private_options |= 1L << PRIVATE_FAX_NONSTANDARD; |
| |
| } |
| else |
| { |
| a->profile.Global_Options &= 0x0000007fL; |
| a->profile.B1_Protocols &= 0x000003dfL; |
| a->profile.B2_Protocols &= 0x00001adfL; |
| a->profile.B3_Protocols &= 0x000000b7L; |
| a->manufacturer_features &= MANUFACTURER_FEATURE_HARDDTMF; |
| } |
| if (a->manufacturer_features & (MANUFACTURER_FEATURE_HARDDTMF | |
| MANUFACTURER_FEATURE_SOFTDTMF_SEND | MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE)) |
| { |
| a->profile.Global_Options |= GL_DTMF_SUPPORTED; |
| } |
| a->manufacturer_features &= ~MANUFACTURER_FEATURE_OOB_CHANNEL; |
| dbug(1, dprintf("[%06x] Profile: %lx %lx %lx %lx %lx", |
| UnMapController(a->Id), a->profile.Global_Options, |
| a->profile.B1_Protocols, a->profile.B2_Protocols, |
| a->profile.B3_Protocols, a->manufacturer_features)); |
| } |
| /* codec plci for the handset/hook state support is just an internal id */ |
| if (plci != a->AdvCodecPLCI) |
| { |
| force_mt_info = SendMultiIE(plci, Id, multi_fac_parms, FTY, 0x20, 0); |
| force_mt_info |= SendMultiIE(plci, Id, multi_pi_parms, PI, 0x210, 0); |
| SendSSExtInd(NULL, plci, Id, multi_ssext_parms); |
| SendInfo(plci, Id, parms, force_mt_info); |
| |
| VSwitchReqInd(plci, Id, multi_vswitch_parms); |
| |
| } |
| |
| /* switch the codec to the b-channel */ |
| if (esc_chi[0] && plci && !plci->SuppState) { |
| plci->b_channel = esc_chi[esc_chi[0]]&0x1f; |
| mixer_set_bchannel_id_esc(plci, plci->b_channel); |
| dbug(1, dprintf("storeChannel=0x%x", plci->b_channel)); |
| if (plci->tel == ADV_VOICE && plci->appl) { |
| SetVoiceChannel(a->AdvCodecPLCI, esc_chi, a); |
| } |
| } |
| |
| if (plci->appl) plci->appl->Number++; |
| |
| switch (plci->Sig.Ind) { |
| /* Response to Get_Supported_Services request */ |
| case S_SUPPORTED: |
| dbug(1, dprintf("S_Supported")); |
| if (!plci->appl) break; |
| if (pty_cai[0] == 4) |
| { |
| PUT_DWORD(&CF_Ind[6], GET_DWORD(&pty_cai[1])); |
| } |
| else |
| { |
| PUT_DWORD(&CF_Ind[6], MASK_TERMINAL_PORTABILITY | MASK_HOLD_RETRIEVE); |
| } |
| PUT_WORD(&CF_Ind[1], 0); |
| PUT_WORD(&CF_Ind[4], 0); |
| sendf(plci->appl, _FACILITY_R | CONFIRM, Id & 0x7, plci->number, "wws", 0, 3, CF_Ind); |
| plci_remove(plci); |
| break; |
| |
| /* Supplementary Service rejected */ |
| case S_SERVICE_REJ: |
| dbug(1, dprintf("S_Reject=0x%x", pty_cai[5])); |
| if (!pty_cai[0]) break; |
| switch (pty_cai[5]) |
| { |
| case ECT_EXECUTE: |
| case THREE_PTY_END: |
| case THREE_PTY_BEGIN: |
| if (!plci->relatedPTYPLCI) break; |
| tplci = plci->relatedPTYPLCI; |
| rId = ((word)tplci->Id << 8) | tplci->adapter->Id; |
| if (tplci->tel) rId |= EXT_CONTROLLER; |
| if (pty_cai[5] == ECT_EXECUTE) |
| { |
| PUT_WORD(&SS_Ind[1], S_ECT); |
| |
| plci->vswitchstate = 0; |
| plci->relatedPTYPLCI->vswitchstate = 0; |
| |
| } |
| else |
| { |
| PUT_WORD(&SS_Ind[1], pty_cai[5] + 3); |
| } |
| if (pty_cai[2] != 0xff) |
| { |
| PUT_WORD(&SS_Ind[4], 0x3600 | (word)pty_cai[2]); |
| } |
| else |
| { |
| PUT_WORD(&SS_Ind[4], 0x300E); |
| } |
| plci->relatedPTYPLCI = NULL; |
| plci->ptyState = 0; |
| sendf(tplci->appl, _FACILITY_I, rId, 0, "ws", 3, SS_Ind); |
| break; |
| |
| case CALL_DEFLECTION: |
| if (pty_cai[2] != 0xff) |
| { |
| PUT_WORD(&SS_Ind[4], 0x3600 | (word)pty_cai[2]); |
| } |
| else |
| { |
| PUT_WORD(&SS_Ind[4], 0x300E); |
| } |
| PUT_WORD(&SS_Ind[1], pty_cai[5]); |
| for (i = 0; i < max_appl; i++) |
| { |
| if (application[i].CDEnable) |
| { |
| if (application[i].Id) sendf(&application[i], _FACILITY_I, Id, 0, "ws", 3, SS_Ind); |
| application[i].CDEnable = false; |
| } |
| } |
| break; |
| |
| case DEACTIVATION_DIVERSION: |
| case ACTIVATION_DIVERSION: |
| case DIVERSION_INTERROGATE_CFU: |
| case DIVERSION_INTERROGATE_CFB: |
| case DIVERSION_INTERROGATE_CFNR: |
| case DIVERSION_INTERROGATE_NUM: |
| case CCBS_REQUEST: |
| case CCBS_DEACTIVATE: |
| case CCBS_INTERROGATE: |
| if (!plci->appl) break; |
| if (pty_cai[2] != 0xff) |
| { |
| PUT_WORD(&Interr_Err_Ind[4], 0x3600 | (word)pty_cai[2]); |
| } |
| else |
| { |
| PUT_WORD(&Interr_Err_Ind[4], 0x300E); |
| } |
| switch (pty_cai[5]) |
| { |
| case DEACTIVATION_DIVERSION: |
| dbug(1, dprintf("Deact_Div")); |
| Interr_Err_Ind[0] = 0x9; |
| Interr_Err_Ind[3] = 0x6; |
| PUT_WORD(&Interr_Err_Ind[1], S_CALL_FORWARDING_STOP); |
| break; |
| case ACTIVATION_DIVERSION: |
| dbug(1, dprintf("Act_Div")); |
| Interr_Err_Ind[0] = 0x9; |
| Interr_Err_Ind[3] = 0x6; |
| PUT_WORD(&Interr_Err_Ind[1], S_CALL_FORWARDING_START); |
| break; |
| case DIVERSION_INTERROGATE_CFU: |
| case DIVERSION_INTERROGATE_CFB: |
| case DIVERSION_INTERROGATE_CFNR: |
| dbug(1, dprintf("Interr_Div")); |
| Interr_Err_Ind[0] = 0xa; |
| Interr_Err_Ind[3] = 0x7; |
| PUT_WORD(&Interr_Err_Ind[1], S_INTERROGATE_DIVERSION); |
| break; |
| case DIVERSION_INTERROGATE_NUM: |
| dbug(1, dprintf("Interr_Num")); |
| Interr_Err_Ind[0] = 0xa; |
| Interr_Err_Ind[3] = 0x7; |
| PUT_WORD(&Interr_Err_Ind[1], S_INTERROGATE_NUMBERS); |
| break; |
| case CCBS_REQUEST: |
| dbug(1, dprintf("CCBS Request")); |
| Interr_Err_Ind[0] = 0xd; |
| Interr_Err_Ind[3] = 0xa; |
| PUT_WORD(&Interr_Err_Ind[1], S_CCBS_REQUEST); |
| break; |
| case CCBS_DEACTIVATE: |
| dbug(1, dprintf("CCBS Deactivate")); |
| Interr_Err_Ind[0] = 0x9; |
| Interr_Err_Ind[3] = 0x6; |
| PUT_WORD(&Interr_Err_Ind[1], S_CCBS_DEACTIVATE); |
| break; |
| case CCBS_INTERROGATE: |
| dbug(1, dprintf("CCBS Interrogate")); |
| Interr_Err_Ind[0] = 0xb; |
| Interr_Err_Ind[3] = 0x8; |
| PUT_WORD(&Interr_Err_Ind[1], S_CCBS_INTERROGATE); |
| break; |
| } |
| PUT_DWORD(&Interr_Err_Ind[6], plci->appl->S_Handle); |
| sendf(plci->appl, _FACILITY_I, Id & 0x7, 0, "ws", 3, Interr_Err_Ind); |
| plci_remove(plci); |
| break; |
| case ACTIVATION_MWI: |
| case DEACTIVATION_MWI: |
| if (pty_cai[5] == ACTIVATION_MWI) |
| { |
| PUT_WORD(&SS_Ind[1], S_MWI_ACTIVATE); |
| } |
| else PUT_WORD(&SS_Ind[1], S_MWI_DEACTIVATE); |
| |
| if (pty_cai[2] != 0xff) |
| { |
| PUT_WORD(&SS_Ind[4], 0x3600 | (word)pty_cai[2]); |
| } |
| else |
| { |
| PUT_WORD(&SS_Ind[4], 0x300E); |
| } |
| |
| if (plci->cr_enquiry) |
| { |
| sendf(plci->appl, _FACILITY_I, Id & 0xf, 0, "ws", 3, SS_Ind); |
| plci_remove(plci); |
| } |
| else |
| { |
| sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, SS_Ind); |
| } |
| break; |
| case CONF_ADD: /* ERROR */ |
| case CONF_BEGIN: |
| case CONF_DROP: |
| case CONF_ISOLATE: |
| case CONF_REATTACH: |
| CONF_Ind[0] = 9; |
| CONF_Ind[3] = 6; |
| switch (pty_cai[5]) |
| { |
| case CONF_BEGIN: |
| PUT_WORD(&CONF_Ind[1], S_CONF_BEGIN); |
| plci->ptyState = 0; |
| break; |
| case CONF_DROP: |
| CONF_Ind[0] = 5; |
| CONF_Ind[3] = 2; |
| PUT_WORD(&CONF_Ind[1], S_CONF_DROP); |
| plci->ptyState = CONNECTED; |
| break; |
| case CONF_ISOLATE: |
| CONF_Ind[0] = 5; |
| CONF_Ind[3] = 2; |
| PUT_WORD(&CONF_Ind[1], S_CONF_ISOLATE); |
| plci->ptyState = CONNECTED; |
| break; |
| case CONF_REATTACH: |
| CONF_Ind[0] = 5; |
| CONF_Ind[3] = 2; |
| PUT_WORD(&CONF_Ind[1], S_CONF_REATTACH); |
| plci->ptyState = CONNECTED; |
| break; |
| case CONF_ADD: |
| PUT_WORD(&CONF_Ind[1], S_CONF_ADD); |
| plci->relatedPTYPLCI = NULL; |
| tplci = plci->relatedPTYPLCI; |
| if (tplci) tplci->ptyState = CONNECTED; |
| plci->ptyState = CONNECTED; |
| break; |
| } |
| |
| if (pty_cai[2] != 0xff) |
| { |
| PUT_WORD(&CONF_Ind[4], 0x3600 | (word)pty_cai[2]); |
| } |
| else |
| { |
| PUT_WORD(&CONF_Ind[4], 0x3303); /* Time-out: network did not respond |
| within the required time */ |
| } |
| |
| PUT_DWORD(&CONF_Ind[6], 0x0); |
| sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, CONF_Ind); |
| break; |
| } |
| break; |
| |
| /* Supplementary Service indicates success */ |
| case S_SERVICE: |
| dbug(1, dprintf("Service_Ind")); |
| PUT_WORD(&CF_Ind[4], 0); |
| switch (pty_cai[5]) |
| { |
| case THREE_PTY_END: |
| case THREE_PTY_BEGIN: |
| case ECT_EXECUTE: |
| if (!plci->relatedPTYPLCI) break; |
| tplci = plci->relatedPTYPLCI; |
| rId = ((word)tplci->Id << 8) | tplci->adapter->Id; |
| if (tplci->tel) rId |= EXT_CONTROLLER; |
| if (pty_cai[5] == ECT_EXECUTE) |
| { |
| PUT_WORD(&SS_Ind[1], S_ECT); |
| |
| if (plci->vswitchstate != 3) |
| { |
| |
| plci->ptyState = IDLE; |
| plci->relatedPTYPLCI = NULL; |
| plci->ptyState = 0; |
| |
| } |
| |
| dbug(1, dprintf("ECT OK")); |
| sendf(tplci->appl, _FACILITY_I, rId, 0, "ws", 3, SS_Ind); |
| |
| |
| |
| } |
| else |
| { |
| switch (plci->ptyState) |
| { |
| case S_3PTY_BEGIN: |
| plci->ptyState = CONNECTED; |
| dbug(1, dprintf("3PTY ON")); |
| break; |
| |
| case S_3PTY_END: |
| plci->ptyState = IDLE; |
| plci->relatedPTYPLCI = NULL; |
| plci->ptyState = 0; |
| dbug(1, dprintf("3PTY OFF")); |
| break; |
| } |
| PUT_WORD(&SS_Ind[1], pty_cai[5] + 3); |
| sendf(tplci->appl, _FACILITY_I, rId, 0, "ws", 3, SS_Ind); |
| } |
| break; |
| |
| case CALL_DEFLECTION: |
| PUT_WORD(&SS_Ind[1], pty_cai[5]); |
| for (i = 0; i < max_appl; i++) |
| { |
| if (application[i].CDEnable) |
| { |
| if (application[i].Id) sendf(&application[i], _FACILITY_I, Id, 0, "ws", 3, SS_Ind); |
| application[i].CDEnable = false; |
| } |
| } |
| break; |
| |
| case DEACTIVATION_DIVERSION: |
| case ACTIVATION_DIVERSION: |
| if (!plci->appl) break; |
| PUT_WORD(&CF_Ind[1], pty_cai[5] + 2); |
| PUT_DWORD(&CF_Ind[6], plci->appl->S_Handle); |
| sendf(plci->appl, _FACILITY_I, Id & 0x7, 0, "ws", 3, CF_Ind); |
| plci_remove(plci); |
| break; |
| |
| case DIVERSION_INTERROGATE_CFU: |
| case DIVERSION_INTERROGATE_CFB: |
| case DIVERSION_INTERROGATE_CFNR: |
| case DIVERSION_INTERROGATE_NUM: |
| case CCBS_REQUEST: |
| case CCBS_DEACTIVATE: |
| case CCBS_INTERROGATE: |
| if (!plci->appl) break; |
| switch (pty_cai[5]) |
| { |
| case DIVERSION_INTERROGATE_CFU: |
| case DIVERSION_INTERROGATE_CFB: |
| case DIVERSION_INTERROGATE_CFNR: |
| dbug(1, dprintf("Interr_Div")); |
| PUT_WORD(&pty_cai[1], S_INTERROGATE_DIVERSION); |
| pty_cai[3] = pty_cai[0] - 3; /* Supplementary Service-specific parameter len */ |
| break; |
| case DIVERSION_INTERROGATE_NUM: |
| dbug(1, dprintf("Interr_Num")); |
| PUT_WORD(&pty_cai[1], S_INTERROGATE_NUMBERS); |
| pty_cai[3] = pty_cai[0] - 3; /* Supplementary Service-specific parameter len */ |
| break; |
| case CCBS_REQUEST: |
| dbug(1, dprintf("CCBS Request")); |
| PUT_WORD(&pty_cai[1], S_CCBS_REQUEST); |
| pty_cai[3] = pty_cai[0] - 3; /* Supplementary Service-specific parameter len */ |
| break; |
| case CCBS_DEACTIVATE: |
| dbug(1, dprintf("CCBS Deactivate")); |
| PUT_WORD(&pty_cai[1], S_CCBS_DEACTIVATE); |
| pty_cai[3] = pty_cai[0] - 3; /* Supplementary Service-specific parameter len */ |
| break; |
| case CCBS_INTERROGATE: |
| dbug(1, dprintf("CCBS Interrogate")); |
| PUT_WORD(&pty_cai[1], S_CCBS_INTERROGATE); |
| pty_cai[3] = pty_cai[0] - 3; /* Supplementary Service-specific parameter len */ |
| break; |
| } |
| PUT_WORD(&pty_cai[4], 0); /* Supplementary Service Reason */ |
| PUT_DWORD(&pty_cai[6], plci->appl->S_Handle); |
| sendf(plci->appl, _FACILITY_I, Id & 0x7, 0, "wS", 3, pty_cai); |
| plci_remove(plci); |
| break; |
| |
| case ACTIVATION_MWI: |
| case DEACTIVATION_MWI: |
| if (pty_cai[5] == ACTIVATION_MWI) |
| { |
| PUT_WORD(&SS_Ind[1], S_MWI_ACTIVATE); |
| } |
| else PUT_WORD(&SS_Ind[1], S_MWI_DEACTIVATE); |
| if (plci->cr_enquiry) |
| { |
| sendf(plci->appl, _FACILITY_I, Id & 0xf, 0, "ws", 3, SS_Ind); |
| plci_remove(plci); |
| } |
| else |
| { |
| sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, SS_Ind); |
| } |
| break; |
| case MWI_INDICATION: |
| if (pty_cai[0] >= 0x12) |
| { |
| PUT_WORD(&pty_cai[3], S_MWI_INDICATE); |
| pty_cai[2] = pty_cai[0] - 2; /* len Parameter */ |
| pty_cai[5] = pty_cai[0] - 5; /* Supplementary Service-specific parameter len */ |
| if (plci->appl && (a->Notification_Mask[plci->appl->Id - 1] & SMASK_MWI)) |
| { |
| if (plci->internal_command == GET_MWI_STATE) /* result on Message Waiting Listen */ |
| { |
| sendf(plci->appl, _FACILITY_I, Id & 0xf, 0, "wS", 3, &pty_cai[2]); |
| plci_remove(plci); |
| return; |
| } |
| else sendf(plci->appl, _FACILITY_I, Id, 0, "wS", 3, &pty_cai[2]); |
| pty_cai[0] = 0; |
| } |
| else |
| { |
| for (i = 0; i < max_appl; i++) |
| { |
| if (a->Notification_Mask[i]&SMASK_MWI) |
| { |
| sendf(&application[i], _FACILITY_I, Id & 0x7, 0, "wS", 3, &pty_cai[2]); |
| pty_cai[0] = 0; |
| } |
| } |
| } |
| |
| if (!pty_cai[0]) |
| { /* acknowledge */ |
| facility[2] = 0; /* returncode */ |
| } |
| else facility[2] = 0xff; |
| } |
| else |
| { |
| /* reject */ |
| facility[2] = 0xff; /* returncode */ |
| } |
| facility[0] = 2; |
| facility[1] = MWI_RESPONSE; /* Function */ |
| add_p(plci, CAI, facility); |
| add_p(plci, ESC, multi_ssext_parms[0]); /* remembered parameter -> only one possible */ |
| sig_req(plci, S_SERVICE, 0); |
| send_req(plci); |
| plci->command = 0; |
| next_internal_command(Id, plci); |
| break; |
| case CONF_ADD: /* OK */ |
| case CONF_BEGIN: |
| case CONF_DROP: |
| case CONF_ISOLATE: |
| case CONF_REATTACH: |
| case CONF_PARTYDISC: |
| CONF_Ind[0] = 9; |
| CONF_Ind[3] = 6; |
| switch (pty_cai[5]) |
| { |
| case CONF_BEGIN: |
| PUT_WORD(&CONF_Ind[1], S_CONF_BEGIN); |
| if (pty_cai[0] == 6) |
| { |
| d = pty_cai[6]; |
| PUT_DWORD(&CONF_Ind[6], d); /* PartyID */ |
| } |
| else |
| { |
| PUT_DWORD(&CONF_Ind[6], 0x0); |
| } |
| break; |
| case CONF_ISOLATE: |
| PUT_WORD(&CONF_Ind[1], S_CONF_ISOLATE); |
| CONF_Ind[0] = 5; |
| CONF_Ind[3] = 2; |
| break; |
| case CONF_REATTACH: |
| PUT_WORD(&CONF_Ind[1], S_CONF_REATTACH); |
| CONF_Ind[0] = 5; |
| CONF_Ind[3] = 2; |
| break; |
| case CONF_DROP: |
| PUT_WORD(&CONF_Ind[1], S_CONF_DROP); |
| CONF_Ind[0] = 5; |
| CONF_Ind[3] = 2; |
| break; |
| case CONF_ADD: |
| PUT_WORD(&CONF_Ind[1], S_CONF_ADD); |
| d = pty_cai[6]; |
| PUT_DWORD(&CONF_Ind[6], d); /* PartyID */ |
| tplci = plci->relatedPTYPLCI; |
| if (tplci) tplci->ptyState = CONNECTED; |
| break; |
| case CONF_PARTYDISC: |
| CONF_Ind[0] = 7; |
| CONF_Ind[3] = 4; |
| PUT_WORD(&CONF_Ind[1], S_CONF_PARTYDISC); |
| d = pty_cai[6]; |
| PUT_DWORD(&CONF_Ind[4], d); /* PartyID */ |
| break; |
| } |
| plci->ptyState = CONNECTED; |
| sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, CONF_Ind); |
| break; |
| case CCBS_INFO_RETAIN: |
| case CCBS_ERASECALLLINKAGEID: |
| case CCBS_STOP_ALERTING: |
| CONF_Ind[0] = 5; |
| CONF_Ind[3] = 2; |
| switch (pty_cai[5]) |
| { |
| case CCBS_INFO_RETAIN: |
| PUT_WORD(&CONF_Ind[1], S_CCBS_INFO_RETAIN); |
| break; |
| case CCBS_STOP_ALERTING: |
| PUT_WORD(&CONF_Ind[1], S_CCBS_STOP_ALERTING); |
| break; |
| case CCBS_ERASECALLLINKAGEID: |
| PUT_WORD(&CONF_Ind[1], S_CCBS_ERASECALLLINKAGEID); |
| CONF_Ind[0] = 7; |
| CONF_Ind[3] = 4; |
| CONF_Ind[6] = 0; |
| CONF_Ind[7] = 0; |
| break; |
| } |
| w = pty_cai[6]; |
| PUT_WORD(&CONF_Ind[4], w); /* PartyID */ |
| |
| if (plci->appl && (a->Notification_Mask[plci->appl->Id - 1] & SMASK_CCBS)) |
| { |
| sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, CONF_Ind); |
| } |
| else |
| { |
| for (i = 0; i < max_appl; i++) |
| if (a->Notification_Mask[i] & SMASK_CCBS) |
| sendf(&application[i], _FACILITY_I, Id & 0x7, 0, "ws", 3, CONF_Ind); |
| } |
| break; |
| } |
| break; |
| case CALL_HOLD_REJ: |
| cau = parms[7]; |
| if (cau) |
| { |
| i = _L3_CAUSE | cau[2]; |
| if (cau[2] == 0) i = 0x3603; |
| } |
| else |
| { |
| i = 0x3603; |
| } |
| PUT_WORD(&SS_Ind[1], S_HOLD); |
| PUT_WORD(&SS_Ind[4], i); |
| if (plci->SuppState == HOLD_REQUEST) |
| { |
| plci->SuppState = IDLE; |
| sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, SS_Ind); |
| } |
| break; |
| |
| case CALL_HOLD_ACK: |
| if (plci->SuppState == HOLD_REQUEST) |
| { |
| plci->SuppState = CALL_HELD; |
| CodecIdCheck(a, plci); |
| start_internal_command(Id, plci, hold_save_command); |
| } |
| break; |
| |
| case CALL_RETRIEVE_REJ: |
| cau = parms[7]; |
| if (cau) |
| { |
| i = _L3_CAUSE | cau[2]; |
| if (cau[2] == 0) i = 0x3603; |
| } |
| else |
| { |
| i = 0x3603; |
| } |
| PUT_WORD(&SS_Ind[1], S_RETRIEVE); |
| PUT_WORD(&SS_Ind[4], i); |
| if (plci->SuppState == RETRIEVE_REQUEST) |
| { |
| plci->SuppState = CALL_HELD; |
| CodecIdCheck(a, plci); |
| sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, SS_Ind); |
| } |
| break; |
| |
| case CALL_RETRIEVE_ACK: |
| PUT_WORD(&SS_Ind[1], S_RETRIEVE); |
| if (plci->SuppState == RETRIEVE_REQUEST) |
| { |
| plci->SuppState = IDLE; |
| plci->call_dir |= CALL_DIR_FORCE_OUTG_NL; |
| plci->b_channel = esc_chi[esc_chi[0]]&0x1f; |
| if (plci->tel) |
| { |
| mixer_set_bchannel_id_esc(plci, plci->b_channel); |
| dbug(1, dprintf("RetrChannel=0x%x", plci->b_channel)); |
| SetVoiceChannel(a->AdvCodecPLCI, esc_chi, a); |
| if (plci->B2_prot == B2_TRANSPARENT && plci->B3_prot == B3_TRANSPARENT) |
| { |
| dbug(1, dprintf("Get B-ch")); |
| start_internal_command(Id, plci, retrieve_restore_command); |
| } |
| else |
| sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, SS_Ind); |
| } |
| else |
| start_internal_command(Id, plci, retrieve_restore_command); |
| } |
| break; |
| |
| case INDICATE_IND: |
| if (plci->State != LISTENING) { |
| sig_req(plci, HANGUP, 0); |
| send_req(plci); |
| break; |
| } |
| cip = find_cip(a, parms[4], parms[6]); |
| cip_mask = 1L << cip; |
| dbug(1, dprintf("cip=%d,cip_mask=%lx", cip, cip_mask)); |
| clear_c_ind_mask(plci); |
| if (!remove_started && !a->adapter_disabled) |
| { |
| set_c_ind_mask_bit(plci, MAX_APPL); |
| group_optimization(a, plci); |
| for (i = 0; i < max_appl; i++) { |
| if (application[i].Id |
| && (a->CIP_Mask[i] & 1 || a->CIP_Mask[i] & cip_mask) |
| && CPN_filter_ok(parms[0], a, i) |
| && test_group_ind_mask_bit(plci, i)) { |
| dbug(1, dprintf("storedcip_mask[%d]=0x%lx", i, a->CIP_Mask[i])); |
| set_c_ind_mask_bit(plci, i); |
| dump_c_ind_mask(plci); |
| plci->State = INC_CON_PENDING; |
| plci->call_dir = (plci->call_dir & ~(CALL_DIR_OUT | CALL_DIR_ORIGINATE)) | |
| CALL_DIR_IN | CALL_DIR_ANSWER; |
| if (esc_chi[0]) { |
| plci->b_channel = esc_chi[esc_chi[0]] & 0x1f; |
| mixer_set_bchannel_id_esc(plci, plci->b_channel); |
| } |
| /* if a listen on the ext controller is done, check if hook states */ |
| /* are supported or if just a on board codec must be activated */ |
| if (a->codec_listen[i] && !a->AdvSignalPLCI) { |
| if (a->profile.Global_Options & HANDSET) |
| plci->tel = ADV_VOICE; |
| else if (a->profile.Global_Options & ON_BOARD_CODEC) |
| plci->tel = CODEC; |
| if (plci->tel) Id |= EXT_CONTROLLER; |
| a->codec_listen[i] = plci; |
| } |
| |
| sendf(&application[i], _CONNECT_I, Id, 0, |
| "wSSSSSSSbSSSSS", cip, /* CIP */ |
| parms[0], /* CalledPartyNumber */ |
| multi_CiPN_parms[0], /* CallingPartyNumber */ |
| parms[2], /* CalledPartySubad */ |
| parms[3], /* CallingPartySubad */ |
| parms[4], /* BearerCapability */ |
| parms[5], /* LowLC */ |
| parms[6], /* HighLC */ |
| ai_len, /* nested struct add_i */ |
| add_i[0], /* B channel info */ |
| add_i[1], /* keypad facility */ |
| add_i[2], /* user user data */ |
| add_i[3], /* nested facility */ |
| multi_CiPN_parms[1] /* second CiPN(SCR) */ |
| ); |
| SendSSExtInd(&application[i], |
| plci, |
| Id, |
| multi_ssext_parms); |
| SendSetupInfo(&application[i], |
| plci, |
| Id, |
| parms, |
| SendMultiIE(plci, Id, multi_pi_parms, PI, 0x210, true)); |
| } |
| } |
| clear_c_ind_mask_bit(plci, MAX_APPL); |
| dump_c_ind_mask(plci); |
| } |
| if (c_ind_mask_empty(plci)) { |
| sig_req(plci, HANGUP, 0); |
| send_req(plci); |
| plci->State = IDLE; |
| } |
| plci->notifiedcall = 0; |
| a->listen_active--; |
| listen_check(a); |
| break; |
| |
| case CALL_PEND_NOTIFY: |
| plci->notifiedcall = 1; |
| listen_check(a); |
| break; |
| |
| case CALL_IND: |
| case CALL_CON: |
| if (plci->State == ADVANCED_VOICE_SIG || plci->State == ADVANCED_VOICE_NOSIG) |
| { |
| if (plci->internal_command == PERM_COD_CONN_PEND) |
| { |
| if (plci->State == ADVANCED_VOICE_NOSIG) |
| { |
| dbug(1, dprintf("***Codec OK")); |
| if (a->AdvSignalPLCI) |
| { |
| tplci = a->AdvSignalPLCI; |
| if (tplci->spoofed_msg) |
| { |
| dbug(1, dprintf("***Spoofed Msg(0x%x)", tplci->spoofed_msg)); |
| tplci->command = 0; |
| tplci->internal_command = 0; |
| x_Id = ((word)tplci->Id << 8) | tplci->adapter->Id | 0x80; |
| switch (tplci->spoofed_msg) |
| { |
| case CALL_RES: |
| tplci->command = _CONNECT_I | RESPONSE; |
| api_load_msg(&tplci->saved_msg, saved_parms); |
| add_b1(tplci, &saved_parms[1], 0, tplci->B1_facilities); |
| if (tplci->adapter->Info_Mask[tplci->appl->Id - 1] & 0x200) |
| { |
| /* early B3 connect (CIP mask bit 9) no release after a disc */ |
| add_p(tplci, LLI, "\x01\x01"); |
| } |
| add_s(tplci, CONN_NR, &saved_parms[2]); |
| add_s(tplci, LLC, &saved_parms[4]); |
| add_ai(tplci, &saved_parms[5]); |
| tplci->State = INC_CON_ACCEPT; |
| sig_req(tplci, CALL_RES, 0); |
| send_req(tplci); |
| break; |
| |
| case AWAITING_SELECT_B: |
| dbug(1, dprintf("Select_B continue")); |
| start_internal_command(x_Id, tplci, select_b_command); |
| break; |
| |
| case AWAITING_MANUF_CON: /* Get_Plci per Manufacturer_Req to ext controller */ |
| if (!tplci->Sig.Id) |
| { |
| dbug(1, dprintf("No SigID!")); |
| sendf(tplci->appl, _MANUFACTURER_R | CONFIRM, x_Id, tplci->number, "dww", _DI_MANU_ID, _MANUFACTURER_R, _OUT_OF_PLCI); |
| plci_remove(tplci); |
| break; |
| } |
| tplci->command = _MANUFACTURER_R; |
| api_load_msg(&tplci->saved_msg, saved_parms); |
| dir = saved_parms[2].info[0]; |
| if (dir == 1) { |
| sig_req(tplci, CALL_REQ, 0); |
| } |
| else if (!dir) { |
| sig_req(tplci, LISTEN_REQ, 0); |
| } |
| send_req(tplci); |
| sendf(tplci->appl, _MANUFACTURER_R | CONFIRM, x_Id, tplci->number, "dww", _DI_MANU_ID, _MANUFACTURER_R, 0); |
| break; |
| |
| case (CALL_REQ | AWAITING_MANUF_CON): |
| sig_req(tplci, CALL_REQ, 0); |
| send_req(tplci); |
| break; |
| |
| case CALL_REQ: |
| if (!tplci->Sig.Id) |
| { |
| dbug(1, dprintf("No SigID!")); |
| sendf(tplci->appl, _CONNECT_R | CONFIRM, tplci->adapter->Id, 0, "w", _OUT_OF_PLCI); |
| plci_remove(tplci); |
| break; |
| } |
| tplci->command = _CONNECT_R; |
| api_load_msg(&tplci->saved_msg, saved_parms); |
| add_s(tplci, CPN, &saved_parms[1]); |
| add_s(tplci, DSA, &saved_parms[3]); |
| add_ai(tplci, &saved_parms[9]); |
| sig_req(tplci, CALL_REQ, 0); |
| send_req(tplci); |
| break; |
| |
| case CALL_RETRIEVE: |
| tplci->command = C_RETRIEVE_REQ; |
| sig_req(tplci, CALL_RETRIEVE, 0); |
| send_req(tplci); |
| break; |
| } |
| tplci->spoofed_msg = 0; |
| if (tplci->internal_command == 0) |
| next_internal_command(x_Id, tplci); |
| } |
| } |
| next_internal_command(Id, plci); |
| break; |
| } |
| dbug(1, dprintf("***Codec Hook Init Req")); |
| plci->internal_command = PERM_COD_HOOK; |
| add_p(plci, FTY, "\x01\x09"); /* Get Hook State*/ |
| sig_req(plci, TEL_CTRL, 0); |
| send_req(plci); |
| } |
| } |
| else if (plci->command != _MANUFACTURER_R /* old style permanent connect */ |
| && plci->State != INC_ACT_PENDING) |
| { |
| mixer_set_bchannel_id_esc(plci, plci->b_channel); |
| if (plci->tel == ADV_VOICE && plci->SuppState == IDLE) /* with permanent codec switch on immediately */ |
| { |
| chi[2] = plci->b_channel; |
| SetVoiceChannel(a->AdvCodecPLCI, chi, a); |
| } |
| sendf(plci->appl, _CONNECT_ACTIVE_I, Id, 0, "Sss", parms[21], "", ""); |
| plci->State = INC_ACT_PENDING; |
| } |
| break; |
| |
| case TEL_CTRL: |
| ie = multi_fac_parms[0]; /* inspect the facility hook indications */ |
| if (plci->State == ADVANCED_VOICE_SIG && ie[0]) { |
| switch (ie[1] & 0x91) { |
| case 0x80: /* hook off */ |
| case 0x81: |
| if (plci->internal_command == PERM_COD_HOOK) |
| { |
| dbug(1, dprintf("init:hook_off")); |
| plci->hook_state = ie[1]; |
| next_internal_command(Id, plci); |
| break; |
| } |
| else /* ignore doubled hook indications */ |
| { |
| if (((plci->hook_state) & 0xf0) == 0x80) |
| { |
| dbug(1, dprintf("ignore hook")); |
| break; |
| } |
| plci->hook_state = ie[1]&0x91; |
| } |
| /* check for incoming call pending */ |
| /* and signal '+'.Appl must decide */ |
| /* with connect_res if call must */ |
| /* accepted or not */ |
| for (i = 0, tplci = NULL; i < max_appl; i++) { |
| if (a->codec_listen[i] |
| && (a->codec_listen[i]->State == INC_CON_PENDING |
| || a->codec_listen[i]->State == INC_CON_ALERT)) { |
| tplci = a->codec_listen[i]; |
| tplci->appl = &application[i]; |
| } |
| } |
| /* no incoming call, do outgoing call */ |
| /* and signal '+' if outg. setup */ |
| if (!a->AdvSignalPLCI && !tplci) { |
| if ((i = get_plci(a))) { |
| a->AdvSignalPLCI = &a->plci[i - 1]; |
| tplci = a->AdvSignalPLCI; |
| tplci->tel = ADV_VOICE; |
| PUT_WORD(&voice_cai[5], a->AdvSignalAppl->MaxDataLength); |
| if (a->Info_Mask[a->AdvSignalAppl->Id - 1] & 0x200) { |
| /* early B3 connect (CIP mask bit 9) no release after a disc */ |
| add_p(tplci, LLI, "\x01\x01"); |
| } |
| add_p(tplci, CAI, voice_cai); |
| add_p(tplci, OAD, a->TelOAD); |
| add_p(tplci, OSA, a->TelOSA); |
| add_p(tplci, SHIFT | 6, NULL); |
| add_p(tplci, SIN, "\x02\x01\x00"); |
| add_p(tplci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| sig_req(tplci, ASSIGN, DSIG_ID); |
| a->AdvSignalPLCI->internal_command = HOOK_OFF_REQ; |
| a->AdvSignalPLCI->command = 0; |
| tplci->appl = a->AdvSignalAppl; |
| tplci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE; |
| send_req(tplci); |
| } |
| |
| } |
| |
| if (!tplci) break; |
| Id = ((word)tplci->Id << 8) | a->Id; |
| Id |= EXT_CONTROLLER; |
| sendf(tplci->appl, |
| _FACILITY_I, |
| Id, |
| 0, |
| "ws", (word)0, "\x01+"); |
| break; |
| |
| case 0x90: /* hook on */ |
| case 0x91: |
| if (plci->internal_command == PERM_COD_HOOK) |
| { |
| dbug(1, dprintf("init:hook_on")); |
| plci->hook_state = ie[1] & 0x91; |
| next_internal_command(Id, plci); |
| break; |
| } |
| else /* ignore doubled hook indications */ |
| { |
| if (((plci->hook_state) & 0xf0) == 0x90) break; |
| plci->hook_state = ie[1] & 0x91; |
| } |
| /* hangup the adv. voice call and signal '-' to the appl */ |
| if (a->AdvSignalPLCI) { |
| Id = ((word)a->AdvSignalPLCI->Id << 8) | a->Id; |
| if (plci->tel) Id |= EXT_CONTROLLER; |
| sendf(a->AdvSignalAppl, |
| _FACILITY_I, |
| Id, |
| 0, |
| "ws", (word)0, "\x01-"); |
| a->AdvSignalPLCI->internal_command = HOOK_ON_REQ; |
| a->AdvSignalPLCI->command = 0; |
| sig_req(a->AdvSignalPLCI, HANGUP, 0); |
| send_req(a->AdvSignalPLCI); |
| } |
| break; |
| } |
| } |
| break; |
| |
| case RESUME: |
| clear_c_ind_mask_bit(plci, (word)(plci->appl->Id - 1)); |
| PUT_WORD(&resume_cau[4], GOOD); |
| sendf(plci->appl, _FACILITY_I, Id, 0, "ws", (word)3, resume_cau); |
| break; |
| |
| case SUSPEND: |
| clear_c_ind_mask(plci); |
| |
| if (plci->NL.Id && !plci->nl_remove_id) { |
| mixer_remove(plci); |
| nl_req_ncci(plci, REMOVE, 0); |
| } |
| if (!plci->sig_remove_id) { |
| plci->internal_command = 0; |
| sig_req(plci, REMOVE, 0); |
| } |
| send_req(plci); |
| if (!plci->channels) { |
| sendf(plci->appl, _FACILITY_I, Id, 0, "ws", (word)3, "\x05\x04\x00\x02\x00\x00"); |
| sendf(plci->appl, _DISCONNECT_I, Id, 0, "w", 0); |
| } |
| break; |
| |
| case SUSPEND_REJ: |
| break; |
| |
| case HANGUP: |
| plci->hangup_flow_ctrl_timer = 0; |
| if (plci->manufacturer && plci->State == LOCAL_CONNECT) break; |
| cau = parms[7]; |
| if (cau) { |
| i = _L3_CAUSE | cau[2]; |
| if (cau[2] == 0) i = 0; |
| else if (cau[2] == 8) i = _L1_ERROR; |
| else if (cau[2] == 9 || cau[2] == 10) i = _L2_ERROR; |
| else if (cau[2] == 5) i = _CAPI_GUARD_ERROR; |
| } |
| else { |
| i = _L3_ERROR; |
| } |
| |
| if (plci->State == INC_CON_PENDING || plci->State == INC_CON_ALERT) |
| { |
| for (i = 0; i < max_appl; i++) |
| { |
| if (test_c_ind_mask_bit(plci, i)) |
| sendf(&application[i], _DISCONNECT_I, Id, 0, "w", 0); |
| } |
| } |
| else |
| { |
| clear_c_ind_mask(plci); |
| } |
| if (!plci->appl) |
| { |
| if (plci->State == LISTENING) |
| { |
| plci->notifiedcall = 0; |
| a->listen_active--; |
| } |
| plci->State = INC_DIS_PENDING; |
| if (c_ind_mask_empty(plci)) |
| { |
| plci->State = IDLE; |
| if (plci->NL.Id && !plci->nl_remove_id) |
| { |
| mixer_remove(plci); |
| nl_req_ncci(plci, REMOVE, 0); |
| } |
| if (!plci->sig_remove_id) |
| { |
| plci->internal_command = 0; |
| sig_req(plci, REMOVE, 0); |
| } |
| send_req(plci); |
| } |
| } |
| else |
| { |
| /* collision of DISCONNECT or CONNECT_RES with HANGUP can */ |
| /* result in a second HANGUP! Don't generate another */ |
| /* DISCONNECT */ |
| if (plci->State != IDLE && plci->State != INC_DIS_PENDING) |
| { |
| if (plci->State == RESUMING) |
| { |
| PUT_WORD(&resume_cau[4], i); |
| sendf(plci->appl, _FACILITY_I, Id, 0, "ws", (word)3, resume_cau); |
| } |
| plci->State = INC_DIS_PENDING; |
| sendf(plci->appl, _DISCONNECT_I, Id, 0, "w", i); |
| } |
| } |
| break; |
| |
| case SSEXT_IND: |
| SendSSExtInd(NULL, plci, Id, multi_ssext_parms); |
| break; |
| |
| case VSWITCH_REQ: |
| VSwitchReqInd(plci, Id, multi_vswitch_parms); |
| break; |
| case VSWITCH_IND: |
| if (plci->relatedPTYPLCI && |
| plci->vswitchstate == 3 && |
| plci->relatedPTYPLCI->vswitchstate == 3 && |
| parms[MAXPARMSIDS - 1][0]) |
| { |
| add_p(plci->relatedPTYPLCI, SMSG, parms[MAXPARMSIDS - 1]); |
| sig_req(plci->relatedPTYPLCI, VSWITCH_REQ, 0); |
| send_req(plci->relatedPTYPLCI); |
| } |
| else VSwitchReqInd(plci, Id, multi_vswitch_parms); |
| break; |
| |
| } |
| } |
| |
| |
| static void SendSetupInfo(APPL *appl, PLCI *plci, dword Id, byte **parms, byte Info_Sent_Flag) |
| { |
| word i; |
| byte *ie; |
| word Info_Number; |
| byte *Info_Element; |
| word Info_Mask = 0; |
| |
| dbug(1, dprintf("SetupInfo")); |
| |
| for (i = 0; i < MAXPARMSIDS; i++) { |
| ie = parms[i]; |
| Info_Number = 0; |
| Info_Element = ie; |
| if (ie[0]) { |
| switch (i) { |
| case 0: |
| dbug(1, dprintf("CPN ")); |
| Info_Number = 0x0070; |
| Info_Mask = 0x80; |
| Info_Sent_Flag = true; |
| break; |
| case 8: /* display */ |
| dbug(1, dprintf("display(%d)", i)); |
| Info_Number = 0x0028; |
| Info_Mask = 0x04; |
| Info_Sent_Flag = true; |
| break; |
| case 16: /* Channel Id */ |
| dbug(1, dprintf("CHI")); |
| Info_Number = 0x0018; |
| Info_Mask = 0x100; |
| Info_Sent_Flag = true; |
| mixer_set_bchannel_id(plci, Info_Element); |
| break; |
| case 19: /* Redirected Number */ |
| dbug(1, dprintf("RDN")); |
| Info_Number = 0x0074; |
| Info_Mask = 0x400; |
| Info_Sent_Flag = true; |
| break; |
| case 20: /* Redirected Number extended */ |
| dbug(1, dprintf("RDX")); |
| Info_Number = 0x0073; |
| Info_Mask = 0x400; |
| Info_Sent_Flag = true; |
| break; |
| case 22: /* Redirecing Number */ |
| dbug(1, dprintf("RIN")); |
| Info_Number = 0x0076; |
| Info_Mask = 0x400; |
| Info_Sent_Flag = true; |
| break; |
| default: |
| Info_Number = 0; |
| break; |
| } |
| } |
| |
| if (i == MAXPARMSIDS - 2) { /* to indicate the message type "Setup" */ |
| Info_Number = 0x8000 | 5; |
| Info_Mask = 0x10; |
| Info_Element = ""; |
| } |
| |
| if (Info_Sent_Flag && Info_Number) { |
| if (plci->adapter->Info_Mask[appl->Id - 1] & Info_Mask) { |
| sendf(appl, _INFO_I, Id, 0, "wS", Info_Number, Info_Element); |
| } |
| } |
| } |
| } |
| |
| |
| static void SendInfo(PLCI *plci, dword Id, byte **parms, byte iesent) |
| { |
| word i; |
| word j; |
| word k; |
| byte *ie; |
| word Info_Number; |
| byte *Info_Element; |
| word Info_Mask = 0; |
| static byte charges[5] = {4, 0, 0, 0, 0}; |
| static byte cause[] = {0x02, 0x80, 0x00}; |
| APPL *appl; |
| |
| dbug(1, dprintf("InfoParse ")); |
| |
| if ( |
| !plci->appl |
| && !plci->State |
| && plci->Sig.Ind != NCR_FACILITY |
| ) |
| { |
| dbug(1, dprintf("NoParse ")); |
| return; |
| } |
| cause[2] = 0; |
| for (i = 0; i < MAXPARMSIDS; i++) { |
| ie = parms[i]; |
| Info_Number = 0; |
| Info_Element = ie; |
| if (ie[0]) { |
| switch (i) { |
| case 0: |
| dbug(1, dprintf("CPN ")); |
| Info_Number = 0x0070; |
| Info_Mask = 0x80; |
| break; |
| case 7: /* ESC_CAU */ |
| dbug(1, dprintf("cau(0x%x)", ie[2])); |
| Info_Number = 0x0008; |
| Info_Mask = 0x00; |
| cause[2] = ie[2]; |
| Info_Element = NULL; |
| break; |
| case 8: /* display */ |
| dbug(1, dprintf("display(%d)", i)); |
| Info_Number = 0x0028; |
| Info_Mask = 0x04; |
| break; |
| case 9: /* Date display */ |
| dbug(1, dprintf("date(%d)", i)); |
| Info_Number = 0x0029; |
| Info_Mask = 0x02; |
| break; |
| case 10: /* charges */ |
| for (j = 0; j < 4; j++) charges[1 + j] = 0; |
| for (j = 0; j < ie[0] && !(ie[1 + j] & 0x80); j++); |
| for (k = 1, j++; j < ie[0] && k <= 4; j++, k++) charges[k] = ie[1 + j]; |
| Info_Number = 0x4000; |
| Info_Mask = 0x40; |
| Info_Element = charges; |
| break; |
| case 11: /* user user info */ |
| dbug(1, dprintf("uui")); |
| Info_Number = 0x007E; |
| Info_Mask = 0x08; |
| break; |
| case 12: /* congestion receiver ready */ |
| dbug(1, dprintf("clRDY")); |
| Info_Number = 0x00B0; |
| Info_Mask = 0x08; |
| Info_Element = ""; |
| break; |
| case 13: /* congestion receiver not ready */ |
| dbug(1, dprintf("clNRDY")); |
| Info_Number = 0x00BF; |
| Info_Mask = 0x08; |
| Info_Element = ""; |
| break; |
| case 15: /* Keypad Facility */ |
| dbug(1, dprintf("KEY")); |
| Info_Number = 0x002C; |
| Info_Mask = 0x20; |
| break; |
| case 16: /* Channel Id */ |
| dbug(1, dprintf("CHI")); |
| Info_Number = 0x0018; |
| Info_Mask = 0x100; |
| mixer_set_bchannel_id(plci, Info_Element); |
| break; |
| case 17: /* if no 1tr6 cause, send full cause, else esc_cause */ |
| dbug(1, dprintf("q9cau(0x%x)", ie[2])); |
| if (!cause[2] || cause[2] < 0x80) break; /* eg. layer 1 error */ |
| Info_Number = 0x0008; |
| Info_Mask = 0x01; |
| if (cause[2] != ie[2]) Info_Element = cause; |
| break; |
| case 19: /* Redirected Number */ |
| dbug(1, dprintf("RDN")); |
| Info_Number = 0x0074; |
| Info_Mask = 0x400; |
| break; |
| case 22: /* Redirecing Number */ |
| dbug(1, dprintf("RIN")); |
| Info_Number = 0x0076; |
| Info_Mask = 0x400; |
| break; |
| case 23: /* Notification Indicator */ |
| dbug(1, dprintf("NI")); |
| Info_Number = (word)NI; |
| Info_Mask = 0x210; |
| break; |
| case 26: /* Call State */ |
| dbug(1, dprintf("CST")); |
| Info_Number = (word)CST; |
| Info_Mask = 0x01; /* do with cause i.e. for now */ |
| break; |
| case MAXPARMSIDS - 2: /* Escape Message Type, must be the last indication */ |
| dbug(1, dprintf("ESC/MT[0x%x]", ie[3])); |
| Info_Number = 0x8000 | ie[3]; |
| if (iesent) Info_Mask = 0xffff; |
| else Info_Mask = 0x10; |
| Info_Element = ""; |
| break; |
| default: |
| Info_Number = 0; |
| Info_Mask = 0; |
| Info_Element = ""; |
| break; |
| } |
| } |
| |
| if (plci->Sig.Ind == NCR_FACILITY) /* check controller broadcast */ |
| { |
| for (j = 0; j < max_appl; j++) |
| { |
| appl = &application[j]; |
| if (Info_Number |
| && appl->Id |
| && plci->adapter->Info_Mask[appl->Id - 1] & Info_Mask) |
| { |
| dbug(1, dprintf("NCR_Ind")); |
| iesent = true; |
| sendf(&application[j], _INFO_I, Id & 0x0f, 0, "wS", Info_Number, Info_Element); |
| } |
| } |
| } |
| else if (!plci->appl) |
| { /* overlap receiving broadcast */ |
| if (Info_Number == CPN |
| || Info_Number == KEY |
| || Info_Number == NI |
| || Info_Number == DSP |
| || Info_Number == UUI) |
| { |
| for (j = 0; j < max_appl; j++) |
| { |
| if (test_c_ind_mask_bit(plci, j)) |
| { |
| dbug(1, dprintf("Ovl_Ind")); |
| iesent = true; |
| sendf(&application[j], _INFO_I, Id, 0, "wS", Info_Number, Info_Element); |
| } |
| } |
| } |
| } /* all other signalling states */ |
| else if (Info_Number |
| && plci->adapter->Info_Mask[plci->appl->Id - 1] & Info_Mask) |
| { |
| dbug(1, dprintf("Std_Ind")); |
| iesent = true; |
| sendf(plci->appl, _INFO_I, Id, 0, "wS", Info_Number, Info_Element); |
| } |
| } |
| } |
| |
| |
| static byte SendMultiIE(PLCI *plci, dword Id, byte **parms, byte ie_type, |
| dword info_mask, byte setupParse) |
| { |
| word i; |
| word j; |
| byte *ie; |
| word Info_Number; |
| byte *Info_Element; |
| APPL *appl; |
| word Info_Mask = 0; |
| byte iesent = 0; |
| |
| if ( |
| !plci->appl |
| && !plci->State |
| && plci->Sig.Ind != NCR_FACILITY |
| && !setupParse |
| ) |
| { |
| dbug(1, dprintf("NoM-IEParse ")); |
| return 0; |
| } |
| dbug(1, dprintf("M-IEParse ")); |
| |
| for (i = 0; i < MAX_MULTI_IE; i++) |
| { |
| ie = parms[i]; |
| Info_Number = 0; |
| Info_Element = ie; |
| if (ie[0]) |
| { |
| dbug(1, dprintf("[Ind0x%x]:IE=0x%x", plci->Sig.Ind, ie_type)); |
| Info_Number = (word)ie_type; |
| Info_Mask = (word)info_mask; |
| } |
| |
| if (plci->Sig.Ind == NCR_FACILITY) /* check controller broadcast */ |
| { |
| for (j = 0; j < max_appl; j++) |
| { |
| appl = &application[j]; |
| if (Info_Number |
| && appl->Id |
| && plci->adapter->Info_Mask[appl->Id - 1] & Info_Mask) |
| { |
| iesent = true; |
| dbug(1, dprintf("Mlt_NCR_Ind")); |
| sendf(&application[j], _INFO_I, Id & 0x0f, 0, "wS", Info_Number, Info_Element); |
| } |
| } |
| } |
| else if (!plci->appl && Info_Number) |
| { /* overlap receiving broadcast */ |
| for (j = 0; j < max_appl; j++) |
| { |
| if (test_c_ind_mask_bit(plci, j)) |
| { |
| iesent = true; |
| dbug(1, dprintf("Mlt_Ovl_Ind")); |
| sendf(&application[j] , _INFO_I, Id, 0, "wS", Info_Number, Info_Element); |
| } |
| } |
| } /* all other signalling states */ |
| else if (Info_Number |
| && plci->adapter->Info_Mask[plci->appl->Id - 1] & Info_Mask) |
| { |
| iesent = true; |
| dbug(1, dprintf("Mlt_Std_Ind")); |
| sendf(plci->appl, _INFO_I, Id, 0, "wS", Info_Number, Info_Element); |
| } |
| } |
| return iesent; |
| } |
| |
| static void SendSSExtInd(APPL *appl, PLCI *plci, dword Id, byte **parms) |
| { |
| word i; |
| /* Format of multi_ssext_parms[i][]: |
| 0 byte length |
| 1 byte SSEXTIE |
| 2 byte SSEXT_REQ/SSEXT_IND |
| 3 byte length |
| 4 word SSExtCommand |
| 6... Params |
| */ |
| if ( |
| plci |
| && plci->State |
| && plci->Sig.Ind != NCR_FACILITY |
| ) |
| for (i = 0; i < MAX_MULTI_IE; i++) |
| { |
| if (parms[i][0] < 6) continue; |
| if (parms[i][2] == SSEXT_REQ) continue; |
| |
| if (appl) |
| { |
| parms[i][0] = 0; /* kill it */ |
| sendf(appl, _MANUFACTURER_I, |
| Id, |
| 0, |
| "dwS", |
| _DI_MANU_ID, |
| _DI_SSEXT_CTRL, |
| &parms[i][3]); |
| } |
| else if (plci->appl) |
| { |
| parms[i][0] = 0; /* kill it */ |
| sendf(plci->appl, _MANUFACTURER_I, |
| Id, |
| 0, |
| "dwS", |
| _DI_MANU_ID, |
| _DI_SSEXT_CTRL, |
| &parms[i][3]); |
| } |
| } |
| }; |
| |
| static void nl_ind(PLCI *plci) |
| { |
| byte ch; |
| word ncci; |
| dword Id; |
| DIVA_CAPI_ADAPTER *a; |
| word NCCIcode; |
| APPL *APPLptr; |
| word count; |
| word Num; |
| word i, ncpi_state; |
| byte len, ncci_state; |
| word msg; |
| word info = 0; |
| word fax_feature_bits; |
| byte fax_send_edata_ack; |
| static byte v120_header_buffer[2 + 3]; |
| static word fax_info[] = { |
| 0, /* T30_SUCCESS */ |
| _FAX_NO_CONNECTION, /* T30_ERR_NO_DIS_RECEIVED */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_TIMEOUT_NO_RESPONSE */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_RESPONSE */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_TOO_MANY_REPEATS */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_UNEXPECTED_MESSAGE */ |
| _FAX_REMOTE_ABORT, /* T30_ERR_UNEXPECTED_DCN */ |
| _FAX_LOCAL_ABORT, /* T30_ERR_DTC_UNSUPPORTED */ |
| _FAX_TRAINING_ERROR, /* T30_ERR_ALL_RATES_FAILED */ |
| _FAX_TRAINING_ERROR, /* T30_ERR_TOO_MANY_TRAINS */ |
| _FAX_PARAMETER_ERROR, /* T30_ERR_RECEIVE_CORRUPTED */ |
| _FAX_REMOTE_ABORT, /* T30_ERR_UNEXPECTED_DISC */ |
| _FAX_LOCAL_ABORT, /* T30_ERR_APPLICATION_DISC */ |
| _FAX_REMOTE_REJECT, /* T30_ERR_INCOMPATIBLE_DIS */ |
| _FAX_LOCAL_ABORT, /* T30_ERR_INCOMPATIBLE_DCS */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_TIMEOUT_NO_COMMAND */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_COMMAND */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_TIMEOUT_COMMAND_TOO_LONG */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_TIMEOUT_RESPONSE_TOO_LONG */ |
| _FAX_NO_CONNECTION, /* T30_ERR_NOT_IDENTIFIED */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_SUPERVISORY_TIMEOUT */ |
| _FAX_PARAMETER_ERROR, /* T30_ERR_TOO_LONG_SCAN_LINE */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_PAGE_AFTER_MPS */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_PAGE_AFTER_CFR */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCS_AFTER_FTT */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCS_AFTER_EOM */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCS_AFTER_MPS */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCN_AFTER_MCF */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCN_AFTER_RTN */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_CFR */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_MCF_AFTER_EOP */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_MCF_AFTER_EOM */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_MCF_AFTER_MPS */ |
| 0x331d, /* T30_ERR_SUB_SEP_UNSUPPORTED */ |
| 0x331e, /* T30_ERR_PWD_UNSUPPORTED */ |
| 0x331f, /* T30_ERR_SUB_SEP_PWD_UNSUPPORTED */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_INVALID_COMMAND_FRAME */ |
| _FAX_PARAMETER_ERROR, /* T30_ERR_UNSUPPORTED_PAGE_CODING */ |
| _FAX_PARAMETER_ERROR, /* T30_ERR_INVALID_PAGE_CODING */ |
| _FAX_REMOTE_REJECT, /* T30_ERR_INCOMPATIBLE_PAGE_CONFIG */ |
| _FAX_LOCAL_ABORT, /* T30_ERR_TIMEOUT_FROM_APPLICATION */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_V34FAX_NO_REACTION_ON_MARK */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_V34FAX_TRAINING_TIMEOUT */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_V34FAX_UNEXPECTED_V21 */ |
| _FAX_PROTOCOL_ERROR, /* T30_ERR_V34FAX_PRIMARY_CTS_ON */ |
| _FAX_LOCAL_ABORT, /* T30_ERR_V34FAX_TURNAROUND_POLLING */ |
| _FAX_LOCAL_ABORT /* T30_ERR_V34FAX_V8_INCOMPATIBILITY */ |
| }; |
| |
| byte dtmf_code_buffer[CAPIDTMF_RECV_DIGIT_BUFFER_SIZE + 1]; |
| |
| |
| static word rtp_info[] = { |
| GOOD, /* RTP_SUCCESS */ |
| 0x3600 /* RTP_ERR_SSRC_OR_PAYLOAD_CHANGE */ |
| }; |
| |
| static dword udata_forwarding_table[0x100 / sizeof(dword)] = |
| { |
| 0x0020301e, 0x00000000, 0x00000000, 0x00000000, |
| 0x00000000, 0x00000000, 0x00000000, 0x00000000 |
| }; |
| |
| ch = plci->NL.IndCh; |
| a = plci->adapter; |
| ncci = a->ch_ncci[ch]; |
| Id = (((dword)(ncci ? ncci : ch)) << 16) | (((word) plci->Id) << 8) | a->Id; |
| if (plci->tel) Id |= EXT_CONTROLLER; |
| APPLptr = plci->appl; |
| dbug(1, dprintf("NL_IND-Id(NL:0x%x)=0x%08lx,plci=%x,tel=%x,state=0x%x,ch=0x%x,chs=%d,Ind=%x", |
| plci->NL.Id, Id, plci->Id, plci->tel, plci->State, ch, plci->channels, plci->NL.Ind & 0x0f)); |
| |
| /* in the case if no connect_active_Ind was sent to the appl we wait for */ |
| |
| if (plci->nl_remove_id) |
| { |
| plci->NL.RNR = 2; /* discard */ |
| dbug(1, dprintf("NL discard while remove pending")); |
| return; |
| } |
| if ((plci->NL.Ind & 0x0f) == N_CONNECT) |
| { |
| if (plci->State == INC_DIS_PENDING |
| || plci->State == OUTG_DIS_PENDING |
| || plci->State == IDLE) |
| { |
| plci->NL.RNR = 2; /* discard */ |
| dbug(1, dprintf("discard n_connect")); |
| return; |
| } |
| if (plci->State < INC_ACT_PENDING) |
| { |
| plci->NL.RNR = 1; /* flow control */ |
| channel_x_off(plci, ch, N_XON_CONNECT_IND); |
| return; |
| } |
| } |
| |
| if (!APPLptr) /* no application or invalid data */ |
| { /* while reloading the DSP */ |
| dbug(1, dprintf("discard1")); |
| plci->NL.RNR = 2; |
| return; |
| } |
| |
| if (((plci->NL.Ind & 0x0f) == N_UDATA) |
| && (((plci->B2_prot != B2_SDLC) && ((plci->B1_resource == 17) || (plci->B1_resource == 18))) |
| || (plci->B2_prot == 7) |
| || (plci->B3_prot == 7))) |
| { |
| plci->ncpi_buffer[0] = 0; |
| |
| ncpi_state = plci->ncpi_state; |
| if (plci->NL.complete == 1) |
| { |
| byte *data = &plci->NL.RBuffer->P[0]; |
| |
| if ((plci->NL.RBuffer->length >= 12) |
| && ((*data == DSP_UDATA_INDICATION_DCD_ON) |
| || (*data == DSP_UDATA_INDICATION_CTS_ON))) |
| { |
| word conn_opt, ncpi_opt = 0x00; |
| /* HexDump ("MDM N_UDATA:", plci->NL.RBuffer->length, data); */ |
| |
| if (*data == DSP_UDATA_INDICATION_DCD_ON) |
| plci->ncpi_state |= NCPI_MDM_DCD_ON_RECEIVED; |
| if (*data == DSP_UDATA_INDICATION_CTS_ON) |
| plci->ncpi_state |= NCPI_MDM_CTS_ON_RECEIVED; |
| |
| data++; /* indication code */ |
| data += 2; /* timestamp */ |
| if ((*data == DSP_CONNECTED_NORM_V18) || (*data == DSP_CONNECTED_NORM_VOWN)) |
| ncpi_state &= ~(NCPI_MDM_DCD_ON_RECEIVED | NCPI_MDM_CTS_ON_RECEIVED); |
| data++; /* connected norm */ |
| conn_opt = GET_WORD(data); |
| data += 2; /* connected options */ |
| |
| PUT_WORD(&(plci->ncpi_buffer[1]), (word)(GET_DWORD(data) & 0x0000FFFF)); |
| |
| if (conn_opt & DSP_CONNECTED_OPTION_MASK_V42) |
| { |
| ncpi_opt |= MDM_NCPI_ECM_V42; |
| } |
| else if (conn_opt & DSP_CONNECTED_OPTION_MASK_MNP) |
| { |
| ncpi_opt |= MDM_NCPI_ECM_MNP; |
| } |
| else |
| { |
| ncpi_opt |= MDM_NCPI_TRANSPARENT; |
| } |
| if (conn_opt & DSP_CONNECTED_OPTION_MASK_COMPRESSION) |
| { |
| ncpi_opt |= MDM_NCPI_COMPRESSED; |
| } |
| PUT_WORD(&(plci->ncpi_buffer[3]), ncpi_opt); |
| plci->ncpi_buffer[0] = 4; |
| |
| plci->ncpi_state |= NCPI_VALID_CONNECT_B3_IND | NCPI_VALID_CONNECT_B3_ACT | NCPI_VALID_DISC_B3_IND; |
| } |
| } |
| if (plci->B3_prot == 7) |
| { |
| if (((a->ncci_state[ncci] == INC_ACT_PENDING) || (a->ncci_state[ncci] == OUTG_CON_PENDING)) |
| && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT) |
| && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT)) |
| { |
| a->ncci_state[ncci] = INC_ACT_PENDING; |
| sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "S", plci->ncpi_buffer); |
| plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT; |
| } |
| } |
| |
| if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id - 1]) |
| & ((1L << PRIVATE_V18) | (1L << PRIVATE_VOWN))) |
| || !(ncpi_state & NCPI_MDM_DCD_ON_RECEIVED) |
| || !(ncpi_state & NCPI_MDM_CTS_ON_RECEIVED)) |
| |
| { |
| plci->NL.RNR = 2; |
| return; |
| } |
| } |
| |
| if (plci->NL.complete == 2) |
| { |
| if (((plci->NL.Ind & 0x0f) == N_UDATA) |
| && !(udata_forwarding_table[plci->RData[0].P[0] >> 5] & (1L << (plci->RData[0].P[0] & 0x1f)))) |
| { |
| switch (plci->RData[0].P[0]) |
| { |
| |
| case DTMF_UDATA_INDICATION_FAX_CALLING_TONE: |
| if (plci->dtmf_rec_active & DTMF_LISTEN_ACTIVE_FLAG) |
| sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", SELECTOR_DTMF, "\x01X"); |
| break; |
| case DTMF_UDATA_INDICATION_ANSWER_TONE: |
| if (plci->dtmf_rec_active & DTMF_LISTEN_ACTIVE_FLAG) |
| sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", SELECTOR_DTMF, "\x01Y"); |
| break; |
| case DTMF_UDATA_INDICATION_DIGITS_RECEIVED: |
| dtmf_indication(Id, plci, plci->RData[0].P, plci->RData[0].PLength); |
| break; |
| case DTMF_UDATA_INDICATION_DIGITS_SENT: |
| dtmf_confirmation(Id, plci); |
| break; |
| |
| |
| case UDATA_INDICATION_MIXER_TAP_DATA: |
| capidtmf_recv_process_block(&(plci->capidtmf_state), plci->RData[0].P + 1, (word)(plci->RData[0].PLength - 1)); |
| i = capidtmf_indication(&(plci->capidtmf_state), dtmf_code_buffer + 1); |
| if (i != 0) |
| { |
| dtmf_code_buffer[0] = DTMF_UDATA_INDICATION_DIGITS_RECEIVED; |
| dtmf_indication(Id, plci, dtmf_code_buffer, (word)(i + 1)); |
| } |
| break; |
| |
| |
| case UDATA_INDICATION_MIXER_COEFS_SET: |
| mixer_indication_coefs_set(Id, plci); |
| break; |
| case UDATA_INDICATION_XCONNECT_FROM: |
| mixer_indication_xconnect_from(Id, plci, plci->RData[0].P, plci->RData[0].PLength); |
| break; |
| case UDATA_INDICATION_XCONNECT_TO: |
| mixer_indication_xconnect_to(Id, plci, plci->RData[0].P, plci->RData[0].PLength); |
| break; |
| |
| |
| case LEC_UDATA_INDICATION_DISABLE_DETECT: |
| ec_indication(Id, plci, plci->RData[0].P, plci->RData[0].PLength); |
| break; |
| |
| |
| |
| default: |
| break; |
| } |
| } |
| else |
| { |
| if ((plci->RData[0].PLength != 0) |
| && ((plci->B2_prot == B2_V120_ASYNC) |
| || (plci->B2_prot == B2_V120_ASYNC_V42BIS) |
| || (plci->B2_prot == B2_V120_BIT_TRANSPARENT))) |
| { |
| |
| sendf(plci->appl, _DATA_B3_I, Id, 0, |
| "dwww", |
| plci->RData[1].P, |
| (plci->NL.RNum < 2) ? 0 : plci->RData[1].PLength, |
| plci->RNum, |
| plci->RFlags); |
| |
| } |
| else |
| { |
| |
| sendf(plci->appl, _DATA_B3_I, Id, 0, |
| "dwww", |
| plci->RData[0].P, |
| plci->RData[0].PLength, |
| plci->RNum, |
| plci->RFlags); |
| |
| } |
| } |
| return; |
| } |
| |
| fax_feature_bits = 0; |
| if ((plci->NL.Ind & 0x0f) == N_CONNECT || |
| (plci->NL.Ind & 0x0f) == N_CONNECT_ACK || |
| (plci->NL.Ind & 0x0f) == N_DISC || |
| (plci->NL.Ind & 0x0f) == N_EDATA || |
| (plci->NL.Ind & 0x0f) == N_DISC_ACK) |
| { |
| info = 0; |
| plci->ncpi_buffer[0] = 0; |
| switch (plci->B3_prot) { |
| case 0: /*XPARENT*/ |
| case 1: /*T.90 NL*/ |
| break; /* no network control protocol info - jfr */ |
| case 2: /*ISO8202*/ |
| case 3: /*X25 DCE*/ |
| for (i = 0; i < plci->NL.RLength; i++) plci->ncpi_buffer[4 + i] = plci->NL.RBuffer->P[i]; |
| plci->ncpi_buffer[0] = (byte)(i + 3); |
| plci->ncpi_buffer[1] = (byte)(plci->NL.Ind & N_D_BIT ? 1 : 0); |
| plci->ncpi_buffer[2] = 0; |
| plci->ncpi_buffer[3] = 0; |
| break; |
| case 4: /*T.30 - FAX*/ |
| case 5: /*T.30 - FAX*/ |
| if (plci->NL.RLength >= sizeof(T30_INFO)) |
| { |
| dbug(1, dprintf("FaxStatus %04x", ((T30_INFO *)plci->NL.RBuffer->P)->code)); |
| len = 9; |
| PUT_WORD(&(plci->ncpi_buffer[1]), ((T30_INFO *)plci->NL.RBuffer->P)->rate_div_2400 * 2400); |
| fax_feature_bits = GET_WORD(&((T30_INFO *)plci->NL.RBuffer->P)->feature_bits_low); |
| i = (((T30_INFO *)plci->NL.RBuffer->P)->resolution & T30_RESOLUTION_R8_0770_OR_200) ? 0x0001 : 0x0000; |
| if (plci->B3_prot == 5) |
| { |
| if (!(fax_feature_bits & T30_FEATURE_BIT_ECM)) |
| i |= 0x8000; /* This is not an ECM connection */ |
| if (fax_feature_bits & T30_FEATURE_BIT_T6_CODING) |
| i |= 0x4000; /* This is a connection with MMR compression */ |
| if (fax_feature_bits & T30_FEATURE_BIT_2D_CODING) |
| i |= 0x2000; /* This is a connection with MR compression */ |
| if (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS) |
| i |= 0x0004; /* More documents */ |
| if (fax_feature_bits & T30_FEATURE_BIT_POLLING) |
| i |= 0x0002; /* Fax-polling indication */ |
| } |
| dbug(1, dprintf("FAX Options %04x %04x", fax_feature_bits, i)); |
| PUT_WORD(&(plci->ncpi_buffer[3]), i); |
| PUT_WORD(&(plci->ncpi_buffer[5]), ((T30_INFO *)plci->NL.RBuffer->P)->data_format); |
| plci->ncpi_buffer[7] = ((T30_INFO *)plci->NL.RBuffer->P)->pages_low; |
| plci->ncpi_buffer[8] = ((T30_INFO *)plci->NL.RBuffer->P)->pages_high; |
| plci->ncpi_buffer[len] = 0; |
| if (((T30_INFO *)plci->NL.RBuffer->P)->station_id_len) |
| { |
| plci->ncpi_buffer[len] = 20; |
| for (i = 0; i < T30_MAX_STATION_ID_LENGTH; i++) |
| plci->ncpi_buffer[++len] = ((T30_INFO *)plci->NL.RBuffer->P)->station_id[i]; |
| } |
| if (((plci->NL.Ind & 0x0f) == N_DISC) || ((plci->NL.Ind & 0x0f) == N_DISC_ACK)) |
| { |
| if (((T30_INFO *)plci->NL.RBuffer->P)->code < ARRAY_SIZE(fax_info)) |
| info = fax_info[((T30_INFO *)plci->NL.RBuffer->P)->code]; |
| else |
| info = _FAX_PROTOCOL_ERROR; |
| } |
| |
| if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id - 1]) |
| & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD))) |
| { |
| i = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + ((T30_INFO *)plci->NL.RBuffer->P)->head_line_len; |
| while (i < plci->NL.RBuffer->length) |
| plci->ncpi_buffer[++len] = plci->NL.RBuffer->P[i++]; |
| } |
| |
| plci->ncpi_buffer[0] = len; |
| fax_feature_bits = GET_WORD(&((T30_INFO *)plci->NL.RBuffer->P)->feature_bits_low); |
| PUT_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->feature_bits_low, fax_feature_bits); |
| |
| plci->ncpi_state |= NCPI_VALID_CONNECT_B3_IND; |
| if (((plci->NL.Ind & 0x0f) == N_CONNECT_ACK) |
| || (((plci->NL.Ind & 0x0f) == N_CONNECT) |
| && (fax_feature_bits & T30_FEATURE_BIT_POLLING)) |
| || (((plci->NL.Ind & 0x0f) == N_EDATA) |
| && ((((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_TRAIN_OK) |
| || (((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_DIS) |
| || (((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_DTC)))) |
| { |
| plci->ncpi_state |= NCPI_VALID_CONNECT_B3_ACT; |
| } |
| if (((plci->NL.Ind & 0x0f) == N_DISC) |
| || ((plci->NL.Ind & 0x0f) == N_DISC_ACK) |
| || (((plci->NL.Ind & 0x0f) == N_EDATA) |
| && (((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_EOP_CAPI))) |
| { |
| plci->ncpi_state |= NCPI_VALID_CONNECT_B3_ACT | NCPI_VALID_DISC_B3_IND; |
| } |
| } |
| break; |
| |
| case B3_RTP: |
| if (((plci->NL.Ind & 0x0f) == N_DISC) || ((plci->NL.Ind & 0x0f) == N_DISC_ACK)) |
| { |
| if (plci->NL.RLength != 0) |
| { |
| info = rtp_info[plci->NL.RBuffer->P[0]]; |
| plci->ncpi_buffer[0] = plci->NL.RLength - 1; |
| for (i = 1; i < plci->NL.RLength; i++) |
| plci->ncpi_buffer[i] = plci->NL.RBuffer->P[i]; |
| } |
| } |
| break; |
| |
| } |
| plci->NL.RNR = 2; |
| } |
| switch (plci->NL.Ind & 0x0f) { |
| case N_EDATA: |
| if ((plci->B3_prot == 4) || (plci->B3_prot == 5)) |
| { |
| dbug(1, dprintf("EDATA ncci=0x%x state=%d code=%02x", ncci, a->ncci_state[ncci], |
| ((T30_INFO *)plci->NL.RBuffer->P)->code)); |
| fax_send_edata_ack = (((T30_INFO *)(plci->fax_connect_info_buffer))->operating_mode == T30_OPERATING_MODE_CAPI_NEG); |
| |
| if ((plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF) |
| && (plci->nsf_control_bits & (T30_NSF_CONTROL_BIT_NEGOTIATE_IND | T30_NSF_CONTROL_BIT_NEGOTIATE_RESP)) |
| && (((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_DIS) |
| && (a->ncci_state[ncci] == OUTG_CON_PENDING) |
| && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT) |
| && !(plci->ncpi_state & NCPI_NEGOTIATE_B3_SENT)) |
| { |
| ((T30_INFO *)(plci->fax_connect_info_buffer))->code = ((T30_INFO *)plci->NL.RBuffer->P)->code; |
| sendf(plci->appl, _MANUFACTURER_I, Id, 0, "dwbS", _DI_MANU_ID, _DI_NEGOTIATE_B3, |
| (byte)(plci->ncpi_buffer[0] + 1), plci->ncpi_buffer); |
| plci->ncpi_state |= NCPI_NEGOTIATE_B3_SENT; |
| if (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP) |
| fax_send_edata_ack = false; |
| } |
| |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS) |
| { |
| switch (((T30_INFO *)plci->NL.RBuffer->P)->code) |
| { |
| case EDATA_T30_DIS: |
| if ((a->ncci_state[ncci] == OUTG_CON_PENDING) |
| && !(GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low) & T30_CONTROL_BIT_REQUEST_POLLING) |
| && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT) |
| && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT)) |
| { |
| a->ncci_state[ncci] = INC_ACT_PENDING; |
| if (plci->B3_prot == 4) |
| sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", ""); |
| else |
| sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "S", plci->ncpi_buffer); |
| plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT; |
| } |
| break; |
| |
| case EDATA_T30_TRAIN_OK: |
| if ((a->ncci_state[ncci] == INC_ACT_PENDING) |
| && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT) |
| && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT)) |
| { |
| if (plci->B3_prot == 4) |
| sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", ""); |
| else |
| sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "S", plci->ncpi_buffer); |
| plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT; |
| } |
| break; |
| |
| case EDATA_T30_EOP_CAPI: |
| if (a->ncci_state[ncci] == CONNECTED) |
| { |
| sendf(plci->appl, _DISCONNECT_B3_I, Id, 0, "wS", GOOD, plci->ncpi_buffer); |
| a->ncci_state[ncci] = INC_DIS_PENDING; |
| plci->ncpi_state = 0; |
| fax_send_edata_ack = false; |
| } |
| break; |
| } |
| } |
| else |
| { |
| switch (((T30_INFO *)plci->NL.RBuffer->P)->code) |
| { |
| case EDATA_T30_TRAIN_OK: |
| if ((a->ncci_state[ncci] == INC_ACT_PENDING) |
| && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT) |
| && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT)) |
| { |
| if (plci->B3_prot == 4) |
| sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", ""); |
| else |
| sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "S", plci->ncpi_buffer); |
| plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT; |
| } |
| break; |
| } |
| } |
| if (fax_send_edata_ack) |
| { |
| ((T30_INFO *)(plci->fax_connect_info_buffer))->code = ((T30_INFO *)plci->NL.RBuffer->P)->code; |
| plci->fax_edata_ack_length = 1; |
| start_internal_command(Id, plci, fax_edata_ack_command); |
| } |
| } |
| else |
| { |
| dbug(1, dprintf("EDATA ncci=0x%x state=%d", ncci, a->ncci_state[ncci])); |
| } |
| break; |
| case N_CONNECT: |
| if (!a->ch_ncci[ch]) |
| { |
| ncci = get_ncci(plci, ch, 0); |
| Id = (Id & 0xffff) | (((dword) ncci) << 16); |
| } |
| dbug(1, dprintf("N_CONNECT: ch=%d state=%d plci=%lx plci_Id=%lx plci_State=%d", |
| ch, a->ncci_state[ncci], a->ncci_plci[ncci], plci->Id, plci->State)); |
| |
| msg = _CONNECT_B3_I; |
| if (a->ncci_state[ncci] == IDLE) |
| plci->channels++; |
| else if (plci->B3_prot == 1) |
| msg = _CONNECT_B3_T90_ACTIVE_I; |
| |
| a->ncci_state[ncci] = INC_CON_PENDING; |
| if (plci->B3_prot == 4) |
| sendf(plci->appl, msg, Id, 0, "s", ""); |
| else |
| sendf(plci->appl, msg, Id, 0, "S", plci->ncpi_buffer); |
| break; |
| case N_CONNECT_ACK: |
| dbug(1, dprintf("N_connect_Ack")); |
| if (plci->internal_command_queue[0] |
| && ((plci->adjust_b_state == ADJUST_B_CONNECT_2) |
| || (plci->adjust_b_state == ADJUST_B_CONNECT_3) |
| || (plci->adjust_b_state == ADJUST_B_CONNECT_4))) |
| { |
| (*(plci->internal_command_queue[0]))(Id, plci, 0); |
| if (!plci->internal_command) |
| next_internal_command(Id, plci); |
| break; |
| } |
| msg = _CONNECT_B3_ACTIVE_I; |
| if (plci->B3_prot == 1) |
| { |
| if (a->ncci_state[ncci] != OUTG_CON_PENDING) |
| msg = _CONNECT_B3_T90_ACTIVE_I; |
| a->ncci_state[ncci] = INC_ACT_PENDING; |
| sendf(plci->appl, msg, Id, 0, "S", plci->ncpi_buffer); |
| } |
| else if ((plci->B3_prot == 4) || (plci->B3_prot == 5) || (plci->B3_prot == 7)) |
| { |
| if ((a->ncci_state[ncci] == OUTG_CON_PENDING) |
| && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT) |
| && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT)) |
| { |
| a->ncci_state[ncci] = INC_ACT_PENDING; |
| if (plci->B3_prot == 4) |
| sendf(plci->appl, msg, Id, 0, "s", ""); |
| else |
| sendf(plci->appl, msg, Id, 0, "S", plci->ncpi_buffer); |
| plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT; |
| } |
| } |
| else |
| { |
| a->ncci_state[ncci] = INC_ACT_PENDING; |
| sendf(plci->appl, msg, Id, 0, "S", plci->ncpi_buffer); |
| } |
| if (plci->adjust_b_restore) |
| { |
| plci->adjust_b_restore = false; |
| start_internal_command(Id, plci, adjust_b_restore); |
| } |
| break; |
| case N_DISC: |
| case N_DISC_ACK: |
| if (plci->internal_command_queue[0] |
| && ((plci->internal_command == FAX_DISCONNECT_COMMAND_1) |
| || (plci->internal_command == FAX_DISCONNECT_COMMAND_2) |
| || (plci->internal_command == FAX_DISCONNECT_COMMAND_3))) |
| { |
| (*(plci->internal_command_queue[0]))(Id, plci, 0); |
| if (!plci->internal_command) |
| next_internal_command(Id, plci); |
| } |
| ncci_state = a->ncci_state[ncci]; |
| ncci_remove(plci, ncci, false); |
| |
| /* with N_DISC or N_DISC_ACK the IDI frees the respective */ |
| /* channel, so we cannot store the state in ncci_state! The */ |
| /* information which channel we received a N_DISC is thus */ |
| /* stored in the inc_dis_ncci_table buffer. */ |
| for (i = 0; plci->inc_dis_ncci_table[i]; i++); |
| plci->inc_dis_ncci_table[i] = (byte) ncci; |
| |
| /* need a connect_b3_ind before a disconnect_b3_ind with FAX */ |
| if (!plci->channels |
| && (plci->B1_resource == 16) |
| && (plci->State <= CONNECTED)) |
| { |
| len = 9; |
| i = ((T30_INFO *)plci->fax_connect_info_buffer)->rate_div_2400 * 2400; |
| PUT_WORD(&plci->ncpi_buffer[1], i); |
| PUT_WORD(&plci->ncpi_buffer[3], 0); |
| i = ((T30_INFO *)plci->fax_connect_info_buffer)->data_format; |
| PUT_WORD(&plci->ncpi_buffer[5], i); |
| PUT_WORD(&plci->ncpi_buffer[7], 0); |
| plci->ncpi_buffer[len] = 0; |
| plci->ncpi_buffer[0] = len; |
| if (plci->B3_prot == 4) |
| sendf(plci->appl, _CONNECT_B3_I, Id, 0, "s", ""); |
| else |
| { |
| |
| if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id - 1]) |
| & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD))) |
| { |
| plci->ncpi_buffer[++len] = 0; |
| plci->ncpi_buffer[++len] = 0; |
| plci->ncpi_buffer[++len] = 0; |
| plci->ncpi_buffer[0] = len; |
| } |
| |
| sendf(plci->appl, _CONNECT_B3_I, Id, 0, "S", plci->ncpi_buffer); |
| } |
| sendf(plci->appl, _DISCONNECT_B3_I, Id, 0, "wS", info, plci->ncpi_buffer); |
| plci->ncpi_state = 0; |
| sig_req(plci, HANGUP, 0); |
| send_req(plci); |
| plci->State = OUTG_DIS_PENDING; |
| /* disc here */ |
| } |
| else if ((a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS) |
| && ((plci->B3_prot == 4) || (plci->B3_prot == 5)) |
| && ((ncci_state == INC_DIS_PENDING) || (ncci_state == IDLE))) |
| { |
| if (ncci_state == IDLE) |
| { |
| if (plci->channels) |
| plci->channels--; |
| if ((plci->State == IDLE || plci->State == SUSPENDING) && !plci->channels) { |
| if (plci->State == SUSPENDING) { |
| sendf(plci->appl, |
| _FACILITY_I, |
| Id & 0xffffL, |
| 0, |
| "ws", (word)3, "\x03\x04\x00\x00"); |
| sendf(plci->appl, _DISCONNECT_I, Id & 0xffffL, 0, "w", 0); |
| } |
| plci_remove(plci); |
| plci->State = IDLE; |
| } |
| } |
| } |
| else if (plci->channels) |
| { |
| sendf(plci->appl, _DISCONNECT_B3_I, Id, 0, "wS", info, plci->ncpi_buffer); |
| plci->ncpi_state = 0; |
| if ((ncci_state == OUTG_REJ_PENDING) |
| && ((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE))) |
| { |
| sig_req(plci, HANGUP, 0); |
| send_req(plci); |
| plci->State = OUTG_DIS_PENDING; |
| } |
| } |
| break; |
| case N_RESET: |
| a->ncci_state[ncci] = INC_RES_PENDING; |
| sendf(plci->appl, _RESET_B3_I, Id, 0, "S", plci->ncpi_buffer); |
| break; |
| case N_RESET_ACK: |
| a->ncci_state[ncci] = CONNECTED; |
| sendf(plci->appl, _RESET_B3_I, Id, 0, "S", plci->ncpi_buffer); |
| break; |
| |
| case N_UDATA: |
| if (!(udata_forwarding_table[plci->NL.RBuffer->P[0] >> 5] & (1L << (plci->NL.RBuffer->P[0] & 0x1f)))) |
| { |
| plci->RData[0].P = plci->internal_ind_buffer + (-((int)(long)(plci->internal_ind_buffer)) & 3); |
| plci->RData[0].PLength = INTERNAL_IND_BUFFER_SIZE; |
| plci->NL.R = plci->RData; |
| plci->NL.RNum = 1; |
| return; |
| } |
| case N_BDATA: |
| case N_DATA: |
| if (((a->ncci_state[ncci] != CONNECTED) && (plci->B2_prot == 1)) /* transparent */ |
| || (a->ncci_state[ncci] == IDLE) |
| || (a->ncci_state[ncci] == INC_DIS_PENDING)) |
| { |
| plci->NL.RNR = 2; |
| break; |
| } |
| if ((a->ncci_state[ncci] != CONNECTED) |
| && (a->ncci_state[ncci] != OUTG_DIS_PENDING) |
| && (a->ncci_state[ncci] != OUTG_REJ_PENDING)) |
| { |
| dbug(1, dprintf("flow control")); |
| plci->NL.RNR = 1; /* flow control */ |
| channel_x_off(plci, ch, 0); |
| break; |
| } |
| |
| NCCIcode = ncci | (((word)a->Id) << 8); |
| |
| /* count all buffers within the Application pool */ |
| /* belonging to the same NCCI. If this is below the */ |
| /* number of buffers available per NCCI we accept */ |
| /* this packet, otherwise we reject it */ |
| count = 0; |
| Num = 0xffff; |
| for (i = 0; i < APPLptr->MaxBuffer; i++) { |
| if (NCCIcode == APPLptr->DataNCCI[i]) count++; |
| if (!APPLptr->DataNCCI[i] && Num == 0xffff) Num = i; |
| } |
| |
| if (count >= APPLptr->MaxNCCIData || Num == 0xffff) |
| { |
| dbug(3, dprintf("Flow-Control")); |
| plci->NL.RNR = 1; |
| if (++(APPLptr->NCCIDataFlowCtrlTimer) >= |
| (word)((a->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL) ? 40 : 2000)) |
| { |
| plci->NL.RNR = 2; |
| dbug(3, dprintf("DiscardData")); |
| } else { |
| channel_x_off(plci, ch, 0); |
| } |
| break; |
| } |
| else |
| { |
| APPLptr->NCCIDataFlowCtrlTimer = 0; |
| } |
| |
| plci->RData[0].P = ReceiveBufferGet(APPLptr, Num); |
| if (!plci->RData[0].P) { |
| plci->NL.RNR = 1; |
| channel_x_off(plci, ch, 0); |
| break; |
| } |
| |
| APPLptr->DataNCCI[Num] = NCCIcode; |
| APPLptr->DataFlags[Num] = (plci->Id << 8) | (plci->NL.Ind >> 4); |
| dbug(3, dprintf("Buffer(%d), Max = %d", Num, APPLptr->MaxBuffer)); |
| |
| plci->RNum = Num; |
| plci->RFlags = plci->NL.Ind >> 4; |
| plci->RData[0].PLength = APPLptr->MaxDataLength; |
| plci->NL.R = plci->RData; |
| if ((plci->NL.RLength != 0) |
| && ((plci->B2_prot == B2_V120_ASYNC) |
| || (plci->B2_prot == B2_V120_ASYNC_V42BIS) |
| || (plci->B2_prot == B2_V120_BIT_TRANSPARENT))) |
| { |
| plci->RData[1].P = plci->RData[0].P; |
| plci->RData[1].PLength = plci->RData[0].PLength; |
| plci->RData[0].P = v120_header_buffer + (-((unsigned long)v120_header_buffer) & 3); |
| if ((plci->NL.RBuffer->P[0] & V120_HEADER_EXTEND_BIT) || (plci->NL.RLength == 1)) |
| plci->RData[0].PLength = 1; |
| else |
| plci->RData[0].PLength = 2; |
| if (plci->NL.RBuffer->P[0] & V120_HEADER_BREAK_BIT) |
| plci->RFlags |= 0x0010; |
| if (plci->NL.RBuffer->P[0] & (V120_HEADER_C1_BIT | V120_HEADER_C2_BIT)) |
| plci->RFlags |= 0x8000; |
| plci->NL.RNum = 2; |
| } |
| else |
| { |
| if ((plci->NL.Ind & 0x0f) == N_UDATA) |
| plci->RFlags |= 0x0010; |
| |
| else if ((plci->B3_prot == B3_RTP) && ((plci->NL.Ind & 0x0f) == N_BDATA)) |
| plci->RFlags |= 0x0001; |
| |
| plci->NL.RNum = 1; |
| } |
| break; |
| case N_DATA_ACK: |
| data_ack(plci, ch); |
| break; |
| default: |
| plci->NL.RNR = 2; |
| break; |
| } |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* find a free PLCI */ |
| /*------------------------------------------------------------------*/ |
| |
| static word get_plci(DIVA_CAPI_ADAPTER *a) |
| { |
| word i, j; |
| PLCI *plci; |
| |
| dump_plcis(a); |
| for (i = 0; i < a->max_plci && a->plci[i].Id; i++); |
| if (i == a->max_plci) { |
| dbug(1, dprintf("get_plci: out of PLCIs")); |
| return 0; |
| } |
| plci = &a->plci[i]; |
| plci->Id = (byte)(i + 1); |
| |
| plci->Sig.Id = 0; |
| plci->NL.Id = 0; |
| plci->sig_req = 0; |
| plci->nl_req = 0; |
| |
| plci->appl = NULL; |
| plci->relatedPTYPLCI = NULL; |
| plci->State = IDLE; |
| plci->SuppState = IDLE; |
| plci->channels = 0; |
| plci->tel = 0; |
| plci->B1_resource = 0; |
| plci->B2_prot = 0; |
| plci->B3_prot = 0; |
| |
| plci->command = 0; |
| plci->m_command = 0; |
| init_internal_command_queue(plci); |
| plci->number = 0; |
| plci->req_in_start = 0; |
| plci->req_in = 0; |
| plci->req_out = 0; |
| plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE; |
| plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE; |
| plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE; |
| |
| plci->data_sent = false; |
| plci->send_disc = 0; |
| plci->sig_global_req = 0; |
| plci->sig_remove_id = 0; |
| plci->nl_global_req = 0; |
| plci->nl_remove_id = 0; |
| plci->adv_nl = 0; |
| plci->manufacturer = false; |
| plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE; |
| plci->spoofed_msg = 0; |
| plci->ptyState = 0; |
| plci->cr_enquiry = false; |
| plci->hangup_flow_ctrl_timer = 0; |
| |
| plci->ncci_ring_list = 0; |
| for (j = 0; j < MAX_CHANNELS_PER_PLCI; j++) plci->inc_dis_ncci_table[j] = 0; |
| clear_c_ind_mask(plci); |
| set_group_ind_mask(plci); |
| plci->fax_connect_info_length = 0; |
| plci->nsf_control_bits = 0; |
| plci->ncpi_state = 0x00; |
| plci->ncpi_buffer[0] = 0; |
| |
| plci->requested_options_conn = 0; |
| plci->requested_options = 0; |
| plci->notifiedcall = 0; |
| plci->vswitchstate = 0; |
| plci->vsprot = 0; |
| plci->vsprotdialect = 0; |
| init_b1_config(plci); |
| dbug(1, dprintf("get_plci(%x)", plci->Id)); |
| return i + 1; |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* put a parameter in the parameter buffer */ |
| /*------------------------------------------------------------------*/ |
| |
| static void add_p(PLCI *plci, byte code, byte *p) |
| { |
| word p_length; |
| |
| p_length = 0; |
| if (p) p_length = p[0]; |
| add_ie(plci, code, p, p_length); |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* put a structure in the parameter buffer */ |
| /*------------------------------------------------------------------*/ |
| static void add_s(PLCI *plci, byte code, API_PARSE *p) |
| { |
| if (p) add_ie(plci, code, p->info, (word)p->length); |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* put multiple structures in the parameter buffer */ |
| /*------------------------------------------------------------------*/ |
| static void add_ss(PLCI *plci, byte code, API_PARSE *p) |
| { |
| byte i; |
| |
| if (p) { |
| dbug(1, dprintf("add_ss(%x,len=%d)", code, p->length)); |
| for (i = 2; i < (byte)p->length; i += p->info[i] + 2) { |
| dbug(1, dprintf("add_ss_ie(%x,len=%d)", p->info[i - 1], p->info[i])); |
| add_ie(plci, p->info[i - 1], (byte *)&(p->info[i]), (word)p->info[i]); |
| } |
| } |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* return the channel number sent by the application in a esc_chi */ |
| /*------------------------------------------------------------------*/ |
| static byte getChannel(API_PARSE *p) |
| { |
| byte i; |
| |
| if (p) { |
| for (i = 2; i < (byte)p->length; i += p->info[i] + 2) { |
| if (p->info[i] == 2) { |
| if (p->info[i - 1] == ESC && p->info[i + 1] == CHI) return (p->info[i + 2]); |
| } |
| } |
| } |
| return 0; |
| } |
| |
| |
| /*------------------------------------------------------------------*/ |
| /* put an information element in the parameter buffer */ |
| /*------------------------------------------------------------------*/ |
| |
| static void add_ie(PLCI *plci, byte code, byte *p, word p_length) |
| { |
| word i; |
| |
| if (!(code & 0x80) && !p_length) return; |
| |
| if (plci->req_in == plci->req_in_start) { |
| plci->req_in += 2; |
| } |
| else { |
| plci->req_in--; |
| } |
| plci->RBuffer[plci->req_in++] = code; |
| |
| if (p) { |
| plci->RBuffer[plci->req_in++] = (byte)p_length; |
| for (i = 0; i < p_length; i++) plci->RBuffer[plci->req_in++] = p[1 + i]; |
| } |
| |
| plci->RBuffer[plci->req_in++] = 0; |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* put a unstructured data into the buffer */ |
| /*------------------------------------------------------------------*/ |
| |
| static void add_d(PLCI *plci, word length, byte *p) |
| { |
| word i; |
| |
| if (plci->req_in == plci->req_in_start) { |
| plci->req_in += 2; |
| } |
| else { |
| plci->req_in--; |
| } |
| for (i = 0; i < length; i++) plci->RBuffer[plci->req_in++] = p[i]; |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* put parameters from the Additional Info parameter in the */ |
| /* parameter buffer */ |
| /*------------------------------------------------------------------*/ |
| |
| static void add_ai(PLCI *plci, API_PARSE *ai) |
| { |
| word i; |
| API_PARSE ai_parms[5]; |
| |
| for (i = 0; i < 5; i++) ai_parms[i].length = 0; |
| |
| if (!ai->length) |
| return; |
| if (api_parse(&ai->info[1], (word)ai->length, "ssss", ai_parms)) |
| return; |
| |
| add_s(plci, KEY, &ai_parms[1]); |
| add_s(plci, UUI, &ai_parms[2]); |
| add_ss(plci, FTY, &ai_parms[3]); |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* put parameter for b1 protocol in the parameter buffer */ |
| /*------------------------------------------------------------------*/ |
| |
| static word add_b1(PLCI *plci, API_PARSE *bp, word b_channel_info, |
| word b1_facilities) |
| { |
| API_PARSE bp_parms[8]; |
| API_PARSE mdm_cfg[9]; |
| API_PARSE global_config[2]; |
| byte cai[256]; |
| byte resource[] = {5, 9, 13, 12, 16, 39, 9, 17, 17, 18}; |
| byte voice_cai[] = "\x06\x14\x00\x00\x00\x00\x08"; |
| word i; |
| |
| API_PARSE mdm_cfg_v18[4]; |
| word j, n, w; |
| dword d; |
| |
| |
| for (i = 0; i < 8; i++) bp_parms[i].length = 0; |
| for (i = 0; i < 2; i++) global_config[i].length = 0; |
| |
| dbug(1, dprintf("add_b1")); |
| api_save_msg(bp, "s", &plci->B_protocol); |
| |
| if (b_channel_info == 2) { |
| plci->B1_resource = 0; |
| adjust_b1_facilities(plci, plci->B1_resource, b1_facilities); |
| add_p(plci, CAI, "\x01\x00"); |
| dbug(1, dprintf("Cai=1,0 (no resource)")); |
| return 0; |
| } |
| |
| if (plci->tel == CODEC_PERMANENT) return 0; |
| else if (plci->tel == CODEC) { |
| plci->B1_resource = 1; |
| adjust_b1_facilities(plci, plci->B1_resource, b1_facilities); |
| add_p(plci, CAI, "\x01\x01"); |
| dbug(1, dprintf("Cai=1,1 (Codec)")); |
| return 0; |
| } |
| else if (plci->tel == ADV_VOICE) { |
| plci->B1_resource = add_b1_facilities(plci, 9, (word)(b1_facilities | B1_FACILITY_VOICE)); |
| adjust_b1_facilities(plci, plci->B1_resource, (word)(b1_facilities | B1_FACILITY_VOICE)); |
| voice_cai[1] = plci->B1_resource; |
| PUT_WORD(&voice_cai[5], plci->appl->MaxDataLength); |
| add_p(plci, CAI, voice_cai); |
| dbug(1, dprintf("Cai=1,0x%x (AdvVoice)", voice_cai[1])); |
| return 0; |
| } |
| plci->call_dir &= ~(CALL_DIR_ORIGINATE | CALL_DIR_ANSWER); |
| if (plci->call_dir & CALL_DIR_OUT) |
| plci->call_dir |= CALL_DIR_ORIGINATE; |
| else if (plci->call_dir & CALL_DIR_IN) |
| plci->call_dir |= CALL_DIR_ANSWER; |
| |
| if (!bp->length) { |
| plci->B1_resource = 0x5; |
| adjust_b1_facilities(plci, plci->B1_resource, b1_facilities); |
| add_p(plci, CAI, "\x01\x05"); |
| return 0; |
| } |
| |
| dbug(1, dprintf("b_prot_len=%d", (word)bp->length)); |
| if (bp->length > 256) return _WRONG_MESSAGE_FORMAT; |
| if (api_parse(&bp->info[1], (word)bp->length, "wwwsssb", bp_parms)) |
| { |
| bp_parms[6].length = 0; |
| if (api_parse(&bp->info[1], (word)bp->length, "wwwsss", bp_parms)) |
| { |
| dbug(1, dprintf("b-form.!")); |
| return _WRONG_MESSAGE_FORMAT; |
| } |
| } |
| else if (api_parse(&bp->info[1], (word)bp->length, "wwwssss", bp_parms)) |
| { |
| dbug(1, dprintf("b-form.!")); |
| return _WRONG_MESSAGE_FORMAT; |
| } |
| |
| if (bp_parms[6].length) |
| { |
| if (api_parse(&bp_parms[6].info[1], (word)bp_parms[6].length, "w", global_config)) |
| { |
| return _WRONG_MESSAGE_FORMAT; |
| } |
| switch (GET_WORD(global_config[0].info)) |
| { |
| case 1: |
| plci->call_dir = (plci->call_dir & ~CALL_DIR_ANSWER) | CALL_DIR_ORIGINATE; |
| break; |
| case 2: |
| plci->call_dir = (plci->call_dir & ~CALL_DIR_ORIGINATE) | CALL_DIR_ANSWER; |
| break; |
| } |
| } |
| dbug(1, dprintf("call_dir=%04x", plci->call_dir)); |
| |
| |
| if ((GET_WORD(bp_parms[0].info) == B1_RTP) |
| && (plci->adapter->man_profile.private_options & (1L << PRIVATE_RTP))) |
| { |
| plci->B1_resource = add_b1_facilities(plci, 31, (word)(b1_facilities & ~B1_FACILITY_VOICE)); |
| adjust_b1_facilities(plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE)); |
| cai[1] = plci->B1_resource; |
| cai[2] = 0; |
| cai[3] = 0; |
| cai[4] = 0; |
| PUT_WORD(&cai[5], plci->appl->MaxDataLength); |
| for (i = 0; i < bp_parms[3].length; i++) |
| cai[7 + i] = bp_parms[3].info[1 + i]; |
| cai[0] = 6 + bp_parms[3].length; |
| add_p(plci, CAI, cai); |
| return 0; |
| } |
| |
| |
| if ((GET_WORD(bp_parms[0].info) == B1_PIAFS) |
| && (plci->adapter->man_profile.private_options & (1L << PRIVATE_PIAFS))) |
| { |
| plci->B1_resource = add_b1_facilities(plci, 35/* PIAFS HARDWARE FACILITY */, (word)(b1_facilities & ~B1_FACILITY_VOICE)); |
| adjust_b1_facilities(plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE)); |
| cai[1] = plci->B1_resource; |
| cai[2] = 0; |
| cai[3] = 0; |
| cai[4] = 0; |
| PUT_WORD(&cai[5], plci->appl->MaxDataLength); |
| cai[0] = 6; |
| add_p(plci, CAI, cai); |
| return 0; |
| } |
| |
| |
| if ((GET_WORD(bp_parms[0].info) >= 32) |
| || (!((1L << GET_WORD(bp_parms[0].info)) & plci->adapter->profile.B1_Protocols) |
| && ((GET_WORD(bp_parms[0].info) != 3) |
| || !((1L << B1_HDLC) & plci->adapter->profile.B1_Protocols) |
| || ((bp_parms[3].length != 0) && (GET_WORD(&bp_parms[3].info[1]) != 0) && (GET_WORD(&bp_parms[3].info[1]) != 56000))))) |
| { |
| return _B1_NOT_SUPPORTED; |
| } |
| plci->B1_resource = add_b1_facilities(plci, resource[GET_WORD(bp_parms[0].info)], |
| (word)(b1_facilities & ~B1_FACILITY_VOICE)); |
| adjust_b1_facilities(plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE)); |
| cai[0] = 6; |
| cai[1] = plci->B1_resource; |
| for (i = 2; i < sizeof(cai); i++) cai[i] = 0; |
| |
| if ((GET_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE) |
| || (GET_WORD(bp_parms[0].info) == B1_MODEM_ASYNC) |
| || (GET_WORD(bp_parms[0].info) == B1_MODEM_SYNC_HDLC)) |
| { /* B1 - modem */ |
| for (i = 0; i < 7; i++) mdm_cfg[i].length = 0; |
| |
| if (bp_parms[3].length) |
| { |
| if (api_parse(&bp_parms[3].info[1], (word)bp_parms[3].length, "wwwwww", mdm_cfg)) |
| { |
| return (_WRONG_MESSAGE_FORMAT); |
| } |
| |
| cai[2] = 0; /* Bit rate for adaptation */ |
| |
| dbug(1, dprintf("MDM Max Bit Rate:<%d>", GET_WORD(mdm_cfg[0].info))); |
| |
| PUT_WORD(&cai[13], 0); /* Min Tx speed */ |
| PUT_WORD(&cai[15], GET_WORD(mdm_cfg[0].info)); /* Max Tx speed */ |
| PUT_WORD(&cai[17], 0); /* Min Rx speed */ |
| PUT_WORD(&cai[19], GET_WORD(mdm_cfg[0].info)); /* Max Rx speed */ |
| |
| cai[3] = 0; /* Async framing parameters */ |
| switch (GET_WORD(mdm_cfg[2].info)) |
| { /* Parity */ |
| case 1: /* odd parity */ |
| cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_ODD); |
| dbug(1, dprintf("MDM: odd parity")); |
| break; |
| |
| case 2: /* even parity */ |
| cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_EVEN); |
| dbug(1, dprintf("MDM: even parity")); |
| break; |
| |
| default: |
| dbug(1, dprintf("MDM: no parity")); |
| break; |
| } |
| |
| switch (GET_WORD(mdm_cfg[3].info)) |
| { /* stop bits */ |
| case 1: /* 2 stop bits */ |
| cai[3] |= DSP_CAI_ASYNC_TWO_STOP_BITS; |
| dbug(1, dprintf("MDM: 2 stop bits")); |
| break; |
| |
| default: |
| dbug(1, dprintf("MDM: 1 stop bit")); |
| break; |
| } |
| |
| switch (GET_WORD(mdm_cfg[1].info)) |
| { /* char length */ |
| case 5: |
| cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_5; |
| dbug(1, dprintf("MDM: 5 bits")); |
| break; |
| |
| case 6: |
| cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_6; |
| dbug(1, dprintf("MDM: 6 bits")); |
| break; |
| |
| case 7: |
| cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_7; |
| dbug(1, dprintf("MDM: 7 bits")); |
| break; |
| |
| default: |
| dbug(1, dprintf("MDM: 8 bits")); |
| break; |
| } |
| |
| cai[7] = 0; /* Line taking options */ |
| cai[8] = 0; /* Modulation negotiation options */ |
| cai[9] = 0; /* Modulation options */ |
| |
| if (((plci->call_dir & CALL_DIR_ORIGINATE) != 0) ^ ((plci->call_dir & CALL_DIR_OUT) != 0)) |
| { |
| cai[9] |= DSP_CAI_MODEM_REVERSE_DIRECTION; |
| dbug(1, dprintf("MDM: Reverse direction")); |
| } |
| |
| if (GET_WORD(mdm_cfg[4].info) & MDM_CAPI_DISABLE_RETRAIN) |
| { |
| cai[9] |= DSP_CAI_MODEM_DISABLE_RETRAIN; |
| dbug(1, dprintf("MDM: Disable retrain")); |
| } |
| |
| if (GET_WORD(mdm_cfg[4].info) & MDM_CAPI_DISABLE_RING_TONE) |
| { |
| cai[7] |= DSP_CAI_MODEM_DISABLE_CALLING_TONE | DSP_CAI_MODEM_DISABLE_ANSWER_TONE; |
| dbug(1, dprintf("MDM: Disable ring tone")); |
| } |
| |
| if (GET_WORD(mdm_cfg[4].info) & MDM_CAPI_GUARD_1800) |
| { |
| cai[8] |= DSP_CAI_MODEM_GUARD_TONE_1800HZ; |
| dbug(1, dprintf("MDM: 1800 guard tone")); |
| } |
| else if (GET_WORD(mdm_cfg[4].info) & MDM_CAPI_GUARD_550) |
| { |
| cai[8] |= DSP_CAI_MODEM_GUARD_TONE_550HZ; |
| dbug(1, dprintf("MDM: 550 guard tone")); |
| } |
| |
| if ((GET_WORD(mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_V100) |
| { |
| cai[8] |= DSP_CAI_MODEM_NEGOTIATE_V100; |
| dbug(1, dprintf("MDM: V100")); |
| } |
| else if ((GET_WORD(mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_MOD_CLASS) |
| { |
| cai[8] |= DSP_CAI_MODEM_NEGOTIATE_IN_CLASS; |
| dbug(1, dprintf("MDM: IN CLASS")); |
| } |
| else if ((GET_WORD(mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_DISABLED) |
| { |
| cai[8] |= DSP_CAI_MODEM_NEGOTIATE_DISABLED; |
| dbug(1, dprintf("MDM: DISABLED")); |
| } |
| cai[0] = 20; |
| |
| if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_V18)) |
| && (GET_WORD(mdm_cfg[5].info) & 0x8000)) /* Private V.18 enable */ |
| { |
| plci->requested_options |= 1L << PRIVATE_V18; |
| } |
| if (GET_WORD(mdm_cfg[5].info) & 0x4000) /* Private VOWN enable */ |
| plci->requested_options |= 1L << PRIVATE_VOWN; |
| |
| if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id - 1]) |
| & ((1L << PRIVATE_V18) | (1L << PRIVATE_VOWN))) |
| { |
| if (!api_parse(&bp_parms[3].info[1], (word)bp_parms[3].length, "wwwwwws", mdm_cfg)) |
| { |
| i = 27; |
| if (mdm_cfg[6].length >= 4) |
| { |
| d = GET_DWORD(&mdm_cfg[6].info[1]); |
| cai[7] |= (byte) d; /* line taking options */ |
| cai[9] |= (byte)(d >> 8); /* modulation options */ |
| cai[++i] = (byte)(d >> 16); /* vown modulation options */ |
| cai[++i] = (byte)(d >> 24); |
| if (mdm_cfg[6].length >= 8) |
| { |
| d = GET_DWORD(&mdm_cfg[6].info[5]); |
| cai[10] |= (byte) d; /* disabled modulations mask */ |
| cai[11] |= (byte)(d >> 8); |
| if (mdm_cfg[6].length >= 12) |
| { |
| d = GET_DWORD(&mdm_cfg[6].info[9]); |
| cai[12] = (byte) d; /* enabled modulations mask */ |
| cai[++i] = (byte)(d >> 8); /* vown enabled modulations */ |
| cai[++i] = (byte)(d >> 16); |
| cai[++i] = (byte)(d >> 24); |
| cai[++i] = 0; |
| if (mdm_cfg[6].length >= 14) |
| { |
| w = GET_WORD(&mdm_cfg[6].info[13]); |
| if (w != 0) |
| PUT_WORD(&cai[13], w); /* min tx speed */ |
| if (mdm_cfg[6].length >= 16) |
| { |
| w = GET_WORD(&mdm_cfg[6].info[15]); |
| if (w != 0) |
| PUT_WORD(&cai[15], w); /* max tx speed */ |
| if (mdm_cfg[6].length >= 18) |
| { |
| w = GET_WORD(&mdm_cfg[6].info[17]); |
| if (w != 0) |
| PUT_WORD(&cai[17], w); /* min rx speed */ |
| if (mdm_cfg[6].length >= 20) |
| { |
| w = GET_WORD(&mdm_cfg[6].info[19]); |
| if (w != 0) |
| PUT_WORD(&cai[19], w); /* max rx speed */ |
| if (mdm_cfg[6].length >= 22) |
| { |
| w = GET_WORD(&mdm_cfg[6].info[21]); |
| cai[23] = (byte)(-((short) w)); /* transmit level */ |
| if (mdm_cfg[6].length >= 24) |
| { |
| w = GET_WORD(&mdm_cfg[6].info[23]); |
| cai[22] |= (byte) w; /* info options mask */ |
| cai[21] |= (byte)(w >> 8); /* disabled symbol rates */ |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| cai[27] = i - 27; |
| i++; |
| if (!api_parse(&bp_parms[3].info[1], (word)bp_parms[3].length, "wwwwwwss", mdm_cfg)) |
| { |
| if (!api_parse(&mdm_cfg[7].info[1], (word)mdm_cfg[7].length, "sss", mdm_cfg_v18)) |
| { |
| for (n = 0; n < 3; n++) |
| { |
| cai[i] = (byte)(mdm_cfg_v18[n].length); |
| for (j = 1; j < ((word)(cai[i] + 1)); j++) |
| cai[i + j] = mdm_cfg_v18[n].info[j]; |
| i += cai[i] + 1; |
| } |
| } |
| } |
| cai[0] = (byte)(i - 1); |
| } |
| } |
| |
| } |
| } |
| if (GET_WORD(bp_parms[0].info) == 2 || /* V.110 async */ |
| GET_WORD(bp_parms[0].info) == 3) /* V.110 sync */ |
| { |
| if (bp_parms[3].length) { |
| dbug(1, dprintf("V.110,%d", GET_WORD(&bp_parms[3].info[1]))); |
| switch (GET_WORD(&bp_parms[3].info[1])) { /* Rate */ |
| case 0: |
| case 56000: |
| if (GET_WORD(bp_parms[0].info) == 3) { /* V.110 sync 56k */ |
| dbug(1, dprintf("56k sync HSCX")); |
| cai[1] = 8; |
| cai[2] = 0; |
| cai[3] = 0; |
| } |
| else if (GET_WORD(bp_parms[0].info) == 2) { |
| dbug(1, dprintf("56k async DSP")); |
| cai[2] = 9; |
| } |
| break; |
| case 50: cai[2] = 1; break; |
| case 75: cai[2] = 1; break; |
| case 110: cai[2] = 1; break; |
| case 150: cai[2] = 1; break; |
| case 200: cai[2] = 1; break; |
| case 300: cai[2] = 1; break; |
| case 600: cai[2] = 1; break; |
| case 1200: cai[2] = 2; break; |
| case 2400: cai[2] = 3; break; |
| case 4800: cai[2] = 4; break; |
| case 7200: cai[2] = 10; break; |
| case 9600: cai[2] = 5; break; |
| case 12000: cai[2] = 13; break; |
| case 24000: cai[2] = 0; break; |
| case 14400: cai[2] = 11; break; |
| case 19200: cai[2] = 6; break; |
| case 28800: cai[2] = 12; break; |
| case 38400: cai[2] = 7; break; |
| case 48000: cai[2] = 8; break; |
| case 76: cai[2] = 15; break; /* 75/1200 */ |
| case 1201: cai[2] = 14; break; /* 1200/75 */ |
| case 56001: cai[2] = 9; break; /* V.110 56000 */ |
| |
| default: |
| return _B1_PARM_NOT_SUPPORTED; |
| } |
| cai[3] = 0; |
| if (cai[1] == 13) /* v.110 async */ |
| { |
| if (bp_parms[3].length >= 8) |
| { |
| switch (GET_WORD(&bp_parms[3].info[3])) |
| { /* char length */ |
| case 5: |
| cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_5; |
| break; |
| case 6: |
| cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_6; |
| break; |
| case 7: |
| cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_7; |
| break; |
| } |
| switch (GET_WORD(&bp_parms[3].info[5])) |
| { /* Parity */ |
| case 1: /* odd parity */ |
| cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_ODD); |
| break; |
| case 2: /* even parity */ |
| cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_EVEN); |
| break; |
| } |
| switch (GET_WORD(&bp_parms[3].info[7])) |
| { /* stop bits */ |
| case 1: /* 2 stop bits */ |
| cai[3] |= DSP_CAI_ASYNC_TWO_STOP_BITS; |
| break; |
| } |
| } |
| } |
| } |
| else if (cai[1] == 8 || GET_WORD(bp_parms[0].info) == 3) { |
| dbug(1, dprintf("V.110 default 56k sync")); |
| cai[1] = 8; |
| cai[2] = 0; |
| cai[3] = 0; |
| } |
| else { |
| dbug(1, dprintf("V.110 default 9600 async")); |
| cai[2] = 5; |
| } |
| } |
| PUT_WORD(&cai[5], plci->appl->MaxDataLength); |
| dbug(1, dprintf("CAI[%d]=%x,%x,%x,%x,%x,%x", cai[0], cai[1], cai[2], cai[3], cai[4], cai[5], cai[6])); |
| /* HexDump ("CAI", sizeof(cai), &cai[0]); */ |
| |
| add_p(plci, CAI, cai); |
| return 0; |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* put parameter for b2 and B3 protocol in the parameter buffer */ |
| /*------------------------------------------------------------------*/ |
| |
| static word add_b23(PLCI *plci, API_PARSE *bp) |
| { |
| word i, fax_control_bits; |
| byte pos, len; |
| byte SAPI = 0x40; /* default SAPI 16 for x.31 */ |
| API_PARSE bp_parms[8]; |
| API_PARSE *b1_config; |
| API_PARSE *b2_config; |
| API_PARSE b2_config_parms[8]; |
| API_PARSE *b3_config; |
| API_PARSE b3_config_parms[6]; |
| API_PARSE global_config[2]; |
| |
| static byte llc[3] = {2,0,0}; |
| static byte dlc[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; |
| static byte nlc[256]; |
| static byte lli[12] = {1,1}; |
| |
| const byte llc2_out[] = {1,2,4,6,2,0,0,0, X75_V42BIS,V120_L2,V120_V42BIS,V120_L2,6}; |
| const byte llc2_in[] = {1,3,4,6,3,0,0,0, X75_V42BIS,V120_L2,V120_V42BIS,V120_L2,6}; |
| |
| const byte llc3[] = {4,3,2,2,6,6,0}; |
| const byte header[] = {0,2,3,3,0,0,0}; |
| |
| for (i = 0; i < 8; i++) bp_parms[i].length = 0; |
| for (i = 0; i < 6; i++) b2_config_parms[i].length = 0; |
| for (i = 0; i < 5; i++) b3_config_parms[i].length = 0; |
| |
| lli[0] = 1; |
| lli[1] = 1; |
| if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL) |
| lli[1] |= 2; |
| if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL) |
| lli[1] |= 4; |
| |
| if ((lli[1] & 0x02) && (diva_xdi_extended_features & DIVA_CAPI_USE_CMA)) { |
| lli[1] |= 0x10; |
| if (plci->rx_dma_descriptor <= 0) { |
| plci->rx_dma_descriptor = diva_get_dma_descriptor(plci, &plci->rx_dma_magic); |
| if (plci->rx_dma_descriptor >= 0) |
| plci->rx_dma_descriptor++; |
| } |
| if (plci->rx_dma_descriptor > 0) { |
| lli[0] = 6; |
| lli[1] |= 0x40; |
| lli[2] = (byte)(plci->rx_dma_descriptor - 1); |
| lli[3] = (byte)plci->rx_dma_magic; |
| lli[4] = (byte)(plci->rx_dma_magic >> 8); |
| lli[5] = (byte)(plci->rx_dma_magic >> 16); |
| lli[6] = (byte)(plci->rx_dma_magic >> 24); |
| } |
| } |
| |
| if (DIVA_CAPI_SUPPORTS_NO_CANCEL(plci->adapter)) { |
| lli[1] |= 0x20; |
| } |
| |
| dbug(1, dprintf("add_b23")); |
| api_save_msg(bp, "s", &plci->B_protocol); |
| |
| if (!bp->length && plci->tel) |
| { |
| plci->adv_nl = true; |
| dbug(1, dprintf("Default adv.Nl")); |
| add_p(plci, LLI, lli); |
| plci->B2_prot = 1 /*XPARENT*/; |
| plci->B3_prot = 0 /*XPARENT*/; |
| llc[1] = 2; |
| llc[2] = 4; |
| add_p(plci, LLC, llc); |
| dlc[0] = 2; |
| PUT_WORD(&dlc[1], plci->appl->MaxDataLength); |
| add_p(plci, DLC, dlc); |
| return 0; |
| } |
| |
| if (!bp->length) /*default*/ |
| { |
| dbug(1, dprintf("ret default")); |
| add_p(plci, LLI, lli); |
| plci->B2_prot = 0 /*X.75 */; |
| plci->B3_prot = 0 /*XPARENT*/; |
| llc[1] = 1; |
| llc[2] = 4; |
| add_p(plci, LLC, llc); |
| dlc[0] = 2; |
| PUT_WORD(&dlc[1], plci->appl->MaxDataLength); |
| add_p(plci, DLC, dlc); |
| return 0; |
| } |
| dbug(1, dprintf("b_prot_len=%d", (word)bp->length)); |
| if ((word)bp->length > 256) return _WRONG_MESSAGE_FORMAT; |
| |
| if (api_parse(&bp->info[1], (word)bp->length, "wwwsssb", bp_parms)) |
| { |
| bp_parms[6].length = 0; |
| if (api_parse(&bp->info[1], (word)bp->length, "wwwsss", bp_parms)) |
| { |
| dbug(1, dprintf("b-form.!")); |
| return _WRONG_MESSAGE_FORMAT; |
| } |
| } |
| else if (api_parse(&bp->info[1], (word)bp->length, "wwwssss", bp_parms)) |
| { |
| dbug(1, dprintf("b-form.!")); |
| return _WRONG_MESSAGE_FORMAT; |
| } |
| |
| if (plci->tel == ADV_VOICE) /* transparent B on advanced voice */ |
| { |
| if (GET_WORD(bp_parms[1].info) != 1 |
| || GET_WORD(bp_parms[2].info) != 0) return _B2_NOT_SUPPORTED; |
| plci->adv_nl = true; |
| } |
| else if (plci->tel) return _B2_NOT_SUPPORTED; |
| |
| |
| if ((GET_WORD(bp_parms[1].info) == B2_RTP) |
| && (GET_WORD(bp_parms[2].info) == B3_RTP) |
| && (plci->adapter->man_profile.private_options & (1L << PRIVATE_RTP))) |
| { |
| add_p(plci, LLI, lli); |
| plci->B2_prot = (byte) GET_WORD(bp_parms[1].info); |
| plci->B3_prot = (byte) GET_WORD(bp_parms[2].info); |
| llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ? 14 : 13; |
| llc[2] = 4; |
| add_p(plci, LLC, llc); |
| dlc[0] = 2; |
| PUT_WORD(&dlc[1], plci->appl->MaxDataLength); |
| dlc[3] = 3; /* Addr A */ |
| dlc[4] = 1; /* Addr B */ |
| dlc[5] = 7; /* modulo mode */ |
| dlc[6] = 7; /* window size */ |
| dlc[7] = 0; /* XID len Lo */ |
| dlc[8] = 0; /* XID len Hi */ |
| for (i = 0; i < bp_parms[4].length; i++) |
| dlc[9 + i] = bp_parms[4].info[1 + i]; |
| dlc[0] = (byte)(8 + bp_parms[4].length); |
| add_p(plci, DLC, dlc); |
| for (i = 0; i < bp_parms[5].length; i++) |
| nlc[1 + i] = bp_parms[5].info[1 + i]; |
| nlc[0] = (byte)(bp_parms[5].length); |
| add_p(plci, NLC, nlc); |
| return 0; |
| } |
| |
| |
| |
| if ((GET_WORD(bp_parms[1].info) >= 32) |
| || (!((1L << GET_WORD(bp_parms[1].info)) & plci->adapter->profile.B2_Protocols) |
| && ((GET_WORD(bp_parms[1].info) != B2_PIAFS) |
| || !(plci->adapter->man_profile.private_options & (1L << PRIVATE_PIAFS))))) |
| |
| { |
| return _B2_NOT_SUPPORTED; |
| } |
| if ((GET_WORD(bp_parms[2].info) >= 32) |
| || !((1L << GET_WORD(bp_parms[2].info)) & plci->adapter->profile.B3_Protocols)) |
| { |
| return _B3_NOT_SUPPORTED; |
| } |
| if ((GET_WORD(bp_parms[1].info) != B2_SDLC) |
| && ((GET_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE) |
| || (GET_WORD(bp_parms[0].info) == B1_MODEM_ASYNC) |
| || (GET_WORD(bp_parms[0].info) == B1_MODEM_SYNC_HDLC))) |
| { |
| return (add_modem_b23(plci, bp_parms)); |
| } |
| |
| add_p(plci, LLI, lli); |
| |
| plci->B2_prot = (byte)GET_WORD(bp_parms[1].info); |
| plci->B3_prot = (byte)GET_WORD(bp_parms[2].info); |
| if (plci->B2_prot == 12) SAPI = 0; /* default SAPI D-channel */ |
| |
| if (bp_parms[6].length) |
| { |
| if (api_parse(&bp_parms[6].info[1], (word)bp_parms[6].length, "w", global_config)) |
| { |
| return _WRONG_MESSAGE_FORMAT; |
| } |
| switch (GET_WORD(global_config[0].info)) |
| { |
| case 1: |
| plci->call_dir = (plci->call_dir & ~CALL_DIR_ANSWER) | CALL_DIR_ORIGINATE; |
| break; |
| case 2: |
| plci->call_dir = (plci->call_dir & ~CALL_DIR_ORIGINATE) | CALL_DIR_ANSWER; |
| break; |
| } |
| } |
| dbug(1, dprintf("call_dir=%04x", plci->call_dir)); |
| |
| |
| if (plci->B2_prot == B2_PIAFS) |
| llc[1] = PIAFS_CRC; |
| else |
| /* IMPLEMENT_PIAFS */ |
| { |
| llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ? |
| llc2_out[GET_WORD(bp_parms[1].info)] : llc2_in[GET_WORD(bp_parms[1].info)]; |
| } |
| llc[2] = llc3[GET_WORD(bp_parms[2].info)]; |
| |
| add_p(plci, LLC, llc); |
| |
| dlc[0] = 2; |
| PUT_WORD(&dlc[1], plci->appl->MaxDataLength + |
| header[GET_WORD(bp_parms[2].info)]); |
| |
| b1_config = &bp_parms[3]; |
| nlc[0] = 0; |
| if (plci->B3_prot == 4 |
| || plci->B3_prot == 5) |
| { |
| for (i = 0; i < sizeof(T30_INFO); i++) nlc[i] = 0; |
| nlc[0] = sizeof(T30_INFO); |
| if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS) |
| ((T30_INFO *)&nlc[1])->operating_mode = T30_OPERATING_MODE_CAPI; |
| ((T30_INFO *)&nlc[1])->rate_div_2400 = 0xff; |
| if (b1_config->length >= 2) |
| { |
| ((T30_INFO *)&nlc[1])->rate_div_2400 = (byte)(GET_WORD(&b1_config->info[1]) / 2400); |
| } |
| } |
| b2_config = &bp_parms[4]; |
| |
| |
| if (llc[1] == PIAFS_CRC) |
| { |
| if (plci->B3_prot != B3_TRANSPARENT) |
| { |
| return _B_STACK_NOT_SUPPORTED; |
| } |
| if (b2_config->length && api_parse(&b2_config->info[1], (word)b2_config->length, "bwww", b2_config_parms)) { |
| return _WRONG_MESSAGE_FORMAT; |
| } |
| PUT_WORD(&dlc[1], plci->appl->MaxDataLength); |
| dlc[3] = 0; /* Addr A */ |
| dlc[4] = 0; /* Addr B */ |
| dlc[5] = 0; /* modulo mode */ |
| dlc[6] = 0; /* window size */ |
| if (b2_config->length >= 7) { |
| dlc[7] = 7; |
| dlc[8] = 0; |
| dlc[9] = b2_config_parms[0].info[0]; /* PIAFS protocol Speed configuration */ |
| dlc[10] = b2_config_parms[1].info[0]; /* V.42bis P0 */ |
| dlc[11] = b2_config_parms[1].info[1]; /* V.42bis P0 */ |
| dlc[12] = b2_config_parms[2].info[0]; /* V.42bis P1 */ |
| dlc[13] = b2_config_parms[2].info[1]; /* V.42bis P1 */ |
| dlc[14] = b2_config_parms[3].info[0]; /* V.42bis P2 */ |
| dlc[15] = b2_config_parms[3].info[1]; /* V.42bis P2 */ |
| dlc[0] = 15; |
| if (b2_config->length >= 8) { /* PIAFS control abilities */ |
| dlc[7] = 10; |
| dlc[16] = 2; /* Length of PIAFS extension */ |
| dlc[17] = PIAFS_UDATA_ABILITIES; /* control (UDATA) ability */ |
| dlc[18] = b2_config_parms[4].info[0]; /* value */ |
| dlc[0] = 18; |
| } |
| } |
| else /* default values, 64K, variable, no compression */ |
| { |
| dlc[7] = 7; |
| dlc[8] = 0; |
| dlc[9] = 0x03; /* PIAFS protocol Speed configuration */ |
| dlc[10] = 0x03; /* V.42bis P0 */ |
| dlc[11] = 0; /* V.42bis P0 */ |
| dlc[12] = 0; /* V.42bis P1 */ |
| dlc[13] = 0; /* V.42bis P1 */ |
| dlc[14] = 0; /* V.42bis P2 */ |
| dlc[15] = 0; /* V.42bis P2 */ |
| dlc[0] = 15; |
| } |
| add_p(plci, DLC, dlc); |
| } |
| else |
| |
| if ((llc[1] == V120_L2) || (llc[1] == V120_V42BIS)) |
| { |
| if (plci->B3_prot != B3_TRANSPARENT) |
| return _B_STACK_NOT_SUPPORTED; |
| |
| dlc[0] = 6; |
| PUT_WORD(&dlc[1], GET_WORD(&dlc[1]) + 2); |
| dlc[3] = 0x08; |
| dlc[4] = 0x01; |
| dlc[5] = 127; |
| dlc[6] = 7; |
| if (b2_config->length != 0) |
| { |
| if ((llc[1] == V120_V42BIS) && api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbwww", b2_config_parms)) { |
| return _WRONG_MESSAGE_FORMAT; |
| } |
| dlc[3] = (byte)((b2_config->info[2] << 3) | ((b2_config->info[1] >> 5) & 0x04)); |
| dlc[4] = (byte)((b2_config->info[1] << 1) | 0x01); |
| if (b2_config->info[3] != 128) |
| { |
| dbug(1, dprintf("1D-dlc= %x %x %x %x %x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4])); |
| return _B2_PARM_NOT_SUPPORTED; |
| } |
| dlc[5] = (byte)(b2_config->info[3] - 1); |
| dlc[6] = b2_config->info[4]; |
| if (llc[1] == V120_V42BIS) { |
| if (b2_config->length >= 10) { |
| dlc[7] = 6; |
| dlc[8] = 0; |
| dlc[9] = b2_config_parms[4].info[0]; |
| dlc[10] = b2_config_parms[4].info[1]; |
| dlc[11] = b2_config_parms[5].info[0]; |
| dlc[12] = b2_config_parms[5].info[1]; |
| dlc[13] = b2_config_parms[6].info[0]; |
| dlc[14] = b2_config_parms[6].info[1]; |
| dlc[0] = 14; |
| dbug(1, dprintf("b2_config_parms[4].info[0] [1]: %x %x", b2_config_parms[4].info[0], b2_config_parms[4].info[1])); |
| dbug(1, dprintf("b2_config_parms[5].info[0] [1]: %x %x", b2_config_parms[5].info[0], b2_config_parms[5].info[1])); |
| dbug(1, dprintf("b2_config_parms[6].info[0] [1]: %x %x", b2_config_parms[6].info[0], b2_config_parms[6].info[1])); |
| } |
| else { |
| dlc[6] = 14; |
| } |
| } |
| } |
| } |
| else |
| { |
| if (b2_config->length) |
| { |
| dbug(1, dprintf("B2-Config")); |
| if (llc[1] == X75_V42BIS) { |
| if (api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbwww", b2_config_parms)) |
| { |
| return _WRONG_MESSAGE_FORMAT; |
| } |
| } |
| else { |
| if (api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbs", b2_config_parms)) |
| { |
| return _WRONG_MESSAGE_FORMAT; |
| } |
| } |
| /* if B2 Protocol is LAPD, b2_config structure is different */ |
| if (llc[1] == 6) |
| { |
| dlc[0] = 4; |
| if (b2_config->length >= 1) dlc[2] = b2_config->info[1]; /* TEI */ |
| else dlc[2] = 0x01; |
| if ((b2_config->length >= 2) && (plci->B2_prot == 12)) |
| { |
| SAPI = b2_config->info[2]; /* SAPI */ |
| } |
| dlc[1] = SAPI; |
| if ((b2_config->length >= 3) && (b2_config->info[3] == 128)) |
| { |
| dlc[3] = 127; /* Mode */ |
| } |
| else |
| { |
| dlc[3] = 7; /* Mode */ |
| } |
| |
| if (b2_config->length >= 4) dlc[4] = b2_config->info[4]; /* Window */ |
| else dlc[4] = 1; |
| dbug(1, dprintf("D-dlc[%d]=%x,%x,%x,%x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4])); |
| if (b2_config->length > 5) return _B2_PARM_NOT_SUPPORTED; |
| } |
| else |
| { |
| dlc[0] = (byte)(b2_config_parms[4].length + 6); |
| dlc[3] = b2_config->info[1]; |
| dlc[4] = b2_config->info[2]; |
| if (b2_config->info[3] != 8 && b2_config->info[3] != 128) { |
| dbug(1, dprintf("1D-dlc= %x %x %x %x %x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4])); |
| return _B2_PARM_NOT_SUPPORTED; |
| } |
| |
| dlc[5] = (byte)(b2_config->info[3] - 1); |
| dlc[6] = b2_config->info[4]; |
| if (dlc[6] > dlc[5]) { |
| dbug(1, dprintf("2D-dlc= %x %x %x %x %x %x %x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4], dlc[5], dlc[6])); |
| return _B2_PARM_NOT_SUPPORTED; |
| } |
| |
| if (llc[1] == X75_V42BIS) { |
| if (b2_config->length >= 10) { |
| dlc[7] = 6; |
| dlc[8] = 0; |
| dlc[9] = b2_config_parms[4].info[0]; |
| dlc[10] = b2_config_parms[4].info[1]; |
| dlc[11] = b2_config_parms[5].info[0]; |
| dlc[12] = b2_config_parms[5].info[1]; |
| dlc[13] = b2_config_parms[6].info[0]; |
| dlc[14] = b2_config_parms[6].info[1]; |
| dlc[0] = 14; |
| dbug(1, dprintf("b2_config_parms[4].info[0] [1]: %x %x", b2_config_parms[4].info[0], b2_config_parms[4].info[1])); |
| dbug(1, dprintf("b2_config_parms[5].info[0] [1]: %x %x", b2_config_parms[5].info[0], b2_config_parms[5].info[1])); |
| dbug(1, dprintf("b2_config_parms[6].info[0] [1]: %x %x", b2_config_parms[6].info[0], b2_config_parms[6].info[1])); |
| } |
| else { |
| dlc[6] = 14; |
| } |
| |
| } |
| else { |
| PUT_WORD(&dlc[7], (word)b2_config_parms[4].length); |
| for (i = 0; i < b2_config_parms[4].length; i++) |
| dlc[11 + i] = b2_config_parms[4].info[1 + i]; |
| } |
| } |
| } |
| } |
| add_p(plci, DLC, dlc); |
| |
| b3_config = &bp_parms[5]; |
| if (b3_config->length) |
| { |
| if (plci->B3_prot == 4 |
| || plci->B3_prot == 5) |
| { |
| if (api_parse(&b3_config->info[1], (word)b3_config->length, "wwss", b3_config_parms)) |
| { |
| return _WRONG_MESSAGE_FORMAT; |
| } |
| i = GET_WORD((byte *)(b3_config_parms[0].info)); |
| ((T30_INFO *)&nlc[1])->resolution = (byte)(((i & 0x0001) || |
| ((plci->B3_prot == 4) && (((byte)(GET_WORD((byte *)b3_config_parms[1].info))) != 5))) ? T30_RESOLUTION_R8_0770_OR_200 : 0); |
| ((T30_INFO *)&nlc[1])->data_format = (byte)(GET_WORD((byte *)b3_config_parms[1].info)); |
| fax_control_bits = T30_CONTROL_BIT_ALL_FEATURES; |
| if ((((T30_INFO *)&nlc[1])->rate_div_2400 != 0) && (((T30_INFO *)&nlc[1])->rate_div_2400 <= 6)) |
| fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_V34FAX; |
| if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS) |
| { |
| |
| if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id - 1]) |
| & (1L << PRIVATE_FAX_PAPER_FORMATS)) |
| { |
| ((T30_INFO *)&nlc[1])->resolution |= T30_RESOLUTION_R8_1540 | |
| T30_RESOLUTION_R16_1540_OR_400 | T30_RESOLUTION_300_300 | |
| T30_RESOLUTION_INCH_BASED | T30_RESOLUTION_METRIC_BASED; |
| } |
| |
| ((T30_INFO *)&nlc[1])->recording_properties = |
| T30_RECORDING_WIDTH_ISO_A3 | |
| (T30_RECORDING_LENGTH_UNLIMITED << 2) | |
| (T30_MIN_SCANLINE_TIME_00_00_00 << 4); |
| } |
| if (plci->B3_prot == 5) |
| { |
| if (i & 0x0002) /* Accept incoming fax-polling requests */ |
| fax_control_bits |= T30_CONTROL_BIT_ACCEPT_POLLING; |
| if (i & 0x2000) /* Do not use MR compression */ |
| fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_2D_CODING; |
| if (i & 0x4000) /* Do not use MMR compression */ |
| fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_T6_CODING; |
| if (i & 0x8000) /* Do not use ECM */ |
| fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_ECM; |
| if (plci->fax_connect_info_length != 0) |
| { |
| ((T30_INFO *)&nlc[1])->resolution = ((T30_INFO *)plci->fax_connect_info_buffer)->resolution; |
| ((T30_INFO *)&nlc[1])->data_format = ((T30_INFO *)plci->fax_connect_info_buffer)->data_format; |
| ((T30_INFO *)&nlc[1])->recording_properties = ((T30_INFO *)plci->fax_connect_info_buffer)->recording_properties; |
| fax_control_bits |= GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low) & |
| (T30_CONTROL_BIT_REQUEST_POLLING | T30_CONTROL_BIT_MORE_DOCUMENTS); |
| } |
| } |
| /* copy station id to NLC */ |
| for (i = 0; i < T30_MAX_STATION_ID_LENGTH; i++) |
| { |
| if (i < b3_config_parms[2].length) |
| { |
| ((T30_INFO *)&nlc[1])->station_id[i] = ((byte *)b3_config_parms[2].info)[1 + i]; |
| } |
| else |
| { |
| ((T30_INFO *)&nlc[1])->station_id[i] = ' '; |
| } |
| } |
| ((T30_INFO *)&nlc[1])->station_id_len = T30_MAX_STATION_ID_LENGTH; |
| /* copy head line to NLC */ |
| if (b3_config_parms[3].length) |
| { |
| |
| pos = (byte)(fax_head_line_time(&(((T30_INFO *)&nlc[1])->station_id[T30_MAX_STATION_ID_LENGTH]))); |
| if (pos != 0) |
| { |
| if (CAPI_MAX_DATE_TIME_LENGTH + 2 + b3_config_parms[3].length > CAPI_MAX_HEAD_LINE_SPACE) |
| pos = 0; |
| else |
| { |
| nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ' '; |
| nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ' '; |
| len = (byte)b3_config_parms[2].length; |
| if (len > 20) |
| len = 20; |
| if (CAPI_MAX_DATE_TIME_LENGTH + 2 + len + 2 + b3_config_parms[3].length <= CAPI_MAX_HEAD_LINE_SPACE) |
| { |
| for (i = 0; i < len; i++) |
| nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ((byte *)b3_config_parms[2].info)[1 + i]; |
| nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ' '; |
| nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ' '; |
| } |
| } |
| } |
| |
| len = (byte)b3_config_parms[3].length; |
| if (len > CAPI_MAX_HEAD_LINE_SPACE - pos) |
| len = (byte)(CAPI_MAX_HEAD_LINE_SPACE - pos); |
| ((T30_INFO *)&nlc[1])->head_line_len = (byte)(pos + len); |
| nlc[0] += (byte)(pos + len); |
| for (i = 0; i < len; i++) |
| nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ((byte *)b3_config_parms[3].info)[1 + i]; |
| } else |
| ((T30_INFO *)&nlc[1])->head_line_len = 0; |
| |
| plci->nsf_control_bits = 0; |
| if (plci->B3_prot == 5) |
| { |
| if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_FAX_SUB_SEP_PWD)) |
| && (GET_WORD((byte *)b3_config_parms[1].info) & 0x8000)) /* Private SUB/SEP/PWD enable */ |
| { |
| plci->requested_options |= 1L << PRIVATE_FAX_SUB_SEP_PWD; |
| } |
| if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_FAX_NONSTANDARD)) |
| && (GET_WORD((byte *)b3_config_parms[1].info) & 0x4000)) /* Private non-standard facilities enable */ |
| { |
| plci->requested_options |= 1L << PRIVATE_FAX_NONSTANDARD; |
| } |
| if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id - 1]) |
| & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD))) |
| { |
| if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id - 1]) |
| & (1L << PRIVATE_FAX_SUB_SEP_PWD)) |
| { |
| fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_PASSWORD; |
| if (fax_control_bits & T30_CONTROL_BIT_ACCEPT_POLLING) |
| fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SEL_POLLING; |
| } |
| len = nlc[0]; |
| pos = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH; |
| if (pos < plci->fax_connect_info_length) |
| { |
| for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--) |
| nlc[++len] = plci->fax_connect_info_buffer[pos++]; |
| } |
| else |
| nlc[++len] = 0; |
| if (pos < plci->fax_connect_info_length) |
| { |
| for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--) |
| nlc[++len] = plci->fax_connect_info_buffer[pos++]; |
| } |
| else |
| nlc[++len] = 0; |
| if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id - 1]) |
| & (1L << PRIVATE_FAX_NONSTANDARD)) |
| { |
| if ((pos < plci->fax_connect_info_length) && (plci->fax_connect_info_buffer[pos] != 0)) |
| { |
| if ((plci->fax_connect_info_buffer[pos] >= 3) && (plci->fax_connect_info_buffer[pos + 1] >= 2)) |
| plci->nsf_control_bits = GET_WORD(&plci->fax_connect_info_buffer[pos + 2]); |
| for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--) |
| nlc[++len] = plci->fax_connect_info_buffer[pos++]; |
| } |
| else |
| { |
| if (api_parse(&b3_config->info[1], (word)b3_config->length, "wwsss", b3_config_parms)) |
| { |
| dbug(1, dprintf("non-standard facilities info missing or wrong format")); |
| nlc[++len] = 0; |
| } |
| else |
| { |
| if ((b3_config_parms[4].length >= 3) && (b3_config_parms[4].info[1] >= 2)) |
| plci->nsf_control_bits = GET_WORD(&b3_config_parms[4].info[2]); |
| nlc[++len] = (byte)(b3_config_parms[4].length); |
| for (i = 0; i < b3_config_parms[4].length; i++) |
| nlc[++len] = b3_config_parms[4].info[1 + i]; |
| } |
| } |
| } |
| nlc[0] = len; |
| if ((plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF) |
| && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP)) |
| { |
| ((T30_INFO *)&nlc[1])->operating_mode = T30_OPERATING_MODE_CAPI_NEG; |
| } |
| } |
| } |
| |
| PUT_WORD(&(((T30_INFO *)&nlc[1])->control_bits_low), fax_control_bits); |
| len = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH; |
| for (i = 0; i < len; i++) |
| plci->fax_connect_info_buffer[i] = nlc[1 + i]; |
| ((T30_INFO *) plci->fax_connect_info_buffer)->head_line_len = 0; |
| i += ((T30_INFO *)&nlc[1])->head_line_len; |
| while (i < nlc[0]) |
| plci->fax_connect_info_buffer[len++] = nlc[++i]; |
| plci->fax_connect_info_length = len; |
| } |
| else |
| { |
| nlc[0] = 14; |
| if (b3_config->length != 16) |
| return _B3_PARM_NOT_SUPPORTED; |
| for (i = 0; i < 12; i++) nlc[1 + i] = b3_config->info[1 + i]; |
| if (GET_WORD(&b3_config->info[13]) != 8 && GET_WORD(&b3_config->info[13]) != 128) |
| return _B3_PARM_NOT_SUPPORTED; |
| nlc[13] = b3_config->info[13]; |
| if (GET_WORD(&b3_config->info[15]) >= nlc[13]) |
| return _B3_PARM_NOT_SUPPORTED; |
| nlc[14] = b3_config->info[15]; |
| } |
| } |
| else |
| { |
| if (plci->B3_prot == 4 |
| || plci->B3_prot == 5 /*T.30 - FAX*/) return _B3_PARM_NOT_SUPPORTED; |
| } |
| add_p(plci, NLC, nlc); |
| return 0; |
| } |
| |
| /*----------------------------------------------------------------*/ |
| /* make the same as add_b23, but only for the modem related */ |
| /* L2 and L3 B-Chan protocol. */ |
| /* */ |
| /* Enabled L2 and L3 Configurations: */ |
| /* If L1 == Modem all negotiation */ |
| /* only L2 == Modem with full negotiation is allowed */ |
| /* If L1 == Modem async or sync */ |
| /* only L2 == Transparent is allowed */ |
| /* L3 == Modem or L3 == Transparent are allowed */ |
| /* B2 Configuration for modem: */ |
| /* word : enable/disable compression, bitoptions */ |
| /* B3 Configuration for modem: */ |
| /* empty */ |
| /*----------------------------------------------------------------*/ |
| static word add_modem_b23(PLCI *plci, API_PARSE *bp_parms) |
| { |
| static byte lli[12] = {1,1}; |
| static byte llc[3] = {2,0,0}; |
| static byte dlc[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; |
| API_PARSE mdm_config[2]; |
| word i; |
| word b2_config = 0; |
| |
| for (i = 0; i < 2; i++) mdm_config[i].length = 0; |
| for (i = 0; i < sizeof(dlc); i++) dlc[i] = 0; |
| |
| if (((GET_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE) |
| && (GET_WORD(bp_parms[1].info) != B2_MODEM_EC_COMPRESSION)) |
| || ((GET_WORD(bp_parms[0].info) != B1_MODEM_ALL_NEGOTIATE) |
| && (GET_WORD(bp_parms[1].info) != B2_TRANSPARENT))) |
| { |
| return (_B_STACK_NOT_SUPPORTED); |
| } |
| if ((GET_WORD(bp_parms[2].info) != B3_MODEM) |
| && (GET_WORD(bp_parms[2].info) != B3_TRANSPARENT)) |
| { |
| return (_B_STACK_NOT_SUPPORTED); |
| } |
| |
| plci->B2_prot = (byte) GET_WORD(bp_parms[1].info); |
| plci->B3_prot = (byte) GET_WORD(bp_parms[2].info); |
| |
| if ((GET_WORD(bp_parms[1].info) == B2_MODEM_EC_COMPRESSION) && bp_parms[4].length) |
| { |
| if (api_parse(&bp_parms[4].info[1], |
| (word)bp_parms[4].length, "w", |
| mdm_config)) |
| { |
| return (_WRONG_MESSAGE_FORMAT); |
| } |
| b2_config = GET_WORD(mdm_config[0].info); |
| } |
| |
| /* OK, L2 is modem */ |
| |
| lli[0] = 1; |
| lli[1] = 1; |
| if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL) |
| lli[1] |= 2; |
| if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL) |
| lli[1] |= 4; |
| |
| if ((lli[1] & 0x02) && (diva_xdi_extended_features & DIVA_CAPI_USE_CMA)) { |
| lli[1] |= 0x10; |
| if (plci->rx_dma_descriptor <= 0) { |
| plci->rx_dma_descriptor = diva_get_dma_descriptor(plci, &plci->rx_dma_magic); |
| if (plci->rx_dma_descriptor >= 0) |
| plci->rx_dma_descriptor++; |
| } |
| if (plci->rx_dma_descriptor > 0) { |
| lli[1] |= 0x40; |
| lli[0] = 6; |
| lli[2] = (byte)(plci->rx_dma_descriptor - 1); |
| lli[3] = (byte)plci->rx_dma_magic; |
| lli[4] = (byte)(plci->rx_dma_magic >> 8); |
| lli[5] = (byte)(plci->rx_dma_magic >> 16); |
| lli[6] = (byte)(plci->rx_dma_magic >> 24); |
| } |
| } |
| |
| if (DIVA_CAPI_SUPPORTS_NO_CANCEL(plci->adapter)) { |
| lli[1] |= 0x20; |
| } |
| |
| llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ? |
| /*V42*/ 10 : /*V42_IN*/ 9; |
| llc[2] = 4; /* pass L3 always transparent */ |
| add_p(plci, LLI, lli); |
| add_p(plci, LLC, llc); |
| i = 1; |
| PUT_WORD(&dlc[i], plci->appl->MaxDataLength); |
| i += 2; |
| if (GET_WORD(bp_parms[1].info) == B2_MODEM_EC_COMPRESSION) |
| { |
| if (bp_parms[4].length) |
| { |
| dbug(1, dprintf("MDM b2_config=%02x", b2_config)); |
| dlc[i++] = 3; /* Addr A */ |
| dlc[i++] = 1; /* Addr B */ |
| dlc[i++] = 7; /* modulo mode */ |
| dlc[i++] = 7; /* window size */ |
| dlc[i++] = 0; /* XID len Lo */ |
| dlc[i++] = 0; /* XID len Hi */ |
| |
| if (b2_config & MDM_B2_DISABLE_V42bis) |
| { |
| dlc[i] |= DLC_MODEMPROT_DISABLE_V42_V42BIS; |
| } |
| if (b2_config & MDM_B2_DISABLE_MNP) |
| { |
| dlc[i] |= DLC_MODEMPROT_DISABLE_MNP_MNP5; |
| } |
| if (b2_config & MDM_B2_DISABLE_TRANS) |
| { |
| dlc[i] |= DLC_MODEMPROT_REQUIRE_PROTOCOL; |
| } |
| if (b2_config & MDM_B2_DISABLE_V42) |
| { |
| dlc[i] |= DLC_MODEMPROT_DISABLE_V42_DETECT; |
| } |
| if (b2_config & MDM_B2_DISABLE_COMP) |
| { |
| dlc[i] |= DLC_MODEMPROT_DISABLE_COMPRESSION; |
| } |
| i++; |
| } |
| } |
| else |
| { |
| dlc[i++] = 3; /* Addr A */ |
| dlc[i++] = 1; /* Addr B */ |
| dlc[i++] = 7; /* modulo mode */ |
| dlc[i++] = 7; /* window size */ |
| dlc[i++] = 0; /* XID len Lo */ |
| dlc[i++] = 0; /* XID len Hi */ |
| dlc[i++] = DLC_MODEMPROT_DISABLE_V42_V42BIS | |
| DLC_MODEMPROT_DISABLE_MNP_MNP5 | |
| DLC_MODEMPROT_DISABLE_V42_DETECT | |
| DLC_MODEMPROT_DISABLE_COMPRESSION; |
| } |
| dlc[0] = (byte)(i - 1); |
| /* HexDump ("DLC", sizeof(dlc), &dlc[0]); */ |
| add_p(plci, DLC, dlc); |
| return (0); |
| } |
| |
| |
| /*------------------------------------------------------------------*/ |
| /* send a request for the signaling entity */ |
| /*------------------------------------------------------------------*/ |
| |
| static void sig_req(PLCI *plci, byte req, byte Id) |
| { |
| if (!plci) return; |
| if (plci->adapter->adapter_disabled) return; |
| dbug(1, dprintf("sig_req(%x)", req)); |
| if (req == REMOVE) |
| plci->sig_remove_id = plci->Sig.Id; |
| if (plci->req_in == plci->req_in_start) { |
| plci->req_in += 2; |
| plci->RBuffer[plci->req_in++] = 0; |
| } |
| PUT_WORD(&plci->RBuffer[plci->req_in_start], plci->req_in-plci->req_in_start - 2); |
| plci->RBuffer[plci->req_in++] = Id; /* sig/nl flag */ |
| plci->RBuffer[plci->req_in++] = req; /* request */ |
| plci->RBuffer[plci->req_in++] = 0; /* channel */ |
| plci->req_in_start = plci->req_in; |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* send a request for the network layer entity */ |
| /*------------------------------------------------------------------*/ |
| |
| static void nl_req_ncci(PLCI *plci, byte req, byte ncci) |
| { |
| if (!plci) return; |
| if (plci->adapter->adapter_disabled) return; |
| dbug(1, dprintf("nl_req %02x %02x %02x", plci->Id, req, ncci)); |
| if (req == REMOVE) |
| { |
| plci->nl_remove_id = plci->NL.Id; |
| ncci_remove(plci, 0, (byte)(ncci != 0)); |
| ncci = 0; |
| } |
| if (plci->req_in == plci->req_in_start) { |
| plci->req_in += 2; |
| plci->RBuffer[plci->req_in++] = 0; |
| } |
| PUT_WORD(&plci->RBuffer[plci->req_in_start], plci->req_in-plci->req_in_start - 2); |
| plci->RBuffer[plci->req_in++] = 1; /* sig/nl flag */ |
| plci->RBuffer[plci->req_in++] = req; /* request */ |
| plci->RBuffer[plci->req_in++] = plci->adapter->ncci_ch[ncci]; /* channel */ |
| plci->req_in_start = plci->req_in; |
| } |
| |
| static void send_req(PLCI *plci) |
| { |
| ENTITY *e; |
| word l; |
| /* word i; */ |
| |
| if (!plci) return; |
| if (plci->adapter->adapter_disabled) return; |
| channel_xmit_xon(plci); |
| |
| /* if nothing to do, return */ |
| if (plci->req_in == plci->req_out) return; |
| dbug(1, dprintf("send_req(in=%d,out=%d)", plci->req_in, plci->req_out)); |
| |
| if (plci->nl_req || plci->sig_req) return; |
| |
| l = GET_WORD(&plci->RBuffer[plci->req_out]); |
| plci->req_out += 2; |
| plci->XData[0].P = &plci->RBuffer[plci->req_out]; |
| plci->req_out += l; |
| if (plci->RBuffer[plci->req_out] == 1) |
| { |
| e = &plci->NL; |
| plci->req_out++; |
| e->Req = plci->nl_req = plci->RBuffer[plci->req_out++]; |
| e->ReqCh = plci->RBuffer[plci->req_out++]; |
| if (!(e->Id & 0x1f)) |
| { |
| e->Id = NL_ID; |
| plci->RBuffer[plci->req_out - 4] = CAI; |
| plci->RBuffer[plci->req_out - 3] = 1; |
| plci->RBuffer[plci->req_out - 2] = (plci->Sig.Id == 0xff) ? 0 : plci->Sig.Id; |
| plci->RBuffer[plci->req_out - 1] = 0; |
| l += 3; |
| plci->nl_global_req = plci->nl_req; |
| } |
| dbug(1, dprintf("%x:NLREQ(%x:%x:%x)", plci->adapter->Id, e->Id, e->Req, e->ReqCh)); |
| } |
| else |
| { |
| e = &plci->Sig; |
| if (plci->RBuffer[plci->req_out]) |
| e->Id = plci->RBuffer[plci->req_out]; |
| plci->req_out++; |
| e->Req = plci->sig_req = plci->RBuffer[plci->req_out++]; |
| e->ReqCh = plci->RBuffer[plci->req_out++]; |
| if (!(e->Id & 0x1f)) |
| plci->sig_global_req = plci->sig_req; |
| dbug(1, dprintf("%x:SIGREQ(%x:%x:%x)", plci->adapter->Id, e->Id, e->Req, e->ReqCh)); |
| } |
| plci->XData[0].PLength = l; |
| e->X = plci->XData; |
| plci->adapter->request(e); |
| dbug(1, dprintf("send_ok")); |
| } |
| |
| static void send_data(PLCI *plci) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| DATA_B3_DESC *data; |
| NCCI *ncci_ptr; |
| word ncci; |
| |
| if (!plci->nl_req && plci->ncci_ring_list) |
| { |
| a = plci->adapter; |
| ncci = plci->ncci_ring_list; |
| do |
| { |
| ncci = a->ncci_next[ncci]; |
| ncci_ptr = &(a->ncci[ncci]); |
| if (!(a->ncci_ch[ncci] |
| && (a->ch_flow_control[a->ncci_ch[ncci]] & N_OK_FC_PENDING))) |
| { |
| if (ncci_ptr->data_pending) |
| { |
| if ((a->ncci_state[ncci] == CONNECTED) |
| || (a->ncci_state[ncci] == INC_ACT_PENDING) |
| || (plci->send_disc == ncci)) |
| { |
| data = &(ncci_ptr->DBuffer[ncci_ptr->data_out]); |
| if ((plci->B2_prot == B2_V120_ASYNC) |
| || (plci->B2_prot == B2_V120_ASYNC_V42BIS) |
| || (plci->B2_prot == B2_V120_BIT_TRANSPARENT)) |
| { |
| plci->NData[1].P = TransmitBufferGet(plci->appl, data->P); |
| plci->NData[1].PLength = data->Length; |
| if (data->Flags & 0x10) |
| plci->NData[0].P = v120_break_header; |
| else |
| plci->NData[0].P = v120_default_header; |
| plci->NData[0].PLength = 1; |
| plci->NL.XNum = 2; |
| plci->NL.Req = plci->nl_req = (byte)((data->Flags & 0x07) << 4 | N_DATA); |
| } |
| else |
| { |
| plci->NData[0].P = TransmitBufferGet(plci->appl, data->P); |
| plci->NData[0].PLength = data->Length; |
| if (data->Flags & 0x10) |
| plci->NL.Req = plci->nl_req = (byte)N_UDATA; |
| |
| else if ((plci->B3_prot == B3_RTP) && (data->Flags & 0x01)) |
| plci->NL.Req = plci->nl_req = (byte)N_BDATA; |
| |
| else |
| plci->NL.Req = plci->nl_req = (byte)((data->Flags & 0x07) << 4 | N_DATA); |
| } |
| plci->NL.X = plci->NData; |
| plci->NL.ReqCh = a->ncci_ch[ncci]; |
| dbug(1, dprintf("%x:DREQ(%x:%x)", a->Id, plci->NL.Id, plci->NL.Req)); |
| plci->data_sent = true; |
| plci->data_sent_ptr = data->P; |
| a->request(&plci->NL); |
| } |
| else { |
| cleanup_ncci_data(plci, ncci); |
| } |
| } |
| else if (plci->send_disc == ncci) |
| { |
| /* dprintf("N_DISC"); */ |
| plci->NData[0].PLength = 0; |
| plci->NL.ReqCh = a->ncci_ch[ncci]; |
| plci->NL.Req = plci->nl_req = N_DISC; |
| a->request(&plci->NL); |
| plci->command = _DISCONNECT_B3_R; |
| plci->send_disc = 0; |
| } |
| } |
| } while (!plci->nl_req && (ncci != plci->ncci_ring_list)); |
| plci->ncci_ring_list = ncci; |
| } |
| } |
| |
| static void listen_check(DIVA_CAPI_ADAPTER *a) |
| { |
| word i, j; |
| PLCI *plci; |
| byte activnotifiedcalls = 0; |
| |
| dbug(1, dprintf("listen_check(%d,%d)", a->listen_active, a->max_listen)); |
| if (!remove_started && !a->adapter_disabled) |
| { |
| for (i = 0; i < a->max_plci; i++) |
| { |
| plci = &(a->plci[i]); |
| if (plci->notifiedcall) activnotifiedcalls++; |
| } |
| dbug(1, dprintf("listen_check(%d)", activnotifiedcalls)); |
| |
| for (i = a->listen_active; i < ((word)(a->max_listen + activnotifiedcalls)); i++) { |
| if ((j = get_plci(a))) { |
| a->listen_active++; |
| plci = &a->plci[j - 1]; |
| plci->State = LISTENING; |
| |
| add_p(plci, OAD, "\x01\xfd"); |
| |
| add_p(plci, KEY, "\x04\x43\x41\x32\x30"); |
| |
| add_p(plci, CAI, "\x01\xc0"); |
| add_p(plci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| add_p(plci, LLI, "\x01\xc4"); /* support Dummy CR FAC + MWI + SpoofNotify */ |
| add_p(plci, SHIFT | 6, NULL); |
| add_p(plci, SIN, "\x02\x00\x00"); |
| plci->internal_command = LISTEN_SIG_ASSIGN_PEND; /* do indicate_req if OK */ |
| sig_req(plci, ASSIGN, DSIG_ID); |
| send_req(plci); |
| } |
| } |
| } |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* functions for all parameters sent in INDs */ |
| /*------------------------------------------------------------------*/ |
| |
| static void IndParse(PLCI *plci, word *parms_id, byte **parms, byte multiIEsize) |
| { |
| word ploc; /* points to current location within packet */ |
| byte w; |
| byte wlen; |
| byte codeset, lock; |
| byte *in; |
| word i; |
| word code; |
| word mIEindex = 0; |
| ploc = 0; |
| codeset = 0; |
| lock = 0; |
| |
| in = plci->Sig.RBuffer->P; |
| for (i = 0; i < parms_id[0]; i++) /* multiIE parms_id contains just the 1st */ |
| { /* element but parms array is larger */ |
| parms[i] = (byte *)""; |
| } |
| for (i = 0; i < multiIEsize; i++) |
| { |
| parms[i] = (byte *)""; |
| } |
| |
| while (ploc < plci->Sig.RBuffer->length - 1) { |
| |
| /* read information element id and length */ |
| w = in[ploc]; |
| |
| if (w & 0x80) { |
| /* w &=0xf0; removed, cannot detect congestion levels */ |
| /* upper 4 bit masked with w==SHIFT now */ |
| wlen = 0; |
| } |
| else { |
| wlen = (byte)(in[ploc + 1] + 1); |
| } |
| /* check if length valid (not exceeding end of packet) */ |
| if ((ploc + wlen) > 270) return; |
| if (lock & 0x80) lock &= 0x7f; |
| else codeset = lock; |
| |
| if ((w & 0xf0) == SHIFT) { |
| codeset = in[ploc]; |
| if (!(codeset & 0x08)) lock = (byte)(codeset & 7); |
| codeset &= 7; |
| lock |= 0x80; |
| } |
| else { |
| if (w == ESC && wlen >= 3) code = in[ploc + 2] | 0x800; |
| else code = w; |
| code |= (codeset << 8); |
| |
| for (i = 1; i < parms_id[0] + 1 && parms_id[i] != code; i++); |
| |
| if (i < parms_id[0] + 1) { |
| if (!multiIEsize) { /* with multiIEs use next field index, */ |
| mIEindex = i - 1; /* with normal IEs use same index like parms_id */ |
| } |
| |
| parms[mIEindex] = &in[ploc + 1]; |
| dbug(1, dprintf("mIE[%d]=0x%x", *parms[mIEindex], in[ploc])); |
| if (parms_id[i] == OAD |
| || parms_id[i] == CONN_NR |
| || parms_id[i] == CAD) { |
| if (in[ploc + 2] & 0x80) { |
| in[ploc + 0] = (byte)(in[ploc + 1] + 1); |
| in[ploc + 1] = (byte)(in[ploc + 2] & 0x7f); |
| in[ploc + 2] = 0x80; |
| parms[mIEindex] = &in[ploc]; |
| } |
| } |
| mIEindex++; /* effects multiIEs only */ |
| } |
| } |
| |
| ploc += (wlen + 1); |
| } |
| return; |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* try to match a cip from received BC and HLC */ |
| /*------------------------------------------------------------------*/ |
| |
| static byte ie_compare(byte *ie1, byte *ie2) |
| { |
| word i; |
| if (!ie1 || !ie2) return false; |
| if (!ie1[0]) return false; |
| for (i = 0; i < (word)(ie1[0] + 1); i++) if (ie1[i] != ie2[i]) return false; |
| return true; |
| } |
| |
| static word find_cip(DIVA_CAPI_ADAPTER *a, byte *bc, byte *hlc) |
| { |
| word i; |
| word j; |
| |
| for (i = 9; i && !ie_compare(bc, cip_bc[i][a->u_law]); i--); |
| |
| for (j = 16; j < 29 && |
| (!ie_compare(bc, cip_bc[j][a->u_law]) || !ie_compare(hlc, cip_hlc[j])); j++); |
| if (j == 29) return i; |
| return j; |
| } |
| |
| |
| static byte AddInfo(byte **add_i, |
| byte **fty_i, |
| byte *esc_chi, |
| byte *facility) |
| { |
| byte i; |
| byte j; |
| byte k; |
| byte flen; |
| byte len = 0; |
| /* facility is a nested structure */ |
| /* FTY can be more than once */ |
| |
| if (esc_chi[0] && !(esc_chi[esc_chi[0]] & 0x7f)) |
| { |
| add_i[0] = (byte *)"\x02\x02\x00"; /* use neither b nor d channel */ |
| } |
| |
| else |
| { |
| add_i[0] = (byte *)""; |
| } |
| if (!fty_i[0][0]) |
| { |
| add_i[3] = (byte *)""; |
| } |
| else |
| { /* facility array found */ |
| for (i = 0, j = 1; i < MAX_MULTI_IE && fty_i[i][0]; i++) |
| { |
| dbug(1, dprintf("AddIFac[%d]", fty_i[i][0])); |
| len += fty_i[i][0]; |
| len += 2; |
| flen = fty_i[i][0]; |
| facility[j++] = 0x1c; /* copy fac IE */ |
| for (k = 0; k <= flen; k++, j++) |
| { |
| facility[j] = fty_i[i][k]; |
| /* dbug(1, dprintf("%x ",facility[j])); */ |
| } |
| } |
| facility[0] = len; |
| add_i[3] = facility; |
| } |
| /* dbug(1, dprintf("FacArrLen=%d ",len)); */ |
| len = add_i[0][0] + add_i[1][0] + add_i[2][0] + add_i[3][0]; |
| len += 4; /* calculate length of all */ |
| return (len); |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* voice and codec features */ |
| /*------------------------------------------------------------------*/ |
| |
| static void SetVoiceChannel(PLCI *plci, byte *chi, DIVA_CAPI_ADAPTER *a) |
| { |
| byte voice_chi[] = "\x02\x18\x01"; |
| byte channel; |
| |
| channel = chi[chi[0]] & 0x3; |
| dbug(1, dprintf("ExtDevON(Ch=0x%x)", channel)); |
| voice_chi[2] = (channel) ? channel : 1; |
| add_p(plci, FTY, "\x02\x01\x07"); /* B On, default on 1 */ |
| add_p(plci, ESC, voice_chi); /* Channel */ |
| sig_req(plci, TEL_CTRL, 0); |
| send_req(plci); |
| if (a->AdvSignalPLCI) |
| { |
| adv_voice_write_coefs(a->AdvSignalPLCI, ADV_VOICE_WRITE_ACTIVATION); |
| } |
| } |
| |
| static void VoiceChannelOff(PLCI *plci) |
| { |
| dbug(1, dprintf("ExtDevOFF")); |
| add_p(plci, FTY, "\x02\x01\x08"); /* B Off */ |
| sig_req(plci, TEL_CTRL, 0); |
| send_req(plci); |
| if (plci->adapter->AdvSignalPLCI) |
| { |
| adv_voice_clear_config(plci->adapter->AdvSignalPLCI); |
| } |
| } |
| |
| |
| static word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, |
| byte hook_listen) |
| { |
| word j; |
| PLCI *splci; |
| |
| /* check if hardware supports handset with hook states (adv.codec) */ |
| /* or if just a on board codec is supported */ |
| /* the advanced codec plci is just for internal use */ |
| |
| /* diva Pro with on-board codec: */ |
| if (a->profile.Global_Options & HANDSET) |
| { |
| /* new call, but hook states are already signalled */ |
| if (a->AdvCodecFLAG) |
| { |
| if (a->AdvSignalAppl != appl || a->AdvSignalPLCI) |
| { |
| dbug(1, dprintf("AdvSigPlci=0x%x", a->AdvSignalPLCI)); |
| return 0x2001; /* codec in use by another application */ |
| } |
| if (plci != NULL) |
| { |
| a->AdvSignalPLCI = plci; |
| plci->tel = ADV_VOICE; |
| } |
| return 0; /* adv codec still used */ |
| } |
| if ((j = get_plci(a))) |
| { |
| splci = &a->plci[j - 1]; |
| splci->tel = CODEC_PERMANENT; |
| /* hook_listen indicates if a facility_req with handset/hook support */ |
| /* was sent. Otherwise if just a call on an external device was made */ |
| /* the codec will be used but the hook info will be discarded (just */ |
| /* the external controller is in use */ |
| if (hook_listen) splci->State = ADVANCED_VOICE_SIG; |
| else |
| { |
| splci->State = ADVANCED_VOICE_NOSIG; |
| if (plci) |
| { |
| plci->spoofed_msg = SPOOFING_REQUIRED; |
| } |
| /* indicate D-ch connect if */ |
| } /* codec is connected OK */ |
| if (plci != NULL) |
| { |
| a->AdvSignalPLCI = plci; |
| plci->tel = ADV_VOICE; |
| } |
| a->AdvSignalAppl = appl; |
| a->AdvCodecFLAG = true; |
| a->AdvCodecPLCI = splci; |
| add_p(splci, CAI, "\x01\x15"); |
| add_p(splci, LLI, "\x01\x00"); |
| add_p(splci, ESC, "\x02\x18\x00"); |
| add_p(splci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| splci->internal_command = PERM_COD_ASSIGN; |
| dbug(1, dprintf("Codec Assign")); |
| sig_req(splci, ASSIGN, DSIG_ID); |
| send_req(splci); |
| } |
| else |
| { |
| return 0x2001; /* wrong state, no more plcis */ |
| } |
| } |
| else if (a->profile.Global_Options & ON_BOARD_CODEC) |
| { |
| if (hook_listen) return 0x300B; /* Facility not supported */ |
| /* no hook with SCOM */ |
| if (plci != NULL) plci->tel = CODEC; |
| dbug(1, dprintf("S/SCOM codec")); |
| /* first time we use the scom-s codec we must shut down the internal */ |
| /* handset application of the card. This can be done by an assign with */ |
| /* a cai with the 0x80 bit set. Assign return code is 'out of resource'*/ |
| if (!a->scom_appl_disable) { |
| if ((j = get_plci(a))) { |
| splci = &a->plci[j - 1]; |
| add_p(splci, CAI, "\x01\x80"); |
| add_p(splci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| sig_req(splci, ASSIGN, 0xC0); /* 0xc0 is the TEL_ID */ |
| send_req(splci); |
| a->scom_appl_disable = true; |
| } |
| else{ |
| return 0x2001; /* wrong state, no more plcis */ |
| } |
| } |
| } |
| else return 0x300B; /* Facility not supported */ |
| |
| return 0; |
| } |
| |
| |
| static void CodecIdCheck(DIVA_CAPI_ADAPTER *a, PLCI *plci) |
| { |
| |
| dbug(1, dprintf("CodecIdCheck")); |
| |
| if (a->AdvSignalPLCI == plci) |
| { |
| dbug(1, dprintf("PLCI owns codec")); |
| VoiceChannelOff(a->AdvCodecPLCI); |
| if (a->AdvCodecPLCI->State == ADVANCED_VOICE_NOSIG) |
| { |
| dbug(1, dprintf("remove temp codec PLCI")); |
| plci_remove(a->AdvCodecPLCI); |
| a->AdvCodecFLAG = 0; |
| a->AdvCodecPLCI = NULL; |
| a->AdvSignalAppl = NULL; |
| } |
| a->AdvSignalPLCI = NULL; |
| } |
| } |
| |
| /* ------------------------------------------------------------------- |
| Ask for physical address of card on PCI bus |
| ------------------------------------------------------------------- */ |
| static void diva_ask_for_xdi_sdram_bar(DIVA_CAPI_ADAPTER *a, |
| IDI_SYNC_REQ *preq) { |
| a->sdram_bar = 0; |
| if (diva_xdi_extended_features & DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR) { |
| ENTITY *e = (ENTITY *)preq; |
| |
| e->user[0] = a->Id - 1; |
| preq->xdi_sdram_bar.info.bar = 0; |
| preq->xdi_sdram_bar.Req = 0; |
| preq->xdi_sdram_bar.Rc = IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR; |
| |
| (*(a->request))(e); |
| |
| a->sdram_bar = preq->xdi_sdram_bar.info.bar; |
| dbug(3, dprintf("A(%d) SDRAM BAR = %08x", a->Id, a->sdram_bar)); |
| } |
| } |
| |
| /* ------------------------------------------------------------------- |
| Ask XDI about extended features |
| ------------------------------------------------------------------- */ |
| static void diva_get_extended_adapter_features(DIVA_CAPI_ADAPTER *a) { |
| IDI_SYNC_REQ *preq; |
| char buffer[((sizeof(preq->xdi_extended_features) + 4) > sizeof(ENTITY)) ? (sizeof(preq->xdi_extended_features) + 4) : sizeof(ENTITY)]; |
| |
| char features[4]; |
| preq = (IDI_SYNC_REQ *)&buffer[0]; |
| |
| if (!diva_xdi_extended_features) { |
| ENTITY *e = (ENTITY *)preq; |
| diva_xdi_extended_features |= 0x80000000; |
| |
| e->user[0] = a->Id - 1; |
| preq->xdi_extended_features.Req = 0; |
| preq->xdi_extended_features.Rc = IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES; |
| preq->xdi_extended_features.info.buffer_length_in_bytes = sizeof(features); |
| preq->xdi_extended_features.info.features = &features[0]; |
| |
| (*(a->request))(e); |
| |
| if (features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) { |
| /* |
| Check features located in the byte '0' |
| */ |
| if (features[0] & DIVA_XDI_EXTENDED_FEATURE_CMA) { |
| diva_xdi_extended_features |= DIVA_CAPI_USE_CMA; |
| } |
| if (features[0] & DIVA_XDI_EXTENDED_FEATURE_RX_DMA) { |
| diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_RX_DMA; |
| dbug(1, dprintf("XDI provides RxDMA")); |
| } |
| if (features[0] & DIVA_XDI_EXTENDED_FEATURE_SDRAM_BAR) { |
| diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR; |
| } |
| if (features[0] & DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC) { |
| diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_NO_CANCEL; |
| dbug(3, dprintf("XDI provides NO_CANCEL_RC feature")); |
| } |
| |
| } |
| } |
| |
| diva_ask_for_xdi_sdram_bar(a, preq); |
| } |
| |
| /*------------------------------------------------------------------*/ |
| /* automatic law */ |
| /*------------------------------------------------------------------*/ |
| /* called from OS specific part after init time to get the Law */ |
| /* a-law (Euro) and u-law (us,japan) use different BCs in the Setup message */ |
| void AutomaticLaw(DIVA_CAPI_ADAPTER *a) |
| { |
| word j; |
| PLCI *splci; |
| |
| if (a->automatic_law) { |
| return; |
| } |
| if ((j = get_plci(a))) { |
| diva_get_extended_adapter_features(a); |
| splci = &a->plci[j - 1]; |
| a->automatic_lawPLCI = splci; |
| a->automatic_law = 1; |
| add_p(splci, CAI, "\x01\x80"); |
| add_p(splci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| splci->internal_command = USELAW_REQ; |
| splci->command = 0; |
| splci->number = 0; |
| sig_req(splci, ASSIGN, DSIG_ID); |
| send_req(splci); |
| } |
| } |
| |
| /* called from OS specific part if an application sends an Capi20Release */ |
| word CapiRelease(word Id) |
| { |
| word i, j, appls_found; |
| PLCI *plci; |
| APPL *this; |
| DIVA_CAPI_ADAPTER *a; |
| |
| if (!Id) |
| { |
| dbug(0, dprintf("A: CapiRelease(Id==0)")); |
| return (_WRONG_APPL_ID); |
| } |
| |
| this = &application[Id - 1]; /* get application pointer */ |
| |
| for (i = 0, appls_found = 0; i < max_appl; i++) |
| { |
| if (application[i].Id) /* an application has been found */ |
| { |
| appls_found++; |
| } |
| } |
| |
| for (i = 0; i < max_adapter; i++) /* scan all adapters... */ |
| { |
| a = &adapter[i]; |
| if (a->request) |
| { |
| a->Info_Mask[Id - 1] = 0; |
| a->CIP_Mask[Id - 1] = 0; |
| a->Notification_Mask[Id - 1] = 0; |
| a->codec_listen[Id - 1] = NULL; |
| a->requested_options_table[Id - 1] = 0; |
| for (j = 0; j < a->max_plci; j++) /* and all PLCIs connected */ |
| { /* with this application */ |
| plci = &a->plci[j]; |
| if (plci->Id) /* if plci owns no application */ |
| { /* it may be not jet connected */ |
| if (plci->State == INC_CON_PENDING |
| || plci->State == INC_CON_ALERT) |
| { |
| if (test_c_ind_mask_bit(plci, (word)(Id - 1))) |
| { |
| clear_c_ind_mask_bit(plci, (word)(Id - 1)); |
| if (c_ind_mask_empty(plci)) |
| { |
| sig_req(plci, HANGUP, 0); |
| send_req(plci); |
| plci->State = OUTG_DIS_PENDING; |
| } |
| } |
| } |
| if (test_c_ind_mask_bit(plci, (word)(Id - 1))) |
| { |
| clear_c_ind_mask_bit(plci, (word)(Id - 1)); |
| if (c_ind_mask_empty(plci)) |
| { |
| if (!plci->appl) |
| { |
| plci_remove(plci); |
| plci->State = IDLE; |
| } |
| } |
| } |
| if (plci->appl == this) |
| { |
| plci->appl = NULL; |
| plci_remove(plci); |
| plci->State = IDLE; |
| } |
| } |
| } |
| listen_check(a); |
| |
| if (a->flag_dynamic_l1_down) |
| { |
| if (appls_found == 1) /* last application does a capi release */ |
| { |
| if ((j = get_plci(a))) |
| { |
| plci = &a->plci[j - 1]; |
| plci->command = 0; |
| add_p(plci, OAD, "\x01\xfd"); |
| add_p(plci, CAI, "\x01\x80"); |
| add_p(plci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| add_p(plci, SHIFT | 6, NULL); |
| add_p(plci, SIN, "\x02\x00\x00"); |
| plci->internal_command = REM_L1_SIG_ASSIGN_PEND; |
| sig_req(plci, ASSIGN, DSIG_ID); |
| add_p(plci, FTY, "\x02\xff\x06"); /* l1 down */ |
| sig_req(plci, SIG_CTRL, 0); |
| send_req(plci); |
| } |
| } |
| } |
| if (a->AdvSignalAppl == this) |
| { |
| this->NullCREnable = false; |
| if (a->AdvCodecPLCI) |
| { |
| plci_remove(a->AdvCodecPLCI); |
| a->AdvCodecPLCI->tel = 0; |
| a->AdvCodecPLCI->adv_nl = 0; |
| } |
| a->AdvSignalAppl = NULL; |
| a->AdvSignalPLCI = NULL; |
| a->AdvCodecFLAG = 0; |
| a->AdvCodecPLCI = NULL; |
| } |
| } |
| } |
| |
| this->Id = 0; |
| |
| return GOOD; |
| } |
| |
| static word plci_remove_check(PLCI *plci) |
| { |
| if (!plci) return true; |
| if (!plci->NL.Id && c_ind_mask_empty(plci)) |
| { |
| if (plci->Sig.Id == 0xff) |
| plci->Sig.Id = 0; |
| if (!plci->Sig.Id) |
| { |
| dbug(1, dprintf("plci_remove_complete(%x)", plci->Id)); |
| dbug(1, dprintf("tel=0x%x,Sig=0x%x", plci->tel, plci->Sig.Id)); |
| if (plci->Id) |
| { |
| CodecIdCheck(plci->adapter, plci); |
| clear_b1_config(plci); |
| ncci_remove(plci, 0, false); |
| plci_free_msg_in_queue(plci); |
| channel_flow_control_remove(plci); |
| plci->Id = 0; |
| plci->State = IDLE; |
| plci->channels = 0; |
| plci->appl = NULL; |
| plci->notifiedcall = 0; |
| } |
| listen_check(plci->adapter); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| /*------------------------------------------------------------------*/ |
| |
| static byte plci_nl_busy(PLCI *plci) |
| { |
| /* only applicable for non-multiplexed protocols */ |
| return (plci->nl_req |
| || (plci->ncci_ring_list |
| && plci->adapter->ncci_ch[plci->ncci_ring_list] |
| && (plci->adapter->ch_flow_control[plci->adapter->ncci_ch[plci->ncci_ring_list]] & N_OK_FC_PENDING))); |
| } |
| |
| |
| /*------------------------------------------------------------------*/ |
| /* DTMF facilities */ |
| /*------------------------------------------------------------------*/ |
| |
| |
| static struct |
| { |
| byte send_mask; |
| byte listen_mask; |
| byte character; |
| byte code; |
| } dtmf_digit_map[] = |
| { |
| { 0x01, 0x01, 0x23, DTMF_DIGIT_TONE_CODE_HASHMARK }, |
| { 0x01, 0x01, 0x2a, DTMF_DIGIT_TONE_CODE_STAR }, |
| { 0x01, 0x01, 0x30, DTMF_DIGIT_TONE_CODE_0 }, |
| { 0x01, 0x01, 0x31, DTMF_DIGIT_TONE_CODE_1 }, |
| { 0x01, 0x01, 0x32, DTMF_DIGIT_TONE_CODE_2 }, |
| { 0x01, 0x01, 0x33, DTMF_DIGIT_TONE_CODE_3 }, |
| { 0x01, 0x01, 0x34, DTMF_DIGIT_TONE_CODE_4 }, |
| { 0x01, 0x01, 0x35, DTMF_DIGIT_TONE_CODE_5 }, |
| { 0x01, 0x01, 0x36, DTMF_DIGIT_TONE_CODE_6 }, |
| { 0x01, 0x01, 0x37, DTMF_DIGIT_TONE_CODE_7 }, |
| { 0x01, 0x01, 0x38, DTMF_DIGIT_TONE_CODE_8 }, |
| { 0x01, 0x01, 0x39, DTMF_DIGIT_TONE_CODE_9 }, |
| { 0x01, 0x01, 0x41, DTMF_DIGIT_TONE_CODE_A }, |
| { 0x01, 0x01, 0x42, DTMF_DIGIT_TONE_CODE_B }, |
| { 0x01, 0x01, 0x43, DTMF_DIGIT_TONE_CODE_C }, |
| { 0x01, 0x01, 0x44, DTMF_DIGIT_TONE_CODE_D }, |
| { 0x01, 0x00, 0x61, DTMF_DIGIT_TONE_CODE_A }, |
| { 0x01, 0x00, 0x62, DTMF_DIGIT_TONE_CODE_B }, |
| { 0x01, 0x00, 0x63, DTMF_DIGIT_TONE_CODE_C }, |
| { 0x01, 0x00, 0x64, DTMF_DIGIT_TONE_CODE_D }, |
| |
| { 0x04, 0x04, 0x80, DTMF_SIGNAL_NO_TONE }, |
| { 0x00, 0x04, 0x81, DTMF_SIGNAL_UNIDENTIFIED_TONE }, |
| { 0x04, 0x04, 0x82, DTMF_SIGNAL_DIAL_TONE }, |
| { 0x04, 0x04, 0x83, DTMF_SIGNAL_PABX_INTERNAL_DIAL_TONE }, |
| { 0x04, 0x04, 0x84, DTMF_SIGNAL_SPECIAL_DIAL_TONE }, |
| { 0x04, 0x04, 0x85, DTMF_SIGNAL_SECOND_DIAL_TONE }, |
| { 0x04, 0x04, 0x86, DTMF_SIGNAL_RINGING_TONE }, |
| { 0x04, 0x04, 0x87, DTMF_SIGNAL_SPECIAL_RINGING_TONE }, |
| { 0x04, 0x04, 0x88, DTMF_SIGNAL_BUSY_TONE }, |
| { 0x04, 0x04, 0x89, DTMF_SIGNAL_CONGESTION_TONE }, |
| { 0x04, 0x04, 0x8a, DTMF_SIGNAL_SPECIAL_INFORMATION_TONE }, |
| { 0x04, 0x04, 0x8b, DTMF_SIGNAL_COMFORT_TONE }, |
| { 0x04, 0x04, 0x8c, DTMF_SIGNAL_HOLD_TONE }, |
| { 0x04, 0x04, 0x8d, DTMF_SIGNAL_RECORD_TONE }, |
| { 0x04, 0x04, 0x8e, DTMF_SIGNAL_CALLER_WAITING_TONE }, |
| { 0x04, 0x04, 0x8f, DTMF_SIGNAL_CALL_WAITING_TONE }, |
| { 0x04, 0x04, 0x90, DTMF_SIGNAL_PAY_TONE }, |
| { 0x04, 0x04, 0x91, DTMF_SIGNAL_POSITIVE_INDICATION_TONE }, |
| { 0x04, 0x04, 0x92, DTMF_SIGNAL_NEGATIVE_INDICATION_TONE }, |
| { 0x04, 0x04, 0x93, DTMF_SIGNAL_WARNING_TONE }, |
| { 0x04, 0x04, 0x94, DTMF_SIGNAL_INTRUSION_TONE }, |
| { 0x04, 0x04, 0x95, DTMF_SIGNAL_CALLING_CARD_SERVICE_TONE }, |
| { 0x04, 0x04, 0x96, DTMF_SIGNAL_PAYPHONE_RECOGNITION_TONE }, |
| { 0x04, 0x04, 0x97, DTMF_SIGNAL_CPE_ALERTING_SIGNAL }, |
| { 0x04, 0x04, 0x98, DTMF_SIGNAL_OFF_HOOK_WARNING_TONE }, |
| { 0x04, 0x04, 0xbf, DTMF_SIGNAL_INTERCEPT_TONE }, |
| { 0x04, 0x04, 0xc0, DTMF_SIGNAL_MODEM_CALLING_TONE }, |
| { 0x04, 0x04, 0xc1, DTMF_SIGNAL_FAX_CALLING_TONE }, |
| { 0x04, 0x04, 0xc2, DTMF_SIGNAL_ANSWER_TONE }, |
| { 0x04, 0x04, 0xc3, DTMF_SIGNAL_REVERSED_ANSWER_TONE }, |
| { 0x04, 0x04, 0xc4, DTMF_SIGNAL_ANSAM_TONE }, |
| { 0x04, 0x04, 0xc5, DTMF_SIGNAL_REVERSED_ANSAM_TONE }, |
| { 0x04, 0x04, 0xc6, DTMF_SIGNAL_BELL103_ANSWER_TONE }, |
| { 0x04, 0x04, 0xc7, DTMF_SIGNAL_FAX_FLAGS }, |
| { 0x04, 0x04, 0xc8, DTMF_SIGNAL_G2_FAX_GROUP_ID }, |
| { 0x00, 0x04, 0xc9, DTMF_SIGNAL_HUMAN_SPEECH }, |
| { 0x04, 0x04, 0xca, DTMF_SIGNAL_ANSWERING_MACHINE_390 }, |
| { 0x02, 0x02, 0xf1, DTMF_MF_DIGIT_TONE_CODE_1 }, |
| { 0x02, 0x02, 0xf2, DTMF_MF_DIGIT_TONE_CODE_2 }, |
| { 0x02, 0x02, 0xf3, DTMF_MF_DIGIT_TONE_CODE_3 }, |
| { 0x02, 0x02, 0xf4, DTMF_MF_DIGIT_TONE_CODE_4 }, |
| { 0x02, 0x02, 0xf5, DTMF_MF_DIGIT_TONE_CODE_5 }, |
| { 0x02, 0x02, 0xf6, DTMF_MF_DIGIT_TONE_CODE_6 }, |
| { 0x02, 0x02, 0xf7, DTMF_MF_DIGIT_TONE_CODE_7 }, |
| { 0x02, 0x02, 0xf8, DTMF_MF_DIGIT_TONE_CODE_8 }, |
| { 0x02, 0x02, 0xf9, DTMF_MF_DIGIT_TONE_CODE_9 }, |
| { 0x02, 0x02, 0xfa, DTMF_MF_DIGIT_TONE_CODE_0 }, |
| { 0x02, 0x02, 0xfb, DTMF_MF_DIGIT_TONE_CODE_K1 }, |
| { 0x02, 0x02, 0xfc, DTMF_MF_DIGIT_TONE_CODE_K2 }, |
| { 0x02, 0x02, 0xfd, DTMF_MF_DIGIT_TONE_CODE_KP }, |
| { 0x02, 0x02, 0xfe, DTMF_MF_DIGIT_TONE_CODE_S1 }, |
| { 0x02, 0x02, 0xff, DTMF_MF_DIGIT_TONE_CODE_ST }, |
| |
| }; |
| |
| #define DTMF_DIGIT_MAP_ENTRIES ARRAY_SIZE(dtmf_digit_map) |
| |
| |
| static void dtmf_enable_receiver(PLCI *plci, byte enable_mask) |
| { |
| word min_digit_duration, min_gap_duration; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_enable_receiver %02x", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__, enable_mask)); |
| |
| if (enable_mask != 0) |
| { |
| min_digit_duration = (plci->dtmf_rec_pulse_ms == 0) ? 40 : plci->dtmf_rec_pulse_ms; |
| min_gap_duration = (plci->dtmf_rec_pause_ms == 0) ? 40 : plci->dtmf_rec_pause_ms; |
| plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_ENABLE_RECEIVER; |
| PUT_WORD(&plci->internal_req_buffer[1], min_digit_duration); |
| PUT_WORD(&plci->internal_req_buffer[3], min_gap_duration); |
| plci->NData[0].PLength = 5; |
| |
| PUT_WORD(&plci->internal_req_buffer[5], INTERNAL_IND_BUFFER_SIZE); |
| plci->NData[0].PLength += 2; |
| capidtmf_recv_enable(&(plci->capidtmf_state), min_digit_duration, min_gap_duration); |
| |
| } |
| else |
| { |
| plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_DISABLE_RECEIVER; |
| plci->NData[0].PLength = 1; |
| |
| capidtmf_recv_disable(&(plci->capidtmf_state)); |
| |
| } |
| plci->NData[0].P = plci->internal_req_buffer; |
| plci->NL.X = plci->NData; |
| plci->NL.ReqCh = 0; |
| plci->NL.Req = plci->nl_req = (byte) N_UDATA; |
| plci->adapter->request(&plci->NL); |
| } |
| |
| |
| static void dtmf_send_digits(PLCI *plci, byte *digit_buffer, word digit_count) |
| { |
| word w, i; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_send_digits %d", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__, digit_count)); |
| |
| plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_SEND_DIGITS; |
| w = (plci->dtmf_send_pulse_ms == 0) ? 40 : plci->dtmf_send_pulse_ms; |
| PUT_WORD(&plci->internal_req_buffer[1], w); |
| w = (plci->dtmf_send_pause_ms == 0) ? 40 : plci->dtmf_send_pause_ms; |
| PUT_WORD(&plci->internal_req_buffer[3], w); |
| for (i = 0; i < digit_count; i++) |
| { |
| w = 0; |
| while ((w < DTMF_DIGIT_MAP_ENTRIES) |
| && (digit_buffer[i] != dtmf_digit_map[w].character)) |
| { |
| w++; |
| } |
| plci->internal_req_buffer[5 + i] = (w < DTMF_DIGIT_MAP_ENTRIES) ? |
| dtmf_digit_map[w].code : DTMF_DIGIT_TONE_CODE_STAR; |
| } |
| plci->NData[0].PLength = 5 + digit_count; |
| plci->NData[0].P = plci->internal_req_buffer; |
| plci->NL.X = plci->NData; |
| plci->NL.ReqCh = 0; |
| plci->NL.Req = plci->nl_req = (byte) N_UDATA; |
| plci->adapter->request(&plci->NL); |
| } |
| |
| |
| static void dtmf_rec_clear_config(PLCI *plci) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_rec_clear_config", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| |
| plci->dtmf_rec_active = 0; |
| plci->dtmf_rec_pulse_ms = 0; |
| plci->dtmf_rec_pause_ms = 0; |
| |
| capidtmf_init(&(plci->capidtmf_state), plci->adapter->u_law); |
| |
| } |
| |
| |
| static void dtmf_send_clear_config(PLCI *plci) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_send_clear_config", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| |
| plci->dtmf_send_requests = 0; |
| plci->dtmf_send_pulse_ms = 0; |
| plci->dtmf_send_pause_ms = 0; |
| } |
| |
| |
| static void dtmf_prepare_switch(dword Id, PLCI *plci) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_prepare_switch", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| |
| while (plci->dtmf_send_requests != 0) |
| dtmf_confirmation(Id, plci); |
| } |
| |
| |
| static word dtmf_save_config(dword Id, PLCI *plci, byte Rc) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_save_config %02x %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state)); |
| |
| return (GOOD); |
| } |
| |
| |
| static word dtmf_restore_config(dword Id, PLCI *plci, byte Rc) |
| { |
| word Info; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_restore_config %02x %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state)); |
| |
| Info = GOOD; |
| if (plci->B1_facilities & B1_FACILITY_DTMFR) |
| { |
| switch (plci->adjust_b_state) |
| { |
| case ADJUST_B_RESTORE_DTMF_1: |
| plci->internal_command = plci->adjust_b_command; |
| if (plci_nl_busy(plci)) |
| { |
| plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1; |
| break; |
| } |
| dtmf_enable_receiver(plci, plci->dtmf_rec_active); |
| plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_2; |
| break; |
| case ADJUST_B_RESTORE_DTMF_2: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Reenable DTMF receiver failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| Info = _WRONG_STATE; |
| break; |
| } |
| break; |
| } |
| } |
| return (Info); |
| } |
| |
| |
| static void dtmf_command(dword Id, PLCI *plci, byte Rc) |
| { |
| word internal_command, Info; |
| byte mask; |
| byte result[4]; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_command %02x %04x %04x %d %d %d %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command, |
| plci->dtmf_cmd, plci->dtmf_rec_pulse_ms, plci->dtmf_rec_pause_ms, |
| plci->dtmf_send_pulse_ms, plci->dtmf_send_pause_ms)); |
| |
| Info = GOOD; |
| result[0] = 2; |
| PUT_WORD(&result[1], DTMF_SUCCESS); |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| mask = 0x01; |
| switch (plci->dtmf_cmd) |
| { |
| |
| case DTMF_LISTEN_TONE_START: |
| mask <<= 1; |
| case DTMF_LISTEN_MF_START: |
| mask <<= 1; |
| |
| case DTMF_LISTEN_START: |
| switch (internal_command) |
| { |
| default: |
| adjust_b1_resource(Id, plci, NULL, (word)(plci->B1_facilities | |
| B1_FACILITY_DTMFR), DTMF_COMMAND_1); |
| case DTMF_COMMAND_1: |
| if (adjust_b_process(Id, plci, Rc) != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Load DTMF failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } |
| if (plci->internal_command) |
| return; |
| case DTMF_COMMAND_2: |
| if (plci_nl_busy(plci)) |
| { |
| plci->internal_command = DTMF_COMMAND_2; |
| return; |
| } |
| plci->internal_command = DTMF_COMMAND_3; |
| dtmf_enable_receiver(plci, (byte)(plci->dtmf_rec_active | mask)); |
| return; |
| case DTMF_COMMAND_3: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Enable DTMF receiver failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } |
| |
| plci->tone_last_indication_code = DTMF_SIGNAL_NO_TONE; |
| |
| plci->dtmf_rec_active |= mask; |
| break; |
| } |
| break; |
| |
| |
| case DTMF_LISTEN_TONE_STOP: |
| mask <<= 1; |
| case DTMF_LISTEN_MF_STOP: |
| mask <<= 1; |
| |
| case DTMF_LISTEN_STOP: |
| switch (internal_command) |
| { |
| default: |
| plci->dtmf_rec_active &= ~mask; |
| if (plci->dtmf_rec_active) |
| break; |
| /* |
| case DTMF_COMMAND_1: |
| if (plci->dtmf_rec_active) |
| { |
| if (plci_nl_busy (plci)) |
| { |
| plci->internal_command = DTMF_COMMAND_1; |
| return; |
| } |
| plci->dtmf_rec_active &= ~mask; |
| plci->internal_command = DTMF_COMMAND_2; |
| dtmf_enable_receiver (plci, false); |
| return; |
| } |
| Rc = OK; |
| case DTMF_COMMAND_2: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug (1, dprintf("[%06lx] %s,%d: Disable DTMF receiver failed %02x", |
| UnMapId (Id), (char far *)(FILE_), __LINE__, Rc)); |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } |
| */ |
| adjust_b1_resource(Id, plci, NULL, (word)(plci->B1_facilities & |
| ~(B1_FACILITY_DTMFX | B1_FACILITY_DTMFR)), DTMF_COMMAND_3); |
| case DTMF_COMMAND_3: |
| if (adjust_b_process(Id, plci, Rc) != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Unload DTMF failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } |
| if (plci->internal_command) |
| return; |
| break; |
| } |
| break; |
| |
| |
| case DTMF_SEND_TONE: |
| mask <<= 1; |
| case DTMF_SEND_MF: |
| mask <<= 1; |
| |
| case DTMF_DIGITS_SEND: |
| switch (internal_command) |
| { |
| default: |
| adjust_b1_resource(Id, plci, NULL, (word)(plci->B1_facilities | |
| ((plci->dtmf_parameter_length != 0) ? B1_FACILITY_DTMFX | B1_FACILITY_DTMFR : B1_FACILITY_DTMFX)), |
| DTMF_COMMAND_1); |
| case DTMF_COMMAND_1: |
| if (adjust_b_process(Id, plci, Rc) != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Load DTMF failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } |
| if (plci->internal_command) |
| return; |
| case DTMF_COMMAND_2: |
| if (plci_nl_busy(plci)) |
| { |
| plci->internal_command = DTMF_COMMAND_2; |
| return; |
| } |
| plci->dtmf_msg_number_queue[(plci->dtmf_send_requests)++] = plci->number; |
| plci->internal_command = DTMF_COMMAND_3; |
| dtmf_send_digits(plci, &plci->saved_msg.parms[3].info[1], plci->saved_msg.parms[3].length); |
| return; |
| case DTMF_COMMAND_3: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Send DTMF digits failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| if (plci->dtmf_send_requests != 0) |
| (plci->dtmf_send_requests)--; |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } |
| return; |
| } |
| break; |
| } |
| sendf(plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->number, |
| "wws", Info, SELECTOR_DTMF, result); |
| } |
| |
| |
| static byte dtmf_request(dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg) |
| { |
| word Info; |
| word i, j; |
| byte mask; |
| API_PARSE dtmf_parms[5]; |
| byte result[40]; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_request", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| |
| Info = GOOD; |
| result[0] = 2; |
| PUT_WORD(&result[1], DTMF_SUCCESS); |
| if (!(a->profile.Global_Options & GL_DTMF_SUPPORTED)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Facility not supported", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _FACILITY_NOT_SUPPORTED; |
| } |
| else if (api_parse(&msg[1].info[1], msg[1].length, "w", dtmf_parms)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong message format", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_MESSAGE_FORMAT; |
| } |
| |
| else if ((GET_WORD(dtmf_parms[0].info) == DTMF_GET_SUPPORTED_DETECT_CODES) |
| || (GET_WORD(dtmf_parms[0].info) == DTMF_GET_SUPPORTED_SEND_CODES)) |
| { |
| if (!((a->requested_options_table[appl->Id - 1]) |
| & (1L << PRIVATE_DTMF_TONE))) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: DTMF unknown request %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, GET_WORD(dtmf_parms[0].info))); |
| PUT_WORD(&result[1], DTMF_UNKNOWN_REQUEST); |
| } |
| else |
| { |
| for (i = 0; i < 32; i++) |
| result[4 + i] = 0; |
| if (GET_WORD(dtmf_parms[0].info) == DTMF_GET_SUPPORTED_DETECT_CODES) |
| { |
| for (i = 0; i < DTMF_DIGIT_MAP_ENTRIES; i++) |
| { |
| if (dtmf_digit_map[i].listen_mask != 0) |
| result[4 + (dtmf_digit_map[i].character >> 3)] |= (1 << (dtmf_digit_map[i].character & 0x7)); |
| } |
| } |
| else |
| { |
| for (i = 0; i < DTMF_DIGIT_MAP_ENTRIES; i++) |
| { |
| if (dtmf_digit_map[i].send_mask != 0) |
| result[4 + (dtmf_digit_map[i].character >> 3)] |= (1 << (dtmf_digit_map[i].character & 0x7)); |
| } |
| } |
| result[0] = 3 + 32; |
| result[3] = 32; |
| } |
| } |
| |
| else if (plci == NULL) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong PLCI", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_IDENTIFIER; |
| } |
| else |
| { |
| if (!plci->State |
| || !plci->NL.Id || plci->nl_remove_id) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong state", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_STATE; |
| } |
| else |
| { |
| plci->command = 0; |
| plci->dtmf_cmd = GET_WORD(dtmf_parms[0].info); |
| mask = 0x01; |
| switch (plci->dtmf_cmd) |
| { |
| |
| case DTMF_LISTEN_TONE_START: |
| case DTMF_LISTEN_TONE_STOP: |
| mask <<= 1; |
| case DTMF_LISTEN_MF_START: |
| case DTMF_LISTEN_MF_STOP: |
| mask <<= 1; |
| if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[appl->Id - 1]) |
| & (1L << PRIVATE_DTMF_TONE))) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: DTMF unknown request %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, GET_WORD(dtmf_parms[0].info))); |
| PUT_WORD(&result[1], DTMF_UNKNOWN_REQUEST); |
| break; |
| } |
| |
| case DTMF_LISTEN_START: |
| case DTMF_LISTEN_STOP: |
| if (!(a->manufacturer_features & MANUFACTURER_FEATURE_HARDDTMF) |
| && !(a->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Facility not supported", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } |
| if (mask & DTMF_LISTEN_ACTIVE_FLAG) |
| { |
| if (api_parse(&msg[1].info[1], msg[1].length, "wwws", dtmf_parms)) |
| { |
| plci->dtmf_rec_pulse_ms = 0; |
| plci->dtmf_rec_pause_ms = 0; |
| } |
| else |
| { |
| plci->dtmf_rec_pulse_ms = GET_WORD(dtmf_parms[1].info); |
| plci->dtmf_rec_pause_ms = GET_WORD(dtmf_parms[2].info); |
| } |
| } |
| start_internal_command(Id, plci, dtmf_command); |
| return (false); |
| |
| |
| case DTMF_SEND_TONE: |
| mask <<= 1; |
| case DTMF_SEND_MF: |
| mask <<= 1; |
| if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[appl->Id - 1]) |
| & (1L << PRIVATE_DTMF_TONE))) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: DTMF unknown request %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, GET_WORD(dtmf_parms[0].info))); |
| PUT_WORD(&result[1], DTMF_UNKNOWN_REQUEST); |
| break; |
| } |
| |
| case DTMF_DIGITS_SEND: |
| if (api_parse(&msg[1].info[1], msg[1].length, "wwws", dtmf_parms)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong message format", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| if (mask & DTMF_LISTEN_ACTIVE_FLAG) |
| { |
| plci->dtmf_send_pulse_ms = GET_WORD(dtmf_parms[1].info); |
| plci->dtmf_send_pause_ms = GET_WORD(dtmf_parms[2].info); |
| } |
| i = 0; |
| j = 0; |
| while ((i < dtmf_parms[3].length) && (j < DTMF_DIGIT_MAP_ENTRIES)) |
| { |
| j = 0; |
| while ((j < DTMF_DIGIT_MAP_ENTRIES) |
| && ((dtmf_parms[3].info[i + 1] != dtmf_digit_map[j].character) |
| || ((dtmf_digit_map[j].send_mask & mask) == 0))) |
| { |
| j++; |
| } |
| i++; |
| } |
| if (j == DTMF_DIGIT_MAP_ENTRIES) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Incorrect DTMF digit %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, dtmf_parms[3].info[i])); |
| PUT_WORD(&result[1], DTMF_INCORRECT_DIGIT); |
| break; |
| } |
| if (plci->dtmf_send_requests >= ARRAY_SIZE(plci->dtmf_msg_number_queue)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: DTMF request overrun", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_STATE; |
| break; |
| } |
| api_save_msg(dtmf_parms, "wwws", &plci->saved_msg); |
| start_internal_command(Id, plci, dtmf_command); |
| return (false); |
| |
| default: |
| dbug(1, dprintf("[%06lx] %s,%d: DTMF unknown request %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, plci->dtmf_cmd)); |
| PUT_WORD(&result[1], DTMF_UNKNOWN_REQUEST); |
| } |
| } |
| } |
| sendf(appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number, |
| "wws", Info, SELECTOR_DTMF, result); |
| return (false); |
| } |
| |
| |
| static void dtmf_confirmation(dword Id, PLCI *plci) |
| { |
| word i; |
| byte result[4]; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_confirmation", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| |
| result[0] = 2; |
| PUT_WORD(&result[1], DTMF_SUCCESS); |
| if (plci->dtmf_send_requests != 0) |
| { |
| sendf(plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->dtmf_msg_number_queue[0], |
| "wws", GOOD, SELECTOR_DTMF, result); |
| (plci->dtmf_send_requests)--; |
| for (i = 0; i < plci->dtmf_send_requests; i++) |
| plci->dtmf_msg_number_queue[i] = plci->dtmf_msg_number_queue[i + 1]; |
| } |
| } |
| |
| |
| static void dtmf_indication(dword Id, PLCI *plci, byte *msg, word length) |
| { |
| word i, j, n; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_indication", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| |
| n = 0; |
| for (i = 1; i < length; i++) |
| { |
| j = 0; |
| while ((j < DTMF_DIGIT_MAP_ENTRIES) |
| && ((msg[i] != dtmf_digit_map[j].code) |
| || ((dtmf_digit_map[j].listen_mask & plci->dtmf_rec_active) == 0))) |
| { |
| j++; |
| } |
| if (j < DTMF_DIGIT_MAP_ENTRIES) |
| { |
| |
| if ((dtmf_digit_map[j].listen_mask & DTMF_TONE_LISTEN_ACTIVE_FLAG) |
| && (plci->tone_last_indication_code == DTMF_SIGNAL_NO_TONE) |
| && (dtmf_digit_map[j].character != DTMF_SIGNAL_UNIDENTIFIED_TONE)) |
| { |
| if (n + 1 == i) |
| { |
| for (i = length; i > n + 1; i--) |
| msg[i] = msg[i - 1]; |
| length++; |
| i++; |
| } |
| msg[++n] = DTMF_SIGNAL_UNIDENTIFIED_TONE; |
| } |
| plci->tone_last_indication_code = dtmf_digit_map[j].character; |
| |
| msg[++n] = dtmf_digit_map[j].character; |
| } |
| } |
| if (n != 0) |
| { |
| msg[0] = (byte) n; |
| sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0, "wS", SELECTOR_DTMF, msg); |
| } |
| } |
| |
| |
| /*------------------------------------------------------------------*/ |
| /* DTMF parameters */ |
| /*------------------------------------------------------------------*/ |
| |
| static void dtmf_parameter_write(PLCI *plci) |
| { |
| word i; |
| byte parameter_buffer[DTMF_PARAMETER_BUFFER_SIZE + 2]; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_parameter_write", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| |
| parameter_buffer[0] = plci->dtmf_parameter_length + 1; |
| parameter_buffer[1] = DSP_CTRL_SET_DTMF_PARAMETERS; |
| for (i = 0; i < plci->dtmf_parameter_length; i++) |
| parameter_buffer[2 + i] = plci->dtmf_parameter_buffer[i]; |
| add_p(plci, FTY, parameter_buffer); |
| sig_req(plci, TEL_CTRL, 0); |
| send_req(plci); |
| } |
| |
| |
| static void dtmf_parameter_clear_config(PLCI *plci) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_parameter_clear_config", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| |
| plci->dtmf_parameter_length = 0; |
| } |
| |
| |
| static void dtmf_parameter_prepare_switch(dword Id, PLCI *plci) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_parameter_prepare_switch", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| |
| } |
| |
| |
| static word dtmf_parameter_save_config(dword Id, PLCI *plci, byte Rc) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_parameter_save_config %02x %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state)); |
| |
| return (GOOD); |
| } |
| |
| |
| static word dtmf_parameter_restore_config(dword Id, PLCI *plci, byte Rc) |
| { |
| word Info; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: dtmf_parameter_restore_config %02x %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state)); |
| |
| Info = GOOD; |
| if ((plci->B1_facilities & B1_FACILITY_DTMFR) |
| && (plci->dtmf_parameter_length != 0)) |
| { |
| switch (plci->adjust_b_state) |
| { |
| case ADJUST_B_RESTORE_DTMF_PARAMETER_1: |
| plci->internal_command = plci->adjust_b_command; |
| if (plci->sig_req) |
| { |
| plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_1; |
| break; |
| } |
| dtmf_parameter_write(plci); |
| plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_2; |
| break; |
| case ADJUST_B_RESTORE_DTMF_PARAMETER_2: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Restore DTMF parameters failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| Info = _WRONG_STATE; |
| break; |
| } |
| break; |
| } |
| } |
| return (Info); |
| } |
| |
| |
| /*------------------------------------------------------------------*/ |
| /* Line interconnect facilities */ |
| /*------------------------------------------------------------------*/ |
| |
| |
| LI_CONFIG *li_config_table; |
| word li_total_channels; |
| |
| |
| /*------------------------------------------------------------------*/ |
| /* translate a CHI information element to a channel number */ |
| /* returns 0xff - any channel */ |
| /* 0xfe - chi wrong coding */ |
| /* 0xfd - D-channel */ |
| /* 0x00 - no channel */ |
| /* else channel number / PRI: timeslot */ |
| /* if channels is provided we accept more than one channel. */ |
| /*------------------------------------------------------------------*/ |
| |
| static byte chi_to_channel(byte *chi, dword *pchannelmap) |
| { |
| int p; |
| int i; |
| dword map; |
| byte excl; |
| byte ofs; |
| byte ch; |
| |
| if (pchannelmap) *pchannelmap = 0; |
| if (!chi[0]) return 0xff; |
| excl = 0; |
| |
| if (chi[1] & 0x20) { |
| if (chi[0] == 1 && chi[1] == 0xac) return 0xfd; /* exclusive d-channel */ |
| for (i = 1; i < chi[0] && !(chi[i] & 0x80); i++); |
| if (i == chi[0] || !(chi[i] & 0x80)) return 0xfe; |
| if ((chi[1] | 0xc8) != 0xe9) return 0xfe; |
| if (chi[1] & 0x08) excl = 0x40; |
| |
| /* int. id present */ |
| if (chi[1] & 0x40) { |
| p = i + 1; |
| for (i = p; i < chi[0] && !(chi[i] & 0x80); i++); |
| if (i == chi[0] || !(chi[i] & 0x80)) return 0xfe; |
| } |
| |
| /* coding standard, Number/Map, Channel Type */ |
| p = i + 1; |
| for (i = p; i < chi[0] && !(chi[i] & 0x80); i++); |
| if (i == chi[0] || !(chi[i] & 0x80)) return 0xfe; |
| if ((chi[p] | 0xd0) != 0xd3) return 0xfe; |
| |
| /* Number/Map */ |
| if (chi[p] & 0x10) { |
| |
| /* map */ |
| if ((chi[0] - p) == 4) ofs = 0; |
| else if ((chi[0] - p) == 3) ofs = 1; |
| else return 0xfe; |
| ch = 0; |
| map = 0; |
| for (i = 0; i < 4 && p < chi[0]; i++) { |
| p++; |
| ch += 8; |
| map <<= 8; |
| if (chi[p]) { |
| for (ch = 0; !(chi[p] & (1 << ch)); ch++); |
| map |= chi[p]; |
| } |
| } |
| ch += ofs; |
| map <<= ofs; |
| } |
| else { |
| |
| /* number */ |
| p = i + 1; |
| ch = chi[p] & 0x3f; |
| if (pchannelmap) { |
| if ((byte)(chi[0] - p) > 30) return 0xfe; |
| map = 0; |
| for (i = p; i <= chi[0]; i++) { |
| if ((chi[i] & 0x7f) > 31) return 0xfe; |
| map |= (1L << (chi[i] & 0x7f)); |
| } |
| } |
| else { |
| if (p != chi[0]) return 0xfe; |
| if (ch > 31) return 0xfe; |
| map = (1L << ch); |
| } |
| if (chi[p] & 0x40) return 0xfe; |
| } |
| if (pchannelmap) *pchannelmap = map; |
| else if (map != ((dword)(1L << ch))) return 0xfe; |
| return (byte)(excl | ch); |
| } |
| else { /* not PRI */ |
| for (i = 1; i < chi[0] && !(chi[i] & 0x80); i++); |
| if (i != chi[0] || !(chi[i] & 0x80)) return 0xfe; |
| if (chi[1] & 0x08) excl = 0x40; |
| |
| switch (chi[1] | 0x98) { |
| case 0x98: return 0; |
| case 0x99: |
| if (pchannelmap) *pchannelmap = 2; |
| return excl | 1; |
| case 0x9a: |
| if (pchannelmap) *pchannelmap = 4; |
| return excl | 2; |
| case 0x9b: return 0xff; |
| case 0x9c: return 0xfd; /* d-ch */ |
| default: return 0xfe; |
| } |
| } |
| } |
| |
| |
| static void mixer_set_bchannel_id_esc(PLCI *plci, byte bchannel_id) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| PLCI *splci; |
| byte old_id; |
| |
| a = plci->adapter; |
| old_id = plci->li_bchannel_id; |
| if (a->li_pri) |
| { |
| if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci)) |
| li_config_table[a->li_base + (old_id - 1)].plci = NULL; |
| plci->li_bchannel_id = (bchannel_id & 0x1f) + 1; |
| if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL) |
| li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci; |
| } |
| else |
| { |
| if (((bchannel_id & 0x03) == 1) || ((bchannel_id & 0x03) == 2)) |
| { |
| if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci)) |
| li_config_table[a->li_base + (old_id - 1)].plci = NULL; |
| plci->li_bchannel_id = bchannel_id & 0x03; |
| if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI != plci) && (a->AdvSignalPLCI->tel == ADV_VOICE)) |
| { |
| splci = a->AdvSignalPLCI; |
| if (li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci == NULL) |
| { |
| if ((splci->li_bchannel_id != 0) |
| && (li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci == splci)) |
| { |
| li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci = NULL; |
| } |
| splci->li_bchannel_id = 3 - plci->li_bchannel_id; |
| li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci = splci; |
| dbug(1, dprintf("[%06lx] %s,%d: adv_voice_set_bchannel_id_esc %d", |
| (dword)((splci->Id << 8) | UnMapController(splci->adapter->Id)), |
| (char *)(FILE_), __LINE__, splci->li_bchannel_id)); |
| } |
| } |
| if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL) |
| li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci; |
| } |
| } |
| if ((old_id == 0) && (plci->li_bchannel_id != 0) |
| && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci)) |
| { |
| mixer_clear_config(plci); |
| } |
| dbug(1, dprintf("[%06lx] %s,%d: mixer_set_bchannel_id_esc %d %d", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__, bchannel_id, plci->li_bchannel_id)); |
| } |
| |
| |
| static void mixer_set_bchannel_id(PLCI *plci, byte *chi) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| PLCI *splci; |
| byte ch, old_id; |
| |
| a = plci->adapter; |
| old_id = plci->li_bchannel_id; |
| ch = chi_to_channel(chi, NULL); |
| if (!(ch & 0x80)) |
| { |
| if (a->li_pri) |
| { |
| if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci)) |
| li_config_table[a->li_base + (old_id - 1)].plci = NULL; |
| plci->li_bchannel_id = (ch & 0x1f) + 1; |
| if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL) |
| li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci; |
| } |
| else |
| { |
| if (((ch & 0x1f) == 1) || ((ch & 0x1f) == 2)) |
| { |
| if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci)) |
| li_config_table[a->li_base + (old_id - 1)].plci = NULL; |
| plci->li_bchannel_id = ch & 0x1f; |
| if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI != plci) && (a->AdvSignalPLCI->tel == ADV_VOICE)) |
| { |
| splci = a->AdvSignalPLCI; |
| if (li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci == NULL) |
| { |
| if ((splci->li_bchannel_id != 0) |
| && (li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci == splci)) |
| { |
| li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci = NULL; |
| } |
| splci->li_bchannel_id = 3 - plci->li_bchannel_id; |
| li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci = splci; |
| dbug(1, dprintf("[%06lx] %s,%d: adv_voice_set_bchannel_id %d", |
| (dword)((splci->Id << 8) | UnMapController(splci->adapter->Id)), |
| (char *)(FILE_), __LINE__, splci->li_bchannel_id)); |
| } |
| } |
| if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL) |
| li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci; |
| } |
| } |
| } |
| if ((old_id == 0) && (plci->li_bchannel_id != 0) |
| && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci)) |
| { |
| mixer_clear_config(plci); |
| } |
| dbug(1, dprintf("[%06lx] %s,%d: mixer_set_bchannel_id %02x %d", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__, ch, plci->li_bchannel_id)); |
| } |
| |
| |
| #define MIXER_MAX_DUMP_CHANNELS 34 |
| |
| static void mixer_calculate_coefs(DIVA_CAPI_ADAPTER *a) |
| { |
| word n, i, j; |
| char *p; |
| char hex_line[2 * MIXER_MAX_DUMP_CHANNELS + MIXER_MAX_DUMP_CHANNELS / 8 + 4]; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: mixer_calculate_coefs", |
| (dword)(UnMapController(a->Id)), (char *)(FILE_), __LINE__)); |
| |
| for (i = 0; i < li_total_channels; i++) |
| { |
| li_config_table[i].channel &= LI_CHANNEL_ADDRESSES_SET; |
| if (li_config_table[i].chflags != 0) |
| li_config_table[i].channel |= LI_CHANNEL_INVOLVED; |
| else |
| { |
| for (j = 0; j < li_total_channels; j++) |
| { |
| if (((li_config_table[i].flag_table[j]) != 0) |
| || ((li_config_table[j].flag_table[i]) != 0)) |
| { |
| li_config_table[i].channel |= LI_CHANNEL_INVOLVED; |
| } |
| if (((li_config_table[i].flag_table[j] & LI_FLAG_CONFERENCE) != 0) |
| || ((li_config_table[j].flag_table[i] & LI_FLAG_CONFERENCE) != 0)) |
| { |
| li_config_table[i].channel |= LI_CHANNEL_CONFERENCE; |
| } |
| } |
| } |
| } |
| for (i = 0; i < li_total_channels; i++) |
| { |
| for (j = 0; j < li_total_channels; j++) |
| { |
| li_config_table[i].coef_table[j] &= ~(LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC); |
| if (li_config_table[i].flag_table[j] & LI_FLAG_CONFERENCE) |
| li_config_table[i].coef_table[j] |= LI_COEF_CH_CH; |
| } |
| } |
| for (n = 0; n < li_total_channels; n++) |
| { |
| if (li_config_table[n].channel & LI_CHANNEL_CONFERENCE) |
| { |
| for (i = 0; i < li_total_channels; i++) |
| { |
| if (li_config_table[i].channel & LI_CHANNEL_CONFERENCE) |
| { |
| for (j = 0; j < li_total_channels; j++) |
| { |
| li_config_table[i].coef_table[j] |= |
| li_config_table[i].coef_table[n] & li_config_table[n].coef_table[j]; |
| } |
| } |
| } |
| } |
| } |
| for (i = 0; i < li_total_channels; i++) |
| { |
| if (li_config_table[i].channel & LI_CHANNEL_INVOLVED) |
| { |
| li_config_table[i].coef_table[i] &= ~LI_COEF_CH_CH; |
| for (j = 0; j < li_total_channels; j++) |
| { |
| if (li_config_table[i].coef_table[j] & LI_COEF_CH_CH) |
| li_config_table[i].flag_table[j] |= LI_FLAG_CONFERENCE; |
| } |
| if (li_config_table[i].flag_table[i] & LI_FLAG_CONFERENCE) |
| li_config_table[i].coef_table[i] |= LI_COEF_CH_CH; |
| } |
| } |
| for (i = 0; i < li_total_channels; i++) |
| { |
| if (li_config_table[i].channel & LI_CHANNEL_INVOLVED) |
| { |
| for (j = 0; j < li_total_channels; j++) |
| { |
| if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT) |
| li_config_table[i].coef_table[j] |= LI_COEF_CH_CH; |
| if (li_config_table[i].flag_table[j] & LI_FLAG_MONITOR) |
| li_config_table[i].coef_table[j] |= LI_COEF_CH_PC; |
| if (li_config_table[i].flag_table[j] & LI_FLAG_MIX) |
| li_config_table[i].coef_table[j] |= LI_COEF_PC_CH; |
| if (li_config_table[i].flag_table[j] & LI_FLAG_PCCONNECT) |
| li_config_table[i].coef_table[j] |= LI_COEF_PC_PC; |
| } |
| if (li_config_table[i].chflags & LI_CHFLAG_MONITOR) |
| { |
| for (j = 0; j < li_total_channels; j++) |
| { |
| if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT) |
| { |
| li_config_table[i].coef_table[j] |= LI_COEF_CH_PC; |
| if (li_config_table[j].chflags & LI_CHFLAG_MIX) |
| li_config_table[i].coef_table[j] |= LI_COEF_PC_CH | LI_COEF_PC_PC; |
| } |
| } |
| } |
| if (li_config_table[i].chflags & LI_CHFLAG_MIX) |
| { |
| for (j = 0; j < li_total_channels; j++) |
| { |
| if (li_config_table[j].flag_table[i] & LI_FLAG_INTERCONNECT) |
| li_config_table[j].coef_table[i] |= LI_COEF_PC_CH; |
| } |
| } |
| if (li_config_table[i].chflags & LI_CHFLAG_LOOP) |
| { |
| for (j = 0; j < li_total_channels; j++) |
| { |
| if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT) |
| { |
| for (n = 0; n < li_total_channels; n++) |
| { |
| if (li_config_table[n].flag_table[i] & LI_FLAG_INTERCONNECT) |
| { |
| li_config_table[n].coef_table[j] |= LI_COEF_CH_CH; |
| if (li_config_table[j].chflags & LI_CHFLAG_MIX) |
| { |
| li_config_table[n].coef_table[j] |= LI_COEF_PC_CH; |
| if (li_config_table[n].chflags & LI_CHFLAG_MONITOR) |
| li_config_table[n].coef_table[j] |= LI_COEF_CH_PC | LI_COEF_PC_PC; |
| } |
| else if (li_config_table[n].chflags & LI_CHFLAG_MONITOR) |
| li_config_table[n].coef_table[j] |= LI_COEF_CH_PC; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| for (i = 0; i < li_total_channels; i++) |
| { |
| if (li_config_table[i].channel & LI_CHANNEL_INVOLVED) |
| { |
| if (li_config_table[i].chflags & (LI_CHFLAG_MONITOR | LI_CHFLAG_MIX | LI_CHFLAG_LOOP)) |
| li_config_table[i].channel |= LI_CHANNEL_ACTIVE; |
| if (li_config_table[i].chflags & LI_CHFLAG_MONITOR) |
| li_config_table[i].channel |= LI_CHANNEL_RX_DATA; |
| if (li_config_table[i].chflags & LI_CHFLAG_MIX) |
| li_config_table[i].channel |= LI_CHANNEL_TX_DATA; |
| for (j = 0; j < li_total_channels; j++) |
| { |
| if ((li_config_table[i].flag_table[j] & |
| (LI_FLAG_INTERCONNECT | LI_FLAG_PCCONNECT | LI_FLAG_CONFERENCE | LI_FLAG_MONITOR)) |
| || (li_config_table[j].flag_table[i] & |
| (LI_FLAG_INTERCONNECT | LI_FLAG_PCCONNECT | LI_FLAG_CONFERENCE | LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX))) |
| { |
| li_config_table[i].channel |= LI_CHANNEL_ACTIVE; |
| } |
| if (li_config_table[i].flag_table[j] & (LI_FLAG_PCCONNECT | LI_FLAG_MONITOR)) |
| li_config_table[i].channel |= LI_CHANNEL_RX_DATA; |
| if (li_config_table[j].flag_table[i] & (LI_FLAG_PCCONNECT | LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX)) |
| li_config_table[i].channel |= LI_CHANNEL_TX_DATA; |
| } |
| if (!(li_config_table[i].channel & LI_CHANNEL_ACTIVE)) |
| { |
| li_config_table[i].coef_table[i] |= LI_COEF_PC_CH | LI_COEF_CH_PC; |
| li_config_table[i].channel |= LI_CHANNEL_TX_DATA | LI_CHANNEL_RX_DATA; |
| } |
| } |
| } |
| for (i = 0; i < li_total_channels; i++) |
| { |
| if (li_config_table[i].channel & LI_CHANNEL_INVOLVED) |
| { |
| j = 0; |
| while ((j < li_total_channels) && !(li_config_table[i].flag_table[j] & LI_FLAG_ANNOUNCEMENT)) |
| j++; |
| if (j < li_total_channels) |
| { |
| for (j = 0; j < li_total_channels; j++) |
| { |
| li_config_table[i].coef_table[j] &= ~(LI_COEF_CH_CH | LI_COEF_PC_CH); |
| if (li_config_table[i].flag_table[j] & LI_FLAG_ANNOUNCEMENT) |
| li_config_table[i].coef_table[j] |= LI_COEF_PC_CH; |
| } |
| } |
| } |
| } |
| n = li_total_channels; |
| if (n > MIXER_MAX_DUMP_CHANNELS) |
| n = MIXER_MAX_DUMP_CHANNELS; |
| |
| p = hex_line; |
| for (j = 0; j < n; j++) |
| { |
| if ((j & 0x7) == 0) |
| *(p++) = ' '; |
| p = hex_byte_pack(p, li_config_table[j].curchnl); |
| } |
| *p = '\0'; |
| dbug(1, dprintf("[%06lx] CURRENT %s", |
| (dword)(UnMapController(a->Id)), (char *)hex_line)); |
| p = hex_line; |
| for (j = 0; j < n; j++) |
| { |
| if ((j & 0x7) == 0) |
| *(p++) = ' '; |
| p = hex_byte_pack(p, li_config_table[j].channel); |
| } |
| *p = '\0'; |
| dbug(1, dprintf("[%06lx] CHANNEL %s", |
| (dword)(UnMapController(a->Id)), (char *)hex_line)); |
| p = hex_line; |
| for (j = 0; j < n; j++) |
| { |
| if ((j & 0x7) == 0) |
| *(p++) = ' '; |
| p = hex_byte_pack(p, li_config_table[j].chflags); |
| } |
| *p = '\0'; |
| dbug(1, dprintf("[%06lx] CHFLAG %s", |
| (dword)(UnMapController(a->Id)), (char *)hex_line)); |
| for (i = 0; i < n; i++) |
| { |
| p = hex_line; |
| for (j = 0; j < n; j++) |
| { |
| if ((j & 0x7) == 0) |
| *(p++) = ' '; |
| p = hex_byte_pack(p, li_config_table[i].flag_table[j]); |
| } |
| *p = '\0'; |
| dbug(1, dprintf("[%06lx] FLAG[%02x]%s", |
| (dword)(UnMapController(a->Id)), i, (char *)hex_line)); |
| } |
| for (i = 0; i < n; i++) |
| { |
| p = hex_line; |
| for (j = 0; j < n; j++) |
| { |
| if ((j & 0x7) == 0) |
| *(p++) = ' '; |
| p = hex_byte_pack(p, li_config_table[i].coef_table[j]); |
| } |
| *p = '\0'; |
| dbug(1, dprintf("[%06lx] COEF[%02x]%s", |
| (dword)(UnMapController(a->Id)), i, (char *)hex_line)); |
| } |
| } |
| |
| |
| static struct |
| { |
| byte mask; |
| byte line_flags; |
| } mixer_write_prog_pri[] = |
| { |
| { LI_COEF_CH_CH, 0 }, |
| { LI_COEF_CH_PC, MIXER_COEF_LINE_TO_PC_FLAG }, |
| { LI_COEF_PC_CH, MIXER_COEF_LINE_FROM_PC_FLAG }, |
| { LI_COEF_PC_PC, MIXER_COEF_LINE_TO_PC_FLAG | MIXER_COEF_LINE_FROM_PC_FLAG } |
| }; |
| |
| static struct |
| { |
| byte from_ch; |
| byte to_ch; |
| byte mask; |
| byte xconnect_override; |
| } mixer_write_prog_bri[] = |
| { |
| { 0, 0, LI_COEF_CH_CH, 0x01 }, /* B to B */ |
| { 1, 0, LI_COEF_CH_CH, 0x01 }, /* Alt B to B */ |
| { 0, 0, LI_COEF_PC_CH, 0x80 }, /* PC to B */ |
| { 1, 0, LI_COEF_PC_CH, 0x01 }, /* Alt PC to B */ |
| { 2, 0, LI_COEF_CH_CH, 0x00 }, /* IC to B */ |
| { 3, 0, LI_COEF_CH_CH, 0x00 }, /* Alt IC to B */ |
| { 0, 0, LI_COEF_CH_PC, 0x80 }, /* B to PC */ |
| { 1, 0, LI_COEF_CH_PC, 0x01 }, /* Alt B to PC */ |
| { 0, 0, LI_COEF_PC_PC, 0x01 }, /* PC to PC */ |
| { 1, 0, LI_COEF_PC_PC, 0x01 }, /* Alt PC to PC */ |
| { 2, 0, LI_COEF_CH_PC, 0x00 }, /* IC to PC */ |
| { 3, 0, LI_COEF_CH_PC, 0x00 }, /* Alt IC to PC */ |
| { 0, 2, LI_COEF_CH_CH, 0x00 }, /* B to IC */ |
| { 1, 2, LI_COEF_CH_CH, 0x00 }, /* Alt B to IC */ |
| { 0, 2, LI_COEF_PC_CH, 0x00 }, /* PC to IC */ |
| { 1, 2, LI_COEF_PC_CH, 0x00 }, /* Alt PC to IC */ |
| { 2, 2, LI_COEF_CH_CH, 0x00 }, /* IC to IC */ |
| { 3, 2, LI_COEF_CH_CH, 0x00 }, /* Alt IC to IC */ |
| { 1, 1, LI_COEF_CH_CH, 0x01 }, /* Alt B to Alt B */ |
| { 0, 1, LI_COEF_CH_CH, 0x01 }, /* B to Alt B */ |
| { 1, 1, LI_COEF_PC_CH, 0x80 }, /* Alt PC to Alt B */ |
| { 0, 1, LI_COEF_PC_CH, 0x01 }, /* PC to Alt B */ |
| { 3, 1, LI_COEF_CH_CH, 0x00 }, /* Alt IC to Alt B */ |
| { 2, 1, LI_COEF_CH_CH, 0x00 }, /* IC to Alt B */ |
| { 1, 1, LI_COEF_CH_PC, 0x80 }, /* Alt B to Alt PC */ |
| { 0, 1, LI_COEF_CH_PC, 0x01 }, /* B to Alt PC */ |
| { 1, 1, LI_COEF_PC_PC, 0x01 }, /* Alt PC to Alt PC */ |
| { 0, 1, LI_COEF_PC_PC, 0x01 }, /* PC to Alt PC */ |
| { 3, 1, LI_COEF_CH_PC, 0x00 }, /* Alt IC to Alt PC */ |
| { 2, 1, LI_COEF_CH_PC, 0x00 }, /* IC to Alt PC */ |
| { 1, 3, LI_COEF_CH_CH, 0x00 }, /* Alt B to Alt IC */ |
| { 0, 3, LI_COEF_CH_CH, 0x00 }, /* B to Alt IC */ |
| { 1, 3, LI_COEF_PC_CH, 0x00 }, /* Alt PC to Alt IC */ |
| { 0, 3, LI_COEF_PC_CH, 0x00 }, /* PC to Alt IC */ |
| { 3, 3, LI_COEF_CH_CH, 0x00 }, /* Alt IC to Alt IC */ |
| { 2, 3, LI_COEF_CH_CH, 0x00 } /* IC to Alt IC */ |
| }; |
| |
| static byte mixer_swapped_index_bri[] = |
| { |
| 18, /* B to B */ |
| 19, /* Alt B to B */ |
| 20, /* PC to B */ |
| 21, /* Alt PC to B */ |
| 22, /* IC to B */ |
| 23, /* Alt IC to B */ |
| 24, /* B to PC */ |
| 25, /* Alt B to PC */ |
| 26, /* PC to PC */ |
| 27, /* Alt PC to PC */ |
| 28, /* IC to PC */ |
| 29, /* Alt IC to PC */ |
| 30, /* B to IC */ |
| 31, /* Alt B to IC */ |
| 32, /* PC to IC */ |
| 33, /* Alt PC to IC */ |
| 34, /* IC to IC */ |
| 35, /* Alt IC to IC */ |
| 0, /* Alt B to Alt B */ |
| 1, /* B to Alt B */ |
| 2, /* Alt PC to Alt B */ |
| 3, /* PC to Alt B */ |
| 4, /* Alt IC to Alt B */ |
| 5, /* IC to Alt B */ |
| 6, /* Alt B to Alt PC */ |
| 7, /* B to Alt PC */ |
| 8, /* Alt PC to Alt PC */ |
| 9, /* PC to Alt PC */ |
| 10, /* Alt IC to Alt PC */ |
| 11, /* IC to Alt PC */ |
| 12, /* Alt B to Alt IC */ |
| 13, /* B to Alt IC */ |
| 14, /* Alt PC to Alt IC */ |
| 15, /* PC to Alt IC */ |
| 16, /* Alt IC to Alt IC */ |
| 17 /* IC to Alt IC */ |
| }; |
| |
| static struct |
| { |
| byte mask; |
| byte from_pc; |
| byte to_pc; |
| } xconnect_write_prog[] = |
| { |
| { LI_COEF_CH_CH, false, false }, |
| { LI_COEF_CH_PC, false, true }, |
| { LI_COEF_PC_CH, true, false }, |
| { LI_COEF_PC_PC, true, true } |
| }; |
| |
| |
| static void xconnect_query_addresses(PLCI *plci) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| word w, ch; |
| byte *p; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: xconnect_query_addresses", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| |
| a = plci->adapter; |
| if (a->li_pri && ((plci->li_bchannel_id == 0) |
| || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci))) |
| { |
| dbug(1, dprintf("[%06x] %s,%d: Channel id wiped out", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| return; |
| } |
| p = plci->internal_req_buffer; |
| ch = (a->li_pri) ? plci->li_bchannel_id - 1 : 0; |
| *(p++) = UDATA_REQUEST_XCONNECT_FROM; |
| w = ch; |
| *(p++) = (byte) w; |
| *(p++) = (byte)(w >> 8); |
| w = ch | XCONNECT_CHANNEL_PORT_PC; |
| *(p++) = (byte) w; |
| *(p++) = (byte)(w >> 8); |
| plci->NData[0].P = plci->internal_req_buffer; |
| plci->NData[0].PLength = p - plci->internal_req_buffer; |
| plci->NL.X = plci->NData; |
| plci->NL.ReqCh = 0; |
| plci->NL.Req = plci->nl_req = (byte) N_UDATA; |
| plci->adapter->request(&plci->NL); |
| } |
| |
| |
| static void xconnect_write_coefs(PLCI *plci, word internal_command) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: xconnect_write_coefs %04x", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__, internal_command)); |
| |
| plci->li_write_command = internal_command; |
| plci->li_write_channel = 0; |
| } |
| |
| |
| static byte xconnect_write_coefs_process(dword Id, PLCI *plci, byte Rc) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| word w, n, i, j, r, s, to_ch; |
| dword d; |
| byte *p; |
| struct xconnect_transfer_address_s *transfer_address; |
| byte ch_map[MIXER_CHANNELS_BRI]; |
| |
| dbug(1, dprintf("[%06x] %s,%d: xconnect_write_coefs_process %02x %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->li_write_channel)); |
| |
| a = plci->adapter; |
| if ((plci->li_bchannel_id == 0) |
| || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci)) |
| { |
| dbug(1, dprintf("[%06x] %s,%d: Channel id wiped out", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| return (true); |
| } |
| i = a->li_base + (plci->li_bchannel_id - 1); |
| j = plci->li_write_channel; |
| p = plci->internal_req_buffer; |
| if (j != 0) |
| { |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: LI write coefs failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| return (false); |
| } |
| } |
| if (li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT) |
| { |
| r = 0; |
| s = 0; |
| if (j < li_total_channels) |
| { |
| if (li_config_table[i].channel & LI_CHANNEL_ADDRESSES_SET) |
| { |
| s = ((li_config_table[i].send_b.card_address.low | li_config_table[i].send_b.card_address.high) ? |
| (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_PC | LI_COEF_PC_PC)) & |
| ((li_config_table[i].send_pc.card_address.low | li_config_table[i].send_pc.card_address.high) ? |
| (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_PC_CH)); |
| } |
| r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4)); |
| while ((j < li_total_channels) |
| && ((r == 0) |
| || (!(li_config_table[j].channel & LI_CHANNEL_ADDRESSES_SET)) |
| || (!li_config_table[j].adapter->li_pri |
| && (j >= li_config_table[j].adapter->li_base + MIXER_BCHANNELS_BRI)) |
| || (((li_config_table[j].send_b.card_address.low != li_config_table[i].send_b.card_address.low) |
| || (li_config_table[j].send_b.card_address.high != li_config_table[i].send_b.card_address.high)) |
| && (!(a->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT) |
| || !(li_config_table[j].adapter->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT))) |
| || ((li_config_table[j].adapter->li_base != a->li_base) |
| && !(r & s & |
| ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ? |
| (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) & |
| ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ? |
| (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC)))))) |
| { |
| j++; |
| if (j < li_total_channels) |
| r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4)); |
| } |
| } |
| if (j < li_total_channels) |
| { |
| plci->internal_command = plci->li_write_command; |
| if (plci_nl_busy(plci)) |
| return (true); |
| to_ch = (a->li_pri) ? plci->li_bchannel_id - 1 : 0; |
| *(p++) = UDATA_REQUEST_XCONNECT_TO; |
| do |
| { |
| if (li_config_table[j].adapter->li_base != a->li_base) |
| { |
| r &= s & |
| ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ? |
| (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) & |
| ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ? |
| (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC)); |
| } |
| n = 0; |
| do |
| { |
| if (r & xconnect_write_prog[n].mask) |
| { |
| if (xconnect_write_prog[n].from_pc) |
| transfer_address = &(li_config_table[j].send_pc); |
| else |
| transfer_address = &(li_config_table[j].send_b); |
| d = transfer_address->card_address.low; |
| *(p++) = (byte) d; |
| *(p++) = (byte)(d >> 8); |
| *(p++) = (byte)(d >> 16); |
| *(p++) = (byte)(d >> 24); |
| d = transfer_address->card_address.high; |
| *(p++) = (byte) d; |
| *(p++) = (byte)(d >> 8); |
| *(p++) = (byte)(d >> 16); |
| *(p++) = (byte)(d >> 24); |
| d = transfer_address->offset; |
| *(p++) = (byte) d; |
| *(p++) = (byte)(d >> 8); |
| *(p++) = (byte)(d >> 16); |
| *(p++) = (byte)(d >> 24); |
| w = xconnect_write_prog[n].to_pc ? to_ch | XCONNECT_CHANNEL_PORT_PC : to_ch; |
| *(p++) = (byte) w; |
| *(p++) = (byte)(w >> 8); |
| w = ((li_config_table[i].coef_table[j] & xconnect_write_prog[n].mask) == 0) ? 0x01 : |
| (li_config_table[i].adapter->u_law ? |
| (li_config_table[j].adapter->u_law ? 0x80 : 0x86) : |
| (li_config_table[j].adapter->u_law ? 0x7a : 0x80)); |
| *(p++) = (byte) w; |
| *(p++) = (byte) 0; |
| li_config_table[i].coef_table[j] ^= xconnect_write_prog[n].mask << 4; |
| } |
| n++; |
| } while ((n < ARRAY_SIZE(xconnect_write_prog)) |
| && ((p - plci->internal_req_buffer) + 16 < INTERNAL_REQ_BUFFER_SIZE)); |
| if (n == ARRAY_SIZE(xconnect_write_prog)) |
| { |
| do |
| { |
| j++; |
| if (j < li_total_channels) |
| r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4)); |
| } while ((j < li_total_channels) |
| && ((r == 0) |
| || (!(li_config_table[j].channel & LI_CHANNEL_ADDRESSES_SET)) |
| || (!li_config_table[j].adapter->li_pri |
| && (j >= li_config_table[j].adapter->li_base + MIXER_BCHANNELS_BRI)) |
| || (((li_config_table[j].send_b.card_address.low != li_config_table[i].send_b.card_address.low) |
| || (li_config_table[j].send_b.card_address.high != li_config_table[i].send_b.card_address.high)) |
| && (!(a->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT) |
| || !(li_config_table[j].adapter->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT))) |
| || ((li_config_table[j].adapter->li_base != a->li_base) |
| && !(r & s & |
| ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ? |
| (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) & |
| ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ? |
| (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC)))))); |
| } |
| } while ((j < li_total_channels) |
| && ((p - plci->internal_req_buffer) + 16 < INTERNAL_REQ_BUFFER_SIZE)); |
| } |
| else if (j == li_total_channels) |
| { |
| plci->internal_command = plci->li_write_command; |
| if (plci_nl_busy(plci)) |
| return (true); |
| if (a->li_pri) |
| { |
| *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC; |
| w = 0; |
| if (li_config_table[i].channel & LI_CHANNEL_TX_DATA) |
| w |= MIXER_FEATURE_ENABLE_TX_DATA; |
| if (li_config_table[i].channel & LI_CHANNEL_RX_DATA) |
| w |= MIXER_FEATURE_ENABLE_RX_DATA; |
| *(p++) = (byte) w; |
| *(p++) = (byte)(w >> 8); |
| } |
| else |
| { |
| *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_BRI; |
| w = 0; |
| if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI) |
| && (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length)) |
| { |
| w = GET_WORD(a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE); |
| } |
| if (li_config_table[i].channel & LI_CHANNEL_TX_DATA) |
| w |= MIXER_FEATURE_ENABLE_TX_DATA; |
| if (li_config_table[i].channel & LI_CHANNEL_RX_DATA) |
| w |= MIXER_FEATURE_ENABLE_RX_DATA; |
| *(p++) = (byte) w; |
| *(p++) = (byte)(w >> 8); |
| for (j = 0; j < sizeof(ch_map); j += 2) |
| { |
| if (plci->li_bchannel_id == 2) |
| { |
| ch_map[j] = (byte)(j + 1); |
| ch_map[j + 1] = (byte) j; |
| } |
| else |
| { |
| ch_map[j] = (byte) j; |
| ch_map[j + 1] = (byte)(j + 1); |
| } |
| } |
| for (n = 0; n < ARRAY_SIZE(mixer_write_prog_bri); n++) |
| { |
| i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch]; |
| j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch]; |
| if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED) |
| { |
| *p = (mixer_write_prog_bri[n].xconnect_override != 0) ? |
| mixer_write_prog_bri[n].xconnect_override : |
| ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01); |
| if ((i >= a->li_base + MIXER_BCHANNELS_BRI) || (j >= a->li_base + MIXER_BCHANNELS_BRI)) |
| { |
| w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4)); |
| li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4; |
| } |
| } |
| else |
| { |
| *p = 0x00; |
| if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI->tel == ADV_VOICE)) |
| { |
| w = (plci == a->AdvSignalPLCI) ? n : mixer_swapped_index_bri[n]; |
| if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w < a->adv_voice_coef_length) |
| *p = a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w]; |
| } |
| } |
| p++; |
| } |
| } |
| j = li_total_channels + 1; |
| } |
| } |
| else |
| { |
| if (j <= li_total_channels) |
| { |
| plci->internal_command = plci->li_write_command; |
| if (plci_nl_busy(plci)) |
| return (true); |
| if (j < a->li_base) |
| j = a->li_base; |
| if (a->li_pri) |
| { |
| *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC; |
| w = 0; |
| if (li_config_table[i].channel & LI_CHANNEL_TX_DATA) |
| w |= MIXER_FEATURE_ENABLE_TX_DATA; |
| if (li_config_table[i].channel & LI_CHANNEL_RX_DATA) |
| w |= MIXER_FEATURE_ENABLE_RX_DATA; |
| *(p++) = (byte) w; |
| *(p++) = (byte)(w >> 8); |
| for (n = 0; n < ARRAY_SIZE(mixer_write_prog_pri); n++) |
| { |
| *(p++) = (byte)((plci->li_bchannel_id - 1) | mixer_write_prog_pri[n].line_flags); |
| for (j = a->li_base; j < a->li_base + MIXER_CHANNELS_PRI; j++) |
| { |
| w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4)); |
| if (w & mixer_write_prog_pri[n].mask) |
| { |
| *(p++) = (li_config_table[i].coef_table[j] & mixer_write_prog_pri[n].mask) ? 0x80 : 0x01; |
| li_config_table[i].coef_table[j] ^= mixer_write_prog_pri[n].mask << 4; |
| } |
| else |
| *(p++) = 0x00; |
| } |
| *(p++) = (byte)((plci->li_bchannel_id - 1) | MIXER_COEF_LINE_ROW_FLAG | mixer_write_prog_pri[n].line_flags); |
| for (j = a->li_base; j < a->li_base + MIXER_CHANNELS_PRI; j++) |
| { |
| w = ((li_config_table[j].coef_table[i] & 0xf) ^ (li_config_table[j].coef_table[i] >> 4)); |
| if (w & mixer_write_prog_pri[n].mask) |
| { |
| *(p++) = (li_config_table[j].coef_table[i] & mixer_write_prog_pri[n].mask) ? 0x80 : 0x01; |
| li_config_table[j].coef_table[i] ^= mixer_write_prog_pri[n].mask << 4; |
| } |
| else |
| *(p++) = 0x00; |
| } |
| } |
| } |
| else |
| { |
| *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_BRI; |
| w = 0; |
| if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI) |
| && (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length)) |
| { |
| w = GET_WORD(a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE); |
| } |
| if (li_config_table[i].channel & LI_CHANNEL_TX_DATA) |
| w |= MIXER_FEATURE_ENABLE_TX_DATA; |
| if (li_config_table[i].channel & LI_CHANNEL_RX_DATA) |
| w |= MIXER_FEATURE_ENABLE_RX_DATA; |
| *(p++) = (byte) w; |
| *(p++) = (byte)(w >> 8); |
| for (j = 0; j < sizeof(ch_map); j += 2) |
| { |
| if (plci->li_bchannel_id == 2) |
| { |
| ch_map[j] = (byte)(j + 1); |
| ch_map[j + 1] = (byte) j; |
| } |
| else |
| { |
| ch_map[j] = (byte) j; |
| ch_map[j + 1] = (byte)(j + 1); |
| } |
| } |
| for (n = 0; n < ARRAY_SIZE(mixer_write_prog_bri); n++) |
| { |
| i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch]; |
| j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch]; |
| if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED) |
| { |
| *p = ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01); |
| w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4)); |
| li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4; |
| } |
| else |
| { |
| *p = 0x00; |
| if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI->tel == ADV_VOICE)) |
| { |
| w = (plci == a->AdvSignalPLCI) ? n : mixer_swapped_index_bri[n]; |
| if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w < a->adv_voice_coef_length) |
| *p = a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w]; |
| } |
| } |
| p++; |
| } |
| } |
| j = li_total_channels + 1; |
| } |
| } |
| plci->li_write_channel = j; |
| if (p != plci->internal_req_buffer) |
| { |
| plci->NData[0].P = plci->internal_req_buffer; |
| plci->NData[0].PLength = p - plci->internal_req_buffer; |
| plci->NL.X = plci->NData; |
| plci->NL.ReqCh = 0; |
| plci->NL.Req = plci->nl_req = (byte) N_UDATA; |
| plci->adapter->request(&plci->NL); |
| } |
| return (true); |
| } |
| |
| |
| static void mixer_notify_update(PLCI *plci, byte others) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| word i, w; |
| PLCI *notify_plci; |
| byte msg[sizeof(CAPI_MSG_HEADER) + 6]; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: mixer_notify_update %d", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__, others)); |
| |
| a = plci->adapter; |
| if (a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED) |
| { |
| if (others) |
| plci->li_notify_update = true; |
| i = 0; |
| do |
| { |
| notify_plci = NULL; |
| if (others) |
| { |
| while ((i < li_total_channels) && (li_config_table[i].plci == NULL)) |
| i++; |
| if (i < li_total_channels) |
| notify_plci = li_config_table[i++].plci; |
| } |
| else |
| { |
| if ((plci->li_bchannel_id != 0) |
| && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci)) |
| { |
| notify_plci = plci; |
| } |
| } |
| if ((notify_plci != NULL) |
| && !notify_plci->li_notify_update |
| && (notify_plci->appl != NULL) |
| && (notify_plci->State) |
| && notify_plci->NL.Id && !notify_plci->nl_remove_id) |
| { |
| notify_plci->li_notify_update = true; |
| ((CAPI_MSG *) msg)->header.length = 18; |
| ((CAPI_MSG *) msg)->header.appl_id = notify_plci->appl->Id; |
| ((CAPI_MSG *) msg)->header.command = _FACILITY_R; |
| ((CAPI_MSG *) msg)->header.number = 0; |
| ((CAPI_MSG *) msg)->header.controller = notify_plci->adapter->Id; |
| ((CAPI_MSG *) msg)->header.plci = notify_plci->Id; |
| ((CAPI_MSG *) msg)->header.ncci = 0; |
| ((CAPI_MSG *) msg)->info.facility_req.Selector = SELECTOR_LINE_INTERCONNECT; |
| ((CAPI_MSG *) msg)->info.facility_req.structs[0] = 3; |
| ((CAPI_MSG *) msg)->info.facility_req.structs[1] = LI_REQ_SILENT_UPDATE & 0xff; |
| ((CAPI_MSG *) msg)->info.facility_req.structs[2] = LI_REQ_SILENT_UPDATE >> 8; |
| ((CAPI_MSG *) msg)->info.facility_req.structs[3] = 0; |
| w = api_put(notify_plci->appl, (CAPI_MSG *) msg); |
| if (w != _QUEUE_FULL) |
| { |
| if (w != 0) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Interconnect notify failed %06x %d", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__, |
| (dword)((notify_plci->Id << 8) | UnMapController(notify_plci->adapter->Id)), w)); |
| } |
| notify_plci->li_notify_update = false; |
| } |
| } |
| } while (others && (notify_plci != NULL)); |
| if (others) |
| plci->li_notify_update = false; |
| } |
| } |
| |
| |
| static void mixer_clear_config(PLCI *plci) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| word i, j; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: mixer_clear_config", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| |
| plci->li_notify_update = false; |
| plci->li_plci_b_write_pos = 0; |
| plci->li_plci_b_read_pos = 0; |
| plci->li_plci_b_req_pos = 0; |
| a = plci->adapter; |
| if ((plci->li_bchannel_id != 0) |
| && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci)) |
| { |
| i = a->li_base + (plci->li_bchannel_id - 1); |
| li_config_table[i].curchnl = 0; |
| li_config_table[i].channel = 0; |
| li_config_table[i].chflags = 0; |
| for (j = 0; j < li_total_channels; j++) |
| { |
| li_config_table[j].flag_table[i] = 0; |
| li_config_table[i].flag_table[j] = 0; |
| li_config_table[i].coef_table[j] = 0; |
| li_config_table[j].coef_table[i] = 0; |
| } |
| if (!a->li_pri) |
| { |
| li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET; |
| if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI)) |
| { |
| i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1); |
| li_config_table[i].curchnl = 0; |
| li_config_table[i].channel = 0; |
| li_config_table[i].chflags = 0; |
| for (j = 0; j < li_total_channels; j++) |
| { |
| li_config_table[i].flag_table[j] = 0; |
| li_config_table[j].flag_table[i] = 0; |
| li_config_table[i].coef_table[j] = 0; |
| li_config_table[j].coef_table[i] = 0; |
| } |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) |
| { |
| i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id); |
| li_config_table[i].curchnl = 0; |
| li_config_table[i].channel = 0; |
| li_config_table[i].chflags = 0; |
| for (j = 0; j < li_total_channels; j++) |
| { |
| li_config_table[i].flag_table[j] = 0; |
| li_config_table[j].flag_table[i] = 0; |
| li_config_table[i].coef_table[j] = 0; |
| li_config_table[j].coef_table[i] = 0; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| |
| static void mixer_prepare_switch(dword Id, PLCI *plci) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: mixer_prepare_switch", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| |
| do |
| { |
| mixer_indication_coefs_set(Id, plci); |
| } while (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos); |
| } |
| |
| |
| static word mixer_save_config(dword Id, PLCI *plci, byte Rc) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| word i, j; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: mixer_save_config %02x %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state)); |
| |
| a = plci->adapter; |
| if ((plci->li_bchannel_id != 0) |
| && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci)) |
| { |
| i = a->li_base + (plci->li_bchannel_id - 1); |
| for (j = 0; j < li_total_channels; j++) |
| { |
| li_config_table[i].coef_table[j] &= 0xf; |
| li_config_table[j].coef_table[i] &= 0xf; |
| } |
| if (!a->li_pri) |
| li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET; |
| } |
| return (GOOD); |
| } |
| |
| |
| static word mixer_restore_config(dword Id, PLCI *plci, byte Rc) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| word Info; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: mixer_restore_config %02x %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state)); |
| |
| Info = GOOD; |
| a = plci->adapter; |
| if ((plci->B1_facilities & B1_FACILITY_MIXER) |
| && (plci->li_bchannel_id != 0) |
| && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci)) |
| { |
| switch (plci->adjust_b_state) |
| { |
| case ADJUST_B_RESTORE_MIXER_1: |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT) |
| { |
| plci->internal_command = plci->adjust_b_command; |
| if (plci_nl_busy(plci)) |
| { |
| plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_1; |
| break; |
| } |
| xconnect_query_addresses(plci); |
| plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_2; |
| break; |
| } |
| plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5; |
| Rc = OK; |
| case ADJUST_B_RESTORE_MIXER_2: |
| case ADJUST_B_RESTORE_MIXER_3: |
| case ADJUST_B_RESTORE_MIXER_4: |
| if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Adjust B query addresses failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| Info = _WRONG_STATE; |
| break; |
| } |
| if (Rc == OK) |
| { |
| if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2) |
| plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_3; |
| else if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_4) |
| plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5; |
| } |
| else if (Rc == 0) |
| { |
| if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2) |
| plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_4; |
| else if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_3) |
| plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5; |
| } |
| if (plci->adjust_b_state != ADJUST_B_RESTORE_MIXER_5) |
| { |
| plci->internal_command = plci->adjust_b_command; |
| break; |
| } |
| case ADJUST_B_RESTORE_MIXER_5: |
| xconnect_write_coefs(plci, plci->adjust_b_command); |
| plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_6; |
| Rc = OK; |
| case ADJUST_B_RESTORE_MIXER_6: |
| if (!xconnect_write_coefs_process(Id, plci, Rc)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Write mixer coefs failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } |
| if (plci->internal_command) |
| break; |
| plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_7; |
| case ADJUST_B_RESTORE_MIXER_7: |
| break; |
| } |
| } |
| return (Info); |
| } |
| |
| |
| static void mixer_command(dword Id, PLCI *plci, byte Rc) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| word i, internal_command; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: mixer_command %02x %04x %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command, |
| plci->li_cmd)); |
| |
| a = plci->adapter; |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| switch (plci->li_cmd) |
| { |
| case LI_REQ_CONNECT: |
| case LI_REQ_DISCONNECT: |
| case LI_REQ_SILENT_UPDATE: |
| switch (internal_command) |
| { |
| default: |
| if (plci->li_channel_bits & LI_CHANNEL_INVOLVED) |
| { |
| adjust_b1_resource(Id, plci, NULL, (word)(plci->B1_facilities | |
| B1_FACILITY_MIXER), MIXER_COMMAND_1); |
| } |
| case MIXER_COMMAND_1: |
| if (plci->li_channel_bits & LI_CHANNEL_INVOLVED) |
| { |
| if (adjust_b_process(Id, plci, Rc) != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Load mixer failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| break; |
| } |
| if (plci->internal_command) |
| return; |
| } |
| plci->li_plci_b_req_pos = plci->li_plci_b_write_pos; |
| if ((plci->li_channel_bits & LI_CHANNEL_INVOLVED) |
| || ((get_b1_facilities(plci, plci->B1_resource) & B1_FACILITY_MIXER) |
| && (add_b1_facilities(plci, plci->B1_resource, (word)(plci->B1_facilities & |
| ~B1_FACILITY_MIXER)) == plci->B1_resource))) |
| { |
| xconnect_write_coefs(plci, MIXER_COMMAND_2); |
| } |
| else |
| { |
| do |
| { |
| mixer_indication_coefs_set(Id, plci); |
| } while (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos); |
| } |
| case MIXER_COMMAND_2: |
| if ((plci->li_channel_bits & LI_CHANNEL_INVOLVED) |
| || ((get_b1_facilities(plci, plci->B1_resource) & B1_FACILITY_MIXER) |
| && (add_b1_facilities(plci, plci->B1_resource, (word)(plci->B1_facilities & |
| ~B1_FACILITY_MIXER)) == plci->B1_resource))) |
| { |
| if (!xconnect_write_coefs_process(Id, plci, Rc)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Write mixer coefs failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| if (plci->li_plci_b_write_pos != plci->li_plci_b_req_pos) |
| { |
| do |
| { |
| plci->li_plci_b_write_pos = (plci->li_plci_b_write_pos == 0) ? |
| LI_PLCI_B_QUEUE_ENTRIES - 1 : plci->li_plci_b_write_pos - 1; |
| i = (plci->li_plci_b_write_pos == 0) ? |
| LI_PLCI_B_QUEUE_ENTRIES - 1 : plci->li_plci_b_write_pos - 1; |
| } while ((plci->li_plci_b_write_pos != plci->li_plci_b_req_pos) |
| && !(plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG)); |
| } |
| break; |
| } |
| if (plci->internal_command) |
| return; |
| } |
| if (!(plci->li_channel_bits & LI_CHANNEL_INVOLVED)) |
| { |
| adjust_b1_resource(Id, plci, NULL, (word)(plci->B1_facilities & |
| ~B1_FACILITY_MIXER), MIXER_COMMAND_3); |
| } |
| case MIXER_COMMAND_3: |
| if (!(plci->li_channel_bits & LI_CHANNEL_INVOLVED)) |
| { |
| if (adjust_b_process(Id, plci, Rc) != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Unload mixer failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| break; |
| } |
| if (plci->internal_command) |
| return; |
| } |
| break; |
| } |
| break; |
| } |
| if ((plci->li_bchannel_id == 0) |
| || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci)) |
| { |
| dbug(1, dprintf("[%06x] %s,%d: Channel id wiped out %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, (int)(plci->li_bchannel_id))); |
| } |
| else |
| { |
| i = a->li_base + (plci->li_bchannel_id - 1); |
| li_config_table[i].curchnl = plci->li_channel_bits; |
| if (!a->li_pri && (plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI)) |
| { |
| i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1); |
| li_config_table[i].curchnl = plci->li_channel_bits; |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) |
| { |
| i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id); |
| li_config_table[i].curchnl = plci->li_channel_bits; |
| } |
| } |
| } |
| } |
| |
| |
| static void li_update_connect(dword Id, DIVA_CAPI_ADAPTER *a, PLCI *plci, |
| dword plci_b_id, byte connect, dword li_flags) |
| { |
| word i, ch_a, ch_a_v, ch_a_s, ch_b, ch_b_v, ch_b_s; |
| PLCI *plci_b; |
| DIVA_CAPI_ADAPTER *a_b; |
| |
| a_b = &(adapter[MapController((byte)(plci_b_id & 0x7f)) - 1]); |
| plci_b = &(a_b->plci[((plci_b_id >> 8) & 0xff) - 1]); |
| ch_a = a->li_base + (plci->li_bchannel_id - 1); |
| if (!a->li_pri && (plci->tel == ADV_VOICE) |
| && (plci == a->AdvSignalPLCI) && (Id & EXT_CONTROLLER)) |
| { |
| ch_a_v = ch_a + MIXER_IC_CHANNEL_BASE; |
| ch_a_s = (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ? |
| a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id) : ch_a_v; |
| } |
| else |
| { |
| ch_a_v = ch_a; |
| ch_a_s = ch_a; |
| } |
| ch_b = a_b->li_base + (plci_b->li_bchannel_id - 1); |
| if (!a_b->li_pri && (plci_b->tel == ADV_VOICE) |
| && (plci_b == a_b->AdvSignalPLCI) && (plci_b_id & EXT_CONTROLLER)) |
| { |
| ch_b_v = ch_b + MIXER_IC_CHANNEL_BASE; |
| ch_b_s = (a_b->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ? |
| a_b->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci_b->li_bchannel_id) : ch_b_v; |
| } |
| else |
| { |
| ch_b_v = ch_b; |
| ch_b_s = ch_b; |
| } |
| if (connect) |
| { |
| li_config_table[ch_a].flag_table[ch_a_v] &= ~LI_FLAG_MONITOR; |
| li_config_table[ch_a].flag_table[ch_a_s] &= ~LI_FLAG_MONITOR; |
| li_config_table[ch_a_v].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX); |
| li_config_table[ch_a_s].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX); |
| } |
| li_config_table[ch_a].flag_table[ch_b_v] &= ~LI_FLAG_MONITOR; |
| li_config_table[ch_a].flag_table[ch_b_s] &= ~LI_FLAG_MONITOR; |
| li_config_table[ch_b_v].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX); |
| li_config_table[ch_b_s].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX); |
| if (ch_a_v == ch_b_v) |
| { |
| li_config_table[ch_a_v].flag_table[ch_b_v] &= ~LI_FLAG_CONFERENCE; |
| li_config_table[ch_a_s].flag_table[ch_b_s] &= ~LI_FLAG_CONFERENCE; |
| } |
| else |
| { |
| if (li_config_table[ch_a_v].flag_table[ch_b_v] & LI_FLAG_CONFERENCE) |
| { |
| for (i = 0; i < li_total_channels; i++) |
| { |
| if (i != ch_a_v) |
| li_config_table[ch_a_v].flag_table[i] &= ~LI_FLAG_CONFERENCE; |
| } |
| } |
| if (li_config_table[ch_a_s].flag_table[ch_b_v] & LI_FLAG_CONFERENCE) |
| { |
| for (i = 0; i < li_total_channels; i++) |
| { |
| if (i != ch_a_s) |
| li_config_table[ch_a_s].flag_table[i] &= ~LI_FLAG_CONFERENCE; |
| } |
| } |
| if (li_config_table[ch_b_v].flag_table[ch_a_v] & LI_FLAG_CONFERENCE) |
| { |
| for (i = 0; i < li_total_channels; i++) |
| { |
| if (i != ch_a_v) |
| li_config_table[i].flag_table[ch_a_v] &= ~LI_FLAG_CONFERENCE; |
| } |
| } |
| if (li_config_table[ch_b_v].flag_table[ch_a_s] & LI_FLAG_CONFERENCE) |
| { |
| for (i = 0; i < li_total_channels; i++) |
| { |
| if (i != ch_a_s) |
| li_config_table[i].flag_table[ch_a_s] &= ~LI_FLAG_CONFERENCE; |
| } |
| } |
| } |
| if (li_flags & LI_FLAG_CONFERENCE_A_B) |
| { |
| li_config_table[ch_b_v].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE; |
| li_config_table[ch_b_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE; |
| li_config_table[ch_b_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE; |
| li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE; |
| } |
| if (li_flags & LI_FLAG_CONFERENCE_B_A) |
| { |
| li_config_table[ch_a_v].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE; |
| li_config_table[ch_a_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE; |
| li_config_table[ch_a_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE; |
| li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE; |
| } |
| if (li_flags & LI_FLAG_MONITOR_A) |
| { |
| li_config_table[ch_a].flag_table[ch_a_v] |= LI_FLAG_MONITOR; |
| li_config_table[ch_a].flag_table[ch_a_s] |= LI_FLAG_MONITOR; |
| } |
| if (li_flags & LI_FLAG_MONITOR_B) |
| { |
| li_config_table[ch_a].flag_table[ch_b_v] |= LI_FLAG_MONITOR; |
| li_config_table[ch_a].flag_table[ch_b_s] |= LI_FLAG_MONITOR; |
| } |
| if (li_flags & LI_FLAG_ANNOUNCEMENT_A) |
| { |
| li_config_table[ch_a_v].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT; |
| li_config_table[ch_a_s].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT; |
| } |
| if (li_flags & LI_FLAG_ANNOUNCEMENT_B) |
| { |
| li_config_table[ch_b_v].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT; |
| li_config_table[ch_b_s].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT; |
| } |
| if (li_flags & LI_FLAG_MIX_A) |
| { |
| li_config_table[ch_a_v].flag_table[ch_a] |= LI_FLAG_MIX; |
| li_config_table[ch_a_s].flag_table[ch_a] |= LI_FLAG_MIX; |
| } |
| if (li_flags & LI_FLAG_MIX_B) |
| { |
| li_config_table[ch_b_v].flag_table[ch_a] |= LI_FLAG_MIX; |
| li_config_table[ch_b_s].flag_table[ch_a] |= LI_FLAG_MIX; |
| } |
| if (ch_a_v != ch_a_s) |
| { |
| li_config_table[ch_a_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE; |
| li_config_table[ch_a_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE; |
| } |
| if (ch_b_v != ch_b_s) |
| { |
| li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE; |
| li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE; |
| } |
| } |
| |
| |
| static void li2_update_connect(dword Id, DIVA_CAPI_ADAPTER *a, PLCI *plci, |
| dword plci_b_id, byte connect, dword li_flags) |
| { |
| word ch_a, ch_a_v, ch_a_s, ch_b, ch_b_v, ch_b_s; |
| PLCI *plci_b; |
| DIVA_CAPI_ADAPTER *a_b; |
| |
| a_b = &(adapter[MapController((byte)(plci_b_id & 0x7f)) - 1]); |
| plci_b = &(a_b->plci[((plci_b_id >> 8) & 0xff) - 1]); |
| ch_a = a->li_base + (plci->li_bchannel_id - 1); |
| if (!a->li_pri && (plci->tel == ADV_VOICE) |
| && (plci == a->AdvSignalPLCI) && (Id & EXT_CONTROLLER)) |
| { |
| ch_a_v = ch_a + MIXER_IC_CHANNEL_BASE; |
| ch_a_s = (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ? |
| a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id) : ch_a_v; |
| } |
| else |
| { |
| ch_a_v = ch_a; |
| ch_a_s = ch_a; |
| } |
| ch_b = a_b->li_base + (plci_b->li_bchannel_id - 1); |
| if (!a_b->li_pri && (plci_b->tel == ADV_VOICE) |
| && (plci_b == a_b->AdvSignalPLCI) && (plci_b_id & EXT_CONTROLLER)) |
| { |
| ch_b_v = ch_b + MIXER_IC_CHANNEL_BASE; |
| ch_b_s = (a_b->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ? |
| a_b->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci_b->li_bchannel_id) : ch_b_v; |
| } |
| else |
| { |
| ch_b_v = ch_b; |
| ch_b_s = ch_b; |
| } |
| if (connect) |
| { |
| li_config_table[ch_b].flag_table[ch_b_v] &= ~LI_FLAG_MONITOR; |
| li_config_table[ch_b].flag_table[ch_b_s] &= ~LI_FLAG_MONITOR; |
| li_config_table[ch_b_v].flag_table[ch_b] &= ~LI_FLAG_MIX; |
| li_config_table[ch_b_s].flag_table[ch_b] &= ~LI_FLAG_MIX; |
| li_config_table[ch_b].flag_table[ch_b] &= ~LI_FLAG_PCCONNECT; |
| li_config_table[ch_b].chflags &= ~(LI_CHFLAG_MONITOR | LI_CHFLAG_MIX | LI_CHFLAG_LOOP); |
| } |
| li_config_table[ch_b_v].flag_table[ch_a_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE); |
| li_config_table[ch_b_s].flag_table[ch_a_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE); |
| li_config_table[ch_b_v].flag_table[ch_a_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE); |
| li_config_table[ch_b_s].flag_table[ch_a_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE); |
| li_config_table[ch_a_v].flag_table[ch_b_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE); |
| li_config_table[ch_a_v].flag_table[ch_b_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE); |
| li_config_table[ch_a_s].flag_table[ch_b_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE); |
| li_config_table[ch_a_s].flag_table[ch_b_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE); |
| if (li_flags & LI2_FLAG_INTERCONNECT_A_B) |
| { |
| li_config_table[ch_b_v].flag_table[ch_a_v] |= LI_FLAG_INTERCONNECT; |
| li_config_table[ch_b_s].flag_table[ch_a_v] |= LI_FLAG_INTERCONNECT; |
| li_config_table[ch_b_v].flag_table[ch_a_s] |= LI_FLAG_INTERCONNECT; |
| li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_INTERCONNECT; |
| } |
| if (li_flags & LI2_FLAG_INTERCONNECT_B_A) |
| { |
| li_config_table[ch_a_v].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT; |
| li_config_table[ch_a_v].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT; |
| li_config_table[ch_a_s].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT; |
| li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT; |
| } |
| if (li_flags & LI2_FLAG_MONITOR_B) |
| { |
| li_config_table[ch_b].flag_table[ch_b_v] |= LI_FLAG_MONITOR; |
| li_config_table[ch_b].flag_table[ch_b_s] |= LI_FLAG_MONITOR; |
| } |
| if (li_flags & LI2_FLAG_MIX_B) |
| { |
| li_config_table[ch_b_v].flag_table[ch_b] |= LI_FLAG_MIX; |
| li_config_table[ch_b_s].flag_table[ch_b] |= LI_FLAG_MIX; |
| } |
| if (li_flags & LI2_FLAG_MONITOR_X) |
| li_config_table[ch_b].chflags |= LI_CHFLAG_MONITOR; |
| if (li_flags & LI2_FLAG_MIX_X) |
| li_config_table[ch_b].chflags |= LI_CHFLAG_MIX; |
| if (li_flags & LI2_FLAG_LOOP_B) |
| { |
| li_config_table[ch_b_v].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT; |
| li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT; |
| li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT; |
| li_config_table[ch_b_s].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT; |
| } |
| if (li_flags & LI2_FLAG_LOOP_PC) |
| li_config_table[ch_b].flag_table[ch_b] |= LI_FLAG_PCCONNECT; |
| if (li_flags & LI2_FLAG_LOOP_X) |
| li_config_table[ch_b].chflags |= LI_CHFLAG_LOOP; |
| if (li_flags & LI2_FLAG_PCCONNECT_A_B) |
| li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_PCCONNECT; |
| if (li_flags & LI2_FLAG_PCCONNECT_B_A) |
| li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_PCCONNECT; |
| if (ch_a_v != ch_a_s) |
| { |
| li_config_table[ch_a_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE; |
| li_config_table[ch_a_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE; |
| } |
| if (ch_b_v != ch_b_s) |
| { |
| li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE; |
| li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE; |
| } |
| } |
| |
| |
| static word li_check_main_plci(dword Id, PLCI *plci) |
| { |
| if (plci == NULL) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong PLCI", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| return (_WRONG_IDENTIFIER); |
| } |
| if (!plci->State |
| || !plci->NL.Id || plci->nl_remove_id |
| || (plci->li_bchannel_id == 0)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong state", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| return (_WRONG_STATE); |
| } |
| li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci = plci; |
| return (GOOD); |
| } |
| |
| |
| static PLCI *li_check_plci_b(dword Id, PLCI *plci, |
| dword plci_b_id, word plci_b_write_pos, byte *p_result) |
| { |
| byte ctlr_b; |
| PLCI *plci_b; |
| |
| if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos : |
| LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: LI request overrun", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| PUT_WORD(p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE); |
| return (NULL); |
| } |
| ctlr_b = 0; |
| if ((plci_b_id & 0x7f) != 0) |
| { |
| ctlr_b = MapController((byte)(plci_b_id & 0x7f)); |
| if ((ctlr_b > max_adapter) || ((ctlr_b != 0) && (adapter[ctlr_b - 1].request == NULL))) |
| ctlr_b = 0; |
| } |
| if ((ctlr_b == 0) |
| || (((plci_b_id >> 8) & 0xff) == 0) |
| || (((plci_b_id >> 8) & 0xff) > adapter[ctlr_b - 1].max_plci)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: LI invalid second PLCI %08lx", |
| UnMapId(Id), (char *)(FILE_), __LINE__, plci_b_id)); |
| PUT_WORD(p_result, _WRONG_IDENTIFIER); |
| return (NULL); |
| } |
| plci_b = &(adapter[ctlr_b - 1].plci[((plci_b_id >> 8) & 0xff) - 1]); |
| if (!plci_b->State |
| || !plci_b->NL.Id || plci_b->nl_remove_id |
| || (plci_b->li_bchannel_id == 0)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: LI peer in wrong state %08lx", |
| UnMapId(Id), (char *)(FILE_), __LINE__, plci_b_id)); |
| PUT_WORD(p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE); |
| return (NULL); |
| } |
| li_config_table[plci_b->adapter->li_base + (plci_b->li_bchannel_id - 1)].plci = plci_b; |
| if (((byte)(plci_b_id & ~EXT_CONTROLLER)) != |
| ((byte)(UnMapController(plci->adapter->Id) & ~EXT_CONTROLLER)) |
| && (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT) |
| || !(plci_b->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT))) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: LI not on same ctrl %08lx", |
| UnMapId(Id), (char *)(FILE_), __LINE__, plci_b_id)); |
| PUT_WORD(p_result, _WRONG_IDENTIFIER); |
| return (NULL); |
| } |
| if (!(get_b1_facilities(plci_b, add_b1_facilities(plci_b, plci_b->B1_resource, |
| (word)(plci_b->B1_facilities | B1_FACILITY_MIXER))) & B1_FACILITY_MIXER)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Interconnect peer cannot mix %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, plci_b->B1_resource)); |
| PUT_WORD(p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE); |
| return (NULL); |
| } |
| return (plci_b); |
| } |
| |
| |
| static PLCI *li2_check_plci_b(dword Id, PLCI *plci, |
| dword plci_b_id, word plci_b_write_pos, byte *p_result) |
| { |
| byte ctlr_b; |
| PLCI *plci_b; |
| |
| if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos : |
| LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: LI request overrun", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| PUT_WORD(p_result, _WRONG_STATE); |
| return (NULL); |
| } |
| ctlr_b = 0; |
| if ((plci_b_id & 0x7f) != 0) |
| { |
| ctlr_b = MapController((byte)(plci_b_id & 0x7f)); |
| if ((ctlr_b > max_adapter) || ((ctlr_b != 0) && (adapter[ctlr_b - 1].request == NULL))) |
| ctlr_b = 0; |
| } |
| if ((ctlr_b == 0) |
| || (((plci_b_id >> 8) & 0xff) == 0) |
| || (((plci_b_id >> 8) & 0xff) > adapter[ctlr_b - 1].max_plci)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: LI invalid second PLCI %08lx", |
| UnMapId(Id), (char *)(FILE_), __LINE__, plci_b_id)); |
| PUT_WORD(p_result, _WRONG_IDENTIFIER); |
| return (NULL); |
| } |
| plci_b = &(adapter[ctlr_b - 1].plci[((plci_b_id >> 8) & 0xff) - 1]); |
| if (!plci_b->State |
| || !plci_b->NL.Id || plci_b->nl_remove_id |
| || (plci_b->li_bchannel_id == 0) |
| || (li_config_table[plci_b->adapter->li_base + (plci_b->li_bchannel_id - 1)].plci != plci_b)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: LI peer in wrong state %08lx", |
| UnMapId(Id), (char *)(FILE_), __LINE__, plci_b_id)); |
| PUT_WORD(p_result, _WRONG_STATE); |
| return (NULL); |
| } |
| if (((byte)(plci_b_id & ~EXT_CONTROLLER)) != |
| ((byte)(UnMapController(plci->adapter->Id) & ~EXT_CONTROLLER)) |
| && (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT) |
| || !(plci_b->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT))) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: LI not on same ctrl %08lx", |
| UnMapId(Id), (char *)(FILE_), __LINE__, plci_b_id)); |
| PUT_WORD(p_result, _WRONG_IDENTIFIER); |
| return (NULL); |
| } |
| if (!(get_b1_facilities(plci_b, add_b1_facilities(plci_b, plci_b->B1_resource, |
| (word)(plci_b->B1_facilities | B1_FACILITY_MIXER))) & B1_FACILITY_MIXER)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Interconnect peer cannot mix %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, plci_b->B1_resource)); |
| PUT_WORD(p_result, _WRONG_STATE); |
| return (NULL); |
| } |
| return (plci_b); |
| } |
| |
| |
| static byte mixer_request(dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg) |
| { |
| word Info; |
| word i; |
| dword d, li_flags, plci_b_id; |
| PLCI *plci_b; |
| API_PARSE li_parms[3]; |
| API_PARSE li_req_parms[3]; |
| API_PARSE li_participant_struct[2]; |
| API_PARSE li_participant_parms[3]; |
| word participant_parms_pos; |
| byte result_buffer[32]; |
| byte *result; |
| word result_pos; |
| word plci_b_write_pos; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: mixer_request", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| |
| Info = GOOD; |
| result = result_buffer; |
| result_buffer[0] = 0; |
| if (!(a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Facility not supported", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _FACILITY_NOT_SUPPORTED; |
| } |
| else if (api_parse(&msg[1].info[1], msg[1].length, "ws", li_parms)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong message format", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_MESSAGE_FORMAT; |
| } |
| else |
| { |
| result_buffer[0] = 3; |
| PUT_WORD(&result_buffer[1], GET_WORD(li_parms[0].info)); |
| result_buffer[3] = 0; |
| switch (GET_WORD(li_parms[0].info)) |
| { |
| case LI_GET_SUPPORTED_SERVICES: |
| if (appl->appl_flags & APPL_FLAG_OLD_LI_SPEC) |
| { |
| result_buffer[0] = 17; |
| result_buffer[3] = 14; |
| PUT_WORD(&result_buffer[4], GOOD); |
| d = 0; |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_CH) |
| d |= LI_CONFERENCING_SUPPORTED; |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_PC) |
| d |= LI_MONITORING_SUPPORTED; |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_CH) |
| d |= LI_ANNOUNCEMENTS_SUPPORTED | LI_MIXING_SUPPORTED; |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT) |
| d |= LI_CROSS_CONTROLLER_SUPPORTED; |
| PUT_DWORD(&result_buffer[6], d); |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT) |
| { |
| d = 0; |
| for (i = 0; i < li_total_channels; i++) |
| { |
| if ((li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT) |
| && (li_config_table[i].adapter->li_pri |
| || (i < li_config_table[i].adapter->li_base + MIXER_BCHANNELS_BRI))) |
| { |
| d++; |
| } |
| } |
| } |
| else |
| { |
| d = a->li_pri ? a->li_channels : MIXER_BCHANNELS_BRI; |
| } |
| PUT_DWORD(&result_buffer[10], d / 2); |
| PUT_DWORD(&result_buffer[14], d); |
| } |
| else |
| { |
| result_buffer[0] = 25; |
| result_buffer[3] = 22; |
| PUT_WORD(&result_buffer[4], GOOD); |
| d = LI2_ASYMMETRIC_SUPPORTED | LI2_B_LOOPING_SUPPORTED | LI2_X_LOOPING_SUPPORTED; |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_PC) |
| d |= LI2_MONITORING_SUPPORTED | LI2_REMOTE_MONITORING_SUPPORTED; |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_CH) |
| d |= LI2_MIXING_SUPPORTED | LI2_REMOTE_MIXING_SUPPORTED; |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_PC) |
| d |= LI2_PC_LOOPING_SUPPORTED; |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT) |
| d |= LI2_CROSS_CONTROLLER_SUPPORTED; |
| PUT_DWORD(&result_buffer[6], d); |
| d = a->li_pri ? a->li_channels : MIXER_BCHANNELS_BRI; |
| PUT_DWORD(&result_buffer[10], d / 2); |
| PUT_DWORD(&result_buffer[14], d - 1); |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT) |
| { |
| d = 0; |
| for (i = 0; i < li_total_channels; i++) |
| { |
| if ((li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT) |
| && (li_config_table[i].adapter->li_pri |
| || (i < li_config_table[i].adapter->li_base + MIXER_BCHANNELS_BRI))) |
| { |
| d++; |
| } |
| } |
| } |
| PUT_DWORD(&result_buffer[18], d / 2); |
| PUT_DWORD(&result_buffer[22], d - 1); |
| } |
| break; |
| |
| case LI_REQ_CONNECT: |
| if (li_parms[1].length == 8) |
| { |
| appl->appl_flags |= APPL_FLAG_OLD_LI_SPEC; |
| if (api_parse(&li_parms[1].info[1], li_parms[1].length, "dd", li_req_parms)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong message format", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| plci_b_id = GET_DWORD(li_req_parms[0].info) & 0xffff; |
| li_flags = GET_DWORD(li_req_parms[1].info); |
| Info = li_check_main_plci(Id, plci); |
| result_buffer[0] = 9; |
| result_buffer[3] = 6; |
| PUT_DWORD(&result_buffer[4], plci_b_id); |
| PUT_WORD(&result_buffer[8], GOOD); |
| if (Info != GOOD) |
| break; |
| result = plci->saved_msg.info; |
| for (i = 0; i <= result_buffer[0]; i++) |
| result[i] = result_buffer[i]; |
| plci_b_write_pos = plci->li_plci_b_write_pos; |
| plci_b = li_check_plci_b(Id, plci, plci_b_id, plci_b_write_pos, &result[8]); |
| if (plci_b == NULL) |
| break; |
| li_update_connect(Id, a, plci, plci_b_id, true, li_flags); |
| plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_LAST_FLAG; |
| plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1; |
| plci->li_plci_b_write_pos = plci_b_write_pos; |
| } |
| else |
| { |
| appl->appl_flags &= ~APPL_FLAG_OLD_LI_SPEC; |
| if (api_parse(&li_parms[1].info[1], li_parms[1].length, "ds", li_req_parms)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong message format", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| li_flags = GET_DWORD(li_req_parms[0].info) & ~(LI2_FLAG_INTERCONNECT_A_B | LI2_FLAG_INTERCONNECT_B_A); |
| Info = li_check_main_plci(Id, plci); |
| result_buffer[0] = 7; |
| result_buffer[3] = 4; |
| PUT_WORD(&result_buffer[4], Info); |
| result_buffer[6] = 0; |
| if (Info != GOOD) |
| break; |
| result = plci->saved_msg.info; |
| for (i = 0; i <= result_buffer[0]; i++) |
| result[i] = result_buffer[i]; |
| plci_b_write_pos = plci->li_plci_b_write_pos; |
| participant_parms_pos = 0; |
| result_pos = 7; |
| li2_update_connect(Id, a, plci, UnMapId(Id), true, li_flags); |
| while (participant_parms_pos < li_req_parms[1].length) |
| { |
| result[result_pos] = 6; |
| result_pos += 7; |
| PUT_DWORD(&result[result_pos - 6], 0); |
| PUT_WORD(&result[result_pos - 2], GOOD); |
| if (api_parse(&li_req_parms[1].info[1 + participant_parms_pos], |
| (word)(li_parms[1].length - participant_parms_pos), "s", li_participant_struct)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong message format", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| PUT_WORD(&result[result_pos - 2], _WRONG_MESSAGE_FORMAT); |
| break; |
| } |
| if (api_parse(&li_participant_struct[0].info[1], |
| li_participant_struct[0].length, "dd", li_participant_parms)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong message format", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| PUT_WORD(&result[result_pos - 2], _WRONG_MESSAGE_FORMAT); |
| break; |
| } |
| plci_b_id = GET_DWORD(li_participant_parms[0].info) & 0xffff; |
| li_flags = GET_DWORD(li_participant_parms[1].info); |
| PUT_DWORD(&result[result_pos - 6], plci_b_id); |
| if (sizeof(result) - result_pos < 7) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: LI result overrun", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| PUT_WORD(&result[result_pos - 2], _WRONG_STATE); |
| break; |
| } |
| plci_b = li2_check_plci_b(Id, plci, plci_b_id, plci_b_write_pos, &result[result_pos - 2]); |
| if (plci_b != NULL) |
| { |
| li2_update_connect(Id, a, plci, plci_b_id, true, li_flags); |
| plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | |
| ((li_flags & (LI2_FLAG_INTERCONNECT_A_B | LI2_FLAG_INTERCONNECT_B_A | |
| LI2_FLAG_PCCONNECT_A_B | LI2_FLAG_PCCONNECT_B_A)) ? 0 : LI_PLCI_B_DISC_FLAG); |
| plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1; |
| } |
| participant_parms_pos = (word)((&li_participant_struct[0].info[1 + li_participant_struct[0].length]) - |
| (&li_req_parms[1].info[1])); |
| } |
| result[0] = (byte)(result_pos - 1); |
| result[3] = (byte)(result_pos - 4); |
| result[6] = (byte)(result_pos - 7); |
| i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES - 1 : plci_b_write_pos - 1; |
| if ((plci_b_write_pos == plci->li_plci_b_read_pos) |
| || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG)) |
| { |
| plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG; |
| plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1; |
| } |
| else |
| plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG; |
| plci->li_plci_b_write_pos = plci_b_write_pos; |
| } |
| mixer_calculate_coefs(a); |
| plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel; |
| mixer_notify_update(plci, true); |
| sendf(appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number, |
| "wwS", Info, SELECTOR_LINE_INTERCONNECT, result); |
| plci->command = 0; |
| plci->li_cmd = GET_WORD(li_parms[0].info); |
| start_internal_command(Id, plci, mixer_command); |
| return (false); |
| |
| case LI_REQ_DISCONNECT: |
| if (li_parms[1].length == 4) |
| { |
| appl->appl_flags |= APPL_FLAG_OLD_LI_SPEC; |
| if (api_parse(&li_parms[1].info[1], li_parms[1].length, "d", li_req_parms)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong message format", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| plci_b_id = GET_DWORD(li_req_parms[0].info) & 0xffff; |
| Info = li_check_main_plci(Id, plci); |
| result_buffer[0] = 9; |
| result_buffer[3] = 6; |
| PUT_DWORD(&result_buffer[4], GET_DWORD(li_req_parms[0].info)); |
| PUT_WORD(&result_buffer[8], GOOD); |
| if (Info != GOOD) |
| break; |
| result = plci->saved_msg.info; |
| for (i = 0; i <= result_buffer[0]; i++) |
| result[i] = result_buffer[i]; |
| plci_b_write_pos = plci->li_plci_b_write_pos; |
| plci_b = li_check_plci_b(Id, plci, plci_b_id, plci_b_write_pos, &result[8]); |
| if (plci_b == NULL) |
| break; |
| li_update_connect(Id, a, plci, plci_b_id, false, 0); |
| plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG | LI_PLCI_B_LAST_FLAG; |
| plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1; |
| plci->li_plci_b_write_pos = plci_b_write_pos; |
| } |
| else |
| { |
| appl->appl_flags &= ~APPL_FLAG_OLD_LI_SPEC; |
| if (api_parse(&li_parms[1].info[1], li_parms[1].length, "s", li_req_parms)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong message format", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_MESSAGE_FORMAT; |
| break; |
| } |
| Info = li_check_main_plci(Id, plci); |
| result_buffer[0] = 7; |
| result_buffer[3] = 4; |
| PUT_WORD(&result_buffer[4], Info); |
| result_buffer[6] = 0; |
| if (Info != GOOD) |
| break; |
| result = plci->saved_msg.info; |
| for (i = 0; i <= result_buffer[0]; i++) |
| result[i] = result_buffer[i]; |
| plci_b_write_pos = plci->li_plci_b_write_pos; |
| participant_parms_pos = 0; |
| result_pos = 7; |
| while (participant_parms_pos < li_req_parms[0].length) |
| { |
| result[result_pos] = 6; |
| result_pos += 7; |
| PUT_DWORD(&result[result_pos - 6], 0); |
| PUT_WORD(&result[result_pos - 2], GOOD); |
| if (api_parse(&li_req_parms[0].info[1 + participant_parms_pos], |
| (word)(li_parms[1].length - participant_parms_pos), "s", li_participant_struct)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong message format", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| PUT_WORD(&result[result_pos - 2], _WRONG_MESSAGE_FORMAT); |
| break; |
| } |
| if (api_parse(&li_participant_struct[0].info[1], |
| li_participant_struct[0].length, "d", li_participant_parms)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong message format", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| PUT_WORD(&result[result_pos - 2], _WRONG_MESSAGE_FORMAT); |
| break; |
| } |
| plci_b_id = GET_DWORD(li_participant_parms[0].info) & 0xffff; |
| PUT_DWORD(&result[result_pos - 6], plci_b_id); |
| if (sizeof(result) - result_pos < 7) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: LI result overrun", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| PUT_WORD(&result[result_pos - 2], _WRONG_STATE); |
| break; |
| } |
| plci_b = li2_check_plci_b(Id, plci, plci_b_id, plci_b_write_pos, &result[result_pos - 2]); |
| if (plci_b != NULL) |
| { |
| li2_update_connect(Id, a, plci, plci_b_id, false, 0); |
| plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG; |
| plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1; |
| } |
| participant_parms_pos = (word)((&li_participant_struct[0].info[1 + li_participant_struct[0].length]) - |
| (&li_req_parms[0].info[1])); |
| } |
| result[0] = (byte)(result_pos - 1); |
| result[3] = (byte)(result_pos - 4); |
| result[6] = (byte)(result_pos - 7); |
| i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES - 1 : plci_b_write_pos - 1; |
| if ((plci_b_write_pos == plci->li_plci_b_read_pos) |
| || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG)) |
| { |
| plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG; |
| plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1; |
| } |
| else |
| plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG; |
| plci->li_plci_b_write_pos = plci_b_write_pos; |
| } |
| mixer_calculate_coefs(a); |
| plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel; |
| mixer_notify_update(plci, true); |
| sendf(appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number, |
| "wwS", Info, SELECTOR_LINE_INTERCONNECT, result); |
| plci->command = 0; |
| plci->li_cmd = GET_WORD(li_parms[0].info); |
| start_internal_command(Id, plci, mixer_command); |
| return (false); |
| |
| case LI_REQ_SILENT_UPDATE: |
| if (!plci || !plci->State |
| || !plci->NL.Id || plci->nl_remove_id |
| || (plci->li_bchannel_id == 0) |
| || (li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci != plci)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong state", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| return (false); |
| } |
| plci_b_write_pos = plci->li_plci_b_write_pos; |
| if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos : |
| LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: LI request overrun", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| return (false); |
| } |
| i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES - 1 : plci_b_write_pos - 1; |
| if ((plci_b_write_pos == plci->li_plci_b_read_pos) |
| || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG)) |
| { |
| plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG; |
| plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1; |
| } |
| else |
| plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG; |
| plci->li_plci_b_write_pos = plci_b_write_pos; |
| plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel; |
| plci->command = 0; |
| plci->li_cmd = GET_WORD(li_parms[0].info); |
| start_internal_command(Id, plci, mixer_command); |
| return (false); |
| |
| default: |
| dbug(1, dprintf("[%06lx] %s,%d: LI unknown request %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, GET_WORD(li_parms[0].info))); |
| Info = _FACILITY_NOT_SUPPORTED; |
| } |
| } |
| sendf(appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number, |
| "wwS", Info, SELECTOR_LINE_INTERCONNECT, result); |
| return (false); |
| } |
| |
| |
| static void mixer_indication_coefs_set(dword Id, PLCI *plci) |
| { |
| dword d; |
| byte result[12]; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: mixer_indication_coefs_set", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| |
| if (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos) |
| { |
| do |
| { |
| d = plci->li_plci_b_queue[plci->li_plci_b_read_pos]; |
| if (!(d & LI_PLCI_B_SKIP_FLAG)) |
| { |
| if (plci->appl->appl_flags & APPL_FLAG_OLD_LI_SPEC) |
| { |
| if (d & LI_PLCI_B_DISC_FLAG) |
| { |
| result[0] = 5; |
| PUT_WORD(&result[1], LI_IND_DISCONNECT); |
| result[3] = 2; |
| PUT_WORD(&result[4], _LI_USER_INITIATED); |
| } |
| else |
| { |
| result[0] = 7; |
| PUT_WORD(&result[1], LI_IND_CONNECT_ACTIVE); |
| result[3] = 4; |
| PUT_DWORD(&result[4], d & ~LI_PLCI_B_FLAG_MASK); |
| } |
| } |
| else |
| { |
| if (d & LI_PLCI_B_DISC_FLAG) |
| { |
| result[0] = 9; |
| PUT_WORD(&result[1], LI_IND_DISCONNECT); |
| result[3] = 6; |
| PUT_DWORD(&result[4], d & ~LI_PLCI_B_FLAG_MASK); |
| PUT_WORD(&result[8], _LI_USER_INITIATED); |
| } |
| else |
| { |
| result[0] = 7; |
| PUT_WORD(&result[1], LI_IND_CONNECT_ACTIVE); |
| result[3] = 4; |
| PUT_DWORD(&result[4], d & ~LI_PLCI_B_FLAG_MASK); |
| } |
| } |
| sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0, |
| "ws", SELECTOR_LINE_INTERCONNECT, result); |
| } |
| plci->li_plci_b_read_pos = (plci->li_plci_b_read_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? |
| 0 : plci->li_plci_b_read_pos + 1; |
| } while (!(d & LI_PLCI_B_LAST_FLAG) && (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos)); |
| } |
| } |
| |
| |
| static void mixer_indication_xconnect_from(dword Id, PLCI *plci, byte *msg, word length) |
| { |
| word i, j, ch; |
| struct xconnect_transfer_address_s s, *p; |
| DIVA_CAPI_ADAPTER *a; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: mixer_indication_xconnect_from %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, (int)length)); |
| |
| a = plci->adapter; |
| i = 1; |
| for (i = 1; i < length; i += 16) |
| { |
| s.card_address.low = msg[i] | (msg[i + 1] << 8) | (((dword)(msg[i + 2])) << 16) | (((dword)(msg[i + 3])) << 24); |
| s.card_address.high = msg[i + 4] | (msg[i + 5] << 8) | (((dword)(msg[i + 6])) << 16) | (((dword)(msg[i + 7])) << 24); |
| s.offset = msg[i + 8] | (msg[i + 9] << 8) | (((dword)(msg[i + 10])) << 16) | (((dword)(msg[i + 11])) << 24); |
| ch = msg[i + 12] | (msg[i + 13] << 8); |
| j = ch & XCONNECT_CHANNEL_NUMBER_MASK; |
| if (!a->li_pri && (plci->li_bchannel_id == 2)) |
| j = 1 - j; |
| j += a->li_base; |
| if (ch & XCONNECT_CHANNEL_PORT_PC) |
| p = &(li_config_table[j].send_pc); |
| else |
| p = &(li_config_table[j].send_b); |
| p->card_address.low = s.card_address.low; |
| p->card_address.high = s.card_address.high; |
| p->offset = s.offset; |
| li_config_table[j].channel |= LI_CHANNEL_ADDRESSES_SET; |
| } |
| if (plci->internal_command_queue[0] |
| && ((plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2) |
| || (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_3) |
| || (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_4))) |
| { |
| (*(plci->internal_command_queue[0]))(Id, plci, 0); |
| if (!plci->internal_command) |
| next_internal_command(Id, plci); |
| } |
| mixer_notify_update(plci, true); |
| } |
| |
| |
| static void mixer_indication_xconnect_to(dword Id, PLCI *plci, byte *msg, word length) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: mixer_indication_xconnect_to %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, (int) length)); |
| |
| } |
| |
| |
| static byte mixer_notify_source_removed(PLCI *plci, dword plci_b_id) |
| { |
| word plci_b_write_pos; |
| |
| plci_b_write_pos = plci->li_plci_b_write_pos; |
| if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos : |
| LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 1) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: LI request overrun", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| return (false); |
| } |
| plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG; |
| plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1; |
| plci->li_plci_b_write_pos = plci_b_write_pos; |
| return (true); |
| } |
| |
| |
| static void mixer_remove(PLCI *plci) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| PLCI *notify_plci; |
| dword plci_b_id; |
| word i, j; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: mixer_remove", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| |
| a = plci->adapter; |
| plci_b_id = (plci->Id << 8) | UnMapController(plci->adapter->Id); |
| if (a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED) |
| { |
| if ((plci->li_bchannel_id != 0) |
| && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci)) |
| { |
| i = a->li_base + (plci->li_bchannel_id - 1); |
| if ((li_config_table[i].curchnl | li_config_table[i].channel) & LI_CHANNEL_INVOLVED) |
| { |
| for (j = 0; j < li_total_channels; j++) |
| { |
| if ((li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT) |
| || (li_config_table[j].flag_table[i] & LI_FLAG_INTERCONNECT)) |
| { |
| notify_plci = li_config_table[j].plci; |
| if ((notify_plci != NULL) |
| && (notify_plci != plci) |
| && (notify_plci->appl != NULL) |
| && !(notify_plci->appl->appl_flags & APPL_FLAG_OLD_LI_SPEC) |
| && (notify_plci->State) |
| && notify_plci->NL.Id && !notify_plci->nl_remove_id) |
| { |
| mixer_notify_source_removed(notify_plci, plci_b_id); |
| } |
| } |
| } |
| mixer_clear_config(plci); |
| mixer_calculate_coefs(a); |
| mixer_notify_update(plci, true); |
| } |
| li_config_table[i].plci = NULL; |
| plci->li_bchannel_id = 0; |
| } |
| } |
| } |
| |
| |
| /*------------------------------------------------------------------*/ |
| /* Echo canceller facilities */ |
| /*------------------------------------------------------------------*/ |
| |
| |
| static void ec_write_parameters(PLCI *plci) |
| { |
| word w; |
| byte parameter_buffer[6]; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: ec_write_parameters", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| |
| parameter_buffer[0] = 5; |
| parameter_buffer[1] = DSP_CTRL_SET_LEC_PARAMETERS; |
| PUT_WORD(¶meter_buffer[2], plci->ec_idi_options); |
| plci->ec_idi_options &= ~LEC_RESET_COEFFICIENTS; |
| w = (plci->ec_tail_length == 0) ? 128 : plci->ec_tail_length; |
| PUT_WORD(¶meter_buffer[4], w); |
| add_p(plci, FTY, parameter_buffer); |
| sig_req(plci, TEL_CTRL, 0); |
| send_req(plci); |
| } |
| |
| |
| static void ec_clear_config(PLCI *plci) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: ec_clear_config", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| |
| plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER | |
| LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING; |
| plci->ec_tail_length = 0; |
| } |
| |
| |
| static void ec_prepare_switch(dword Id, PLCI *plci) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: ec_prepare_switch", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| |
| } |
| |
| |
| static word ec_save_config(dword Id, PLCI *plci, byte Rc) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: ec_save_config %02x %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state)); |
| |
| return (GOOD); |
| } |
| |
| |
| static word ec_restore_config(dword Id, PLCI *plci, byte Rc) |
| { |
| word Info; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: ec_restore_config %02x %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state)); |
| |
| Info = GOOD; |
| if (plci->B1_facilities & B1_FACILITY_EC) |
| { |
| switch (plci->adjust_b_state) |
| { |
| case ADJUST_B_RESTORE_EC_1: |
| plci->internal_command = plci->adjust_b_command; |
| if (plci->sig_req) |
| { |
| plci->adjust_b_state = ADJUST_B_RESTORE_EC_1; |
| break; |
| } |
| ec_write_parameters(plci); |
| plci->adjust_b_state = ADJUST_B_RESTORE_EC_2; |
| break; |
| case ADJUST_B_RESTORE_EC_2: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Restore EC failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| Info = _WRONG_STATE; |
| break; |
| } |
| break; |
| } |
| } |
| return (Info); |
| } |
| |
| |
| static void ec_command(dword Id, PLCI *plci, byte Rc) |
| { |
| word internal_command, Info; |
| byte result[8]; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: ec_command %02x %04x %04x %04x %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command, |
| plci->ec_cmd, plci->ec_idi_options, plci->ec_tail_length)); |
| |
| Info = GOOD; |
| if (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) |
| { |
| result[0] = 2; |
| PUT_WORD(&result[1], EC_SUCCESS); |
| } |
| else |
| { |
| result[0] = 5; |
| PUT_WORD(&result[1], plci->ec_cmd); |
| result[3] = 2; |
| PUT_WORD(&result[4], GOOD); |
| } |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| switch (plci->ec_cmd) |
| { |
| case EC_ENABLE_OPERATION: |
| case EC_FREEZE_COEFFICIENTS: |
| case EC_RESUME_COEFFICIENT_UPDATE: |
| case EC_RESET_COEFFICIENTS: |
| switch (internal_command) |
| { |
| default: |
| adjust_b1_resource(Id, plci, NULL, (word)(plci->B1_facilities | |
| B1_FACILITY_EC), EC_COMMAND_1); |
| case EC_COMMAND_1: |
| if (adjust_b_process(Id, plci, Rc) != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Load EC failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } |
| if (plci->internal_command) |
| return; |
| case EC_COMMAND_2: |
| if (plci->sig_req) |
| { |
| plci->internal_command = EC_COMMAND_2; |
| return; |
| } |
| plci->internal_command = EC_COMMAND_3; |
| ec_write_parameters(plci); |
| return; |
| case EC_COMMAND_3: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Enable EC failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } |
| break; |
| } |
| break; |
| |
| case EC_DISABLE_OPERATION: |
| switch (internal_command) |
| { |
| default: |
| case EC_COMMAND_1: |
| if (plci->B1_facilities & B1_FACILITY_EC) |
| { |
| if (plci->sig_req) |
| { |
| plci->internal_command = EC_COMMAND_1; |
| return; |
| } |
| plci->internal_command = EC_COMMAND_2; |
| ec_write_parameters(plci); |
| return; |
| } |
| Rc = OK; |
| case EC_COMMAND_2: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Disable EC failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } |
| adjust_b1_resource(Id, plci, NULL, (word)(plci->B1_facilities & |
| ~B1_FACILITY_EC), EC_COMMAND_3); |
| case EC_COMMAND_3: |
| if (adjust_b_process(Id, plci, Rc) != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Unload EC failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _FACILITY_NOT_SUPPORTED; |
| break; |
| } |
| if (plci->internal_command) |
| return; |
| break; |
| } |
| break; |
| } |
| sendf(plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->number, |
| "wws", Info, (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ? |
| PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result); |
| } |
| |
| |
| static byte ec_request(dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg) |
| { |
| word Info; |
| word opt; |
| API_PARSE ec_parms[3]; |
| byte result[16]; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: ec_request", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| |
| Info = GOOD; |
| result[0] = 0; |
| if (!(a->man_profile.private_options & (1L << PRIVATE_ECHO_CANCELLER))) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Facility not supported", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _FACILITY_NOT_SUPPORTED; |
| } |
| else |
| { |
| if (appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) |
| { |
| if (api_parse(&msg[1].info[1], msg[1].length, "w", ec_parms)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong message format", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_MESSAGE_FORMAT; |
| } |
| else |
| { |
| if (plci == NULL) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong PLCI", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_IDENTIFIER; |
| } |
| else if (!plci->State || !plci->NL.Id || plci->nl_remove_id) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong state", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_STATE; |
| } |
| else |
| { |
| plci->command = 0; |
| plci->ec_cmd = GET_WORD(ec_parms[0].info); |
| plci->ec_idi_options &= ~(LEC_MANUAL_DISABLE | LEC_RESET_COEFFICIENTS); |
| result[0] = 2; |
| PUT_WORD(&result[1], EC_SUCCESS); |
| if (msg[1].length >= 4) |
| { |
| opt = GET_WORD(&ec_parms[0].info[2]); |
| plci->ec_idi_options &= ~(LEC_ENABLE_NONLINEAR_PROCESSING | |
| LEC_ENABLE_2100HZ_DETECTOR | LEC_REQUIRE_2100HZ_REVERSALS); |
| if (!(opt & EC_DISABLE_NON_LINEAR_PROCESSING)) |
| plci->ec_idi_options |= LEC_ENABLE_NONLINEAR_PROCESSING; |
| if (opt & EC_DETECT_DISABLE_TONE) |
| plci->ec_idi_options |= LEC_ENABLE_2100HZ_DETECTOR; |
| if (!(opt & EC_DO_NOT_REQUIRE_REVERSALS)) |
| plci->ec_idi_options |= LEC_REQUIRE_2100HZ_REVERSALS; |
| if (msg[1].length >= 6) |
| { |
| plci->ec_tail_length = GET_WORD(&ec_parms[0].info[4]); |
| } |
| } |
| switch (plci->ec_cmd) |
| { |
| case EC_ENABLE_OPERATION: |
| plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS; |
| start_internal_command(Id, plci, ec_command); |
| return (false); |
| |
| case EC_DISABLE_OPERATION: |
| plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER | |
| LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING | |
| LEC_RESET_COEFFICIENTS; |
| start_internal_command(Id, plci, ec_command); |
| return (false); |
| |
| case EC_FREEZE_COEFFICIENTS: |
| plci->ec_idi_options |= LEC_FREEZE_COEFFICIENTS; |
| start_internal_command(Id, plci, ec_command); |
| return (false); |
| |
| case EC_RESUME_COEFFICIENT_UPDATE: |
| plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS; |
| start_internal_command(Id, plci, ec_command); |
| return (false); |
| |
| case EC_RESET_COEFFICIENTS: |
| plci->ec_idi_options |= LEC_RESET_COEFFICIENTS; |
| start_internal_command(Id, plci, ec_command); |
| return (false); |
| |
| default: |
| dbug(1, dprintf("[%06lx] %s,%d: EC unknown request %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, plci->ec_cmd)); |
| PUT_WORD(&result[1], EC_UNSUPPORTED_OPERATION); |
| } |
| } |
| } |
| } |
| else |
| { |
| if (api_parse(&msg[1].info[1], msg[1].length, "ws", ec_parms)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong message format", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_MESSAGE_FORMAT; |
| } |
| else |
| { |
| if (GET_WORD(ec_parms[0].info) == EC_GET_SUPPORTED_SERVICES) |
| { |
| result[0] = 11; |
| PUT_WORD(&result[1], EC_GET_SUPPORTED_SERVICES); |
| result[3] = 8; |
| PUT_WORD(&result[4], GOOD); |
| PUT_WORD(&result[6], 0x0007); |
| PUT_WORD(&result[8], LEC_MAX_SUPPORTED_TAIL_LENGTH); |
| PUT_WORD(&result[10], 0); |
| } |
| else if (plci == NULL) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong PLCI", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_IDENTIFIER; |
| } |
| else if (!plci->State || !plci->NL.Id || plci->nl_remove_id) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Wrong state", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| Info = _WRONG_STATE; |
| } |
| else |
| { |
| plci->command = 0; |
| plci->ec_cmd = GET_WORD(ec_parms[0].info); |
| plci->ec_idi_options &= ~(LEC_MANUAL_DISABLE | LEC_RESET_COEFFICIENTS); |
| result[0] = 5; |
| PUT_WORD(&result[1], plci->ec_cmd); |
| result[3] = 2; |
| PUT_WORD(&result[4], GOOD); |
| plci->ec_idi_options &= ~(LEC_ENABLE_NONLINEAR_PROCESSING | |
| LEC_ENABLE_2100HZ_DETECTOR | LEC_REQUIRE_2100HZ_REVERSALS); |
| plci->ec_tail_length = 0; |
| if (ec_parms[1].length >= 2) |
| { |
| opt = GET_WORD(&ec_parms[1].info[1]); |
| if (opt & EC_ENABLE_NON_LINEAR_PROCESSING) |
| plci->ec_idi_options |= LEC_ENABLE_NONLINEAR_PROCESSING; |
| if (opt & EC_DETECT_DISABLE_TONE) |
| plci->ec_idi_options |= LEC_ENABLE_2100HZ_DETECTOR; |
| if (!(opt & EC_DO_NOT_REQUIRE_REVERSALS)) |
| plci->ec_idi_options |= LEC_REQUIRE_2100HZ_REVERSALS; |
| if (ec_parms[1].length >= 4) |
| { |
| plci->ec_tail_length = GET_WORD(&ec_parms[1].info[3]); |
| } |
| } |
| switch (plci->ec_cmd) |
| { |
| case EC_ENABLE_OPERATION: |
| plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS; |
| start_internal_command(Id, plci, ec_command); |
| return (false); |
| |
| case EC_DISABLE_OPERATION: |
| plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER | |
| LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING | |
| LEC_RESET_COEFFICIENTS; |
| start_internal_command(Id, plci, ec_command); |
| return (false); |
| |
| default: |
| dbug(1, dprintf("[%06lx] %s,%d: EC unknown request %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, plci->ec_cmd)); |
| PUT_WORD(&result[4], _FACILITY_SPECIFIC_FUNCTION_NOT_SUPP); |
| } |
| } |
| } |
| } |
| } |
| sendf(appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number, |
| "wws", Info, (appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ? |
| PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result); |
| return (false); |
| } |
| |
| |
| static void ec_indication(dword Id, PLCI *plci, byte *msg, word length) |
| { |
| byte result[8]; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: ec_indication", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| |
| if (!(plci->ec_idi_options & LEC_MANUAL_DISABLE)) |
| { |
| if (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) |
| { |
| result[0] = 2; |
| PUT_WORD(&result[1], 0); |
| switch (msg[1]) |
| { |
| case LEC_DISABLE_TYPE_CONTIGNUOUS_2100HZ: |
| PUT_WORD(&result[1], EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ); |
| break; |
| case LEC_DISABLE_TYPE_REVERSED_2100HZ: |
| PUT_WORD(&result[1], EC_BYPASS_DUE_TO_REVERSED_2100HZ); |
| break; |
| case LEC_DISABLE_RELEASED: |
| PUT_WORD(&result[1], EC_BYPASS_RELEASED); |
| break; |
| } |
| } |
| else |
| { |
| result[0] = 5; |
| PUT_WORD(&result[1], EC_BYPASS_INDICATION); |
| result[3] = 2; |
| PUT_WORD(&result[4], 0); |
| switch (msg[1]) |
| { |
| case LEC_DISABLE_TYPE_CONTIGNUOUS_2100HZ: |
| PUT_WORD(&result[4], EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ); |
| break; |
| case LEC_DISABLE_TYPE_REVERSED_2100HZ: |
| PUT_WORD(&result[4], EC_BYPASS_DUE_TO_REVERSED_2100HZ); |
| break; |
| case LEC_DISABLE_RELEASED: |
| PUT_WORD(&result[4], EC_BYPASS_RELEASED); |
| break; |
| } |
| } |
| sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ? |
| PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result); |
| } |
| } |
| |
| |
| |
| /*------------------------------------------------------------------*/ |
| /* Advanced voice */ |
| /*------------------------------------------------------------------*/ |
| |
| static void adv_voice_write_coefs(PLCI *plci, word write_command) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| word i; |
| byte *p; |
| |
| word w, n, j, k; |
| byte ch_map[MIXER_CHANNELS_BRI]; |
| |
| byte coef_buffer[ADV_VOICE_COEF_BUFFER_SIZE + 2]; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: adv_voice_write_coefs %d", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__, write_command)); |
| |
| a = plci->adapter; |
| p = coef_buffer + 1; |
| *(p++) = DSP_CTRL_OLD_SET_MIXER_COEFFICIENTS; |
| i = 0; |
| while (i + sizeof(word) <= a->adv_voice_coef_length) |
| { |
| PUT_WORD(p, GET_WORD(a->adv_voice_coef_buffer + i)); |
| p += 2; |
| i += 2; |
| } |
| while (i < ADV_VOICE_OLD_COEF_COUNT * sizeof(word)) |
| { |
| PUT_WORD(p, 0x8000); |
| p += 2; |
| i += 2; |
| } |
| |
| if (!a->li_pri && (plci->li_bchannel_id == 0)) |
| { |
| if ((li_config_table[a->li_base].plci == NULL) && (li_config_table[a->li_base + 1].plci != NULL)) |
| { |
| plci->li_bchannel_id = 1; |
| li_config_table[a->li_base].plci = plci; |
| dbug(1, dprintf("[%06lx] %s,%d: adv_voice_set_bchannel_id %d", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__, plci->li_bchannel_id)); |
| } |
| else if ((li_config_table[a->li_base].plci != NULL) && (li_config_table[a->li_base + 1].plci == NULL)) |
| { |
| plci->li_bchannel_id = 2; |
| li_config_table[a->li_base + 1].plci = plci; |
| dbug(1, dprintf("[%06lx] %s,%d: adv_voice_set_bchannel_id %d", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__, plci->li_bchannel_id)); |
| } |
| } |
| if (!a->li_pri && (plci->li_bchannel_id != 0) |
| && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci)) |
| { |
| i = a->li_base + (plci->li_bchannel_id - 1); |
| switch (write_command) |
| { |
| case ADV_VOICE_WRITE_ACTIVATION: |
| j = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1); |
| k = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id); |
| if (!(plci->B1_facilities & B1_FACILITY_MIXER)) |
| { |
| li_config_table[j].flag_table[i] |= LI_FLAG_CONFERENCE | LI_FLAG_MIX; |
| li_config_table[i].flag_table[j] |= LI_FLAG_CONFERENCE | LI_FLAG_MONITOR; |
| } |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) |
| { |
| li_config_table[k].flag_table[i] |= LI_FLAG_CONFERENCE | LI_FLAG_MIX; |
| li_config_table[i].flag_table[k] |= LI_FLAG_CONFERENCE | LI_FLAG_MONITOR; |
| li_config_table[k].flag_table[j] |= LI_FLAG_CONFERENCE; |
| li_config_table[j].flag_table[k] |= LI_FLAG_CONFERENCE; |
| } |
| mixer_calculate_coefs(a); |
| li_config_table[i].curchnl = li_config_table[i].channel; |
| li_config_table[j].curchnl = li_config_table[j].channel; |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) |
| li_config_table[k].curchnl = li_config_table[k].channel; |
| break; |
| |
| case ADV_VOICE_WRITE_DEACTIVATION: |
| for (j = 0; j < li_total_channels; j++) |
| { |
| li_config_table[i].flag_table[j] = 0; |
| li_config_table[j].flag_table[i] = 0; |
| } |
| k = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1); |
| for (j = 0; j < li_total_channels; j++) |
| { |
| li_config_table[k].flag_table[j] = 0; |
| li_config_table[j].flag_table[k] = 0; |
| } |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) |
| { |
| k = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id); |
| for (j = 0; j < li_total_channels; j++) |
| { |
| li_config_table[k].flag_table[j] = 0; |
| li_config_table[j].flag_table[k] = 0; |
| } |
| } |
| mixer_calculate_coefs(a); |
| break; |
| } |
| if (plci->B1_facilities & B1_FACILITY_MIXER) |
| { |
| w = 0; |
| if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length) |
| w = GET_WORD(a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE); |
| if (li_config_table[i].channel & LI_CHANNEL_TX_DATA) |
| w |= MIXER_FEATURE_ENABLE_TX_DATA; |
| if (li_config_table[i].channel & LI_CHANNEL_RX_DATA) |
| w |= MIXER_FEATURE_ENABLE_RX_DATA; |
| *(p++) = (byte) w; |
| *(p++) = (byte)(w >> 8); |
| for (j = 0; j < sizeof(ch_map); j += 2) |
| { |
| ch_map[j] = (byte)(j + (plci->li_bchannel_id - 1)); |
| ch_map[j + 1] = (byte)(j + (2 - plci->li_bchannel_id)); |
| } |
| for (n = 0; n < ARRAY_SIZE(mixer_write_prog_bri); n++) |
| { |
| i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch]; |
| j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch]; |
| if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED) |
| { |
| *(p++) = ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01); |
| w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4)); |
| li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4; |
| } |
| else |
| { |
| *(p++) = (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + n < a->adv_voice_coef_length) ? |
| a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + n] : 0x00; |
| } |
| } |
| } |
| else |
| { |
| for (i = ADV_VOICE_NEW_COEF_BASE; i < a->adv_voice_coef_length; i++) |
| *(p++) = a->adv_voice_coef_buffer[i]; |
| } |
| } |
| else |
| |
| { |
| for (i = ADV_VOICE_NEW_COEF_BASE; i < a->adv_voice_coef_length; i++) |
| *(p++) = a->adv_voice_coef_buffer[i]; |
| } |
| coef_buffer[0] = (p - coef_buffer) - 1; |
| add_p(plci, FTY, coef_buffer); |
| sig_req(plci, TEL_CTRL, 0); |
| send_req(plci); |
| } |
| |
| |
| static void adv_voice_clear_config(PLCI *plci) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| |
| word i, j; |
| |
| |
| dbug(1, dprintf("[%06lx] %s,%d: adv_voice_clear_config", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| |
| a = plci->adapter; |
| if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI)) |
| { |
| a->adv_voice_coef_length = 0; |
| |
| if (!a->li_pri && (plci->li_bchannel_id != 0) |
| && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci)) |
| { |
| i = a->li_base + (plci->li_bchannel_id - 1); |
| li_config_table[i].curchnl = 0; |
| li_config_table[i].channel = 0; |
| li_config_table[i].chflags = 0; |
| for (j = 0; j < li_total_channels; j++) |
| { |
| li_config_table[i].flag_table[j] = 0; |
| li_config_table[j].flag_table[i] = 0; |
| li_config_table[i].coef_table[j] = 0; |
| li_config_table[j].coef_table[i] = 0; |
| } |
| li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET; |
| i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1); |
| li_config_table[i].curchnl = 0; |
| li_config_table[i].channel = 0; |
| li_config_table[i].chflags = 0; |
| for (j = 0; j < li_total_channels; j++) |
| { |
| li_config_table[i].flag_table[j] = 0; |
| li_config_table[j].flag_table[i] = 0; |
| li_config_table[i].coef_table[j] = 0; |
| li_config_table[j].coef_table[i] = 0; |
| } |
| if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) |
| { |
| i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id); |
| li_config_table[i].curchnl = 0; |
| li_config_table[i].channel = 0; |
| li_config_table[i].chflags = 0; |
| for (j = 0; j < li_total_channels; j++) |
| { |
| li_config_table[i].flag_table[j] = 0; |
| li_config_table[j].flag_table[i] = 0; |
| li_config_table[i].coef_table[j] = 0; |
| li_config_table[j].coef_table[i] = 0; |
| } |
| } |
| } |
| |
| } |
| } |
| |
| |
| static void adv_voice_prepare_switch(dword Id, PLCI *plci) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: adv_voice_prepare_switch", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| |
| } |
| |
| |
| static word adv_voice_save_config(dword Id, PLCI *plci, byte Rc) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: adv_voice_save_config %02x %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state)); |
| |
| return (GOOD); |
| } |
| |
| |
| static word adv_voice_restore_config(dword Id, PLCI *plci, byte Rc) |
| { |
| DIVA_CAPI_ADAPTER *a; |
| word Info; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: adv_voice_restore_config %02x %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state)); |
| |
| Info = GOOD; |
| a = plci->adapter; |
| if ((plci->B1_facilities & B1_FACILITY_VOICE) |
| && (plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI)) |
| { |
| switch (plci->adjust_b_state) |
| { |
| case ADJUST_B_RESTORE_VOICE_1: |
| plci->internal_command = plci->adjust_b_command; |
| if (plci->sig_req) |
| { |
| plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_1; |
| break; |
| } |
| adv_voice_write_coefs(plci, ADV_VOICE_WRITE_UPDATE); |
| plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_2; |
| break; |
| case ADJUST_B_RESTORE_VOICE_2: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Restore voice config failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| Info = _WRONG_STATE; |
| break; |
| } |
| break; |
| } |
| } |
| return (Info); |
| } |
| |
| |
| |
| |
| /*------------------------------------------------------------------*/ |
| /* B1 resource switching */ |
| /*------------------------------------------------------------------*/ |
| |
| static byte b1_facilities_table[] = |
| { |
| 0x00, /* 0 No bchannel resources */ |
| 0x00, /* 1 Codec (automatic law) */ |
| 0x00, /* 2 Codec (A-law) */ |
| 0x00, /* 3 Codec (y-law) */ |
| 0x00, /* 4 HDLC for X.21 */ |
| 0x00, /* 5 HDLC */ |
| 0x00, /* 6 External Device 0 */ |
| 0x00, /* 7 External Device 1 */ |
| 0x00, /* 8 HDLC 56k */ |
| 0x00, /* 9 Transparent */ |
| 0x00, /* 10 Loopback to network */ |
| 0x00, /* 11 Test pattern to net */ |
| 0x00, /* 12 Rate adaptation sync */ |
| 0x00, /* 13 Rate adaptation async */ |
| 0x00, /* 14 R-Interface */ |
| 0x00, /* 15 HDLC 128k leased line */ |
| 0x00, /* 16 FAX */ |
| 0x00, /* 17 Modem async */ |
| 0x00, /* 18 Modem sync HDLC */ |
| 0x00, /* 19 V.110 async HDLC */ |
| 0x12, /* 20 Adv voice (Trans,mixer) */ |
| 0x00, /* 21 Codec connected to IC */ |
| 0x0c, /* 22 Trans,DTMF */ |
| 0x1e, /* 23 Trans,DTMF+mixer */ |
| 0x1f, /* 24 Trans,DTMF+mixer+local */ |
| 0x13, /* 25 Trans,mixer+local */ |
| 0x12, /* 26 HDLC,mixer */ |
| 0x12, /* 27 HDLC 56k,mixer */ |
| 0x2c, /* 28 Trans,LEC+DTMF */ |
| 0x3e, /* 29 Trans,LEC+DTMF+mixer */ |
| 0x3f, /* 30 Trans,LEC+DTMF+mixer+local */ |
| 0x2c, /* 31 RTP,LEC+DTMF */ |
| 0x3e, /* 32 RTP,LEC+DTMF+mixer */ |
| 0x3f, /* 33 RTP,LEC+DTMF+mixer+local */ |
| 0x00, /* 34 Signaling task */ |
| 0x00, /* 35 PIAFS */ |
| 0x0c, /* 36 Trans,DTMF+TONE */ |
| 0x1e, /* 37 Trans,DTMF+TONE+mixer */ |
| 0x1f /* 38 Trans,DTMF+TONE+mixer+local*/ |
| }; |
| |
| |
| static word get_b1_facilities(PLCI *plci, byte b1_resource) |
| { |
| word b1_facilities; |
| |
| b1_facilities = b1_facilities_table[b1_resource]; |
| if ((b1_resource == 9) || (b1_resource == 20) || (b1_resource == 25)) |
| { |
| |
| if (!(((plci->requested_options_conn | plci->requested_options) & (1L << PRIVATE_DTMF_TONE)) |
| || (plci->appl && (plci->adapter->requested_options_table[plci->appl->Id - 1] & (1L << PRIVATE_DTMF_TONE))))) |
| |
| { |
| if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_SEND) |
| b1_facilities |= B1_FACILITY_DTMFX; |
| if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE) |
| b1_facilities |= B1_FACILITY_DTMFR; |
| } |
| } |
| if ((b1_resource == 17) || (b1_resource == 18)) |
| { |
| if (plci->adapter->manufacturer_features & (MANUFACTURER_FEATURE_V18 | MANUFACTURER_FEATURE_VOWN)) |
| b1_facilities |= B1_FACILITY_DTMFX | B1_FACILITY_DTMFR; |
| } |
| /* |
| dbug (1, dprintf("[%06lx] %s,%d: get_b1_facilities %d %04x", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char far *)(FILE_), __LINE__, b1_resource, b1_facilites)); |
| */ |
| return (b1_facilities); |
| } |
| |
| |
| static byte add_b1_facilities(PLCI *plci, byte b1_resource, word b1_facilities) |
| { |
| byte b; |
| |
| switch (b1_resource) |
| { |
| case 5: |
| case 26: |
| if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE)) |
| b = 26; |
| else |
| b = 5; |
| break; |
| |
| case 8: |
| case 27: |
| if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE)) |
| b = 27; |
| else |
| b = 8; |
| break; |
| |
| case 9: |
| case 20: |
| case 22: |
| case 23: |
| case 24: |
| case 25: |
| case 28: |
| case 29: |
| case 30: |
| case 36: |
| case 37: |
| case 38: |
| if (b1_facilities & B1_FACILITY_EC) |
| { |
| if (b1_facilities & B1_FACILITY_LOCAL) |
| b = 30; |
| else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE)) |
| b = 29; |
| else |
| b = 28; |
| } |
| |
| else if ((b1_facilities & (B1_FACILITY_DTMFX | B1_FACILITY_DTMFR | B1_FACILITY_MIXER)) |
| && (((plci->requested_options_conn | plci->requested_options) & (1L << PRIVATE_DTMF_TONE)) |
| || (plci->appl && (plci->adapter->requested_options_table[plci->appl->Id - 1] & (1L << PRIVATE_DTMF_TONE))))) |
| { |
| if (b1_facilities & B1_FACILITY_LOCAL) |
| b = 38; |
| else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE)) |
| b = 37; |
| else |
| b = 36; |
| } |
| |
| else if (((plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_HARDDTMF) |
| && !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE)) |
| || ((b1_facilities & B1_FACILITY_DTMFR) |
| && ((b1_facilities & B1_FACILITY_MIXER) |
| || !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE))) |
| || ((b1_facilities & B1_FACILITY_DTMFX) |
| && ((b1_facilities & B1_FACILITY_MIXER) |
| || !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_SEND)))) |
| { |
| if (b1_facilities & B1_FACILITY_LOCAL) |
| b = 24; |
| else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE)) |
| b = 23; |
| else |
| b = 22; |
| } |
| else |
| { |
| if (b1_facilities & B1_FACILITY_LOCAL) |
| b = 25; |
| else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE)) |
| b = 20; |
| else |
| b = 9; |
| } |
| break; |
| |
| case 31: |
| case 32: |
| case 33: |
| if (b1_facilities & B1_FACILITY_LOCAL) |
| b = 33; |
| else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE)) |
| b = 32; |
| else |
| b = 31; |
| break; |
| |
| default: |
| b = b1_resource; |
| } |
| dbug(1, dprintf("[%06lx] %s,%d: add_b1_facilities %d %04x %d %04x", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__, |
| b1_resource, b1_facilities, b, get_b1_facilities(plci, b))); |
| return (b); |
| } |
| |
| |
| static void adjust_b1_facilities(PLCI *plci, byte new_b1_resource, word new_b1_facilities) |
| { |
| word removed_facilities; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: adjust_b1_facilities %d %04x %04x", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__, new_b1_resource, new_b1_facilities, |
| new_b1_facilities & get_b1_facilities(plci, new_b1_resource))); |
| |
| new_b1_facilities &= get_b1_facilities(plci, new_b1_resource); |
| removed_facilities = plci->B1_facilities & ~new_b1_facilities; |
| |
| if (removed_facilities & B1_FACILITY_EC) |
| ec_clear_config(plci); |
| |
| |
| if (removed_facilities & B1_FACILITY_DTMFR) |
| { |
| dtmf_rec_clear_config(plci); |
| dtmf_parameter_clear_config(plci); |
| } |
| if (removed_facilities & B1_FACILITY_DTMFX) |
| dtmf_send_clear_config(plci); |
| |
| |
| if (removed_facilities & B1_FACILITY_MIXER) |
| mixer_clear_config(plci); |
| |
| if (removed_facilities & B1_FACILITY_VOICE) |
| adv_voice_clear_config(plci); |
| plci->B1_facilities = new_b1_facilities; |
| } |
| |
| |
| static void adjust_b_clear(PLCI *plci) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: adjust_b_clear", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| |
| plci->adjust_b_restore = false; |
| } |
| |
| |
| static word adjust_b_process(dword Id, PLCI *plci, byte Rc) |
| { |
| word Info; |
| byte b1_resource; |
| NCCI *ncci_ptr; |
| API_PARSE bp[2]; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: adjust_b_process %02x %d", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state)); |
| |
| Info = GOOD; |
| switch (plci->adjust_b_state) |
| { |
| case ADJUST_B_START: |
| if ((plci->adjust_b_parms_msg == NULL) |
| && (plci->adjust_b_mode & ADJUST_B_MODE_SWITCH_L1) |
| && ((plci->adjust_b_mode & ~(ADJUST_B_MODE_SAVE | ADJUST_B_MODE_SWITCH_L1 | |
| ADJUST_B_MODE_NO_RESOURCE | ADJUST_B_MODE_RESTORE)) == 0)) |
| { |
| b1_resource = (plci->adjust_b_mode == ADJUST_B_MODE_NO_RESOURCE) ? |
| 0 : add_b1_facilities(plci, plci->B1_resource, plci->adjust_b_facilities); |
| if (b1_resource == plci->B1_resource) |
| { |
| adjust_b1_facilities(plci, b1_resource, plci->adjust_b_facilities); |
| break; |
| } |
| if (plci->adjust_b_facilities & ~get_b1_facilities(plci, b1_resource)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Adjust B nonsupported facilities %d %d %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, |
| plci->B1_resource, b1_resource, plci->adjust_b_facilities)); |
| Info = _WRONG_STATE; |
| break; |
| } |
| } |
| if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE) |
| { |
| |
| mixer_prepare_switch(Id, plci); |
| |
| |
| dtmf_prepare_switch(Id, plci); |
| dtmf_parameter_prepare_switch(Id, plci); |
| |
| |
| ec_prepare_switch(Id, plci); |
| |
| adv_voice_prepare_switch(Id, plci); |
| } |
| plci->adjust_b_state = ADJUST_B_SAVE_MIXER_1; |
| Rc = OK; |
| case ADJUST_B_SAVE_MIXER_1: |
| if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE) |
| { |
| |
| Info = mixer_save_config(Id, plci, Rc); |
| if ((Info != GOOD) || plci->internal_command) |
| break; |
| |
| } |
| plci->adjust_b_state = ADJUST_B_SAVE_DTMF_1; |
| Rc = OK; |
| case ADJUST_B_SAVE_DTMF_1: |
| if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE) |
| { |
| |
| Info = dtmf_save_config(Id, plci, Rc); |
| if ((Info != GOOD) || plci->internal_command) |
| break; |
| |
| } |
| plci->adjust_b_state = ADJUST_B_REMOVE_L23_1; |
| case ADJUST_B_REMOVE_L23_1: |
| if ((plci->adjust_b_mode & ADJUST_B_MODE_REMOVE_L23) |
| && plci->NL.Id && !plci->nl_remove_id) |
| { |
| plci->internal_command = plci->adjust_b_command; |
| if (plci->adjust_b_ncci != 0) |
| { |
| ncci_ptr = &(plci->adapter->ncci[plci->adjust_b_ncci]); |
| while (ncci_ptr->data_pending) |
| { |
| plci->data_sent_ptr = ncci_ptr->DBuffer[ncci_ptr->data_out].P; |
| data_rc(plci, plci->adapter->ncci_ch[plci->adjust_b_ncci]); |
| } |
| while (ncci_ptr->data_ack_pending) |
| data_ack(plci, plci->adapter->ncci_ch[plci->adjust_b_ncci]); |
| } |
| nl_req_ncci(plci, REMOVE, |
| (byte)((plci->adjust_b_mode & ADJUST_B_MODE_CONNECT) ? plci->adjust_b_ncci : 0)); |
| send_req(plci); |
| plci->adjust_b_state = ADJUST_B_REMOVE_L23_2; |
| break; |
| } |
| plci->adjust_b_state = ADJUST_B_REMOVE_L23_2; |
| Rc = OK; |
| case ADJUST_B_REMOVE_L23_2: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Adjust B remove failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| Info = _WRONG_STATE; |
| break; |
| } |
| if (plci->adjust_b_mode & ADJUST_B_MODE_REMOVE_L23) |
| { |
| if (plci_nl_busy(plci)) |
| { |
| plci->internal_command = plci->adjust_b_command; |
| break; |
| } |
| } |
| plci->adjust_b_state = ADJUST_B_SAVE_EC_1; |
| Rc = OK; |
| case ADJUST_B_SAVE_EC_1: |
| if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE) |
| { |
| |
| Info = ec_save_config(Id, plci, Rc); |
| if ((Info != GOOD) || plci->internal_command) |
| break; |
| |
| } |
| plci->adjust_b_state = ADJUST_B_SAVE_DTMF_PARAMETER_1; |
| Rc = OK; |
| case ADJUST_B_SAVE_DTMF_PARAMETER_1: |
| if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE) |
| { |
| |
| Info = dtmf_parameter_save_config(Id, plci, Rc); |
| if ((Info != GOOD) || plci->internal_command) |
| break; |
| |
| } |
| plci->adjust_b_state = ADJUST_B_SAVE_VOICE_1; |
| Rc = OK; |
| case ADJUST_B_SAVE_VOICE_1: |
| if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE) |
| { |
| Info = adv_voice_save_config(Id, plci, Rc); |
| if ((Info != GOOD) || plci->internal_command) |
| break; |
| } |
| plci->adjust_b_state = ADJUST_B_SWITCH_L1_1; |
| case ADJUST_B_SWITCH_L1_1: |
| if (plci->adjust_b_mode & ADJUST_B_MODE_SWITCH_L1) |
| { |
| if (plci->sig_req) |
| { |
| plci->internal_command = plci->adjust_b_command; |
| break; |
| } |
| if (plci->adjust_b_parms_msg != NULL) |
| api_load_msg(plci->adjust_b_parms_msg, bp); |
| else |
| api_load_msg(&plci->B_protocol, bp); |
| Info = add_b1(plci, bp, |
| (word)((plci->adjust_b_mode & ADJUST_B_MODE_NO_RESOURCE) ? 2 : 0), |
| plci->adjust_b_facilities); |
| if (Info != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Adjust B invalid L1 parameters %d %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, |
| plci->B1_resource, plci->adjust_b_facilities)); |
| break; |
| } |
| plci->internal_command = plci->adjust_b_command; |
| sig_req(plci, RESOURCES, 0); |
| send_req(plci); |
| plci->adjust_b_state = ADJUST_B_SWITCH_L1_2; |
| break; |
| } |
| plci->adjust_b_state = ADJUST_B_SWITCH_L1_2; |
| Rc = OK; |
| case ADJUST_B_SWITCH_L1_2: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Adjust B switch failed %02x %d %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, |
| Rc, plci->B1_resource, plci->adjust_b_facilities)); |
| Info = _WRONG_STATE; |
| break; |
| } |
| plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_1; |
| Rc = OK; |
| case ADJUST_B_RESTORE_VOICE_1: |
| case ADJUST_B_RESTORE_VOICE_2: |
| if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE) |
| { |
| Info = adv_voice_restore_config(Id, plci, Rc); |
| if ((Info != GOOD) || plci->internal_command) |
| break; |
| } |
| plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_1; |
| Rc = OK; |
| case ADJUST_B_RESTORE_DTMF_PARAMETER_1: |
| case ADJUST_B_RESTORE_DTMF_PARAMETER_2: |
| if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE) |
| { |
| |
| Info = dtmf_parameter_restore_config(Id, plci, Rc); |
| if ((Info != GOOD) || plci->internal_command) |
| break; |
| |
| } |
| plci->adjust_b_state = ADJUST_B_RESTORE_EC_1; |
| Rc = OK; |
| case ADJUST_B_RESTORE_EC_1: |
| case ADJUST_B_RESTORE_EC_2: |
| if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE) |
| { |
| |
| Info = ec_restore_config(Id, plci, Rc); |
| if ((Info != GOOD) || plci->internal_command) |
| break; |
| |
| } |
| plci->adjust_b_state = ADJUST_B_ASSIGN_L23_1; |
| case ADJUST_B_ASSIGN_L23_1: |
| if (plci->adjust_b_mode & ADJUST_B_MODE_ASSIGN_L23) |
| { |
| if (plci_nl_busy(plci)) |
| { |
| plci->internal_command = plci->adjust_b_command; |
| break; |
| } |
| if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT) |
| plci->call_dir |= CALL_DIR_FORCE_OUTG_NL; |
| if (plci->adjust_b_parms_msg != NULL) |
| api_load_msg(plci->adjust_b_parms_msg, bp); |
| else |
| api_load_msg(&plci->B_protocol, bp); |
| Info = add_b23(plci, bp); |
| if (Info != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Adjust B invalid L23 parameters %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Info)); |
| break; |
| } |
| plci->internal_command = plci->adjust_b_command; |
| nl_req_ncci(plci, ASSIGN, 0); |
| send_req(plci); |
| plci->adjust_b_state = ADJUST_B_ASSIGN_L23_2; |
| break; |
| } |
| plci->adjust_b_state = ADJUST_B_ASSIGN_L23_2; |
| Rc = ASSIGN_OK; |
| case ADJUST_B_ASSIGN_L23_2: |
| if ((Rc != OK) && (Rc != OK_FC) && (Rc != ASSIGN_OK)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Adjust B assign failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| Info = _WRONG_STATE; |
| break; |
| } |
| if (plci->adjust_b_mode & ADJUST_B_MODE_ASSIGN_L23) |
| { |
| if (Rc != ASSIGN_OK) |
| { |
| plci->internal_command = plci->adjust_b_command; |
| break; |
| } |
| } |
| if (plci->adjust_b_mode & ADJUST_B_MODE_USER_CONNECT) |
| { |
| plci->adjust_b_restore = true; |
| break; |
| } |
| plci->adjust_b_state = ADJUST_B_CONNECT_1; |
| case ADJUST_B_CONNECT_1: |
| if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT) |
| { |
| plci->internal_command = plci->adjust_b_command; |
| if (plci_nl_busy(plci)) |
| break; |
| nl_req_ncci(plci, N_CONNECT, 0); |
| send_req(plci); |
| plci->adjust_b_state = ADJUST_B_CONNECT_2; |
| break; |
| } |
| plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1; |
| Rc = OK; |
| case ADJUST_B_CONNECT_2: |
| case ADJUST_B_CONNECT_3: |
| case ADJUST_B_CONNECT_4: |
| if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Adjust B connect failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| Info = _WRONG_STATE; |
| break; |
| } |
| if (Rc == OK) |
| { |
| if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT) |
| { |
| get_ncci(plci, (byte)(Id >> 16), plci->adjust_b_ncci); |
| Id = (Id & 0xffff) | (((dword)(plci->adjust_b_ncci)) << 16); |
| } |
| if (plci->adjust_b_state == ADJUST_B_CONNECT_2) |
| plci->adjust_b_state = ADJUST_B_CONNECT_3; |
| else if (plci->adjust_b_state == ADJUST_B_CONNECT_4) |
| plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1; |
| } |
| else if (Rc == 0) |
| { |
| if (plci->adjust_b_state == ADJUST_B_CONNECT_2) |
| plci->adjust_b_state = ADJUST_B_CONNECT_4; |
| else if (plci->adjust_b_state == ADJUST_B_CONNECT_3) |
| plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1; |
| } |
| if (plci->adjust_b_state != ADJUST_B_RESTORE_DTMF_1) |
| { |
| plci->internal_command = plci->adjust_b_command; |
| break; |
| } |
| Rc = OK; |
| case ADJUST_B_RESTORE_DTMF_1: |
| case ADJUST_B_RESTORE_DTMF_2: |
| if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE) |
| { |
| |
| Info = dtmf_restore_config(Id, plci, Rc); |
| if ((Info != GOOD) || plci->internal_command) |
| break; |
| |
| } |
| plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_1; |
| Rc = OK; |
| case ADJUST_B_RESTORE_MIXER_1: |
| case ADJUST_B_RESTORE_MIXER_2: |
| case ADJUST_B_RESTORE_MIXER_3: |
| case ADJUST_B_RESTORE_MIXER_4: |
| case ADJUST_B_RESTORE_MIXER_5: |
| case ADJUST_B_RESTORE_MIXER_6: |
| case ADJUST_B_RESTORE_MIXER_7: |
| if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE) |
| { |
| |
| Info = mixer_restore_config(Id, plci, Rc); |
| if ((Info != GOOD) || plci->internal_command) |
| break; |
| |
| } |
| plci->adjust_b_state = ADJUST_B_END; |
| case ADJUST_B_END: |
| break; |
| } |
| return (Info); |
| } |
| |
| |
| static void adjust_b1_resource(dword Id, PLCI *plci, API_SAVE *bp_msg, word b1_facilities, word internal_command) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: adjust_b1_resource %d %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, |
| plci->B1_resource, b1_facilities)); |
| |
| plci->adjust_b_parms_msg = bp_msg; |
| plci->adjust_b_facilities = b1_facilities; |
| plci->adjust_b_command = internal_command; |
| plci->adjust_b_ncci = (word)(Id >> 16); |
| if ((bp_msg == NULL) && (plci->B1_resource == 0)) |
| plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_NO_RESOURCE | ADJUST_B_MODE_SWITCH_L1; |
| else |
| plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_SWITCH_L1 | ADJUST_B_MODE_RESTORE; |
| plci->adjust_b_state = ADJUST_B_START; |
| dbug(1, dprintf("[%06lx] %s,%d: Adjust B1 resource %d %04x...", |
| UnMapId(Id), (char *)(FILE_), __LINE__, |
| plci->B1_resource, b1_facilities)); |
| } |
| |
| |
| static void adjust_b_restore(dword Id, PLCI *plci, byte Rc) |
| { |
| word internal_command; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: adjust_b_restore %02x %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); |
| |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| switch (internal_command) |
| { |
| default: |
| plci->command = 0; |
| if (plci->req_in != 0) |
| { |
| plci->internal_command = ADJUST_B_RESTORE_1; |
| break; |
| } |
| Rc = OK; |
| case ADJUST_B_RESTORE_1: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Adjust B enqueued failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| } |
| plci->adjust_b_parms_msg = NULL; |
| plci->adjust_b_facilities = plci->B1_facilities; |
| plci->adjust_b_command = ADJUST_B_RESTORE_2; |
| plci->adjust_b_ncci = (word)(Id >> 16); |
| plci->adjust_b_mode = ADJUST_B_MODE_RESTORE; |
| plci->adjust_b_state = ADJUST_B_START; |
| dbug(1, dprintf("[%06lx] %s,%d: Adjust B restore...", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| case ADJUST_B_RESTORE_2: |
| if (adjust_b_process(Id, plci, Rc) != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Adjust B restore failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| } |
| if (plci->internal_command) |
| break; |
| break; |
| } |
| } |
| |
| |
| static void reset_b3_command(dword Id, PLCI *plci, byte Rc) |
| { |
| word Info; |
| word internal_command; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: reset_b3_command %02x %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); |
| |
| Info = GOOD; |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| switch (internal_command) |
| { |
| default: |
| plci->command = 0; |
| plci->adjust_b_parms_msg = NULL; |
| plci->adjust_b_facilities = plci->B1_facilities; |
| plci->adjust_b_command = RESET_B3_COMMAND_1; |
| plci->adjust_b_ncci = (word)(Id >> 16); |
| plci->adjust_b_mode = ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_CONNECT; |
| plci->adjust_b_state = ADJUST_B_START; |
| dbug(1, dprintf("[%06lx] %s,%d: Reset B3...", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| case RESET_B3_COMMAND_1: |
| Info = adjust_b_process(Id, plci, Rc); |
| if (Info != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Reset failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| break; |
| } |
| if (plci->internal_command) |
| return; |
| break; |
| } |
| /* sendf (plci->appl, _RESET_B3_R | CONFIRM, Id, plci->number, "w", Info);*/ |
| sendf(plci->appl, _RESET_B3_I, Id, 0, "s", ""); |
| } |
| |
| |
| static void select_b_command(dword Id, PLCI *plci, byte Rc) |
| { |
| word Info; |
| word internal_command; |
| byte esc_chi[3]; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: select_b_command %02x %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); |
| |
| Info = GOOD; |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| switch (internal_command) |
| { |
| default: |
| plci->command = 0; |
| plci->adjust_b_parms_msg = &plci->saved_msg; |
| if ((plci->tel == ADV_VOICE) && (plci == plci->adapter->AdvSignalPLCI)) |
| plci->adjust_b_facilities = plci->B1_facilities | B1_FACILITY_VOICE; |
| else |
| plci->adjust_b_facilities = plci->B1_facilities & ~B1_FACILITY_VOICE; |
| plci->adjust_b_command = SELECT_B_COMMAND_1; |
| plci->adjust_b_ncci = (word)(Id >> 16); |
| if (plci->saved_msg.parms[0].length == 0) |
| { |
| plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_SWITCH_L1 | |
| ADJUST_B_MODE_NO_RESOURCE; |
| } |
| else |
| { |
| plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_SWITCH_L1 | |
| ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_USER_CONNECT | ADJUST_B_MODE_RESTORE; |
| } |
| plci->adjust_b_state = ADJUST_B_START; |
| dbug(1, dprintf("[%06lx] %s,%d: Select B protocol...", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| case SELECT_B_COMMAND_1: |
| Info = adjust_b_process(Id, plci, Rc); |
| if (Info != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: Select B protocol failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| break; |
| } |
| if (plci->internal_command) |
| return; |
| if (plci->tel == ADV_VOICE) |
| { |
| esc_chi[0] = 0x02; |
| esc_chi[1] = 0x18; |
| esc_chi[2] = plci->b_channel; |
| SetVoiceChannel(plci->adapter->AdvCodecPLCI, esc_chi, plci->adapter); |
| } |
| break; |
| } |
| sendf(plci->appl, _SELECT_B_REQ | CONFIRM, Id, plci->number, "w", Info); |
| } |
| |
| |
| static void fax_connect_ack_command(dword Id, PLCI *plci, byte Rc) |
| { |
| word internal_command; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: fax_connect_ack_command %02x %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); |
| |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| switch (internal_command) |
| { |
| default: |
| plci->command = 0; |
| case FAX_CONNECT_ACK_COMMAND_1: |
| if (plci_nl_busy(plci)) |
| { |
| plci->internal_command = FAX_CONNECT_ACK_COMMAND_1; |
| return; |
| } |
| plci->internal_command = FAX_CONNECT_ACK_COMMAND_2; |
| plci->NData[0].P = plci->fax_connect_info_buffer; |
| plci->NData[0].PLength = plci->fax_connect_info_length; |
| plci->NL.X = plci->NData; |
| plci->NL.ReqCh = 0; |
| plci->NL.Req = plci->nl_req = (byte) N_CONNECT_ACK; |
| plci->adapter->request(&plci->NL); |
| return; |
| case FAX_CONNECT_ACK_COMMAND_2: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: FAX issue CONNECT ACK failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| break; |
| } |
| } |
| if ((plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT) |
| && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT)) |
| { |
| if (plci->B3_prot == 4) |
| sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", ""); |
| else |
| sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "S", plci->ncpi_buffer); |
| plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT; |
| } |
| } |
| |
| |
| static void fax_edata_ack_command(dword Id, PLCI *plci, byte Rc) |
| { |
| word internal_command; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: fax_edata_ack_command %02x %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); |
| |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| switch (internal_command) |
| { |
| default: |
| plci->command = 0; |
| case FAX_EDATA_ACK_COMMAND_1: |
| if (plci_nl_busy(plci)) |
| { |
| plci->internal_command = FAX_EDATA_ACK_COMMAND_1; |
| return; |
| } |
| plci->internal_command = FAX_EDATA_ACK_COMMAND_2; |
| plci->NData[0].P = plci->fax_connect_info_buffer; |
| plci->NData[0].PLength = plci->fax_edata_ack_length; |
| plci->NL.X = plci->NData; |
| plci->NL.ReqCh = 0; |
| plci->NL.Req = plci->nl_req = (byte) N_EDATA; |
| plci->adapter->request(&plci->NL); |
| return; |
| case FAX_EDATA_ACK_COMMAND_2: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: FAX issue EDATA ACK failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| break; |
| } |
| } |
| } |
| |
| |
| static void fax_connect_info_command(dword Id, PLCI *plci, byte Rc) |
| { |
| word Info; |
| word internal_command; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: fax_connect_info_command %02x %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); |
| |
| Info = GOOD; |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| switch (internal_command) |
| { |
| default: |
| plci->command = 0; |
| case FAX_CONNECT_INFO_COMMAND_1: |
| if (plci_nl_busy(plci)) |
| { |
| plci->internal_command = FAX_CONNECT_INFO_COMMAND_1; |
| return; |
| } |
| plci->internal_command = FAX_CONNECT_INFO_COMMAND_2; |
| plci->NData[0].P = plci->fax_connect_info_buffer; |
| plci->NData[0].PLength = plci->fax_connect_info_length; |
| plci->NL.X = plci->NData; |
| plci->NL.ReqCh = 0; |
| plci->NL.Req = plci->nl_req = (byte) N_EDATA; |
| plci->adapter->request(&plci->NL); |
| return; |
| case FAX_CONNECT_INFO_COMMAND_2: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: FAX setting connect info failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| Info = _WRONG_STATE; |
| break; |
| } |
| if (plci_nl_busy(plci)) |
| { |
| plci->internal_command = FAX_CONNECT_INFO_COMMAND_2; |
| return; |
| } |
| plci->command = _CONNECT_B3_R; |
| nl_req_ncci(plci, N_CONNECT, 0); |
| send_req(plci); |
| return; |
| } |
| sendf(plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info); |
| } |
| |
| |
| static void fax_adjust_b23_command(dword Id, PLCI *plci, byte Rc) |
| { |
| word Info; |
| word internal_command; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: fax_adjust_b23_command %02x %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); |
| |
| Info = GOOD; |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| switch (internal_command) |
| { |
| default: |
| plci->command = 0; |
| plci->adjust_b_parms_msg = NULL; |
| plci->adjust_b_facilities = plci->B1_facilities; |
| plci->adjust_b_command = FAX_ADJUST_B23_COMMAND_1; |
| plci->adjust_b_ncci = (word)(Id >> 16); |
| plci->adjust_b_mode = ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_ASSIGN_L23; |
| plci->adjust_b_state = ADJUST_B_START; |
| dbug(1, dprintf("[%06lx] %s,%d: FAX adjust B23...", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| case FAX_ADJUST_B23_COMMAND_1: |
| Info = adjust_b_process(Id, plci, Rc); |
| if (Info != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: FAX adjust failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| break; |
| } |
| if (plci->internal_command) |
| return; |
| case FAX_ADJUST_B23_COMMAND_2: |
| if (plci_nl_busy(plci)) |
| { |
| plci->internal_command = FAX_ADJUST_B23_COMMAND_2; |
| return; |
| } |
| plci->command = _CONNECT_B3_R; |
| nl_req_ncci(plci, N_CONNECT, 0); |
| send_req(plci); |
| return; |
| } |
| sendf(plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info); |
| } |
| |
| |
| static void fax_disconnect_command(dword Id, PLCI *plci, byte Rc) |
| { |
| word internal_command; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: fax_disconnect_command %02x %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); |
| |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| switch (internal_command) |
| { |
| default: |
| plci->command = 0; |
| plci->internal_command = FAX_DISCONNECT_COMMAND_1; |
| return; |
| case FAX_DISCONNECT_COMMAND_1: |
| case FAX_DISCONNECT_COMMAND_2: |
| case FAX_DISCONNECT_COMMAND_3: |
| if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: FAX disconnect EDATA failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| break; |
| } |
| if (Rc == OK) |
| { |
| if ((internal_command == FAX_DISCONNECT_COMMAND_1) |
| || (internal_command == FAX_DISCONNECT_COMMAND_2)) |
| { |
| plci->internal_command = FAX_DISCONNECT_COMMAND_2; |
| } |
| } |
| else if (Rc == 0) |
| { |
| if (internal_command == FAX_DISCONNECT_COMMAND_1) |
| plci->internal_command = FAX_DISCONNECT_COMMAND_3; |
| } |
| return; |
| } |
| } |
| |
| |
| |
| static void rtp_connect_b3_req_command(dword Id, PLCI *plci, byte Rc) |
| { |
| word Info; |
| word internal_command; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: rtp_connect_b3_req_command %02x %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); |
| |
| Info = GOOD; |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| switch (internal_command) |
| { |
| default: |
| plci->command = 0; |
| case RTP_CONNECT_B3_REQ_COMMAND_1: |
| if (plci_nl_busy(plci)) |
| { |
| plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_1; |
| return; |
| } |
| plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_2; |
| nl_req_ncci(plci, N_CONNECT, 0); |
| send_req(plci); |
| return; |
| case RTP_CONNECT_B3_REQ_COMMAND_2: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: RTP setting connect info failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| Info = _WRONG_STATE; |
| break; |
| } |
| if (plci_nl_busy(plci)) |
| { |
| plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_2; |
| return; |
| } |
| plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_3; |
| plci->NData[0].PLength = plci->internal_req_buffer[0]; |
| plci->NData[0].P = plci->internal_req_buffer + 1; |
| plci->NL.X = plci->NData; |
| plci->NL.ReqCh = 0; |
| plci->NL.Req = plci->nl_req = (byte) N_UDATA; |
| plci->adapter->request(&plci->NL); |
| break; |
| case RTP_CONNECT_B3_REQ_COMMAND_3: |
| return; |
| } |
| sendf(plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info); |
| } |
| |
| |
| static void rtp_connect_b3_res_command(dword Id, PLCI *plci, byte Rc) |
| { |
| word internal_command; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: rtp_connect_b3_res_command %02x %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); |
| |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| switch (internal_command) |
| { |
| default: |
| plci->command = 0; |
| case RTP_CONNECT_B3_RES_COMMAND_1: |
| if (plci_nl_busy(plci)) |
| { |
| plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_1; |
| return; |
| } |
| plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_2; |
| nl_req_ncci(plci, N_CONNECT_ACK, (byte)(Id >> 16)); |
| send_req(plci); |
| return; |
| case RTP_CONNECT_B3_RES_COMMAND_2: |
| if ((Rc != OK) && (Rc != OK_FC)) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: RTP setting connect resp info failed %02x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc)); |
| break; |
| } |
| if (plci_nl_busy(plci)) |
| { |
| plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_2; |
| return; |
| } |
| sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", ""); |
| plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_3; |
| plci->NData[0].PLength = plci->internal_req_buffer[0]; |
| plci->NData[0].P = plci->internal_req_buffer + 1; |
| plci->NL.X = plci->NData; |
| plci->NL.ReqCh = 0; |
| plci->NL.Req = plci->nl_req = (byte) N_UDATA; |
| plci->adapter->request(&plci->NL); |
| return; |
| case RTP_CONNECT_B3_RES_COMMAND_3: |
| return; |
| } |
| } |
| |
| |
| |
| static void hold_save_command(dword Id, PLCI *plci, byte Rc) |
| { |
| byte SS_Ind[] = "\x05\x02\x00\x02\x00\x00"; /* Hold_Ind struct*/ |
| word Info; |
| word internal_command; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: hold_save_command %02x %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); |
| |
| Info = GOOD; |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| switch (internal_command) |
| { |
| default: |
| if (!plci->NL.Id) |
| break; |
| plci->command = 0; |
| plci->adjust_b_parms_msg = NULL; |
| plci->adjust_b_facilities = plci->B1_facilities; |
| plci->adjust_b_command = HOLD_SAVE_COMMAND_1; |
| plci->adjust_b_ncci = (word)(Id >> 16); |
| plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23; |
| plci->adjust_b_state = ADJUST_B_START; |
| dbug(1, dprintf("[%06lx] %s,%d: HOLD save...", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| case HOLD_SAVE_COMMAND_1: |
| Info = adjust_b_process(Id, plci, Rc); |
| if (Info != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: HOLD save failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| break; |
| } |
| if (plci->internal_command) |
| return; |
| } |
| sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", 3, SS_Ind); |
| } |
| |
| |
| static void retrieve_restore_command(dword Id, PLCI *plci, byte Rc) |
| { |
| byte SS_Ind[] = "\x05\x03\x00\x02\x00\x00"; /* Retrieve_Ind struct*/ |
| word Info; |
| word internal_command; |
| |
| dbug(1, dprintf("[%06lx] %s,%d: retrieve_restore_command %02x %04x", |
| UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); |
| |
| Info = GOOD; |
| internal_command = plci->internal_command; |
| plci->internal_command = 0; |
| switch (internal_command) |
| { |
| default: |
| plci->command = 0; |
| plci->adjust_b_parms_msg = NULL; |
| plci->adjust_b_facilities = plci->B1_facilities; |
| plci->adjust_b_command = RETRIEVE_RESTORE_COMMAND_1; |
| plci->adjust_b_ncci = (word)(Id >> 16); |
| plci->adjust_b_mode = ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_USER_CONNECT | ADJUST_B_MODE_RESTORE; |
| plci->adjust_b_state = ADJUST_B_START; |
| dbug(1, dprintf("[%06lx] %s,%d: RETRIEVE restore...", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| case RETRIEVE_RESTORE_COMMAND_1: |
| Info = adjust_b_process(Id, plci, Rc); |
| if (Info != GOOD) |
| { |
| dbug(1, dprintf("[%06lx] %s,%d: RETRIEVE restore failed", |
| UnMapId(Id), (char *)(FILE_), __LINE__)); |
| break; |
| } |
| if (plci->internal_command) |
| return; |
| } |
| sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", 3, SS_Ind); |
| } |
| |
| |
| static void init_b1_config(PLCI *plci) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: init_b1_config", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| |
| plci->B1_resource = 0; |
| plci->B1_facilities = 0; |
| |
| plci->li_bchannel_id = 0; |
| mixer_clear_config(plci); |
| |
| |
| ec_clear_config(plci); |
| |
| |
| dtmf_rec_clear_config(plci); |
| dtmf_send_clear_config(plci); |
| dtmf_parameter_clear_config(plci); |
| |
| adv_voice_clear_config(plci); |
| adjust_b_clear(plci); |
| } |
| |
| |
| static void clear_b1_config(PLCI *plci) |
| { |
| |
| dbug(1, dprintf("[%06lx] %s,%d: clear_b1_config", |
| (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)), |
| (char *)(FILE_), __LINE__)); |
| |
| adv_voice_clear_config(plci); |
| adjust_b_clear(plci); |
| |
| ec_clear_config(plci); |
| |
| |
| dtmf_rec_clear_config(plci); |
| dtmf_send_clear_config(plci); |
| dtmf_parameter_clear_config(plci); |
| |
| |
| if ((plci->li_bchannel_id != 0) |
| && (li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci == plci)) |
| { |
| mixer_clear_config(plci); |
| li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci = NULL; |
| plci->li_bchannel_id = 0; |
| } |
| |
| plci->B1_resource = 0; |
| plci->B1_facilities = 0; |
| } |
| |
| |
| /* ----------------------------------------------------------------- |
| XON protocol local helpers |
| ----------------------------------------------------------------- */ |
| static void channel_flow_control_remove(PLCI *plci) { |
| DIVA_CAPI_ADAPTER *a = plci->adapter; |
| word i; |
| for (i = 1; i < MAX_NL_CHANNEL + 1; i++) { |
| if (a->ch_flow_plci[i] == plci->Id) { |
| a->ch_flow_plci[i] = 0; |
| a->ch_flow_control[i] = 0; |
| } |
| } |
| } |
| |
| static void channel_x_on(PLCI *plci, byte ch) { |
| DIVA_CAPI_ADAPTER *a = plci->adapter; |
| if (a->ch_flow_control[ch] & N_XON_SENT) { |
| a->ch_flow_control[ch] &= ~N_XON_SENT; |
| } |
| } |
| |
| static void channel_x_off(PLCI *plci, byte ch, byte flag) { |
| DIVA_CAPI_ADAPTER *a = plci->adapter; |
| if ((a->ch_flow_control[ch] & N_RX_FLOW_CONTROL_MASK) == 0) { |
| a->ch_flow_control[ch] |= (N_CH_XOFF | flag); |
| a->ch_flow_plci[ch] = plci->Id; |
| a->ch_flow_control_pending++; |
| } |
| } |
| |
| static void channel_request_xon(PLCI *plci, byte ch) { |
| DIVA_CAPI_ADAPTER *a = plci->adapter; |
| |
| if (a->ch_flow_control[ch] & N_CH_XOFF) { |
| a->ch_flow_control[ch] |= N_XON_REQ; |
| a->ch_flow_control[ch] &= ~N_CH_XOFF; |
| a->ch_flow_control[ch] &= ~N_XON_CONNECT_IND; |
| } |
| } |
| |
| static void channel_xmit_extended_xon(PLCI *plci) { |
| DIVA_CAPI_ADAPTER *a; |
| int max_ch = ARRAY_SIZE(a->ch_flow_control); |
| int i, one_requested = 0; |
| |
| if ((!plci) || (!plci->Id) || ((a = plci->adapter) == NULL)) { |
| return; |
| } |
| |
| for (i = 0; i < max_ch; i++) { |
| if ((a->ch_flow_control[i] & N_CH_XOFF) && |
| (a->ch_flow_control[i] & N_XON_CONNECT_IND) && |
| (plci->Id == a->ch_flow_plci[i])) { |
| channel_request_xon(plci, (byte)i); |
| one_requested = 1; |
| } |
| } |
| |
| if (one_requested) { |
| channel_xmit_xon(plci); |
| } |
| } |
| |
| /* |
| Try to xmit next X_ON |
| */ |
| static int find_channel_with_pending_x_on(DIVA_CAPI_ADAPTER *a, PLCI *plci) { |
| int max_ch = ARRAY_SIZE(a->ch_flow_control); |
| int i; |
| |
| if (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)) { |
| return (0); |
| } |
| |
| if (a->last_flow_control_ch >= max_ch) { |
| a->last_flow_control_ch = 1; |
| } |
| for (i = a->last_flow_control_ch; i < max_ch; i++) { |
| if ((a->ch_flow_control[i] & N_XON_REQ) && |
| (plci->Id == a->ch_flow_plci[i])) { |
| a->last_flow_control_ch = i + 1; |
| return (i); |
| } |
| } |
| |
| for (i = 1; i < a->last_flow_control_ch; i++) { |
| if ((a->ch_flow_control[i] & N_XON_REQ) && |
| (plci->Id == a->ch_flow_plci[i])) { |
| a->last_flow_control_ch = i + 1; |
| return (i); |
| } |
| } |
| |
| return (0); |
| } |
| |
| static void channel_xmit_xon(PLCI *plci) { |
| DIVA_CAPI_ADAPTER *a = plci->adapter; |
| byte ch; |
| |
| if (plci->nl_req || !plci->NL.Id || plci->nl_remove_id) { |
| return; |
| } |
| if ((ch = (byte)find_channel_with_pending_x_on(a, plci)) == 0) { |
| return; |
| } |
| a->ch_flow_control[ch] &= ~N_XON_REQ; |
| a->ch_flow_control[ch] |= N_XON_SENT; |
| |
| plci->NL.Req = plci->nl_req = (byte)N_XON; |
| plci->NL.ReqCh = ch; |
| plci->NL.X = plci->NData; |
| plci->NL.XNum = 1; |
| plci->NData[0].P = &plci->RBuffer[0]; |
| plci->NData[0].PLength = 0; |
| |
| plci->adapter->request(&plci->NL); |
| } |
| |
| static int channel_can_xon(PLCI *plci, byte ch) { |
| APPL *APPLptr; |
| DIVA_CAPI_ADAPTER *a; |
| word NCCIcode; |
| dword count; |
| word Num; |
| word i; |
| |
| APPLptr = plci->appl; |
| a = plci->adapter; |
| |
| if (!APPLptr) |
| return (0); |
| |
| NCCIcode = a->ch_ncci[ch] | (((word) a->Id) << 8); |
| |
| /* count all buffers within the Application pool */ |
| /* belonging to the same NCCI. XON if a first is */ |
| /* used. */ |
| count = 0; |
| Num = 0xffff; |
| for (i = 0; i < APPLptr->MaxBuffer; i++) { |
| if (NCCIcode == APPLptr->DataNCCI[i]) count++; |
| if (!APPLptr->DataNCCI[i] && Num == 0xffff) Num = i; |
| } |
| if ((count > 2) || (Num == 0xffff)) { |
| return (0); |
| } |
| return (1); |
| } |
| |
| |
| /*------------------------------------------------------------------*/ |
| |
| static word CPN_filter_ok(byte *cpn, DIVA_CAPI_ADAPTER *a, word offset) |
| { |
| return 1; |
| } |
| |
| |
| |
| /**********************************************************************************/ |
| /* function groups the listening applications according to the CIP mask and the */ |
| /* Info_Mask. Each group gets just one Connect_Ind. Some application manufacturer */ |
| /* are not multi-instance capable, so they start e.g. 30 applications what causes */ |
| /* big problems on application level (one call, 30 Connect_Ind, ect). The */ |
| /* function must be enabled by setting "a->group_optimization_enabled" from the */ |
| /* OS specific part (per adapter). */ |
| /**********************************************************************************/ |
| static void group_optimization(DIVA_CAPI_ADAPTER *a, PLCI *plci) |
| { |
| word i, j, k, busy, group_found; |
| dword info_mask_group[MAX_CIP_TYPES]; |
| dword cip_mask_group[MAX_CIP_TYPES]; |
| word appl_number_group_type[MAX_APPL]; |
| PLCI *auxplci; |
| |
| set_group_ind_mask(plci); /* all APPLs within this inc. call are allowed to dial in */ |
| |
| if (!a->group_optimization_enabled) |
| { |
| dbug(1, dprintf("No group optimization")); |
| return; |
| } |
| |
| dbug(1, dprintf("Group optimization = 0x%x...", a->group_optimization_enabled)); |
| |
| for (i = 0; i < MAX_CIP_TYPES; i++) |
| { |
| info_mask_group[i] = 0; |
| cip_mask_group[i] = 0; |
| } |
| for (i = 0; i < MAX_APPL; i++) |
| { |
| appl_number_group_type[i] = 0; |
| } |
| for (i = 0; i < max_appl; i++) /* check if any multi instance capable application is present */ |
| { /* group_optimization set to 1 means not to optimize multi-instance capable applications (default) */ |
| if (application[i].Id && (application[i].MaxNCCI) > 1 && (a->CIP_Mask[i]) && (a->group_optimization_enabled == 1)) |
| { |
| dbug(1, dprintf("Multi-Instance capable, no optimization required")); |
| return; /* allow good application unfiltered access */ |
| } |
| } |
| for (i = 0; i < max_appl; i++) /* Build CIP Groups */ |
| { |
| if (application[i].Id && a->CIP_Mask[i]) |
| { |
| for (k = 0, busy = false; k < a->max_plci; k++) |
| { |
| if (a->plci[k].Id) |
| { |
| auxplci = &a->plci[k]; |
| if (auxplci->appl == &application[i]) /* application has a busy PLCI */ |
| { |
| busy = true; |
| dbug(1, dprintf("Appl 0x%x is busy", i + 1)); |
| } |
| else if (test_c_ind_mask_bit(auxplci, i)) /* application has an incoming call pending */ |
| { |
| busy = true; |
| dbug(1, dprintf("Appl 0x%x has inc. call pending", i + 1)); |
| } |
| } |
| } |
| |
| for (j = 0, group_found = 0; j <= (MAX_CIP_TYPES) && !busy && !group_found; j++) /* build groups with free applications only */ |
| { |
| if (j == MAX_CIP_TYPES) /* all groups are in use but group still not found */ |
| { /* the MAX_CIP_TYPES group enables all calls because of field overflow */ |
| appl_number_group_type[i] = MAX_CIP_TYPES; |
| group_found = true; |
| dbug(1, dprintf("Field overflow appl 0x%x", i + 1)); |
| } |
| else if ((info_mask_group[j] == a->CIP_Mask[i]) && (cip_mask_group[j] == a->Info_Mask[i])) |
| { /* is group already present ? */ |
| appl_number_group_type[i] = j | 0x80; /* store the group number for each application */ |
| group_found = true; |
| dbug(1, dprintf("Group 0x%x found with appl 0x%x, CIP=0x%lx", appl_number_group_type[i], i + 1, info_mask_group[j])); |
| } |
| else if (!info_mask_group[j]) |
| { /* establish a new group */ |
| appl_number_group_type[i] = j | 0x80; /* store the group number for each application */ |
| info_mask_group[j] = a->CIP_Mask[i]; /* store the new CIP mask for the new group */ |
| cip_mask_group[j] = a->Info_Mask[i]; /* store the new Info_Mask for this new group */ |
| group_found = true; |
| dbug(1, dprintf("New Group 0x%x established with appl 0x%x, CIP=0x%lx", appl_number_group_type[i], i + 1, info_mask_group[j])); |
| } |
| } |
| } |
| } |
| |
| for (i = 0; i < max_appl; i++) /* Build group_optimization_mask_table */ |
| { |
| if (appl_number_group_type[i]) /* application is free, has listens and is member of a group */ |
| { |
| if (appl_number_group_type[i] == MAX_CIP_TYPES) |
| { |
| dbug(1, dprintf("OverflowGroup 0x%x, valid appl = 0x%x, call enabled", appl_number_group_type[i], i + 1)); |
| } |
| else |
| { |
| dbug(1, dprintf("Group 0x%x, valid appl = 0x%x", appl_number_group_type[i], i + 1)); |
| for (j = i + 1; j < max_appl; j++) /* search other group members and mark them as busy */ |
| { |
| if (appl_number_group_type[i] == appl_number_group_type[j]) |
| { |
| dbug(1, dprintf("Appl 0x%x is member of group 0x%x, no call", j + 1, appl_number_group_type[j])); |
| clear_group_ind_mask_bit(plci, j); /* disable call on other group members */ |
| appl_number_group_type[j] = 0; /* remove disabled group member from group list */ |
| } |
| } |
| } |
| } |
| else /* application should not get a call */ |
| { |
| clear_group_ind_mask_bit(plci, i); |
| } |
| } |
| |
| } |
| |
| |
| |
| /* OS notifies the driver about a application Capi_Register */ |
| word CapiRegister(word id) |
| { |
| word i, j, appls_found; |
| |
| PLCI *plci; |
| DIVA_CAPI_ADAPTER *a; |
| |
| for (i = 0, appls_found = 0; i < max_appl; i++) |
| { |
| if (application[i].Id && (application[i].Id != id)) |
| { |
| appls_found++; /* an application has been found */ |
| } |
| } |
| |
| if (appls_found) return true; |
| for (i = 0; i < max_adapter; i++) /* scan all adapters... */ |
| { |
| a = &adapter[i]; |
| if (a->request) |
| { |
| if (a->flag_dynamic_l1_down) /* remove adapter from L1 tristate (Huntgroup) */ |
| { |
| if (!appls_found) /* first application does a capi register */ |
| { |
| if ((j = get_plci(a))) /* activate L1 of all adapters */ |
| { |
| plci = &a->plci[j - 1]; |
| plci->command = 0; |
| add_p(plci, OAD, "\x01\xfd"); |
| add_p(plci, CAI, "\x01\x80"); |
| add_p(plci, UID, "\x06\x43\x61\x70\x69\x32\x30"); |
| add_p(plci, SHIFT | 6, NULL); |
| add_p(plci, SIN, "\x02\x00\x00"); |
| plci->internal_command = START_L1_SIG_ASSIGN_PEND; |
| sig_req(plci, ASSIGN, DSIG_ID); |
| add_p(plci, FTY, "\x02\xff\x07"); /* l1 start */ |
| sig_req(plci, SIG_CTRL, 0); |
| send_req(plci); |
| } |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| /*------------------------------------------------------------------*/ |
| |
| /* Functions for virtual Switching e.g. Transfer by join, Conference */ |
| |
| static void VSwitchReqInd(PLCI *plci, dword Id, byte **parms) |
| { |
| word i; |
| /* Format of vswitch_t: |
| 0 byte length |
| 1 byte VSWITCHIE |
| 2 byte VSWITCH_REQ/VSWITCH_IND |
| 3 byte reserved |
| 4 word VSwitchcommand |
| 6 word returnerror |
| 8... Params |
| */ |
| if (!plci || |
| !plci->appl || |
| !plci->State || |
| plci->Sig.Ind == NCR_FACILITY |
| ) |
| return; |
| |
| for (i = 0; i < MAX_MULTI_IE; i++) |
| { |
| if (!parms[i][0]) continue; |
| if (parms[i][0] < 7) |
| { |
| parms[i][0] = 0; /* kill it */ |
| continue; |
| } |
| dbug(1, dprintf("VSwitchReqInd(%d)", parms[i][4])); |
| switch (parms[i][4]) |
| { |
| case VSJOIN: |
| if (!plci->relatedPTYPLCI || |
| (plci->ptyState != S_ECT && plci->relatedPTYPLCI->ptyState != S_ECT)) |
| { /* Error */ |
| break; |
| } |
| /* remember all necessary informations */ |
| if (parms[i][0] != 11 || parms[i][8] != 3) /* Length Test */ |
| { |
| break; |
| } |
| if (parms[i][2] == VSWITCH_IND && parms[i][9] == 1) |
| { /* first indication after ECT-Request on Consultation Call */ |
| plci->vswitchstate = parms[i][9]; |
| parms[i][9] = 2; /* State */ |
| /* now ask first Call to join */ |
| } |
| else if (parms[i][2] == VSWITCH_REQ && parms[i][9] == 3) |
| { /* Answer of VSWITCH_REQ from first Call */ |
| plci->vswitchstate = parms[i][9]; |
| /* tell consultation call to join |
| and the protocol capabilities of the first call */ |
| } |
| else |
| { /* Error */ |
| break; |
| } |
| plci->vsprot = parms[i][10]; /* protocol */ |
| plci->vsprotdialect = parms[i][11]; /* protocoldialect */ |
| /* send join request to related PLCI */ |
| parms[i][1] = VSWITCHIE; |
| parms[i][2] = VSWITCH_REQ; |
| |
| plci->relatedPTYPLCI->command = 0; |
| plci->relatedPTYPLCI->internal_command = VSWITCH_REQ_PEND; |
| add_p(plci->relatedPTYPLCI, ESC, &parms[i][0]); |
| sig_req(plci->relatedPTYPLCI, VSWITCH_REQ, 0); |
| send_req(plci->relatedPTYPLCI); |
| break; |
| case VSTRANSPORT: |
| default: |
| if (plci->relatedPTYPLCI && |
| plci->vswitchstate == 3 && |
| plci->relatedPTYPLCI->vswitchstate == 3) |
| { |
| add_p(plci->relatedPTYPLCI, ESC, &parms[i][0]); |
| sig_req(plci->relatedPTYPLCI, VSWITCH_REQ, 0); |
| send_req(plci->relatedPTYPLCI); |
| } |
| break; |
| } |
| parms[i][0] = 0; /* kill it */ |
| } |
| } |
| |
| |
| /*------------------------------------------------------------------*/ |
| |
| static int diva_get_dma_descriptor(PLCI *plci, dword *dma_magic) { |
| ENTITY e; |
| IDI_SYNC_REQ *pReq = (IDI_SYNC_REQ *)&e; |
| |
| if (!(diva_xdi_extended_features & DIVA_CAPI_XDI_PROVIDES_RX_DMA)) { |
| return (-1); |
| } |
| |
| pReq->xdi_dma_descriptor_operation.Req = 0; |
| pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION; |
| |
| pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC; |
| pReq->xdi_dma_descriptor_operation.info.descriptor_number = -1; |
| pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL; |
| pReq->xdi_dma_descriptor_operation.info.descriptor_magic = 0; |
| |
| e.user[0] = plci->adapter->Id - 1; |
| plci->adapter->request((ENTITY *)pReq); |
| |
| if (!pReq->xdi_dma_descriptor_operation.info.operation && |
| (pReq->xdi_dma_descriptor_operation.info.descriptor_number >= 0) && |
| pReq->xdi_dma_descriptor_operation.info.descriptor_magic) { |
| *dma_magic = pReq->xdi_dma_descriptor_operation.info.descriptor_magic; |
| dbug(3, dprintf("dma_alloc, a:%d (%d-%08x)", |
| plci->adapter->Id, |
| pReq->xdi_dma_descriptor_operation.info.descriptor_number, |
| *dma_magic)); |
| return (pReq->xdi_dma_descriptor_operation.info.descriptor_number); |
| } else { |
| dbug(1, dprintf("dma_alloc failed")); |
| return (-1); |
| } |
| } |
| |
| static void diva_free_dma_descriptor(PLCI *plci, int nr) { |
| ENTITY e; |
| IDI_SYNC_REQ *pReq = (IDI_SYNC_REQ *)&e; |
| |
| if (nr < 0) { |
| return; |
| } |
| |
| pReq->xdi_dma_descriptor_operation.Req = 0; |
| pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION; |
| |
| pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE; |
| pReq->xdi_dma_descriptor_operation.info.descriptor_number = nr; |
| pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL; |
| pReq->xdi_dma_descriptor_operation.info.descriptor_magic = 0; |
| |
| e.user[0] = plci->adapter->Id - 1; |
| plci->adapter->request((ENTITY *)pReq); |
| |
| if (!pReq->xdi_dma_descriptor_operation.info.operation) { |
| dbug(1, dprintf("dma_free(%d)", nr)); |
| } else { |
| dbug(1, dprintf("dma_free failed (%d)", nr)); |
| } |
| } |
| |
| /*------------------------------------------------------------------*/ |