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