[CONNECTOR]: Initialize subsystem earlier.
[linux-2.6/verdex.git] / drivers / isdn / hardware / eicon / diva.c
blob8ab8027f33c0ae2fe28c18ba4949203879fd1423
1 /* $Id: diva.c,v 1.21.4.1 2004/05/08 14:33:43 armin Exp $ */
3 #define CARDTYPE_H_WANT_DATA 1
4 #define CARDTYPE_H_WANT_IDI_DATA 0
5 #define CARDTYPE_H_WANT_RESOURCE_DATA 0
6 #define CARDTYPE_H_WANT_FILE_DATA 0
8 #include "platform.h"
9 #include "debuglib.h"
10 #include "cardtype.h"
11 #include "pc.h"
12 #include "di_defs.h"
13 #include "di.h"
14 #include "io.h"
15 #include "pc_maint.h"
16 #include "xdi_msg.h"
17 #include "xdi_adapter.h"
18 #include "diva_pci.h"
19 #include "diva.h"
21 #ifdef CONFIG_ISDN_DIVAS_PRIPCI
22 #include "os_pri.h"
23 #endif
24 #ifdef CONFIG_ISDN_DIVAS_BRIPCI
25 #include "os_bri.h"
26 #include "os_4bri.h"
27 #endif
29 PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
30 extern IDI_CALL Requests[MAX_ADAPTER];
31 extern int create_adapter_proc(diva_os_xdi_adapter_t * a);
32 extern void remove_adapter_proc(diva_os_xdi_adapter_t * a);
34 #define DivaIdiReqFunc(N) \
35 static void DivaIdiRequest##N(ENTITY *e) \
36 { if ( IoAdapters[N] ) (* IoAdapters[N]->DIRequest)(IoAdapters[N], e) ; }
39 ** Create own 32 Adapters
41 DivaIdiReqFunc(0)
42 DivaIdiReqFunc(1)
43 DivaIdiReqFunc(2)
44 DivaIdiReqFunc(3)
45 DivaIdiReqFunc(4)
46 DivaIdiReqFunc(5)
47 DivaIdiReqFunc(6)
48 DivaIdiReqFunc(7)
49 DivaIdiReqFunc(8)
50 DivaIdiReqFunc(9)
51 DivaIdiReqFunc(10)
52 DivaIdiReqFunc(11)
53 DivaIdiReqFunc(12)
54 DivaIdiReqFunc(13)
55 DivaIdiReqFunc(14)
56 DivaIdiReqFunc(15)
57 DivaIdiReqFunc(16)
58 DivaIdiReqFunc(17)
59 DivaIdiReqFunc(18)
60 DivaIdiReqFunc(19)
61 DivaIdiReqFunc(20)
62 DivaIdiReqFunc(21)
63 DivaIdiReqFunc(22)
64 DivaIdiReqFunc(23)
65 DivaIdiReqFunc(24)
66 DivaIdiReqFunc(25)
67 DivaIdiReqFunc(26)
68 DivaIdiReqFunc(27)
69 DivaIdiReqFunc(28)
70 DivaIdiReqFunc(29)
71 DivaIdiReqFunc(30)
72 DivaIdiReqFunc(31)
74 struct pt_regs;
77 ** LOCALS
79 static LIST_HEAD(adapter_queue);
81 typedef struct _diva_get_xlog {
82 word command;
83 byte req;
84 byte rc;
85 byte data[sizeof(struct mi_pc_maint)];
86 } diva_get_xlog_t;
88 typedef struct _diva_supported_cards_info {
89 int CardOrdinal;
90 diva_init_card_proc_t init_card;
91 } diva_supported_cards_info_t;
93 static diva_supported_cards_info_t divas_supported_cards[] = {
94 #ifdef CONFIG_ISDN_DIVAS_PRIPCI
96 PRI Cards
98 {CARDTYPE_DIVASRV_P_30M_PCI, diva_pri_init_card},
100 PRI Rev.2 Cards
102 {CARDTYPE_DIVASRV_P_30M_V2_PCI, diva_pri_init_card},
104 PRI Rev.2 VoIP Cards
106 {CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI, diva_pri_init_card},
107 #endif
108 #ifdef CONFIG_ISDN_DIVAS_BRIPCI
110 4BRI Rev 1 Cards
112 {CARDTYPE_DIVASRV_Q_8M_PCI, diva_4bri_init_card},
113 {CARDTYPE_DIVASRV_VOICE_Q_8M_PCI, diva_4bri_init_card},
115 4BRI Rev 2 Cards
117 {CARDTYPE_DIVASRV_Q_8M_V2_PCI, diva_4bri_init_card},
118 {CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI, diva_4bri_init_card},
120 4BRI Based BRI Rev 2 Cards
122 {CARDTYPE_DIVASRV_B_2M_V2_PCI, diva_4bri_init_card},
123 {CARDTYPE_DIVASRV_B_2F_PCI, diva_4bri_init_card},
124 {CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI, diva_4bri_init_card},
128 {CARDTYPE_MAESTRA_PCI, diva_bri_init_card},
129 #endif
134 {-1}
137 static void diva_init_request_array(void);
138 static void *divas_create_pci_card(int handle, void *pci_dev_handle);
140 static diva_os_spin_lock_t adapter_lock;
142 static int diva_find_free_adapters(int base, int nr)
144 int i;
146 for (i = 0; i < nr; i++) {
147 if (IoAdapters[base + i]) {
148 return (-1);
152 return (0);
155 static diva_os_xdi_adapter_t *diva_q_get_next(struct list_head * what)
157 diva_os_xdi_adapter_t *a = NULL;
159 if (what && (what->next != &adapter_queue))
160 a = list_entry(what->next, diva_os_xdi_adapter_t, link);
162 return(a);
165 /* --------------------------------------------------------------------------
166 Add card to the card list
167 -------------------------------------------------------------------------- */
168 void *diva_driver_add_card(void *pdev, unsigned long CardOrdinal)
170 diva_os_spin_lock_magic_t old_irql;
171 diva_os_xdi_adapter_t *pdiva, *pa;
172 int i, j, max, nr;
174 for (i = 0; divas_supported_cards[i].CardOrdinal != -1; i++) {
175 if (divas_supported_cards[i].CardOrdinal == CardOrdinal) {
176 if (!(pdiva = divas_create_pci_card(i, pdev))) {
177 return NULL;
179 switch (CardOrdinal) {
180 case CARDTYPE_DIVASRV_Q_8M_PCI:
181 case CARDTYPE_DIVASRV_VOICE_Q_8M_PCI:
182 case CARDTYPE_DIVASRV_Q_8M_V2_PCI:
183 case CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI:
184 max = MAX_ADAPTER - 4;
185 nr = 4;
186 break;
188 default:
189 max = MAX_ADAPTER;
190 nr = 1;
193 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
195 for (i = 0; i < max; i++) {
196 if (!diva_find_free_adapters(i, nr)) {
197 pdiva->controller = i + 1;
198 pdiva->xdi_adapter.ANum = pdiva->controller;
199 IoAdapters[i] = &pdiva->xdi_adapter;
200 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
201 create_adapter_proc(pdiva); /* add adapter to proc file system */
203 DBG_LOG(("add %s:%d",
204 CardProperties
205 [CardOrdinal].Name,
206 pdiva->controller))
208 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
209 pa = pdiva;
210 for (j = 1; j < nr; j++) { /* slave adapters, if any */
211 pa = diva_q_get_next(&pa->link);
212 if (pa && !pa->interface.cleanup_adapter_proc) {
213 pa->controller = i + 1 + j;
214 pa->xdi_adapter.ANum = pa->controller;
215 IoAdapters[i + j] = &pa->xdi_adapter;
216 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
217 DBG_LOG(("add slave adapter (%d)",
218 pa->controller))
219 create_adapter_proc(pa); /* add adapter to proc file system */
220 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
221 } else {
222 DBG_ERR(("slave adapter problem"))
223 break;
227 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
228 return (pdiva);
232 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
235 Not able to add adapter - remove it and return error
237 DBG_ERR(("can not alloc request array"))
238 diva_driver_remove_card(pdiva);
240 return NULL;
244 return NULL;
247 /* --------------------------------------------------------------------------
248 Called on driver load, MAIN, main, DriverEntry
249 -------------------------------------------------------------------------- */
250 int divasa_xdi_driver_entry(void)
252 diva_os_initialize_spin_lock(&adapter_lock, "adapter");
253 memset(&IoAdapters[0], 0x00, sizeof(IoAdapters));
254 diva_init_request_array();
256 return (0);
259 /* --------------------------------------------------------------------------
260 Remove adapter from list
261 -------------------------------------------------------------------------- */
262 static diva_os_xdi_adapter_t *get_and_remove_from_queue(void)
264 diva_os_spin_lock_magic_t old_irql;
265 diva_os_xdi_adapter_t *a = NULL;
267 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "driver_unload");
269 if (!list_empty(&adapter_queue)) {
270 a = list_entry(adapter_queue.next, diva_os_xdi_adapter_t, link);
271 list_del(adapter_queue.next);
274 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
275 return (a);
278 /* --------------------------------------------------------------------------
279 Remove card from the card list
280 -------------------------------------------------------------------------- */
281 void diva_driver_remove_card(void *pdiva)
283 diva_os_spin_lock_magic_t old_irql;
284 diva_os_xdi_adapter_t *a[4];
285 diva_os_xdi_adapter_t *pa;
286 int i;
288 pa = a[0] = (diva_os_xdi_adapter_t *) pdiva;
289 a[1] = a[2] = a[3] = NULL;
291 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "remode adapter");
293 for (i = 1; i < 4; i++) {
294 if ((pa = diva_q_get_next(&pa->link))
295 && !pa->interface.cleanup_adapter_proc) {
296 a[i] = pa;
297 } else {
298 break;
302 for (i = 0; ((i < 4) && a[i]); i++) {
303 list_del(&a[i]->link);
306 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
308 (*(a[0]->interface.cleanup_adapter_proc)) (a[0]);
310 for (i = 0; i < 4; i++) {
311 if (a[i]) {
312 if (a[i]->controller) {
313 DBG_LOG(("remove adapter (%d)",
314 a[i]->controller)) IoAdapters[a[i]->controller - 1] = NULL;
315 remove_adapter_proc(a[i]);
317 diva_os_free(0, a[i]);
322 /* --------------------------------------------------------------------------
323 Create diva PCI adapter and init internal adapter structures
324 -------------------------------------------------------------------------- */
325 static void *divas_create_pci_card(int handle, void *pci_dev_handle)
327 diva_supported_cards_info_t *pI = &divas_supported_cards[handle];
328 diva_os_spin_lock_magic_t old_irql;
329 diva_os_xdi_adapter_t *a;
331 DBG_LOG(("found %d-%s", pI->CardOrdinal, CardProperties[pI->CardOrdinal].Name))
333 if (!(a = (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a)))) {
334 DBG_ERR(("A: can't alloc adapter"));
335 return NULL;
338 memset(a, 0x00, sizeof(*a));
340 a->CardIndex = handle;
341 a->CardOrdinal = pI->CardOrdinal;
342 a->Bus = DIVAS_XDI_ADAPTER_BUS_PCI;
343 a->xdi_adapter.cardType = a->CardOrdinal;
344 a->resources.pci.bus = diva_os_get_pci_bus(pci_dev_handle);
345 a->resources.pci.func = diva_os_get_pci_func(pci_dev_handle);
346 a->resources.pci.hdev = pci_dev_handle;
349 Add master adapter first, so slave adapters will receive higher
350 numbers as master adapter
352 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
353 list_add_tail(&a->link, &adapter_queue);
354 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
356 if ((*(pI->init_card)) (a)) {
357 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
358 list_del(&a->link);
359 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
360 diva_os_free(0, a);
361 DBG_ERR(("A: can't get adapter resources"));
362 return NULL;
365 return (a);
368 /* --------------------------------------------------------------------------
369 Called on driver unload FINIT, finit, Unload
370 -------------------------------------------------------------------------- */
371 void divasa_xdi_driver_unload(void)
373 diva_os_xdi_adapter_t *a;
375 while ((a = get_and_remove_from_queue())) {
376 if (a->interface.cleanup_adapter_proc) {
377 (*(a->interface.cleanup_adapter_proc)) (a);
379 if (a->controller) {
380 IoAdapters[a->controller - 1] = NULL;
381 remove_adapter_proc(a);
383 diva_os_free(0, a);
385 diva_os_destroy_spin_lock(&adapter_lock, "adapter");
389 ** Receive and process command from user mode utility
391 void *diva_xdi_open_adapter(void *os_handle, const void __user *src,
392 int length,
393 divas_xdi_copy_from_user_fn_t cp_fn)
395 diva_xdi_um_cfg_cmd_t msg;
396 diva_os_xdi_adapter_t *a = NULL;
397 diva_os_spin_lock_magic_t old_irql;
398 struct list_head *tmp;
400 if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
401 DBG_ERR(("A: A(?) open, msg too small (%d < %d)",
402 length, sizeof(diva_xdi_um_cfg_cmd_t)))
403 return NULL;
405 if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) {
406 DBG_ERR(("A: A(?) open, write error"))
407 return NULL;
409 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter");
410 list_for_each(tmp, &adapter_queue) {
411 a = list_entry(tmp, diva_os_xdi_adapter_t, link);
412 if (a->controller == (int)msg.adapter)
413 break;
414 a = NULL;
416 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter");
418 if (!a) {
419 DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter))
422 return (a);
426 ** Easy cleanup mailbox status
428 void diva_xdi_close_adapter(void *adapter, void *os_handle)
430 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
432 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
433 if (a->xdi_mbox.data) {
434 diva_os_free(0, a->xdi_mbox.data);
435 a->xdi_mbox.data = NULL;
440 diva_xdi_write(void *adapter, void *os_handle, const void __user *src,
441 int length, divas_xdi_copy_from_user_fn_t cp_fn)
443 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
444 void *data;
446 if (a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY) {
447 DBG_ERR(("A: A(%d) write, mbox busy", a->controller))
448 return (-1);
451 if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
452 DBG_ERR(("A: A(%d) write, message too small (%d < %d)",
453 a->controller, length,
454 sizeof(diva_xdi_um_cfg_cmd_t)))
455 return (-3);
458 if (!(data = diva_os_malloc(0, length))) {
459 DBG_ERR(("A: A(%d) write, ENOMEM", a->controller))
460 return (-2);
463 length = (*cp_fn) (os_handle, data, src, length);
464 if (length > 0) {
465 if ((*(a->interface.cmd_proc))
466 (a, (diva_xdi_um_cfg_cmd_t *) data, length)) {
467 length = -3;
469 } else {
470 DBG_ERR(("A: A(%d) write error (%d)", a->controller,
471 length))
474 diva_os_free(0, data);
476 return (length);
480 ** Write answers to user mode utility, if any
483 diva_xdi_read(void *adapter, void *os_handle, void __user *dst,
484 int max_length, divas_xdi_copy_to_user_fn_t cp_fn)
486 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
487 int ret;
489 if (!(a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY)) {
490 DBG_ERR(("A: A(%d) rx mbox empty", a->controller))
491 return (-1);
493 if (!a->xdi_mbox.data) {
494 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
495 DBG_ERR(("A: A(%d) rx ENOMEM", a->controller))
496 return (-2);
499 if (max_length < a->xdi_mbox.data_length) {
500 DBG_ERR(("A: A(%d) rx buffer too short(%d < %d)",
501 a->controller, max_length,
502 a->xdi_mbox.data_length))
503 return (-3);
506 ret = (*cp_fn) (os_handle, dst, a->xdi_mbox.data,
507 a->xdi_mbox.data_length);
508 if (ret > 0) {
509 diva_os_free(0, a->xdi_mbox.data);
510 a->xdi_mbox.data = NULL;
511 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
514 return (ret);
518 irqreturn_t diva_os_irq_wrapper(int irq, void *context, struct pt_regs *regs)
520 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) context;
521 diva_xdi_clear_interrupts_proc_t clear_int_proc;
523 if (!a || !a->xdi_adapter.diva_isr_handler) {
524 return IRQ_NONE;
527 if ((clear_int_proc = a->clear_interrupts_proc)) {
528 (*clear_int_proc) (a);
529 a->clear_interrupts_proc = NULL;
530 return IRQ_HANDLED;
533 (*(a->xdi_adapter.diva_isr_handler)) (&a->xdi_adapter);
534 return IRQ_HANDLED;
537 static void diva_init_request_array(void)
539 Requests[0] = DivaIdiRequest0;
540 Requests[1] = DivaIdiRequest1;
541 Requests[2] = DivaIdiRequest2;
542 Requests[3] = DivaIdiRequest3;
543 Requests[4] = DivaIdiRequest4;
544 Requests[5] = DivaIdiRequest5;
545 Requests[6] = DivaIdiRequest6;
546 Requests[7] = DivaIdiRequest7;
547 Requests[8] = DivaIdiRequest8;
548 Requests[9] = DivaIdiRequest9;
549 Requests[10] = DivaIdiRequest10;
550 Requests[11] = DivaIdiRequest11;
551 Requests[12] = DivaIdiRequest12;
552 Requests[13] = DivaIdiRequest13;
553 Requests[14] = DivaIdiRequest14;
554 Requests[15] = DivaIdiRequest15;
555 Requests[16] = DivaIdiRequest16;
556 Requests[17] = DivaIdiRequest17;
557 Requests[18] = DivaIdiRequest18;
558 Requests[19] = DivaIdiRequest19;
559 Requests[20] = DivaIdiRequest20;
560 Requests[21] = DivaIdiRequest21;
561 Requests[22] = DivaIdiRequest22;
562 Requests[23] = DivaIdiRequest23;
563 Requests[24] = DivaIdiRequest24;
564 Requests[25] = DivaIdiRequest25;
565 Requests[26] = DivaIdiRequest26;
566 Requests[27] = DivaIdiRequest27;
567 Requests[28] = DivaIdiRequest28;
568 Requests[29] = DivaIdiRequest29;
569 Requests[30] = DivaIdiRequest30;
570 Requests[31] = DivaIdiRequest31;
573 void diva_xdi_display_adapter_features(int card)
575 dword features;
576 if (!card || ((card - 1) >= MAX_ADAPTER) || !IoAdapters[card - 1]) {
577 return;
579 card--;
580 features = IoAdapters[card]->Properties.Features;
582 DBG_LOG(("FEATURES FOR ADAPTER: %d", card + 1))
583 DBG_LOG((" DI_FAX3 : %s",
584 (features & DI_FAX3) ? "Y" : "N"))
585 DBG_LOG((" DI_MODEM : %s",
586 (features & DI_MODEM) ? "Y" : "N"))
587 DBG_LOG((" DI_POST : %s",
588 (features & DI_POST) ? "Y" : "N"))
589 DBG_LOG((" DI_V110 : %s",
590 (features & DI_V110) ? "Y" : "N"))
591 DBG_LOG((" DI_V120 : %s",
592 (features & DI_V120) ? "Y" : "N"))
593 DBG_LOG((" DI_POTS : %s",
594 (features & DI_POTS) ? "Y" : "N"))
595 DBG_LOG((" DI_CODEC : %s",
596 (features & DI_CODEC) ? "Y" : "N"))
597 DBG_LOG((" DI_MANAGE : %s",
598 (features & DI_MANAGE) ? "Y" : "N"))
599 DBG_LOG((" DI_V_42 : %s",
600 (features & DI_V_42) ? "Y" : "N"))
601 DBG_LOG((" DI_EXTD_FAX : %s",
602 (features & DI_EXTD_FAX) ? "Y" : "N"))
603 DBG_LOG((" DI_AT_PARSER : %s",
604 (features & DI_AT_PARSER) ? "Y" : "N"))
605 DBG_LOG((" DI_VOICE_OVER_IP : %s",
606 (features & DI_VOICE_OVER_IP) ? "Y" : "N"))
609 void diva_add_slave_adapter(diva_os_xdi_adapter_t * a)
611 diva_os_spin_lock_magic_t old_irql;
613 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add_slave");
614 list_add_tail(&a->link, &adapter_queue);
615 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add_slave");
618 int diva_card_read_xlog(diva_os_xdi_adapter_t * a)
620 diva_get_xlog_t *req;
621 byte *data;
623 if (!a->xdi_adapter.Initialized || !a->xdi_adapter.DIRequest) {
624 return (-1);
626 if (!(data = diva_os_malloc(0, sizeof(struct mi_pc_maint)))) {
627 return (-1);
629 memset(data, 0x00, sizeof(struct mi_pc_maint));
631 if (!(req = diva_os_malloc(0, sizeof(*req)))) {
632 diva_os_free(0, data);
633 return (-1);
635 req->command = 0x0400;
636 req->req = LOG;
637 req->rc = 0x00;
639 (*(a->xdi_adapter.DIRequest)) (&a->xdi_adapter, (ENTITY *) req);
641 if (!req->rc || req->req) {
642 diva_os_free(0, data);
643 diva_os_free(0, req);
644 return (-1);
647 memcpy(data, &req->req, sizeof(struct mi_pc_maint));
649 diva_os_free(0, req);
651 a->xdi_mbox.data_length = sizeof(struct mi_pc_maint);
652 a->xdi_mbox.data = data;
653 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
655 return (0);
658 void xdiFreeFile(void *handle)