blob: a82e542ffc21dd4dccf9d1b810ab9373984c1d0d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 *
Joe Perches475be4d2012-02-19 19:52:38 -08003 Copyright (c) Eicon Networks, 2002.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Joe Perches475be4d2012-02-19 19:52:38 -08005 This source file is supplied for the use with
6 Eicon Networks range of DIVA Server Adapters.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Joe Perches475be4d2012-02-19 19:52:38 -08008 Eicon File Revision : 2.1
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
Joe Perches475be4d2012-02-19 19:52:38 -080010 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 *
Joe Perches475be4d2012-02-19 19:52:38 -080015 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
17 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070019 *
Joe Perches475be4d2012-02-19 19:52:38 -080020 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Linus Torvalds1da177e2005-04-16 15:20:36 -070023 *
24 */
25
26
27
28
29
30#include "platform.h"
31#include "di_defs.h"
32#include "pc.h"
33#include "capi20.h"
34#include "divacapi.h"
35#include "mdm_msg.h"
36#include "divasync.h"
37
38
39
40#define FILE_ "MESSAGE.C"
41#define dprintf
42
43
44
45
46
47
48
49
50
51/*------------------------------------------------------------------*/
52/* This is options supported for all adapters that are server by */
53/* XDI driver. Allo it is not necessary to ask it from every adapter*/
54/* and it is not necessary to save it separate for every adapter */
55/* Macrose defined here have only local meaning */
56/*------------------------------------------------------------------*/
57static dword diva_xdi_extended_features = 0;
58
59#define DIVA_CAPI_USE_CMA 0x00000001
60#define DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR 0x00000002
61#define DIVA_CAPI_XDI_PROVIDES_NO_CANCEL 0x00000004
62#define DIVA_CAPI_XDI_PROVIDES_RX_DMA 0x00000008
63
64/*
65 CAPI can request to process all return codes self only if:
66 protocol code supports this && xdi supports this
Joe Perches475be4d2012-02-19 19:52:38 -080067*/
68#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))
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70/*------------------------------------------------------------------*/
71/* local function prototypes */
72/*------------------------------------------------------------------*/
73
Joe Perches475be4d2012-02-19 19:52:38 -080074static void group_optimization(DIVA_CAPI_ADAPTER *a, PLCI *plci);
75static void set_group_ind_mask(PLCI *plci);
76static void clear_group_ind_mask_bit(PLCI *plci, word b);
77static byte test_group_ind_mask_bit(PLCI *plci, word b);
78void AutomaticLaw(DIVA_CAPI_ADAPTER *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079word CapiRelease(word);
80word CapiRegister(word);
Joe Perches475be4d2012-02-19 19:52:38 -080081word api_put(APPL *, CAPI_MSG *);
82static word api_parse(byte *, word, byte *, API_PARSE *);
83static void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out);
84static void api_load_msg(API_SAVE *in, API_PARSE *out);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86word api_remove_start(void);
87void api_remove_complete(void);
88
Joe Perches475be4d2012-02-19 19:52:38 -080089static void plci_remove(PLCI *);
90static void diva_get_extended_adapter_features(DIVA_CAPI_ADAPTER *a);
91static void diva_ask_for_xdi_sdram_bar(DIVA_CAPI_ADAPTER *, IDI_SYNC_REQ *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Joe Perches475be4d2012-02-19 19:52:38 -080093void callback(ENTITY *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Joe Perches475be4d2012-02-19 19:52:38 -080095static void control_rc(PLCI *, byte, byte, byte, byte, byte);
96static void data_rc(PLCI *, byte);
97static void data_ack(PLCI *, byte);
98static void sig_ind(PLCI *);
99static void SendInfo(PLCI *, dword, byte **, byte);
100static void SendSetupInfo(APPL *, PLCI *, dword, byte **, byte);
101static void SendSSExtInd(APPL *, PLCI *plci, dword Id, byte **parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
Joe Perches475be4d2012-02-19 19:52:38 -0800103static void VSwitchReqInd(PLCI *plci, dword Id, byte **parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Joe Perches475be4d2012-02-19 19:52:38 -0800105static void nl_ind(PLCI *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
Joe Perches475be4d2012-02-19 19:52:38 -0800107static byte connect_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
108static byte connect_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
109static byte connect_a_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
110static byte disconnect_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
111static byte disconnect_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
112static byte listen_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
113static byte info_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
114static byte info_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
115static byte alert_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
116static byte facility_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
117static byte facility_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
118static byte connect_b3_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
119static byte connect_b3_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
120static byte connect_b3_a_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
121static byte disconnect_b3_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
122static byte disconnect_b3_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
123static byte data_b3_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
124static byte data_b3_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
125static byte reset_b3_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
126static byte reset_b3_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
127static byte connect_b3_t90_a_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
128static byte select_b_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
129static byte manufacturer_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
130static byte manufacturer_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
Joe Perches475be4d2012-02-19 19:52:38 -0800132static word get_plci(DIVA_CAPI_ADAPTER *);
133static void add_p(PLCI *, byte, byte *);
134static void add_s(PLCI *plci, byte code, API_PARSE *p);
135static void add_ss(PLCI *plci, byte code, API_PARSE *p);
136static void add_ie(PLCI *plci, byte code, byte *p, word p_length);
137static void add_d(PLCI *, word, byte *);
138static void add_ai(PLCI *, API_PARSE *);
139static word add_b1(PLCI *, API_PARSE *, word, word);
140static word add_b23(PLCI *, API_PARSE *);
141static word add_modem_b23(PLCI *plci, API_PARSE *bp_parms);
142static void sig_req(PLCI *, byte, byte);
143static void nl_req_ncci(PLCI *, byte, byte);
144static void send_req(PLCI *);
145static void send_data(PLCI *);
146static word plci_remove_check(PLCI *);
147static void listen_check(DIVA_CAPI_ADAPTER *);
148static byte AddInfo(byte **, byte **, byte *, byte *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149static byte getChannel(API_PARSE *);
Joe Perches475be4d2012-02-19 19:52:38 -0800150static void IndParse(PLCI *, word *, byte **, byte);
151static byte ie_compare(byte *, byte *);
152static word find_cip(DIVA_CAPI_ADAPTER *, byte *, byte *);
153static word CPN_filter_ok(byte *cpn, DIVA_CAPI_ADAPTER *, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
155/*
156 XON protocol helpers
Joe Perches475be4d2012-02-19 19:52:38 -0800157*/
158static void channel_flow_control_remove(PLCI *plci);
159static void channel_x_off(PLCI *plci, byte ch, byte flag);
160static void channel_x_on(PLCI *plci, byte ch);
161static void channel_request_xon(PLCI *plci, byte ch);
162static void channel_xmit_xon(PLCI *plci);
163static int channel_can_xon(PLCI *plci, byte ch);
164static void channel_xmit_extended_xon(PLCI *plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
Joe Perches475be4d2012-02-19 19:52:38 -0800166static byte SendMultiIE(PLCI *plci, dword Id, byte **parms, byte ie_type, dword info_mask, byte setupParse);
167static word AdvCodecSupport(DIVA_CAPI_ADAPTER *, PLCI *, APPL *, byte);
168static void CodecIdCheck(DIVA_CAPI_ADAPTER *, PLCI *);
169static void SetVoiceChannel(PLCI *, byte *, DIVA_CAPI_ADAPTER *);
170static void VoiceChannelOff(PLCI *plci);
171static void adv_voice_write_coefs(PLCI *plci, word write_command);
172static void adv_voice_clear_config(PLCI *plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
Joe Perches475be4d2012-02-19 19:52:38 -0800174static word get_b1_facilities(PLCI *plci, byte b1_resource);
175static byte add_b1_facilities(PLCI *plci, byte b1_resource, word b1_facilities);
176static void adjust_b1_facilities(PLCI *plci, byte new_b1_resource, word new_b1_facilities);
177static word adjust_b_process(dword Id, PLCI *plci, byte Rc);
178static void adjust_b1_resource(dword Id, PLCI *plci, API_SAVE *bp_msg, word b1_facilities, word internal_command);
179static void adjust_b_restore(dword Id, PLCI *plci, byte Rc);
180static void reset_b3_command(dword Id, PLCI *plci, byte Rc);
181static void select_b_command(dword Id, PLCI *plci, byte Rc);
182static void fax_connect_ack_command(dword Id, PLCI *plci, byte Rc);
183static void fax_edata_ack_command(dword Id, PLCI *plci, byte Rc);
184static void fax_connect_info_command(dword Id, PLCI *plci, byte Rc);
185static void fax_adjust_b23_command(dword Id, PLCI *plci, byte Rc);
186static void fax_disconnect_command(dword Id, PLCI *plci, byte Rc);
187static void hold_save_command(dword Id, PLCI *plci, byte Rc);
188static void retrieve_restore_command(dword Id, PLCI *plci, byte Rc);
189static void init_b1_config(PLCI *plci);
190static void clear_b1_config(PLCI *plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
Joe Perches475be4d2012-02-19 19:52:38 -0800192static void dtmf_command(dword Id, PLCI *plci, byte Rc);
193static byte dtmf_request(dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg);
194static void dtmf_confirmation(dword Id, PLCI *plci);
195static void dtmf_indication(dword Id, PLCI *plci, byte *msg, word length);
196static void dtmf_parameter_write(PLCI *plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
198
Joe Perches475be4d2012-02-19 19:52:38 -0800199static void mixer_set_bchannel_id_esc(PLCI *plci, byte bchannel_id);
200static void mixer_set_bchannel_id(PLCI *plci, byte *chi);
201static void mixer_clear_config(PLCI *plci);
202static void mixer_notify_update(PLCI *plci, byte others);
203static void mixer_command(dword Id, PLCI *plci, byte Rc);
204static byte mixer_request(dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg);
205static void mixer_indication_coefs_set(dword Id, PLCI *plci);
206static void mixer_indication_xconnect_from(dword Id, PLCI *plci, byte *msg, word length);
207static void mixer_indication_xconnect_to(dword Id, PLCI *plci, byte *msg, word length);
208static void mixer_remove(PLCI *plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
210
Joe Perches475be4d2012-02-19 19:52:38 -0800211static void ec_command(dword Id, PLCI *plci, byte Rc);
212static byte ec_request(dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg);
213static void ec_indication(dword Id, PLCI *plci, byte *msg, word length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
215
Joe Perches475be4d2012-02-19 19:52:38 -0800216static void rtp_connect_b3_req_command(dword Id, PLCI *plci, byte Rc);
217static void rtp_connect_b3_res_command(dword Id, PLCI *plci, byte Rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219
Joe Perches475be4d2012-02-19 19:52:38 -0800220static int diva_get_dma_descriptor(PLCI *plci, dword *dma_magic);
221static void diva_free_dma_descriptor(PLCI *plci, int nr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
223/*------------------------------------------------------------------*/
224/* external function prototypes */
225/*------------------------------------------------------------------*/
226
Joe Perches475be4d2012-02-19 19:52:38 -0800227extern byte MapController(byte);
228extern byte UnMapController(byte);
229#define MapId(Id)(((Id) & 0xffffff00L) | MapController((byte)(Id)))
230#define UnMapId(Id)(((Id) & 0xffffff00L) | UnMapController((byte)(Id)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
Joe Perches475be4d2012-02-19 19:52:38 -0800232void sendf(APPL *, word, dword, word, byte *, ...);
233void *TransmitBufferSet(APPL *appl, dword ref);
234void *TransmitBufferGet(APPL *appl, void *p);
235void TransmitBufferFree(APPL *appl, void *p);
236void *ReceiveBufferGet(APPL *appl, int Num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Joe Perches475be4d2012-02-19 19:52:38 -0800238int fax_head_line_time(char *buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240
241/*------------------------------------------------------------------*/
242/* Global data definitions */
243/*------------------------------------------------------------------*/
244extern byte max_adapter;
245extern byte max_appl;
Joe Perches475be4d2012-02-19 19:52:38 -0800246extern DIVA_CAPI_ADAPTER *adapter;
247extern APPL *application;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
249
250
251
252
253
254
Richard Knutsson986c4bb2007-02-12 00:53:24 -0800255static byte remove_started = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256static PLCI dummy_plci;
257
258
259static struct _ftable {
Joe Perches475be4d2012-02-19 19:52:38 -0800260 word command;
261 byte *format;
262 byte (*function)(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263} ftable[] = {
Joe Perches475be4d2012-02-19 19:52:38 -0800264 {_DATA_B3_R, "dwww", data_b3_req},
265 {_DATA_B3_I | RESPONSE, "w", data_b3_res},
266 {_INFO_R, "ss", info_req},
267 {_INFO_I | RESPONSE, "", info_res},
268 {_CONNECT_R, "wsssssssss", connect_req},
269 {_CONNECT_I | RESPONSE, "wsssss", connect_res},
270 {_CONNECT_ACTIVE_I | RESPONSE, "", connect_a_res},
271 {_DISCONNECT_R, "s", disconnect_req},
272 {_DISCONNECT_I | RESPONSE, "", disconnect_res},
273 {_LISTEN_R, "dddss", listen_req},
274 {_ALERT_R, "s", alert_req},
275 {_FACILITY_R, "ws", facility_req},
276 {_FACILITY_I | RESPONSE, "ws", facility_res},
277 {_CONNECT_B3_R, "s", connect_b3_req},
278 {_CONNECT_B3_I | RESPONSE, "ws", connect_b3_res},
279 {_CONNECT_B3_ACTIVE_I | RESPONSE, "", connect_b3_a_res},
280 {_DISCONNECT_B3_R, "s", disconnect_b3_req},
281 {_DISCONNECT_B3_I | RESPONSE, "", disconnect_b3_res},
282 {_RESET_B3_R, "s", reset_b3_req},
283 {_RESET_B3_I | RESPONSE, "", reset_b3_res},
284 {_CONNECT_B3_T90_ACTIVE_I | RESPONSE, "ws", connect_b3_t90_a_res},
285 {_CONNECT_B3_T90_ACTIVE_I | RESPONSE, "", connect_b3_t90_a_res},
286 {_SELECT_B_REQ, "s", select_b_req},
287 {_MANUFACTURER_R, "dws", manufacturer_req},
288 {_MANUFACTURER_I | RESPONSE, "dws", manufacturer_res},
289 {_MANUFACTURER_I | RESPONSE, "", manufacturer_res}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290};
291
Joe Perches475be4d2012-02-19 19:52:38 -0800292static byte *cip_bc[29][2] = {
293 { "", "" }, /* 0 */
294 { "\x03\x80\x90\xa3", "\x03\x80\x90\xa2" }, /* 1 */
295 { "\x02\x88\x90", "\x02\x88\x90" }, /* 2 */
296 { "\x02\x89\x90", "\x02\x89\x90" }, /* 3 */
297 { "\x03\x90\x90\xa3", "\x03\x90\x90\xa2" }, /* 4 */
298 { "\x03\x91\x90\xa5", "\x03\x91\x90\xa5" }, /* 5 */
299 { "\x02\x98\x90", "\x02\x98\x90" }, /* 6 */
300 { "\x04\x88\xc0\xc6\xe6", "\x04\x88\xc0\xc6\xe6" }, /* 7 */
301 { "\x04\x88\x90\x21\x8f", "\x04\x88\x90\x21\x8f" }, /* 8 */
302 { "\x03\x91\x90\xa5", "\x03\x91\x90\xa5" }, /* 9 */
303 { "", "" }, /* 10 */
304 { "", "" }, /* 11 */
305 { "", "" }, /* 12 */
306 { "", "" }, /* 13 */
307 { "", "" }, /* 14 */
308 { "", "" }, /* 15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Joe Perches475be4d2012-02-19 19:52:38 -0800310 { "\x03\x80\x90\xa3", "\x03\x80\x90\xa2" }, /* 16 */
311 { "\x03\x90\x90\xa3", "\x03\x90\x90\xa2" }, /* 17 */
312 { "\x02\x88\x90", "\x02\x88\x90" }, /* 18 */
313 { "\x02\x88\x90", "\x02\x88\x90" }, /* 19 */
314 { "\x02\x88\x90", "\x02\x88\x90" }, /* 20 */
315 { "\x02\x88\x90", "\x02\x88\x90" }, /* 21 */
316 { "\x02\x88\x90", "\x02\x88\x90" }, /* 22 */
317 { "\x02\x88\x90", "\x02\x88\x90" }, /* 23 */
318 { "\x02\x88\x90", "\x02\x88\x90" }, /* 24 */
319 { "\x02\x88\x90", "\x02\x88\x90" }, /* 25 */
320 { "\x03\x91\x90\xa5", "\x03\x91\x90\xa5" }, /* 26 */
321 { "\x03\x91\x90\xa5", "\x03\x91\x90\xa5" }, /* 27 */
322 { "\x02\x88\x90", "\x02\x88\x90" } /* 28 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323};
324
Joe Perches475be4d2012-02-19 19:52:38 -0800325static byte *cip_hlc[29] = {
326 "", /* 0 */
327 "", /* 1 */
328 "", /* 2 */
329 "", /* 3 */
330 "", /* 4 */
331 "", /* 5 */
332 "", /* 6 */
333 "", /* 7 */
334 "", /* 8 */
335 "", /* 9 */
336 "", /* 10 */
337 "", /* 11 */
338 "", /* 12 */
339 "", /* 13 */
340 "", /* 14 */
341 "", /* 15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
Joe Perches475be4d2012-02-19 19:52:38 -0800343 "\x02\x91\x81", /* 16 */
344 "\x02\x91\x84", /* 17 */
345 "\x02\x91\xa1", /* 18 */
346 "\x02\x91\xa4", /* 19 */
347 "\x02\x91\xa8", /* 20 */
348 "\x02\x91\xb1", /* 21 */
349 "\x02\x91\xb2", /* 22 */
350 "\x02\x91\xb5", /* 23 */
351 "\x02\x91\xb8", /* 24 */
352 "\x02\x91\xc1", /* 25 */
353 "\x02\x91\x81", /* 26 */
354 "\x03\x91\xe0\x01", /* 27 */
355 "\x03\x91\xe0\x02" /* 28 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356};
357
358/*------------------------------------------------------------------*/
359
360#define V120_HEADER_LENGTH 1
361#define V120_HEADER_EXTEND_BIT 0x80
362#define V120_HEADER_BREAK_BIT 0x40
363#define V120_HEADER_C1_BIT 0x04
364#define V120_HEADER_C2_BIT 0x08
365#define V120_HEADER_FLUSH_COND (V120_HEADER_BREAK_BIT | V120_HEADER_C1_BIT | V120_HEADER_C2_BIT)
366
367static byte v120_default_header[] =
368{
369
Joe Perches475be4d2012-02-19 19:52:38 -0800370 0x83 /* Ext, BR , res, res, C2 , C1 , B , F */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
372};
373
374static byte v120_break_header[] =
375{
376
Joe Perches475be4d2012-02-19 19:52:38 -0800377 0xc3 | V120_HEADER_BREAK_BIT /* Ext, BR , res, res, C2 , C1 , B , F */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
379};
380
381
382/*------------------------------------------------------------------*/
383/* API_PUT function */
384/*------------------------------------------------------------------*/
385
Joe Perches475be4d2012-02-19 19:52:38 -0800386word api_put(APPL *appl, CAPI_MSG *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387{
Joe Perches475be4d2012-02-19 19:52:38 -0800388 word i, j, k, l, n;
389 word ret;
390 byte c;
391 byte controller;
392 DIVA_CAPI_ADAPTER *a;
393 PLCI *plci;
394 NCCI *ncci_ptr;
395 word ncci;
396 CAPI_MSG *m;
397 API_PARSE msg_parms[MAX_MSG_PARMS + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
Joe Perches475be4d2012-02-19 19:52:38 -0800399 if (msg->header.length < sizeof(msg->header) ||
400 msg->header.length > MAX_MSG_SIZE) {
401 dbug(1, dprintf("bad len"));
402 return _BAD_MSG;
403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
Joe Perches475be4d2012-02-19 19:52:38 -0800405 controller = (byte)((msg->header.controller & 0x7f) - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Joe Perches475be4d2012-02-19 19:52:38 -0800407 /* controller starts with 0 up to (max_adapter - 1) */
408 if (controller >= max_adapter)
409 {
410 dbug(1, dprintf("invalid ctrl"));
411 return _BAD_MSG;
412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Joe Perches475be4d2012-02-19 19:52:38 -0800414 a = &adapter[controller];
415 plci = NULL;
416 if ((msg->header.plci != 0) && (msg->header.plci <= a->max_plci) && !a->adapter_disabled)
417 {
418 dbug(1, dprintf("plci=%x", msg->header.plci));
419 plci = &a->plci[msg->header.plci - 1];
420 ncci = GET_WORD(&msg->header.ncci);
421 if (plci->Id
422 && (plci->appl
423 || (plci->State == INC_CON_PENDING)
424 || (plci->State == INC_CON_ALERT)
425 || (msg->header.command == (_DISCONNECT_I | RESPONSE)))
426 && ((ncci == 0)
427 || (msg->header.command == (_DISCONNECT_B3_I | RESPONSE))
428 || ((ncci < MAX_NCCI + 1) && (a->ncci_plci[ncci] == plci->Id))))
429 {
430 i = plci->msg_in_read_pos;
431 j = plci->msg_in_write_pos;
432 if (j >= i)
433 {
434 if (j + msg->header.length + MSG_IN_OVERHEAD <= MSG_IN_QUEUE_SIZE)
435 i += MSG_IN_QUEUE_SIZE - j;
436 else
437 j = 0;
438 }
439 else
440 {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
Joe Perches475be4d2012-02-19 19:52:38 -0800442 n = (((CAPI_MSG *)(plci->msg_in_queue))->header.length + MSG_IN_OVERHEAD + 3) & 0xfffc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
Joe Perches475be4d2012-02-19 19:52:38 -0800444 if (i > MSG_IN_QUEUE_SIZE - n)
445 i = MSG_IN_QUEUE_SIZE - n + 1;
446 i -= j;
447 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Joe Perches475be4d2012-02-19 19:52:38 -0800449 if (i <= ((msg->header.length + MSG_IN_OVERHEAD + 3) & 0xfffc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
Joe Perches475be4d2012-02-19 19:52:38 -0800451 {
452 dbug(0, dprintf("Q-FULL1(msg) - len=%d write=%d read=%d wrap=%d free=%d",
453 msg->header.length, plci->msg_in_write_pos,
454 plci->msg_in_read_pos, plci->msg_in_wrap_pos, i));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
Joe Perches475be4d2012-02-19 19:52:38 -0800456 return _QUEUE_FULL;
457 }
458 c = false;
459 if ((((byte *) msg) < ((byte *)(plci->msg_in_queue)))
460 || (((byte *) msg) >= ((byte *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
461 {
462 if (plci->msg_in_write_pos != plci->msg_in_read_pos)
463 c = true;
464 }
465 if (msg->header.command == _DATA_B3_R)
466 {
467 if (msg->header.length < 20)
468 {
469 dbug(1, dprintf("DATA_B3 REQ wrong length %d", msg->header.length));
470 return _BAD_MSG;
471 }
472 ncci_ptr = &(a->ncci[ncci]);
473 n = ncci_ptr->data_pending;
474 l = ncci_ptr->data_ack_pending;
475 k = plci->msg_in_read_pos;
476 while (k != plci->msg_in_write_pos)
477 {
478 if (k == plci->msg_in_wrap_pos)
479 k = 0;
480 if ((((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[k]))->header.command == _DATA_B3_R)
481 && (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[k]))->header.ncci == ncci))
482 {
483 n++;
484 if (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[k]))->info.data_b3_req.Flags & 0x0004)
485 l++;
486 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Joe Perches475be4d2012-02-19 19:52:38 -0800488 k += (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[k]))->header.length +
489 MSG_IN_OVERHEAD + 3) & 0xfffc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
Joe Perches475be4d2012-02-19 19:52:38 -0800491 }
492 if ((n >= MAX_DATA_B3) || (l >= MAX_DATA_ACK))
493 {
494 dbug(0, dprintf("Q-FULL2(data) - pending=%d/%d ack_pending=%d/%d",
495 ncci_ptr->data_pending, n, ncci_ptr->data_ack_pending, l));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Joe Perches475be4d2012-02-19 19:52:38 -0800497 return _QUEUE_FULL;
498 }
499 if (plci->req_in || plci->internal_command)
500 {
501 if ((((byte *) msg) >= ((byte *)(plci->msg_in_queue)))
502 && (((byte *) msg) < ((byte *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
503 {
504 dbug(0, dprintf("Q-FULL3(requeue)"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
Joe Perches475be4d2012-02-19 19:52:38 -0800506 return _QUEUE_FULL;
507 }
508 c = true;
509 }
510 }
511 else
512 {
513 if (plci->req_in || plci->internal_command)
514 c = true;
515 else
516 {
517 plci->command = msg->header.command;
518 plci->number = msg->header.number;
519 }
520 }
521 if (c)
522 {
523 dbug(1, dprintf("enqueue msg(0x%04x,0x%x,0x%x) - len=%d write=%d read=%d wrap=%d free=%d",
524 msg->header.command, plci->req_in, plci->internal_command,
525 msg->header.length, plci->msg_in_write_pos,
526 plci->msg_in_read_pos, plci->msg_in_wrap_pos, i));
527 if (j == 0)
528 plci->msg_in_wrap_pos = plci->msg_in_write_pos;
529 m = (CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[j]);
530 for (i = 0; i < msg->header.length; i++)
531 ((byte *)(plci->msg_in_queue))[j++] = ((byte *) msg)[i];
532 if (m->header.command == _DATA_B3_R)
533 {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
Joe Perches475be4d2012-02-19 19:52:38 -0800535 m->info.data_b3_req.Data = (dword)(long)(TransmitBufferSet(appl, m->info.data_b3_req.Data));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
Joe Perches475be4d2012-02-19 19:52:38 -0800537 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
Joe Perches475be4d2012-02-19 19:52:38 -0800539 j = (j + 3) & 0xfffc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
Joe Perches475be4d2012-02-19 19:52:38 -0800541 *((APPL **)(&((byte *)(plci->msg_in_queue))[j])) = appl;
542 plci->msg_in_write_pos = j + MSG_IN_OVERHEAD;
543 return 0;
544 }
545 }
546 else
547 {
548 plci = NULL;
549 }
550 }
551 dbug(1, dprintf("com=%x", msg->header.command));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
Joe Perches475be4d2012-02-19 19:52:38 -0800553 for (j = 0; j < MAX_MSG_PARMS + 1; j++) msg_parms[j].length = 0;
554 for (i = 0, ret = _BAD_MSG; i < ARRAY_SIZE(ftable); i++) {
555
556 if (ftable[i].command == msg->header.command) {
557 /* break loop if the message is correct, otherwise continue scan */
558 /* (for example: CONNECT_B3_T90_ACT_RES has two specifications) */
559 if (!api_parse(msg->info.b, (word)(msg->header.length - 12), ftable[i].format, msg_parms)) {
560 ret = 0;
561 break;
562 }
563 for (j = 0; j < MAX_MSG_PARMS + 1; j++) msg_parms[j].length = 0;
564 }
565 }
566 if (ret) {
567 dbug(1, dprintf("BAD_MSG"));
568 if (plci) plci->command = 0;
569 return ret;
570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
572
Joe Perches475be4d2012-02-19 19:52:38 -0800573 c = ftable[i].function(GET_DWORD(&msg->header.controller),
574 msg->header.number,
575 a,
576 plci,
577 appl,
578 msg_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Joe Perches475be4d2012-02-19 19:52:38 -0800580 channel_xmit_extended_xon(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Joe Perches475be4d2012-02-19 19:52:38 -0800582 if (c == 1) send_req(plci);
583 if (c == 2 && plci) plci->req_in = plci->req_in_start = plci->req_out = 0;
584 if (plci && !plci->req_in) plci->command = 0;
585 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586}
587
588
589/*------------------------------------------------------------------*/
590/* api_parse function, check the format of api messages */
591/*------------------------------------------------------------------*/
592
Hannes Eder4ee59d52008-12-16 01:17:33 -0800593static word api_parse(byte *msg, word length, byte *format, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594{
Joe Perches475be4d2012-02-19 19:52:38 -0800595 word i;
596 word p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
Joe Perches475be4d2012-02-19 19:52:38 -0800598 for (i = 0, p = 0; format[i]; i++) {
599 if (parms)
600 {
601 parms[i].info = &msg[p];
602 }
603 switch (format[i]) {
604 case 'b':
605 p += 1;
606 break;
607 case 'w':
608 p += 2;
609 break;
610 case 'd':
611 p += 4;
612 break;
613 case 's':
614 if (msg[p] == 0xff) {
615 parms[i].info += 2;
616 parms[i].length = msg[p + 1] + (msg[p + 2] << 8);
617 p += (parms[i].length + 3);
618 }
619 else {
620 parms[i].length = msg[p];
621 p += (parms[i].length + 1);
622 }
623 break;
624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
Joe Perches475be4d2012-02-19 19:52:38 -0800626 if (p > length) return true;
627 }
628 if (parms) parms[i].info = NULL;
629 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630}
631
Hannes Eder4ee59d52008-12-16 01:17:33 -0800632static void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633{
Joe Perches475be4d2012-02-19 19:52:38 -0800634 word i, j, n = 0;
635 byte *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
Joe Perches475be4d2012-02-19 19:52:38 -0800637 p = out->info;
638 for (i = 0; format[i] != '\0'; i++)
639 {
640 out->parms[i].info = p;
641 out->parms[i].length = in[i].length;
642 switch (format[i])
643 {
644 case 'b':
645 n = 1;
646 break;
647 case 'w':
648 n = 2;
649 break;
650 case 'd':
651 n = 4;
652 break;
653 case 's':
654 n = in[i].length + 1;
655 break;
656 }
657 for (j = 0; j < n; j++)
658 *(p++) = in[i].info[j];
659 }
660 out->parms[i].info = NULL;
661 out->parms[i].length = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662}
663
Hannes Eder4ee59d52008-12-16 01:17:33 -0800664static void api_load_msg(API_SAVE *in, API_PARSE *out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665{
Joe Perches475be4d2012-02-19 19:52:38 -0800666 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Joe Perches475be4d2012-02-19 19:52:38 -0800668 i = 0;
669 do
670 {
671 out[i].info = in->parms[i].info;
672 out[i].length = in->parms[i].length;
673 } while (in->parms[i++].info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674}
675
676
677/*------------------------------------------------------------------*/
678/* CAPI remove function */
679/*------------------------------------------------------------------*/
680
681word api_remove_start(void)
682{
Joe Perches475be4d2012-02-19 19:52:38 -0800683 word i;
684 word j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Joe Perches475be4d2012-02-19 19:52:38 -0800686 if (!remove_started) {
687 remove_started = true;
688 for (i = 0; i < max_adapter; i++) {
689 if (adapter[i].request) {
690 for (j = 0; j < adapter[i].max_plci; j++) {
691 if (adapter[i].plci[j].Sig.Id) plci_remove(&adapter[i].plci[j]);
692 }
693 }
694 }
695 return 1;
696 }
697 else {
698 for (i = 0; i < max_adapter; i++) {
699 if (adapter[i].request) {
700 for (j = 0; j < adapter[i].max_plci; j++) {
701 if (adapter[i].plci[j].Sig.Id) return 1;
702 }
703 }
704 }
705 }
706 api_remove_complete();
707 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708}
709
710
711/*------------------------------------------------------------------*/
712/* internal command queue */
713/*------------------------------------------------------------------*/
714
Joe Perches475be4d2012-02-19 19:52:38 -0800715static void init_internal_command_queue(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716{
Joe Perches475be4d2012-02-19 19:52:38 -0800717 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
Joe Perches475be4d2012-02-19 19:52:38 -0800719 dbug(1, dprintf("%s,%d: init_internal_command_queue",
720 (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
Joe Perches475be4d2012-02-19 19:52:38 -0800722 plci->internal_command = 0;
723 for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS; i++)
724 plci->internal_command_queue[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725}
726
727
Joe Perches475be4d2012-02-19 19:52:38 -0800728static void start_internal_command(dword Id, PLCI *plci, t_std_internal_command command_function)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729{
Joe Perches475be4d2012-02-19 19:52:38 -0800730 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
Joe Perches475be4d2012-02-19 19:52:38 -0800732 dbug(1, dprintf("[%06lx] %s,%d: start_internal_command",
733 UnMapId(Id), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Joe Perches475be4d2012-02-19 19:52:38 -0800735 if (plci->internal_command == 0)
736 {
737 plci->internal_command_queue[0] = command_function;
738 (*command_function)(Id, plci, OK);
739 }
740 else
741 {
742 i = 1;
743 while (plci->internal_command_queue[i] != NULL)
744 i++;
745 plci->internal_command_queue[i] = command_function;
746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747}
748
749
Joe Perches475be4d2012-02-19 19:52:38 -0800750static void next_internal_command(dword Id, PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
Joe Perches475be4d2012-02-19 19:52:38 -0800752 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Joe Perches475be4d2012-02-19 19:52:38 -0800754 dbug(1, dprintf("[%06lx] %s,%d: next_internal_command",
755 UnMapId(Id), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Joe Perches475be4d2012-02-19 19:52:38 -0800757 plci->internal_command = 0;
758 plci->internal_command_queue[0] = NULL;
759 while (plci->internal_command_queue[1] != NULL)
760 {
761 for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS - 1; i++)
762 plci->internal_command_queue[i] = plci->internal_command_queue[i + 1];
763 plci->internal_command_queue[MAX_INTERNAL_COMMAND_LEVELS - 1] = NULL;
764 (*(plci->internal_command_queue[0]))(Id, plci, OK);
765 if (plci->internal_command != 0)
766 return;
767 plci->internal_command_queue[0] = NULL;
768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769}
770
771
772/*------------------------------------------------------------------*/
773/* NCCI allocate/remove function */
774/*------------------------------------------------------------------*/
775
776static dword ncci_mapping_bug = 0;
777
Joe Perches475be4d2012-02-19 19:52:38 -0800778static word get_ncci(PLCI *plci, byte ch, word force_ncci)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779{
Joe Perches475be4d2012-02-19 19:52:38 -0800780 DIVA_CAPI_ADAPTER *a;
781 word ncci, i, j, k;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Joe Perches475be4d2012-02-19 19:52:38 -0800783 a = plci->adapter;
784 if (!ch || a->ch_ncci[ch])
785 {
786 ncci_mapping_bug++;
787 dbug(1, dprintf("NCCI mapping exists %ld %02x %02x %02x-%02x",
788 ncci_mapping_bug, ch, force_ncci, a->ncci_ch[a->ch_ncci[ch]], a->ch_ncci[ch]));
789 ncci = ch;
790 }
791 else
792 {
793 if (force_ncci)
794 ncci = force_ncci;
795 else
796 {
797 if ((ch < MAX_NCCI + 1) && !a->ncci_ch[ch])
798 ncci = ch;
799 else
800 {
801 ncci = 1;
802 while ((ncci < MAX_NCCI + 1) && a->ncci_ch[ncci])
803 ncci++;
804 if (ncci == MAX_NCCI + 1)
805 {
806 ncci_mapping_bug++;
807 i = 1;
808 do
809 {
810 j = 1;
811 while ((j < MAX_NCCI + 1) && (a->ncci_ch[j] != i))
812 j++;
813 k = j;
814 if (j < MAX_NCCI + 1)
815 {
816 do
817 {
818 j++;
819 } while ((j < MAX_NCCI + 1) && (a->ncci_ch[j] != i));
820 }
821 } while ((i < MAX_NL_CHANNEL + 1) && (j < MAX_NCCI + 1));
822 if (i < MAX_NL_CHANNEL + 1)
823 {
824 dbug(1, dprintf("NCCI mapping overflow %ld %02x %02x %02x-%02x-%02x",
825 ncci_mapping_bug, ch, force_ncci, i, k, j));
826 }
827 else
828 {
829 dbug(1, dprintf("NCCI mapping overflow %ld %02x %02x",
830 ncci_mapping_bug, ch, force_ncci));
831 }
832 ncci = ch;
833 }
834 }
835 a->ncci_plci[ncci] = plci->Id;
836 a->ncci_state[ncci] = IDLE;
837 if (!plci->ncci_ring_list)
838 plci->ncci_ring_list = ncci;
839 else
840 a->ncci_next[ncci] = a->ncci_next[plci->ncci_ring_list];
841 a->ncci_next[plci->ncci_ring_list] = (byte) ncci;
842 }
843 a->ncci_ch[ncci] = ch;
844 a->ch_ncci[ch] = (byte) ncci;
845 dbug(1, dprintf("NCCI mapping established %ld %02x %02x %02x-%02x",
846 ncci_mapping_bug, ch, force_ncci, ch, ncci));
847 }
848 return (ncci);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849}
850
851
Joe Perches475be4d2012-02-19 19:52:38 -0800852static void ncci_free_receive_buffers(PLCI *plci, word ncci)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853{
Joe Perches475be4d2012-02-19 19:52:38 -0800854 DIVA_CAPI_ADAPTER *a;
855 APPL *appl;
856 word i, ncci_code;
857 dword Id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
Joe Perches475be4d2012-02-19 19:52:38 -0800859 a = plci->adapter;
860 Id = (((dword) ncci) << 16) | (((word)(plci->Id)) << 8) | a->Id;
861 if (ncci)
862 {
863 if (a->ncci_plci[ncci] == plci->Id)
864 {
865 if (!plci->appl)
866 {
867 ncci_mapping_bug++;
868 dbug(1, dprintf("NCCI mapping appl expected %ld %08lx",
869 ncci_mapping_bug, Id));
870 }
871 else
872 {
873 appl = plci->appl;
874 ncci_code = ncci | (((word) a->Id) << 8);
875 for (i = 0; i < appl->MaxBuffer; i++)
876 {
877 if ((appl->DataNCCI[i] == ncci_code)
878 && (((byte)(appl->DataFlags[i] >> 8)) == plci->Id))
879 {
880 appl->DataNCCI[i] = 0;
881 }
882 }
883 }
884 }
885 }
886 else
887 {
888 for (ncci = 1; ncci < MAX_NCCI + 1; ncci++)
889 {
890 if (a->ncci_plci[ncci] == plci->Id)
891 {
892 if (!plci->appl)
893 {
894 ncci_mapping_bug++;
895 dbug(1, dprintf("NCCI mapping no appl %ld %08lx",
896 ncci_mapping_bug, Id));
897 }
898 else
899 {
900 appl = plci->appl;
901 ncci_code = ncci | (((word) a->Id) << 8);
902 for (i = 0; i < appl->MaxBuffer; i++)
903 {
904 if ((appl->DataNCCI[i] == ncci_code)
905 && (((byte)(appl->DataFlags[i] >> 8)) == plci->Id))
906 {
907 appl->DataNCCI[i] = 0;
908 }
909 }
910 }
911 }
912 }
913 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914}
915
916
Joe Perches475be4d2012-02-19 19:52:38 -0800917static void cleanup_ncci_data(PLCI *plci, word ncci)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918{
Joe Perches475be4d2012-02-19 19:52:38 -0800919 NCCI *ncci_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Joe Perches475be4d2012-02-19 19:52:38 -0800921 if (ncci && (plci->adapter->ncci_plci[ncci] == plci->Id))
922 {
923 ncci_ptr = &(plci->adapter->ncci[ncci]);
924 if (plci->appl)
925 {
926 while (ncci_ptr->data_pending != 0)
927 {
928 if (!plci->data_sent || (ncci_ptr->DBuffer[ncci_ptr->data_out].P != plci->data_sent_ptr))
929 TransmitBufferFree(plci->appl, ncci_ptr->DBuffer[ncci_ptr->data_out].P);
930 (ncci_ptr->data_out)++;
931 if (ncci_ptr->data_out == MAX_DATA_B3)
932 ncci_ptr->data_out = 0;
933 (ncci_ptr->data_pending)--;
934 }
935 }
936 ncci_ptr->data_out = 0;
937 ncci_ptr->data_pending = 0;
938 ncci_ptr->data_ack_out = 0;
939 ncci_ptr->data_ack_pending = 0;
940 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941}
942
943
Joe Perches475be4d2012-02-19 19:52:38 -0800944static void ncci_remove(PLCI *plci, word ncci, byte preserve_ncci)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945{
Joe Perches475be4d2012-02-19 19:52:38 -0800946 DIVA_CAPI_ADAPTER *a;
947 dword Id;
948 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
Joe Perches475be4d2012-02-19 19:52:38 -0800950 a = plci->adapter;
951 Id = (((dword) ncci) << 16) | (((word)(plci->Id)) << 8) | a->Id;
952 if (!preserve_ncci)
953 ncci_free_receive_buffers(plci, ncci);
954 if (ncci)
955 {
956 if (a->ncci_plci[ncci] != plci->Id)
957 {
958 ncci_mapping_bug++;
959 dbug(1, dprintf("NCCI mapping doesn't exist %ld %08lx %02x",
960 ncci_mapping_bug, Id, preserve_ncci));
961 }
962 else
963 {
964 cleanup_ncci_data(plci, ncci);
965 dbug(1, dprintf("NCCI mapping released %ld %08lx %02x %02x-%02x",
966 ncci_mapping_bug, Id, preserve_ncci, a->ncci_ch[ncci], ncci));
967 a->ch_ncci[a->ncci_ch[ncci]] = 0;
968 if (!preserve_ncci)
969 {
970 a->ncci_ch[ncci] = 0;
971 a->ncci_plci[ncci] = 0;
972 a->ncci_state[ncci] = IDLE;
973 i = plci->ncci_ring_list;
974 while ((i != 0) && (a->ncci_next[i] != plci->ncci_ring_list) && (a->ncci_next[i] != ncci))
975 i = a->ncci_next[i];
976 if ((i != 0) && (a->ncci_next[i] == ncci))
977 {
978 if (i == ncci)
979 plci->ncci_ring_list = 0;
980 else if (plci->ncci_ring_list == ncci)
981 plci->ncci_ring_list = i;
982 a->ncci_next[i] = a->ncci_next[ncci];
983 }
984 a->ncci_next[ncci] = 0;
985 }
986 }
987 }
988 else
989 {
990 for (ncci = 1; ncci < MAX_NCCI + 1; ncci++)
991 {
992 if (a->ncci_plci[ncci] == plci->Id)
993 {
994 cleanup_ncci_data(plci, ncci);
995 dbug(1, dprintf("NCCI mapping released %ld %08lx %02x %02x-%02x",
996 ncci_mapping_bug, Id, preserve_ncci, a->ncci_ch[ncci], ncci));
997 a->ch_ncci[a->ncci_ch[ncci]] = 0;
998 if (!preserve_ncci)
999 {
1000 a->ncci_ch[ncci] = 0;
1001 a->ncci_plci[ncci] = 0;
1002 a->ncci_state[ncci] = IDLE;
1003 a->ncci_next[ncci] = 0;
1004 }
1005 }
1006 }
1007 if (!preserve_ncci)
1008 plci->ncci_ring_list = 0;
1009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010}
1011
1012
1013/*------------------------------------------------------------------*/
1014/* PLCI remove function */
1015/*------------------------------------------------------------------*/
1016
Joe Perches475be4d2012-02-19 19:52:38 -08001017static void plci_free_msg_in_queue(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018{
Joe Perches475be4d2012-02-19 19:52:38 -08001019 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
Joe Perches475be4d2012-02-19 19:52:38 -08001021 if (plci->appl)
1022 {
1023 i = plci->msg_in_read_pos;
1024 while (i != plci->msg_in_write_pos)
1025 {
1026 if (i == plci->msg_in_wrap_pos)
1027 i = 0;
1028 if (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[i]))->header.command == _DATA_B3_R)
1029 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
Joe Perches475be4d2012-02-19 19:52:38 -08001031 TransmitBufferFree(plci->appl,
1032 (byte *)(long)(((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[i]))->info.data_b3_req.Data));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
Joe Perches475be4d2012-02-19 19:52:38 -08001034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
Joe Perches475be4d2012-02-19 19:52:38 -08001036 i += (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[i]))->header.length +
1037 MSG_IN_OVERHEAD + 3) & 0xfffc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
Joe Perches475be4d2012-02-19 19:52:38 -08001039 }
1040 }
1041 plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE;
1042 plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
1043 plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044}
1045
1046
Joe Perches475be4d2012-02-19 19:52:38 -08001047static void plci_remove(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048{
1049
Joe Perches475be4d2012-02-19 19:52:38 -08001050 if (!plci) {
1051 dbug(1, dprintf("plci_remove(no plci)"));
1052 return;
1053 }
1054 init_internal_command_queue(plci);
1055 dbug(1, dprintf("plci_remove(%x,tel=%x)", plci->Id, plci->tel));
1056 if (plci_remove_check(plci))
1057 {
1058 return;
1059 }
1060 if (plci->Sig.Id == 0xff)
1061 {
1062 dbug(1, dprintf("D-channel X.25 plci->NL.Id:%0x", plci->NL.Id));
1063 if (plci->NL.Id && !plci->nl_remove_id)
1064 {
1065 nl_req_ncci(plci, REMOVE, 0);
1066 send_req(plci);
1067 }
1068 }
1069 else
1070 {
1071 if (!plci->sig_remove_id
1072 && (plci->Sig.Id
1073 || (plci->req_in != plci->req_out)
1074 || (plci->nl_req || plci->sig_req)))
1075 {
1076 sig_req(plci, HANGUP, 0);
1077 send_req(plci);
1078 }
1079 }
1080 ncci_remove(plci, 0, false);
1081 plci_free_msg_in_queue(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
Joe Perches475be4d2012-02-19 19:52:38 -08001083 plci->channels = 0;
1084 plci->appl = NULL;
1085 if ((plci->State == INC_CON_PENDING) || (plci->State == INC_CON_ALERT))
1086 plci->State = OUTG_DIS_PENDING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087}
1088
1089/*------------------------------------------------------------------*/
1090/* Application Group function helpers */
1091/*------------------------------------------------------------------*/
1092
Joe Perches475be4d2012-02-19 19:52:38 -08001093static void set_group_ind_mask(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094{
Joe Perches475be4d2012-02-19 19:52:38 -08001095 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
Joe Perches475be4d2012-02-19 19:52:38 -08001097 for (i = 0; i < C_IND_MASK_DWORDS; i++)
1098 plci->group_optimization_mask_table[i] = 0xffffffffL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099}
1100
Joe Perches475be4d2012-02-19 19:52:38 -08001101static void clear_group_ind_mask_bit(PLCI *plci, word b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102{
Joe Perches475be4d2012-02-19 19:52:38 -08001103 plci->group_optimization_mask_table[b >> 5] &= ~(1L << (b & 0x1f));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104}
1105
Joe Perches475be4d2012-02-19 19:52:38 -08001106static byte test_group_ind_mask_bit(PLCI *plci, word b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107{
Joe Perches475be4d2012-02-19 19:52:38 -08001108 return ((plci->group_optimization_mask_table[b >> 5] & (1L << (b & 0x1f))) != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109}
1110
1111/*------------------------------------------------------------------*/
1112/* c_ind_mask operations for arbitrary MAX_APPL */
1113/*------------------------------------------------------------------*/
1114
Joe Perches475be4d2012-02-19 19:52:38 -08001115static void clear_c_ind_mask(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116{
Joe Perches475be4d2012-02-19 19:52:38 -08001117 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
Joe Perches475be4d2012-02-19 19:52:38 -08001119 for (i = 0; i < C_IND_MASK_DWORDS; i++)
1120 plci->c_ind_mask_table[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121}
1122
Joe Perches475be4d2012-02-19 19:52:38 -08001123static byte c_ind_mask_empty(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124{
Joe Perches475be4d2012-02-19 19:52:38 -08001125 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
Joe Perches475be4d2012-02-19 19:52:38 -08001127 i = 0;
1128 while ((i < C_IND_MASK_DWORDS) && (plci->c_ind_mask_table[i] == 0))
1129 i++;
1130 return (i == C_IND_MASK_DWORDS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131}
1132
Joe Perches475be4d2012-02-19 19:52:38 -08001133static void set_c_ind_mask_bit(PLCI *plci, word b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134{
Joe Perches475be4d2012-02-19 19:52:38 -08001135 plci->c_ind_mask_table[b >> 5] |= (1L << (b & 0x1f));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136}
1137
Joe Perches475be4d2012-02-19 19:52:38 -08001138static void clear_c_ind_mask_bit(PLCI *plci, word b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139{
Joe Perches475be4d2012-02-19 19:52:38 -08001140 plci->c_ind_mask_table[b >> 5] &= ~(1L << (b & 0x1f));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141}
1142
Joe Perches475be4d2012-02-19 19:52:38 -08001143static byte test_c_ind_mask_bit(PLCI *plci, word b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144{
Joe Perches475be4d2012-02-19 19:52:38 -08001145 return ((plci->c_ind_mask_table[b >> 5] & (1L << (b & 0x1f))) != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146}
1147
Joe Perches475be4d2012-02-19 19:52:38 -08001148static void dump_c_ind_mask(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149{
Joe Perches475be4d2012-02-19 19:52:38 -08001150 static char hex_digit_table[0x10] =
1151 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
1152 word i, j, k;
1153 dword d;
1154 char *p;
1155 char buf[40];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
Joe Perches475be4d2012-02-19 19:52:38 -08001157 for (i = 0; i < C_IND_MASK_DWORDS; i += 4)
1158 {
1159 p = buf + 36;
1160 *p = '\0';
1161 for (j = 0; j < 4; j++)
1162 {
1163 if (i + j < C_IND_MASK_DWORDS)
1164 {
1165 d = plci->c_ind_mask_table[i + j];
1166 for (k = 0; k < 8; k++)
1167 {
1168 *(--p) = hex_digit_table[d & 0xf];
1169 d >>= 4;
1170 }
1171 }
1172 else if (i != 0)
1173 {
1174 for (k = 0; k < 8; k++)
1175 *(--p) = ' ';
1176 }
1177 *(--p) = ' ';
1178 }
1179 dbug(1, dprintf("c_ind_mask =%s", (char *) p));
1180 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181}
1182
1183
1184
1185
1186
1187#define dump_plcis(a)
1188
1189
1190
1191/*------------------------------------------------------------------*/
1192/* translation function for each message */
1193/*------------------------------------------------------------------*/
1194
Hannes Eder465e9852009-02-25 13:11:37 +00001195static byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
1196 PLCI *plci, APPL *appl, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197{
Joe Perches475be4d2012-02-19 19:52:38 -08001198 word ch;
1199 word i;
1200 word Info;
1201 byte LinkLayer;
1202 API_PARSE *ai;
1203 API_PARSE *bp;
1204 API_PARSE ai_parms[5];
1205 word channel = 0;
1206 dword ch_mask;
1207 byte m;
1208 static byte esc_chi[35] = {0x02, 0x18, 0x01};
1209 static byte lli[2] = {0x01, 0x00};
1210 byte noCh = 0;
1211 word dir = 0;
1212 byte *p_chi = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
Joe Perches475be4d2012-02-19 19:52:38 -08001214 for (i = 0; i < 5; i++) ai_parms[i].length = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
Joe Perches475be4d2012-02-19 19:52:38 -08001216 dbug(1, dprintf("connect_req(%d)", parms->length));
1217 Info = _WRONG_IDENTIFIER;
1218 if (a)
1219 {
1220 if (a->adapter_disabled)
1221 {
1222 dbug(1, dprintf("adapter disabled"));
1223 Id = ((word)1 << 8) | a->Id;
1224 sendf(appl, _CONNECT_R | CONFIRM, Id, Number, "w", 0);
1225 sendf(appl, _DISCONNECT_I, Id, 0, "w", _L1_ERROR);
1226 return false;
1227 }
1228 Info = _OUT_OF_PLCI;
1229 if ((i = get_plci(a)))
1230 {
1231 Info = 0;
1232 plci = &a->plci[i - 1];
1233 plci->appl = appl;
1234 plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
1235 /* check 'external controller' bit for codec support */
1236 if (Id & EXT_CONTROLLER)
1237 {
1238 if (AdvCodecSupport(a, plci, appl, 0))
1239 {
1240 plci->Id = 0;
1241 sendf(appl, _CONNECT_R | CONFIRM, Id, Number, "w", _WRONG_IDENTIFIER);
1242 return 2;
1243 }
1244 }
1245 ai = &parms[9];
1246 bp = &parms[5];
1247 ch = 0;
1248 if (bp->length)LinkLayer = bp->info[3];
1249 else LinkLayer = 0;
1250 if (ai->length)
1251 {
1252 ch = 0xffff;
1253 if (!api_parse(&ai->info[1], (word)ai->length, "ssss", ai_parms))
1254 {
1255 ch = 0;
1256 if (ai_parms[0].length)
1257 {
1258 ch = GET_WORD(ai_parms[0].info + 1);
1259 if (ch > 4) ch = 0; /* safety -> ignore ChannelID */
1260 if (ch == 4) /* explizit CHI in message */
1261 {
1262 /* check length of B-CH struct */
1263 if ((ai_parms[0].info)[3] >= 1)
1264 {
1265 if ((ai_parms[0].info)[4] == CHI)
1266 {
1267 p_chi = &((ai_parms[0].info)[5]);
1268 }
1269 else
1270 {
1271 p_chi = &((ai_parms[0].info)[3]);
1272 }
1273 if (p_chi[0] > 35) /* check length of channel ID */
1274 {
1275 Info = _WRONG_MESSAGE_FORMAT;
1276 }
1277 }
1278 else Info = _WRONG_MESSAGE_FORMAT;
1279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
Joe Perches475be4d2012-02-19 19:52:38 -08001281 if (ch == 3 && ai_parms[0].length >= 7 && ai_parms[0].length <= 36)
1282 {
1283 dir = GET_WORD(ai_parms[0].info + 3);
1284 ch_mask = 0;
1285 m = 0x3f;
1286 for (i = 0; i + 5 <= ai_parms[0].length; i++)
1287 {
1288 if (ai_parms[0].info[i + 5] != 0)
1289 {
1290 if ((ai_parms[0].info[i + 5] | m) != 0xff)
1291 Info = _WRONG_MESSAGE_FORMAT;
1292 else
1293 {
1294 if (ch_mask == 0)
1295 channel = i;
1296 ch_mask |= 1L << i;
1297 }
1298 }
1299 m = 0;
1300 }
1301 if (ch_mask == 0)
1302 Info = _WRONG_MESSAGE_FORMAT;
1303 if (!Info)
1304 {
1305 if ((ai_parms[0].length == 36) || (ch_mask != ((dword)(1L << channel))))
1306 {
1307 esc_chi[0] = (byte)(ai_parms[0].length - 2);
1308 for (i = 0; i + 5 <= ai_parms[0].length; i++)
1309 esc_chi[i + 3] = ai_parms[0].info[i + 5];
1310 }
1311 else
1312 esc_chi[0] = 2;
1313 esc_chi[2] = (byte)channel;
1314 plci->b_channel = (byte)channel; /* not correct for ETSI ch 17..31 */
1315 add_p(plci, LLI, lli);
1316 add_p(plci, ESC, esc_chi);
1317 plci->State = LOCAL_CONNECT;
1318 if (!dir) plci->call_dir |= CALL_DIR_FORCE_OUTG_NL; /* dir 0=DTE, 1=DCE */
1319 }
1320 }
1321 }
1322 }
1323 else Info = _WRONG_MESSAGE_FORMAT;
1324 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
Joe Perches475be4d2012-02-19 19:52:38 -08001326 dbug(1, dprintf("ch=%x,dir=%x,p_ch=%d", ch, dir, channel));
1327 plci->command = _CONNECT_R;
1328 plci->number = Number;
1329 /* x.31 or D-ch free SAPI in LinkLayer? */
1330 if (ch == 1 && LinkLayer != 3 && LinkLayer != 12) noCh = true;
1331 if ((ch == 0 || ch == 2 || noCh || ch == 3 || ch == 4) && !Info)
1332 {
1333 /* B-channel used for B3 connections (ch==0), or no B channel */
1334 /* is used (ch==2) or perm. connection (3) is used do a CALL */
1335 if (noCh) Info = add_b1(plci, &parms[5], 2, 0); /* no resource */
1336 else Info = add_b1(plci, &parms[5], ch, 0);
1337 add_s(plci, OAD, &parms[2]);
1338 add_s(plci, OSA, &parms[4]);
1339 add_s(plci, BC, &parms[6]);
1340 add_s(plci, LLC, &parms[7]);
1341 add_s(plci, HLC, &parms[8]);
1342 if (a->Info_Mask[appl->Id - 1] & 0x200)
1343 {
1344 /* early B3 connect (CIP mask bit 9) no release after a disc */
1345 add_p(plci, LLI, "\x01\x01");
1346 }
1347 if (GET_WORD(parms[0].info) < 29) {
1348 add_p(plci, BC, cip_bc[GET_WORD(parms[0].info)][a->u_law]);
1349 add_p(plci, HLC, cip_hlc[GET_WORD(parms[0].info)]);
1350 }
1351 add_p(plci, UID, "\x06\x43\x61\x70\x69\x32\x30");
1352 sig_req(plci, ASSIGN, DSIG_ID);
1353 }
1354 else if (ch == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
Joe Perches475be4d2012-02-19 19:52:38 -08001356 /* D-Channel used for B3 connections */
1357 plci->Sig.Id = 0xff;
1358 Info = 0;
1359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
Joe Perches475be4d2012-02-19 19:52:38 -08001361 if (!Info && ch != 2 && !noCh) {
1362 Info = add_b23(plci, &parms[5]);
1363 if (!Info) {
1364 if (!(plci->tel && !plci->adv_nl))nl_req_ncci(plci, ASSIGN, 0);
1365 }
1366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
Joe Perches475be4d2012-02-19 19:52:38 -08001368 if (!Info)
1369 {
1370 if (ch == 0 || ch == 2 || ch == 3 || noCh || ch == 4)
1371 {
1372 if (plci->spoofed_msg == SPOOFING_REQUIRED)
1373 {
1374 api_save_msg(parms, "wsssssssss", &plci->saved_msg);
1375 plci->spoofed_msg = CALL_REQ;
1376 plci->internal_command = BLOCK_PLCI;
1377 plci->command = 0;
1378 dbug(1, dprintf("Spoof"));
1379 send_req(plci);
1380 return false;
1381 }
1382 if (ch == 4)add_p(plci, CHI, p_chi);
1383 add_s(plci, CPN, &parms[1]);
1384 add_s(plci, DSA, &parms[3]);
1385 if (noCh) add_p(plci, ESC, "\x02\x18\xfd"); /* D-channel, no B-L3 */
1386 add_ai(plci, &parms[9]);
1387 if (!dir)sig_req(plci, CALL_REQ, 0);
1388 else
1389 {
1390 plci->command = PERM_LIST_REQ;
1391 plci->appl = appl;
1392 sig_req(plci, LISTEN_REQ, 0);
1393 send_req(plci);
1394 return false;
1395 }
1396 }
1397 send_req(plci);
1398 return false;
1399 }
1400 plci->Id = 0;
1401 }
1402 }
1403 sendf(appl,
1404 _CONNECT_R | CONFIRM,
1405 Id,
1406 Number,
1407 "w", Info);
1408 return 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409}
1410
Hannes Eder465e9852009-02-25 13:11:37 +00001411static byte connect_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
1412 PLCI *plci, APPL *appl, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413{
Joe Perches475be4d2012-02-19 19:52:38 -08001414 word i, Info;
1415 word Reject;
1416 static byte cau_t[] = {0, 0, 0x90, 0x91, 0xac, 0x9d, 0x86, 0xd8, 0x9b};
1417 static byte esc_t[] = {0x03, 0x08, 0x00, 0x00};
1418 API_PARSE *ai;
1419 API_PARSE ai_parms[5];
1420 word ch = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421
Joe Perches475be4d2012-02-19 19:52:38 -08001422 if (!plci) {
1423 dbug(1, dprintf("connect_res(no plci)"));
1424 return 0; /* no plci, no send */
1425 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426
Joe Perches475be4d2012-02-19 19:52:38 -08001427 dbug(1, dprintf("connect_res(State=0x%x)", plci->State));
1428 for (i = 0; i < 5; i++) ai_parms[i].length = 0;
1429 ai = &parms[5];
1430 dbug(1, dprintf("ai->length=%d", ai->length));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431
Joe Perches475be4d2012-02-19 19:52:38 -08001432 if (ai->length)
1433 {
1434 if (!api_parse(&ai->info[1], (word)ai->length, "ssss", ai_parms))
1435 {
1436 dbug(1, dprintf("ai_parms[0].length=%d/0x%x", ai_parms[0].length, GET_WORD(ai_parms[0].info + 1)));
1437 ch = 0;
1438 if (ai_parms[0].length)
1439 {
1440 ch = GET_WORD(ai_parms[0].info + 1);
1441 dbug(1, dprintf("BCH-I=0x%x", ch));
1442 }
1443 }
1444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445
Joe Perches475be4d2012-02-19 19:52:38 -08001446 if (plci->State == INC_CON_CONNECTED_ALERT)
1447 {
1448 dbug(1, dprintf("Connected Alert Call_Res"));
1449 if (a->Info_Mask[appl->Id - 1] & 0x200)
1450 {
1451 /* early B3 connect (CIP mask bit 9) no release after a disc */
1452 add_p(plci, LLI, "\x01\x01");
1453 }
1454 add_s(plci, CONN_NR, &parms[2]);
1455 add_s(plci, LLC, &parms[4]);
1456 add_ai(plci, &parms[5]);
1457 plci->State = INC_CON_ACCEPT;
1458 sig_req(plci, CALL_RES, 0);
1459 return 1;
1460 }
1461 else if (plci->State == INC_CON_PENDING || plci->State == INC_CON_ALERT) {
1462 clear_c_ind_mask_bit(plci, (word)(appl->Id - 1));
1463 dump_c_ind_mask(plci);
1464 Reject = GET_WORD(parms[0].info);
1465 dbug(1, dprintf("Reject=0x%x", Reject));
1466 if (Reject)
1467 {
1468 if (c_ind_mask_empty(plci))
1469 {
1470 if ((Reject & 0xff00) == 0x3400)
1471 {
1472 esc_t[2] = ((byte)(Reject & 0x00ff)) | 0x80;
1473 add_p(plci, ESC, esc_t);
1474 add_ai(plci, &parms[5]);
1475 sig_req(plci, REJECT, 0);
1476 }
1477 else if (Reject == 1 || Reject > 9)
1478 {
1479 add_ai(plci, &parms[5]);
1480 sig_req(plci, HANGUP, 0);
1481 }
1482 else
1483 {
1484 esc_t[2] = cau_t[(Reject&0x000f)];
1485 add_p(plci, ESC, esc_t);
1486 add_ai(plci, &parms[5]);
1487 sig_req(plci, REJECT, 0);
1488 }
1489 plci->appl = appl;
1490 }
1491 else
1492 {
1493 sendf(appl, _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED);
1494 }
1495 }
1496 else {
1497 plci->appl = appl;
1498 if (Id & EXT_CONTROLLER) {
1499 if (AdvCodecSupport(a, plci, appl, 0)) {
1500 dbug(1, dprintf("connect_res(error from AdvCodecSupport)"));
1501 sig_req(plci, HANGUP, 0);
1502 return 1;
1503 }
1504 if (plci->tel == ADV_VOICE && a->AdvCodecPLCI)
1505 {
1506 Info = add_b23(plci, &parms[1]);
1507 if (Info)
1508 {
1509 dbug(1, dprintf("connect_res(error from add_b23)"));
1510 sig_req(plci, HANGUP, 0);
1511 return 1;
1512 }
1513 if (plci->adv_nl)
1514 {
1515 nl_req_ncci(plci, ASSIGN, 0);
1516 }
1517 }
1518 }
1519 else
1520 {
1521 plci->tel = 0;
1522 if (ch != 2)
1523 {
1524 Info = add_b23(plci, &parms[1]);
1525 if (Info)
1526 {
1527 dbug(1, dprintf("connect_res(error from add_b23 2)"));
1528 sig_req(plci, HANGUP, 0);
1529 return 1;
1530 }
1531 }
1532 nl_req_ncci(plci, ASSIGN, 0);
1533 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
Joe Perches475be4d2012-02-19 19:52:38 -08001535 if (plci->spoofed_msg == SPOOFING_REQUIRED)
1536 {
1537 api_save_msg(parms, "wsssss", &plci->saved_msg);
1538 plci->spoofed_msg = CALL_RES;
1539 plci->internal_command = BLOCK_PLCI;
1540 plci->command = 0;
1541 dbug(1, dprintf("Spoof"));
1542 }
1543 else
1544 {
1545 add_b1(plci, &parms[1], ch, plci->B1_facilities);
1546 if (a->Info_Mask[appl->Id - 1] & 0x200)
1547 {
1548 /* early B3 connect (CIP mask bit 9) no release after a disc */
1549 add_p(plci, LLI, "\x01\x01");
1550 }
1551 add_s(plci, CONN_NR, &parms[2]);
1552 add_s(plci, LLC, &parms[4]);
1553 add_ai(plci, &parms[5]);
1554 plci->State = INC_CON_ACCEPT;
1555 sig_req(plci, CALL_RES, 0);
1556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557
Joe Perches475be4d2012-02-19 19:52:38 -08001558 for (i = 0; i < max_appl; i++) {
1559 if (test_c_ind_mask_bit(plci, i)) {
1560 sendf(&application[i], _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED);
1561 }
1562 }
1563 }
1564 }
1565 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566}
1567
Hannes Eder465e9852009-02-25 13:11:37 +00001568static byte connect_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
1569 PLCI *plci, APPL *appl, API_PARSE *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570{
Joe Perches475be4d2012-02-19 19:52:38 -08001571 dbug(1, dprintf("connect_a_res"));
1572 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573}
1574
Hannes Eder465e9852009-02-25 13:11:37 +00001575static byte disconnect_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
1576 PLCI *plci, APPL *appl, API_PARSE *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577{
Joe Perches475be4d2012-02-19 19:52:38 -08001578 word Info;
1579 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580
Joe Perches475be4d2012-02-19 19:52:38 -08001581 dbug(1, dprintf("disconnect_req"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
Joe Perches475be4d2012-02-19 19:52:38 -08001583 Info = _WRONG_IDENTIFIER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
Joe Perches475be4d2012-02-19 19:52:38 -08001585 if (plci)
1586 {
1587 if (plci->State == INC_CON_PENDING || plci->State == INC_CON_ALERT)
1588 {
1589 clear_c_ind_mask_bit(plci, (word)(appl->Id - 1));
1590 plci->appl = appl;
1591 for (i = 0; i < max_appl; i++)
1592 {
1593 if (test_c_ind_mask_bit(plci, i))
1594 sendf(&application[i], _DISCONNECT_I, Id, 0, "w", 0);
1595 }
1596 plci->State = OUTG_DIS_PENDING;
1597 }
1598 if (plci->Sig.Id && plci->appl)
1599 {
1600 Info = 0;
1601 if (plci->Sig.Id != 0xff)
1602 {
1603 if (plci->State != INC_DIS_PENDING)
1604 {
1605 add_ai(plci, &msg[0]);
1606 sig_req(plci, HANGUP, 0);
1607 plci->State = OUTG_DIS_PENDING;
1608 return 1;
1609 }
1610 }
1611 else
1612 {
1613 if (plci->NL.Id && !plci->nl_remove_id)
1614 {
1615 mixer_remove(plci);
1616 nl_req_ncci(plci, REMOVE, 0);
1617 sendf(appl, _DISCONNECT_R | CONFIRM, Id, Number, "w", 0);
1618 sendf(appl, _DISCONNECT_I, Id, 0, "w", 0);
1619 plci->State = INC_DIS_PENDING;
1620 }
1621 return 1;
1622 }
1623 }
1624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625
Joe Perches475be4d2012-02-19 19:52:38 -08001626 if (!appl) return false;
1627 sendf(appl, _DISCONNECT_R | CONFIRM, Id, Number, "w", Info);
1628 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629}
1630
Hannes Eder465e9852009-02-25 13:11:37 +00001631static byte disconnect_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
1632 PLCI *plci, APPL *appl, API_PARSE *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633{
Joe Perches475be4d2012-02-19 19:52:38 -08001634 dbug(1, dprintf("disconnect_res"));
1635 if (plci)
1636 {
1637 /* clear ind mask bit, just in case of collsion of */
1638 /* DISCONNECT_IND and CONNECT_RES */
1639 clear_c_ind_mask_bit(plci, (word)(appl->Id - 1));
1640 ncci_free_receive_buffers(plci, 0);
1641 if (plci_remove_check(plci))
1642 {
1643 return 0;
1644 }
1645 if (plci->State == INC_DIS_PENDING
1646 || plci->State == SUSPENDING) {
1647 if (c_ind_mask_empty(plci)) {
1648 if (plci->State != SUSPENDING) plci->State = IDLE;
1649 dbug(1, dprintf("chs=%d", plci->channels));
1650 if (!plci->channels) {
1651 plci_remove(plci);
1652 }
1653 }
1654 }
1655 }
1656 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657}
1658
Hannes Eder465e9852009-02-25 13:11:37 +00001659static byte listen_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
1660 PLCI *plci, APPL *appl, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661{
Joe Perches475be4d2012-02-19 19:52:38 -08001662 word Info;
1663 byte i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664
Joe Perches475be4d2012-02-19 19:52:38 -08001665 dbug(1, dprintf("listen_req(Appl=0x%x)", appl->Id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
Joe Perches475be4d2012-02-19 19:52:38 -08001667 Info = _WRONG_IDENTIFIER;
1668 if (a) {
1669 Info = 0;
1670 a->Info_Mask[appl->Id - 1] = GET_DWORD(parms[0].info);
1671 a->CIP_Mask[appl->Id - 1] = GET_DWORD(parms[1].info);
1672 dbug(1, dprintf("CIP_MASK=0x%lx", GET_DWORD(parms[1].info)));
1673 if (a->Info_Mask[appl->Id - 1] & 0x200) { /* early B3 connect provides */
1674 a->Info_Mask[appl->Id - 1] |= 0x10; /* call progression infos */
1675 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676
Joe Perches475be4d2012-02-19 19:52:38 -08001677 /* check if external controller listen and switch listen on or off*/
1678 if (Id&EXT_CONTROLLER && GET_DWORD(parms[1].info)) {
1679 if (a->profile.Global_Options & ON_BOARD_CODEC) {
1680 dummy_plci.State = IDLE;
1681 a->codec_listen[appl->Id - 1] = &dummy_plci;
1682 a->TelOAD[0] = (byte)(parms[3].length);
1683 for (i = 1; parms[3].length >= i && i < 22; i++) {
1684 a->TelOAD[i] = parms[3].info[i];
1685 }
1686 a->TelOAD[i] = 0;
1687 a->TelOSA[0] = (byte)(parms[4].length);
1688 for (i = 1; parms[4].length >= i && i < 22; i++) {
1689 a->TelOSA[i] = parms[4].info[i];
1690 }
1691 a->TelOSA[i] = 0;
1692 }
1693 else Info = 0x2002; /* wrong controller, codec not supported */
1694 }
1695 else{ /* clear listen */
1696 a->codec_listen[appl->Id - 1] = (PLCI *)0;
1697 }
1698 }
1699 sendf(appl,
1700 _LISTEN_R | CONFIRM,
1701 Id,
1702 Number,
1703 "w", Info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704
Joe Perches475be4d2012-02-19 19:52:38 -08001705 if (a) listen_check(a);
1706 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707}
1708
Hannes Eder465e9852009-02-25 13:11:37 +00001709static byte info_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
1710 PLCI *plci, APPL *appl, API_PARSE *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711{
Joe Perches475be4d2012-02-19 19:52:38 -08001712 word i;
1713 API_PARSE *ai;
1714 PLCI *rc_plci = NULL;
1715 API_PARSE ai_parms[5];
1716 word Info = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717
Joe Perches475be4d2012-02-19 19:52:38 -08001718 dbug(1, dprintf("info_req"));
1719 for (i = 0; i < 5; i++) ai_parms[i].length = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720
Joe Perches475be4d2012-02-19 19:52:38 -08001721 ai = &msg[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722
Joe Perches475be4d2012-02-19 19:52:38 -08001723 if (ai->length)
1724 {
1725 if (api_parse(&ai->info[1], (word)ai->length, "ssss", ai_parms))
1726 {
1727 dbug(1, dprintf("AddInfo wrong"));
1728 Info = _WRONG_MESSAGE_FORMAT;
1729 }
1730 }
1731 if (!a) Info = _WRONG_STATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732
Joe Perches475be4d2012-02-19 19:52:38 -08001733 if (!Info && plci)
1734 { /* no fac, with CPN, or KEY */
1735 rc_plci = plci;
1736 if (!ai_parms[3].length && plci->State && (msg[0].length || ai_parms[1].length))
1737 {
1738 /* overlap sending option */
1739 dbug(1, dprintf("OvlSnd"));
1740 add_s(plci, CPN, &msg[0]);
1741 add_s(plci, KEY, &ai_parms[1]);
1742 sig_req(plci, INFO_REQ, 0);
1743 send_req(plci);
1744 return false;
1745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746
Joe Perches475be4d2012-02-19 19:52:38 -08001747 if (plci->State && ai_parms[2].length)
1748 {
1749 /* User_Info option */
1750 dbug(1, dprintf("UUI"));
1751 add_s(plci, UUI, &ai_parms[2]);
1752 sig_req(plci, USER_DATA, 0);
1753 }
1754 else if (plci->State && ai_parms[3].length)
1755 {
1756 /* Facility option */
1757 dbug(1, dprintf("FAC"));
1758 add_s(plci, CPN, &msg[0]);
1759 add_ai(plci, &msg[1]);
1760 sig_req(plci, FACILITY_REQ, 0);
1761 }
1762 else
1763 {
1764 Info = _WRONG_STATE;
1765 }
1766 }
1767 else if ((ai_parms[1].length || ai_parms[2].length || ai_parms[3].length) && !Info)
1768 {
1769 /* NCR_Facility option -> send UUI and Keypad too */
1770 dbug(1, dprintf("NCR_FAC"));
1771 if ((i = get_plci(a)))
1772 {
1773 rc_plci = &a->plci[i - 1];
1774 appl->NullCREnable = true;
1775 rc_plci->internal_command = C_NCR_FAC_REQ;
1776 rc_plci->appl = appl;
1777 add_p(rc_plci, CAI, "\x01\x80");
1778 add_p(rc_plci, UID, "\x06\x43\x61\x70\x69\x32\x30");
1779 sig_req(rc_plci, ASSIGN, DSIG_ID);
1780 send_req(rc_plci);
1781 }
1782 else
1783 {
1784 Info = _OUT_OF_PLCI;
1785 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786
Joe Perches475be4d2012-02-19 19:52:38 -08001787 if (!Info)
1788 {
1789 add_s(rc_plci, CPN, &msg[0]);
1790 add_ai(rc_plci, &msg[1]);
1791 sig_req(rc_plci, NCR_FACILITY, 0);
1792 send_req(rc_plci);
1793 return false;
1794 /* for application controlled supplementary services */
1795 }
1796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797
Joe Perches475be4d2012-02-19 19:52:38 -08001798 if (!rc_plci)
1799 {
1800 Info = _WRONG_MESSAGE_FORMAT;
1801 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802
Joe Perches475be4d2012-02-19 19:52:38 -08001803 if (!Info)
1804 {
1805 send_req(rc_plci);
1806 }
1807 else
1808 { /* appl is not assigned to a PLCI or error condition */
1809 dbug(1, dprintf("localInfoCon"));
1810 sendf(appl,
1811 _INFO_R | CONFIRM,
1812 Id,
1813 Number,
1814 "w", Info);
1815 }
1816 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817}
1818
Hannes Eder465e9852009-02-25 13:11:37 +00001819static byte info_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
1820 PLCI *plci, APPL *appl, API_PARSE *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821{
Joe Perches475be4d2012-02-19 19:52:38 -08001822 dbug(1, dprintf("info_res"));
1823 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824}
1825
Hannes Eder465e9852009-02-25 13:11:37 +00001826static byte alert_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
1827 PLCI *plci, APPL *appl, API_PARSE *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828{
Joe Perches475be4d2012-02-19 19:52:38 -08001829 word Info;
1830 byte ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831
Joe Perches475be4d2012-02-19 19:52:38 -08001832 dbug(1, dprintf("alert_req"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833
Joe Perches475be4d2012-02-19 19:52:38 -08001834 Info = _WRONG_IDENTIFIER;
1835 ret = false;
1836 if (plci) {
1837 Info = _ALERT_IGNORED;
1838 if (plci->State != INC_CON_ALERT) {
1839 Info = _WRONG_STATE;
1840 if (plci->State == INC_CON_PENDING) {
1841 Info = 0;
1842 plci->State = INC_CON_ALERT;
1843 add_ai(plci, &msg[0]);
1844 sig_req(plci, CALL_ALERT, 0);
1845 ret = 1;
1846 }
1847 }
1848 }
1849 sendf(appl,
1850 _ALERT_R | CONFIRM,
1851 Id,
1852 Number,
1853 "w", Info);
1854 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855}
1856
Hannes Eder465e9852009-02-25 13:11:37 +00001857static byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
1858 PLCI *plci, APPL *appl, API_PARSE *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859{
Joe Perches475be4d2012-02-19 19:52:38 -08001860 word Info = 0;
1861 word i = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862
Joe Perches475be4d2012-02-19 19:52:38 -08001863 word selector;
1864 word SSreq;
1865 long relatedPLCIvalue;
1866 DIVA_CAPI_ADAPTER *relatedadapter;
1867 byte *SSparms = "";
1868 byte RCparms[] = "\x05\x00\x00\x02\x00\x00";
1869 byte SSstruct[] = "\x09\x00\x00\x06\x00\x00\x00\x00\x00\x00";
1870 API_PARSE *parms;
1871 API_PARSE ss_parms[11];
1872 PLCI *rplci;
1873 byte cai[15];
1874 dword d;
1875 API_PARSE dummy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876
Joe Perches475be4d2012-02-19 19:52:38 -08001877 dbug(1, dprintf("facility_req"));
1878 for (i = 0; i < 9; i++) ss_parms[i].length = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
Joe Perches475be4d2012-02-19 19:52:38 -08001880 parms = &msg[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
Joe Perches475be4d2012-02-19 19:52:38 -08001882 if (!a)
1883 {
1884 dbug(1, dprintf("wrong Ctrl"));
1885 Info = _WRONG_IDENTIFIER;
1886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
Joe Perches475be4d2012-02-19 19:52:38 -08001888 selector = GET_WORD(msg[0].info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
Joe Perches475be4d2012-02-19 19:52:38 -08001890 if (!Info)
1891 {
1892 switch (selector)
1893 {
1894 case SELECTOR_HANDSET:
1895 Info = AdvCodecSupport(a, plci, appl, HOOK_SUPPORT);
1896 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
Joe Perches475be4d2012-02-19 19:52:38 -08001898 case SELECTOR_SU_SERV:
1899 if (!msg[1].length)
1900 {
1901 Info = _WRONG_MESSAGE_FORMAT;
1902 break;
1903 }
1904 SSreq = GET_WORD(&(msg[1].info[1]));
1905 PUT_WORD(&RCparms[1], SSreq);
1906 SSparms = RCparms;
1907 switch (SSreq)
1908 {
1909 case S_GET_SUPPORTED_SERVICES:
1910 if ((i = get_plci(a)))
1911 {
1912 rplci = &a->plci[i - 1];
1913 rplci->appl = appl;
1914 add_p(rplci, CAI, "\x01\x80");
1915 add_p(rplci, UID, "\x06\x43\x61\x70\x69\x32\x30");
1916 sig_req(rplci, ASSIGN, DSIG_ID);
1917 send_req(rplci);
1918 }
1919 else
1920 {
1921 PUT_DWORD(&SSstruct[6], MASK_TERMINAL_PORTABILITY);
1922 SSparms = (byte *)SSstruct;
1923 break;
1924 }
1925 rplci->internal_command = GETSERV_REQ_PEND;
1926 rplci->number = Number;
1927 rplci->appl = appl;
1928 sig_req(rplci, S_SUPPORTED, 0);
1929 send_req(rplci);
1930 return false;
1931 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932
Joe Perches475be4d2012-02-19 19:52:38 -08001933 case S_LISTEN:
1934 if (parms->length == 7)
1935 {
1936 if (api_parse(&parms->info[1], (word)parms->length, "wbd", ss_parms))
1937 {
1938 dbug(1, dprintf("format wrong"));
1939 Info = _WRONG_MESSAGE_FORMAT;
1940 break;
1941 }
1942 }
1943 else
1944 {
1945 Info = _WRONG_MESSAGE_FORMAT;
1946 break;
1947 }
1948 a->Notification_Mask[appl->Id - 1] = GET_DWORD(ss_parms[2].info);
1949 if (a->Notification_Mask[appl->Id - 1] & SMASK_MWI) /* MWI active? */
1950 {
1951 if ((i = get_plci(a)))
1952 {
1953 rplci = &a->plci[i - 1];
1954 rplci->appl = appl;
1955 add_p(rplci, CAI, "\x01\x80");
1956 add_p(rplci, UID, "\x06\x43\x61\x70\x69\x32\x30");
1957 sig_req(rplci, ASSIGN, DSIG_ID);
1958 send_req(rplci);
1959 }
1960 else
1961 {
1962 break;
1963 }
1964 rplci->internal_command = GET_MWI_STATE;
1965 rplci->number = Number;
1966 sig_req(rplci, MWI_POLL, 0);
1967 send_req(rplci);
1968 }
1969 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970
Joe Perches475be4d2012-02-19 19:52:38 -08001971 case S_HOLD:
1972 api_parse(&parms->info[1], (word)parms->length, "ws", ss_parms);
1973 if (plci && plci->State && plci->SuppState == IDLE)
1974 {
1975 plci->SuppState = HOLD_REQUEST;
1976 plci->command = C_HOLD_REQ;
1977 add_s(plci, CAI, &ss_parms[1]);
1978 sig_req(plci, CALL_HOLD, 0);
1979 send_req(plci);
1980 return false;
1981 }
1982 else Info = 0x3010; /* wrong state */
1983 break;
1984 case S_RETRIEVE:
1985 if (plci && plci->State && plci->SuppState == CALL_HELD)
1986 {
1987 if (Id & EXT_CONTROLLER)
1988 {
1989 if (AdvCodecSupport(a, plci, appl, 0))
1990 {
1991 Info = 0x3010; /* wrong state */
1992 break;
1993 }
1994 }
1995 else plci->tel = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
Joe Perches475be4d2012-02-19 19:52:38 -08001997 plci->SuppState = RETRIEVE_REQUEST;
1998 plci->command = C_RETRIEVE_REQ;
1999 if (plci->spoofed_msg == SPOOFING_REQUIRED)
2000 {
2001 plci->spoofed_msg = CALL_RETRIEVE;
2002 plci->internal_command = BLOCK_PLCI;
2003 plci->command = 0;
2004 dbug(1, dprintf("Spoof"));
2005 return false;
2006 }
2007 else
2008 {
2009 sig_req(plci, CALL_RETRIEVE, 0);
2010 send_req(plci);
2011 return false;
2012 }
2013 }
2014 else Info = 0x3010; /* wrong state */
2015 break;
2016 case S_SUSPEND:
2017 if (parms->length)
2018 {
2019 if (api_parse(&parms->info[1], (word)parms->length, "wbs", ss_parms))
2020 {
2021 dbug(1, dprintf("format wrong"));
2022 Info = _WRONG_MESSAGE_FORMAT;
2023 break;
2024 }
2025 }
2026 if (plci && plci->State)
2027 {
2028 add_s(plci, CAI, &ss_parms[2]);
2029 plci->command = SUSPEND_REQ;
2030 sig_req(plci, SUSPEND, 0);
2031 plci->State = SUSPENDING;
2032 send_req(plci);
2033 }
2034 else Info = 0x3010; /* wrong state */
2035 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036
Joe Perches475be4d2012-02-19 19:52:38 -08002037 case S_RESUME:
2038 if (!(i = get_plci(a)))
2039 {
2040 Info = _OUT_OF_PLCI;
2041 break;
2042 }
2043 rplci = &a->plci[i - 1];
2044 rplci->appl = appl;
2045 rplci->number = Number;
2046 rplci->tel = 0;
2047 rplci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
2048 /* check 'external controller' bit for codec support */
2049 if (Id & EXT_CONTROLLER)
2050 {
2051 if (AdvCodecSupport(a, rplci, appl, 0))
2052 {
2053 rplci->Id = 0;
2054 Info = 0x300A;
2055 break;
2056 }
2057 }
2058 if (parms->length)
2059 {
2060 if (api_parse(&parms->info[1], (word)parms->length, "wbs", ss_parms))
2061 {
2062 dbug(1, dprintf("format wrong"));
2063 rplci->Id = 0;
2064 Info = _WRONG_MESSAGE_FORMAT;
2065 break;
2066 }
2067 }
2068 dummy.length = 0;
2069 dummy.info = "\x00";
2070 add_b1(rplci, &dummy, 0, 0);
2071 if (a->Info_Mask[appl->Id - 1] & 0x200)
2072 {
2073 /* early B3 connect (CIP mask bit 9) no release after a disc */
2074 add_p(rplci, LLI, "\x01\x01");
2075 }
2076 add_p(rplci, UID, "\x06\x43\x61\x70\x69\x32\x30");
2077 sig_req(rplci, ASSIGN, DSIG_ID);
2078 send_req(rplci);
2079 add_s(rplci, CAI, &ss_parms[2]);
2080 rplci->command = RESUME_REQ;
2081 sig_req(rplci, RESUME, 0);
2082 rplci->State = RESUMING;
2083 send_req(rplci);
2084 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085
Joe Perches475be4d2012-02-19 19:52:38 -08002086 case S_CONF_BEGIN: /* Request */
2087 case S_CONF_DROP:
2088 case S_CONF_ISOLATE:
2089 case S_CONF_REATTACH:
2090 if (api_parse(&parms->info[1], (word)parms->length, "wbd", ss_parms))
2091 {
2092 dbug(1, dprintf("format wrong"));
2093 Info = _WRONG_MESSAGE_FORMAT;
2094 break;
2095 }
2096 if (plci && plci->State && ((plci->SuppState == IDLE) || (plci->SuppState == CALL_HELD)))
2097 {
2098 d = GET_DWORD(ss_parms[2].info);
2099 if (d >= 0x80)
2100 {
2101 dbug(1, dprintf("format wrong"));
2102 Info = _WRONG_MESSAGE_FORMAT;
2103 break;
2104 }
2105 plci->ptyState = (byte)SSreq;
2106 plci->command = 0;
2107 cai[0] = 2;
2108 switch (SSreq)
2109 {
2110 case S_CONF_BEGIN:
2111 cai[1] = CONF_BEGIN;
2112 plci->internal_command = CONF_BEGIN_REQ_PEND;
2113 break;
2114 case S_CONF_DROP:
2115 cai[1] = CONF_DROP;
2116 plci->internal_command = CONF_DROP_REQ_PEND;
2117 break;
2118 case S_CONF_ISOLATE:
2119 cai[1] = CONF_ISOLATE;
2120 plci->internal_command = CONF_ISOLATE_REQ_PEND;
2121 break;
2122 case S_CONF_REATTACH:
2123 cai[1] = CONF_REATTACH;
2124 plci->internal_command = CONF_REATTACH_REQ_PEND;
2125 break;
2126 }
2127 cai[2] = (byte)d; /* Conference Size resp. PartyId */
2128 add_p(plci, CAI, cai);
2129 sig_req(plci, S_SERVICE, 0);
2130 send_req(plci);
2131 return false;
2132 }
2133 else Info = 0x3010; /* wrong state */
2134 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
Joe Perches475be4d2012-02-19 19:52:38 -08002136 case S_ECT:
2137 case S_3PTY_BEGIN:
2138 case S_3PTY_END:
2139 case S_CONF_ADD:
2140 if (parms->length == 7)
2141 {
2142 if (api_parse(&parms->info[1], (word)parms->length, "wbd", ss_parms))
2143 {
2144 dbug(1, dprintf("format wrong"));
2145 Info = _WRONG_MESSAGE_FORMAT;
2146 break;
2147 }
2148 }
2149 else if (parms->length == 8) /* workaround for the T-View-S */
2150 {
2151 if (api_parse(&parms->info[1], (word)parms->length, "wbdb", ss_parms))
2152 {
2153 dbug(1, dprintf("format wrong"));
2154 Info = _WRONG_MESSAGE_FORMAT;
2155 break;
2156 }
2157 }
2158 else
2159 {
2160 Info = _WRONG_MESSAGE_FORMAT;
2161 break;
2162 }
2163 if (!msg[1].length)
2164 {
2165 Info = _WRONG_MESSAGE_FORMAT;
2166 break;
2167 }
2168 if (!plci)
2169 {
2170 Info = _WRONG_IDENTIFIER;
2171 break;
2172 }
2173 relatedPLCIvalue = GET_DWORD(ss_parms[2].info);
2174 relatedPLCIvalue &= 0x0000FFFF;
2175 dbug(1, dprintf("PTY/ECT/addCONF,relPLCI=%lx", relatedPLCIvalue));
2176 /* controller starts with 0 up to (max_adapter - 1) */
2177 if (((relatedPLCIvalue & 0x7f) == 0)
2178 || (MapController((byte)(relatedPLCIvalue & 0x7f)) == 0)
2179 || (MapController((byte)(relatedPLCIvalue & 0x7f)) > max_adapter))
2180 {
2181 if (SSreq == S_3PTY_END)
2182 {
2183 dbug(1, dprintf("wrong Controller use 2nd PLCI=PLCI"));
2184 rplci = plci;
2185 }
2186 else
2187 {
2188 Info = 0x3010; /* wrong state */
2189 break;
2190 }
2191 }
2192 else
2193 {
2194 relatedadapter = &adapter[MapController((byte)(relatedPLCIvalue & 0x7f)) - 1];
2195 relatedPLCIvalue >>= 8;
2196 /* find PLCI PTR*/
2197 for (i = 0, rplci = NULL; i < relatedadapter->max_plci; i++)
2198 {
2199 if (relatedadapter->plci[i].Id == (byte)relatedPLCIvalue)
2200 {
2201 rplci = &relatedadapter->plci[i];
2202 }
2203 }
2204 if (!rplci || !relatedPLCIvalue)
2205 {
2206 if (SSreq == S_3PTY_END)
2207 {
2208 dbug(1, dprintf("use 2nd PLCI=PLCI"));
2209 rplci = plci;
2210 }
2211 else
2212 {
2213 Info = 0x3010; /* wrong state */
2214 break;
2215 }
2216 }
2217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218/*
Joe Perches475be4d2012-02-19 19:52:38 -08002219 dbug(1, dprintf("rplci:%x", rplci));
2220 dbug(1, dprintf("plci:%x", plci));
2221 dbug(1, dprintf("rplci->ptyState:%x", rplci->ptyState));
2222 dbug(1, dprintf("plci->ptyState:%x", plci->ptyState));
2223 dbug(1, dprintf("SSreq:%x", SSreq));
2224 dbug(1, dprintf("rplci->internal_command:%x", rplci->internal_command));
2225 dbug(1, dprintf("rplci->appl:%x", rplci->appl));
2226 dbug(1, dprintf("rplci->Id:%x", rplci->Id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227*/
Joe Perches475be4d2012-02-19 19:52:38 -08002228 /* send PTY/ECT req, cannot check all states because of US stuff */
2229 if (!rplci->internal_command && rplci->appl)
2230 {
2231 plci->command = 0;
2232 rplci->relatedPTYPLCI = plci;
2233 plci->relatedPTYPLCI = rplci;
2234 rplci->ptyState = (byte)SSreq;
2235 if (SSreq == S_ECT)
2236 {
2237 rplci->internal_command = ECT_REQ_PEND;
2238 cai[1] = ECT_EXECUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239
Joe Perches475be4d2012-02-19 19:52:38 -08002240 rplci->vswitchstate = 0;
2241 rplci->vsprot = 0;
2242 rplci->vsprotdialect = 0;
2243 plci->vswitchstate = 0;
2244 plci->vsprot = 0;
2245 plci->vsprotdialect = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
Joe Perches475be4d2012-02-19 19:52:38 -08002247 }
2248 else if (SSreq == S_CONF_ADD)
2249 {
2250 rplci->internal_command = CONF_ADD_REQ_PEND;
2251 cai[1] = CONF_ADD;
2252 }
2253 else
2254 {
2255 rplci->internal_command = PTY_REQ_PEND;
2256 cai[1] = (byte)(SSreq - 3);
2257 }
2258 rplci->number = Number;
2259 if (plci != rplci) /* explicit invocation */
2260 {
2261 cai[0] = 2;
2262 cai[2] = plci->Sig.Id;
2263 dbug(1, dprintf("explicit invocation"));
2264 }
2265 else
2266 {
2267 dbug(1, dprintf("implicit invocation"));
2268 cai[0] = 1;
2269 }
2270 add_p(rplci, CAI, cai);
2271 sig_req(rplci, S_SERVICE, 0);
2272 send_req(rplci);
2273 return false;
2274 }
2275 else
2276 {
2277 dbug(0, dprintf("Wrong line"));
2278 Info = 0x3010; /* wrong state */
2279 break;
2280 }
2281 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282
Joe Perches475be4d2012-02-19 19:52:38 -08002283 case S_CALL_DEFLECTION:
2284 if (api_parse(&parms->info[1], (word)parms->length, "wbwss", ss_parms))
2285 {
2286 dbug(1, dprintf("format wrong"));
2287 Info = _WRONG_MESSAGE_FORMAT;
2288 break;
2289 }
2290 if (!plci)
2291 {
2292 Info = _WRONG_IDENTIFIER;
2293 break;
2294 }
2295 /* reuse unused screening indicator */
2296 ss_parms[3].info[3] = (byte)GET_WORD(&(ss_parms[2].info[0]));
2297 plci->command = 0;
2298 plci->internal_command = CD_REQ_PEND;
2299 appl->CDEnable = true;
2300 cai[0] = 1;
2301 cai[1] = CALL_DEFLECTION;
2302 add_p(plci, CAI, cai);
2303 add_p(plci, CPN, ss_parms[3].info);
2304 sig_req(plci, S_SERVICE, 0);
2305 send_req(plci);
2306 return false;
2307 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
Joe Perches475be4d2012-02-19 19:52:38 -08002309 case S_CALL_FORWARDING_START:
2310 if (api_parse(&parms->info[1], (word)parms->length, "wbdwwsss", ss_parms))
2311 {
2312 dbug(1, dprintf("format wrong"));
2313 Info = _WRONG_MESSAGE_FORMAT;
2314 break;
2315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
Joe Perches475be4d2012-02-19 19:52:38 -08002317 if ((i = get_plci(a)))
2318 {
2319 rplci = &a->plci[i - 1];
2320 rplci->appl = appl;
2321 add_p(rplci, CAI, "\x01\x80");
2322 add_p(rplci, UID, "\x06\x43\x61\x70\x69\x32\x30");
2323 sig_req(rplci, ASSIGN, DSIG_ID);
2324 send_req(rplci);
2325 }
2326 else
2327 {
2328 Info = _OUT_OF_PLCI;
2329 break;
2330 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331
Joe Perches475be4d2012-02-19 19:52:38 -08002332 /* reuse unused screening indicator */
2333 rplci->internal_command = CF_START_PEND;
2334 rplci->appl = appl;
2335 rplci->number = Number;
2336 appl->S_Handle = GET_DWORD(&(ss_parms[2].info[0]));
2337 cai[0] = 2;
2338 cai[1] = 0x70 | (byte)GET_WORD(&(ss_parms[3].info[0])); /* Function */
2339 cai[2] = (byte)GET_WORD(&(ss_parms[4].info[0])); /* Basic Service */
2340 add_p(rplci, CAI, cai);
2341 add_p(rplci, OAD, ss_parms[5].info);
2342 add_p(rplci, CPN, ss_parms[6].info);
2343 sig_req(rplci, S_SERVICE, 0);
2344 send_req(rplci);
2345 return false;
2346 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347
Joe Perches475be4d2012-02-19 19:52:38 -08002348 case S_INTERROGATE_DIVERSION:
2349 case S_INTERROGATE_NUMBERS:
2350 case S_CALL_FORWARDING_STOP:
2351 case S_CCBS_REQUEST:
2352 case S_CCBS_DEACTIVATE:
2353 case S_CCBS_INTERROGATE:
2354 switch (SSreq)
2355 {
2356 case S_INTERROGATE_NUMBERS:
2357 if (api_parse(&parms->info[1], (word)parms->length, "wbd", ss_parms))
2358 {
2359 dbug(0, dprintf("format wrong"));
2360 Info = _WRONG_MESSAGE_FORMAT;
2361 }
2362 break;
2363 case S_CCBS_REQUEST:
2364 case S_CCBS_DEACTIVATE:
2365 if (api_parse(&parms->info[1], (word)parms->length, "wbdw", ss_parms))
2366 {
2367 dbug(0, dprintf("format wrong"));
2368 Info = _WRONG_MESSAGE_FORMAT;
2369 }
2370 break;
2371 case S_CCBS_INTERROGATE:
2372 if (api_parse(&parms->info[1], (word)parms->length, "wbdws", ss_parms))
2373 {
2374 dbug(0, dprintf("format wrong"));
2375 Info = _WRONG_MESSAGE_FORMAT;
2376 }
2377 break;
2378 default:
2379 if (api_parse(&parms->info[1], (word)parms->length, "wbdwws", ss_parms))
2380 {
2381 dbug(0, dprintf("format wrong"));
2382 Info = _WRONG_MESSAGE_FORMAT;
2383 break;
2384 }
2385 break;
2386 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387
Joe Perches475be4d2012-02-19 19:52:38 -08002388 if (Info) break;
2389 if ((i = get_plci(a)))
2390 {
2391 rplci = &a->plci[i - 1];
2392 switch (SSreq)
2393 {
2394 case S_INTERROGATE_DIVERSION: /* use cai with S_SERVICE below */
2395 cai[1] = 0x60 | (byte)GET_WORD(&(ss_parms[3].info[0])); /* Function */
2396 rplci->internal_command = INTERR_DIVERSION_REQ_PEND; /* move to rplci if assigned */
2397 break;
2398 case S_INTERROGATE_NUMBERS: /* use cai with S_SERVICE below */
2399 cai[1] = DIVERSION_INTERROGATE_NUM; /* Function */
2400 rplci->internal_command = INTERR_NUMBERS_REQ_PEND; /* move to rplci if assigned */
2401 break;
2402 case S_CALL_FORWARDING_STOP:
2403 rplci->internal_command = CF_STOP_PEND;
2404 cai[1] = 0x80 | (byte)GET_WORD(&(ss_parms[3].info[0])); /* Function */
2405 break;
2406 case S_CCBS_REQUEST:
2407 cai[1] = CCBS_REQUEST;
2408 rplci->internal_command = CCBS_REQUEST_REQ_PEND;
2409 break;
2410 case S_CCBS_DEACTIVATE:
2411 cai[1] = CCBS_DEACTIVATE;
2412 rplci->internal_command = CCBS_DEACTIVATE_REQ_PEND;
2413 break;
2414 case S_CCBS_INTERROGATE:
2415 cai[1] = CCBS_INTERROGATE;
2416 rplci->internal_command = CCBS_INTERROGATE_REQ_PEND;
2417 break;
2418 default:
2419 cai[1] = 0;
2420 break;
2421 }
2422 rplci->appl = appl;
2423 rplci->number = Number;
2424 add_p(rplci, CAI, "\x01\x80");
2425 add_p(rplci, UID, "\x06\x43\x61\x70\x69\x32\x30");
2426 sig_req(rplci, ASSIGN, DSIG_ID);
2427 send_req(rplci);
2428 }
2429 else
2430 {
2431 Info = _OUT_OF_PLCI;
2432 break;
2433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
Joe Perches475be4d2012-02-19 19:52:38 -08002435 appl->S_Handle = GET_DWORD(&(ss_parms[2].info[0]));
2436 switch (SSreq)
2437 {
2438 case S_INTERROGATE_NUMBERS:
2439 cai[0] = 1;
2440 add_p(rplci, CAI, cai);
2441 break;
2442 case S_CCBS_REQUEST:
2443 case S_CCBS_DEACTIVATE:
2444 cai[0] = 3;
2445 PUT_WORD(&cai[2], GET_WORD(&(ss_parms[3].info[0])));
2446 add_p(rplci, CAI, cai);
2447 break;
2448 case S_CCBS_INTERROGATE:
2449 cai[0] = 3;
2450 PUT_WORD(&cai[2], GET_WORD(&(ss_parms[3].info[0])));
2451 add_p(rplci, CAI, cai);
2452 add_p(rplci, OAD, ss_parms[4].info);
2453 break;
2454 default:
2455 cai[0] = 2;
2456 cai[2] = (byte)GET_WORD(&(ss_parms[4].info[0])); /* Basic Service */
2457 add_p(rplci, CAI, cai);
2458 add_p(rplci, OAD, ss_parms[5].info);
2459 break;
2460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
Joe Perches475be4d2012-02-19 19:52:38 -08002462 sig_req(rplci, S_SERVICE, 0);
2463 send_req(rplci);
2464 return false;
2465 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466
Joe Perches475be4d2012-02-19 19:52:38 -08002467 case S_MWI_ACTIVATE:
2468 if (api_parse(&parms->info[1], (word)parms->length, "wbwdwwwssss", ss_parms))
2469 {
2470 dbug(1, dprintf("format wrong"));
2471 Info = _WRONG_MESSAGE_FORMAT;
2472 break;
2473 }
2474 if (!plci)
2475 {
2476 if ((i = get_plci(a)))
2477 {
2478 rplci = &a->plci[i - 1];
2479 rplci->appl = appl;
2480 rplci->cr_enquiry = true;
2481 add_p(rplci, CAI, "\x01\x80");
2482 add_p(rplci, UID, "\x06\x43\x61\x70\x69\x32\x30");
2483 sig_req(rplci, ASSIGN, DSIG_ID);
2484 send_req(rplci);
2485 }
2486 else
2487 {
2488 Info = _OUT_OF_PLCI;
2489 break;
2490 }
2491 }
2492 else
2493 {
2494 rplci = plci;
2495 rplci->cr_enquiry = false;
2496 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497
Joe Perches475be4d2012-02-19 19:52:38 -08002498 rplci->command = 0;
2499 rplci->internal_command = MWI_ACTIVATE_REQ_PEND;
2500 rplci->appl = appl;
2501 rplci->number = Number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502
Joe Perches475be4d2012-02-19 19:52:38 -08002503 cai[0] = 13;
2504 cai[1] = ACTIVATION_MWI; /* Function */
2505 PUT_WORD(&cai[2], GET_WORD(&(ss_parms[2].info[0]))); /* Basic Service */
2506 PUT_DWORD(&cai[4], GET_DWORD(&(ss_parms[3].info[0]))); /* Number of Messages */
2507 PUT_WORD(&cai[8], GET_WORD(&(ss_parms[4].info[0]))); /* Message Status */
2508 PUT_WORD(&cai[10], GET_WORD(&(ss_parms[5].info[0]))); /* Message Reference */
2509 PUT_WORD(&cai[12], GET_WORD(&(ss_parms[6].info[0]))); /* Invocation Mode */
2510 add_p(rplci, CAI, cai);
2511 add_p(rplci, CPN, ss_parms[7].info); /* Receiving User Number */
2512 add_p(rplci, OAD, ss_parms[8].info); /* Controlling User Number */
2513 add_p(rplci, OSA, ss_parms[9].info); /* Controlling User Provided Number */
2514 add_p(rplci, UID, ss_parms[10].info); /* Time */
2515 sig_req(rplci, S_SERVICE, 0);
2516 send_req(rplci);
2517 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518
Joe Perches475be4d2012-02-19 19:52:38 -08002519 case S_MWI_DEACTIVATE:
2520 if (api_parse(&parms->info[1], (word)parms->length, "wbwwss", ss_parms))
2521 {
2522 dbug(1, dprintf("format wrong"));
2523 Info = _WRONG_MESSAGE_FORMAT;
2524 break;
2525 }
2526 if (!plci)
2527 {
2528 if ((i = get_plci(a)))
2529 {
2530 rplci = &a->plci[i - 1];
2531 rplci->appl = appl;
2532 rplci->cr_enquiry = true;
2533 add_p(rplci, CAI, "\x01\x80");
2534 add_p(rplci, UID, "\x06\x43\x61\x70\x69\x32\x30");
2535 sig_req(rplci, ASSIGN, DSIG_ID);
2536 send_req(rplci);
2537 }
2538 else
2539 {
2540 Info = _OUT_OF_PLCI;
2541 break;
2542 }
2543 }
2544 else
2545 {
2546 rplci = plci;
2547 rplci->cr_enquiry = false;
2548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549
Joe Perches475be4d2012-02-19 19:52:38 -08002550 rplci->command = 0;
2551 rplci->internal_command = MWI_DEACTIVATE_REQ_PEND;
2552 rplci->appl = appl;
2553 rplci->number = Number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554
Joe Perches475be4d2012-02-19 19:52:38 -08002555 cai[0] = 5;
2556 cai[1] = DEACTIVATION_MWI; /* Function */
2557 PUT_WORD(&cai[2], GET_WORD(&(ss_parms[2].info[0]))); /* Basic Service */
2558 PUT_WORD(&cai[4], GET_WORD(&(ss_parms[3].info[0]))); /* Invocation Mode */
2559 add_p(rplci, CAI, cai);
2560 add_p(rplci, CPN, ss_parms[4].info); /* Receiving User Number */
2561 add_p(rplci, OAD, ss_parms[5].info); /* Controlling User Number */
2562 sig_req(rplci, S_SERVICE, 0);
2563 send_req(rplci);
2564 return false;
2565
2566 default:
2567 Info = 0x300E; /* not supported */
2568 break;
2569 }
2570 break; /* case SELECTOR_SU_SERV: end */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571
2572
Joe Perches475be4d2012-02-19 19:52:38 -08002573 case SELECTOR_DTMF:
2574 return (dtmf_request(Id, Number, a, plci, appl, msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575
2576
2577
Joe Perches475be4d2012-02-19 19:52:38 -08002578 case SELECTOR_LINE_INTERCONNECT:
2579 return (mixer_request(Id, Number, a, plci, appl, msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
2581
2582
Joe Perches475be4d2012-02-19 19:52:38 -08002583 case PRIV_SELECTOR_ECHO_CANCELLER:
2584 appl->appl_flags |= APPL_FLAG_PRIV_EC_SPEC;
2585 return (ec_request(Id, Number, a, plci, appl, msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
Joe Perches475be4d2012-02-19 19:52:38 -08002587 case SELECTOR_ECHO_CANCELLER:
2588 appl->appl_flags &= ~APPL_FLAG_PRIV_EC_SPEC;
2589 return (ec_request(Id, Number, a, plci, appl, msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590
2591
Joe Perches475be4d2012-02-19 19:52:38 -08002592 case SELECTOR_V42BIS:
2593 default:
2594 Info = _FACILITY_NOT_SUPPORTED;
2595 break;
2596 } /* end of switch (selector) */
2597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598
Joe Perches475be4d2012-02-19 19:52:38 -08002599 dbug(1, dprintf("SendFacRc"));
2600 sendf(appl,
2601 _FACILITY_R | CONFIRM,
2602 Id,
2603 Number,
2604 "wws", Info, selector, SSparms);
2605 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606}
2607
Hannes Eder465e9852009-02-25 13:11:37 +00002608static byte facility_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
2609 PLCI *plci, APPL *appl, API_PARSE *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610{
Joe Perches475be4d2012-02-19 19:52:38 -08002611 dbug(1, dprintf("facility_res"));
2612 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613}
2614
Hannes Eder465e9852009-02-25 13:11:37 +00002615static byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
2616 PLCI *plci, APPL *appl, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617{
Joe Perches475be4d2012-02-19 19:52:38 -08002618 word Info = 0;
2619 byte req;
2620 byte len;
2621 word w;
2622 word fax_control_bits, fax_feature_bits, fax_info_change;
2623 API_PARSE *ncpi;
2624 byte pvc[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
Joe Perches475be4d2012-02-19 19:52:38 -08002626 API_PARSE fax_parms[9];
2627 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628
2629
Joe Perches475be4d2012-02-19 19:52:38 -08002630 dbug(1, dprintf("connect_b3_req"));
2631 if (plci)
2632 {
2633 if ((plci->State == IDLE) || (plci->State == OUTG_DIS_PENDING)
2634 || (plci->State == INC_DIS_PENDING) || (plci->SuppState != IDLE))
2635 {
2636 Info = _WRONG_STATE;
2637 }
2638 else
2639 {
2640 /* local reply if assign unsuccessful
2641 or B3 protocol allows only one layer 3 connection
2642 and already connected
2643 or B2 protocol not any LAPD
2644 and connect_b3_req contradicts originate/answer direction */
2645 if (!plci->NL.Id
2646 || (((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE))
2647 && ((plci->channels != 0)
2648 || (((plci->B2_prot != B2_SDLC) && (plci->B2_prot != B2_LAPD) && (plci->B2_prot != B2_LAPD_FREE_SAPI_SEL))
2649 && ((plci->call_dir & CALL_DIR_ANSWER) && !(plci->call_dir & CALL_DIR_FORCE_OUTG_NL))))))
2650 {
2651 dbug(1, dprintf("B3 already connected=%d or no NL.Id=0x%x, dir=%d sstate=0x%x",
2652 plci->channels, plci->NL.Id, plci->call_dir, plci->SuppState));
2653 Info = _WRONG_STATE;
2654 sendf(appl,
2655 _CONNECT_B3_R | CONFIRM,
2656 Id,
2657 Number,
2658 "w", Info);
2659 return false;
2660 }
2661 plci->requested_options_conn = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662
Joe Perches475be4d2012-02-19 19:52:38 -08002663 req = N_CONNECT;
2664 ncpi = &parms[0];
2665 if (plci->B3_prot == 2 || plci->B3_prot == 3)
2666 {
2667 if (ncpi->length > 2)
2668 {
2669 /* check for PVC */
2670 if (ncpi->info[2] || ncpi->info[3])
2671 {
2672 pvc[0] = ncpi->info[3];
2673 pvc[1] = ncpi->info[2];
2674 add_d(plci, 2, pvc);
2675 req = N_RESET;
2676 }
2677 else
2678 {
2679 if (ncpi->info[1] & 1) req = N_CONNECT | N_D_BIT;
2680 add_d(plci, (word)(ncpi->length - 3), &ncpi->info[4]);
2681 }
2682 }
2683 }
2684 else if (plci->B3_prot == 5)
2685 {
2686 if (plci->NL.Id && !plci->nl_remove_id)
2687 {
2688 fax_control_bits = GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low);
2689 fax_feature_bits = GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->feature_bits_low);
2690 if (!(fax_control_bits & T30_CONTROL_BIT_MORE_DOCUMENTS)
2691 || (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS))
2692 {
2693 len = offsetof(T30_INFO, universal_6);
2694 fax_info_change = false;
2695 if (ncpi->length >= 4)
2696 {
2697 w = GET_WORD(&ncpi->info[3]);
2698 if ((w & 0x0001) != ((word)(((T30_INFO *)(plci->fax_connect_info_buffer))->resolution & 0x0001)))
2699 {
2700 ((T30_INFO *)(plci->fax_connect_info_buffer))->resolution =
2701 (byte)((((T30_INFO *)(plci->fax_connect_info_buffer))->resolution & ~T30_RESOLUTION_R8_0770_OR_200) |
2702 ((w & 0x0001) ? T30_RESOLUTION_R8_0770_OR_200 : 0));
2703 fax_info_change = true;
2704 }
2705 fax_control_bits &= ~(T30_CONTROL_BIT_REQUEST_POLLING | T30_CONTROL_BIT_MORE_DOCUMENTS);
2706 if (w & 0x0002) /* Fax-polling request */
2707 fax_control_bits |= T30_CONTROL_BIT_REQUEST_POLLING;
2708 if ((w & 0x0004) /* Request to send / poll another document */
2709 && (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_MORE_DOCUMENTS))
2710 {
2711 fax_control_bits |= T30_CONTROL_BIT_MORE_DOCUMENTS;
2712 }
2713 if (ncpi->length >= 6)
2714 {
2715 w = GET_WORD(&ncpi->info[5]);
2716 if (((byte) w) != ((T30_INFO *)(plci->fax_connect_info_buffer))->data_format)
2717 {
2718 ((T30_INFO *)(plci->fax_connect_info_buffer))->data_format = (byte) w;
2719 fax_info_change = true;
2720 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721
Joe Perches475be4d2012-02-19 19:52:38 -08002722 if ((a->man_profile.private_options & (1L << PRIVATE_FAX_SUB_SEP_PWD))
2723 && (GET_WORD(&ncpi->info[5]) & 0x8000)) /* Private SEP/SUB/PWD enable */
2724 {
2725 plci->requested_options_conn |= (1L << PRIVATE_FAX_SUB_SEP_PWD);
2726 }
2727 if ((a->man_profile.private_options & (1L << PRIVATE_FAX_NONSTANDARD))
2728 && (GET_WORD(&ncpi->info[5]) & 0x4000)) /* Private non-standard facilities enable */
2729 {
2730 plci->requested_options_conn |= (1L << PRIVATE_FAX_NONSTANDARD);
2731 }
2732 fax_control_bits &= ~(T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_SEL_POLLING |
2733 T30_CONTROL_BIT_ACCEPT_PASSWORD);
2734 if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id - 1])
2735 & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
2736 {
2737 if (api_parse(&ncpi->info[1], ncpi->length, "wwwwsss", fax_parms))
2738 Info = _WRONG_MESSAGE_FORMAT;
2739 else
2740 {
2741 if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id - 1])
2742 & (1L << PRIVATE_FAX_SUB_SEP_PWD))
2743 {
2744 fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_PASSWORD;
2745 if (fax_control_bits & T30_CONTROL_BIT_ACCEPT_POLLING)
2746 fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SEL_POLLING;
2747 }
2748 w = fax_parms[4].length;
2749 if (w > 20)
2750 w = 20;
2751 ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = (byte) w;
2752 for (i = 0; i < w; i++)
2753 ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id[i] = fax_parms[4].info[1 + i];
2754 ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0;
2755 len = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH;
2756 w = fax_parms[5].length;
2757 if (w > 20)
2758 w = 20;
2759 plci->fax_connect_info_buffer[len++] = (byte) w;
2760 for (i = 0; i < w; i++)
2761 plci->fax_connect_info_buffer[len++] = fax_parms[5].info[1 + i];
2762 w = fax_parms[6].length;
2763 if (w > 20)
2764 w = 20;
2765 plci->fax_connect_info_buffer[len++] = (byte) w;
2766 for (i = 0; i < w; i++)
2767 plci->fax_connect_info_buffer[len++] = fax_parms[6].info[1 + i];
2768 if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id - 1])
2769 & (1L << PRIVATE_FAX_NONSTANDARD))
2770 {
2771 if (api_parse(&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms))
2772 {
2773 dbug(1, dprintf("non-standard facilities info missing or wrong format"));
2774 plci->fax_connect_info_buffer[len++] = 0;
2775 }
2776 else
2777 {
2778 if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2))
2779 plci->nsf_control_bits = GET_WORD(&fax_parms[7].info[2]);
2780 plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length);
2781 for (i = 0; i < fax_parms[7].length; i++)
2782 plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1 + i];
2783 }
2784 }
2785 }
2786 }
2787 else
2788 {
2789 len = offsetof(T30_INFO, universal_6);
2790 }
2791 fax_info_change = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792
Joe Perches475be4d2012-02-19 19:52:38 -08002793 }
2794 if (fax_control_bits != GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low))
2795 {
2796 PUT_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low, fax_control_bits);
2797 fax_info_change = true;
2798 }
2799 }
2800 if (Info == GOOD)
2801 {
2802 plci->fax_connect_info_length = len;
2803 if (fax_info_change)
2804 {
2805 if (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS)
2806 {
2807 start_internal_command(Id, plci, fax_connect_info_command);
2808 return false;
2809 }
2810 else
2811 {
2812 start_internal_command(Id, plci, fax_adjust_b23_command);
2813 return false;
2814 }
2815 }
2816 }
2817 }
2818 else Info = _WRONG_STATE;
2819 }
2820 else Info = _WRONG_STATE;
2821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822
Joe Perches475be4d2012-02-19 19:52:38 -08002823 else if (plci->B3_prot == B3_RTP)
2824 {
2825 plci->internal_req_buffer[0] = ncpi->length + 1;
2826 plci->internal_req_buffer[1] = UDATA_REQUEST_RTP_RECONFIGURE;
2827 for (w = 0; w < ncpi->length; w++)
2828 plci->internal_req_buffer[2 + w] = ncpi->info[1 + w];
2829 start_internal_command(Id, plci, rtp_connect_b3_req_command);
2830 return false;
2831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832
Joe Perches475be4d2012-02-19 19:52:38 -08002833 if (!Info)
2834 {
2835 nl_req_ncci(plci, req, 0);
2836 return 1;
2837 }
2838 }
2839 }
2840 else Info = _WRONG_IDENTIFIER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841
Joe Perches475be4d2012-02-19 19:52:38 -08002842 sendf(appl,
2843 _CONNECT_B3_R | CONFIRM,
2844 Id,
2845 Number,
2846 "w", Info);
2847 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848}
2849
Hannes Eder465e9852009-02-25 13:11:37 +00002850static byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
2851 PLCI *plci, APPL *appl, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852{
Joe Perches475be4d2012-02-19 19:52:38 -08002853 word ncci;
2854 API_PARSE *ncpi;
2855 byte req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856
Joe Perches475be4d2012-02-19 19:52:38 -08002857 word w;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858
2859
Joe Perches475be4d2012-02-19 19:52:38 -08002860 API_PARSE fax_parms[9];
2861 word i;
2862 byte len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863
2864
Joe Perches475be4d2012-02-19 19:52:38 -08002865 dbug(1, dprintf("connect_b3_res"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866
Joe Perches475be4d2012-02-19 19:52:38 -08002867 ncci = (word)(Id >> 16);
2868 if (plci && ncci) {
2869 if (a->ncci_state[ncci] == INC_CON_PENDING) {
2870 if (GET_WORD(&parms[0].info[0]) != 0)
2871 {
2872 a->ncci_state[ncci] = OUTG_REJ_PENDING;
2873 channel_request_xon(plci, a->ncci_ch[ncci]);
2874 channel_xmit_xon(plci);
2875 cleanup_ncci_data(plci, ncci);
2876 nl_req_ncci(plci, N_DISC, (byte)ncci);
2877 return 1;
2878 }
2879 a->ncci_state[ncci] = INC_ACT_PENDING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880
Joe Perches475be4d2012-02-19 19:52:38 -08002881 req = N_CONNECT_ACK;
2882 ncpi = &parms[1];
2883 if ((plci->B3_prot == 4) || (plci->B3_prot == 5) || (plci->B3_prot == 7))
2884 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885
Joe Perches475be4d2012-02-19 19:52:38 -08002886 if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id - 1])
2887 & (1L << PRIVATE_FAX_NONSTANDARD))
2888 {
2889 if (((plci->B3_prot == 4) || (plci->B3_prot == 5))
2890 && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF)
2891 && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP))
2892 {
2893 len = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH;
2894 if (plci->fax_connect_info_length < len)
2895 {
2896 ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0;
2897 ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0;
2898 }
2899 if (api_parse(&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms))
2900 {
2901 dbug(1, dprintf("non-standard facilities info missing or wrong format"));
2902 }
2903 else
2904 {
2905 if (plci->fax_connect_info_length <= len)
2906 plci->fax_connect_info_buffer[len] = 0;
2907 len += 1 + plci->fax_connect_info_buffer[len];
2908 if (plci->fax_connect_info_length <= len)
2909 plci->fax_connect_info_buffer[len] = 0;
2910 len += 1 + plci->fax_connect_info_buffer[len];
2911 if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2))
2912 plci->nsf_control_bits = GET_WORD(&fax_parms[7].info[2]);
2913 plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length);
2914 for (i = 0; i < fax_parms[7].length; i++)
2915 plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1 + i];
2916 }
2917 plci->fax_connect_info_length = len;
2918 ((T30_INFO *)(plci->fax_connect_info_buffer))->code = 0;
2919 start_internal_command(Id, plci, fax_connect_ack_command);
2920 return false;
2921 }
2922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
Joe Perches475be4d2012-02-19 19:52:38 -08002924 nl_req_ncci(plci, req, (byte)ncci);
2925 if ((plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
2926 && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
2927 {
2928 if (plci->B3_prot == 4)
2929 sendf(appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", "");
2930 else
2931 sendf(appl, _CONNECT_B3_ACTIVE_I, Id, 0, "S", plci->ncpi_buffer);
2932 plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
2933 }
2934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935
Joe Perches475be4d2012-02-19 19:52:38 -08002936 else if (plci->B3_prot == B3_RTP)
2937 {
2938 plci->internal_req_buffer[0] = ncpi->length + 1;
2939 plci->internal_req_buffer[1] = UDATA_REQUEST_RTP_RECONFIGURE;
2940 for (w = 0; w < ncpi->length; w++)
2941 plci->internal_req_buffer[2 + w] = ncpi->info[1+w];
2942 start_internal_command(Id, plci, rtp_connect_b3_res_command);
2943 return false;
2944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945
Joe Perches475be4d2012-02-19 19:52:38 -08002946 else
2947 {
2948 if (ncpi->length > 2) {
2949 if (ncpi->info[1] & 1) req = N_CONNECT_ACK | N_D_BIT;
2950 add_d(plci, (word)(ncpi->length - 3), &ncpi->info[4]);
2951 }
2952 nl_req_ncci(plci, req, (byte)ncci);
2953 sendf(appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", "");
2954 if (plci->adjust_b_restore)
2955 {
2956 plci->adjust_b_restore = false;
2957 start_internal_command(Id, plci, adjust_b_restore);
2958 }
2959 }
2960 return 1;
2961 }
2962 }
2963 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964}
2965
Hannes Eder465e9852009-02-25 13:11:37 +00002966static byte connect_b3_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
2967 PLCI *plci, APPL *appl, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968{
Joe Perches475be4d2012-02-19 19:52:38 -08002969 word ncci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970
Joe Perches475be4d2012-02-19 19:52:38 -08002971 ncci = (word)(Id >> 16);
2972 dbug(1, dprintf("connect_b3_a_res(ncci=0x%x)", ncci));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973
Joe Perches475be4d2012-02-19 19:52:38 -08002974 if (plci && ncci && (plci->State != IDLE) && (plci->State != INC_DIS_PENDING)
2975 && (plci->State != OUTG_DIS_PENDING))
2976 {
2977 if (a->ncci_state[ncci] == INC_ACT_PENDING) {
2978 a->ncci_state[ncci] = CONNECTED;
2979 if (plci->State != INC_CON_CONNECTED_ALERT) plci->State = CONNECTED;
2980 channel_request_xon(plci, a->ncci_ch[ncci]);
2981 channel_xmit_xon(plci);
2982 }
2983 }
2984 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985}
2986
Hannes Eder465e9852009-02-25 13:11:37 +00002987static byte disconnect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
2988 PLCI *plci, APPL *appl, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989{
Joe Perches475be4d2012-02-19 19:52:38 -08002990 word Info;
2991 word ncci;
2992 API_PARSE *ncpi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993
Joe Perches475be4d2012-02-19 19:52:38 -08002994 dbug(1, dprintf("disconnect_b3_req"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995
Joe Perches475be4d2012-02-19 19:52:38 -08002996 Info = _WRONG_IDENTIFIER;
2997 ncci = (word)(Id >> 16);
2998 if (plci && ncci)
2999 {
3000 Info = _WRONG_STATE;
3001 if ((a->ncci_state[ncci] == CONNECTED)
3002 || (a->ncci_state[ncci] == OUTG_CON_PENDING)
3003 || (a->ncci_state[ncci] == INC_CON_PENDING)
3004 || (a->ncci_state[ncci] == INC_ACT_PENDING))
3005 {
3006 a->ncci_state[ncci] = OUTG_DIS_PENDING;
3007 channel_request_xon(plci, a->ncci_ch[ncci]);
3008 channel_xmit_xon(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009
Joe Perches475be4d2012-02-19 19:52:38 -08003010 if (a->ncci[ncci].data_pending
3011 && ((plci->B3_prot == B3_TRANSPARENT)
3012 || (plci->B3_prot == B3_T30)
3013 || (plci->B3_prot == B3_T30_WITH_EXTENSIONS)))
3014 {
3015 plci->send_disc = (byte)ncci;
3016 plci->command = 0;
3017 return false;
3018 }
3019 else
3020 {
3021 cleanup_ncci_data(plci, ncci);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022
Joe Perches475be4d2012-02-19 19:52:38 -08003023 if (plci->B3_prot == 2 || plci->B3_prot == 3)
3024 {
3025 ncpi = &parms[0];
3026 if (ncpi->length > 3)
3027 {
3028 add_d(plci, (word)(ncpi->length - 3), (byte *)&(ncpi->info[4]));
3029 }
3030 }
3031 nl_req_ncci(plci, N_DISC, (byte)ncci);
3032 }
3033 return 1;
3034 }
3035 }
3036 sendf(appl,
3037 _DISCONNECT_B3_R | CONFIRM,
3038 Id,
3039 Number,
3040 "w", Info);
3041 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042}
3043
Hannes Eder465e9852009-02-25 13:11:37 +00003044static byte disconnect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
3045 PLCI *plci, APPL *appl, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046{
Joe Perches475be4d2012-02-19 19:52:38 -08003047 word ncci;
3048 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049
Joe Perches475be4d2012-02-19 19:52:38 -08003050 ncci = (word)(Id >> 16);
3051 dbug(1, dprintf("disconnect_b3_res(ncci=0x%x", ncci));
3052 if (plci && ncci) {
3053 plci->requested_options_conn = 0;
3054 plci->fax_connect_info_length = 0;
3055 plci->ncpi_state = 0x00;
3056 if (((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE))
3057 && ((plci->B2_prot != B2_LAPD) && (plci->B2_prot != B2_LAPD_FREE_SAPI_SEL)))
3058 {
3059 plci->call_dir |= CALL_DIR_FORCE_OUTG_NL;
3060 }
3061 for (i = 0; i < MAX_CHANNELS_PER_PLCI && plci->inc_dis_ncci_table[i] != (byte)ncci; i++);
3062 if (i < MAX_CHANNELS_PER_PLCI) {
3063 if (plci->channels)plci->channels--;
3064 for (; i < MAX_CHANNELS_PER_PLCI - 1; i++) plci->inc_dis_ncci_table[i] = plci->inc_dis_ncci_table[i + 1];
3065 plci->inc_dis_ncci_table[MAX_CHANNELS_PER_PLCI - 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066
Joe Perches475be4d2012-02-19 19:52:38 -08003067 ncci_free_receive_buffers(plci, ncci);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068
Joe Perches475be4d2012-02-19 19:52:38 -08003069 if ((plci->State == IDLE || plci->State == SUSPENDING) && !plci->channels) {
3070 if (plci->State == SUSPENDING) {
3071 sendf(plci->appl,
3072 _FACILITY_I,
3073 Id & 0xffffL,
3074 0,
3075 "ws", (word)3, "\x03\x04\x00\x00");
3076 sendf(plci->appl, _DISCONNECT_I, Id & 0xffffL, 0, "w", 0);
3077 }
3078 plci_remove(plci);
3079 plci->State = IDLE;
3080 }
3081 }
3082 else
3083 {
3084 if ((a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
3085 && ((plci->B3_prot == 4) || (plci->B3_prot == 5))
3086 && (a->ncci_state[ncci] == INC_DIS_PENDING))
3087 {
3088 ncci_free_receive_buffers(plci, ncci);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089
Joe Perches475be4d2012-02-19 19:52:38 -08003090 nl_req_ncci(plci, N_EDATA, (byte)ncci);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091
Joe Perches475be4d2012-02-19 19:52:38 -08003092 plci->adapter->ncci_state[ncci] = IDLE;
3093 start_internal_command(Id, plci, fax_disconnect_command);
3094 return 1;
3095 }
3096 }
3097 }
3098 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099}
3100
Hannes Eder465e9852009-02-25 13:11:37 +00003101static byte data_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
3102 PLCI *plci, APPL *appl, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103{
Joe Perches475be4d2012-02-19 19:52:38 -08003104 NCCI *ncci_ptr;
3105 DATA_B3_DESC *data;
3106 word Info;
3107 word ncci;
3108 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
Joe Perches475be4d2012-02-19 19:52:38 -08003110 dbug(1, dprintf("data_b3_req"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111
Joe Perches475be4d2012-02-19 19:52:38 -08003112 Info = _WRONG_IDENTIFIER;
3113 ncci = (word)(Id >> 16);
3114 dbug(1, dprintf("ncci=0x%x, plci=0x%x", ncci, plci));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115
Joe Perches475be4d2012-02-19 19:52:38 -08003116 if (plci && ncci)
3117 {
3118 Info = _WRONG_STATE;
3119 if ((a->ncci_state[ncci] == CONNECTED)
3120 || (a->ncci_state[ncci] == INC_ACT_PENDING))
3121 {
3122 /* queue data */
3123 ncci_ptr = &(a->ncci[ncci]);
3124 i = ncci_ptr->data_out + ncci_ptr->data_pending;
3125 if (i >= MAX_DATA_B3)
3126 i -= MAX_DATA_B3;
3127 data = &(ncci_ptr->DBuffer[i]);
3128 data->Number = Number;
3129 if ((((byte *)(parms[0].info)) >= ((byte *)(plci->msg_in_queue)))
3130 && (((byte *)(parms[0].info)) < ((byte *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
3131 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132
Joe Perches475be4d2012-02-19 19:52:38 -08003133 data->P = (byte *)(long)(*((dword *)(parms[0].info)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134
Joe Perches475be4d2012-02-19 19:52:38 -08003135 }
3136 else
3137 data->P = TransmitBufferSet(appl, *(dword *)parms[0].info);
3138 data->Length = GET_WORD(parms[1].info);
3139 data->Handle = GET_WORD(parms[2].info);
3140 data->Flags = GET_WORD(parms[3].info);
3141 (ncci_ptr->data_pending)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142
Joe Perches475be4d2012-02-19 19:52:38 -08003143 /* check for delivery confirmation */
3144 if (data->Flags & 0x0004)
3145 {
3146 i = ncci_ptr->data_ack_out + ncci_ptr->data_ack_pending;
3147 if (i >= MAX_DATA_ACK)
3148 i -= MAX_DATA_ACK;
3149 ncci_ptr->DataAck[i].Number = data->Number;
3150 ncci_ptr->DataAck[i].Handle = data->Handle;
3151 (ncci_ptr->data_ack_pending)++;
3152 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153
Joe Perches475be4d2012-02-19 19:52:38 -08003154 send_data(plci);
3155 return false;
3156 }
3157 }
3158 if (appl)
3159 {
3160 if (plci)
3161 {
3162 if ((((byte *)(parms[0].info)) >= ((byte *)(plci->msg_in_queue)))
3163 && (((byte *)(parms[0].info)) < ((byte *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
3164 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165
Joe Perches475be4d2012-02-19 19:52:38 -08003166 TransmitBufferFree(appl, (byte *)(long)(*((dword *)(parms[0].info))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167
Joe Perches475be4d2012-02-19 19:52:38 -08003168 }
3169 }
3170 sendf(appl,
3171 _DATA_B3_R | CONFIRM,
3172 Id,
3173 Number,
3174 "ww", GET_WORD(parms[2].info), Info);
3175 }
3176 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177}
3178
Hannes Eder465e9852009-02-25 13:11:37 +00003179static byte data_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
3180 PLCI *plci, APPL *appl, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181{
Joe Perches475be4d2012-02-19 19:52:38 -08003182 word n;
3183 word ncci;
3184 word NCCIcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185
Joe Perches475be4d2012-02-19 19:52:38 -08003186 dbug(1, dprintf("data_b3_res"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187
Joe Perches475be4d2012-02-19 19:52:38 -08003188 ncci = (word)(Id >> 16);
3189 if (plci && ncci) {
3190 n = GET_WORD(parms[0].info);
3191 dbug(1, dprintf("free(%d)", n));
3192 NCCIcode = ncci | (((word) a->Id) << 8);
3193 if (n < appl->MaxBuffer &&
3194 appl->DataNCCI[n] == NCCIcode &&
3195 (byte)(appl->DataFlags[n] >> 8) == plci->Id) {
3196 dbug(1, dprintf("found"));
3197 appl->DataNCCI[n] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198
Joe Perches475be4d2012-02-19 19:52:38 -08003199 if (channel_can_xon(plci, a->ncci_ch[ncci])) {
3200 channel_request_xon(plci, a->ncci_ch[ncci]);
3201 }
3202 channel_xmit_xon(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203
Joe Perches475be4d2012-02-19 19:52:38 -08003204 if (appl->DataFlags[n] & 4) {
3205 nl_req_ncci(plci, N_DATA_ACK, (byte)ncci);
3206 return 1;
3207 }
3208 }
3209 }
3210 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211}
3212
Hannes Eder465e9852009-02-25 13:11:37 +00003213static byte reset_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
3214 PLCI *plci, APPL *appl, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215{
Joe Perches475be4d2012-02-19 19:52:38 -08003216 word Info;
3217 word ncci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218
Joe Perches475be4d2012-02-19 19:52:38 -08003219 dbug(1, dprintf("reset_b3_req"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220
Joe Perches475be4d2012-02-19 19:52:38 -08003221 Info = _WRONG_IDENTIFIER;
3222 ncci = (word)(Id >> 16);
3223 if (plci && ncci)
3224 {
3225 Info = _WRONG_STATE;
3226 switch (plci->B3_prot)
3227 {
3228 case B3_ISO8208:
3229 case B3_X25_DCE:
3230 if (a->ncci_state[ncci] == CONNECTED)
3231 {
3232 nl_req_ncci(plci, N_RESET, (byte)ncci);
3233 send_req(plci);
3234 Info = GOOD;
3235 }
3236 break;
3237 case B3_TRANSPARENT:
3238 if (a->ncci_state[ncci] == CONNECTED)
3239 {
3240 start_internal_command(Id, plci, reset_b3_command);
3241 Info = GOOD;
3242 }
3243 break;
3244 }
3245 }
3246 /* reset_b3 must result in a reset_b3_con & reset_b3_Ind */
3247 sendf(appl,
3248 _RESET_B3_R | CONFIRM,
3249 Id,
3250 Number,
3251 "w", Info);
3252 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253}
3254
Hannes Eder465e9852009-02-25 13:11:37 +00003255static byte reset_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
3256 PLCI *plci, APPL *appl, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257{
Joe Perches475be4d2012-02-19 19:52:38 -08003258 word ncci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259
Joe Perches475be4d2012-02-19 19:52:38 -08003260 dbug(1, dprintf("reset_b3_res"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261
Joe Perches475be4d2012-02-19 19:52:38 -08003262 ncci = (word)(Id >> 16);
3263 if (plci && ncci) {
3264 switch (plci->B3_prot)
3265 {
3266 case B3_ISO8208:
3267 case B3_X25_DCE:
3268 if (a->ncci_state[ncci] == INC_RES_PENDING)
3269 {
3270 a->ncci_state[ncci] = CONNECTED;
3271 nl_req_ncci(plci, N_RESET_ACK, (byte)ncci);
3272 return true;
3273 }
3274 break;
3275 }
3276 }
3277 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278}
3279
Hannes Eder465e9852009-02-25 13:11:37 +00003280static byte connect_b3_t90_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
3281 PLCI *plci, APPL *appl, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282{
Joe Perches475be4d2012-02-19 19:52:38 -08003283 word ncci;
3284 API_PARSE *ncpi;
3285 byte req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286
Joe Perches475be4d2012-02-19 19:52:38 -08003287 dbug(1, dprintf("connect_b3_t90_a_res"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288
Joe Perches475be4d2012-02-19 19:52:38 -08003289 ncci = (word)(Id >> 16);
3290 if (plci && ncci) {
3291 if (a->ncci_state[ncci] == INC_ACT_PENDING) {
3292 a->ncci_state[ncci] = CONNECTED;
3293 }
3294 else if (a->ncci_state[ncci] == INC_CON_PENDING) {
3295 a->ncci_state[ncci] = CONNECTED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296
Joe Perches475be4d2012-02-19 19:52:38 -08003297 req = N_CONNECT_ACK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298
Joe Perches475be4d2012-02-19 19:52:38 -08003299 /* parms[0]==0 for CAPI original message definition! */
3300 if (parms[0].info) {
3301 ncpi = &parms[1];
3302 if (ncpi->length > 2) {
3303 if (ncpi->info[1] & 1) req = N_CONNECT_ACK | N_D_BIT;
3304 add_d(plci, (word)(ncpi->length - 3), &ncpi->info[4]);
3305 }
3306 }
3307 nl_req_ncci(plci, req, (byte)ncci);
3308 return 1;
3309 }
3310 }
3311 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312}
3313
3314
Hannes Eder465e9852009-02-25 13:11:37 +00003315static byte select_b_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
3316 PLCI *plci, APPL *appl, API_PARSE *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317{
Joe Perches475be4d2012-02-19 19:52:38 -08003318 word Info = 0;
3319 word i;
3320 byte tel;
3321 API_PARSE bp_parms[7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322
Joe Perches475be4d2012-02-19 19:52:38 -08003323 if (!plci || !msg)
3324 {
3325 Info = _WRONG_IDENTIFIER;
3326 }
3327 else
3328 {
3329 dbug(1, dprintf("select_b_req[%d],PLCI=0x%x,Tel=0x%x,NL=0x%x,appl=0x%x,sstate=0x%x",
3330 msg->length, plci->Id, plci->tel, plci->NL.Id, plci->appl, plci->SuppState));
3331 dbug(1, dprintf("PlciState=0x%x", plci->State));
3332 for (i = 0; i < 7; i++) bp_parms[i].length = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333
Joe Perches475be4d2012-02-19 19:52:38 -08003334 /* check if no channel is open, no B3 connected only */
3335 if ((plci->State == IDLE) || (plci->State == OUTG_DIS_PENDING) || (plci->State == INC_DIS_PENDING)
3336 || (plci->SuppState != IDLE) || plci->channels || plci->nl_remove_id)
3337 {
3338 Info = _WRONG_STATE;
3339 }
3340 /* check message format and fill bp_parms pointer */
3341 else if (msg->length && api_parse(&msg->info[1], (word)msg->length, "wwwsss", bp_parms))
3342 {
3343 Info = _WRONG_MESSAGE_FORMAT;
3344 }
3345 else
3346 {
3347 if ((plci->State == INC_CON_PENDING) || (plci->State == INC_CON_ALERT)) /* send alert tone inband to the network, */
3348 { /* e.g. Qsig or RBS or Cornet-N or xess PRI */
3349 if (Id & EXT_CONTROLLER)
3350 {
3351 sendf(appl, _SELECT_B_REQ | CONFIRM, Id, Number, "w", 0x2002); /* wrong controller */
3352 return 0;
3353 }
3354 plci->State = INC_CON_CONNECTED_ALERT;
3355 plci->appl = appl;
3356 clear_c_ind_mask_bit(plci, (word)(appl->Id - 1));
3357 dump_c_ind_mask(plci);
3358 for (i = 0; i < max_appl; i++) /* disconnect the other appls */
3359 { /* its quasi a connect */
3360 if (test_c_ind_mask_bit(plci, i))
3361 sendf(&application[i], _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED);
3362 }
3363 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364
Joe Perches475be4d2012-02-19 19:52:38 -08003365 api_save_msg(msg, "s", &plci->saved_msg);
3366 tel = plci->tel;
3367 if (Id & EXT_CONTROLLER)
3368 {
3369 if (tel) /* external controller in use by this PLCI */
3370 {
3371 if (a->AdvSignalAppl && a->AdvSignalAppl != appl)
3372 {
3373 dbug(1, dprintf("Ext_Ctrl in use 1"));
3374 Info = _WRONG_STATE;
3375 }
3376 }
3377 else /* external controller NOT in use by this PLCI ? */
3378 {
3379 if (a->AdvSignalPLCI)
3380 {
3381 dbug(1, dprintf("Ext_Ctrl in use 2"));
3382 Info = _WRONG_STATE;
3383 }
3384 else /* activate the codec */
3385 {
3386 dbug(1, dprintf("Ext_Ctrl start"));
3387 if (AdvCodecSupport(a, plci, appl, 0))
3388 {
3389 dbug(1, dprintf("Error in codec procedures"));
3390 Info = _WRONG_STATE;
3391 }
3392 else if (plci->spoofed_msg == SPOOFING_REQUIRED) /* wait until codec is active */
3393 {
3394 plci->spoofed_msg = AWAITING_SELECT_B;
3395 plci->internal_command = BLOCK_PLCI; /* lock other commands */
3396 plci->command = 0;
3397 dbug(1, dprintf("continue if codec loaded"));
3398 return false;
3399 }
3400 }
3401 }
3402 }
3403 else /* external controller bit is OFF */
3404 {
3405 if (tel) /* external controller in use, need to switch off */
3406 {
3407 if (a->AdvSignalAppl == appl)
3408 {
3409 CodecIdCheck(a, plci);
3410 plci->tel = 0;
3411 plci->adv_nl = 0;
3412 dbug(1, dprintf("Ext_Ctrl disable"));
3413 }
3414 else
3415 {
3416 dbug(1, dprintf("Ext_Ctrl not requested"));
3417 }
3418 }
3419 }
3420 if (!Info)
3421 {
3422 if (plci->call_dir & CALL_DIR_OUT)
3423 plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
3424 else if (plci->call_dir & CALL_DIR_IN)
3425 plci->call_dir = CALL_DIR_IN | CALL_DIR_ANSWER;
3426 start_internal_command(Id, plci, select_b_command);
3427 return false;
3428 }
3429 }
3430 }
3431 sendf(appl, _SELECT_B_REQ | CONFIRM, Id, Number, "w", Info);
3432 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433}
3434
Hannes Eder4ee59d52008-12-16 01:17:33 -08003435static byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
3436 PLCI *plci, APPL *appl, API_PARSE *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437{
Joe Perches475be4d2012-02-19 19:52:38 -08003438 word command;
3439 word i;
3440 word ncci;
3441 API_PARSE *m;
3442 API_PARSE m_parms[5];
3443 word codec;
3444 byte req;
3445 byte ch;
3446 byte dir;
3447 static byte chi[2] = {0x01, 0x00};
3448 static byte lli[2] = {0x01, 0x00};
3449 static byte codec_cai[2] = {0x01, 0x01};
3450 static byte null_msg = {0};
3451 static API_PARSE null_parms = { 0, &null_msg };
3452 PLCI *v_plci;
3453 word Info = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454
Joe Perches475be4d2012-02-19 19:52:38 -08003455 dbug(1, dprintf("manufacturer_req"));
3456 for (i = 0; i < 5; i++) m_parms[i].length = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457
Joe Perches475be4d2012-02-19 19:52:38 -08003458 if (GET_DWORD(parms[0].info) != _DI_MANU_ID) {
3459 Info = _WRONG_MESSAGE_FORMAT;
3460 }
3461 command = GET_WORD(parms[1].info);
3462 m = &parms[2];
3463 if (!Info)
3464 {
3465 switch (command) {
3466 case _DI_ASSIGN_PLCI:
3467 if (api_parse(&m->info[1], (word)m->length, "wbbs", m_parms)) {
3468 Info = _WRONG_MESSAGE_FORMAT;
3469 break;
3470 }
3471 codec = GET_WORD(m_parms[0].info);
3472 ch = m_parms[1].info[0];
3473 dir = m_parms[2].info[0];
3474 if ((i = get_plci(a))) {
3475 plci = &a->plci[i - 1];
3476 plci->appl = appl;
3477 plci->command = _MANUFACTURER_R;
3478 plci->m_command = command;
3479 plci->number = Number;
3480 plci->State = LOCAL_CONNECT;
3481 Id = (((word)plci->Id << 8) | plci->adapter->Id | 0x80);
3482 dbug(1, dprintf("ManCMD,plci=0x%x", Id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483
Joe Perches475be4d2012-02-19 19:52:38 -08003484 if ((ch == 1 || ch == 2) && (dir <= 2)) {
3485 chi[1] = (byte)(0x80 | ch);
3486 lli[1] = 0;
3487 plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
3488 switch (codec)
3489 {
3490 case 0:
3491 Info = add_b1(plci, &m_parms[3], 0, 0);
3492 break;
3493 case 1:
3494 add_p(plci, CAI, codec_cai);
3495 break;
3496 /* manual 'swich on' to the codec support without signalling */
3497 /* first 'assign plci' with this function, then use */
3498 case 2:
3499 if (AdvCodecSupport(a, plci, appl, 0)) {
3500 Info = _RESOURCE_ERROR;
3501 }
3502 else {
3503 Info = add_b1(plci, &null_parms, 0, B1_FACILITY_LOCAL);
3504 lli[1] = 0x10; /* local call codec stream */
3505 }
3506 break;
3507 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508
Joe Perches475be4d2012-02-19 19:52:38 -08003509 plci->State = LOCAL_CONNECT;
3510 plci->manufacturer = true;
3511 plci->command = _MANUFACTURER_R;
3512 plci->m_command = command;
3513 plci->number = Number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514
Joe Perches475be4d2012-02-19 19:52:38 -08003515 if (!Info)
3516 {
3517 add_p(plci, LLI, lli);
3518 add_p(plci, CHI, chi);
3519 add_p(plci, UID, "\x06\x43\x61\x70\x69\x32\x30");
3520 sig_req(plci, ASSIGN, DSIG_ID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521
Joe Perches475be4d2012-02-19 19:52:38 -08003522 if (!codec)
3523 {
3524 Info = add_b23(plci, &m_parms[3]);
3525 if (!Info)
3526 {
3527 nl_req_ncci(plci, ASSIGN, 0);
3528 send_req(plci);
3529 }
3530 }
3531 if (!Info)
3532 {
3533 dbug(1, dprintf("dir=0x%x,spoof=0x%x", dir, plci->spoofed_msg));
3534 if (plci->spoofed_msg == SPOOFING_REQUIRED)
3535 {
3536 api_save_msg(m_parms, "wbbs", &plci->saved_msg);
3537 plci->spoofed_msg = AWAITING_MANUF_CON;
3538 plci->internal_command = BLOCK_PLCI; /* reject other req meanwhile */
3539 plci->command = 0;
3540 send_req(plci);
3541 return false;
3542 }
3543 if (dir == 1) {
3544 sig_req(plci, CALL_REQ, 0);
3545 }
3546 else if (!dir) {
3547 sig_req(plci, LISTEN_REQ, 0);
3548 }
3549 send_req(plci);
3550 }
3551 else
3552 {
3553 sendf(appl,
3554 _MANUFACTURER_R | CONFIRM,
3555 Id,
3556 Number,
3557 "dww", _DI_MANU_ID, command, Info);
3558 return 2;
3559 }
3560 }
3561 }
3562 }
3563 else Info = _OUT_OF_PLCI;
3564 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565
Joe Perches475be4d2012-02-19 19:52:38 -08003566 case _DI_IDI_CTRL:
3567 if (!plci)
3568 {
3569 Info = _WRONG_IDENTIFIER;
3570 break;
3571 }
3572 if (api_parse(&m->info[1], (word)m->length, "bs", m_parms)) {
3573 Info = _WRONG_MESSAGE_FORMAT;
3574 break;
3575 }
3576 req = m_parms[0].info[0];
3577 plci->command = _MANUFACTURER_R;
3578 plci->m_command = command;
3579 plci->number = Number;
3580 if (req == CALL_REQ)
3581 {
3582 plci->b_channel = getChannel(&m_parms[1]);
3583 mixer_set_bchannel_id_esc(plci, plci->b_channel);
3584 if (plci->spoofed_msg == SPOOFING_REQUIRED)
3585 {
3586 plci->spoofed_msg = CALL_REQ | AWAITING_MANUF_CON;
3587 plci->internal_command = BLOCK_PLCI; /* reject other req meanwhile */
3588 plci->command = 0;
3589 break;
3590 }
3591 }
3592 else if (req == LAW_REQ)
3593 {
3594 plci->cr_enquiry = true;
3595 }
3596 add_ss(plci, FTY, &m_parms[1]);
3597 sig_req(plci, req, 0);
3598 send_req(plci);
3599 if (req == HANGUP)
3600 {
3601 if (plci->NL.Id && !plci->nl_remove_id)
3602 {
3603 if (plci->channels)
3604 {
3605 for (ncci = 1; ncci < MAX_NCCI + 1; ncci++)
3606 {
3607 if ((a->ncci_plci[ncci] == plci->Id) && (a->ncci_state[ncci] == CONNECTED))
3608 {
3609 a->ncci_state[ncci] = OUTG_DIS_PENDING;
3610 cleanup_ncci_data(plci, ncci);
3611 nl_req_ncci(plci, N_DISC, (byte)ncci);
3612 }
3613 }
3614 }
3615 mixer_remove(plci);
3616 nl_req_ncci(plci, REMOVE, 0);
3617 send_req(plci);
3618 }
3619 }
3620 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621
Joe Perches475be4d2012-02-19 19:52:38 -08003622 case _DI_SIG_CTRL:
3623 /* signalling control for loop activation B-channel */
3624 if (!plci)
3625 {
3626 Info = _WRONG_IDENTIFIER;
3627 break;
3628 }
3629 if (m->length) {
3630 plci->command = _MANUFACTURER_R;
3631 plci->number = Number;
3632 add_ss(plci, FTY, m);
3633 sig_req(plci, SIG_CTRL, 0);
3634 send_req(plci);
3635 }
3636 else Info = _WRONG_MESSAGE_FORMAT;
3637 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638
Joe Perches475be4d2012-02-19 19:52:38 -08003639 case _DI_RXT_CTRL:
3640 /* activation control for receiver/transmitter B-channel */
3641 if (!plci)
3642 {
3643 Info = _WRONG_IDENTIFIER;
3644 break;
3645 }
3646 if (m->length) {
3647 plci->command = _MANUFACTURER_R;
3648 plci->number = Number;
3649 add_ss(plci, FTY, m);
3650 sig_req(plci, DSP_CTRL, 0);
3651 send_req(plci);
3652 }
3653 else Info = _WRONG_MESSAGE_FORMAT;
3654 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655
Joe Perches475be4d2012-02-19 19:52:38 -08003656 case _DI_ADV_CODEC:
3657 case _DI_DSP_CTRL:
3658 /* TEL_CTRL commands to support non standard adjustments: */
3659 /* Ring on/off, Handset micro volume, external micro vol. */
3660 /* handset+external speaker volume, receiver+transm. gain,*/
3661 /* handsfree on (hookinfo off), set mixer command */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662
Joe Perches475be4d2012-02-19 19:52:38 -08003663 if (command == _DI_ADV_CODEC)
3664 {
3665 if (!a->AdvCodecPLCI) {
3666 Info = _WRONG_STATE;
3667 break;
3668 }
3669 v_plci = a->AdvCodecPLCI;
3670 }
3671 else
3672 {
3673 if (plci
3674 && (m->length >= 3)
3675 && (m->info[1] == 0x1c)
3676 && (m->info[2] >= 1))
3677 {
3678 if (m->info[3] == DSP_CTRL_OLD_SET_MIXER_COEFFICIENTS)
3679 {
3680 if ((plci->tel != ADV_VOICE) || (plci != a->AdvSignalPLCI))
3681 {
3682 Info = _WRONG_STATE;
3683 break;
3684 }
3685 a->adv_voice_coef_length = m->info[2] - 1;
3686 if (a->adv_voice_coef_length > m->length - 3)
3687 a->adv_voice_coef_length = (byte)(m->length - 3);
3688 if (a->adv_voice_coef_length > ADV_VOICE_COEF_BUFFER_SIZE)
3689 a->adv_voice_coef_length = ADV_VOICE_COEF_BUFFER_SIZE;
3690 for (i = 0; i < a->adv_voice_coef_length; i++)
3691 a->adv_voice_coef_buffer[i] = m->info[4 + i];
3692 if (plci->B1_facilities & B1_FACILITY_VOICE)
3693 adv_voice_write_coefs(plci, ADV_VOICE_WRITE_UPDATE);
3694 break;
3695 }
3696 else if (m->info[3] == DSP_CTRL_SET_DTMF_PARAMETERS)
3697 {
3698 if (!(a->manufacturer_features & MANUFACTURER_FEATURE_DTMF_PARAMETERS))
3699 {
3700 Info = _FACILITY_NOT_SUPPORTED;
3701 break;
3702 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703
Joe Perches475be4d2012-02-19 19:52:38 -08003704 plci->dtmf_parameter_length = m->info[2] - 1;
3705 if (plci->dtmf_parameter_length > m->length - 3)
3706 plci->dtmf_parameter_length = (byte)(m->length - 3);
3707 if (plci->dtmf_parameter_length > DTMF_PARAMETER_BUFFER_SIZE)
3708 plci->dtmf_parameter_length = DTMF_PARAMETER_BUFFER_SIZE;
3709 for (i = 0; i < plci->dtmf_parameter_length; i++)
3710 plci->dtmf_parameter_buffer[i] = m->info[4 + i];
3711 if (plci->B1_facilities & B1_FACILITY_DTMFR)
3712 dtmf_parameter_write(plci);
3713 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714
Joe Perches475be4d2012-02-19 19:52:38 -08003715 }
3716 }
3717 v_plci = plci;
3718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719
Joe Perches475be4d2012-02-19 19:52:38 -08003720 if (!v_plci)
3721 {
3722 Info = _WRONG_IDENTIFIER;
3723 break;
3724 }
3725 if (m->length) {
3726 add_ss(v_plci, FTY, m);
3727 sig_req(v_plci, TEL_CTRL, 0);
3728 send_req(v_plci);
3729 }
3730 else Info = _WRONG_MESSAGE_FORMAT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731
Joe Perches475be4d2012-02-19 19:52:38 -08003732 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733
Joe Perches475be4d2012-02-19 19:52:38 -08003734 case _DI_OPTIONS_REQUEST:
3735 if (api_parse(&m->info[1], (word)m->length, "d", m_parms)) {
3736 Info = _WRONG_MESSAGE_FORMAT;
3737 break;
3738 }
3739 if (GET_DWORD(m_parms[0].info) & ~a->man_profile.private_options)
3740 {
3741 Info = _FACILITY_NOT_SUPPORTED;
3742 break;
3743 }
3744 a->requested_options_table[appl->Id - 1] = GET_DWORD(m_parms[0].info);
3745 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746
3747
3748
Joe Perches475be4d2012-02-19 19:52:38 -08003749 default:
3750 Info = _WRONG_MESSAGE_FORMAT;
3751 break;
3752 }
3753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754
Joe Perches475be4d2012-02-19 19:52:38 -08003755 sendf(appl,
3756 _MANUFACTURER_R | CONFIRM,
3757 Id,
3758 Number,
3759 "dww", _DI_MANU_ID, command, Info);
3760 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761}
3762
3763
Hannes Eder4ee59d52008-12-16 01:17:33 -08003764static byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
3765 PLCI *plci, APPL *appl, API_PARSE *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766{
Joe Perches475be4d2012-02-19 19:52:38 -08003767 word indication;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768
Joe Perches475be4d2012-02-19 19:52:38 -08003769 API_PARSE m_parms[3];
3770 API_PARSE *ncpi;
3771 API_PARSE fax_parms[9];
3772 word i;
3773 byte len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774
3775
Joe Perches475be4d2012-02-19 19:52:38 -08003776 dbug(1, dprintf("manufacturer_res"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777
Joe Perches475be4d2012-02-19 19:52:38 -08003778 if ((msg[0].length == 0)
3779 || (msg[1].length == 0)
3780 || (GET_DWORD(msg[0].info) != _DI_MANU_ID))
3781 {
3782 return false;
3783 }
3784 indication = GET_WORD(msg[1].info);
3785 switch (indication)
3786 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787
Joe Perches475be4d2012-02-19 19:52:38 -08003788 case _DI_NEGOTIATE_B3:
3789 if (!plci)
3790 break;
3791 if (((plci->B3_prot != 4) && (plci->B3_prot != 5))
3792 || !(plci->ncpi_state & NCPI_NEGOTIATE_B3_SENT))
3793 {
3794 dbug(1, dprintf("wrong state for NEGOTIATE_B3 parameters"));
3795 break;
3796 }
3797 if (api_parse(&msg[2].info[1], msg[2].length, "ws", m_parms))
3798 {
3799 dbug(1, dprintf("wrong format in NEGOTIATE_B3 parameters"));
3800 break;
3801 }
3802 ncpi = &m_parms[1];
3803 len = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH;
3804 if (plci->fax_connect_info_length < len)
3805 {
3806 ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0;
3807 ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0;
3808 }
3809 if (api_parse(&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms))
3810 {
3811 dbug(1, dprintf("non-standard facilities info missing or wrong format"));
3812 }
3813 else
3814 {
3815 if (plci->fax_connect_info_length <= len)
3816 plci->fax_connect_info_buffer[len] = 0;
3817 len += 1 + plci->fax_connect_info_buffer[len];
3818 if (plci->fax_connect_info_length <= len)
3819 plci->fax_connect_info_buffer[len] = 0;
3820 len += 1 + plci->fax_connect_info_buffer[len];
3821 if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2))
3822 plci->nsf_control_bits = GET_WORD(&fax_parms[7].info[2]);
3823 plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length);
3824 for (i = 0; i < fax_parms[7].length; i++)
3825 plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1 + i];
3826 }
3827 plci->fax_connect_info_length = len;
3828 plci->fax_edata_ack_length = plci->fax_connect_info_length;
3829 start_internal_command(Id, plci, fax_edata_ack_command);
3830 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831
Joe Perches475be4d2012-02-19 19:52:38 -08003832 }
3833 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834}
3835
3836/*------------------------------------------------------------------*/
3837/* IDI callback function */
3838/*------------------------------------------------------------------*/
3839
Joe Perches475be4d2012-02-19 19:52:38 -08003840void callback(ENTITY *e)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841{
Joe Perches475be4d2012-02-19 19:52:38 -08003842 DIVA_CAPI_ADAPTER *a;
3843 APPL *appl;
3844 PLCI *plci;
3845 CAPI_MSG *m;
3846 word i, j;
3847 byte rc;
3848 byte ch;
3849 byte req;
3850 byte global_req;
3851 int no_cancel_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852
Joe Perches475be4d2012-02-19 19:52:38 -08003853 dbug(1, dprintf("%x:CB(%x:Req=%x,Rc=%x,Ind=%x)",
3854 (e->user[0] + 1) & 0x7fff, e->Id, e->Req, e->Rc, e->Ind));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855
Joe Perches475be4d2012-02-19 19:52:38 -08003856 a = &(adapter[(byte)e->user[0]]);
3857 plci = &(a->plci[e->user[1]]);
3858 no_cancel_rc = DIVA_CAPI_SUPPORTS_NO_CANCEL(a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859
Joe Perches475be4d2012-02-19 19:52:38 -08003860 /*
3861 If new protocol code and new XDI is used then CAPI should work
3862 fully in accordance with IDI cpec an look on callback field instead
3863 of Rc field for return codes.
3864 */
3865 if (((e->complete == 0xff) && no_cancel_rc) ||
3866 (e->Rc && !no_cancel_rc)) {
3867 rc = e->Rc;
3868 ch = e->RcCh;
3869 req = e->Req;
3870 e->Rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871
Joe Perches475be4d2012-02-19 19:52:38 -08003872 if (e->user[0] & 0x8000)
3873 {
3874 /*
3875 If REMOVE request was sent then we have to wait until
3876 return code with Id set to zero arrives.
3877 All other return codes should be ignored.
3878 */
3879 if (req == REMOVE)
3880 {
3881 if (e->Id)
3882 {
3883 dbug(1, dprintf("cancel RC in REMOVE state"));
3884 return;
3885 }
3886 channel_flow_control_remove(plci);
3887 for (i = 0; i < 256; i++)
3888 {
3889 if (a->FlowControlIdTable[i] == plci->nl_remove_id)
3890 a->FlowControlIdTable[i] = 0;
3891 }
3892 plci->nl_remove_id = 0;
3893 if (plci->rx_dma_descriptor > 0) {
3894 diva_free_dma_descriptor(plci, plci->rx_dma_descriptor - 1);
3895 plci->rx_dma_descriptor = 0;
3896 }
3897 }
3898 if (rc == OK_FC)
3899 {
3900 a->FlowControlIdTable[ch] = e->Id;
3901 a->FlowControlSkipTable[ch] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902
Joe Perches475be4d2012-02-19 19:52:38 -08003903 a->ch_flow_control[ch] |= N_OK_FC_PENDING;
3904 a->ch_flow_plci[ch] = plci->Id;
3905 plci->nl_req = 0;
3906 }
3907 else
3908 {
3909 /*
3910 Cancel return codes self, if feature was requested
3911 */
3912 if (no_cancel_rc && (a->FlowControlIdTable[ch] == e->Id) && e->Id) {
3913 a->FlowControlIdTable[ch] = 0;
3914 if ((rc == OK) && a->FlowControlSkipTable[ch]) {
3915 dbug(3, dprintf("XDI CAPI: RC cancelled Id:0x02, Ch:%02x", e->Id, ch));
3916 return;
3917 }
3918 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919
Joe Perches475be4d2012-02-19 19:52:38 -08003920 if (a->ch_flow_control[ch] & N_OK_FC_PENDING)
3921 {
3922 a->ch_flow_control[ch] &= ~N_OK_FC_PENDING;
3923 if (ch == e->ReqCh)
3924 plci->nl_req = 0;
3925 }
3926 else
3927 plci->nl_req = 0;
3928 }
3929 if (plci->nl_req)
3930 control_rc(plci, 0, rc, ch, 0, true);
3931 else
3932 {
3933 if (req == N_XON)
3934 {
3935 channel_x_on(plci, ch);
3936 if (plci->internal_command)
3937 control_rc(plci, req, rc, ch, 0, true);
3938 }
3939 else
3940 {
3941 if (plci->nl_global_req)
3942 {
3943 global_req = plci->nl_global_req;
3944 plci->nl_global_req = 0;
3945 if (rc != ASSIGN_OK) {
3946 e->Id = 0;
3947 if (plci->rx_dma_descriptor > 0) {
3948 diva_free_dma_descriptor(plci, plci->rx_dma_descriptor - 1);
3949 plci->rx_dma_descriptor = 0;
3950 }
3951 }
3952 channel_xmit_xon(plci);
3953 control_rc(plci, 0, rc, ch, global_req, true);
3954 }
3955 else if (plci->data_sent)
3956 {
3957 channel_xmit_xon(plci);
3958 plci->data_sent = false;
3959 plci->NL.XNum = 1;
3960 data_rc(plci, ch);
3961 if (plci->internal_command)
3962 control_rc(plci, req, rc, ch, 0, true);
3963 }
3964 else
3965 {
3966 channel_xmit_xon(plci);
3967 control_rc(plci, req, rc, ch, 0, true);
3968 }
3969 }
3970 }
3971 }
3972 else
3973 {
3974 /*
3975 If REMOVE request was sent then we have to wait until
3976 return code with Id set to zero arrives.
3977 All other return codes should be ignored.
3978 */
3979 if (req == REMOVE)
3980 {
3981 if (e->Id)
3982 {
3983 dbug(1, dprintf("cancel RC in REMOVE state"));
3984 return;
3985 }
3986 plci->sig_remove_id = 0;
3987 }
3988 plci->sig_req = 0;
3989 if (plci->sig_global_req)
3990 {
3991 global_req = plci->sig_global_req;
3992 plci->sig_global_req = 0;
3993 if (rc != ASSIGN_OK)
3994 e->Id = 0;
3995 channel_xmit_xon(plci);
3996 control_rc(plci, 0, rc, ch, global_req, false);
3997 }
3998 else
3999 {
4000 channel_xmit_xon(plci);
4001 control_rc(plci, req, rc, ch, 0, false);
4002 }
4003 }
4004 /*
4005 Again: in accordance with IDI spec Rc and Ind can't be delivered in the
4006 same callback. Also if new XDI and protocol code used then jump
4007 direct to finish.
4008 */
4009 if (no_cancel_rc) {
4010 channel_xmit_xon(plci);
4011 goto capi_callback_suffix;
4012 }
4013 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014
Joe Perches475be4d2012-02-19 19:52:38 -08004015 channel_xmit_xon(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016
Joe Perches475be4d2012-02-19 19:52:38 -08004017 if (e->Ind) {
4018 if (e->user[0] & 0x8000) {
4019 byte Ind = e->Ind & 0x0f;
4020 byte Ch = e->IndCh;
4021 if (((Ind == N_DISC) || (Ind == N_DISC_ACK)) &&
4022 (a->ch_flow_plci[Ch] == plci->Id)) {
4023 if (a->ch_flow_control[Ch] & N_RX_FLOW_CONTROL_MASK) {
4024 dbug(3, dprintf("XDI CAPI: I: pending N-XON Ch:%02x", Ch));
4025 }
4026 a->ch_flow_control[Ch] &= ~N_RX_FLOW_CONTROL_MASK;
4027 }
4028 nl_ind(plci);
4029 if ((e->RNR != 1) &&
4030 (a->ch_flow_plci[Ch] == plci->Id) &&
4031 (a->ch_flow_control[Ch] & N_RX_FLOW_CONTROL_MASK)) {
4032 a->ch_flow_control[Ch] &= ~N_RX_FLOW_CONTROL_MASK;
4033 dbug(3, dprintf("XDI CAPI: I: remove faked N-XON Ch:%02x", Ch));
4034 }
4035 } else {
4036 sig_ind(plci);
4037 }
4038 e->Ind = 0;
4039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040
4041capi_callback_suffix:
4042
Joe Perches475be4d2012-02-19 19:52:38 -08004043 while (!plci->req_in
4044 && !plci->internal_command
4045 && (plci->msg_in_write_pos != plci->msg_in_read_pos))
4046 {
4047 j = (plci->msg_in_read_pos == plci->msg_in_wrap_pos) ? 0 : plci->msg_in_read_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048
Joe Perches475be4d2012-02-19 19:52:38 -08004049 i = (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[j]))->header.length + 3) & 0xfffc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050
Joe Perches475be4d2012-02-19 19:52:38 -08004051 m = (CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[j]);
4052 appl = *((APPL **)(&((byte *)(plci->msg_in_queue))[j + i]));
4053 dbug(1, dprintf("dequeue msg(0x%04x) - write=%d read=%d wrap=%d",
4054 m->header.command, plci->msg_in_write_pos, plci->msg_in_read_pos, plci->msg_in_wrap_pos));
4055 if (plci->msg_in_read_pos == plci->msg_in_wrap_pos)
4056 {
4057 plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
4058 plci->msg_in_read_pos = i + MSG_IN_OVERHEAD;
4059 }
4060 else
4061 {
4062 plci->msg_in_read_pos = j + i + MSG_IN_OVERHEAD;
4063 }
4064 if (plci->msg_in_read_pos == plci->msg_in_write_pos)
4065 {
4066 plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE;
4067 plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
4068 }
4069 else if (plci->msg_in_read_pos == plci->msg_in_wrap_pos)
4070 {
4071 plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
4072 plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
4073 }
4074 i = api_put(appl, m);
4075 if (i != 0)
4076 {
4077 if (m->header.command == _DATA_B3_R)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078
Joe Perches475be4d2012-02-19 19:52:38 -08004079 TransmitBufferFree(appl, (byte *)(long)(m->info.data_b3_req.Data));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080
Joe Perches475be4d2012-02-19 19:52:38 -08004081 dbug(1, dprintf("Error 0x%04x from msg(0x%04x)", i, m->header.command));
4082 break;
4083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084
Joe Perches475be4d2012-02-19 19:52:38 -08004085 if (plci->li_notify_update)
4086 {
4087 plci->li_notify_update = false;
4088 mixer_notify_update(plci, false);
4089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090
Joe Perches475be4d2012-02-19 19:52:38 -08004091 }
4092 send_data(plci);
4093 send_req(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094}
4095
4096
Hannes Eder4ee59d52008-12-16 01:17:33 -08004097static void control_rc(PLCI *plci, byte req, byte rc, byte ch, byte global_req,
4098 byte nl_rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099{
Joe Perches475be4d2012-02-19 19:52:38 -08004100 dword Id;
4101 dword rId;
4102 word Number;
4103 word Info = 0;
4104 word i;
4105 word ncci;
4106 DIVA_CAPI_ADAPTER *a;
4107 APPL *appl;
4108 PLCI *rplci;
4109 byte SSparms[] = "\x05\x00\x00\x02\x00\x00";
4110 byte SSstruct[] = "\x09\x00\x00\x06\x00\x00\x00\x00\x00\x00";
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111
Joe Perches475be4d2012-02-19 19:52:38 -08004112 if (!plci) {
4113 dbug(0, dprintf("A: control_rc, no plci %02x:%02x:%02x:%02x:%02x", req, rc, ch, global_req, nl_rc));
4114 return;
4115 }
4116 dbug(1, dprintf("req0_in/out=%d/%d", plci->req_in, plci->req_out));
4117 if (plci->req_in != plci->req_out)
4118 {
4119 if (nl_rc || (global_req != ASSIGN) || (rc == ASSIGN_OK))
4120 {
4121 dbug(1, dprintf("req_1return"));
4122 return;
4123 }
4124 /* cancel outstanding request on the PLCI after SIG ASSIGN failure */
4125 }
4126 plci->req_in = plci->req_in_start = plci->req_out = 0;
4127 dbug(1, dprintf("control_rc"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128
Joe Perches475be4d2012-02-19 19:52:38 -08004129 appl = plci->appl;
4130 a = plci->adapter;
4131 ncci = a->ch_ncci[ch];
4132 if (appl)
4133 {
4134 Id = (((dword)(ncci ? ncci : ch)) << 16) | ((word)plci->Id << 8) | a->Id;
4135 if (plci->tel && plci->SuppState != CALL_HELD) Id |= EXT_CONTROLLER;
4136 Number = plci->number;
4137 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));
4138 dbug(1, dprintf("channels=0x%x", plci->channels));
4139 if (plci_remove_check(plci))
4140 return;
4141 if (req == REMOVE && rc == ASSIGN_OK)
4142 {
4143 sig_req(plci, HANGUP, 0);
4144 sig_req(plci, REMOVE, 0);
4145 send_req(plci);
4146 }
4147 if (plci->command)
4148 {
4149 switch (plci->command)
4150 {
4151 case C_HOLD_REQ:
4152 dbug(1, dprintf("HoldRC=0x%x", rc));
4153 SSparms[1] = (byte)S_HOLD;
4154 if (rc != OK)
4155 {
4156 plci->SuppState = IDLE;
4157 Info = 0x2001;
4158 }
4159 sendf(appl, _FACILITY_R | CONFIRM, Id, Number, "wws", Info, 3, SSparms);
4160 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161
Joe Perches475be4d2012-02-19 19:52:38 -08004162 case C_RETRIEVE_REQ:
4163 dbug(1, dprintf("RetrieveRC=0x%x", rc));
4164 SSparms[1] = (byte)S_RETRIEVE;
4165 if (rc != OK)
4166 {
4167 plci->SuppState = CALL_HELD;
4168 Info = 0x2001;
4169 }
4170 sendf(appl, _FACILITY_R | CONFIRM, Id, Number, "wws", Info, 3, SSparms);
4171 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172
Joe Perches475be4d2012-02-19 19:52:38 -08004173 case _INFO_R:
4174 dbug(1, dprintf("InfoRC=0x%x", rc));
4175 if (rc != OK) Info = _WRONG_STATE;
4176 sendf(appl, _INFO_R | CONFIRM, Id, Number, "w", Info);
4177 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178
Joe Perches475be4d2012-02-19 19:52:38 -08004179 case _CONNECT_R:
4180 dbug(1, dprintf("Connect_R=0x%x/0x%x/0x%x/0x%x", req, rc, global_req, nl_rc));
4181 if (plci->State == INC_DIS_PENDING)
4182 break;
4183 if (plci->Sig.Id != 0xff)
4184 {
4185 if (((global_req == ASSIGN) && (rc != ASSIGN_OK))
4186 || (!nl_rc && (req == CALL_REQ) && (rc != OK)))
4187 {
4188 dbug(1, dprintf("No more IDs/Call_Req failed"));
4189 sendf(appl, _CONNECT_R | CONFIRM, Id & 0xffL, Number, "w", _OUT_OF_PLCI);
4190 plci_remove(plci);
4191 plci->State = IDLE;
4192 break;
4193 }
4194 if (plci->State != LOCAL_CONNECT) plci->State = OUTG_CON_PENDING;
4195 sendf(appl, _CONNECT_R | CONFIRM, Id, Number, "w", 0);
4196 }
4197 else /* D-ch activation */
4198 {
4199 if (rc != ASSIGN_OK)
4200 {
4201 dbug(1, dprintf("No more IDs/X.25 Call_Req failed"));
4202 sendf(appl, _CONNECT_R | CONFIRM, Id & 0xffL, Number, "w", _OUT_OF_PLCI);
4203 plci_remove(plci);
4204 plci->State = IDLE;
4205 break;
4206 }
4207 sendf(appl, _CONNECT_R | CONFIRM, Id, Number, "w", 0);
4208 sendf(plci->appl, _CONNECT_ACTIVE_I, Id, 0, "sss", "", "", "");
4209 plci->State = INC_ACT_PENDING;
4210 }
4211 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212
Joe Perches475be4d2012-02-19 19:52:38 -08004213 case _CONNECT_I | RESPONSE:
4214 if (plci->State != INC_DIS_PENDING)
4215 plci->State = INC_CON_ACCEPT;
4216 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217
Joe Perches475be4d2012-02-19 19:52:38 -08004218 case _DISCONNECT_R:
4219 if (plci->State == INC_DIS_PENDING)
4220 break;
4221 if (plci->Sig.Id != 0xff)
4222 {
4223 plci->State = OUTG_DIS_PENDING;
4224 sendf(appl, _DISCONNECT_R | CONFIRM, Id, Number, "w", 0);
4225 }
4226 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227
Joe Perches475be4d2012-02-19 19:52:38 -08004228 case SUSPEND_REQ:
4229 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230
Joe Perches475be4d2012-02-19 19:52:38 -08004231 case RESUME_REQ:
4232 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233
Joe Perches475be4d2012-02-19 19:52:38 -08004234 case _CONNECT_B3_R:
4235 if (rc != OK)
4236 {
4237 sendf(appl, _CONNECT_B3_R | CONFIRM, Id, Number, "w", _WRONG_IDENTIFIER);
4238 break;
4239 }
4240 ncci = get_ncci(plci, ch, 0);
4241 Id = (Id & 0xffff) | (((dword) ncci) << 16);
4242 plci->channels++;
4243 if (req == N_RESET)
4244 {
4245 a->ncci_state[ncci] = INC_ACT_PENDING;
4246 sendf(appl, _CONNECT_B3_R | CONFIRM, Id, Number, "w", 0);
4247 sendf(appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", "");
4248 }
4249 else
4250 {
4251 a->ncci_state[ncci] = OUTG_CON_PENDING;
4252 sendf(appl, _CONNECT_B3_R | CONFIRM, Id, Number, "w", 0);
4253 }
4254 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255
Joe Perches475be4d2012-02-19 19:52:38 -08004256 case _CONNECT_B3_I | RESPONSE:
4257 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258
Joe Perches475be4d2012-02-19 19:52:38 -08004259 case _RESET_B3_R:
4260/* sendf(appl, _RESET_B3_R | CONFIRM, Id, Number, "w", 0);*/
4261 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262
Joe Perches475be4d2012-02-19 19:52:38 -08004263 case _DISCONNECT_B3_R:
4264 sendf(appl, _DISCONNECT_B3_R | CONFIRM, Id, Number, "w", 0);
4265 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266
Joe Perches475be4d2012-02-19 19:52:38 -08004267 case _MANUFACTURER_R:
4268 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269
Joe Perches475be4d2012-02-19 19:52:38 -08004270 case PERM_LIST_REQ:
4271 if (rc != OK)
4272 {
4273 Info = _WRONG_IDENTIFIER;
4274 sendf(plci->appl, _CONNECT_R | CONFIRM, Id, Number, "w", Info);
4275 plci_remove(plci);
4276 }
4277 else
4278 sendf(plci->appl, _CONNECT_R | CONFIRM, Id, Number, "w", Info);
4279 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280
Joe Perches475be4d2012-02-19 19:52:38 -08004281 default:
4282 break;
4283 }
4284 plci->command = 0;
4285 }
4286 else if (plci->internal_command)
4287 {
4288 switch (plci->internal_command)
4289 {
4290 case BLOCK_PLCI:
4291 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292
Joe Perches475be4d2012-02-19 19:52:38 -08004293 case GET_MWI_STATE:
4294 if (rc == OK) /* command supported, wait for indication */
4295 {
4296 return;
4297 }
4298 plci_remove(plci);
4299 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300
Joe Perches475be4d2012-02-19 19:52:38 -08004301 /* Get Supported Services */
4302 case GETSERV_REQ_PEND:
4303 if (rc == OK) /* command supported, wait for indication */
4304 {
4305 break;
4306 }
4307 PUT_DWORD(&SSstruct[6], MASK_TERMINAL_PORTABILITY);
4308 sendf(appl, _FACILITY_R | CONFIRM, Id, Number, "wws", 0, 3, SSstruct);
4309 plci_remove(plci);
4310 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311
Joe Perches475be4d2012-02-19 19:52:38 -08004312 case INTERR_DIVERSION_REQ_PEND: /* Interrogate Parameters */
4313 case INTERR_NUMBERS_REQ_PEND:
4314 case CF_START_PEND: /* Call Forwarding Start pending */
4315 case CF_STOP_PEND: /* Call Forwarding Stop pending */
4316 case CCBS_REQUEST_REQ_PEND:
4317 case CCBS_DEACTIVATE_REQ_PEND:
4318 case CCBS_INTERROGATE_REQ_PEND:
4319 switch (plci->internal_command)
4320 {
4321 case INTERR_DIVERSION_REQ_PEND:
4322 SSparms[1] = S_INTERROGATE_DIVERSION;
4323 break;
4324 case INTERR_NUMBERS_REQ_PEND:
4325 SSparms[1] = S_INTERROGATE_NUMBERS;
4326 break;
4327 case CF_START_PEND:
4328 SSparms[1] = S_CALL_FORWARDING_START;
4329 break;
4330 case CF_STOP_PEND:
4331 SSparms[1] = S_CALL_FORWARDING_STOP;
4332 break;
4333 case CCBS_REQUEST_REQ_PEND:
4334 SSparms[1] = S_CCBS_REQUEST;
4335 break;
4336 case CCBS_DEACTIVATE_REQ_PEND:
4337 SSparms[1] = S_CCBS_DEACTIVATE;
4338 break;
4339 case CCBS_INTERROGATE_REQ_PEND:
4340 SSparms[1] = S_CCBS_INTERROGATE;
4341 break;
4342 }
4343 if (global_req == ASSIGN)
4344 {
4345 dbug(1, dprintf("AssignDiversion_RC=0x%x/0x%x", req, rc));
4346 return;
4347 }
4348 if (!plci->appl) break;
4349 if (rc == ISDN_GUARD_REJ)
4350 {
4351 Info = _CAPI_GUARD_ERROR;
4352 }
4353 else if (rc != OK)
4354 {
4355 Info = _SUPPLEMENTARY_SERVICE_NOT_SUPPORTED;
4356 }
4357 sendf(plci->appl, _FACILITY_R | CONFIRM, Id & 0x7,
4358 plci->number, "wws", Info, (word)3, SSparms);
4359 if (Info) plci_remove(plci);
4360 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361
Joe Perches475be4d2012-02-19 19:52:38 -08004362 /* 3pty conference pending */
4363 case PTY_REQ_PEND:
4364 if (!plci->relatedPTYPLCI) break;
4365 rplci = plci->relatedPTYPLCI;
4366 SSparms[1] = plci->ptyState;
4367 rId = ((word)rplci->Id << 8) | rplci->adapter->Id;
4368 if (rplci->tel) rId |= EXT_CONTROLLER;
4369 if (rc != OK)
4370 {
4371 Info = 0x300E; /* not supported */
4372 plci->relatedPTYPLCI = NULL;
4373 plci->ptyState = 0;
4374 }
4375 sendf(rplci->appl,
4376 _FACILITY_R | CONFIRM,
4377 rId,
4378 plci->number,
4379 "wws", Info, (word)3, SSparms);
4380 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381
Joe Perches475be4d2012-02-19 19:52:38 -08004382 /* Explicit Call Transfer pending */
4383 case ECT_REQ_PEND:
4384 dbug(1, dprintf("ECT_RC=0x%x/0x%x", req, rc));
4385 if (!plci->relatedPTYPLCI) break;
4386 rplci = plci->relatedPTYPLCI;
4387 SSparms[1] = S_ECT;
4388 rId = ((word)rplci->Id << 8) | rplci->adapter->Id;
4389 if (rplci->tel) rId |= EXT_CONTROLLER;
4390 if (rc != OK)
4391 {
4392 Info = 0x300E; /* not supported */
4393 plci->relatedPTYPLCI = NULL;
4394 plci->ptyState = 0;
4395 }
4396 sendf(rplci->appl,
4397 _FACILITY_R | CONFIRM,
4398 rId,
4399 plci->number,
4400 "wws", Info, (word)3, SSparms);
4401 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402
Joe Perches475be4d2012-02-19 19:52:38 -08004403 case _MANUFACTURER_R:
4404 dbug(1, dprintf("_Manufacturer_R=0x%x/0x%x", req, rc));
4405 if ((global_req == ASSIGN) && (rc != ASSIGN_OK))
4406 {
4407 dbug(1, dprintf("No more IDs"));
4408 sendf(appl, _MANUFACTURER_R | CONFIRM, Id, Number, "dww", _DI_MANU_ID, _MANUFACTURER_R, _OUT_OF_PLCI);
4409 plci_remove(plci); /* after codec init, internal codec commands pending */
4410 }
4411 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412
Joe Perches475be4d2012-02-19 19:52:38 -08004413 case _CONNECT_R:
4414 dbug(1, dprintf("_Connect_R=0x%x/0x%x", req, rc));
4415 if ((global_req == ASSIGN) && (rc != ASSIGN_OK))
4416 {
4417 dbug(1, dprintf("No more IDs"));
4418 sendf(appl, _CONNECT_R | CONFIRM, Id & 0xffL, Number, "w", _OUT_OF_PLCI);
4419 plci_remove(plci); /* after codec init, internal codec commands pending */
4420 }
4421 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422
Joe Perches475be4d2012-02-19 19:52:38 -08004423 case PERM_COD_HOOK: /* finished with Hook_Ind */
4424 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425
Joe Perches475be4d2012-02-19 19:52:38 -08004426 case PERM_COD_CALL:
4427 dbug(1, dprintf("***Codec Connect_Pending A, Rc = 0x%x", rc));
4428 plci->internal_command = PERM_COD_CONN_PEND;
4429 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430
Joe Perches475be4d2012-02-19 19:52:38 -08004431 case PERM_COD_ASSIGN:
4432 dbug(1, dprintf("***Codec Assign A, Rc = 0x%x", rc));
4433 if (rc != ASSIGN_OK) break;
4434 sig_req(plci, CALL_REQ, 0);
4435 send_req(plci);
4436 plci->internal_command = PERM_COD_CALL;
4437 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438
Joe Perches475be4d2012-02-19 19:52:38 -08004439 /* Null Call Reference Request pending */
4440 case C_NCR_FAC_REQ:
4441 dbug(1, dprintf("NCR_FAC=0x%x/0x%x", req, rc));
4442 if (global_req == ASSIGN)
4443 {
4444 if (rc == ASSIGN_OK)
4445 {
4446 return;
4447 }
4448 else
4449 {
4450 sendf(appl, _INFO_R | CONFIRM, Id & 0xf, Number, "w", _WRONG_STATE);
4451 appl->NullCREnable = false;
4452 plci_remove(plci);
4453 }
4454 }
4455 else if (req == NCR_FACILITY)
4456 {
4457 if (rc == OK)
4458 {
4459 sendf(appl, _INFO_R | CONFIRM, Id & 0xf, Number, "w", 0);
4460 }
4461 else
4462 {
4463 sendf(appl, _INFO_R | CONFIRM, Id & 0xf, Number, "w", _WRONG_STATE);
4464 appl->NullCREnable = false;
4465 }
4466 plci_remove(plci);
4467 }
4468 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469
Joe Perches475be4d2012-02-19 19:52:38 -08004470 case HOOK_ON_REQ:
4471 if (plci->channels)
4472 {
4473 if (a->ncci_state[ncci] == CONNECTED)
4474 {
4475 a->ncci_state[ncci] = OUTG_DIS_PENDING;
4476 cleanup_ncci_data(plci, ncci);
4477 nl_req_ncci(plci, N_DISC, (byte)ncci);
4478 }
4479 break;
4480 }
4481 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482
Joe Perches475be4d2012-02-19 19:52:38 -08004483 case HOOK_OFF_REQ:
4484 if (plci->State == INC_DIS_PENDING)
4485 break;
4486 sig_req(plci, CALL_REQ, 0);
4487 send_req(plci);
4488 plci->State = OUTG_CON_PENDING;
4489 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490
4491
Joe Perches475be4d2012-02-19 19:52:38 -08004492 case MWI_ACTIVATE_REQ_PEND:
4493 case MWI_DEACTIVATE_REQ_PEND:
4494 if (global_req == ASSIGN && rc == ASSIGN_OK)
4495 {
4496 dbug(1, dprintf("MWI_REQ assigned"));
4497 return;
4498 }
4499 else if (rc != OK)
4500 {
4501 if (rc == WRONG_IE)
4502 {
4503 Info = 0x2007; /* Illegal message parameter coding */
4504 dbug(1, dprintf("MWI_REQ invalid parameter"));
4505 }
4506 else
4507 {
4508 Info = 0x300B; /* not supported */
4509 dbug(1, dprintf("MWI_REQ not supported"));
4510 }
4511 /* 0x3010: Request not allowed in this state */
4512 PUT_WORD(&SSparms[4], 0x300E); /* SS not supported */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513
Joe Perches475be4d2012-02-19 19:52:38 -08004514 }
4515 if (plci->internal_command == MWI_ACTIVATE_REQ_PEND)
4516 {
4517 PUT_WORD(&SSparms[1], S_MWI_ACTIVATE);
4518 }
4519 else PUT_WORD(&SSparms[1], S_MWI_DEACTIVATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520
Joe Perches475be4d2012-02-19 19:52:38 -08004521 if (plci->cr_enquiry)
4522 {
4523 sendf(plci->appl,
4524 _FACILITY_R | CONFIRM,
4525 Id & 0xf,
4526 plci->number,
4527 "wws", Info, (word)3, SSparms);
4528 if (rc != OK) plci_remove(plci);
4529 }
4530 else
4531 {
4532 sendf(plci->appl,
4533 _FACILITY_R | CONFIRM,
4534 Id,
4535 plci->number,
4536 "wws", Info, (word)3, SSparms);
4537 }
4538 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539
Joe Perches475be4d2012-02-19 19:52:38 -08004540 case CONF_BEGIN_REQ_PEND:
4541 case CONF_ADD_REQ_PEND:
4542 case CONF_SPLIT_REQ_PEND:
4543 case CONF_DROP_REQ_PEND:
4544 case CONF_ISOLATE_REQ_PEND:
4545 case CONF_REATTACH_REQ_PEND:
4546 dbug(1, dprintf("CONF_RC=0x%x/0x%x", req, rc));
4547 if ((plci->internal_command == CONF_ADD_REQ_PEND) && (!plci->relatedPTYPLCI)) break;
4548 rplci = plci;
4549 rId = Id;
4550 switch (plci->internal_command)
4551 {
4552 case CONF_BEGIN_REQ_PEND:
4553 SSparms[1] = S_CONF_BEGIN;
4554 break;
4555 case CONF_ADD_REQ_PEND:
4556 SSparms[1] = S_CONF_ADD;
4557 rplci = plci->relatedPTYPLCI;
4558 rId = ((word)rplci->Id << 8) | rplci->adapter->Id;
4559 break;
4560 case CONF_SPLIT_REQ_PEND:
4561 SSparms[1] = S_CONF_SPLIT;
4562 break;
4563 case CONF_DROP_REQ_PEND:
4564 SSparms[1] = S_CONF_DROP;
4565 break;
4566 case CONF_ISOLATE_REQ_PEND:
4567 SSparms[1] = S_CONF_ISOLATE;
4568 break;
4569 case CONF_REATTACH_REQ_PEND:
4570 SSparms[1] = S_CONF_REATTACH;
4571 break;
4572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573
Joe Perches475be4d2012-02-19 19:52:38 -08004574 if (rc != OK)
4575 {
4576 Info = 0x300E; /* not supported */
4577 plci->relatedPTYPLCI = NULL;
4578 plci->ptyState = 0;
4579 }
4580 sendf(rplci->appl,
4581 _FACILITY_R | CONFIRM,
4582 rId,
4583 plci->number,
4584 "wws", Info, (word)3, SSparms);
4585 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586
Joe Perches475be4d2012-02-19 19:52:38 -08004587 case VSWITCH_REQ_PEND:
4588 if (rc != OK)
4589 {
4590 if (plci->relatedPTYPLCI)
4591 {
4592 plci->relatedPTYPLCI->vswitchstate = 0;
4593 plci->relatedPTYPLCI->vsprot = 0;
4594 plci->relatedPTYPLCI->vsprotdialect = 0;
4595 }
4596 plci->vswitchstate = 0;
4597 plci->vsprot = 0;
4598 plci->vsprotdialect = 0;
4599 }
4600 else
4601 {
4602 if (plci->relatedPTYPLCI &&
4603 plci->vswitchstate == 1 &&
4604 plci->relatedPTYPLCI->vswitchstate == 3) /* join complete */
4605 plci->vswitchstate = 3;
4606 }
4607 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608
Joe Perches475be4d2012-02-19 19:52:38 -08004609 /* Call Deflection Request pending (SSCT) */
4610 case CD_REQ_PEND:
4611 SSparms[1] = S_CALL_DEFLECTION;
4612 if (rc != OK)
4613 {
4614 Info = 0x300E; /* not supported */
4615 plci->appl->CDEnable = 0;
4616 }
4617 sendf(plci->appl, _FACILITY_R | CONFIRM, Id,
4618 plci->number, "wws", Info, (word)3, SSparms);
4619 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620
Joe Perches475be4d2012-02-19 19:52:38 -08004621 case RTP_CONNECT_B3_REQ_COMMAND_2:
4622 if (rc == OK)
4623 {
4624 ncci = get_ncci(plci, ch, 0);
4625 Id = (Id & 0xffff) | (((dword) ncci) << 16);
4626 plci->channels++;
4627 a->ncci_state[ncci] = OUTG_CON_PENDING;
4628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629
Joe Perches475be4d2012-02-19 19:52:38 -08004630 default:
4631 if (plci->internal_command_queue[0])
4632 {
4633 (*(plci->internal_command_queue[0]))(Id, plci, rc);
4634 if (plci->internal_command)
4635 return;
4636 }
4637 break;
4638 }
4639 next_internal_command(Id, plci);
4640 }
4641 }
4642 else /* appl==0 */
4643 {
4644 Id = ((word)plci->Id << 8) | plci->adapter->Id;
4645 if (plci->tel) Id |= EXT_CONTROLLER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646
Joe Perches475be4d2012-02-19 19:52:38 -08004647 switch (plci->internal_command)
4648 {
4649 case BLOCK_PLCI:
4650 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651
Joe Perches475be4d2012-02-19 19:52:38 -08004652 case START_L1_SIG_ASSIGN_PEND:
4653 case REM_L1_SIG_ASSIGN_PEND:
4654 if (global_req == ASSIGN)
4655 {
4656 break;
4657 }
4658 else
4659 {
4660 dbug(1, dprintf("***L1 Req rem PLCI"));
4661 plci->internal_command = 0;
4662 sig_req(plci, REMOVE, 0);
4663 send_req(plci);
4664 }
4665 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666
Joe Perches475be4d2012-02-19 19:52:38 -08004667 /* Call Deflection Request pending, just no appl ptr assigned */
4668 case CD_REQ_PEND:
4669 SSparms[1] = S_CALL_DEFLECTION;
4670 if (rc != OK)
4671 {
4672 Info = 0x300E; /* not supported */
4673 }
4674 for (i = 0; i < max_appl; i++)
4675 {
4676 if (application[i].CDEnable)
4677 {
4678 if (!application[i].Id) application[i].CDEnable = 0;
4679 else
4680 {
4681 sendf(&application[i], _FACILITY_R | CONFIRM, Id,
4682 plci->number, "wws", Info, (word)3, SSparms);
4683 if (Info) application[i].CDEnable = 0;
4684 }
4685 }
4686 }
4687 plci->internal_command = 0;
4688 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689
Joe Perches475be4d2012-02-19 19:52:38 -08004690 case PERM_COD_HOOK: /* finished with Hook_Ind */
4691 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692
Joe Perches475be4d2012-02-19 19:52:38 -08004693 case PERM_COD_CALL:
4694 plci->internal_command = PERM_COD_CONN_PEND;
4695 dbug(1, dprintf("***Codec Connect_Pending, Rc = 0x%x", rc));
4696 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697
Joe Perches475be4d2012-02-19 19:52:38 -08004698 case PERM_COD_ASSIGN:
4699 dbug(1, dprintf("***Codec Assign, Rc = 0x%x", rc));
4700 plci->internal_command = 0;
4701 if (rc != ASSIGN_OK) break;
4702 plci->internal_command = PERM_COD_CALL;
4703 sig_req(plci, CALL_REQ, 0);
4704 send_req(plci);
4705 return;
4706
4707 case LISTEN_SIG_ASSIGN_PEND:
4708 if (rc == ASSIGN_OK)
4709 {
4710 plci->internal_command = 0;
4711 dbug(1, dprintf("ListenCheck, new SIG_ID = 0x%x", plci->Sig.Id));
4712 add_p(plci, ESC, "\x02\x18\x00"); /* support call waiting */
4713 sig_req(plci, INDICATE_REQ, 0);
4714 send_req(plci);
4715 }
4716 else
4717 {
4718 dbug(1, dprintf("ListenCheck failed (assignRc=0x%x)", rc));
4719 a->listen_active--;
4720 plci_remove(plci);
4721 plci->State = IDLE;
4722 }
4723 break;
4724
4725 case USELAW_REQ:
4726 if (global_req == ASSIGN)
4727 {
4728 if (rc == ASSIGN_OK)
4729 {
4730 sig_req(plci, LAW_REQ, 0);
4731 send_req(plci);
4732 dbug(1, dprintf("Auto-Law assigned"));
4733 }
4734 else
4735 {
4736 dbug(1, dprintf("Auto-Law assign failed"));
4737 a->automatic_law = 3;
4738 plci->internal_command = 0;
4739 a->automatic_lawPLCI = NULL;
4740 }
4741 break;
4742 }
4743 else if (req == LAW_REQ && rc == OK)
4744 {
4745 dbug(1, dprintf("Auto-Law initiated"));
4746 a->automatic_law = 2;
4747 plci->internal_command = 0;
4748 }
4749 else
4750 {
4751 dbug(1, dprintf("Auto-Law not supported"));
4752 a->automatic_law = 3;
4753 plci->internal_command = 0;
4754 sig_req(plci, REMOVE, 0);
4755 send_req(plci);
4756 a->automatic_lawPLCI = NULL;
4757 }
4758 break;
4759 }
4760 plci_remove_check(plci);
4761 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762}
4763
Hannes Eder4ee59d52008-12-16 01:17:33 -08004764static void data_rc(PLCI *plci, byte ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765{
Joe Perches475be4d2012-02-19 19:52:38 -08004766 dword Id;
4767 DIVA_CAPI_ADAPTER *a;
4768 NCCI *ncci_ptr;
4769 DATA_B3_DESC *data;
4770 word ncci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771
Joe Perches475be4d2012-02-19 19:52:38 -08004772 if (plci->appl)
4773 {
4774 TransmitBufferFree(plci->appl, plci->data_sent_ptr);
4775 a = plci->adapter;
4776 ncci = a->ch_ncci[ch];
4777 if (ncci && (a->ncci_plci[ncci] == plci->Id))
4778 {
4779 ncci_ptr = &(a->ncci[ncci]);
4780 dbug(1, dprintf("data_out=%d, data_pending=%d", ncci_ptr->data_out, ncci_ptr->data_pending));
4781 if (ncci_ptr->data_pending)
4782 {
4783 data = &(ncci_ptr->DBuffer[ncci_ptr->data_out]);
4784 if (!(data->Flags & 4) && a->ncci_state[ncci])
4785 {
4786 Id = (((dword)ncci) << 16) | ((word)plci->Id << 8) | a->Id;
4787 if (plci->tel) Id |= EXT_CONTROLLER;
4788 sendf(plci->appl, _DATA_B3_R | CONFIRM, Id, data->Number,
4789 "ww", data->Handle, 0);
4790 }
4791 (ncci_ptr->data_out)++;
4792 if (ncci_ptr->data_out == MAX_DATA_B3)
4793 ncci_ptr->data_out = 0;
4794 (ncci_ptr->data_pending)--;
4795 }
4796 }
4797 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798}
4799
Hannes Eder4ee59d52008-12-16 01:17:33 -08004800static void data_ack(PLCI *plci, byte ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801{
Joe Perches475be4d2012-02-19 19:52:38 -08004802 dword Id;
4803 DIVA_CAPI_ADAPTER *a;
4804 NCCI *ncci_ptr;
4805 word ncci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806
Joe Perches475be4d2012-02-19 19:52:38 -08004807 a = plci->adapter;
4808 ncci = a->ch_ncci[ch];
4809 ncci_ptr = &(a->ncci[ncci]);
4810 if (ncci_ptr->data_ack_pending)
4811 {
4812 if (a->ncci_state[ncci] && (a->ncci_plci[ncci] == plci->Id))
4813 {
4814 Id = (((dword)ncci) << 16) | ((word)plci->Id << 8) | a->Id;
4815 if (plci->tel) Id |= EXT_CONTROLLER;
4816 sendf(plci->appl, _DATA_B3_R | CONFIRM, Id, ncci_ptr->DataAck[ncci_ptr->data_ack_out].Number,
4817 "ww", ncci_ptr->DataAck[ncci_ptr->data_ack_out].Handle, 0);
4818 }
4819 (ncci_ptr->data_ack_out)++;
4820 if (ncci_ptr->data_ack_out == MAX_DATA_ACK)
4821 ncci_ptr->data_ack_out = 0;
4822 (ncci_ptr->data_ack_pending)--;
4823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824}
4825
Hannes Eder4ee59d52008-12-16 01:17:33 -08004826static void sig_ind(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827{
Joe Perches475be4d2012-02-19 19:52:38 -08004828 dword x_Id;
4829 dword Id;
4830 dword rId;
4831 word i;
4832 word cip;
4833 dword cip_mask;
4834 byte *ie;
4835 DIVA_CAPI_ADAPTER *a;
4836 API_PARSE saved_parms[MAX_MSG_PARMS + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837#define MAXPARMSIDS 31
Joe Perches475be4d2012-02-19 19:52:38 -08004838 byte *parms[MAXPARMSIDS];
4839 byte *add_i[4];
4840 byte *multi_fac_parms[MAX_MULTI_IE];
4841 byte *multi_pi_parms[MAX_MULTI_IE];
4842 byte *multi_ssext_parms[MAX_MULTI_IE];
4843 byte *multi_CiPN_parms[MAX_MULTI_IE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844
Joe Perches475be4d2012-02-19 19:52:38 -08004845 byte *multi_vswitch_parms[MAX_MULTI_IE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846
Joe Perches475be4d2012-02-19 19:52:38 -08004847 byte ai_len;
4848 byte *esc_chi = "";
4849 byte *esc_law = "";
4850 byte *pty_cai = "";
4851 byte *esc_cr = "";
4852 byte *esc_profile = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853
Joe Perches475be4d2012-02-19 19:52:38 -08004854 byte facility[256];
4855 PLCI *tplci = NULL;
4856 byte chi[] = "\x02\x18\x01";
4857 byte voice_cai[] = "\x06\x14\x00\x00\x00\x00\x08";
4858 byte resume_cau[] = "\x05\x05\x00\x02\x00\x00";
4859 /* ESC_MSGTYPE must be the last but one message, a new IE has to be */
4860 /* included before the ESC_MSGTYPE and MAXPARMSIDS has to be incremented */
4861 /* SMSG is situated at the end because its 0 (for compatibility reasons */
4862 /* (see Info_Mask Bit 4, first IE. then the message type) */
4863 word parms_id[] =
4864 {MAXPARMSIDS, CPN, 0xff, DSA, OSA, BC, LLC, HLC, ESC_CAUSE, DSP, DT, CHA,
4865 UUI, CONG_RR, CONG_RNR, ESC_CHI, KEY, CHI, CAU, ESC_LAW,
4866 RDN, RDX, CONN_NR, RIN, NI, CAI, ESC_CR,
4867 CST, ESC_PROFILE, 0xff, ESC_MSGTYPE, SMSG};
4868 /* 14 FTY repl by ESC_CHI */
4869 /* 18 PI repl by ESC_LAW */
4870 /* removed OAD changed to 0xff for future use, OAD is multiIE now */
4871 word multi_fac_id[] = {1, FTY};
4872 word multi_pi_id[] = {1, PI};
4873 word multi_CiPN_id[] = {1, OAD};
4874 word multi_ssext_id[] = {1, ESC_SSEXT};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875
Joe Perches475be4d2012-02-19 19:52:38 -08004876 word multi_vswitch_id[] = {1, ESC_VSWITCH};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877
Joe Perches475be4d2012-02-19 19:52:38 -08004878 byte *cau;
4879 word ncci;
4880 byte SS_Ind[] = "\x05\x02\x00\x02\x00\x00"; /* Hold_Ind struct*/
4881 byte CF_Ind[] = "\x09\x02\x00\x06\x00\x00\x00\x00\x00\x00";
4882 byte Interr_Err_Ind[] = "\x0a\x02\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
4883 byte CONF_Ind[] = "\x09\x16\x00\x06\x00\x00\0x00\0x00\0x00\0x00";
4884 byte force_mt_info = false;
4885 byte dir;
4886 dword d;
4887 word w;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888
Joe Perches475be4d2012-02-19 19:52:38 -08004889 a = plci->adapter;
4890 Id = ((word)plci->Id << 8) | a->Id;
4891 PUT_WORD(&SS_Ind[4], 0x0000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892
Joe Perches475be4d2012-02-19 19:52:38 -08004893 if (plci->sig_remove_id)
4894 {
4895 plci->Sig.RNR = 2; /* discard */
4896 dbug(1, dprintf("SIG discard while remove pending"));
4897 return;
4898 }
4899 if (plci->tel && plci->SuppState != CALL_HELD) Id |= EXT_CONTROLLER;
4900 dbug(1, dprintf("SigInd-Id=%08lx,plci=%x,tel=%x,state=0x%x,channels=%d,Discflowcl=%d",
4901 Id, plci->Id, plci->tel, plci->State, plci->channels, plci->hangup_flow_ctrl_timer));
4902 if (plci->Sig.Ind == CALL_HOLD_ACK && plci->channels)
4903 {
4904 plci->Sig.RNR = 1;
4905 return;
4906 }
4907 if (plci->Sig.Ind == HANGUP && plci->channels)
4908 {
4909 plci->Sig.RNR = 1;
4910 plci->hangup_flow_ctrl_timer++;
4911 /* recover the network layer after timeout */
4912 if (plci->hangup_flow_ctrl_timer == 100)
4913 {
4914 dbug(1, dprintf("Exceptional disc"));
4915 plci->Sig.RNR = 0;
4916 plci->hangup_flow_ctrl_timer = 0;
4917 for (ncci = 1; ncci < MAX_NCCI + 1; ncci++)
4918 {
4919 if (a->ncci_plci[ncci] == plci->Id)
4920 {
4921 cleanup_ncci_data(plci, ncci);
4922 if (plci->channels)plci->channels--;
4923 if (plci->appl)
4924 sendf(plci->appl, _DISCONNECT_B3_I, (((dword) ncci) << 16) | Id, 0, "ws", 0, "");
4925 }
4926 }
4927 if (plci->appl)
4928 sendf(plci->appl, _DISCONNECT_I, Id, 0, "w", 0);
4929 plci_remove(plci);
4930 plci->State = IDLE;
4931 }
4932 return;
4933 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934
Joe Perches475be4d2012-02-19 19:52:38 -08004935 /* do first parse the info with no OAD in, because OAD will be converted */
4936 /* first the multiple facility IE, then mult. progress ind. */
4937 /* then the parameters for the info_ind + conn_ind */
4938 IndParse(plci, multi_fac_id, multi_fac_parms, MAX_MULTI_IE);
4939 IndParse(plci, multi_pi_id, multi_pi_parms, MAX_MULTI_IE);
4940 IndParse(plci, multi_ssext_id, multi_ssext_parms, MAX_MULTI_IE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941
Joe Perches475be4d2012-02-19 19:52:38 -08004942 IndParse(plci, multi_vswitch_id, multi_vswitch_parms, MAX_MULTI_IE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943
Joe Perches475be4d2012-02-19 19:52:38 -08004944 IndParse(plci, parms_id, parms, 0);
4945 IndParse(plci, multi_CiPN_id, multi_CiPN_parms, MAX_MULTI_IE);
4946 esc_chi = parms[14];
4947 esc_law = parms[18];
4948 pty_cai = parms[24];
4949 esc_cr = parms[25];
4950 esc_profile = parms[27];
4951 if (esc_cr[0] && plci)
4952 {
4953 if (plci->cr_enquiry && plci->appl)
4954 {
4955 plci->cr_enquiry = false;
4956 /* d = MANU_ID */
4957 /* w = m_command */
4958 /* b = total length */
4959 /* b = indication type */
4960 /* b = length of all IEs */
4961 /* b = IE1 */
4962 /* S = IE1 length + cont. */
4963 /* b = IE2 */
4964 /* S = IE2 length + cont. */
4965 sendf(plci->appl,
4966 _MANUFACTURER_I,
4967 Id,
4968 0,
4969 "dwbbbbSbS", _DI_MANU_ID, plci->m_command,
4970 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);
4971 }
4972 }
4973 /* create the additional info structure */
4974 add_i[1] = parms[15]; /* KEY of additional info */
4975 add_i[2] = parms[11]; /* UUI of additional info */
4976 ai_len = AddInfo(add_i, multi_fac_parms, esc_chi, facility);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977
Joe Perches475be4d2012-02-19 19:52:38 -08004978 /* the ESC_LAW indicates if u-Law or a-Law is actually used by the card */
4979 /* indication returns by the card if requested by the function */
4980 /* AutomaticLaw() after driver init */
4981 if (a->automatic_law < 4)
4982 {
4983 if (esc_law[0]) {
4984 if (esc_law[2]) {
4985 dbug(0, dprintf("u-Law selected"));
4986 a->u_law = 1;
4987 }
4988 else {
4989 dbug(0, dprintf("a-Law selected"));
4990 a->u_law = 0;
4991 }
4992 a->automatic_law = 4;
4993 if (plci == a->automatic_lawPLCI) {
4994 plci->internal_command = 0;
4995 sig_req(plci, REMOVE, 0);
4996 send_req(plci);
4997 a->automatic_lawPLCI = NULL;
4998 }
4999 }
5000 if (esc_profile[0])
5001 {
5002 dbug(1, dprintf("[%06x] CardProfile: %lx %lx %lx %lx %lx",
5003 UnMapController(a->Id), GET_DWORD(&esc_profile[6]),
5004 GET_DWORD(&esc_profile[10]), GET_DWORD(&esc_profile[14]),
5005 GET_DWORD(&esc_profile[18]), GET_DWORD(&esc_profile[46])));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006
Joe Perches475be4d2012-02-19 19:52:38 -08005007 a->profile.Global_Options &= 0x000000ffL;
5008 a->profile.B1_Protocols &= 0x000003ffL;
5009 a->profile.B2_Protocols &= 0x00001fdfL;
5010 a->profile.B3_Protocols &= 0x000000b7L;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011
Joe Perches475be4d2012-02-19 19:52:38 -08005012 a->profile.Global_Options &= GET_DWORD(&esc_profile[6]) |
5013 GL_BCHANNEL_OPERATION_SUPPORTED;
5014 a->profile.B1_Protocols &= GET_DWORD(&esc_profile[10]);
5015 a->profile.B2_Protocols &= GET_DWORD(&esc_profile[14]);
5016 a->profile.B3_Protocols &= GET_DWORD(&esc_profile[18]);
5017 a->manufacturer_features = GET_DWORD(&esc_profile[46]);
5018 a->man_profile.private_options = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019
Joe Perches475be4d2012-02-19 19:52:38 -08005020 if (a->manufacturer_features & MANUFACTURER_FEATURE_ECHO_CANCELLER)
5021 {
5022 a->man_profile.private_options |= 1L << PRIVATE_ECHO_CANCELLER;
5023 a->profile.Global_Options |= GL_ECHO_CANCELLER_SUPPORTED;
5024 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025
5026
Joe Perches475be4d2012-02-19 19:52:38 -08005027 if (a->manufacturer_features & MANUFACTURER_FEATURE_RTP)
5028 a->man_profile.private_options |= 1L << PRIVATE_RTP;
5029 a->man_profile.rtp_primary_payloads = GET_DWORD(&esc_profile[50]);
5030 a->man_profile.rtp_additional_payloads = GET_DWORD(&esc_profile[54]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031
5032
Joe Perches475be4d2012-02-19 19:52:38 -08005033 if (a->manufacturer_features & MANUFACTURER_FEATURE_T38)
5034 a->man_profile.private_options |= 1L << PRIVATE_T38;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035
5036
Joe Perches475be4d2012-02-19 19:52:38 -08005037 if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_SUB_SEP_PWD)
5038 a->man_profile.private_options |= 1L << PRIVATE_FAX_SUB_SEP_PWD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039
5040
Joe Perches475be4d2012-02-19 19:52:38 -08005041 if (a->manufacturer_features & MANUFACTURER_FEATURE_V18)
5042 a->man_profile.private_options |= 1L << PRIVATE_V18;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043
5044
Joe Perches475be4d2012-02-19 19:52:38 -08005045 if (a->manufacturer_features & MANUFACTURER_FEATURE_DTMF_TONE)
5046 a->man_profile.private_options |= 1L << PRIVATE_DTMF_TONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047
5048
Joe Perches475be4d2012-02-19 19:52:38 -08005049 if (a->manufacturer_features & MANUFACTURER_FEATURE_PIAFS)
5050 a->man_profile.private_options |= 1L << PRIVATE_PIAFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051
5052
Joe Perches475be4d2012-02-19 19:52:38 -08005053 if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
5054 a->man_profile.private_options |= 1L << PRIVATE_FAX_PAPER_FORMATS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055
5056
Joe Perches475be4d2012-02-19 19:52:38 -08005057 if (a->manufacturer_features & MANUFACTURER_FEATURE_VOWN)
5058 a->man_profile.private_options |= 1L << PRIVATE_VOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059
5060
Joe Perches475be4d2012-02-19 19:52:38 -08005061 if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_NONSTANDARD)
5062 a->man_profile.private_options |= 1L << PRIVATE_FAX_NONSTANDARD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063
Joe Perches475be4d2012-02-19 19:52:38 -08005064 }
5065 else
5066 {
5067 a->profile.Global_Options &= 0x0000007fL;
5068 a->profile.B1_Protocols &= 0x000003dfL;
5069 a->profile.B2_Protocols &= 0x00001adfL;
5070 a->profile.B3_Protocols &= 0x000000b7L;
5071 a->manufacturer_features &= MANUFACTURER_FEATURE_HARDDTMF;
5072 }
5073 if (a->manufacturer_features & (MANUFACTURER_FEATURE_HARDDTMF |
5074 MANUFACTURER_FEATURE_SOFTDTMF_SEND | MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE))
5075 {
5076 a->profile.Global_Options |= GL_DTMF_SUPPORTED;
5077 }
5078 a->manufacturer_features &= ~MANUFACTURER_FEATURE_OOB_CHANNEL;
5079 dbug(1, dprintf("[%06x] Profile: %lx %lx %lx %lx %lx",
5080 UnMapController(a->Id), a->profile.Global_Options,
5081 a->profile.B1_Protocols, a->profile.B2_Protocols,
5082 a->profile.B3_Protocols, a->manufacturer_features));
5083 }
5084 /* codec plci for the handset/hook state support is just an internal id */
5085 if (plci != a->AdvCodecPLCI)
5086 {
5087 force_mt_info = SendMultiIE(plci, Id, multi_fac_parms, FTY, 0x20, 0);
5088 force_mt_info |= SendMultiIE(plci, Id, multi_pi_parms, PI, 0x210, 0);
5089 SendSSExtInd(NULL, plci, Id, multi_ssext_parms);
5090 SendInfo(plci, Id, parms, force_mt_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091
Joe Perches475be4d2012-02-19 19:52:38 -08005092 VSwitchReqInd(plci, Id, multi_vswitch_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093
Joe Perches475be4d2012-02-19 19:52:38 -08005094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095
Joe Perches475be4d2012-02-19 19:52:38 -08005096 /* switch the codec to the b-channel */
5097 if (esc_chi[0] && plci && !plci->SuppState) {
5098 plci->b_channel = esc_chi[esc_chi[0]]&0x1f;
5099 mixer_set_bchannel_id_esc(plci, plci->b_channel);
5100 dbug(1, dprintf("storeChannel=0x%x", plci->b_channel));
5101 if (plci->tel == ADV_VOICE && plci->appl) {
5102 SetVoiceChannel(a->AdvCodecPLCI, esc_chi, a);
5103 }
5104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105
Joe Perches475be4d2012-02-19 19:52:38 -08005106 if (plci->appl) plci->appl->Number++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107
Joe Perches475be4d2012-02-19 19:52:38 -08005108 switch (plci->Sig.Ind) {
5109 /* Response to Get_Supported_Services request */
5110 case S_SUPPORTED:
5111 dbug(1, dprintf("S_Supported"));
5112 if (!plci->appl) break;
5113 if (pty_cai[0] == 4)
5114 {
5115 PUT_DWORD(&CF_Ind[6], GET_DWORD(&pty_cai[1]));
5116 }
5117 else
5118 {
5119 PUT_DWORD(&CF_Ind[6], MASK_TERMINAL_PORTABILITY | MASK_HOLD_RETRIEVE);
5120 }
5121 PUT_WORD(&CF_Ind[1], 0);
5122 PUT_WORD(&CF_Ind[4], 0);
5123 sendf(plci->appl, _FACILITY_R | CONFIRM, Id & 0x7, plci->number, "wws", 0, 3, CF_Ind);
5124 plci_remove(plci);
5125 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126
Joe Perches475be4d2012-02-19 19:52:38 -08005127 /* Supplementary Service rejected */
5128 case S_SERVICE_REJ:
5129 dbug(1, dprintf("S_Reject=0x%x", pty_cai[5]));
5130 if (!pty_cai[0]) break;
5131 switch (pty_cai[5])
5132 {
5133 case ECT_EXECUTE:
5134 case THREE_PTY_END:
5135 case THREE_PTY_BEGIN:
5136 if (!plci->relatedPTYPLCI) break;
5137 tplci = plci->relatedPTYPLCI;
5138 rId = ((word)tplci->Id << 8) | tplci->adapter->Id;
5139 if (tplci->tel) rId |= EXT_CONTROLLER;
5140 if (pty_cai[5] == ECT_EXECUTE)
5141 {
5142 PUT_WORD(&SS_Ind[1], S_ECT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143
Joe Perches475be4d2012-02-19 19:52:38 -08005144 plci->vswitchstate = 0;
5145 plci->relatedPTYPLCI->vswitchstate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146
Joe Perches475be4d2012-02-19 19:52:38 -08005147 }
5148 else
5149 {
5150 PUT_WORD(&SS_Ind[1], pty_cai[5] + 3);
5151 }
5152 if (pty_cai[2] != 0xff)
5153 {
5154 PUT_WORD(&SS_Ind[4], 0x3600 | (word)pty_cai[2]);
5155 }
5156 else
5157 {
5158 PUT_WORD(&SS_Ind[4], 0x300E);
5159 }
5160 plci->relatedPTYPLCI = NULL;
5161 plci->ptyState = 0;
5162 sendf(tplci->appl, _FACILITY_I, rId, 0, "ws", 3, SS_Ind);
5163 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164
Joe Perches475be4d2012-02-19 19:52:38 -08005165 case CALL_DEFLECTION:
5166 if (pty_cai[2] != 0xff)
5167 {
5168 PUT_WORD(&SS_Ind[4], 0x3600 | (word)pty_cai[2]);
5169 }
5170 else
5171 {
5172 PUT_WORD(&SS_Ind[4], 0x300E);
5173 }
5174 PUT_WORD(&SS_Ind[1], pty_cai[5]);
5175 for (i = 0; i < max_appl; i++)
5176 {
5177 if (application[i].CDEnable)
5178 {
5179 if (application[i].Id) sendf(&application[i], _FACILITY_I, Id, 0, "ws", 3, SS_Ind);
5180 application[i].CDEnable = false;
5181 }
5182 }
5183 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184
Joe Perches475be4d2012-02-19 19:52:38 -08005185 case DEACTIVATION_DIVERSION:
5186 case ACTIVATION_DIVERSION:
5187 case DIVERSION_INTERROGATE_CFU:
5188 case DIVERSION_INTERROGATE_CFB:
5189 case DIVERSION_INTERROGATE_CFNR:
5190 case DIVERSION_INTERROGATE_NUM:
5191 case CCBS_REQUEST:
5192 case CCBS_DEACTIVATE:
5193 case CCBS_INTERROGATE:
5194 if (!plci->appl) break;
5195 if (pty_cai[2] != 0xff)
5196 {
5197 PUT_WORD(&Interr_Err_Ind[4], 0x3600 | (word)pty_cai[2]);
5198 }
5199 else
5200 {
5201 PUT_WORD(&Interr_Err_Ind[4], 0x300E);
5202 }
5203 switch (pty_cai[5])
5204 {
5205 case DEACTIVATION_DIVERSION:
5206 dbug(1, dprintf("Deact_Div"));
5207 Interr_Err_Ind[0] = 0x9;
5208 Interr_Err_Ind[3] = 0x6;
5209 PUT_WORD(&Interr_Err_Ind[1], S_CALL_FORWARDING_STOP);
5210 break;
5211 case ACTIVATION_DIVERSION:
5212 dbug(1, dprintf("Act_Div"));
5213 Interr_Err_Ind[0] = 0x9;
5214 Interr_Err_Ind[3] = 0x6;
5215 PUT_WORD(&Interr_Err_Ind[1], S_CALL_FORWARDING_START);
5216 break;
5217 case DIVERSION_INTERROGATE_CFU:
5218 case DIVERSION_INTERROGATE_CFB:
5219 case DIVERSION_INTERROGATE_CFNR:
5220 dbug(1, dprintf("Interr_Div"));
5221 Interr_Err_Ind[0] = 0xa;
5222 Interr_Err_Ind[3] = 0x7;
5223 PUT_WORD(&Interr_Err_Ind[1], S_INTERROGATE_DIVERSION);
5224 break;
5225 case DIVERSION_INTERROGATE_NUM:
5226 dbug(1, dprintf("Interr_Num"));
5227 Interr_Err_Ind[0] = 0xa;
5228 Interr_Err_Ind[3] = 0x7;
5229 PUT_WORD(&Interr_Err_Ind[1], S_INTERROGATE_NUMBERS);
5230 break;
5231 case CCBS_REQUEST:
5232 dbug(1, dprintf("CCBS Request"));
5233 Interr_Err_Ind[0] = 0xd;
5234 Interr_Err_Ind[3] = 0xa;
5235 PUT_WORD(&Interr_Err_Ind[1], S_CCBS_REQUEST);
5236 break;
5237 case CCBS_DEACTIVATE:
5238 dbug(1, dprintf("CCBS Deactivate"));
5239 Interr_Err_Ind[0] = 0x9;
5240 Interr_Err_Ind[3] = 0x6;
5241 PUT_WORD(&Interr_Err_Ind[1], S_CCBS_DEACTIVATE);
5242 break;
5243 case CCBS_INTERROGATE:
5244 dbug(1, dprintf("CCBS Interrogate"));
5245 Interr_Err_Ind[0] = 0xb;
5246 Interr_Err_Ind[3] = 0x8;
5247 PUT_WORD(&Interr_Err_Ind[1], S_CCBS_INTERROGATE);
5248 break;
5249 }
5250 PUT_DWORD(&Interr_Err_Ind[6], plci->appl->S_Handle);
5251 sendf(plci->appl, _FACILITY_I, Id & 0x7, 0, "ws", 3, Interr_Err_Ind);
5252 plci_remove(plci);
5253 break;
5254 case ACTIVATION_MWI:
5255 case DEACTIVATION_MWI:
5256 if (pty_cai[5] == ACTIVATION_MWI)
5257 {
5258 PUT_WORD(&SS_Ind[1], S_MWI_ACTIVATE);
5259 }
5260 else PUT_WORD(&SS_Ind[1], S_MWI_DEACTIVATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261
Joe Perches475be4d2012-02-19 19:52:38 -08005262 if (pty_cai[2] != 0xff)
5263 {
5264 PUT_WORD(&SS_Ind[4], 0x3600 | (word)pty_cai[2]);
5265 }
5266 else
5267 {
5268 PUT_WORD(&SS_Ind[4], 0x300E);
5269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270
Joe Perches475be4d2012-02-19 19:52:38 -08005271 if (plci->cr_enquiry)
5272 {
5273 sendf(plci->appl, _FACILITY_I, Id & 0xf, 0, "ws", 3, SS_Ind);
5274 plci_remove(plci);
5275 }
5276 else
5277 {
5278 sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, SS_Ind);
5279 }
5280 break;
5281 case CONF_ADD: /* ERROR */
5282 case CONF_BEGIN:
5283 case CONF_DROP:
5284 case CONF_ISOLATE:
5285 case CONF_REATTACH:
5286 CONF_Ind[0] = 9;
5287 CONF_Ind[3] = 6;
5288 switch (pty_cai[5])
5289 {
5290 case CONF_BEGIN:
5291 PUT_WORD(&CONF_Ind[1], S_CONF_BEGIN);
5292 plci->ptyState = 0;
5293 break;
5294 case CONF_DROP:
5295 CONF_Ind[0] = 5;
5296 CONF_Ind[3] = 2;
5297 PUT_WORD(&CONF_Ind[1], S_CONF_DROP);
5298 plci->ptyState = CONNECTED;
5299 break;
5300 case CONF_ISOLATE:
5301 CONF_Ind[0] = 5;
5302 CONF_Ind[3] = 2;
5303 PUT_WORD(&CONF_Ind[1], S_CONF_ISOLATE);
5304 plci->ptyState = CONNECTED;
5305 break;
5306 case CONF_REATTACH:
5307 CONF_Ind[0] = 5;
5308 CONF_Ind[3] = 2;
5309 PUT_WORD(&CONF_Ind[1], S_CONF_REATTACH);
5310 plci->ptyState = CONNECTED;
5311 break;
5312 case CONF_ADD:
5313 PUT_WORD(&CONF_Ind[1], S_CONF_ADD);
5314 plci->relatedPTYPLCI = NULL;
5315 tplci = plci->relatedPTYPLCI;
5316 if (tplci) tplci->ptyState = CONNECTED;
5317 plci->ptyState = CONNECTED;
5318 break;
5319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320
Joe Perches475be4d2012-02-19 19:52:38 -08005321 if (pty_cai[2] != 0xff)
5322 {
5323 PUT_WORD(&CONF_Ind[4], 0x3600 | (word)pty_cai[2]);
5324 }
5325 else
5326 {
5327 PUT_WORD(&CONF_Ind[4], 0x3303); /* Time-out: network did not respond
5328 within the required time */
5329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330
Joe Perches475be4d2012-02-19 19:52:38 -08005331 PUT_DWORD(&CONF_Ind[6], 0x0);
5332 sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, CONF_Ind);
5333 break;
5334 }
5335 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336
Joe Perches475be4d2012-02-19 19:52:38 -08005337 /* Supplementary Service indicates success */
5338 case S_SERVICE:
5339 dbug(1, dprintf("Service_Ind"));
5340 PUT_WORD(&CF_Ind[4], 0);
5341 switch (pty_cai[5])
5342 {
5343 case THREE_PTY_END:
5344 case THREE_PTY_BEGIN:
5345 case ECT_EXECUTE:
5346 if (!plci->relatedPTYPLCI) break;
5347 tplci = plci->relatedPTYPLCI;
5348 rId = ((word)tplci->Id << 8) | tplci->adapter->Id;
5349 if (tplci->tel) rId |= EXT_CONTROLLER;
5350 if (pty_cai[5] == ECT_EXECUTE)
5351 {
5352 PUT_WORD(&SS_Ind[1], S_ECT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353
Joe Perches475be4d2012-02-19 19:52:38 -08005354 if (plci->vswitchstate != 3)
5355 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356
Joe Perches475be4d2012-02-19 19:52:38 -08005357 plci->ptyState = IDLE;
5358 plci->relatedPTYPLCI = NULL;
5359 plci->ptyState = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360
Joe Perches475be4d2012-02-19 19:52:38 -08005361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362
Joe Perches475be4d2012-02-19 19:52:38 -08005363 dbug(1, dprintf("ECT OK"));
5364 sendf(tplci->appl, _FACILITY_I, rId, 0, "ws", 3, SS_Ind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367
Joe Perches475be4d2012-02-19 19:52:38 -08005368 }
5369 else
5370 {
5371 switch (plci->ptyState)
5372 {
5373 case S_3PTY_BEGIN:
5374 plci->ptyState = CONNECTED;
5375 dbug(1, dprintf("3PTY ON"));
5376 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377
Joe Perches475be4d2012-02-19 19:52:38 -08005378 case S_3PTY_END:
5379 plci->ptyState = IDLE;
5380 plci->relatedPTYPLCI = NULL;
5381 plci->ptyState = 0;
5382 dbug(1, dprintf("3PTY OFF"));
5383 break;
5384 }
5385 PUT_WORD(&SS_Ind[1], pty_cai[5] + 3);
5386 sendf(tplci->appl, _FACILITY_I, rId, 0, "ws", 3, SS_Ind);
5387 }
5388 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389
Joe Perches475be4d2012-02-19 19:52:38 -08005390 case CALL_DEFLECTION:
5391 PUT_WORD(&SS_Ind[1], pty_cai[5]);
5392 for (i = 0; i < max_appl; i++)
5393 {
5394 if (application[i].CDEnable)
5395 {
5396 if (application[i].Id) sendf(&application[i], _FACILITY_I, Id, 0, "ws", 3, SS_Ind);
5397 application[i].CDEnable = false;
5398 }
5399 }
5400 break;
5401
5402 case DEACTIVATION_DIVERSION:
5403 case ACTIVATION_DIVERSION:
5404 if (!plci->appl) break;
5405 PUT_WORD(&CF_Ind[1], pty_cai[5] + 2);
5406 PUT_DWORD(&CF_Ind[6], plci->appl->S_Handle);
5407 sendf(plci->appl, _FACILITY_I, Id & 0x7, 0, "ws", 3, CF_Ind);
5408 plci_remove(plci);
5409 break;
5410
5411 case DIVERSION_INTERROGATE_CFU:
5412 case DIVERSION_INTERROGATE_CFB:
5413 case DIVERSION_INTERROGATE_CFNR:
5414 case DIVERSION_INTERROGATE_NUM:
5415 case CCBS_REQUEST:
5416 case CCBS_DEACTIVATE:
5417 case CCBS_INTERROGATE:
5418 if (!plci->appl) break;
5419 switch (pty_cai[5])
5420 {
5421 case DIVERSION_INTERROGATE_CFU:
5422 case DIVERSION_INTERROGATE_CFB:
5423 case DIVERSION_INTERROGATE_CFNR:
5424 dbug(1, dprintf("Interr_Div"));
5425 PUT_WORD(&pty_cai[1], S_INTERROGATE_DIVERSION);
5426 pty_cai[3] = pty_cai[0] - 3; /* Supplementary Service-specific parameter len */
5427 break;
5428 case DIVERSION_INTERROGATE_NUM:
5429 dbug(1, dprintf("Interr_Num"));
5430 PUT_WORD(&pty_cai[1], S_INTERROGATE_NUMBERS);
5431 pty_cai[3] = pty_cai[0] - 3; /* Supplementary Service-specific parameter len */
5432 break;
5433 case CCBS_REQUEST:
5434 dbug(1, dprintf("CCBS Request"));
5435 PUT_WORD(&pty_cai[1], S_CCBS_REQUEST);
5436 pty_cai[3] = pty_cai[0] - 3; /* Supplementary Service-specific parameter len */
5437 break;
5438 case CCBS_DEACTIVATE:
5439 dbug(1, dprintf("CCBS Deactivate"));
5440 PUT_WORD(&pty_cai[1], S_CCBS_DEACTIVATE);
5441 pty_cai[3] = pty_cai[0] - 3; /* Supplementary Service-specific parameter len */
5442 break;
5443 case CCBS_INTERROGATE:
5444 dbug(1, dprintf("CCBS Interrogate"));
5445 PUT_WORD(&pty_cai[1], S_CCBS_INTERROGATE);
5446 pty_cai[3] = pty_cai[0] - 3; /* Supplementary Service-specific parameter len */
5447 break;
5448 }
5449 PUT_WORD(&pty_cai[4], 0); /* Supplementary Service Reason */
5450 PUT_DWORD(&pty_cai[6], plci->appl->S_Handle);
5451 sendf(plci->appl, _FACILITY_I, Id & 0x7, 0, "wS", 3, pty_cai);
5452 plci_remove(plci);
5453 break;
5454
5455 case ACTIVATION_MWI:
5456 case DEACTIVATION_MWI:
5457 if (pty_cai[5] == ACTIVATION_MWI)
5458 {
5459 PUT_WORD(&SS_Ind[1], S_MWI_ACTIVATE);
5460 }
5461 else PUT_WORD(&SS_Ind[1], S_MWI_DEACTIVATE);
5462 if (plci->cr_enquiry)
5463 {
5464 sendf(plci->appl, _FACILITY_I, Id & 0xf, 0, "ws", 3, SS_Ind);
5465 plci_remove(plci);
5466 }
5467 else
5468 {
5469 sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, SS_Ind);
5470 }
5471 break;
5472 case MWI_INDICATION:
5473 if (pty_cai[0] >= 0x12)
5474 {
5475 PUT_WORD(&pty_cai[3], S_MWI_INDICATE);
5476 pty_cai[2] = pty_cai[0] - 2; /* len Parameter */
5477 pty_cai[5] = pty_cai[0] - 5; /* Supplementary Service-specific parameter len */
5478 if (plci->appl && (a->Notification_Mask[plci->appl->Id - 1] & SMASK_MWI))
5479 {
5480 if (plci->internal_command == GET_MWI_STATE) /* result on Message Waiting Listen */
5481 {
5482 sendf(plci->appl, _FACILITY_I, Id & 0xf, 0, "wS", 3, &pty_cai[2]);
5483 plci_remove(plci);
5484 return;
5485 }
5486 else sendf(plci->appl, _FACILITY_I, Id, 0, "wS", 3, &pty_cai[2]);
5487 pty_cai[0] = 0;
5488 }
5489 else
5490 {
5491 for (i = 0; i < max_appl; i++)
5492 {
5493 if (a->Notification_Mask[i]&SMASK_MWI)
5494 {
5495 sendf(&application[i], _FACILITY_I, Id & 0x7, 0, "wS", 3, &pty_cai[2]);
5496 pty_cai[0] = 0;
5497 }
5498 }
5499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500
Joe Perches475be4d2012-02-19 19:52:38 -08005501 if (!pty_cai[0])
5502 { /* acknowledge */
5503 facility[2] = 0; /* returncode */
5504 }
5505 else facility[2] = 0xff;
5506 }
5507 else
5508 {
5509 /* reject */
5510 facility[2] = 0xff; /* returncode */
5511 }
5512 facility[0] = 2;
5513 facility[1] = MWI_RESPONSE; /* Function */
5514 add_p(plci, CAI, facility);
5515 add_p(plci, ESC, multi_ssext_parms[0]); /* remembered parameter -> only one possible */
5516 sig_req(plci, S_SERVICE, 0);
5517 send_req(plci);
5518 plci->command = 0;
5519 next_internal_command(Id, plci);
5520 break;
5521 case CONF_ADD: /* OK */
5522 case CONF_BEGIN:
5523 case CONF_DROP:
5524 case CONF_ISOLATE:
5525 case CONF_REATTACH:
5526 case CONF_PARTYDISC:
5527 CONF_Ind[0] = 9;
5528 CONF_Ind[3] = 6;
5529 switch (pty_cai[5])
5530 {
5531 case CONF_BEGIN:
5532 PUT_WORD(&CONF_Ind[1], S_CONF_BEGIN);
5533 if (pty_cai[0] == 6)
5534 {
5535 d = pty_cai[6];
5536 PUT_DWORD(&CONF_Ind[6], d); /* PartyID */
5537 }
5538 else
5539 {
5540 PUT_DWORD(&CONF_Ind[6], 0x0);
5541 }
5542 break;
5543 case CONF_ISOLATE:
5544 PUT_WORD(&CONF_Ind[1], S_CONF_ISOLATE);
5545 CONF_Ind[0] = 5;
5546 CONF_Ind[3] = 2;
5547 break;
5548 case CONF_REATTACH:
5549 PUT_WORD(&CONF_Ind[1], S_CONF_REATTACH);
5550 CONF_Ind[0] = 5;
5551 CONF_Ind[3] = 2;
5552 break;
5553 case CONF_DROP:
5554 PUT_WORD(&CONF_Ind[1], S_CONF_DROP);
5555 CONF_Ind[0] = 5;
5556 CONF_Ind[3] = 2;
5557 break;
5558 case CONF_ADD:
5559 PUT_WORD(&CONF_Ind[1], S_CONF_ADD);
5560 d = pty_cai[6];
5561 PUT_DWORD(&CONF_Ind[6], d); /* PartyID */
5562 tplci = plci->relatedPTYPLCI;
5563 if (tplci) tplci->ptyState = CONNECTED;
5564 break;
5565 case CONF_PARTYDISC:
5566 CONF_Ind[0] = 7;
5567 CONF_Ind[3] = 4;
5568 PUT_WORD(&CONF_Ind[1], S_CONF_PARTYDISC);
5569 d = pty_cai[6];
5570 PUT_DWORD(&CONF_Ind[4], d); /* PartyID */
5571 break;
5572 }
5573 plci->ptyState = CONNECTED;
5574 sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, CONF_Ind);
5575 break;
5576 case CCBS_INFO_RETAIN:
5577 case CCBS_ERASECALLLINKAGEID:
5578 case CCBS_STOP_ALERTING:
5579 CONF_Ind[0] = 5;
5580 CONF_Ind[3] = 2;
5581 switch (pty_cai[5])
5582 {
5583 case CCBS_INFO_RETAIN:
5584 PUT_WORD(&CONF_Ind[1], S_CCBS_INFO_RETAIN);
5585 break;
5586 case CCBS_STOP_ALERTING:
5587 PUT_WORD(&CONF_Ind[1], S_CCBS_STOP_ALERTING);
5588 break;
5589 case CCBS_ERASECALLLINKAGEID:
5590 PUT_WORD(&CONF_Ind[1], S_CCBS_ERASECALLLINKAGEID);
5591 CONF_Ind[0] = 7;
5592 CONF_Ind[3] = 4;
5593 CONF_Ind[6] = 0;
5594 CONF_Ind[7] = 0;
5595 break;
5596 }
5597 w = pty_cai[6];
5598 PUT_WORD(&CONF_Ind[4], w); /* PartyID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599
Joe Perches475be4d2012-02-19 19:52:38 -08005600 if (plci->appl && (a->Notification_Mask[plci->appl->Id - 1] & SMASK_CCBS))
5601 {
5602 sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, CONF_Ind);
5603 }
5604 else
5605 {
5606 for (i = 0; i < max_appl; i++)
5607 if (a->Notification_Mask[i] & SMASK_CCBS)
5608 sendf(&application[i], _FACILITY_I, Id & 0x7, 0, "ws", 3, CONF_Ind);
5609 }
5610 break;
5611 }
5612 break;
5613 case CALL_HOLD_REJ:
5614 cau = parms[7];
5615 if (cau)
5616 {
5617 i = _L3_CAUSE | cau[2];
5618 if (cau[2] == 0) i = 0x3603;
5619 }
5620 else
5621 {
5622 i = 0x3603;
5623 }
5624 PUT_WORD(&SS_Ind[1], S_HOLD);
5625 PUT_WORD(&SS_Ind[4], i);
5626 if (plci->SuppState == HOLD_REQUEST)
5627 {
5628 plci->SuppState = IDLE;
5629 sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, SS_Ind);
5630 }
5631 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632
Joe Perches475be4d2012-02-19 19:52:38 -08005633 case CALL_HOLD_ACK:
5634 if (plci->SuppState == HOLD_REQUEST)
5635 {
5636 plci->SuppState = CALL_HELD;
5637 CodecIdCheck(a, plci);
5638 start_internal_command(Id, plci, hold_save_command);
5639 }
5640 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641
Joe Perches475be4d2012-02-19 19:52:38 -08005642 case CALL_RETRIEVE_REJ:
5643 cau = parms[7];
5644 if (cau)
5645 {
5646 i = _L3_CAUSE | cau[2];
5647 if (cau[2] == 0) i = 0x3603;
5648 }
5649 else
5650 {
5651 i = 0x3603;
5652 }
5653 PUT_WORD(&SS_Ind[1], S_RETRIEVE);
5654 PUT_WORD(&SS_Ind[4], i);
5655 if (plci->SuppState == RETRIEVE_REQUEST)
5656 {
5657 plci->SuppState = CALL_HELD;
5658 CodecIdCheck(a, plci);
5659 sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, SS_Ind);
5660 }
5661 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662
Joe Perches475be4d2012-02-19 19:52:38 -08005663 case CALL_RETRIEVE_ACK:
5664 PUT_WORD(&SS_Ind[1], S_RETRIEVE);
5665 if (plci->SuppState == RETRIEVE_REQUEST)
5666 {
5667 plci->SuppState = IDLE;
5668 plci->call_dir |= CALL_DIR_FORCE_OUTG_NL;
5669 plci->b_channel = esc_chi[esc_chi[0]]&0x1f;
5670 if (plci->tel)
5671 {
5672 mixer_set_bchannel_id_esc(plci, plci->b_channel);
5673 dbug(1, dprintf("RetrChannel=0x%x", plci->b_channel));
5674 SetVoiceChannel(a->AdvCodecPLCI, esc_chi, a);
5675 if (plci->B2_prot == B2_TRANSPARENT && plci->B3_prot == B3_TRANSPARENT)
5676 {
5677 dbug(1, dprintf("Get B-ch"));
5678 start_internal_command(Id, plci, retrieve_restore_command);
5679 }
5680 else
5681 sendf(plci->appl, _FACILITY_I, Id, 0, "ws", 3, SS_Ind);
5682 }
5683 else
5684 start_internal_command(Id, plci, retrieve_restore_command);
5685 }
5686 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687
Joe Perches475be4d2012-02-19 19:52:38 -08005688 case INDICATE_IND:
5689 if (plci->State != LISTENING) {
5690 sig_req(plci, HANGUP, 0);
5691 send_req(plci);
5692 break;
5693 }
5694 cip = find_cip(a, parms[4], parms[6]);
5695 cip_mask = 1L << cip;
5696 dbug(1, dprintf("cip=%d,cip_mask=%lx", cip, cip_mask));
5697 clear_c_ind_mask(plci);
5698 if (!remove_started && !a->adapter_disabled)
5699 {
5700 set_c_ind_mask_bit(plci, MAX_APPL);
5701 group_optimization(a, plci);
5702 for (i = 0; i < max_appl; i++) {
5703 if (application[i].Id
5704 && (a->CIP_Mask[i] & 1 || a->CIP_Mask[i] & cip_mask)
5705 && CPN_filter_ok(parms[0], a, i)
5706 && test_group_ind_mask_bit(plci, i)) {
5707 dbug(1, dprintf("storedcip_mask[%d]=0x%lx", i, a->CIP_Mask[i]));
5708 set_c_ind_mask_bit(plci, i);
5709 dump_c_ind_mask(plci);
5710 plci->State = INC_CON_PENDING;
5711 plci->call_dir = (plci->call_dir & ~(CALL_DIR_OUT | CALL_DIR_ORIGINATE)) |
5712 CALL_DIR_IN | CALL_DIR_ANSWER;
5713 if (esc_chi[0]) {
5714 plci->b_channel = esc_chi[esc_chi[0]] & 0x1f;
5715 mixer_set_bchannel_id_esc(plci, plci->b_channel);
5716 }
5717 /* if a listen on the ext controller is done, check if hook states */
5718 /* are supported or if just a on board codec must be activated */
5719 if (a->codec_listen[i] && !a->AdvSignalPLCI) {
5720 if (a->profile.Global_Options & HANDSET)
5721 plci->tel = ADV_VOICE;
5722 else if (a->profile.Global_Options & ON_BOARD_CODEC)
5723 plci->tel = CODEC;
5724 if (plci->tel) Id |= EXT_CONTROLLER;
5725 a->codec_listen[i] = plci;
5726 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727
Joe Perches475be4d2012-02-19 19:52:38 -08005728 sendf(&application[i], _CONNECT_I, Id, 0,
5729 "wSSSSSSSbSSSSS", cip, /* CIP */
5730 parms[0], /* CalledPartyNumber */
5731 multi_CiPN_parms[0], /* CallingPartyNumber */
5732 parms[2], /* CalledPartySubad */
5733 parms[3], /* CallingPartySubad */
5734 parms[4], /* BearerCapability */
5735 parms[5], /* LowLC */
5736 parms[6], /* HighLC */
5737 ai_len, /* nested struct add_i */
5738 add_i[0], /* B channel info */
5739 add_i[1], /* keypad facility */
5740 add_i[2], /* user user data */
5741 add_i[3], /* nested facility */
5742 multi_CiPN_parms[1] /* second CiPN(SCR) */
5743 );
5744 SendSSExtInd(&application[i],
5745 plci,
5746 Id,
5747 multi_ssext_parms);
5748 SendSetupInfo(&application[i],
5749 plci,
5750 Id,
5751 parms,
5752 SendMultiIE(plci, Id, multi_pi_parms, PI, 0x210, true));
5753 }
5754 }
5755 clear_c_ind_mask_bit(plci, MAX_APPL);
5756 dump_c_ind_mask(plci);
5757 }
5758 if (c_ind_mask_empty(plci)) {
5759 sig_req(plci, HANGUP, 0);
5760 send_req(plci);
5761 plci->State = IDLE;
5762 }
5763 plci->notifiedcall = 0;
5764 a->listen_active--;
5765 listen_check(a);
5766 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767
Joe Perches475be4d2012-02-19 19:52:38 -08005768 case CALL_PEND_NOTIFY:
5769 plci->notifiedcall = 1;
5770 listen_check(a);
5771 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772
Joe Perches475be4d2012-02-19 19:52:38 -08005773 case CALL_IND:
5774 case CALL_CON:
5775 if (plci->State == ADVANCED_VOICE_SIG || plci->State == ADVANCED_VOICE_NOSIG)
5776 {
5777 if (plci->internal_command == PERM_COD_CONN_PEND)
5778 {
5779 if (plci->State == ADVANCED_VOICE_NOSIG)
5780 {
5781 dbug(1, dprintf("***Codec OK"));
5782 if (a->AdvSignalPLCI)
5783 {
5784 tplci = a->AdvSignalPLCI;
5785 if (tplci->spoofed_msg)
5786 {
5787 dbug(1, dprintf("***Spoofed Msg(0x%x)", tplci->spoofed_msg));
5788 tplci->command = 0;
5789 tplci->internal_command = 0;
5790 x_Id = ((word)tplci->Id << 8) | tplci->adapter->Id | 0x80;
5791 switch (tplci->spoofed_msg)
5792 {
5793 case CALL_RES:
5794 tplci->command = _CONNECT_I | RESPONSE;
5795 api_load_msg(&tplci->saved_msg, saved_parms);
5796 add_b1(tplci, &saved_parms[1], 0, tplci->B1_facilities);
5797 if (tplci->adapter->Info_Mask[tplci->appl->Id - 1] & 0x200)
5798 {
5799 /* early B3 connect (CIP mask bit 9) no release after a disc */
5800 add_p(tplci, LLI, "\x01\x01");
5801 }
5802 add_s(tplci, CONN_NR, &saved_parms[2]);
5803 add_s(tplci, LLC, &saved_parms[4]);
5804 add_ai(tplci, &saved_parms[5]);
5805 tplci->State = INC_CON_ACCEPT;
5806 sig_req(tplci, CALL_RES, 0);
5807 send_req(tplci);
5808 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809
Joe Perches475be4d2012-02-19 19:52:38 -08005810 case AWAITING_SELECT_B:
5811 dbug(1, dprintf("Select_B continue"));
5812 start_internal_command(x_Id, tplci, select_b_command);
5813 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814
Joe Perches475be4d2012-02-19 19:52:38 -08005815 case AWAITING_MANUF_CON: /* Get_Plci per Manufacturer_Req to ext controller */
5816 if (!tplci->Sig.Id)
5817 {
5818 dbug(1, dprintf("No SigID!"));
5819 sendf(tplci->appl, _MANUFACTURER_R | CONFIRM, x_Id, tplci->number, "dww", _DI_MANU_ID, _MANUFACTURER_R, _OUT_OF_PLCI);
5820 plci_remove(tplci);
5821 break;
5822 }
5823 tplci->command = _MANUFACTURER_R;
5824 api_load_msg(&tplci->saved_msg, saved_parms);
5825 dir = saved_parms[2].info[0];
5826 if (dir == 1) {
5827 sig_req(tplci, CALL_REQ, 0);
5828 }
5829 else if (!dir) {
5830 sig_req(tplci, LISTEN_REQ, 0);
5831 }
5832 send_req(tplci);
5833 sendf(tplci->appl, _MANUFACTURER_R | CONFIRM, x_Id, tplci->number, "dww", _DI_MANU_ID, _MANUFACTURER_R, 0);
5834 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835
Joe Perches475be4d2012-02-19 19:52:38 -08005836 case (CALL_REQ | AWAITING_MANUF_CON):
5837 sig_req(tplci, CALL_REQ, 0);
5838 send_req(tplci);
5839 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005840
Joe Perches475be4d2012-02-19 19:52:38 -08005841 case CALL_REQ:
5842 if (!tplci->Sig.Id)
5843 {
5844 dbug(1, dprintf("No SigID!"));
5845 sendf(tplci->appl, _CONNECT_R | CONFIRM, tplci->adapter->Id, 0, "w", _OUT_OF_PLCI);
5846 plci_remove(tplci);
5847 break;
5848 }
5849 tplci->command = _CONNECT_R;
5850 api_load_msg(&tplci->saved_msg, saved_parms);
5851 add_s(tplci, CPN, &saved_parms[1]);
5852 add_s(tplci, DSA, &saved_parms[3]);
5853 add_ai(tplci, &saved_parms[9]);
5854 sig_req(tplci, CALL_REQ, 0);
5855 send_req(tplci);
5856 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857
Joe Perches475be4d2012-02-19 19:52:38 -08005858 case CALL_RETRIEVE:
5859 tplci->command = C_RETRIEVE_REQ;
5860 sig_req(tplci, CALL_RETRIEVE, 0);
5861 send_req(tplci);
5862 break;
5863 }
5864 tplci->spoofed_msg = 0;
5865 if (tplci->internal_command == 0)
5866 next_internal_command(x_Id, tplci);
5867 }
5868 }
5869 next_internal_command(Id, plci);
5870 break;
5871 }
5872 dbug(1, dprintf("***Codec Hook Init Req"));
5873 plci->internal_command = PERM_COD_HOOK;
5874 add_p(plci, FTY, "\x01\x09"); /* Get Hook State*/
5875 sig_req(plci, TEL_CTRL, 0);
5876 send_req(plci);
5877 }
5878 }
5879 else if (plci->command != _MANUFACTURER_R /* old style permanent connect */
5880 && plci->State != INC_ACT_PENDING)
5881 {
5882 mixer_set_bchannel_id_esc(plci, plci->b_channel);
5883 if (plci->tel == ADV_VOICE && plci->SuppState == IDLE) /* with permanent codec switch on immediately */
5884 {
5885 chi[2] = plci->b_channel;
5886 SetVoiceChannel(a->AdvCodecPLCI, chi, a);
5887 }
5888 sendf(plci->appl, _CONNECT_ACTIVE_I, Id, 0, "Sss", parms[21], "", "");
5889 plci->State = INC_ACT_PENDING;
5890 }
5891 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892
Joe Perches475be4d2012-02-19 19:52:38 -08005893 case TEL_CTRL:
5894 ie = multi_fac_parms[0]; /* inspect the facility hook indications */
5895 if (plci->State == ADVANCED_VOICE_SIG && ie[0]) {
5896 switch (ie[1] & 0x91) {
5897 case 0x80: /* hook off */
5898 case 0x81:
5899 if (plci->internal_command == PERM_COD_HOOK)
5900 {
5901 dbug(1, dprintf("init:hook_off"));
5902 plci->hook_state = ie[1];
5903 next_internal_command(Id, plci);
5904 break;
5905 }
5906 else /* ignore doubled hook indications */
5907 {
5908 if (((plci->hook_state) & 0xf0) == 0x80)
5909 {
5910 dbug(1, dprintf("ignore hook"));
5911 break;
5912 }
5913 plci->hook_state = ie[1]&0x91;
5914 }
5915 /* check for incoming call pending */
5916 /* and signal '+'.Appl must decide */
5917 /* with connect_res if call must */
5918 /* accepted or not */
5919 for (i = 0, tplci = NULL; i < max_appl; i++) {
5920 if (a->codec_listen[i]
5921 && (a->codec_listen[i]->State == INC_CON_PENDING
5922 || a->codec_listen[i]->State == INC_CON_ALERT)) {
5923 tplci = a->codec_listen[i];
5924 tplci->appl = &application[i];
5925 }
5926 }
5927 /* no incoming call, do outgoing call */
5928 /* and signal '+' if outg. setup */
5929 if (!a->AdvSignalPLCI && !tplci) {
5930 if ((i = get_plci(a))) {
5931 a->AdvSignalPLCI = &a->plci[i - 1];
5932 tplci = a->AdvSignalPLCI;
5933 tplci->tel = ADV_VOICE;
5934 PUT_WORD(&voice_cai[5], a->AdvSignalAppl->MaxDataLength);
5935 if (a->Info_Mask[a->AdvSignalAppl->Id - 1] & 0x200) {
5936 /* early B3 connect (CIP mask bit 9) no release after a disc */
5937 add_p(tplci, LLI, "\x01\x01");
5938 }
5939 add_p(tplci, CAI, voice_cai);
5940 add_p(tplci, OAD, a->TelOAD);
5941 add_p(tplci, OSA, a->TelOSA);
5942 add_p(tplci, SHIFT | 6, NULL);
5943 add_p(tplci, SIN, "\x02\x01\x00");
5944 add_p(tplci, UID, "\x06\x43\x61\x70\x69\x32\x30");
5945 sig_req(tplci, ASSIGN, DSIG_ID);
5946 a->AdvSignalPLCI->internal_command = HOOK_OFF_REQ;
5947 a->AdvSignalPLCI->command = 0;
5948 tplci->appl = a->AdvSignalAppl;
5949 tplci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
5950 send_req(tplci);
5951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952
Joe Perches475be4d2012-02-19 19:52:38 -08005953 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954
Joe Perches475be4d2012-02-19 19:52:38 -08005955 if (!tplci) break;
5956 Id = ((word)tplci->Id << 8) | a->Id;
5957 Id |= EXT_CONTROLLER;
5958 sendf(tplci->appl,
5959 _FACILITY_I,
5960 Id,
5961 0,
5962 "ws", (word)0, "\x01+");
5963 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964
Joe Perches475be4d2012-02-19 19:52:38 -08005965 case 0x90: /* hook on */
5966 case 0x91:
5967 if (plci->internal_command == PERM_COD_HOOK)
5968 {
5969 dbug(1, dprintf("init:hook_on"));
5970 plci->hook_state = ie[1] & 0x91;
5971 next_internal_command(Id, plci);
5972 break;
5973 }
5974 else /* ignore doubled hook indications */
5975 {
5976 if (((plci->hook_state) & 0xf0) == 0x90) break;
5977 plci->hook_state = ie[1] & 0x91;
5978 }
5979 /* hangup the adv. voice call and signal '-' to the appl */
5980 if (a->AdvSignalPLCI) {
5981 Id = ((word)a->AdvSignalPLCI->Id << 8) | a->Id;
5982 if (plci->tel) Id |= EXT_CONTROLLER;
5983 sendf(a->AdvSignalAppl,
5984 _FACILITY_I,
5985 Id,
5986 0,
5987 "ws", (word)0, "\x01-");
5988 a->AdvSignalPLCI->internal_command = HOOK_ON_REQ;
5989 a->AdvSignalPLCI->command = 0;
5990 sig_req(a->AdvSignalPLCI, HANGUP, 0);
5991 send_req(a->AdvSignalPLCI);
5992 }
5993 break;
5994 }
5995 }
5996 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005997
Joe Perches475be4d2012-02-19 19:52:38 -08005998 case RESUME:
5999 clear_c_ind_mask_bit(plci, (word)(plci->appl->Id - 1));
6000 PUT_WORD(&resume_cau[4], GOOD);
6001 sendf(plci->appl, _FACILITY_I, Id, 0, "ws", (word)3, resume_cau);
6002 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006003
Joe Perches475be4d2012-02-19 19:52:38 -08006004 case SUSPEND:
6005 clear_c_ind_mask(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006006
Joe Perches475be4d2012-02-19 19:52:38 -08006007 if (plci->NL.Id && !plci->nl_remove_id) {
6008 mixer_remove(plci);
6009 nl_req_ncci(plci, REMOVE, 0);
6010 }
6011 if (!plci->sig_remove_id) {
6012 plci->internal_command = 0;
6013 sig_req(plci, REMOVE, 0);
6014 }
6015 send_req(plci);
6016 if (!plci->channels) {
6017 sendf(plci->appl, _FACILITY_I, Id, 0, "ws", (word)3, "\x05\x04\x00\x02\x00\x00");
6018 sendf(plci->appl, _DISCONNECT_I, Id, 0, "w", 0);
6019 }
6020 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021
Joe Perches475be4d2012-02-19 19:52:38 -08006022 case SUSPEND_REJ:
6023 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024
Joe Perches475be4d2012-02-19 19:52:38 -08006025 case HANGUP:
6026 plci->hangup_flow_ctrl_timer = 0;
6027 if (plci->manufacturer && plci->State == LOCAL_CONNECT) break;
6028 cau = parms[7];
6029 if (cau) {
6030 i = _L3_CAUSE | cau[2];
6031 if (cau[2] == 0) i = 0;
6032 else if (cau[2] == 8) i = _L1_ERROR;
6033 else if (cau[2] == 9 || cau[2] == 10) i = _L2_ERROR;
6034 else if (cau[2] == 5) i = _CAPI_GUARD_ERROR;
6035 }
6036 else {
6037 i = _L3_ERROR;
6038 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039
Joe Perches475be4d2012-02-19 19:52:38 -08006040 if (plci->State == INC_CON_PENDING || plci->State == INC_CON_ALERT)
6041 {
6042 for (i = 0; i < max_appl; i++)
6043 {
6044 if (test_c_ind_mask_bit(plci, i))
6045 sendf(&application[i], _DISCONNECT_I, Id, 0, "w", 0);
6046 }
6047 }
6048 else
6049 {
6050 clear_c_ind_mask(plci);
6051 }
6052 if (!plci->appl)
6053 {
6054 if (plci->State == LISTENING)
6055 {
6056 plci->notifiedcall = 0;
6057 a->listen_active--;
6058 }
6059 plci->State = INC_DIS_PENDING;
6060 if (c_ind_mask_empty(plci))
6061 {
6062 plci->State = IDLE;
6063 if (plci->NL.Id && !plci->nl_remove_id)
6064 {
6065 mixer_remove(plci);
6066 nl_req_ncci(plci, REMOVE, 0);
6067 }
6068 if (!plci->sig_remove_id)
6069 {
6070 plci->internal_command = 0;
6071 sig_req(plci, REMOVE, 0);
6072 }
6073 send_req(plci);
6074 }
6075 }
6076 else
6077 {
6078 /* collision of DISCONNECT or CONNECT_RES with HANGUP can */
6079 /* result in a second HANGUP! Don't generate another */
6080 /* DISCONNECT */
6081 if (plci->State != IDLE && plci->State != INC_DIS_PENDING)
6082 {
6083 if (plci->State == RESUMING)
6084 {
6085 PUT_WORD(&resume_cau[4], i);
6086 sendf(plci->appl, _FACILITY_I, Id, 0, "ws", (word)3, resume_cau);
6087 }
6088 plci->State = INC_DIS_PENDING;
6089 sendf(plci->appl, _DISCONNECT_I, Id, 0, "w", i);
6090 }
6091 }
6092 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093
Joe Perches475be4d2012-02-19 19:52:38 -08006094 case SSEXT_IND:
6095 SendSSExtInd(NULL, plci, Id, multi_ssext_parms);
6096 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006097
Joe Perches475be4d2012-02-19 19:52:38 -08006098 case VSWITCH_REQ:
6099 VSwitchReqInd(plci, Id, multi_vswitch_parms);
6100 break;
6101 case VSWITCH_IND:
6102 if (plci->relatedPTYPLCI &&
6103 plci->vswitchstate == 3 &&
6104 plci->relatedPTYPLCI->vswitchstate == 3 &&
6105 parms[MAXPARMSIDS - 1][0])
6106 {
6107 add_p(plci->relatedPTYPLCI, SMSG, parms[MAXPARMSIDS - 1]);
6108 sig_req(plci->relatedPTYPLCI, VSWITCH_REQ, 0);
6109 send_req(plci->relatedPTYPLCI);
6110 }
6111 else VSwitchReqInd(plci, Id, multi_vswitch_parms);
6112 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113
Joe Perches475be4d2012-02-19 19:52:38 -08006114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115}
6116
6117
Joe Perches475be4d2012-02-19 19:52:38 -08006118static void SendSetupInfo(APPL *appl, PLCI *plci, dword Id, byte **parms, byte Info_Sent_Flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119{
Joe Perches475be4d2012-02-19 19:52:38 -08006120 word i;
6121 byte *ie;
6122 word Info_Number;
6123 byte *Info_Element;
6124 word Info_Mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125
Joe Perches475be4d2012-02-19 19:52:38 -08006126 dbug(1, dprintf("SetupInfo"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127
Joe Perches475be4d2012-02-19 19:52:38 -08006128 for (i = 0; i < MAXPARMSIDS; i++) {
6129 ie = parms[i];
6130 Info_Number = 0;
6131 Info_Element = ie;
6132 if (ie[0]) {
6133 switch (i) {
6134 case 0:
6135 dbug(1, dprintf("CPN "));
6136 Info_Number = 0x0070;
6137 Info_Mask = 0x80;
6138 Info_Sent_Flag = true;
6139 break;
6140 case 8: /* display */
6141 dbug(1, dprintf("display(%d)", i));
6142 Info_Number = 0x0028;
6143 Info_Mask = 0x04;
6144 Info_Sent_Flag = true;
6145 break;
6146 case 16: /* Channel Id */
6147 dbug(1, dprintf("CHI"));
6148 Info_Number = 0x0018;
6149 Info_Mask = 0x100;
6150 Info_Sent_Flag = true;
6151 mixer_set_bchannel_id(plci, Info_Element);
6152 break;
6153 case 19: /* Redirected Number */
6154 dbug(1, dprintf("RDN"));
6155 Info_Number = 0x0074;
6156 Info_Mask = 0x400;
6157 Info_Sent_Flag = true;
6158 break;
6159 case 20: /* Redirected Number extended */
6160 dbug(1, dprintf("RDX"));
6161 Info_Number = 0x0073;
6162 Info_Mask = 0x400;
6163 Info_Sent_Flag = true;
6164 break;
6165 case 22: /* Redirecing Number */
6166 dbug(1, dprintf("RIN"));
6167 Info_Number = 0x0076;
6168 Info_Mask = 0x400;
6169 Info_Sent_Flag = true;
6170 break;
6171 default:
6172 Info_Number = 0;
6173 break;
6174 }
6175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176
Joe Perches475be4d2012-02-19 19:52:38 -08006177 if (i == MAXPARMSIDS - 2) { /* to indicate the message type "Setup" */
6178 Info_Number = 0x8000 | 5;
6179 Info_Mask = 0x10;
6180 Info_Element = "";
6181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182
Joe Perches475be4d2012-02-19 19:52:38 -08006183 if (Info_Sent_Flag && Info_Number) {
6184 if (plci->adapter->Info_Mask[appl->Id - 1] & Info_Mask) {
6185 sendf(appl, _INFO_I, Id, 0, "wS", Info_Number, Info_Element);
6186 }
6187 }
6188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189}
6190
6191
Hannes Eder4ee59d52008-12-16 01:17:33 -08006192static void SendInfo(PLCI *plci, dword Id, byte **parms, byte iesent)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006193{
Joe Perches475be4d2012-02-19 19:52:38 -08006194 word i;
6195 word j;
6196 word k;
6197 byte *ie;
6198 word Info_Number;
6199 byte *Info_Element;
6200 word Info_Mask = 0;
6201 static byte charges[5] = {4, 0, 0, 0, 0};
6202 static byte cause[] = {0x02, 0x80, 0x00};
6203 APPL *appl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204
Joe Perches475be4d2012-02-19 19:52:38 -08006205 dbug(1, dprintf("InfoParse "));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206
Joe Perches475be4d2012-02-19 19:52:38 -08006207 if (
6208 !plci->appl
6209 && !plci->State
6210 && plci->Sig.Ind != NCR_FACILITY
6211 )
6212 {
6213 dbug(1, dprintf("NoParse "));
6214 return;
6215 }
6216 cause[2] = 0;
6217 for (i = 0; i < MAXPARMSIDS; i++) {
6218 ie = parms[i];
6219 Info_Number = 0;
6220 Info_Element = ie;
6221 if (ie[0]) {
6222 switch (i) {
6223 case 0:
6224 dbug(1, dprintf("CPN "));
6225 Info_Number = 0x0070;
6226 Info_Mask = 0x80;
6227 break;
6228 case 7: /* ESC_CAU */
6229 dbug(1, dprintf("cau(0x%x)", ie[2]));
6230 Info_Number = 0x0008;
6231 Info_Mask = 0x00;
6232 cause[2] = ie[2];
6233 Info_Element = NULL;
6234 break;
6235 case 8: /* display */
6236 dbug(1, dprintf("display(%d)", i));
6237 Info_Number = 0x0028;
6238 Info_Mask = 0x04;
6239 break;
6240 case 9: /* Date display */
6241 dbug(1, dprintf("date(%d)", i));
6242 Info_Number = 0x0029;
6243 Info_Mask = 0x02;
6244 break;
6245 case 10: /* charges */
6246 for (j = 0; j < 4; j++) charges[1 + j] = 0;
6247 for (j = 0; j < ie[0] && !(ie[1 + j] & 0x80); j++);
6248 for (k = 1, j++; j < ie[0] && k <= 4; j++, k++) charges[k] = ie[1 + j];
6249 Info_Number = 0x4000;
6250 Info_Mask = 0x40;
6251 Info_Element = charges;
6252 break;
6253 case 11: /* user user info */
6254 dbug(1, dprintf("uui"));
6255 Info_Number = 0x007E;
6256 Info_Mask = 0x08;
6257 break;
6258 case 12: /* congestion receiver ready */
6259 dbug(1, dprintf("clRDY"));
6260 Info_Number = 0x00B0;
6261 Info_Mask = 0x08;
6262 Info_Element = "";
6263 break;
6264 case 13: /* congestion receiver not ready */
6265 dbug(1, dprintf("clNRDY"));
6266 Info_Number = 0x00BF;
6267 Info_Mask = 0x08;
6268 Info_Element = "";
6269 break;
6270 case 15: /* Keypad Facility */
6271 dbug(1, dprintf("KEY"));
6272 Info_Number = 0x002C;
6273 Info_Mask = 0x20;
6274 break;
6275 case 16: /* Channel Id */
6276 dbug(1, dprintf("CHI"));
6277 Info_Number = 0x0018;
6278 Info_Mask = 0x100;
6279 mixer_set_bchannel_id(plci, Info_Element);
6280 break;
6281 case 17: /* if no 1tr6 cause, send full cause, else esc_cause */
6282 dbug(1, dprintf("q9cau(0x%x)", ie[2]));
6283 if (!cause[2] || cause[2] < 0x80) break; /* eg. layer 1 error */
6284 Info_Number = 0x0008;
6285 Info_Mask = 0x01;
6286 if (cause[2] != ie[2]) Info_Element = cause;
6287 break;
6288 case 19: /* Redirected Number */
6289 dbug(1, dprintf("RDN"));
6290 Info_Number = 0x0074;
6291 Info_Mask = 0x400;
6292 break;
6293 case 22: /* Redirecing Number */
6294 dbug(1, dprintf("RIN"));
6295 Info_Number = 0x0076;
6296 Info_Mask = 0x400;
6297 break;
6298 case 23: /* Notification Indicator */
6299 dbug(1, dprintf("NI"));
6300 Info_Number = (word)NI;
6301 Info_Mask = 0x210;
6302 break;
6303 case 26: /* Call State */
6304 dbug(1, dprintf("CST"));
6305 Info_Number = (word)CST;
6306 Info_Mask = 0x01; /* do with cause i.e. for now */
6307 break;
6308 case MAXPARMSIDS - 2: /* Escape Message Type, must be the last indication */
6309 dbug(1, dprintf("ESC/MT[0x%x]", ie[3]));
6310 Info_Number = 0x8000 | ie[3];
6311 if (iesent) Info_Mask = 0xffff;
6312 else Info_Mask = 0x10;
6313 Info_Element = "";
6314 break;
6315 default:
6316 Info_Number = 0;
6317 Info_Mask = 0;
6318 Info_Element = "";
6319 break;
6320 }
6321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006322
Joe Perches475be4d2012-02-19 19:52:38 -08006323 if (plci->Sig.Ind == NCR_FACILITY) /* check controller broadcast */
6324 {
6325 for (j = 0; j < max_appl; j++)
6326 {
6327 appl = &application[j];
6328 if (Info_Number
6329 && appl->Id
6330 && plci->adapter->Info_Mask[appl->Id - 1] & Info_Mask)
6331 {
6332 dbug(1, dprintf("NCR_Ind"));
6333 iesent = true;
6334 sendf(&application[j], _INFO_I, Id & 0x0f, 0, "wS", Info_Number, Info_Element);
6335 }
6336 }
6337 }
6338 else if (!plci->appl)
6339 { /* overlap receiving broadcast */
6340 if (Info_Number == CPN
6341 || Info_Number == KEY
6342 || Info_Number == NI
6343 || Info_Number == DSP
6344 || Info_Number == UUI)
6345 {
6346 for (j = 0; j < max_appl; j++)
6347 {
6348 if (test_c_ind_mask_bit(plci, j))
6349 {
6350 dbug(1, dprintf("Ovl_Ind"));
6351 iesent = true;
6352 sendf(&application[j], _INFO_I, Id, 0, "wS", Info_Number, Info_Element);
6353 }
6354 }
6355 }
6356 } /* all other signalling states */
6357 else if (Info_Number
6358 && plci->adapter->Info_Mask[plci->appl->Id - 1] & Info_Mask)
6359 {
6360 dbug(1, dprintf("Std_Ind"));
6361 iesent = true;
6362 sendf(plci->appl, _INFO_I, Id, 0, "wS", Info_Number, Info_Element);
6363 }
6364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006365}
6366
6367
Hannes Eder4ee59d52008-12-16 01:17:33 -08006368static byte SendMultiIE(PLCI *plci, dword Id, byte **parms, byte ie_type,
6369 dword info_mask, byte setupParse)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006370{
Joe Perches475be4d2012-02-19 19:52:38 -08006371 word i;
6372 word j;
6373 byte *ie;
6374 word Info_Number;
6375 byte *Info_Element;
6376 APPL *appl;
6377 word Info_Mask = 0;
6378 byte iesent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006379
Joe Perches475be4d2012-02-19 19:52:38 -08006380 if (
6381 !plci->appl
6382 && !plci->State
6383 && plci->Sig.Ind != NCR_FACILITY
6384 && !setupParse
6385 )
6386 {
6387 dbug(1, dprintf("NoM-IEParse "));
6388 return 0;
6389 }
6390 dbug(1, dprintf("M-IEParse "));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391
Joe Perches475be4d2012-02-19 19:52:38 -08006392 for (i = 0; i < MAX_MULTI_IE; i++)
6393 {
6394 ie = parms[i];
6395 Info_Number = 0;
6396 Info_Element = ie;
6397 if (ie[0])
6398 {
6399 dbug(1, dprintf("[Ind0x%x]:IE=0x%x", plci->Sig.Ind, ie_type));
6400 Info_Number = (word)ie_type;
6401 Info_Mask = (word)info_mask;
6402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403
Joe Perches475be4d2012-02-19 19:52:38 -08006404 if (plci->Sig.Ind == NCR_FACILITY) /* check controller broadcast */
6405 {
6406 for (j = 0; j < max_appl; j++)
6407 {
6408 appl = &application[j];
6409 if (Info_Number
6410 && appl->Id
6411 && plci->adapter->Info_Mask[appl->Id - 1] & Info_Mask)
6412 {
6413 iesent = true;
6414 dbug(1, dprintf("Mlt_NCR_Ind"));
6415 sendf(&application[j], _INFO_I, Id & 0x0f, 0, "wS", Info_Number, Info_Element);
6416 }
6417 }
6418 }
6419 else if (!plci->appl && Info_Number)
6420 { /* overlap receiving broadcast */
6421 for (j = 0; j < max_appl; j++)
6422 {
6423 if (test_c_ind_mask_bit(plci, j))
6424 {
6425 iesent = true;
6426 dbug(1, dprintf("Mlt_Ovl_Ind"));
6427 sendf(&application[j] , _INFO_I, Id, 0, "wS", Info_Number, Info_Element);
6428 }
6429 }
6430 } /* all other signalling states */
6431 else if (Info_Number
6432 && plci->adapter->Info_Mask[plci->appl->Id - 1] & Info_Mask)
6433 {
6434 iesent = true;
6435 dbug(1, dprintf("Mlt_Std_Ind"));
6436 sendf(plci->appl, _INFO_I, Id, 0, "wS", Info_Number, Info_Element);
6437 }
6438 }
6439 return iesent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440}
6441
Joe Perches475be4d2012-02-19 19:52:38 -08006442static void SendSSExtInd(APPL *appl, PLCI *plci, dword Id, byte **parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006443{
Joe Perches475be4d2012-02-19 19:52:38 -08006444 word i;
6445 /* Format of multi_ssext_parms[i][]:
6446 0 byte length
6447 1 byte SSEXTIE
6448 2 byte SSEXT_REQ/SSEXT_IND
6449 3 byte length
6450 4 word SSExtCommand
6451 6... Params
6452 */
6453 if (
6454 plci
6455 && plci->State
6456 && plci->Sig.Ind != NCR_FACILITY
6457 )
6458 for (i = 0; i < MAX_MULTI_IE; i++)
6459 {
6460 if (parms[i][0] < 6) continue;
6461 if (parms[i][2] == SSEXT_REQ) continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006462
Joe Perches475be4d2012-02-19 19:52:38 -08006463 if (appl)
6464 {
6465 parms[i][0] = 0; /* kill it */
6466 sendf(appl, _MANUFACTURER_I,
6467 Id,
6468 0,
6469 "dwS",
6470 _DI_MANU_ID,
6471 _DI_SSEXT_CTRL,
6472 &parms[i][3]);
6473 }
6474 else if (plci->appl)
6475 {
6476 parms[i][0] = 0; /* kill it */
6477 sendf(plci->appl, _MANUFACTURER_I,
6478 Id,
6479 0,
6480 "dwS",
6481 _DI_MANU_ID,
6482 _DI_SSEXT_CTRL,
6483 &parms[i][3]);
6484 }
6485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006486};
6487
Hannes Eder4ee59d52008-12-16 01:17:33 -08006488static void nl_ind(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006489{
Joe Perches475be4d2012-02-19 19:52:38 -08006490 byte ch;
6491 word ncci;
6492 dword Id;
6493 DIVA_CAPI_ADAPTER *a;
6494 word NCCIcode;
6495 APPL *APPLptr;
6496 word count;
6497 word Num;
6498 word i, ncpi_state;
6499 byte len, ncci_state;
6500 word msg;
6501 word info = 0;
6502 word fax_feature_bits;
6503 byte fax_send_edata_ack;
6504 static byte v120_header_buffer[2 + 3];
6505 static word fax_info[] = {
6506 0, /* T30_SUCCESS */
6507 _FAX_NO_CONNECTION, /* T30_ERR_NO_DIS_RECEIVED */
6508 _FAX_PROTOCOL_ERROR, /* T30_ERR_TIMEOUT_NO_RESPONSE */
6509 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_RESPONSE */
6510 _FAX_PROTOCOL_ERROR, /* T30_ERR_TOO_MANY_REPEATS */
6511 _FAX_PROTOCOL_ERROR, /* T30_ERR_UNEXPECTED_MESSAGE */
6512 _FAX_REMOTE_ABORT, /* T30_ERR_UNEXPECTED_DCN */
6513 _FAX_LOCAL_ABORT, /* T30_ERR_DTC_UNSUPPORTED */
6514 _FAX_TRAINING_ERROR, /* T30_ERR_ALL_RATES_FAILED */
6515 _FAX_TRAINING_ERROR, /* T30_ERR_TOO_MANY_TRAINS */
6516 _FAX_PARAMETER_ERROR, /* T30_ERR_RECEIVE_CORRUPTED */
6517 _FAX_REMOTE_ABORT, /* T30_ERR_UNEXPECTED_DISC */
6518 _FAX_LOCAL_ABORT, /* T30_ERR_APPLICATION_DISC */
6519 _FAX_REMOTE_REJECT, /* T30_ERR_INCOMPATIBLE_DIS */
6520 _FAX_LOCAL_ABORT, /* T30_ERR_INCOMPATIBLE_DCS */
6521 _FAX_PROTOCOL_ERROR, /* T30_ERR_TIMEOUT_NO_COMMAND */
6522 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_COMMAND */
6523 _FAX_PROTOCOL_ERROR, /* T30_ERR_TIMEOUT_COMMAND_TOO_LONG */
6524 _FAX_PROTOCOL_ERROR, /* T30_ERR_TIMEOUT_RESPONSE_TOO_LONG */
6525 _FAX_NO_CONNECTION, /* T30_ERR_NOT_IDENTIFIED */
6526 _FAX_PROTOCOL_ERROR, /* T30_ERR_SUPERVISORY_TIMEOUT */
6527 _FAX_PARAMETER_ERROR, /* T30_ERR_TOO_LONG_SCAN_LINE */
6528 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_PAGE_AFTER_MPS */
6529 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_PAGE_AFTER_CFR */
6530 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCS_AFTER_FTT */
6531 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCS_AFTER_EOM */
6532 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCS_AFTER_MPS */
6533 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCN_AFTER_MCF */
6534 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCN_AFTER_RTN */
6535 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_CFR */
6536 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_MCF_AFTER_EOP */
6537 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_MCF_AFTER_EOM */
6538 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_MCF_AFTER_MPS */
6539 0x331d, /* T30_ERR_SUB_SEP_UNSUPPORTED */
6540 0x331e, /* T30_ERR_PWD_UNSUPPORTED */
6541 0x331f, /* T30_ERR_SUB_SEP_PWD_UNSUPPORTED */
6542 _FAX_PROTOCOL_ERROR, /* T30_ERR_INVALID_COMMAND_FRAME */
6543 _FAX_PARAMETER_ERROR, /* T30_ERR_UNSUPPORTED_PAGE_CODING */
6544 _FAX_PARAMETER_ERROR, /* T30_ERR_INVALID_PAGE_CODING */
6545 _FAX_REMOTE_REJECT, /* T30_ERR_INCOMPATIBLE_PAGE_CONFIG */
6546 _FAX_LOCAL_ABORT, /* T30_ERR_TIMEOUT_FROM_APPLICATION */
6547 _FAX_PROTOCOL_ERROR, /* T30_ERR_V34FAX_NO_REACTION_ON_MARK */
6548 _FAX_PROTOCOL_ERROR, /* T30_ERR_V34FAX_TRAINING_TIMEOUT */
6549 _FAX_PROTOCOL_ERROR, /* T30_ERR_V34FAX_UNEXPECTED_V21 */
6550 _FAX_PROTOCOL_ERROR, /* T30_ERR_V34FAX_PRIMARY_CTS_ON */
6551 _FAX_LOCAL_ABORT, /* T30_ERR_V34FAX_TURNAROUND_POLLING */
6552 _FAX_LOCAL_ABORT /* T30_ERR_V34FAX_V8_INCOMPATIBILITY */
6553 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006554
Joe Perches475be4d2012-02-19 19:52:38 -08006555 byte dtmf_code_buffer[CAPIDTMF_RECV_DIGIT_BUFFER_SIZE + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006556
6557
Joe Perches475be4d2012-02-19 19:52:38 -08006558 static word rtp_info[] = {
6559 GOOD, /* RTP_SUCCESS */
6560 0x3600 /* RTP_ERR_SSRC_OR_PAYLOAD_CHANGE */
6561 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006562
Joe Perches475be4d2012-02-19 19:52:38 -08006563 static dword udata_forwarding_table[0x100 / sizeof(dword)] =
6564 {
6565 0x0020301e, 0x00000000, 0x00000000, 0x00000000,
6566 0x00000000, 0x00000000, 0x00000000, 0x00000000
6567 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006568
Joe Perches475be4d2012-02-19 19:52:38 -08006569 ch = plci->NL.IndCh;
6570 a = plci->adapter;
6571 ncci = a->ch_ncci[ch];
6572 Id = (((dword)(ncci ? ncci : ch)) << 16) | (((word) plci->Id) << 8) | a->Id;
6573 if (plci->tel) Id |= EXT_CONTROLLER;
6574 APPLptr = plci->appl;
6575 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",
6576 plci->NL.Id, Id, plci->Id, plci->tel, plci->State, ch, plci->channels, plci->NL.Ind & 0x0f));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006577
Joe Perches475be4d2012-02-19 19:52:38 -08006578 /* in the case if no connect_active_Ind was sent to the appl we wait for */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006579
Joe Perches475be4d2012-02-19 19:52:38 -08006580 if (plci->nl_remove_id)
6581 {
6582 plci->NL.RNR = 2; /* discard */
6583 dbug(1, dprintf("NL discard while remove pending"));
6584 return;
6585 }
6586 if ((plci->NL.Ind & 0x0f) == N_CONNECT)
6587 {
6588 if (plci->State == INC_DIS_PENDING
6589 || plci->State == OUTG_DIS_PENDING
6590 || plci->State == IDLE)
6591 {
6592 plci->NL.RNR = 2; /* discard */
6593 dbug(1, dprintf("discard n_connect"));
6594 return;
6595 }
6596 if (plci->State < INC_ACT_PENDING)
6597 {
6598 plci->NL.RNR = 1; /* flow control */
6599 channel_x_off(plci, ch, N_XON_CONNECT_IND);
6600 return;
6601 }
6602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006603
Joe Perches475be4d2012-02-19 19:52:38 -08006604 if (!APPLptr) /* no application or invalid data */
6605 { /* while reloading the DSP */
6606 dbug(1, dprintf("discard1"));
6607 plci->NL.RNR = 2;
6608 return;
6609 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006610
Joe Perches475be4d2012-02-19 19:52:38 -08006611 if (((plci->NL.Ind & 0x0f) == N_UDATA)
6612 && (((plci->B2_prot != B2_SDLC) && ((plci->B1_resource == 17) || (plci->B1_resource == 18)))
6613 || (plci->B2_prot == 7)
6614 || (plci->B3_prot == 7)))
6615 {
6616 plci->ncpi_buffer[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006617
Joe Perches475be4d2012-02-19 19:52:38 -08006618 ncpi_state = plci->ncpi_state;
6619 if (plci->NL.complete == 1)
6620 {
6621 byte *data = &plci->NL.RBuffer->P[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006622
Joe Perches475be4d2012-02-19 19:52:38 -08006623 if ((plci->NL.RBuffer->length >= 12)
6624 && ((*data == DSP_UDATA_INDICATION_DCD_ON)
6625 || (*data == DSP_UDATA_INDICATION_CTS_ON)))
6626 {
6627 word conn_opt, ncpi_opt = 0x00;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006628/* HexDump ("MDM N_UDATA:", plci->NL.RBuffer->length, data); */
6629
Joe Perches475be4d2012-02-19 19:52:38 -08006630 if (*data == DSP_UDATA_INDICATION_DCD_ON)
6631 plci->ncpi_state |= NCPI_MDM_DCD_ON_RECEIVED;
6632 if (*data == DSP_UDATA_INDICATION_CTS_ON)
6633 plci->ncpi_state |= NCPI_MDM_CTS_ON_RECEIVED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006634
Joe Perches475be4d2012-02-19 19:52:38 -08006635 data++; /* indication code */
6636 data += 2; /* timestamp */
6637 if ((*data == DSP_CONNECTED_NORM_V18) || (*data == DSP_CONNECTED_NORM_VOWN))
6638 ncpi_state &= ~(NCPI_MDM_DCD_ON_RECEIVED | NCPI_MDM_CTS_ON_RECEIVED);
6639 data++; /* connected norm */
6640 conn_opt = GET_WORD(data);
6641 data += 2; /* connected options */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006642
Joe Perches475be4d2012-02-19 19:52:38 -08006643 PUT_WORD(&(plci->ncpi_buffer[1]), (word)(GET_DWORD(data) & 0x0000FFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006644
Joe Perches475be4d2012-02-19 19:52:38 -08006645 if (conn_opt & DSP_CONNECTED_OPTION_MASK_V42)
6646 {
6647 ncpi_opt |= MDM_NCPI_ECM_V42;
6648 }
6649 else if (conn_opt & DSP_CONNECTED_OPTION_MASK_MNP)
6650 {
6651 ncpi_opt |= MDM_NCPI_ECM_MNP;
6652 }
6653 else
6654 {
6655 ncpi_opt |= MDM_NCPI_TRANSPARENT;
6656 }
6657 if (conn_opt & DSP_CONNECTED_OPTION_MASK_COMPRESSION)
6658 {
6659 ncpi_opt |= MDM_NCPI_COMPRESSED;
6660 }
6661 PUT_WORD(&(plci->ncpi_buffer[3]), ncpi_opt);
6662 plci->ncpi_buffer[0] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006663
Joe Perches475be4d2012-02-19 19:52:38 -08006664 plci->ncpi_state |= NCPI_VALID_CONNECT_B3_IND | NCPI_VALID_CONNECT_B3_ACT | NCPI_VALID_DISC_B3_IND;
6665 }
6666 }
6667 if (plci->B3_prot == 7)
6668 {
6669 if (((a->ncci_state[ncci] == INC_ACT_PENDING) || (a->ncci_state[ncci] == OUTG_CON_PENDING))
6670 && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
6671 && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
6672 {
6673 a->ncci_state[ncci] = INC_ACT_PENDING;
6674 sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "S", plci->ncpi_buffer);
6675 plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
6676 }
6677 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006678
Joe Perches475be4d2012-02-19 19:52:38 -08006679 if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id - 1])
6680 & ((1L << PRIVATE_V18) | (1L << PRIVATE_VOWN)))
6681 || !(ncpi_state & NCPI_MDM_DCD_ON_RECEIVED)
6682 || !(ncpi_state & NCPI_MDM_CTS_ON_RECEIVED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07006683
Joe Perches475be4d2012-02-19 19:52:38 -08006684 {
6685 plci->NL.RNR = 2;
6686 return;
6687 }
6688 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006689
Joe Perches475be4d2012-02-19 19:52:38 -08006690 if (plci->NL.complete == 2)
6691 {
6692 if (((plci->NL.Ind & 0x0f) == N_UDATA)
6693 && !(udata_forwarding_table[plci->RData[0].P[0] >> 5] & (1L << (plci->RData[0].P[0] & 0x1f))))
6694 {
6695 switch (plci->RData[0].P[0])
6696 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006697
Joe Perches475be4d2012-02-19 19:52:38 -08006698 case DTMF_UDATA_INDICATION_FAX_CALLING_TONE:
6699 if (plci->dtmf_rec_active & DTMF_LISTEN_ACTIVE_FLAG)
6700 sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", SELECTOR_DTMF, "\x01X");
6701 break;
6702 case DTMF_UDATA_INDICATION_ANSWER_TONE:
6703 if (plci->dtmf_rec_active & DTMF_LISTEN_ACTIVE_FLAG)
6704 sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", SELECTOR_DTMF, "\x01Y");
6705 break;
6706 case DTMF_UDATA_INDICATION_DIGITS_RECEIVED:
6707 dtmf_indication(Id, plci, plci->RData[0].P, plci->RData[0].PLength);
6708 break;
6709 case DTMF_UDATA_INDICATION_DIGITS_SENT:
6710 dtmf_confirmation(Id, plci);
6711 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006712
6713
Joe Perches475be4d2012-02-19 19:52:38 -08006714 case UDATA_INDICATION_MIXER_TAP_DATA:
6715 capidtmf_recv_process_block(&(plci->capidtmf_state), plci->RData[0].P + 1, (word)(plci->RData[0].PLength - 1));
6716 i = capidtmf_indication(&(plci->capidtmf_state), dtmf_code_buffer + 1);
6717 if (i != 0)
6718 {
6719 dtmf_code_buffer[0] = DTMF_UDATA_INDICATION_DIGITS_RECEIVED;
6720 dtmf_indication(Id, plci, dtmf_code_buffer, (word)(i + 1));
6721 }
6722 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006723
6724
Joe Perches475be4d2012-02-19 19:52:38 -08006725 case UDATA_INDICATION_MIXER_COEFS_SET:
6726 mixer_indication_coefs_set(Id, plci);
6727 break;
6728 case UDATA_INDICATION_XCONNECT_FROM:
6729 mixer_indication_xconnect_from(Id, plci, plci->RData[0].P, plci->RData[0].PLength);
6730 break;
6731 case UDATA_INDICATION_XCONNECT_TO:
6732 mixer_indication_xconnect_to(Id, plci, plci->RData[0].P, plci->RData[0].PLength);
6733 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006734
6735
Joe Perches475be4d2012-02-19 19:52:38 -08006736 case LEC_UDATA_INDICATION_DISABLE_DETECT:
6737 ec_indication(Id, plci, plci->RData[0].P, plci->RData[0].PLength);
6738 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006739
6740
6741
Joe Perches475be4d2012-02-19 19:52:38 -08006742 default:
6743 break;
6744 }
6745 }
6746 else
6747 {
6748 if ((plci->RData[0].PLength != 0)
6749 && ((plci->B2_prot == B2_V120_ASYNC)
6750 || (plci->B2_prot == B2_V120_ASYNC_V42BIS)
6751 || (plci->B2_prot == B2_V120_BIT_TRANSPARENT)))
6752 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006753
Joe Perches475be4d2012-02-19 19:52:38 -08006754 sendf(plci->appl, _DATA_B3_I, Id, 0,
6755 "dwww",
6756 plci->RData[1].P,
6757 (plci->NL.RNum < 2) ? 0 : plci->RData[1].PLength,
6758 plci->RNum,
6759 plci->RFlags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006760
Joe Perches475be4d2012-02-19 19:52:38 -08006761 }
6762 else
6763 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006764
Joe Perches475be4d2012-02-19 19:52:38 -08006765 sendf(plci->appl, _DATA_B3_I, Id, 0,
6766 "dwww",
6767 plci->RData[0].P,
6768 plci->RData[0].PLength,
6769 plci->RNum,
6770 plci->RFlags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006771
Joe Perches475be4d2012-02-19 19:52:38 -08006772 }
6773 }
6774 return;
6775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006776
Joe Perches475be4d2012-02-19 19:52:38 -08006777 fax_feature_bits = 0;
6778 if ((plci->NL.Ind & 0x0f) == N_CONNECT ||
6779 (plci->NL.Ind & 0x0f) == N_CONNECT_ACK ||
6780 (plci->NL.Ind & 0x0f) == N_DISC ||
6781 (plci->NL.Ind & 0x0f) == N_EDATA ||
6782 (plci->NL.Ind & 0x0f) == N_DISC_ACK)
6783 {
6784 info = 0;
6785 plci->ncpi_buffer[0] = 0;
6786 switch (plci->B3_prot) {
6787 case 0: /*XPARENT*/
6788 case 1: /*T.90 NL*/
6789 break; /* no network control protocol info - jfr */
6790 case 2: /*ISO8202*/
6791 case 3: /*X25 DCE*/
6792 for (i = 0; i < plci->NL.RLength; i++) plci->ncpi_buffer[4 + i] = plci->NL.RBuffer->P[i];
6793 plci->ncpi_buffer[0] = (byte)(i + 3);
6794 plci->ncpi_buffer[1] = (byte)(plci->NL.Ind & N_D_BIT ? 1 : 0);
6795 plci->ncpi_buffer[2] = 0;
6796 plci->ncpi_buffer[3] = 0;
6797 break;
6798 case 4: /*T.30 - FAX*/
6799 case 5: /*T.30 - FAX*/
6800 if (plci->NL.RLength >= sizeof(T30_INFO))
6801 {
6802 dbug(1, dprintf("FaxStatus %04x", ((T30_INFO *)plci->NL.RBuffer->P)->code));
6803 len = 9;
6804 PUT_WORD(&(plci->ncpi_buffer[1]), ((T30_INFO *)plci->NL.RBuffer->P)->rate_div_2400 * 2400);
6805 fax_feature_bits = GET_WORD(&((T30_INFO *)plci->NL.RBuffer->P)->feature_bits_low);
6806 i = (((T30_INFO *)plci->NL.RBuffer->P)->resolution & T30_RESOLUTION_R8_0770_OR_200) ? 0x0001 : 0x0000;
6807 if (plci->B3_prot == 5)
6808 {
6809 if (!(fax_feature_bits & T30_FEATURE_BIT_ECM))
6810 i |= 0x8000; /* This is not an ECM connection */
6811 if (fax_feature_bits & T30_FEATURE_BIT_T6_CODING)
6812 i |= 0x4000; /* This is a connection with MMR compression */
6813 if (fax_feature_bits & T30_FEATURE_BIT_2D_CODING)
6814 i |= 0x2000; /* This is a connection with MR compression */
6815 if (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS)
6816 i |= 0x0004; /* More documents */
6817 if (fax_feature_bits & T30_FEATURE_BIT_POLLING)
6818 i |= 0x0002; /* Fax-polling indication */
6819 }
6820 dbug(1, dprintf("FAX Options %04x %04x", fax_feature_bits, i));
6821 PUT_WORD(&(plci->ncpi_buffer[3]), i);
6822 PUT_WORD(&(plci->ncpi_buffer[5]), ((T30_INFO *)plci->NL.RBuffer->P)->data_format);
6823 plci->ncpi_buffer[7] = ((T30_INFO *)plci->NL.RBuffer->P)->pages_low;
6824 plci->ncpi_buffer[8] = ((T30_INFO *)plci->NL.RBuffer->P)->pages_high;
6825 plci->ncpi_buffer[len] = 0;
6826 if (((T30_INFO *)plci->NL.RBuffer->P)->station_id_len)
6827 {
6828 plci->ncpi_buffer[len] = 20;
6829 for (i = 0; i < T30_MAX_STATION_ID_LENGTH; i++)
6830 plci->ncpi_buffer[++len] = ((T30_INFO *)plci->NL.RBuffer->P)->station_id[i];
6831 }
6832 if (((plci->NL.Ind & 0x0f) == N_DISC) || ((plci->NL.Ind & 0x0f) == N_DISC_ACK))
6833 {
6834 if (((T30_INFO *)plci->NL.RBuffer->P)->code < ARRAY_SIZE(fax_info))
6835 info = fax_info[((T30_INFO *)plci->NL.RBuffer->P)->code];
6836 else
6837 info = _FAX_PROTOCOL_ERROR;
6838 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006839
Joe Perches475be4d2012-02-19 19:52:38 -08006840 if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id - 1])
6841 & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
6842 {
6843 i = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + ((T30_INFO *)plci->NL.RBuffer->P)->head_line_len;
6844 while (i < plci->NL.RBuffer->length)
6845 plci->ncpi_buffer[++len] = plci->NL.RBuffer->P[i++];
6846 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006847
Joe Perches475be4d2012-02-19 19:52:38 -08006848 plci->ncpi_buffer[0] = len;
6849 fax_feature_bits = GET_WORD(&((T30_INFO *)plci->NL.RBuffer->P)->feature_bits_low);
6850 PUT_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->feature_bits_low, fax_feature_bits);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006851
Joe Perches475be4d2012-02-19 19:52:38 -08006852 plci->ncpi_state |= NCPI_VALID_CONNECT_B3_IND;
6853 if (((plci->NL.Ind & 0x0f) == N_CONNECT_ACK)
6854 || (((plci->NL.Ind & 0x0f) == N_CONNECT)
6855 && (fax_feature_bits & T30_FEATURE_BIT_POLLING))
6856 || (((plci->NL.Ind & 0x0f) == N_EDATA)
6857 && ((((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_TRAIN_OK)
6858 || (((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_DIS)
6859 || (((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_DTC))))
6860 {
6861 plci->ncpi_state |= NCPI_VALID_CONNECT_B3_ACT;
6862 }
6863 if (((plci->NL.Ind & 0x0f) == N_DISC)
6864 || ((plci->NL.Ind & 0x0f) == N_DISC_ACK)
6865 || (((plci->NL.Ind & 0x0f) == N_EDATA)
6866 && (((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_EOP_CAPI)))
6867 {
6868 plci->ncpi_state |= NCPI_VALID_CONNECT_B3_ACT | NCPI_VALID_DISC_B3_IND;
6869 }
6870 }
6871 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006872
Joe Perches475be4d2012-02-19 19:52:38 -08006873 case B3_RTP:
6874 if (((plci->NL.Ind & 0x0f) == N_DISC) || ((plci->NL.Ind & 0x0f) == N_DISC_ACK))
6875 {
6876 if (plci->NL.RLength != 0)
6877 {
6878 info = rtp_info[plci->NL.RBuffer->P[0]];
6879 plci->ncpi_buffer[0] = plci->NL.RLength - 1;
6880 for (i = 1; i < plci->NL.RLength; i++)
6881 plci->ncpi_buffer[i] = plci->NL.RBuffer->P[i];
6882 }
6883 }
6884 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006885
Joe Perches475be4d2012-02-19 19:52:38 -08006886 }
6887 plci->NL.RNR = 2;
6888 }
6889 switch (plci->NL.Ind & 0x0f) {
6890 case N_EDATA:
6891 if ((plci->B3_prot == 4) || (plci->B3_prot == 5))
6892 {
6893 dbug(1, dprintf("EDATA ncci=0x%x state=%d code=%02x", ncci, a->ncci_state[ncci],
6894 ((T30_INFO *)plci->NL.RBuffer->P)->code));
6895 fax_send_edata_ack = (((T30_INFO *)(plci->fax_connect_info_buffer))->operating_mode == T30_OPERATING_MODE_CAPI_NEG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006896
Joe Perches475be4d2012-02-19 19:52:38 -08006897 if ((plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF)
6898 && (plci->nsf_control_bits & (T30_NSF_CONTROL_BIT_NEGOTIATE_IND | T30_NSF_CONTROL_BIT_NEGOTIATE_RESP))
6899 && (((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_DIS)
6900 && (a->ncci_state[ncci] == OUTG_CON_PENDING)
6901 && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
6902 && !(plci->ncpi_state & NCPI_NEGOTIATE_B3_SENT))
6903 {
6904 ((T30_INFO *)(plci->fax_connect_info_buffer))->code = ((T30_INFO *)plci->NL.RBuffer->P)->code;
6905 sendf(plci->appl, _MANUFACTURER_I, Id, 0, "dwbS", _DI_MANU_ID, _DI_NEGOTIATE_B3,
6906 (byte)(plci->ncpi_buffer[0] + 1), plci->ncpi_buffer);
6907 plci->ncpi_state |= NCPI_NEGOTIATE_B3_SENT;
6908 if (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP)
6909 fax_send_edata_ack = false;
6910 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006911
Joe Perches475be4d2012-02-19 19:52:38 -08006912 if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
6913 {
6914 switch (((T30_INFO *)plci->NL.RBuffer->P)->code)
6915 {
6916 case EDATA_T30_DIS:
6917 if ((a->ncci_state[ncci] == OUTG_CON_PENDING)
6918 && !(GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low) & T30_CONTROL_BIT_REQUEST_POLLING)
6919 && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
6920 && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
6921 {
6922 a->ncci_state[ncci] = INC_ACT_PENDING;
6923 if (plci->B3_prot == 4)
6924 sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", "");
6925 else
6926 sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "S", plci->ncpi_buffer);
6927 plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
6928 }
6929 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006930
Joe Perches475be4d2012-02-19 19:52:38 -08006931 case EDATA_T30_TRAIN_OK:
6932 if ((a->ncci_state[ncci] == INC_ACT_PENDING)
6933 && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
6934 && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
6935 {
6936 if (plci->B3_prot == 4)
6937 sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", "");
6938 else
6939 sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "S", plci->ncpi_buffer);
6940 plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
6941 }
6942 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006943
Joe Perches475be4d2012-02-19 19:52:38 -08006944 case EDATA_T30_EOP_CAPI:
6945 if (a->ncci_state[ncci] == CONNECTED)
6946 {
6947 sendf(plci->appl, _DISCONNECT_B3_I, Id, 0, "wS", GOOD, plci->ncpi_buffer);
6948 a->ncci_state[ncci] = INC_DIS_PENDING;
6949 plci->ncpi_state = 0;
6950 fax_send_edata_ack = false;
6951 }
6952 break;
6953 }
6954 }
6955 else
6956 {
6957 switch (((T30_INFO *)plci->NL.RBuffer->P)->code)
6958 {
6959 case EDATA_T30_TRAIN_OK:
6960 if ((a->ncci_state[ncci] == INC_ACT_PENDING)
6961 && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
6962 && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
6963 {
6964 if (plci->B3_prot == 4)
6965 sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", "");
6966 else
6967 sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "S", plci->ncpi_buffer);
6968 plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
6969 }
6970 break;
6971 }
6972 }
6973 if (fax_send_edata_ack)
6974 {
6975 ((T30_INFO *)(plci->fax_connect_info_buffer))->code = ((T30_INFO *)plci->NL.RBuffer->P)->code;
6976 plci->fax_edata_ack_length = 1;
6977 start_internal_command(Id, plci, fax_edata_ack_command);
6978 }
6979 }
6980 else
6981 {
6982 dbug(1, dprintf("EDATA ncci=0x%x state=%d", ncci, a->ncci_state[ncci]));
6983 }
6984 break;
6985 case N_CONNECT:
6986 if (!a->ch_ncci[ch])
6987 {
6988 ncci = get_ncci(plci, ch, 0);
6989 Id = (Id & 0xffff) | (((dword) ncci) << 16);
6990 }
6991 dbug(1, dprintf("N_CONNECT: ch=%d state=%d plci=%lx plci_Id=%lx plci_State=%d",
6992 ch, a->ncci_state[ncci], a->ncci_plci[ncci], plci->Id, plci->State));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006993
Joe Perches475be4d2012-02-19 19:52:38 -08006994 msg = _CONNECT_B3_I;
6995 if (a->ncci_state[ncci] == IDLE)
6996 plci->channels++;
6997 else if (plci->B3_prot == 1)
6998 msg = _CONNECT_B3_T90_ACTIVE_I;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006999
Joe Perches475be4d2012-02-19 19:52:38 -08007000 a->ncci_state[ncci] = INC_CON_PENDING;
7001 if (plci->B3_prot == 4)
7002 sendf(plci->appl, msg, Id, 0, "s", "");
7003 else
7004 sendf(plci->appl, msg, Id, 0, "S", plci->ncpi_buffer);
7005 break;
7006 case N_CONNECT_ACK:
7007 dbug(1, dprintf("N_connect_Ack"));
7008 if (plci->internal_command_queue[0]
7009 && ((plci->adjust_b_state == ADJUST_B_CONNECT_2)
7010 || (plci->adjust_b_state == ADJUST_B_CONNECT_3)
7011 || (plci->adjust_b_state == ADJUST_B_CONNECT_4)))
7012 {
7013 (*(plci->internal_command_queue[0]))(Id, plci, 0);
7014 if (!plci->internal_command)
7015 next_internal_command(Id, plci);
7016 break;
7017 }
7018 msg = _CONNECT_B3_ACTIVE_I;
7019 if (plci->B3_prot == 1)
7020 {
7021 if (a->ncci_state[ncci] != OUTG_CON_PENDING)
7022 msg = _CONNECT_B3_T90_ACTIVE_I;
7023 a->ncci_state[ncci] = INC_ACT_PENDING;
7024 sendf(plci->appl, msg, Id, 0, "S", plci->ncpi_buffer);
7025 }
7026 else if ((plci->B3_prot == 4) || (plci->B3_prot == 5) || (plci->B3_prot == 7))
7027 {
7028 if ((a->ncci_state[ncci] == OUTG_CON_PENDING)
7029 && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
7030 && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
7031 {
7032 a->ncci_state[ncci] = INC_ACT_PENDING;
7033 if (plci->B3_prot == 4)
7034 sendf(plci->appl, msg, Id, 0, "s", "");
7035 else
7036 sendf(plci->appl, msg, Id, 0, "S", plci->ncpi_buffer);
7037 plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
7038 }
7039 }
7040 else
7041 {
7042 a->ncci_state[ncci] = INC_ACT_PENDING;
7043 sendf(plci->appl, msg, Id, 0, "S", plci->ncpi_buffer);
7044 }
7045 if (plci->adjust_b_restore)
7046 {
7047 plci->adjust_b_restore = false;
7048 start_internal_command(Id, plci, adjust_b_restore);
7049 }
7050 break;
7051 case N_DISC:
7052 case N_DISC_ACK:
7053 if (plci->internal_command_queue[0]
7054 && ((plci->internal_command == FAX_DISCONNECT_COMMAND_1)
7055 || (plci->internal_command == FAX_DISCONNECT_COMMAND_2)
7056 || (plci->internal_command == FAX_DISCONNECT_COMMAND_3)))
7057 {
7058 (*(plci->internal_command_queue[0]))(Id, plci, 0);
7059 if (!plci->internal_command)
7060 next_internal_command(Id, plci);
7061 }
7062 ncci_state = a->ncci_state[ncci];
7063 ncci_remove(plci, ncci, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007064
Joe Perches475be4d2012-02-19 19:52:38 -08007065 /* with N_DISC or N_DISC_ACK the IDI frees the respective */
7066 /* channel, so we cannot store the state in ncci_state! The */
7067 /* information which channel we received a N_DISC is thus */
7068 /* stored in the inc_dis_ncci_table buffer. */
7069 for (i = 0; plci->inc_dis_ncci_table[i]; i++);
7070 plci->inc_dis_ncci_table[i] = (byte) ncci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007071
Joe Perches475be4d2012-02-19 19:52:38 -08007072 /* need a connect_b3_ind before a disconnect_b3_ind with FAX */
7073 if (!plci->channels
7074 && (plci->B1_resource == 16)
7075 && (plci->State <= CONNECTED))
7076 {
7077 len = 9;
7078 i = ((T30_INFO *)plci->fax_connect_info_buffer)->rate_div_2400 * 2400;
7079 PUT_WORD(&plci->ncpi_buffer[1], i);
7080 PUT_WORD(&plci->ncpi_buffer[3], 0);
7081 i = ((T30_INFO *)plci->fax_connect_info_buffer)->data_format;
7082 PUT_WORD(&plci->ncpi_buffer[5], i);
7083 PUT_WORD(&plci->ncpi_buffer[7], 0);
7084 plci->ncpi_buffer[len] = 0;
7085 plci->ncpi_buffer[0] = len;
7086 if (plci->B3_prot == 4)
7087 sendf(plci->appl, _CONNECT_B3_I, Id, 0, "s", "");
7088 else
7089 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007090
Joe Perches475be4d2012-02-19 19:52:38 -08007091 if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id - 1])
7092 & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
7093 {
7094 plci->ncpi_buffer[++len] = 0;
7095 plci->ncpi_buffer[++len] = 0;
7096 plci->ncpi_buffer[++len] = 0;
7097 plci->ncpi_buffer[0] = len;
7098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007099
Joe Perches475be4d2012-02-19 19:52:38 -08007100 sendf(plci->appl, _CONNECT_B3_I, Id, 0, "S", plci->ncpi_buffer);
7101 }
7102 sendf(plci->appl, _DISCONNECT_B3_I, Id, 0, "wS", info, plci->ncpi_buffer);
7103 plci->ncpi_state = 0;
7104 sig_req(plci, HANGUP, 0);
7105 send_req(plci);
7106 plci->State = OUTG_DIS_PENDING;
7107 /* disc here */
7108 }
7109 else if ((a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
7110 && ((plci->B3_prot == 4) || (plci->B3_prot == 5))
7111 && ((ncci_state == INC_DIS_PENDING) || (ncci_state == IDLE)))
7112 {
7113 if (ncci_state == IDLE)
7114 {
7115 if (plci->channels)
7116 plci->channels--;
7117 if ((plci->State == IDLE || plci->State == SUSPENDING) && !plci->channels) {
7118 if (plci->State == SUSPENDING) {
7119 sendf(plci->appl,
7120 _FACILITY_I,
7121 Id & 0xffffL,
7122 0,
7123 "ws", (word)3, "\x03\x04\x00\x00");
7124 sendf(plci->appl, _DISCONNECT_I, Id & 0xffffL, 0, "w", 0);
7125 }
7126 plci_remove(plci);
7127 plci->State = IDLE;
7128 }
7129 }
7130 }
7131 else if (plci->channels)
7132 {
7133 sendf(plci->appl, _DISCONNECT_B3_I, Id, 0, "wS", info, plci->ncpi_buffer);
7134 plci->ncpi_state = 0;
7135 if ((ncci_state == OUTG_REJ_PENDING)
7136 && ((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE)))
7137 {
7138 sig_req(plci, HANGUP, 0);
7139 send_req(plci);
7140 plci->State = OUTG_DIS_PENDING;
7141 }
7142 }
7143 break;
7144 case N_RESET:
7145 a->ncci_state[ncci] = INC_RES_PENDING;
7146 sendf(plci->appl, _RESET_B3_I, Id, 0, "S", plci->ncpi_buffer);
7147 break;
7148 case N_RESET_ACK:
7149 a->ncci_state[ncci] = CONNECTED;
7150 sendf(plci->appl, _RESET_B3_I, Id, 0, "S", plci->ncpi_buffer);
7151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007152
Joe Perches475be4d2012-02-19 19:52:38 -08007153 case N_UDATA:
7154 if (!(udata_forwarding_table[plci->NL.RBuffer->P[0] >> 5] & (1L << (plci->NL.RBuffer->P[0] & 0x1f))))
7155 {
7156 plci->RData[0].P = plci->internal_ind_buffer + (-((int)(long)(plci->internal_ind_buffer)) & 3);
7157 plci->RData[0].PLength = INTERNAL_IND_BUFFER_SIZE;
7158 plci->NL.R = plci->RData;
7159 plci->NL.RNum = 1;
7160 return;
7161 }
7162 case N_BDATA:
7163 case N_DATA:
7164 if (((a->ncci_state[ncci] != CONNECTED) && (plci->B2_prot == 1)) /* transparent */
7165 || (a->ncci_state[ncci] == IDLE)
7166 || (a->ncci_state[ncci] == INC_DIS_PENDING))
7167 {
7168 plci->NL.RNR = 2;
7169 break;
7170 }
7171 if ((a->ncci_state[ncci] != CONNECTED)
7172 && (a->ncci_state[ncci] != OUTG_DIS_PENDING)
7173 && (a->ncci_state[ncci] != OUTG_REJ_PENDING))
7174 {
7175 dbug(1, dprintf("flow control"));
7176 plci->NL.RNR = 1; /* flow control */
7177 channel_x_off(plci, ch, 0);
7178 break;
7179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007180
Joe Perches475be4d2012-02-19 19:52:38 -08007181 NCCIcode = ncci | (((word)a->Id) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007182
Joe Perches475be4d2012-02-19 19:52:38 -08007183 /* count all buffers within the Application pool */
7184 /* belonging to the same NCCI. If this is below the */
7185 /* number of buffers available per NCCI we accept */
7186 /* this packet, otherwise we reject it */
7187 count = 0;
7188 Num = 0xffff;
7189 for (i = 0; i < APPLptr->MaxBuffer; i++) {
7190 if (NCCIcode == APPLptr->DataNCCI[i]) count++;
7191 if (!APPLptr->DataNCCI[i] && Num == 0xffff) Num = i;
7192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007193
Joe Perches475be4d2012-02-19 19:52:38 -08007194 if (count >= APPLptr->MaxNCCIData || Num == 0xffff)
7195 {
7196 dbug(3, dprintf("Flow-Control"));
7197 plci->NL.RNR = 1;
7198 if (++(APPLptr->NCCIDataFlowCtrlTimer) >=
7199 (word)((a->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL) ? 40 : 2000))
7200 {
7201 plci->NL.RNR = 2;
7202 dbug(3, dprintf("DiscardData"));
7203 } else {
7204 channel_x_off(plci, ch, 0);
7205 }
7206 break;
7207 }
7208 else
7209 {
7210 APPLptr->NCCIDataFlowCtrlTimer = 0;
7211 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007212
Joe Perches475be4d2012-02-19 19:52:38 -08007213 plci->RData[0].P = ReceiveBufferGet(APPLptr, Num);
7214 if (!plci->RData[0].P) {
7215 plci->NL.RNR = 1;
7216 channel_x_off(plci, ch, 0);
7217 break;
7218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219
Joe Perches475be4d2012-02-19 19:52:38 -08007220 APPLptr->DataNCCI[Num] = NCCIcode;
7221 APPLptr->DataFlags[Num] = (plci->Id << 8) | (plci->NL.Ind >> 4);
7222 dbug(3, dprintf("Buffer(%d), Max = %d", Num, APPLptr->MaxBuffer));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007223
Joe Perches475be4d2012-02-19 19:52:38 -08007224 plci->RNum = Num;
7225 plci->RFlags = plci->NL.Ind >> 4;
7226 plci->RData[0].PLength = APPLptr->MaxDataLength;
7227 plci->NL.R = plci->RData;
7228 if ((plci->NL.RLength != 0)
7229 && ((plci->B2_prot == B2_V120_ASYNC)
7230 || (plci->B2_prot == B2_V120_ASYNC_V42BIS)
7231 || (plci->B2_prot == B2_V120_BIT_TRANSPARENT)))
7232 {
7233 plci->RData[1].P = plci->RData[0].P;
7234 plci->RData[1].PLength = plci->RData[0].PLength;
7235 plci->RData[0].P = v120_header_buffer + (-((unsigned long)v120_header_buffer) & 3);
7236 if ((plci->NL.RBuffer->P[0] & V120_HEADER_EXTEND_BIT) || (plci->NL.RLength == 1))
7237 plci->RData[0].PLength = 1;
7238 else
7239 plci->RData[0].PLength = 2;
7240 if (plci->NL.RBuffer->P[0] & V120_HEADER_BREAK_BIT)
7241 plci->RFlags |= 0x0010;
7242 if (plci->NL.RBuffer->P[0] & (V120_HEADER_C1_BIT | V120_HEADER_C2_BIT))
7243 plci->RFlags |= 0x8000;
7244 plci->NL.RNum = 2;
7245 }
7246 else
7247 {
7248 if ((plci->NL.Ind & 0x0f) == N_UDATA)
7249 plci->RFlags |= 0x0010;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007250
Joe Perches475be4d2012-02-19 19:52:38 -08007251 else if ((plci->B3_prot == B3_RTP) && ((plci->NL.Ind & 0x0f) == N_BDATA))
7252 plci->RFlags |= 0x0001;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007253
Joe Perches475be4d2012-02-19 19:52:38 -08007254 plci->NL.RNum = 1;
7255 }
7256 break;
7257 case N_DATA_ACK:
7258 data_ack(plci, ch);
7259 break;
7260 default:
7261 plci->NL.RNR = 2;
7262 break;
7263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007264}
7265
7266/*------------------------------------------------------------------*/
Joe Perches475be4d2012-02-19 19:52:38 -08007267/* find a free PLCI */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007268/*------------------------------------------------------------------*/
7269
Hannes Eder4ee59d52008-12-16 01:17:33 -08007270static word get_plci(DIVA_CAPI_ADAPTER *a)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007271{
Joe Perches475be4d2012-02-19 19:52:38 -08007272 word i, j;
7273 PLCI *plci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007274
Joe Perches475be4d2012-02-19 19:52:38 -08007275 dump_plcis(a);
7276 for (i = 0; i < a->max_plci && a->plci[i].Id; i++);
7277 if (i == a->max_plci) {
7278 dbug(1, dprintf("get_plci: out of PLCIs"));
7279 return 0;
7280 }
7281 plci = &a->plci[i];
7282 plci->Id = (byte)(i + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007283
Joe Perches475be4d2012-02-19 19:52:38 -08007284 plci->Sig.Id = 0;
7285 plci->NL.Id = 0;
7286 plci->sig_req = 0;
7287 plci->nl_req = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007288
Joe Perches475be4d2012-02-19 19:52:38 -08007289 plci->appl = NULL;
7290 plci->relatedPTYPLCI = NULL;
7291 plci->State = IDLE;
7292 plci->SuppState = IDLE;
7293 plci->channels = 0;
7294 plci->tel = 0;
7295 plci->B1_resource = 0;
7296 plci->B2_prot = 0;
7297 plci->B3_prot = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007298
Joe Perches475be4d2012-02-19 19:52:38 -08007299 plci->command = 0;
7300 plci->m_command = 0;
7301 init_internal_command_queue(plci);
7302 plci->number = 0;
7303 plci->req_in_start = 0;
7304 plci->req_in = 0;
7305 plci->req_out = 0;
7306 plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE;
7307 plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
7308 plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007309
Joe Perches475be4d2012-02-19 19:52:38 -08007310 plci->data_sent = false;
7311 plci->send_disc = 0;
7312 plci->sig_global_req = 0;
7313 plci->sig_remove_id = 0;
7314 plci->nl_global_req = 0;
7315 plci->nl_remove_id = 0;
7316 plci->adv_nl = 0;
7317 plci->manufacturer = false;
7318 plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
7319 plci->spoofed_msg = 0;
7320 plci->ptyState = 0;
7321 plci->cr_enquiry = false;
7322 plci->hangup_flow_ctrl_timer = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007323
Joe Perches475be4d2012-02-19 19:52:38 -08007324 plci->ncci_ring_list = 0;
7325 for (j = 0; j < MAX_CHANNELS_PER_PLCI; j++) plci->inc_dis_ncci_table[j] = 0;
7326 clear_c_ind_mask(plci);
7327 set_group_ind_mask(plci);
7328 plci->fax_connect_info_length = 0;
7329 plci->nsf_control_bits = 0;
7330 plci->ncpi_state = 0x00;
7331 plci->ncpi_buffer[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007332
Joe Perches475be4d2012-02-19 19:52:38 -08007333 plci->requested_options_conn = 0;
7334 plci->requested_options = 0;
7335 plci->notifiedcall = 0;
7336 plci->vswitchstate = 0;
7337 plci->vsprot = 0;
7338 plci->vsprotdialect = 0;
7339 init_b1_config(plci);
7340 dbug(1, dprintf("get_plci(%x)", plci->Id));
7341 return i + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007342}
7343
7344/*------------------------------------------------------------------*/
7345/* put a parameter in the parameter buffer */
7346/*------------------------------------------------------------------*/
7347
Joe Perches475be4d2012-02-19 19:52:38 -08007348static void add_p(PLCI *plci, byte code, byte *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007349{
Joe Perches475be4d2012-02-19 19:52:38 -08007350 word p_length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007351
Joe Perches475be4d2012-02-19 19:52:38 -08007352 p_length = 0;
7353 if (p) p_length = p[0];
7354 add_ie(plci, code, p, p_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007355}
7356
7357/*------------------------------------------------------------------*/
7358/* put a structure in the parameter buffer */
7359/*------------------------------------------------------------------*/
Joe Perches475be4d2012-02-19 19:52:38 -08007360static void add_s(PLCI *plci, byte code, API_PARSE *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007361{
Joe Perches475be4d2012-02-19 19:52:38 -08007362 if (p) add_ie(plci, code, p->info, (word)p->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007363}
7364
7365/*------------------------------------------------------------------*/
7366/* put multiple structures in the parameter buffer */
7367/*------------------------------------------------------------------*/
Joe Perches475be4d2012-02-19 19:52:38 -08007368static void add_ss(PLCI *plci, byte code, API_PARSE *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007369{
Joe Perches475be4d2012-02-19 19:52:38 -08007370 byte i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007371
Joe Perches475be4d2012-02-19 19:52:38 -08007372 if (p) {
7373 dbug(1, dprintf("add_ss(%x,len=%d)", code, p->length));
7374 for (i = 2; i < (byte)p->length; i += p->info[i] + 2) {
7375 dbug(1, dprintf("add_ss_ie(%x,len=%d)", p->info[i - 1], p->info[i]));
7376 add_ie(plci, p->info[i - 1], (byte *)&(p->info[i]), (word)p->info[i]);
7377 }
7378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007379}
7380
7381/*------------------------------------------------------------------*/
7382/* return the channel number sent by the application in a esc_chi */
7383/*------------------------------------------------------------------*/
Joe Perches475be4d2012-02-19 19:52:38 -08007384static byte getChannel(API_PARSE *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007385{
Joe Perches475be4d2012-02-19 19:52:38 -08007386 byte i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007387
Joe Perches475be4d2012-02-19 19:52:38 -08007388 if (p) {
7389 for (i = 2; i < (byte)p->length; i += p->info[i] + 2) {
7390 if (p->info[i] == 2) {
7391 if (p->info[i - 1] == ESC && p->info[i + 1] == CHI) return (p->info[i + 2]);
7392 }
7393 }
7394 }
7395 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007396}
7397
7398
7399/*------------------------------------------------------------------*/
7400/* put an information element in the parameter buffer */
7401/*------------------------------------------------------------------*/
7402
Joe Perches475be4d2012-02-19 19:52:38 -08007403static void add_ie(PLCI *plci, byte code, byte *p, word p_length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007404{
Joe Perches475be4d2012-02-19 19:52:38 -08007405 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007406
Joe Perches475be4d2012-02-19 19:52:38 -08007407 if (!(code & 0x80) && !p_length) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007408
Joe Perches475be4d2012-02-19 19:52:38 -08007409 if (plci->req_in == plci->req_in_start) {
7410 plci->req_in += 2;
7411 }
7412 else {
7413 plci->req_in--;
7414 }
7415 plci->RBuffer[plci->req_in++] = code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007416
Joe Perches475be4d2012-02-19 19:52:38 -08007417 if (p) {
7418 plci->RBuffer[plci->req_in++] = (byte)p_length;
7419 for (i = 0; i < p_length; i++) plci->RBuffer[plci->req_in++] = p[1 + i];
7420 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007421
Joe Perches475be4d2012-02-19 19:52:38 -08007422 plci->RBuffer[plci->req_in++] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007423}
7424
7425/*------------------------------------------------------------------*/
7426/* put a unstructured data into the buffer */
7427/*------------------------------------------------------------------*/
7428
Hannes Eder4ee59d52008-12-16 01:17:33 -08007429static void add_d(PLCI *plci, word length, byte *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007430{
Joe Perches475be4d2012-02-19 19:52:38 -08007431 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007432
Joe Perches475be4d2012-02-19 19:52:38 -08007433 if (plci->req_in == plci->req_in_start) {
7434 plci->req_in += 2;
7435 }
7436 else {
7437 plci->req_in--;
7438 }
7439 for (i = 0; i < length; i++) plci->RBuffer[plci->req_in++] = p[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007440}
7441
7442/*------------------------------------------------------------------*/
7443/* put parameters from the Additional Info parameter in the */
7444/* parameter buffer */
7445/*------------------------------------------------------------------*/
7446
Hannes Eder4ee59d52008-12-16 01:17:33 -08007447static void add_ai(PLCI *plci, API_PARSE *ai)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007448{
Joe Perches475be4d2012-02-19 19:52:38 -08007449 word i;
7450 API_PARSE ai_parms[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007451
Joe Perches475be4d2012-02-19 19:52:38 -08007452 for (i = 0; i < 5; i++) ai_parms[i].length = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007453
Joe Perches475be4d2012-02-19 19:52:38 -08007454 if (!ai->length)
7455 return;
7456 if (api_parse(&ai->info[1], (word)ai->length, "ssss", ai_parms))
7457 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007458
Joe Perches475be4d2012-02-19 19:52:38 -08007459 add_s(plci, KEY, &ai_parms[1]);
7460 add_s(plci, UUI, &ai_parms[2]);
7461 add_ss(plci, FTY, &ai_parms[3]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007462}
7463
7464/*------------------------------------------------------------------*/
7465/* put parameter for b1 protocol in the parameter buffer */
7466/*------------------------------------------------------------------*/
7467
Hannes Eder4ee59d52008-12-16 01:17:33 -08007468static word add_b1(PLCI *plci, API_PARSE *bp, word b_channel_info,
7469 word b1_facilities)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007470{
Joe Perches475be4d2012-02-19 19:52:38 -08007471 API_PARSE bp_parms[8];
7472 API_PARSE mdm_cfg[9];
7473 API_PARSE global_config[2];
7474 byte cai[256];
7475 byte resource[] = {5, 9, 13, 12, 16, 39, 9, 17, 17, 18};
7476 byte voice_cai[] = "\x06\x14\x00\x00\x00\x00\x08";
7477 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007478
Joe Perches475be4d2012-02-19 19:52:38 -08007479 API_PARSE mdm_cfg_v18[4];
7480 word j, n, w;
7481 dword d;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007482
7483
Joe Perches475be4d2012-02-19 19:52:38 -08007484 for (i = 0; i < 8; i++) bp_parms[i].length = 0;
7485 for (i = 0; i < 2; i++) global_config[i].length = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007486
Joe Perches475be4d2012-02-19 19:52:38 -08007487 dbug(1, dprintf("add_b1"));
7488 api_save_msg(bp, "s", &plci->B_protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007489
Joe Perches475be4d2012-02-19 19:52:38 -08007490 if (b_channel_info == 2) {
7491 plci->B1_resource = 0;
7492 adjust_b1_facilities(plci, plci->B1_resource, b1_facilities);
7493 add_p(plci, CAI, "\x01\x00");
7494 dbug(1, dprintf("Cai=1,0 (no resource)"));
7495 return 0;
7496 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007497
Joe Perches475be4d2012-02-19 19:52:38 -08007498 if (plci->tel == CODEC_PERMANENT) return 0;
7499 else if (plci->tel == CODEC) {
7500 plci->B1_resource = 1;
7501 adjust_b1_facilities(plci, plci->B1_resource, b1_facilities);
7502 add_p(plci, CAI, "\x01\x01");
7503 dbug(1, dprintf("Cai=1,1 (Codec)"));
7504 return 0;
7505 }
7506 else if (plci->tel == ADV_VOICE) {
7507 plci->B1_resource = add_b1_facilities(plci, 9, (word)(b1_facilities | B1_FACILITY_VOICE));
7508 adjust_b1_facilities(plci, plci->B1_resource, (word)(b1_facilities | B1_FACILITY_VOICE));
7509 voice_cai[1] = plci->B1_resource;
7510 PUT_WORD(&voice_cai[5], plci->appl->MaxDataLength);
7511 add_p(plci, CAI, voice_cai);
7512 dbug(1, dprintf("Cai=1,0x%x (AdvVoice)", voice_cai[1]));
7513 return 0;
7514 }
7515 plci->call_dir &= ~(CALL_DIR_ORIGINATE | CALL_DIR_ANSWER);
7516 if (plci->call_dir & CALL_DIR_OUT)
7517 plci->call_dir |= CALL_DIR_ORIGINATE;
7518 else if (plci->call_dir & CALL_DIR_IN)
7519 plci->call_dir |= CALL_DIR_ANSWER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007520
Joe Perches475be4d2012-02-19 19:52:38 -08007521 if (!bp->length) {
7522 plci->B1_resource = 0x5;
7523 adjust_b1_facilities(plci, plci->B1_resource, b1_facilities);
7524 add_p(plci, CAI, "\x01\x05");
7525 return 0;
7526 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007527
Joe Perches475be4d2012-02-19 19:52:38 -08007528 dbug(1, dprintf("b_prot_len=%d", (word)bp->length));
7529 if (bp->length > 256) return _WRONG_MESSAGE_FORMAT;
7530 if (api_parse(&bp->info[1], (word)bp->length, "wwwsssb", bp_parms))
7531 {
7532 bp_parms[6].length = 0;
7533 if (api_parse(&bp->info[1], (word)bp->length, "wwwsss", bp_parms))
7534 {
7535 dbug(1, dprintf("b-form.!"));
7536 return _WRONG_MESSAGE_FORMAT;
7537 }
7538 }
7539 else if (api_parse(&bp->info[1], (word)bp->length, "wwwssss", bp_parms))
7540 {
7541 dbug(1, dprintf("b-form.!"));
7542 return _WRONG_MESSAGE_FORMAT;
7543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007544
Joe Perches475be4d2012-02-19 19:52:38 -08007545 if (bp_parms[6].length)
7546 {
7547 if (api_parse(&bp_parms[6].info[1], (word)bp_parms[6].length, "w", global_config))
7548 {
7549 return _WRONG_MESSAGE_FORMAT;
7550 }
7551 switch (GET_WORD(global_config[0].info))
7552 {
7553 case 1:
7554 plci->call_dir = (plci->call_dir & ~CALL_DIR_ANSWER) | CALL_DIR_ORIGINATE;
7555 break;
7556 case 2:
7557 plci->call_dir = (plci->call_dir & ~CALL_DIR_ORIGINATE) | CALL_DIR_ANSWER;
7558 break;
7559 }
7560 }
7561 dbug(1, dprintf("call_dir=%04x", plci->call_dir));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007562
7563
Joe Perches475be4d2012-02-19 19:52:38 -08007564 if ((GET_WORD(bp_parms[0].info) == B1_RTP)
7565 && (plci->adapter->man_profile.private_options & (1L << PRIVATE_RTP)))
7566 {
7567 plci->B1_resource = add_b1_facilities(plci, 31, (word)(b1_facilities & ~B1_FACILITY_VOICE));
7568 adjust_b1_facilities(plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE));
7569 cai[1] = plci->B1_resource;
7570 cai[2] = 0;
7571 cai[3] = 0;
7572 cai[4] = 0;
7573 PUT_WORD(&cai[5], plci->appl->MaxDataLength);
7574 for (i = 0; i < bp_parms[3].length; i++)
7575 cai[7 + i] = bp_parms[3].info[1 + i];
7576 cai[0] = 6 + bp_parms[3].length;
7577 add_p(plci, CAI, cai);
7578 return 0;
7579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007580
7581
Joe Perches475be4d2012-02-19 19:52:38 -08007582 if ((GET_WORD(bp_parms[0].info) == B1_PIAFS)
7583 && (plci->adapter->man_profile.private_options & (1L << PRIVATE_PIAFS)))
7584 {
7585 plci->B1_resource = add_b1_facilities(plci, 35/* PIAFS HARDWARE FACILITY */, (word)(b1_facilities & ~B1_FACILITY_VOICE));
7586 adjust_b1_facilities(plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE));
7587 cai[1] = plci->B1_resource;
7588 cai[2] = 0;
7589 cai[3] = 0;
7590 cai[4] = 0;
7591 PUT_WORD(&cai[5], plci->appl->MaxDataLength);
7592 cai[0] = 6;
7593 add_p(plci, CAI, cai);
7594 return 0;
7595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007596
7597
Joe Perches475be4d2012-02-19 19:52:38 -08007598 if ((GET_WORD(bp_parms[0].info) >= 32)
7599 || (!((1L << GET_WORD(bp_parms[0].info)) & plci->adapter->profile.B1_Protocols)
7600 && ((GET_WORD(bp_parms[0].info) != 3)
7601 || !((1L << B1_HDLC) & plci->adapter->profile.B1_Protocols)
7602 || ((bp_parms[3].length != 0) && (GET_WORD(&bp_parms[3].info[1]) != 0) && (GET_WORD(&bp_parms[3].info[1]) != 56000)))))
7603 {
7604 return _B1_NOT_SUPPORTED;
7605 }
7606 plci->B1_resource = add_b1_facilities(plci, resource[GET_WORD(bp_parms[0].info)],
7607 (word)(b1_facilities & ~B1_FACILITY_VOICE));
7608 adjust_b1_facilities(plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE));
7609 cai[0] = 6;
7610 cai[1] = plci->B1_resource;
7611 for (i = 2; i < sizeof(cai); i++) cai[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007612
Joe Perches475be4d2012-02-19 19:52:38 -08007613 if ((GET_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE)
7614 || (GET_WORD(bp_parms[0].info) == B1_MODEM_ASYNC)
7615 || (GET_WORD(bp_parms[0].info) == B1_MODEM_SYNC_HDLC))
7616 { /* B1 - modem */
7617 for (i = 0; i < 7; i++) mdm_cfg[i].length = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007618
Joe Perches475be4d2012-02-19 19:52:38 -08007619 if (bp_parms[3].length)
7620 {
7621 if (api_parse(&bp_parms[3].info[1], (word)bp_parms[3].length, "wwwwww", mdm_cfg))
7622 {
7623 return (_WRONG_MESSAGE_FORMAT);
7624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007625
Joe Perches475be4d2012-02-19 19:52:38 -08007626 cai[2] = 0; /* Bit rate for adaptation */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007627
Joe Perches475be4d2012-02-19 19:52:38 -08007628 dbug(1, dprintf("MDM Max Bit Rate:<%d>", GET_WORD(mdm_cfg[0].info)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007629
Joe Perches475be4d2012-02-19 19:52:38 -08007630 PUT_WORD(&cai[13], 0); /* Min Tx speed */
7631 PUT_WORD(&cai[15], GET_WORD(mdm_cfg[0].info)); /* Max Tx speed */
7632 PUT_WORD(&cai[17], 0); /* Min Rx speed */
7633 PUT_WORD(&cai[19], GET_WORD(mdm_cfg[0].info)); /* Max Rx speed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007634
Joe Perches475be4d2012-02-19 19:52:38 -08007635 cai[3] = 0; /* Async framing parameters */
7636 switch (GET_WORD(mdm_cfg[2].info))
7637 { /* Parity */
7638 case 1: /* odd parity */
7639 cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_ODD);
7640 dbug(1, dprintf("MDM: odd parity"));
7641 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007642
Joe Perches475be4d2012-02-19 19:52:38 -08007643 case 2: /* even parity */
7644 cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_EVEN);
7645 dbug(1, dprintf("MDM: even parity"));
7646 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007647
Joe Perches475be4d2012-02-19 19:52:38 -08007648 default:
7649 dbug(1, dprintf("MDM: no parity"));
7650 break;
7651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007652
Joe Perches475be4d2012-02-19 19:52:38 -08007653 switch (GET_WORD(mdm_cfg[3].info))
7654 { /* stop bits */
7655 case 1: /* 2 stop bits */
7656 cai[3] |= DSP_CAI_ASYNC_TWO_STOP_BITS;
7657 dbug(1, dprintf("MDM: 2 stop bits"));
7658 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007659
Joe Perches475be4d2012-02-19 19:52:38 -08007660 default:
7661 dbug(1, dprintf("MDM: 1 stop bit"));
7662 break;
7663 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007664
Joe Perches475be4d2012-02-19 19:52:38 -08007665 switch (GET_WORD(mdm_cfg[1].info))
7666 { /* char length */
7667 case 5:
7668 cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_5;
7669 dbug(1, dprintf("MDM: 5 bits"));
7670 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007671
Joe Perches475be4d2012-02-19 19:52:38 -08007672 case 6:
7673 cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_6;
7674 dbug(1, dprintf("MDM: 6 bits"));
7675 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007676
Joe Perches475be4d2012-02-19 19:52:38 -08007677 case 7:
7678 cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_7;
7679 dbug(1, dprintf("MDM: 7 bits"));
7680 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007681
Joe Perches475be4d2012-02-19 19:52:38 -08007682 default:
7683 dbug(1, dprintf("MDM: 8 bits"));
7684 break;
7685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007686
Joe Perches475be4d2012-02-19 19:52:38 -08007687 cai[7] = 0; /* Line taking options */
7688 cai[8] = 0; /* Modulation negotiation options */
7689 cai[9] = 0; /* Modulation options */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007690
Joe Perches475be4d2012-02-19 19:52:38 -08007691 if (((plci->call_dir & CALL_DIR_ORIGINATE) != 0) ^ ((plci->call_dir & CALL_DIR_OUT) != 0))
7692 {
7693 cai[9] |= DSP_CAI_MODEM_REVERSE_DIRECTION;
7694 dbug(1, dprintf("MDM: Reverse direction"));
7695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007696
Joe Perches475be4d2012-02-19 19:52:38 -08007697 if (GET_WORD(mdm_cfg[4].info) & MDM_CAPI_DISABLE_RETRAIN)
7698 {
7699 cai[9] |= DSP_CAI_MODEM_DISABLE_RETRAIN;
7700 dbug(1, dprintf("MDM: Disable retrain"));
7701 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007702
Joe Perches475be4d2012-02-19 19:52:38 -08007703 if (GET_WORD(mdm_cfg[4].info) & MDM_CAPI_DISABLE_RING_TONE)
7704 {
7705 cai[7] |= DSP_CAI_MODEM_DISABLE_CALLING_TONE | DSP_CAI_MODEM_DISABLE_ANSWER_TONE;
7706 dbug(1, dprintf("MDM: Disable ring tone"));
7707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007708
Joe Perches475be4d2012-02-19 19:52:38 -08007709 if (GET_WORD(mdm_cfg[4].info) & MDM_CAPI_GUARD_1800)
7710 {
7711 cai[8] |= DSP_CAI_MODEM_GUARD_TONE_1800HZ;
7712 dbug(1, dprintf("MDM: 1800 guard tone"));
7713 }
7714 else if (GET_WORD(mdm_cfg[4].info) & MDM_CAPI_GUARD_550)
7715 {
7716 cai[8] |= DSP_CAI_MODEM_GUARD_TONE_550HZ;
7717 dbug(1, dprintf("MDM: 550 guard tone"));
7718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007719
Joe Perches475be4d2012-02-19 19:52:38 -08007720 if ((GET_WORD(mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_V100)
7721 {
7722 cai[8] |= DSP_CAI_MODEM_NEGOTIATE_V100;
7723 dbug(1, dprintf("MDM: V100"));
7724 }
7725 else if ((GET_WORD(mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_MOD_CLASS)
7726 {
7727 cai[8] |= DSP_CAI_MODEM_NEGOTIATE_IN_CLASS;
7728 dbug(1, dprintf("MDM: IN CLASS"));
7729 }
7730 else if ((GET_WORD(mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_DISABLED)
7731 {
7732 cai[8] |= DSP_CAI_MODEM_NEGOTIATE_DISABLED;
7733 dbug(1, dprintf("MDM: DISABLED"));
7734 }
7735 cai[0] = 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007736
Joe Perches475be4d2012-02-19 19:52:38 -08007737 if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_V18))
7738 && (GET_WORD(mdm_cfg[5].info) & 0x8000)) /* Private V.18 enable */
7739 {
7740 plci->requested_options |= 1L << PRIVATE_V18;
7741 }
7742 if (GET_WORD(mdm_cfg[5].info) & 0x4000) /* Private VOWN enable */
7743 plci->requested_options |= 1L << PRIVATE_VOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007744
Joe Perches475be4d2012-02-19 19:52:38 -08007745 if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id - 1])
7746 & ((1L << PRIVATE_V18) | (1L << PRIVATE_VOWN)))
7747 {
7748 if (!api_parse(&bp_parms[3].info[1], (word)bp_parms[3].length, "wwwwwws", mdm_cfg))
7749 {
7750 i = 27;
7751 if (mdm_cfg[6].length >= 4)
7752 {
7753 d = GET_DWORD(&mdm_cfg[6].info[1]);
7754 cai[7] |= (byte) d; /* line taking options */
7755 cai[9] |= (byte)(d >> 8); /* modulation options */
7756 cai[++i] = (byte)(d >> 16); /* vown modulation options */
7757 cai[++i] = (byte)(d >> 24);
7758 if (mdm_cfg[6].length >= 8)
7759 {
7760 d = GET_DWORD(&mdm_cfg[6].info[5]);
7761 cai[10] |= (byte) d; /* disabled modulations mask */
7762 cai[11] |= (byte)(d >> 8);
7763 if (mdm_cfg[6].length >= 12)
7764 {
7765 d = GET_DWORD(&mdm_cfg[6].info[9]);
7766 cai[12] = (byte) d; /* enabled modulations mask */
7767 cai[++i] = (byte)(d >> 8); /* vown enabled modulations */
7768 cai[++i] = (byte)(d >> 16);
7769 cai[++i] = (byte)(d >> 24);
7770 cai[++i] = 0;
7771 if (mdm_cfg[6].length >= 14)
7772 {
7773 w = GET_WORD(&mdm_cfg[6].info[13]);
7774 if (w != 0)
7775 PUT_WORD(&cai[13], w); /* min tx speed */
7776 if (mdm_cfg[6].length >= 16)
7777 {
7778 w = GET_WORD(&mdm_cfg[6].info[15]);
7779 if (w != 0)
7780 PUT_WORD(&cai[15], w); /* max tx speed */
7781 if (mdm_cfg[6].length >= 18)
7782 {
7783 w = GET_WORD(&mdm_cfg[6].info[17]);
7784 if (w != 0)
7785 PUT_WORD(&cai[17], w); /* min rx speed */
7786 if (mdm_cfg[6].length >= 20)
7787 {
7788 w = GET_WORD(&mdm_cfg[6].info[19]);
7789 if (w != 0)
7790 PUT_WORD(&cai[19], w); /* max rx speed */
7791 if (mdm_cfg[6].length >= 22)
7792 {
7793 w = GET_WORD(&mdm_cfg[6].info[21]);
7794 cai[23] = (byte)(-((short) w)); /* transmit level */
7795 if (mdm_cfg[6].length >= 24)
7796 {
7797 w = GET_WORD(&mdm_cfg[6].info[23]);
7798 cai[22] |= (byte) w; /* info options mask */
7799 cai[21] |= (byte)(w >> 8); /* disabled symbol rates */
7800 }
7801 }
7802 }
7803 }
7804 }
7805 }
7806 }
7807 }
7808 }
7809 cai[27] = i - 27;
7810 i++;
7811 if (!api_parse(&bp_parms[3].info[1], (word)bp_parms[3].length, "wwwwwwss", mdm_cfg))
7812 {
7813 if (!api_parse(&mdm_cfg[7].info[1], (word)mdm_cfg[7].length, "sss", mdm_cfg_v18))
7814 {
7815 for (n = 0; n < 3; n++)
7816 {
7817 cai[i] = (byte)(mdm_cfg_v18[n].length);
7818 for (j = 1; j < ((word)(cai[i] + 1)); j++)
7819 cai[i + j] = mdm_cfg_v18[n].info[j];
7820 i += cai[i] + 1;
7821 }
7822 }
7823 }
7824 cai[0] = (byte)(i - 1);
7825 }
7826 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007827
Joe Perches475be4d2012-02-19 19:52:38 -08007828 }
7829 }
7830 if (GET_WORD(bp_parms[0].info) == 2 || /* V.110 async */
7831 GET_WORD(bp_parms[0].info) == 3) /* V.110 sync */
7832 {
7833 if (bp_parms[3].length) {
7834 dbug(1, dprintf("V.110,%d", GET_WORD(&bp_parms[3].info[1])));
7835 switch (GET_WORD(&bp_parms[3].info[1])) { /* Rate */
7836 case 0:
7837 case 56000:
7838 if (GET_WORD(bp_parms[0].info) == 3) { /* V.110 sync 56k */
7839 dbug(1, dprintf("56k sync HSCX"));
7840 cai[1] = 8;
7841 cai[2] = 0;
7842 cai[3] = 0;
7843 }
7844 else if (GET_WORD(bp_parms[0].info) == 2) {
7845 dbug(1, dprintf("56k async DSP"));
7846 cai[2] = 9;
7847 }
7848 break;
7849 case 50: cai[2] = 1; break;
7850 case 75: cai[2] = 1; break;
7851 case 110: cai[2] = 1; break;
7852 case 150: cai[2] = 1; break;
7853 case 200: cai[2] = 1; break;
7854 case 300: cai[2] = 1; break;
7855 case 600: cai[2] = 1; break;
7856 case 1200: cai[2] = 2; break;
7857 case 2400: cai[2] = 3; break;
7858 case 4800: cai[2] = 4; break;
7859 case 7200: cai[2] = 10; break;
7860 case 9600: cai[2] = 5; break;
7861 case 12000: cai[2] = 13; break;
7862 case 24000: cai[2] = 0; break;
7863 case 14400: cai[2] = 11; break;
7864 case 19200: cai[2] = 6; break;
7865 case 28800: cai[2] = 12; break;
7866 case 38400: cai[2] = 7; break;
7867 case 48000: cai[2] = 8; break;
7868 case 76: cai[2] = 15; break; /* 75/1200 */
7869 case 1201: cai[2] = 14; break; /* 1200/75 */
7870 case 56001: cai[2] = 9; break; /* V.110 56000 */
7871
7872 default:
7873 return _B1_PARM_NOT_SUPPORTED;
7874 }
7875 cai[3] = 0;
7876 if (cai[1] == 13) /* v.110 async */
7877 {
7878 if (bp_parms[3].length >= 8)
7879 {
7880 switch (GET_WORD(&bp_parms[3].info[3]))
7881 { /* char length */
7882 case 5:
7883 cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_5;
7884 break;
7885 case 6:
7886 cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_6;
7887 break;
7888 case 7:
7889 cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_7;
7890 break;
7891 }
7892 switch (GET_WORD(&bp_parms[3].info[5]))
7893 { /* Parity */
7894 case 1: /* odd parity */
7895 cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_ODD);
7896 break;
7897 case 2: /* even parity */
7898 cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_EVEN);
7899 break;
7900 }
7901 switch (GET_WORD(&bp_parms[3].info[7]))
7902 { /* stop bits */
7903 case 1: /* 2 stop bits */
7904 cai[3] |= DSP_CAI_ASYNC_TWO_STOP_BITS;
7905 break;
7906 }
7907 }
7908 }
7909 }
7910 else if (cai[1] == 8 || GET_WORD(bp_parms[0].info) == 3) {
7911 dbug(1, dprintf("V.110 default 56k sync"));
7912 cai[1] = 8;
7913 cai[2] = 0;
7914 cai[3] = 0;
7915 }
7916 else {
7917 dbug(1, dprintf("V.110 default 9600 async"));
7918 cai[2] = 5;
7919 }
7920 }
7921 PUT_WORD(&cai[5], plci->appl->MaxDataLength);
7922 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]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007923/* HexDump ("CAI", sizeof(cai), &cai[0]); */
7924
Joe Perches475be4d2012-02-19 19:52:38 -08007925 add_p(plci, CAI, cai);
7926 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007927}
7928
7929/*------------------------------------------------------------------*/
7930/* put parameter for b2 and B3 protocol in the parameter buffer */
7931/*------------------------------------------------------------------*/
7932
Hannes Eder4ee59d52008-12-16 01:17:33 -08007933static word add_b23(PLCI *plci, API_PARSE *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007934{
Joe Perches475be4d2012-02-19 19:52:38 -08007935 word i, fax_control_bits;
7936 byte pos, len;
7937 byte SAPI = 0x40; /* default SAPI 16 for x.31 */
7938 API_PARSE bp_parms[8];
7939 API_PARSE *b1_config;
7940 API_PARSE *b2_config;
7941 API_PARSE b2_config_parms[8];
7942 API_PARSE *b3_config;
7943 API_PARSE b3_config_parms[6];
7944 API_PARSE global_config[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007945
Joe Perches475be4d2012-02-19 19:52:38 -08007946 static byte llc[3] = {2,0,0};
7947 static byte dlc[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
7948 static byte nlc[256];
7949 static byte lli[12] = {1,1};
Linus Torvalds1da177e2005-04-16 15:20:36 -07007950
Joe Perches475be4d2012-02-19 19:52:38 -08007951 const byte llc2_out[] = {1,2,4,6,2,0,0,0, X75_V42BIS,V120_L2,V120_V42BIS,V120_L2,6};
7952 const byte llc2_in[] = {1,3,4,6,3,0,0,0, X75_V42BIS,V120_L2,V120_V42BIS,V120_L2,6};
Linus Torvalds1da177e2005-04-16 15:20:36 -07007953
Joe Perches475be4d2012-02-19 19:52:38 -08007954 const byte llc3[] = {4,3,2,2,6,6,0};
7955 const byte header[] = {0,2,3,3,0,0,0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07007956
Joe Perches475be4d2012-02-19 19:52:38 -08007957 for (i = 0; i < 8; i++) bp_parms[i].length = 0;
7958 for (i = 0; i < 6; i++) b2_config_parms[i].length = 0;
7959 for (i = 0; i < 5; i++) b3_config_parms[i].length = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007960
Joe Perches475be4d2012-02-19 19:52:38 -08007961 lli[0] = 1;
7962 lli[1] = 1;
7963 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)
7964 lli[1] |= 2;
7965 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL)
7966 lli[1] |= 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007967
Joe Perches475be4d2012-02-19 19:52:38 -08007968 if ((lli[1] & 0x02) && (diva_xdi_extended_features & DIVA_CAPI_USE_CMA)) {
7969 lli[1] |= 0x10;
7970 if (plci->rx_dma_descriptor <= 0) {
7971 plci->rx_dma_descriptor = diva_get_dma_descriptor(plci, &plci->rx_dma_magic);
7972 if (plci->rx_dma_descriptor >= 0)
7973 plci->rx_dma_descriptor++;
7974 }
7975 if (plci->rx_dma_descriptor > 0) {
7976 lli[0] = 6;
7977 lli[1] |= 0x40;
7978 lli[2] = (byte)(plci->rx_dma_descriptor - 1);
7979 lli[3] = (byte)plci->rx_dma_magic;
7980 lli[4] = (byte)(plci->rx_dma_magic >> 8);
7981 lli[5] = (byte)(plci->rx_dma_magic >> 16);
7982 lli[6] = (byte)(plci->rx_dma_magic >> 24);
7983 }
7984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007985
Joe Perches475be4d2012-02-19 19:52:38 -08007986 if (DIVA_CAPI_SUPPORTS_NO_CANCEL(plci->adapter)) {
7987 lli[1] |= 0x20;
7988 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007989
Joe Perches475be4d2012-02-19 19:52:38 -08007990 dbug(1, dprintf("add_b23"));
7991 api_save_msg(bp, "s", &plci->B_protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007992
Joe Perches475be4d2012-02-19 19:52:38 -08007993 if (!bp->length && plci->tel)
7994 {
7995 plci->adv_nl = true;
7996 dbug(1, dprintf("Default adv.Nl"));
7997 add_p(plci, LLI, lli);
7998 plci->B2_prot = 1 /*XPARENT*/;
7999 plci->B3_prot = 0 /*XPARENT*/;
8000 llc[1] = 2;
8001 llc[2] = 4;
8002 add_p(plci, LLC, llc);
8003 dlc[0] = 2;
8004 PUT_WORD(&dlc[1], plci->appl->MaxDataLength);
8005 add_p(plci, DLC, dlc);
8006 return 0;
8007 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008008
Joe Perches475be4d2012-02-19 19:52:38 -08008009 if (!bp->length) /*default*/
8010 {
8011 dbug(1, dprintf("ret default"));
8012 add_p(plci, LLI, lli);
8013 plci->B2_prot = 0 /*X.75 */;
8014 plci->B3_prot = 0 /*XPARENT*/;
8015 llc[1] = 1;
8016 llc[2] = 4;
8017 add_p(plci, LLC, llc);
8018 dlc[0] = 2;
8019 PUT_WORD(&dlc[1], plci->appl->MaxDataLength);
8020 add_p(plci, DLC, dlc);
8021 return 0;
8022 }
8023 dbug(1, dprintf("b_prot_len=%d", (word)bp->length));
8024 if ((word)bp->length > 256) return _WRONG_MESSAGE_FORMAT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008025
Joe Perches475be4d2012-02-19 19:52:38 -08008026 if (api_parse(&bp->info[1], (word)bp->length, "wwwsssb", bp_parms))
8027 {
8028 bp_parms[6].length = 0;
8029 if (api_parse(&bp->info[1], (word)bp->length, "wwwsss", bp_parms))
8030 {
8031 dbug(1, dprintf("b-form.!"));
8032 return _WRONG_MESSAGE_FORMAT;
8033 }
8034 }
8035 else if (api_parse(&bp->info[1], (word)bp->length, "wwwssss", bp_parms))
8036 {
8037 dbug(1, dprintf("b-form.!"));
8038 return _WRONG_MESSAGE_FORMAT;
8039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008040
Joe Perches475be4d2012-02-19 19:52:38 -08008041 if (plci->tel == ADV_VOICE) /* transparent B on advanced voice */
8042 {
8043 if (GET_WORD(bp_parms[1].info) != 1
8044 || GET_WORD(bp_parms[2].info) != 0) return _B2_NOT_SUPPORTED;
8045 plci->adv_nl = true;
8046 }
8047 else if (plci->tel) return _B2_NOT_SUPPORTED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008048
8049
Joe Perches475be4d2012-02-19 19:52:38 -08008050 if ((GET_WORD(bp_parms[1].info) == B2_RTP)
8051 && (GET_WORD(bp_parms[2].info) == B3_RTP)
8052 && (plci->adapter->man_profile.private_options & (1L << PRIVATE_RTP)))
8053 {
8054 add_p(plci, LLI, lli);
8055 plci->B2_prot = (byte) GET_WORD(bp_parms[1].info);
8056 plci->B3_prot = (byte) GET_WORD(bp_parms[2].info);
8057 llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ? 14 : 13;
8058 llc[2] = 4;
8059 add_p(plci, LLC, llc);
8060 dlc[0] = 2;
8061 PUT_WORD(&dlc[1], plci->appl->MaxDataLength);
8062 dlc[3] = 3; /* Addr A */
8063 dlc[4] = 1; /* Addr B */
8064 dlc[5] = 7; /* modulo mode */
8065 dlc[6] = 7; /* window size */
8066 dlc[7] = 0; /* XID len Lo */
8067 dlc[8] = 0; /* XID len Hi */
8068 for (i = 0; i < bp_parms[4].length; i++)
8069 dlc[9 + i] = bp_parms[4].info[1 + i];
8070 dlc[0] = (byte)(8 + bp_parms[4].length);
8071 add_p(plci, DLC, dlc);
8072 for (i = 0; i < bp_parms[5].length; i++)
8073 nlc[1 + i] = bp_parms[5].info[1 + i];
8074 nlc[0] = (byte)(bp_parms[5].length);
8075 add_p(plci, NLC, nlc);
8076 return 0;
8077 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008078
8079
8080
Joe Perches475be4d2012-02-19 19:52:38 -08008081 if ((GET_WORD(bp_parms[1].info) >= 32)
8082 || (!((1L << GET_WORD(bp_parms[1].info)) & plci->adapter->profile.B2_Protocols)
8083 && ((GET_WORD(bp_parms[1].info) != B2_PIAFS)
8084 || !(plci->adapter->man_profile.private_options & (1L << PRIVATE_PIAFS)))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07008085
Joe Perches475be4d2012-02-19 19:52:38 -08008086 {
8087 return _B2_NOT_SUPPORTED;
8088 }
8089 if ((GET_WORD(bp_parms[2].info) >= 32)
8090 || !((1L << GET_WORD(bp_parms[2].info)) & plci->adapter->profile.B3_Protocols))
8091 {
8092 return _B3_NOT_SUPPORTED;
8093 }
8094 if ((GET_WORD(bp_parms[1].info) != B2_SDLC)
8095 && ((GET_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE)
8096 || (GET_WORD(bp_parms[0].info) == B1_MODEM_ASYNC)
8097 || (GET_WORD(bp_parms[0].info) == B1_MODEM_SYNC_HDLC)))
8098 {
8099 return (add_modem_b23(plci, bp_parms));
8100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008101
Joe Perches475be4d2012-02-19 19:52:38 -08008102 add_p(plci, LLI, lli);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008103
Joe Perches475be4d2012-02-19 19:52:38 -08008104 plci->B2_prot = (byte)GET_WORD(bp_parms[1].info);
8105 plci->B3_prot = (byte)GET_WORD(bp_parms[2].info);
8106 if (plci->B2_prot == 12) SAPI = 0; /* default SAPI D-channel */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008107
Joe Perches475be4d2012-02-19 19:52:38 -08008108 if (bp_parms[6].length)
8109 {
8110 if (api_parse(&bp_parms[6].info[1], (word)bp_parms[6].length, "w", global_config))
8111 {
8112 return _WRONG_MESSAGE_FORMAT;
8113 }
8114 switch (GET_WORD(global_config[0].info))
8115 {
8116 case 1:
8117 plci->call_dir = (plci->call_dir & ~CALL_DIR_ANSWER) | CALL_DIR_ORIGINATE;
8118 break;
8119 case 2:
8120 plci->call_dir = (plci->call_dir & ~CALL_DIR_ORIGINATE) | CALL_DIR_ANSWER;
8121 break;
8122 }
8123 }
8124 dbug(1, dprintf("call_dir=%04x", plci->call_dir));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008125
8126
Joe Perches475be4d2012-02-19 19:52:38 -08008127 if (plci->B2_prot == B2_PIAFS)
8128 llc[1] = PIAFS_CRC;
8129 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07008130/* IMPLEMENT_PIAFS */
Joe Perches475be4d2012-02-19 19:52:38 -08008131 {
8132 llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ?
8133 llc2_out[GET_WORD(bp_parms[1].info)] : llc2_in[GET_WORD(bp_parms[1].info)];
8134 }
8135 llc[2] = llc3[GET_WORD(bp_parms[2].info)];
Linus Torvalds1da177e2005-04-16 15:20:36 -07008136
Joe Perches475be4d2012-02-19 19:52:38 -08008137 add_p(plci, LLC, llc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008138
Joe Perches475be4d2012-02-19 19:52:38 -08008139 dlc[0] = 2;
8140 PUT_WORD(&dlc[1], plci->appl->MaxDataLength +
8141 header[GET_WORD(bp_parms[2].info)]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008142
Joe Perches475be4d2012-02-19 19:52:38 -08008143 b1_config = &bp_parms[3];
8144 nlc[0] = 0;
8145 if (plci->B3_prot == 4
8146 || plci->B3_prot == 5)
8147 {
8148 for (i = 0; i < sizeof(T30_INFO); i++) nlc[i] = 0;
8149 nlc[0] = sizeof(T30_INFO);
8150 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
8151 ((T30_INFO *)&nlc[1])->operating_mode = T30_OPERATING_MODE_CAPI;
8152 ((T30_INFO *)&nlc[1])->rate_div_2400 = 0xff;
8153 if (b1_config->length >= 2)
8154 {
8155 ((T30_INFO *)&nlc[1])->rate_div_2400 = (byte)(GET_WORD(&b1_config->info[1]) / 2400);
8156 }
8157 }
8158 b2_config = &bp_parms[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07008159
8160
Joe Perches475be4d2012-02-19 19:52:38 -08008161 if (llc[1] == PIAFS_CRC)
8162 {
8163 if (plci->B3_prot != B3_TRANSPARENT)
8164 {
8165 return _B_STACK_NOT_SUPPORTED;
8166 }
8167 if (b2_config->length && api_parse(&b2_config->info[1], (word)b2_config->length, "bwww", b2_config_parms)) {
8168 return _WRONG_MESSAGE_FORMAT;
8169 }
8170 PUT_WORD(&dlc[1], plci->appl->MaxDataLength);
8171 dlc[3] = 0; /* Addr A */
8172 dlc[4] = 0; /* Addr B */
8173 dlc[5] = 0; /* modulo mode */
8174 dlc[6] = 0; /* window size */
8175 if (b2_config->length >= 7) {
8176 dlc[7] = 7;
8177 dlc[8] = 0;
8178 dlc[9] = b2_config_parms[0].info[0]; /* PIAFS protocol Speed configuration */
8179 dlc[10] = b2_config_parms[1].info[0]; /* V.42bis P0 */
8180 dlc[11] = b2_config_parms[1].info[1]; /* V.42bis P0 */
8181 dlc[12] = b2_config_parms[2].info[0]; /* V.42bis P1 */
8182 dlc[13] = b2_config_parms[2].info[1]; /* V.42bis P1 */
8183 dlc[14] = b2_config_parms[3].info[0]; /* V.42bis P2 */
8184 dlc[15] = b2_config_parms[3].info[1]; /* V.42bis P2 */
8185 dlc[0] = 15;
8186 if (b2_config->length >= 8) { /* PIAFS control abilities */
8187 dlc[7] = 10;
8188 dlc[16] = 2; /* Length of PIAFS extension */
8189 dlc[17] = PIAFS_UDATA_ABILITIES; /* control (UDATA) ability */
8190 dlc[18] = b2_config_parms[4].info[0]; /* value */
8191 dlc[0] = 18;
8192 }
8193 }
8194 else /* default values, 64K, variable, no compression */
8195 {
8196 dlc[7] = 7;
8197 dlc[8] = 0;
8198 dlc[9] = 0x03; /* PIAFS protocol Speed configuration */
8199 dlc[10] = 0x03; /* V.42bis P0 */
8200 dlc[11] = 0; /* V.42bis P0 */
8201 dlc[12] = 0; /* V.42bis P1 */
8202 dlc[13] = 0; /* V.42bis P1 */
8203 dlc[14] = 0; /* V.42bis P2 */
8204 dlc[15] = 0; /* V.42bis P2 */
8205 dlc[0] = 15;
8206 }
8207 add_p(plci, DLC, dlc);
8208 }
8209 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07008210
Joe Perches475be4d2012-02-19 19:52:38 -08008211 if ((llc[1] == V120_L2) || (llc[1] == V120_V42BIS))
8212 {
8213 if (plci->B3_prot != B3_TRANSPARENT)
8214 return _B_STACK_NOT_SUPPORTED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008215
Joe Perches475be4d2012-02-19 19:52:38 -08008216 dlc[0] = 6;
8217 PUT_WORD(&dlc[1], GET_WORD(&dlc[1]) + 2);
8218 dlc[3] = 0x08;
8219 dlc[4] = 0x01;
8220 dlc[5] = 127;
8221 dlc[6] = 7;
8222 if (b2_config->length != 0)
8223 {
8224 if ((llc[1] == V120_V42BIS) && api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbwww", b2_config_parms)) {
8225 return _WRONG_MESSAGE_FORMAT;
8226 }
8227 dlc[3] = (byte)((b2_config->info[2] << 3) | ((b2_config->info[1] >> 5) & 0x04));
8228 dlc[4] = (byte)((b2_config->info[1] << 1) | 0x01);
8229 if (b2_config->info[3] != 128)
8230 {
8231 dbug(1, dprintf("1D-dlc= %x %x %x %x %x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4]));
8232 return _B2_PARM_NOT_SUPPORTED;
8233 }
8234 dlc[5] = (byte)(b2_config->info[3] - 1);
8235 dlc[6] = b2_config->info[4];
8236 if (llc[1] == V120_V42BIS) {
8237 if (b2_config->length >= 10) {
8238 dlc[7] = 6;
8239 dlc[8] = 0;
8240 dlc[9] = b2_config_parms[4].info[0];
8241 dlc[10] = b2_config_parms[4].info[1];
8242 dlc[11] = b2_config_parms[5].info[0];
8243 dlc[12] = b2_config_parms[5].info[1];
8244 dlc[13] = b2_config_parms[6].info[0];
8245 dlc[14] = b2_config_parms[6].info[1];
8246 dlc[0] = 14;
8247 dbug(1, dprintf("b2_config_parms[4].info[0] [1]: %x %x", b2_config_parms[4].info[0], b2_config_parms[4].info[1]));
8248 dbug(1, dprintf("b2_config_parms[5].info[0] [1]: %x %x", b2_config_parms[5].info[0], b2_config_parms[5].info[1]));
8249 dbug(1, dprintf("b2_config_parms[6].info[0] [1]: %x %x", b2_config_parms[6].info[0], b2_config_parms[6].info[1]));
8250 }
8251 else {
8252 dlc[6] = 14;
8253 }
8254 }
8255 }
8256 }
8257 else
8258 {
8259 if (b2_config->length)
8260 {
8261 dbug(1, dprintf("B2-Config"));
8262 if (llc[1] == X75_V42BIS) {
8263 if (api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbwww", b2_config_parms))
8264 {
8265 return _WRONG_MESSAGE_FORMAT;
8266 }
8267 }
8268 else {
8269 if (api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbs", b2_config_parms))
8270 {
8271 return _WRONG_MESSAGE_FORMAT;
8272 }
8273 }
8274 /* if B2 Protocol is LAPD, b2_config structure is different */
8275 if (llc[1] == 6)
8276 {
8277 dlc[0] = 4;
8278 if (b2_config->length >= 1) dlc[2] = b2_config->info[1]; /* TEI */
8279 else dlc[2] = 0x01;
8280 if ((b2_config->length >= 2) && (plci->B2_prot == 12))
8281 {
8282 SAPI = b2_config->info[2]; /* SAPI */
8283 }
8284 dlc[1] = SAPI;
8285 if ((b2_config->length >= 3) && (b2_config->info[3] == 128))
8286 {
8287 dlc[3] = 127; /* Mode */
8288 }
8289 else
8290 {
8291 dlc[3] = 7; /* Mode */
8292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008293
Joe Perches475be4d2012-02-19 19:52:38 -08008294 if (b2_config->length >= 4) dlc[4] = b2_config->info[4]; /* Window */
8295 else dlc[4] = 1;
8296 dbug(1, dprintf("D-dlc[%d]=%x,%x,%x,%x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4]));
8297 if (b2_config->length > 5) return _B2_PARM_NOT_SUPPORTED;
8298 }
8299 else
8300 {
8301 dlc[0] = (byte)(b2_config_parms[4].length + 6);
8302 dlc[3] = b2_config->info[1];
8303 dlc[4] = b2_config->info[2];
8304 if (b2_config->info[3] != 8 && b2_config->info[3] != 128) {
8305 dbug(1, dprintf("1D-dlc= %x %x %x %x %x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4]));
8306 return _B2_PARM_NOT_SUPPORTED;
8307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008308
Joe Perches475be4d2012-02-19 19:52:38 -08008309 dlc[5] = (byte)(b2_config->info[3] - 1);
8310 dlc[6] = b2_config->info[4];
8311 if (dlc[6] > dlc[5]) {
8312 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]));
8313 return _B2_PARM_NOT_SUPPORTED;
8314 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008315
Joe Perches475be4d2012-02-19 19:52:38 -08008316 if (llc[1] == X75_V42BIS) {
8317 if (b2_config->length >= 10) {
8318 dlc[7] = 6;
8319 dlc[8] = 0;
8320 dlc[9] = b2_config_parms[4].info[0];
8321 dlc[10] = b2_config_parms[4].info[1];
8322 dlc[11] = b2_config_parms[5].info[0];
8323 dlc[12] = b2_config_parms[5].info[1];
8324 dlc[13] = b2_config_parms[6].info[0];
8325 dlc[14] = b2_config_parms[6].info[1];
8326 dlc[0] = 14;
8327 dbug(1, dprintf("b2_config_parms[4].info[0] [1]: %x %x", b2_config_parms[4].info[0], b2_config_parms[4].info[1]));
8328 dbug(1, dprintf("b2_config_parms[5].info[0] [1]: %x %x", b2_config_parms[5].info[0], b2_config_parms[5].info[1]));
8329 dbug(1, dprintf("b2_config_parms[6].info[0] [1]: %x %x", b2_config_parms[6].info[0], b2_config_parms[6].info[1]));
8330 }
8331 else {
8332 dlc[6] = 14;
8333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008334
Joe Perches475be4d2012-02-19 19:52:38 -08008335 }
8336 else {
8337 PUT_WORD(&dlc[7], (word)b2_config_parms[4].length);
8338 for (i = 0; i < b2_config_parms[4].length; i++)
8339 dlc[11 + i] = b2_config_parms[4].info[1 + i];
8340 }
8341 }
8342 }
8343 }
8344 add_p(plci, DLC, dlc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008345
Joe Perches475be4d2012-02-19 19:52:38 -08008346 b3_config = &bp_parms[5];
8347 if (b3_config->length)
8348 {
8349 if (plci->B3_prot == 4
8350 || plci->B3_prot == 5)
8351 {
8352 if (api_parse(&b3_config->info[1], (word)b3_config->length, "wwss", b3_config_parms))
8353 {
8354 return _WRONG_MESSAGE_FORMAT;
8355 }
8356 i = GET_WORD((byte *)(b3_config_parms[0].info));
8357 ((T30_INFO *)&nlc[1])->resolution = (byte)(((i & 0x0001) ||
8358 ((plci->B3_prot == 4) && (((byte)(GET_WORD((byte *)b3_config_parms[1].info))) != 5))) ? T30_RESOLUTION_R8_0770_OR_200 : 0);
8359 ((T30_INFO *)&nlc[1])->data_format = (byte)(GET_WORD((byte *)b3_config_parms[1].info));
8360 fax_control_bits = T30_CONTROL_BIT_ALL_FEATURES;
8361 if ((((T30_INFO *)&nlc[1])->rate_div_2400 != 0) && (((T30_INFO *)&nlc[1])->rate_div_2400 <= 6))
8362 fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_V34FAX;
8363 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
8364 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008365
Joe Perches475be4d2012-02-19 19:52:38 -08008366 if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id - 1])
8367 & (1L << PRIVATE_FAX_PAPER_FORMATS))
8368 {
8369 ((T30_INFO *)&nlc[1])->resolution |= T30_RESOLUTION_R8_1540 |
8370 T30_RESOLUTION_R16_1540_OR_400 | T30_RESOLUTION_300_300 |
8371 T30_RESOLUTION_INCH_BASED | T30_RESOLUTION_METRIC_BASED;
8372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008373
Joe Perches475be4d2012-02-19 19:52:38 -08008374 ((T30_INFO *)&nlc[1])->recording_properties =
8375 T30_RECORDING_WIDTH_ISO_A3 |
8376 (T30_RECORDING_LENGTH_UNLIMITED << 2) |
8377 (T30_MIN_SCANLINE_TIME_00_00_00 << 4);
8378 }
8379 if (plci->B3_prot == 5)
8380 {
8381 if (i & 0x0002) /* Accept incoming fax-polling requests */
8382 fax_control_bits |= T30_CONTROL_BIT_ACCEPT_POLLING;
8383 if (i & 0x2000) /* Do not use MR compression */
8384 fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_2D_CODING;
8385 if (i & 0x4000) /* Do not use MMR compression */
8386 fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_T6_CODING;
8387 if (i & 0x8000) /* Do not use ECM */
8388 fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_ECM;
8389 if (plci->fax_connect_info_length != 0)
8390 {
8391 ((T30_INFO *)&nlc[1])->resolution = ((T30_INFO *)plci->fax_connect_info_buffer)->resolution;
8392 ((T30_INFO *)&nlc[1])->data_format = ((T30_INFO *)plci->fax_connect_info_buffer)->data_format;
8393 ((T30_INFO *)&nlc[1])->recording_properties = ((T30_INFO *)plci->fax_connect_info_buffer)->recording_properties;
8394 fax_control_bits |= GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low) &
8395 (T30_CONTROL_BIT_REQUEST_POLLING | T30_CONTROL_BIT_MORE_DOCUMENTS);
8396 }
8397 }
8398 /* copy station id to NLC */
8399 for (i = 0; i < T30_MAX_STATION_ID_LENGTH; i++)
8400 {
8401 if (i < b3_config_parms[2].length)
8402 {
8403 ((T30_INFO *)&nlc[1])->station_id[i] = ((byte *)b3_config_parms[2].info)[1 + i];
8404 }
8405 else
8406 {
8407 ((T30_INFO *)&nlc[1])->station_id[i] = ' ';
8408 }
8409 }
8410 ((T30_INFO *)&nlc[1])->station_id_len = T30_MAX_STATION_ID_LENGTH;
8411 /* copy head line to NLC */
8412 if (b3_config_parms[3].length)
8413 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008414
Joe Perches475be4d2012-02-19 19:52:38 -08008415 pos = (byte)(fax_head_line_time(&(((T30_INFO *)&nlc[1])->station_id[T30_MAX_STATION_ID_LENGTH])));
8416 if (pos != 0)
8417 {
8418 if (CAPI_MAX_DATE_TIME_LENGTH + 2 + b3_config_parms[3].length > CAPI_MAX_HEAD_LINE_SPACE)
8419 pos = 0;
8420 else
8421 {
8422 nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ' ';
8423 nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ' ';
8424 len = (byte)b3_config_parms[2].length;
8425 if (len > 20)
8426 len = 20;
8427 if (CAPI_MAX_DATE_TIME_LENGTH + 2 + len + 2 + b3_config_parms[3].length <= CAPI_MAX_HEAD_LINE_SPACE)
8428 {
8429 for (i = 0; i < len; i++)
8430 nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ((byte *)b3_config_parms[2].info)[1 + i];
8431 nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ' ';
8432 nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ' ';
8433 }
8434 }
8435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008436
Joe Perches475be4d2012-02-19 19:52:38 -08008437 len = (byte)b3_config_parms[3].length;
8438 if (len > CAPI_MAX_HEAD_LINE_SPACE - pos)
8439 len = (byte)(CAPI_MAX_HEAD_LINE_SPACE - pos);
8440 ((T30_INFO *)&nlc[1])->head_line_len = (byte)(pos + len);
8441 nlc[0] += (byte)(pos + len);
8442 for (i = 0; i < len; i++)
8443 nlc[1 + offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH + pos++] = ((byte *)b3_config_parms[3].info)[1 + i];
8444 } else
8445 ((T30_INFO *)&nlc[1])->head_line_len = 0;
8446
8447 plci->nsf_control_bits = 0;
8448 if (plci->B3_prot == 5)
8449 {
8450 if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_FAX_SUB_SEP_PWD))
8451 && (GET_WORD((byte *)b3_config_parms[1].info) & 0x8000)) /* Private SUB/SEP/PWD enable */
8452 {
8453 plci->requested_options |= 1L << PRIVATE_FAX_SUB_SEP_PWD;
8454 }
8455 if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_FAX_NONSTANDARD))
8456 && (GET_WORD((byte *)b3_config_parms[1].info) & 0x4000)) /* Private non-standard facilities enable */
8457 {
8458 plci->requested_options |= 1L << PRIVATE_FAX_NONSTANDARD;
8459 }
8460 if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id - 1])
8461 & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
8462 {
8463 if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id - 1])
8464 & (1L << PRIVATE_FAX_SUB_SEP_PWD))
8465 {
8466 fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_PASSWORD;
8467 if (fax_control_bits & T30_CONTROL_BIT_ACCEPT_POLLING)
8468 fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SEL_POLLING;
8469 }
8470 len = nlc[0];
8471 pos = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH;
8472 if (pos < plci->fax_connect_info_length)
8473 {
8474 for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--)
8475 nlc[++len] = plci->fax_connect_info_buffer[pos++];
8476 }
8477 else
8478 nlc[++len] = 0;
8479 if (pos < plci->fax_connect_info_length)
8480 {
8481 for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--)
8482 nlc[++len] = plci->fax_connect_info_buffer[pos++];
8483 }
8484 else
8485 nlc[++len] = 0;
8486 if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id - 1])
8487 & (1L << PRIVATE_FAX_NONSTANDARD))
8488 {
8489 if ((pos < plci->fax_connect_info_length) && (plci->fax_connect_info_buffer[pos] != 0))
8490 {
8491 if ((plci->fax_connect_info_buffer[pos] >= 3) && (plci->fax_connect_info_buffer[pos + 1] >= 2))
8492 plci->nsf_control_bits = GET_WORD(&plci->fax_connect_info_buffer[pos + 2]);
8493 for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--)
8494 nlc[++len] = plci->fax_connect_info_buffer[pos++];
8495 }
8496 else
8497 {
8498 if (api_parse(&b3_config->info[1], (word)b3_config->length, "wwsss", b3_config_parms))
8499 {
8500 dbug(1, dprintf("non-standard facilities info missing or wrong format"));
8501 nlc[++len] = 0;
8502 }
8503 else
8504 {
8505 if ((b3_config_parms[4].length >= 3) && (b3_config_parms[4].info[1] >= 2))
8506 plci->nsf_control_bits = GET_WORD(&b3_config_parms[4].info[2]);
8507 nlc[++len] = (byte)(b3_config_parms[4].length);
8508 for (i = 0; i < b3_config_parms[4].length; i++)
8509 nlc[++len] = b3_config_parms[4].info[1 + i];
8510 }
8511 }
8512 }
8513 nlc[0] = len;
8514 if ((plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF)
8515 && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP))
8516 {
8517 ((T30_INFO *)&nlc[1])->operating_mode = T30_OPERATING_MODE_CAPI_NEG;
8518 }
8519 }
8520 }
8521
8522 PUT_WORD(&(((T30_INFO *)&nlc[1])->control_bits_low), fax_control_bits);
8523 len = offsetof(T30_INFO, station_id) + T30_MAX_STATION_ID_LENGTH;
8524 for (i = 0; i < len; i++)
8525 plci->fax_connect_info_buffer[i] = nlc[1 + i];
8526 ((T30_INFO *) plci->fax_connect_info_buffer)->head_line_len = 0;
8527 i += ((T30_INFO *)&nlc[1])->head_line_len;
8528 while (i < nlc[0])
8529 plci->fax_connect_info_buffer[len++] = nlc[++i];
8530 plci->fax_connect_info_length = len;
8531 }
8532 else
8533 {
8534 nlc[0] = 14;
8535 if (b3_config->length != 16)
8536 return _B3_PARM_NOT_SUPPORTED;
8537 for (i = 0; i < 12; i++) nlc[1 + i] = b3_config->info[1 + i];
8538 if (GET_WORD(&b3_config->info[13]) != 8 && GET_WORD(&b3_config->info[13]) != 128)
8539 return _B3_PARM_NOT_SUPPORTED;
8540 nlc[13] = b3_config->info[13];
8541 if (GET_WORD(&b3_config->info[15]) >= nlc[13])
8542 return _B3_PARM_NOT_SUPPORTED;
8543 nlc[14] = b3_config->info[15];
8544 }
8545 }
8546 else
8547 {
8548 if (plci->B3_prot == 4
8549 || plci->B3_prot == 5 /*T.30 - FAX*/) return _B3_PARM_NOT_SUPPORTED;
8550 }
8551 add_p(plci, NLC, nlc);
8552 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008553}
8554
8555/*----------------------------------------------------------------*/
8556/* make the same as add_b23, but only for the modem related */
8557/* L2 and L3 B-Chan protocol. */
8558/* */
8559/* Enabled L2 and L3 Configurations: */
8560/* If L1 == Modem all negotiation */
8561/* only L2 == Modem with full negotiation is allowed */
8562/* If L1 == Modem async or sync */
8563/* only L2 == Transparent is allowed */
8564/* L3 == Modem or L3 == Transparent are allowed */
8565/* B2 Configuration for modem: */
8566/* word : enable/disable compression, bitoptions */
8567/* B3 Configuration for modem: */
8568/* empty */
8569/*----------------------------------------------------------------*/
Joe Perches475be4d2012-02-19 19:52:38 -08008570static word add_modem_b23(PLCI *plci, API_PARSE *bp_parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008571{
Joe Perches475be4d2012-02-19 19:52:38 -08008572 static byte lli[12] = {1,1};
8573 static byte llc[3] = {2,0,0};
8574 static byte dlc[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
8575 API_PARSE mdm_config[2];
8576 word i;
8577 word b2_config = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008578
Joe Perches475be4d2012-02-19 19:52:38 -08008579 for (i = 0; i < 2; i++) mdm_config[i].length = 0;
8580 for (i = 0; i < sizeof(dlc); i++) dlc[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008581
Joe Perches475be4d2012-02-19 19:52:38 -08008582 if (((GET_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE)
8583 && (GET_WORD(bp_parms[1].info) != B2_MODEM_EC_COMPRESSION))
8584 || ((GET_WORD(bp_parms[0].info) != B1_MODEM_ALL_NEGOTIATE)
8585 && (GET_WORD(bp_parms[1].info) != B2_TRANSPARENT)))
8586 {
8587 return (_B_STACK_NOT_SUPPORTED);
8588 }
8589 if ((GET_WORD(bp_parms[2].info) != B3_MODEM)
8590 && (GET_WORD(bp_parms[2].info) != B3_TRANSPARENT))
8591 {
8592 return (_B_STACK_NOT_SUPPORTED);
8593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008594
Joe Perches475be4d2012-02-19 19:52:38 -08008595 plci->B2_prot = (byte) GET_WORD(bp_parms[1].info);
8596 plci->B3_prot = (byte) GET_WORD(bp_parms[2].info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008597
Joe Perches475be4d2012-02-19 19:52:38 -08008598 if ((GET_WORD(bp_parms[1].info) == B2_MODEM_EC_COMPRESSION) && bp_parms[4].length)
8599 {
8600 if (api_parse(&bp_parms[4].info[1],
8601 (word)bp_parms[4].length, "w",
8602 mdm_config))
8603 {
8604 return (_WRONG_MESSAGE_FORMAT);
8605 }
8606 b2_config = GET_WORD(mdm_config[0].info);
8607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008608
Joe Perches475be4d2012-02-19 19:52:38 -08008609 /* OK, L2 is modem */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008610
Joe Perches475be4d2012-02-19 19:52:38 -08008611 lli[0] = 1;
8612 lli[1] = 1;
8613 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)
8614 lli[1] |= 2;
8615 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL)
8616 lli[1] |= 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008617
Joe Perches475be4d2012-02-19 19:52:38 -08008618 if ((lli[1] & 0x02) && (diva_xdi_extended_features & DIVA_CAPI_USE_CMA)) {
8619 lli[1] |= 0x10;
8620 if (plci->rx_dma_descriptor <= 0) {
8621 plci->rx_dma_descriptor = diva_get_dma_descriptor(plci, &plci->rx_dma_magic);
8622 if (plci->rx_dma_descriptor >= 0)
8623 plci->rx_dma_descriptor++;
8624 }
8625 if (plci->rx_dma_descriptor > 0) {
8626 lli[1] |= 0x40;
8627 lli[0] = 6;
8628 lli[2] = (byte)(plci->rx_dma_descriptor - 1);
8629 lli[3] = (byte)plci->rx_dma_magic;
8630 lli[4] = (byte)(plci->rx_dma_magic >> 8);
8631 lli[5] = (byte)(plci->rx_dma_magic >> 16);
8632 lli[6] = (byte)(plci->rx_dma_magic >> 24);
8633 }
8634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008635
Joe Perches475be4d2012-02-19 19:52:38 -08008636 if (DIVA_CAPI_SUPPORTS_NO_CANCEL(plci->adapter)) {
8637 lli[1] |= 0x20;
8638 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008639
Joe Perches475be4d2012-02-19 19:52:38 -08008640 llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ?
8641 /*V42*/ 10 : /*V42_IN*/ 9;
8642 llc[2] = 4; /* pass L3 always transparent */
8643 add_p(plci, LLI, lli);
8644 add_p(plci, LLC, llc);
8645 i = 1;
8646 PUT_WORD(&dlc[i], plci->appl->MaxDataLength);
8647 i += 2;
8648 if (GET_WORD(bp_parms[1].info) == B2_MODEM_EC_COMPRESSION)
8649 {
8650 if (bp_parms[4].length)
8651 {
8652 dbug(1, dprintf("MDM b2_config=%02x", b2_config));
8653 dlc[i++] = 3; /* Addr A */
8654 dlc[i++] = 1; /* Addr B */
8655 dlc[i++] = 7; /* modulo mode */
8656 dlc[i++] = 7; /* window size */
8657 dlc[i++] = 0; /* XID len Lo */
8658 dlc[i++] = 0; /* XID len Hi */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008659
Joe Perches475be4d2012-02-19 19:52:38 -08008660 if (b2_config & MDM_B2_DISABLE_V42bis)
8661 {
8662 dlc[i] |= DLC_MODEMPROT_DISABLE_V42_V42BIS;
8663 }
8664 if (b2_config & MDM_B2_DISABLE_MNP)
8665 {
8666 dlc[i] |= DLC_MODEMPROT_DISABLE_MNP_MNP5;
8667 }
8668 if (b2_config & MDM_B2_DISABLE_TRANS)
8669 {
8670 dlc[i] |= DLC_MODEMPROT_REQUIRE_PROTOCOL;
8671 }
8672 if (b2_config & MDM_B2_DISABLE_V42)
8673 {
8674 dlc[i] |= DLC_MODEMPROT_DISABLE_V42_DETECT;
8675 }
8676 if (b2_config & MDM_B2_DISABLE_COMP)
8677 {
8678 dlc[i] |= DLC_MODEMPROT_DISABLE_COMPRESSION;
8679 }
8680 i++;
8681 }
8682 }
8683 else
8684 {
8685 dlc[i++] = 3; /* Addr A */
8686 dlc[i++] = 1; /* Addr B */
8687 dlc[i++] = 7; /* modulo mode */
8688 dlc[i++] = 7; /* window size */
8689 dlc[i++] = 0; /* XID len Lo */
8690 dlc[i++] = 0; /* XID len Hi */
8691 dlc[i++] = DLC_MODEMPROT_DISABLE_V42_V42BIS |
8692 DLC_MODEMPROT_DISABLE_MNP_MNP5 |
8693 DLC_MODEMPROT_DISABLE_V42_DETECT |
8694 DLC_MODEMPROT_DISABLE_COMPRESSION;
8695 }
8696 dlc[0] = (byte)(i - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008697/* HexDump ("DLC", sizeof(dlc), &dlc[0]); */
Joe Perches475be4d2012-02-19 19:52:38 -08008698 add_p(plci, DLC, dlc);
8699 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008700}
8701
8702
8703/*------------------------------------------------------------------*/
8704/* send a request for the signaling entity */
8705/*------------------------------------------------------------------*/
8706
Hannes Eder465e9852009-02-25 13:11:37 +00008707static void sig_req(PLCI *plci, byte req, byte Id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008708{
Joe Perches475be4d2012-02-19 19:52:38 -08008709 if (!plci) return;
8710 if (plci->adapter->adapter_disabled) return;
8711 dbug(1, dprintf("sig_req(%x)", req));
8712 if (req == REMOVE)
8713 plci->sig_remove_id = plci->Sig.Id;
8714 if (plci->req_in == plci->req_in_start) {
8715 plci->req_in += 2;
8716 plci->RBuffer[plci->req_in++] = 0;
8717 }
8718 PUT_WORD(&plci->RBuffer[plci->req_in_start], plci->req_in-plci->req_in_start - 2);
8719 plci->RBuffer[plci->req_in++] = Id; /* sig/nl flag */
8720 plci->RBuffer[plci->req_in++] = req; /* request */
8721 plci->RBuffer[plci->req_in++] = 0; /* channel */
8722 plci->req_in_start = plci->req_in;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008723}
8724
8725/*------------------------------------------------------------------*/
8726/* send a request for the network layer entity */
8727/*------------------------------------------------------------------*/
8728
Hannes Eder4ee59d52008-12-16 01:17:33 -08008729static void nl_req_ncci(PLCI *plci, byte req, byte ncci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008730{
Joe Perches475be4d2012-02-19 19:52:38 -08008731 if (!plci) return;
8732 if (plci->adapter->adapter_disabled) return;
8733 dbug(1, dprintf("nl_req %02x %02x %02x", plci->Id, req, ncci));
8734 if (req == REMOVE)
8735 {
8736 plci->nl_remove_id = plci->NL.Id;
8737 ncci_remove(plci, 0, (byte)(ncci != 0));
8738 ncci = 0;
8739 }
8740 if (plci->req_in == plci->req_in_start) {
8741 plci->req_in += 2;
8742 plci->RBuffer[plci->req_in++] = 0;
8743 }
8744 PUT_WORD(&plci->RBuffer[plci->req_in_start], plci->req_in-plci->req_in_start - 2);
8745 plci->RBuffer[plci->req_in++] = 1; /* sig/nl flag */
8746 plci->RBuffer[plci->req_in++] = req; /* request */
8747 plci->RBuffer[plci->req_in++] = plci->adapter->ncci_ch[ncci]; /* channel */
8748 plci->req_in_start = plci->req_in;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008749}
8750
Hannes Eder4ee59d52008-12-16 01:17:33 -08008751static void send_req(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008752{
Joe Perches475be4d2012-02-19 19:52:38 -08008753 ENTITY *e;
8754 word l;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008755/* word i; */
8756
Joe Perches475be4d2012-02-19 19:52:38 -08008757 if (!plci) return;
8758 if (plci->adapter->adapter_disabled) return;
8759 channel_xmit_xon(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008760
Joe Perches475be4d2012-02-19 19:52:38 -08008761 /* if nothing to do, return */
8762 if (plci->req_in == plci->req_out) return;
8763 dbug(1, dprintf("send_req(in=%d,out=%d)", plci->req_in, plci->req_out));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008764
Joe Perches475be4d2012-02-19 19:52:38 -08008765 if (plci->nl_req || plci->sig_req) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008766
Joe Perches475be4d2012-02-19 19:52:38 -08008767 l = GET_WORD(&plci->RBuffer[plci->req_out]);
8768 plci->req_out += 2;
8769 plci->XData[0].P = &plci->RBuffer[plci->req_out];
8770 plci->req_out += l;
8771 if (plci->RBuffer[plci->req_out] == 1)
8772 {
8773 e = &plci->NL;
8774 plci->req_out++;
8775 e->Req = plci->nl_req = plci->RBuffer[plci->req_out++];
8776 e->ReqCh = plci->RBuffer[plci->req_out++];
8777 if (!(e->Id & 0x1f))
8778 {
8779 e->Id = NL_ID;
8780 plci->RBuffer[plci->req_out - 4] = CAI;
8781 plci->RBuffer[plci->req_out - 3] = 1;
8782 plci->RBuffer[plci->req_out - 2] = (plci->Sig.Id == 0xff) ? 0 : plci->Sig.Id;
8783 plci->RBuffer[plci->req_out - 1] = 0;
8784 l += 3;
8785 plci->nl_global_req = plci->nl_req;
8786 }
8787 dbug(1, dprintf("%x:NLREQ(%x:%x:%x)", plci->adapter->Id, e->Id, e->Req, e->ReqCh));
8788 }
8789 else
8790 {
8791 e = &plci->Sig;
8792 if (plci->RBuffer[plci->req_out])
8793 e->Id = plci->RBuffer[plci->req_out];
8794 plci->req_out++;
8795 e->Req = plci->sig_req = plci->RBuffer[plci->req_out++];
8796 e->ReqCh = plci->RBuffer[plci->req_out++];
8797 if (!(e->Id & 0x1f))
8798 plci->sig_global_req = plci->sig_req;
8799 dbug(1, dprintf("%x:SIGREQ(%x:%x:%x)", plci->adapter->Id, e->Id, e->Req, e->ReqCh));
8800 }
8801 plci->XData[0].PLength = l;
8802 e->X = plci->XData;
8803 plci->adapter->request(e);
8804 dbug(1, dprintf("send_ok"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008805}
8806
Hannes Eder465e9852009-02-25 13:11:37 +00008807static void send_data(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008808{
Joe Perches475be4d2012-02-19 19:52:38 -08008809 DIVA_CAPI_ADAPTER *a;
8810 DATA_B3_DESC *data;
8811 NCCI *ncci_ptr;
8812 word ncci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008813
Joe Perches475be4d2012-02-19 19:52:38 -08008814 if (!plci->nl_req && plci->ncci_ring_list)
8815 {
8816 a = plci->adapter;
8817 ncci = plci->ncci_ring_list;
8818 do
8819 {
8820 ncci = a->ncci_next[ncci];
8821 ncci_ptr = &(a->ncci[ncci]);
8822 if (!(a->ncci_ch[ncci]
8823 && (a->ch_flow_control[a->ncci_ch[ncci]] & N_OK_FC_PENDING)))
8824 {
8825 if (ncci_ptr->data_pending)
8826 {
8827 if ((a->ncci_state[ncci] == CONNECTED)
8828 || (a->ncci_state[ncci] == INC_ACT_PENDING)
8829 || (plci->send_disc == ncci))
8830 {
8831 data = &(ncci_ptr->DBuffer[ncci_ptr->data_out]);
8832 if ((plci->B2_prot == B2_V120_ASYNC)
8833 || (plci->B2_prot == B2_V120_ASYNC_V42BIS)
8834 || (plci->B2_prot == B2_V120_BIT_TRANSPARENT))
8835 {
8836 plci->NData[1].P = TransmitBufferGet(plci->appl, data->P);
8837 plci->NData[1].PLength = data->Length;
8838 if (data->Flags & 0x10)
8839 plci->NData[0].P = v120_break_header;
8840 else
8841 plci->NData[0].P = v120_default_header;
8842 plci->NData[0].PLength = 1;
8843 plci->NL.XNum = 2;
8844 plci->NL.Req = plci->nl_req = (byte)((data->Flags & 0x07) << 4 | N_DATA);
8845 }
8846 else
8847 {
8848 plci->NData[0].P = TransmitBufferGet(plci->appl, data->P);
8849 plci->NData[0].PLength = data->Length;
8850 if (data->Flags & 0x10)
8851 plci->NL.Req = plci->nl_req = (byte)N_UDATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008852
Joe Perches475be4d2012-02-19 19:52:38 -08008853 else if ((plci->B3_prot == B3_RTP) && (data->Flags & 0x01))
8854 plci->NL.Req = plci->nl_req = (byte)N_BDATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008855
Joe Perches475be4d2012-02-19 19:52:38 -08008856 else
8857 plci->NL.Req = plci->nl_req = (byte)((data->Flags & 0x07) << 4 | N_DATA);
8858 }
8859 plci->NL.X = plci->NData;
8860 plci->NL.ReqCh = a->ncci_ch[ncci];
8861 dbug(1, dprintf("%x:DREQ(%x:%x)", a->Id, plci->NL.Id, plci->NL.Req));
8862 plci->data_sent = true;
8863 plci->data_sent_ptr = data->P;
8864 a->request(&plci->NL);
8865 }
8866 else {
8867 cleanup_ncci_data(plci, ncci);
8868 }
8869 }
8870 else if (plci->send_disc == ncci)
8871 {
8872 /* dprintf("N_DISC"); */
8873 plci->NData[0].PLength = 0;
8874 plci->NL.ReqCh = a->ncci_ch[ncci];
8875 plci->NL.Req = plci->nl_req = N_DISC;
8876 a->request(&plci->NL);
8877 plci->command = _DISCONNECT_B3_R;
8878 plci->send_disc = 0;
8879 }
8880 }
8881 } while (!plci->nl_req && (ncci != plci->ncci_ring_list));
8882 plci->ncci_ring_list = ncci;
8883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008884}
8885
Hannes Eder4ee59d52008-12-16 01:17:33 -08008886static void listen_check(DIVA_CAPI_ADAPTER *a)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008887{
Joe Perches475be4d2012-02-19 19:52:38 -08008888 word i, j;
8889 PLCI *plci;
8890 byte activnotifiedcalls = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008891
Joe Perches475be4d2012-02-19 19:52:38 -08008892 dbug(1, dprintf("listen_check(%d,%d)", a->listen_active, a->max_listen));
8893 if (!remove_started && !a->adapter_disabled)
8894 {
8895 for (i = 0; i < a->max_plci; i++)
8896 {
8897 plci = &(a->plci[i]);
8898 if (plci->notifiedcall) activnotifiedcalls++;
8899 }
8900 dbug(1, dprintf("listen_check(%d)", activnotifiedcalls));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008901
Joe Perches475be4d2012-02-19 19:52:38 -08008902 for (i = a->listen_active; i < ((word)(a->max_listen + activnotifiedcalls)); i++) {
8903 if ((j = get_plci(a))) {
8904 a->listen_active++;
8905 plci = &a->plci[j - 1];
8906 plci->State = LISTENING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008907
Joe Perches475be4d2012-02-19 19:52:38 -08008908 add_p(plci, OAD, "\x01\xfd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07008909
Joe Perches475be4d2012-02-19 19:52:38 -08008910 add_p(plci, KEY, "\x04\x43\x41\x32\x30");
Linus Torvalds1da177e2005-04-16 15:20:36 -07008911
Joe Perches475be4d2012-02-19 19:52:38 -08008912 add_p(plci, CAI, "\x01\xc0");
8913 add_p(plci, UID, "\x06\x43\x61\x70\x69\x32\x30");
8914 add_p(plci, LLI, "\x01\xc4"); /* support Dummy CR FAC + MWI + SpoofNotify */
8915 add_p(plci, SHIFT | 6, NULL);
8916 add_p(plci, SIN, "\x02\x00\x00");
8917 plci->internal_command = LISTEN_SIG_ASSIGN_PEND; /* do indicate_req if OK */
8918 sig_req(plci, ASSIGN, DSIG_ID);
8919 send_req(plci);
8920 }
8921 }
8922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008923}
8924
8925/*------------------------------------------------------------------*/
8926/* functions for all parameters sent in INDs */
8927/*------------------------------------------------------------------*/
8928
Hannes Eder4ee59d52008-12-16 01:17:33 -08008929static void IndParse(PLCI *plci, word *parms_id, byte **parms, byte multiIEsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008930{
Joe Perches475be4d2012-02-19 19:52:38 -08008931 word ploc; /* points to current location within packet */
8932 byte w;
8933 byte wlen;
8934 byte codeset, lock;
8935 byte *in;
8936 word i;
8937 word code;
8938 word mIEindex = 0;
8939 ploc = 0;
8940 codeset = 0;
8941 lock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008942
Joe Perches475be4d2012-02-19 19:52:38 -08008943 in = plci->Sig.RBuffer->P;
8944 for (i = 0; i < parms_id[0]; i++) /* multiIE parms_id contains just the 1st */
8945 { /* element but parms array is larger */
8946 parms[i] = (byte *)"";
8947 }
8948 for (i = 0; i < multiIEsize; i++)
8949 {
8950 parms[i] = (byte *)"";
8951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008952
Joe Perches475be4d2012-02-19 19:52:38 -08008953 while (ploc < plci->Sig.RBuffer->length - 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008954
Joe Perches475be4d2012-02-19 19:52:38 -08008955 /* read information element id and length */
8956 w = in[ploc];
Linus Torvalds1da177e2005-04-16 15:20:36 -07008957
Joe Perches475be4d2012-02-19 19:52:38 -08008958 if (w & 0x80) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008959/* w &=0xf0; removed, cannot detect congestion levels */
8960/* upper 4 bit masked with w==SHIFT now */
Joe Perches475be4d2012-02-19 19:52:38 -08008961 wlen = 0;
8962 }
8963 else {
8964 wlen = (byte)(in[ploc + 1] + 1);
8965 }
8966 /* check if length valid (not exceeding end of packet) */
8967 if ((ploc + wlen) > 270) return;
8968 if (lock & 0x80) lock &= 0x7f;
8969 else codeset = lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008970
Joe Perches475be4d2012-02-19 19:52:38 -08008971 if ((w & 0xf0) == SHIFT) {
8972 codeset = in[ploc];
8973 if (!(codeset & 0x08)) lock = (byte)(codeset & 7);
8974 codeset &= 7;
8975 lock |= 0x80;
8976 }
8977 else {
8978 if (w == ESC && wlen >= 3) code = in[ploc + 2] | 0x800;
8979 else code = w;
8980 code |= (codeset << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008981
Joe Perches475be4d2012-02-19 19:52:38 -08008982 for (i = 1; i < parms_id[0] + 1 && parms_id[i] != code; i++);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008983
Joe Perches475be4d2012-02-19 19:52:38 -08008984 if (i < parms_id[0] + 1) {
8985 if (!multiIEsize) { /* with multiIEs use next field index, */
8986 mIEindex = i - 1; /* with normal IEs use same index like parms_id */
8987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008988
Joe Perches475be4d2012-02-19 19:52:38 -08008989 parms[mIEindex] = &in[ploc + 1];
8990 dbug(1, dprintf("mIE[%d]=0x%x", *parms[mIEindex], in[ploc]));
8991 if (parms_id[i] == OAD
8992 || parms_id[i] == CONN_NR
8993 || parms_id[i] == CAD) {
8994 if (in[ploc + 2] & 0x80) {
8995 in[ploc + 0] = (byte)(in[ploc + 1] + 1);
8996 in[ploc + 1] = (byte)(in[ploc + 2] & 0x7f);
8997 in[ploc + 2] = 0x80;
8998 parms[mIEindex] = &in[ploc];
8999 }
9000 }
9001 mIEindex++; /* effects multiIEs only */
9002 }
9003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009004
Joe Perches475be4d2012-02-19 19:52:38 -08009005 ploc += (wlen + 1);
9006 }
9007 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009008}
9009
9010/*------------------------------------------------------------------*/
9011/* try to match a cip from received BC and HLC */
9012/*------------------------------------------------------------------*/
9013
Hannes Eder4ee59d52008-12-16 01:17:33 -08009014static byte ie_compare(byte *ie1, byte *ie2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009015{
Joe Perches475be4d2012-02-19 19:52:38 -08009016 word i;
9017 if (!ie1 || !ie2) return false;
9018 if (!ie1[0]) return false;
9019 for (i = 0; i < (word)(ie1[0] + 1); i++) if (ie1[i] != ie2[i]) return false;
9020 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009021}
9022
Hannes Eder4ee59d52008-12-16 01:17:33 -08009023static word find_cip(DIVA_CAPI_ADAPTER *a, byte *bc, byte *hlc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009024{
Joe Perches475be4d2012-02-19 19:52:38 -08009025 word i;
9026 word j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009027
Joe Perches475be4d2012-02-19 19:52:38 -08009028 for (i = 9; i && !ie_compare(bc, cip_bc[i][a->u_law]); i--);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009029
Joe Perches475be4d2012-02-19 19:52:38 -08009030 for (j = 16; j < 29 &&
9031 (!ie_compare(bc, cip_bc[j][a->u_law]) || !ie_compare(hlc, cip_hlc[j])); j++);
9032 if (j == 29) return i;
9033 return j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009034}
9035
9036
Joe Perches475be4d2012-02-19 19:52:38 -08009037static byte AddInfo(byte **add_i,
9038 byte **fty_i,
9039 byte *esc_chi,
9040 byte *facility)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009041{
Joe Perches475be4d2012-02-19 19:52:38 -08009042 byte i;
9043 byte j;
9044 byte k;
9045 byte flen;
9046 byte len = 0;
9047 /* facility is a nested structure */
9048 /* FTY can be more than once */
Linus Torvalds1da177e2005-04-16 15:20:36 -07009049
Roel Kluin3eb1a6f2008-02-06 01:38:30 -08009050 if (esc_chi[0] && !(esc_chi[esc_chi[0]] & 0x7f))
Joe Perches475be4d2012-02-19 19:52:38 -08009051 {
9052 add_i[0] = (byte *)"\x02\x02\x00"; /* use neither b nor d channel */
9053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009054
Joe Perches475be4d2012-02-19 19:52:38 -08009055 else
9056 {
9057 add_i[0] = (byte *)"";
9058 }
9059 if (!fty_i[0][0])
9060 {
9061 add_i[3] = (byte *)"";
9062 }
9063 else
9064 { /* facility array found */
9065 for (i = 0, j = 1; i < MAX_MULTI_IE && fty_i[i][0]; i++)
9066 {
9067 dbug(1, dprintf("AddIFac[%d]", fty_i[i][0]));
9068 len += fty_i[i][0];
9069 len += 2;
9070 flen = fty_i[i][0];
9071 facility[j++] = 0x1c; /* copy fac IE */
9072 for (k = 0; k <= flen; k++, j++)
9073 {
9074 facility[j] = fty_i[i][k];
9075/* dbug(1, dprintf("%x ",facility[j])); */
9076 }
9077 }
9078 facility[0] = len;
9079 add_i[3] = facility;
9080 }
9081/* dbug(1, dprintf("FacArrLen=%d ",len)); */
9082 len = add_i[0][0] + add_i[1][0] + add_i[2][0] + add_i[3][0];
9083 len += 4; /* calculate length of all */
9084 return (len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009085}
9086
9087/*------------------------------------------------------------------*/
9088/* voice and codec features */
9089/*------------------------------------------------------------------*/
9090
Hannes Eder4ee59d52008-12-16 01:17:33 -08009091static void SetVoiceChannel(PLCI *plci, byte *chi, DIVA_CAPI_ADAPTER *a)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009092{
Joe Perches475be4d2012-02-19 19:52:38 -08009093 byte voice_chi[] = "\x02\x18\x01";
9094 byte channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009095
Joe Perches475be4d2012-02-19 19:52:38 -08009096 channel = chi[chi[0]] & 0x3;
9097 dbug(1, dprintf("ExtDevON(Ch=0x%x)", channel));
9098 voice_chi[2] = (channel) ? channel : 1;
9099 add_p(plci, FTY, "\x02\x01\x07"); /* B On, default on 1 */
9100 add_p(plci, ESC, voice_chi); /* Channel */
9101 sig_req(plci, TEL_CTRL, 0);
9102 send_req(plci);
9103 if (a->AdvSignalPLCI)
9104 {
9105 adv_voice_write_coefs(a->AdvSignalPLCI, ADV_VOICE_WRITE_ACTIVATION);
9106 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009107}
9108
Hannes Eder4ee59d52008-12-16 01:17:33 -08009109static void VoiceChannelOff(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009110{
Joe Perches475be4d2012-02-19 19:52:38 -08009111 dbug(1, dprintf("ExtDevOFF"));
9112 add_p(plci, FTY, "\x02\x01\x08"); /* B Off */
9113 sig_req(plci, TEL_CTRL, 0);
9114 send_req(plci);
9115 if (plci->adapter->AdvSignalPLCI)
9116 {
9117 adv_voice_clear_config(plci->adapter->AdvSignalPLCI);
9118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009119}
9120
9121
Hannes Eder4ee59d52008-12-16 01:17:33 -08009122static word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl,
9123 byte hook_listen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009124{
Joe Perches475be4d2012-02-19 19:52:38 -08009125 word j;
9126 PLCI *splci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009127
Joe Perches475be4d2012-02-19 19:52:38 -08009128 /* check if hardware supports handset with hook states (adv.codec) */
9129 /* or if just a on board codec is supported */
9130 /* the advanced codec plci is just for internal use */
Linus Torvalds1da177e2005-04-16 15:20:36 -07009131
Joe Perches475be4d2012-02-19 19:52:38 -08009132 /* diva Pro with on-board codec: */
9133 if (a->profile.Global_Options & HANDSET)
9134 {
9135 /* new call, but hook states are already signalled */
9136 if (a->AdvCodecFLAG)
9137 {
9138 if (a->AdvSignalAppl != appl || a->AdvSignalPLCI)
9139 {
9140 dbug(1, dprintf("AdvSigPlci=0x%x", a->AdvSignalPLCI));
9141 return 0x2001; /* codec in use by another application */
9142 }
9143 if (plci != NULL)
9144 {
9145 a->AdvSignalPLCI = plci;
9146 plci->tel = ADV_VOICE;
9147 }
9148 return 0; /* adv codec still used */
9149 }
9150 if ((j = get_plci(a)))
9151 {
9152 splci = &a->plci[j - 1];
9153 splci->tel = CODEC_PERMANENT;
9154 /* hook_listen indicates if a facility_req with handset/hook support */
9155 /* was sent. Otherwise if just a call on an external device was made */
9156 /* the codec will be used but the hook info will be discarded (just */
9157 /* the external controller is in use */
9158 if (hook_listen) splci->State = ADVANCED_VOICE_SIG;
9159 else
9160 {
9161 splci->State = ADVANCED_VOICE_NOSIG;
9162 if (plci)
9163 {
9164 plci->spoofed_msg = SPOOFING_REQUIRED;
9165 }
9166 /* indicate D-ch connect if */
9167 } /* codec is connected OK */
9168 if (plci != NULL)
9169 {
9170 a->AdvSignalPLCI = plci;
9171 plci->tel = ADV_VOICE;
9172 }
9173 a->AdvSignalAppl = appl;
9174 a->AdvCodecFLAG = true;
9175 a->AdvCodecPLCI = splci;
9176 add_p(splci, CAI, "\x01\x15");
9177 add_p(splci, LLI, "\x01\x00");
9178 add_p(splci, ESC, "\x02\x18\x00");
9179 add_p(splci, UID, "\x06\x43\x61\x70\x69\x32\x30");
9180 splci->internal_command = PERM_COD_ASSIGN;
9181 dbug(1, dprintf("Codec Assign"));
9182 sig_req(splci, ASSIGN, DSIG_ID);
9183 send_req(splci);
9184 }
9185 else
9186 {
9187 return 0x2001; /* wrong state, no more plcis */
9188 }
9189 }
9190 else if (a->profile.Global_Options & ON_BOARD_CODEC)
9191 {
9192 if (hook_listen) return 0x300B; /* Facility not supported */
9193 /* no hook with SCOM */
9194 if (plci != NULL) plci->tel = CODEC;
9195 dbug(1, dprintf("S/SCOM codec"));
9196 /* first time we use the scom-s codec we must shut down the internal */
9197 /* handset application of the card. This can be done by an assign with */
9198 /* a cai with the 0x80 bit set. Assign return code is 'out of resource'*/
9199 if (!a->scom_appl_disable) {
9200 if ((j = get_plci(a))) {
9201 splci = &a->plci[j - 1];
9202 add_p(splci, CAI, "\x01\x80");
9203 add_p(splci, UID, "\x06\x43\x61\x70\x69\x32\x30");
9204 sig_req(splci, ASSIGN, 0xC0); /* 0xc0 is the TEL_ID */
9205 send_req(splci);
9206 a->scom_appl_disable = true;
9207 }
9208 else{
9209 return 0x2001; /* wrong state, no more plcis */
9210 }
9211 }
9212 }
9213 else return 0x300B; /* Facility not supported */
Linus Torvalds1da177e2005-04-16 15:20:36 -07009214
Joe Perches475be4d2012-02-19 19:52:38 -08009215 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009216}
9217
9218
Hannes Eder4ee59d52008-12-16 01:17:33 -08009219static void CodecIdCheck(DIVA_CAPI_ADAPTER *a, PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009220{
9221
Joe Perches475be4d2012-02-19 19:52:38 -08009222 dbug(1, dprintf("CodecIdCheck"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009223
Joe Perches475be4d2012-02-19 19:52:38 -08009224 if (a->AdvSignalPLCI == plci)
9225 {
9226 dbug(1, dprintf("PLCI owns codec"));
9227 VoiceChannelOff(a->AdvCodecPLCI);
9228 if (a->AdvCodecPLCI->State == ADVANCED_VOICE_NOSIG)
9229 {
9230 dbug(1, dprintf("remove temp codec PLCI"));
9231 plci_remove(a->AdvCodecPLCI);
9232 a->AdvCodecFLAG = 0;
9233 a->AdvCodecPLCI = NULL;
9234 a->AdvSignalAppl = NULL;
9235 }
9236 a->AdvSignalPLCI = NULL;
9237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009238}
9239
9240/* -------------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -08009241 Ask for physical address of card on PCI bus
Linus Torvalds1da177e2005-04-16 15:20:36 -07009242 ------------------------------------------------------------------- */
Joe Perches475be4d2012-02-19 19:52:38 -08009243static void diva_ask_for_xdi_sdram_bar(DIVA_CAPI_ADAPTER *a,
9244 IDI_SYNC_REQ *preq) {
9245 a->sdram_bar = 0;
9246 if (diva_xdi_extended_features & DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR) {
9247 ENTITY *e = (ENTITY *)preq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009248
Joe Perches475be4d2012-02-19 19:52:38 -08009249 e->user[0] = a->Id - 1;
9250 preq->xdi_sdram_bar.info.bar = 0;
9251 preq->xdi_sdram_bar.Req = 0;
9252 preq->xdi_sdram_bar.Rc = IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009253
Joe Perches475be4d2012-02-19 19:52:38 -08009254 (*(a->request))(e);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009255
Joe Perches475be4d2012-02-19 19:52:38 -08009256 a->sdram_bar = preq->xdi_sdram_bar.info.bar;
9257 dbug(3, dprintf("A(%d) SDRAM BAR = %08x", a->Id, a->sdram_bar));
9258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009259}
9260
9261/* -------------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -08009262 Ask XDI about extended features
Linus Torvalds1da177e2005-04-16 15:20:36 -07009263 ------------------------------------------------------------------- */
Joe Perches475be4d2012-02-19 19:52:38 -08009264static void diva_get_extended_adapter_features(DIVA_CAPI_ADAPTER *a) {
9265 IDI_SYNC_REQ *preq;
9266 char buffer[((sizeof(preq->xdi_extended_features) + 4) > sizeof(ENTITY)) ? (sizeof(preq->xdi_extended_features) + 4) : sizeof(ENTITY)];
Linus Torvalds1da177e2005-04-16 15:20:36 -07009267
Joe Perches475be4d2012-02-19 19:52:38 -08009268 char features[4];
9269 preq = (IDI_SYNC_REQ *)&buffer[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07009270
Joe Perches475be4d2012-02-19 19:52:38 -08009271 if (!diva_xdi_extended_features) {
9272 ENTITY *e = (ENTITY *)preq;
9273 diva_xdi_extended_features |= 0x80000000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009274
Joe Perches475be4d2012-02-19 19:52:38 -08009275 e->user[0] = a->Id - 1;
9276 preq->xdi_extended_features.Req = 0;
9277 preq->xdi_extended_features.Rc = IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES;
9278 preq->xdi_extended_features.info.buffer_length_in_bytes = sizeof(features);
9279 preq->xdi_extended_features.info.features = &features[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07009280
Joe Perches475be4d2012-02-19 19:52:38 -08009281 (*(a->request))(e);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009282
Joe Perches475be4d2012-02-19 19:52:38 -08009283 if (features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) {
9284 /*
9285 Check features located in the byte '0'
9286 */
9287 if (features[0] & DIVA_XDI_EXTENDED_FEATURE_CMA) {
9288 diva_xdi_extended_features |= DIVA_CAPI_USE_CMA;
9289 }
9290 if (features[0] & DIVA_XDI_EXTENDED_FEATURE_RX_DMA) {
9291 diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_RX_DMA;
9292 dbug(1, dprintf("XDI provides RxDMA"));
9293 }
9294 if (features[0] & DIVA_XDI_EXTENDED_FEATURE_SDRAM_BAR) {
9295 diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR;
9296 }
9297 if (features[0] & DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC) {
9298 diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_NO_CANCEL;
9299 dbug(3, dprintf("XDI provides NO_CANCEL_RC feature"));
9300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009301
Joe Perches475be4d2012-02-19 19:52:38 -08009302 }
9303 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009304
Joe Perches475be4d2012-02-19 19:52:38 -08009305 diva_ask_for_xdi_sdram_bar(a, preq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009306}
9307
9308/*------------------------------------------------------------------*/
9309/* automatic law */
9310/*------------------------------------------------------------------*/
9311/* called from OS specific part after init time to get the Law */
9312/* a-law (Euro) and u-law (us,japan) use different BCs in the Setup message */
Joe Perches475be4d2012-02-19 19:52:38 -08009313void AutomaticLaw(DIVA_CAPI_ADAPTER *a)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009314{
Joe Perches475be4d2012-02-19 19:52:38 -08009315 word j;
9316 PLCI *splci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009317
Joe Perches475be4d2012-02-19 19:52:38 -08009318 if (a->automatic_law) {
9319 return;
9320 }
9321 if ((j = get_plci(a))) {
9322 diva_get_extended_adapter_features(a);
9323 splci = &a->plci[j - 1];
9324 a->automatic_lawPLCI = splci;
9325 a->automatic_law = 1;
9326 add_p(splci, CAI, "\x01\x80");
9327 add_p(splci, UID, "\x06\x43\x61\x70\x69\x32\x30");
9328 splci->internal_command = USELAW_REQ;
9329 splci->command = 0;
9330 splci->number = 0;
9331 sig_req(splci, ASSIGN, DSIG_ID);
9332 send_req(splci);
9333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009334}
9335
9336/* called from OS specific part if an application sends an Capi20Release */
9337word CapiRelease(word Id)
9338{
Joe Perches475be4d2012-02-19 19:52:38 -08009339 word i, j, appls_found;
9340 PLCI *plci;
9341 APPL *this;
9342 DIVA_CAPI_ADAPTER *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009343
Joe Perches475be4d2012-02-19 19:52:38 -08009344 if (!Id)
9345 {
9346 dbug(0, dprintf("A: CapiRelease(Id==0)"));
9347 return (_WRONG_APPL_ID);
9348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009349
Joe Perches475be4d2012-02-19 19:52:38 -08009350 this = &application[Id - 1]; /* get application pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07009351
Joe Perches475be4d2012-02-19 19:52:38 -08009352 for (i = 0, appls_found = 0; i < max_appl; i++)
9353 {
9354 if (application[i].Id) /* an application has been found */
9355 {
9356 appls_found++;
9357 }
9358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009359
Joe Perches475be4d2012-02-19 19:52:38 -08009360 for (i = 0; i < max_adapter; i++) /* scan all adapters... */
9361 {
9362 a = &adapter[i];
9363 if (a->request)
9364 {
9365 a->Info_Mask[Id - 1] = 0;
9366 a->CIP_Mask[Id - 1] = 0;
9367 a->Notification_Mask[Id - 1] = 0;
9368 a->codec_listen[Id - 1] = NULL;
9369 a->requested_options_table[Id - 1] = 0;
9370 for (j = 0; j < a->max_plci; j++) /* and all PLCIs connected */
9371 { /* with this application */
9372 plci = &a->plci[j];
9373 if (plci->Id) /* if plci owns no application */
9374 { /* it may be not jet connected */
9375 if (plci->State == INC_CON_PENDING
9376 || plci->State == INC_CON_ALERT)
9377 {
9378 if (test_c_ind_mask_bit(plci, (word)(Id - 1)))
9379 {
9380 clear_c_ind_mask_bit(plci, (word)(Id - 1));
9381 if (c_ind_mask_empty(plci))
9382 {
9383 sig_req(plci, HANGUP, 0);
9384 send_req(plci);
9385 plci->State = OUTG_DIS_PENDING;
9386 }
9387 }
9388 }
9389 if (test_c_ind_mask_bit(plci, (word)(Id - 1)))
9390 {
9391 clear_c_ind_mask_bit(plci, (word)(Id - 1));
9392 if (c_ind_mask_empty(plci))
9393 {
9394 if (!plci->appl)
9395 {
9396 plci_remove(plci);
9397 plci->State = IDLE;
9398 }
9399 }
9400 }
9401 if (plci->appl == this)
9402 {
9403 plci->appl = NULL;
9404 plci_remove(plci);
9405 plci->State = IDLE;
9406 }
9407 }
9408 }
9409 listen_check(a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009410
Joe Perches475be4d2012-02-19 19:52:38 -08009411 if (a->flag_dynamic_l1_down)
9412 {
9413 if (appls_found == 1) /* last application does a capi release */
9414 {
9415 if ((j = get_plci(a)))
9416 {
9417 plci = &a->plci[j - 1];
9418 plci->command = 0;
9419 add_p(plci, OAD, "\x01\xfd");
9420 add_p(plci, CAI, "\x01\x80");
9421 add_p(plci, UID, "\x06\x43\x61\x70\x69\x32\x30");
9422 add_p(plci, SHIFT | 6, NULL);
9423 add_p(plci, SIN, "\x02\x00\x00");
9424 plci->internal_command = REM_L1_SIG_ASSIGN_PEND;
9425 sig_req(plci, ASSIGN, DSIG_ID);
9426 add_p(plci, FTY, "\x02\xff\x06"); /* l1 down */
9427 sig_req(plci, SIG_CTRL, 0);
9428 send_req(plci);
9429 }
9430 }
9431 }
9432 if (a->AdvSignalAppl == this)
9433 {
9434 this->NullCREnable = false;
9435 if (a->AdvCodecPLCI)
9436 {
9437 plci_remove(a->AdvCodecPLCI);
9438 a->AdvCodecPLCI->tel = 0;
9439 a->AdvCodecPLCI->adv_nl = 0;
9440 }
9441 a->AdvSignalAppl = NULL;
9442 a->AdvSignalPLCI = NULL;
9443 a->AdvCodecFLAG = 0;
9444 a->AdvCodecPLCI = NULL;
9445 }
9446 }
9447 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009448
Joe Perches475be4d2012-02-19 19:52:38 -08009449 this->Id = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009450
Joe Perches475be4d2012-02-19 19:52:38 -08009451 return GOOD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009452}
9453
Joe Perches475be4d2012-02-19 19:52:38 -08009454static word plci_remove_check(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009455{
Joe Perches475be4d2012-02-19 19:52:38 -08009456 if (!plci) return true;
9457 if (!plci->NL.Id && c_ind_mask_empty(plci))
9458 {
9459 if (plci->Sig.Id == 0xff)
9460 plci->Sig.Id = 0;
9461 if (!plci->Sig.Id)
9462 {
9463 dbug(1, dprintf("plci_remove_complete(%x)", plci->Id));
9464 dbug(1, dprintf("tel=0x%x,Sig=0x%x", plci->tel, plci->Sig.Id));
9465 if (plci->Id)
9466 {
9467 CodecIdCheck(plci->adapter, plci);
9468 clear_b1_config(plci);
9469 ncci_remove(plci, 0, false);
9470 plci_free_msg_in_queue(plci);
9471 channel_flow_control_remove(plci);
9472 plci->Id = 0;
9473 plci->State = IDLE;
9474 plci->channels = 0;
9475 plci->appl = NULL;
9476 plci->notifiedcall = 0;
9477 }
9478 listen_check(plci->adapter);
9479 return true;
9480 }
9481 }
9482 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009483}
9484
9485
9486/*------------------------------------------------------------------*/
9487
Joe Perches475be4d2012-02-19 19:52:38 -08009488static byte plci_nl_busy(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009489{
Joe Perches475be4d2012-02-19 19:52:38 -08009490 /* only applicable for non-multiplexed protocols */
9491 return (plci->nl_req
9492 || (plci->ncci_ring_list
9493 && plci->adapter->ncci_ch[plci->ncci_ring_list]
9494 && (plci->adapter->ch_flow_control[plci->adapter->ncci_ch[plci->ncci_ring_list]] & N_OK_FC_PENDING)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009495}
9496
9497
9498/*------------------------------------------------------------------*/
9499/* DTMF facilities */
9500/*------------------------------------------------------------------*/
9501
9502
9503static struct
9504{
Joe Perches475be4d2012-02-19 19:52:38 -08009505 byte send_mask;
9506 byte listen_mask;
9507 byte character;
9508 byte code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009509} dtmf_digit_map[] =
9510{
Joe Perches475be4d2012-02-19 19:52:38 -08009511 { 0x01, 0x01, 0x23, DTMF_DIGIT_TONE_CODE_HASHMARK },
9512 { 0x01, 0x01, 0x2a, DTMF_DIGIT_TONE_CODE_STAR },
9513 { 0x01, 0x01, 0x30, DTMF_DIGIT_TONE_CODE_0 },
9514 { 0x01, 0x01, 0x31, DTMF_DIGIT_TONE_CODE_1 },
9515 { 0x01, 0x01, 0x32, DTMF_DIGIT_TONE_CODE_2 },
9516 { 0x01, 0x01, 0x33, DTMF_DIGIT_TONE_CODE_3 },
9517 { 0x01, 0x01, 0x34, DTMF_DIGIT_TONE_CODE_4 },
9518 { 0x01, 0x01, 0x35, DTMF_DIGIT_TONE_CODE_5 },
9519 { 0x01, 0x01, 0x36, DTMF_DIGIT_TONE_CODE_6 },
9520 { 0x01, 0x01, 0x37, DTMF_DIGIT_TONE_CODE_7 },
9521 { 0x01, 0x01, 0x38, DTMF_DIGIT_TONE_CODE_8 },
9522 { 0x01, 0x01, 0x39, DTMF_DIGIT_TONE_CODE_9 },
9523 { 0x01, 0x01, 0x41, DTMF_DIGIT_TONE_CODE_A },
9524 { 0x01, 0x01, 0x42, DTMF_DIGIT_TONE_CODE_B },
9525 { 0x01, 0x01, 0x43, DTMF_DIGIT_TONE_CODE_C },
9526 { 0x01, 0x01, 0x44, DTMF_DIGIT_TONE_CODE_D },
9527 { 0x01, 0x00, 0x61, DTMF_DIGIT_TONE_CODE_A },
9528 { 0x01, 0x00, 0x62, DTMF_DIGIT_TONE_CODE_B },
9529 { 0x01, 0x00, 0x63, DTMF_DIGIT_TONE_CODE_C },
9530 { 0x01, 0x00, 0x64, DTMF_DIGIT_TONE_CODE_D },
Linus Torvalds1da177e2005-04-16 15:20:36 -07009531
Joe Perches475be4d2012-02-19 19:52:38 -08009532 { 0x04, 0x04, 0x80, DTMF_SIGNAL_NO_TONE },
9533 { 0x00, 0x04, 0x81, DTMF_SIGNAL_UNIDENTIFIED_TONE },
9534 { 0x04, 0x04, 0x82, DTMF_SIGNAL_DIAL_TONE },
9535 { 0x04, 0x04, 0x83, DTMF_SIGNAL_PABX_INTERNAL_DIAL_TONE },
9536 { 0x04, 0x04, 0x84, DTMF_SIGNAL_SPECIAL_DIAL_TONE },
9537 { 0x04, 0x04, 0x85, DTMF_SIGNAL_SECOND_DIAL_TONE },
9538 { 0x04, 0x04, 0x86, DTMF_SIGNAL_RINGING_TONE },
9539 { 0x04, 0x04, 0x87, DTMF_SIGNAL_SPECIAL_RINGING_TONE },
9540 { 0x04, 0x04, 0x88, DTMF_SIGNAL_BUSY_TONE },
9541 { 0x04, 0x04, 0x89, DTMF_SIGNAL_CONGESTION_TONE },
9542 { 0x04, 0x04, 0x8a, DTMF_SIGNAL_SPECIAL_INFORMATION_TONE },
9543 { 0x04, 0x04, 0x8b, DTMF_SIGNAL_COMFORT_TONE },
9544 { 0x04, 0x04, 0x8c, DTMF_SIGNAL_HOLD_TONE },
9545 { 0x04, 0x04, 0x8d, DTMF_SIGNAL_RECORD_TONE },
9546 { 0x04, 0x04, 0x8e, DTMF_SIGNAL_CALLER_WAITING_TONE },
9547 { 0x04, 0x04, 0x8f, DTMF_SIGNAL_CALL_WAITING_TONE },
9548 { 0x04, 0x04, 0x90, DTMF_SIGNAL_PAY_TONE },
9549 { 0x04, 0x04, 0x91, DTMF_SIGNAL_POSITIVE_INDICATION_TONE },
9550 { 0x04, 0x04, 0x92, DTMF_SIGNAL_NEGATIVE_INDICATION_TONE },
9551 { 0x04, 0x04, 0x93, DTMF_SIGNAL_WARNING_TONE },
9552 { 0x04, 0x04, 0x94, DTMF_SIGNAL_INTRUSION_TONE },
9553 { 0x04, 0x04, 0x95, DTMF_SIGNAL_CALLING_CARD_SERVICE_TONE },
9554 { 0x04, 0x04, 0x96, DTMF_SIGNAL_PAYPHONE_RECOGNITION_TONE },
9555 { 0x04, 0x04, 0x97, DTMF_SIGNAL_CPE_ALERTING_SIGNAL },
9556 { 0x04, 0x04, 0x98, DTMF_SIGNAL_OFF_HOOK_WARNING_TONE },
9557 { 0x04, 0x04, 0xbf, DTMF_SIGNAL_INTERCEPT_TONE },
9558 { 0x04, 0x04, 0xc0, DTMF_SIGNAL_MODEM_CALLING_TONE },
9559 { 0x04, 0x04, 0xc1, DTMF_SIGNAL_FAX_CALLING_TONE },
9560 { 0x04, 0x04, 0xc2, DTMF_SIGNAL_ANSWER_TONE },
9561 { 0x04, 0x04, 0xc3, DTMF_SIGNAL_REVERSED_ANSWER_TONE },
9562 { 0x04, 0x04, 0xc4, DTMF_SIGNAL_ANSAM_TONE },
9563 { 0x04, 0x04, 0xc5, DTMF_SIGNAL_REVERSED_ANSAM_TONE },
9564 { 0x04, 0x04, 0xc6, DTMF_SIGNAL_BELL103_ANSWER_TONE },
9565 { 0x04, 0x04, 0xc7, DTMF_SIGNAL_FAX_FLAGS },
9566 { 0x04, 0x04, 0xc8, DTMF_SIGNAL_G2_FAX_GROUP_ID },
9567 { 0x00, 0x04, 0xc9, DTMF_SIGNAL_HUMAN_SPEECH },
9568 { 0x04, 0x04, 0xca, DTMF_SIGNAL_ANSWERING_MACHINE_390 },
9569 { 0x02, 0x02, 0xf1, DTMF_MF_DIGIT_TONE_CODE_1 },
9570 { 0x02, 0x02, 0xf2, DTMF_MF_DIGIT_TONE_CODE_2 },
9571 { 0x02, 0x02, 0xf3, DTMF_MF_DIGIT_TONE_CODE_3 },
9572 { 0x02, 0x02, 0xf4, DTMF_MF_DIGIT_TONE_CODE_4 },
9573 { 0x02, 0x02, 0xf5, DTMF_MF_DIGIT_TONE_CODE_5 },
9574 { 0x02, 0x02, 0xf6, DTMF_MF_DIGIT_TONE_CODE_6 },
9575 { 0x02, 0x02, 0xf7, DTMF_MF_DIGIT_TONE_CODE_7 },
9576 { 0x02, 0x02, 0xf8, DTMF_MF_DIGIT_TONE_CODE_8 },
9577 { 0x02, 0x02, 0xf9, DTMF_MF_DIGIT_TONE_CODE_9 },
9578 { 0x02, 0x02, 0xfa, DTMF_MF_DIGIT_TONE_CODE_0 },
9579 { 0x02, 0x02, 0xfb, DTMF_MF_DIGIT_TONE_CODE_K1 },
9580 { 0x02, 0x02, 0xfc, DTMF_MF_DIGIT_TONE_CODE_K2 },
9581 { 0x02, 0x02, 0xfd, DTMF_MF_DIGIT_TONE_CODE_KP },
9582 { 0x02, 0x02, 0xfe, DTMF_MF_DIGIT_TONE_CODE_S1 },
9583 { 0x02, 0x02, 0xff, DTMF_MF_DIGIT_TONE_CODE_ST },
Linus Torvalds1da177e2005-04-16 15:20:36 -07009584
9585};
9586
Ahmed S. Darwishf85aaeb2007-02-12 00:53:27 -08009587#define DTMF_DIGIT_MAP_ENTRIES ARRAY_SIZE(dtmf_digit_map)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009588
9589
Joe Perches475be4d2012-02-19 19:52:38 -08009590static void dtmf_enable_receiver(PLCI *plci, byte enable_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009591{
Joe Perches475be4d2012-02-19 19:52:38 -08009592 word min_digit_duration, min_gap_duration;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009593
Joe Perches475be4d2012-02-19 19:52:38 -08009594 dbug(1, dprintf("[%06lx] %s,%d: dtmf_enable_receiver %02x",
9595 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
9596 (char *)(FILE_), __LINE__, enable_mask));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009597
Joe Perches475be4d2012-02-19 19:52:38 -08009598 if (enable_mask != 0)
9599 {
9600 min_digit_duration = (plci->dtmf_rec_pulse_ms == 0) ? 40 : plci->dtmf_rec_pulse_ms;
9601 min_gap_duration = (plci->dtmf_rec_pause_ms == 0) ? 40 : plci->dtmf_rec_pause_ms;
9602 plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_ENABLE_RECEIVER;
9603 PUT_WORD(&plci->internal_req_buffer[1], min_digit_duration);
9604 PUT_WORD(&plci->internal_req_buffer[3], min_gap_duration);
9605 plci->NData[0].PLength = 5;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009606
Joe Perches475be4d2012-02-19 19:52:38 -08009607 PUT_WORD(&plci->internal_req_buffer[5], INTERNAL_IND_BUFFER_SIZE);
9608 plci->NData[0].PLength += 2;
9609 capidtmf_recv_enable(&(plci->capidtmf_state), min_digit_duration, min_gap_duration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009610
Joe Perches475be4d2012-02-19 19:52:38 -08009611 }
9612 else
9613 {
9614 plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_DISABLE_RECEIVER;
9615 plci->NData[0].PLength = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009616
Joe Perches475be4d2012-02-19 19:52:38 -08009617 capidtmf_recv_disable(&(plci->capidtmf_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009618
Joe Perches475be4d2012-02-19 19:52:38 -08009619 }
9620 plci->NData[0].P = plci->internal_req_buffer;
9621 plci->NL.X = plci->NData;
9622 plci->NL.ReqCh = 0;
9623 plci->NL.Req = plci->nl_req = (byte) N_UDATA;
9624 plci->adapter->request(&plci->NL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009625}
9626
9627
Joe Perches475be4d2012-02-19 19:52:38 -08009628static void dtmf_send_digits(PLCI *plci, byte *digit_buffer, word digit_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009629{
Joe Perches475be4d2012-02-19 19:52:38 -08009630 word w, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009631
Joe Perches475be4d2012-02-19 19:52:38 -08009632 dbug(1, dprintf("[%06lx] %s,%d: dtmf_send_digits %d",
9633 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
9634 (char *)(FILE_), __LINE__, digit_count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009635
Joe Perches475be4d2012-02-19 19:52:38 -08009636 plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_SEND_DIGITS;
9637 w = (plci->dtmf_send_pulse_ms == 0) ? 40 : plci->dtmf_send_pulse_ms;
9638 PUT_WORD(&plci->internal_req_buffer[1], w);
9639 w = (plci->dtmf_send_pause_ms == 0) ? 40 : plci->dtmf_send_pause_ms;
9640 PUT_WORD(&plci->internal_req_buffer[3], w);
9641 for (i = 0; i < digit_count; i++)
9642 {
9643 w = 0;
9644 while ((w < DTMF_DIGIT_MAP_ENTRIES)
9645 && (digit_buffer[i] != dtmf_digit_map[w].character))
9646 {
9647 w++;
9648 }
9649 plci->internal_req_buffer[5 + i] = (w < DTMF_DIGIT_MAP_ENTRIES) ?
9650 dtmf_digit_map[w].code : DTMF_DIGIT_TONE_CODE_STAR;
9651 }
9652 plci->NData[0].PLength = 5 + digit_count;
9653 plci->NData[0].P = plci->internal_req_buffer;
9654 plci->NL.X = plci->NData;
9655 plci->NL.ReqCh = 0;
9656 plci->NL.Req = plci->nl_req = (byte) N_UDATA;
9657 plci->adapter->request(&plci->NL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009658}
9659
9660
Joe Perches475be4d2012-02-19 19:52:38 -08009661static void dtmf_rec_clear_config(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009662{
9663
Joe Perches475be4d2012-02-19 19:52:38 -08009664 dbug(1, dprintf("[%06lx] %s,%d: dtmf_rec_clear_config",
9665 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
9666 (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009667
Joe Perches475be4d2012-02-19 19:52:38 -08009668 plci->dtmf_rec_active = 0;
9669 plci->dtmf_rec_pulse_ms = 0;
9670 plci->dtmf_rec_pause_ms = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009671
Joe Perches475be4d2012-02-19 19:52:38 -08009672 capidtmf_init(&(plci->capidtmf_state), plci->adapter->u_law);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009673
9674}
9675
9676
Joe Perches475be4d2012-02-19 19:52:38 -08009677static void dtmf_send_clear_config(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009678{
9679
Joe Perches475be4d2012-02-19 19:52:38 -08009680 dbug(1, dprintf("[%06lx] %s,%d: dtmf_send_clear_config",
9681 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
9682 (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009683
Joe Perches475be4d2012-02-19 19:52:38 -08009684 plci->dtmf_send_requests = 0;
9685 plci->dtmf_send_pulse_ms = 0;
9686 plci->dtmf_send_pause_ms = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009687}
9688
9689
Joe Perches475be4d2012-02-19 19:52:38 -08009690static void dtmf_prepare_switch(dword Id, PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009691{
9692
Joe Perches475be4d2012-02-19 19:52:38 -08009693 dbug(1, dprintf("[%06lx] %s,%d: dtmf_prepare_switch",
9694 UnMapId(Id), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009695
Joe Perches475be4d2012-02-19 19:52:38 -08009696 while (plci->dtmf_send_requests != 0)
9697 dtmf_confirmation(Id, plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009698}
9699
9700
Joe Perches475be4d2012-02-19 19:52:38 -08009701static word dtmf_save_config(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009702{
9703
Joe Perches475be4d2012-02-19 19:52:38 -08009704 dbug(1, dprintf("[%06lx] %s,%d: dtmf_save_config %02x %d",
9705 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009706
Joe Perches475be4d2012-02-19 19:52:38 -08009707 return (GOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009708}
9709
9710
Joe Perches475be4d2012-02-19 19:52:38 -08009711static word dtmf_restore_config(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009712{
Joe Perches475be4d2012-02-19 19:52:38 -08009713 word Info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009714
Joe Perches475be4d2012-02-19 19:52:38 -08009715 dbug(1, dprintf("[%06lx] %s,%d: dtmf_restore_config %02x %d",
9716 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009717
Joe Perches475be4d2012-02-19 19:52:38 -08009718 Info = GOOD;
9719 if (plci->B1_facilities & B1_FACILITY_DTMFR)
9720 {
9721 switch (plci->adjust_b_state)
9722 {
9723 case ADJUST_B_RESTORE_DTMF_1:
9724 plci->internal_command = plci->adjust_b_command;
9725 if (plci_nl_busy(plci))
9726 {
9727 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
9728 break;
9729 }
9730 dtmf_enable_receiver(plci, plci->dtmf_rec_active);
9731 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_2;
9732 break;
9733 case ADJUST_B_RESTORE_DTMF_2:
9734 if ((Rc != OK) && (Rc != OK_FC))
9735 {
9736 dbug(1, dprintf("[%06lx] %s,%d: Reenable DTMF receiver failed %02x",
9737 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
9738 Info = _WRONG_STATE;
9739 break;
9740 }
9741 break;
9742 }
9743 }
9744 return (Info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009745}
9746
9747
Joe Perches475be4d2012-02-19 19:52:38 -08009748static void dtmf_command(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009749{
Joe Perches475be4d2012-02-19 19:52:38 -08009750 word internal_command, Info;
9751 byte mask;
9752 byte result[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07009753
Joe Perches475be4d2012-02-19 19:52:38 -08009754 dbug(1, dprintf("[%06lx] %s,%d: dtmf_command %02x %04x %04x %d %d %d %d",
9755 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command,
9756 plci->dtmf_cmd, plci->dtmf_rec_pulse_ms, plci->dtmf_rec_pause_ms,
9757 plci->dtmf_send_pulse_ms, plci->dtmf_send_pause_ms));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009758
Joe Perches475be4d2012-02-19 19:52:38 -08009759 Info = GOOD;
9760 result[0] = 2;
9761 PUT_WORD(&result[1], DTMF_SUCCESS);
9762 internal_command = plci->internal_command;
9763 plci->internal_command = 0;
9764 mask = 0x01;
9765 switch (plci->dtmf_cmd)
9766 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009767
Joe Perches475be4d2012-02-19 19:52:38 -08009768 case DTMF_LISTEN_TONE_START:
9769 mask <<= 1;
9770 case DTMF_LISTEN_MF_START:
9771 mask <<= 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009772
Joe Perches475be4d2012-02-19 19:52:38 -08009773 case DTMF_LISTEN_START:
9774 switch (internal_command)
9775 {
9776 default:
9777 adjust_b1_resource(Id, plci, NULL, (word)(plci->B1_facilities |
9778 B1_FACILITY_DTMFR), DTMF_COMMAND_1);
9779 case DTMF_COMMAND_1:
9780 if (adjust_b_process(Id, plci, Rc) != GOOD)
9781 {
9782 dbug(1, dprintf("[%06lx] %s,%d: Load DTMF failed",
9783 UnMapId(Id), (char *)(FILE_), __LINE__));
9784 Info = _FACILITY_NOT_SUPPORTED;
9785 break;
9786 }
9787 if (plci->internal_command)
9788 return;
9789 case DTMF_COMMAND_2:
9790 if (plci_nl_busy(plci))
9791 {
9792 plci->internal_command = DTMF_COMMAND_2;
9793 return;
9794 }
9795 plci->internal_command = DTMF_COMMAND_3;
9796 dtmf_enable_receiver(plci, (byte)(plci->dtmf_rec_active | mask));
9797 return;
9798 case DTMF_COMMAND_3:
9799 if ((Rc != OK) && (Rc != OK_FC))
9800 {
9801 dbug(1, dprintf("[%06lx] %s,%d: Enable DTMF receiver failed %02x",
9802 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
9803 Info = _FACILITY_NOT_SUPPORTED;
9804 break;
9805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009806
Joe Perches475be4d2012-02-19 19:52:38 -08009807 plci->tone_last_indication_code = DTMF_SIGNAL_NO_TONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009808
Joe Perches475be4d2012-02-19 19:52:38 -08009809 plci->dtmf_rec_active |= mask;
9810 break;
9811 }
9812 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009813
9814
Joe Perches475be4d2012-02-19 19:52:38 -08009815 case DTMF_LISTEN_TONE_STOP:
9816 mask <<= 1;
9817 case DTMF_LISTEN_MF_STOP:
9818 mask <<= 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009819
Joe Perches475be4d2012-02-19 19:52:38 -08009820 case DTMF_LISTEN_STOP:
9821 switch (internal_command)
9822 {
9823 default:
9824 plci->dtmf_rec_active &= ~mask;
9825 if (plci->dtmf_rec_active)
9826 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009827/*
Joe Perches475be4d2012-02-19 19:52:38 -08009828 case DTMF_COMMAND_1:
9829 if (plci->dtmf_rec_active)
9830 {
9831 if (plci_nl_busy (plci))
9832 {
9833 plci->internal_command = DTMF_COMMAND_1;
9834 return;
9835 }
9836 plci->dtmf_rec_active &= ~mask;
9837 plci->internal_command = DTMF_COMMAND_2;
9838 dtmf_enable_receiver (plci, false);
9839 return;
9840 }
9841 Rc = OK;
9842 case DTMF_COMMAND_2:
9843 if ((Rc != OK) && (Rc != OK_FC))
9844 {
9845 dbug (1, dprintf("[%06lx] %s,%d: Disable DTMF receiver failed %02x",
9846 UnMapId (Id), (char far *)(FILE_), __LINE__, Rc));
9847 Info = _FACILITY_NOT_SUPPORTED;
9848 break;
9849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009850*/
Joe Perches475be4d2012-02-19 19:52:38 -08009851 adjust_b1_resource(Id, plci, NULL, (word)(plci->B1_facilities &
9852 ~(B1_FACILITY_DTMFX | B1_FACILITY_DTMFR)), DTMF_COMMAND_3);
9853 case DTMF_COMMAND_3:
9854 if (adjust_b_process(Id, plci, Rc) != GOOD)
9855 {
9856 dbug(1, dprintf("[%06lx] %s,%d: Unload DTMF failed",
9857 UnMapId(Id), (char *)(FILE_), __LINE__));
9858 Info = _FACILITY_NOT_SUPPORTED;
9859 break;
9860 }
9861 if (plci->internal_command)
9862 return;
9863 break;
9864 }
9865 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009866
9867
Joe Perches475be4d2012-02-19 19:52:38 -08009868 case DTMF_SEND_TONE:
9869 mask <<= 1;
9870 case DTMF_SEND_MF:
9871 mask <<= 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009872
Joe Perches475be4d2012-02-19 19:52:38 -08009873 case DTMF_DIGITS_SEND:
9874 switch (internal_command)
9875 {
9876 default:
9877 adjust_b1_resource(Id, plci, NULL, (word)(plci->B1_facilities |
9878 ((plci->dtmf_parameter_length != 0) ? B1_FACILITY_DTMFX | B1_FACILITY_DTMFR : B1_FACILITY_DTMFX)),
9879 DTMF_COMMAND_1);
9880 case DTMF_COMMAND_1:
9881 if (adjust_b_process(Id, plci, Rc) != GOOD)
9882 {
9883 dbug(1, dprintf("[%06lx] %s,%d: Load DTMF failed",
9884 UnMapId(Id), (char *)(FILE_), __LINE__));
9885 Info = _FACILITY_NOT_SUPPORTED;
9886 break;
9887 }
9888 if (plci->internal_command)
9889 return;
9890 case DTMF_COMMAND_2:
9891 if (plci_nl_busy(plci))
9892 {
9893 plci->internal_command = DTMF_COMMAND_2;
9894 return;
9895 }
9896 plci->dtmf_msg_number_queue[(plci->dtmf_send_requests)++] = plci->number;
9897 plci->internal_command = DTMF_COMMAND_3;
9898 dtmf_send_digits(plci, &plci->saved_msg.parms[3].info[1], plci->saved_msg.parms[3].length);
9899 return;
9900 case DTMF_COMMAND_3:
9901 if ((Rc != OK) && (Rc != OK_FC))
9902 {
9903 dbug(1, dprintf("[%06lx] %s,%d: Send DTMF digits failed %02x",
9904 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
9905 if (plci->dtmf_send_requests != 0)
9906 (plci->dtmf_send_requests)--;
9907 Info = _FACILITY_NOT_SUPPORTED;
9908 break;
9909 }
9910 return;
9911 }
9912 break;
9913 }
9914 sendf(plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->number,
9915 "wws", Info, SELECTOR_DTMF, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009916}
9917
9918
Joe Perches475be4d2012-02-19 19:52:38 -08009919static byte dtmf_request(dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009920{
Joe Perches475be4d2012-02-19 19:52:38 -08009921 word Info;
9922 word i, j;
9923 byte mask;
9924 API_PARSE dtmf_parms[5];
9925 byte result[40];
Linus Torvalds1da177e2005-04-16 15:20:36 -07009926
Joe Perches475be4d2012-02-19 19:52:38 -08009927 dbug(1, dprintf("[%06lx] %s,%d: dtmf_request",
9928 UnMapId(Id), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009929
Joe Perches475be4d2012-02-19 19:52:38 -08009930 Info = GOOD;
9931 result[0] = 2;
9932 PUT_WORD(&result[1], DTMF_SUCCESS);
9933 if (!(a->profile.Global_Options & GL_DTMF_SUPPORTED))
9934 {
9935 dbug(1, dprintf("[%06lx] %s,%d: Facility not supported",
9936 UnMapId(Id), (char *)(FILE_), __LINE__));
9937 Info = _FACILITY_NOT_SUPPORTED;
9938 }
9939 else if (api_parse(&msg[1].info[1], msg[1].length, "w", dtmf_parms))
9940 {
9941 dbug(1, dprintf("[%06lx] %s,%d: Wrong message format",
9942 UnMapId(Id), (char *)(FILE_), __LINE__));
9943 Info = _WRONG_MESSAGE_FORMAT;
9944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009945
Joe Perches475be4d2012-02-19 19:52:38 -08009946 else if ((GET_WORD(dtmf_parms[0].info) == DTMF_GET_SUPPORTED_DETECT_CODES)
9947 || (GET_WORD(dtmf_parms[0].info) == DTMF_GET_SUPPORTED_SEND_CODES))
9948 {
9949 if (!((a->requested_options_table[appl->Id - 1])
9950 & (1L << PRIVATE_DTMF_TONE)))
9951 {
9952 dbug(1, dprintf("[%06lx] %s,%d: DTMF unknown request %04x",
9953 UnMapId(Id), (char *)(FILE_), __LINE__, GET_WORD(dtmf_parms[0].info)));
9954 PUT_WORD(&result[1], DTMF_UNKNOWN_REQUEST);
9955 }
9956 else
9957 {
9958 for (i = 0; i < 32; i++)
9959 result[4 + i] = 0;
9960 if (GET_WORD(dtmf_parms[0].info) == DTMF_GET_SUPPORTED_DETECT_CODES)
9961 {
9962 for (i = 0; i < DTMF_DIGIT_MAP_ENTRIES; i++)
9963 {
9964 if (dtmf_digit_map[i].listen_mask != 0)
9965 result[4 + (dtmf_digit_map[i].character >> 3)] |= (1 << (dtmf_digit_map[i].character & 0x7));
9966 }
9967 }
9968 else
9969 {
9970 for (i = 0; i < DTMF_DIGIT_MAP_ENTRIES; i++)
9971 {
9972 if (dtmf_digit_map[i].send_mask != 0)
9973 result[4 + (dtmf_digit_map[i].character >> 3)] |= (1 << (dtmf_digit_map[i].character & 0x7));
9974 }
9975 }
9976 result[0] = 3 + 32;
9977 result[3] = 32;
9978 }
9979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009980
Joe Perches475be4d2012-02-19 19:52:38 -08009981 else if (plci == NULL)
9982 {
9983 dbug(1, dprintf("[%06lx] %s,%d: Wrong PLCI",
9984 UnMapId(Id), (char *)(FILE_), __LINE__));
9985 Info = _WRONG_IDENTIFIER;
9986 }
9987 else
9988 {
9989 if (!plci->State
9990 || !plci->NL.Id || plci->nl_remove_id)
9991 {
9992 dbug(1, dprintf("[%06lx] %s,%d: Wrong state",
9993 UnMapId(Id), (char *)(FILE_), __LINE__));
9994 Info = _WRONG_STATE;
9995 }
9996 else
9997 {
9998 plci->command = 0;
9999 plci->dtmf_cmd = GET_WORD(dtmf_parms[0].info);
10000 mask = 0x01;
10001 switch (plci->dtmf_cmd)
10002 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010003
Joe Perches475be4d2012-02-19 19:52:38 -080010004 case DTMF_LISTEN_TONE_START:
10005 case DTMF_LISTEN_TONE_STOP:
10006 mask <<= 1;
10007 case DTMF_LISTEN_MF_START:
10008 case DTMF_LISTEN_MF_STOP:
10009 mask <<= 1;
10010 if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[appl->Id - 1])
10011 & (1L << PRIVATE_DTMF_TONE)))
10012 {
10013 dbug(1, dprintf("[%06lx] %s,%d: DTMF unknown request %04x",
10014 UnMapId(Id), (char *)(FILE_), __LINE__, GET_WORD(dtmf_parms[0].info)));
10015 PUT_WORD(&result[1], DTMF_UNKNOWN_REQUEST);
10016 break;
10017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010018
Joe Perches475be4d2012-02-19 19:52:38 -080010019 case DTMF_LISTEN_START:
10020 case DTMF_LISTEN_STOP:
10021 if (!(a->manufacturer_features & MANUFACTURER_FEATURE_HARDDTMF)
10022 && !(a->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE))
10023 {
10024 dbug(1, dprintf("[%06lx] %s,%d: Facility not supported",
10025 UnMapId(Id), (char *)(FILE_), __LINE__));
10026 Info = _FACILITY_NOT_SUPPORTED;
10027 break;
10028 }
10029 if (mask & DTMF_LISTEN_ACTIVE_FLAG)
10030 {
10031 if (api_parse(&msg[1].info[1], msg[1].length, "wwws", dtmf_parms))
10032 {
10033 plci->dtmf_rec_pulse_ms = 0;
10034 plci->dtmf_rec_pause_ms = 0;
10035 }
10036 else
10037 {
10038 plci->dtmf_rec_pulse_ms = GET_WORD(dtmf_parms[1].info);
10039 plci->dtmf_rec_pause_ms = GET_WORD(dtmf_parms[2].info);
10040 }
10041 }
10042 start_internal_command(Id, plci, dtmf_command);
10043 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010044
10045
Joe Perches475be4d2012-02-19 19:52:38 -080010046 case DTMF_SEND_TONE:
10047 mask <<= 1;
10048 case DTMF_SEND_MF:
10049 mask <<= 1;
10050 if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[appl->Id - 1])
10051 & (1L << PRIVATE_DTMF_TONE)))
10052 {
10053 dbug(1, dprintf("[%06lx] %s,%d: DTMF unknown request %04x",
10054 UnMapId(Id), (char *)(FILE_), __LINE__, GET_WORD(dtmf_parms[0].info)));
10055 PUT_WORD(&result[1], DTMF_UNKNOWN_REQUEST);
10056 break;
10057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010058
Joe Perches475be4d2012-02-19 19:52:38 -080010059 case DTMF_DIGITS_SEND:
10060 if (api_parse(&msg[1].info[1], msg[1].length, "wwws", dtmf_parms))
10061 {
10062 dbug(1, dprintf("[%06lx] %s,%d: Wrong message format",
10063 UnMapId(Id), (char *)(FILE_), __LINE__));
10064 Info = _WRONG_MESSAGE_FORMAT;
10065 break;
10066 }
10067 if (mask & DTMF_LISTEN_ACTIVE_FLAG)
10068 {
10069 plci->dtmf_send_pulse_ms = GET_WORD(dtmf_parms[1].info);
10070 plci->dtmf_send_pause_ms = GET_WORD(dtmf_parms[2].info);
10071 }
10072 i = 0;
10073 j = 0;
10074 while ((i < dtmf_parms[3].length) && (j < DTMF_DIGIT_MAP_ENTRIES))
10075 {
10076 j = 0;
10077 while ((j < DTMF_DIGIT_MAP_ENTRIES)
10078 && ((dtmf_parms[3].info[i + 1] != dtmf_digit_map[j].character)
10079 || ((dtmf_digit_map[j].send_mask & mask) == 0)))
10080 {
10081 j++;
10082 }
10083 i++;
10084 }
10085 if (j == DTMF_DIGIT_MAP_ENTRIES)
10086 {
10087 dbug(1, dprintf("[%06lx] %s,%d: Incorrect DTMF digit %02x",
10088 UnMapId(Id), (char *)(FILE_), __LINE__, dtmf_parms[3].info[i]));
10089 PUT_WORD(&result[1], DTMF_INCORRECT_DIGIT);
10090 break;
10091 }
10092 if (plci->dtmf_send_requests >= ARRAY_SIZE(plci->dtmf_msg_number_queue))
10093 {
10094 dbug(1, dprintf("[%06lx] %s,%d: DTMF request overrun",
10095 UnMapId(Id), (char *)(FILE_), __LINE__));
10096 Info = _WRONG_STATE;
10097 break;
10098 }
10099 api_save_msg(dtmf_parms, "wwws", &plci->saved_msg);
10100 start_internal_command(Id, plci, dtmf_command);
10101 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010102
Joe Perches475be4d2012-02-19 19:52:38 -080010103 default:
10104 dbug(1, dprintf("[%06lx] %s,%d: DTMF unknown request %04x",
10105 UnMapId(Id), (char *)(FILE_), __LINE__, plci->dtmf_cmd));
10106 PUT_WORD(&result[1], DTMF_UNKNOWN_REQUEST);
10107 }
10108 }
10109 }
10110 sendf(appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
10111 "wws", Info, SELECTOR_DTMF, result);
10112 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010113}
10114
10115
Joe Perches475be4d2012-02-19 19:52:38 -080010116static void dtmf_confirmation(dword Id, PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010117{
Joe Perches475be4d2012-02-19 19:52:38 -080010118 word i;
10119 byte result[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -070010120
Joe Perches475be4d2012-02-19 19:52:38 -080010121 dbug(1, dprintf("[%06lx] %s,%d: dtmf_confirmation",
10122 UnMapId(Id), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010123
Joe Perches475be4d2012-02-19 19:52:38 -080010124 result[0] = 2;
10125 PUT_WORD(&result[1], DTMF_SUCCESS);
10126 if (plci->dtmf_send_requests != 0)
10127 {
10128 sendf(plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->dtmf_msg_number_queue[0],
10129 "wws", GOOD, SELECTOR_DTMF, result);
10130 (plci->dtmf_send_requests)--;
10131 for (i = 0; i < plci->dtmf_send_requests; i++)
10132 plci->dtmf_msg_number_queue[i] = plci->dtmf_msg_number_queue[i + 1];
10133 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010134}
10135
10136
Joe Perches475be4d2012-02-19 19:52:38 -080010137static void dtmf_indication(dword Id, PLCI *plci, byte *msg, word length)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010138{
Joe Perches475be4d2012-02-19 19:52:38 -080010139 word i, j, n;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010140
Joe Perches475be4d2012-02-19 19:52:38 -080010141 dbug(1, dprintf("[%06lx] %s,%d: dtmf_indication",
10142 UnMapId(Id), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010143
Joe Perches475be4d2012-02-19 19:52:38 -080010144 n = 0;
10145 for (i = 1; i < length; i++)
10146 {
10147 j = 0;
10148 while ((j < DTMF_DIGIT_MAP_ENTRIES)
10149 && ((msg[i] != dtmf_digit_map[j].code)
10150 || ((dtmf_digit_map[j].listen_mask & plci->dtmf_rec_active) == 0)))
10151 {
10152 j++;
10153 }
10154 if (j < DTMF_DIGIT_MAP_ENTRIES)
10155 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010156
Joe Perches475be4d2012-02-19 19:52:38 -080010157 if ((dtmf_digit_map[j].listen_mask & DTMF_TONE_LISTEN_ACTIVE_FLAG)
10158 && (plci->tone_last_indication_code == DTMF_SIGNAL_NO_TONE)
10159 && (dtmf_digit_map[j].character != DTMF_SIGNAL_UNIDENTIFIED_TONE))
10160 {
10161 if (n + 1 == i)
10162 {
10163 for (i = length; i > n + 1; i--)
10164 msg[i] = msg[i - 1];
10165 length++;
10166 i++;
10167 }
10168 msg[++n] = DTMF_SIGNAL_UNIDENTIFIED_TONE;
10169 }
10170 plci->tone_last_indication_code = dtmf_digit_map[j].character;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010171
Joe Perches475be4d2012-02-19 19:52:38 -080010172 msg[++n] = dtmf_digit_map[j].character;
10173 }
10174 }
10175 if (n != 0)
10176 {
10177 msg[0] = (byte) n;
10178 sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0, "wS", SELECTOR_DTMF, msg);
10179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010180}
10181
10182
10183/*------------------------------------------------------------------*/
10184/* DTMF parameters */
10185/*------------------------------------------------------------------*/
10186
Joe Perches475be4d2012-02-19 19:52:38 -080010187static void dtmf_parameter_write(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010188{
Joe Perches475be4d2012-02-19 19:52:38 -080010189 word i;
10190 byte parameter_buffer[DTMF_PARAMETER_BUFFER_SIZE + 2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070010191
Joe Perches475be4d2012-02-19 19:52:38 -080010192 dbug(1, dprintf("[%06lx] %s,%d: dtmf_parameter_write",
10193 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
10194 (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010195
Joe Perches475be4d2012-02-19 19:52:38 -080010196 parameter_buffer[0] = plci->dtmf_parameter_length + 1;
10197 parameter_buffer[1] = DSP_CTRL_SET_DTMF_PARAMETERS;
10198 for (i = 0; i < plci->dtmf_parameter_length; i++)
10199 parameter_buffer[2 + i] = plci->dtmf_parameter_buffer[i];
10200 add_p(plci, FTY, parameter_buffer);
10201 sig_req(plci, TEL_CTRL, 0);
10202 send_req(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010203}
10204
10205
Joe Perches475be4d2012-02-19 19:52:38 -080010206static void dtmf_parameter_clear_config(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010207{
10208
Joe Perches475be4d2012-02-19 19:52:38 -080010209 dbug(1, dprintf("[%06lx] %s,%d: dtmf_parameter_clear_config",
10210 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
10211 (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010212
Joe Perches475be4d2012-02-19 19:52:38 -080010213 plci->dtmf_parameter_length = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010214}
10215
10216
Joe Perches475be4d2012-02-19 19:52:38 -080010217static void dtmf_parameter_prepare_switch(dword Id, PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010218{
10219
Joe Perches475be4d2012-02-19 19:52:38 -080010220 dbug(1, dprintf("[%06lx] %s,%d: dtmf_parameter_prepare_switch",
10221 UnMapId(Id), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010222
10223}
10224
10225
Joe Perches475be4d2012-02-19 19:52:38 -080010226static word dtmf_parameter_save_config(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010227{
10228
Joe Perches475be4d2012-02-19 19:52:38 -080010229 dbug(1, dprintf("[%06lx] %s,%d: dtmf_parameter_save_config %02x %d",
10230 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010231
Joe Perches475be4d2012-02-19 19:52:38 -080010232 return (GOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010233}
10234
10235
Joe Perches475be4d2012-02-19 19:52:38 -080010236static word dtmf_parameter_restore_config(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010237{
Joe Perches475be4d2012-02-19 19:52:38 -080010238 word Info;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010239
Joe Perches475be4d2012-02-19 19:52:38 -080010240 dbug(1, dprintf("[%06lx] %s,%d: dtmf_parameter_restore_config %02x %d",
10241 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010242
Joe Perches475be4d2012-02-19 19:52:38 -080010243 Info = GOOD;
10244 if ((plci->B1_facilities & B1_FACILITY_DTMFR)
10245 && (plci->dtmf_parameter_length != 0))
10246 {
10247 switch (plci->adjust_b_state)
10248 {
10249 case ADJUST_B_RESTORE_DTMF_PARAMETER_1:
10250 plci->internal_command = plci->adjust_b_command;
10251 if (plci->sig_req)
10252 {
10253 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_1;
10254 break;
10255 }
10256 dtmf_parameter_write(plci);
10257 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_2;
10258 break;
10259 case ADJUST_B_RESTORE_DTMF_PARAMETER_2:
10260 if ((Rc != OK) && (Rc != OK_FC))
10261 {
10262 dbug(1, dprintf("[%06lx] %s,%d: Restore DTMF parameters failed %02x",
10263 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
10264 Info = _WRONG_STATE;
10265 break;
10266 }
10267 break;
10268 }
10269 }
10270 return (Info);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010271}
10272
10273
10274/*------------------------------------------------------------------*/
10275/* Line interconnect facilities */
10276/*------------------------------------------------------------------*/
10277
10278
10279LI_CONFIG *li_config_table;
10280word li_total_channels;
10281
10282
10283/*------------------------------------------------------------------*/
10284/* translate a CHI information element to a channel number */
10285/* returns 0xff - any channel */
10286/* 0xfe - chi wrong coding */
10287/* 0xfd - D-channel */
10288/* 0x00 - no channel */
10289/* else channel number / PRI: timeslot */
10290/* if channels is provided we accept more than one channel. */
10291/*------------------------------------------------------------------*/
10292
Joe Perches475be4d2012-02-19 19:52:38 -080010293static byte chi_to_channel(byte *chi, dword *pchannelmap)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010294{
Joe Perches475be4d2012-02-19 19:52:38 -080010295 int p;
10296 int i;
10297 dword map;
10298 byte excl;
10299 byte ofs;
10300 byte ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010301
Joe Perches475be4d2012-02-19 19:52:38 -080010302 if (pchannelmap) *pchannelmap = 0;
10303 if (!chi[0]) return 0xff;
10304 excl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010305
Joe Perches475be4d2012-02-19 19:52:38 -080010306 if (chi[1] & 0x20) {
10307 if (chi[0] == 1 && chi[1] == 0xac) return 0xfd; /* exclusive d-channel */
10308 for (i = 1; i < chi[0] && !(chi[i] & 0x80); i++);
10309 if (i == chi[0] || !(chi[i] & 0x80)) return 0xfe;
10310 if ((chi[1] | 0xc8) != 0xe9) return 0xfe;
10311 if (chi[1] & 0x08) excl = 0x40;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010312
Joe Perches475be4d2012-02-19 19:52:38 -080010313 /* int. id present */
10314 if (chi[1] & 0x40) {
10315 p = i + 1;
10316 for (i = p; i < chi[0] && !(chi[i] & 0x80); i++);
10317 if (i == chi[0] || !(chi[i] & 0x80)) return 0xfe;
10318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010319
Joe Perches475be4d2012-02-19 19:52:38 -080010320 /* coding standard, Number/Map, Channel Type */
10321 p = i + 1;
10322 for (i = p; i < chi[0] && !(chi[i] & 0x80); i++);
10323 if (i == chi[0] || !(chi[i] & 0x80)) return 0xfe;
10324 if ((chi[p] | 0xd0) != 0xd3) return 0xfe;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010325
Joe Perches475be4d2012-02-19 19:52:38 -080010326 /* Number/Map */
10327 if (chi[p] & 0x10) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010328
Joe Perches475be4d2012-02-19 19:52:38 -080010329 /* map */
10330 if ((chi[0] - p) == 4) ofs = 0;
10331 else if ((chi[0] - p) == 3) ofs = 1;
10332 else return 0xfe;
10333 ch = 0;
10334 map = 0;
10335 for (i = 0; i < 4 && p < chi[0]; i++) {
10336 p++;
10337 ch += 8;
10338 map <<= 8;
10339 if (chi[p]) {
10340 for (ch = 0; !(chi[p] & (1 << ch)); ch++);
10341 map |= chi[p];
10342 }
10343 }
10344 ch += ofs;
10345 map <<= ofs;
10346 }
10347 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010348
Joe Perches475be4d2012-02-19 19:52:38 -080010349 /* number */
10350 p = i + 1;
10351 ch = chi[p] & 0x3f;
10352 if (pchannelmap) {
10353 if ((byte)(chi[0] - p) > 30) return 0xfe;
10354 map = 0;
10355 for (i = p; i <= chi[0]; i++) {
10356 if ((chi[i] & 0x7f) > 31) return 0xfe;
10357 map |= (1L << (chi[i] & 0x7f));
10358 }
10359 }
10360 else {
10361 if (p != chi[0]) return 0xfe;
10362 if (ch > 31) return 0xfe;
10363 map = (1L << ch);
10364 }
10365 if (chi[p] & 0x40) return 0xfe;
10366 }
10367 if (pchannelmap) *pchannelmap = map;
10368 else if (map != ((dword)(1L << ch))) return 0xfe;
10369 return (byte)(excl | ch);
10370 }
10371 else { /* not PRI */
10372 for (i = 1; i < chi[0] && !(chi[i] & 0x80); i++);
10373 if (i != chi[0] || !(chi[i] & 0x80)) return 0xfe;
10374 if (chi[1] & 0x08) excl = 0x40;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010375
Joe Perches475be4d2012-02-19 19:52:38 -080010376 switch (chi[1] | 0x98) {
10377 case 0x98: return 0;
10378 case 0x99:
10379 if (pchannelmap) *pchannelmap = 2;
10380 return excl | 1;
10381 case 0x9a:
10382 if (pchannelmap) *pchannelmap = 4;
10383 return excl | 2;
10384 case 0x9b: return 0xff;
10385 case 0x9c: return 0xfd; /* d-ch */
10386 default: return 0xfe;
10387 }
10388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010389}
10390
10391
Joe Perches475be4d2012-02-19 19:52:38 -080010392static void mixer_set_bchannel_id_esc(PLCI *plci, byte bchannel_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010393{
Joe Perches475be4d2012-02-19 19:52:38 -080010394 DIVA_CAPI_ADAPTER *a;
10395 PLCI *splci;
10396 byte old_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010397
Joe Perches475be4d2012-02-19 19:52:38 -080010398 a = plci->adapter;
10399 old_id = plci->li_bchannel_id;
10400 if (a->li_pri)
10401 {
10402 if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
10403 li_config_table[a->li_base + (old_id - 1)].plci = NULL;
10404 plci->li_bchannel_id = (bchannel_id & 0x1f) + 1;
10405 if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
10406 li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
10407 }
10408 else
10409 {
10410 if (((bchannel_id & 0x03) == 1) || ((bchannel_id & 0x03) == 2))
10411 {
10412 if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
10413 li_config_table[a->li_base + (old_id - 1)].plci = NULL;
10414 plci->li_bchannel_id = bchannel_id & 0x03;
10415 if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI != plci) && (a->AdvSignalPLCI->tel == ADV_VOICE))
10416 {
10417 splci = a->AdvSignalPLCI;
10418 if (li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci == NULL)
10419 {
10420 if ((splci->li_bchannel_id != 0)
10421 && (li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci == splci))
10422 {
10423 li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci = NULL;
10424 }
10425 splci->li_bchannel_id = 3 - plci->li_bchannel_id;
10426 li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci = splci;
10427 dbug(1, dprintf("[%06lx] %s,%d: adv_voice_set_bchannel_id_esc %d",
10428 (dword)((splci->Id << 8) | UnMapController(splci->adapter->Id)),
10429 (char *)(FILE_), __LINE__, splci->li_bchannel_id));
10430 }
10431 }
10432 if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
10433 li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
10434 }
10435 }
10436 if ((old_id == 0) && (plci->li_bchannel_id != 0)
10437 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
10438 {
10439 mixer_clear_config(plci);
10440 }
10441 dbug(1, dprintf("[%06lx] %s,%d: mixer_set_bchannel_id_esc %d %d",
10442 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
10443 (char *)(FILE_), __LINE__, bchannel_id, plci->li_bchannel_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010444}
10445
10446
Joe Perches475be4d2012-02-19 19:52:38 -080010447static void mixer_set_bchannel_id(PLCI *plci, byte *chi)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010448{
Joe Perches475be4d2012-02-19 19:52:38 -080010449 DIVA_CAPI_ADAPTER *a;
10450 PLCI *splci;
10451 byte ch, old_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010452
Joe Perches475be4d2012-02-19 19:52:38 -080010453 a = plci->adapter;
10454 old_id = plci->li_bchannel_id;
10455 ch = chi_to_channel(chi, NULL);
10456 if (!(ch & 0x80))
10457 {
10458 if (a->li_pri)
10459 {
10460 if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
10461 li_config_table[a->li_base + (old_id - 1)].plci = NULL;
10462 plci->li_bchannel_id = (ch & 0x1f) + 1;
10463 if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
10464 li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
10465 }
10466 else
10467 {
10468 if (((ch & 0x1f) == 1) || ((ch & 0x1f) == 2))
10469 {
10470 if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
10471 li_config_table[a->li_base + (old_id - 1)].plci = NULL;
10472 plci->li_bchannel_id = ch & 0x1f;
10473 if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI != plci) && (a->AdvSignalPLCI->tel == ADV_VOICE))
10474 {
10475 splci = a->AdvSignalPLCI;
10476 if (li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci == NULL)
10477 {
10478 if ((splci->li_bchannel_id != 0)
10479 && (li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci == splci))
10480 {
10481 li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci = NULL;
10482 }
10483 splci->li_bchannel_id = 3 - plci->li_bchannel_id;
10484 li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci = splci;
10485 dbug(1, dprintf("[%06lx] %s,%d: adv_voice_set_bchannel_id %d",
10486 (dword)((splci->Id << 8) | UnMapController(splci->adapter->Id)),
10487 (char *)(FILE_), __LINE__, splci->li_bchannel_id));
10488 }
10489 }
10490 if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
10491 li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
10492 }
10493 }
10494 }
10495 if ((old_id == 0) && (plci->li_bchannel_id != 0)
10496 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
10497 {
10498 mixer_clear_config(plci);
10499 }
10500 dbug(1, dprintf("[%06lx] %s,%d: mixer_set_bchannel_id %02x %d",
10501 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
10502 (char *)(FILE_), __LINE__, ch, plci->li_bchannel_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010503}
10504
10505
10506#define MIXER_MAX_DUMP_CHANNELS 34
10507
Joe Perches475be4d2012-02-19 19:52:38 -080010508static void mixer_calculate_coefs(DIVA_CAPI_ADAPTER *a)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010509{
Joe Perches475be4d2012-02-19 19:52:38 -080010510 static char hex_digit_table[0x10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
10511 word n, i, j;
10512 char *p;
10513 char hex_line[2 * MIXER_MAX_DUMP_CHANNELS + MIXER_MAX_DUMP_CHANNELS / 8 + 4];
Linus Torvalds1da177e2005-04-16 15:20:36 -070010514
Joe Perches475be4d2012-02-19 19:52:38 -080010515 dbug(1, dprintf("[%06lx] %s,%d: mixer_calculate_coefs",
10516 (dword)(UnMapController(a->Id)), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010517
Joe Perches475be4d2012-02-19 19:52:38 -080010518 for (i = 0; i < li_total_channels; i++)
10519 {
10520 li_config_table[i].channel &= LI_CHANNEL_ADDRESSES_SET;
10521 if (li_config_table[i].chflags != 0)
10522 li_config_table[i].channel |= LI_CHANNEL_INVOLVED;
10523 else
10524 {
10525 for (j = 0; j < li_total_channels; j++)
10526 {
10527 if (((li_config_table[i].flag_table[j]) != 0)
10528 || ((li_config_table[j].flag_table[i]) != 0))
10529 {
10530 li_config_table[i].channel |= LI_CHANNEL_INVOLVED;
10531 }
10532 if (((li_config_table[i].flag_table[j] & LI_FLAG_CONFERENCE) != 0)
10533 || ((li_config_table[j].flag_table[i] & LI_FLAG_CONFERENCE) != 0))
10534 {
10535 li_config_table[i].channel |= LI_CHANNEL_CONFERENCE;
10536 }
10537 }
10538 }
10539 }
10540 for (i = 0; i < li_total_channels; i++)
10541 {
10542 for (j = 0; j < li_total_channels; j++)
10543 {
10544 li_config_table[i].coef_table[j] &= ~(LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC);
10545 if (li_config_table[i].flag_table[j] & LI_FLAG_CONFERENCE)
10546 li_config_table[i].coef_table[j] |= LI_COEF_CH_CH;
10547 }
10548 }
10549 for (n = 0; n < li_total_channels; n++)
10550 {
10551 if (li_config_table[n].channel & LI_CHANNEL_CONFERENCE)
10552 {
10553 for (i = 0; i < li_total_channels; i++)
10554 {
10555 if (li_config_table[i].channel & LI_CHANNEL_CONFERENCE)
10556 {
10557 for (j = 0; j < li_total_channels; j++)
10558 {
10559 li_config_table[i].coef_table[j] |=
10560 li_config_table[i].coef_table[n] & li_config_table[n].coef_table[j];
10561 }
10562 }
10563 }
10564 }
10565 }
10566 for (i = 0; i < li_total_channels; i++)
10567 {
10568 if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
10569 {
10570 li_config_table[i].coef_table[i] &= ~LI_COEF_CH_CH;
10571 for (j = 0; j < li_total_channels; j++)
10572 {
10573 if (li_config_table[i].coef_table[j] & LI_COEF_CH_CH)
10574 li_config_table[i].flag_table[j] |= LI_FLAG_CONFERENCE;
10575 }
10576 if (li_config_table[i].flag_table[i] & LI_FLAG_CONFERENCE)
10577 li_config_table[i].coef_table[i] |= LI_COEF_CH_CH;
10578 }
10579 }
10580 for (i = 0; i < li_total_channels; i++)
10581 {
10582 if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
10583 {
10584 for (j = 0; j < li_total_channels; j++)
10585 {
10586 if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
10587 li_config_table[i].coef_table[j] |= LI_COEF_CH_CH;
10588 if (li_config_table[i].flag_table[j] & LI_FLAG_MONITOR)
10589 li_config_table[i].coef_table[j] |= LI_COEF_CH_PC;
10590 if (li_config_table[i].flag_table[j] & LI_FLAG_MIX)
10591 li_config_table[i].coef_table[j] |= LI_COEF_PC_CH;
10592 if (li_config_table[i].flag_table[j] & LI_FLAG_PCCONNECT)
10593 li_config_table[i].coef_table[j] |= LI_COEF_PC_PC;
10594 }
10595 if (li_config_table[i].chflags & LI_CHFLAG_MONITOR)
10596 {
10597 for (j = 0; j < li_total_channels; j++)
10598 {
10599 if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
10600 {
10601 li_config_table[i].coef_table[j] |= LI_COEF_CH_PC;
10602 if (li_config_table[j].chflags & LI_CHFLAG_MIX)
10603 li_config_table[i].coef_table[j] |= LI_COEF_PC_CH | LI_COEF_PC_PC;
10604 }
10605 }
10606 }
10607 if (li_config_table[i].chflags & LI_CHFLAG_MIX)
10608 {
10609 for (j = 0; j < li_total_channels; j++)
10610 {
10611 if (li_config_table[j].flag_table[i] & LI_FLAG_INTERCONNECT)
10612 li_config_table[j].coef_table[i] |= LI_COEF_PC_CH;
10613 }
10614 }
10615 if (li_config_table[i].chflags & LI_CHFLAG_LOOP)
10616 {
10617 for (j = 0; j < li_total_channels; j++)
10618 {
10619 if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
10620 {
10621 for (n = 0; n < li_total_channels; n++)
10622 {
10623 if (li_config_table[n].flag_table[i] & LI_FLAG_INTERCONNECT)
10624 {
10625 li_config_table[n].coef_table[j] |= LI_COEF_CH_CH;
10626 if (li_config_table[j].chflags & LI_CHFLAG_MIX)
10627 {
10628 li_config_table[n].coef_table[j] |= LI_COEF_PC_CH;
10629 if (li_config_table[n].chflags & LI_CHFLAG_MONITOR)
10630 li_config_table[n].coef_table[j] |= LI_COEF_CH_PC | LI_COEF_PC_PC;
10631 }
10632 else if (li_config_table[n].chflags & LI_CHFLAG_MONITOR)
10633 li_config_table[n].coef_table[j] |= LI_COEF_CH_PC;
10634 }
10635 }
10636 }
10637 }
10638 }
10639 }
10640 }
10641 for (i = 0; i < li_total_channels; i++)
10642 {
10643 if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
10644 {
10645 if (li_config_table[i].chflags & (LI_CHFLAG_MONITOR | LI_CHFLAG_MIX | LI_CHFLAG_LOOP))
10646 li_config_table[i].channel |= LI_CHANNEL_ACTIVE;
10647 if (li_config_table[i].chflags & LI_CHFLAG_MONITOR)
10648 li_config_table[i].channel |= LI_CHANNEL_RX_DATA;
10649 if (li_config_table[i].chflags & LI_CHFLAG_MIX)
10650 li_config_table[i].channel |= LI_CHANNEL_TX_DATA;
10651 for (j = 0; j < li_total_channels; j++)
10652 {
10653 if ((li_config_table[i].flag_table[j] &
10654 (LI_FLAG_INTERCONNECT | LI_FLAG_PCCONNECT | LI_FLAG_CONFERENCE | LI_FLAG_MONITOR))
10655 || (li_config_table[j].flag_table[i] &
10656 (LI_FLAG_INTERCONNECT | LI_FLAG_PCCONNECT | LI_FLAG_CONFERENCE | LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX)))
10657 {
10658 li_config_table[i].channel |= LI_CHANNEL_ACTIVE;
10659 }
10660 if (li_config_table[i].flag_table[j] & (LI_FLAG_PCCONNECT | LI_FLAG_MONITOR))
10661 li_config_table[i].channel |= LI_CHANNEL_RX_DATA;
10662 if (li_config_table[j].flag_table[i] & (LI_FLAG_PCCONNECT | LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX))
10663 li_config_table[i].channel |= LI_CHANNEL_TX_DATA;
10664 }
10665 if (!(li_config_table[i].channel & LI_CHANNEL_ACTIVE))
10666 {
10667 li_config_table[i].coef_table[i] |= LI_COEF_PC_CH | LI_COEF_CH_PC;
10668 li_config_table[i].channel |= LI_CHANNEL_TX_DATA | LI_CHANNEL_RX_DATA;
10669 }
10670 }
10671 }
10672 for (i = 0; i < li_total_channels; i++)
10673 {
10674 if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
10675 {
10676 j = 0;
10677 while ((j < li_total_channels) && !(li_config_table[i].flag_table[j] & LI_FLAG_ANNOUNCEMENT))
10678 j++;
10679 if (j < li_total_channels)
10680 {
10681 for (j = 0; j < li_total_channels; j++)
10682 {
10683 li_config_table[i].coef_table[j] &= ~(LI_COEF_CH_CH | LI_COEF_PC_CH);
10684 if (li_config_table[i].flag_table[j] & LI_FLAG_ANNOUNCEMENT)
10685 li_config_table[i].coef_table[j] |= LI_COEF_PC_CH;
10686 }
10687 }
10688 }
10689 }
10690 n = li_total_channels;
10691 if (n > MIXER_MAX_DUMP_CHANNELS)
10692 n = MIXER_MAX_DUMP_CHANNELS;
10693 p = hex_line;
10694 for (j = 0; j < n; j++)
10695 {
10696 if ((j & 0x7) == 0)
10697 *(p++) = ' ';
10698 *(p++) = hex_digit_table[li_config_table[j].curchnl >> 4];
10699 *(p++) = hex_digit_table[li_config_table[j].curchnl & 0xf];
10700 }
10701 *p = '\0';
10702 dbug(1, dprintf("[%06lx] CURRENT %s",
10703 (dword)(UnMapController(a->Id)), (char *)hex_line));
10704 p = hex_line;
10705 for (j = 0; j < n; j++)
10706 {
10707 if ((j & 0x7) == 0)
10708 *(p++) = ' ';
10709 *(p++) = hex_digit_table[li_config_table[j].channel >> 4];
10710 *(p++) = hex_digit_table[li_config_table[j].channel & 0xf];
10711 }
10712 *p = '\0';
10713 dbug(1, dprintf("[%06lx] CHANNEL %s",
10714 (dword)(UnMapController(a->Id)), (char *)hex_line));
10715 p = hex_line;
10716 for (j = 0; j < n; j++)
10717 {
10718 if ((j & 0x7) == 0)
10719 *(p++) = ' ';
10720 *(p++) = hex_digit_table[li_config_table[j].chflags >> 4];
10721 *(p++) = hex_digit_table[li_config_table[j].chflags & 0xf];
10722 }
10723 *p = '\0';
10724 dbug(1, dprintf("[%06lx] CHFLAG %s",
10725 (dword)(UnMapController(a->Id)), (char *)hex_line));
10726 for (i = 0; i < n; i++)
10727 {
10728 p = hex_line;
10729 for (j = 0; j < n; j++)
10730 {
10731 if ((j & 0x7) == 0)
10732 *(p++) = ' ';
10733 *(p++) = hex_digit_table[li_config_table[i].flag_table[j] >> 4];
10734 *(p++) = hex_digit_table[li_config_table[i].flag_table[j] & 0xf];
10735 }
10736 *p = '\0';
10737 dbug(1, dprintf("[%06lx] FLAG[%02x]%s",
10738 (dword)(UnMapController(a->Id)), i, (char *)hex_line));
10739 }
10740 for (i = 0; i < n; i++)
10741 {
10742 p = hex_line;
10743 for (j = 0; j < n; j++)
10744 {
10745 if ((j & 0x7) == 0)
10746 *(p++) = ' ';
10747 *(p++) = hex_digit_table[li_config_table[i].coef_table[j] >> 4];
10748 *(p++) = hex_digit_table[li_config_table[i].coef_table[j] & 0xf];
10749 }
10750 *p = '\0';
10751 dbug(1, dprintf("[%06lx] COEF[%02x]%s",
10752 (dword)(UnMapController(a->Id)), i, (char *)hex_line));
10753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010754}
10755
10756
10757static struct
10758{
Joe Perches475be4d2012-02-19 19:52:38 -080010759 byte mask;
10760 byte line_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010761} mixer_write_prog_pri[] =
10762{
Joe Perches475be4d2012-02-19 19:52:38 -080010763 { LI_COEF_CH_CH, 0 },
10764 { LI_COEF_CH_PC, MIXER_COEF_LINE_TO_PC_FLAG },
10765 { LI_COEF_PC_CH, MIXER_COEF_LINE_FROM_PC_FLAG },
10766 { LI_COEF_PC_PC, MIXER_COEF_LINE_TO_PC_FLAG | MIXER_COEF_LINE_FROM_PC_FLAG }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010767};
10768
10769static struct
10770{
Joe Perches475be4d2012-02-19 19:52:38 -080010771 byte from_ch;
10772 byte to_ch;
10773 byte mask;
10774 byte xconnect_override;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010775} mixer_write_prog_bri[] =
10776{
Joe Perches475be4d2012-02-19 19:52:38 -080010777 { 0, 0, LI_COEF_CH_CH, 0x01 }, /* B to B */
10778 { 1, 0, LI_COEF_CH_CH, 0x01 }, /* Alt B to B */
10779 { 0, 0, LI_COEF_PC_CH, 0x80 }, /* PC to B */
10780 { 1, 0, LI_COEF_PC_CH, 0x01 }, /* Alt PC to B */
10781 { 2, 0, LI_COEF_CH_CH, 0x00 }, /* IC to B */
10782 { 3, 0, LI_COEF_CH_CH, 0x00 }, /* Alt IC to B */
10783 { 0, 0, LI_COEF_CH_PC, 0x80 }, /* B to PC */
10784 { 1, 0, LI_COEF_CH_PC, 0x01 }, /* Alt B to PC */
10785 { 0, 0, LI_COEF_PC_PC, 0x01 }, /* PC to PC */
10786 { 1, 0, LI_COEF_PC_PC, 0x01 }, /* Alt PC to PC */
10787 { 2, 0, LI_COEF_CH_PC, 0x00 }, /* IC to PC */
10788 { 3, 0, LI_COEF_CH_PC, 0x00 }, /* Alt IC to PC */
10789 { 0, 2, LI_COEF_CH_CH, 0x00 }, /* B to IC */
10790 { 1, 2, LI_COEF_CH_CH, 0x00 }, /* Alt B to IC */
10791 { 0, 2, LI_COEF_PC_CH, 0x00 }, /* PC to IC */
10792 { 1, 2, LI_COEF_PC_CH, 0x00 }, /* Alt PC to IC */
10793 { 2, 2, LI_COEF_CH_CH, 0x00 }, /* IC to IC */
10794 { 3, 2, LI_COEF_CH_CH, 0x00 }, /* Alt IC to IC */
10795 { 1, 1, LI_COEF_CH_CH, 0x01 }, /* Alt B to Alt B */
10796 { 0, 1, LI_COEF_CH_CH, 0x01 }, /* B to Alt B */
10797 { 1, 1, LI_COEF_PC_CH, 0x80 }, /* Alt PC to Alt B */
10798 { 0, 1, LI_COEF_PC_CH, 0x01 }, /* PC to Alt B */
10799 { 3, 1, LI_COEF_CH_CH, 0x00 }, /* Alt IC to Alt B */
10800 { 2, 1, LI_COEF_CH_CH, 0x00 }, /* IC to Alt B */
10801 { 1, 1, LI_COEF_CH_PC, 0x80 }, /* Alt B to Alt PC */
10802 { 0, 1, LI_COEF_CH_PC, 0x01 }, /* B to Alt PC */
10803 { 1, 1, LI_COEF_PC_PC, 0x01 }, /* Alt PC to Alt PC */
10804 { 0, 1, LI_COEF_PC_PC, 0x01 }, /* PC to Alt PC */
10805 { 3, 1, LI_COEF_CH_PC, 0x00 }, /* Alt IC to Alt PC */
10806 { 2, 1, LI_COEF_CH_PC, 0x00 }, /* IC to Alt PC */
10807 { 1, 3, LI_COEF_CH_CH, 0x00 }, /* Alt B to Alt IC */
10808 { 0, 3, LI_COEF_CH_CH, 0x00 }, /* B to Alt IC */
10809 { 1, 3, LI_COEF_PC_CH, 0x00 }, /* Alt PC to Alt IC */
10810 { 0, 3, LI_COEF_PC_CH, 0x00 }, /* PC to Alt IC */
10811 { 3, 3, LI_COEF_CH_CH, 0x00 }, /* Alt IC to Alt IC */
10812 { 2, 3, LI_COEF_CH_CH, 0x00 } /* IC to Alt IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010813};
10814
10815static byte mixer_swapped_index_bri[] =
10816{
Joe Perches475be4d2012-02-19 19:52:38 -080010817 18, /* B to B */
10818 19, /* Alt B to B */
10819 20, /* PC to B */
10820 21, /* Alt PC to B */
10821 22, /* IC to B */
10822 23, /* Alt IC to B */
10823 24, /* B to PC */
10824 25, /* Alt B to PC */
10825 26, /* PC to PC */
10826 27, /* Alt PC to PC */
10827 28, /* IC to PC */
10828 29, /* Alt IC to PC */
10829 30, /* B to IC */
10830 31, /* Alt B to IC */
10831 32, /* PC to IC */
10832 33, /* Alt PC to IC */
10833 34, /* IC to IC */
10834 35, /* Alt IC to IC */
10835 0, /* Alt B to Alt B */
10836 1, /* B to Alt B */
10837 2, /* Alt PC to Alt B */
10838 3, /* PC to Alt B */
10839 4, /* Alt IC to Alt B */
10840 5, /* IC to Alt B */
10841 6, /* Alt B to Alt PC */
10842 7, /* B to Alt PC */
10843 8, /* Alt PC to Alt PC */
10844 9, /* PC to Alt PC */
10845 10, /* Alt IC to Alt PC */
10846 11, /* IC to Alt PC */
10847 12, /* Alt B to Alt IC */
10848 13, /* B to Alt IC */
10849 14, /* Alt PC to Alt IC */
10850 15, /* PC to Alt IC */
10851 16, /* Alt IC to Alt IC */
10852 17 /* IC to Alt IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010853};
10854
10855static struct
10856{
Joe Perches475be4d2012-02-19 19:52:38 -080010857 byte mask;
10858 byte from_pc;
10859 byte to_pc;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010860} xconnect_write_prog[] =
10861{
Joe Perches475be4d2012-02-19 19:52:38 -080010862 { LI_COEF_CH_CH, false, false },
10863 { LI_COEF_CH_PC, false, true },
10864 { LI_COEF_PC_CH, true, false },
10865 { LI_COEF_PC_PC, true, true }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010866};
10867
10868
Joe Perches475be4d2012-02-19 19:52:38 -080010869static void xconnect_query_addresses(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010870{
Joe Perches475be4d2012-02-19 19:52:38 -080010871 DIVA_CAPI_ADAPTER *a;
10872 word w, ch;
10873 byte *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010874
Joe Perches475be4d2012-02-19 19:52:38 -080010875 dbug(1, dprintf("[%06lx] %s,%d: xconnect_query_addresses",
10876 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
10877 (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010878
Joe Perches475be4d2012-02-19 19:52:38 -080010879 a = plci->adapter;
10880 if (a->li_pri && ((plci->li_bchannel_id == 0)
10881 || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci)))
10882 {
10883 dbug(1, dprintf("[%06x] %s,%d: Channel id wiped out",
10884 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
10885 (char *)(FILE_), __LINE__));
10886 return;
10887 }
10888 p = plci->internal_req_buffer;
10889 ch = (a->li_pri) ? plci->li_bchannel_id - 1 : 0;
10890 *(p++) = UDATA_REQUEST_XCONNECT_FROM;
10891 w = ch;
10892 *(p++) = (byte) w;
10893 *(p++) = (byte)(w >> 8);
10894 w = ch | XCONNECT_CHANNEL_PORT_PC;
10895 *(p++) = (byte) w;
10896 *(p++) = (byte)(w >> 8);
10897 plci->NData[0].P = plci->internal_req_buffer;
10898 plci->NData[0].PLength = p - plci->internal_req_buffer;
10899 plci->NL.X = plci->NData;
10900 plci->NL.ReqCh = 0;
10901 plci->NL.Req = plci->nl_req = (byte) N_UDATA;
10902 plci->adapter->request(&plci->NL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010903}
10904
10905
Joe Perches475be4d2012-02-19 19:52:38 -080010906static void xconnect_write_coefs(PLCI *plci, word internal_command)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010907{
10908
Joe Perches475be4d2012-02-19 19:52:38 -080010909 dbug(1, dprintf("[%06lx] %s,%d: xconnect_write_coefs %04x",
10910 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
10911 (char *)(FILE_), __LINE__, internal_command));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010912
Joe Perches475be4d2012-02-19 19:52:38 -080010913 plci->li_write_command = internal_command;
10914 plci->li_write_channel = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010915}
10916
10917
Joe Perches475be4d2012-02-19 19:52:38 -080010918static byte xconnect_write_coefs_process(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010919{
Joe Perches475be4d2012-02-19 19:52:38 -080010920 DIVA_CAPI_ADAPTER *a;
10921 word w, n, i, j, r, s, to_ch;
10922 dword d;
10923 byte *p;
10924 struct xconnect_transfer_address_s *transfer_address;
10925 byte ch_map[MIXER_CHANNELS_BRI];
Linus Torvalds1da177e2005-04-16 15:20:36 -070010926
Joe Perches475be4d2012-02-19 19:52:38 -080010927 dbug(1, dprintf("[%06x] %s,%d: xconnect_write_coefs_process %02x %d",
10928 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->li_write_channel));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010929
Joe Perches475be4d2012-02-19 19:52:38 -080010930 a = plci->adapter;
10931 if ((plci->li_bchannel_id == 0)
10932 || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci))
10933 {
10934 dbug(1, dprintf("[%06x] %s,%d: Channel id wiped out",
10935 UnMapId(Id), (char *)(FILE_), __LINE__));
10936 return (true);
10937 }
10938 i = a->li_base + (plci->li_bchannel_id - 1);
10939 j = plci->li_write_channel;
10940 p = plci->internal_req_buffer;
10941 if (j != 0)
10942 {
10943 if ((Rc != OK) && (Rc != OK_FC))
10944 {
10945 dbug(1, dprintf("[%06lx] %s,%d: LI write coefs failed %02x",
10946 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
10947 return (false);
10948 }
10949 }
10950 if (li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
10951 {
10952 r = 0;
10953 s = 0;
10954 if (j < li_total_channels)
10955 {
10956 if (li_config_table[i].channel & LI_CHANNEL_ADDRESSES_SET)
10957 {
10958 s = ((li_config_table[i].send_b.card_address.low | li_config_table[i].send_b.card_address.high) ?
10959 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_PC | LI_COEF_PC_PC)) &
10960 ((li_config_table[i].send_pc.card_address.low | li_config_table[i].send_pc.card_address.high) ?
10961 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_PC_CH));
10962 }
10963 r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
10964 while ((j < li_total_channels)
10965 && ((r == 0)
10966 || (!(li_config_table[j].channel & LI_CHANNEL_ADDRESSES_SET))
10967 || (!li_config_table[j].adapter->li_pri
10968 && (j >= li_config_table[j].adapter->li_base + MIXER_BCHANNELS_BRI))
10969 || (((li_config_table[j].send_b.card_address.low != li_config_table[i].send_b.card_address.low)
10970 || (li_config_table[j].send_b.card_address.high != li_config_table[i].send_b.card_address.high))
10971 && (!(a->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)
10972 || !(li_config_table[j].adapter->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)))
10973 || ((li_config_table[j].adapter->li_base != a->li_base)
10974 && !(r & s &
10975 ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ?
10976 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) &
10977 ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ?
10978 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC))))))
10979 {
10980 j++;
10981 if (j < li_total_channels)
10982 r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
10983 }
10984 }
10985 if (j < li_total_channels)
10986 {
10987 plci->internal_command = plci->li_write_command;
10988 if (plci_nl_busy(plci))
10989 return (true);
10990 to_ch = (a->li_pri) ? plci->li_bchannel_id - 1 : 0;
10991 *(p++) = UDATA_REQUEST_XCONNECT_TO;
10992 do
10993 {
10994 if (li_config_table[j].adapter->li_base != a->li_base)
10995 {
10996 r &= s &
10997 ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ?
10998 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) &
10999 ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ?
11000 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC));
11001 }
11002 n = 0;
11003 do
11004 {
11005 if (r & xconnect_write_prog[n].mask)
11006 {
11007 if (xconnect_write_prog[n].from_pc)
11008 transfer_address = &(li_config_table[j].send_pc);
11009 else
11010 transfer_address = &(li_config_table[j].send_b);
11011 d = transfer_address->card_address.low;
11012 *(p++) = (byte) d;
11013 *(p++) = (byte)(d >> 8);
11014 *(p++) = (byte)(d >> 16);
11015 *(p++) = (byte)(d >> 24);
11016 d = transfer_address->card_address.high;
11017 *(p++) = (byte) d;
11018 *(p++) = (byte)(d >> 8);
11019 *(p++) = (byte)(d >> 16);
11020 *(p++) = (byte)(d >> 24);
11021 d = transfer_address->offset;
11022 *(p++) = (byte) d;
11023 *(p++) = (byte)(d >> 8);
11024 *(p++) = (byte)(d >> 16);
11025 *(p++) = (byte)(d >> 24);
11026 w = xconnect_write_prog[n].to_pc ? to_ch | XCONNECT_CHANNEL_PORT_PC : to_ch;
11027 *(p++) = (byte) w;
11028 *(p++) = (byte)(w >> 8);
11029 w = ((li_config_table[i].coef_table[j] & xconnect_write_prog[n].mask) == 0) ? 0x01 :
11030 (li_config_table[i].adapter->u_law ?
11031 (li_config_table[j].adapter->u_law ? 0x80 : 0x86) :
11032 (li_config_table[j].adapter->u_law ? 0x7a : 0x80));
11033 *(p++) = (byte) w;
11034 *(p++) = (byte) 0;
11035 li_config_table[i].coef_table[j] ^= xconnect_write_prog[n].mask << 4;
11036 }
11037 n++;
11038 } while ((n < ARRAY_SIZE(xconnect_write_prog))
11039 && ((p - plci->internal_req_buffer) + 16 < INTERNAL_REQ_BUFFER_SIZE));
11040 if (n == ARRAY_SIZE(xconnect_write_prog))
11041 {
11042 do
11043 {
11044 j++;
11045 if (j < li_total_channels)
11046 r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
11047 } while ((j < li_total_channels)
11048 && ((r == 0)
11049 || (!(li_config_table[j].channel & LI_CHANNEL_ADDRESSES_SET))
11050 || (!li_config_table[j].adapter->li_pri
11051 && (j >= li_config_table[j].adapter->li_base + MIXER_BCHANNELS_BRI))
11052 || (((li_config_table[j].send_b.card_address.low != li_config_table[i].send_b.card_address.low)
11053 || (li_config_table[j].send_b.card_address.high != li_config_table[i].send_b.card_address.high))
11054 && (!(a->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)
11055 || !(li_config_table[j].adapter->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)))
11056 || ((li_config_table[j].adapter->li_base != a->li_base)
11057 && !(r & s &
11058 ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ?
11059 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) &
11060 ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ?
11061 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC))))));
11062 }
11063 } while ((j < li_total_channels)
11064 && ((p - plci->internal_req_buffer) + 16 < INTERNAL_REQ_BUFFER_SIZE));
11065 }
11066 else if (j == li_total_channels)
11067 {
11068 plci->internal_command = plci->li_write_command;
11069 if (plci_nl_busy(plci))
11070 return (true);
11071 if (a->li_pri)
11072 {
11073 *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC;
11074 w = 0;
11075 if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
11076 w |= MIXER_FEATURE_ENABLE_TX_DATA;
11077 if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
11078 w |= MIXER_FEATURE_ENABLE_RX_DATA;
11079 *(p++) = (byte) w;
11080 *(p++) = (byte)(w >> 8);
11081 }
11082 else
11083 {
11084 *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_BRI;
11085 w = 0;
11086 if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI)
11087 && (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length))
11088 {
11089 w = GET_WORD(a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE);
11090 }
11091 if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
11092 w |= MIXER_FEATURE_ENABLE_TX_DATA;
11093 if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
11094 w |= MIXER_FEATURE_ENABLE_RX_DATA;
11095 *(p++) = (byte) w;
11096 *(p++) = (byte)(w >> 8);
11097 for (j = 0; j < sizeof(ch_map); j += 2)
11098 {
11099 if (plci->li_bchannel_id == 2)
11100 {
11101 ch_map[j] = (byte)(j + 1);
11102 ch_map[j + 1] = (byte) j;
11103 }
11104 else
11105 {
11106 ch_map[j] = (byte) j;
11107 ch_map[j + 1] = (byte)(j + 1);
11108 }
11109 }
11110 for (n = 0; n < ARRAY_SIZE(mixer_write_prog_bri); n++)
11111 {
11112 i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
11113 j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
11114 if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED)
11115 {
11116 *p = (mixer_write_prog_bri[n].xconnect_override != 0) ?
11117 mixer_write_prog_bri[n].xconnect_override :
11118 ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01);
11119 if ((i >= a->li_base + MIXER_BCHANNELS_BRI) || (j >= a->li_base + MIXER_BCHANNELS_BRI))
11120 {
11121 w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
11122 li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4;
11123 }
11124 }
11125 else
11126 {
11127 *p = 0x00;
11128 if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI->tel == ADV_VOICE))
11129 {
11130 w = (plci == a->AdvSignalPLCI) ? n : mixer_swapped_index_bri[n];
11131 if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w < a->adv_voice_coef_length)
11132 *p = a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w];
11133 }
11134 }
11135 p++;
11136 }
11137 }
11138 j = li_total_channels + 1;
11139 }
11140 }
11141 else
11142 {
11143 if (j <= li_total_channels)
11144 {
11145 plci->internal_command = plci->li_write_command;
11146 if (plci_nl_busy(plci))
11147 return (true);
11148 if (j < a->li_base)
11149 j = a->li_base;
11150 if (a->li_pri)
11151 {
11152 *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC;
11153 w = 0;
11154 if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
11155 w |= MIXER_FEATURE_ENABLE_TX_DATA;
11156 if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
11157 w |= MIXER_FEATURE_ENABLE_RX_DATA;
11158 *(p++) = (byte) w;
11159 *(p++) = (byte)(w >> 8);
11160 for (n = 0; n < ARRAY_SIZE(mixer_write_prog_pri); n++)
11161 {
11162 *(p++) = (byte)((plci->li_bchannel_id - 1) | mixer_write_prog_pri[n].line_flags);
11163 for (j = a->li_base; j < a->li_base + MIXER_CHANNELS_PRI; j++)
11164 {
11165 w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
11166 if (w & mixer_write_prog_pri[n].mask)
11167 {
11168 *(p++) = (li_config_table[i].coef_table[j] & mixer_write_prog_pri[n].mask) ? 0x80 : 0x01;
11169 li_config_table[i].coef_table[j] ^= mixer_write_prog_pri[n].mask << 4;
11170 }
11171 else
11172 *(p++) = 0x00;
11173 }
11174 *(p++) = (byte)((plci->li_bchannel_id - 1) | MIXER_COEF_LINE_ROW_FLAG | mixer_write_prog_pri[n].line_flags);
11175 for (j = a->li_base; j < a->li_base + MIXER_CHANNELS_PRI; j++)
11176 {
11177 w = ((li_config_table[j].coef_table[i] & 0xf) ^ (li_config_table[j].coef_table[i] >> 4));
11178 if (w & mixer_write_prog_pri[n].mask)
11179 {
11180 *(p++) = (li_config_table[j].coef_table[i] & mixer_write_prog_pri[n].mask) ? 0x80 : 0x01;
11181 li_config_table[j].coef_table[i] ^= mixer_write_prog_pri[n].mask << 4;
11182 }
11183 else
11184 *(p++) = 0x00;
11185 }
11186 }
11187 }
11188 else
11189 {
11190 *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_BRI;
11191 w = 0;
11192 if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI)
11193 && (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length))
11194 {
11195 w = GET_WORD(a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE);
11196 }
11197 if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
11198 w |= MIXER_FEATURE_ENABLE_TX_DATA;
11199 if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
11200 w |= MIXER_FEATURE_ENABLE_RX_DATA;
11201 *(p++) = (byte) w;
11202 *(p++) = (byte)(w >> 8);
11203 for (j = 0; j < sizeof(ch_map); j += 2)
11204 {
11205 if (plci->li_bchannel_id == 2)
11206 {
11207 ch_map[j] = (byte)(j + 1);
11208 ch_map[j + 1] = (byte) j;
11209 }
11210 else
11211 {
11212 ch_map[j] = (byte) j;
11213 ch_map[j + 1] = (byte)(j + 1);
11214 }
11215 }
11216 for (n = 0; n < ARRAY_SIZE(mixer_write_prog_bri); n++)
11217 {
11218 i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
11219 j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
11220 if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED)
11221 {
11222 *p = ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01);
11223 w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
11224 li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4;
11225 }
11226 else
11227 {
11228 *p = 0x00;
11229 if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI->tel == ADV_VOICE))
11230 {
11231 w = (plci == a->AdvSignalPLCI) ? n : mixer_swapped_index_bri[n];
11232 if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w < a->adv_voice_coef_length)
11233 *p = a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w];
11234 }
11235 }
11236 p++;
11237 }
11238 }
11239 j = li_total_channels + 1;
11240 }
11241 }
11242 plci->li_write_channel = j;
11243 if (p != plci->internal_req_buffer)
11244 {
11245 plci->NData[0].P = plci->internal_req_buffer;
11246 plci->NData[0].PLength = p - plci->internal_req_buffer;
11247 plci->NL.X = plci->NData;
11248 plci->NL.ReqCh = 0;
11249 plci->NL.Req = plci->nl_req = (byte) N_UDATA;
11250 plci->adapter->request(&plci->NL);
11251 }
11252 return (true);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011253}
11254
11255
Joe Perches475be4d2012-02-19 19:52:38 -080011256static void mixer_notify_update(PLCI *plci, byte others)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011257{
Joe Perches475be4d2012-02-19 19:52:38 -080011258 DIVA_CAPI_ADAPTER *a;
11259 word i, w;
11260 PLCI *notify_plci;
11261 byte msg[sizeof(CAPI_MSG_HEADER) + 6];
Linus Torvalds1da177e2005-04-16 15:20:36 -070011262
Joe Perches475be4d2012-02-19 19:52:38 -080011263 dbug(1, dprintf("[%06lx] %s,%d: mixer_notify_update %d",
11264 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
11265 (char *)(FILE_), __LINE__, others));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011266
Joe Perches475be4d2012-02-19 19:52:38 -080011267 a = plci->adapter;
11268 if (a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED)
11269 {
11270 if (others)
11271 plci->li_notify_update = true;
11272 i = 0;
11273 do
11274 {
11275 notify_plci = NULL;
11276 if (others)
11277 {
11278 while ((i < li_total_channels) && (li_config_table[i].plci == NULL))
11279 i++;
11280 if (i < li_total_channels)
11281 notify_plci = li_config_table[i++].plci;
11282 }
11283 else
11284 {
11285 if ((plci->li_bchannel_id != 0)
11286 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
11287 {
11288 notify_plci = plci;
11289 }
11290 }
11291 if ((notify_plci != NULL)
11292 && !notify_plci->li_notify_update
11293 && (notify_plci->appl != NULL)
11294 && (notify_plci->State)
11295 && notify_plci->NL.Id && !notify_plci->nl_remove_id)
11296 {
11297 notify_plci->li_notify_update = true;
11298 ((CAPI_MSG *) msg)->header.length = 18;
11299 ((CAPI_MSG *) msg)->header.appl_id = notify_plci->appl->Id;
11300 ((CAPI_MSG *) msg)->header.command = _FACILITY_R;
11301 ((CAPI_MSG *) msg)->header.number = 0;
11302 ((CAPI_MSG *) msg)->header.controller = notify_plci->adapter->Id;
11303 ((CAPI_MSG *) msg)->header.plci = notify_plci->Id;
11304 ((CAPI_MSG *) msg)->header.ncci = 0;
11305 ((CAPI_MSG *) msg)->info.facility_req.Selector = SELECTOR_LINE_INTERCONNECT;
11306 ((CAPI_MSG *) msg)->info.facility_req.structs[0] = 3;
11307 PUT_WORD(&(((CAPI_MSG *) msg)->info.facility_req.structs[1]), LI_REQ_SILENT_UPDATE);
11308 ((CAPI_MSG *) msg)->info.facility_req.structs[3] = 0;
11309 w = api_put(notify_plci->appl, (CAPI_MSG *) msg);
11310 if (w != _QUEUE_FULL)
11311 {
11312 if (w != 0)
11313 {
11314 dbug(1, dprintf("[%06lx] %s,%d: Interconnect notify failed %06x %d",
11315 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
11316 (char *)(FILE_), __LINE__,
11317 (dword)((notify_plci->Id << 8) | UnMapController(notify_plci->adapter->Id)), w));
11318 }
11319 notify_plci->li_notify_update = false;
11320 }
11321 }
11322 } while (others && (notify_plci != NULL));
11323 if (others)
11324 plci->li_notify_update = false;
11325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011326}
11327
11328
Joe Perches475be4d2012-02-19 19:52:38 -080011329static void mixer_clear_config(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011330{
Joe Perches475be4d2012-02-19 19:52:38 -080011331 DIVA_CAPI_ADAPTER *a;
11332 word i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011333
Joe Perches475be4d2012-02-19 19:52:38 -080011334 dbug(1, dprintf("[%06lx] %s,%d: mixer_clear_config",
11335 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
11336 (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011337
Joe Perches475be4d2012-02-19 19:52:38 -080011338 plci->li_notify_update = false;
11339 plci->li_plci_b_write_pos = 0;
11340 plci->li_plci_b_read_pos = 0;
11341 plci->li_plci_b_req_pos = 0;
11342 a = plci->adapter;
11343 if ((plci->li_bchannel_id != 0)
11344 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
11345 {
11346 i = a->li_base + (plci->li_bchannel_id - 1);
11347 li_config_table[i].curchnl = 0;
11348 li_config_table[i].channel = 0;
11349 li_config_table[i].chflags = 0;
11350 for (j = 0; j < li_total_channels; j++)
11351 {
11352 li_config_table[j].flag_table[i] = 0;
11353 li_config_table[i].flag_table[j] = 0;
11354 li_config_table[i].coef_table[j] = 0;
11355 li_config_table[j].coef_table[i] = 0;
11356 }
11357 if (!a->li_pri)
11358 {
11359 li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET;
11360 if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
11361 {
11362 i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
11363 li_config_table[i].curchnl = 0;
11364 li_config_table[i].channel = 0;
11365 li_config_table[i].chflags = 0;
11366 for (j = 0; j < li_total_channels; j++)
11367 {
11368 li_config_table[i].flag_table[j] = 0;
11369 li_config_table[j].flag_table[i] = 0;
11370 li_config_table[i].coef_table[j] = 0;
11371 li_config_table[j].coef_table[i] = 0;
11372 }
11373 if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
11374 {
11375 i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
11376 li_config_table[i].curchnl = 0;
11377 li_config_table[i].channel = 0;
11378 li_config_table[i].chflags = 0;
11379 for (j = 0; j < li_total_channels; j++)
11380 {
11381 li_config_table[i].flag_table[j] = 0;
11382 li_config_table[j].flag_table[i] = 0;
11383 li_config_table[i].coef_table[j] = 0;
11384 li_config_table[j].coef_table[i] = 0;
11385 }
11386 }
11387 }
11388 }
11389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011390}
11391
11392
Joe Perches475be4d2012-02-19 19:52:38 -080011393static void mixer_prepare_switch(dword Id, PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011394{
11395
Joe Perches475be4d2012-02-19 19:52:38 -080011396 dbug(1, dprintf("[%06lx] %s,%d: mixer_prepare_switch",
11397 UnMapId(Id), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011398
Joe Perches475be4d2012-02-19 19:52:38 -080011399 do
11400 {
11401 mixer_indication_coefs_set(Id, plci);
11402 } while (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011403}
11404
11405
Joe Perches475be4d2012-02-19 19:52:38 -080011406static word mixer_save_config(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011407{
Joe Perches475be4d2012-02-19 19:52:38 -080011408 DIVA_CAPI_ADAPTER *a;
11409 word i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011410
Joe Perches475be4d2012-02-19 19:52:38 -080011411 dbug(1, dprintf("[%06lx] %s,%d: mixer_save_config %02x %d",
11412 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011413
Joe Perches475be4d2012-02-19 19:52:38 -080011414 a = plci->adapter;
11415 if ((plci->li_bchannel_id != 0)
11416 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
11417 {
11418 i = a->li_base + (plci->li_bchannel_id - 1);
11419 for (j = 0; j < li_total_channels; j++)
11420 {
11421 li_config_table[i].coef_table[j] &= 0xf;
11422 li_config_table[j].coef_table[i] &= 0xf;
11423 }
11424 if (!a->li_pri)
11425 li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET;
11426 }
11427 return (GOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011428}
11429
11430
Joe Perches475be4d2012-02-19 19:52:38 -080011431static word mixer_restore_config(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011432{
Joe Perches475be4d2012-02-19 19:52:38 -080011433 DIVA_CAPI_ADAPTER *a;
11434 word Info;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011435
Joe Perches475be4d2012-02-19 19:52:38 -080011436 dbug(1, dprintf("[%06lx] %s,%d: mixer_restore_config %02x %d",
11437 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011438
Joe Perches475be4d2012-02-19 19:52:38 -080011439 Info = GOOD;
11440 a = plci->adapter;
11441 if ((plci->B1_facilities & B1_FACILITY_MIXER)
11442 && (plci->li_bchannel_id != 0)
11443 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
11444 {
11445 switch (plci->adjust_b_state)
11446 {
11447 case ADJUST_B_RESTORE_MIXER_1:
11448 if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
11449 {
11450 plci->internal_command = plci->adjust_b_command;
11451 if (plci_nl_busy(plci))
11452 {
11453 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_1;
11454 break;
11455 }
11456 xconnect_query_addresses(plci);
11457 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_2;
11458 break;
11459 }
11460 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5;
11461 Rc = OK;
11462 case ADJUST_B_RESTORE_MIXER_2:
11463 case ADJUST_B_RESTORE_MIXER_3:
11464 case ADJUST_B_RESTORE_MIXER_4:
11465 if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0))
11466 {
11467 dbug(1, dprintf("[%06lx] %s,%d: Adjust B query addresses failed %02x",
11468 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
11469 Info = _WRONG_STATE;
11470 break;
11471 }
11472 if (Rc == OK)
11473 {
11474 if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2)
11475 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_3;
11476 else if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_4)
11477 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5;
11478 }
11479 else if (Rc == 0)
11480 {
11481 if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2)
11482 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_4;
11483 else if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_3)
11484 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5;
11485 }
11486 if (plci->adjust_b_state != ADJUST_B_RESTORE_MIXER_5)
11487 {
11488 plci->internal_command = plci->adjust_b_command;
11489 break;
11490 }
11491 case ADJUST_B_RESTORE_MIXER_5:
11492 xconnect_write_coefs(plci, plci->adjust_b_command);
11493 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_6;
11494 Rc = OK;
11495 case ADJUST_B_RESTORE_MIXER_6:
11496 if (!xconnect_write_coefs_process(Id, plci, Rc))
11497 {
11498 dbug(1, dprintf("[%06lx] %s,%d: Write mixer coefs failed",
11499 UnMapId(Id), (char *)(FILE_), __LINE__));
11500 Info = _FACILITY_NOT_SUPPORTED;
11501 break;
11502 }
11503 if (plci->internal_command)
11504 break;
11505 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_7;
11506 case ADJUST_B_RESTORE_MIXER_7:
11507 break;
11508 }
11509 }
11510 return (Info);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011511}
11512
11513
Joe Perches475be4d2012-02-19 19:52:38 -080011514static void mixer_command(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011515{
Joe Perches475be4d2012-02-19 19:52:38 -080011516 DIVA_CAPI_ADAPTER *a;
11517 word i, internal_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011518
Joe Perches475be4d2012-02-19 19:52:38 -080011519 dbug(1, dprintf("[%06lx] %s,%d: mixer_command %02x %04x %04x",
11520 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command,
11521 plci->li_cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011522
Joe Perches475be4d2012-02-19 19:52:38 -080011523 a = plci->adapter;
11524 internal_command = plci->internal_command;
11525 plci->internal_command = 0;
11526 switch (plci->li_cmd)
11527 {
11528 case LI_REQ_CONNECT:
11529 case LI_REQ_DISCONNECT:
11530 case LI_REQ_SILENT_UPDATE:
11531 switch (internal_command)
11532 {
11533 default:
11534 if (plci->li_channel_bits & LI_CHANNEL_INVOLVED)
11535 {
11536 adjust_b1_resource(Id, plci, NULL, (word)(plci->B1_facilities |
11537 B1_FACILITY_MIXER), MIXER_COMMAND_1);
11538 }
11539 case MIXER_COMMAND_1:
11540 if (plci->li_channel_bits & LI_CHANNEL_INVOLVED)
11541 {
11542 if (adjust_b_process(Id, plci, Rc) != GOOD)
11543 {
11544 dbug(1, dprintf("[%06lx] %s,%d: Load mixer failed",
11545 UnMapId(Id), (char *)(FILE_), __LINE__));
11546 break;
11547 }
11548 if (plci->internal_command)
11549 return;
11550 }
11551 plci->li_plci_b_req_pos = plci->li_plci_b_write_pos;
11552 if ((plci->li_channel_bits & LI_CHANNEL_INVOLVED)
11553 || ((get_b1_facilities(plci, plci->B1_resource) & B1_FACILITY_MIXER)
11554 && (add_b1_facilities(plci, plci->B1_resource, (word)(plci->B1_facilities &
11555 ~B1_FACILITY_MIXER)) == plci->B1_resource)))
11556 {
11557 xconnect_write_coefs(plci, MIXER_COMMAND_2);
11558 }
11559 else
11560 {
11561 do
11562 {
11563 mixer_indication_coefs_set(Id, plci);
11564 } while (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos);
11565 }
11566 case MIXER_COMMAND_2:
11567 if ((plci->li_channel_bits & LI_CHANNEL_INVOLVED)
11568 || ((get_b1_facilities(plci, plci->B1_resource) & B1_FACILITY_MIXER)
11569 && (add_b1_facilities(plci, plci->B1_resource, (word)(plci->B1_facilities &
11570 ~B1_FACILITY_MIXER)) == plci->B1_resource)))
11571 {
11572 if (!xconnect_write_coefs_process(Id, plci, Rc))
11573 {
11574 dbug(1, dprintf("[%06lx] %s,%d: Write mixer coefs failed",
11575 UnMapId(Id), (char *)(FILE_), __LINE__));
11576 if (plci->li_plci_b_write_pos != plci->li_plci_b_req_pos)
11577 {
11578 do
11579 {
11580 plci->li_plci_b_write_pos = (plci->li_plci_b_write_pos == 0) ?
11581 LI_PLCI_B_QUEUE_ENTRIES - 1 : plci->li_plci_b_write_pos - 1;
11582 i = (plci->li_plci_b_write_pos == 0) ?
11583 LI_PLCI_B_QUEUE_ENTRIES - 1 : plci->li_plci_b_write_pos - 1;
11584 } while ((plci->li_plci_b_write_pos != plci->li_plci_b_req_pos)
11585 && !(plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG));
11586 }
11587 break;
11588 }
11589 if (plci->internal_command)
11590 return;
11591 }
11592 if (!(plci->li_channel_bits & LI_CHANNEL_INVOLVED))
11593 {
11594 adjust_b1_resource(Id, plci, NULL, (word)(plci->B1_facilities &
11595 ~B1_FACILITY_MIXER), MIXER_COMMAND_3);
11596 }
11597 case MIXER_COMMAND_3:
11598 if (!(plci->li_channel_bits & LI_CHANNEL_INVOLVED))
11599 {
11600 if (adjust_b_process(Id, plci, Rc) != GOOD)
11601 {
11602 dbug(1, dprintf("[%06lx] %s,%d: Unload mixer failed",
11603 UnMapId(Id), (char *)(FILE_), __LINE__));
11604 break;
11605 }
11606 if (plci->internal_command)
11607 return;
11608 }
11609 break;
11610 }
11611 break;
11612 }
11613 if ((plci->li_bchannel_id == 0)
11614 || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci))
11615 {
11616 dbug(1, dprintf("[%06x] %s,%d: Channel id wiped out %d",
11617 UnMapId(Id), (char *)(FILE_), __LINE__, (int)(plci->li_bchannel_id)));
11618 }
11619 else
11620 {
11621 i = a->li_base + (plci->li_bchannel_id - 1);
11622 li_config_table[i].curchnl = plci->li_channel_bits;
11623 if (!a->li_pri && (plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
11624 {
11625 i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
11626 li_config_table[i].curchnl = plci->li_channel_bits;
11627 if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
11628 {
11629 i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
11630 li_config_table[i].curchnl = plci->li_channel_bits;
11631 }
11632 }
11633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011634}
11635
11636
Joe Perches475be4d2012-02-19 19:52:38 -080011637static void li_update_connect(dword Id, DIVA_CAPI_ADAPTER *a, PLCI *plci,
11638 dword plci_b_id, byte connect, dword li_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011639{
Joe Perches475be4d2012-02-19 19:52:38 -080011640 word i, ch_a, ch_a_v, ch_a_s, ch_b, ch_b_v, ch_b_s;
11641 PLCI *plci_b;
11642 DIVA_CAPI_ADAPTER *a_b;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011643
Joe Perches475be4d2012-02-19 19:52:38 -080011644 a_b = &(adapter[MapController((byte)(plci_b_id & 0x7f)) - 1]);
11645 plci_b = &(a_b->plci[((plci_b_id >> 8) & 0xff) - 1]);
11646 ch_a = a->li_base + (plci->li_bchannel_id - 1);
11647 if (!a->li_pri && (plci->tel == ADV_VOICE)
11648 && (plci == a->AdvSignalPLCI) && (Id & EXT_CONTROLLER))
11649 {
11650 ch_a_v = ch_a + MIXER_IC_CHANNEL_BASE;
11651 ch_a_s = (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
11652 a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id) : ch_a_v;
11653 }
11654 else
11655 {
11656 ch_a_v = ch_a;
11657 ch_a_s = ch_a;
11658 }
11659 ch_b = a_b->li_base + (plci_b->li_bchannel_id - 1);
11660 if (!a_b->li_pri && (plci_b->tel == ADV_VOICE)
11661 && (plci_b == a_b->AdvSignalPLCI) && (plci_b_id & EXT_CONTROLLER))
11662 {
11663 ch_b_v = ch_b + MIXER_IC_CHANNEL_BASE;
11664 ch_b_s = (a_b->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
11665 a_b->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci_b->li_bchannel_id) : ch_b_v;
11666 }
11667 else
11668 {
11669 ch_b_v = ch_b;
11670 ch_b_s = ch_b;
11671 }
11672 if (connect)
11673 {
11674 li_config_table[ch_a].flag_table[ch_a_v] &= ~LI_FLAG_MONITOR;
11675 li_config_table[ch_a].flag_table[ch_a_s] &= ~LI_FLAG_MONITOR;
11676 li_config_table[ch_a_v].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
11677 li_config_table[ch_a_s].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
11678 }
11679 li_config_table[ch_a].flag_table[ch_b_v] &= ~LI_FLAG_MONITOR;
11680 li_config_table[ch_a].flag_table[ch_b_s] &= ~LI_FLAG_MONITOR;
11681 li_config_table[ch_b_v].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
11682 li_config_table[ch_b_s].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
11683 if (ch_a_v == ch_b_v)
11684 {
11685 li_config_table[ch_a_v].flag_table[ch_b_v] &= ~LI_FLAG_CONFERENCE;
11686 li_config_table[ch_a_s].flag_table[ch_b_s] &= ~LI_FLAG_CONFERENCE;
11687 }
11688 else
11689 {
11690 if (li_config_table[ch_a_v].flag_table[ch_b_v] & LI_FLAG_CONFERENCE)
11691 {
11692 for (i = 0; i < li_total_channels; i++)
11693 {
11694 if (i != ch_a_v)
11695 li_config_table[ch_a_v].flag_table[i] &= ~LI_FLAG_CONFERENCE;
11696 }
11697 }
11698 if (li_config_table[ch_a_s].flag_table[ch_b_v] & LI_FLAG_CONFERENCE)
11699 {
11700 for (i = 0; i < li_total_channels; i++)
11701 {
11702 if (i != ch_a_s)
11703 li_config_table[ch_a_s].flag_table[i] &= ~LI_FLAG_CONFERENCE;
11704 }
11705 }
11706 if (li_config_table[ch_b_v].flag_table[ch_a_v] & LI_FLAG_CONFERENCE)
11707 {
11708 for (i = 0; i < li_total_channels; i++)
11709 {
11710 if (i != ch_a_v)
11711 li_config_table[i].flag_table[ch_a_v] &= ~LI_FLAG_CONFERENCE;
11712 }
11713 }
11714 if (li_config_table[ch_b_v].flag_table[ch_a_s] & LI_FLAG_CONFERENCE)
11715 {
11716 for (i = 0; i < li_total_channels; i++)
11717 {
11718 if (i != ch_a_s)
11719 li_config_table[i].flag_table[ch_a_s] &= ~LI_FLAG_CONFERENCE;
11720 }
11721 }
11722 }
11723 if (li_flags & LI_FLAG_CONFERENCE_A_B)
11724 {
11725 li_config_table[ch_b_v].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
11726 li_config_table[ch_b_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
11727 li_config_table[ch_b_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
11728 li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
11729 }
11730 if (li_flags & LI_FLAG_CONFERENCE_B_A)
11731 {
11732 li_config_table[ch_a_v].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
11733 li_config_table[ch_a_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
11734 li_config_table[ch_a_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
11735 li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
11736 }
11737 if (li_flags & LI_FLAG_MONITOR_A)
11738 {
11739 li_config_table[ch_a].flag_table[ch_a_v] |= LI_FLAG_MONITOR;
11740 li_config_table[ch_a].flag_table[ch_a_s] |= LI_FLAG_MONITOR;
11741 }
11742 if (li_flags & LI_FLAG_MONITOR_B)
11743 {
11744 li_config_table[ch_a].flag_table[ch_b_v] |= LI_FLAG_MONITOR;
11745 li_config_table[ch_a].flag_table[ch_b_s] |= LI_FLAG_MONITOR;
11746 }
11747 if (li_flags & LI_FLAG_ANNOUNCEMENT_A)
11748 {
11749 li_config_table[ch_a_v].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
11750 li_config_table[ch_a_s].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
11751 }
11752 if (li_flags & LI_FLAG_ANNOUNCEMENT_B)
11753 {
11754 li_config_table[ch_b_v].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
11755 li_config_table[ch_b_s].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
11756 }
11757 if (li_flags & LI_FLAG_MIX_A)
11758 {
11759 li_config_table[ch_a_v].flag_table[ch_a] |= LI_FLAG_MIX;
11760 li_config_table[ch_a_s].flag_table[ch_a] |= LI_FLAG_MIX;
11761 }
11762 if (li_flags & LI_FLAG_MIX_B)
11763 {
11764 li_config_table[ch_b_v].flag_table[ch_a] |= LI_FLAG_MIX;
11765 li_config_table[ch_b_s].flag_table[ch_a] |= LI_FLAG_MIX;
11766 }
11767 if (ch_a_v != ch_a_s)
11768 {
11769 li_config_table[ch_a_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
11770 li_config_table[ch_a_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
11771 }
11772 if (ch_b_v != ch_b_s)
11773 {
11774 li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
11775 li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
11776 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011777}
11778
11779
Joe Perches475be4d2012-02-19 19:52:38 -080011780static void li2_update_connect(dword Id, DIVA_CAPI_ADAPTER *a, PLCI *plci,
11781 dword plci_b_id, byte connect, dword li_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011782{
Joe Perches475be4d2012-02-19 19:52:38 -080011783 word ch_a, ch_a_v, ch_a_s, ch_b, ch_b_v, ch_b_s;
11784 PLCI *plci_b;
11785 DIVA_CAPI_ADAPTER *a_b;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011786
Joe Perches475be4d2012-02-19 19:52:38 -080011787 a_b = &(adapter[MapController((byte)(plci_b_id & 0x7f)) - 1]);
11788 plci_b = &(a_b->plci[((plci_b_id >> 8) & 0xff) - 1]);
11789 ch_a = a->li_base + (plci->li_bchannel_id - 1);
11790 if (!a->li_pri && (plci->tel == ADV_VOICE)
11791 && (plci == a->AdvSignalPLCI) && (Id & EXT_CONTROLLER))
11792 {
11793 ch_a_v = ch_a + MIXER_IC_CHANNEL_BASE;
11794 ch_a_s = (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
11795 a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id) : ch_a_v;
11796 }
11797 else
11798 {
11799 ch_a_v = ch_a;
11800 ch_a_s = ch_a;
11801 }
11802 ch_b = a_b->li_base + (plci_b->li_bchannel_id - 1);
11803 if (!a_b->li_pri && (plci_b->tel == ADV_VOICE)
11804 && (plci_b == a_b->AdvSignalPLCI) && (plci_b_id & EXT_CONTROLLER))
11805 {
11806 ch_b_v = ch_b + MIXER_IC_CHANNEL_BASE;
11807 ch_b_s = (a_b->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
11808 a_b->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci_b->li_bchannel_id) : ch_b_v;
11809 }
11810 else
11811 {
11812 ch_b_v = ch_b;
11813 ch_b_s = ch_b;
11814 }
11815 if (connect)
11816 {
11817 li_config_table[ch_b].flag_table[ch_b_v] &= ~LI_FLAG_MONITOR;
11818 li_config_table[ch_b].flag_table[ch_b_s] &= ~LI_FLAG_MONITOR;
11819 li_config_table[ch_b_v].flag_table[ch_b] &= ~LI_FLAG_MIX;
11820 li_config_table[ch_b_s].flag_table[ch_b] &= ~LI_FLAG_MIX;
11821 li_config_table[ch_b].flag_table[ch_b] &= ~LI_FLAG_PCCONNECT;
11822 li_config_table[ch_b].chflags &= ~(LI_CHFLAG_MONITOR | LI_CHFLAG_MIX | LI_CHFLAG_LOOP);
11823 }
11824 li_config_table[ch_b_v].flag_table[ch_a_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11825 li_config_table[ch_b_s].flag_table[ch_a_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11826 li_config_table[ch_b_v].flag_table[ch_a_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11827 li_config_table[ch_b_s].flag_table[ch_a_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11828 li_config_table[ch_a_v].flag_table[ch_b_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11829 li_config_table[ch_a_v].flag_table[ch_b_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11830 li_config_table[ch_a_s].flag_table[ch_b_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11831 li_config_table[ch_a_s].flag_table[ch_b_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11832 if (li_flags & LI2_FLAG_INTERCONNECT_A_B)
11833 {
11834 li_config_table[ch_b_v].flag_table[ch_a_v] |= LI_FLAG_INTERCONNECT;
11835 li_config_table[ch_b_s].flag_table[ch_a_v] |= LI_FLAG_INTERCONNECT;
11836 li_config_table[ch_b_v].flag_table[ch_a_s] |= LI_FLAG_INTERCONNECT;
11837 li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_INTERCONNECT;
11838 }
11839 if (li_flags & LI2_FLAG_INTERCONNECT_B_A)
11840 {
11841 li_config_table[ch_a_v].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
11842 li_config_table[ch_a_v].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
11843 li_config_table[ch_a_s].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
11844 li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
11845 }
11846 if (li_flags & LI2_FLAG_MONITOR_B)
11847 {
11848 li_config_table[ch_b].flag_table[ch_b_v] |= LI_FLAG_MONITOR;
11849 li_config_table[ch_b].flag_table[ch_b_s] |= LI_FLAG_MONITOR;
11850 }
11851 if (li_flags & LI2_FLAG_MIX_B)
11852 {
11853 li_config_table[ch_b_v].flag_table[ch_b] |= LI_FLAG_MIX;
11854 li_config_table[ch_b_s].flag_table[ch_b] |= LI_FLAG_MIX;
11855 }
11856 if (li_flags & LI2_FLAG_MONITOR_X)
11857 li_config_table[ch_b].chflags |= LI_CHFLAG_MONITOR;
11858 if (li_flags & LI2_FLAG_MIX_X)
11859 li_config_table[ch_b].chflags |= LI_CHFLAG_MIX;
11860 if (li_flags & LI2_FLAG_LOOP_B)
11861 {
11862 li_config_table[ch_b_v].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
11863 li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
11864 li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
11865 li_config_table[ch_b_s].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
11866 }
11867 if (li_flags & LI2_FLAG_LOOP_PC)
11868 li_config_table[ch_b].flag_table[ch_b] |= LI_FLAG_PCCONNECT;
11869 if (li_flags & LI2_FLAG_LOOP_X)
11870 li_config_table[ch_b].chflags |= LI_CHFLAG_LOOP;
11871 if (li_flags & LI2_FLAG_PCCONNECT_A_B)
11872 li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_PCCONNECT;
11873 if (li_flags & LI2_FLAG_PCCONNECT_B_A)
11874 li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_PCCONNECT;
11875 if (ch_a_v != ch_a_s)
11876 {
11877 li_config_table[ch_a_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
11878 li_config_table[ch_a_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
11879 }
11880 if (ch_b_v != ch_b_s)
11881 {
11882 li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
11883 li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
11884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011885}
11886
11887
Joe Perches475be4d2012-02-19 19:52:38 -080011888static word li_check_main_plci(dword Id, PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011889{
Joe Perches475be4d2012-02-19 19:52:38 -080011890 if (plci == NULL)
11891 {
11892 dbug(1, dprintf("[%06lx] %s,%d: Wrong PLCI",
11893 UnMapId(Id), (char *)(FILE_), __LINE__));
11894 return (_WRONG_IDENTIFIER);
11895 }
11896 if (!plci->State
11897 || !plci->NL.Id || plci->nl_remove_id
11898 || (plci->li_bchannel_id == 0))
11899 {
11900 dbug(1, dprintf("[%06lx] %s,%d: Wrong state",
11901 UnMapId(Id), (char *)(FILE_), __LINE__));
11902 return (_WRONG_STATE);
11903 }
11904 li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci = plci;
11905 return (GOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011906}
11907
11908
Joe Perches475be4d2012-02-19 19:52:38 -080011909static PLCI *li_check_plci_b(dword Id, PLCI *plci,
11910 dword plci_b_id, word plci_b_write_pos, byte *p_result)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011911{
Joe Perches475be4d2012-02-19 19:52:38 -080011912 byte ctlr_b;
11913 PLCI *plci_b;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011914
Joe Perches475be4d2012-02-19 19:52:38 -080011915 if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
11916 LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2)
11917 {
11918 dbug(1, dprintf("[%06lx] %s,%d: LI request overrun",
11919 UnMapId(Id), (char *)(FILE_), __LINE__));
11920 PUT_WORD(p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE);
11921 return (NULL);
11922 }
11923 ctlr_b = 0;
11924 if ((plci_b_id & 0x7f) != 0)
11925 {
11926 ctlr_b = MapController((byte)(plci_b_id & 0x7f));
11927 if ((ctlr_b > max_adapter) || ((ctlr_b != 0) && (adapter[ctlr_b - 1].request == NULL)))
11928 ctlr_b = 0;
11929 }
11930 if ((ctlr_b == 0)
11931 || (((plci_b_id >> 8) & 0xff) == 0)
11932 || (((plci_b_id >> 8) & 0xff) > adapter[ctlr_b - 1].max_plci))
11933 {
11934 dbug(1, dprintf("[%06lx] %s,%d: LI invalid second PLCI %08lx",
11935 UnMapId(Id), (char *)(FILE_), __LINE__, plci_b_id));
11936 PUT_WORD(p_result, _WRONG_IDENTIFIER);
11937 return (NULL);
11938 }
11939 plci_b = &(adapter[ctlr_b - 1].plci[((plci_b_id >> 8) & 0xff) - 1]);
11940 if (!plci_b->State
11941 || !plci_b->NL.Id || plci_b->nl_remove_id
11942 || (plci_b->li_bchannel_id == 0))
11943 {
11944 dbug(1, dprintf("[%06lx] %s,%d: LI peer in wrong state %08lx",
11945 UnMapId(Id), (char *)(FILE_), __LINE__, plci_b_id));
11946 PUT_WORD(p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE);
11947 return (NULL);
11948 }
11949 li_config_table[plci_b->adapter->li_base + (plci_b->li_bchannel_id - 1)].plci = plci_b;
11950 if (((byte)(plci_b_id & ~EXT_CONTROLLER)) !=
11951 ((byte)(UnMapController(plci->adapter->Id) & ~EXT_CONTROLLER))
11952 && (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
11953 || !(plci_b->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)))
11954 {
11955 dbug(1, dprintf("[%06lx] %s,%d: LI not on same ctrl %08lx",
11956 UnMapId(Id), (char *)(FILE_), __LINE__, plci_b_id));
11957 PUT_WORD(p_result, _WRONG_IDENTIFIER);
11958 return (NULL);
11959 }
11960 if (!(get_b1_facilities(plci_b, add_b1_facilities(plci_b, plci_b->B1_resource,
11961 (word)(plci_b->B1_facilities | B1_FACILITY_MIXER))) & B1_FACILITY_MIXER))
11962 {
11963 dbug(1, dprintf("[%06lx] %s,%d: Interconnect peer cannot mix %d",
11964 UnMapId(Id), (char *)(FILE_), __LINE__, plci_b->B1_resource));
11965 PUT_WORD(p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE);
11966 return (NULL);
11967 }
11968 return (plci_b);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011969}
11970
11971
Joe Perches475be4d2012-02-19 19:52:38 -080011972static PLCI *li2_check_plci_b(dword Id, PLCI *plci,
11973 dword plci_b_id, word plci_b_write_pos, byte *p_result)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011974{
Joe Perches475be4d2012-02-19 19:52:38 -080011975 byte ctlr_b;
11976 PLCI *plci_b;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011977
Joe Perches475be4d2012-02-19 19:52:38 -080011978 if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
11979 LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2)
11980 {
11981 dbug(1, dprintf("[%06lx] %s,%d: LI request overrun",
11982 UnMapId(Id), (char *)(FILE_), __LINE__));
11983 PUT_WORD(p_result, _WRONG_STATE);
11984 return (NULL);
11985 }
11986 ctlr_b = 0;
11987 if ((plci_b_id & 0x7f) != 0)
11988 {
11989 ctlr_b = MapController((byte)(plci_b_id & 0x7f));
11990 if ((ctlr_b > max_adapter) || ((ctlr_b != 0) && (adapter[ctlr_b - 1].request == NULL)))
11991 ctlr_b = 0;
11992 }
11993 if ((ctlr_b == 0)
11994 || (((plci_b_id >> 8) & 0xff) == 0)
11995 || (((plci_b_id >> 8) & 0xff) > adapter[ctlr_b - 1].max_plci))
11996 {
11997 dbug(1, dprintf("[%06lx] %s,%d: LI invalid second PLCI %08lx",
11998 UnMapId(Id), (char *)(FILE_), __LINE__, plci_b_id));
11999 PUT_WORD(p_result, _WRONG_IDENTIFIER);
12000 return (NULL);
12001 }
12002 plci_b = &(adapter[ctlr_b - 1].plci[((plci_b_id >> 8) & 0xff) - 1]);
12003 if (!plci_b->State
12004 || !plci_b->NL.Id || plci_b->nl_remove_id
12005 || (plci_b->li_bchannel_id == 0)
12006 || (li_config_table[plci_b->adapter->li_base + (plci_b->li_bchannel_id - 1)].plci != plci_b))
12007 {
12008 dbug(1, dprintf("[%06lx] %s,%d: LI peer in wrong state %08lx",
12009 UnMapId(Id), (char *)(FILE_), __LINE__, plci_b_id));
12010 PUT_WORD(p_result, _WRONG_STATE);
12011 return (NULL);
12012 }
12013 if (((byte)(plci_b_id & ~EXT_CONTROLLER)) !=
12014 ((byte)(UnMapController(plci->adapter->Id) & ~EXT_CONTROLLER))
12015 && (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
12016 || !(plci_b->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)))
12017 {
12018 dbug(1, dprintf("[%06lx] %s,%d: LI not on same ctrl %08lx",
12019 UnMapId(Id), (char *)(FILE_), __LINE__, plci_b_id));
12020 PUT_WORD(p_result, _WRONG_IDENTIFIER);
12021 return (NULL);
12022 }
12023 if (!(get_b1_facilities(plci_b, add_b1_facilities(plci_b, plci_b->B1_resource,
12024 (word)(plci_b->B1_facilities | B1_FACILITY_MIXER))) & B1_FACILITY_MIXER))
12025 {
12026 dbug(1, dprintf("[%06lx] %s,%d: Interconnect peer cannot mix %d",
12027 UnMapId(Id), (char *)(FILE_), __LINE__, plci_b->B1_resource));
12028 PUT_WORD(p_result, _WRONG_STATE);
12029 return (NULL);
12030 }
12031 return (plci_b);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012032}
12033
12034
Joe Perches475be4d2012-02-19 19:52:38 -080012035static byte mixer_request(dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012036{
Joe Perches475be4d2012-02-19 19:52:38 -080012037 word Info;
12038 word i;
12039 dword d, li_flags, plci_b_id;
12040 PLCI *plci_b;
12041 API_PARSE li_parms[3];
12042 API_PARSE li_req_parms[3];
12043 API_PARSE li_participant_struct[2];
12044 API_PARSE li_participant_parms[3];
12045 word participant_parms_pos;
12046 byte result_buffer[32];
12047 byte *result;
12048 word result_pos;
12049 word plci_b_write_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012050
Joe Perches475be4d2012-02-19 19:52:38 -080012051 dbug(1, dprintf("[%06lx] %s,%d: mixer_request",
12052 UnMapId(Id), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012053
Joe Perches475be4d2012-02-19 19:52:38 -080012054 Info = GOOD;
12055 result = result_buffer;
12056 result_buffer[0] = 0;
12057 if (!(a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED))
12058 {
12059 dbug(1, dprintf("[%06lx] %s,%d: Facility not supported",
12060 UnMapId(Id), (char *)(FILE_), __LINE__));
12061 Info = _FACILITY_NOT_SUPPORTED;
12062 }
12063 else if (api_parse(&msg[1].info[1], msg[1].length, "ws", li_parms))
12064 {
12065 dbug(1, dprintf("[%06lx] %s,%d: Wrong message format",
12066 UnMapId(Id), (char *)(FILE_), __LINE__));
12067 Info = _WRONG_MESSAGE_FORMAT;
12068 }
12069 else
12070 {
12071 result_buffer[0] = 3;
12072 PUT_WORD(&result_buffer[1], GET_WORD(li_parms[0].info));
12073 result_buffer[3] = 0;
12074 switch (GET_WORD(li_parms[0].info))
12075 {
12076 case LI_GET_SUPPORTED_SERVICES:
12077 if (appl->appl_flags & APPL_FLAG_OLD_LI_SPEC)
12078 {
12079 result_buffer[0] = 17;
12080 result_buffer[3] = 14;
12081 PUT_WORD(&result_buffer[4], GOOD);
12082 d = 0;
12083 if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_CH)
12084 d |= LI_CONFERENCING_SUPPORTED;
12085 if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_PC)
12086 d |= LI_MONITORING_SUPPORTED;
12087 if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_CH)
12088 d |= LI_ANNOUNCEMENTS_SUPPORTED | LI_MIXING_SUPPORTED;
12089 if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
12090 d |= LI_CROSS_CONTROLLER_SUPPORTED;
12091 PUT_DWORD(&result_buffer[6], d);
12092 if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
12093 {
12094 d = 0;
12095 for (i = 0; i < li_total_channels; i++)
12096 {
12097 if ((li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
12098 && (li_config_table[i].adapter->li_pri
12099 || (i < li_config_table[i].adapter->li_base + MIXER_BCHANNELS_BRI)))
12100 {
12101 d++;
12102 }
12103 }
12104 }
12105 else
12106 {
12107 d = a->li_pri ? a->li_channels : MIXER_BCHANNELS_BRI;
12108 }
12109 PUT_DWORD(&result_buffer[10], d / 2);
12110 PUT_DWORD(&result_buffer[14], d);
12111 }
12112 else
12113 {
12114 result_buffer[0] = 25;
12115 result_buffer[3] = 22;
12116 PUT_WORD(&result_buffer[4], GOOD);
12117 d = LI2_ASYMMETRIC_SUPPORTED | LI2_B_LOOPING_SUPPORTED | LI2_X_LOOPING_SUPPORTED;
12118 if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_PC)
12119 d |= LI2_MONITORING_SUPPORTED | LI2_REMOTE_MONITORING_SUPPORTED;
12120 if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_CH)
12121 d |= LI2_MIXING_SUPPORTED | LI2_REMOTE_MIXING_SUPPORTED;
12122 if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_PC)
12123 d |= LI2_PC_LOOPING_SUPPORTED;
12124 if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
12125 d |= LI2_CROSS_CONTROLLER_SUPPORTED;
12126 PUT_DWORD(&result_buffer[6], d);
12127 d = a->li_pri ? a->li_channels : MIXER_BCHANNELS_BRI;
12128 PUT_DWORD(&result_buffer[10], d / 2);
12129 PUT_DWORD(&result_buffer[14], d - 1);
12130 if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
12131 {
12132 d = 0;
12133 for (i = 0; i < li_total_channels; i++)
12134 {
12135 if ((li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
12136 && (li_config_table[i].adapter->li_pri
12137 || (i < li_config_table[i].adapter->li_base + MIXER_BCHANNELS_BRI)))
12138 {
12139 d++;
12140 }
12141 }
12142 }
12143 PUT_DWORD(&result_buffer[18], d / 2);
12144 PUT_DWORD(&result_buffer[22], d - 1);
12145 }
12146 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012147
Joe Perches475be4d2012-02-19 19:52:38 -080012148 case LI_REQ_CONNECT:
12149 if (li_parms[1].length == 8)
12150 {
12151 appl->appl_flags |= APPL_FLAG_OLD_LI_SPEC;
12152 if (api_parse(&li_parms[1].info[1], li_parms[1].length, "dd", li_req_parms))
12153 {
12154 dbug(1, dprintf("[%06lx] %s,%d: Wrong message format",
12155 UnMapId(Id), (char *)(FILE_), __LINE__));
12156 Info = _WRONG_MESSAGE_FORMAT;
12157 break;
12158 }
12159 plci_b_id = GET_DWORD(li_req_parms[0].info) & 0xffff;
12160 li_flags = GET_DWORD(li_req_parms[1].info);
12161 Info = li_check_main_plci(Id, plci);
12162 result_buffer[0] = 9;
12163 result_buffer[3] = 6;
12164 PUT_DWORD(&result_buffer[4], plci_b_id);
12165 PUT_WORD(&result_buffer[8], GOOD);
12166 if (Info != GOOD)
12167 break;
12168 result = plci->saved_msg.info;
12169 for (i = 0; i <= result_buffer[0]; i++)
12170 result[i] = result_buffer[i];
12171 plci_b_write_pos = plci->li_plci_b_write_pos;
12172 plci_b = li_check_plci_b(Id, plci, plci_b_id, plci_b_write_pos, &result[8]);
12173 if (plci_b == NULL)
12174 break;
12175 li_update_connect(Id, a, plci, plci_b_id, true, li_flags);
12176 plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_LAST_FLAG;
12177 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1;
12178 plci->li_plci_b_write_pos = plci_b_write_pos;
12179 }
12180 else
12181 {
12182 appl->appl_flags &= ~APPL_FLAG_OLD_LI_SPEC;
12183 if (api_parse(&li_parms[1].info[1], li_parms[1].length, "ds", li_req_parms))
12184 {
12185 dbug(1, dprintf("[%06lx] %s,%d: Wrong message format",
12186 UnMapId(Id), (char *)(FILE_), __LINE__));
12187 Info = _WRONG_MESSAGE_FORMAT;
12188 break;
12189 }
12190 li_flags = GET_DWORD(li_req_parms[0].info) & ~(LI2_FLAG_INTERCONNECT_A_B | LI2_FLAG_INTERCONNECT_B_A);
12191 Info = li_check_main_plci(Id, plci);
12192 result_buffer[0] = 7;
12193 result_buffer[3] = 4;
12194 PUT_WORD(&result_buffer[4], Info);
12195 result_buffer[6] = 0;
12196 if (Info != GOOD)
12197 break;
12198 result = plci->saved_msg.info;
12199 for (i = 0; i <= result_buffer[0]; i++)
12200 result[i] = result_buffer[i];
12201 plci_b_write_pos = plci->li_plci_b_write_pos;
12202 participant_parms_pos = 0;
12203 result_pos = 7;
12204 li2_update_connect(Id, a, plci, UnMapId(Id), true, li_flags);
12205 while (participant_parms_pos < li_req_parms[1].length)
12206 {
12207 result[result_pos] = 6;
12208 result_pos += 7;
12209 PUT_DWORD(&result[result_pos - 6], 0);
12210 PUT_WORD(&result[result_pos - 2], GOOD);
12211 if (api_parse(&li_req_parms[1].info[1 + participant_parms_pos],
12212 (word)(li_parms[1].length - participant_parms_pos), "s", li_participant_struct))
12213 {
12214 dbug(1, dprintf("[%06lx] %s,%d: Wrong message format",
12215 UnMapId(Id), (char *)(FILE_), __LINE__));
12216 PUT_WORD(&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
12217 break;
12218 }
12219 if (api_parse(&li_participant_struct[0].info[1],
12220 li_participant_struct[0].length, "dd", li_participant_parms))
12221 {
12222 dbug(1, dprintf("[%06lx] %s,%d: Wrong message format",
12223 UnMapId(Id), (char *)(FILE_), __LINE__));
12224 PUT_WORD(&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
12225 break;
12226 }
12227 plci_b_id = GET_DWORD(li_participant_parms[0].info) & 0xffff;
12228 li_flags = GET_DWORD(li_participant_parms[1].info);
12229 PUT_DWORD(&result[result_pos - 6], plci_b_id);
12230 if (sizeof(result) - result_pos < 7)
12231 {
12232 dbug(1, dprintf("[%06lx] %s,%d: LI result overrun",
12233 UnMapId(Id), (char *)(FILE_), __LINE__));
12234 PUT_WORD(&result[result_pos - 2], _WRONG_STATE);
12235 break;
12236 }
12237 plci_b = li2_check_plci_b(Id, plci, plci_b_id, plci_b_write_pos, &result[result_pos - 2]);
12238 if (plci_b != NULL)
12239 {
12240 li2_update_connect(Id, a, plci, plci_b_id, true, li_flags);
12241 plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id |
12242 ((li_flags & (LI2_FLAG_INTERCONNECT_A_B | LI2_FLAG_INTERCONNECT_B_A |
12243 LI2_FLAG_PCCONNECT_A_B | LI2_FLAG_PCCONNECT_B_A)) ? 0 : LI_PLCI_B_DISC_FLAG);
12244 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1;
12245 }
12246 participant_parms_pos = (word)((&li_participant_struct[0].info[1 + li_participant_struct[0].length]) -
12247 (&li_req_parms[1].info[1]));
12248 }
12249 result[0] = (byte)(result_pos - 1);
12250 result[3] = (byte)(result_pos - 4);
12251 result[6] = (byte)(result_pos - 7);
12252 i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES - 1 : plci_b_write_pos - 1;
12253 if ((plci_b_write_pos == plci->li_plci_b_read_pos)
12254 || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG))
12255 {
12256 plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG;
12257 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1;
12258 }
12259 else
12260 plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG;
12261 plci->li_plci_b_write_pos = plci_b_write_pos;
12262 }
12263 mixer_calculate_coefs(a);
12264 plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel;
12265 mixer_notify_update(plci, true);
12266 sendf(appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
12267 "wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
12268 plci->command = 0;
12269 plci->li_cmd = GET_WORD(li_parms[0].info);
12270 start_internal_command(Id, plci, mixer_command);
12271 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012272
Joe Perches475be4d2012-02-19 19:52:38 -080012273 case LI_REQ_DISCONNECT:
12274 if (li_parms[1].length == 4)
12275 {
12276 appl->appl_flags |= APPL_FLAG_OLD_LI_SPEC;
12277 if (api_parse(&li_parms[1].info[1], li_parms[1].length, "d", li_req_parms))
12278 {
12279 dbug(1, dprintf("[%06lx] %s,%d: Wrong message format",
12280 UnMapId(Id), (char *)(FILE_), __LINE__));
12281 Info = _WRONG_MESSAGE_FORMAT;
12282 break;
12283 }
12284 plci_b_id = GET_DWORD(li_req_parms[0].info) & 0xffff;
12285 Info = li_check_main_plci(Id, plci);
12286 result_buffer[0] = 9;
12287 result_buffer[3] = 6;
12288 PUT_DWORD(&result_buffer[4], GET_DWORD(li_req_parms[0].info));
12289 PUT_WORD(&result_buffer[8], GOOD);
12290 if (Info != GOOD)
12291 break;
12292 result = plci->saved_msg.info;
12293 for (i = 0; i <= result_buffer[0]; i++)
12294 result[i] = result_buffer[i];
12295 plci_b_write_pos = plci->li_plci_b_write_pos;
12296 plci_b = li_check_plci_b(Id, plci, plci_b_id, plci_b_write_pos, &result[8]);
12297 if (plci_b == NULL)
12298 break;
12299 li_update_connect(Id, a, plci, plci_b_id, false, 0);
12300 plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG | LI_PLCI_B_LAST_FLAG;
12301 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1;
12302 plci->li_plci_b_write_pos = plci_b_write_pos;
12303 }
12304 else
12305 {
12306 appl->appl_flags &= ~APPL_FLAG_OLD_LI_SPEC;
12307 if (api_parse(&li_parms[1].info[1], li_parms[1].length, "s", li_req_parms))
12308 {
12309 dbug(1, dprintf("[%06lx] %s,%d: Wrong message format",
12310 UnMapId(Id), (char *)(FILE_), __LINE__));
12311 Info = _WRONG_MESSAGE_FORMAT;
12312 break;
12313 }
12314 Info = li_check_main_plci(Id, plci);
12315 result_buffer[0] = 7;
12316 result_buffer[3] = 4;
12317 PUT_WORD(&result_buffer[4], Info);
12318 result_buffer[6] = 0;
12319 if (Info != GOOD)
12320 break;
12321 result = plci->saved_msg.info;
12322 for (i = 0; i <= result_buffer[0]; i++)
12323 result[i] = result_buffer[i];
12324 plci_b_write_pos = plci->li_plci_b_write_pos;
12325 participant_parms_pos = 0;
12326 result_pos = 7;
12327 while (participant_parms_pos < li_req_parms[0].length)
12328 {
12329 result[result_pos] = 6;
12330 result_pos += 7;
12331 PUT_DWORD(&result[result_pos - 6], 0);
12332 PUT_WORD(&result[result_pos - 2], GOOD);
12333 if (api_parse(&li_req_parms[0].info[1 + participant_parms_pos],
12334 (word)(li_parms[1].length - participant_parms_pos), "s", li_participant_struct))
12335 {
12336 dbug(1, dprintf("[%06lx] %s,%d: Wrong message format",
12337 UnMapId(Id), (char *)(FILE_), __LINE__));
12338 PUT_WORD(&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
12339 break;
12340 }
12341 if (api_parse(&li_participant_struct[0].info[1],
12342 li_participant_struct[0].length, "d", li_participant_parms))
12343 {
12344 dbug(1, dprintf("[%06lx] %s,%d: Wrong message format",
12345 UnMapId(Id), (char *)(FILE_), __LINE__));
12346 PUT_WORD(&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
12347 break;
12348 }
12349 plci_b_id = GET_DWORD(li_participant_parms[0].info) & 0xffff;
12350 PUT_DWORD(&result[result_pos - 6], plci_b_id);
12351 if (sizeof(result) - result_pos < 7)
12352 {
12353 dbug(1, dprintf("[%06lx] %s,%d: LI result overrun",
12354 UnMapId(Id), (char *)(FILE_), __LINE__));
12355 PUT_WORD(&result[result_pos - 2], _WRONG_STATE);
12356 break;
12357 }
12358 plci_b = li2_check_plci_b(Id, plci, plci_b_id, plci_b_write_pos, &result[result_pos - 2]);
12359 if (plci_b != NULL)
12360 {
12361 li2_update_connect(Id, a, plci, plci_b_id, false, 0);
12362 plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG;
12363 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1;
12364 }
12365 participant_parms_pos = (word)((&li_participant_struct[0].info[1 + li_participant_struct[0].length]) -
12366 (&li_req_parms[0].info[1]));
12367 }
12368 result[0] = (byte)(result_pos - 1);
12369 result[3] = (byte)(result_pos - 4);
12370 result[6] = (byte)(result_pos - 7);
12371 i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES - 1 : plci_b_write_pos - 1;
12372 if ((plci_b_write_pos == plci->li_plci_b_read_pos)
12373 || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG))
12374 {
12375 plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG;
12376 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1;
12377 }
12378 else
12379 plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG;
12380 plci->li_plci_b_write_pos = plci_b_write_pos;
12381 }
12382 mixer_calculate_coefs(a);
12383 plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel;
12384 mixer_notify_update(plci, true);
12385 sendf(appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
12386 "wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
12387 plci->command = 0;
12388 plci->li_cmd = GET_WORD(li_parms[0].info);
12389 start_internal_command(Id, plci, mixer_command);
12390 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012391
Joe Perches475be4d2012-02-19 19:52:38 -080012392 case LI_REQ_SILENT_UPDATE:
12393 if (!plci || !plci->State
12394 || !plci->NL.Id || plci->nl_remove_id
12395 || (plci->li_bchannel_id == 0)
12396 || (li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci != plci))
12397 {
12398 dbug(1, dprintf("[%06lx] %s,%d: Wrong state",
12399 UnMapId(Id), (char *)(FILE_), __LINE__));
12400 return (false);
12401 }
12402 plci_b_write_pos = plci->li_plci_b_write_pos;
12403 if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
12404 LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2)
12405 {
12406 dbug(1, dprintf("[%06lx] %s,%d: LI request overrun",
12407 UnMapId(Id), (char *)(FILE_), __LINE__));
12408 return (false);
12409 }
12410 i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES - 1 : plci_b_write_pos - 1;
12411 if ((plci_b_write_pos == plci->li_plci_b_read_pos)
12412 || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG))
12413 {
12414 plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG;
12415 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1;
12416 }
12417 else
12418 plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG;
12419 plci->li_plci_b_write_pos = plci_b_write_pos;
12420 plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel;
12421 plci->command = 0;
12422 plci->li_cmd = GET_WORD(li_parms[0].info);
12423 start_internal_command(Id, plci, mixer_command);
12424 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012425
Joe Perches475be4d2012-02-19 19:52:38 -080012426 default:
12427 dbug(1, dprintf("[%06lx] %s,%d: LI unknown request %04x",
12428 UnMapId(Id), (char *)(FILE_), __LINE__, GET_WORD(li_parms[0].info)));
12429 Info = _FACILITY_NOT_SUPPORTED;
12430 }
12431 }
12432 sendf(appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
12433 "wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
12434 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012435}
12436
12437
Joe Perches475be4d2012-02-19 19:52:38 -080012438static void mixer_indication_coefs_set(dword Id, PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012439{
Joe Perches475be4d2012-02-19 19:52:38 -080012440 dword d;
12441 byte result[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -070012442
Joe Perches475be4d2012-02-19 19:52:38 -080012443 dbug(1, dprintf("[%06lx] %s,%d: mixer_indication_coefs_set",
12444 UnMapId(Id), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012445
Joe Perches475be4d2012-02-19 19:52:38 -080012446 if (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos)
12447 {
12448 do
12449 {
12450 d = plci->li_plci_b_queue[plci->li_plci_b_read_pos];
12451 if (!(d & LI_PLCI_B_SKIP_FLAG))
12452 {
12453 if (plci->appl->appl_flags & APPL_FLAG_OLD_LI_SPEC)
12454 {
12455 if (d & LI_PLCI_B_DISC_FLAG)
12456 {
12457 result[0] = 5;
12458 PUT_WORD(&result[1], LI_IND_DISCONNECT);
12459 result[3] = 2;
12460 PUT_WORD(&result[4], _LI_USER_INITIATED);
12461 }
12462 else
12463 {
12464 result[0] = 7;
12465 PUT_WORD(&result[1], LI_IND_CONNECT_ACTIVE);
12466 result[3] = 4;
12467 PUT_DWORD(&result[4], d & ~LI_PLCI_B_FLAG_MASK);
12468 }
12469 }
12470 else
12471 {
12472 if (d & LI_PLCI_B_DISC_FLAG)
12473 {
12474 result[0] = 9;
12475 PUT_WORD(&result[1], LI_IND_DISCONNECT);
12476 result[3] = 6;
12477 PUT_DWORD(&result[4], d & ~LI_PLCI_B_FLAG_MASK);
12478 PUT_WORD(&result[8], _LI_USER_INITIATED);
12479 }
12480 else
12481 {
12482 result[0] = 7;
12483 PUT_WORD(&result[1], LI_IND_CONNECT_ACTIVE);
12484 result[3] = 4;
12485 PUT_DWORD(&result[4], d & ~LI_PLCI_B_FLAG_MASK);
12486 }
12487 }
12488 sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0,
12489 "ws", SELECTOR_LINE_INTERCONNECT, result);
12490 }
12491 plci->li_plci_b_read_pos = (plci->li_plci_b_read_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ?
12492 0 : plci->li_plci_b_read_pos + 1;
12493 } while (!(d & LI_PLCI_B_LAST_FLAG) && (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos));
12494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012495}
12496
12497
Joe Perches475be4d2012-02-19 19:52:38 -080012498static void mixer_indication_xconnect_from(dword Id, PLCI *plci, byte *msg, word length)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012499{
Joe Perches475be4d2012-02-19 19:52:38 -080012500 word i, j, ch;
12501 struct xconnect_transfer_address_s s, *p;
12502 DIVA_CAPI_ADAPTER *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012503
Joe Perches475be4d2012-02-19 19:52:38 -080012504 dbug(1, dprintf("[%06lx] %s,%d: mixer_indication_xconnect_from %d",
12505 UnMapId(Id), (char *)(FILE_), __LINE__, (int)length));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012506
Joe Perches475be4d2012-02-19 19:52:38 -080012507 a = plci->adapter;
12508 i = 1;
12509 for (i = 1; i < length; i += 16)
12510 {
12511 s.card_address.low = msg[i] | (msg[i + 1] << 8) | (((dword)(msg[i + 2])) << 16) | (((dword)(msg[i + 3])) << 24);
12512 s.card_address.high = msg[i + 4] | (msg[i + 5] << 8) | (((dword)(msg[i + 6])) << 16) | (((dword)(msg[i + 7])) << 24);
12513 s.offset = msg[i + 8] | (msg[i + 9] << 8) | (((dword)(msg[i + 10])) << 16) | (((dword)(msg[i + 11])) << 24);
12514 ch = msg[i + 12] | (msg[i + 13] << 8);
12515 j = ch & XCONNECT_CHANNEL_NUMBER_MASK;
12516 if (!a->li_pri && (plci->li_bchannel_id == 2))
12517 j = 1 - j;
12518 j += a->li_base;
12519 if (ch & XCONNECT_CHANNEL_PORT_PC)
12520 p = &(li_config_table[j].send_pc);
12521 else
12522 p = &(li_config_table[j].send_b);
12523 p->card_address.low = s.card_address.low;
12524 p->card_address.high = s.card_address.high;
12525 p->offset = s.offset;
12526 li_config_table[j].channel |= LI_CHANNEL_ADDRESSES_SET;
12527 }
12528 if (plci->internal_command_queue[0]
12529 && ((plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2)
12530 || (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_3)
12531 || (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_4)))
12532 {
12533 (*(plci->internal_command_queue[0]))(Id, plci, 0);
12534 if (!plci->internal_command)
12535 next_internal_command(Id, plci);
12536 }
12537 mixer_notify_update(plci, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012538}
12539
12540
Joe Perches475be4d2012-02-19 19:52:38 -080012541static void mixer_indication_xconnect_to(dword Id, PLCI *plci, byte *msg, word length)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012542{
12543
Joe Perches475be4d2012-02-19 19:52:38 -080012544 dbug(1, dprintf("[%06lx] %s,%d: mixer_indication_xconnect_to %d",
12545 UnMapId(Id), (char *)(FILE_), __LINE__, (int) length));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012546
12547}
12548
12549
Joe Perches475be4d2012-02-19 19:52:38 -080012550static byte mixer_notify_source_removed(PLCI *plci, dword plci_b_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012551{
Joe Perches475be4d2012-02-19 19:52:38 -080012552 word plci_b_write_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012553
Joe Perches475be4d2012-02-19 19:52:38 -080012554 plci_b_write_pos = plci->li_plci_b_write_pos;
12555 if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
12556 LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 1)
12557 {
12558 dbug(1, dprintf("[%06lx] %s,%d: LI request overrun",
12559 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
12560 (char *)(FILE_), __LINE__));
12561 return (false);
12562 }
12563 plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG;
12564 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES - 1) ? 0 : plci_b_write_pos + 1;
12565 plci->li_plci_b_write_pos = plci_b_write_pos;
12566 return (true);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012567}
12568
12569
Joe Perches475be4d2012-02-19 19:52:38 -080012570static void mixer_remove(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012571{
Joe Perches475be4d2012-02-19 19:52:38 -080012572 DIVA_CAPI_ADAPTER *a;
12573 PLCI *notify_plci;
12574 dword plci_b_id;
12575 word i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012576
Joe Perches475be4d2012-02-19 19:52:38 -080012577 dbug(1, dprintf("[%06lx] %s,%d: mixer_remove",
12578 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
12579 (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012580
Joe Perches475be4d2012-02-19 19:52:38 -080012581 a = plci->adapter;
12582 plci_b_id = (plci->Id << 8) | UnMapController(plci->adapter->Id);
12583 if (a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED)
12584 {
12585 if ((plci->li_bchannel_id != 0)
12586 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
12587 {
12588 i = a->li_base + (plci->li_bchannel_id - 1);
12589 if ((li_config_table[i].curchnl | li_config_table[i].channel) & LI_CHANNEL_INVOLVED)
12590 {
12591 for (j = 0; j < li_total_channels; j++)
12592 {
12593 if ((li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
12594 || (li_config_table[j].flag_table[i] & LI_FLAG_INTERCONNECT))
12595 {
12596 notify_plci = li_config_table[j].plci;
12597 if ((notify_plci != NULL)
12598 && (notify_plci != plci)
12599 && (notify_plci->appl != NULL)
12600 && !(notify_plci->appl->appl_flags & APPL_FLAG_OLD_LI_SPEC)
12601 && (notify_plci->State)
12602 && notify_plci->NL.Id && !notify_plci->nl_remove_id)
12603 {
12604 mixer_notify_source_removed(notify_plci, plci_b_id);
12605 }
12606 }
12607 }
12608 mixer_clear_config(plci);
12609 mixer_calculate_coefs(a);
12610 mixer_notify_update(plci, true);
12611 }
12612 li_config_table[i].plci = NULL;
12613 plci->li_bchannel_id = 0;
12614 }
12615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012616}
12617
12618
12619/*------------------------------------------------------------------*/
12620/* Echo canceller facilities */
12621/*------------------------------------------------------------------*/
12622
12623
Joe Perches475be4d2012-02-19 19:52:38 -080012624static void ec_write_parameters(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012625{
Joe Perches475be4d2012-02-19 19:52:38 -080012626 word w;
12627 byte parameter_buffer[6];
Linus Torvalds1da177e2005-04-16 15:20:36 -070012628
Joe Perches475be4d2012-02-19 19:52:38 -080012629 dbug(1, dprintf("[%06lx] %s,%d: ec_write_parameters",
12630 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
12631 (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012632
Joe Perches475be4d2012-02-19 19:52:38 -080012633 parameter_buffer[0] = 5;
12634 parameter_buffer[1] = DSP_CTRL_SET_LEC_PARAMETERS;
12635 PUT_WORD(&parameter_buffer[2], plci->ec_idi_options);
12636 plci->ec_idi_options &= ~LEC_RESET_COEFFICIENTS;
12637 w = (plci->ec_tail_length == 0) ? 128 : plci->ec_tail_length;
12638 PUT_WORD(&parameter_buffer[4], w);
12639 add_p(plci, FTY, parameter_buffer);
12640 sig_req(plci, TEL_CTRL, 0);
12641 send_req(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012642}
12643
12644
Joe Perches475be4d2012-02-19 19:52:38 -080012645static void ec_clear_config(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012646{
12647
Joe Perches475be4d2012-02-19 19:52:38 -080012648 dbug(1, dprintf("[%06lx] %s,%d: ec_clear_config",
12649 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
12650 (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012651
Joe Perches475be4d2012-02-19 19:52:38 -080012652 plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER |
12653 LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING;
12654 plci->ec_tail_length = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012655}
12656
12657
Joe Perches475be4d2012-02-19 19:52:38 -080012658static void ec_prepare_switch(dword Id, PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012659{
12660
Joe Perches475be4d2012-02-19 19:52:38 -080012661 dbug(1, dprintf("[%06lx] %s,%d: ec_prepare_switch",
12662 UnMapId(Id), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012663
12664}
12665
12666
Joe Perches475be4d2012-02-19 19:52:38 -080012667static word ec_save_config(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012668{
12669
Joe Perches475be4d2012-02-19 19:52:38 -080012670 dbug(1, dprintf("[%06lx] %s,%d: ec_save_config %02x %d",
12671 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012672
Joe Perches475be4d2012-02-19 19:52:38 -080012673 return (GOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012674}
12675
12676
Joe Perches475be4d2012-02-19 19:52:38 -080012677static word ec_restore_config(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012678{
Joe Perches475be4d2012-02-19 19:52:38 -080012679 word Info;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012680
Joe Perches475be4d2012-02-19 19:52:38 -080012681 dbug(1, dprintf("[%06lx] %s,%d: ec_restore_config %02x %d",
12682 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012683
Joe Perches475be4d2012-02-19 19:52:38 -080012684 Info = GOOD;
12685 if (plci->B1_facilities & B1_FACILITY_EC)
12686 {
12687 switch (plci->adjust_b_state)
12688 {
12689 case ADJUST_B_RESTORE_EC_1:
12690 plci->internal_command = plci->adjust_b_command;
12691 if (plci->sig_req)
12692 {
12693 plci->adjust_b_state = ADJUST_B_RESTORE_EC_1;
12694 break;
12695 }
12696 ec_write_parameters(plci);
12697 plci->adjust_b_state = ADJUST_B_RESTORE_EC_2;
12698 break;
12699 case ADJUST_B_RESTORE_EC_2:
12700 if ((Rc != OK) && (Rc != OK_FC))
12701 {
12702 dbug(1, dprintf("[%06lx] %s,%d: Restore EC failed %02x",
12703 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
12704 Info = _WRONG_STATE;
12705 break;
12706 }
12707 break;
12708 }
12709 }
12710 return (Info);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012711}
12712
12713
Joe Perches475be4d2012-02-19 19:52:38 -080012714static void ec_command(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012715{
Joe Perches475be4d2012-02-19 19:52:38 -080012716 word internal_command, Info;
12717 byte result[8];
Linus Torvalds1da177e2005-04-16 15:20:36 -070012718
Joe Perches475be4d2012-02-19 19:52:38 -080012719 dbug(1, dprintf("[%06lx] %s,%d: ec_command %02x %04x %04x %04x %d",
12720 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command,
12721 plci->ec_cmd, plci->ec_idi_options, plci->ec_tail_length));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012722
Joe Perches475be4d2012-02-19 19:52:38 -080012723 Info = GOOD;
12724 if (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC)
12725 {
12726 result[0] = 2;
12727 PUT_WORD(&result[1], EC_SUCCESS);
12728 }
12729 else
12730 {
12731 result[0] = 5;
12732 PUT_WORD(&result[1], plci->ec_cmd);
12733 result[3] = 2;
12734 PUT_WORD(&result[4], GOOD);
12735 }
12736 internal_command = plci->internal_command;
12737 plci->internal_command = 0;
12738 switch (plci->ec_cmd)
12739 {
12740 case EC_ENABLE_OPERATION:
12741 case EC_FREEZE_COEFFICIENTS:
12742 case EC_RESUME_COEFFICIENT_UPDATE:
12743 case EC_RESET_COEFFICIENTS:
12744 switch (internal_command)
12745 {
12746 default:
12747 adjust_b1_resource(Id, plci, NULL, (word)(plci->B1_facilities |
12748 B1_FACILITY_EC), EC_COMMAND_1);
12749 case EC_COMMAND_1:
12750 if (adjust_b_process(Id, plci, Rc) != GOOD)
12751 {
12752 dbug(1, dprintf("[%06lx] %s,%d: Load EC failed",
12753 UnMapId(Id), (char *)(FILE_), __LINE__));
12754 Info = _FACILITY_NOT_SUPPORTED;
12755 break;
12756 }
12757 if (plci->internal_command)
12758 return;
12759 case EC_COMMAND_2:
12760 if (plci->sig_req)
12761 {
12762 plci->internal_command = EC_COMMAND_2;
12763 return;
12764 }
12765 plci->internal_command = EC_COMMAND_3;
12766 ec_write_parameters(plci);
12767 return;
12768 case EC_COMMAND_3:
12769 if ((Rc != OK) && (Rc != OK_FC))
12770 {
12771 dbug(1, dprintf("[%06lx] %s,%d: Enable EC failed %02x",
12772 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
12773 Info = _FACILITY_NOT_SUPPORTED;
12774 break;
12775 }
12776 break;
12777 }
12778 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012779
Joe Perches475be4d2012-02-19 19:52:38 -080012780 case EC_DISABLE_OPERATION:
12781 switch (internal_command)
12782 {
12783 default:
12784 case EC_COMMAND_1:
12785 if (plci->B1_facilities & B1_FACILITY_EC)
12786 {
12787 if (plci->sig_req)
12788 {
12789 plci->internal_command = EC_COMMAND_1;
12790 return;
12791 }
12792 plci->internal_command = EC_COMMAND_2;
12793 ec_write_parameters(plci);
12794 return;
12795 }
12796 Rc = OK;
12797 case EC_COMMAND_2:
12798 if ((Rc != OK) && (Rc != OK_FC))
12799 {
12800 dbug(1, dprintf("[%06lx] %s,%d: Disable EC failed %02x",
12801 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
12802 Info = _FACILITY_NOT_SUPPORTED;
12803 break;
12804 }
12805 adjust_b1_resource(Id, plci, NULL, (word)(plci->B1_facilities &
12806 ~B1_FACILITY_EC), EC_COMMAND_3);
12807 case EC_COMMAND_3:
12808 if (adjust_b_process(Id, plci, Rc) != GOOD)
12809 {
12810 dbug(1, dprintf("[%06lx] %s,%d: Unload EC failed",
12811 UnMapId(Id), (char *)(FILE_), __LINE__));
12812 Info = _FACILITY_NOT_SUPPORTED;
12813 break;
12814 }
12815 if (plci->internal_command)
12816 return;
12817 break;
12818 }
12819 break;
12820 }
12821 sendf(plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->number,
12822 "wws", Info, (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ?
12823 PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012824}
12825
12826
Joe Perches475be4d2012-02-19 19:52:38 -080012827static byte ec_request(dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012828{
Joe Perches475be4d2012-02-19 19:52:38 -080012829 word Info;
12830 word opt;
12831 API_PARSE ec_parms[3];
12832 byte result[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -070012833
Joe Perches475be4d2012-02-19 19:52:38 -080012834 dbug(1, dprintf("[%06lx] %s,%d: ec_request",
12835 UnMapId(Id), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012836
Joe Perches475be4d2012-02-19 19:52:38 -080012837 Info = GOOD;
12838 result[0] = 0;
12839 if (!(a->man_profile.private_options & (1L << PRIVATE_ECHO_CANCELLER)))
12840 {
12841 dbug(1, dprintf("[%06lx] %s,%d: Facility not supported",
12842 UnMapId(Id), (char *)(FILE_), __LINE__));
12843 Info = _FACILITY_NOT_SUPPORTED;
12844 }
12845 else
12846 {
12847 if (appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC)
12848 {
12849 if (api_parse(&msg[1].info[1], msg[1].length, "w", ec_parms))
12850 {
12851 dbug(1, dprintf("[%06lx] %s,%d: Wrong message format",
12852 UnMapId(Id), (char *)(FILE_), __LINE__));
12853 Info = _WRONG_MESSAGE_FORMAT;
12854 }
12855 else
12856 {
12857 if (plci == NULL)
12858 {
12859 dbug(1, dprintf("[%06lx] %s,%d: Wrong PLCI",
12860 UnMapId(Id), (char *)(FILE_), __LINE__));
12861 Info = _WRONG_IDENTIFIER;
12862 }
12863 else if (!plci->State || !plci->NL.Id || plci->nl_remove_id)
12864 {
12865 dbug(1, dprintf("[%06lx] %s,%d: Wrong state",
12866 UnMapId(Id), (char *)(FILE_), __LINE__));
12867 Info = _WRONG_STATE;
12868 }
12869 else
12870 {
12871 plci->command = 0;
12872 plci->ec_cmd = GET_WORD(ec_parms[0].info);
12873 plci->ec_idi_options &= ~(LEC_MANUAL_DISABLE | LEC_RESET_COEFFICIENTS);
12874 result[0] = 2;
12875 PUT_WORD(&result[1], EC_SUCCESS);
12876 if (msg[1].length >= 4)
12877 {
12878 opt = GET_WORD(&ec_parms[0].info[2]);
12879 plci->ec_idi_options &= ~(LEC_ENABLE_NONLINEAR_PROCESSING |
12880 LEC_ENABLE_2100HZ_DETECTOR | LEC_REQUIRE_2100HZ_REVERSALS);
12881 if (!(opt & EC_DISABLE_NON_LINEAR_PROCESSING))
12882 plci->ec_idi_options |= LEC_ENABLE_NONLINEAR_PROCESSING;
12883 if (opt & EC_DETECT_DISABLE_TONE)
12884 plci->ec_idi_options |= LEC_ENABLE_2100HZ_DETECTOR;
12885 if (!(opt & EC_DO_NOT_REQUIRE_REVERSALS))
12886 plci->ec_idi_options |= LEC_REQUIRE_2100HZ_REVERSALS;
12887 if (msg[1].length >= 6)
12888 {
12889 plci->ec_tail_length = GET_WORD(&ec_parms[0].info[4]);
12890 }
12891 }
12892 switch (plci->ec_cmd)
12893 {
12894 case EC_ENABLE_OPERATION:
12895 plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
12896 start_internal_command(Id, plci, ec_command);
12897 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012898
Joe Perches475be4d2012-02-19 19:52:38 -080012899 case EC_DISABLE_OPERATION:
12900 plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER |
12901 LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING |
12902 LEC_RESET_COEFFICIENTS;
12903 start_internal_command(Id, plci, ec_command);
12904 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012905
Joe Perches475be4d2012-02-19 19:52:38 -080012906 case EC_FREEZE_COEFFICIENTS:
12907 plci->ec_idi_options |= LEC_FREEZE_COEFFICIENTS;
12908 start_internal_command(Id, plci, ec_command);
12909 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012910
Joe Perches475be4d2012-02-19 19:52:38 -080012911 case EC_RESUME_COEFFICIENT_UPDATE:
12912 plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
12913 start_internal_command(Id, plci, ec_command);
12914 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012915
Joe Perches475be4d2012-02-19 19:52:38 -080012916 case EC_RESET_COEFFICIENTS:
12917 plci->ec_idi_options |= LEC_RESET_COEFFICIENTS;
12918 start_internal_command(Id, plci, ec_command);
12919 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012920
Joe Perches475be4d2012-02-19 19:52:38 -080012921 default:
12922 dbug(1, dprintf("[%06lx] %s,%d: EC unknown request %04x",
12923 UnMapId(Id), (char *)(FILE_), __LINE__, plci->ec_cmd));
12924 PUT_WORD(&result[1], EC_UNSUPPORTED_OPERATION);
12925 }
12926 }
12927 }
12928 }
12929 else
12930 {
12931 if (api_parse(&msg[1].info[1], msg[1].length, "ws", ec_parms))
12932 {
12933 dbug(1, dprintf("[%06lx] %s,%d: Wrong message format",
12934 UnMapId(Id), (char *)(FILE_), __LINE__));
12935 Info = _WRONG_MESSAGE_FORMAT;
12936 }
12937 else
12938 {
12939 if (GET_WORD(ec_parms[0].info) == EC_GET_SUPPORTED_SERVICES)
12940 {
12941 result[0] = 11;
12942 PUT_WORD(&result[1], EC_GET_SUPPORTED_SERVICES);
12943 result[3] = 8;
12944 PUT_WORD(&result[4], GOOD);
12945 PUT_WORD(&result[6], 0x0007);
12946 PUT_WORD(&result[8], LEC_MAX_SUPPORTED_TAIL_LENGTH);
12947 PUT_WORD(&result[10], 0);
12948 }
12949 else if (plci == NULL)
12950 {
12951 dbug(1, dprintf("[%06lx] %s,%d: Wrong PLCI",
12952 UnMapId(Id), (char *)(FILE_), __LINE__));
12953 Info = _WRONG_IDENTIFIER;
12954 }
12955 else if (!plci->State || !plci->NL.Id || plci->nl_remove_id)
12956 {
12957 dbug(1, dprintf("[%06lx] %s,%d: Wrong state",
12958 UnMapId(Id), (char *)(FILE_), __LINE__));
12959 Info = _WRONG_STATE;
12960 }
12961 else
12962 {
12963 plci->command = 0;
12964 plci->ec_cmd = GET_WORD(ec_parms[0].info);
12965 plci->ec_idi_options &= ~(LEC_MANUAL_DISABLE | LEC_RESET_COEFFICIENTS);
12966 result[0] = 5;
12967 PUT_WORD(&result[1], plci->ec_cmd);
12968 result[3] = 2;
12969 PUT_WORD(&result[4], GOOD);
12970 plci->ec_idi_options &= ~(LEC_ENABLE_NONLINEAR_PROCESSING |
12971 LEC_ENABLE_2100HZ_DETECTOR | LEC_REQUIRE_2100HZ_REVERSALS);
12972 plci->ec_tail_length = 0;
12973 if (ec_parms[1].length >= 2)
12974 {
12975 opt = GET_WORD(&ec_parms[1].info[1]);
12976 if (opt & EC_ENABLE_NON_LINEAR_PROCESSING)
12977 plci->ec_idi_options |= LEC_ENABLE_NONLINEAR_PROCESSING;
12978 if (opt & EC_DETECT_DISABLE_TONE)
12979 plci->ec_idi_options |= LEC_ENABLE_2100HZ_DETECTOR;
12980 if (!(opt & EC_DO_NOT_REQUIRE_REVERSALS))
12981 plci->ec_idi_options |= LEC_REQUIRE_2100HZ_REVERSALS;
12982 if (ec_parms[1].length >= 4)
12983 {
12984 plci->ec_tail_length = GET_WORD(&ec_parms[1].info[3]);
12985 }
12986 }
12987 switch (plci->ec_cmd)
12988 {
12989 case EC_ENABLE_OPERATION:
12990 plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
12991 start_internal_command(Id, plci, ec_command);
12992 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012993
Joe Perches475be4d2012-02-19 19:52:38 -080012994 case EC_DISABLE_OPERATION:
12995 plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER |
12996 LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING |
12997 LEC_RESET_COEFFICIENTS;
12998 start_internal_command(Id, plci, ec_command);
12999 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013000
Joe Perches475be4d2012-02-19 19:52:38 -080013001 default:
13002 dbug(1, dprintf("[%06lx] %s,%d: EC unknown request %04x",
13003 UnMapId(Id), (char *)(FILE_), __LINE__, plci->ec_cmd));
13004 PUT_WORD(&result[4], _FACILITY_SPECIFIC_FUNCTION_NOT_SUPP);
13005 }
13006 }
13007 }
13008 }
13009 }
13010 sendf(appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
13011 "wws", Info, (appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ?
13012 PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result);
13013 return (false);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013014}
13015
13016
Joe Perches475be4d2012-02-19 19:52:38 -080013017static void ec_indication(dword Id, PLCI *plci, byte *msg, word length)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013018{
Joe Perches475be4d2012-02-19 19:52:38 -080013019 byte result[8];
Linus Torvalds1da177e2005-04-16 15:20:36 -070013020
Joe Perches475be4d2012-02-19 19:52:38 -080013021 dbug(1, dprintf("[%06lx] %s,%d: ec_indication",
13022 UnMapId(Id), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013023
Joe Perches475be4d2012-02-19 19:52:38 -080013024 if (!(plci->ec_idi_options & LEC_MANUAL_DISABLE))
13025 {
13026 if (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC)
13027 {
13028 result[0] = 2;
13029 PUT_WORD(&result[1], 0);
13030 switch (msg[1])
13031 {
13032 case LEC_DISABLE_TYPE_CONTIGNUOUS_2100HZ:
13033 PUT_WORD(&result[1], EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ);
13034 break;
13035 case LEC_DISABLE_TYPE_REVERSED_2100HZ:
13036 PUT_WORD(&result[1], EC_BYPASS_DUE_TO_REVERSED_2100HZ);
13037 break;
13038 case LEC_DISABLE_RELEASED:
13039 PUT_WORD(&result[1], EC_BYPASS_RELEASED);
13040 break;
13041 }
13042 }
13043 else
13044 {
13045 result[0] = 5;
13046 PUT_WORD(&result[1], EC_BYPASS_INDICATION);
13047 result[3] = 2;
13048 PUT_WORD(&result[4], 0);
13049 switch (msg[1])
13050 {
13051 case LEC_DISABLE_TYPE_CONTIGNUOUS_2100HZ:
13052 PUT_WORD(&result[4], EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ);
13053 break;
13054 case LEC_DISABLE_TYPE_REVERSED_2100HZ:
13055 PUT_WORD(&result[4], EC_BYPASS_DUE_TO_REVERSED_2100HZ);
13056 break;
13057 case LEC_DISABLE_RELEASED:
13058 PUT_WORD(&result[4], EC_BYPASS_RELEASED);
13059 break;
13060 }
13061 }
13062 sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ?
13063 PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result);
13064 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013065}
13066
13067
13068
13069/*------------------------------------------------------------------*/
13070/* Advanced voice */
13071/*------------------------------------------------------------------*/
13072
Joe Perches475be4d2012-02-19 19:52:38 -080013073static void adv_voice_write_coefs(PLCI *plci, word write_command)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013074{
Joe Perches475be4d2012-02-19 19:52:38 -080013075 DIVA_CAPI_ADAPTER *a;
13076 word i;
13077 byte *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013078
Joe Perches475be4d2012-02-19 19:52:38 -080013079 word w, n, j, k;
13080 byte ch_map[MIXER_CHANNELS_BRI];
Linus Torvalds1da177e2005-04-16 15:20:36 -070013081
Joe Perches475be4d2012-02-19 19:52:38 -080013082 byte coef_buffer[ADV_VOICE_COEF_BUFFER_SIZE + 2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070013083
Joe Perches475be4d2012-02-19 19:52:38 -080013084 dbug(1, dprintf("[%06lx] %s,%d: adv_voice_write_coefs %d",
13085 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
13086 (char *)(FILE_), __LINE__, write_command));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013087
Joe Perches475be4d2012-02-19 19:52:38 -080013088 a = plci->adapter;
13089 p = coef_buffer + 1;
13090 *(p++) = DSP_CTRL_OLD_SET_MIXER_COEFFICIENTS;
13091 i = 0;
13092 while (i + sizeof(word) <= a->adv_voice_coef_length)
13093 {
13094 PUT_WORD(p, GET_WORD(a->adv_voice_coef_buffer + i));
13095 p += 2;
13096 i += 2;
13097 }
13098 while (i < ADV_VOICE_OLD_COEF_COUNT * sizeof(word))
13099 {
13100 PUT_WORD(p, 0x8000);
13101 p += 2;
13102 i += 2;
13103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013104
Joe Perches475be4d2012-02-19 19:52:38 -080013105 if (!a->li_pri && (plci->li_bchannel_id == 0))
13106 {
13107 if ((li_config_table[a->li_base].plci == NULL) && (li_config_table[a->li_base + 1].plci != NULL))
13108 {
13109 plci->li_bchannel_id = 1;
13110 li_config_table[a->li_base].plci = plci;
13111 dbug(1, dprintf("[%06lx] %s,%d: adv_voice_set_bchannel_id %d",
13112 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
13113 (char *)(FILE_), __LINE__, plci->li_bchannel_id));
13114 }
13115 else if ((li_config_table[a->li_base].plci != NULL) && (li_config_table[a->li_base + 1].plci == NULL))
13116 {
13117 plci->li_bchannel_id = 2;
13118 li_config_table[a->li_base + 1].plci = plci;
13119 dbug(1, dprintf("[%06lx] %s,%d: adv_voice_set_bchannel_id %d",
13120 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
13121 (char *)(FILE_), __LINE__, plci->li_bchannel_id));
13122 }
13123 }
13124 if (!a->li_pri && (plci->li_bchannel_id != 0)
13125 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
13126 {
13127 i = a->li_base + (plci->li_bchannel_id - 1);
13128 switch (write_command)
13129 {
13130 case ADV_VOICE_WRITE_ACTIVATION:
13131 j = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
13132 k = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
13133 if (!(plci->B1_facilities & B1_FACILITY_MIXER))
13134 {
13135 li_config_table[j].flag_table[i] |= LI_FLAG_CONFERENCE | LI_FLAG_MIX;
13136 li_config_table[i].flag_table[j] |= LI_FLAG_CONFERENCE | LI_FLAG_MONITOR;
13137 }
13138 if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
13139 {
13140 li_config_table[k].flag_table[i] |= LI_FLAG_CONFERENCE | LI_FLAG_MIX;
13141 li_config_table[i].flag_table[k] |= LI_FLAG_CONFERENCE | LI_FLAG_MONITOR;
13142 li_config_table[k].flag_table[j] |= LI_FLAG_CONFERENCE;
13143 li_config_table[j].flag_table[k] |= LI_FLAG_CONFERENCE;
13144 }
13145 mixer_calculate_coefs(a);
13146 li_config_table[i].curchnl = li_config_table[i].channel;
13147 li_config_table[j].curchnl = li_config_table[j].channel;
13148 if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
13149 li_config_table[k].curchnl = li_config_table[k].channel;
13150 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013151
Joe Perches475be4d2012-02-19 19:52:38 -080013152 case ADV_VOICE_WRITE_DEACTIVATION:
13153 for (j = 0; j < li_total_channels; j++)
13154 {
13155 li_config_table[i].flag_table[j] = 0;
13156 li_config_table[j].flag_table[i] = 0;
13157 }
13158 k = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
13159 for (j = 0; j < li_total_channels; j++)
13160 {
13161 li_config_table[k].flag_table[j] = 0;
13162 li_config_table[j].flag_table[k] = 0;
13163 }
13164 if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
13165 {
13166 k = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
13167 for (j = 0; j < li_total_channels; j++)
13168 {
13169 li_config_table[k].flag_table[j] = 0;
13170 li_config_table[j].flag_table[k] = 0;
13171 }
13172 }
13173 mixer_calculate_coefs(a);
13174 break;
13175 }
13176 if (plci->B1_facilities & B1_FACILITY_MIXER)
13177 {
13178 w = 0;
13179 if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length)
13180 w = GET_WORD(a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE);
13181 if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
13182 w |= MIXER_FEATURE_ENABLE_TX_DATA;
13183 if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
13184 w |= MIXER_FEATURE_ENABLE_RX_DATA;
13185 *(p++) = (byte) w;
13186 *(p++) = (byte)(w >> 8);
13187 for (j = 0; j < sizeof(ch_map); j += 2)
13188 {
13189 ch_map[j] = (byte)(j + (plci->li_bchannel_id - 1));
13190 ch_map[j + 1] = (byte)(j + (2 - plci->li_bchannel_id));
13191 }
13192 for (n = 0; n < ARRAY_SIZE(mixer_write_prog_bri); n++)
13193 {
13194 i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
13195 j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
13196 if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED)
13197 {
13198 *(p++) = ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01);
13199 w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
13200 li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4;
13201 }
13202 else
13203 {
13204 *(p++) = (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + n < a->adv_voice_coef_length) ?
13205 a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + n] : 0x00;
13206 }
13207 }
13208 }
13209 else
13210 {
13211 for (i = ADV_VOICE_NEW_COEF_BASE; i < a->adv_voice_coef_length; i++)
13212 *(p++) = a->adv_voice_coef_buffer[i];
13213 }
13214 }
13215 else
Linus Torvalds1da177e2005-04-16 15:20:36 -070013216
Joe Perches475be4d2012-02-19 19:52:38 -080013217 {
13218 for (i = ADV_VOICE_NEW_COEF_BASE; i < a->adv_voice_coef_length; i++)
13219 *(p++) = a->adv_voice_coef_buffer[i];
13220 }
13221 coef_buffer[0] = (p - coef_buffer) - 1;
13222 add_p(plci, FTY, coef_buffer);
13223 sig_req(plci, TEL_CTRL, 0);
13224 send_req(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013225}
13226
13227
Joe Perches475be4d2012-02-19 19:52:38 -080013228static void adv_voice_clear_config(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013229{
Joe Perches475be4d2012-02-19 19:52:38 -080013230 DIVA_CAPI_ADAPTER *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013231
Joe Perches475be4d2012-02-19 19:52:38 -080013232 word i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013233
13234
Joe Perches475be4d2012-02-19 19:52:38 -080013235 dbug(1, dprintf("[%06lx] %s,%d: adv_voice_clear_config",
13236 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
13237 (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013238
Joe Perches475be4d2012-02-19 19:52:38 -080013239 a = plci->adapter;
13240 if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
13241 {
13242 a->adv_voice_coef_length = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013243
Joe Perches475be4d2012-02-19 19:52:38 -080013244 if (!a->li_pri && (plci->li_bchannel_id != 0)
13245 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
13246 {
13247 i = a->li_base + (plci->li_bchannel_id - 1);
13248 li_config_table[i].curchnl = 0;
13249 li_config_table[i].channel = 0;
13250 li_config_table[i].chflags = 0;
13251 for (j = 0; j < li_total_channels; j++)
13252 {
13253 li_config_table[i].flag_table[j] = 0;
13254 li_config_table[j].flag_table[i] = 0;
13255 li_config_table[i].coef_table[j] = 0;
13256 li_config_table[j].coef_table[i] = 0;
13257 }
13258 li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET;
13259 i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
13260 li_config_table[i].curchnl = 0;
13261 li_config_table[i].channel = 0;
13262 li_config_table[i].chflags = 0;
13263 for (j = 0; j < li_total_channels; j++)
13264 {
13265 li_config_table[i].flag_table[j] = 0;
13266 li_config_table[j].flag_table[i] = 0;
13267 li_config_table[i].coef_table[j] = 0;
13268 li_config_table[j].coef_table[i] = 0;
13269 }
13270 if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
13271 {
13272 i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
13273 li_config_table[i].curchnl = 0;
13274 li_config_table[i].channel = 0;
13275 li_config_table[i].chflags = 0;
13276 for (j = 0; j < li_total_channels; j++)
13277 {
13278 li_config_table[i].flag_table[j] = 0;
13279 li_config_table[j].flag_table[i] = 0;
13280 li_config_table[i].coef_table[j] = 0;
13281 li_config_table[j].coef_table[i] = 0;
13282 }
13283 }
13284 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013285
Joe Perches475be4d2012-02-19 19:52:38 -080013286 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013287}
13288
13289
Joe Perches475be4d2012-02-19 19:52:38 -080013290static void adv_voice_prepare_switch(dword Id, PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013291{
13292
Joe Perches475be4d2012-02-19 19:52:38 -080013293 dbug(1, dprintf("[%06lx] %s,%d: adv_voice_prepare_switch",
13294 UnMapId(Id), (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013295
13296}
13297
13298
Joe Perches475be4d2012-02-19 19:52:38 -080013299static word adv_voice_save_config(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013300{
13301
Joe Perches475be4d2012-02-19 19:52:38 -080013302 dbug(1, dprintf("[%06lx] %s,%d: adv_voice_save_config %02x %d",
13303 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013304
Joe Perches475be4d2012-02-19 19:52:38 -080013305 return (GOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013306}
13307
13308
Joe Perches475be4d2012-02-19 19:52:38 -080013309static word adv_voice_restore_config(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013310{
Joe Perches475be4d2012-02-19 19:52:38 -080013311 DIVA_CAPI_ADAPTER *a;
13312 word Info;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013313
Joe Perches475be4d2012-02-19 19:52:38 -080013314 dbug(1, dprintf("[%06lx] %s,%d: adv_voice_restore_config %02x %d",
13315 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013316
Joe Perches475be4d2012-02-19 19:52:38 -080013317 Info = GOOD;
13318 a = plci->adapter;
13319 if ((plci->B1_facilities & B1_FACILITY_VOICE)
13320 && (plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
13321 {
13322 switch (plci->adjust_b_state)
13323 {
13324 case ADJUST_B_RESTORE_VOICE_1:
13325 plci->internal_command = plci->adjust_b_command;
13326 if (plci->sig_req)
13327 {
13328 plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_1;
13329 break;
13330 }
13331 adv_voice_write_coefs(plci, ADV_VOICE_WRITE_UPDATE);
13332 plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_2;
13333 break;
13334 case ADJUST_B_RESTORE_VOICE_2:
13335 if ((Rc != OK) && (Rc != OK_FC))
13336 {
13337 dbug(1, dprintf("[%06lx] %s,%d: Restore voice config failed %02x",
13338 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
13339 Info = _WRONG_STATE;
13340 break;
13341 }
13342 break;
13343 }
13344 }
13345 return (Info);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013346}
13347
13348
13349
13350
13351/*------------------------------------------------------------------*/
13352/* B1 resource switching */
13353/*------------------------------------------------------------------*/
13354
13355static byte b1_facilities_table[] =
13356{
Joe Perches475be4d2012-02-19 19:52:38 -080013357 0x00, /* 0 No bchannel resources */
13358 0x00, /* 1 Codec (automatic law) */
13359 0x00, /* 2 Codec (A-law) */
13360 0x00, /* 3 Codec (y-law) */
13361 0x00, /* 4 HDLC for X.21 */
13362 0x00, /* 5 HDLC */
13363 0x00, /* 6 External Device 0 */
13364 0x00, /* 7 External Device 1 */
13365 0x00, /* 8 HDLC 56k */
13366 0x00, /* 9 Transparent */
13367 0x00, /* 10 Loopback to network */
13368 0x00, /* 11 Test pattern to net */
13369 0x00, /* 12 Rate adaptation sync */
13370 0x00, /* 13 Rate adaptation async */
13371 0x00, /* 14 R-Interface */
13372 0x00, /* 15 HDLC 128k leased line */
13373 0x00, /* 16 FAX */
13374 0x00, /* 17 Modem async */
13375 0x00, /* 18 Modem sync HDLC */
13376 0x00, /* 19 V.110 async HDLC */
13377 0x12, /* 20 Adv voice (Trans,mixer) */
13378 0x00, /* 21 Codec connected to IC */
13379 0x0c, /* 22 Trans,DTMF */
13380 0x1e, /* 23 Trans,DTMF+mixer */
13381 0x1f, /* 24 Trans,DTMF+mixer+local */
13382 0x13, /* 25 Trans,mixer+local */
13383 0x12, /* 26 HDLC,mixer */
13384 0x12, /* 27 HDLC 56k,mixer */
13385 0x2c, /* 28 Trans,LEC+DTMF */
13386 0x3e, /* 29 Trans,LEC+DTMF+mixer */
13387 0x3f, /* 30 Trans,LEC+DTMF+mixer+local */
13388 0x2c, /* 31 RTP,LEC+DTMF */
13389 0x3e, /* 32 RTP,LEC+DTMF+mixer */
13390 0x3f, /* 33 RTP,LEC+DTMF+mixer+local */
13391 0x00, /* 34 Signaling task */
13392 0x00, /* 35 PIAFS */
13393 0x0c, /* 36 Trans,DTMF+TONE */
13394 0x1e, /* 37 Trans,DTMF+TONE+mixer */
13395 0x1f /* 38 Trans,DTMF+TONE+mixer+local*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070013396};
13397
13398
Joe Perches475be4d2012-02-19 19:52:38 -080013399static word get_b1_facilities(PLCI *plci, byte b1_resource)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013400{
Joe Perches475be4d2012-02-19 19:52:38 -080013401 word b1_facilities;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013402
Joe Perches475be4d2012-02-19 19:52:38 -080013403 b1_facilities = b1_facilities_table[b1_resource];
13404 if ((b1_resource == 9) || (b1_resource == 20) || (b1_resource == 25))
13405 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070013406
Joe Perches475be4d2012-02-19 19:52:38 -080013407 if (!(((plci->requested_options_conn | plci->requested_options) & (1L << PRIVATE_DTMF_TONE))
13408 || (plci->appl && (plci->adapter->requested_options_table[plci->appl->Id - 1] & (1L << PRIVATE_DTMF_TONE)))))
Linus Torvalds1da177e2005-04-16 15:20:36 -070013409
Joe Perches475be4d2012-02-19 19:52:38 -080013410 {
13411 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_SEND)
13412 b1_facilities |= B1_FACILITY_DTMFX;
13413 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE)
13414 b1_facilities |= B1_FACILITY_DTMFR;
13415 }
13416 }
13417 if ((b1_resource == 17) || (b1_resource == 18))
13418 {
13419 if (plci->adapter->manufacturer_features & (MANUFACTURER_FEATURE_V18 | MANUFACTURER_FEATURE_VOWN))
13420 b1_facilities |= B1_FACILITY_DTMFX | B1_FACILITY_DTMFR;
13421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013422/*
Joe Perches475be4d2012-02-19 19:52:38 -080013423 dbug (1, dprintf("[%06lx] %s,%d: get_b1_facilities %d %04x",
13424 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
13425 (char far *)(FILE_), __LINE__, b1_resource, b1_facilites));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013426*/
Joe Perches475be4d2012-02-19 19:52:38 -080013427 return (b1_facilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013428}
13429
13430
Joe Perches475be4d2012-02-19 19:52:38 -080013431static byte add_b1_facilities(PLCI *plci, byte b1_resource, word b1_facilities)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013432{
Joe Perches475be4d2012-02-19 19:52:38 -080013433 byte b;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013434
Joe Perches475be4d2012-02-19 19:52:38 -080013435 switch (b1_resource)
13436 {
13437 case 5:
13438 case 26:
13439 if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
13440 b = 26;
13441 else
13442 b = 5;
13443 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013444
Joe Perches475be4d2012-02-19 19:52:38 -080013445 case 8:
13446 case 27:
13447 if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
13448 b = 27;
13449 else
13450 b = 8;
13451 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013452
Joe Perches475be4d2012-02-19 19:52:38 -080013453 case 9:
13454 case 20:
13455 case 22:
13456 case 23:
13457 case 24:
13458 case 25:
13459 case 28:
13460 case 29:
13461 case 30:
13462 case 36:
13463 case 37:
13464 case 38:
13465 if (b1_facilities & B1_FACILITY_EC)
13466 {
13467 if (b1_facilities & B1_FACILITY_LOCAL)
13468 b = 30;
13469 else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
13470 b = 29;
13471 else
13472 b = 28;
13473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013474
Joe Perches475be4d2012-02-19 19:52:38 -080013475 else if ((b1_facilities & (B1_FACILITY_DTMFX | B1_FACILITY_DTMFR | B1_FACILITY_MIXER))
13476 && (((plci->requested_options_conn | plci->requested_options) & (1L << PRIVATE_DTMF_TONE))
13477 || (plci->appl && (plci->adapter->requested_options_table[plci->appl->Id - 1] & (1L << PRIVATE_DTMF_TONE)))))
13478 {
13479 if (b1_facilities & B1_FACILITY_LOCAL)
13480 b = 38;
13481 else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
13482 b = 37;
13483 else
13484 b = 36;
13485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013486
Joe Perches475be4d2012-02-19 19:52:38 -080013487 else if (((plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_HARDDTMF)
13488 && !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE))
13489 || ((b1_facilities & B1_FACILITY_DTMFR)
13490 && ((b1_facilities & B1_FACILITY_MIXER)
13491 || !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE)))
13492 || ((b1_facilities & B1_FACILITY_DTMFX)
13493 && ((b1_facilities & B1_FACILITY_MIXER)
13494 || !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_SEND))))
13495 {
13496 if (b1_facilities & B1_FACILITY_LOCAL)
13497 b = 24;
13498 else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
13499 b = 23;
13500 else
13501 b = 22;
13502 }
13503 else
13504 {
13505 if (b1_facilities & B1_FACILITY_LOCAL)
13506 b = 25;
13507 else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
13508 b = 20;
13509 else
13510 b = 9;
13511 }
13512 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013513
Joe Perches475be4d2012-02-19 19:52:38 -080013514 case 31:
13515 case 32:
13516 case 33:
13517 if (b1_facilities & B1_FACILITY_LOCAL)
13518 b = 33;
13519 else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
13520 b = 32;
13521 else
13522 b = 31;
13523 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013524
Joe Perches475be4d2012-02-19 19:52:38 -080013525 default:
13526 b = b1_resource;
13527 }
13528 dbug(1, dprintf("[%06lx] %s,%d: add_b1_facilities %d %04x %d %04x",
13529 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
13530 (char *)(FILE_), __LINE__,
13531 b1_resource, b1_facilities, b, get_b1_facilities(plci, b)));
13532 return (b);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013533}
13534
13535
Joe Perches475be4d2012-02-19 19:52:38 -080013536static void adjust_b1_facilities(PLCI *plci, byte new_b1_resource, word new_b1_facilities)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013537{
Joe Perches475be4d2012-02-19 19:52:38 -080013538 word removed_facilities;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013539
Joe Perches475be4d2012-02-19 19:52:38 -080013540 dbug(1, dprintf("[%06lx] %s,%d: adjust_b1_facilities %d %04x %04x",
13541 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
13542 (char *)(FILE_), __LINE__, new_b1_resource, new_b1_facilities,
13543 new_b1_facilities & get_b1_facilities(plci, new_b1_resource)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013544
Joe Perches475be4d2012-02-19 19:52:38 -080013545 new_b1_facilities &= get_b1_facilities(plci, new_b1_resource);
13546 removed_facilities = plci->B1_facilities & ~new_b1_facilities;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013547
Joe Perches475be4d2012-02-19 19:52:38 -080013548 if (removed_facilities & B1_FACILITY_EC)
13549 ec_clear_config(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013550
13551
Joe Perches475be4d2012-02-19 19:52:38 -080013552 if (removed_facilities & B1_FACILITY_DTMFR)
13553 {
13554 dtmf_rec_clear_config(plci);
13555 dtmf_parameter_clear_config(plci);
13556 }
13557 if (removed_facilities & B1_FACILITY_DTMFX)
13558 dtmf_send_clear_config(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013559
13560
Joe Perches475be4d2012-02-19 19:52:38 -080013561 if (removed_facilities & B1_FACILITY_MIXER)
13562 mixer_clear_config(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013563
Joe Perches475be4d2012-02-19 19:52:38 -080013564 if (removed_facilities & B1_FACILITY_VOICE)
13565 adv_voice_clear_config(plci);
13566 plci->B1_facilities = new_b1_facilities;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013567}
13568
13569
Joe Perches475be4d2012-02-19 19:52:38 -080013570static void adjust_b_clear(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013571{
13572
Joe Perches475be4d2012-02-19 19:52:38 -080013573 dbug(1, dprintf("[%06lx] %s,%d: adjust_b_clear",
13574 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
13575 (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013576
Joe Perches475be4d2012-02-19 19:52:38 -080013577 plci->adjust_b_restore = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013578}
13579
13580
Joe Perches475be4d2012-02-19 19:52:38 -080013581static word adjust_b_process(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013582{
Joe Perches475be4d2012-02-19 19:52:38 -080013583 word Info;
13584 byte b1_resource;
13585 NCCI *ncci_ptr;
13586 API_PARSE bp[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070013587
Joe Perches475be4d2012-02-19 19:52:38 -080013588 dbug(1, dprintf("[%06lx] %s,%d: adjust_b_process %02x %d",
13589 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013590
Joe Perches475be4d2012-02-19 19:52:38 -080013591 Info = GOOD;
13592 switch (plci->adjust_b_state)
13593 {
13594 case ADJUST_B_START:
13595 if ((plci->adjust_b_parms_msg == NULL)
13596 && (plci->adjust_b_mode & ADJUST_B_MODE_SWITCH_L1)
13597 && ((plci->adjust_b_mode & ~(ADJUST_B_MODE_SAVE | ADJUST_B_MODE_SWITCH_L1 |
13598 ADJUST_B_MODE_NO_RESOURCE | ADJUST_B_MODE_RESTORE)) == 0))
13599 {
13600 b1_resource = (plci->adjust_b_mode == ADJUST_B_MODE_NO_RESOURCE) ?
13601 0 : add_b1_facilities(plci, plci->B1_resource, plci->adjust_b_facilities);
13602 if (b1_resource == plci->B1_resource)
13603 {
13604 adjust_b1_facilities(plci, b1_resource, plci->adjust_b_facilities);
13605 break;
13606 }
13607 if (plci->adjust_b_facilities & ~get_b1_facilities(plci, b1_resource))
13608 {
13609 dbug(1, dprintf("[%06lx] %s,%d: Adjust B nonsupported facilities %d %d %04x",
13610 UnMapId(Id), (char *)(FILE_), __LINE__,
13611 plci->B1_resource, b1_resource, plci->adjust_b_facilities));
13612 Info = _WRONG_STATE;
13613 break;
13614 }
13615 }
13616 if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
13617 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070013618
Joe Perches475be4d2012-02-19 19:52:38 -080013619 mixer_prepare_switch(Id, plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013620
13621
Joe Perches475be4d2012-02-19 19:52:38 -080013622 dtmf_prepare_switch(Id, plci);
13623 dtmf_parameter_prepare_switch(Id, plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013624
13625
Joe Perches475be4d2012-02-19 19:52:38 -080013626 ec_prepare_switch(Id, plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013627
Joe Perches475be4d2012-02-19 19:52:38 -080013628 adv_voice_prepare_switch(Id, plci);
13629 }
13630 plci->adjust_b_state = ADJUST_B_SAVE_MIXER_1;
13631 Rc = OK;
13632 case ADJUST_B_SAVE_MIXER_1:
13633 if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
13634 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070013635
Joe Perches475be4d2012-02-19 19:52:38 -080013636 Info = mixer_save_config(Id, plci, Rc);
13637 if ((Info != GOOD) || plci->internal_command)
13638 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013639
Joe Perches475be4d2012-02-19 19:52:38 -080013640 }
13641 plci->adjust_b_state = ADJUST_B_SAVE_DTMF_1;
13642 Rc = OK;
13643 case ADJUST_B_SAVE_DTMF_1:
13644 if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
13645 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070013646
Joe Perches475be4d2012-02-19 19:52:38 -080013647 Info = dtmf_save_config(Id, plci, Rc);
13648 if ((Info != GOOD) || plci->internal_command)
13649 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013650
Joe Perches475be4d2012-02-19 19:52:38 -080013651 }
13652 plci->adjust_b_state = ADJUST_B_REMOVE_L23_1;
13653 case ADJUST_B_REMOVE_L23_1:
13654 if ((plci->adjust_b_mode & ADJUST_B_MODE_REMOVE_L23)
13655 && plci->NL.Id && !plci->nl_remove_id)
13656 {
13657 plci->internal_command = plci->adjust_b_command;
13658 if (plci->adjust_b_ncci != 0)
13659 {
13660 ncci_ptr = &(plci->adapter->ncci[plci->adjust_b_ncci]);
13661 while (ncci_ptr->data_pending)
13662 {
13663 plci->data_sent_ptr = ncci_ptr->DBuffer[ncci_ptr->data_out].P;
13664 data_rc(plci, plci->adapter->ncci_ch[plci->adjust_b_ncci]);
13665 }
13666 while (ncci_ptr->data_ack_pending)
13667 data_ack(plci, plci->adapter->ncci_ch[plci->adjust_b_ncci]);
13668 }
13669 nl_req_ncci(plci, REMOVE,
13670 (byte)((plci->adjust_b_mode & ADJUST_B_MODE_CONNECT) ? plci->adjust_b_ncci : 0));
13671 send_req(plci);
13672 plci->adjust_b_state = ADJUST_B_REMOVE_L23_2;
13673 break;
13674 }
13675 plci->adjust_b_state = ADJUST_B_REMOVE_L23_2;
13676 Rc = OK;
13677 case ADJUST_B_REMOVE_L23_2:
13678 if ((Rc != OK) && (Rc != OK_FC))
13679 {
13680 dbug(1, dprintf("[%06lx] %s,%d: Adjust B remove failed %02x",
13681 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
13682 Info = _WRONG_STATE;
13683 break;
13684 }
13685 if (plci->adjust_b_mode & ADJUST_B_MODE_REMOVE_L23)
13686 {
13687 if (plci_nl_busy(plci))
13688 {
13689 plci->internal_command = plci->adjust_b_command;
13690 break;
13691 }
13692 }
13693 plci->adjust_b_state = ADJUST_B_SAVE_EC_1;
13694 Rc = OK;
13695 case ADJUST_B_SAVE_EC_1:
13696 if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
13697 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070013698
Joe Perches475be4d2012-02-19 19:52:38 -080013699 Info = ec_save_config(Id, plci, Rc);
13700 if ((Info != GOOD) || plci->internal_command)
13701 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013702
Joe Perches475be4d2012-02-19 19:52:38 -080013703 }
13704 plci->adjust_b_state = ADJUST_B_SAVE_DTMF_PARAMETER_1;
13705 Rc = OK;
13706 case ADJUST_B_SAVE_DTMF_PARAMETER_1:
13707 if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
13708 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070013709
Joe Perches475be4d2012-02-19 19:52:38 -080013710 Info = dtmf_parameter_save_config(Id, plci, Rc);
13711 if ((Info != GOOD) || plci->internal_command)
13712 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013713
Joe Perches475be4d2012-02-19 19:52:38 -080013714 }
13715 plci->adjust_b_state = ADJUST_B_SAVE_VOICE_1;
13716 Rc = OK;
13717 case ADJUST_B_SAVE_VOICE_1:
13718 if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
13719 {
13720 Info = adv_voice_save_config(Id, plci, Rc);
13721 if ((Info != GOOD) || plci->internal_command)
13722 break;
13723 }
13724 plci->adjust_b_state = ADJUST_B_SWITCH_L1_1;
13725 case ADJUST_B_SWITCH_L1_1:
13726 if (plci->adjust_b_mode & ADJUST_B_MODE_SWITCH_L1)
13727 {
13728 if (plci->sig_req)
13729 {
13730 plci->internal_command = plci->adjust_b_command;
13731 break;
13732 }
13733 if (plci->adjust_b_parms_msg != NULL)
13734 api_load_msg(plci->adjust_b_parms_msg, bp);
13735 else
13736 api_load_msg(&plci->B_protocol, bp);
13737 Info = add_b1(plci, bp,
13738 (word)((plci->adjust_b_mode & ADJUST_B_MODE_NO_RESOURCE) ? 2 : 0),
13739 plci->adjust_b_facilities);
13740 if (Info != GOOD)
13741 {
13742 dbug(1, dprintf("[%06lx] %s,%d: Adjust B invalid L1 parameters %d %04x",
13743 UnMapId(Id), (char *)(FILE_), __LINE__,
13744 plci->B1_resource, plci->adjust_b_facilities));
13745 break;
13746 }
13747 plci->internal_command = plci->adjust_b_command;
13748 sig_req(plci, RESOURCES, 0);
13749 send_req(plci);
13750 plci->adjust_b_state = ADJUST_B_SWITCH_L1_2;
13751 break;
13752 }
13753 plci->adjust_b_state = ADJUST_B_SWITCH_L1_2;
13754 Rc = OK;
13755 case ADJUST_B_SWITCH_L1_2:
13756 if ((Rc != OK) && (Rc != OK_FC))
13757 {
13758 dbug(1, dprintf("[%06lx] %s,%d: Adjust B switch failed %02x %d %04x",
13759 UnMapId(Id), (char *)(FILE_), __LINE__,
13760 Rc, plci->B1_resource, plci->adjust_b_facilities));
13761 Info = _WRONG_STATE;
13762 break;
13763 }
13764 plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_1;
13765 Rc = OK;
13766 case ADJUST_B_RESTORE_VOICE_1:
13767 case ADJUST_B_RESTORE_VOICE_2:
13768 if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
13769 {
13770 Info = adv_voice_restore_config(Id, plci, Rc);
13771 if ((Info != GOOD) || plci->internal_command)
13772 break;
13773 }
13774 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_1;
13775 Rc = OK;
13776 case ADJUST_B_RESTORE_DTMF_PARAMETER_1:
13777 case ADJUST_B_RESTORE_DTMF_PARAMETER_2:
13778 if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
13779 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070013780
Joe Perches475be4d2012-02-19 19:52:38 -080013781 Info = dtmf_parameter_restore_config(Id, plci, Rc);
13782 if ((Info != GOOD) || plci->internal_command)
13783 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013784
Joe Perches475be4d2012-02-19 19:52:38 -080013785 }
13786 plci->adjust_b_state = ADJUST_B_RESTORE_EC_1;
13787 Rc = OK;
13788 case ADJUST_B_RESTORE_EC_1:
13789 case ADJUST_B_RESTORE_EC_2:
13790 if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
13791 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070013792
Joe Perches475be4d2012-02-19 19:52:38 -080013793 Info = ec_restore_config(Id, plci, Rc);
13794 if ((Info != GOOD) || plci->internal_command)
13795 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013796
Joe Perches475be4d2012-02-19 19:52:38 -080013797 }
13798 plci->adjust_b_state = ADJUST_B_ASSIGN_L23_1;
13799 case ADJUST_B_ASSIGN_L23_1:
13800 if (plci->adjust_b_mode & ADJUST_B_MODE_ASSIGN_L23)
13801 {
13802 if (plci_nl_busy(plci))
13803 {
13804 plci->internal_command = plci->adjust_b_command;
13805 break;
13806 }
13807 if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT)
13808 plci->call_dir |= CALL_DIR_FORCE_OUTG_NL;
13809 if (plci->adjust_b_parms_msg != NULL)
13810 api_load_msg(plci->adjust_b_parms_msg, bp);
13811 else
13812 api_load_msg(&plci->B_protocol, bp);
13813 Info = add_b23(plci, bp);
13814 if (Info != GOOD)
13815 {
13816 dbug(1, dprintf("[%06lx] %s,%d: Adjust B invalid L23 parameters %04x",
13817 UnMapId(Id), (char *)(FILE_), __LINE__, Info));
13818 break;
13819 }
13820 plci->internal_command = plci->adjust_b_command;
13821 nl_req_ncci(plci, ASSIGN, 0);
13822 send_req(plci);
13823 plci->adjust_b_state = ADJUST_B_ASSIGN_L23_2;
13824 break;
13825 }
13826 plci->adjust_b_state = ADJUST_B_ASSIGN_L23_2;
13827 Rc = ASSIGN_OK;
13828 case ADJUST_B_ASSIGN_L23_2:
13829 if ((Rc != OK) && (Rc != OK_FC) && (Rc != ASSIGN_OK))
13830 {
13831 dbug(1, dprintf("[%06lx] %s,%d: Adjust B assign failed %02x",
13832 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
13833 Info = _WRONG_STATE;
13834 break;
13835 }
13836 if (plci->adjust_b_mode & ADJUST_B_MODE_ASSIGN_L23)
13837 {
13838 if (Rc != ASSIGN_OK)
13839 {
13840 plci->internal_command = plci->adjust_b_command;
13841 break;
13842 }
13843 }
13844 if (plci->adjust_b_mode & ADJUST_B_MODE_USER_CONNECT)
13845 {
13846 plci->adjust_b_restore = true;
13847 break;
13848 }
13849 plci->adjust_b_state = ADJUST_B_CONNECT_1;
13850 case ADJUST_B_CONNECT_1:
13851 if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT)
13852 {
13853 plci->internal_command = plci->adjust_b_command;
13854 if (plci_nl_busy(plci))
13855 break;
13856 nl_req_ncci(plci, N_CONNECT, 0);
13857 send_req(plci);
13858 plci->adjust_b_state = ADJUST_B_CONNECT_2;
13859 break;
13860 }
13861 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
13862 Rc = OK;
13863 case ADJUST_B_CONNECT_2:
13864 case ADJUST_B_CONNECT_3:
13865 case ADJUST_B_CONNECT_4:
13866 if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0))
13867 {
13868 dbug(1, dprintf("[%06lx] %s,%d: Adjust B connect failed %02x",
13869 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
13870 Info = _WRONG_STATE;
13871 break;
13872 }
13873 if (Rc == OK)
13874 {
13875 if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT)
13876 {
13877 get_ncci(plci, (byte)(Id >> 16), plci->adjust_b_ncci);
13878 Id = (Id & 0xffff) | (((dword)(plci->adjust_b_ncci)) << 16);
13879 }
13880 if (plci->adjust_b_state == ADJUST_B_CONNECT_2)
13881 plci->adjust_b_state = ADJUST_B_CONNECT_3;
13882 else if (plci->adjust_b_state == ADJUST_B_CONNECT_4)
13883 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
13884 }
13885 else if (Rc == 0)
13886 {
13887 if (plci->adjust_b_state == ADJUST_B_CONNECT_2)
13888 plci->adjust_b_state = ADJUST_B_CONNECT_4;
13889 else if (plci->adjust_b_state == ADJUST_B_CONNECT_3)
13890 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
13891 }
13892 if (plci->adjust_b_state != ADJUST_B_RESTORE_DTMF_1)
13893 {
13894 plci->internal_command = plci->adjust_b_command;
13895 break;
13896 }
13897 Rc = OK;
13898 case ADJUST_B_RESTORE_DTMF_1:
13899 case ADJUST_B_RESTORE_DTMF_2:
13900 if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
13901 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070013902
Joe Perches475be4d2012-02-19 19:52:38 -080013903 Info = dtmf_restore_config(Id, plci, Rc);
13904 if ((Info != GOOD) || plci->internal_command)
13905 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013906
Joe Perches475be4d2012-02-19 19:52:38 -080013907 }
13908 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_1;
13909 Rc = OK;
13910 case ADJUST_B_RESTORE_MIXER_1:
13911 case ADJUST_B_RESTORE_MIXER_2:
13912 case ADJUST_B_RESTORE_MIXER_3:
13913 case ADJUST_B_RESTORE_MIXER_4:
13914 case ADJUST_B_RESTORE_MIXER_5:
13915 case ADJUST_B_RESTORE_MIXER_6:
13916 case ADJUST_B_RESTORE_MIXER_7:
13917 if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
13918 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070013919
Joe Perches475be4d2012-02-19 19:52:38 -080013920 Info = mixer_restore_config(Id, plci, Rc);
13921 if ((Info != GOOD) || plci->internal_command)
13922 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013923
Joe Perches475be4d2012-02-19 19:52:38 -080013924 }
13925 plci->adjust_b_state = ADJUST_B_END;
13926 case ADJUST_B_END:
13927 break;
13928 }
13929 return (Info);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013930}
13931
13932
Joe Perches475be4d2012-02-19 19:52:38 -080013933static void adjust_b1_resource(dword Id, PLCI *plci, API_SAVE *bp_msg, word b1_facilities, word internal_command)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013934{
13935
Joe Perches475be4d2012-02-19 19:52:38 -080013936 dbug(1, dprintf("[%06lx] %s,%d: adjust_b1_resource %d %04x",
13937 UnMapId(Id), (char *)(FILE_), __LINE__,
13938 plci->B1_resource, b1_facilities));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013939
Joe Perches475be4d2012-02-19 19:52:38 -080013940 plci->adjust_b_parms_msg = bp_msg;
13941 plci->adjust_b_facilities = b1_facilities;
13942 plci->adjust_b_command = internal_command;
13943 plci->adjust_b_ncci = (word)(Id >> 16);
13944 if ((bp_msg == NULL) && (plci->B1_resource == 0))
13945 plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_NO_RESOURCE | ADJUST_B_MODE_SWITCH_L1;
13946 else
13947 plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_SWITCH_L1 | ADJUST_B_MODE_RESTORE;
13948 plci->adjust_b_state = ADJUST_B_START;
13949 dbug(1, dprintf("[%06lx] %s,%d: Adjust B1 resource %d %04x...",
13950 UnMapId(Id), (char *)(FILE_), __LINE__,
13951 plci->B1_resource, b1_facilities));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013952}
13953
13954
Joe Perches475be4d2012-02-19 19:52:38 -080013955static void adjust_b_restore(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013956{
Joe Perches475be4d2012-02-19 19:52:38 -080013957 word internal_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013958
Joe Perches475be4d2012-02-19 19:52:38 -080013959 dbug(1, dprintf("[%06lx] %s,%d: adjust_b_restore %02x %04x",
13960 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013961
Joe Perches475be4d2012-02-19 19:52:38 -080013962 internal_command = plci->internal_command;
13963 plci->internal_command = 0;
13964 switch (internal_command)
13965 {
13966 default:
13967 plci->command = 0;
13968 if (plci->req_in != 0)
13969 {
13970 plci->internal_command = ADJUST_B_RESTORE_1;
13971 break;
13972 }
13973 Rc = OK;
13974 case ADJUST_B_RESTORE_1:
13975 if ((Rc != OK) && (Rc != OK_FC))
13976 {
13977 dbug(1, dprintf("[%06lx] %s,%d: Adjust B enqueued failed %02x",
13978 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
13979 }
13980 plci->adjust_b_parms_msg = NULL;
13981 plci->adjust_b_facilities = plci->B1_facilities;
13982 plci->adjust_b_command = ADJUST_B_RESTORE_2;
13983 plci->adjust_b_ncci = (word)(Id >> 16);
13984 plci->adjust_b_mode = ADJUST_B_MODE_RESTORE;
13985 plci->adjust_b_state = ADJUST_B_START;
13986 dbug(1, dprintf("[%06lx] %s,%d: Adjust B restore...",
13987 UnMapId(Id), (char *)(FILE_), __LINE__));
13988 case ADJUST_B_RESTORE_2:
13989 if (adjust_b_process(Id, plci, Rc) != GOOD)
13990 {
13991 dbug(1, dprintf("[%06lx] %s,%d: Adjust B restore failed",
13992 UnMapId(Id), (char *)(FILE_), __LINE__));
13993 }
13994 if (plci->internal_command)
13995 break;
13996 break;
13997 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013998}
13999
14000
Joe Perches475be4d2012-02-19 19:52:38 -080014001static void reset_b3_command(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014002{
Joe Perches475be4d2012-02-19 19:52:38 -080014003 word Info;
14004 word internal_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014005
Joe Perches475be4d2012-02-19 19:52:38 -080014006 dbug(1, dprintf("[%06lx] %s,%d: reset_b3_command %02x %04x",
14007 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014008
Joe Perches475be4d2012-02-19 19:52:38 -080014009 Info = GOOD;
14010 internal_command = plci->internal_command;
14011 plci->internal_command = 0;
14012 switch (internal_command)
14013 {
14014 default:
14015 plci->command = 0;
14016 plci->adjust_b_parms_msg = NULL;
14017 plci->adjust_b_facilities = plci->B1_facilities;
14018 plci->adjust_b_command = RESET_B3_COMMAND_1;
14019 plci->adjust_b_ncci = (word)(Id >> 16);
14020 plci->adjust_b_mode = ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_CONNECT;
14021 plci->adjust_b_state = ADJUST_B_START;
14022 dbug(1, dprintf("[%06lx] %s,%d: Reset B3...",
14023 UnMapId(Id), (char *)(FILE_), __LINE__));
14024 case RESET_B3_COMMAND_1:
14025 Info = adjust_b_process(Id, plci, Rc);
14026 if (Info != GOOD)
14027 {
14028 dbug(1, dprintf("[%06lx] %s,%d: Reset failed",
14029 UnMapId(Id), (char *)(FILE_), __LINE__));
14030 break;
14031 }
14032 if (plci->internal_command)
14033 return;
14034 break;
14035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014036/* sendf (plci->appl, _RESET_B3_R | CONFIRM, Id, plci->number, "w", Info);*/
Joe Perches475be4d2012-02-19 19:52:38 -080014037 sendf(plci->appl, _RESET_B3_I, Id, 0, "s", "");
Linus Torvalds1da177e2005-04-16 15:20:36 -070014038}
14039
14040
Joe Perches475be4d2012-02-19 19:52:38 -080014041static void select_b_command(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014042{
Joe Perches475be4d2012-02-19 19:52:38 -080014043 word Info;
14044 word internal_command;
14045 byte esc_chi[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014046
Joe Perches475be4d2012-02-19 19:52:38 -080014047 dbug(1, dprintf("[%06lx] %s,%d: select_b_command %02x %04x",
14048 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014049
Joe Perches475be4d2012-02-19 19:52:38 -080014050 Info = GOOD;
14051 internal_command = plci->internal_command;
14052 plci->internal_command = 0;
14053 switch (internal_command)
14054 {
14055 default:
14056 plci->command = 0;
14057 plci->adjust_b_parms_msg = &plci->saved_msg;
14058 if ((plci->tel == ADV_VOICE) && (plci == plci->adapter->AdvSignalPLCI))
14059 plci->adjust_b_facilities = plci->B1_facilities | B1_FACILITY_VOICE;
14060 else
14061 plci->adjust_b_facilities = plci->B1_facilities & ~B1_FACILITY_VOICE;
14062 plci->adjust_b_command = SELECT_B_COMMAND_1;
14063 plci->adjust_b_ncci = (word)(Id >> 16);
14064 if (plci->saved_msg.parms[0].length == 0)
14065 {
14066 plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_SWITCH_L1 |
14067 ADJUST_B_MODE_NO_RESOURCE;
14068 }
14069 else
14070 {
14071 plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_SWITCH_L1 |
14072 ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_USER_CONNECT | ADJUST_B_MODE_RESTORE;
14073 }
14074 plci->adjust_b_state = ADJUST_B_START;
14075 dbug(1, dprintf("[%06lx] %s,%d: Select B protocol...",
14076 UnMapId(Id), (char *)(FILE_), __LINE__));
14077 case SELECT_B_COMMAND_1:
14078 Info = adjust_b_process(Id, plci, Rc);
14079 if (Info != GOOD)
14080 {
14081 dbug(1, dprintf("[%06lx] %s,%d: Select B protocol failed",
14082 UnMapId(Id), (char *)(FILE_), __LINE__));
14083 break;
14084 }
14085 if (plci->internal_command)
14086 return;
14087 if (plci->tel == ADV_VOICE)
14088 {
14089 esc_chi[0] = 0x02;
14090 esc_chi[1] = 0x18;
14091 esc_chi[2] = plci->b_channel;
14092 SetVoiceChannel(plci->adapter->AdvCodecPLCI, esc_chi, plci->adapter);
14093 }
14094 break;
14095 }
14096 sendf(plci->appl, _SELECT_B_REQ | CONFIRM, Id, plci->number, "w", Info);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014097}
14098
14099
Joe Perches475be4d2012-02-19 19:52:38 -080014100static void fax_connect_ack_command(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014101{
Joe Perches475be4d2012-02-19 19:52:38 -080014102 word internal_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014103
Joe Perches475be4d2012-02-19 19:52:38 -080014104 dbug(1, dprintf("[%06lx] %s,%d: fax_connect_ack_command %02x %04x",
14105 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014106
Joe Perches475be4d2012-02-19 19:52:38 -080014107 internal_command = plci->internal_command;
14108 plci->internal_command = 0;
14109 switch (internal_command)
14110 {
14111 default:
14112 plci->command = 0;
14113 case FAX_CONNECT_ACK_COMMAND_1:
14114 if (plci_nl_busy(plci))
14115 {
14116 plci->internal_command = FAX_CONNECT_ACK_COMMAND_1;
14117 return;
14118 }
14119 plci->internal_command = FAX_CONNECT_ACK_COMMAND_2;
14120 plci->NData[0].P = plci->fax_connect_info_buffer;
14121 plci->NData[0].PLength = plci->fax_connect_info_length;
14122 plci->NL.X = plci->NData;
14123 plci->NL.ReqCh = 0;
14124 plci->NL.Req = plci->nl_req = (byte) N_CONNECT_ACK;
14125 plci->adapter->request(&plci->NL);
14126 return;
14127 case FAX_CONNECT_ACK_COMMAND_2:
14128 if ((Rc != OK) && (Rc != OK_FC))
14129 {
14130 dbug(1, dprintf("[%06lx] %s,%d: FAX issue CONNECT ACK failed %02x",
14131 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
14132 break;
14133 }
14134 }
14135 if ((plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
14136 && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
14137 {
14138 if (plci->B3_prot == 4)
14139 sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", "");
14140 else
14141 sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "S", plci->ncpi_buffer);
14142 plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
14143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014144}
14145
14146
Joe Perches475be4d2012-02-19 19:52:38 -080014147static void fax_edata_ack_command(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014148{
Joe Perches475be4d2012-02-19 19:52:38 -080014149 word internal_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014150
Joe Perches475be4d2012-02-19 19:52:38 -080014151 dbug(1, dprintf("[%06lx] %s,%d: fax_edata_ack_command %02x %04x",
14152 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014153
Joe Perches475be4d2012-02-19 19:52:38 -080014154 internal_command = plci->internal_command;
14155 plci->internal_command = 0;
14156 switch (internal_command)
14157 {
14158 default:
14159 plci->command = 0;
14160 case FAX_EDATA_ACK_COMMAND_1:
14161 if (plci_nl_busy(plci))
14162 {
14163 plci->internal_command = FAX_EDATA_ACK_COMMAND_1;
14164 return;
14165 }
14166 plci->internal_command = FAX_EDATA_ACK_COMMAND_2;
14167 plci->NData[0].P = plci->fax_connect_info_buffer;
14168 plci->NData[0].PLength = plci->fax_edata_ack_length;
14169 plci->NL.X = plci->NData;
14170 plci->NL.ReqCh = 0;
14171 plci->NL.Req = plci->nl_req = (byte) N_EDATA;
14172 plci->adapter->request(&plci->NL);
14173 return;
14174 case FAX_EDATA_ACK_COMMAND_2:
14175 if ((Rc != OK) && (Rc != OK_FC))
14176 {
14177 dbug(1, dprintf("[%06lx] %s,%d: FAX issue EDATA ACK failed %02x",
14178 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
14179 break;
14180 }
14181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014182}
14183
14184
Joe Perches475be4d2012-02-19 19:52:38 -080014185static void fax_connect_info_command(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014186{
Joe Perches475be4d2012-02-19 19:52:38 -080014187 word Info;
14188 word internal_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014189
Joe Perches475be4d2012-02-19 19:52:38 -080014190 dbug(1, dprintf("[%06lx] %s,%d: fax_connect_info_command %02x %04x",
14191 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014192
Joe Perches475be4d2012-02-19 19:52:38 -080014193 Info = GOOD;
14194 internal_command = plci->internal_command;
14195 plci->internal_command = 0;
14196 switch (internal_command)
14197 {
14198 default:
14199 plci->command = 0;
14200 case FAX_CONNECT_INFO_COMMAND_1:
14201 if (plci_nl_busy(plci))
14202 {
14203 plci->internal_command = FAX_CONNECT_INFO_COMMAND_1;
14204 return;
14205 }
14206 plci->internal_command = FAX_CONNECT_INFO_COMMAND_2;
14207 plci->NData[0].P = plci->fax_connect_info_buffer;
14208 plci->NData[0].PLength = plci->fax_connect_info_length;
14209 plci->NL.X = plci->NData;
14210 plci->NL.ReqCh = 0;
14211 plci->NL.Req = plci->nl_req = (byte) N_EDATA;
14212 plci->adapter->request(&plci->NL);
14213 return;
14214 case FAX_CONNECT_INFO_COMMAND_2:
14215 if ((Rc != OK) && (Rc != OK_FC))
14216 {
14217 dbug(1, dprintf("[%06lx] %s,%d: FAX setting connect info failed %02x",
14218 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
14219 Info = _WRONG_STATE;
14220 break;
14221 }
14222 if (plci_nl_busy(plci))
14223 {
14224 plci->internal_command = FAX_CONNECT_INFO_COMMAND_2;
14225 return;
14226 }
14227 plci->command = _CONNECT_B3_R;
14228 nl_req_ncci(plci, N_CONNECT, 0);
14229 send_req(plci);
14230 return;
14231 }
14232 sendf(plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014233}
14234
14235
Joe Perches475be4d2012-02-19 19:52:38 -080014236static void fax_adjust_b23_command(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014237{
Joe Perches475be4d2012-02-19 19:52:38 -080014238 word Info;
14239 word internal_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014240
Joe Perches475be4d2012-02-19 19:52:38 -080014241 dbug(1, dprintf("[%06lx] %s,%d: fax_adjust_b23_command %02x %04x",
14242 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014243
Joe Perches475be4d2012-02-19 19:52:38 -080014244 Info = GOOD;
14245 internal_command = plci->internal_command;
14246 plci->internal_command = 0;
14247 switch (internal_command)
14248 {
14249 default:
14250 plci->command = 0;
14251 plci->adjust_b_parms_msg = NULL;
14252 plci->adjust_b_facilities = plci->B1_facilities;
14253 plci->adjust_b_command = FAX_ADJUST_B23_COMMAND_1;
14254 plci->adjust_b_ncci = (word)(Id >> 16);
14255 plci->adjust_b_mode = ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_ASSIGN_L23;
14256 plci->adjust_b_state = ADJUST_B_START;
14257 dbug(1, dprintf("[%06lx] %s,%d: FAX adjust B23...",
14258 UnMapId(Id), (char *)(FILE_), __LINE__));
14259 case FAX_ADJUST_B23_COMMAND_1:
14260 Info = adjust_b_process(Id, plci, Rc);
14261 if (Info != GOOD)
14262 {
14263 dbug(1, dprintf("[%06lx] %s,%d: FAX adjust failed",
14264 UnMapId(Id), (char *)(FILE_), __LINE__));
14265 break;
14266 }
14267 if (plci->internal_command)
14268 return;
14269 case FAX_ADJUST_B23_COMMAND_2:
14270 if (plci_nl_busy(plci))
14271 {
14272 plci->internal_command = FAX_ADJUST_B23_COMMAND_2;
14273 return;
14274 }
14275 plci->command = _CONNECT_B3_R;
14276 nl_req_ncci(plci, N_CONNECT, 0);
14277 send_req(plci);
14278 return;
14279 }
14280 sendf(plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014281}
14282
14283
Joe Perches475be4d2012-02-19 19:52:38 -080014284static void fax_disconnect_command(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014285{
Joe Perches475be4d2012-02-19 19:52:38 -080014286 word internal_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014287
Joe Perches475be4d2012-02-19 19:52:38 -080014288 dbug(1, dprintf("[%06lx] %s,%d: fax_disconnect_command %02x %04x",
14289 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014290
Joe Perches475be4d2012-02-19 19:52:38 -080014291 internal_command = plci->internal_command;
14292 plci->internal_command = 0;
14293 switch (internal_command)
14294 {
14295 default:
14296 plci->command = 0;
14297 plci->internal_command = FAX_DISCONNECT_COMMAND_1;
14298 return;
14299 case FAX_DISCONNECT_COMMAND_1:
14300 case FAX_DISCONNECT_COMMAND_2:
14301 case FAX_DISCONNECT_COMMAND_3:
14302 if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0))
14303 {
14304 dbug(1, dprintf("[%06lx] %s,%d: FAX disconnect EDATA failed %02x",
14305 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
14306 break;
14307 }
14308 if (Rc == OK)
14309 {
14310 if ((internal_command == FAX_DISCONNECT_COMMAND_1)
14311 || (internal_command == FAX_DISCONNECT_COMMAND_2))
14312 {
14313 plci->internal_command = FAX_DISCONNECT_COMMAND_2;
14314 }
14315 }
14316 else if (Rc == 0)
14317 {
14318 if (internal_command == FAX_DISCONNECT_COMMAND_1)
14319 plci->internal_command = FAX_DISCONNECT_COMMAND_3;
14320 }
14321 return;
14322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014323}
14324
14325
14326
Joe Perches475be4d2012-02-19 19:52:38 -080014327static void rtp_connect_b3_req_command(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014328{
Joe Perches475be4d2012-02-19 19:52:38 -080014329 word Info;
14330 word internal_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014331
Joe Perches475be4d2012-02-19 19:52:38 -080014332 dbug(1, dprintf("[%06lx] %s,%d: rtp_connect_b3_req_command %02x %04x",
14333 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014334
Joe Perches475be4d2012-02-19 19:52:38 -080014335 Info = GOOD;
14336 internal_command = plci->internal_command;
14337 plci->internal_command = 0;
14338 switch (internal_command)
14339 {
14340 default:
14341 plci->command = 0;
14342 case RTP_CONNECT_B3_REQ_COMMAND_1:
14343 if (plci_nl_busy(plci))
14344 {
14345 plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_1;
14346 return;
14347 }
14348 plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_2;
14349 nl_req_ncci(plci, N_CONNECT, 0);
14350 send_req(plci);
14351 return;
14352 case RTP_CONNECT_B3_REQ_COMMAND_2:
14353 if ((Rc != OK) && (Rc != OK_FC))
14354 {
14355 dbug(1, dprintf("[%06lx] %s,%d: RTP setting connect info failed %02x",
14356 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
14357 Info = _WRONG_STATE;
14358 break;
14359 }
14360 if (plci_nl_busy(plci))
14361 {
14362 plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_2;
14363 return;
14364 }
14365 plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_3;
14366 plci->NData[0].PLength = plci->internal_req_buffer[0];
14367 plci->NData[0].P = plci->internal_req_buffer + 1;
14368 plci->NL.X = plci->NData;
14369 plci->NL.ReqCh = 0;
14370 plci->NL.Req = plci->nl_req = (byte) N_UDATA;
14371 plci->adapter->request(&plci->NL);
14372 break;
14373 case RTP_CONNECT_B3_REQ_COMMAND_3:
14374 return;
14375 }
14376 sendf(plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014377}
14378
14379
Joe Perches475be4d2012-02-19 19:52:38 -080014380static void rtp_connect_b3_res_command(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014381{
Joe Perches475be4d2012-02-19 19:52:38 -080014382 word internal_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014383
Joe Perches475be4d2012-02-19 19:52:38 -080014384 dbug(1, dprintf("[%06lx] %s,%d: rtp_connect_b3_res_command %02x %04x",
14385 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014386
Joe Perches475be4d2012-02-19 19:52:38 -080014387 internal_command = plci->internal_command;
14388 plci->internal_command = 0;
14389 switch (internal_command)
14390 {
14391 default:
14392 plci->command = 0;
14393 case RTP_CONNECT_B3_RES_COMMAND_1:
14394 if (plci_nl_busy(plci))
14395 {
14396 plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_1;
14397 return;
14398 }
14399 plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_2;
14400 nl_req_ncci(plci, N_CONNECT_ACK, (byte)(Id >> 16));
14401 send_req(plci);
14402 return;
14403 case RTP_CONNECT_B3_RES_COMMAND_2:
14404 if ((Rc != OK) && (Rc != OK_FC))
14405 {
14406 dbug(1, dprintf("[%06lx] %s,%d: RTP setting connect resp info failed %02x",
14407 UnMapId(Id), (char *)(FILE_), __LINE__, Rc));
14408 break;
14409 }
14410 if (plci_nl_busy(plci))
14411 {
14412 plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_2;
14413 return;
14414 }
14415 sendf(plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", "");
14416 plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_3;
14417 plci->NData[0].PLength = plci->internal_req_buffer[0];
14418 plci->NData[0].P = plci->internal_req_buffer + 1;
14419 plci->NL.X = plci->NData;
14420 plci->NL.ReqCh = 0;
14421 plci->NL.Req = plci->nl_req = (byte) N_UDATA;
14422 plci->adapter->request(&plci->NL);
14423 return;
14424 case RTP_CONNECT_B3_RES_COMMAND_3:
14425 return;
14426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014427}
14428
14429
14430
Joe Perches475be4d2012-02-19 19:52:38 -080014431static void hold_save_command(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014432{
Joe Perches475be4d2012-02-19 19:52:38 -080014433 byte SS_Ind[] = "\x05\x02\x00\x02\x00\x00"; /* Hold_Ind struct*/
14434 word Info;
14435 word internal_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014436
Joe Perches475be4d2012-02-19 19:52:38 -080014437 dbug(1, dprintf("[%06lx] %s,%d: hold_save_command %02x %04x",
14438 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014439
Joe Perches475be4d2012-02-19 19:52:38 -080014440 Info = GOOD;
14441 internal_command = plci->internal_command;
14442 plci->internal_command = 0;
14443 switch (internal_command)
14444 {
14445 default:
14446 if (!plci->NL.Id)
14447 break;
14448 plci->command = 0;
14449 plci->adjust_b_parms_msg = NULL;
14450 plci->adjust_b_facilities = plci->B1_facilities;
14451 plci->adjust_b_command = HOLD_SAVE_COMMAND_1;
14452 plci->adjust_b_ncci = (word)(Id >> 16);
14453 plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23;
14454 plci->adjust_b_state = ADJUST_B_START;
14455 dbug(1, dprintf("[%06lx] %s,%d: HOLD save...",
14456 UnMapId(Id), (char *)(FILE_), __LINE__));
14457 case HOLD_SAVE_COMMAND_1:
14458 Info = adjust_b_process(Id, plci, Rc);
14459 if (Info != GOOD)
14460 {
14461 dbug(1, dprintf("[%06lx] %s,%d: HOLD save failed",
14462 UnMapId(Id), (char *)(FILE_), __LINE__));
14463 break;
14464 }
14465 if (plci->internal_command)
14466 return;
14467 }
14468 sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", 3, SS_Ind);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014469}
14470
14471
Joe Perches475be4d2012-02-19 19:52:38 -080014472static void retrieve_restore_command(dword Id, PLCI *plci, byte Rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014473{
Joe Perches475be4d2012-02-19 19:52:38 -080014474 byte SS_Ind[] = "\x05\x03\x00\x02\x00\x00"; /* Retrieve_Ind struct*/
14475 word Info;
14476 word internal_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014477
Joe Perches475be4d2012-02-19 19:52:38 -080014478 dbug(1, dprintf("[%06lx] %s,%d: retrieve_restore_command %02x %04x",
14479 UnMapId(Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014480
Joe Perches475be4d2012-02-19 19:52:38 -080014481 Info = GOOD;
14482 internal_command = plci->internal_command;
14483 plci->internal_command = 0;
14484 switch (internal_command)
14485 {
14486 default:
14487 plci->command = 0;
14488 plci->adjust_b_parms_msg = NULL;
14489 plci->adjust_b_facilities = plci->B1_facilities;
14490 plci->adjust_b_command = RETRIEVE_RESTORE_COMMAND_1;
14491 plci->adjust_b_ncci = (word)(Id >> 16);
14492 plci->adjust_b_mode = ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_USER_CONNECT | ADJUST_B_MODE_RESTORE;
14493 plci->adjust_b_state = ADJUST_B_START;
14494 dbug(1, dprintf("[%06lx] %s,%d: RETRIEVE restore...",
14495 UnMapId(Id), (char *)(FILE_), __LINE__));
14496 case RETRIEVE_RESTORE_COMMAND_1:
14497 Info = adjust_b_process(Id, plci, Rc);
14498 if (Info != GOOD)
14499 {
14500 dbug(1, dprintf("[%06lx] %s,%d: RETRIEVE restore failed",
14501 UnMapId(Id), (char *)(FILE_), __LINE__));
14502 break;
14503 }
14504 if (plci->internal_command)
14505 return;
14506 }
14507 sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", 3, SS_Ind);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014508}
14509
14510
Joe Perches475be4d2012-02-19 19:52:38 -080014511static void init_b1_config(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014512{
14513
Joe Perches475be4d2012-02-19 19:52:38 -080014514 dbug(1, dprintf("[%06lx] %s,%d: init_b1_config",
14515 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
14516 (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014517
Joe Perches475be4d2012-02-19 19:52:38 -080014518 plci->B1_resource = 0;
14519 plci->B1_facilities = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014520
Joe Perches475be4d2012-02-19 19:52:38 -080014521 plci->li_bchannel_id = 0;
14522 mixer_clear_config(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014523
14524
Joe Perches475be4d2012-02-19 19:52:38 -080014525 ec_clear_config(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014526
14527
Joe Perches475be4d2012-02-19 19:52:38 -080014528 dtmf_rec_clear_config(plci);
14529 dtmf_send_clear_config(plci);
14530 dtmf_parameter_clear_config(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014531
Joe Perches475be4d2012-02-19 19:52:38 -080014532 adv_voice_clear_config(plci);
14533 adjust_b_clear(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014534}
14535
14536
Joe Perches475be4d2012-02-19 19:52:38 -080014537static void clear_b1_config(PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014538{
14539
Joe Perches475be4d2012-02-19 19:52:38 -080014540 dbug(1, dprintf("[%06lx] %s,%d: clear_b1_config",
14541 (dword)((plci->Id << 8) | UnMapController(plci->adapter->Id)),
14542 (char *)(FILE_), __LINE__));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014543
Joe Perches475be4d2012-02-19 19:52:38 -080014544 adv_voice_clear_config(plci);
14545 adjust_b_clear(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014546
Joe Perches475be4d2012-02-19 19:52:38 -080014547 ec_clear_config(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014548
14549
Joe Perches475be4d2012-02-19 19:52:38 -080014550 dtmf_rec_clear_config(plci);
14551 dtmf_send_clear_config(plci);
14552 dtmf_parameter_clear_config(plci);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014553
14554
Joe Perches475be4d2012-02-19 19:52:38 -080014555 if ((plci->li_bchannel_id != 0)
14556 && (li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci == plci))
14557 {
14558 mixer_clear_config(plci);
14559 li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci = NULL;
14560 plci->li_bchannel_id = 0;
14561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014562
Joe Perches475be4d2012-02-19 19:52:38 -080014563 plci->B1_resource = 0;
14564 plci->B1_facilities = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014565}
14566
14567
14568/* -----------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -080014569 XON protocol local helpers
Linus Torvalds1da177e2005-04-16 15:20:36 -070014570 ----------------------------------------------------------------- */
Joe Perches475be4d2012-02-19 19:52:38 -080014571static void channel_flow_control_remove(PLCI *plci) {
14572 DIVA_CAPI_ADAPTER *a = plci->adapter;
14573 word i;
14574 for (i = 1; i < MAX_NL_CHANNEL + 1; i++) {
14575 if (a->ch_flow_plci[i] == plci->Id) {
14576 a->ch_flow_plci[i] = 0;
14577 a->ch_flow_control[i] = 0;
14578 }
14579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014580}
14581
Joe Perches475be4d2012-02-19 19:52:38 -080014582static void channel_x_on(PLCI *plci, byte ch) {
14583 DIVA_CAPI_ADAPTER *a = plci->adapter;
14584 if (a->ch_flow_control[ch] & N_XON_SENT) {
14585 a->ch_flow_control[ch] &= ~N_XON_SENT;
14586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014587}
14588
Joe Perches475be4d2012-02-19 19:52:38 -080014589static void channel_x_off(PLCI *plci, byte ch, byte flag) {
14590 DIVA_CAPI_ADAPTER *a = plci->adapter;
14591 if ((a->ch_flow_control[ch] & N_RX_FLOW_CONTROL_MASK) == 0) {
14592 a->ch_flow_control[ch] |= (N_CH_XOFF | flag);
14593 a->ch_flow_plci[ch] = plci->Id;
14594 a->ch_flow_control_pending++;
14595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014596}
14597
Joe Perches475be4d2012-02-19 19:52:38 -080014598static void channel_request_xon(PLCI *plci, byte ch) {
14599 DIVA_CAPI_ADAPTER *a = plci->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014600
Joe Perches475be4d2012-02-19 19:52:38 -080014601 if (a->ch_flow_control[ch] & N_CH_XOFF) {
14602 a->ch_flow_control[ch] |= N_XON_REQ;
14603 a->ch_flow_control[ch] &= ~N_CH_XOFF;
14604 a->ch_flow_control[ch] &= ~N_XON_CONNECT_IND;
14605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014606}
14607
Joe Perches475be4d2012-02-19 19:52:38 -080014608static void channel_xmit_extended_xon(PLCI *plci) {
14609 DIVA_CAPI_ADAPTER *a;
14610 int max_ch = ARRAY_SIZE(a->ch_flow_control);
14611 int i, one_requested = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014612
Joe Perches475be4d2012-02-19 19:52:38 -080014613 if ((!plci) || (!plci->Id) || ((a = plci->adapter) == NULL)) {
14614 return;
14615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014616
Joe Perches475be4d2012-02-19 19:52:38 -080014617 for (i = 0; i < max_ch; i++) {
14618 if ((a->ch_flow_control[i] & N_CH_XOFF) &&
14619 (a->ch_flow_control[i] & N_XON_CONNECT_IND) &&
14620 (plci->Id == a->ch_flow_plci[i])) {
14621 channel_request_xon(plci, (byte)i);
14622 one_requested = 1;
14623 }
14624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014625
Joe Perches475be4d2012-02-19 19:52:38 -080014626 if (one_requested) {
14627 channel_xmit_xon(plci);
14628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014629}
14630
14631/*
14632 Try to xmit next X_ON
Joe Perches475be4d2012-02-19 19:52:38 -080014633*/
14634static int find_channel_with_pending_x_on(DIVA_CAPI_ADAPTER *a, PLCI *plci) {
14635 int max_ch = ARRAY_SIZE(a->ch_flow_control);
14636 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014637
Joe Perches475be4d2012-02-19 19:52:38 -080014638 if (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)) {
14639 return (0);
14640 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014641
Joe Perches475be4d2012-02-19 19:52:38 -080014642 if (a->last_flow_control_ch >= max_ch) {
14643 a->last_flow_control_ch = 1;
14644 }
14645 for (i = a->last_flow_control_ch; i < max_ch; i++) {
14646 if ((a->ch_flow_control[i] & N_XON_REQ) &&
14647 (plci->Id == a->ch_flow_plci[i])) {
14648 a->last_flow_control_ch = i + 1;
14649 return (i);
14650 }
14651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014652
Joe Perches475be4d2012-02-19 19:52:38 -080014653 for (i = 1; i < a->last_flow_control_ch; i++) {
14654 if ((a->ch_flow_control[i] & N_XON_REQ) &&
14655 (plci->Id == a->ch_flow_plci[i])) {
14656 a->last_flow_control_ch = i + 1;
14657 return (i);
14658 }
14659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014660
Joe Perches475be4d2012-02-19 19:52:38 -080014661 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014662}
14663
Joe Perches475be4d2012-02-19 19:52:38 -080014664static void channel_xmit_xon(PLCI *plci) {
14665 DIVA_CAPI_ADAPTER *a = plci->adapter;
14666 byte ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014667
Joe Perches475be4d2012-02-19 19:52:38 -080014668 if (plci->nl_req || !plci->NL.Id || plci->nl_remove_id) {
14669 return;
14670 }
14671 if ((ch = (byte)find_channel_with_pending_x_on(a, plci)) == 0) {
14672 return;
14673 }
14674 a->ch_flow_control[ch] &= ~N_XON_REQ;
14675 a->ch_flow_control[ch] |= N_XON_SENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014676
Joe Perches475be4d2012-02-19 19:52:38 -080014677 plci->NL.Req = plci->nl_req = (byte)N_XON;
14678 plci->NL.ReqCh = ch;
14679 plci->NL.X = plci->NData;
14680 plci->NL.XNum = 1;
14681 plci->NData[0].P = &plci->RBuffer[0];
14682 plci->NData[0].PLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014683
Joe Perches475be4d2012-02-19 19:52:38 -080014684 plci->adapter->request(&plci->NL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014685}
14686
Joe Perches475be4d2012-02-19 19:52:38 -080014687static int channel_can_xon(PLCI *plci, byte ch) {
14688 APPL *APPLptr;
14689 DIVA_CAPI_ADAPTER *a;
14690 word NCCIcode;
14691 dword count;
14692 word Num;
14693 word i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014694
Joe Perches475be4d2012-02-19 19:52:38 -080014695 APPLptr = plci->appl;
14696 a = plci->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014697
Joe Perches475be4d2012-02-19 19:52:38 -080014698 if (!APPLptr)
14699 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014700
Joe Perches475be4d2012-02-19 19:52:38 -080014701 NCCIcode = a->ch_ncci[ch] | (((word) a->Id) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014702
Joe Perches475be4d2012-02-19 19:52:38 -080014703 /* count all buffers within the Application pool */
14704 /* belonging to the same NCCI. XON if a first is */
14705 /* used. */
14706 count = 0;
14707 Num = 0xffff;
14708 for (i = 0; i < APPLptr->MaxBuffer; i++) {
14709 if (NCCIcode == APPLptr->DataNCCI[i]) count++;
14710 if (!APPLptr->DataNCCI[i] && Num == 0xffff) Num = i;
14711 }
14712 if ((count > 2) || (Num == 0xffff)) {
14713 return (0);
14714 }
14715 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014716}
14717
14718
14719/*------------------------------------------------------------------*/
14720
Joe Perches475be4d2012-02-19 19:52:38 -080014721static word CPN_filter_ok(byte *cpn, DIVA_CAPI_ADAPTER *a, word offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014722{
Joe Perches475be4d2012-02-19 19:52:38 -080014723 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014724}
14725
14726
14727
14728/**********************************************************************************/
14729/* function groups the listening applications according to the CIP mask and the */
14730/* Info_Mask. Each group gets just one Connect_Ind. Some application manufacturer */
14731/* are not multi-instance capable, so they start e.g. 30 applications what causes */
14732/* big problems on application level (one call, 30 Connect_Ind, ect). The */
14733/* function must be enabled by setting "a->group_optimization_enabled" from the */
14734/* OS specific part (per adapter). */
14735/**********************************************************************************/
Joe Perches475be4d2012-02-19 19:52:38 -080014736static void group_optimization(DIVA_CAPI_ADAPTER *a, PLCI *plci)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014737{
Joe Perches475be4d2012-02-19 19:52:38 -080014738 word i, j, k, busy, group_found;
14739 dword info_mask_group[MAX_CIP_TYPES];
14740 dword cip_mask_group[MAX_CIP_TYPES];
14741 word appl_number_group_type[MAX_APPL];
14742 PLCI *auxplci;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014743
Joe Perches475be4d2012-02-19 19:52:38 -080014744 set_group_ind_mask(plci); /* all APPLs within this inc. call are allowed to dial in */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014745
Joe Perches475be4d2012-02-19 19:52:38 -080014746 if (!a->group_optimization_enabled)
14747 {
14748 dbug(1, dprintf("No group optimization"));
14749 return;
14750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014751
Joe Perches475be4d2012-02-19 19:52:38 -080014752 dbug(1, dprintf("Group optimization = 0x%x...", a->group_optimization_enabled));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014753
Joe Perches475be4d2012-02-19 19:52:38 -080014754 for (i = 0; i < MAX_CIP_TYPES; i++)
14755 {
14756 info_mask_group[i] = 0;
14757 cip_mask_group[i] = 0;
14758 }
14759 for (i = 0; i < MAX_APPL; i++)
14760 {
14761 appl_number_group_type[i] = 0;
14762 }
14763 for (i = 0; i < max_appl; i++) /* check if any multi instance capable application is present */
14764 { /* group_optimization set to 1 means not to optimize multi-instance capable applications (default) */
14765 if (application[i].Id && (application[i].MaxNCCI) > 1 && (a->CIP_Mask[i]) && (a->group_optimization_enabled == 1))
14766 {
14767 dbug(1, dprintf("Multi-Instance capable, no optimization required"));
14768 return; /* allow good application unfiltered access */
14769 }
14770 }
14771 for (i = 0; i < max_appl; i++) /* Build CIP Groups */
14772 {
14773 if (application[i].Id && a->CIP_Mask[i])
14774 {
14775 for (k = 0, busy = false; k < a->max_plci; k++)
14776 {
14777 if (a->plci[k].Id)
14778 {
14779 auxplci = &a->plci[k];
14780 if (auxplci->appl == &application[i]) /* application has a busy PLCI */
14781 {
14782 busy = true;
14783 dbug(1, dprintf("Appl 0x%x is busy", i + 1));
14784 }
14785 else if (test_c_ind_mask_bit(auxplci, i)) /* application has an incoming call pending */
14786 {
14787 busy = true;
14788 dbug(1, dprintf("Appl 0x%x has inc. call pending", i + 1));
14789 }
14790 }
14791 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014792
Joe Perches475be4d2012-02-19 19:52:38 -080014793 for (j = 0, group_found = 0; j <= (MAX_CIP_TYPES) && !busy && !group_found; j++) /* build groups with free applications only */
14794 {
14795 if (j == MAX_CIP_TYPES) /* all groups are in use but group still not found */
14796 { /* the MAX_CIP_TYPES group enables all calls because of field overflow */
14797 appl_number_group_type[i] = MAX_CIP_TYPES;
14798 group_found = true;
14799 dbug(1, dprintf("Field overflow appl 0x%x", i + 1));
14800 }
14801 else if ((info_mask_group[j] == a->CIP_Mask[i]) && (cip_mask_group[j] == a->Info_Mask[i]))
14802 { /* is group already present ? */
14803 appl_number_group_type[i] = j | 0x80; /* store the group number for each application */
14804 group_found = true;
14805 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]));
14806 }
14807 else if (!info_mask_group[j])
14808 { /* establish a new group */
14809 appl_number_group_type[i] = j | 0x80; /* store the group number for each application */
14810 info_mask_group[j] = a->CIP_Mask[i]; /* store the new CIP mask for the new group */
14811 cip_mask_group[j] = a->Info_Mask[i]; /* store the new Info_Mask for this new group */
14812 group_found = true;
14813 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]));
14814 }
14815 }
14816 }
14817 }
14818
14819 for (i = 0; i < max_appl; i++) /* Build group_optimization_mask_table */
14820 {
14821 if (appl_number_group_type[i]) /* application is free, has listens and is member of a group */
14822 {
14823 if (appl_number_group_type[i] == MAX_CIP_TYPES)
14824 {
14825 dbug(1, dprintf("OverflowGroup 0x%x, valid appl = 0x%x, call enabled", appl_number_group_type[i], i + 1));
14826 }
14827 else
14828 {
14829 dbug(1, dprintf("Group 0x%x, valid appl = 0x%x", appl_number_group_type[i], i + 1));
14830 for (j = i + 1; j < max_appl; j++) /* search other group members and mark them as busy */
14831 {
14832 if (appl_number_group_type[i] == appl_number_group_type[j])
14833 {
14834 dbug(1, dprintf("Appl 0x%x is member of group 0x%x, no call", j + 1, appl_number_group_type[j]));
14835 clear_group_ind_mask_bit(plci, j); /* disable call on other group members */
14836 appl_number_group_type[j] = 0; /* remove disabled group member from group list */
14837 }
14838 }
14839 }
14840 }
14841 else /* application should not get a call */
14842 {
14843 clear_group_ind_mask_bit(plci, i);
14844 }
14845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014846
14847}
14848
14849
14850
14851/* OS notifies the driver about a application Capi_Register */
14852word CapiRegister(word id)
14853{
Joe Perches475be4d2012-02-19 19:52:38 -080014854 word i, j, appls_found;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014855
Joe Perches475be4d2012-02-19 19:52:38 -080014856 PLCI *plci;
14857 DIVA_CAPI_ADAPTER *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014858
Joe Perches475be4d2012-02-19 19:52:38 -080014859 for (i = 0, appls_found = 0; i < max_appl; i++)
14860 {
14861 if (application[i].Id && (application[i].Id != id))
14862 {
14863 appls_found++; /* an application has been found */
14864 }
14865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014866
Joe Perches475be4d2012-02-19 19:52:38 -080014867 if (appls_found) return true;
14868 for (i = 0; i < max_adapter; i++) /* scan all adapters... */
14869 {
14870 a = &adapter[i];
14871 if (a->request)
14872 {
14873 if (a->flag_dynamic_l1_down) /* remove adapter from L1 tristate (Huntgroup) */
14874 {
14875 if (!appls_found) /* first application does a capi register */
14876 {
14877 if ((j = get_plci(a))) /* activate L1 of all adapters */
14878 {
14879 plci = &a->plci[j - 1];
14880 plci->command = 0;
14881 add_p(plci, OAD, "\x01\xfd");
14882 add_p(plci, CAI, "\x01\x80");
14883 add_p(plci, UID, "\x06\x43\x61\x70\x69\x32\x30");
14884 add_p(plci, SHIFT | 6, NULL);
14885 add_p(plci, SIN, "\x02\x00\x00");
14886 plci->internal_command = START_L1_SIG_ASSIGN_PEND;
14887 sig_req(plci, ASSIGN, DSIG_ID);
14888 add_p(plci, FTY, "\x02\xff\x07"); /* l1 start */
14889 sig_req(plci, SIG_CTRL, 0);
14890 send_req(plci);
14891 }
14892 }
14893 }
14894 }
14895 }
14896 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014897}
14898
14899/*------------------------------------------------------------------*/
14900
14901/* Functions for virtual Switching e.g. Transfer by join, Conference */
14902
Joe Perches475be4d2012-02-19 19:52:38 -080014903static void VSwitchReqInd(PLCI *plci, dword Id, byte **parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014904{
Joe Perches475be4d2012-02-19 19:52:38 -080014905 word i;
14906 /* Format of vswitch_t:
14907 0 byte length
14908 1 byte VSWITCHIE
14909 2 byte VSWITCH_REQ/VSWITCH_IND
14910 3 byte reserved
14911 4 word VSwitchcommand
14912 6 word returnerror
14913 8... Params
14914 */
14915 if (!plci ||
14916 !plci->appl ||
14917 !plci->State ||
14918 plci->Sig.Ind == NCR_FACILITY
14919 )
14920 return;
14921
14922 for (i = 0; i < MAX_MULTI_IE; i++)
14923 {
14924 if (!parms[i][0]) continue;
14925 if (parms[i][0] < 7)
14926 {
14927 parms[i][0] = 0; /* kill it */
14928 continue;
14929 }
14930 dbug(1, dprintf("VSwitchReqInd(%d)", parms[i][4]));
14931 switch (parms[i][4])
14932 {
14933 case VSJOIN:
14934 if (!plci->relatedPTYPLCI ||
14935 (plci->ptyState != S_ECT && plci->relatedPTYPLCI->ptyState != S_ECT))
14936 { /* Error */
14937 break;
14938 }
14939 /* remember all necessary informations */
14940 if (parms[i][0] != 11 || parms[i][8] != 3) /* Length Test */
14941 {
14942 break;
14943 }
14944 if (parms[i][2] == VSWITCH_IND && parms[i][9] == 1)
14945 { /* first indication after ECT-Request on Consultation Call */
14946 plci->vswitchstate = parms[i][9];
14947 parms[i][9] = 2; /* State */
14948 /* now ask first Call to join */
14949 }
14950 else if (parms[i][2] == VSWITCH_REQ && parms[i][9] == 3)
14951 { /* Answer of VSWITCH_REQ from first Call */
14952 plci->vswitchstate = parms[i][9];
14953 /* tell consultation call to join
14954 and the protocol capabilities of the first call */
14955 }
14956 else
14957 { /* Error */
14958 break;
14959 }
14960 plci->vsprot = parms[i][10]; /* protocol */
14961 plci->vsprotdialect = parms[i][11]; /* protocoldialect */
14962 /* send join request to related PLCI */
14963 parms[i][1] = VSWITCHIE;
14964 parms[i][2] = VSWITCH_REQ;
14965
14966 plci->relatedPTYPLCI->command = 0;
14967 plci->relatedPTYPLCI->internal_command = VSWITCH_REQ_PEND;
14968 add_p(plci->relatedPTYPLCI, ESC, &parms[i][0]);
14969 sig_req(plci->relatedPTYPLCI, VSWITCH_REQ, 0);
14970 send_req(plci->relatedPTYPLCI);
14971 break;
14972 case VSTRANSPORT:
14973 default:
14974 if (plci->relatedPTYPLCI &&
14975 plci->vswitchstate == 3 &&
14976 plci->relatedPTYPLCI->vswitchstate == 3)
14977 {
14978 add_p(plci->relatedPTYPLCI, ESC, &parms[i][0]);
14979 sig_req(plci->relatedPTYPLCI, VSWITCH_REQ, 0);
14980 send_req(plci->relatedPTYPLCI);
14981 }
14982 break;
14983 }
14984 parms[i][0] = 0; /* kill it */
14985 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014986}
14987
14988
14989/*------------------------------------------------------------------*/
14990
Joe Perches475be4d2012-02-19 19:52:38 -080014991static int diva_get_dma_descriptor(PLCI *plci, dword *dma_magic) {
14992 ENTITY e;
14993 IDI_SYNC_REQ *pReq = (IDI_SYNC_REQ *)&e;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014994
Joe Perches475be4d2012-02-19 19:52:38 -080014995 if (!(diva_xdi_extended_features & DIVA_CAPI_XDI_PROVIDES_RX_DMA)) {
14996 return (-1);
14997 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014998
Joe Perches475be4d2012-02-19 19:52:38 -080014999 pReq->xdi_dma_descriptor_operation.Req = 0;
15000 pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015001
Joe Perches475be4d2012-02-19 19:52:38 -080015002 pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC;
15003 pReq->xdi_dma_descriptor_operation.info.descriptor_number = -1;
15004 pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL;
15005 pReq->xdi_dma_descriptor_operation.info.descriptor_magic = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015006
Joe Perches475be4d2012-02-19 19:52:38 -080015007 e.user[0] = plci->adapter->Id - 1;
15008 plci->adapter->request((ENTITY *)pReq);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015009
Joe Perches475be4d2012-02-19 19:52:38 -080015010 if (!pReq->xdi_dma_descriptor_operation.info.operation &&
15011 (pReq->xdi_dma_descriptor_operation.info.descriptor_number >= 0) &&
15012 pReq->xdi_dma_descriptor_operation.info.descriptor_magic) {
15013 *dma_magic = pReq->xdi_dma_descriptor_operation.info.descriptor_magic;
15014 dbug(3, dprintf("dma_alloc, a:%d (%d-%08x)",
15015 plci->adapter->Id,
15016 pReq->xdi_dma_descriptor_operation.info.descriptor_number,
15017 *dma_magic));
15018 return (pReq->xdi_dma_descriptor_operation.info.descriptor_number);
15019 } else {
15020 dbug(1, dprintf("dma_alloc failed"));
15021 return (-1);
15022 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015023}
15024
Joe Perches475be4d2012-02-19 19:52:38 -080015025static void diva_free_dma_descriptor(PLCI *plci, int nr) {
15026 ENTITY e;
15027 IDI_SYNC_REQ *pReq = (IDI_SYNC_REQ *)&e;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015028
Joe Perches475be4d2012-02-19 19:52:38 -080015029 if (nr < 0) {
15030 return;
15031 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015032
Joe Perches475be4d2012-02-19 19:52:38 -080015033 pReq->xdi_dma_descriptor_operation.Req = 0;
15034 pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015035
Joe Perches475be4d2012-02-19 19:52:38 -080015036 pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE;
15037 pReq->xdi_dma_descriptor_operation.info.descriptor_number = nr;
15038 pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL;
15039 pReq->xdi_dma_descriptor_operation.info.descriptor_magic = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015040
Joe Perches475be4d2012-02-19 19:52:38 -080015041 e.user[0] = plci->adapter->Id - 1;
15042 plci->adapter->request((ENTITY *)pReq);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015043
Joe Perches475be4d2012-02-19 19:52:38 -080015044 if (!pReq->xdi_dma_descriptor_operation.info.operation) {
15045 dbug(1, dprintf("dma_free(%d)", nr));
15046 } else {
15047 dbug(1, dprintf("dma_free failed (%d)", nr));
15048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015049}
15050
15051/*------------------------------------------------------------------*/