import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / drivers / isdn / hisax / niccy.c
1 /* $Id: niccy.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
2  *
3  * low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
4  * compatible (SAGEM cybermodem)
5  *
6  * Author       Karsten Keil
7  * Copyright    by Karsten Keil      <keil@isdn4linux.de>
8  * 
9  * This software may be used and distributed according to the terms
10  * of the GNU General Public License, incorporated herein by reference.
11  * 
12  * Thanks to Dr. Neuhaus and SAGEM for information
13  *
14  */
15
16
17 #define __NO_VERSION__
18 #include <linux/config.h>
19 #include <linux/init.h>
20 #include "hisax.h"
21 #include "isac.h"
22 #include "hscx.h"
23 #include "isdnl1.h"
24 #include <linux/pci.h>
25 #include <linux/isapnp.h>
26
27 extern const char *CardType[];
28 const char *niccy_revision = "$Revision: 1.1.4.1 $";
29
30 #define byteout(addr,val) outb(val,addr)
31 #define bytein(addr) inb(addr)
32
33 #define ISAC_PCI_DATA   0
34 #define HSCX_PCI_DATA   1
35 #define ISAC_PCI_ADDR   2
36 #define HSCX_PCI_ADDR   3
37 #define ISAC_PNP        0
38 #define HSCX_PNP        1
39
40 /* SUB Types */
41 #define NICCY_PNP       1
42 #define NICCY_PCI       2
43
44 /* PCI stuff */
45 #define PCI_IRQ_CTRL_REG        0x38
46 #define PCI_IRQ_ENABLE          0x1f00
47 #define PCI_IRQ_DISABLE         0xff0000
48 #define PCI_IRQ_ASSERT          0x800000
49
50 static inline u_char
51 readreg(unsigned int ale, unsigned int adr, u_char off)
52 {
53         register u_char ret;
54         long flags;
55
56         save_flags(flags);
57         cli();
58         byteout(ale, off);
59         ret = bytein(adr);
60         restore_flags(flags);
61         return (ret);
62 }
63
64 static inline void
65 readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
66 {
67         /* fifo read without cli because it's allready done  */
68
69         byteout(ale, off);
70         insb(adr, data, size);
71 }
72
73
74 static inline void
75 writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
76 {
77         long flags;
78
79         save_flags(flags);
80         cli();
81         byteout(ale, off);
82         byteout(adr, data);
83         restore_flags(flags);
84 }
85
86 static inline void
87 writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
88 {
89         /* fifo write without cli because it's allready done  */
90         byteout(ale, off);
91         outsb(adr, data, size);
92 }
93
94 /* Interface functions */
95
96 static u_char
97 ReadISAC(struct IsdnCardState *cs, u_char offset)
98 {
99         return (readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset));
100 }
101
102 static void
103 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
104 {
105         writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value);
106 }
107
108 static void
109 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
110 {
111         readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
112 }
113
114 static void
115 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
116 {
117         writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
118 }
119
120 static u_char
121 ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
122 {
123         return (readreg(cs->hw.niccy.hscx_ale,
124                         cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0)));
125 }
126
127 static void
128 WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
129 {
130         writereg(cs->hw.niccy.hscx_ale,
131                  cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value);
132 }
133
134 #define READHSCX(cs, nr, reg) readreg(cs->hw.niccy.hscx_ale, \
135                 cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0))
136 #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.niccy.hscx_ale, \
137                 cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0), data)
138
139 #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.niccy.hscx_ale, \
140                 cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
141
142 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.niccy.hscx_ale, \
143                 cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
144
145 #include "hscx_irq.c"
146
147 static void
148 niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
149 {
150         struct IsdnCardState *cs = dev_id;
151         u_char val;
152
153         if (!cs) {
154                 printk(KERN_WARNING "Niccy: Spurious interrupt!\n");
155                 return;
156         }
157         if (cs->subtyp == NICCY_PCI) {
158                 int ival;
159                 ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
160                 if (!(ival & PCI_IRQ_ASSERT)) /* IRQ not for us (shared) */
161                         return;
162                 outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
163         }
164         val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
165       Start_HSCX:
166         if (val)
167                 hscx_int_main(cs, val);
168         val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
169       Start_ISAC:
170         if (val)
171                 isac_interrupt(cs, val);
172         val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
173         if (val) {
174                 if (cs->debug & L1_DEB_HSCX)
175                         debugl1(cs, "HSCX IntStat after IntRoutine");
176                 goto Start_HSCX;
177         }
178         val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
179         if (val) {
180                 if (cs->debug & L1_DEB_ISAC)
181                         debugl1(cs, "ISAC IntStat after IntRoutine");
182                 goto Start_ISAC;
183         }
184         writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF);
185         writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0xFF);
186         writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF);
187         writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0);
188         writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0);
189         writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0);
190 }
191
192 void
193 release_io_niccy(struct IsdnCardState *cs)
194 {
195         if (cs->subtyp == NICCY_PCI) {
196                 int val;
197                 
198                 val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
199                 val &= PCI_IRQ_DISABLE;
200                 outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
201                 release_region(cs->hw.niccy.cfg_reg, 0x40);
202                 release_region(cs->hw.niccy.isac, 4);
203         } else {
204                 release_region(cs->hw.niccy.isac, 2);
205                 release_region(cs->hw.niccy.isac_ale, 2);
206         }
207 }
208
209 static void
210 niccy_reset(struct IsdnCardState *cs)
211 {
212         if (cs->subtyp == NICCY_PCI) {
213                 int val;
214
215                 val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
216                 val |= PCI_IRQ_ENABLE;
217                 outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
218         }
219         inithscxisac(cs, 3);
220 }
221
222 static int
223 niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
224 {
225         switch (mt) {
226                 case CARD_RESET:
227                         niccy_reset(cs);
228                         return(0);
229                 case CARD_RELEASE:
230                         release_io_niccy(cs);
231                         return(0);
232                 case CARD_INIT:
233                         niccy_reset(cs);
234                         return(0);
235                 case CARD_TEST:
236                         return(0);
237         }
238         return(0);
239 }
240
241 static struct pci_dev *niccy_dev __initdata = NULL;
242 #ifdef __ISAPNP__
243 static struct pci_bus *pnp_c __devinitdata = NULL;
244 #endif
245
246 int __init
247 setup_niccy(struct IsdnCard *card)
248 {
249         struct IsdnCardState *cs = card->cs;
250         char tmp[64];
251
252         strcpy(tmp, niccy_revision);
253         printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
254         if (cs->typ != ISDN_CTYPE_NICCY)
255                 return (0);
256 #ifdef __ISAPNP__
257         if (!card->para[1] && isapnp_present()) {
258                 struct pci_bus *pb;
259                 struct pci_dev *pd;
260
261                 if ((pb = isapnp_find_card(
262                         ISAPNP_VENDOR('S', 'D', 'A'),
263                         ISAPNP_FUNCTION(0x0150), pnp_c))) {
264                         pnp_c = pb;
265                         pd = NULL;
266                         if (!(pd = isapnp_find_dev(pnp_c,
267                                 ISAPNP_VENDOR('S', 'D', 'A'),
268                                 ISAPNP_FUNCTION(0x0150), pd))) {
269                                 printk(KERN_ERR "NiccyPnP: PnP error card found, no device\n");
270                                 return (0);
271                         }
272                         pd->prepare(pd);
273                         pd->deactivate(pd);
274                         pd->activate(pd);
275                         card->para[1] = pd->resource[0].start;
276                         card->para[2] = pd->resource[1].start;
277                         card->para[0] = pd->irq_resource[0].start;
278                         if (!card->para[0] || !card->para[1] || !card->para[2]) {
279                                 printk(KERN_ERR "NiccyPnP:some resources are missing %ld/%lx/%lx\n",
280                                         card->para[0], card->para[1], card->para[2]);
281                                 pd->deactivate(pd);
282                                 return(0);
283                         }
284                 } else {
285                         printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n");
286                 }
287         }
288 #endif
289         if (card->para[1]) {
290                 cs->hw.niccy.isac = card->para[1] + ISAC_PNP;
291                 cs->hw.niccy.hscx = card->para[1] + HSCX_PNP;
292                 cs->hw.niccy.isac_ale = card->para[2] + ISAC_PNP;
293                 cs->hw.niccy.hscx_ale = card->para[2] + HSCX_PNP;
294                 cs->hw.niccy.cfg_reg = 0;
295                 cs->subtyp = NICCY_PNP;
296                 cs->irq = card->para[0];
297                 if (check_region((cs->hw.niccy.isac), 2)) {
298                         printk(KERN_WARNING
299                                 "HiSax: %s data port %x-%x already in use\n",
300                                 CardType[card->typ],
301                                 cs->hw.niccy.isac,
302                                 cs->hw.niccy.isac + 1);
303                         return (0);
304                 } else
305                         request_region(cs->hw.niccy.isac, 2, "niccy data");
306                 if (check_region((cs->hw.niccy.isac_ale), 2)) {
307                         printk(KERN_WARNING
308                                 "HiSax: %s address port %x-%x already in use\n",
309                                 CardType[card->typ],
310                                 cs->hw.niccy.isac_ale,
311                                 cs->hw.niccy.isac_ale + 1);
312                         release_region(cs->hw.niccy.isac, 2);
313                         return (0);
314                 } else
315                         request_region(cs->hw.niccy.isac_ale, 2, "niccy addr");
316         } else {
317 #if CONFIG_PCI
318                 u_int pci_ioaddr;
319                 if (!pci_present()) {
320                         printk(KERN_ERR "Niccy: no PCI bus present\n");
321                         return(0);
322                 }
323                 cs->subtyp = 0;
324                 if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM,
325                         PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) {
326                         if (pci_enable_device(niccy_dev))
327                                 return(0);
328                         /* get IRQ */
329                         if (!niccy_dev->irq) {
330                                 printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
331                                 return(0);
332                         }
333                         cs->irq = niccy_dev->irq;
334                         cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0);
335                         if (!cs->hw.niccy.cfg_reg) {
336                                 printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
337                                 return(0);
338                         }
339                         pci_ioaddr = pci_resource_start(niccy_dev, 1);
340                         if (!pci_ioaddr) {
341                                 printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
342                                 return(0);
343                         }
344                         cs->subtyp = NICCY_PCI;
345                 } else {
346                         printk(KERN_WARNING "Niccy: No PCI card found\n");
347                         return(0);
348                 }
349                 cs->irq_flags |= SA_SHIRQ;
350                 cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
351                 cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR;
352                 cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA;
353                 cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR;
354                 if (check_region((cs->hw.niccy.isac), 4)) {
355                         printk(KERN_WARNING
356                                 "HiSax: %s data port %x-%x already in use\n",
357                                 CardType[card->typ],
358                                 cs->hw.niccy.isac,
359                                 cs->hw.niccy.isac + 4);
360                         return (0);
361                 } else
362                         request_region(cs->hw.niccy.isac, 4, "niccy");
363                 if (check_region(cs->hw.niccy.cfg_reg, 0x40)) {
364                         printk(KERN_WARNING
365                                "HiSax: %s pci port %x-%x already in use\n",
366                                 CardType[card->typ],
367                                 cs->hw.niccy.cfg_reg,
368                                 cs->hw.niccy.cfg_reg + 0x40);
369                         release_region(cs->hw.niccy.isac, 4);
370                         return (0);
371                 } else {
372                         request_region(cs->hw.niccy.cfg_reg, 0x40, "niccy pci");
373                 }
374 #else
375                 printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n");
376                 printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n");
377                 return (0);
378 #endif /* CONFIG_PCI */
379         }
380         printk(KERN_INFO
381                 "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n",
382                 CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI",
383                 cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale);
384         cs->readisac = &ReadISAC;
385         cs->writeisac = &WriteISAC;
386         cs->readisacfifo = &ReadISACfifo;
387         cs->writeisacfifo = &WriteISACfifo;
388         cs->BC_Read_Reg = &ReadHSCX;
389         cs->BC_Write_Reg = &WriteHSCX;
390         cs->BC_Send_Data = &hscx_fill_fifo;
391         cs->cardmsg = &niccy_card_msg;
392         cs->irq_func = &niccy_interrupt;
393         ISACVersion(cs, "Niccy:");
394         if (HscxVersion(cs, "Niccy:")) {
395                 printk(KERN_WARNING
396                     "Niccy: wrong HSCX versions check IO address\n");
397                 release_io_niccy(cs);
398                 return (0);
399         }
400         return (1);
401 }