Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[linux/fpc-iii.git] / drivers / isdn / hardware / eicon / diva.c
blobd91dd580e9781bc73704d3ad41c009265e227320
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)
75 ** LOCALS
77 static LIST_HEAD(adapter_queue);
79 typedef struct _diva_get_xlog {
80 word command;
81 byte req;
82 byte rc;
83 byte data[sizeof(struct mi_pc_maint)];
84 } diva_get_xlog_t;
86 typedef struct _diva_supported_cards_info {
87 int CardOrdinal;
88 diva_init_card_proc_t init_card;
89 } diva_supported_cards_info_t;
91 static diva_supported_cards_info_t divas_supported_cards[] = {
92 #ifdef CONFIG_ISDN_DIVAS_PRIPCI
94 PRI Cards
96 {CARDTYPE_DIVASRV_P_30M_PCI, diva_pri_init_card},
98 PRI Rev.2 Cards
100 {CARDTYPE_DIVASRV_P_30M_V2_PCI, diva_pri_init_card},
102 PRI Rev.2 VoIP Cards
104 {CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI, diva_pri_init_card},
105 #endif
106 #ifdef CONFIG_ISDN_DIVAS_BRIPCI
108 4BRI Rev 1 Cards
110 {CARDTYPE_DIVASRV_Q_8M_PCI, diva_4bri_init_card},
111 {CARDTYPE_DIVASRV_VOICE_Q_8M_PCI, diva_4bri_init_card},
113 4BRI Rev 2 Cards
115 {CARDTYPE_DIVASRV_Q_8M_V2_PCI, diva_4bri_init_card},
116 {CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI, diva_4bri_init_card},
118 4BRI Based BRI Rev 2 Cards
120 {CARDTYPE_DIVASRV_B_2M_V2_PCI, diva_4bri_init_card},
121 {CARDTYPE_DIVASRV_B_2F_PCI, diva_4bri_init_card},
122 {CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI, diva_4bri_init_card},
126 {CARDTYPE_MAESTRA_PCI, diva_bri_init_card},
127 #endif
132 {-1}
135 static void diva_init_request_array(void);
136 static void *divas_create_pci_card(int handle, void *pci_dev_handle);
138 static diva_os_spin_lock_t adapter_lock;
140 static int diva_find_free_adapters(int base, int nr)
142 int i;
144 for (i = 0; i < nr; i++) {
145 if (IoAdapters[base + i]) {
146 return (-1);
150 return (0);
153 static diva_os_xdi_adapter_t *diva_q_get_next(struct list_head *what)
155 diva_os_xdi_adapter_t *a = NULL;
157 if (what && (what->next != &adapter_queue))
158 a = list_entry(what->next, diva_os_xdi_adapter_t, link);
160 return (a);
163 /* --------------------------------------------------------------------------
164 Add card to the card list
165 -------------------------------------------------------------------------- */
166 void *diva_driver_add_card(void *pdev, unsigned long CardOrdinal)
168 diva_os_spin_lock_magic_t old_irql;
169 diva_os_xdi_adapter_t *pdiva, *pa;
170 int i, j, max, nr;
172 for (i = 0; divas_supported_cards[i].CardOrdinal != -1; i++) {
173 if (divas_supported_cards[i].CardOrdinal == CardOrdinal) {
174 if (!(pdiva = divas_create_pci_card(i, pdev))) {
175 return NULL;
177 switch (CardOrdinal) {
178 case CARDTYPE_DIVASRV_Q_8M_PCI:
179 case CARDTYPE_DIVASRV_VOICE_Q_8M_PCI:
180 case CARDTYPE_DIVASRV_Q_8M_V2_PCI:
181 case CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI:
182 max = MAX_ADAPTER - 4;
183 nr = 4;
184 break;
186 default:
187 max = MAX_ADAPTER;
188 nr = 1;
191 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
193 for (i = 0; i < max; i++) {
194 if (!diva_find_free_adapters(i, nr)) {
195 pdiva->controller = i + 1;
196 pdiva->xdi_adapter.ANum = pdiva->controller;
197 IoAdapters[i] = &pdiva->xdi_adapter;
198 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
199 create_adapter_proc(pdiva); /* add adapter to proc file system */
201 DBG_LOG(("add %s:%d",
202 CardProperties
203 [CardOrdinal].Name,
204 pdiva->controller))
206 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
207 pa = pdiva;
208 for (j = 1; j < nr; j++) { /* slave adapters, if any */
209 pa = diva_q_get_next(&pa->link);
210 if (pa && !pa->interface.cleanup_adapter_proc) {
211 pa->controller = i + 1 + j;
212 pa->xdi_adapter.ANum = pa->controller;
213 IoAdapters[i + j] = &pa->xdi_adapter;
214 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
215 DBG_LOG(("add slave adapter (%d)",
216 pa->controller))
217 create_adapter_proc(pa); /* add adapter to proc file system */
218 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
219 } else {
220 DBG_ERR(("slave adapter problem"))
221 break;
225 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
226 return (pdiva);
230 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
233 Not able to add adapter - remove it and return error
235 DBG_ERR(("can not alloc request array"))
236 diva_driver_remove_card(pdiva);
238 return NULL;
242 return NULL;
245 /* --------------------------------------------------------------------------
246 Called on driver load, MAIN, main, DriverEntry
247 -------------------------------------------------------------------------- */
248 int divasa_xdi_driver_entry(void)
250 diva_os_initialize_spin_lock(&adapter_lock, "adapter");
251 memset(&IoAdapters[0], 0x00, sizeof(IoAdapters));
252 diva_init_request_array();
254 return (0);
257 /* --------------------------------------------------------------------------
258 Remove adapter from list
259 -------------------------------------------------------------------------- */
260 static diva_os_xdi_adapter_t *get_and_remove_from_queue(void)
262 diva_os_spin_lock_magic_t old_irql;
263 diva_os_xdi_adapter_t *a = NULL;
265 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "driver_unload");
267 if (!list_empty(&adapter_queue)) {
268 a = list_entry(adapter_queue.next, diva_os_xdi_adapter_t, link);
269 list_del(adapter_queue.next);
272 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
273 return (a);
276 /* --------------------------------------------------------------------------
277 Remove card from the card list
278 -------------------------------------------------------------------------- */
279 void diva_driver_remove_card(void *pdiva)
281 diva_os_spin_lock_magic_t old_irql;
282 diva_os_xdi_adapter_t *a[4];
283 diva_os_xdi_adapter_t *pa;
284 int i;
286 pa = a[0] = (diva_os_xdi_adapter_t *) pdiva;
287 a[1] = a[2] = a[3] = NULL;
289 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "remode adapter");
291 for (i = 1; i < 4; i++) {
292 if ((pa = diva_q_get_next(&pa->link))
293 && !pa->interface.cleanup_adapter_proc) {
294 a[i] = pa;
295 } else {
296 break;
300 for (i = 0; ((i < 4) && a[i]); i++) {
301 list_del(&a[i]->link);
304 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
306 (*(a[0]->interface.cleanup_adapter_proc)) (a[0]);
308 for (i = 0; i < 4; i++) {
309 if (a[i]) {
310 if (a[i]->controller) {
311 DBG_LOG(("remove adapter (%d)",
312 a[i]->controller)) IoAdapters[a[i]->controller - 1] = NULL;
313 remove_adapter_proc(a[i]);
315 diva_os_free(0, a[i]);
320 /* --------------------------------------------------------------------------
321 Create diva PCI adapter and init internal adapter structures
322 -------------------------------------------------------------------------- */
323 static void *divas_create_pci_card(int handle, void *pci_dev_handle)
325 diva_supported_cards_info_t *pI = &divas_supported_cards[handle];
326 diva_os_spin_lock_magic_t old_irql;
327 diva_os_xdi_adapter_t *a;
329 DBG_LOG(("found %d-%s", pI->CardOrdinal, CardProperties[pI->CardOrdinal].Name))
331 if (!(a = (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a)))) {
332 DBG_ERR(("A: can't alloc adapter"));
333 return NULL;
336 memset(a, 0x00, sizeof(*a));
338 a->CardIndex = handle;
339 a->CardOrdinal = pI->CardOrdinal;
340 a->Bus = DIVAS_XDI_ADAPTER_BUS_PCI;
341 a->xdi_adapter.cardType = a->CardOrdinal;
342 a->resources.pci.bus = diva_os_get_pci_bus(pci_dev_handle);
343 a->resources.pci.func = diva_os_get_pci_func(pci_dev_handle);
344 a->resources.pci.hdev = pci_dev_handle;
347 Add master adapter first, so slave adapters will receive higher
348 numbers as master adapter
350 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
351 list_add_tail(&a->link, &adapter_queue);
352 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
354 if ((*(pI->init_card)) (a)) {
355 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
356 list_del(&a->link);
357 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
358 diva_os_free(0, a);
359 DBG_ERR(("A: can't get adapter resources"));
360 return NULL;
363 return (a);
366 /* --------------------------------------------------------------------------
367 Called on driver unload FINIT, finit, Unload
368 -------------------------------------------------------------------------- */
369 void divasa_xdi_driver_unload(void)
371 diva_os_xdi_adapter_t *a;
373 while ((a = get_and_remove_from_queue())) {
374 if (a->interface.cleanup_adapter_proc) {
375 (*(a->interface.cleanup_adapter_proc)) (a);
377 if (a->controller) {
378 IoAdapters[a->controller - 1] = NULL;
379 remove_adapter_proc(a);
381 diva_os_free(0, a);
383 diva_os_destroy_spin_lock(&adapter_lock, "adapter");
387 ** Receive and process command from user mode utility
389 void *diva_xdi_open_adapter(void *os_handle, const void __user *src,
390 int length,
391 divas_xdi_copy_from_user_fn_t cp_fn)
393 diva_xdi_um_cfg_cmd_t msg;
394 diva_os_xdi_adapter_t *a = NULL;
395 diva_os_spin_lock_magic_t old_irql;
396 struct list_head *tmp;
398 if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
399 DBG_ERR(("A: A(?) open, msg too small (%d < %d)",
400 length, sizeof(diva_xdi_um_cfg_cmd_t)))
401 return NULL;
403 if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) {
404 DBG_ERR(("A: A(?) open, write error"))
405 return NULL;
407 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter");
408 list_for_each(tmp, &adapter_queue) {
409 a = list_entry(tmp, diva_os_xdi_adapter_t, link);
410 if (a->controller == (int)msg.adapter)
411 break;
412 a = NULL;
414 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter");
416 if (!a) {
417 DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter))
420 return (a);
424 ** Easy cleanup mailbox status
426 void diva_xdi_close_adapter(void *adapter, void *os_handle)
428 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
430 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
431 if (a->xdi_mbox.data) {
432 diva_os_free(0, a->xdi_mbox.data);
433 a->xdi_mbox.data = NULL;
438 diva_xdi_write(void *adapter, void *os_handle, const void __user *src,
439 int length, divas_xdi_copy_from_user_fn_t cp_fn)
441 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
442 void *data;
444 if (a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY) {
445 DBG_ERR(("A: A(%d) write, mbox busy", a->controller))
446 return (-1);
449 if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
450 DBG_ERR(("A: A(%d) write, message too small (%d < %d)",
451 a->controller, length,
452 sizeof(diva_xdi_um_cfg_cmd_t)))
453 return (-3);
456 if (!(data = diva_os_malloc(0, length))) {
457 DBG_ERR(("A: A(%d) write, ENOMEM", a->controller))
458 return (-2);
461 length = (*cp_fn) (os_handle, data, src, length);
462 if (length > 0) {
463 if ((*(a->interface.cmd_proc))
464 (a, (diva_xdi_um_cfg_cmd_t *) data, length)) {
465 length = -3;
467 } else {
468 DBG_ERR(("A: A(%d) write error (%d)", a->controller,
469 length))
472 diva_os_free(0, data);
474 return (length);
478 ** Write answers to user mode utility, if any
481 diva_xdi_read(void *adapter, void *os_handle, void __user *dst,
482 int max_length, divas_xdi_copy_to_user_fn_t cp_fn)
484 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
485 int ret;
487 if (!(a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY)) {
488 DBG_ERR(("A: A(%d) rx mbox empty", a->controller))
489 return (-1);
491 if (!a->xdi_mbox.data) {
492 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
493 DBG_ERR(("A: A(%d) rx ENOMEM", a->controller))
494 return (-2);
497 if (max_length < a->xdi_mbox.data_length) {
498 DBG_ERR(("A: A(%d) rx buffer too short(%d < %d)",
499 a->controller, max_length,
500 a->xdi_mbox.data_length))
501 return (-3);
504 ret = (*cp_fn) (os_handle, dst, a->xdi_mbox.data,
505 a->xdi_mbox.data_length);
506 if (ret > 0) {
507 diva_os_free(0, a->xdi_mbox.data);
508 a->xdi_mbox.data = NULL;
509 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
512 return (ret);
516 irqreturn_t diva_os_irq_wrapper(int irq, void *context)
518 diva_os_xdi_adapter_t *a = context;
519 diva_xdi_clear_interrupts_proc_t clear_int_proc;
521 if (!a || !a->xdi_adapter.diva_isr_handler)
522 return IRQ_NONE;
524 if ((clear_int_proc = a->clear_interrupts_proc)) {
525 (*clear_int_proc) (a);
526 a->clear_interrupts_proc = NULL;
527 return IRQ_HANDLED;
530 (*(a->xdi_adapter.diva_isr_handler)) (&a->xdi_adapter);
531 return IRQ_HANDLED;
534 static void diva_init_request_array(void)
536 Requests[0] = DivaIdiRequest0;
537 Requests[1] = DivaIdiRequest1;
538 Requests[2] = DivaIdiRequest2;
539 Requests[3] = DivaIdiRequest3;
540 Requests[4] = DivaIdiRequest4;
541 Requests[5] = DivaIdiRequest5;
542 Requests[6] = DivaIdiRequest6;
543 Requests[7] = DivaIdiRequest7;
544 Requests[8] = DivaIdiRequest8;
545 Requests[9] = DivaIdiRequest9;
546 Requests[10] = DivaIdiRequest10;
547 Requests[11] = DivaIdiRequest11;
548 Requests[12] = DivaIdiRequest12;
549 Requests[13] = DivaIdiRequest13;
550 Requests[14] = DivaIdiRequest14;
551 Requests[15] = DivaIdiRequest15;
552 Requests[16] = DivaIdiRequest16;
553 Requests[17] = DivaIdiRequest17;
554 Requests[18] = DivaIdiRequest18;
555 Requests[19] = DivaIdiRequest19;
556 Requests[20] = DivaIdiRequest20;
557 Requests[21] = DivaIdiRequest21;
558 Requests[22] = DivaIdiRequest22;
559 Requests[23] = DivaIdiRequest23;
560 Requests[24] = DivaIdiRequest24;
561 Requests[25] = DivaIdiRequest25;
562 Requests[26] = DivaIdiRequest26;
563 Requests[27] = DivaIdiRequest27;
564 Requests[28] = DivaIdiRequest28;
565 Requests[29] = DivaIdiRequest29;
566 Requests[30] = DivaIdiRequest30;
567 Requests[31] = DivaIdiRequest31;
570 void diva_xdi_display_adapter_features(int card)
572 dword features;
573 if (!card || ((card - 1) >= MAX_ADAPTER) || !IoAdapters[card - 1]) {
574 return;
576 card--;
577 features = IoAdapters[card]->Properties.Features;
579 DBG_LOG(("FEATURES FOR ADAPTER: %d", card + 1))
580 DBG_LOG((" DI_FAX3 : %s",
581 (features & DI_FAX3) ? "Y" : "N"))
582 DBG_LOG((" DI_MODEM : %s",
583 (features & DI_MODEM) ? "Y" : "N"))
584 DBG_LOG((" DI_POST : %s",
585 (features & DI_POST) ? "Y" : "N"))
586 DBG_LOG((" DI_V110 : %s",
587 (features & DI_V110) ? "Y" : "N"))
588 DBG_LOG((" DI_V120 : %s",
589 (features & DI_V120) ? "Y" : "N"))
590 DBG_LOG((" DI_POTS : %s",
591 (features & DI_POTS) ? "Y" : "N"))
592 DBG_LOG((" DI_CODEC : %s",
593 (features & DI_CODEC) ? "Y" : "N"))
594 DBG_LOG((" DI_MANAGE : %s",
595 (features & DI_MANAGE) ? "Y" : "N"))
596 DBG_LOG((" DI_V_42 : %s",
597 (features & DI_V_42) ? "Y" : "N"))
598 DBG_LOG((" DI_EXTD_FAX : %s",
599 (features & DI_EXTD_FAX) ? "Y" : "N"))
600 DBG_LOG((" DI_AT_PARSER : %s",
601 (features & DI_AT_PARSER) ? "Y" : "N"))
602 DBG_LOG((" DI_VOICE_OVER_IP : %s",
603 (features & DI_VOICE_OVER_IP) ? "Y" : "N"))
606 void diva_add_slave_adapter(diva_os_xdi_adapter_t *a)
608 diva_os_spin_lock_magic_t old_irql;
610 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add_slave");
611 list_add_tail(&a->link, &adapter_queue);
612 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add_slave");
615 int diva_card_read_xlog(diva_os_xdi_adapter_t *a)
617 diva_get_xlog_t *req;
618 byte *data;
620 if (!a->xdi_adapter.Initialized || !a->xdi_adapter.DIRequest) {
621 return (-1);
623 if (!(data = diva_os_malloc(0, sizeof(struct mi_pc_maint)))) {
624 return (-1);
626 memset(data, 0x00, sizeof(struct mi_pc_maint));
628 if (!(req = diva_os_malloc(0, sizeof(*req)))) {
629 diva_os_free(0, data);
630 return (-1);
632 req->command = 0x0400;
633 req->req = LOG;
634 req->rc = 0x00;
636 (*(a->xdi_adapter.DIRequest)) (&a->xdi_adapter, (ENTITY *) req);
638 if (!req->rc || req->req) {
639 diva_os_free(0, data);
640 diva_os_free(0, req);
641 return (-1);
644 memcpy(data, &req->req, sizeof(struct mi_pc_maint));
646 diva_os_free(0, req);
648 a->xdi_mbox.data_length = sizeof(struct mi_pc_maint);
649 a->xdi_mbox.data = data;
650 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
652 return (0);
655 void xdiFreeFile(void *handle)