Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* $Id: capifunc.c,v 1.61.4.7 2005/02/11 19:40:25 armin Exp $ |
2 | * | |
3 | * ISDN interface module for Eicon active cards DIVA. | |
4 | * CAPI Interface common functions | |
475be4d8 JP |
5 | * |
6 | * Copyright 2000-2003 by Armin Schindler (mac@melware.de) | |
1da177e4 | 7 | * Copyright 2000-2003 Cytronics & Melware (info@melware.de) |
475be4d8 | 8 | * |
1da177e4 LT |
9 | * This software may be used and distributed according to the terms |
10 | * of the GNU General Public License, incorporated herein by reference. | |
11 | * | |
12 | */ | |
13 | ||
14 | #include "platform.h" | |
15 | #include "os_capi.h" | |
16 | #include "di_defs.h" | |
17 | #include "capi20.h" | |
18 | #include "divacapi.h" | |
19 | #include "divasync.h" | |
20 | #include "capifunc.h" | |
21 | ||
22 | #define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR) | |
23 | #define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG) | |
24 | ||
25 | DIVA_CAPI_ADAPTER *adapter = (DIVA_CAPI_ADAPTER *) NULL; | |
26 | APPL *application = (APPL *) NULL; | |
27 | byte max_appl = MAX_APPL; | |
28 | byte max_adapter = 0; | |
29 | static CAPI_MSG *mapped_msg = (CAPI_MSG *) NULL; | |
30 | ||
31 | byte UnMapController(byte); | |
32 | char DRIVERRELEASE_CAPI[32]; | |
33 | ||
34 | extern void AutomaticLaw(DIVA_CAPI_ADAPTER *); | |
35 | extern void callback(ENTITY *); | |
36 | extern word api_remove_start(void); | |
37 | extern word CapiRelease(word); | |
38 | extern word CapiRegister(word); | |
39 | extern word api_put(APPL *, CAPI_MSG *); | |
40 | ||
41 | static diva_os_spin_lock_t api_lock; | |
42 | ||
43 | static LIST_HEAD(cards); | |
44 | ||
45 | static dword notify_handle; | |
475be4d8 | 46 | static void DIRequest(ENTITY *e); |
1da177e4 LT |
47 | static DESCRIPTOR MAdapter; |
48 | static DESCRIPTOR DAdapter; | |
49 | static byte ControllerMap[MAX_DESCRIPTORS + 1]; | |
50 | ||
51 | ||
52 | static void diva_register_appl(struct capi_ctr *, __u16, | |
53 | capi_register_params *); | |
54 | static void diva_release_appl(struct capi_ctr *, __u16); | |
55 | static char *diva_procinfo(struct capi_ctr *); | |
56 | static u16 diva_send_message(struct capi_ctr *, | |
57 | diva_os_message_buffer_s *); | |
58 | extern void diva_os_set_controller_struct(struct capi_ctr *); | |
59 | ||
60 | extern void DIVA_DIDD_Read(DESCRIPTOR *, int); | |
61 | ||
62 | /* | |
63 | * debug | |
64 | */ | |
65 | static void no_printf(unsigned char *, ...); | |
66 | #include "debuglib.c" | |
67 | static void xlog(char *x, ...) | |
68 | { | |
69 | #ifndef DIVA_NO_DEBUGLIB | |
70 | va_list ap; | |
71 | if (myDriverDebugHandle.dbgMask & DL_XLOG) { | |
72 | va_start(ap, x); | |
73 | if (myDriverDebugHandle.dbg_irq) { | |
74 | myDriverDebugHandle.dbg_irq(myDriverDebugHandle.id, | |
75 | DLI_XLOG, x, ap); | |
76 | } else if (myDriverDebugHandle.dbg_old) { | |
77 | myDriverDebugHandle.dbg_old(myDriverDebugHandle.id, | |
78 | x, ap); | |
79 | } | |
80 | va_end(ap); | |
81 | } | |
82 | #endif | |
83 | } | |
84 | ||
85 | /* | |
86 | * info for proc | |
87 | */ | |
88 | static char *diva_procinfo(struct capi_ctr *ctrl) | |
89 | { | |
90 | return (ctrl->serial); | |
91 | } | |
92 | ||
93 | /* | |
94 | * stop debugging | |
95 | */ | |
96 | static void stop_dbg(void) | |
97 | { | |
98 | DbgDeregister(); | |
99 | memset(&MAdapter, 0, sizeof(MAdapter)); | |
100 | dprintf = no_printf; | |
101 | } | |
102 | ||
103 | /* | |
104 | * dummy debug function | |
105 | */ | |
106 | static void no_printf(unsigned char *x, ...) | |
107 | { | |
108 | } | |
109 | ||
110 | /* | |
111 | * Controller mapping | |
112 | */ | |
113 | byte MapController(byte Controller) | |
114 | { | |
115 | byte i; | |
116 | byte MappedController = 0; | |
117 | byte ctrl = Controller & 0x7f; /* mask external controller bit off */ | |
118 | ||
119 | for (i = 1; i < max_adapter + 1; i++) { | |
120 | if (ctrl == ControllerMap[i]) { | |
121 | MappedController = (byte) i; | |
122 | break; | |
123 | } | |
124 | } | |
125 | if (i > max_adapter) { | |
126 | ControllerMap[0] = ctrl; | |
127 | MappedController = 0; | |
128 | } | |
129 | return (MappedController | (Controller & 0x80)); /* put back external controller bit */ | |
130 | } | |
131 | ||
132 | /* | |
133 | * Controller unmapping | |
134 | */ | |
135 | byte UnMapController(byte MappedController) | |
136 | { | |
137 | byte Controller; | |
138 | byte ctrl = MappedController & 0x7f; /* mask external controller bit off */ | |
139 | ||
140 | if (ctrl <= max_adapter) { | |
141 | Controller = ControllerMap[ctrl]; | |
142 | } else { | |
143 | Controller = 0; | |
144 | } | |
145 | ||
146 | return (Controller | (MappedController & 0x80)); /* put back external controller bit */ | |
147 | } | |
148 | ||
149 | /* | |
150 | * find a new free id | |
151 | */ | |
152 | static int find_free_id(void) | |
153 | { | |
154 | int num = 0; | |
155 | DIVA_CAPI_ADAPTER *a; | |
156 | ||
157 | while (num < MAX_DESCRIPTORS) { | |
158 | a = &adapter[num]; | |
159 | if (!a->Id) | |
160 | break; | |
161 | num++; | |
162 | } | |
475be4d8 | 163 | return (num + 1); |
1da177e4 LT |
164 | } |
165 | ||
166 | /* | |
167 | * find a card structure by controller number | |
168 | */ | |
169 | static diva_card *find_card_by_ctrl(word controller) | |
170 | { | |
171 | struct list_head *tmp; | |
172 | diva_card *card; | |
173 | ||
174 | list_for_each(tmp, &cards) { | |
175 | card = list_entry(tmp, diva_card, list); | |
176 | if (ControllerMap[card->Id] == controller) { | |
177 | if (card->remove_in_progress) | |
178 | card = NULL; | |
475be4d8 | 179 | return (card); |
1da177e4 LT |
180 | } |
181 | } | |
182 | return (diva_card *) 0; | |
183 | } | |
184 | ||
185 | /* | |
475be4d8 | 186 | * Buffer RX/TX |
1da177e4 | 187 | */ |
475be4d8 | 188 | void *TransmitBufferSet(APPL *appl, dword ref) |
1da177e4 | 189 | { |
986c4bb8 | 190 | appl->xbuffer_used[ref] = true; |
1da177e4 | 191 | DBG_PRV1(("%d:xbuf_used(%d)", appl->Id, ref + 1)) |
475be4d8 | 192 | return (void *)(long)ref; |
1da177e4 LT |
193 | } |
194 | ||
475be4d8 | 195 | void *TransmitBufferGet(APPL *appl, void *p) |
1da177e4 | 196 | { |
241be8d9 AM |
197 | if (appl->xbuffer_internal[(dword)(long)p]) |
198 | return appl->xbuffer_internal[(dword)(long)p]; | |
1da177e4 | 199 | |
241be8d9 | 200 | return appl->xbuffer_ptr[(dword)(long)p]; |
1da177e4 LT |
201 | } |
202 | ||
475be4d8 | 203 | void TransmitBufferFree(APPL *appl, void *p) |
1da177e4 | 204 | { |
241be8d9 AM |
205 | appl->xbuffer_used[(dword)(long)p] = false; |
206 | DBG_PRV1(("%d:xbuf_free(%d)", appl->Id, ((dword)(long)p) + 1)) | |
475be4d8 | 207 | } |
1da177e4 | 208 | |
475be4d8 | 209 | void *ReceiveBufferGet(APPL *appl, int Num) |
1da177e4 LT |
210 | { |
211 | return &appl->ReceiveBuffer[Num * appl->MaxDataLength]; | |
212 | } | |
213 | ||
214 | /* | |
215 | * api_remove_start/complete for cleanup | |
216 | */ | |
217 | void api_remove_complete(void) | |
218 | { | |
219 | DBG_PRV1(("api_remove_complete")) | |
475be4d8 | 220 | } |
1da177e4 LT |
221 | |
222 | /* | |
223 | * main function called by message.c | |
224 | */ | |
475be4d8 | 225 | void sendf(APPL *appl, word command, dword Id, word Number, byte *format, ...) |
1da177e4 LT |
226 | { |
227 | word i, j; | |
228 | word length = 12, dlength = 0; | |
229 | byte *write; | |
230 | CAPI_MSG msg; | |
231 | byte *string = NULL; | |
232 | va_list ap; | |
233 | diva_os_message_buffer_s *dmb; | |
234 | diva_card *card = NULL; | |
235 | dword tmp; | |
236 | ||
237 | if (!appl) | |
238 | return; | |
239 | ||
240 | DBG_PRV1(("sendf(a=%d,cmd=%x,format=%s)", | |
241 | appl->Id, command, (byte *) format)) | |
242 | ||
475be4d8 | 243 | PUT_WORD(&msg.header.appl_id, appl->Id); |
1da177e4 LT |
244 | PUT_WORD(&msg.header.command, command); |
245 | if ((byte) (command >> 8) == 0x82) | |
246 | Number = appl->Number++; | |
247 | PUT_WORD(&msg.header.number, Number); | |
248 | ||
249 | PUT_DWORD(&msg.header.controller, Id); | |
475be4d8 | 250 | write = (byte *)&msg; |
1da177e4 LT |
251 | write += 12; |
252 | ||
253 | va_start(ap, format); | |
254 | for (i = 0; format[i]; i++) { | |
255 | switch (format[i]) { | |
256 | case 'b': | |
257 | tmp = va_arg(ap, dword); | |
258 | *(byte *) write = (byte) (tmp & 0xff); | |
259 | write += 1; | |
260 | length += 1; | |
261 | break; | |
262 | case 'w': | |
263 | tmp = va_arg(ap, dword); | |
264 | PUT_WORD(write, (tmp & 0xffff)); | |
265 | write += 2; | |
266 | length += 2; | |
267 | break; | |
268 | case 'd': | |
269 | tmp = va_arg(ap, dword); | |
270 | PUT_DWORD(write, tmp); | |
271 | write += 4; | |
272 | length += 4; | |
273 | break; | |
274 | case 's': | |
275 | case 'S': | |
276 | string = va_arg(ap, byte *); | |
277 | length += string[0] + 1; | |
278 | for (j = 0; j <= string[0]; j++) | |
279 | *write++ = string[j]; | |
280 | break; | |
281 | } | |
282 | } | |
283 | va_end(ap); | |
284 | ||
285 | PUT_WORD(&msg.header.length, length); | |
286 | msg.header.controller = UnMapController(msg.header.controller); | |
287 | ||
288 | if (command == _DATA_B3_I) | |
289 | dlength = GET_WORD( | |
475be4d8 | 290 | ((byte *)&msg.info.data_b3_ind.Data_Length)); |
1da177e4 LT |
291 | |
292 | if (!(dmb = diva_os_alloc_message_buffer(length + dlength, | |
475be4d8 | 293 | (void **) &write))) { |
1da177e4 | 294 | DBG_ERR(("sendf: alloc_message_buffer failed, incoming msg dropped.")) |
475be4d8 | 295 | return; |
1da177e4 LT |
296 | } |
297 | ||
298 | /* copy msg header to sk_buff */ | |
475be4d8 | 299 | memcpy(write, (byte *)&msg, length); |
1da177e4 LT |
300 | |
301 | /* if DATA_B3_IND, copy data too */ | |
302 | if (command == _DATA_B3_I) { | |
303 | dword data = GET_DWORD(&msg.info.data_b3_ind.Data); | |
241be8d9 | 304 | memcpy(write + length, (void *)(long)data, dlength); |
1da177e4 LT |
305 | } |
306 | ||
307 | #ifndef DIVA_NO_DEBUGLIB | |
308 | if (myDriverDebugHandle.dbgMask & DL_XLOG) { | |
309 | switch (command) { | |
310 | default: | |
311 | xlog("\x00\x02", &msg, 0x81, length); | |
312 | break; | |
313 | case _DATA_B3_R | CONFIRM: | |
314 | if (myDriverDebugHandle.dbgMask & DL_BLK) | |
315 | xlog("\x00\x02", &msg, 0x81, length); | |
316 | break; | |
317 | case _DATA_B3_I: | |
318 | if (myDriverDebugHandle.dbgMask & DL_BLK) { | |
319 | xlog("\x00\x02", &msg, 0x81, length); | |
320 | for (i = 0; i < dlength; i += 256) { | |
475be4d8 JP |
321 | DBG_BLK((((char *)(long)GET_DWORD(&msg.info.data_b3_ind.Data)) + i, |
322 | ((dlength - i) < 256) ? (dlength - i) : 256)) | |
323 | if (!(myDriverDebugHandle.dbgMask & DL_PRV0)) | |
324 | break; /* not more if not explicitly requested */ | |
1da177e4 LT |
325 | } |
326 | } | |
327 | break; | |
328 | } | |
329 | } | |
330 | #endif | |
331 | ||
332 | /* find the card structure for this controller */ | |
333 | if (!(card = find_card_by_ctrl(write[8] & 0x7f))) { | |
334 | DBG_ERR(("sendf - controller %d not found, incoming msg dropped", | |
335 | write[8] & 0x7f)) | |
475be4d8 | 336 | diva_os_free_message_buffer(dmb); |
1da177e4 LT |
337 | return; |
338 | } | |
339 | /* send capi msg to capi layer */ | |
340 | capi_ctr_handle_message(&card->capi_ctrl, appl->Id, dmb); | |
341 | } | |
342 | ||
343 | /* | |
344 | * cleanup adapter | |
345 | */ | |
346 | static void clean_adapter(int id, struct list_head *free_mem_q) | |
347 | { | |
348 | DIVA_CAPI_ADAPTER *a; | |
349 | int i, k; | |
350 | ||
351 | a = &adapter[id]; | |
352 | k = li_total_channels - a->li_channels; | |
353 | if (k == 0) { | |
354 | if (li_config_table) { | |
355 | list_add((struct list_head *)li_config_table, free_mem_q); | |
356 | li_config_table = NULL; | |
357 | } | |
358 | } else { | |
359 | if (a->li_base < k) { | |
360 | memmove(&li_config_table[a->li_base], | |
361 | &li_config_table[a->li_base + a->li_channels], | |
362 | (k - a->li_base) * sizeof(LI_CONFIG)); | |
363 | for (i = 0; i < k; i++) { | |
364 | memmove(&li_config_table[i].flag_table[a->li_base], | |
365 | &li_config_table[i].flag_table[a->li_base + a->li_channels], | |
366 | k - a->li_base); | |
367 | memmove(&li_config_table[i]. | |
368 | coef_table[a->li_base], | |
369 | &li_config_table[i].coef_table[a->li_base + a->li_channels], | |
370 | k - a->li_base); | |
371 | } | |
372 | } | |
373 | } | |
374 | li_total_channels = k; | |
375 | for (i = id; i < max_adapter; i++) { | |
376 | if (adapter[i].request) | |
377 | adapter[i].li_base -= a->li_channels; | |
378 | } | |
379 | if (a->plci) | |
380 | list_add((struct list_head *)a->plci, free_mem_q); | |
381 | ||
382 | memset(a, 0x00, sizeof(DIVA_CAPI_ADAPTER)); | |
383 | while ((max_adapter != 0) && !adapter[max_adapter - 1].request) | |
384 | max_adapter--; | |
385 | } | |
386 | ||
387 | /* | |
388 | * remove a card, but ensures consistent state of LI tables | |
389 | * in the time adapter is removed | |
390 | */ | |
475be4d8 | 391 | static void divacapi_remove_card(DESCRIPTOR *d) |
1da177e4 LT |
392 | { |
393 | diva_card *card = NULL; | |
394 | diva_os_spin_lock_magic_t old_irql; | |
395 | LIST_HEAD(free_mem_q); | |
396 | struct list_head *link; | |
397 | struct list_head *tmp; | |
398 | ||
399 | /* | |
400 | * Set "remove in progress flag". | |
401 | * Ensures that there is no call from sendf to CAPI in | |
402 | * the time CAPI controller is about to be removed. | |
403 | */ | |
404 | diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card"); | |
405 | list_for_each(tmp, &cards) { | |
406 | card = list_entry(tmp, diva_card, list); | |
407 | if (card->d.request == d->request) { | |
408 | card->remove_in_progress = 1; | |
409 | list_del(tmp); | |
410 | break; | |
411 | } | |
412 | } | |
413 | diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card"); | |
414 | ||
415 | if (card) { | |
416 | /* | |
417 | * Detach CAPI. Sendf cannot call to CAPI any more. | |
418 | * After detach no call to send_message() is done too. | |
419 | */ | |
420 | detach_capi_ctr(&card->capi_ctrl); | |
421 | ||
422 | /* | |
423 | * Now get API lock (to ensure stable state of LI tables) | |
424 | * and update the adapter map/LI table. | |
425 | */ | |
426 | diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card"); | |
427 | ||
428 | clean_adapter(card->Id - 1, &free_mem_q); | |
429 | DBG_TRC(("DelAdapterMap (%d) -> (%d)", | |
475be4d8 JP |
430 | ControllerMap[card->Id], card->Id)) |
431 | ControllerMap[card->Id] = 0; | |
1da177e4 | 432 | DBG_TRC(("adapter remove, max_adapter=%d", |
475be4d8 | 433 | max_adapter)); |
1da177e4 | 434 | diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card"); |
475be4d8 | 435 | |
1da177e4 | 436 | /* After releasing the lock, we can free the memory */ |
475be4d8 | 437 | diva_os_free(0, card); |
1da177e4 LT |
438 | } |
439 | ||
440 | /* free queued memory areas */ | |
441 | list_for_each_safe(link, tmp, &free_mem_q) { | |
442 | list_del(link); | |
443 | diva_os_free(0, link); | |
444 | } | |
445 | } | |
446 | ||
447 | /* | |
448 | * remove cards | |
449 | */ | |
450 | static void divacapi_remove_cards(void) | |
451 | { | |
452 | DESCRIPTOR d; | |
453 | struct list_head *tmp; | |
454 | diva_card *card; | |
455 | diva_os_spin_lock_magic_t old_irql; | |
456 | ||
457 | rescan: | |
458 | diva_os_enter_spin_lock(&api_lock, &old_irql, "remove cards"); | |
459 | list_for_each(tmp, &cards) { | |
460 | card = list_entry(tmp, diva_card, list); | |
461 | diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards"); | |
462 | d.request = card->d.request; | |
463 | divacapi_remove_card(&d); | |
464 | goto rescan; | |
465 | } | |
466 | diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards"); | |
467 | } | |
468 | ||
469 | /* | |
470 | * sync_callback | |
471 | */ | |
475be4d8 | 472 | static void sync_callback(ENTITY *e) |
1da177e4 LT |
473 | { |
474 | diva_os_spin_lock_magic_t old_irql; | |
475 | ||
476 | DBG_TRC(("cb:Id=%x,Rc=%x,Ind=%x", e->Id, e->Rc, e->Ind)) | |
477 | ||
475be4d8 | 478 | diva_os_enter_spin_lock(&api_lock, &old_irql, "sync_callback"); |
1da177e4 LT |
479 | callback(e); |
480 | diva_os_leave_spin_lock(&api_lock, &old_irql, "sync_callback"); | |
481 | } | |
482 | ||
483 | /* | |
484 | * add a new card | |
485 | */ | |
475be4d8 | 486 | static int diva_add_card(DESCRIPTOR *d) |
1da177e4 LT |
487 | { |
488 | int k = 0, i = 0; | |
489 | diva_os_spin_lock_magic_t old_irql; | |
490 | diva_card *card = NULL; | |
491 | struct capi_ctr *ctrl = NULL; | |
492 | DIVA_CAPI_ADAPTER *a = NULL; | |
493 | IDI_SYNC_REQ sync_req; | |
494 | char serial[16]; | |
475be4d8 | 495 | void *mem_to_free; |
1da177e4 LT |
496 | LI_CONFIG *new_li_config_table; |
497 | int j; | |
498 | ||
499 | if (!(card = (diva_card *) diva_os_malloc(0, sizeof(diva_card)))) { | |
500 | DBG_ERR(("diva_add_card: failed to allocate card struct.")) | |
475be4d8 | 501 | return (0); |
1da177e4 LT |
502 | } |
503 | memset((char *) card, 0x00, sizeof(diva_card)); | |
504 | memcpy(&card->d, d, sizeof(DESCRIPTOR)); | |
505 | sync_req.GetName.Req = 0; | |
506 | sync_req.GetName.Rc = IDI_SYNC_REQ_GET_NAME; | |
475be4d8 | 507 | card->d.request((ENTITY *)&sync_req); |
1da177e4 LT |
508 | strlcpy(card->name, sync_req.GetName.name, sizeof(card->name)); |
509 | ctrl = &card->capi_ctrl; | |
510 | strcpy(ctrl->name, card->name); | |
511 | ctrl->register_appl = diva_register_appl; | |
512 | ctrl->release_appl = diva_release_appl; | |
513 | ctrl->send_message = diva_send_message; | |
514 | ctrl->procinfo = diva_procinfo; | |
515 | ctrl->driverdata = card; | |
516 | diva_os_set_controller_struct(ctrl); | |
517 | ||
518 | if (attach_capi_ctr(ctrl)) { | |
519 | DBG_ERR(("diva_add_card: failed to attach controller.")) | |
475be4d8 | 520 | diva_os_free(0, card); |
1da177e4 LT |
521 | return (0); |
522 | } | |
475be4d8 | 523 | |
1da177e4 LT |
524 | diva_os_enter_spin_lock(&api_lock, &old_irql, "find id"); |
525 | card->Id = find_free_id(); | |
526 | diva_os_leave_spin_lock(&api_lock, &old_irql, "find id"); | |
475be4d8 | 527 | |
1da177e4 LT |
528 | strlcpy(ctrl->manu, M_COMPANY, sizeof(ctrl->manu)); |
529 | ctrl->version.majorversion = 2; | |
530 | ctrl->version.minorversion = 0; | |
531 | ctrl->version.majormanuversion = DRRELMAJOR; | |
532 | ctrl->version.minormanuversion = DRRELMINOR; | |
533 | sync_req.GetSerial.Req = 0; | |
534 | sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL; | |
535 | sync_req.GetSerial.serial = 0; | |
475be4d8 | 536 | card->d.request((ENTITY *)&sync_req); |
1da177e4 LT |
537 | if ((i = ((sync_req.GetSerial.serial & 0xff000000) >> 24))) { |
538 | sprintf(serial, "%ld-%d", | |
539 | sync_req.GetSerial.serial & 0x00ffffff, i + 1); | |
540 | } else { | |
541 | sprintf(serial, "%ld", sync_req.GetSerial.serial); | |
542 | } | |
543 | serial[CAPI_SERIAL_LEN - 1] = 0; | |
544 | strlcpy(ctrl->serial, serial, sizeof(ctrl->serial)); | |
545 | ||
546 | a = &adapter[card->Id - 1]; | |
547 | card->adapter = a; | |
548 | a->os_card = card; | |
549 | ControllerMap[card->Id] = (byte) (ctrl->cnr); | |
550 | ||
551 | DBG_TRC(("AddAdapterMap (%d) -> (%d)", ctrl->cnr, card->Id)) | |
552 | ||
475be4d8 | 553 | sync_req.xdi_capi_prms.Req = 0; |
1da177e4 LT |
554 | sync_req.xdi_capi_prms.Rc = IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS; |
555 | sync_req.xdi_capi_prms.info.structure_length = | |
475be4d8 JP |
556 | sizeof(diva_xdi_get_capi_parameters_t); |
557 | card->d.request((ENTITY *)&sync_req); | |
1da177e4 | 558 | a->flag_dynamic_l1_down = |
475be4d8 | 559 | sync_req.xdi_capi_prms.info.flag_dynamic_l1_down; |
1da177e4 | 560 | a->group_optimization_enabled = |
475be4d8 | 561 | sync_req.xdi_capi_prms.info.group_optimization_enabled; |
1da177e4 LT |
562 | a->request = DIRequest; /* card->d.request; */ |
563 | a->max_plci = card->d.channels + 30; | |
564 | a->max_listen = (card->d.channels > 2) ? 8 : 2; | |
565 | if (! | |
566 | (a->plci = | |
567 | (PLCI *) diva_os_malloc(0, sizeof(PLCI) * a->max_plci))) { | |
568 | DBG_ERR(("diva_add_card: failed alloc plci struct.")) | |
475be4d8 | 569 | memset(a, 0, sizeof(DIVA_CAPI_ADAPTER)); |
1da177e4 LT |
570 | return (0); |
571 | } | |
572 | memset(a->plci, 0, sizeof(PLCI) * a->max_plci); | |
573 | ||
574 | for (k = 0; k < a->max_plci; k++) { | |
575 | a->Id = (byte) card->Id; | |
576 | a->plci[k].Sig.callback = sync_callback; | |
577 | a->plci[k].Sig.XNum = 1; | |
578 | a->plci[k].Sig.X = a->plci[k].XData; | |
579 | a->plci[k].Sig.user[0] = (word) (card->Id - 1); | |
580 | a->plci[k].Sig.user[1] = (word) k; | |
581 | a->plci[k].NL.callback = sync_callback; | |
582 | a->plci[k].NL.XNum = 1; | |
583 | a->plci[k].NL.X = a->plci[k].XData; | |
584 | a->plci[k].NL.user[0] = (word) ((card->Id - 1) | 0x8000); | |
585 | a->plci[k].NL.user[1] = (word) k; | |
586 | a->plci[k].adapter = a; | |
587 | } | |
588 | ||
589 | a->profile.Number = card->Id; | |
590 | a->profile.Channels = card->d.channels; | |
591 | if (card->d.features & DI_FAX3) { | |
592 | a->profile.Global_Options = 0x71; | |
593 | if (card->d.features & DI_CODEC) | |
594 | a->profile.Global_Options |= 0x6; | |
595 | #if IMPLEMENT_DTMF | |
596 | a->profile.Global_Options |= 0x8; | |
597 | #endif /* IMPLEMENT_DTMF */ | |
598 | a->profile.Global_Options |= 0x80; /* Line Interconnect */ | |
599 | #if IMPLEMENT_ECHO_CANCELLER | |
600 | a->profile.Global_Options |= 0x100; | |
601 | #endif /* IMPLEMENT_ECHO_CANCELLER */ | |
602 | a->profile.B1_Protocols = 0xdf; | |
603 | a->profile.B2_Protocols = 0x1fdb; | |
604 | a->profile.B3_Protocols = 0xb7; | |
605 | a->manufacturer_features = MANUFACTURER_FEATURE_HARDDTMF; | |
606 | } else { | |
607 | a->profile.Global_Options = 0x71; | |
608 | if (card->d.features & DI_CODEC) | |
609 | a->profile.Global_Options |= 0x2; | |
610 | a->profile.B1_Protocols = 0x43; | |
611 | a->profile.B2_Protocols = 0x1f0f; | |
612 | a->profile.B3_Protocols = 0x07; | |
613 | a->manufacturer_features = 0; | |
614 | } | |
615 | ||
616 | a->li_pri = (a->profile.Channels > 2); | |
617 | a->li_channels = a->li_pri ? MIXER_CHANNELS_PRI : MIXER_CHANNELS_BRI; | |
618 | a->li_base = 0; | |
619 | for (i = 0; &adapter[i] != a; i++) { | |
620 | if (adapter[i].request) | |
621 | a->li_base = adapter[i].li_base + adapter[i].li_channels; | |
622 | } | |
623 | k = li_total_channels + a->li_channels; | |
624 | new_li_config_table = | |
625 | (LI_CONFIG *) diva_os_malloc(0, ((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * k) * ((k + 3) & ~3)); | |
626 | if (new_li_config_table == NULL) { | |
627 | DBG_ERR(("diva_add_card: failed alloc li_config table.")) | |
475be4d8 | 628 | memset(a, 0, sizeof(DIVA_CAPI_ADAPTER)); |
1da177e4 LT |
629 | return (0); |
630 | } | |
631 | ||
632 | /* Prevent access to line interconnect table in process update */ | |
633 | diva_os_enter_spin_lock(&api_lock, &old_irql, "add card"); | |
475be4d8 | 634 | |
1da177e4 LT |
635 | j = 0; |
636 | for (i = 0; i < k; i++) { | |
637 | if ((i >= a->li_base) && (i < a->li_base + a->li_channels)) | |
638 | memset(&new_li_config_table[i], 0, sizeof(LI_CONFIG)); | |
639 | else | |
640 | memcpy(&new_li_config_table[i], &li_config_table[j], sizeof(LI_CONFIG)); | |
641 | new_li_config_table[i].flag_table = | |
642 | ((byte *) new_li_config_table) + (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i) * ((k + 3) & ~3)); | |
643 | new_li_config_table[i].coef_table = | |
644 | ((byte *) new_li_config_table) + (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i + 1) * ((k + 3) & ~3)); | |
645 | if ((i >= a->li_base) && (i < a->li_base + a->li_channels)) { | |
646 | new_li_config_table[i].adapter = a; | |
647 | memset(&new_li_config_table[i].flag_table[0], 0, k); | |
648 | memset(&new_li_config_table[i].coef_table[0], 0, k); | |
649 | } else { | |
650 | if (a->li_base != 0) { | |
651 | memcpy(&new_li_config_table[i].flag_table[0], | |
652 | &li_config_table[j].flag_table[0], | |
653 | a->li_base); | |
654 | memcpy(&new_li_config_table[i].coef_table[0], | |
655 | &li_config_table[j].coef_table[0], | |
656 | a->li_base); | |
657 | } | |
658 | memset(&new_li_config_table[i].flag_table[a->li_base], 0, a->li_channels); | |
659 | memset(&new_li_config_table[i].coef_table[a->li_base], 0, a->li_channels); | |
660 | if (a->li_base + a->li_channels < k) { | |
661 | memcpy(&new_li_config_table[i].flag_table[a->li_base + | |
475be4d8 | 662 | a->li_channels], |
1da177e4 LT |
663 | &li_config_table[j].flag_table[a->li_base], |
664 | k - (a->li_base + a->li_channels)); | |
665 | memcpy(&new_li_config_table[i].coef_table[a->li_base + | |
475be4d8 | 666 | a->li_channels], |
1da177e4 LT |
667 | &li_config_table[j].coef_table[a->li_base], |
668 | k - (a->li_base + a->li_channels)); | |
669 | } | |
670 | j++; | |
671 | } | |
672 | } | |
673 | li_total_channels = k; | |
674 | ||
675 | mem_to_free = li_config_table; | |
676 | ||
677 | li_config_table = new_li_config_table; | |
678 | for (i = card->Id; i < max_adapter; i++) { | |
679 | if (adapter[i].request) | |
680 | adapter[i].li_base += a->li_channels; | |
681 | } | |
682 | ||
683 | if (a == &adapter[max_adapter]) | |
684 | max_adapter++; | |
685 | ||
686 | list_add(&(card->list), &cards); | |
687 | AutomaticLaw(a); | |
688 | ||
689 | diva_os_leave_spin_lock(&api_lock, &old_irql, "add card"); | |
690 | ||
691 | if (mem_to_free) { | |
475be4d8 | 692 | diva_os_free(0, mem_to_free); |
1da177e4 LT |
693 | } |
694 | ||
695 | i = 0; | |
696 | while (i++ < 30) { | |
697 | if (a->automatic_law > 3) | |
698 | break; | |
699 | diva_os_sleep(10); | |
700 | } | |
701 | ||
702 | /* profile information */ | |
703 | PUT_WORD(&ctrl->profile.nbchannel, card->d.channels); | |
704 | ctrl->profile.goptions = a->profile.Global_Options; | |
705 | ctrl->profile.support1 = a->profile.B1_Protocols; | |
706 | ctrl->profile.support2 = a->profile.B2_Protocols; | |
707 | ctrl->profile.support3 = a->profile.B3_Protocols; | |
708 | /* manufacturer profile information */ | |
709 | ctrl->profile.manu[0] = a->man_profile.private_options; | |
710 | ctrl->profile.manu[1] = a->man_profile.rtp_primary_payloads; | |
711 | ctrl->profile.manu[2] = a->man_profile.rtp_additional_payloads; | |
712 | ctrl->profile.manu[3] = 0; | |
713 | ctrl->profile.manu[4] = 0; | |
714 | ||
715 | capi_ctr_ready(ctrl); | |
716 | ||
717 | DBG_TRC(("adapter added, max_adapter=%d", max_adapter)); | |
718 | return (1); | |
719 | } | |
720 | ||
721 | /* | |
722 | * register appl | |
723 | */ | |
724 | static void diva_register_appl(struct capi_ctr *ctrl, __u16 appl, | |
475be4d8 | 725 | capi_register_params *rp) |
1da177e4 LT |
726 | { |
727 | APPL *this; | |
728 | word bnum, xnum; | |
729 | int i = 0; | |
730 | unsigned char *p; | |
731 | void *DataNCCI, *DataFlags, *ReceiveBuffer, *xbuffer_used; | |
732 | void **xbuffer_ptr, **xbuffer_internal; | |
733 | diva_os_spin_lock_magic_t old_irql; | |
734 | unsigned int mem_len; | |
735 | int nconn = rp->level3cnt; | |
736 | ||
737 | ||
738 | if (diva_os_in_irq()) { | |
739 | DBG_ERR(("CAPI_REGISTER - in irq context !")) | |
475be4d8 | 740 | return; |
1da177e4 LT |
741 | } |
742 | ||
743 | DBG_TRC(("application register Id=%d", appl)) | |
744 | ||
475be4d8 JP |
745 | if (appl > MAX_APPL) { |
746 | DBG_ERR(("CAPI_REGISTER - appl.Id exceeds MAX_APPL")) | |
747 | return; | |
748 | } | |
1da177e4 LT |
749 | |
750 | if (nconn <= 0) | |
751 | nconn = ctrl->profile.nbchannel * -nconn; | |
752 | ||
475be4d8 | 753 | if (nconn == 0) |
1da177e4 LT |
754 | nconn = ctrl->profile.nbchannel; |
755 | ||
756 | DBG_LOG(("CAPI_REGISTER - Id = %d", appl)) | |
475be4d8 JP |
757 | DBG_LOG((" MaxLogicalConnections = %d(%d)", nconn, rp->level3cnt)) |
758 | DBG_LOG((" MaxBDataBuffers = %d", rp->datablkcnt)) | |
759 | DBG_LOG((" MaxBDataLength = %d", rp->datablklen)) | |
760 | ||
761 | if (nconn < 1 || | |
762 | nconn > 255 || | |
763 | rp->datablklen < 80 || | |
764 | rp->datablklen > 2150 || rp->datablkcnt > 255) { | |
765 | DBG_ERR(("CAPI_REGISTER - invalid parameters")) | |
766 | return; | |
767 | } | |
1da177e4 LT |
768 | |
769 | if (application[appl - 1].Id == appl) { | |
770 | DBG_LOG(("CAPI_REGISTER - appl already registered")) | |
475be4d8 | 771 | return; /* appl already registered */ |
1da177e4 LT |
772 | } |
773 | ||
774 | /* alloc memory */ | |
775 | ||
776 | bnum = nconn * rp->datablkcnt; | |
777 | xnum = nconn * MAX_DATA_B3; | |
778 | ||
779 | mem_len = bnum * sizeof(word); /* DataNCCI */ | |
780 | mem_len += bnum * sizeof(word); /* DataFlags */ | |
781 | mem_len += bnum * rp->datablklen; /* ReceiveBuffer */ | |
782 | mem_len += xnum; /* xbuffer_used */ | |
783 | mem_len += xnum * sizeof(void *); /* xbuffer_ptr */ | |
784 | mem_len += xnum * sizeof(void *); /* xbuffer_internal */ | |
785 | mem_len += xnum * rp->datablklen; /* xbuffer_ptr[xnum] */ | |
786 | ||
787 | DBG_LOG((" Allocated Memory = %d", mem_len)) | |
475be4d8 JP |
788 | if (!(p = diva_os_malloc(0, mem_len))) { |
789 | DBG_ERR(("CAPI_REGISTER - memory allocation failed")) | |
790 | return; | |
791 | } | |
1da177e4 LT |
792 | memset(p, 0, mem_len); |
793 | ||
794 | DataNCCI = (void *)p; | |
795 | p += bnum * sizeof(word); | |
796 | DataFlags = (void *)p; | |
797 | p += bnum * sizeof(word); | |
798 | ReceiveBuffer = (void *)p; | |
799 | p += bnum * rp->datablklen; | |
800 | xbuffer_used = (void *)p; | |
801 | p += xnum; | |
802 | xbuffer_ptr = (void **)p; | |
803 | p += xnum * sizeof(void *); | |
804 | xbuffer_internal = (void **)p; | |
805 | p += xnum * sizeof(void *); | |
806 | for (i = 0; i < xnum; i++) { | |
807 | xbuffer_ptr[i] = (void *)p; | |
808 | p += rp->datablklen; | |
809 | } | |
810 | ||
811 | /* initialize application data */ | |
812 | diva_os_enter_spin_lock(&api_lock, &old_irql, "register_appl"); | |
813 | ||
814 | this = &application[appl - 1]; | |
815 | memset(this, 0, sizeof(APPL)); | |
816 | ||
817 | this->Id = appl; | |
818 | ||
819 | for (i = 0; i < max_adapter; i++) { | |
820 | adapter[i].CIP_Mask[appl - 1] = 0; | |
821 | } | |
822 | ||
823 | this->queue_size = 1000; | |
824 | ||
825 | this->MaxNCCI = (byte) nconn; | |
826 | this->MaxNCCIData = (byte) rp->datablkcnt; | |
827 | this->MaxBuffer = bnum; | |
828 | this->MaxDataLength = rp->datablklen; | |
829 | ||
830 | this->DataNCCI = DataNCCI; | |
831 | this->DataFlags = DataFlags; | |
832 | this->ReceiveBuffer = ReceiveBuffer; | |
833 | this->xbuffer_used = xbuffer_used; | |
834 | this->xbuffer_ptr = xbuffer_ptr; | |
835 | this->xbuffer_internal = xbuffer_internal; | |
836 | for (i = 0; i < xnum; i++) { | |
837 | this->xbuffer_ptr[i] = xbuffer_ptr[i]; | |
838 | } | |
839 | ||
840 | CapiRegister(this->Id); | |
841 | diva_os_leave_spin_lock(&api_lock, &old_irql, "register_appl"); | |
842 | ||
843 | } | |
844 | ||
845 | /* | |
846 | * release appl | |
847 | */ | |
848 | static void diva_release_appl(struct capi_ctr *ctrl, __u16 appl) | |
849 | { | |
850 | diva_os_spin_lock_magic_t old_irql; | |
851 | APPL *this = &application[appl - 1]; | |
852 | void *mem_to_free = NULL; | |
853 | ||
854 | DBG_TRC(("application %d(%d) cleanup", this->Id, appl)) | |
855 | ||
475be4d8 JP |
856 | if (diva_os_in_irq()) { |
857 | DBG_ERR(("CAPI_RELEASE - in irq context !")) | |
858 | return; | |
859 | } | |
1da177e4 LT |
860 | |
861 | diva_os_enter_spin_lock(&api_lock, &old_irql, "release_appl"); | |
862 | if (this->Id) { | |
863 | CapiRelease(this->Id); | |
864 | mem_to_free = this->DataNCCI; | |
865 | this->DataNCCI = NULL; | |
866 | this->Id = 0; | |
867 | } | |
868 | diva_os_leave_spin_lock(&api_lock, &old_irql, "release_appl"); | |
869 | ||
870 | if (mem_to_free) | |
871 | diva_os_free(0, mem_to_free); | |
872 | ||
873 | } | |
874 | ||
875 | /* | |
876 | * send message | |
877 | */ | |
878 | static u16 diva_send_message(struct capi_ctr *ctrl, | |
475be4d8 | 879 | diva_os_message_buffer_s *dmb) |
1da177e4 LT |
880 | { |
881 | int i = 0; | |
882 | word ret = 0; | |
883 | diva_os_spin_lock_magic_t old_irql; | |
884 | CAPI_MSG *msg = (CAPI_MSG *) DIVA_MESSAGE_BUFFER_DATA(dmb); | |
885 | APPL *this = &application[GET_WORD(&msg->header.appl_id) - 1]; | |
886 | diva_card *card = ctrl->driverdata; | |
887 | __u32 length = DIVA_MESSAGE_BUFFER_LEN(dmb); | |
888 | word clength = GET_WORD(&msg->header.length); | |
889 | word command = GET_WORD(&msg->header.command); | |
890 | u16 retval = CAPI_NOERROR; | |
891 | ||
892 | if (diva_os_in_irq()) { | |
893 | DBG_ERR(("CAPI_SEND_MSG - in irq context !")) | |
475be4d8 | 894 | return CAPI_REGOSRESOURCEERR; |
1da177e4 LT |
895 | } |
896 | DBG_PRV1(("Write - appl = %d, cmd = 0x%x", this->Id, command)) | |
897 | ||
475be4d8 JP |
898 | if (card->remove_in_progress) { |
899 | DBG_ERR(("CAPI_SEND_MSG - remove in progress!")) | |
900 | return CAPI_REGOSRESOURCEERR; | |
901 | } | |
1da177e4 LT |
902 | |
903 | diva_os_enter_spin_lock(&api_lock, &old_irql, "send message"); | |
904 | ||
905 | if (!this->Id) { | |
906 | diva_os_leave_spin_lock(&api_lock, &old_irql, "send message"); | |
907 | return CAPI_ILLAPPNR; | |
908 | } | |
909 | ||
910 | /* patch controller number */ | |
911 | msg->header.controller = ControllerMap[card->Id] | |
475be4d8 | 912 | | (msg->header.controller & 0x80); /* preserve external controller bit */ |
1da177e4 LT |
913 | |
914 | switch (command) { | |
915 | default: | |
916 | xlog("\x00\x02", msg, 0x80, clength); | |
917 | break; | |
918 | ||
919 | case _DATA_B3_I | RESPONSE: | |
920 | #ifndef DIVA_NO_DEBUGLIB | |
921 | if (myDriverDebugHandle.dbgMask & DL_BLK) | |
922 | xlog("\x00\x02", msg, 0x80, clength); | |
923 | #endif | |
924 | break; | |
925 | ||
926 | case _DATA_B3_R: | |
927 | #ifndef DIVA_NO_DEBUGLIB | |
928 | if (myDriverDebugHandle.dbgMask & DL_BLK) | |
929 | xlog("\x00\x02", msg, 0x80, clength); | |
930 | #endif | |
931 | ||
932 | if (clength == 24) | |
933 | clength = 22; /* workaround for PPcom bug */ | |
934 | /* header is always 22 */ | |
935 | if (GET_WORD(&msg->info.data_b3_req.Data_Length) > | |
936 | this->MaxDataLength | |
937 | || GET_WORD(&msg->info.data_b3_req.Data_Length) > | |
938 | (length - clength)) { | |
939 | DBG_ERR(("Write - invalid message size")) | |
475be4d8 | 940 | retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL; |
1da177e4 LT |
941 | goto write_end; |
942 | } | |
943 | ||
944 | for (i = 0; i < (MAX_DATA_B3 * this->MaxNCCI) | |
475be4d8 | 945 | && this->xbuffer_used[i]; i++); |
1da177e4 LT |
946 | if (i == (MAX_DATA_B3 * this->MaxNCCI)) { |
947 | DBG_ERR(("Write - too many data pending")) | |
475be4d8 | 948 | retval = CAPI_SENDQUEUEFULL; |
1da177e4 LT |
949 | goto write_end; |
950 | } | |
951 | msg->info.data_b3_req.Data = i; | |
952 | ||
953 | this->xbuffer_internal[i] = NULL; | |
954 | memcpy(this->xbuffer_ptr[i], &((__u8 *) msg)[clength], | |
955 | GET_WORD(&msg->info.data_b3_req.Data_Length)); | |
956 | ||
957 | #ifndef DIVA_NO_DEBUGLIB | |
958 | if ((myDriverDebugHandle.dbgMask & DL_BLK) | |
959 | && (myDriverDebugHandle.dbgMask & DL_XLOG)) { | |
960 | int j; | |
961 | for (j = 0; j < | |
475be4d8 | 962 | GET_WORD(&msg->info.data_b3_req.Data_Length); |
1da177e4 LT |
963 | j += 256) { |
964 | DBG_BLK((((char *) this->xbuffer_ptr[i]) + j, | |
475be4d8 | 965 | ((GET_WORD(&msg->info.data_b3_req.Data_Length) - j) < |
1da177e4 | 966 | 256) ? (GET_WORD(&msg->info.data_b3_req.Data_Length) - j) : 256)) |
475be4d8 JP |
967 | if (!(myDriverDebugHandle.dbgMask & DL_PRV0)) |
968 | break; /* not more if not explicitly requested */ | |
1da177e4 LT |
969 | } |
970 | } | |
971 | #endif | |
972 | break; | |
973 | } | |
974 | ||
975 | memcpy(mapped_msg, msg, (__u32) clength); | |
976 | mapped_msg->header.controller = MapController(mapped_msg->header.controller); | |
977 | mapped_msg->header.length = clength; | |
978 | mapped_msg->header.command = command; | |
979 | mapped_msg->header.number = GET_WORD(&msg->header.number); | |
980 | ||
981 | ret = api_put(this, mapped_msg); | |
982 | switch (ret) { | |
983 | case 0: | |
984 | break; | |
985 | case _BAD_MSG: | |
986 | DBG_ERR(("Write - bad message")) | |
475be4d8 | 987 | retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL; |
1da177e4 LT |
988 | break; |
989 | case _QUEUE_FULL: | |
990 | DBG_ERR(("Write - queue full")) | |
475be4d8 | 991 | retval = CAPI_SENDQUEUEFULL; |
1da177e4 LT |
992 | break; |
993 | default: | |
994 | DBG_ERR(("Write - api_put returned unknown error")) | |
475be4d8 | 995 | retval = CAPI_UNKNOWNNOTPAR; |
1da177e4 LT |
996 | break; |
997 | } | |
998 | ||
475be4d8 | 999 | write_end: |
1da177e4 LT |
1000 | diva_os_leave_spin_lock(&api_lock, &old_irql, "send message"); |
1001 | if (retval == CAPI_NOERROR) | |
1002 | diva_os_free_message_buffer(dmb); | |
1003 | return retval; | |
1004 | } | |
1005 | ||
1006 | ||
1007 | /* | |
1008 | * cards request function | |
1009 | */ | |
475be4d8 | 1010 | static void DIRequest(ENTITY *e) |
1da177e4 LT |
1011 | { |
1012 | DIVA_CAPI_ADAPTER *a = &(adapter[(byte) e->user[0]]); | |
1013 | diva_card *os_card = (diva_card *) a->os_card; | |
1014 | ||
1015 | if (e->Req && (a->FlowControlIdTable[e->ReqCh] == e->Id)) { | |
1016 | a->FlowControlSkipTable[e->ReqCh] = 1; | |
1017 | } | |
1018 | ||
1019 | (*(os_card->d.request)) (e); | |
1020 | } | |
1021 | ||
1022 | /* | |
1023 | * callback function from didd | |
1024 | */ | |
475be4d8 | 1025 | static void didd_callback(void *context, DESCRIPTOR *adapter, int removal) |
1da177e4 LT |
1026 | { |
1027 | if (adapter->type == IDI_DADAPTER) { | |
1028 | DBG_ERR(("Notification about IDI_DADAPTER change ! Oops.")); | |
1029 | return; | |
1030 | } else if (adapter->type == IDI_DIMAINT) { | |
1031 | if (removal) { | |
1032 | stop_dbg(); | |
1033 | } else { | |
1034 | memcpy(&MAdapter, adapter, sizeof(MAdapter)); | |
1035 | dprintf = (DIVA_DI_PRINTF) MAdapter.request; | |
1036 | DbgRegister("CAPI20", DRIVERRELEASE_CAPI, DBG_DEFAULT); | |
1037 | } | |
1038 | } else if ((adapter->type > 0) && (adapter->type < 16)) { /* IDI Adapter */ | |
1039 | if (removal) { | |
1040 | divacapi_remove_card(adapter); | |
1041 | } else { | |
1042 | diva_add_card(adapter); | |
1043 | } | |
1044 | } | |
1045 | return; | |
1046 | } | |
1047 | ||
1048 | /* | |
1049 | * connect to didd | |
1050 | */ | |
1051 | static int divacapi_connect_didd(void) | |
1052 | { | |
1053 | int x = 0; | |
1054 | int dadapter = 0; | |
1055 | IDI_SYNC_REQ req; | |
1056 | DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS]; | |
1057 | ||
1058 | DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table)); | |
1059 | ||
1060 | for (x = 0; x < MAX_DESCRIPTORS; x++) { | |
1061 | if (DIDD_Table[x].type == IDI_DIMAINT) { /* MAINT found */ | |
1062 | memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter)); | |
1063 | dprintf = (DIVA_DI_PRINTF) MAdapter.request; | |
1064 | DbgRegister("CAPI20", DRIVERRELEASE_CAPI, DBG_DEFAULT); | |
1065 | break; | |
1066 | } | |
1067 | } | |
1068 | for (x = 0; x < MAX_DESCRIPTORS; x++) { | |
1069 | if (DIDD_Table[x].type == IDI_DADAPTER) { /* DADAPTER found */ | |
1070 | dadapter = 1; | |
1071 | memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter)); | |
1072 | req.didd_notify.e.Req = 0; | |
1073 | req.didd_notify.e.Rc = | |
475be4d8 | 1074 | IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY; |
1da177e4 LT |
1075 | req.didd_notify.info.callback = (void *)didd_callback; |
1076 | req.didd_notify.info.context = NULL; | |
475be4d8 | 1077 | DAdapter.request((ENTITY *)&req); |
1da177e4 LT |
1078 | if (req.didd_notify.e.Rc != 0xff) { |
1079 | stop_dbg(); | |
1080 | return (0); | |
1081 | } | |
1082 | notify_handle = req.didd_notify.info.handle; | |
1083 | } | |
475be4d8 | 1084 | else if ((DIDD_Table[x].type > 0) && (DIDD_Table[x].type < 16)) { /* IDI Adapter found */ |
1da177e4 LT |
1085 | diva_add_card(&DIDD_Table[x]); |
1086 | } | |
1087 | } | |
1088 | ||
1089 | if (!dadapter) { | |
1090 | stop_dbg(); | |
1091 | } | |
1092 | ||
1093 | return (dadapter); | |
1094 | } | |
1095 | ||
1096 | /* | |
1097 | * diconnect from didd | |
1098 | */ | |
1099 | static void divacapi_disconnect_didd(void) | |
1100 | { | |
1101 | IDI_SYNC_REQ req; | |
1102 | ||
1103 | stop_dbg(); | |
1104 | ||
1105 | req.didd_notify.e.Req = 0; | |
1106 | req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY; | |
1107 | req.didd_notify.info.handle = notify_handle; | |
475be4d8 | 1108 | DAdapter.request((ENTITY *)&req); |
1da177e4 LT |
1109 | } |
1110 | ||
1111 | /* | |
1112 | * we do not provide date/time here, | |
475be4d8 | 1113 | * the application should do this. |
1da177e4 LT |
1114 | */ |
1115 | int fax_head_line_time(char *buffer) | |
1116 | { | |
1117 | return (0); | |
1118 | } | |
1119 | ||
1120 | /* | |
1121 | * init (alloc) main structures | |
1122 | */ | |
1123 | static int DIVA_INIT_FUNCTION init_main_structs(void) | |
1124 | { | |
1125 | if (!(mapped_msg = (CAPI_MSG *) diva_os_malloc(0, MAX_MSG_SIZE))) { | |
1126 | DBG_ERR(("init: failed alloc mapped_msg.")) | |
475be4d8 | 1127 | return 0; |
1da177e4 LT |
1128 | } |
1129 | ||
1130 | if (!(adapter = diva_os_malloc(0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS))) { | |
1131 | DBG_ERR(("init: failed alloc adapter struct.")) | |
475be4d8 | 1132 | diva_os_free(0, mapped_msg); |
1da177e4 LT |
1133 | return 0; |
1134 | } | |
1135 | memset(adapter, 0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS); | |
1136 | ||
1137 | if (!(application = diva_os_malloc(0, sizeof(APPL) * MAX_APPL))) { | |
1138 | DBG_ERR(("init: failed alloc application struct.")) | |
475be4d8 | 1139 | diva_os_free(0, mapped_msg); |
1da177e4 LT |
1140 | diva_os_free(0, adapter); |
1141 | return 0; | |
1142 | } | |
1143 | memset(application, 0, sizeof(APPL) * MAX_APPL); | |
1144 | ||
1145 | return (1); | |
1146 | } | |
1147 | ||
1148 | /* | |
1149 | * remove (free) main structures | |
1150 | */ | |
1151 | static void remove_main_structs(void) | |
1152 | { | |
1153 | if (application) | |
1154 | diva_os_free(0, application); | |
1155 | if (adapter) | |
1156 | diva_os_free(0, adapter); | |
1157 | if (mapped_msg) | |
1158 | diva_os_free(0, mapped_msg); | |
1159 | } | |
1160 | ||
1161 | /* | |
1162 | * api_remove_start | |
1163 | */ | |
1164 | static void do_api_remove_start(void) | |
1165 | { | |
1166 | diva_os_spin_lock_magic_t old_irql; | |
1167 | int ret = 1, count = 100; | |
1168 | ||
1169 | do { | |
1170 | diva_os_enter_spin_lock(&api_lock, &old_irql, "api remove start"); | |
1171 | ret = api_remove_start(); | |
1172 | diva_os_leave_spin_lock(&api_lock, &old_irql, "api remove start"); | |
1173 | ||
1174 | diva_os_sleep(10); | |
1175 | } while (ret && count--); | |
1176 | ||
1177 | if (ret) | |
1178 | DBG_ERR(("could not remove signaling ID's")) | |
475be4d8 | 1179 | } |
1da177e4 LT |
1180 | |
1181 | /* | |
1182 | * init | |
1183 | */ | |
1184 | int DIVA_INIT_FUNCTION init_capifunc(void) | |
1185 | { | |
1186 | diva_os_initialize_spin_lock(&api_lock, "capifunc"); | |
1187 | memset(ControllerMap, 0, MAX_DESCRIPTORS + 1); | |
1188 | max_adapter = 0; | |
1189 | ||
1190 | ||
1191 | if (!init_main_structs()) { | |
1192 | DBG_ERR(("init: failed to init main structs.")) | |
475be4d8 | 1193 | diva_os_destroy_spin_lock(&api_lock, "capifunc"); |
1da177e4 LT |
1194 | return (0); |
1195 | } | |
1196 | ||
1197 | if (!divacapi_connect_didd()) { | |
1198 | DBG_ERR(("init: failed to connect to DIDD.")) | |
475be4d8 | 1199 | do_api_remove_start(); |
1da177e4 LT |
1200 | divacapi_remove_cards(); |
1201 | remove_main_structs(); | |
1202 | diva_os_destroy_spin_lock(&api_lock, "capifunc"); | |
1203 | return (0); | |
1204 | } | |
1205 | ||
1206 | return (1); | |
1207 | } | |
1208 | ||
1209 | /* | |
1210 | * finit | |
1211 | */ | |
1212 | void DIVA_EXIT_FUNCTION finit_capifunc(void) | |
1213 | { | |
1214 | do_api_remove_start(); | |
1215 | divacapi_disconnect_didd(); | |
1216 | divacapi_remove_cards(); | |
1217 | remove_main_structs(); | |
1218 | diva_os_destroy_spin_lock(&api_lock, "capifunc"); | |
1219 | } |