more debug output
[linux-2.4.git] / drivers / isdn / hisax / enternow_pci.c
1 /* enternow_pci.c,v 0.99 2001/10/02
2  *
3  * enternow_pci.c       Card-specific routines for
4  *                      Formula-n enter:now ISDN PCI ab
5  *                      Gerdes AG Power ISDN PCI
6  *                      Woerltronic SA 16 PCI
7  *                      (based on HiSax driver by Karsten Keil)
8  *
9  * Author               Christoph Ersfeld <info@formula-n.de>
10  *                      Formula-n Europe AG (www.formula-n.com)
11  *                      previously Gerdes AG
12  *
13  *
14  *                      This file is (c) under GNU PUBLIC LICENSE
15  *
16  * Notes:
17  * This driver interfaces to netjet.c which performs B-channel
18  * processing.
19  *
20  * Version 0.99 is the first release of this driver and there are
21  * certainly a few bugs.
22  * It isn't testet on linux 2.4 yet, so consider this code to be
23  * beta.
24  *
25  * Please don't report me any malfunction without sending
26  * (compressed) debug-logs.
27  * It would be nearly impossible to retrace it.
28  *
29  * Log D-channel-processing as follows:
30  *
31  * 1. Load hisax with card-specific parameters, this example ist for
32  *    Formula-n enter:now ISDN PCI and compatible
33  *    (f.e. Gerdes Power ISDN PCI)
34  *
35  *    modprobe hisax type=41 protocol=2 id=gerdes
36  *
37  *    if you chose an other value for id, you need to modify the
38  *    code below, too.
39  *
40  * 2. set debug-level
41  *
42  *    hisaxctrl gerdes 1 0x3ff
43  *    hisaxctrl gerdes 11 0x4f
44  *    cat /dev/isdnctrl >> ~/log &
45  *
46  * Please take also a look into /var/log/messages if there is
47  * anything importand concerning HISAX.
48  *
49  *
50  * Credits:
51  * Programming the driver for Formula-n enter:now ISDN PCI and
52  * neccessary the driver for the used Amd 7930 D-channel-controller
53  * was spnsored by Formula-n Europe AG.
54  * Thanks to Karsten Keil and Petr Novak, who gave me support in
55  * Hisax-specific questions.
56  * I want so say special thanks to Carl-Friedrich Braun, who had to
57  * answer a lot of questions about generally ISDN and about handling
58  * of the Amd-Chip.
59  *
60  */
61
62
63 #define __NO_VERSION__
64 #include <linux/config.h>
65 #include "hisax.h"
66 #include "isac.h"
67 #include "isdnl1.h"
68 #include "amd7930_fn.h"
69 #include "enternow.h"
70 #include <linux/interrupt.h>
71 #include <linux/ppp_defs.h>
72 #include <linux/pci.h>
73 #include <linux/init.h>
74 #include "netjet.h"
75
76
77
78 const char *enternow_pci_rev = "$Revision: 1.1.2.1 $";
79
80
81 /* *************************** I/O-Interface functions ************************************* */
82
83
84 /* cs->readisac, macro rByteAMD */
85 BYTE
86 ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset)
87 {
88         /* direktes Register */
89         if(offset < 8)
90                 return (InByte(cs->hw.njet.isac + 4*offset));
91
92         /* indirektes Register */
93         else {
94                 OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
95                 return(InByte(cs->hw.njet.isac + 4*AMD_DR));
96         }
97 }
98
99 /* cs->writeisac, macro wByteAMD */
100 void
101 WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value)
102 {
103         /* direktes Register */
104         if(offset < 8)
105                 OutByte(cs->hw.njet.isac + 4*offset, value);
106
107         /* indirektes Register */
108         else {
109                 OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
110                 OutByte(cs->hw.njet.isac + 4*AMD_DR, value);
111         }
112 }
113
114
115 void
116 enpci_setIrqMask(struct IsdnCardState *cs, BYTE val) {
117         if (!val)
118                 OutByte(cs->hw.njet.base+NETJET_IRQMASK1, 0x00);
119         else
120                 OutByte(cs->hw.njet.base+NETJET_IRQMASK1, TJ_AMD_IRQ);
121 }
122
123
124 static BYTE dummyrr(struct IsdnCardState *cs, int chan, BYTE off)
125 {
126         return(5);
127 }
128
129 static void dummywr(struct IsdnCardState *cs, int chan, BYTE off, BYTE value)
130 {
131
132 }
133
134
135 /* ******************************************************************************** */
136
137
138 static void
139 reset_enpci(struct IsdnCardState *cs)
140 {
141         long flags;
142
143         if (cs->debug & L1_DEB_ISAC)
144                 debugl1(cs, "enter:now PCI: reset");
145
146         save_flags(flags);
147         sti();
148         /* Reset on, (also for AMD) */
149         cs->hw.njet.ctrl_reg = 0x07;
150         OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
151         set_current_state(TASK_UNINTERRUPTIBLE);
152         /* 80 ms delay */
153         schedule_timeout((80*HZ)/1000);
154         /* Reset off */
155         cs->hw.njet.ctrl_reg = 0x70;
156         OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
157         set_current_state(TASK_UNINTERRUPTIBLE);
158         /* 80ms delay */
159         schedule_timeout((80*HZ)/1000);
160         restore_flags(flags);
161         cs->hw.njet.auxd = 0;  // LED-status
162         cs->hw.njet.dmactrl = 0;
163         OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
164         OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
165         OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); // LED off
166
167 }
168
169
170 static int
171 enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
172 {
173         BYTE *chan;
174
175         if (cs->debug & L1_DEB_ISAC)
176                 debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt);
177
178         switch (mt) {
179                 case CARD_RESET:
180                         reset_enpci(cs);
181                         Amd7930_init(cs);
182                         break;
183                 case CARD_RELEASE:
184                         release_io_netjet(cs);
185                         break;
186                 case CARD_INIT:
187                         inittiger(cs);
188                         Amd7930_init(cs);
189                         break;
190                 case CARD_TEST:
191                         break;
192                 case MDL_ASSIGN:
193                         /* TEI assigned, LED1 on */
194                         cs->hw.njet.auxd = TJ_AMD_IRQ << 1;
195                         OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
196                         break;
197                 case MDL_REMOVE:
198                         /* TEI removed, LEDs off */
199                         cs->hw.njet.auxd = 0;
200                         OutByte(cs->hw.njet.base + NETJET_AUXDATA, 0x00);
201                         break;
202                 case MDL_BC_ASSIGN:
203                         /* activate B-channel */
204                         chan = (BYTE *)arg;
205
206                         if (cs->debug & L1_DEB_ISAC)
207                                 debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan);
208
209                         cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN");
210                         /* at least one b-channel in use, LED 2 on */
211                         cs->hw.njet.auxd |= TJ_AMD_IRQ << 2;
212                         OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
213                         break;
214                 case MDL_BC_RELEASE:
215                         /* deactivate B-channel */
216                         chan = (BYTE *)arg;
217
218                         if (cs->debug & L1_DEB_ISAC)
219                                 debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan);
220
221                         cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(*chan + 1)), "MDL_BC_RELEASE");
222                         /* no b-channel active -> LED2 off */
223                         if (!(cs->dc.amd7930.lmr1 & 3)) {
224                                 cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2);
225                                 OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
226                         }
227                         break;
228                 default:
229                         break;
230
231         }
232         return(0);
233 }
234
235
236 static void
237 enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
238 {
239         struct IsdnCardState *cs = dev_id;
240         BYTE sval, ir;
241         long flags;
242
243
244         if (!cs) {
245                 printk(KERN_WARNING "enter:now PCI: Spurious interrupt!\n");
246                 return;
247         }
248
249         sval = InByte(cs->hw.njet.base + NETJET_IRQSTAT1);
250
251         /* AMD threw an interrupt */
252         if (!(sval & TJ_AMD_IRQ)) {
253                 /* read and clear interrupt-register */
254                 ir = ReadByteAmd7930(cs, 0x00);
255                 Amd7930_interrupt(cs, ir);
256         }
257
258         /* DMA-Interrupt: B-channel-stuff */
259         /* set bits in sval to indicate which page is free */
260
261         save_flags(flags);
262         cli();
263         /* set bits in sval to indicate which page is free */
264         if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
265                 inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
266                 /* the 2nd write page is free */
267                 sval = 0x08;
268         else    /* the 1st write page is free */
269                 sval = 0x04;
270         if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
271                 inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
272                 /* the 2nd read page is free */
273                 sval = sval | 0x02;
274         else    /* the 1st read page is free */
275                 sval = sval | 0x01;
276         if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
277         {
278                 if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
279                         restore_flags(flags);
280                         return;
281                 }
282                 cs->hw.njet.irqstat0 = sval;
283                 restore_flags(flags);
284                 if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
285                         (cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
286                         /* we have a read dma int */
287                         read_tiger(cs);
288                 if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
289                         (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
290                         /* we have a write dma int */
291                         write_tiger(cs);
292                 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
293         } else
294                 restore_flags(flags);
295 }
296
297
298 static struct pci_dev *dev_netjet __initdata = NULL;
299
300 /* called by config.c */
301 int __init
302 setup_enternow_pci(struct IsdnCard *card)
303 {
304         int bytecnt;
305         struct IsdnCardState *cs = card->cs;
306         char tmp[64];
307         long flags;
308
309 #if CONFIG_PCI
310 #ifdef __BIG_ENDIAN
311 #error "not running on big endian machines now"
312 #endif
313         strcpy(tmp, enternow_pci_rev);
314         printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp));
315         if (cs->typ != ISDN_CTYPE_ENTERNOW)
316                 return(0);
317         test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
318
319         for ( ;; )
320         {
321                 if (!pci_present()) {
322                         printk(KERN_ERR "enter:now PCI: no PCI bus present\n");
323                         return(0);
324                 }
325                 if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
326                         PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
327                         if (pci_enable_device(dev_netjet))
328                                 return(0);
329                         cs->irq = dev_netjet->irq;
330                         if (!cs->irq) {
331                                 printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n");
332                                 return(0);
333                         }
334                         cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
335                         if (!cs->hw.njet.base) {
336                                 printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n");
337                                 return(0);
338                         }
339                         /* checks Sub-Vendor ID because system crashes with Traverse-Card */
340                         if ((dev_netjet->subsystem_vendor != 0x55) ||
341                                 (dev_netjet->subsystem_device != 0x02)) {
342                                 printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n");
343                                 printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n");
344                                 return(0);
345                         }
346                 } else {
347                         printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
348                         return(0);
349                 }
350
351                 cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
352                 cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
353
354                 save_flags(flags);
355                 sti();
356
357                 /* Reset an */
358                 cs->hw.njet.ctrl_reg = 0x07;  // geƤndert von 0xff
359                 OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
360
361                 set_current_state(TASK_UNINTERRUPTIBLE);
362                 /* 50 ms Pause */
363                 schedule_timeout((50*HZ)/1000);
364
365                 cs->hw.njet.ctrl_reg = 0x30;  /* Reset Off and status read clear */
366                 OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
367
368                 set_current_state(TASK_UNINTERRUPTIBLE);
369                 schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
370
371                 restore_flags(flags);
372
373                 cs->hw.njet.auxd = 0x00; // war 0xc0
374                 cs->hw.njet.dmactrl = 0;
375
376                 OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
377                 OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
378                 OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd);
379
380                            break;
381         }
382 #else
383
384         printk(KERN_WARNING "enter:now PCI: NO_PCI_BIOS\n");
385         printk(KERN_WARNING "enter:now PCI: unable to config Formula-n enter:now ISDN PCI ab\n");
386         return (0);
387
388 #endif /* CONFIG_PCI */
389
390         bytecnt = 256;
391
392         printk(KERN_INFO
393                 "enter:now PCI: PCI card configured at 0x%lx IRQ %d\n",
394                 cs->hw.njet.base, cs->irq);
395         if (check_region(cs->hw.njet.base, bytecnt)) {
396                 printk(KERN_WARNING
397                            "HiSax: %s config port %lx-%lx already in use\n",
398                            CardType[card->typ],
399                            cs->hw.njet.base,
400                            cs->hw.njet.base + bytecnt);
401                 return (0);
402         } else {
403                 request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN");
404         }
405         reset_enpci(cs);
406         cs->hw.njet.last_is0 = 0;
407         /* macro rByteAMD */
408         cs->readisac = &ReadByteAmd7930;
409         /* macro wByteAMD */
410         cs->writeisac = &WriteByteAmd7930;
411         cs->dc.amd7930.setIrqMask = &enpci_setIrqMask;
412
413         cs->BC_Read_Reg  = &dummyrr;
414         cs->BC_Write_Reg = &dummywr;
415         cs->BC_Send_Data = &netjet_fill_dma;
416         cs->cardmsg = &enpci_card_msg;
417         cs->irq_func = &enpci_interrupt;
418         cs->irq_flags |= SA_SHIRQ;
419
420         return (1);
421 }
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447