Merge with Linu 2.4.0-test6-pre6.
[linux-2.6/linux-mips.git] / drivers / isdn / hisax / niccy.c
blob31f01355ec9f1c49e638f339118d73ddf7508684
1 /* $Id: niccy.c,v 1.12 2000/06/26 08:59:14 keil Exp $
3 * niccy.c low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
4 * compatible (SAGEM cybermodem)
6 * Author Karsten Keil
7 *
8 * Thanks to Dr. Neuhaus and SAGEM for informations
10 * This file is (c) under GNU PUBLIC LICENSE
15 #define __NO_VERSION__
16 #include <linux/config.h>
17 #include "hisax.h"
18 #include "isac.h"
19 #include "hscx.h"
20 #include "isdnl1.h"
21 #include <linux/pci.h>
23 extern const char *CardType[];
24 const char *niccy_revision = "$Revision: 1.12 $";
26 #define byteout(addr,val) outb(val,addr)
27 #define bytein(addr) inb(addr)
29 #define ISAC_PCI_DATA 0
30 #define HSCX_PCI_DATA 1
31 #define ISAC_PCI_ADDR 2
32 #define HSCX_PCI_ADDR 3
33 #define ISAC_PNP 0
34 #define HSCX_PNP 1
36 /* SUB Types */
37 #define NICCY_PNP 1
38 #define NICCY_PCI 2
40 /* PCI stuff */
41 #define PCI_VENDOR_DR_NEUHAUS 0x1267
42 #define PCI_NICCY_ID 0x1016
43 #define PCI_IRQ_CTRL_REG 0x38
44 #define PCI_IRQ_ENABLE 0x1f00
45 #define PCI_IRQ_DISABLE 0xff0000
46 #define PCI_IRQ_ASSERT 0x800000
48 static inline u_char
49 readreg(unsigned int ale, unsigned int adr, u_char off)
51 register u_char ret;
52 long flags;
54 save_flags(flags);
55 cli();
56 byteout(ale, off);
57 ret = bytein(adr);
58 restore_flags(flags);
59 return (ret);
62 static inline void
63 readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
65 /* fifo read without cli because it's allready done */
67 byteout(ale, off);
68 insb(adr, data, size);
72 static inline void
73 writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
75 long flags;
77 save_flags(flags);
78 cli();
79 byteout(ale, off);
80 byteout(adr, data);
81 restore_flags(flags);
84 static inline void
85 writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
87 /* fifo write without cli because it's allready done */
88 byteout(ale, off);
89 outsb(adr, data, size);
92 /* Interface functions */
94 static u_char
95 ReadISAC(struct IsdnCardState *cs, u_char offset)
97 return (readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset));
100 static void
101 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
103 writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value);
106 static void
107 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
109 readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
112 static void
113 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
115 writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
118 static u_char
119 ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
121 return (readreg(cs->hw.niccy.hscx_ale,
122 cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0)));
125 static void
126 WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
128 writereg(cs->hw.niccy.hscx_ale,
129 cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value);
132 #define READHSCX(cs, nr, reg) readreg(cs->hw.niccy.hscx_ale, \
133 cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0))
134 #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.niccy.hscx_ale, \
135 cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0), data)
137 #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.niccy.hscx_ale, \
138 cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
140 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.niccy.hscx_ale, \
141 cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
143 #include "hscx_irq.c"
145 static void
146 niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
148 struct IsdnCardState *cs = dev_id;
149 u_char val;
151 if (!cs) {
152 printk(KERN_WARNING "Niccy: Spurious interrupt!\n");
153 return;
155 if (cs->subtyp == NICCY_PCI) {
156 int ival;
157 ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
158 if (!(ival & PCI_IRQ_ASSERT)) /* IRQ not for us (shared) */
159 return;
160 outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
162 val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
163 Start_HSCX:
164 if (val)
165 hscx_int_main(cs, val);
166 val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
167 Start_ISAC:
168 if (val)
169 isac_interrupt(cs, val);
170 val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
171 if (val) {
172 if (cs->debug & L1_DEB_HSCX)
173 debugl1(cs, "HSCX IntStat after IntRoutine");
174 goto Start_HSCX;
176 val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
177 if (val) {
178 if (cs->debug & L1_DEB_ISAC)
179 debugl1(cs, "ISAC IntStat after IntRoutine");
180 goto Start_ISAC;
182 writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF);
183 writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0xFF);
184 writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF);
185 writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0);
186 writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0);
187 writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0);
190 void
191 release_io_niccy(struct IsdnCardState *cs)
193 if (cs->subtyp == NICCY_PCI) {
194 int val;
196 val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
197 val &= PCI_IRQ_DISABLE;
198 outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
199 release_region(cs->hw.niccy.cfg_reg, 0x80);
200 release_region(cs->hw.niccy.isac, 4);
201 } else {
202 release_region(cs->hw.niccy.isac, 2);
203 release_region(cs->hw.niccy.isac_ale, 2);
207 static void
208 niccy_reset(struct IsdnCardState *cs)
210 if (cs->subtyp == NICCY_PCI) {
211 int val;
213 val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
214 val |= PCI_IRQ_ENABLE;
215 outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
217 inithscxisac(cs, 3);
220 static int
221 niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
223 switch (mt) {
224 case CARD_RESET:
225 niccy_reset(cs);
226 return(0);
227 case CARD_RELEASE:
228 release_io_niccy(cs);
229 return(0);
230 case CARD_INIT:
231 niccy_reset(cs);
232 return(0);
233 case CARD_TEST:
234 return(0);
236 return(0);
239 static struct pci_dev *niccy_dev __initdata = NULL;
241 __initfunc(int
242 setup_niccy(struct IsdnCard *card))
244 struct IsdnCardState *cs = card->cs;
245 char tmp[64];
247 strcpy(tmp, niccy_revision);
248 printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
249 if (cs->typ != ISDN_CTYPE_NICCY)
250 return (0);
252 if (card->para[1]) {
253 cs->hw.niccy.isac = card->para[1] + ISAC_PNP;
254 cs->hw.niccy.hscx = card->para[1] + HSCX_PNP;
255 cs->hw.niccy.isac_ale = card->para[2] + ISAC_PNP;
256 cs->hw.niccy.hscx_ale = card->para[2] + HSCX_PNP;
257 cs->hw.niccy.cfg_reg = 0;
258 cs->subtyp = NICCY_PNP;
259 cs->irq = card->para[0];
260 if (check_region((cs->hw.niccy.isac), 2)) {
261 printk(KERN_WARNING
262 "HiSax: %s data port %x-%x already in use\n",
263 CardType[card->typ],
264 cs->hw.niccy.isac,
265 cs->hw.niccy.isac + 1);
266 return (0);
267 } else
268 request_region(cs->hw.niccy.isac, 2, "niccy data");
269 if (check_region((cs->hw.niccy.isac_ale), 2)) {
270 printk(KERN_WARNING
271 "HiSax: %s address port %x-%x already in use\n",
272 CardType[card->typ],
273 cs->hw.niccy.isac_ale,
274 cs->hw.niccy.isac_ale + 1);
275 release_region(cs->hw.niccy.isac, 2);
276 return (0);
277 } else
278 request_region(cs->hw.niccy.isac_ale, 2, "niccy addr");
279 } else {
280 #if CONFIG_PCI
281 u_int pci_ioaddr;
282 if (!pci_present()) {
283 printk(KERN_ERR "Niccy: no PCI bus present\n");
284 return(0);
286 cs->subtyp = 0;
287 if ((niccy_dev = pci_find_device(PCI_VENDOR_DR_NEUHAUS,
288 PCI_NICCY_ID, niccy_dev))) {
289 if (pci_enable_device(niccy_dev))
290 return (0);
291 /* get IRQ */
292 if (!niccy_dev->irq) {
293 printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
294 return(0);
296 cs->irq = niccy_dev->irq;
297 if (!niccy_dev->resource[ 0].start) {
298 printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
299 return(0);
301 cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0);
302 if (!niccy_dev->resource[ 1].start) {
303 printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
304 return(0);
306 pci_ioaddr = pci_resource_start(niccy_dev, 1);
307 cs->subtyp = NICCY_PCI;
308 } else {
309 printk(KERN_WARNING "Niccy: No PCI card found\n");
310 return(0);
312 cs->irq_flags |= SA_SHIRQ;
313 cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
314 cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR;
315 cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA;
316 cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR;
317 if (check_region((cs->hw.niccy.isac), 4)) {
318 printk(KERN_WARNING
319 "HiSax: %s data port %x-%x already in use\n",
320 CardType[card->typ],
321 cs->hw.niccy.isac,
322 cs->hw.niccy.isac + 4);
323 return (0);
324 } else
325 request_region(cs->hw.niccy.isac, 4, "niccy");
326 if (check_region(cs->hw.niccy.cfg_reg, 0x80)) {
327 printk(KERN_WARNING
328 "HiSax: %s pci port %x-%x already in use\n",
329 CardType[card->typ],
330 cs->hw.niccy.cfg_reg,
331 cs->hw.niccy.cfg_reg + 0x80);
332 release_region(cs->hw.niccy.isac, 4);
333 return (0);
334 } else {
335 request_region(cs->hw.niccy.cfg_reg, 0x80, "niccy pci");
337 #else
338 printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n");
339 printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n");
340 return (0);
341 #endif /* CONFIG_PCI */
343 printk(KERN_INFO
344 "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n",
345 CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI",
346 cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale);
347 cs->readisac = &ReadISAC;
348 cs->writeisac = &WriteISAC;
349 cs->readisacfifo = &ReadISACfifo;
350 cs->writeisacfifo = &WriteISACfifo;
351 cs->BC_Read_Reg = &ReadHSCX;
352 cs->BC_Write_Reg = &WriteHSCX;
353 cs->BC_Send_Data = &hscx_fill_fifo;
354 cs->cardmsg = &niccy_card_msg;
355 cs->irq_func = &niccy_interrupt;
356 ISACVersion(cs, "Niccy:");
357 if (HscxVersion(cs, "Niccy:")) {
358 printk(KERN_WARNING
359 "Niccy: wrong HSCX versions check IO address\n");
360 release_io_niccy(cs);
361 return (0);
363 return (1);