This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / net / wan / comx-hw-munich.c
1 /*
2  * Hardware-level driver for the SliceCOM board for Linux kernels 2.4.X
3  *
4  * Current maintainer / latest changes: Pasztor Szilard <don@itc.hu>
5  *
6  * Original author: Bartok Istvan <bartoki@itc.hu>
7  * Based on skeleton by Tivadar Szemethy <tiv@itc.hu>
8  *
9  * 0.51:
10  *      - port for 2.4.x
11  *      - clean up some code, make it more portable
12  *      - busted direct hardware access through mapped memory
13  *      - fix a possible race
14  *      - prevent procfs buffer overflow
15  *
16  * 0.50:
17  *      - support for the pcicom board, lots of rearrangements
18  *      - handle modem status lines
19  *
20  * 0.50a:
21  *      - fix for falc version 1.0
22  *
23  * 0.50b: T&t
24  *      - fix for bad localbus
25  */
26
27 #define VERSION         "0.51"
28 #define VERSIONSTR      "SliceCOM v" VERSION ", 2002/01/07\n"
29
30 #include <linux/config.h>
31 #include <linux/ctype.h>
32 #include <linux/module.h>
33 #include <linux/types.h>
34 #include <linux/netdevice.h>
35 #include <linux/proc_fs.h>
36 #include <linux/ioport.h>
37 #include <linux/pci.h>
38 #include <linux/init.h>
39
40 #include <asm/delay.h>
41 #include <asm/types.h>
42 #include <asm/uaccess.h>
43 #include <asm/io.h>
44
45 #define COMX_NEW
46
47 #ifndef COMX_NEW
48 #include "../include/comx.h"
49 #include "../include/munich32x.h"
50 #include "../include/falc-lh.h"
51 #else
52 #include "comx.h"
53 #include "munich32x.h"
54 #include "falc-lh.h"
55 #endif
56
57 MODULE_AUTHOR("Bartok Istvan <bartoki@itc.hu>, Gergely Madarasz <gorgo@itc.hu>, Szilard Pasztor <don@itc.hu>");
58 MODULE_DESCRIPTION("Hardware-level driver for the SliceCOM and PciCOM (WelCOM) adapters");
59 MODULE_LICENSE("GPL");
60 /*
61  *      TODO: az ilyenek a comxhw.h -ban szoktak lenni, idovel menjenek majd oda:
62  */
63
64 #define FILENAME_BOARDNUM       "boardnum"      /* /proc/comx/comx0.1/boardnum          */
65 #define FILENAME_TIMESLOTS      "timeslots"     /* /proc/comx/comx0.1/timeslots         */
66 #define FILENAME_FRAMING        "framing"       /* /proc/comx/comx0.1/framing           */
67 #define FILENAME_LINECODE       "linecode"      /* /proc/comx/comx0.1/linecode          */
68 #define FILENAME_CLOCK_SOURCE   "clock_source"  /* /proc/comx/comx0.1/clock_source      */
69 #define FILENAME_LOOPBACK       "loopback"      /* /proc/comx/comx0.1/loopback          */
70 #define FILENAME_REG            "reg"           /* /proc/comx/comx0.1/reg               */
71 #define FILENAME_LBIREG         "lbireg"        /* /proc/comx/comx0.1/lbireg            */
72
73 #define SLICECOM_BOARDNUM_DEFAULT       0
74
75 #define SLICECOM_FRAMING_CRC4           1
76 #define SLICECOM_FRAMING_NO_CRC4        2
77 #define SLICECOM_FRAMING_DEFAULT        SLICECOM_FRAMING_CRC4
78
79 #define SLICECOM_LINECODE_HDB3          1
80 #define SLICECOM_LINECODE_AMI           2
81 #define SLICECOM_LINECODE_DEFAULT       SLICECOM_LINECODE_HDB3
82
83 #define SLICECOM_CLOCK_SOURCE_LINE      1
84 #define SLICECOM_CLOCK_SOURCE_INTERNAL  2
85 #define SLICECOM_CLOCK_SOURCE_DEFAULT   SLICECOM_CLOCK_SOURCE_LINE
86
87 #define SLICECOM_LOOPBACK_NONE          1
88 #define SLICECOM_LOOPBACK_LOCAL         2
89 #define SLICECOM_LOOPBACK_REMOTE        3
90 #define SLICECOM_LOOPBACK_DEFAULT       SLICECOM_LOOPBACK_NONE
91
92 #define MUNICH_VIRT(addr) (void *)(&bar1[addr])
93
94 struct slicecom_stringtable
95 {
96     char *name;
97     int value;
98 };
99
100 /* A convention: keep "default" the last not NULL when reading from /proc,
101    "error" is an indication that something went wrong, we have an undefined value */
102
103 struct slicecom_stringtable slicecom_framings[] =
104 {
105     {"crc4", SLICECOM_FRAMING_CRC4},
106     {"no-crc4", SLICECOM_FRAMING_NO_CRC4},
107     {"default", SLICECOM_FRAMING_DEFAULT},
108     {"error", 0}
109 };
110
111 struct slicecom_stringtable slicecom_linecodes[] =
112 {
113     {"hdb3", SLICECOM_LINECODE_HDB3},
114     {"ami", SLICECOM_LINECODE_AMI},
115     {"default", SLICECOM_LINECODE_DEFAULT},
116     {"error", 0}
117 };
118
119 struct slicecom_stringtable slicecom_clock_sources[] =
120 {
121     {"line", SLICECOM_CLOCK_SOURCE_LINE},
122     {"internal", SLICECOM_CLOCK_SOURCE_INTERNAL},
123     {"default", SLICECOM_CLOCK_SOURCE_DEFAULT},
124     {"error", 0}
125 };
126
127 struct slicecom_stringtable slicecom_loopbacks[] =
128 {
129     {"none", SLICECOM_LOOPBACK_NONE},
130     {"local", SLICECOM_LOOPBACK_LOCAL},
131     {"remote", SLICECOM_LOOPBACK_REMOTE},
132     {"default", SLICECOM_LOOPBACK_DEFAULT},
133     {"error", 0}
134 };
135
136 /*
137  *      Some tunable values...
138  *
139  *      Note: when tuning values which change the length of text in
140  *      /proc/comx/comx[n]/status, keep in mind that it must be shorter then
141  *      PAGESIZE !
142  */
143
144 #define MAX_BOARDS      4       /* ezzel 4 kartya lehet a gepben: 0..3          */
145 #define RX_DESC_MAX     8       /* Rx ring size, must be >= 4                   */
146 #define TX_DESC_MAX     4       /* Tx ring size, must be >= 2                   */
147                                 /* a sokkal hosszabb Tx ring mar ronthatja a nem-FIFO packet    */
148                                 /* schedulerek (fair queueing, stb.) hatekonysagat.             */
149 #define MAX_WORK        10      /* TOD: update the info max. ennyi-1 esemenyt dolgoz fel egy interrupt hivasnal */
150
151 /*
152  *      These are tunable too, but don't touch them without fully understanding what is happening
153  */
154
155 #define UDELAY          20      /* We wait UDELAY usecs with disabled interrupts before and     */
156                                 /* after each command to avoid writing into each other's        */
157                                 /* ccb->action_spec. A _send_packet nem var, mert azt az        */
158                                 /* _interrupt()-bol is meghivhatja a LINE_tx()                  */
159
160 /*
161  *      Just to avoid warnings about implicit declarations:
162  */
163
164 static int MUNICH_close(struct net_device *dev);
165 static struct comx_hardware slicecomhw;
166 static struct comx_hardware pcicomhw;
167
168 static unsigned long flags;
169 static spinlock_t mister_lock = SPIN_LOCK_UNLOCKED;
170
171 typedef volatile struct         /* Time Slot Assignment */
172 {
173     u32 rxfillmask:8,           // ----------------------------+------+
174                                 //                             |      |
175       rxchannel:5,              // ----------------------+---+ |      |
176       rti:1,                    // ---------------------+|   | |      |
177       res2:2,                   // -------------------++||   | |      |
178                                 //                    ||||   | |      |
179       txfillmask:8,             // ----------+------+ ||||   | |      |
180                                 //           |      | ||||   | |      |
181       txchannel:5,              // ----+---+ |      | ||||   | |      |
182       tti:1,                    // ---+|   | |      | ||||   | |      |
183       res1:2;                   // -++||   | |      | ||||   | |      |
184                                 //   3          2          1
185                                 //  10987654 32109876 54321098 76543210
186 } timeslot_spec_t;
187
188 typedef volatile struct         /* Receive Descriptor */
189 {
190     u32 zero1:16, no:13, hi:1, hold:1, zero2:1;
191
192     u32 next;
193     u32 data;
194
195     u32 zero3:8, status:8, bno:13, zero4:1, c:1, fe:1;
196 } rx_desc_t;
197
198 typedef volatile struct         /* Transmit Descriptor */
199 {
200     u32 fnum:11, csm:1, no13:1, zero1:2, v110:1, no:13, hi:1, hold:1, fe:1;
201
202     u32 next;
203     u32 data;
204
205 } tx_desc_t;
206
207 typedef volatile struct         /* Channel Specification */
208 {
209     u32 iftf:1, mode:2, fa:1, trv:2, crc:1, inv:1, cs:1, tflag:7, ra:1, ro:1,
210         th:1, ta:1, to:1, ti:1, ri:1, nitbs:1, fit:1, fir:1, re:1, te:1, ch:1,
211         ifc:1, sfe:1, fe2:1;
212
213     u32 frda;
214     u32 ftda;
215
216     u32 itbs:6, zero1:26;
217
218 } channel_spec_t;
219
220 typedef volatile struct         /* Configuration Control Block */
221 {
222     u32 action_spec;
223     u32 reserved1;
224     u32 reserved2;
225     timeslot_spec_t timeslot_spec[32];
226     channel_spec_t channel_spec[32];
227     u32 current_rx_desc[32];
228     u32 current_tx_desc[32];
229     u32 csa;                    /* Control Start Address. CSA = *CCBA; CCB = *CSA */
230                                 /* MUNICH does it like: CCB = *( *CCBA )          */
231 } munich_ccb_t;
232
233 typedef volatile struct         /* Entry in the interrupt queue */
234 {
235     u32 all;
236 } munich_intq_t;
237
238 #define MUNICH_INTQLEN  63      /* Rx/Tx Interrupt Queue Length
239                                    (not the real len, but the TIQL/RIQL value)  */
240 #define MUNICH_INTQMAX  ( 16*(MUNICH_INTQLEN+1) )       /* Rx/Tx/Periph Interrupt Queue size in munich_intq_t's */
241 #define MUNICH_INTQSIZE ( 4*MUNICH_INTQMAX )    /* Rx/Tx/Periph Interrupt Queue size in bytes           */
242
243 #define MUNICH_PIQLEN   4       /* Peripheral Interrupt Queue Length. Unlike the RIQL/TIQL, */
244 #define MUNICH_PIQMAX   ( 4*MUNICH_PIQLEN )     /* PIQL register needs it like this                     */
245 #define MUNICH_PIQSIZE  ( 4*MUNICH_PIQMAX )
246
247 typedef volatile u32 vol_u32;   /* TOD: ezek megszunnek ha atirom readw()/writew()-re - kész */
248 typedef volatile u8 vol_u8;
249
250 typedef volatile struct         /* counters of E1-errors and errored seconds, see rfc2495 */
251 {
252     /* use here only unsigned ints, we depend on it when calculating the sum for the last N intervals */
253
254     unsigned line_code_violations,      /* AMI: bipolar violations, HDB3: hdb3 violations                       */
255       path_code_violations,     /* FAS errors and CRC4 errors                                                   */
256       e_bit_errors,             /* E-Bit Errors (the remote side received from us with CRC4-error) */
257       slip_secs,                /* number of seconds with (receive) Controlled Slip(s)          */
258       fr_loss_secs,             /* number of seconds an Out Of Frame defect was detected                */
259       line_err_secs,            /* number of seconds with one or more Line Code Violations              */
260       degraded_mins,            /* Degraded Minute - the estimated error rate is >1E-6, but <1E-3       */
261       errored_secs,             /* Errored Second - at least one of these happened:
262                                    - Path Code Violation
263                                    - Out Of Frame defect
264                                    - Slip
265                                    - receiving AIS
266                                    - not incremented during an Unavailable Second                       */
267       bursty_err_secs,          /* Bursty Errored Second: (rfc2495 says it does not apply to E1)
268                                    - Path Code Violations >1, but <320
269                                    - not a Severely Errored Second
270                                    - no AIS
271                                    - not incremented during an Unavailabla Second                       */
272       severely_err_secs,        /* Severely Errored Second:
273                                    - CRC4: >=832 Path COde Violations || >0 Out Of Frame defects
274                                    - noCRC4: >=2048 Line Code Violations
275                                    - not incremented during an Unavailable Second                       */
276       unavail_secs;             /* number of Unavailable Seconds. Unavailable state is said after:
277                                    - 10 contiguous Severely Errored Seconds
278                                    - or RAI || AIS || LOF || LOS 
279                                    - (any) loopback has been set                                                */
280
281     /*
282      * we do not strictly comply to the rfc: we do not retroactively reduce errored_secs,
283      * bursty_err_secs, severely_err_secs when 'unavailable state' is reached
284      */
285
286 } e1_stats_t;
287
288 typedef volatile struct         /* ezek board-adatok, nem lehetnek a slicecom_privdata -ban     */
289 {
290     int use_count;              /* num. of interfaces using the board                           */
291     int irq;                    /* a kartya irq-ja. belemasoljuk a dev->irq -kba is, de csak hogy       */
292     /* szebb legyen az ifconfig outputja                            */
293     /* ha != 0, az azt jelenti hogy az az irq most nekunk sikeresen */
294     /* le van foglalva                                              */
295     struct pci_dev *pci;        /* a kartya PCI strukturaja. NULL, ha nincs kartya              */
296     u32 *bar1;                  /* pci->base_address[0] ioremap()-ed by munich_probe(),         */
297     /* on x86 can be used both as a bus or virtual address.         */
298     /* These are the Munich's registers                             */
299     u8 *lbi;                    /* pci->base_address[1] ioremap()-ed by munich_probe(),         */
300     /* this is a 256-byte range, the start of the LBI on the board  */
301     munich_ccb_t *ccb;          /* virtual address of CCB                                       */
302     munich_intq_t *tiq;         /* Tx Interrupt Queue                                           */
303     munich_intq_t *riq;         /* Rx Interrupt Queue                                           */
304     munich_intq_t *piq;         /* Peripheral Interrupt Queue (FALC interrupts arrive here)     */
305     int tiq_ptr,                /* A 'current' helyek a tiq/riq/piq -ban.                       */
306       riq_ptr,                  /* amikor feldolgoztam az interruptokat, a legelso ures         */
307       piq_ptr;                  /* interrupt_information szora mutatnak.                        */
308     struct net_device *twins[32];       /* MUNICH channel -> network interface assignment       */
309
310     unsigned long lastcheck;    /* When were the Rx rings last checked. Time in jiffies         */
311
312     struct timer_list modemline_timer;
313     char isx21;
314     char lineup;
315     char framing;               /* a beallitasok tarolasa                               */
316     char linecode;
317     char clock_source;
318     char loopback;
319
320     char devname[30];           /* what to show in /proc/interrupts                     */
321     unsigned histogram[MAX_WORK];       /* number of processed events in the interrupt loop     */
322     unsigned stat_pri_races;    /* number of special events, we try to handle them      */
323     unsigned stat_pti_races;
324     unsigned stat_pri_races_missed;     /* when it can not be handled, because of MAX_WORK      */
325     unsigned stat_pti_races_missed;
326
327 #define SLICECOM_BOARD_INTERVALS_SIZE   97
328     e1_stats_t intervals[SLICECOM_BOARD_INTERVALS_SIZE];        /* E1 line statistics           */
329     unsigned current_interval;  /* pointer to the current interval                      */
330     unsigned elapsed_seconds;   /* elapsed seconds from the start of the current interval */
331     unsigned ses_seconds;       /* counter of contiguous Severely Errored Seconds       */
332     unsigned is_unavailable;    /* set to 1 after 10 contiguous Severely Errored Seconds */
333     unsigned no_ses_seconds;    /* contiguous Severely Error -free seconds in unavail state */
334
335     unsigned deg_elapsed_seconds;       /* for counting the 'Degraded Mins'                     */
336     unsigned deg_cumulated_errors;
337
338     struct module *owner;       /* pointer to our module to avoid module load races */
339 } munich_board_t;
340
341 struct slicecom_privdata
342 {
343     int busy;                   /* transmitter busy - number of packets in the Tx ring  */
344     int channel;                /* Munich logical channel ('channel-group' in Cisco)    */
345     unsigned boardnum;
346     u32 timeslots;              /* i-th bit means i-th timeslot is our                  */
347
348     int tx_ring_hist[TX_DESC_MAX];      /* histogram: number of packets in Tx ring when _send_packet is called  */
349
350     tx_desc_t tx_desc[TX_DESC_MAX];     /* the ring of Tx descriptors                           */
351     u8 tx_data[TX_DESC_MAX][TXBUFFER_SIZE];     /* buffers for data to transmit                 */
352     int tx_desc_ptr;            /* hanyadik descriptornal tartunk a beirassal   */
353     /* ahol ez all, oda irtunk utoljara                     */
354
355     rx_desc_t rx_desc[RX_DESC_MAX];     /* the ring of Rx descriptors                           */
356     u8 rx_data[RX_DESC_MAX][RXBUFFER_SIZE];     /* buffers for received data                            */
357     int rx_desc_ptr;            /* hanyadik descriptornal tartunk az olvasassal */
358
359     int rafutott;
360 };
361
362 static u32 reg, reg_ertek;      /* why static: don't write stack trash into regs if strtoul() fails */
363 static u32 lbireg;
364 static u8 lbireg_ertek;         /* why static: don't write stack trash into regs if strtoul() fails */
365
366 static munich_board_t slicecom_boards[MAX_BOARDS];
367 static munich_board_t pcicom_boards[MAX_BOARDS];
368
369 /*
370  * Reprogram Idle Channel Registers in the FALC - send special code in not used channels
371  * Should be called from the open and close, when the timeslot assignment changes
372  */
373
374 void rework_idle_channels(struct net_device *dev)
375 {
376     struct comx_channel *ch = netdev_priv(dev);
377     struct slicecom_privdata *hw = ch->HW_privdata;
378     munich_board_t *board = slicecom_boards + hw->boardnum;
379     munich_ccb_t *ccb = board->ccb;
380
381     u8 *lbi = board->lbi;
382     int i, j, tmp;
383
384
385     spin_lock_irqsave(&mister_lock, flags);
386
387     for (i = 0; i < 4; i++)
388     {
389         tmp = 0xFF;
390         for (j = 0; j < 8; j++)
391             if (ccb->timeslot_spec[8 * i + j].tti == 0) tmp ^= (0x80 >> j);
392         writeb(tmp, lbi + 0x30 + i);
393     }
394
395     spin_unlock_irqrestore(&mister_lock, flags);
396 }
397
398 /*
399  * Set PCM framing - /proc/comx/comx0/framing
400  */
401
402 void slicecom_set_framing(int boardnum, int value)
403 {
404     u8 *lbi = slicecom_boards[boardnum].lbi;
405
406     spin_lock_irqsave(&mister_lock, flags);
407
408     slicecom_boards[boardnum].framing = value;
409     switch (value)
410     {
411         case SLICECOM_FRAMING_CRC4:
412             writeb(readb(lbi + FMR1) | 8, lbi + FMR1);
413             writeb((readb(lbi + FMR2) & 0x3f) | 0x80, lbi + FMR2);
414             break;
415         case SLICECOM_FRAMING_NO_CRC4:
416             writeb(readb(lbi + FMR1) & 0xf7, lbi + FMR1);
417             writeb(readb(lbi + FMR2) & 0x3f, lbi + FMR2);
418             break;
419         default:
420             printk("slicecom: board %d: unhandled " FILENAME_FRAMING
421                    " value %d\n", boardnum, value);
422     }
423
424     spin_unlock_irqrestore(&mister_lock, flags);
425 }
426
427 /*
428  * Set PCM linecode - /proc/comx/comx0/linecode
429  */
430
431 void slicecom_set_linecode(int boardnum, int value)
432 {
433     u8 *lbi = slicecom_boards[boardnum].lbi;
434
435     spin_lock_irqsave(&mister_lock, flags);
436
437     slicecom_boards[boardnum].linecode = value;
438     switch (value)
439     {
440         case SLICECOM_LINECODE_HDB3:
441             writeb(readb(lbi + FMR0) | 0xf0, lbi + FMR0);
442             break;
443         case SLICECOM_LINECODE_AMI:
444             writeb((readb(lbi + FMR0) & 0x0f) | 0xa0, lbi + FMR0);
445             break;
446         default:
447             printk("slicecom: board %d: unhandled " FILENAME_LINECODE
448                    " value %d\n", boardnum, value);
449     }
450     spin_unlock_irqrestore(&mister_lock, flags);
451 }
452
453 /*
454  * Set PCM clock source - /proc/comx/comx0/clock_source
455  */
456
457 void slicecom_set_clock_source(int boardnum, int value)
458 {
459     u8 *lbi = slicecom_boards[boardnum].lbi;
460
461     spin_lock_irqsave(&mister_lock, flags);
462
463     slicecom_boards[boardnum].clock_source = value;
464     switch (value)
465     {
466         case SLICECOM_CLOCK_SOURCE_LINE:
467             writeb(readb(lbi + LIM0) & ~1, lbi + LIM0);
468             break;
469         case SLICECOM_CLOCK_SOURCE_INTERNAL:
470             writeb(readb(lbi + LIM0) | 1, lbi + LIM0);
471             break;
472         default:
473             printk("slicecom: board %d: unhandled " FILENAME_CLOCK_SOURCE
474                    " value %d\n", boardnum, value);
475     }
476     spin_unlock_irqrestore(&mister_lock, flags);
477 }
478
479 /*
480  * Set loopbacks - /proc/comx/comx0/loopback
481  */
482
483 void slicecom_set_loopback(int boardnum, int value)
484 {
485     u8 *lbi = slicecom_boards[boardnum].lbi;
486
487     spin_lock_irqsave(&mister_lock, flags);
488
489     slicecom_boards[boardnum].loopback = value;
490     switch (value)
491     {
492         case SLICECOM_LOOPBACK_NONE:
493             writeb(readb(lbi + LIM0) & ~2, lbi + LIM0); /* Local Loop OFF  */
494             writeb(readb(lbi + LIM1) & ~2, lbi + LIM1); /* Remote Loop OFF */
495             break;
496         case SLICECOM_LOOPBACK_LOCAL:
497             writeb(readb(lbi + LIM1) & ~2, lbi + LIM1); /* Remote Loop OFF */
498             writeb(readb(lbi + LIM0) | 2, lbi + LIM0);  /* Local Loop ON   */
499             break;
500         case SLICECOM_LOOPBACK_REMOTE:
501             writeb(readb(lbi + LIM0) & ~2, lbi + LIM0); /* Local Loop OFF  */
502             writeb(readb(lbi + LIM1) | 2, lbi + LIM1);  /* Remote Loop ON  */
503             break;
504         default:
505             printk("slicecom: board %d: unhandled " FILENAME_LOOPBACK
506                    " value %d\n", boardnum, value);
507     }
508     spin_unlock_irqrestore(&mister_lock, flags);
509 }
510
511 /*
512  * Update E1 line status LEDs on the adapter
513  */
514
515 void slicecom_update_leds(munich_board_t * board)
516 {
517     u32 *bar1 = board->bar1;
518     u8 *lbi = board->lbi;
519     u8 frs0;
520     u32 leds;
521     int i;
522
523     spin_lock_irqsave(&mister_lock, flags);
524
525     leds = 0;
526     frs0 = readb(lbi + FRS0);   /* FRS0 bits described on page 137 */
527
528     if (!(frs0 & 0xa0))
529     {
530         leds |= 0x2000;         /* Green LED: Input signal seems to be OK, no LOS, no LFA       */
531         if (frs0 & 0x10)
532             leds |= 0x8000;     /* Red LED: Receiving Remote Alarm                                      */
533     }
534     writel(leds, MUNICH_VIRT(GPDATA));
535
536     if (leds == 0x2000 && !board->lineup)
537     {                           /* line up */
538         board->lineup = 1;
539         for (i = 0; i < 32; i++)
540         {
541             if (board->twins[i] && (board->twins[i]->flags & IFF_RUNNING))
542             {
543                 struct comx_channel *ch = board->twins[i]->priv;
544
545                 if (!test_and_set_bit(0, &ch->lineup_pending))
546                 {
547                     ch->lineup_timer.function = comx_lineup_func;
548                     ch->lineup_timer.data = (unsigned long)board->twins[i];
549                     ch->lineup_timer.expires = jiffies + HZ * ch->lineup_delay;
550                     add_timer(&ch->lineup_timer);
551                 }
552             }
553         }
554     }
555     else if (leds != 0x2000 && board->lineup)
556     {                           /* line down */
557         board->lineup = 0;
558         for (i = 0; i < 32; i++)
559             if (board->twins[i] && (board->twins[i]->flags & IFF_RUNNING))
560             {
561                 struct comx_channel *ch = board->twins[i]->priv;
562
563                 if (test_and_clear_bit(0, &ch->lineup_pending))
564                     del_timer(&ch->lineup_timer);
565                 else if (ch->line_status & LINE_UP)
566                 {
567                     ch->line_status &= ~LINE_UP;
568                     if (ch->LINE_status)
569                         ch->LINE_status(board->twins[i], ch->line_status);
570                 }
571             }
572     }
573     spin_unlock_irqrestore(&mister_lock, flags);
574 }
575
576 /*
577  * This function gets called every second when the FALC issues the interrupt.
578  * Hardware counters contain error counts for last 1-second time interval.
579  * We add them to the global counters here.
580  * Read rfc2495 to understand this.
581  */
582
583 void slicecom_update_line_counters(munich_board_t * board)
584 {
585     e1_stats_t *curr_int = &board->intervals[board->current_interval];
586
587     u8 *lbi = board->lbi;
588
589     unsigned framing_errors, code_violations, path_code_violations, crc4_errors,
590         e_bit_errors;
591     unsigned slip_detected,     /* this one has logical value, not the number of slips! */
592       out_of_frame_defect,      /* logical value        */
593       ais_defect,               /* logical value        */
594       errored_sec, bursty_err_sec, severely_err_sec = 0, failure_sec;
595     u8 isr2, isr3, isr5, frs0;
596
597     spin_lock_irqsave(&mister_lock, flags);
598
599     isr2 = readb(lbi + ISR2);   /* ISR0-5 described on page 156     */
600     isr3 = readb(lbi + ISR3);
601     isr5 = readb(lbi + ISR5);
602     frs0 = readb(lbi + FRS0);   /* FRS0 described on page 137       */
603
604     /* Error Events: */
605
606     code_violations = readb(lbi + CVCL) + (readb(lbi + CVCH) << 8);
607     framing_errors = readb(lbi + FECL) + (readb(lbi + FECH) << 8);
608     crc4_errors = readb(lbi + CEC1L) + (readb(lbi + CEC1H) << 8);
609     e_bit_errors = readb(lbi + EBCL) + (readb(lbi + EBCH) << 8);
610     slip_detected = isr3 & (ISR3_RSN | ISR3_RSP);
611
612     path_code_violations = framing_errors + crc4_errors;
613
614     curr_int->line_code_violations += code_violations;
615     curr_int->path_code_violations += path_code_violations;
616     curr_int->e_bit_errors += e_bit_errors;
617
618     /* Performance Defects: */
619
620     /* there was an LFA in the last second, but maybe disappeared: */
621     out_of_frame_defect = (isr2 & ISR2_LFA) || (frs0 & FRS0_LFA);
622
623     /* there was an AIS in the last second, but maybe disappeared: */
624     ais_defect = (isr2 & ISR2_AIS) || (frs0 & FRS0_AIS);
625
626     /* Performance Parameters: */
627
628     if (out_of_frame_defect)
629         curr_int->fr_loss_secs++;
630     if (code_violations)
631         curr_int->line_err_secs++;
632
633     errored_sec = ((board->framing == SLICECOM_FRAMING_NO_CRC4) &&
634                    (code_violations)) || path_code_violations ||
635         out_of_frame_defect || slip_detected || ais_defect;
636
637     bursty_err_sec = !out_of_frame_defect && !ais_defect &&
638         (path_code_violations > 1) && (path_code_violations < 320);
639
640     switch (board->framing)
641     {
642         case SLICECOM_FRAMING_CRC4:
643             severely_err_sec = out_of_frame_defect ||
644                 (path_code_violations >= 832);
645             break;
646         case SLICECOM_FRAMING_NO_CRC4:
647             severely_err_sec = (code_violations >= 2048);
648             break;
649     }
650
651     /*
652      * failure_sec: true if there was a condition leading to a failure
653      * (and leading to unavailable state) in this second:
654      */
655
656     failure_sec = (isr2 & ISR2_RA) || (frs0 & FRS0_RRA) /* Remote/Far End/Distant Alarm Failure */
657         || ais_defect || out_of_frame_defect    /* AIS or LOF Failure                           */
658         || (isr2 & ISR2_LOS) || (frs0 & FRS0_LOS)       /* Loss Of Signal Failure                       */
659         || (board->loopback != SLICECOM_LOOPBACK_NONE); /* Loopback has been set                        */
660
661     if (board->is_unavailable)
662     {
663         if (severely_err_sec)
664             board->no_ses_seconds = 0;
665         else
666             board->no_ses_seconds++;
667
668         if ((board->no_ses_seconds >= 10) && !failure_sec)
669         {
670             board->is_unavailable = 0;
671             board->ses_seconds = 0;
672             board->no_ses_seconds = 0;
673         }
674     }
675     else
676     {
677         if (severely_err_sec)
678             board->ses_seconds++;
679         else
680             board->ses_seconds = 0;
681
682         if ((board->ses_seconds >= 10) || failure_sec)
683         {
684             board->is_unavailable = 1;
685             board->ses_seconds = 0;
686             board->no_ses_seconds = 0;
687         }
688     }
689
690     if (board->is_unavailable)
691         curr_int->unavail_secs++;
692     else
693     {
694         if (slip_detected)
695             curr_int->slip_secs++;
696         curr_int->errored_secs += errored_sec;
697         curr_int->bursty_err_secs += bursty_err_sec;
698         curr_int->severely_err_secs += severely_err_sec;
699     }
700
701     /* the RFC does not say clearly which errors to count here, we try to count bit errors */
702
703     if (!board->is_unavailable && !severely_err_sec)
704     {
705         board->deg_cumulated_errors += code_violations;
706         board->deg_elapsed_seconds++;
707         if (board->deg_elapsed_seconds >= 60)
708         {
709             if (board->deg_cumulated_errors >= 123)
710                 curr_int->degraded_mins++;
711             board->deg_cumulated_errors = 0;
712             board->deg_elapsed_seconds = 0;
713         }
714
715     }
716
717     board->elapsed_seconds++;
718     if (board->elapsed_seconds >= 900)
719     {
720         board->current_interval =
721             (board->current_interval + 1) % SLICECOM_BOARD_INTERVALS_SIZE;
722         memset((void *)&board->intervals[board->current_interval], 0,
723                sizeof(e1_stats_t));
724         board->elapsed_seconds = 0;
725     }
726
727     spin_unlock_irqrestore(&mister_lock, flags);
728 }
729
730 static void pcicom_modemline(unsigned long b)
731 {
732     munich_board_t *board = (munich_board_t *) b;
733     struct net_device *dev = board->twins[0];
734     struct comx_channel *ch = netdev_priv(dev);
735     unsigned long regs;
736
737     regs = readl((void *)(&board->bar1[GPDATA]));
738     if ((ch->line_status & LINE_UP) && (regs & 0x0800))
739     {
740         ch->line_status &= ~LINE_UP;
741         board->lineup = 0;
742         if (ch->LINE_status)
743         {
744             ch->LINE_status(dev, ch->line_status);
745         }
746     }
747
748     if (!(ch->line_status & LINE_UP) && !(regs & 0x0800))
749     {
750         ch->line_status |= LINE_UP;
751         board->lineup = 1;
752         if (ch->LINE_status)
753         {
754             ch->LINE_status(dev, ch->line_status);
755         }
756     }
757
758     mod_timer((struct timer_list *)&board->modemline_timer, jiffies + HZ);
759 }
760
761 /* 
762  * Is it possible to transmit ?
763  * Called (may be called) by the protocol layer 
764  */
765
766 static int MUNICH_txe(struct net_device *dev)
767 {
768     struct comx_channel *ch = netdev_priv(dev);
769     struct slicecom_privdata *hw = ch->HW_privdata;
770
771     return (hw->busy < TX_DESC_MAX - 1);
772 }
773
774 /* 
775  * Hw probe function. Detects all the boards in the system,
776  * and fills up slicecom_boards[] and pcicom_boards[]
777  * Returns 0 on success.
778  * We do not disable interrupts!
779  */
780 static int munich_probe(void)
781 {
782     struct pci_dev *pci;
783     int boardnum;
784     int slicecom_boardnum;
785     int pcicom_boardnum;
786     u32 *bar1;
787     u8 *lbi;
788     munich_board_t *board;
789
790     for (boardnum = 0; boardnum < MAX_BOARDS; boardnum++)
791     {
792         pcicom_boards[boardnum].pci = 0;
793         pcicom_boards[boardnum].bar1 = 0;
794         pcicom_boards[boardnum].lbi = 0;
795         slicecom_boards[boardnum].pci = 0;
796         slicecom_boards[boardnum].bar1 = 0;
797         slicecom_boards[boardnum].lbi = 0;
798     }
799
800     pci = NULL;
801     board = NULL;
802     slicecom_boardnum = 0;
803     pcicom_boardnum = 0;
804
805     for (boardnum = 0;
806         boardnum < MAX_BOARDS && (pci = pci_find_device(PCI_VENDOR_ID_SIEMENS,
807         PCI_DEVICE_ID_SIEMENS_MUNICH32X, pci)); boardnum++)
808     {
809         if (pci_enable_device(pci))
810             continue;
811
812         printk("munich_probe: munich chip found, IRQ %d\n", pci->irq);
813
814         bar1 = ioremap_nocache(pci->resource[0].start, 0x100);
815         lbi = ioremap_nocache(pci->resource[1].start, 0x100);
816
817         if (bar1 && lbi)
818         {
819             pci_write_config_dword(pci, MUNICH_PCI_PCIRES, 0xe0000);
820             set_current_state(TASK_UNINTERRUPTIBLE);
821             schedule_timeout(1);
822             pci_write_config_dword(pci, MUNICH_PCI_PCIRES, 0);
823             set_current_state(TASK_UNINTERRUPTIBLE);
824             schedule_timeout(1);
825             /* check the type of the card */
826             writel(LREG0_MAGIC, MUNICH_VIRT(LREG0));
827             writel(LREG1_MAGIC, MUNICH_VIRT(LREG1));
828             writel(LREG2_MAGIC, MUNICH_VIRT(LREG2));
829             writel(LREG3_MAGIC, MUNICH_VIRT(LREG3));
830             writel(LREG4_MAGIC, MUNICH_VIRT(LREG4));
831             writel(LREG5_MAGIC, MUNICH_VIRT(LREG5));
832             writel(LCONF_MAGIC2,MUNICH_VIRT(LCONF));    /* enable the DMSM */
833
834             if ((readb(lbi + VSTR) == 0x13) || (readb(lbi + VSTR) == 0x10))
835             {
836                 board = slicecom_boards + slicecom_boardnum;
837                 sprintf((char *)board->devname, "slicecom%d",
838                         slicecom_boardnum);
839                 board->isx21 = 0;
840                 slicecom_boardnum++;
841             }
842             else if ((readb(lbi + VSTR) == 0x6) || (readb(lbi + GIS) == 0x6))
843             {
844                 board = pcicom_boards + pcicom_boardnum;
845                 sprintf((char *)board->devname, "pcicom%d", pcicom_boardnum);
846                 board->isx21 = 1;
847                 pcicom_boardnum++;
848             }
849             if (board)
850             {
851                 printk("munich_probe: %s board found\n", board->devname);
852                 writel(LCONF_MAGIC1, MUNICH_VIRT(LCONF));       /* reset the DMSM */
853                 board->pci = pci;
854                 board->bar1 = bar1;
855                 board->lbi = lbi;
856                 board->framing = SLICECOM_FRAMING_DEFAULT;
857                 board->linecode = SLICECOM_LINECODE_DEFAULT;
858                 board->clock_source = SLICECOM_CLOCK_SOURCE_DEFAULT;
859                 board->loopback = SLICECOM_LOOPBACK_DEFAULT;
860                 board->owner = THIS_MODULE;
861             }
862             else
863             {
864                 printk("munich_probe: Board error, VSTR: %02X\n",
865                        readb(lbi + VSTR));
866                 iounmap((void *)bar1);
867                 iounmap((void *)lbi);
868             }
869         }
870         else
871         {
872             printk("munich_probe: ioremap() failed, not enabling this board!\n");
873             /* .pci = NULL, so the MUNICH_open will not try to open it            */
874             if (bar1) iounmap((void *)bar1);
875             if (lbi) iounmap((void *)lbi);
876         }
877     }
878
879     if (!pci && !boardnum)
880     {
881         printk("munich_probe: no PCI present!\n");
882         return -ENODEV;
883     }
884
885     if (pcicom_boardnum + slicecom_boardnum == 0)
886     {
887         printk
888             ("munich_probe: Couldn't find any munich board: vendor:device %x:%x not found\n",
889              PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_MUNICH32X);
890         return -ENODEV;
891     }
892
893     /* Found some */
894     if (pcicom_boardnum)
895         printk("%d pcicom board(s) found.\n", pcicom_boardnum);
896     if (slicecom_boardnum)
897         printk("%d slicecom board(s) found.\n", slicecom_boardnum);
898
899     return 0;
900 }
901
902 /* 
903  * Reset the hardware. Get called only from within this module if needed.
904  */
905 #if 0
906 static int slicecom_reset(struct net_device *dev)
907 {
908     struct comx_channel *ch = netdev_priv(dev);
909
910     printk("slicecom_reset: resetting the hardware\n");
911
912     /* Begin to reset the hardware */
913
914     if (ch->HW_set_clock)
915         ch->HW_set_clock(dev);
916
917     /* And finish it */
918
919     return 0;
920 }
921 #endif
922
923 /* 
924  * Transmit a packet. 
925  * Called by the protocol layer
926  * Return values:       
927  *      FRAME_ACCEPTED: frame is being transmited, transmitter is busy
928  *      FRAME_QUEUED:   frame is being transmitted, there's more room in
929  *                              the transmitter for additional packet(s)
930  *      FRAME_ERROR:
931  *      FRAME_DROPPED:  there was some error
932  */
933
934 static int MUNICH_send_packet(struct net_device *dev, struct sk_buff *skb)
935 {
936     struct comx_channel *ch = netdev_priv(dev);
937     struct slicecom_privdata *hw = ch->HW_privdata;
938
939     /* Send it to the debug facility too if needed: */
940
941     if (ch->debug_flags & DEBUG_HW_TX)
942         comx_debug_bytes(dev, skb->data, skb->len, "MUNICH_send_packet");
943
944     /* If the line is inactive, don't accept: */
945
946     /* TODO: atgondolni hogy mi is legyen itt */
947     /* if (!(ch->line_status & LINE_UP)) return FRAME_DROPPED; */
948
949     /* More check, to be sure: */
950
951     if (skb->len > TXBUFFER_SIZE)
952     {
953         ch->stats.tx_errors++;
954         kfree_skb(skb);
955         return FRAME_ERROR;
956     }
957
958     /* Maybe you have to disable irq's while programming the hw: */
959
960     spin_lock_irqsave(&mister_lock, flags);
961
962     /* And more check: */
963
964     if (hw->busy >= TX_DESC_MAX - 1)
965     {
966         printk(KERN_ERR
967                "%s: Transmitter called while busy... dropping frame, busy = %d\n",
968                dev->name, hw->busy);
969         spin_unlock_irqrestore(&mister_lock, flags);
970         kfree_skb(skb);
971         return FRAME_DROPPED;
972     }
973
974     if (hw->busy >= 0)
975         hw->tx_ring_hist[hw->busy]++;
976     /* DELL: */
977     else
978         printk("slicecom: %s: FATAL: busy = %d\n", dev->name, hw->busy);
979
980 //              /* DEL: */
981 //      printk("slicecom: %s: _send_packet called, busy = %d\n", dev->name, hw->busy );
982
983     /* Packet can go, update stats: */
984
985     ch->stats.tx_packets++;
986     ch->stats.tx_bytes += skb->len;
987
988     /* Pass the packet to the HW:                   */
989     /* Step forward with the transmit descriptors:  */
990
991     hw->tx_desc_ptr = (hw->tx_desc_ptr + 1) % TX_DESC_MAX;
992
993     memcpy(&(hw->tx_data[hw->tx_desc_ptr][0]), skb->data, skb->len);
994     hw->tx_desc[hw->tx_desc_ptr].no = skb->len;
995
996     /* We don't issue any command, just step with the HOLD bit      */
997
998     hw->tx_desc[hw->tx_desc_ptr].hold = 1;
999     hw->tx_desc[(hw->tx_desc_ptr + TX_DESC_MAX - 1) % TX_DESC_MAX].hold = 0;
1000
1001 #ifdef COMX_NEW
1002     dev_kfree_skb(skb);
1003 #endif
1004     /* csomag kerult a Tx ringbe: */
1005
1006     hw->busy++;
1007
1008     /* Report it: */
1009
1010     if (ch->debug_flags & DEBUG_HW_TX)
1011         comx_debug(dev, "%s: MUNICH_send_packet was successful\n\n", dev->name);
1012
1013     if (hw->busy >= TX_DESC_MAX - 1)
1014     {
1015         spin_unlock_irqrestore(&mister_lock, flags);
1016         return FRAME_ACCEPTED;
1017     }
1018
1019     spin_unlock_irqrestore(&mister_lock, flags);
1020
1021     /* All done */
1022
1023     return FRAME_QUEUED;
1024 }
1025
1026 /*
1027  * Interrupt handler routine.
1028  * Called by the Linux kernel.
1029  * BEWARE! The interrupts are enabled on the call!
1030  */
1031 static irqreturn_t MUNICH_interrupt(int irq, void *dev_id, struct pt_regs *regs)
1032 {
1033     struct sk_buff *skb;
1034     int length;
1035     int rx_status;
1036     int work;                   /* hany esemenyt kezeltem mar le                                */
1037     u32 *bar1;
1038     u8 *lbi;
1039     u32 stat,                   /* az esemenyek, amiket a ebben a loop korben le kell meg kezelni       */
1040       race_stat = 0,            /* race eseten ebben uzenek magamnak hogy mit kell meg lekezelni        */
1041       ack;                      /* ezt fogom a vegen a STAT-ba irni, kiveszek belole 1-1 bitet ha       */
1042
1043     /* az adott dolgot nem kell ack-olni mert volt vele munkam, es  */
1044     /* legjobb ha visszaterek ide megegyszer                        */
1045     munich_intq_t int_info;
1046
1047     struct net_device *dev;
1048     struct comx_channel *ch;
1049     struct slicecom_privdata *hw;
1050     munich_board_t *board = (munich_board_t *) dev_id;
1051     int channel;
1052
1053     //      , boardnum = (int)dev_id;
1054
1055     // board = munich_boards + boardnum;
1056     bar1 = board->bar1;
1057     lbi = board->lbi;
1058
1059     //      Do not uncomment this under heavy load! :->
1060     //      printk("MUNICH_interrupt: masked STAT=0x%08x, tiq=0x%08x, riq=0x%08x, piq=0x%08x\n", stat, board->tiq[0].all, board->riq[0].all, board->piq[0].all );
1061
1062     for (work = 0; (stat = (race_stat | (readl(MUNICH_VIRT(STAT)) & ~STAT_NOT_HANDLED_BY_INTERRUPT))) && (work < MAX_WORK - 1); work++)
1063     {
1064         ack = stat & (STAT_PRI | STAT_PTI | STAT_LBII);
1065
1066         /* Handle the interrupt information in the Rx queue. We don't really trust      */
1067         /* info from this queue, because it can be overflowed, so later check           */
1068         /* every Rx ring for received packets. But there are some errors which can't    */
1069         /* be counted from the Rx rings, so we parse it.                                        */
1070
1071         int_info = board->riq[board->riq_ptr];
1072         if (int_info.all & 0xF0000000)  /* ha ez nem 0, akkor itt interrupt_info van                    */
1073         {
1074             ack &= ~STAT_PRI;   /* don't ack the interrupt, we had some work to do              */
1075
1076             channel = PCM_INT_CHANNEL(int_info.all);
1077             dev = board->twins[channel];
1078
1079             if (dev == NULL)
1080             {
1081                 printk
1082                     ("MUNICH_interrupt: got an Rx interrupt info for NULL device "
1083                      "%s.twins[%d], int_info = 0x%08x\n", board->devname,
1084                      channel, int_info.all);
1085                 goto go_for_next_interrupt;
1086             }
1087
1088             ch = netdev_priv(dev);
1089             hw = (struct slicecom_privdata *)ch->HW_privdata;
1090
1091             //      printk("Rx STAT=0x%08x int_info=0x%08x rx_desc_ptr=%d rx_desc.status=0x%01x\n",
1092             //              stat, int_info.all, hw->rx_desc_ptr, hw->rx_desc[ hw->rx_desc_ptr ].status );
1093
1094             if (int_info.all & PCM_INT_HI)
1095                 printk("SliceCOM: %s: Host Initiated interrupt\n", dev->name);
1096             if (int_info.all & PCM_INT_IFC)
1097                 printk("SliceCOM: %s: Idle/Flag Change\n", dev->name);
1098             /* TOD: jo ez az Idle/Flag Change valamire? - azonnal latszik belole hogy mikor ad a masik oldal */
1099             /* TOD: ilyen IT most nem is jon, mert ki van maszkolva az interrupt, biztosan kell ez? */
1100
1101             if (int_info.all & PCM_INT_FO)
1102                 /* Internal buffer (RB) overrun */
1103                 ch->stats.rx_over_errors++;     /* TOD: Ez azt jelenti hogy a belso RB nem volt hozzaferheto, es ezert kihagyott valamit. De nem csak csomag lehetett, hanem esemeny, stb. is. lasd page 247. Ezzel a 'cat status'-hoz igazodok, de a netdevice.h szerint nem egyertelmu hogy ide ez kellene. Nem lehet hogy rx_missed ? */
1104                 /* DE: nem gotozok sehova, elvileg jo igy */
1105                 /* kesobb meg visszaterek az FO-ra, ha packet-FO volt. Keresd a "packet-FO"-t. */
1106             if (int_info.all & PCM_INT_FI)      /* frame received, but we do not trust the int_info queue       */
1107                 if (int_info.all & PCM_INT_SF)
1108                 {               /* Short Frame: rovidebb mint a CRC */
1109                     /* "rovidebb mint CRC+2byte" vizsgalat a "CRC+2"-nel */
1110                     ch->stats.rx_length_errors++;       /* TOD: noveljem? ne noveljem? */
1111                     goto go_for_next_interrupt;
1112                 }
1113
1114             go_for_next_interrupt:      /* One step in the interrupt queue */
1115             board->riq[board->riq_ptr].all = 0; /* megjelolom hogy itt meg nem jart a hw */
1116             board->riq_ptr = (board->riq_ptr + 1) % MUNICH_INTQMAX;
1117
1118         }
1119
1120         /* Check every Rx ring for incomed packets: */
1121
1122         for (channel = 0; channel < 32; channel++)
1123         {
1124             dev = board->twins[channel];
1125
1126             if (dev != NULL)
1127             {
1128                 ch = netdev_priv(dev);
1129                 hw = (struct slicecom_privdata *)ch->HW_privdata;
1130
1131                 rx_status = hw->rx_desc[hw->rx_desc_ptr].status;
1132
1133                 if (!(rx_status & 0x80))        /* mar jart itt a hardver */
1134                 {
1135                     ack &= ~STAT_PRI;   /* Don't ack, we had some work          */
1136
1137                     /* Ez most egy kicsit zuros, mert itt mar nem latom az int_infot        */
1138                     if (rx_status & RX_STATUS_ROF)
1139                         ch->stats.rx_over_errors++;     /* TOD: 'cat status'-hoz igazodok */
1140
1141                     if (rx_status & RX_STATUS_RA)
1142                         /* Abort received or issued on channel  */
1143                         ch->stats.rx_frame_errors++;    /* or HOLD bit in the descriptor                */
1144                         /* TOD: 'cat status'-hoz igazodok */
1145
1146                     if (rx_status & RX_STATUS_LFD)
1147                     {           /* Long Frame (longer then MFL in the MODE1) */
1148                         ch->stats.rx_length_errors++;
1149                         goto go_for_next_frame;
1150                     }
1151
1152                     if (rx_status & RX_STATUS_NOB)
1153                     {           /* Not n*8 bits long frame - frame alignment */
1154                         ch->stats.rx_frame_errors++;    /* ez viszont nem igazodik a 'cat status'-hoz */
1155                         goto go_for_next_frame;
1156                     }
1157
1158                     if (rx_status & RX_STATUS_CRCO)
1159                     {           /* CRC error */
1160                         ch->stats.rx_crc_errors++;
1161                         goto go_for_next_frame;
1162                     }
1163
1164                     if (rx_status & RX_STATUS_SF)
1165                     {           /* Short Frame: rovidebb mint CRC+2byte */
1166                         ch->stats.rx_errors++;  /* The HW does not set PCI_INT_ERR bit for this one, see page 246 */
1167                         ch->stats.rx_length_errors++;
1168                         goto go_for_next_frame;
1169                     }
1170
1171                     if (rx_status != 0)
1172                     {
1173                         printk("SliceCOM: %s: unhandled rx_status: 0x%02x\n",
1174                                dev->name, rx_status);
1175                         goto go_for_next_frame;
1176                     }
1177
1178                     /* frame received without errors: */
1179
1180                     length = hw->rx_desc[hw->rx_desc_ptr].bno;
1181                     ch->stats.rx_packets++;     /* Count only 'good' packets */
1182                     ch->stats.rx_bytes += length;
1183
1184                     /* Allocate a larger skb and reserve the heading for efficiency: */
1185
1186                     if ((skb = dev_alloc_skb(length + 16)) == NULL)
1187                     {
1188                         ch->stats.rx_dropped++;
1189                         goto go_for_next_frame;
1190                     }
1191
1192                     /* Do bookkeeping: */
1193
1194                     skb_reserve(skb, 16);
1195                     skb_put(skb, length);
1196                     skb->dev = dev;
1197
1198                     /* Now copy the data into the buffer: */
1199
1200                     memcpy(skb->data, &(hw->rx_data[hw->rx_desc_ptr][0]), length);
1201
1202                     /* DEL: UGLY HACK!!!! */
1203                     if (*((int *)skb->data) == 0x02000000 &&
1204                         *(((int *)skb->data) + 1) == 0x3580008f)
1205                     {
1206                         printk("%s: swapping hack\n", dev->name);
1207                         *((int *)skb->data) = 0x3580008f;
1208                         *(((int *)skb->data) + 1) = 0x02000000;
1209                     }
1210
1211                     if (ch->debug_flags & DEBUG_HW_RX)
1212                         comx_debug_skb(dev, skb, "MUNICH_interrupt receiving");
1213
1214                     /* Pass it to the protocol entity: */
1215
1216                     ch->LINE_rx(dev, skb);
1217
1218                     go_for_next_frame:
1219                     /* DEL: rafutott-e a HOLD bitre -detektalas */
1220                     {
1221                         if( ((rx_desc_t*)phys_to_virt(board->ccb->current_rx_desc[channel]))->hold
1222                             && ((rx_desc_t*)phys_to_virt(board->ccb->current_rx_desc[channel]))->status != 0xff)
1223                             hw->rafutott++;     /* rafutott: hanyszor volt olyan hogy a current descriptoron HOLD bit volt, es a hw mar befejezte az irast (azaz a hw rafutott a HOLD bitre) */
1224                     }
1225
1226                     //      if( jiffies % 2 )               /* DELL: okozzunk egy kis Rx ring slipet :) */
1227                     //      {
1228                     /* Step forward with the receive descriptors: */
1229                     /* if you change this, change the copy of it below too! Search for: "RxSlip" */
1230                     hw->rx_desc[(hw->rx_desc_ptr + RX_DESC_MAX - 1) % RX_DESC_MAX].hold = 1;
1231                     hw->rx_desc[hw->rx_desc_ptr].status = 0xFF; /* megjelolom hogy itt meg nem jart a hw */
1232                     hw->rx_desc[(hw->rx_desc_ptr + RX_DESC_MAX - 2) % RX_DESC_MAX].hold = 0;
1233                     hw->rx_desc_ptr = (hw->rx_desc_ptr + 1) % RX_DESC_MAX;
1234                     //      }
1235                 }
1236             }
1237         }
1238
1239         stat &= ~STAT_PRI;
1240
1241 //      }
1242
1243 //      if( stat & STAT_PTI )   /* TOD: primko megvalositas: mindig csak egy esemenyt dolgozok fel, */
1244         /* es nem torlom a STAT-ot, ezert ujra visszajon ide a rendszer. Amikor */
1245         /* jon interrupt, de nincs mit feldolgozni, akkor torlom a STAT-ot.     */
1246         /* 'needs a rewrite', de elso megoldasnak jo lesz                       */
1247 //              {
1248         int_info = board->tiq[board->tiq_ptr];
1249         if (int_info.all & 0xF0000000)  /* ha ez nem 0, akkor itt interrupt_info van    */
1250         {
1251             ack &= ~STAT_PTI;   /* don't ack the interrupt, we had some work to do      */
1252
1253             channel = PCM_INT_CHANNEL(int_info.all);
1254             dev = board->twins[channel];
1255
1256             if (dev == NULL)
1257             {
1258                 printk("MUNICH_interrupt: got a Tx interrupt for NULL device "
1259                        "%s.twins[%d], int_info = 0x%08x\n",
1260                        board->isx21 ? "pcicom" : "slicecom", channel, int_info.all);
1261                 goto go_for_next_tx_interrupt;
1262             }
1263
1264             ch = netdev_priv(dev);
1265             hw = (struct slicecom_privdata *)ch->HW_privdata;
1266
1267             //      printk("Tx STAT=0x%08x int_info=0x%08x tiq_ptr=%d\n", stat, int_info.all, board->tiq_ptr );
1268
1269             if (int_info.all & PCM_INT_FE2)
1270             {                   /* "Tx available"                               */
1271                 /* do nothing */
1272             }
1273             else if (int_info.all & PCM_INT_FO)
1274             {                   /* Internal buffer (RB) overrun */
1275                 ch->stats.rx_over_errors++;
1276             }
1277             else
1278             {
1279                 printk("slicecom: %s: unhandled Tx int_info: 0x%08x\n",
1280                        dev->name, int_info.all);
1281             }
1282
1283             go_for_next_tx_interrupt:
1284             board->tiq[board->tiq_ptr].all = 0;
1285             board->tiq_ptr = (board->tiq_ptr + 1) % MUNICH_INTQMAX;
1286         }
1287
1288         /* Check every Tx ring for incoming packets: */
1289
1290         for (channel = 0; channel < 32; channel++)
1291         {
1292             dev = board->twins[channel];
1293
1294             if (dev != NULL)
1295             {
1296                 int newbusy;
1297
1298                 ch = netdev_priv(dev);
1299                 hw = (struct slicecom_privdata *)ch->HW_privdata;
1300
1301                 /* We don't trust the "Tx available" info from the TIQ, but check        */
1302                 /* every ring if there is some free room                                        */
1303
1304                 if (ch->init_status && netif_running(dev))
1305                 {
1306                     newbusy = ( TX_DESC_MAX + (& hw->tx_desc[ hw->tx_desc_ptr ]) -
1307                         (tx_desc_t*)phys_to_virt(board->ccb->current_tx_desc[ hw->channel ]) ) % TX_DESC_MAX;
1308
1309                     if(newbusy < 0)
1310                     {
1311                         printk("slicecom: %s: FATAL: fresly computed busy = %d, HW: 0x%p, SW: 0x%p\n",
1312                         dev->name, newbusy,
1313                         phys_to_virt(board->ccb->current_tx_desc[hw->channel]),
1314                         & hw->tx_desc[hw->tx_desc_ptr]);
1315                     }
1316
1317                     /* Fogyott valami a Tx ringbol? */
1318
1319                     if (newbusy < hw->busy)
1320                     {
1321                         // ack &= ~STAT_PTI;                            /* Don't ack, we had some work  */
1322                         hw->busy = newbusy;
1323                         if (ch->LINE_tx)
1324                             ch->LINE_tx(dev);   /* Report it to protocol driver */
1325                     }
1326                     else if (newbusy > hw->busy)
1327                         printk("slicecom: %s: newbusy > hw->busy, this should not happen!\n", dev->name);
1328                 }
1329             }
1330         }
1331         stat &= ~STAT_PTI;
1332
1333         int_info = board->piq[board->piq_ptr];
1334         if (int_info.all & 0xF0000000)  /* ha ez nem 0, akkor itt interrupt_info van            */
1335         {
1336             ack &= ~STAT_LBII;  /* don't ack the interrupt, we had some work to do      */
1337
1338             /* We do not really use (yet) the interrupt info from this queue, */
1339
1340             // printk("slicecom: %s: LBI Interrupt event: %08x\n", board->devname, int_info.all);
1341
1342             if (!board->isx21)
1343             {
1344                 slicecom_update_leds(board);
1345                 slicecom_update_line_counters(board);
1346             }
1347
1348             goto go_for_next_lbi_interrupt;     /* To avoid warning about unused label  */
1349
1350             go_for_next_lbi_interrupt:  /* One step in the interrupt queue */
1351             board->piq[board->piq_ptr].all = 0; /* megjelolom hogy itt meg nem jart a hw        */
1352             board->piq_ptr = (board->piq_ptr + 1) % MUNICH_PIQMAX;
1353         }
1354         stat &= ~STAT_LBII;
1355
1356         writel(ack, MUNICH_VIRT(STAT));
1357
1358         if (stat & STAT_TSPA)
1359         {
1360             //      printk("slicecom: %s: PCM TSP Asynchronous\n", board->devname);
1361             writel(STAT_TSPA, MUNICH_VIRT(STAT));
1362             stat &= ~STAT_TSPA;
1363         }
1364
1365         if (stat & STAT_RSPA)
1366         {
1367             //      printk("slicecom: %s: PCM RSP Asynchronous\n", board->devname);
1368             writel(STAT_RSPA, MUNICH_VIRT(STAT));
1369             stat &= ~STAT_RSPA;
1370         }
1371         if (stat)
1372         {
1373             printk("MUNICH_interrupt: unhandled interrupt, STAT=0x%08x\n",
1374                    stat);
1375             writel(stat, MUNICH_VIRT(STAT));    /* ha valamit megsem kezeltunk le, azert ack-ot kuldunk neki */
1376         }
1377
1378     }
1379     board->histogram[work]++;
1380
1381     /* We can miss these if we reach the MAX_WORK   */
1382     /* Count it to see how often it happens         */
1383
1384     if (race_stat & STAT_PRI)
1385         board->stat_pri_races_missed++;
1386     if (race_stat & STAT_PTI)
1387         board->stat_pti_races_missed++;
1388     return IRQ_HANDLED;
1389 }
1390
1391 /* 
1392  * Hardware open routine.
1393  * Called by comx (upper) layer when the user wants to bring up the interface
1394  * with ifconfig.
1395  * Initializes hardware, allocates resources etc.
1396  * Returns 0 on OK, or standard error value on error.
1397  */
1398
1399 static int MUNICH_open(struct net_device *dev)
1400 {
1401     struct comx_channel *ch = netdev_priv(dev);
1402     struct slicecom_privdata *hw = ch->HW_privdata;
1403     struct proc_dir_entry *procfile = ch->procdir->subdir;
1404     munich_board_t *board;
1405     munich_ccb_t *ccb;
1406
1407     u32 *bar1;
1408     u8 *lbi;
1409     u32 stat;
1410     unsigned long flags, jiffs;
1411
1412     int i, channel;
1413     u32 timeslots = hw->timeslots;
1414
1415     board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
1416
1417     bar1 = board->bar1;
1418     lbi = board->lbi;
1419
1420     /* TODO: a timeslotok ellenorzese kell majd ide .. hat, biztos? mar a write_proc-ban is
1421        ellenorzom valamennyire.
1422        if (!dev->io || !dev->irq) return -ENODEV;
1423      */
1424
1425     if (!board->pci)
1426     {
1427         printk("MUNICH_open: no %s board with boardnum = %d\n",
1428                ch->hardware->name, hw->boardnum);
1429         return -ENODEV;
1430     }
1431
1432     spin_lock_irqsave(&mister_lock, flags);
1433     /* lock the section to avoid race with multiple opens and make sure
1434        that no interrupts get called while this lock is active */
1435
1436     if (board->use_count == 0)  /* bring up the board if it was unused                  */
1437         /* if fails, frees allocated resources and returns.     */
1438         /* TOD: is it safe? nem kellene resetelni a kartyat?    */
1439     {
1440         printk("MUNICH_open: %s: bringing up board\n", board->devname);
1441
1442         /* Clean up the board's static struct if messed: */
1443
1444         for (i = 0; i < 32; i++)
1445             board->twins[i] = NULL;
1446         for (i = 0; i < MAX_WORK; i++)
1447             board->histogram[i] = 0;
1448
1449         board->lineup = 0;
1450
1451         /* Allocate CCB: */
1452         board->ccb = kmalloc(sizeof(munich_ccb_t), GFP_KERNEL);
1453         if (board->ccb == NULL)
1454         {
1455             spin_unlock_irqrestore(&mister_lock, flags);
1456             return -ENOMEM;
1457         }
1458         memset((void *)board->ccb, 0, sizeof(munich_ccb_t));
1459         board->ccb->csa = virt_to_phys(board->ccb);
1460         ccb = board->ccb;
1461         for (i = 0; i < 32; i++)
1462         {
1463             ccb->timeslot_spec[i].tti = 1;
1464             ccb->timeslot_spec[i].rti = 1;
1465         }
1466
1467         /* Interrupt queues: */
1468
1469         board->tiq = kmalloc(MUNICH_INTQSIZE, GFP_KERNEL);
1470         if (board->tiq == NULL)
1471         {
1472             spin_unlock_irqrestore(&mister_lock, flags);
1473             return -ENOMEM;
1474         }
1475         memset((void *)board->tiq, 0, MUNICH_INTQSIZE);
1476
1477         board->riq = kmalloc(MUNICH_INTQSIZE, GFP_KERNEL);
1478         if (board->riq == NULL)
1479         {
1480             spin_unlock_irqrestore(&mister_lock, flags);
1481             return -ENOMEM;
1482         }
1483         memset((void *)board->riq, 0, MUNICH_INTQSIZE);
1484
1485         board->piq = kmalloc(MUNICH_PIQSIZE, GFP_KERNEL);
1486         if (board->piq == NULL)
1487         {
1488             spin_unlock_irqrestore(&mister_lock, flags);
1489             return -ENOMEM;
1490         }
1491         memset((void *)board->piq, 0, MUNICH_PIQSIZE);
1492
1493         board->tiq_ptr = 0;
1494         board->riq_ptr = 0;
1495         board->piq_ptr = 0;
1496
1497         /* Request irq: */
1498
1499         board->irq = 0;
1500
1501         /* (char*) cast to avoid warning about discarding volatile:             */
1502         if (request_irq(board->pci->irq, MUNICH_interrupt, 0,
1503             (char *)board->devname, (void *)board))
1504         {
1505             printk("MUNICH_open: %s: unable to obtain irq %d\n", board->devname,
1506                    board->pci->irq);
1507             /* TOD: free other resources (a sok malloc feljebb)                     */
1508             spin_unlock_irqrestore(&mister_lock, flags);
1509             return -EAGAIN;
1510         }
1511         board->irq = board->pci->irq;   /* csak akkor legyen != 0, ha tenyleg le van foglalva nekunk */
1512
1513         /* Programming device: */
1514
1515         /* Reset the board like a power-on: */
1516         /* TOD:
1517            - It is not a real power-on: if a DMA transaction fails with master abort, the board
1518            stays in half-dead state.
1519            - It doesn't reset the FALC line driver */
1520
1521         pci_write_config_dword(board->pci, MUNICH_PCI_PCIRES, 0xe0000);
1522         set_current_state(TASK_UNINTERRUPTIBLE);
1523         schedule_timeout(1);
1524         pci_write_config_dword(board->pci, MUNICH_PCI_PCIRES, 0);
1525         set_current_state(TASK_UNINTERRUPTIBLE);
1526         schedule_timeout(1);
1527
1528         writel(virt_to_phys(&ccb->csa), MUNICH_VIRT(CCBA));
1529         writel(virt_to_phys( board->tiq ), MUNICH_VIRT(TIQBA));
1530         writel(MUNICH_INTQLEN, MUNICH_VIRT(TIQL));
1531         writel(virt_to_phys( board->riq ), MUNICH_VIRT(RIQBA));
1532         writel(MUNICH_INTQLEN, MUNICH_VIRT(RIQL));
1533         writel(virt_to_phys( board->piq ), MUNICH_VIRT(PIQBA));
1534         writel(MUNICH_PIQLEN, MUNICH_VIRT(PIQL));
1535         
1536         /* Put the magic values into the registers: */
1537
1538         writel(MODE1_MAGIC, MUNICH_VIRT(MODE1));
1539         writel(MODE2_MAGIC, MUNICH_VIRT(MODE2));
1540
1541         writel(LREG0_MAGIC, MUNICH_VIRT(LREG0));
1542         writel(LREG1_MAGIC, MUNICH_VIRT(LREG1));
1543         writel(LREG2_MAGIC, MUNICH_VIRT(LREG2));
1544         writel(LREG3_MAGIC, MUNICH_VIRT(LREG3));
1545         writel(LREG4_MAGIC, MUNICH_VIRT(LREG4));
1546         writel(LREG5_MAGIC, MUNICH_VIRT(LREG5));
1547
1548         writel(LCONF_MAGIC1, MUNICH_VIRT(LCONF));       /* reset the DMSM */
1549         writel(LCONF_MAGIC2, MUNICH_VIRT(LCONF));       /* enable the DMSM */
1550
1551         writel(~0, MUNICH_VIRT(TXPOLL));
1552         writel(board->isx21 ? 0x1400 : 0xa000, MUNICH_VIRT(GPDIR));
1553
1554         if (readl(MUNICH_VIRT(STAT))) writel(readl(MUNICH_VIRT(STAT)), MUNICH_VIRT(STAT));
1555
1556         ccb->action_spec = CCB_ACTIONSPEC_RES | CCB_ACTIONSPEC_IA;
1557         writel(CMD_ARPCM, MUNICH_VIRT(CMD));    /* Start the PCM core reset */
1558         set_current_state(TASK_UNINTERRUPTIBLE);
1559         schedule_timeout(1);
1560
1561         stat = 0;               /* Wait for the action to complete max. 1 second */
1562         jiffs = jiffies;
1563         while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ))
1564         {
1565             set_current_state(TASK_UNINTERRUPTIBLE);
1566             schedule_timeout(1);
1567         }
1568
1569         if (stat & STAT_PCMF)
1570         {
1571             printk(KERN_ERR
1572                    "MUNICH_open: %s: Initial ARPCM failed. STAT=0x%08x\n",
1573                    board->devname, stat);
1574             writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT));
1575             free_irq(board->irq, (void *)board);        /* TOD: free other resources too *//* maybe shut down hw? */
1576             board->irq = 0;
1577             spin_unlock_irqrestore(&mister_lock, flags);
1578             return -EAGAIN;
1579         }
1580         else if (!(stat & STAT_PCMA))
1581         {
1582             printk(KERN_ERR
1583                    "MUNICH_open: %s: Initial ARPCM timeout. STAT=0x%08x\n",
1584                    board->devname, stat);
1585             free_irq(board->irq, (void *)board);        /* TOD: free other resources too *//* maybe shut off the hw? */
1586             board->irq = 0;
1587             spin_unlock_irqrestore(&mister_lock, flags);
1588             return -EIO;
1589         }
1590
1591         writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT));        /* Acknowledge */
1592
1593         if (board->isx21) writel(0, MUNICH_VIRT(GPDATA));
1594
1595         printk("MUNICH_open: %s: succesful HW-open took %ld jiffies\n",
1596                board->devname, jiffies - jiffs);
1597
1598         /* Set up the FALC hanging on the Local Bus: */
1599
1600         if (!board->isx21)
1601         {
1602             writeb(0x0e, lbi + FMR1);
1603             writeb(0, lbi + LIM0);
1604             writeb(0xb0, lbi + LIM1);   /* TODO: input threshold */
1605             writeb(0xf7, lbi + XPM0);
1606             writeb(0x02, lbi + XPM1);
1607             writeb(0x00, lbi + XPM2);
1608             writeb(0xf0, lbi + FMR0);
1609             writeb(0x80, lbi + PCD);
1610             writeb(0x80, lbi + PCR);
1611             writeb(0x00, lbi + LIM2);
1612             writeb(0x07, lbi + XC0);
1613             writeb(0x3d, lbi + XC1);
1614             writeb(0x05, lbi + RC0);
1615             writeb(0x00, lbi + RC1);
1616             writeb(0x83, lbi + FMR2);
1617             writeb(0x9f, lbi + XSW);
1618             writeb(0x0f, lbi + XSP);
1619             writeb(0x00, lbi + TSWM);
1620             writeb(0xe0, lbi + MODE);
1621             writeb(0xff, lbi + IDLE);   /* Idle Code to send in unused timeslots        */
1622             writeb(0x83, lbi + IPC);    /* interrupt query line mode: Push/pull output, active high     */
1623             writeb(0xbf, lbi + IMR3);   /* send an interrupt every second               */
1624
1625             slicecom_set_framing(hw->boardnum, board->framing);
1626             slicecom_set_linecode(hw->boardnum, board->linecode);
1627             slicecom_set_clock_source(hw->boardnum, board->clock_source);
1628             slicecom_set_loopback(hw->boardnum, board->loopback);
1629
1630             memset((void *)board->intervals, 0, sizeof(board->intervals));
1631             board->current_interval = 0;
1632             board->elapsed_seconds = 0;
1633             board->ses_seconds = 0;
1634             board->is_unavailable = 0;
1635             board->no_ses_seconds = 0;
1636             board->deg_elapsed_seconds = 0;
1637             board->deg_cumulated_errors = 0;
1638         }
1639
1640         /* Enable the interrupts last                                                   */
1641         /* These interrupts will be enabled. We do not need the others. */
1642
1643         writel(readl(MUNICH_VIRT(IMASK)) & ~(STAT_PTI | STAT_PRI | STAT_LBII | STAT_TSPA | STAT_RSPA), MUNICH_VIRT(IMASK));
1644     }
1645
1646     spin_unlock_irqrestore(&mister_lock, flags);
1647
1648     dev->irq = board->irq;      /* hogy szep legyen az ifconfig outputja */
1649     ccb = board->ccb;           /* TODO: ez igy csunya egy kicsit hogy benn is meg kinn is beletoltom :( */
1650
1651     spin_lock_irqsave(&mister_lock, flags);
1652
1653     set_current_state(TASK_UNINTERRUPTIBLE);
1654     schedule_timeout(1);
1655
1656     /* Check if the selected timeslots aren't used already */
1657
1658     for (i = 0; i < 32; i++)
1659         if (((1 << i) & timeslots) && !ccb->timeslot_spec[i].tti)
1660         {
1661             printk("MUNICH_open: %s: timeslot %d already used by %s\n",
1662                    dev->name, i, board->twins[ccb->timeslot_spec[i].txchannel]->name);
1663             spin_unlock_irqrestore(&mister_lock, flags);
1664             return -EBUSY;      /* TODO: lehet hogy valami mas errno kellene? */
1665         }
1666
1667     /* find a free channel: */
1668     /* TODO: ugly, rewrite it  */
1669
1670     for (channel = 0; channel <= 32; channel++)
1671     {
1672         if (channel == 32)
1673         {                       /* not found a free one */
1674             printk
1675                 ("MUNICH_open: %s: FATAL: can not find a free channel - this should not happen!\n",
1676                  dev->name);
1677             spin_unlock_irqrestore(&mister_lock, flags);
1678             return -ENODEV;
1679         }
1680         if (board->twins[channel] == NULL)
1681             break;              /* found the first free one */
1682     }
1683
1684     board->lastcheck = jiffies; /* avoid checking uninitialized hardware channel */
1685
1686     /* Open the channel. If fails, calls MUNICH_close() to properly free resources and stop the HW */
1687
1688     hw->channel = channel;
1689     board->twins[channel] = dev;
1690
1691     board->use_count++;         /* meg nem nyitottuk meg a csatornat, de a twins-ben
1692                                    mar elfoglaltunk egyet, es ha a _close-t akarjuk hivni, akkor ez kell. */
1693     for (i = 0; i < 32; i++)
1694         if ((1 << i) & timeslots)
1695         {
1696             ccb->timeslot_spec[i].tti = 0;
1697             ccb->timeslot_spec[i].txchannel = channel;
1698             ccb->timeslot_spec[i].txfillmask = ~0;
1699
1700             ccb->timeslot_spec[i].rti = 0;
1701             ccb->timeslot_spec[i].rxchannel = channel;
1702             ccb->timeslot_spec[i].rxfillmask = ~0;
1703         }
1704
1705     if (!board->isx21) rework_idle_channels(dev);
1706
1707     memset((void *)&(hw->tx_desc), 0, TX_DESC_MAX * sizeof(tx_desc_t));
1708     memset((void *)&(hw->rx_desc), 0, RX_DESC_MAX * sizeof(rx_desc_t));
1709
1710     for (i = 0; i < TX_DESC_MAX; i++)
1711     {
1712         hw->tx_desc[i].fe = 1;
1713         hw->tx_desc[i].fnum = 2;
1714                 hw->tx_desc[i].data     = virt_to_phys( & (hw->tx_data[i][0]) );
1715                 hw->tx_desc[i].next     = virt_to_phys( & (hw->tx_desc[ (i+1) % TX_DESC_MAX ]) );
1716
1717     }
1718     hw->tx_desc_ptr = 0;        /* we will send an initial packet so it is correct: "oda irtunk utoljara" */
1719     hw->busy = 0;
1720     hw->tx_desc[hw->tx_desc_ptr].hold = 1;
1721     hw->tx_desc[hw->tx_desc_ptr].no = 1;        /* TOD: inkabb csak 0 hosszut kuldjunk ki az initkor? */
1722
1723     for (i = 0; i < RX_DESC_MAX; i++)
1724     {
1725         hw->rx_desc[i].no = RXBUFFER_SIZE;
1726         hw->rx_desc[i].data = virt_to_phys(&(hw->rx_data[i][0]));
1727         hw->rx_desc[i].next = virt_to_phys(&(hw->rx_desc[(i+1) % RX_DESC_MAX]));
1728         hw->rx_desc[i].status = 0xFF;
1729     }
1730     hw->rx_desc_ptr = 0;
1731
1732     hw->rx_desc[(hw->rx_desc_ptr + RX_DESC_MAX - 2) % RX_DESC_MAX].hold = 1;
1733
1734     memset((void *)&ccb->channel_spec[channel], 0, sizeof(channel_spec_t));
1735
1736     ccb->channel_spec[channel].ti = 0;  /* Transmit off */
1737     ccb->channel_spec[channel].to = 1;
1738     ccb->channel_spec[channel].ta = 0;
1739
1740     ccb->channel_spec[channel].th = 1;  /* Transmit hold        */
1741
1742     ccb->channel_spec[channel].ri = 0;  /* Receive off  */
1743     ccb->channel_spec[channel].ro = 1;
1744     ccb->channel_spec[channel].ra = 0;
1745
1746     ccb->channel_spec[channel].mode = 3;        /* HDLC */
1747
1748     ccb->action_spec = CCB_ACTIONSPEC_IN | (channel << 8);
1749     writel(CMD_ARPCM, MUNICH_VIRT(CMD));
1750     set_current_state(TASK_UNINTERRUPTIBLE);
1751     schedule_timeout(1);
1752
1753     spin_unlock_irqrestore(&mister_lock, flags);
1754
1755     stat = 0;
1756     jiffs = jiffies;
1757     while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ))
1758     {
1759         set_current_state(TASK_UNINTERRUPTIBLE);
1760         schedule_timeout(1);
1761     }
1762
1763     if (stat & STAT_PCMF)
1764     {
1765         printk(KERN_ERR "MUNICH_open: %s: %s channel %d off failed\n",
1766                dev->name, board->devname, channel);
1767         writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT));
1768         MUNICH_close(dev);
1769         return -EAGAIN;
1770     }
1771     else if (!(stat & STAT_PCMA))
1772     {
1773         printk(KERN_ERR "MUNICH_open: %s: %s channel %d off timeout\n",
1774                dev->name, board->devname, channel);
1775         MUNICH_close(dev);
1776         return -EIO;
1777     }
1778
1779     writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT));
1780     //      printk("MUNICH_open: %s: succesful channel off took %ld jiffies\n", board->devname, jiffies-jiffs);
1781
1782     spin_lock_irqsave(&mister_lock, flags);
1783
1784     set_current_state(TASK_UNINTERRUPTIBLE);
1785     schedule_timeout(1);
1786
1787     ccb->channel_spec[channel].ifc = 1; /* 1 .. 'Idle/Flag change' interrupt letiltva   */
1788     ccb->channel_spec[channel].fit = 1;
1789     ccb->channel_spec[channel].nitbs = 1;
1790     ccb->channel_spec[channel].itbs = 2;
1791
1792     /* TODOO: lehet hogy jo lenne igy, de utana kellene nezni hogy nem okoz-e fragmentaciot */
1793     //      ccb->channel_spec[channel].itbs = 2 * number_of_timeslots;
1794     //      printk("open: %s: number_of_timeslots: %d\n", dev->name, number_of_timeslots);
1795
1796     ccb->channel_spec[channel].mode = 3;        /* HDLC */
1797     ccb->channel_spec[channel].ftda = virt_to_phys(&(hw->tx_desc));
1798     ccb->channel_spec[channel].frda = virt_to_phys(&(hw->rx_desc[0]));
1799
1800     ccb->channel_spec[channel].ti = 1;  /* Transmit init        */
1801     ccb->channel_spec[channel].to = 0;
1802     ccb->channel_spec[channel].ta = 1;
1803
1804     ccb->channel_spec[channel].th = 0;
1805
1806     ccb->channel_spec[channel].ri = 1;  /* Receive init */
1807     ccb->channel_spec[channel].ro = 0;
1808     ccb->channel_spec[channel].ra = 1;
1809
1810     ccb->action_spec = CCB_ACTIONSPEC_ICO | (channel << 8);
1811     writel(CMD_ARPCM, MUNICH_VIRT(CMD));        /* Start the channel init */
1812     set_current_state(TASK_UNINTERRUPTIBLE);
1813     schedule_timeout(1);
1814
1815     spin_unlock_irqrestore(&mister_lock, flags);
1816
1817     stat = 0;                   /* Wait for the action to complete max. 1 second */
1818     jiffs = jiffies;
1819     while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ))
1820     {
1821         set_current_state(TASK_UNINTERRUPTIBLE);
1822         schedule_timeout(1);
1823     }
1824
1825     if (stat & STAT_PCMF)
1826     {
1827         printk(KERN_ERR "MUNICH_open: %s: channel open ARPCM failed\n",
1828                board->devname);
1829         writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT));
1830         MUNICH_close(dev);
1831         return -EAGAIN;
1832     }
1833     else if (!(stat & STAT_PCMA))
1834     {
1835         printk(KERN_ERR "MUNICH_open: %s: channel open ARPCM timeout\n",
1836                board->devname);
1837         MUNICH_close(dev);
1838         return -EIO;
1839     }
1840
1841     writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT));
1842     //      printk("MUNICH_open: %s: succesful channel open took %ld jiffies\n", board->devname, jiffies-jiffs);
1843
1844     spin_lock_irqsave(&mister_lock, flags);
1845
1846     ccb->channel_spec[channel].nitbs = 0;       /* once ITBS defined, these must be 0   */
1847     ccb->channel_spec[channel].itbs = 0;
1848
1849     if (board->isx21)
1850     {
1851         init_timer(&board->modemline_timer);
1852         board->modemline_timer.data = (unsigned long)board;
1853         board->modemline_timer.function = pcicom_modemline;
1854         board->modemline_timer.expires = jiffies + HZ;
1855         add_timer((struct timer_list *)&board->modemline_timer);
1856     }
1857
1858     /* It is done. Declare that we're open: */
1859     hw->busy = 0;               /* It may be 1 if the frame at Tx init already ended, but it is not     */
1860     /* a real problem: we compute hw->busy on every interrupt                       */
1861     hw->rafutott = 0;
1862     ch->init_status |= HW_OPEN;
1863
1864     /* Initialize line state: */
1865     if (board->lineup)
1866         ch->line_status |= LINE_UP;
1867     else
1868         ch->line_status &= ~LINE_UP;
1869
1870     /* Remove w attribute from /proc files associated to hw parameters:
1871        no write when the device is open */
1872
1873     for (; procfile; procfile = procfile->next)
1874         if (strcmp(procfile->name, FILENAME_BOARDNUM) == 0 ||
1875             strcmp(procfile->name, FILENAME_TIMESLOTS) == 0)
1876             procfile->mode = S_IFREG | 0444;
1877
1878     spin_unlock_irqrestore(&mister_lock, flags);
1879
1880     return 0;
1881 }
1882
1883 /*
1884  * Hardware close routine.
1885  * Called by comx (upper) layer when the user wants to bring down the interface
1886  * with ifconfig.
1887  * We also call it from MUNICH_open, if the open fails.
1888  * Brings down hardware, frees resources, stops receiver
1889  * Returns 0 on OK, or standard error value on error.
1890  */
1891
1892 static int MUNICH_close(struct net_device *dev)
1893 {
1894     struct comx_channel *ch = netdev_priv(dev);
1895     struct slicecom_privdata *hw = ch->HW_privdata;
1896     struct proc_dir_entry *procfile = ch->procdir->subdir;
1897     munich_board_t *board;
1898     munich_ccb_t *ccb;
1899
1900     u32 *bar1;
1901     u32 timeslots = hw->timeslots;
1902     int stat, i, channel = hw->channel;
1903     unsigned long jiffs;
1904
1905     board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
1906
1907     ccb = board->ccb;
1908     bar1 = board->bar1;
1909
1910     if (board->isx21)
1911         del_timer((struct timer_list *)&board->modemline_timer);
1912
1913     spin_lock_irqsave(&mister_lock, flags);
1914
1915     set_current_state(TASK_UNINTERRUPTIBLE);
1916     schedule_timeout(1);
1917
1918     /* Disable receiver for the channel: */
1919
1920     for (i = 0; i < 32; i++)
1921         if ((1 << i) & timeslots)
1922         {
1923             ccb->timeslot_spec[i].tti = 1;
1924             ccb->timeslot_spec[i].txfillmask = 0;       /* just to be double-sure :) */
1925
1926             ccb->timeslot_spec[i].rti = 1;
1927             ccb->timeslot_spec[i].rxfillmask = 0;
1928         }
1929
1930     if (!board->isx21) rework_idle_channels(dev);
1931
1932     ccb->channel_spec[channel].ti = 0;  /* Receive off, Transmit off */
1933     ccb->channel_spec[channel].to = 1;
1934     ccb->channel_spec[channel].ta = 0;
1935     ccb->channel_spec[channel].th = 1;
1936
1937     ccb->channel_spec[channel].ri = 0;
1938     ccb->channel_spec[channel].ro = 1;
1939     ccb->channel_spec[channel].ra = 0;
1940
1941     board->twins[channel] = NULL;
1942
1943     ccb->action_spec = CCB_ACTIONSPEC_IN | (channel << 8);
1944     writel(CMD_ARPCM, MUNICH_VIRT(CMD));
1945     set_current_state(TASK_UNINTERRUPTIBLE);
1946     schedule_timeout(1);
1947
1948     spin_unlock_irqrestore(&mister_lock, flags);
1949
1950     stat = 0;
1951     jiffs = jiffies;
1952     while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ))
1953     {
1954         set_current_state(TASK_UNINTERRUPTIBLE);
1955         schedule_timeout(1);
1956     }
1957
1958     if (stat & STAT_PCMF)
1959     {
1960         printk(KERN_ERR
1961                "MUNICH_close: %s: FATAL: channel off ARPCM failed, not closing!\n",
1962                dev->name);
1963         writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT));
1964         /* If we return success, the privdata (and the descriptor list) will be freed */
1965         return -EIO;
1966     }
1967     else if (!(stat & STAT_PCMA))
1968         printk(KERN_ERR "MUNICH_close: %s: channel off ARPCM timeout\n",
1969                board->devname);
1970
1971     writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT));
1972     //      printk("MUNICH_close: %s: channel off took %ld jiffies\n", board->devname, jiffies-jiffs);
1973
1974     spin_lock_irqsave(&mister_lock, flags);
1975
1976     if (board->use_count) board->use_count--;
1977
1978     if (!board->use_count)      /* we were the last user of the board */
1979     {
1980         printk("MUNICH_close: bringing down board %s\n", board->devname);
1981
1982         /* program down the board: */
1983
1984         writel(0x0000FF7F, MUNICH_VIRT(IMASK)); /* do not send any interrupts */
1985         writel(0, MUNICH_VIRT(CMD));    /* stop the timer if someone started it */
1986         writel(~0U, MUNICH_VIRT(STAT)); /* if an interrupt came between the cli()-sti(), quiet it */
1987         if (ch->hardware == &pcicomhw)
1988             writel(0x1400, MUNICH_VIRT(GPDATA));
1989
1990         /* Put the board into 'reset' state: */
1991         pci_write_config_dword(board->pci, MUNICH_PCI_PCIRES, 0xe0000);
1992
1993         /* Free irq and other resources: */
1994         if (board->irq)
1995             free_irq(board->irq, (void *)board);        /* Ha nem inicializalta magat, akkor meg nincs irq */
1996         board->irq = 0;
1997
1998         /* Free CCB and the interrupt queues */
1999         if (board->ccb) kfree((void *)board->ccb);
2000         if (board->tiq) kfree((void *)board->tiq);
2001         if (board->riq) kfree((void *)board->riq);
2002         if (board->piq) kfree((void *)board->piq);
2003         board->ccb = NULL;
2004         board->tiq = board->riq = board->piq = NULL;
2005     }
2006
2007     /* Enable setting of hw parameters */
2008     for (; procfile; procfile = procfile->next)
2009         if (strcmp(procfile->name, FILENAME_BOARDNUM) == 0 ||
2010             strcmp(procfile->name, FILENAME_TIMESLOTS) == 0)
2011             procfile->mode = S_IFREG | 0644;
2012
2013     /* We're not open anymore */
2014     ch->init_status &= ~HW_OPEN;
2015
2016     spin_unlock_irqrestore(&mister_lock, flags);
2017
2018     return 0;
2019 }
2020
2021 /* 
2022  * Give (textual) status information.
2023  * The text it returns will be a part of what appears when the user does a
2024  * cat /proc/comx/comx[n]/status 
2025  * Don't write more than PAGESIZE.
2026  * Return value: number of bytes written (length of the string, incl. 0)
2027  */
2028
2029 static int MUNICH_minden(struct net_device *dev, char *page)
2030 {
2031     struct comx_channel *ch = netdev_priv(dev);
2032     struct slicecom_privdata *hw = ch->HW_privdata;
2033     munich_board_t *board;
2034     struct net_device *devp;
2035
2036     u8 *lbi;
2037     e1_stats_t *curr_int, *prev_int;
2038     e1_stats_t last4, last96;   /* sum of last 4, resp. last 96 intervals               */
2039     unsigned *sump,             /* running pointer for the sum data                     */
2040      *p;                        /* running pointer for the interval data                */
2041
2042     int len = 0;
2043     u8 frs0, frs1;
2044     u8 fmr2;
2045     int i, j;
2046     u32 timeslots;
2047
2048     board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
2049
2050     lbi = board->lbi;
2051     curr_int = &board->intervals[board->current_interval];
2052     prev_int =
2053         &board->
2054         intervals[(board->current_interval + SLICECOM_BOARD_INTERVALS_SIZE -
2055                    1) % SLICECOM_BOARD_INTERVALS_SIZE];
2056
2057     if (!board->isx21)
2058     {
2059         frs0 = readb(lbi + FRS0);
2060         fmr2 = readb(lbi + FMR2);
2061         len += scnprintf(page + len, PAGE_SIZE - len, "Controller status:\n");
2062         if (frs0 == 0)
2063             len += scnprintf(page + len, PAGE_SIZE - len, "\tNo alarms\n");
2064         else
2065         {
2066             if (frs0 & FRS0_LOS)
2067                     len += scnprintf(page + len, PAGE_SIZE - len, "\tLoss Of Signal\n");
2068             else
2069             {
2070                 if (frs0 & FRS0_AIS)
2071                     len += scnprintf(page + len, PAGE_SIZE - len,
2072                                  "\tAlarm Indication Signal\n");
2073                 else
2074                 {
2075                     if (frs0 & FRS0_AUXP)
2076                         len += scnprintf(page + len, PAGE_SIZE - len,
2077                                      "\tAuxiliary Pattern Indication\n");
2078                     if (frs0 & FRS0_LFA)
2079                         len += scnprintf(page + len, PAGE_SIZE - len,
2080                                      "\tLoss of Frame Alignment\n");
2081                     else
2082                     {
2083                         if (frs0 & FRS0_RRA)
2084                             len += scnprintf(page + len, PAGE_SIZE - len,
2085                                          "\tReceive Remote Alarm\n");
2086
2087                         /* You can't set this framing with the /proc interface, but it  */
2088                         /* may be good to have here this alarm if you set it by hand:   */
2089
2090                         if ((board->framing == SLICECOM_FRAMING_CRC4) &&
2091                             (frs0 & FRS0_LMFA))
2092                             len += scnprintf(page + len, PAGE_SIZE - len,
2093                                          "\tLoss of CRC4 Multiframe Alignment\n");
2094
2095                         if (((fmr2 & 0xc0) == 0xc0) && (frs0 & FRS0_NMF))
2096                             len += scnprintf(page + len, PAGE_SIZE - len,
2097                                  "\tNo CRC4 Multiframe alignment Found after 400 msec\n");
2098                     }
2099                 }
2100             }
2101         }
2102
2103         frs1 = readb(lbi + FRS1);
2104         if (FRS1_XLS & frs1)
2105             len += scnprintf(page + len, PAGE_SIZE - len,
2106                  "\tTransmit Line Short\n");
2107
2108         /* debug Rx ring: DEL: - vagy meghagyni, de akkor legyen kicsit altalanosabb */
2109     }
2110
2111     len += scnprintf(page + len, PAGE_SIZE - len, "Rx ring:\n");
2112     len += scnprintf(page + len, PAGE_SIZE - len, "\trafutott: %d\n", hw->rafutott);
2113     len += scnprintf(page + len, PAGE_SIZE - len,
2114                  "\tlastcheck: %ld, jiffies: %ld\n", board->lastcheck, jiffies);
2115     len += scnprintf(page + len, PAGE_SIZE - len, "\tbase: %08x\n",
2116         (u32) virt_to_phys(&hw->rx_desc[0]));
2117     len += scnprintf(page + len, PAGE_SIZE - len, "\trx_desc_ptr: %d\n",
2118                  hw->rx_desc_ptr);
2119     len += scnprintf(page + len, PAGE_SIZE - len, "\trx_desc_ptr: %08x\n",
2120         (u32) virt_to_phys(&hw->rx_desc[hw->rx_desc_ptr]));
2121     len += scnprintf(page + len, PAGE_SIZE - len, "\thw_curr_ptr: %08x\n",
2122                  board->ccb->current_rx_desc[hw->channel]);
2123
2124     for (i = 0; i < RX_DESC_MAX; i++)
2125         len += scnprintf(page + len, PAGE_SIZE - len, "\t%08x %08x %08x %08x\n",
2126                      *((u32 *) & hw->rx_desc[i] + 0),
2127                      *((u32 *) & hw->rx_desc[i] + 1),
2128                      *((u32 *) & hw->rx_desc[i] + 2),
2129                      *((u32 *) & hw->rx_desc[i] + 3));
2130
2131     if (!board->isx21)
2132     {
2133         len += scnprintf(page + len, PAGE_SIZE - len,
2134                      "Interfaces using this board: (channel-group, interface, timeslots)\n");
2135         for (i = 0; i < 32; i++)
2136         {
2137             devp = board->twins[i];
2138             if (devp != NULL)
2139             {
2140                 timeslots =
2141                     ((struct slicecom_privdata *)((struct comx_channel *)devp->
2142                                                   priv)->HW_privdata)->
2143                     timeslots;
2144                 len += scnprintf(page + len, PAGE_SIZE - len, "\t%2d %s: ", i,
2145                              devp->name);
2146                 for (j = 0; j < 32; j++)
2147                     if ((1 << j) & timeslots)
2148                         len += scnprintf(page + len, PAGE_SIZE - len, "%d ", j);
2149                 len += scnprintf(page + len, PAGE_SIZE - len, "\n");
2150             }
2151         }
2152     }
2153
2154     len += scnprintf(page + len, PAGE_SIZE - len, "Interrupt work histogram:\n");
2155     for (i = 0; i < MAX_WORK; i++)
2156         len += scnprintf(page + len, PAGE_SIZE - len, "hist[%2d]: %8u%c", i,
2157                      board->histogram[i], (i &&
2158                                            ((i + 1) % 4 == 0 ||
2159                                             i == MAX_WORK - 1)) ? '\n' : ' ');
2160
2161     len += scnprintf(page + len, PAGE_SIZE - len, "Tx ring histogram:\n");
2162     for (i = 0; i < TX_DESC_MAX; i++)
2163         len += scnprintf(page + len, PAGE_SIZE - len, "hist[%2d]: %8u%c", i,
2164                      hw->tx_ring_hist[i], (i &&
2165                                            ((i + 1) % 4 == 0 ||
2166                                             i ==
2167                                             TX_DESC_MAX - 1)) ? '\n' : ' ');
2168
2169     if (!board->isx21)
2170     {
2171
2172         memset((void *)&last4, 0, sizeof(last4));
2173         memset((void *)&last96, 0, sizeof(last96));
2174
2175         /* Calculate the sum of last 4 intervals: */
2176
2177         for (i = 1; i <= 4; i++)
2178         {
2179             p = (unsigned *)&board->intervals[(board->current_interval +
2180                            SLICECOM_BOARD_INTERVALS_SIZE -
2181                            i) % SLICECOM_BOARD_INTERVALS_SIZE];
2182             sump = (unsigned *)&last4;
2183             for (j = 0; j < (sizeof(e1_stats_t) / sizeof(unsigned)); j++)
2184                 sump[j] += p[j];
2185         }
2186
2187         /* Calculate the sum of last 96 intervals: */
2188
2189         for (i = 1; i <= 96; i++)
2190         {
2191             p = (unsigned *)&board->intervals[(board->current_interval +
2192                            SLICECOM_BOARD_INTERVALS_SIZE -
2193                            i) % SLICECOM_BOARD_INTERVALS_SIZE];
2194             sump = (unsigned *)&last96;
2195             for (j = 0; j < (sizeof(e1_stats_t) / sizeof(unsigned)); j++)
2196                 sump[j] += p[j];
2197         }
2198
2199         len += scnprintf(page + len, PAGE_SIZE - len,
2200                      "Data in current interval (%d seconds elapsed):\n",
2201                      board->elapsed_seconds);
2202         len += scnprintf(page + len, PAGE_SIZE - len,
2203                      "   %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n",
2204                      curr_int->line_code_violations,
2205                      curr_int->path_code_violations, curr_int->e_bit_errors);
2206         len += scnprintf(page + len, PAGE_SIZE - len,
2207                      "   %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n",
2208                      curr_int->slip_secs, curr_int->fr_loss_secs,
2209                      curr_int->line_err_secs, curr_int->degraded_mins);
2210         len += scnprintf(page + len, PAGE_SIZE - len,
2211                      "   %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n",
2212                      curr_int->errored_secs, curr_int->bursty_err_secs,
2213                      curr_int->severely_err_secs, curr_int->unavail_secs);
2214
2215         len += scnprintf(page + len, PAGE_SIZE - len,
2216                      "Data in Interval 1 (15 minutes):\n");
2217         len += scnprintf(page + len, PAGE_SIZE - len,
2218                      "   %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n",
2219                      prev_int->line_code_violations,
2220                      prev_int->path_code_violations, prev_int->e_bit_errors);
2221         len += scnprintf(page + len, PAGE_SIZE - len,
2222                      "   %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n",
2223                      prev_int->slip_secs, prev_int->fr_loss_secs,
2224                      prev_int->line_err_secs, prev_int->degraded_mins);
2225         len += scnprintf(page + len, PAGE_SIZE - len,
2226                      "   %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n",
2227                      prev_int->errored_secs, prev_int->bursty_err_secs,
2228                      prev_int->severely_err_secs, prev_int->unavail_secs);
2229
2230         len += scnprintf(page + len, PAGE_SIZE - len,
2231                      "Data in last 4 intervals (1 hour):\n");
2232         len += scnprintf(page + len, PAGE_SIZE - len,
2233                      "   %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n",
2234                      last4.line_code_violations, last4.path_code_violations,
2235                      last4.e_bit_errors);
2236         len += scnprintf(page + len, PAGE_SIZE - len,
2237                      "   %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n",
2238                      last4.slip_secs, last4.fr_loss_secs, last4.line_err_secs,
2239                      last4.degraded_mins);
2240         len += scnprintf(page + len, PAGE_SIZE - len,
2241                      "   %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n",
2242                      last4.errored_secs, last4.bursty_err_secs,
2243                      last4.severely_err_secs, last4.unavail_secs);
2244
2245         len += scnprintf(page + len, PAGE_SIZE - len,
2246                      "Data in last 96 intervals (24 hours):\n");
2247         len += scnprintf(page + len, PAGE_SIZE - len,
2248                      "   %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n",
2249                      last96.line_code_violations, last96.path_code_violations,
2250                      last96.e_bit_errors);
2251         len += scnprintf(page + len, PAGE_SIZE - len,
2252                      "   %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n",
2253                      last96.slip_secs, last96.fr_loss_secs,
2254                      last96.line_err_secs, last96.degraded_mins);
2255         len += scnprintf(page + len, PAGE_SIZE - len,
2256                      "   %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n",
2257                      last96.errored_secs, last96.bursty_err_secs,
2258                      last96.severely_err_secs, last96.unavail_secs);
2259
2260     }
2261
2262 //      len +=scnprintf( page + len, PAGE_SIZE - len, "Special events:\n" );
2263 //      len +=scnprintf( page + len, PAGE_SIZE - len, "\tstat_pri/missed: %u / %u\n", board->stat_pri_races, board->stat_pri_races_missed );
2264 //      len +=scnprintf( page + len, PAGE_SIZE - len, "\tstat_pti/missed: %u / %u\n", board->stat_pti_races, board->stat_pti_races_missed );
2265     return len;
2266 }
2267
2268 /*
2269  * Memory dump function. Not used currently.
2270  */
2271 static int BOARD_dump(struct net_device *dev)
2272 {
2273     printk
2274         ("BOARD_dump() requested. It is unimplemented, it should not be called\n");
2275     return (-1);
2276 }
2277
2278 /* 
2279  * /proc file read function for the files registered by this module.
2280  * This function is called by the procfs implementation when a user
2281  * wants to read from a file registered by this module.
2282  * page is the workspace, start should point to the real start of data,
2283  * off is the file offset, data points to the file's proc_dir_entry
2284  * structure.
2285  * Returns the number of bytes copied to the request buffer.
2286  */
2287
2288 static int munich_read_proc(char *page, char **start, off_t off, int count,
2289                             int *eof, void *data)
2290 {
2291     struct proc_dir_entry *file = (struct proc_dir_entry *)data;
2292     struct net_device *dev = file->parent->data;
2293     struct comx_channel *ch = netdev_priv(dev);
2294     struct slicecom_privdata *hw = ch->HW_privdata;
2295     munich_board_t *board;
2296
2297     int len = 0, i;
2298     u32 timeslots = hw->timeslots;
2299
2300     board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
2301
2302     if (!strcmp(file->name, FILENAME_BOARDNUM))
2303         len = sprintf(page, "%d\n", hw->boardnum);
2304     else if (!strcmp(file->name, FILENAME_TIMESLOTS))
2305     {
2306         for (i = 0; i < 32; i++)
2307             if ((1 << i) & timeslots)
2308                 len += scnprintf(page + len, PAGE_SIZE - len, "%d ", i);
2309         len += scnprintf(page + len, PAGE_SIZE - len, "\n");
2310     }
2311     else if (!strcmp(file->name, FILENAME_FRAMING))
2312     {
2313         i = 0;
2314         while (slicecom_framings[i].value &&
2315                slicecom_framings[i].value != board->framing)
2316             i++;
2317         len += scnprintf(page + len, PAGE_SIZE - len, "%s\n",
2318                      slicecom_framings[i].name);
2319     }
2320     else if (!strcmp(file->name, FILENAME_LINECODE))
2321     {
2322         i = 0;
2323         while (slicecom_linecodes[i].value &&
2324                slicecom_linecodes[i].value != board->linecode)
2325             i++;
2326         len += scnprintf(page + len, PAGE_SIZE - len, "%s\n",
2327                      slicecom_linecodes[i].name);
2328     }
2329     else if (!strcmp(file->name, FILENAME_CLOCK_SOURCE))
2330     {
2331         i = 0;
2332         while (slicecom_clock_sources[i].value &&
2333                slicecom_clock_sources[i].value != board->clock_source)
2334             i++;
2335         len +=
2336             scnprintf(page + len, PAGE_SIZE - len, "%s\n",
2337                      slicecom_clock_sources[i].name);
2338     }
2339     else if (!strcmp(file->name, FILENAME_LOOPBACK))
2340     {
2341         i = 0;
2342         while (slicecom_loopbacks[i].value &&
2343                slicecom_loopbacks[i].value != board->loopback)
2344             i++;
2345         len += scnprintf(page + len, PAGE_SIZE - len, "%s\n",
2346                      slicecom_loopbacks[i].name);
2347     }
2348     /* We set permissions to write-only for REG and LBIREG, but root can read them anyway: */
2349     else if (!strcmp(file->name, FILENAME_REG))
2350     {
2351         len += scnprintf(page + len, PAGE_SIZE - len,
2352                      "%s: " FILENAME_REG ": write-only file\n", dev->name);
2353     }
2354     else if (!strcmp(file->name, FILENAME_LBIREG))
2355     {
2356         len += scnprintf(page + len, PAGE_SIZE - len,
2357                      "%s: " FILENAME_LBIREG ": write-only file\n", dev->name);
2358     }
2359     else
2360     {
2361         printk("slicecom_read_proc: internal error, filename %s\n", file->name);
2362         return -EBADF;
2363     }
2364     /* file handling administration: count eof status, offset, start address
2365        and count: */
2366
2367     if (off >= len)
2368     {
2369         *eof = 1;
2370         return 0;
2371     }
2372
2373     *start = page + off;
2374     if (count >= len - off)
2375         *eof = 1;
2376     return min((off_t) count, (off_t) len - off);
2377 }
2378
2379 /* 
2380  * Write function for /proc files registered by us.
2381  * See the comment on read function above.
2382  * Beware! buffer is in userspace!!!
2383  * Returns the number of bytes written
2384  */
2385
2386 static int munich_write_proc(struct file *file, const char *buffer,
2387                              u_long count, void *data)
2388 {
2389     struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
2390     struct net_device *dev = (struct net_device *)entry->parent->data;
2391     struct comx_channel *ch = netdev_priv(dev);
2392     struct slicecom_privdata *hw = ch->HW_privdata;
2393     munich_board_t *board;
2394
2395     unsigned long ts, tmp_boardnum;
2396
2397     u32 tmp_timeslots = 0;
2398     char *page, *p;
2399     int i;
2400
2401     board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
2402
2403     /* Paranoia checking: */
2404
2405     if (PDE(file->f_dentry->d_inode) != entry)
2406     {
2407         printk(KERN_ERR "munich_write_proc: file <-> data internal error\n");
2408         return -EIO;
2409     }
2410
2411     /* Request tmp buffer */
2412     if (!(page = (char *)__get_free_page(GFP_KERNEL)))
2413         return -ENOMEM;
2414
2415     /* Copy user data and cut trailing \n */
2416     if (copy_from_user(page, buffer, count = min(count, PAGE_SIZE))) {
2417             free_page((unsigned long)page);
2418             return -EFAULT;
2419     }
2420     if (*(page + count - 1) == '\n')
2421         *(page + count - 1) = 0;
2422     *(page + PAGE_SIZE - 1) = 0;
2423
2424     if (!strcmp(entry->name, FILENAME_BOARDNUM))
2425     {
2426         tmp_boardnum = simple_strtoul(page, NULL, 0);
2427         if (0 <= tmp_boardnum && tmp_boardnum < MAX_BOARDS)
2428             hw->boardnum = tmp_boardnum;
2429         else
2430         {
2431             printk("%s: " FILENAME_BOARDNUM " range is 0...%d\n", dev->name,
2432                    MAX_BOARDS - 1);
2433             free_page((unsigned long)page);
2434             return -EINVAL;
2435         }
2436     }
2437     else if (!strcmp(entry->name, FILENAME_TIMESLOTS))
2438     {
2439         p = page;
2440         while (*p)
2441         {
2442             if (isspace(*p))
2443                 p++;
2444             else
2445             {
2446                 ts = simple_strtoul(p, &p, 10); /* base = 10: Don't read 09 as an octal number */
2447                 /* ts = 0 ha nem tudta beolvasni a stringet, erre egy kicsit epitek itt: */
2448                 if (0 <= ts && ts < 32)
2449                 {
2450                     tmp_timeslots |= (1 << ts);
2451                 }
2452                 else
2453                 {
2454                     printk("%s: " FILENAME_TIMESLOTS " range is 1...31\n",
2455                            dev->name);
2456                     free_page((unsigned long)page);
2457                     return -EINVAL;
2458                 }
2459             }
2460         }
2461         hw->timeslots = tmp_timeslots;
2462     }
2463     else if (!strcmp(entry->name, FILENAME_FRAMING))
2464     {
2465         i = 0;
2466         while (slicecom_framings[i].value &&
2467                strncmp(slicecom_framings[i].name, page,
2468                        strlen(slicecom_framings[i].name)))
2469             i++;
2470         if (!slicecom_framings[i].value)
2471         {
2472             printk("slicecom: %s: Invalid " FILENAME_FRAMING " '%s'\n",
2473                    dev->name, page);
2474             free_page((unsigned long)page);
2475             return -EINVAL;
2476         }
2477         else
2478         {                       /*
2479                                  * If somebody says:
2480                                  *      echo >boardnum  0
2481                                  *      echo >framing   no-crc4
2482                                  *      echo >boardnum  1
2483                                  * - when the framing was set, hw->boardnum was 0, so it would set the framing for board 0
2484                                  * Workaround: allow to set it only if interface is administrative UP
2485                                  */
2486             if (netif_running(dev))
2487                 slicecom_set_framing(hw->boardnum, slicecom_framings[i].value);
2488             else
2489             {
2490                 printk("%s: " FILENAME_FRAMING
2491                        " can not be set while the interface is DOWN\n",
2492                        dev->name);
2493                 free_page((unsigned long)page);
2494                 return -EINVAL;
2495             }
2496         }
2497     }
2498     else if (!strcmp(entry->name, FILENAME_LINECODE))
2499     {
2500         i = 0;
2501         while (slicecom_linecodes[i].value &&
2502                strncmp(slicecom_linecodes[i].name, page,
2503                        strlen(slicecom_linecodes[i].name)))
2504             i++;
2505         if (!slicecom_linecodes[i].value)
2506         {
2507             printk("slicecom: %s: Invalid " FILENAME_LINECODE " '%s'\n",
2508                    dev->name, page);
2509             free_page((unsigned long)page);
2510             return -EINVAL;
2511         }
2512         else
2513         {                       /*
2514                                  * Allow to set it only if interface is administrative UP,
2515                                  * for the same reason as FILENAME_FRAMING
2516                                  */
2517             if (netif_running(dev))
2518                 slicecom_set_linecode(hw->boardnum,
2519                                       slicecom_linecodes[i].value);
2520             else
2521             {
2522                 printk("%s: " FILENAME_LINECODE
2523                        " can not be set while the interface is DOWN\n",
2524                        dev->name);
2525                 free_page((unsigned long)page);
2526                 return -EINVAL;
2527             }
2528         }
2529     }
2530     else if (!strcmp(entry->name, FILENAME_CLOCK_SOURCE))
2531     {
2532         i = 0;
2533         while (slicecom_clock_sources[i].value &&
2534                strncmp(slicecom_clock_sources[i].name, page,
2535                        strlen(slicecom_clock_sources[i].name)))
2536             i++;
2537         if (!slicecom_clock_sources[i].value)
2538         {
2539             printk("%s: Invalid " FILENAME_CLOCK_SOURCE " '%s'\n", dev->name,
2540                    page);
2541             free_page((unsigned long)page);
2542             return -EINVAL;
2543         }
2544         else
2545         {                       /*
2546                                  * Allow to set it only if interface is administrative UP,
2547                                  * for the same reason as FILENAME_FRAMING
2548                                  */
2549             if (netif_running(dev))
2550                 slicecom_set_clock_source(hw->boardnum,
2551                                           slicecom_clock_sources[i].value);
2552             else
2553             {
2554                 printk("%s: " FILENAME_CLOCK_SOURCE
2555                        " can not be set while the interface is DOWN\n",
2556                        dev->name);
2557                 free_page((unsigned long)page);
2558                 return -EINVAL;
2559             }
2560         }
2561     }
2562     else if (!strcmp(entry->name, FILENAME_LOOPBACK))
2563     {
2564         i = 0;
2565         while (slicecom_loopbacks[i].value &&
2566                strncmp(slicecom_loopbacks[i].name, page,
2567                        strlen(slicecom_loopbacks[i].name)))
2568             i++;
2569         if (!slicecom_loopbacks[i].value)
2570         {
2571             printk("%s: Invalid " FILENAME_LOOPBACK " '%s'\n", dev->name, page);
2572             free_page((unsigned long)page);
2573             return -EINVAL;
2574         }
2575         else
2576         {                       /*
2577                                  * Allow to set it only if interface is administrative UP,
2578                                  * for the same reason as FILENAME_FRAMING
2579                                  */
2580             if (netif_running(dev))
2581                 slicecom_set_loopback(hw->boardnum,
2582                                       slicecom_loopbacks[i].value);
2583             else
2584             {
2585                 printk("%s: " FILENAME_LOOPBACK
2586                        " can not be set while the interface is DOWN\n",
2587                        dev->name);
2588                 free_page((unsigned long)page);
2589                 return -EINVAL;
2590             }
2591         }
2592     }
2593     else if (!strcmp(entry->name, FILENAME_REG))
2594     {                           /* DEL: 'reg' csak tmp */
2595         char *p;
2596         u32 *bar1 = board->bar1;
2597
2598         reg = simple_strtoul(page, &p, 0);
2599         reg_ertek = simple_strtoul(p + 1, NULL, 0);
2600
2601         if (reg < 0x100)
2602         {
2603             printk("reg(0x%02x) := 0x%08x  jiff: %lu\n", reg, reg_ertek, jiffies);
2604             writel(reg_ertek, MUNICH_VIRT(reg >> 2));
2605         }
2606         else
2607         {
2608             printk("reg(0x%02x) is 0x%08x  jiff: %lu\n", reg - 0x100,
2609                    readl(MUNICH_VIRT((reg - 0x100) >> 2)), jiffies);
2610         }
2611     }
2612     else if (!strcmp(entry->name, FILENAME_LBIREG))
2613     {                           /* DEL: 'lbireg' csak tmp */
2614         char *p;
2615         u8 *lbi = board->lbi;
2616
2617         lbireg = simple_strtoul(page, &p, 0);
2618         lbireg_ertek = simple_strtoul(p + 1, NULL, 0);
2619
2620         if (lbireg < 0x100)
2621         {
2622             printk("lbireg(0x%02x) := 0x%02x  jiff: %lu\n", lbireg,
2623                    lbireg_ertek, jiffies);
2624             writeb(lbireg_ertek, lbi + lbireg);
2625         }
2626         else
2627             printk("lbireg(0x%02x) is 0x%02x  jiff: %lu\n", lbireg - 0x100,
2628                    readb(lbi + lbireg - 0x100), jiffies);
2629     }
2630     else
2631     {
2632         printk(KERN_ERR "munich_write_proc: internal error, filename %s\n",
2633                entry->name);
2634         free_page((unsigned long)page);
2635         return -EBADF;
2636     }
2637
2638     /* Don't forget to free the workspace */
2639     free_page((unsigned long)page);
2640     return count;
2641 }
2642
2643 /* 
2644  * Boardtype init function.
2645  * Called by the comx (upper) layer, when you set boardtype.
2646  * Allocates resources associated to using munich board for this device,
2647  * initializes ch_struct pointers etc.
2648  * Returns 0 on success and standard error codes on error.
2649  */
2650
2651 static int init_escape(struct comx_channel *ch)
2652 {
2653     kfree(ch->HW_privdata);
2654     return -EIO;
2655 }
2656
2657 static int BOARD_init(struct net_device *dev)
2658 {
2659     struct comx_channel *ch = netdev_priv(dev);
2660     struct slicecom_privdata *hw;
2661     struct proc_dir_entry *new_file;
2662
2663     /* Alloc data for private structure */
2664     if ((ch->HW_privdata =
2665         kmalloc(sizeof(struct slicecom_privdata), GFP_KERNEL)) == NULL)
2666         return -ENOMEM;
2667         
2668     memset(hw = ch->HW_privdata, 0, sizeof(struct slicecom_privdata));
2669
2670     /* Register /proc files */
2671     if ((new_file = create_proc_entry(FILENAME_BOARDNUM, S_IFREG | 0644,
2672                            ch->procdir)) == NULL)
2673         return init_escape(ch);
2674     new_file->data = (void *)new_file;
2675     new_file->read_proc = &munich_read_proc;
2676     new_file->write_proc = &munich_write_proc;
2677 //      new_file->proc_iops = &comx_normal_inode_ops;
2678     new_file->nlink = 1;
2679
2680     if (ch->hardware == &slicecomhw)
2681     {
2682         if ((new_file = create_proc_entry(FILENAME_TIMESLOTS, S_IFREG | 0644,
2683                                ch->procdir)) == NULL)
2684             return init_escape(ch);
2685         new_file->data = (void *)new_file;
2686         new_file->read_proc = &munich_read_proc;
2687         new_file->write_proc = &munich_write_proc;
2688 //              new_file->proc_iops = &comx_normal_inode_ops;
2689         new_file->nlink = 1;
2690
2691         if ((new_file = create_proc_entry(FILENAME_FRAMING, S_IFREG | 0644,
2692                                ch->procdir)) == NULL)
2693             return init_escape(ch);
2694         new_file->data = (void *)new_file;
2695         new_file->read_proc = &munich_read_proc;
2696         new_file->write_proc = &munich_write_proc;
2697 //              new_file->proc_iops = &comx_normal_inode_ops;
2698         new_file->nlink = 1;
2699
2700         if ((new_file = create_proc_entry(FILENAME_LINECODE, S_IFREG | 0644,
2701                                ch->procdir)) == NULL)
2702             return init_escape(ch);
2703         new_file->data = (void *)new_file;
2704         new_file->read_proc = &munich_read_proc;
2705         new_file->write_proc = &munich_write_proc;
2706 //              new_file->proc_iops = &comx_normal_inode_ops;
2707         new_file->nlink = 1;
2708
2709         if ((new_file = create_proc_entry(FILENAME_CLOCK_SOURCE, S_IFREG | 0644,
2710                                ch->procdir)) == NULL)
2711             return init_escape(ch);
2712         new_file->data = (void *)new_file;
2713         new_file->read_proc = &munich_read_proc;
2714         new_file->write_proc = &munich_write_proc;
2715 //              new_file->proc_iops = &comx_normal_inode_ops;
2716         new_file->nlink = 1;
2717
2718         if ((new_file = create_proc_entry(FILENAME_LOOPBACK, S_IFREG | 0644,
2719                                ch->procdir)) == NULL)
2720             return init_escape(ch);
2721         new_file->data = (void *)new_file;
2722         new_file->read_proc = &munich_read_proc;
2723         new_file->write_proc = &munich_write_proc;
2724 //              new_file->proc_iops = &comx_normal_inode_ops;
2725         new_file->nlink = 1;
2726     }
2727
2728     /* DEL: ez itt csak fejlesztesi celokra!! */
2729     if ((new_file = create_proc_entry(FILENAME_REG, S_IFREG | 0200, ch->procdir)) == NULL)
2730         return init_escape(ch);
2731     new_file->data = (void *)new_file;
2732     new_file->read_proc = &munich_read_proc;
2733     new_file->write_proc = &munich_write_proc;
2734 //      new_file->proc_iops = &comx_normal_inode_ops;
2735     new_file->nlink = 1;
2736
2737     /* DEL: ez itt csak fejlesztesi celokra!! */
2738     if ((new_file = create_proc_entry(FILENAME_LBIREG, S_IFREG | 0200,
2739                            ch->procdir)) == NULL)
2740         return init_escape(ch);
2741     new_file->data = (void *)new_file;
2742     new_file->read_proc = &munich_read_proc;
2743     new_file->write_proc = &munich_write_proc;
2744 //      new_file->proc_iops = &comx_normal_inode_ops;
2745     new_file->nlink = 1;
2746
2747     /* Fill in ch_struct hw specific pointers: */
2748
2749     ch->HW_txe = MUNICH_txe;
2750     ch->HW_open = MUNICH_open;
2751     ch->HW_close = MUNICH_close;
2752     ch->HW_send_packet = MUNICH_send_packet;
2753 #ifndef COMX_NEW
2754     ch->HW_minden = MUNICH_minden;
2755 #else
2756     ch->HW_statistics = MUNICH_minden;
2757 #endif
2758
2759     hw->boardnum = SLICECOM_BOARDNUM_DEFAULT;
2760     hw->timeslots = ch->hardware == &pcicomhw ?  0xffffffff : 2;
2761
2762     /* O.K. Count one more user on this module */
2763     MOD_INC_USE_COUNT;
2764     return 0;
2765 }
2766
2767 /* 
2768  * Boardtype exit function.
2769  * Called by the comx (upper) layer, when you clear boardtype from munich.
2770  * Frees resources associated to using munich board for this device,
2771  * resets ch_struct pointers etc.
2772  */
2773 static int BOARD_exit(struct net_device *dev)
2774 {
2775     struct comx_channel *ch = netdev_priv(dev);
2776
2777     /* Free private data area */
2778 //    board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
2779
2780     kfree(ch->HW_privdata);
2781     /* Remove /proc files */
2782     remove_proc_entry(FILENAME_BOARDNUM, ch->procdir);
2783     if (ch->hardware == &slicecomhw)
2784     {
2785         remove_proc_entry(FILENAME_TIMESLOTS, ch->procdir);
2786         remove_proc_entry(FILENAME_FRAMING, ch->procdir);
2787         remove_proc_entry(FILENAME_LINECODE, ch->procdir);
2788         remove_proc_entry(FILENAME_CLOCK_SOURCE, ch->procdir);
2789         remove_proc_entry(FILENAME_LOOPBACK, ch->procdir);
2790     }
2791     remove_proc_entry(FILENAME_REG, ch->procdir);
2792     remove_proc_entry(FILENAME_LBIREG, ch->procdir);
2793
2794     /* Minus one user for the module accounting */
2795     MOD_DEC_USE_COUNT;
2796     return 0;
2797 }
2798
2799 static struct comx_hardware slicecomhw =
2800 {
2801     "slicecom",
2802 #ifdef COMX_NEW
2803     VERSION,
2804 #endif
2805     BOARD_init,
2806     BOARD_exit,
2807     BOARD_dump,
2808     NULL
2809 };
2810
2811 static struct comx_hardware pcicomhw =
2812 {
2813     "pcicom",
2814 #ifdef COMX_NEW
2815     VERSION,
2816 #endif
2817     BOARD_init,
2818     BOARD_exit,
2819     BOARD_dump,
2820     NULL
2821 };
2822
2823 /* Module management */
2824
2825 static int __init init_mister(void)
2826 {
2827     printk(VERSIONSTR);
2828     comx_register_hardware(&slicecomhw);
2829     comx_register_hardware(&pcicomhw);
2830     return munich_probe();
2831 }
2832
2833 static void __exit cleanup_mister(void)
2834 {
2835     int i;
2836
2837     comx_unregister_hardware("slicecom");
2838     comx_unregister_hardware("pcicom");
2839
2840     for (i = 0; i < MAX_BOARDS; i++)
2841     {
2842         if (slicecom_boards[i].bar1)
2843             iounmap((void *)slicecom_boards[i].bar1);
2844         if (slicecom_boards[i].lbi)
2845             iounmap((void *)slicecom_boards[i].lbi);
2846         if (pcicom_boards[i].bar1)
2847             iounmap((void *)pcicom_boards[i].bar1);
2848         if (pcicom_boards[i].lbi)
2849             iounmap((void *)pcicom_boards[i].lbi);
2850     }
2851 }
2852
2853 module_init(init_mister);
2854 module_exit(cleanup_mister);