Linux 4.19.133
[linux/fpc-iii.git] / drivers / isdn / hardware / eicon / diva.c
blob1b25d8bc153aec16ea8e9ee0cd47de0604a2a393
1 // SPDX-License-Identifier: GPL-2.0
2 /* $Id: diva.c,v 1.21.4.1 2004/05/08 14:33:43 armin Exp $ */
4 #define CARDTYPE_H_WANT_DATA 1
5 #define CARDTYPE_H_WANT_IDI_DATA 0
6 #define CARDTYPE_H_WANT_RESOURCE_DATA 0
7 #define CARDTYPE_H_WANT_FILE_DATA 0
9 #include "platform.h"
10 #include "debuglib.h"
11 #include "cardtype.h"
12 #include "pc.h"
13 #include "di_defs.h"
14 #include "di.h"
15 #include "io.h"
16 #include "pc_maint.h"
17 #include "xdi_msg.h"
18 #include "xdi_adapter.h"
19 #include "diva_pci.h"
20 #include "diva.h"
22 #ifdef CONFIG_ISDN_DIVAS_PRIPCI
23 #include "os_pri.h"
24 #endif
25 #ifdef CONFIG_ISDN_DIVAS_BRIPCI
26 #include "os_bri.h"
27 #include "os_4bri.h"
28 #endif
30 PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
31 extern IDI_CALL Requests[MAX_ADAPTER];
32 extern int create_adapter_proc(diva_os_xdi_adapter_t *a);
33 extern void remove_adapter_proc(diva_os_xdi_adapter_t *a);
35 #define DivaIdiReqFunc(N) \
36 static void DivaIdiRequest##N(ENTITY *e) \
37 { if (IoAdapters[N]) (*IoAdapters[N]->DIRequest)(IoAdapters[N], e); }
40 ** Create own 32 Adapters
42 DivaIdiReqFunc(0)
43 DivaIdiReqFunc(1)
44 DivaIdiReqFunc(2)
45 DivaIdiReqFunc(3)
46 DivaIdiReqFunc(4)
47 DivaIdiReqFunc(5)
48 DivaIdiReqFunc(6)
49 DivaIdiReqFunc(7)
50 DivaIdiReqFunc(8)
51 DivaIdiReqFunc(9)
52 DivaIdiReqFunc(10)
53 DivaIdiReqFunc(11)
54 DivaIdiReqFunc(12)
55 DivaIdiReqFunc(13)
56 DivaIdiReqFunc(14)
57 DivaIdiReqFunc(15)
58 DivaIdiReqFunc(16)
59 DivaIdiReqFunc(17)
60 DivaIdiReqFunc(18)
61 DivaIdiReqFunc(19)
62 DivaIdiReqFunc(20)
63 DivaIdiReqFunc(21)
64 DivaIdiReqFunc(22)
65 DivaIdiReqFunc(23)
66 DivaIdiReqFunc(24)
67 DivaIdiReqFunc(25)
68 DivaIdiReqFunc(26)
69 DivaIdiReqFunc(27)
70 DivaIdiReqFunc(28)
71 DivaIdiReqFunc(29)
72 DivaIdiReqFunc(30)
73 DivaIdiReqFunc(31)
76 ** LOCALS
78 static LIST_HEAD(adapter_queue);
80 typedef struct _diva_get_xlog {
81 word command;
82 byte req;
83 byte rc;
84 byte data[sizeof(struct mi_pc_maint)];
85 } diva_get_xlog_t;
87 typedef struct _diva_supported_cards_info {
88 int CardOrdinal;
89 diva_init_card_proc_t init_card;
90 } diva_supported_cards_info_t;
92 static diva_supported_cards_info_t divas_supported_cards[] = {
93 #ifdef CONFIG_ISDN_DIVAS_PRIPCI
95 PRI Cards
97 {CARDTYPE_DIVASRV_P_30M_PCI, diva_pri_init_card},
99 PRI Rev.2 Cards
101 {CARDTYPE_DIVASRV_P_30M_V2_PCI, diva_pri_init_card},
103 PRI Rev.2 VoIP Cards
105 {CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI, diva_pri_init_card},
106 #endif
107 #ifdef CONFIG_ISDN_DIVAS_BRIPCI
109 4BRI Rev 1 Cards
111 {CARDTYPE_DIVASRV_Q_8M_PCI, diva_4bri_init_card},
112 {CARDTYPE_DIVASRV_VOICE_Q_8M_PCI, diva_4bri_init_card},
114 4BRI Rev 2 Cards
116 {CARDTYPE_DIVASRV_Q_8M_V2_PCI, diva_4bri_init_card},
117 {CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI, diva_4bri_init_card},
119 4BRI Based BRI Rev 2 Cards
121 {CARDTYPE_DIVASRV_B_2M_V2_PCI, diva_4bri_init_card},
122 {CARDTYPE_DIVASRV_B_2F_PCI, diva_4bri_init_card},
123 {CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI, diva_4bri_init_card},
127 {CARDTYPE_MAESTRA_PCI, diva_bri_init_card},
128 #endif
133 {-1}
136 static void diva_init_request_array(void);
137 static void *divas_create_pci_card(int handle, void *pci_dev_handle);
139 static diva_os_spin_lock_t adapter_lock;
141 static int diva_find_free_adapters(int base, int nr)
143 int i;
145 for (i = 0; i < nr; i++) {
146 if (IoAdapters[base + i]) {
147 return (-1);
151 return (0);
154 static diva_os_xdi_adapter_t *diva_q_get_next(struct list_head *what)
156 diva_os_xdi_adapter_t *a = NULL;
158 if (what && (what->next != &adapter_queue))
159 a = list_entry(what->next, diva_os_xdi_adapter_t, link);
161 return (a);
164 /* --------------------------------------------------------------------------
165 Add card to the card list
166 -------------------------------------------------------------------------- */
167 void *diva_driver_add_card(void *pdev, unsigned long CardOrdinal)
169 diva_os_spin_lock_magic_t old_irql;
170 diva_os_xdi_adapter_t *pdiva, *pa;
171 int i, j, max, nr;
173 for (i = 0; divas_supported_cards[i].CardOrdinal != -1; i++) {
174 if (divas_supported_cards[i].CardOrdinal == CardOrdinal) {
175 if (!(pdiva = divas_create_pci_card(i, pdev))) {
176 return NULL;
178 switch (CardOrdinal) {
179 case CARDTYPE_DIVASRV_Q_8M_PCI:
180 case CARDTYPE_DIVASRV_VOICE_Q_8M_PCI:
181 case CARDTYPE_DIVASRV_Q_8M_V2_PCI:
182 case CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI:
183 max = MAX_ADAPTER - 4;
184 nr = 4;
185 break;
187 default:
188 max = MAX_ADAPTER;
189 nr = 1;
192 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
194 for (i = 0; i < max; i++) {
195 if (!diva_find_free_adapters(i, nr)) {
196 pdiva->controller = i + 1;
197 pdiva->xdi_adapter.ANum = pdiva->controller;
198 IoAdapters[i] = &pdiva->xdi_adapter;
199 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
200 create_adapter_proc(pdiva); /* add adapter to proc file system */
202 DBG_LOG(("add %s:%d",
203 CardProperties
204 [CardOrdinal].Name,
205 pdiva->controller))
207 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
208 pa = pdiva;
209 for (j = 1; j < nr; j++) { /* slave adapters, if any */
210 pa = diva_q_get_next(&pa->link);
211 if (pa && !pa->interface.cleanup_adapter_proc) {
212 pa->controller = i + 1 + j;
213 pa->xdi_adapter.ANum = pa->controller;
214 IoAdapters[i + j] = &pa->xdi_adapter;
215 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
216 DBG_LOG(("add slave adapter (%d)",
217 pa->controller))
218 create_adapter_proc(pa); /* add adapter to proc file system */
219 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
220 } else {
221 DBG_ERR(("slave adapter problem"))
222 break;
226 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
227 return (pdiva);
231 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
234 Not able to add adapter - remove it and return error
236 DBG_ERR(("can not alloc request array"))
237 diva_driver_remove_card(pdiva);
239 return NULL;
243 return NULL;
246 /* --------------------------------------------------------------------------
247 Called on driver load, MAIN, main, DriverEntry
248 -------------------------------------------------------------------------- */
249 int divasa_xdi_driver_entry(void)
251 diva_os_initialize_spin_lock(&adapter_lock, "adapter");
252 memset(&IoAdapters[0], 0x00, sizeof(IoAdapters));
253 diva_init_request_array();
255 return (0);
258 /* --------------------------------------------------------------------------
259 Remove adapter from list
260 -------------------------------------------------------------------------- */
261 static diva_os_xdi_adapter_t *get_and_remove_from_queue(void)
263 diva_os_spin_lock_magic_t old_irql;
264 diva_os_xdi_adapter_t *a = NULL;
266 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "driver_unload");
268 if (!list_empty(&adapter_queue)) {
269 a = list_entry(adapter_queue.next, diva_os_xdi_adapter_t, link);
270 list_del(adapter_queue.next);
273 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
274 return (a);
277 /* --------------------------------------------------------------------------
278 Remove card from the card list
279 -------------------------------------------------------------------------- */
280 void diva_driver_remove_card(void *pdiva)
282 diva_os_spin_lock_magic_t old_irql;
283 diva_os_xdi_adapter_t *a[4];
284 diva_os_xdi_adapter_t *pa;
285 int i;
287 pa = a[0] = (diva_os_xdi_adapter_t *) pdiva;
288 a[1] = a[2] = a[3] = NULL;
290 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "remode adapter");
292 for (i = 1; i < 4; i++) {
293 if ((pa = diva_q_get_next(&pa->link))
294 && !pa->interface.cleanup_adapter_proc) {
295 a[i] = pa;
296 } else {
297 break;
301 for (i = 0; ((i < 4) && a[i]); i++) {
302 list_del(&a[i]->link);
305 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
307 (*(a[0]->interface.cleanup_adapter_proc)) (a[0]);
309 for (i = 0; i < 4; i++) {
310 if (a[i]) {
311 if (a[i]->controller) {
312 DBG_LOG(("remove adapter (%d)",
313 a[i]->controller)) IoAdapters[a[i]->controller - 1] = NULL;
314 remove_adapter_proc(a[i]);
316 diva_os_free(0, a[i]);
321 /* --------------------------------------------------------------------------
322 Create diva PCI adapter and init internal adapter structures
323 -------------------------------------------------------------------------- */
324 static void *divas_create_pci_card(int handle, void *pci_dev_handle)
326 diva_supported_cards_info_t *pI = &divas_supported_cards[handle];
327 diva_os_spin_lock_magic_t old_irql;
328 diva_os_xdi_adapter_t *a;
330 DBG_LOG(("found %d-%s", pI->CardOrdinal, CardProperties[pI->CardOrdinal].Name))
332 if (!(a = (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a)))) {
333 DBG_ERR(("A: can't alloc adapter"));
334 return NULL;
337 memset(a, 0x00, sizeof(*a));
339 a->CardIndex = handle;
340 a->CardOrdinal = pI->CardOrdinal;
341 a->Bus = DIVAS_XDI_ADAPTER_BUS_PCI;
342 a->xdi_adapter.cardType = a->CardOrdinal;
343 a->resources.pci.bus = diva_os_get_pci_bus(pci_dev_handle);
344 a->resources.pci.func = diva_os_get_pci_func(pci_dev_handle);
345 a->resources.pci.hdev = pci_dev_handle;
348 Add master adapter first, so slave adapters will receive higher
349 numbers as master adapter
351 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
352 list_add_tail(&a->link, &adapter_queue);
353 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
355 if ((*(pI->init_card)) (a)) {
356 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
357 list_del(&a->link);
358 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
359 diva_os_free(0, a);
360 DBG_ERR(("A: can't get adapter resources"));
361 return NULL;
364 return (a);
367 /* --------------------------------------------------------------------------
368 Called on driver unload FINIT, finit, Unload
369 -------------------------------------------------------------------------- */
370 void divasa_xdi_driver_unload(void)
372 diva_os_xdi_adapter_t *a;
374 while ((a = get_and_remove_from_queue())) {
375 if (a->interface.cleanup_adapter_proc) {
376 (*(a->interface.cleanup_adapter_proc)) (a);
378 if (a->controller) {
379 IoAdapters[a->controller - 1] = NULL;
380 remove_adapter_proc(a);
382 diva_os_free(0, a);
384 diva_os_destroy_spin_lock(&adapter_lock, "adapter");
388 ** Receive and process command from user mode utility
390 void *diva_xdi_open_adapter(void *os_handle, const void __user *src,
391 int length, void *mptr,
392 divas_xdi_copy_from_user_fn_t cp_fn)
394 diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr;
395 diva_os_xdi_adapter_t *a = NULL;
396 diva_os_spin_lock_magic_t old_irql;
397 struct list_head *tmp;
399 if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
400 DBG_ERR(("A: A(?) open, msg too small (%d < %d)",
401 length, sizeof(diva_xdi_um_cfg_cmd_t)))
402 return NULL;
404 if ((*cp_fn) (os_handle, msg, src, sizeof(*msg)) <= 0) {
405 DBG_ERR(("A: A(?) open, write error"))
406 return NULL;
408 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter");
409 list_for_each(tmp, &adapter_queue) {
410 a = list_entry(tmp, diva_os_xdi_adapter_t, link);
411 if (a->controller == (int)msg->adapter)
412 break;
413 a = NULL;
415 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter");
417 if (!a) {
418 DBG_ERR(("A: A(%d) open, adapter not found", msg->adapter))
421 return (a);
425 ** Easy cleanup mailbox status
427 void diva_xdi_close_adapter(void *adapter, void *os_handle)
429 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
431 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
432 if (a->xdi_mbox.data) {
433 diva_os_free(0, a->xdi_mbox.data);
434 a->xdi_mbox.data = NULL;
439 diva_xdi_write(void *adapter, void *os_handle, const void __user *src,
440 int length, void *mptr,
441 divas_xdi_copy_from_user_fn_t cp_fn)
443 diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr;
444 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
445 void *data;
447 if (a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY) {
448 DBG_ERR(("A: A(%d) write, mbox busy", a->controller))
449 return (-1);
452 if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
453 DBG_ERR(("A: A(%d) write, message too small (%d < %d)",
454 a->controller, length,
455 sizeof(diva_xdi_um_cfg_cmd_t)))
456 return (-3);
459 if (!(data = diva_os_malloc(0, length))) {
460 DBG_ERR(("A: A(%d) write, ENOMEM", a->controller))
461 return (-2);
464 if (msg) {
465 *(diva_xdi_um_cfg_cmd_t *)data = *msg;
466 length = (*cp_fn) (os_handle, (char *)data + sizeof(*msg),
467 src + sizeof(*msg), length - sizeof(*msg));
468 } else {
469 length = (*cp_fn) (os_handle, data, src, length);
471 if (length > 0) {
472 if ((*(a->interface.cmd_proc))
473 (a, (diva_xdi_um_cfg_cmd_t *) data, length)) {
474 length = -3;
476 } else {
477 DBG_ERR(("A: A(%d) write error (%d)", a->controller,
478 length))
481 diva_os_free(0, data);
483 return (length);
487 ** Write answers to user mode utility, if any
490 diva_xdi_read(void *adapter, void *os_handle, void __user *dst,
491 int max_length, divas_xdi_copy_to_user_fn_t cp_fn)
493 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
494 int ret;
496 if (!(a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY)) {
497 DBG_ERR(("A: A(%d) rx mbox empty", a->controller))
498 return (-1);
500 if (!a->xdi_mbox.data) {
501 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
502 DBG_ERR(("A: A(%d) rx ENOMEM", a->controller))
503 return (-2);
506 if (max_length < a->xdi_mbox.data_length) {
507 DBG_ERR(("A: A(%d) rx buffer too short(%d < %d)",
508 a->controller, max_length,
509 a->xdi_mbox.data_length))
510 return (-3);
513 ret = (*cp_fn) (os_handle, dst, a->xdi_mbox.data,
514 a->xdi_mbox.data_length);
515 if (ret > 0) {
516 diva_os_free(0, a->xdi_mbox.data);
517 a->xdi_mbox.data = NULL;
518 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
521 return (ret);
525 irqreturn_t diva_os_irq_wrapper(int irq, void *context)
527 diva_os_xdi_adapter_t *a = context;
528 diva_xdi_clear_interrupts_proc_t clear_int_proc;
530 if (!a || !a->xdi_adapter.diva_isr_handler)
531 return IRQ_NONE;
533 if ((clear_int_proc = a->clear_interrupts_proc)) {
534 (*clear_int_proc) (a);
535 a->clear_interrupts_proc = NULL;
536 return IRQ_HANDLED;
539 (*(a->xdi_adapter.diva_isr_handler)) (&a->xdi_adapter);
540 return IRQ_HANDLED;
543 static void diva_init_request_array(void)
545 Requests[0] = DivaIdiRequest0;
546 Requests[1] = DivaIdiRequest1;
547 Requests[2] = DivaIdiRequest2;
548 Requests[3] = DivaIdiRequest3;
549 Requests[4] = DivaIdiRequest4;
550 Requests[5] = DivaIdiRequest5;
551 Requests[6] = DivaIdiRequest6;
552 Requests[7] = DivaIdiRequest7;
553 Requests[8] = DivaIdiRequest8;
554 Requests[9] = DivaIdiRequest9;
555 Requests[10] = DivaIdiRequest10;
556 Requests[11] = DivaIdiRequest11;
557 Requests[12] = DivaIdiRequest12;
558 Requests[13] = DivaIdiRequest13;
559 Requests[14] = DivaIdiRequest14;
560 Requests[15] = DivaIdiRequest15;
561 Requests[16] = DivaIdiRequest16;
562 Requests[17] = DivaIdiRequest17;
563 Requests[18] = DivaIdiRequest18;
564 Requests[19] = DivaIdiRequest19;
565 Requests[20] = DivaIdiRequest20;
566 Requests[21] = DivaIdiRequest21;
567 Requests[22] = DivaIdiRequest22;
568 Requests[23] = DivaIdiRequest23;
569 Requests[24] = DivaIdiRequest24;
570 Requests[25] = DivaIdiRequest25;
571 Requests[26] = DivaIdiRequest26;
572 Requests[27] = DivaIdiRequest27;
573 Requests[28] = DivaIdiRequest28;
574 Requests[29] = DivaIdiRequest29;
575 Requests[30] = DivaIdiRequest30;
576 Requests[31] = DivaIdiRequest31;
579 void diva_xdi_display_adapter_features(int card)
581 dword features;
582 if (!card || ((card - 1) >= MAX_ADAPTER) || !IoAdapters[card - 1]) {
583 return;
585 card--;
586 features = IoAdapters[card]->Properties.Features;
588 DBG_LOG(("FEATURES FOR ADAPTER: %d", card + 1))
589 DBG_LOG((" DI_FAX3 : %s",
590 (features & DI_FAX3) ? "Y" : "N"))
591 DBG_LOG((" DI_MODEM : %s",
592 (features & DI_MODEM) ? "Y" : "N"))
593 DBG_LOG((" DI_POST : %s",
594 (features & DI_POST) ? "Y" : "N"))
595 DBG_LOG((" DI_V110 : %s",
596 (features & DI_V110) ? "Y" : "N"))
597 DBG_LOG((" DI_V120 : %s",
598 (features & DI_V120) ? "Y" : "N"))
599 DBG_LOG((" DI_POTS : %s",
600 (features & DI_POTS) ? "Y" : "N"))
601 DBG_LOG((" DI_CODEC : %s",
602 (features & DI_CODEC) ? "Y" : "N"))
603 DBG_LOG((" DI_MANAGE : %s",
604 (features & DI_MANAGE) ? "Y" : "N"))
605 DBG_LOG((" DI_V_42 : %s",
606 (features & DI_V_42) ? "Y" : "N"))
607 DBG_LOG((" DI_EXTD_FAX : %s",
608 (features & DI_EXTD_FAX) ? "Y" : "N"))
609 DBG_LOG((" DI_AT_PARSER : %s",
610 (features & DI_AT_PARSER) ? "Y" : "N"))
611 DBG_LOG((" DI_VOICE_OVER_IP : %s",
612 (features & DI_VOICE_OVER_IP) ? "Y" : "N"))
615 void diva_add_slave_adapter(diva_os_xdi_adapter_t *a)
617 diva_os_spin_lock_magic_t old_irql;
619 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add_slave");
620 list_add_tail(&a->link, &adapter_queue);
621 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add_slave");
624 int diva_card_read_xlog(diva_os_xdi_adapter_t *a)
626 diva_get_xlog_t *req;
627 byte *data;
629 if (!a->xdi_adapter.Initialized || !a->xdi_adapter.DIRequest) {
630 return (-1);
632 if (!(data = diva_os_malloc(0, sizeof(struct mi_pc_maint)))) {
633 return (-1);
635 memset(data, 0x00, sizeof(struct mi_pc_maint));
637 if (!(req = diva_os_malloc(0, sizeof(*req)))) {
638 diva_os_free(0, data);
639 return (-1);
641 req->command = 0x0400;
642 req->req = LOG;
643 req->rc = 0x00;
645 (*(a->xdi_adapter.DIRequest)) (&a->xdi_adapter, (ENTITY *) req);
647 if (!req->rc || req->req) {
648 diva_os_free(0, data);
649 diva_os_free(0, req);
650 return (-1);
653 memcpy(data, &req->req, sizeof(struct mi_pc_maint));
655 diva_os_free(0, req);
657 a->xdi_mbox.data_length = sizeof(struct mi_pc_maint);
658 a->xdi_mbox.data = data;
659 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
661 return (0);
664 void xdiFreeFile(void *handle)