diff options
Diffstat (limited to 'drivers/isdn/hardware/eicon/capifunc.c')
-rw-r--r-- | drivers/isdn/hardware/eicon/capifunc.c | 1219 |
1 files changed, 1219 insertions, 0 deletions
diff --git a/drivers/isdn/hardware/eicon/capifunc.c b/drivers/isdn/hardware/eicon/capifunc.c new file mode 100644 index 000000000000..0afd7633556d --- /dev/null +++ b/drivers/isdn/hardware/eicon/capifunc.c | |||
@@ -0,0 +1,1219 @@ | |||
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 | ||
5 | * | ||
6 | * Copyright 2000-2003 by Armin Schindler (mac@melware.de) | ||
7 | * Copyright 2000-2003 Cytronics & Melware (info@melware.de) | ||
8 | * | ||
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; | ||
46 | static void DIRequest(ENTITY * e); | ||
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 | } | ||
163 | return(num + 1); | ||
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; | ||
179 | return(card); | ||
180 | } | ||
181 | } | ||
182 | return (diva_card *) 0; | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | * Buffer RX/TX | ||
187 | */ | ||
188 | void *TransmitBufferSet(APPL * appl, dword ref) | ||
189 | { | ||
190 | appl->xbuffer_used[ref] = TRUE; | ||
191 | DBG_PRV1(("%d:xbuf_used(%d)", appl->Id, ref + 1)) | ||
192 | return (void *) ref; | ||
193 | } | ||
194 | |||
195 | void *TransmitBufferGet(APPL * appl, void *p) | ||
196 | { | ||
197 | if (appl->xbuffer_internal[(dword) p]) | ||
198 | return appl->xbuffer_internal[(dword) p]; | ||
199 | |||
200 | return appl->xbuffer_ptr[(dword) p]; | ||
201 | } | ||
202 | |||
203 | void TransmitBufferFree(APPL * appl, void *p) | ||
204 | { | ||
205 | appl->xbuffer_used[(dword) p] = FALSE; | ||
206 | DBG_PRV1(("%d:xbuf_free(%d)", appl->Id, ((dword) p) + 1)) | ||
207 | } | ||
208 | |||
209 | void *ReceiveBufferGet(APPL * appl, int Num) | ||
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")) | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * main function called by message.c | ||
224 | */ | ||
225 | void sendf(APPL * appl, word command, dword Id, word Number, byte * format, ...) | ||
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 | |||
243 | PUT_WORD(&msg.header.appl_id, appl->Id); | ||
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); | ||
250 | write = (byte *) & msg; | ||
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( | ||
290 | ((byte *) & msg.info.data_b3_ind.Data_Length)); | ||
291 | |||
292 | if (!(dmb = diva_os_alloc_message_buffer(length + dlength, | ||
293 | (void **) &write))) { | ||
294 | DBG_ERR(("sendf: alloc_message_buffer failed, incoming msg dropped.")) | ||
295 | return; | ||
296 | } | ||
297 | |||
298 | /* copy msg header to sk_buff */ | ||
299 | memcpy(write, (byte *) & msg, length); | ||
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); | ||
304 | memcpy(write + length, (void *) data, dlength); | ||
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) { | ||
321 | DBG_BLK((((char *) 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 explicitely requested */ | ||
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)) | ||
336 | diva_os_free_message_buffer(dmb); | ||
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 | */ | ||
391 | static void divacapi_remove_card(DESCRIPTOR * d) | ||
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)", | ||
430 | ControllerMap[card->Id], card->Id)) | ||
431 | ControllerMap[card->Id] = 0; | ||
432 | DBG_TRC(("adapter remove, max_adapter=%d", | ||
433 | max_adapter)); | ||
434 | diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card"); | ||
435 | |||
436 | /* After releasing the lock, we can free the memory */ | ||
437 | diva_os_free (0, card); | ||
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 | */ | ||
472 | static void sync_callback(ENTITY * e) | ||
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 | |||
478 | diva_os_enter_spin_lock(&api_lock, &old_irql, "sync_callback"); | ||
479 | callback(e); | ||
480 | diva_os_leave_spin_lock(&api_lock, &old_irql, "sync_callback"); | ||
481 | } | ||
482 | |||
483 | /* | ||
484 | * add a new card | ||
485 | */ | ||
486 | static int diva_add_card(DESCRIPTOR * d) | ||
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]; | ||
495 | void* mem_to_free; | ||
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.")) | ||
501 | return (0); | ||
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; | ||
507 | card->d.request((ENTITY *) & sync_req); | ||
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.")) | ||
520 | diva_os_free(0, card); | ||
521 | return (0); | ||
522 | } | ||
523 | |||
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"); | ||
527 | |||
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; | ||
536 | card->d.request((ENTITY *) & sync_req); | ||
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 | |||
553 | sync_req.xdi_capi_prms.Req = 0; | ||
554 | sync_req.xdi_capi_prms.Rc = IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS; | ||
555 | sync_req.xdi_capi_prms.info.structure_length = | ||
556 | sizeof(diva_xdi_get_capi_parameters_t); | ||
557 | card->d.request((ENTITY *) & sync_req); | ||
558 | a->flag_dynamic_l1_down = | ||
559 | sync_req.xdi_capi_prms.info.flag_dynamic_l1_down; | ||
560 | a->group_optimization_enabled = | ||
561 | sync_req.xdi_capi_prms.info.group_optimization_enabled; | ||
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.")) | ||
569 | memset(a, 0, sizeof(DIVA_CAPI_ADAPTER)); | ||
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.")) | ||
628 | memset(a, 0, sizeof(DIVA_CAPI_ADAPTER)); | ||
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"); | ||
634 | |||
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 + | ||
662 | a->li_channels], | ||
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 + | ||
666 | a->li_channels], | ||
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) { | ||
692 | diva_os_free (0, mem_to_free); | ||
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, | ||
725 | capi_register_params * rp) | ||
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 !")) | ||
740 | return; | ||
741 | } | ||
742 | |||
743 | DBG_TRC(("application register Id=%d", appl)) | ||
744 | |||
745 | if (appl > MAX_APPL) { | ||
746 | DBG_ERR(("CAPI_REGISTER - appl.Id exceeds MAX_APPL")) | ||
747 | return; | ||
748 | } | ||
749 | |||
750 | if (nconn <= 0) | ||
751 | nconn = ctrl->profile.nbchannel * -nconn; | ||
752 | |||
753 | if (nconn == 0) | ||
754 | nconn = ctrl->profile.nbchannel; | ||
755 | |||
756 | DBG_LOG(("CAPI_REGISTER - Id = %d", appl)) | ||
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 | } | ||
768 | |||
769 | if (application[appl - 1].Id == appl) { | ||
770 | DBG_LOG(("CAPI_REGISTER - appl already registered")) | ||
771 | return; /* appl already registered */ | ||
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)) | ||
788 | if (!(p = diva_os_malloc(0, mem_len))) { | ||
789 | DBG_ERR(("CAPI_REGISTER - memory allocation failed")) | ||
790 | return; | ||
791 | } | ||
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 | |||
856 | if (diva_os_in_irq()) { | ||
857 | DBG_ERR(("CAPI_RELEASE - in irq context !")) | ||
858 | return; | ||
859 | } | ||
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, | ||
879 | diva_os_message_buffer_s * dmb) | ||
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 !")) | ||
894 | return CAPI_REGOSRESOURCEERR; | ||
895 | } | ||
896 | DBG_PRV1(("Write - appl = %d, cmd = 0x%x", this->Id, command)) | ||
897 | |||
898 | if (card->remove_in_progress) { | ||
899 | DBG_ERR(("CAPI_SEND_MSG - remove in progress!")) | ||
900 | return CAPI_REGOSRESOURCEERR; | ||
901 | } | ||
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] | ||
912 | | (msg->header.controller & 0x80); /* preserve external controller bit */ | ||
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")) | ||
940 | retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL; | ||
941 | goto write_end; | ||
942 | } | ||
943 | |||
944 | for (i = 0; i < (MAX_DATA_B3 * this->MaxNCCI) | ||
945 | && this->xbuffer_used[i]; i++); | ||
946 | if (i == (MAX_DATA_B3 * this->MaxNCCI)) { | ||
947 | DBG_ERR(("Write - too many data pending")) | ||
948 | retval = CAPI_SENDQUEUEFULL; | ||
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 < | ||
962 | GET_WORD(&msg->info.data_b3_req.Data_Length); | ||
963 | j += 256) { | ||
964 | DBG_BLK((((char *) this->xbuffer_ptr[i]) + j, | ||
965 | ((GET_WORD(&msg->info.data_b3_req.Data_Length) - j) < | ||
966 | 256) ? (GET_WORD(&msg->info.data_b3_req.Data_Length) - j) : 256)) | ||
967 | if (!(myDriverDebugHandle.dbgMask & DL_PRV0)) | ||
968 | break; /* not more if not explicitely requested */ | ||
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")) | ||
987 | retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL; | ||
988 | break; | ||
989 | case _QUEUE_FULL: | ||
990 | DBG_ERR(("Write - queue full")) | ||
991 | retval = CAPI_SENDQUEUEFULL; | ||
992 | break; | ||
993 | default: | ||
994 | DBG_ERR(("Write - api_put returned unknown error")) | ||
995 | retval = CAPI_UNKNOWNNOTPAR; | ||
996 | break; | ||
997 | } | ||
998 | |||
999 | write_end: | ||
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 | */ | ||
1010 | static void DIRequest(ENTITY * e) | ||
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 | */ | ||
1025 | static void didd_callback(void *context, DESCRIPTOR * adapter, int removal) | ||
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 = | ||
1074 | IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY; | ||
1075 | req.didd_notify.info.callback = (void *)didd_callback; | ||
1076 | req.didd_notify.info.context = NULL; | ||
1077 | DAdapter.request((ENTITY *) & req); | ||
1078 | if (req.didd_notify.e.Rc != 0xff) { | ||
1079 | stop_dbg(); | ||
1080 | return (0); | ||
1081 | } | ||
1082 | notify_handle = req.didd_notify.info.handle; | ||
1083 | } | ||
1084 | else if ((DIDD_Table[x].type > 0) && (DIDD_Table[x].type < 16)) { /* IDI Adapter found */ | ||
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; | ||
1108 | DAdapter.request((ENTITY *) & req); | ||
1109 | } | ||
1110 | |||
1111 | /* | ||
1112 | * we do not provide date/time here, | ||
1113 | * the application should do this. | ||
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.")) | ||
1127 | return 0; | ||
1128 | } | ||
1129 | |||
1130 | if (!(adapter = diva_os_malloc(0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS))) { | ||
1131 | DBG_ERR(("init: failed alloc adapter struct.")) | ||
1132 | diva_os_free(0, mapped_msg); | ||
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.")) | ||
1139 | diva_os_free(0, mapped_msg); | ||
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")) | ||
1179 | } | ||
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.")) | ||
1193 | diva_os_destroy_spin_lock(&api_lock, "capifunc"); | ||
1194 | return (0); | ||
1195 | } | ||
1196 | |||
1197 | if (!divacapi_connect_didd()) { | ||
1198 | DBG_ERR(("init: failed to connect to DIDD.")) | ||
1199 | do_api_remove_start(); | ||
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 | } | ||