/home/lenb/src/to-linus branch 'acpi-2.6.12'
[linux-2.6] / drivers / isdn / hisax / avm_a1.c
1 /* $Id: avm_a1.c,v 2.15.2.4 2004/01/13 21:46:03 keil Exp $
2  *
3  * low level stuff for AVM A1 (Fritz) isdn cards
4  *
5  * Author       Karsten Keil
6  * Copyright    by Karsten Keil      <keil@isdn4linux.de>
7  *
8  * This software may be used and distributed according to the terms
9  * of the GNU General Public License, incorporated herein by reference.
10  *
11  */
12
13 #include <linux/init.h>
14 #include "hisax.h"
15 #include "isac.h"
16 #include "hscx.h"
17 #include "isdnl1.h"
18
19 extern const char *CardType[];
20 static const char *avm_revision = "$Revision: 2.15.2.4 $";
21
22 #define  AVM_A1_STAT_ISAC       0x01
23 #define  AVM_A1_STAT_HSCX       0x02
24 #define  AVM_A1_STAT_TIMER      0x04
25
26 #define byteout(addr,val) outb(val,addr)
27 #define bytein(addr) inb(addr)
28
29 static inline u_char
30 readreg(unsigned int adr, u_char off)
31 {
32         return (bytein(adr + off));
33 }
34
35 static inline void
36 writereg(unsigned int adr, u_char off, u_char data)
37 {
38         byteout(adr + off, data);
39 }
40
41
42 static inline void
43 read_fifo(unsigned int adr, u_char * data, int size)
44 {
45         insb(adr, data, size);
46 }
47
48 static void
49 write_fifo(unsigned int adr, u_char * data, int size)
50 {
51         outsb(adr, data, size);
52 }
53
54 /* Interface functions */
55
56 static u_char
57 ReadISAC(struct IsdnCardState *cs, u_char offset)
58 {
59         return (readreg(cs->hw.avm.isac, offset));
60 }
61
62 static void
63 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
64 {
65         writereg(cs->hw.avm.isac, offset, value);
66 }
67
68 static void
69 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
70 {
71         read_fifo(cs->hw.avm.isacfifo, data, size);
72 }
73
74 static void
75 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
76 {
77         write_fifo(cs->hw.avm.isacfifo, data, size);
78 }
79
80 static u_char
81 ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
82 {
83         return (readreg(cs->hw.avm.hscx[hscx], offset));
84 }
85
86 static void
87 WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
88 {
89         writereg(cs->hw.avm.hscx[hscx], offset, value);
90 }
91
92 /*
93  * fast interrupt HSCX stuff goes here
94  */
95
96 #define READHSCX(cs, nr, reg) readreg(cs->hw.avm.hscx[nr], reg)
97 #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.avm.hscx[nr], reg, data)
98 #define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
99 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
100
101 #include "hscx_irq.c"
102
103 static irqreturn_t
104 avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
105 {
106         struct IsdnCardState *cs = dev_id;
107         u_char val, sval;
108         u_long flags;
109
110         spin_lock_irqsave(&cs->lock, flags);
111         while (((sval = bytein(cs->hw.avm.cfg_reg)) & 0xf) != 0x7) {
112                 if (!(sval & AVM_A1_STAT_TIMER)) {
113                         byteout(cs->hw.avm.cfg_reg, 0x1E);
114                         sval = bytein(cs->hw.avm.cfg_reg);
115                 } else if (cs->debug & L1_DEB_INTSTAT)
116                         debugl1(cs, "avm IntStatus %x", sval);
117                 if (!(sval & AVM_A1_STAT_HSCX)) {
118                         val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA);
119                         if (val)
120                                 hscx_int_main(cs, val);
121                 }
122                 if (!(sval & AVM_A1_STAT_ISAC)) {
123                         val = readreg(cs->hw.avm.isac, ISAC_ISTA);
124                         if (val)
125                                 isac_interrupt(cs, val);
126                 }
127         }
128         writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF);
129         writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF);
130         writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF);
131         writereg(cs->hw.avm.isac, ISAC_MASK, 0x0);
132         writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0);
133         writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0);
134         spin_unlock_irqrestore(&cs->lock, flags);
135         return IRQ_HANDLED;
136 }
137
138 static inline void
139 release_ioregs(struct IsdnCardState *cs, int mask)
140 {
141         release_region(cs->hw.avm.cfg_reg, 8);
142         if (mask & 1)
143                 release_region(cs->hw.avm.isac + 32, 32);
144         if (mask & 2)
145                 release_region(cs->hw.avm.isacfifo, 1);
146         if (mask & 4)
147                 release_region(cs->hw.avm.hscx[0] + 32, 32);
148         if (mask & 8)
149                 release_region(cs->hw.avm.hscxfifo[0], 1);
150         if (mask & 0x10)
151                 release_region(cs->hw.avm.hscx[1] + 32, 32);
152         if (mask & 0x20)
153                 release_region(cs->hw.avm.hscxfifo[1], 1);
154 }
155
156 static int
157 AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
158 {
159         u_long flags;
160
161         switch (mt) {
162                 case CARD_RESET:
163                         return(0);
164                 case CARD_RELEASE:
165                         release_ioregs(cs, 0x3f);
166                         return(0);
167                 case CARD_INIT:
168                         spin_lock_irqsave(&cs->lock, flags);
169                         inithscxisac(cs, 1);
170                         byteout(cs->hw.avm.cfg_reg, 0x16);
171                         byteout(cs->hw.avm.cfg_reg, 0x1E);
172                         inithscxisac(cs, 2);
173                         spin_unlock_irqrestore(&cs->lock, flags);
174                         return(0);
175                 case CARD_TEST:
176                         return(0);
177         }
178         return(0);
179 }
180
181 int __init
182 setup_avm_a1(struct IsdnCard *card)
183 {
184         u_char val;
185         struct IsdnCardState *cs = card->cs;
186         char tmp[64];
187
188         strcpy(tmp, avm_revision);
189         printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp));
190         if (cs->typ != ISDN_CTYPE_A1)
191                 return (0);
192
193         cs->hw.avm.cfg_reg = card->para[1] + 0x1800;
194         cs->hw.avm.isac = card->para[1] + 0x1400 - 0x20;
195         cs->hw.avm.hscx[0] = card->para[1] + 0x400 - 0x20;
196         cs->hw.avm.hscx[1] = card->para[1] + 0xc00 - 0x20;
197         cs->hw.avm.isacfifo = card->para[1] + 0x1000;
198         cs->hw.avm.hscxfifo[0] = card->para[1];
199         cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800;
200         cs->irq = card->para[0];
201         if (!request_region(cs->hw.avm.cfg_reg, 8, "avm cfg")) {
202                 printk(KERN_WARNING
203                        "HiSax: %s config port %x-%x already in use\n",
204                        CardType[card->typ],
205                        cs->hw.avm.cfg_reg,
206                        cs->hw.avm.cfg_reg + 8);
207                 return (0);
208         }
209         if (!request_region(cs->hw.avm.isac + 32, 32, "HiSax isac")) {
210                 printk(KERN_WARNING
211                        "HiSax: %s isac ports %x-%x already in use\n",
212                        CardType[cs->typ],
213                        cs->hw.avm.isac + 32,
214                        cs->hw.avm.isac + 64);
215                 release_ioregs(cs, 0);
216                 return (0);
217         }
218         if (!request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo")) {
219                 printk(KERN_WARNING
220                        "HiSax: %s isac fifo port %x already in use\n",
221                        CardType[cs->typ],
222                        cs->hw.avm.isacfifo);
223                 release_ioregs(cs, 1);
224                 return (0);
225         }
226         if (!request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A")) {
227                 printk(KERN_WARNING
228                        "HiSax: %s hscx A ports %x-%x already in use\n",
229                        CardType[cs->typ],
230                        cs->hw.avm.hscx[0] + 32,
231                        cs->hw.avm.hscx[0] + 64);
232                 release_ioregs(cs, 3);
233                 return (0);
234         }
235         if (!request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo")) {
236                 printk(KERN_WARNING
237                        "HiSax: %s hscx A fifo port %x already in use\n",
238                        CardType[cs->typ],
239                        cs->hw.avm.hscxfifo[0]);
240                 release_ioregs(cs, 7);
241                 return (0);
242         }
243         if (!request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B")) {
244                 printk(KERN_WARNING
245                        "HiSax: %s hscx B ports %x-%x already in use\n",
246                        CardType[cs->typ],
247                        cs->hw.avm.hscx[1] + 32,
248                        cs->hw.avm.hscx[1] + 64);
249                 release_ioregs(cs, 0xf);
250                 return (0);
251         }
252         if (!request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo")) {
253                 printk(KERN_WARNING
254                        "HiSax: %s hscx B fifo port %x already in use\n",
255                        CardType[cs->typ],
256                        cs->hw.avm.hscxfifo[1]);
257                 release_ioregs(cs, 0x1f);
258                 return (0);
259         }
260         byteout(cs->hw.avm.cfg_reg, 0x0);
261         HZDELAY(HZ / 5 + 1);
262         byteout(cs->hw.avm.cfg_reg, 0x1);
263         HZDELAY(HZ / 5 + 1);
264         byteout(cs->hw.avm.cfg_reg, 0x0);
265         HZDELAY(HZ / 5 + 1);
266         val = cs->irq;
267         if (val == 9)
268                 val = 2;
269         byteout(cs->hw.avm.cfg_reg + 1, val);
270         HZDELAY(HZ / 5 + 1);
271         byteout(cs->hw.avm.cfg_reg, 0x0);
272         HZDELAY(HZ / 5 + 1);
273
274         val = bytein(cs->hw.avm.cfg_reg);
275         printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
276                cs->hw.avm.cfg_reg, val);
277         val = bytein(cs->hw.avm.cfg_reg + 3);
278         printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
279                cs->hw.avm.cfg_reg + 3, val);
280         val = bytein(cs->hw.avm.cfg_reg + 2);
281         printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
282                cs->hw.avm.cfg_reg + 2, val);
283         val = bytein(cs->hw.avm.cfg_reg);
284         printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
285                cs->hw.avm.cfg_reg, val);
286
287         printk(KERN_INFO
288                "HiSax: %s config irq:%d cfg:0x%X\n",
289                CardType[cs->typ], cs->irq,
290                cs->hw.avm.cfg_reg);
291         printk(KERN_INFO
292                "HiSax: isac:0x%X/0x%X\n",
293                cs->hw.avm.isac + 32, cs->hw.avm.isacfifo);
294         printk(KERN_INFO
295                "HiSax: hscx A:0x%X/0x%X  hscx B:0x%X/0x%X\n",
296                cs->hw.avm.hscx[0] + 32, cs->hw.avm.hscxfifo[0],
297                cs->hw.avm.hscx[1] + 32, cs->hw.avm.hscxfifo[1]);
298
299         cs->readisac = &ReadISAC;
300         cs->writeisac = &WriteISAC;
301         cs->readisacfifo = &ReadISACfifo;
302         cs->writeisacfifo = &WriteISACfifo;
303         cs->BC_Read_Reg = &ReadHSCX;
304         cs->BC_Write_Reg = &WriteHSCX;
305         cs->BC_Send_Data = &hscx_fill_fifo;
306         setup_isac(cs);
307         cs->cardmsg = &AVM_card_msg;
308         cs->irq_func = &avm_a1_interrupt;
309         ISACVersion(cs, "AVM A1:");
310         if (HscxVersion(cs, "AVM A1:")) {
311                 printk(KERN_WARNING
312                        "AVM A1: wrong HSCX versions check IO address\n");
313                 release_ioregs(cs, 0x3f);
314                 return (0);
315         }
316         return (1);
317 }