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
77
static LIST_HEAD(adapter_queue);
79
typedef struct _diva_get_xlog {
83
byte data[sizeof(struct mi_pc_maint)];
86
typedef struct _diva_supported_cards_info {
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
96
{CARDTYPE_DIVASRV_P_30M_PCI, diva_pri_init_card},
100
{CARDTYPE_DIVASRV_P_30M_V2_PCI, diva_pri_init_card},
104
{CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI, diva_pri_init_card},
106
#ifdef CONFIG_ISDN_DIVAS_BRIPCI
110
{CARDTYPE_DIVASRV_Q_8M_PCI, diva_4bri_init_card},
111
{CARDTYPE_DIVASRV_VOICE_Q_8M_PCI, diva_4bri_init_card},
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},
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)
144
for (i = 0; i < nr; i++) {
145
if (IoAdapters[base + i]) {
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);
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;
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))) {
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;
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",
206
diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
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)",
217
create_adapter_proc(pa); /* add adapter to proc file system */
218
diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
220
DBG_ERR(("slave adapter problem"))
225
diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
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);
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();
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");
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;
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) {
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++) {
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"));
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");
357
diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
359
DBG_ERR(("A: can't get adapter resources"));
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);
378
IoAdapters[a->controller - 1] = NULL;
379
remove_adapter_proc(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,
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)))
403
if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) {
404
DBG_ERR(("A: A(?) open, write error"))
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)
414
diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter");
417
DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter))
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;
444
if (a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY) {
445
DBG_ERR(("A: A(%d) write, mbox busy", a->controller))
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)))
456
if (!(data = diva_os_malloc(0, length))) {
457
DBG_ERR(("A: A(%d) write, ENOMEM", a->controller))
461
length = (*cp_fn) (os_handle, data, src, length);
463
if ((*(a->interface.cmd_proc))
464
(a, (diva_xdi_um_cfg_cmd_t *) data, length)) {
468
DBG_ERR(("A: A(%d) write error (%d)", a->controller,
472
diva_os_free(0, data);
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;
487
if (!(a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY)) {
488
DBG_ERR(("A: A(%d) rx mbox empty", a->controller))
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))
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))
504
ret = (*cp_fn) (os_handle, dst, a->xdi_mbox.data,
505
a->xdi_mbox.data_length);
507
diva_os_free(0, a->xdi_mbox.data);
508
a->xdi_mbox.data = NULL;
509
a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
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)
524
if ((clear_int_proc = a->clear_interrupts_proc)) {
525
(*clear_int_proc) (a);
526
a->clear_interrupts_proc = NULL;
530
(*(a->xdi_adapter.diva_isr_handler)) (&a->xdi_adapter);
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)
573
if (!card || ((card - 1) >= MAX_ADAPTER) || !IoAdapters[card - 1]) {
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;
620
if (!a->xdi_adapter.Initialized || !a->xdi_adapter.DIRequest) {
623
if (!(data = diva_os_malloc(0, sizeof(struct mi_pc_maint)))) {
626
memset(data, 0x00, sizeof(struct mi_pc_maint));
628
if (!(req = diva_os_malloc(0, sizeof(*req)))) {
629
diva_os_free(0, data);
632
req->command = 0x0400;
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);
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;
655
void xdiFreeFile(void *handle)