1 /* $Id: teles3.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
2 *
3 * low level stuff for Teles 16.3 & PNP isdn cards
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * Thanks to Jan den Ouden
12 * Fritz Elfert
13 * Beat Doebeli
14 *
15 */
16 #define __NO_VERSION__
17 #include <linux/init.h>
18 #include <linux/isapnp.h>
19 #include "hisax.h"
20 #include "isac.h"
21 #include "hscx.h"
22 #include "isdnl1.h"
23
24 extern const char *CardType[];
25 const char *teles3_revision = "$Revision: 1.1.4.1 $";
26
27 #define byteout(addr,val) outb(val,addr)
28 #define bytein(addr) inb(addr)
29
30 static inline u_char
readreg(unsigned int adr,u_char off)31 readreg(unsigned int adr, u_char off)
32 {
33 return (bytein(adr + off));
34 }
35
36 static inline void
writereg(unsigned int adr,u_char off,u_char data)37 writereg(unsigned int adr, u_char off, u_char data)
38 {
39 byteout(adr + off, data);
40 }
41
42
43 static inline void
read_fifo(unsigned int adr,u_char * data,int size)44 read_fifo(unsigned int adr, u_char * data, int size)
45 {
46 insb(adr, data, size);
47 }
48
49 static void
write_fifo(unsigned int adr,u_char * data,int size)50 write_fifo(unsigned int adr, u_char * data, int size)
51 {
52 outsb(adr, data, size);
53 }
54
55 /* Interface functions */
56
57 static u_char
ReadISAC(struct IsdnCardState * cs,u_char offset)58 ReadISAC(struct IsdnCardState *cs, u_char offset)
59 {
60 return (readreg(cs->hw.teles3.isac, offset));
61 }
62
63 static void
WriteISAC(struct IsdnCardState * cs,u_char offset,u_char value)64 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
65 {
66 writereg(cs->hw.teles3.isac, offset, value);
67 }
68
69 static void
ReadISACfifo(struct IsdnCardState * cs,u_char * data,int size)70 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
71 {
72 read_fifo(cs->hw.teles3.isacfifo, data, size);
73 }
74
75 static void
WriteISACfifo(struct IsdnCardState * cs,u_char * data,int size)76 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
77 {
78 write_fifo(cs->hw.teles3.isacfifo, data, size);
79 }
80
81 static u_char
ReadHSCX(struct IsdnCardState * cs,int hscx,u_char offset)82 ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
83 {
84 return (readreg(cs->hw.teles3.hscx[hscx], offset));
85 }
86
87 static void
WriteHSCX(struct IsdnCardState * cs,int hscx,u_char offset,u_char value)88 WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
89 {
90 writereg(cs->hw.teles3.hscx[hscx], offset, value);
91 }
92
93 /*
94 * fast interrupt HSCX stuff goes here
95 */
96
97 #define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.hscx[nr], reg)
98 #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.hscx[nr], reg, data)
99 #define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
100 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
101
102 #include "hscx_irq.c"
103
104 static void
teles3_interrupt(int intno,void * dev_id,struct pt_regs * regs)105 teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
106 {
107 #define MAXCOUNT 5
108 struct IsdnCardState *cs = dev_id;
109 u_char val;
110 int count = 0;
111
112 if (!cs) {
113 printk(KERN_WARNING "Teles: Spurious interrupt!\n");
114 return;
115 }
116 val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
117 Start_HSCX:
118 if (val)
119 hscx_int_main(cs, val);
120 val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
121 Start_ISAC:
122 if (val)
123 isac_interrupt(cs, val);
124 count++;
125 val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
126 if (val && count < MAXCOUNT) {
127 if (cs->debug & L1_DEB_HSCX)
128 debugl1(cs, "HSCX IntStat after IntRoutine");
129 goto Start_HSCX;
130 }
131 val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
132 if (val && count < MAXCOUNT) {
133 if (cs->debug & L1_DEB_ISAC)
134 debugl1(cs, "ISAC IntStat after IntRoutine");
135 goto Start_ISAC;
136 }
137 if (count >= MAXCOUNT)
138 printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count);
139 writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
140 writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
141 writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF);
142 writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0);
143 writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
144 writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
145 }
146
147 inline static void
release_ioregs(struct IsdnCardState * cs,int mask)148 release_ioregs(struct IsdnCardState *cs, int mask)
149 {
150 if (mask & 1)
151 release_region(cs->hw.teles3.isac + 32, 32);
152 if (mask & 2)
153 release_region(cs->hw.teles3.hscx[0] + 32, 32);
154 if (mask & 4)
155 release_region(cs->hw.teles3.hscx[1] + 32, 32);
156 }
157
158 void
release_io_teles3(struct IsdnCardState * cs)159 release_io_teles3(struct IsdnCardState *cs)
160 {
161 if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
162 release_region(cs->hw.teles3.hscx[1], 96);
163 } else {
164 if (cs->hw.teles3.cfg_reg) {
165 if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
166 release_region(cs->hw.teles3.cfg_reg, 1);
167 } else {
168 release_region(cs->hw.teles3.cfg_reg, 8);
169 }
170 }
171 release_ioregs(cs, 0x7);
172 }
173 }
174
175 static int
reset_teles3(struct IsdnCardState * cs)176 reset_teles3(struct IsdnCardState *cs)
177 {
178 long flags;
179 u_char irqcfg;
180
181 if (cs->typ != ISDN_CTYPE_TELESPCMCIA) {
182 if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
183 switch (cs->irq) {
184 case 2:
185 case 9:
186 irqcfg = 0x00;
187 break;
188 case 3:
189 irqcfg = 0x02;
190 break;
191 case 4:
192 irqcfg = 0x04;
193 break;
194 case 5:
195 irqcfg = 0x06;
196 break;
197 case 10:
198 irqcfg = 0x08;
199 break;
200 case 11:
201 irqcfg = 0x0A;
202 break;
203 case 12:
204 irqcfg = 0x0C;
205 break;
206 case 15:
207 irqcfg = 0x0E;
208 break;
209 default:
210 return(1);
211 }
212 save_flags(flags);
213 byteout(cs->hw.teles3.cfg_reg + 4, irqcfg);
214 sti();
215 HZDELAY(HZ / 10 + 1);
216 byteout(cs->hw.teles3.cfg_reg + 4, irqcfg | 1);
217 HZDELAY(HZ / 10 + 1);
218 restore_flags(flags);
219 } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
220 save_flags(flags);
221 byteout(cs->hw.teles3.cfg_reg, 0xff);
222 HZDELAY(2);
223 byteout(cs->hw.teles3.cfg_reg, 0x00);
224 HZDELAY(2);
225 restore_flags(flags);
226 } else {
227 /* Reset off for 16.3 PnP , thanks to Georg Acher */
228 save_flags(flags);
229 byteout(cs->hw.teles3.isac + 0x3c, 0);
230 HZDELAY(2);
231 byteout(cs->hw.teles3.isac + 0x3c, 1);
232 HZDELAY(2);
233 restore_flags(flags);
234 }
235 }
236 return(0);
237 }
238
239 static int
Teles_card_msg(struct IsdnCardState * cs,int mt,void * arg)240 Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
241 {
242 switch (mt) {
243 case CARD_RESET:
244 reset_teles3(cs);
245 return(0);
246 case CARD_RELEASE:
247 release_io_teles3(cs);
248 return(0);
249 case CARD_INIT:
250 inithscxisac(cs, 3);
251 return(0);
252 case CARD_TEST:
253 return(0);
254 }
255 return(0);
256 }
257
258 #ifdef __ISAPNP__
259 static struct isapnp_device_id teles_ids[] __initdata = {
260 { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
261 ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
262 (unsigned long) "Teles 16.3 PnP" },
263 { ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
264 ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
265 (unsigned long) "Creatix 16.3 PnP" },
266 { ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
267 ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
268 (unsigned long) "Compaq ISDN S0" },
269 { 0, }
270 };
271
272 static struct isapnp_device_id *tdev = &teles_ids[0];
273 static struct pci_bus *pnp_c __devinitdata = NULL;
274 #endif
275
276 int __devinit
setup_teles3(struct IsdnCard * card)277 setup_teles3(struct IsdnCard *card)
278 {
279 u_char val;
280 struct IsdnCardState *cs = card->cs;
281 char tmp[64];
282
283 strcpy(tmp, teles3_revision);
284 printk(KERN_INFO "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp));
285 if ((cs->typ != ISDN_CTYPE_16_3) && (cs->typ != ISDN_CTYPE_PNP)
286 && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA))
287 return (0);
288
289 #ifdef __ISAPNP__
290 if (!card->para[1] && isapnp_present()) {
291 struct pci_bus *pb;
292 struct pci_dev *pd;
293
294 while(tdev->card_vendor) {
295 if ((pb = isapnp_find_card(tdev->card_vendor,
296 tdev->card_device, pnp_c))) {
297 pnp_c = pb;
298 pd = NULL;
299 if ((pd = isapnp_find_dev(pnp_c,
300 tdev->vendor, tdev->function, pd))) {
301 printk(KERN_INFO "HiSax: %s detected\n",
302 (char *)tdev->driver_data);
303 pd->prepare(pd);
304 pd->deactivate(pd);
305 pd->activate(pd);
306 card->para[3] = pd->resource[2].start;
307 card->para[2] = pd->resource[1].start;
308 card->para[1] = pd->resource[0].start;
309 card->para[0] = pd->irq_resource[0].start;
310 if (!card->para[0] || !card->para[1] || !card->para[2]) {
311 printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n",
312 card->para[0], card->para[1], card->para[2]);
313 pd->deactivate(pd);
314 return(0);
315 }
316 break;
317 } else {
318 printk(KERN_ERR "Teles PnP: PnP error card found, no device\n");
319 }
320 }
321 tdev++;
322 pnp_c=NULL;
323 }
324 if (!tdev->card_vendor) {
325 printk(KERN_INFO "Teles PnP: no ISAPnP card found\n");
326 return(0);
327 }
328 }
329 #endif
330 if (cs->typ == ISDN_CTYPE_16_3) {
331 cs->hw.teles3.cfg_reg = card->para[1];
332 switch (cs->hw.teles3.cfg_reg) {
333 case 0x180:
334 case 0x280:
335 case 0x380:
336 cs->hw.teles3.cfg_reg |= 0xc00;
337 break;
338 }
339 cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420;
340 cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20;
341 cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820;
342 } else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
343 cs->hw.teles3.cfg_reg = 0;
344 cs->hw.teles3.hscx[0] = card->para[1] - 0x20;
345 cs->hw.teles3.hscx[1] = card->para[1];
346 cs->hw.teles3.isac = card->para[1] + 0x20;
347 } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
348 cs->hw.teles3.cfg_reg = card->para[3];
349 cs->hw.teles3.isac = card->para[2] - 32;
350 cs->hw.teles3.hscx[0] = card->para[1] - 32;
351 cs->hw.teles3.hscx[1] = card->para[1];
352 } else { /* PNP */
353 cs->hw.teles3.cfg_reg = 0;
354 cs->hw.teles3.isac = card->para[1] - 32;
355 cs->hw.teles3.hscx[0] = card->para[2] - 32;
356 cs->hw.teles3.hscx[1] = card->para[2];
357 }
358 cs->irq = card->para[0];
359 cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
360 cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
361 cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
362 if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
363 if (check_region((cs->hw.teles3.hscx[1]), 96 )) {
364 printk(KERN_WARNING
365 "HiSax: %s ports %x-%x already in use\n",
366 CardType[cs->typ],
367 cs->hw.teles3.hscx[1],
368 cs->hw.teles3.hscx[1] + 96);
369 return (0);
370 } else
371 request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA");
372 } else {
373 if (cs->hw.teles3.cfg_reg) {
374 if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
375 if (check_region((cs->hw.teles3.cfg_reg), 1)) {
376 printk(KERN_WARNING
377 "HiSax: %s config port %x already in use\n",
378 CardType[card->typ],
379 cs->hw.teles3.cfg_reg);
380 return (0);
381 } else
382 request_region(cs->hw.teles3.cfg_reg, 1, "teles3 cfg");
383 } else {
384 if (check_region((cs->hw.teles3.cfg_reg), 8)) {
385 printk(KERN_WARNING
386 "HiSax: %s config port %x-%x already in use\n",
387 CardType[card->typ],
388 cs->hw.teles3.cfg_reg,
389 cs->hw.teles3.cfg_reg + 8);
390 return (0);
391 } else
392 request_region(cs->hw.teles3.cfg_reg, 8, "teles3 cfg");
393 }
394 }
395 if (check_region((cs->hw.teles3.isac + 32), 32)) {
396 printk(KERN_WARNING
397 "HiSax: %s isac ports %x-%x already in use\n",
398 CardType[cs->typ],
399 cs->hw.teles3.isac + 32,
400 cs->hw.teles3.isac + 64);
401 if (cs->hw.teles3.cfg_reg) {
402 if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
403 release_region(cs->hw.teles3.cfg_reg, 1);
404 } else {
405 release_region(cs->hw.teles3.cfg_reg, 8);
406 }
407 }
408 return (0);
409 } else
410 request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac");
411 if (check_region((cs->hw.teles3.hscx[0] + 32), 32)) {
412 printk(KERN_WARNING
413 "HiSax: %s hscx A ports %x-%x already in use\n",
414 CardType[cs->typ],
415 cs->hw.teles3.hscx[0] + 32,
416 cs->hw.teles3.hscx[0] + 64);
417 if (cs->hw.teles3.cfg_reg) {
418 if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
419 release_region(cs->hw.teles3.cfg_reg, 1);
420 } else {
421 release_region(cs->hw.teles3.cfg_reg, 8);
422 }
423 }
424 release_ioregs(cs, 1);
425 return (0);
426 } else
427 request_region(cs->hw.teles3.hscx[0] + 32, 32, "HiSax hscx A");
428 if (check_region((cs->hw.teles3.hscx[1] + 32), 32)) {
429 printk(KERN_WARNING
430 "HiSax: %s hscx B ports %x-%x already in use\n",
431 CardType[cs->typ],
432 cs->hw.teles3.hscx[1] + 32,
433 cs->hw.teles3.hscx[1] + 64);
434 if (cs->hw.teles3.cfg_reg) {
435 if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
436 release_region(cs->hw.teles3.cfg_reg, 1);
437 } else {
438 release_region(cs->hw.teles3.cfg_reg, 8);
439 }
440 }
441 release_ioregs(cs, 3);
442 return (0);
443 } else
444 request_region(cs->hw.teles3.hscx[1] + 32, 32, "HiSax hscx B");
445 }
446 if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
447 if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) {
448 printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
449 cs->hw.teles3.cfg_reg + 0, val);
450 release_io_teles3(cs);
451 return (0);
452 }
453 if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) {
454 printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
455 cs->hw.teles3.cfg_reg + 1, val);
456 release_io_teles3(cs);
457 return (0);
458 }
459 val = bytein(cs->hw.teles3.cfg_reg + 2);/* 0x1e=without AB
460 * 0x1f=with AB
461 * 0x1c 16.3 ???
462 * 0x39 16.3 1.1
463 * 0x38 16.3 1.3
464 * 0x46 16.3 with AB + Video (Teles-Vision)
465 */
466 if (val != 0x46 && val != 0x39 && val != 0x38 && val != 0x1c && val != 0x1e && val != 0x1f) {
467 printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
468 cs->hw.teles3.cfg_reg + 2, val);
469 release_io_teles3(cs);
470 return (0);
471 }
472 }
473 printk(KERN_INFO
474 "HiSax: %s config irq:%d isac:0x%X cfg:0x%X\n",
475 CardType[cs->typ], cs->irq,
476 cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg);
477 printk(KERN_INFO
478 "HiSax: hscx A:0x%X hscx B:0x%X\n",
479 cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32);
480
481 if (reset_teles3(cs)) {
482 printk(KERN_WARNING "Teles3: wrong IRQ\n");
483 release_io_teles3(cs);
484 return (0);
485 }
486 cs->readisac = &ReadISAC;
487 cs->writeisac = &WriteISAC;
488 cs->readisacfifo = &ReadISACfifo;
489 cs->writeisacfifo = &WriteISACfifo;
490 cs->BC_Read_Reg = &ReadHSCX;
491 cs->BC_Write_Reg = &WriteHSCX;
492 cs->BC_Send_Data = &hscx_fill_fifo;
493 cs->cardmsg = &Teles_card_msg;
494 cs->irq_func = &teles3_interrupt;
495 ISACVersion(cs, "Teles3:");
496 if (HscxVersion(cs, "Teles3:")) {
497 printk(KERN_WARNING
498 "Teles3: wrong HSCX versions check IO address\n");
499 release_io_teles3(cs);
500 return (0);
501 }
502 return (1);
503 }
504