1 /* $Id: teles3.c,v 2.13 1999/08/30 12:01:28 keil Exp $
3 * teles3.c low level stuff for Teles 16.3 & PNP isdn cards
5 * based on the teles driver from Jan den Ouden
7 * Author Karsten Keil (keil@temic-ech.spacenet.de)
9 * Thanks to Jan den Ouden
14 * Revision 2.13 1999/08/30 12:01:28 keil
15 * HW version v1.3 support
17 * Revision 2.12 1999/07/12 21:05:32 keil
18 * fix race in IRQ handling
19 * added watchdog for lost IRQs
21 * Revision 2.11 1999/07/01 08:12:14 keil
22 * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
24 * Revision 2.10 1999/02/15 14:37:15 cpetig
25 * oops, missed something in last commit
27 * Revision 2.9 1999/02/15 14:11:02 cpetig
28 * fixed a bug with Teles PCMCIA, it doesn't have a config register
30 * Revision 2.8 1998/04/15 16:44:30 keil
33 * Revision 2.7 1998/02/02 13:29:48 keil
36 * Revision 2.6 1997/11/13 16:22:44 keil
39 * Revision 2.5 1997/11/12 15:01:25 keil
42 * Revision 2.4 1997/11/08 21:35:56 keil
45 * Revision 2.3 1997/11/06 17:09:33 keil
48 * Revision 2.2 1997/10/29 18:55:59 keil
49 * changes for 2.1.60 (irq2dev_map)
51 * Revision 2.1 1997/07/27 21:47:12 keil
52 * new interface structures
54 * Revision 2.0 1997/06/26 11:02:46 keil
55 * New Layer and card interface
57 * Revision 1.11 1997/04/13 19:54:05 keil
58 * Change in IRQ check delay for SMP
60 * Revision 1.10 1997/04/06 22:54:05 keil
63 * Revision 1.9 1997/03/22 02:01:07 fritz
64 * -Reworked toplevel Makefile. From now on, no different Makefiles
65 * for standalone- and in-kernel-compilation are needed any more.
66 * -Added local Rules.make for above reason.
67 * -Experimental changes in teles3.c for enhanced IRQ-checking with
68 * 2.1.X and SMP kernels.
69 * -Removed diffstd-script, same functionality is in stddiff -r.
70 * -Enhanced scripts std2kern and stddiff.
72 * Revision 1.8 1997/02/23 18:43:55 fritz
73 * Added support for Teles-Vision.
75 * Revision 1.7 1997/01/28 22:48:33 keil
76 * fixes for Teles PCMCIA (Christof Petig)
78 * Revision 1.6 1997/01/27 15:52:55 keil
79 * SMP proof,cosmetics, PCMCIA added
81 * removed old log info /KKe
84 #define __NO_VERSION__
90 extern const char *CardType
[];
91 const char *teles3_revision
= "$Revision: 2.13 $";
93 #define byteout(addr,val) outb(val,addr)
94 #define bytein(addr) inb(addr)
97 readreg(unsigned int adr
, u_char off
)
99 return (bytein(adr
+ off
));
103 writereg(unsigned int adr
, u_char off
, u_char data
)
105 byteout(adr
+ off
, data
);
110 read_fifo(unsigned int adr
, u_char
* data
, int size
)
112 insb(adr
, data
, size
);
116 write_fifo(unsigned int adr
, u_char
* data
, int size
)
118 outsb(adr
, data
, size
);
121 /* Interface functions */
124 ReadISAC(struct IsdnCardState
*cs
, u_char offset
)
126 return (readreg(cs
->hw
.teles3
.isac
, offset
));
130 WriteISAC(struct IsdnCardState
*cs
, u_char offset
, u_char value
)
132 writereg(cs
->hw
.teles3
.isac
, offset
, value
);
136 ReadISACfifo(struct IsdnCardState
*cs
, u_char
* data
, int size
)
138 read_fifo(cs
->hw
.teles3
.isacfifo
, data
, size
);
142 WriteISACfifo(struct IsdnCardState
*cs
, u_char
* data
, int size
)
144 write_fifo(cs
->hw
.teles3
.isacfifo
, data
, size
);
148 ReadHSCX(struct IsdnCardState
*cs
, int hscx
, u_char offset
)
150 return (readreg(cs
->hw
.teles3
.hscx
[hscx
], offset
));
154 WriteHSCX(struct IsdnCardState
*cs
, int hscx
, u_char offset
, u_char value
)
156 writereg(cs
->hw
.teles3
.hscx
[hscx
], offset
, value
);
160 * fast interrupt HSCX stuff goes here
163 #define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.hscx[nr], reg)
164 #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.hscx[nr], reg, data)
165 #define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
166 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
168 #include "hscx_irq.c"
171 teles3_interrupt(int intno
, void *dev_id
, struct pt_regs
*regs
)
174 struct IsdnCardState
*cs
= dev_id
;
179 printk(KERN_WARNING
"Teles: Spurious interrupt!\n");
182 val
= readreg(cs
->hw
.teles3
.hscx
[1], HSCX_ISTA
);
185 hscx_int_main(cs
, val
);
186 val
= readreg(cs
->hw
.teles3
.isac
, ISAC_ISTA
);
189 isac_interrupt(cs
, val
);
191 val
= readreg(cs
->hw
.teles3
.hscx
[1], HSCX_ISTA
);
192 if (val
&& count
< MAXCOUNT
) {
193 if (cs
->debug
& L1_DEB_HSCX
)
194 debugl1(cs
, "HSCX IntStat after IntRoutine");
197 val
= readreg(cs
->hw
.teles3
.isac
, ISAC_ISTA
);
198 if (val
&& count
< MAXCOUNT
) {
199 if (cs
->debug
& L1_DEB_ISAC
)
200 debugl1(cs
, "ISAC IntStat after IntRoutine");
203 if (count
>= MAXCOUNT
)
204 printk(KERN_WARNING
"Teles3: more than %d loops in teles3_interrupt\n", count
);
205 writereg(cs
->hw
.teles3
.hscx
[0], HSCX_MASK
, 0xFF);
206 writereg(cs
->hw
.teles3
.hscx
[1], HSCX_MASK
, 0xFF);
207 writereg(cs
->hw
.teles3
.isac
, ISAC_MASK
, 0xFF);
208 writereg(cs
->hw
.teles3
.isac
, ISAC_MASK
, 0x0);
209 writereg(cs
->hw
.teles3
.hscx
[0], HSCX_MASK
, 0x0);
210 writereg(cs
->hw
.teles3
.hscx
[1], HSCX_MASK
, 0x0);
214 release_ioregs(struct IsdnCardState
*cs
, int mask
)
217 release_region(cs
->hw
.teles3
.isac
+ 32, 32);
219 release_region(cs
->hw
.teles3
.hscx
[0] + 32, 32);
221 release_region(cs
->hw
.teles3
.hscx
[1] + 32, 32);
225 release_io_teles3(struct IsdnCardState
*cs
)
227 if (cs
->typ
== ISDN_CTYPE_TELESPCMCIA
) {
228 release_region(cs
->hw
.teles3
.hscx
[0], 97);
230 if (cs
->hw
.teles3
.cfg_reg
) {
231 if (cs
->typ
== ISDN_CTYPE_COMPAQ_ISA
) {
232 release_region(cs
->hw
.teles3
.cfg_reg
, 1);
234 release_region(cs
->hw
.teles3
.cfg_reg
, 8);
237 release_ioregs(cs
, 0x7);
242 reset_teles3(struct IsdnCardState
*cs
)
247 if (cs
->typ
!= ISDN_CTYPE_TELESPCMCIA
) {
248 if ((cs
->hw
.teles3
.cfg_reg
) && (cs
->typ
!= ISDN_CTYPE_COMPAQ_ISA
)) {
279 byteout(cs
->hw
.teles3
.cfg_reg
+ 4, irqcfg
);
281 HZDELAY(HZ
/ 10 + 1);
282 byteout(cs
->hw
.teles3
.cfg_reg
+ 4, irqcfg
| 1);
283 HZDELAY(HZ
/ 10 + 1);
284 restore_flags(flags
);
285 } else if (cs
->typ
== ISDN_CTYPE_COMPAQ_ISA
) {
287 byteout(cs
->hw
.teles3
.cfg_reg
, 0xff);
289 byteout(cs
->hw
.teles3
.cfg_reg
, 0x00);
291 restore_flags(flags
);
293 /* Reset off for 16.3 PnP , thanks to Georg Acher */
295 byteout(cs
->hw
.teles3
.isac
+ 0x3c, 0);
297 byteout(cs
->hw
.teles3
.isac
+ 0x3c, 1);
299 restore_flags(flags
);
306 Teles_card_msg(struct IsdnCardState
*cs
, int mt
, void *arg
)
313 release_io_teles3(cs
);
325 setup_teles3(struct IsdnCard
*card
)
328 struct IsdnCardState
*cs
= card
->cs
;
331 strcpy(tmp
, teles3_revision
);
332 printk(KERN_INFO
"HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp
));
333 if ((cs
->typ
!= ISDN_CTYPE_16_3
) && (cs
->typ
!= ISDN_CTYPE_PNP
)
334 && (cs
->typ
!= ISDN_CTYPE_TELESPCMCIA
) && (cs
->typ
!= ISDN_CTYPE_COMPAQ_ISA
))
337 if (cs
->typ
== ISDN_CTYPE_16_3
) {
338 cs
->hw
.teles3
.cfg_reg
= card
->para
[1];
339 switch (cs
->hw
.teles3
.cfg_reg
) {
343 cs
->hw
.teles3
.cfg_reg
|= 0xc00;
346 cs
->hw
.teles3
.isac
= cs
->hw
.teles3
.cfg_reg
- 0x420;
347 cs
->hw
.teles3
.hscx
[0] = cs
->hw
.teles3
.cfg_reg
- 0xc20;
348 cs
->hw
.teles3
.hscx
[1] = cs
->hw
.teles3
.cfg_reg
- 0x820;
349 } else if (cs
->typ
== ISDN_CTYPE_TELESPCMCIA
) {
350 cs
->hw
.teles3
.cfg_reg
= 0;
351 cs
->hw
.teles3
.hscx
[0] = card
->para
[1] - 0x20;
352 cs
->hw
.teles3
.hscx
[1] = card
->para
[1];
353 cs
->hw
.teles3
.isac
= card
->para
[1] + 0x20;
354 } else if (cs
->typ
== ISDN_CTYPE_COMPAQ_ISA
) {
355 cs
->hw
.teles3
.cfg_reg
= card
->para
[3];
356 cs
->hw
.teles3
.isac
= card
->para
[2] - 32;
357 cs
->hw
.teles3
.hscx
[0] = card
->para
[1] - 32;
358 cs
->hw
.teles3
.hscx
[1] = card
->para
[1];
360 cs
->hw
.teles3
.cfg_reg
= 0;
361 cs
->hw
.teles3
.isac
= card
->para
[1] - 32;
362 cs
->hw
.teles3
.hscx
[0] = card
->para
[2] - 32;
363 cs
->hw
.teles3
.hscx
[1] = card
->para
[2];
365 cs
->irq
= card
->para
[0];
366 cs
->hw
.teles3
.isacfifo
= cs
->hw
.teles3
.isac
+ 0x3e;
367 cs
->hw
.teles3
.hscxfifo
[0] = cs
->hw
.teles3
.hscx
[0] + 0x3e;
368 cs
->hw
.teles3
.hscxfifo
[1] = cs
->hw
.teles3
.hscx
[1] + 0x3e;
369 if (cs
->typ
== ISDN_CTYPE_TELESPCMCIA
) {
370 if (check_region((cs
->hw
.teles3
.hscx
[0]), 97)) {
372 "HiSax: %s ports %x-%x already in use\n",
374 cs
->hw
.teles3
.hscx
[0],
375 cs
->hw
.teles3
.hscx
[0] + 96);
378 request_region(cs
->hw
.teles3
.hscx
[0], 97, "HiSax Teles PCMCIA");
380 if (cs
->hw
.teles3
.cfg_reg
) {
381 if (cs
->typ
== ISDN_CTYPE_COMPAQ_ISA
) {
382 if (check_region((cs
->hw
.teles3
.cfg_reg
), 1)) {
384 "HiSax: %s config port %x already in use\n",
386 cs
->hw
.teles3
.cfg_reg
);
389 request_region(cs
->hw
.teles3
.cfg_reg
, 1, "teles3 cfg");
391 if (check_region((cs
->hw
.teles3
.cfg_reg
), 8)) {
393 "HiSax: %s config port %x-%x already in use\n",
395 cs
->hw
.teles3
.cfg_reg
,
396 cs
->hw
.teles3
.cfg_reg
+ 8);
399 request_region(cs
->hw
.teles3
.cfg_reg
, 8, "teles3 cfg");
402 if (check_region((cs
->hw
.teles3
.isac
+ 32), 32)) {
404 "HiSax: %s isac ports %x-%x already in use\n",
406 cs
->hw
.teles3
.isac
+ 32,
407 cs
->hw
.teles3
.isac
+ 64);
408 if (cs
->hw
.teles3
.cfg_reg
) {
409 if (cs
->typ
== ISDN_CTYPE_COMPAQ_ISA
) {
410 release_region(cs
->hw
.teles3
.cfg_reg
, 1);
412 release_region(cs
->hw
.teles3
.cfg_reg
, 8);
417 request_region(cs
->hw
.teles3
.isac
+ 32, 32, "HiSax isac");
418 if (check_region((cs
->hw
.teles3
.hscx
[0] + 32), 32)) {
420 "HiSax: %s hscx A ports %x-%x already in use\n",
422 cs
->hw
.teles3
.hscx
[0] + 32,
423 cs
->hw
.teles3
.hscx
[0] + 64);
424 if (cs
->hw
.teles3
.cfg_reg
) {
425 if (cs
->typ
== ISDN_CTYPE_COMPAQ_ISA
) {
426 release_region(cs
->hw
.teles3
.cfg_reg
, 1);
428 release_region(cs
->hw
.teles3
.cfg_reg
, 8);
431 release_ioregs(cs
, 1);
434 request_region(cs
->hw
.teles3
.hscx
[0] + 32, 32, "HiSax hscx A");
435 if (check_region((cs
->hw
.teles3
.hscx
[1] + 32), 32)) {
437 "HiSax: %s hscx B ports %x-%x already in use\n",
439 cs
->hw
.teles3
.hscx
[1] + 32,
440 cs
->hw
.teles3
.hscx
[1] + 64);
441 if (cs
->hw
.teles3
.cfg_reg
) {
442 if (cs
->typ
== ISDN_CTYPE_COMPAQ_ISA
) {
443 release_region(cs
->hw
.teles3
.cfg_reg
, 1);
445 release_region(cs
->hw
.teles3
.cfg_reg
, 8);
448 release_ioregs(cs
, 3);
451 request_region(cs
->hw
.teles3
.hscx
[1] + 32, 32, "HiSax hscx B");
453 if ((cs
->hw
.teles3
.cfg_reg
) && (cs
->typ
!= ISDN_CTYPE_COMPAQ_ISA
)) {
454 if ((val
= bytein(cs
->hw
.teles3
.cfg_reg
+ 0)) != 0x51) {
455 printk(KERN_WARNING
"Teles: 16.3 Byte at %x is %x\n",
456 cs
->hw
.teles3
.cfg_reg
+ 0, val
);
457 release_io_teles3(cs
);
460 if ((val
= bytein(cs
->hw
.teles3
.cfg_reg
+ 1)) != 0x93) {
461 printk(KERN_WARNING
"Teles: 16.3 Byte at %x is %x\n",
462 cs
->hw
.teles3
.cfg_reg
+ 1, val
);
463 release_io_teles3(cs
);
466 val
= bytein(cs
->hw
.teles3
.cfg_reg
+ 2);/* 0x1e=without AB
471 * 0x46 16.3 with AB + Video (Teles-Vision)
473 if (val
!= 0x46 && val
!= 0x39 && val
!= 0x38 && val
!= 0x1c && val
!= 0x1e && val
!= 0x1f) {
474 printk(KERN_WARNING
"Teles: 16.3 Byte at %x is %x\n",
475 cs
->hw
.teles3
.cfg_reg
+ 2, val
);
476 release_io_teles3(cs
);
481 "HiSax: %s config irq:%d isac:0x%X cfg:0x%X\n",
482 CardType
[cs
->typ
], cs
->irq
,
483 cs
->hw
.teles3
.isac
+ 32, cs
->hw
.teles3
.cfg_reg
);
485 "HiSax: hscx A:0x%X hscx B:0x%X\n",
486 cs
->hw
.teles3
.hscx
[0] + 32, cs
->hw
.teles3
.hscx
[1] + 32);
488 if (reset_teles3(cs
)) {
489 printk(KERN_WARNING
"Teles3: wrong IRQ\n");
490 release_io_teles3(cs
);
493 cs
->readisac
= &ReadISAC
;
494 cs
->writeisac
= &WriteISAC
;
495 cs
->readisacfifo
= &ReadISACfifo
;
496 cs
->writeisacfifo
= &WriteISACfifo
;
497 cs
->BC_Read_Reg
= &ReadHSCX
;
498 cs
->BC_Write_Reg
= &WriteHSCX
;
499 cs
->BC_Send_Data
= &hscx_fill_fifo
;
500 cs
->cardmsg
= &Teles_card_msg
;
501 cs
->irq_func
= &teles3_interrupt
;
502 ISACVersion(cs
, "Teles3:");
503 if (HscxVersion(cs
, "Teles3:")) {
505 "Teles3: wrong HSCX versions check IO address\n");
506 release_io_teles3(cs
);