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
17 #include "xdi_adapter.h"
21 #ifdef CONFIG_ISDN_DIVAS_PRIPCI
24 #ifdef CONFIG_ISDN_DIVAS_BRIPCI
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
79 static LIST_HEAD(adapter_queue);
81 typedef struct _diva_get_xlog {
85 byte data[sizeof(struct mi_pc_maint)];
88 typedef struct _diva_supported_cards_info {
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
98 {CARDTYPE_DIVASRV_P_30M_PCI, diva_pri_init_card},
102 {CARDTYPE_DIVASRV_P_30M_V2_PCI, diva_pri_init_card},
106 {CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI, diva_pri_init_card},
108 #ifdef CONFIG_ISDN_DIVAS_BRIPCI
112 {CARDTYPE_DIVASRV_Q_8M_PCI, diva_4bri_init_card},
113 {CARDTYPE_DIVASRV_VOICE_Q_8M_PCI, diva_4bri_init_card},
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},
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)
146 for (i = 0; i < nr; i++) {
147 if (IoAdapters[base + i]) {
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);
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;
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))) {
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;
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",
208 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
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)",
219 create_adapter_proc(pa); /* add adapter to proc file system */
220 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
222 DBG_ERR(("slave adapter problem"))
227 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
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);
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();
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");
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;
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) {
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++) {
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"));
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");
359 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
361 DBG_ERR(("A: can't get adapter resources"));
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);
380 IoAdapters[a->controller - 1] = NULL;
381 remove_adapter_proc(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,
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)))
405 if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) {
406 DBG_ERR(("A: A(?) open, write error"))
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)
416 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter");
419 DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter))
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;
446 if (a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY) {
447 DBG_ERR(("A: A(%d) write, mbox busy", a->controller))
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)))
458 if (!(data = diva_os_malloc(0, length))) {
459 DBG_ERR(("A: A(%d) write, ENOMEM", a->controller))
463 length = (*cp_fn) (os_handle, data, src, length);
465 if ((*(a->interface.cmd_proc))
466 (a, (diva_xdi_um_cfg_cmd_t *) data, length)) {
470 DBG_ERR(("A: A(%d) write error (%d)", a->controller,
474 diva_os_free(0, data);
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;
489 if (!(a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY)) {
490 DBG_ERR(("A: A(%d) rx mbox empty", a->controller))
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))
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))
506 ret = (*cp_fn) (os_handle, dst, a->xdi_mbox.data,
507 a->xdi_mbox.data_length);
509 diva_os_free(0, a->xdi_mbox.data);
510 a->xdi_mbox.data = NULL;
511 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
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) {
527 if ((clear_int_proc = a->clear_interrupts_proc)) {
528 (*clear_int_proc) (a);
529 a->clear_interrupts_proc = NULL;
533 (*(a->xdi_adapter.diva_isr_handler)) (&a->xdi_adapter);
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)
576 if (!card || ((card - 1) >= MAX_ADAPTER) || !IoAdapters[card - 1]) {
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;
623 if (!a->xdi_adapter.Initialized || !a->xdi_adapter.DIRequest) {
626 if (!(data = diva_os_malloc(0, sizeof(struct mi_pc_maint)))) {
629 memset(data, 0x00, sizeof(struct mi_pc_maint));
631 if (!(req = diva_os_malloc(0, sizeof(*req)))) {
632 diva_os_free(0, data);
635 req->command = 0x0400;
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);
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;
658 void xdiFreeFile(void *handle)