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)
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>
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
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
49 readreg(unsigned int ale
, unsigned int adr
, u_char off
)
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 */
68 insb(adr
, data
, size
);
73 writereg(unsigned int ale
, unsigned int adr
, u_char off
, u_char data
)
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 */
89 outsb(adr
, data
, size
);
92 /* Interface functions */
95 ReadISAC(struct IsdnCardState
*cs
, u_char offset
)
97 return (readreg(cs
->hw
.niccy
.isac_ale
, cs
->hw
.niccy
.isac
, offset
));
101 WriteISAC(struct IsdnCardState
*cs
, u_char offset
, u_char value
)
103 writereg(cs
->hw
.niccy
.isac_ale
, cs
->hw
.niccy
.isac
, offset
, value
);
107 ReadISACfifo(struct IsdnCardState
*cs
, u_char
* data
, int size
)
109 readfifo(cs
->hw
.niccy
.isac_ale
, cs
->hw
.niccy
.isac
, 0, data
, size
);
113 WriteISACfifo(struct IsdnCardState
*cs
, u_char
* data
, int size
)
115 writefifo(cs
->hw
.niccy
.isac_ale
, cs
->hw
.niccy
.isac
, 0, data
, size
);
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)));
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"
146 niccy_interrupt(int intno
, void *dev_id
, struct pt_regs
*regs
)
148 struct IsdnCardState
*cs
= dev_id
;
152 printk(KERN_WARNING
"Niccy: Spurious interrupt!\n");
155 if (cs
->subtyp
== NICCY_PCI
) {
157 ival
= inl(cs
->hw
.niccy
.cfg_reg
+ PCI_IRQ_CTRL_REG
);
158 if (!(ival
& PCI_IRQ_ASSERT
)) /* IRQ not for us (shared) */
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);
165 hscx_int_main(cs
, val
);
166 val
= readreg(cs
->hw
.niccy
.isac_ale
, cs
->hw
.niccy
.isac
, ISAC_ISTA
);
169 isac_interrupt(cs
, val
);
170 val
= readreg(cs
->hw
.niccy
.hscx_ale
, cs
->hw
.niccy
.hscx
, HSCX_ISTA
+ 0x40);
172 if (cs
->debug
& L1_DEB_HSCX
)
173 debugl1(cs
, "HSCX IntStat after IntRoutine");
176 val
= readreg(cs
->hw
.niccy
.isac_ale
, cs
->hw
.niccy
.isac
, ISAC_ISTA
);
178 if (cs
->debug
& L1_DEB_ISAC
)
179 debugl1(cs
, "ISAC IntStat after IntRoutine");
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);
191 release_io_niccy(struct IsdnCardState
*cs
)
193 if (cs
->subtyp
== NICCY_PCI
) {
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);
202 release_region(cs
->hw
.niccy
.isac
, 2);
203 release_region(cs
->hw
.niccy
.isac_ale
, 2);
208 niccy_reset(struct IsdnCardState
*cs
)
210 if (cs
->subtyp
== NICCY_PCI
) {
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
);
221 niccy_card_msg(struct IsdnCardState
*cs
, int mt
, void *arg
)
228 release_io_niccy(cs
);
239 static struct pci_dev
*niccy_dev __initdata
= NULL
;
242 setup_niccy(struct IsdnCard
*card
))
244 struct IsdnCardState
*cs
= card
->cs
;
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
)
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)) {
262 "HiSax: %s data port %x-%x already in use\n",
265 cs
->hw
.niccy
.isac
+ 1);
268 request_region(cs
->hw
.niccy
.isac
, 2, "niccy data");
269 if (check_region((cs
->hw
.niccy
.isac_ale
), 2)) {
271 "HiSax: %s address port %x-%x already in use\n",
273 cs
->hw
.niccy
.isac_ale
,
274 cs
->hw
.niccy
.isac_ale
+ 1);
275 release_region(cs
->hw
.niccy
.isac
, 2);
278 request_region(cs
->hw
.niccy
.isac_ale
, 2, "niccy addr");
282 if (!pci_present()) {
283 printk(KERN_ERR
"Niccy: no PCI bus present\n");
287 if ((niccy_dev
= pci_find_device(PCI_VENDOR_DR_NEUHAUS
,
288 PCI_NICCY_ID
, niccy_dev
))) {
289 if (pci_enable_device(niccy_dev
))
292 if (!niccy_dev
->irq
) {
293 printk(KERN_WARNING
"Niccy: No IRQ for PCI card found\n");
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");
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");
306 pci_ioaddr
= pci_resource_start(niccy_dev
, 1);
307 cs
->subtyp
= NICCY_PCI
;
309 printk(KERN_WARNING
"Niccy: No PCI card found\n");
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)) {
319 "HiSax: %s data port %x-%x already in use\n",
322 cs
->hw
.niccy
.isac
+ 4);
325 request_region(cs
->hw
.niccy
.isac
, 4, "niccy");
326 if (check_region(cs
->hw
.niccy
.cfg_reg
, 0x80)) {
328 "HiSax: %s pci port %x-%x already in use\n",
330 cs
->hw
.niccy
.cfg_reg
,
331 cs
->hw
.niccy
.cfg_reg
+ 0x80);
332 release_region(cs
->hw
.niccy
.isac
, 4);
335 request_region(cs
->hw
.niccy
.cfg_reg
, 0x80, "niccy pci");
338 printk(KERN_WARNING
"Niccy: io0 0 and NO_PCI_BIOS\n");
339 printk(KERN_WARNING
"Niccy: unable to config NICCY PCI\n");
341 #endif /* CONFIG_PCI */
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:")) {
359 "Niccy: wrong HSCX versions check IO address\n");
360 release_io_niccy(cs
);