Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[cris-mirror.git] / drivers / isdn / hardware / eicon / diva.c
blob944a7f3380991d107b0a3f50a9dfd100ba0719a8
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,
392 divas_xdi_copy_from_user_fn_t cp_fn)
394 diva_xdi_um_cfg_cmd_t msg;
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, divas_xdi_copy_from_user_fn_t cp_fn)
442 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
443 void *data;
445 if (a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY) {
446 DBG_ERR(("A: A(%d) write, mbox busy", a->controller))
447 return (-1);
450 if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
451 DBG_ERR(("A: A(%d) write, message too small (%d < %d)",
452 a->controller, length,
453 sizeof(diva_xdi_um_cfg_cmd_t)))
454 return (-3);
457 if (!(data = diva_os_malloc(0, length))) {
458 DBG_ERR(("A: A(%d) write, ENOMEM", a->controller))
459 return (-2);
462 length = (*cp_fn) (os_handle, data, src, length);
463 if (length > 0) {
464 if ((*(a->interface.cmd_proc))
465 (a, (diva_xdi_um_cfg_cmd_t *) data, length)) {
466 length = -3;
468 } else {
469 DBG_ERR(("A: A(%d) write error (%d)", a->controller,
470 length))
473 diva_os_free(0, data);
475 return (length);
479 ** Write answers to user mode utility, if any
482 diva_xdi_read(void *adapter, void *os_handle, void __user *dst,
483 int max_length, divas_xdi_copy_to_user_fn_t cp_fn)
485 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
486 int ret;
488 if (!(a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY)) {
489 DBG_ERR(("A: A(%d) rx mbox empty", a->controller))
490 return (-1);
492 if (!a->xdi_mbox.data) {
493 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
494 DBG_ERR(("A: A(%d) rx ENOMEM", a->controller))
495 return (-2);
498 if (max_length < a->xdi_mbox.data_length) {
499 DBG_ERR(("A: A(%d) rx buffer too short(%d < %d)",
500 a->controller, max_length,
501 a->xdi_mbox.data_length))
502 return (-3);
505 ret = (*cp_fn) (os_handle, dst, a->xdi_mbox.data,
506 a->xdi_mbox.data_length);
507 if (ret > 0) {
508 diva_os_free(0, a->xdi_mbox.data);
509 a->xdi_mbox.data = NULL;
510 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
513 return (ret);
517 irqreturn_t diva_os_irq_wrapper(int irq, void *context)
519 diva_os_xdi_adapter_t *a = context;
520 diva_xdi_clear_interrupts_proc_t clear_int_proc;
522 if (!a || !a->xdi_adapter.diva_isr_handler)
523 return IRQ_NONE;
525 if ((clear_int_proc = a->clear_interrupts_proc)) {
526 (*clear_int_proc) (a);
527 a->clear_interrupts_proc = NULL;
528 return IRQ_HANDLED;
531 (*(a->xdi_adapter.diva_isr_handler)) (&a->xdi_adapter);
532 return IRQ_HANDLED;
535 static void diva_init_request_array(void)
537 Requests[0] = DivaIdiRequest0;
538 Requests[1] = DivaIdiRequest1;
539 Requests[2] = DivaIdiRequest2;
540 Requests[3] = DivaIdiRequest3;
541 Requests[4] = DivaIdiRequest4;
542 Requests[5] = DivaIdiRequest5;
543 Requests[6] = DivaIdiRequest6;
544 Requests[7] = DivaIdiRequest7;
545 Requests[8] = DivaIdiRequest8;
546 Requests[9] = DivaIdiRequest9;
547 Requests[10] = DivaIdiRequest10;
548 Requests[11] = DivaIdiRequest11;
549 Requests[12] = DivaIdiRequest12;
550 Requests[13] = DivaIdiRequest13;
551 Requests[14] = DivaIdiRequest14;
552 Requests[15] = DivaIdiRequest15;
553 Requests[16] = DivaIdiRequest16;
554 Requests[17] = DivaIdiRequest17;
555 Requests[18] = DivaIdiRequest18;
556 Requests[19] = DivaIdiRequest19;
557 Requests[20] = DivaIdiRequest20;
558 Requests[21] = DivaIdiRequest21;
559 Requests[22] = DivaIdiRequest22;
560 Requests[23] = DivaIdiRequest23;
561 Requests[24] = DivaIdiRequest24;
562 Requests[25] = DivaIdiRequest25;
563 Requests[26] = DivaIdiRequest26;
564 Requests[27] = DivaIdiRequest27;
565 Requests[28] = DivaIdiRequest28;
566 Requests[29] = DivaIdiRequest29;
567 Requests[30] = DivaIdiRequest30;
568 Requests[31] = DivaIdiRequest31;
571 void diva_xdi_display_adapter_features(int card)
573 dword features;
574 if (!card || ((card - 1) >= MAX_ADAPTER) || !IoAdapters[card - 1]) {
575 return;
577 card--;
578 features = IoAdapters[card]->Properties.Features;
580 DBG_LOG(("FEATURES FOR ADAPTER: %d", card + 1))
581 DBG_LOG((" DI_FAX3 : %s",
582 (features & DI_FAX3) ? "Y" : "N"))
583 DBG_LOG((" DI_MODEM : %s",
584 (features & DI_MODEM) ? "Y" : "N"))
585 DBG_LOG((" DI_POST : %s",
586 (features & DI_POST) ? "Y" : "N"))
587 DBG_LOG((" DI_V110 : %s",
588 (features & DI_V110) ? "Y" : "N"))
589 DBG_LOG((" DI_V120 : %s",
590 (features & DI_V120) ? "Y" : "N"))
591 DBG_LOG((" DI_POTS : %s",
592 (features & DI_POTS) ? "Y" : "N"))
593 DBG_LOG((" DI_CODEC : %s",
594 (features & DI_CODEC) ? "Y" : "N"))
595 DBG_LOG((" DI_MANAGE : %s",
596 (features & DI_MANAGE) ? "Y" : "N"))
597 DBG_LOG((" DI_V_42 : %s",
598 (features & DI_V_42) ? "Y" : "N"))
599 DBG_LOG((" DI_EXTD_FAX : %s",
600 (features & DI_EXTD_FAX) ? "Y" : "N"))
601 DBG_LOG((" DI_AT_PARSER : %s",
602 (features & DI_AT_PARSER) ? "Y" : "N"))
603 DBG_LOG((" DI_VOICE_OVER_IP : %s",
604 (features & DI_VOICE_OVER_IP) ? "Y" : "N"))
607 void diva_add_slave_adapter(diva_os_xdi_adapter_t *a)
609 diva_os_spin_lock_magic_t old_irql;
611 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add_slave");
612 list_add_tail(&a->link, &adapter_queue);
613 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add_slave");
616 int diva_card_read_xlog(diva_os_xdi_adapter_t *a)
618 diva_get_xlog_t *req;
619 byte *data;
621 if (!a->xdi_adapter.Initialized || !a->xdi_adapter.DIRequest) {
622 return (-1);
624 if (!(data = diva_os_malloc(0, sizeof(struct mi_pc_maint)))) {
625 return (-1);
627 memset(data, 0x00, sizeof(struct mi_pc_maint));
629 if (!(req = diva_os_malloc(0, sizeof(*req)))) {
630 diva_os_free(0, data);
631 return (-1);
633 req->command = 0x0400;
634 req->req = LOG;
635 req->rc = 0x00;
637 (*(a->xdi_adapter.DIRequest)) (&a->xdi_adapter, (ENTITY *) req);
639 if (!req->rc || req->req) {
640 diva_os_free(0, data);
641 diva_os_free(0, req);
642 return (-1);
645 memcpy(data, &req->req, sizeof(struct mi_pc_maint));
647 diva_os_free(0, req);
649 a->xdi_mbox.data_length = sizeof(struct mi_pc_maint);
650 a->xdi_mbox.data = data;
651 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
653 return (0);
656 void xdiFreeFile(void *handle)