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