import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / isdn / hisax / mic.c
1 /* $Id: mic.c,v 1.1.1.1 2005/04/11 02:50:23 jack Exp $
2  *
3  * low level stuff for mic cards
4  *
5  * Author       Stephan von Krawczynski
6  * Copyright    by Stephan von Krawczynski <skraw@ithnet.com>
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 #define __NO_VERSION__
14 #include <linux/init.h>
15 #include "hisax.h"
16 #include "isac.h"
17 #include "hscx.h"
18 #include "isdnl1.h"
19
20 extern const char *CardType[];
21
22 const char *mic_revision = "$Revision: 1.1.1.1 $";
23
24 #define byteout(addr,val) outb(val,addr)
25 #define bytein(addr) inb(addr)
26
27 #define MIC_ISAC        2
28 #define MIC_HSCX        1
29 #define MIC_ADR         7
30
31 /* CARD_ADR (Write) */
32 #define MIC_RESET      0x3      /* same as DOS driver */
33
34 static inline u_char
35 readreg(unsigned int ale, unsigned int adr, u_char off)
36 {
37         register u_char ret;
38         long flags;
39
40         save_flags(flags);
41         cli();
42         byteout(ale, off);
43         ret = bytein(adr);
44         restore_flags(flags);
45
46         return (ret);
47 }
48
49 static inline void
50 readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
51 {
52         /* fifo read without cli because it's allready done  */
53
54         byteout(ale, off);
55         insb(adr, data, size);
56 }
57
58
59 static inline void
60 writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
61 {
62         long flags;
63
64         save_flags(flags);
65         cli();
66         byteout(ale, off);
67         byteout(adr, data);
68         restore_flags(flags);
69 }
70
71 static inline void
72 writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
73 {
74         /* fifo write without cli because it's allready done  */
75         byteout(ale, off);
76         outsb(adr, data, size);
77 }
78
79 /* Interface functions */
80
81 static u_char
82 ReadISAC(struct IsdnCardState *cs, u_char offset)
83 {
84         return (readreg(cs->hw.mic.adr, cs->hw.mic.isac, offset));
85 }
86
87 static void
88 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
89 {
90         writereg(cs->hw.mic.adr, cs->hw.mic.isac, offset, value);
91 }
92
93 static void
94 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
95 {
96         readfifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size);
97 }
98
99 static void
100 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
101 {
102         writefifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size);
103 }
104
105 static u_char
106 ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
107 {
108         return (readreg(cs->hw.mic.adr,
109                         cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0)));
110 }
111
112 static void
113 WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
114 {
115         writereg(cs->hw.mic.adr,
116                  cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0), value);
117 }
118
119 /*
120  * fast interrupt HSCX stuff goes here
121  */
122
123 #define READHSCX(cs, nr, reg) readreg(cs->hw.mic.adr, \
124                 cs->hw.mic.hscx, reg + (nr ? 0x40 : 0))
125 #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.mic.adr, \
126                 cs->hw.mic.hscx, reg + (nr ? 0x40 : 0), data)
127
128 #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.mic.adr, \
129                 cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
130
131 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.mic.adr, \
132                 cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
133
134 #include "hscx_irq.c"
135
136 static void
137 mic_interrupt(int intno, void *dev_id, struct pt_regs *regs)
138 {
139         struct IsdnCardState *cs = dev_id;
140         u_char val;
141
142         if (!cs) {
143                 printk(KERN_WARNING "mic: Spurious interrupt!\n");
144                 return;
145         }
146         val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
147       Start_HSCX:
148         if (val)
149                 hscx_int_main(cs, val);
150         val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
151       Start_ISAC:
152         if (val)
153                 isac_interrupt(cs, val);
154         val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
155         if (val) {
156                 if (cs->debug & L1_DEB_HSCX)
157                         debugl1(cs, "HSCX IntStat after IntRoutine");
158                 goto Start_HSCX;
159         }
160         val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
161         if (val) {
162                 if (cs->debug & L1_DEB_ISAC)
163                         debugl1(cs, "ISAC IntStat after IntRoutine");
164                 goto Start_ISAC;
165         }
166         writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0xFF);
167         writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0xFF);
168         writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0xFF);
169         writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0);
170         writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0x0);
171         writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0x0);
172 }
173
174 void
175 release_io_mic(struct IsdnCardState *cs)
176 {
177         int bytecnt = 8;
178
179         if (cs->hw.mic.cfg_reg)
180                 release_region(cs->hw.mic.cfg_reg, bytecnt);
181 }
182
183 static int
184 mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
185 {
186         switch (mt) {
187                 case CARD_RESET:
188                         return(0);
189                 case CARD_RELEASE:
190                         release_io_mic(cs);
191                         return(0);
192                 case CARD_INIT:
193                         inithscx(cs); /* /RTSA := ISAC RST */
194                         inithscxisac(cs, 3);
195                         return(0);
196                 case CARD_TEST:
197                         return(0);
198         }
199         return(0);
200 }
201
202 int __init
203 setup_mic(struct IsdnCard *card)
204 {
205         int bytecnt;
206         struct IsdnCardState *cs = card->cs;
207         char tmp[64];
208
209         strcpy(tmp, mic_revision);
210         printk(KERN_INFO "HiSax: mic driver Rev. %s\n", HiSax_getrev(tmp));
211         if (cs->typ != ISDN_CTYPE_MIC)
212                 return (0);
213
214         bytecnt = 8;
215         cs->hw.mic.cfg_reg = card->para[1];
216         cs->irq = card->para[0];
217         cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR;
218         cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC;
219         cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX;
220
221         if (check_region((cs->hw.mic.cfg_reg), bytecnt)) {
222                 printk(KERN_WARNING
223                        "HiSax: %s config port %x-%x already in use\n",
224                        CardType[card->typ],
225                        cs->hw.mic.cfg_reg,
226                        cs->hw.mic.cfg_reg + bytecnt);
227                 return (0);
228         } else {
229                 request_region(cs->hw.mic.cfg_reg, bytecnt, "mic isdn");
230         }
231
232         printk(KERN_INFO
233                "mic: defined at 0x%x IRQ %d\n",
234                cs->hw.mic.cfg_reg,
235                cs->irq);
236         cs->readisac = &ReadISAC;
237         cs->writeisac = &WriteISAC;
238         cs->readisacfifo = &ReadISACfifo;
239         cs->writeisacfifo = &WriteISACfifo;
240         cs->BC_Read_Reg = &ReadHSCX;
241         cs->BC_Write_Reg = &WriteHSCX;
242         cs->BC_Send_Data = &hscx_fill_fifo;
243         cs->cardmsg = &mic_card_msg;
244         cs->irq_func = &mic_interrupt;
245         ISACVersion(cs, "mic:");
246         if (HscxVersion(cs, "mic:")) {
247                 printk(KERN_WARNING
248                     "mic: wrong HSCX versions check IO address\n");
249                 release_io_mic(cs);
250                 return (0);
251         }
252         return (1);
253 }