Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / drivers / isdn / hardware / eicon / os_bri.c
1 /* $Id: os_bri.c,v 1.21 2004/03/21 17:26:01 armin Exp $ */
2
3 #include "platform.h"
4 #include "debuglib.h"
5 #include "cardtype.h"
6 #include "pc.h"
7 #include "pr_pc.h"
8 #include "di_defs.h"
9 #include "dsp_defs.h"
10 #include "di.h"
11 #include "io.h"
12
13 #include "xdi_msg.h"
14 #include "xdi_adapter.h"
15 #include "os_bri.h"
16 #include "diva_pci.h"
17 #include "mi_pc.h"
18 #include "pc_maint.h"
19
20 /*
21 **  IMPORTS
22 */
23 extern void prepare_maestra_functions(PISDN_ADAPTER IoAdapter);
24 extern void diva_xdi_display_adapter_features(int card);
25 extern int diva_card_read_xlog(diva_os_xdi_adapter_t * a);
26
27 /*
28 **  LOCALS
29 */
30 static int bri_bar_length[3] = {
31         0x80,
32         0x80,
33         0x20
34 };
35 static int diva_bri_cleanup_adapter(diva_os_xdi_adapter_t * a);
36 static dword diva_bri_get_serial_number(diva_os_xdi_adapter_t * a);
37 static int diva_bri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
38                                   diva_xdi_um_cfg_cmd_t * cmd, int length);
39 static int diva_bri_reregister_io(diva_os_xdi_adapter_t * a);
40 static int diva_bri_reset_adapter(PISDN_ADAPTER IoAdapter);
41 static int diva_bri_write_sdram_block(PISDN_ADAPTER IoAdapter,
42                                       dword address,
43                                       const byte * data, dword length);
44 static int diva_bri_start_adapter(PISDN_ADAPTER IoAdapter,
45                                   dword start_address, dword features);
46 static int diva_bri_stop_adapter(diva_os_xdi_adapter_t * a);
47
48 static void diva_bri_set_addresses(diva_os_xdi_adapter_t * a)
49 {
50         a->resources.pci.mem_type_id[MEM_TYPE_RAM] = 0;
51         a->resources.pci.mem_type_id[MEM_TYPE_CFG] = 1;
52         a->resources.pci.mem_type_id[MEM_TYPE_ADDRESS] = 2;
53         a->resources.pci.mem_type_id[MEM_TYPE_RESET] = 1;
54         a->resources.pci.mem_type_id[MEM_TYPE_PORT] = 2;
55         a->resources.pci.mem_type_id[MEM_TYPE_CTLREG] = 2;
56         
57         a->xdi_adapter.ram = a->resources.pci.addr[0];
58         a->xdi_adapter.cfg = a->resources.pci.addr[1];
59         a->xdi_adapter.Address = a->resources.pci.addr[2];
60
61         a->xdi_adapter.reset = a->xdi_adapter.cfg;
62         a->xdi_adapter.port = a->xdi_adapter.Address;
63
64         a->xdi_adapter.ctlReg = a->xdi_adapter.port + M_PCI_RESET;
65
66         a->xdi_adapter.reset += 0x4C;   /* PLX 9050 !! */
67 }
68
69 /*
70 **  BAR0 - MEM Addr  - 0x80  - NOT USED
71 **  BAR1 - I/O Addr  - 0x80
72 **  BAR2 - I/O Addr  - 0x20
73 */
74 int diva_bri_init_card(diva_os_xdi_adapter_t * a)
75 {
76         int bar;
77         dword bar2 = 0, bar2_length = 0xffffffff;
78         word cmd = 0, cmd_org;
79         byte Bus, Slot;
80         void *hdev;
81         byte __iomem *p;
82
83         /*
84            Set properties
85          */
86         a->xdi_adapter.Properties = CardProperties[a->CardOrdinal];
87         DBG_LOG(("Load %s", a->xdi_adapter.Properties.Name))
88
89             /*
90                Get resources
91              */
92             for (bar = 0; bar < 3; bar++) {
93                 a->resources.pci.bar[bar] =
94                     divasa_get_pci_bar(a->resources.pci.bus,
95                                        a->resources.pci.func, bar,
96                                        a->resources.pci.hdev);
97                 if (!a->resources.pci.bar[bar]) {
98                         DBG_ERR(("A: can't get BAR[%d]", bar))
99                         return (-1);
100                 }
101         }
102
103         a->resources.pci.irq =
104             (byte) divasa_get_pci_irq(a->resources.pci.bus,
105                                       a->resources.pci.func,
106                                       a->resources.pci.hdev);
107         if (!a->resources.pci.irq) {
108                 DBG_ERR(("A: invalid irq"));
109                 return (-1);
110         }
111
112         /*
113            Get length of I/O bar 2 - it is different by older
114            EEPROM version
115          */
116         Bus = a->resources.pci.bus;
117         Slot = a->resources.pci.func;
118         hdev = a->resources.pci.hdev;
119
120         /*
121            Get plain original values of the BAR2 CDM registers
122          */
123         PCIread(Bus, Slot, 0x18, &bar2, sizeof(bar2), hdev);
124         PCIread(Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev);
125         /*
126            Disable device and get BAR2 length
127          */
128         PCIwrite(Bus, Slot, 0x04, &cmd, sizeof(cmd), hdev);
129         PCIwrite(Bus, Slot, 0x18, &bar2_length, sizeof(bar2_length), hdev);
130         PCIread(Bus, Slot, 0x18, &bar2_length, sizeof(bar2_length), hdev);
131         /*
132            Restore BAR2 and CMD registers
133          */
134         PCIwrite(Bus, Slot, 0x18, &bar2, sizeof(bar2), hdev);
135         PCIwrite(Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev);
136
137         /*
138            Calculate BAR2 length
139          */
140         bar2_length = (~(bar2_length & ~7)) + 1;
141         DBG_LOG(("BAR[2] length=%lx", bar2_length))
142
143             /*
144                Map and register resources
145              */
146             if (!(a->resources.pci.addr[0] =
147                  divasa_remap_pci_bar(a, 0, a->resources.pci.bar[0],
148                                       bri_bar_length[0]))) {
149                 DBG_ERR(("A: BRI, can't map BAR[0]"))
150                 diva_bri_cleanup_adapter(a);
151                 return (-1);
152         }
153
154         sprintf(&a->port_name[0], "BRI %02x:%02x",
155                 a->resources.pci.bus, a->resources.pci.func);
156
157         if (diva_os_register_io_port(a, 1, a->resources.pci.bar[1],
158                                      bri_bar_length[1], &a->port_name[0], 1)) {
159                 DBG_ERR(("A: BRI, can't register BAR[1]"))
160                 diva_bri_cleanup_adapter(a);
161                 return (-1);
162         }
163         a->resources.pci.addr[1] = (void *) (unsigned long) a->resources.pci.bar[1];
164         a->resources.pci.length[1] = bri_bar_length[1];
165
166         if (diva_os_register_io_port(a, 1, a->resources.pci.bar[2],
167                                      bar2_length, &a->port_name[0], 2)) {
168                 DBG_ERR(("A: BRI, can't register BAR[2]"))
169                 diva_bri_cleanup_adapter(a);
170                 return (-1);
171         }
172         a->resources.pci.addr[2] = (void *) (unsigned long) a->resources.pci.bar[2];
173         a->resources.pci.length[2] = bar2_length;
174
175         /*
176            Set all memory areas
177          */
178         diva_bri_set_addresses(a);
179
180         /*
181            Get Serial Number
182          */
183         a->xdi_adapter.serialNo = diva_bri_get_serial_number(a);
184
185         /*
186            Register I/O ports with correct name now
187          */
188         if (diva_bri_reregister_io(a)) {
189                 diva_bri_cleanup_adapter(a);
190                 return (-1);
191         }
192
193         /*
194            Initialize OS dependent objects
195          */
196         if (diva_os_initialize_spin_lock
197             (&a->xdi_adapter.isr_spin_lock, "isr")) {
198                 diva_bri_cleanup_adapter(a);
199                 return (-1);
200         }
201         if (diva_os_initialize_spin_lock
202             (&a->xdi_adapter.data_spin_lock, "data")) {
203                 diva_bri_cleanup_adapter(a);
204                 return (-1);
205         }
206
207         strcpy(a->xdi_adapter.req_soft_isr.dpc_thread_name, "kdivasbrid");
208
209         if (diva_os_initialize_soft_isr(&a->xdi_adapter.req_soft_isr,
210                                         DIDpcRoutine, &a->xdi_adapter)) {
211                 diva_bri_cleanup_adapter(a);
212                 return (-1);
213         }
214         /*
215            Do not initialize second DPC - only one thread will be created
216          */
217         a->xdi_adapter.isr_soft_isr.object = a->xdi_adapter.req_soft_isr.object;
218
219         /*
220            Create entity table
221          */
222         a->xdi_adapter.Channels = CardProperties[a->CardOrdinal].Channels;
223         a->xdi_adapter.e_max = CardProperties[a->CardOrdinal].E_info;
224         a->xdi_adapter.e_tbl = diva_os_malloc(0, a->xdi_adapter.e_max * sizeof(E_INFO));
225         if (!a->xdi_adapter.e_tbl) {
226                 diva_bri_cleanup_adapter(a);
227                 return (-1);
228         }
229         memset(a->xdi_adapter.e_tbl, 0x00, a->xdi_adapter.e_max * sizeof(E_INFO));
230
231         /*
232            Set up interface
233          */
234         a->xdi_adapter.a.io = &a->xdi_adapter;
235         a->xdi_adapter.DIRequest = request;
236         a->interface.cleanup_adapter_proc = diva_bri_cleanup_adapter;
237         a->interface.cmd_proc = diva_bri_cmd_card_proc;
238
239         p = DIVA_OS_MEM_ATTACH_RESET(&a->xdi_adapter);
240         outpp(p, 0x41);
241         DIVA_OS_MEM_DETACH_RESET(&a->xdi_adapter, p);
242
243         prepare_maestra_functions(&a->xdi_adapter);
244
245         a->dsp_mask = 0x00000003;
246
247         /*
248            Set IRQ handler
249          */
250         a->xdi_adapter.irq_info.irq_nr = a->resources.pci.irq;
251         sprintf(a->xdi_adapter.irq_info.irq_name, "DIVA BRI %ld",
252                 (long) a->xdi_adapter.serialNo);
253         if (diva_os_register_irq(a, a->xdi_adapter.irq_info.irq_nr,
254                                  a->xdi_adapter.irq_info.irq_name)) {
255                 diva_bri_cleanup_adapter(a);
256                 return (-1);
257         }
258         a->xdi_adapter.irq_info.registered = 1;
259
260         diva_log_info("%s IRQ:%d SerNo:%d", a->xdi_adapter.Properties.Name,
261                       a->resources.pci.irq, a->xdi_adapter.serialNo);
262
263         return (0);
264 }
265
266
267 static int diva_bri_cleanup_adapter(diva_os_xdi_adapter_t * a)
268 {
269         int i;
270
271         if (a->xdi_adapter.Initialized) {
272                 diva_bri_stop_adapter(a);
273         }
274
275         /*
276            Remove ISR Handler
277          */
278         if (a->xdi_adapter.irq_info.registered) {
279                 diva_os_remove_irq(a, a->xdi_adapter.irq_info.irq_nr);
280         }
281         a->xdi_adapter.irq_info.registered = 0;
282
283         if (a->resources.pci.addr[0] && a->resources.pci.bar[0]) {
284                 divasa_unmap_pci_bar(a->resources.pci.addr[0]);
285                 a->resources.pci.addr[0] = NULL;
286                 a->resources.pci.bar[0] = 0;
287         }
288
289         for (i = 1; i < 3; i++) {
290                 if (a->resources.pci.addr[i] && a->resources.pci.bar[i]) {
291                         diva_os_register_io_port(a, 0,
292                                                  a->resources.pci.bar[i],
293                                                  a->resources.pci.
294                                                  length[i],
295                                                  &a->port_name[0], i);
296                         a->resources.pci.addr[i] = NULL;
297                         a->resources.pci.bar[i] = 0;
298                 }
299         }
300
301         /*
302            Free OS objects
303          */
304         diva_os_cancel_soft_isr(&a->xdi_adapter.req_soft_isr);
305         diva_os_cancel_soft_isr(&a->xdi_adapter.isr_soft_isr);
306
307         diva_os_remove_soft_isr(&a->xdi_adapter.req_soft_isr);
308         a->xdi_adapter.isr_soft_isr.object = NULL;
309
310         diva_os_destroy_spin_lock(&a->xdi_adapter.isr_spin_lock, "rm");
311         diva_os_destroy_spin_lock(&a->xdi_adapter.data_spin_lock, "rm");
312
313         /*
314            Free memory
315          */
316         if (a->xdi_adapter.e_tbl) {
317                 diva_os_free(0, a->xdi_adapter.e_tbl);
318                 a->xdi_adapter.e_tbl = NULL;
319         }
320
321         return (0);
322 }
323
324 void diva_os_prepare_maestra_functions(PISDN_ADAPTER IoAdapter)
325 {
326 }
327
328 /*
329 **  Get serial number
330 */
331 static dword diva_bri_get_serial_number(diva_os_xdi_adapter_t * a)
332 {
333         dword serNo = 0;
334         byte __iomem *confIO;
335         word serHi, serLo;
336         word __iomem *confMem;
337
338         confIO = DIVA_OS_MEM_ATTACH_CFG(&a->xdi_adapter);
339         serHi = (word) (inppw(&confIO[0x22]) & 0x0FFF);
340         serLo = (word) (inppw(&confIO[0x26]) & 0x0FFF);
341         serNo = ((dword) serHi << 16) | (dword) serLo;
342         DIVA_OS_MEM_DETACH_CFG(&a->xdi_adapter, confIO);
343
344         if ((serNo == 0) || (serNo == 0xFFFFFFFF)) {
345                 DBG_FTL(("W: BRI use BAR[0] to get card serial number"))
346
347                 confMem = (word __iomem *)DIVA_OS_MEM_ATTACH_RAM(&a->xdi_adapter);
348                 serHi = (word) (READ_WORD(&confMem[0x11]) & 0x0FFF);
349                 serLo = (word) (READ_WORD(&confMem[0x13]) & 0x0FFF);
350                 serNo = (((dword) serHi) << 16) | ((dword) serLo);
351                 DIVA_OS_MEM_DETACH_RAM(&a->xdi_adapter, confMem);
352         }
353
354         DBG_LOG(("Serial Number=%ld", serNo))
355
356         return (serNo);
357 }
358
359 /*
360 **  Unregister I/O and register it with new name,
361 **  based on Serial Number
362 */
363 static int diva_bri_reregister_io(diva_os_xdi_adapter_t * a)
364 {
365         int i;
366
367         for (i = 1; i < 3; i++) {
368                 diva_os_register_io_port(a, 0, a->resources.pci.bar[i],
369                                          a->resources.pci.length[i],
370                                          &a->port_name[0], i);
371                 a->resources.pci.addr[i] = NULL;
372         }
373
374         sprintf(a->port_name, "DIVA BRI %ld",
375                 (long) a->xdi_adapter.serialNo);
376
377         for (i = 1; i < 3; i++) {
378                 if (diva_os_register_io_port(a, 1, a->resources.pci.bar[i],
379                                              a->resources.pci.length[i],
380                                              &a->port_name[0], i)) {
381                         DBG_ERR(("A: failed to reregister BAR[%d]", i))
382                         return (-1);
383                 }
384                 a->resources.pci.addr[i] =
385                     (void *) (unsigned long) a->resources.pci.bar[i];
386         }
387
388         return (0);
389 }
390
391 /*
392 **  Process command from user mode
393 */
394 static int
395 diva_bri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
396                        diva_xdi_um_cfg_cmd_t * cmd, int length)
397 {
398         int ret = -1;
399
400         if (cmd->adapter != a->controller) {
401                 DBG_ERR(("A: pri_cmd, invalid controller=%d != %d",
402                          cmd->adapter, a->controller))
403                 return (-1);
404         }
405
406         switch (cmd->command) {
407         case DIVA_XDI_UM_CMD_GET_CARD_ORDINAL:
408                 a->xdi_mbox.data_length = sizeof(dword);
409                 a->xdi_mbox.data =
410                     diva_os_malloc(0, a->xdi_mbox.data_length);
411                 if (a->xdi_mbox.data) {
412                         *(dword *) a->xdi_mbox.data =
413                             (dword) a->CardOrdinal;
414                         a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
415                         ret = 0;
416                 }
417                 break;
418
419         case DIVA_XDI_UM_CMD_GET_SERIAL_NR:
420                 a->xdi_mbox.data_length = sizeof(dword);
421                 a->xdi_mbox.data =
422                     diva_os_malloc(0, a->xdi_mbox.data_length);
423                 if (a->xdi_mbox.data) {
424                         *(dword *) a->xdi_mbox.data =
425                             (dword) a->xdi_adapter.serialNo;
426                         a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
427                         ret = 0;
428                 }
429                 break;
430
431         case DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG:
432                 a->xdi_mbox.data_length = sizeof(dword) * 9;
433                 a->xdi_mbox.data =
434                     diva_os_malloc(0, a->xdi_mbox.data_length);
435                 if (a->xdi_mbox.data) {
436                         int i;
437                         dword *data = (dword *) a->xdi_mbox.data;
438
439                         for (i = 0; i < 8; i++) {
440                                 *data++ = a->resources.pci.bar[i];
441                         }
442                         *data++ = (dword) a->resources.pci.irq;
443                         a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
444                         ret = 0;
445                 }
446                 break;
447
448         case DIVA_XDI_UM_CMD_GET_CARD_STATE:
449                 a->xdi_mbox.data_length = sizeof(dword);
450                 a->xdi_mbox.data =
451                     diva_os_malloc(0, a->xdi_mbox.data_length);
452                 if (a->xdi_mbox.data) {
453                         dword *data = (dword *) a->xdi_mbox.data;
454                         if (!a->xdi_adapter.port) {
455                                 *data = 3;
456                         } else if (a->xdi_adapter.trapped) {
457                                 *data = 2;
458                         } else if (a->xdi_adapter.Initialized) {
459                                 *data = 1;
460                         } else {
461                                 *data = 0;
462                         }
463                         a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
464                         ret = 0;
465                 }
466                 break;
467
468         case DIVA_XDI_UM_CMD_RESET_ADAPTER:
469                 ret = diva_bri_reset_adapter(&a->xdi_adapter);
470                 break;
471
472         case DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK:
473                 ret = diva_bri_write_sdram_block(&a->xdi_adapter,
474                                                  cmd->command_data.
475                                                  write_sdram.offset,
476                                                  (byte *) & cmd[1],
477                                                  cmd->command_data.
478                                                  write_sdram.length);
479                 break;
480
481         case DIVA_XDI_UM_CMD_START_ADAPTER:
482                 ret = diva_bri_start_adapter(&a->xdi_adapter,
483                                              cmd->command_data.start.
484                                              offset,
485                                              cmd->command_data.start.
486                                              features);
487                 break;
488
489         case DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES:
490                 a->xdi_adapter.features =
491                     cmd->command_data.features.features;
492                 a->xdi_adapter.a.protocol_capabilities =
493                     a->xdi_adapter.features;
494                 DBG_TRC(
495                         ("Set raw protocol features (%08x)",
496                          a->xdi_adapter.features)) ret = 0;
497                 break;
498
499         case DIVA_XDI_UM_CMD_STOP_ADAPTER:
500                 ret = diva_bri_stop_adapter(a);
501                 break;
502
503         case DIVA_XDI_UM_CMD_READ_XLOG_ENTRY:
504                 ret = diva_card_read_xlog(a);
505                 break;
506
507         default:
508                 DBG_ERR(
509                         ("A: A(%d) invalid cmd=%d", a->controller,
510                          cmd->command))}
511
512         return (ret);
513 }
514
515 static int diva_bri_reset_adapter(PISDN_ADAPTER IoAdapter)
516 {
517         byte __iomem *addrHi, *addrLo, *ioaddr;
518         dword i;
519         byte __iomem *Port;
520
521         if (!IoAdapter->port) {
522                 return (-1);
523         }
524         if (IoAdapter->Initialized) {
525                 DBG_ERR(("A: A(%d) can't reset BRI adapter - please stop first",
526                          IoAdapter->ANum)) return (-1);
527         }
528         (*(IoAdapter->rstFnc)) (IoAdapter);
529         diva_os_wait(100);
530         Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
531         addrHi = Port +
532             ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
533         addrLo = Port + ADDR;
534         ioaddr = Port + DATA;
535         /*
536            recover
537          */
538         outpp(addrHi, (byte) 0);
539         outppw(addrLo, (word) 0);
540         outppw(ioaddr, (word) 0);
541         /*
542            clear shared memory
543          */
544         outpp(addrHi,
545               (byte) (
546                       (IoAdapter->MemoryBase + IoAdapter->MemorySize -
547                        BRI_SHARED_RAM_SIZE) >> 16));
548         outppw(addrLo, 0);
549         for (i = 0; i < 0x8000; outppw(ioaddr, 0), ++i);
550         diva_os_wait(100);
551
552         /*
553            clear signature
554          */
555         outpp(addrHi,
556               (byte) (
557                       (IoAdapter->MemoryBase + IoAdapter->MemorySize -
558                        BRI_SHARED_RAM_SIZE) >> 16));
559         outppw(addrLo, 0x1e);
560         outpp(ioaddr, 0);
561         outpp(ioaddr, 0);
562
563         outpp(addrHi, (byte) 0);
564         outppw(addrLo, (word) 0);
565         outppw(ioaddr, (word) 0);
566
567         DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
568
569         /*
570            Forget all outstanding entities
571          */
572         IoAdapter->e_count = 0;
573         if (IoAdapter->e_tbl) {
574                 memset(IoAdapter->e_tbl, 0x00,
575                        IoAdapter->e_max * sizeof(E_INFO));
576         }
577         IoAdapter->head = 0;
578         IoAdapter->tail = 0;
579         IoAdapter->assign = 0;
580         IoAdapter->trapped = 0;
581
582         memset(&IoAdapter->a.IdTable[0], 0x00,
583                sizeof(IoAdapter->a.IdTable));
584         memset(&IoAdapter->a.IdTypeTable[0], 0x00,
585                sizeof(IoAdapter->a.IdTypeTable));
586         memset(&IoAdapter->a.FlowControlIdTable[0], 0x00,
587                sizeof(IoAdapter->a.FlowControlIdTable));
588         memset(&IoAdapter->a.FlowControlSkipTable[0], 0x00,
589                sizeof(IoAdapter->a.FlowControlSkipTable));
590         memset(&IoAdapter->a.misc_flags_table[0], 0x00,
591                sizeof(IoAdapter->a.misc_flags_table));
592         memset(&IoAdapter->a.rx_stream[0], 0x00,
593                sizeof(IoAdapter->a.rx_stream));
594         memset(&IoAdapter->a.tx_stream[0], 0x00,
595                sizeof(IoAdapter->a.tx_stream));
596         memset(&IoAdapter->a.tx_pos[0], 0x00, sizeof(IoAdapter->a.tx_pos));
597         memset(&IoAdapter->a.rx_pos[0], 0x00, sizeof(IoAdapter->a.rx_pos));
598
599         return (0);
600 }
601
602 static int
603 diva_bri_write_sdram_block(PISDN_ADAPTER IoAdapter,
604                            dword address, const byte * data, dword length)
605 {
606         byte __iomem *addrHi, *addrLo, *ioaddr;
607         byte __iomem *Port;
608
609         if (!IoAdapter->port) {
610                 return (-1);
611         }
612
613         Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
614         addrHi = Port +
615             ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
616         addrLo = Port + ADDR;
617         ioaddr = Port + DATA;
618
619         while (length--) {
620                 outpp(addrHi, (word) (address >> 16));
621                 outppw(addrLo, (word) (address & 0x0000ffff));
622                 outpp(ioaddr, *data++);
623                 address++;
624         }
625
626         DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
627         return (0);
628 }
629
630 static int
631 diva_bri_start_adapter(PISDN_ADAPTER IoAdapter,
632                        dword start_address, dword features)
633 {
634         byte __iomem *Port;
635         dword i, test;
636         byte __iomem *addrHi, *addrLo, *ioaddr;
637         int started = 0;
638         ADAPTER *a = &IoAdapter->a;
639
640         if (IoAdapter->Initialized) {
641                 DBG_ERR(
642                         ("A: A(%d) bri_start_adapter, adapter already running",
643                          IoAdapter->ANum)) return (-1);
644         }
645         if (!IoAdapter->port) {
646                 DBG_ERR(("A: A(%d) bri_start_adapter, adapter not mapped",
647                          IoAdapter->ANum)) return (-1);
648         }
649
650         sprintf(IoAdapter->Name, "A(%d)", (int) IoAdapter->ANum);
651         DBG_LOG(("A(%d) start BRI", IoAdapter->ANum))
652
653         Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
654         addrHi = Port +
655             ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
656         addrLo = Port + ADDR;
657         ioaddr = Port + DATA;
658
659         outpp(addrHi,
660               (byte) (
661                       (IoAdapter->MemoryBase + IoAdapter->MemorySize -
662                        BRI_SHARED_RAM_SIZE) >> 16));
663         outppw(addrLo, 0x1e);
664         outppw(ioaddr, 0x00);
665         DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
666
667         /*
668            start the protocol code
669          */
670         Port = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
671         outpp(Port, 0x08);
672         DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, Port);
673
674         Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
675         addrHi = Port +
676             ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
677         addrLo = Port + ADDR;
678         ioaddr = Port + DATA;
679         /*
680            wait for signature (max. 3 seconds)
681          */
682         for (i = 0; i < 300; ++i) {
683                 diva_os_wait(10);
684                 outpp(addrHi,
685                       (byte) (
686                               (IoAdapter->MemoryBase +
687                                IoAdapter->MemorySize -
688                                BRI_SHARED_RAM_SIZE) >> 16));
689                 outppw(addrLo, 0x1e);
690                 test = (dword) inppw(ioaddr);
691                 if (test == 0x4447) {
692                         DBG_LOG(
693                                 ("Protocol startup time %d.%02d seconds",
694                                  (i / 100), (i % 100)))
695                         started = 1;
696                         break;
697                 }
698         }
699         DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
700
701         if (!started) {
702                 DBG_FTL(("A: A(%d) %s: Adapter selftest failed 0x%04X",
703                          IoAdapter->ANum, IoAdapter->Properties.Name,
704                          test))
705                 (*(IoAdapter->trapFnc)) (IoAdapter);
706                 return (-1);
707         }
708
709         IoAdapter->Initialized = 1;
710
711         /*
712            Check Interrupt
713          */
714         IoAdapter->IrqCount = 0;
715         a->ReadyInt = 1;
716
717         if (IoAdapter->reset) {
718                 Port = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
719                 outpp(Port, 0x41);
720                 DIVA_OS_MEM_DETACH_RESET(IoAdapter, Port);
721         }
722
723         a->ram_out(a, &PR_RAM->ReadyInt, 1);
724         for (i = 0; ((!IoAdapter->IrqCount) && (i < 100)); i++) {
725                 diva_os_wait(10);
726         }
727         if (!IoAdapter->IrqCount) {
728                 DBG_ERR(
729                         ("A: A(%d) interrupt test failed",
730                          IoAdapter->ANum))
731                 IoAdapter->Initialized = 0;
732                 IoAdapter->stop(IoAdapter);
733                 return (-1);
734         }
735
736         IoAdapter->Properties.Features = (word) features;
737         diva_xdi_display_adapter_features(IoAdapter->ANum);
738         DBG_LOG(("A(%d) BRI adapter successfull started", IoAdapter->ANum))
739             /*
740                Register with DIDD
741              */
742         diva_xdi_didd_register_adapter(IoAdapter->ANum);
743
744         return (0);
745 }
746
747 static void diva_bri_clear_interrupts(diva_os_xdi_adapter_t * a)
748 {
749         PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
750
751         /*
752            clear any pending interrupt
753          */
754         IoAdapter->disIrq(IoAdapter);
755
756         IoAdapter->tst_irq(&IoAdapter->a);
757         IoAdapter->clr_irq(&IoAdapter->a);
758         IoAdapter->tst_irq(&IoAdapter->a);
759
760         /*
761            kill pending dpcs
762          */
763         diva_os_cancel_soft_isr(&IoAdapter->req_soft_isr);
764         diva_os_cancel_soft_isr(&IoAdapter->isr_soft_isr);
765 }
766
767 /*
768 **  Stop card
769 */
770 static int diva_bri_stop_adapter(diva_os_xdi_adapter_t * a)
771 {
772         PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
773         int i = 100;
774
775         if (!IoAdapter->port) {
776                 return (-1);
777         }
778         if (!IoAdapter->Initialized) {
779                 DBG_ERR(("A: A(%d) can't stop BRI adapter - not running",
780                          IoAdapter->ANum))
781                 return (-1);    /* nothing to stop */
782         }
783         IoAdapter->Initialized = 0;
784
785         /*
786            Disconnect Adapter from DIDD
787          */
788         diva_xdi_didd_remove_adapter(IoAdapter->ANum);
789
790         /*
791            Stop interrupts
792          */
793         a->clear_interrupts_proc = diva_bri_clear_interrupts;
794         IoAdapter->a.ReadyInt = 1;
795         IoAdapter->a.ram_inc(&IoAdapter->a, &PR_RAM->ReadyInt);
796         do {
797                 diva_os_sleep(10);
798         } while (i-- && a->clear_interrupts_proc);
799         if (a->clear_interrupts_proc) {
800                 diva_bri_clear_interrupts(a);
801                 a->clear_interrupts_proc = NULL;
802                 DBG_ERR(("A: A(%d) no final interrupt from BRI adapter",
803                          IoAdapter->ANum))
804         }
805         IoAdapter->a.ReadyInt = 0;
806
807         /*
808            Stop and reset adapter
809          */
810         IoAdapter->stop(IoAdapter);
811
812         return (0);
813 }