ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.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 *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] = 0;
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] = 0;
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 = 0;
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 = 0;
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 *confIO;
335         word serHi, serLo, *confMem;
336
337         confIO = (byte *) DIVA_OS_MEM_ATTACH_CFG(&a->xdi_adapter);
338         serHi = (word) (inppw(&confIO[0x22]) & 0x0FFF);
339         serLo = (word) (inppw(&confIO[0x26]) & 0x0FFF);
340         serNo = ((dword) serHi << 16) | (dword) serLo;
341         DIVA_OS_MEM_DETACH_CFG(&a->xdi_adapter, confIO);
342
343         if ((serNo == 0) || (serNo == 0xFFFFFFFF)) {
344                 DBG_FTL(("W: BRI use BAR[0] to get card serial number"))
345
346                 confMem = (word *) DIVA_OS_MEM_ATTACH_RAM(&a->xdi_adapter);
347                 serHi = (word) (READ_WORD(&confMem[0x11]) & 0x0FFF);
348                 serLo = (word) (READ_WORD(&confMem[0x13]) & 0x0FFF);
349                 serNo = (((dword) serHi) << 16) | ((dword) serLo);
350                 DIVA_OS_MEM_DETACH_RAM(&a->xdi_adapter, confMem);
351         }
352
353         DBG_LOG(("Serial Number=%ld", serNo))
354
355         return (serNo);
356 }
357
358 /*
359 **  Unregister I/O and register it with new name,
360 **  based on Serial Number
361 */
362 static int diva_bri_reregister_io(diva_os_xdi_adapter_t * a)
363 {
364         int i;
365
366         for (i = 1; i < 3; i++) {
367                 diva_os_register_io_port(a, 0, a->resources.pci.bar[i],
368                                          a->resources.pci.length[i],
369                                          &a->port_name[0], i);
370                 a->resources.pci.addr[i] = 0;
371         }
372
373         sprintf(a->port_name, "DIVA BRI %ld",
374                 (long) a->xdi_adapter.serialNo);
375
376         for (i = 1; i < 3; i++) {
377                 if (diva_os_register_io_port(a, 1, a->resources.pci.bar[i],
378                                              a->resources.pci.length[i],
379                                              &a->port_name[0], i)) {
380                         DBG_ERR(("A: failed to reregister BAR[%d]", i))
381                         return (-1);
382                 }
383                 a->resources.pci.addr[i] =
384                     (void *) (unsigned long) a->resources.pci.bar[i];
385         }
386
387         return (0);
388 }
389
390 /*
391 **  Process command from user mode
392 */
393 static int
394 diva_bri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
395                        diva_xdi_um_cfg_cmd_t * cmd, int length)
396 {
397         int ret = -1;
398
399         if (cmd->adapter != a->controller) {
400                 DBG_ERR(("A: pri_cmd, invalid controller=%d != %d",
401                          cmd->adapter, a->controller))
402                 return (-1);
403         }
404
405         switch (cmd->command) {
406         case DIVA_XDI_UM_CMD_GET_CARD_ORDINAL:
407                 a->xdi_mbox.data_length = sizeof(dword);
408                 a->xdi_mbox.data =
409                     diva_os_malloc(0, a->xdi_mbox.data_length);
410                 if (a->xdi_mbox.data) {
411                         *(dword *) a->xdi_mbox.data =
412                             (dword) a->CardOrdinal;
413                         a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
414                         ret = 0;
415                 }
416                 break;
417
418         case DIVA_XDI_UM_CMD_GET_SERIAL_NR:
419                 a->xdi_mbox.data_length = sizeof(dword);
420                 a->xdi_mbox.data =
421                     diva_os_malloc(0, a->xdi_mbox.data_length);
422                 if (a->xdi_mbox.data) {
423                         *(dword *) a->xdi_mbox.data =
424                             (dword) a->xdi_adapter.serialNo;
425                         a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
426                         ret = 0;
427                 }
428                 break;
429
430         case DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG:
431                 a->xdi_mbox.data_length = sizeof(dword) * 9;
432                 a->xdi_mbox.data =
433                     diva_os_malloc(0, a->xdi_mbox.data_length);
434                 if (a->xdi_mbox.data) {
435                         int i;
436                         dword *data = (dword *) a->xdi_mbox.data;
437
438                         for (i = 0; i < 8; i++) {
439                                 *data++ = a->resources.pci.bar[i];
440                         }
441                         *data++ = (dword) a->resources.pci.irq;
442                         a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
443                         ret = 0;
444                 }
445                 break;
446
447         case DIVA_XDI_UM_CMD_GET_CARD_STATE:
448                 a->xdi_mbox.data_length = sizeof(dword);
449                 a->xdi_mbox.data =
450                     diva_os_malloc(0, a->xdi_mbox.data_length);
451                 if (a->xdi_mbox.data) {
452                         dword *data = (dword *) a->xdi_mbox.data;
453                         if (!a->xdi_adapter.port) {
454                                 *data = 3;
455                         } else if (a->xdi_adapter.trapped) {
456                                 *data = 2;
457                         } else if (a->xdi_adapter.Initialized) {
458                                 *data = 1;
459                         } else {
460                                 *data = 0;
461                         }
462                         a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
463                         ret = 0;
464                 }
465                 break;
466
467         case DIVA_XDI_UM_CMD_RESET_ADAPTER:
468                 ret = diva_bri_reset_adapter(&a->xdi_adapter);
469                 break;
470
471         case DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK:
472                 ret = diva_bri_write_sdram_block(&a->xdi_adapter,
473                                                  cmd->command_data.
474                                                  write_sdram.offset,
475                                                  (byte *) & cmd[1],
476                                                  cmd->command_data.
477                                                  write_sdram.length);
478                 break;
479
480         case DIVA_XDI_UM_CMD_START_ADAPTER:
481                 ret = diva_bri_start_adapter(&a->xdi_adapter,
482                                              cmd->command_data.start.
483                                              offset,
484                                              cmd->command_data.start.
485                                              features);
486                 break;
487
488         case DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES:
489                 a->xdi_adapter.features =
490                     cmd->command_data.features.features;
491                 a->xdi_adapter.a.protocol_capabilities =
492                     a->xdi_adapter.features;
493                 DBG_TRC(
494                         ("Set raw protocol features (%08x)",
495                          a->xdi_adapter.features)) ret = 0;
496                 break;
497
498         case DIVA_XDI_UM_CMD_STOP_ADAPTER:
499                 ret = diva_bri_stop_adapter(a);
500                 break;
501
502         case DIVA_XDI_UM_CMD_READ_XLOG_ENTRY:
503                 ret = diva_card_read_xlog(a);
504                 break;
505
506         default:
507                 DBG_ERR(
508                         ("A: A(%d) invalid cmd=%d", a->controller,
509                          cmd->command))}
510
511         return (ret);
512 }
513
514 static int diva_bri_reset_adapter(PISDN_ADAPTER IoAdapter)
515 {
516         byte *addrHi, *addrLo, *ioaddr;
517         dword i;
518         byte *Port;
519
520         if (!IoAdapter->port) {
521                 return (-1);
522         }
523         if (IoAdapter->Initialized) {
524                 DBG_ERR(("A: A(%d) can't reset BRI adapter - please stop first",
525                          IoAdapter->ANum)) return (-1);
526         }
527         (*(IoAdapter->rstFnc)) (IoAdapter);
528         diva_os_wait(100);
529         Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
530         addrHi = Port +
531             ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
532         addrLo = Port + ADDR;
533         ioaddr = Port + DATA;
534         /*
535            recover
536          */
537         outpp(addrHi, (byte) 0);
538         outppw(addrLo, (word) 0);
539         outppw(ioaddr, (word) 0);
540         /*
541            clear shared memory
542          */
543         outpp(addrHi,
544               (byte) (
545                       (IoAdapter->MemoryBase + IoAdapter->MemorySize -
546                        BRI_SHARED_RAM_SIZE) >> 16));
547         outppw(addrLo, 0);
548         for (i = 0; i < 0x8000; outppw(ioaddr, 0), ++i);
549         diva_os_wait(100);
550
551         /*
552            clear signature
553          */
554         outpp(addrHi,
555               (byte) (
556                       (IoAdapter->MemoryBase + IoAdapter->MemorySize -
557                        BRI_SHARED_RAM_SIZE) >> 16));
558         outppw(addrLo, 0x1e);
559         outpp(ioaddr, 0);
560         outpp(ioaddr, 0);
561
562         outpp(addrHi, (byte) 0);
563         outppw(addrLo, (word) 0);
564         outppw(ioaddr, (word) 0);
565
566         DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
567
568         /*
569            Forget all outstanding entities
570          */
571         IoAdapter->e_count = 0;
572         if (IoAdapter->e_tbl) {
573                 memset(IoAdapter->e_tbl, 0x00,
574                        IoAdapter->e_max * sizeof(E_INFO));
575         }
576         IoAdapter->head = 0;
577         IoAdapter->tail = 0;
578         IoAdapter->assign = 0;
579         IoAdapter->trapped = 0;
580
581         memset(&IoAdapter->a.IdTable[0], 0x00,
582                sizeof(IoAdapter->a.IdTable));
583         memset(&IoAdapter->a.IdTypeTable[0], 0x00,
584                sizeof(IoAdapter->a.IdTypeTable));
585         memset(&IoAdapter->a.FlowControlIdTable[0], 0x00,
586                sizeof(IoAdapter->a.FlowControlIdTable));
587         memset(&IoAdapter->a.FlowControlSkipTable[0], 0x00,
588                sizeof(IoAdapter->a.FlowControlSkipTable));
589         memset(&IoAdapter->a.misc_flags_table[0], 0x00,
590                sizeof(IoAdapter->a.misc_flags_table));
591         memset(&IoAdapter->a.rx_stream[0], 0x00,
592                sizeof(IoAdapter->a.rx_stream));
593         memset(&IoAdapter->a.tx_stream[0], 0x00,
594                sizeof(IoAdapter->a.tx_stream));
595         memset(&IoAdapter->a.tx_pos[0], 0x00, sizeof(IoAdapter->a.tx_pos));
596         memset(&IoAdapter->a.rx_pos[0], 0x00, sizeof(IoAdapter->a.rx_pos));
597
598         return (0);
599 }
600
601 static int
602 diva_bri_write_sdram_block(PISDN_ADAPTER IoAdapter,
603                            dword address, const byte * data, dword length)
604 {
605         byte *addrHi, *addrLo, *ioaddr;
606         byte *Port;
607
608         if (!IoAdapter->port) {
609                 return (-1);
610         }
611
612         Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
613         addrHi = Port +
614             ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
615         addrLo = Port + ADDR;
616         ioaddr = Port + DATA;
617
618         while (length--) {
619                 outpp(addrHi, (word) (address >> 16));
620                 outppw(addrLo, (word) (address & 0x0000ffff));
621                 outpp(ioaddr, *data++);
622                 address++;
623         }
624
625         DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
626         return (0);
627 }
628
629 static int
630 diva_bri_start_adapter(PISDN_ADAPTER IoAdapter,
631                        dword start_address, dword features)
632 {
633         byte *Port;
634         dword i, test;
635         byte *addrHi, *addrLo, *ioaddr;
636         int started = 0;
637         ADAPTER *a = &IoAdapter->a;
638
639         if (IoAdapter->Initialized) {
640                 DBG_ERR(
641                         ("A: A(%d) bri_start_adapter, adapter already running",
642                          IoAdapter->ANum)) return (-1);
643         }
644         if (!IoAdapter->port) {
645                 DBG_ERR(("A: A(%d) bri_start_adapter, adapter not mapped",
646                          IoAdapter->ANum)) return (-1);
647         }
648
649         sprintf(IoAdapter->Name, "A(%d)", (int) IoAdapter->ANum);
650         DBG_LOG(("A(%d) start BRI", IoAdapter->ANum))
651
652         Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
653         addrHi = Port +
654             ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
655         addrLo = Port + ADDR;
656         ioaddr = Port + DATA;
657
658         outpp(addrHi,
659               (byte) (
660                       (IoAdapter->MemoryBase + IoAdapter->MemorySize -
661                        BRI_SHARED_RAM_SIZE) >> 16));
662         outppw(addrLo, 0x1e);
663         outppw(ioaddr, 0x00);
664         DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
665
666         /*
667            start the protocol code
668          */
669         Port = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
670         outpp(Port, 0x08);
671         DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, Port);
672
673         Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
674         addrHi = Port +
675             ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
676         addrLo = Port + ADDR;
677         ioaddr = Port + DATA;
678         /*
679            wait for signature (max. 3 seconds)
680          */
681         for (i = 0; i < 300; ++i) {
682                 diva_os_wait(10);
683                 outpp(addrHi,
684                       (byte) (
685                               (IoAdapter->MemoryBase +
686                                IoAdapter->MemorySize -
687                                BRI_SHARED_RAM_SIZE) >> 16));
688                 outppw(addrLo, 0x1e);
689                 test = (dword) inppw(ioaddr);
690                 if (test == 0x4447) {
691                         DBG_LOG(
692                                 ("Protocol startup time %d.%02d seconds",
693                                  (i / 100), (i % 100)))
694                         started = 1;
695                         break;
696                 }
697         }
698         DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
699
700         if (!started) {
701                 DBG_FTL(("A: A(%d) %s: Adapter selftest failed 0x%04X",
702                          IoAdapter->ANum, IoAdapter->Properties.Name,
703                          test))
704                 (*(IoAdapter->trapFnc)) (IoAdapter);
705                 return (-1);
706         }
707
708         IoAdapter->Initialized = 1;
709
710         /*
711            Check Interrupt
712          */
713         IoAdapter->IrqCount = 0;
714         a->ReadyInt = 1;
715
716         if (IoAdapter->reset) {
717                 Port = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
718                 outpp(Port, 0x41);
719                 DIVA_OS_MEM_DETACH_RESET(IoAdapter, Port);
720         }
721
722         a->ram_out(a, &PR_RAM->ReadyInt, 1);
723         for (i = 0; ((!IoAdapter->IrqCount) && (i < 100)); i++) {
724                 diva_os_wait(10);
725         }
726         if (!IoAdapter->IrqCount) {
727                 DBG_ERR(
728                         ("A: A(%d) interrupt test failed",
729                          IoAdapter->ANum))
730                 IoAdapter->Initialized = 0;
731                 IoAdapter->stop(IoAdapter);
732                 return (-1);
733         }
734
735         IoAdapter->Properties.Features = (word) features;
736         diva_xdi_display_adapter_features(IoAdapter->ANum);
737         DBG_LOG(("A(%d) BRI adapter successfull started", IoAdapter->ANum))
738             /*
739                Register with DIDD
740              */
741         diva_xdi_didd_register_adapter(IoAdapter->ANum);
742
743         return (0);
744 }
745
746 static void diva_bri_clear_interrupts(diva_os_xdi_adapter_t * a)
747 {
748         PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
749
750         /*
751            clear any pending interrupt
752          */
753         IoAdapter->disIrq(IoAdapter);
754
755         IoAdapter->tst_irq(&IoAdapter->a);
756         IoAdapter->clr_irq(&IoAdapter->a);
757         IoAdapter->tst_irq(&IoAdapter->a);
758
759         /*
760            kill pending dpcs
761          */
762         diva_os_cancel_soft_isr(&IoAdapter->req_soft_isr);
763         diva_os_cancel_soft_isr(&IoAdapter->isr_soft_isr);
764 }
765
766 /*
767 **  Stop card
768 */
769 static int diva_bri_stop_adapter(diva_os_xdi_adapter_t * a)
770 {
771         PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
772         int i = 100;
773
774         if (!IoAdapter->port) {
775                 return (-1);
776         }
777         if (!IoAdapter->Initialized) {
778                 DBG_ERR(("A: A(%d) can't stop BRI adapter - not running",
779                          IoAdapter->ANum))
780                 return (-1);    /* nothing to stop */
781         }
782         IoAdapter->Initialized = 0;
783
784         /*
785            Disconnect Adapter from DIDD
786          */
787         diva_xdi_didd_remove_adapter(IoAdapter->ANum);
788
789         /*
790            Stop interrupts
791          */
792         a->clear_interrupts_proc = diva_bri_clear_interrupts;
793         IoAdapter->a.ReadyInt = 1;
794         IoAdapter->a.ram_inc(&IoAdapter->a, &PR_RAM->ReadyInt);
795         do {
796                 diva_os_sleep(10);
797         } while (i-- && a->clear_interrupts_proc);
798         if (a->clear_interrupts_proc) {
799                 diva_bri_clear_interrupts(a);
800                 a->clear_interrupts_proc = 0;
801                 DBG_ERR(("A: A(%d) no final interrupt from BRI adapter",
802                          IoAdapter->ANum))
803         }
804         IoAdapter->a.ReadyInt = 0;
805
806         /*
807            Stop and reset adapter
808          */
809         IoAdapter->stop(IoAdapter);
810
811         return (0);
812 }