import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / isdn / hisax / ix1_micro.c
1 /* $Id: ix1_micro.c,v 1.1.1.1 2005/04/11 02:50:23 jack Exp $
2  *
3  * low level stuff for ITK ix1-micro Rev.2 isdn cards
4  * derived from the original file teles3.c from Karsten Keil
5  *
6  * Author       Klaus-Peter Nischke
7  * Copyright    by Klaus-Peter Nischke, ITK AG
8  *                                   <klaus@nischke.do.eunet.de>
9  *              by Karsten Keil      <keil@isdn4linux.de>
10  * 
11  * This software may be used and distributed according to the terms
12  * of the GNU General Public License, incorporated herein by reference.
13  *
14  * Klaus-Peter Nischke
15  * Deusener Str. 287
16  * 44369 Dortmund
17  * Germany
18  */
19
20 #define __NO_VERSION__
21 #include <linux/init.h>
22 #include <linux/isapnp.h>
23 #include "hisax.h"
24 #include "isac.h"
25 #include "hscx.h"
26 #include "isdnl1.h"
27
28 extern const char *CardType[];
29 const char *ix1_revision = "$Revision: 1.1.1.1 $";
30
31 #define byteout(addr,val) outb(val,addr)
32 #define bytein(addr) inb(addr)
33
34 #define SPECIAL_PORT_OFFSET 3
35
36 #define ISAC_COMMAND_OFFSET 2
37 #define ISAC_DATA_OFFSET 0
38 #define HSCX_COMMAND_OFFSET 2
39 #define HSCX_DATA_OFFSET 1
40
41 #define TIMEOUT 50
42
43 static inline u_char
44 readreg(unsigned int ale, unsigned int adr, u_char off)
45 {
46         register u_char ret;
47         long flags;
48
49         save_flags(flags);
50         cli();
51         byteout(ale, off);
52         ret = bytein(adr);
53         restore_flags(flags);
54         return (ret);
55 }
56
57 static inline void
58 readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
59 {
60         /* fifo read without cli because it's allready done  */
61
62         byteout(ale, off);
63         insb(adr, data, size);
64 }
65
66
67 static inline void
68 writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
69 {
70         long flags;
71
72         save_flags(flags);
73         cli();
74         byteout(ale, off);
75         byteout(adr, data);
76         restore_flags(flags);
77 }
78
79 static inline void
80 writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
81 {
82         /* fifo write without cli because it's allready done  */
83         byteout(ale, off);
84         outsb(adr, data, size);
85 }
86
87 /* Interface functions */
88
89 static u_char
90 ReadISAC(struct IsdnCardState *cs, u_char offset)
91 {
92         return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset));
93 }
94
95 static void
96 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
97 {
98         writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value);
99 }
100
101 static void
102 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
103 {
104         readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
105 }
106
107 static void
108 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
109 {
110         writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
111 }
112
113 static u_char
114 ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
115 {
116         return (readreg(cs->hw.ix1.hscx_ale,
117                         cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0)));
118 }
119
120 static void
121 WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
122 {
123         writereg(cs->hw.ix1.hscx_ale,
124                  cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value);
125 }
126
127 #define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \
128                 cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0))
129 #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \
130                 cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data)
131
132 #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \
133                 cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
134
135 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \
136                 cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
137
138 #include "hscx_irq.c"
139
140 static void
141 ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
142 {
143         struct IsdnCardState *cs = dev_id;
144         u_char val;
145
146         if (!cs) {
147                 printk(KERN_WARNING "IX1: Spurious interrupt!\n");
148                 return;
149         }
150         val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
151       Start_HSCX:
152         if (val)
153                 hscx_int_main(cs, val);
154         val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
155       Start_ISAC:
156         if (val)
157                 isac_interrupt(cs, val);
158         val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
159         if (val) {
160                 if (cs->debug & L1_DEB_HSCX)
161                         debugl1(cs, "HSCX IntStat after IntRoutine");
162                 goto Start_HSCX;
163         }
164         val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
165         if (val) {
166                 if (cs->debug & L1_DEB_ISAC)
167                         debugl1(cs, "ISAC IntStat after IntRoutine");
168                 goto Start_ISAC;
169         }
170         writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF);
171         writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF);
172         writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF);
173         writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0);
174         writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0);
175         writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0);
176 }
177
178 void
179 release_io_ix1micro(struct IsdnCardState *cs)
180 {
181         if (cs->hw.ix1.cfg_reg)
182                 release_region(cs->hw.ix1.cfg_reg, 4);
183 }
184
185 static void
186 ix1_reset(struct IsdnCardState *cs)
187 {
188         long flags;
189         int cnt;
190
191         /* reset isac */
192         save_flags(flags);
193         cnt = 3 * (HZ / 10) + 1;
194         sti();
195         while (cnt--) {
196                 byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 1);
197                 HZDELAY(1);     /* wait >=10 ms */
198         }
199         byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0);
200         restore_flags(flags);
201 }
202
203 static int
204 ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
205 {
206         switch (mt) {
207                 case CARD_RESET:
208                         ix1_reset(cs);
209                         return(0);
210                 case CARD_RELEASE:
211                         release_io_ix1micro(cs);
212                         return(0);
213                 case CARD_INIT:
214                         inithscxisac(cs, 3);
215                         return(0);
216                 case CARD_TEST:
217                         return(0);
218         }
219         return(0);
220 }
221
222 #ifdef __ISAPNP__
223 static struct isapnp_device_id itk_ids[] __initdata = {
224         { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
225           ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), 
226           (unsigned long) "ITK micro 2" },
227         { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
228           ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), 
229           (unsigned long) "ITK micro 2." },
230         { 0, }
231 };
232
233 static struct isapnp_device_id *idev = &itk_ids[0];
234 static struct pci_bus *pnp_c __devinitdata = NULL;
235 #endif
236
237
238 int __init
239 setup_ix1micro(struct IsdnCard *card)
240 {
241         struct IsdnCardState *cs = card->cs;
242         char tmp[64];
243
244         strcpy(tmp, ix1_revision);
245         printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp));
246         if (cs->typ != ISDN_CTYPE_IX1MICROR2)
247                 return (0);
248
249 #ifdef __ISAPNP__
250         if (!card->para[1] && isapnp_present()) {
251                 struct pci_bus *pb;
252                 struct pci_dev *pd;
253
254                 while(idev->card_vendor) {
255                         if ((pb = isapnp_find_card(idev->card_vendor,
256                                 idev->card_device, pnp_c))) {
257                                 pnp_c = pb;
258                                 pd = NULL;
259                                 if ((pd = isapnp_find_dev(pnp_c,
260                                         idev->vendor, idev->function, pd))) {
261                                         printk(KERN_INFO "HiSax: %s detected\n",
262                                                 (char *)idev->driver_data);
263                                         pd->prepare(pd);
264                                         pd->deactivate(pd);
265                                         pd->activate(pd);
266                                         card->para[1] = pd->resource[0].start;
267                                         card->para[0] = pd->irq_resource[0].start;
268                                         if (!card->para[0] || !card->para[1]) {
269                                                 printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n",
270                                                 card->para[0], card->para[1]);
271                                                 pd->deactivate(pd);
272                                                 return(0);
273                                         }
274                                         break;
275                                 } else {
276                                         printk(KERN_ERR "ITK PnP: PnP error card found, no device\n");
277                                 }
278                         }
279                         idev++;
280                         pnp_c=NULL;
281                 } 
282                 if (!idev->card_vendor) {
283                         printk(KERN_INFO "ITK PnP: no ISAPnP card found\n");
284                         return(0);
285                 }
286         }
287 #endif
288         /* IO-Ports */
289         cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET;
290         cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET;
291         cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET;
292         cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET;
293         cs->hw.ix1.cfg_reg = card->para[1];
294         cs->irq = card->para[0];
295         if (cs->hw.ix1.cfg_reg) {
296                 if (check_region((cs->hw.ix1.cfg_reg), 4)) {
297                         printk(KERN_WARNING
298                           "HiSax: %s config port %x-%x already in use\n",
299                                CardType[card->typ],
300                                cs->hw.ix1.cfg_reg,
301                                cs->hw.ix1.cfg_reg + 4);
302                         return (0);
303                 } else
304                         request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg");
305         }
306         printk(KERN_INFO
307                "HiSax: %s config irq:%d io:0x%X\n",
308                CardType[cs->typ], cs->irq,
309                cs->hw.ix1.cfg_reg);
310         ix1_reset(cs);
311         cs->readisac = &ReadISAC;
312         cs->writeisac = &WriteISAC;
313         cs->readisacfifo = &ReadISACfifo;
314         cs->writeisacfifo = &WriteISACfifo;
315         cs->BC_Read_Reg = &ReadHSCX;
316         cs->BC_Write_Reg = &WriteHSCX;
317         cs->BC_Send_Data = &hscx_fill_fifo;
318         cs->cardmsg = &ix1_card_msg;
319         cs->irq_func = &ix1micro_interrupt;
320         ISACVersion(cs, "ix1-Micro:");
321         if (HscxVersion(cs, "ix1-Micro:")) {
322                 printk(KERN_WARNING
323                     "ix1-Micro: wrong HSCX versions check IO address\n");
324                 release_io_ix1micro(cs);
325                 return (0);
326         }
327         return (1);
328 }