| /* $Id: teles3.c,v 2.19.2.4 2004/01/13 23:48:39 keil Exp $ | 
 |  * | 
 |  * low level stuff for Teles 16.3 & PNP isdn cards | 
 |  * | 
 |  * Author       Karsten Keil | 
 |  * Copyright    by Karsten Keil      <keil@isdn4linux.de> | 
 |  * | 
 |  * This software may be used and distributed according to the terms | 
 |  * of the GNU General Public License, incorporated herein by reference. | 
 |  * | 
 |  * Thanks to    Jan den Ouden | 
 |  *              Fritz Elfert | 
 |  *              Beat Doebeli | 
 |  * | 
 |  */ | 
 | #include <linux/init.h> | 
 | #include <linux/isapnp.h> | 
 | #include "hisax.h" | 
 | #include "isac.h" | 
 | #include "hscx.h" | 
 | #include "isdnl1.h" | 
 |  | 
 | static const char *teles3_revision = "$Revision: 2.19.2.4 $"; | 
 |  | 
 | #define byteout(addr, val) outb(val, addr) | 
 | #define bytein(addr) inb(addr) | 
 |  | 
 | static inline u_char | 
 | readreg(unsigned int adr, u_char off) | 
 | { | 
 | 	return (bytein(adr + off)); | 
 | } | 
 |  | 
 | static inline void | 
 | writereg(unsigned int adr, u_char off, u_char data) | 
 | { | 
 | 	byteout(adr + off, data); | 
 | } | 
 |  | 
 |  | 
 | static inline void | 
 | read_fifo(unsigned int adr, u_char *data, int size) | 
 | { | 
 | 	insb(adr, data, size); | 
 | } | 
 |  | 
 | static void | 
 | write_fifo(unsigned int adr, u_char *data, int size) | 
 | { | 
 | 	outsb(adr, data, size); | 
 | } | 
 |  | 
 | /* Interface functions */ | 
 |  | 
 | static u_char | 
 | ReadISAC(struct IsdnCardState *cs, u_char offset) | 
 | { | 
 | 	return (readreg(cs->hw.teles3.isac, offset)); | 
 | } | 
 |  | 
 | static void | 
 | WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) | 
 | { | 
 | 	writereg(cs->hw.teles3.isac, offset, value); | 
 | } | 
 |  | 
 | static void | 
 | ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) | 
 | { | 
 | 	read_fifo(cs->hw.teles3.isacfifo, data, size); | 
 | } | 
 |  | 
 | static void | 
 | WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) | 
 | { | 
 | 	write_fifo(cs->hw.teles3.isacfifo, data, size); | 
 | } | 
 |  | 
 | static u_char | 
 | ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) | 
 | { | 
 | 	return (readreg(cs->hw.teles3.hscx[hscx], offset)); | 
 | } | 
 |  | 
 | static void | 
 | WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) | 
 | { | 
 | 	writereg(cs->hw.teles3.hscx[hscx], offset, value); | 
 | } | 
 |  | 
 | /* | 
 |  * fast interrupt HSCX stuff goes here | 
 |  */ | 
 |  | 
 | #define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.hscx[nr], reg) | 
 | #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.hscx[nr], reg, data) | 
 | #define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt) | 
 | #define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt) | 
 |  | 
 | #include "hscx_irq.c" | 
 |  | 
 | static irqreturn_t | 
 | teles3_interrupt(int intno, void *dev_id) | 
 | { | 
 | #define MAXCOUNT 5 | 
 | 	struct IsdnCardState *cs = dev_id; | 
 | 	u_char val; | 
 | 	u_long flags; | 
 | 	int count = 0; | 
 |  | 
 | 	spin_lock_irqsave(&cs->lock, flags); | 
 | 	val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA); | 
 | Start_HSCX: | 
 | 	if (val) | 
 | 		hscx_int_main(cs, val); | 
 | 	val = readreg(cs->hw.teles3.isac, ISAC_ISTA); | 
 | Start_ISAC: | 
 | 	if (val) | 
 | 		isac_interrupt(cs, val); | 
 | 	count++; | 
 | 	val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA); | 
 | 	if (val && count < MAXCOUNT) { | 
 | 		if (cs->debug & L1_DEB_HSCX) | 
 | 			debugl1(cs, "HSCX IntStat after IntRoutine"); | 
 | 		goto Start_HSCX; | 
 | 	} | 
 | 	val = readreg(cs->hw.teles3.isac, ISAC_ISTA); | 
 | 	if (val && count < MAXCOUNT) { | 
 | 		if (cs->debug & L1_DEB_ISAC) | 
 | 			debugl1(cs, "ISAC IntStat after IntRoutine"); | 
 | 		goto Start_ISAC; | 
 | 	} | 
 | 	if (count >= MAXCOUNT) | 
 | 		printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count); | 
 | 	writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF); | 
 | 	writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF); | 
 | 	writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF); | 
 | 	writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0); | 
 | 	writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0); | 
 | 	writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0); | 
 | 	spin_unlock_irqrestore(&cs->lock, flags); | 
 | 	return IRQ_HANDLED; | 
 | } | 
 |  | 
 | static inline void | 
 | release_ioregs(struct IsdnCardState *cs, int mask) | 
 | { | 
 | 	if (mask & 1) | 
 | 		release_region(cs->hw.teles3.isac + 32, 32); | 
 | 	if (mask & 2) | 
 | 		release_region(cs->hw.teles3.hscx[0] + 32, 32); | 
 | 	if (mask & 4) | 
 | 		release_region(cs->hw.teles3.hscx[1] + 32, 32); | 
 | } | 
 |  | 
 | static void | 
 | release_io_teles3(struct IsdnCardState *cs) | 
 | { | 
 | 	if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { | 
 | 		release_region(cs->hw.teles3.hscx[1], 96); | 
 | 	} else { | 
 | 		if (cs->hw.teles3.cfg_reg) { | 
 | 			if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { | 
 | 				release_region(cs->hw.teles3.cfg_reg, 1); | 
 | 			} else { | 
 | 				release_region(cs->hw.teles3.cfg_reg, 8); | 
 | 			} | 
 | 		} | 
 | 		release_ioregs(cs, 0x7); | 
 | 	} | 
 | } | 
 |  | 
 | static int | 
 | reset_teles3(struct IsdnCardState *cs) | 
 | { | 
 | 	u_char irqcfg; | 
 |  | 
 | 	if (cs->typ != ISDN_CTYPE_TELESPCMCIA) { | 
 | 		if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) { | 
 | 			switch (cs->irq) { | 
 | 			case 2: | 
 | 			case 9: | 
 | 				irqcfg = 0x00; | 
 | 				break; | 
 | 			case 3: | 
 | 				irqcfg = 0x02; | 
 | 				break; | 
 | 			case 4: | 
 | 				irqcfg = 0x04; | 
 | 				break; | 
 | 			case 5: | 
 | 				irqcfg = 0x06; | 
 | 				break; | 
 | 			case 10: | 
 | 				irqcfg = 0x08; | 
 | 				break; | 
 | 			case 11: | 
 | 				irqcfg = 0x0A; | 
 | 				break; | 
 | 			case 12: | 
 | 				irqcfg = 0x0C; | 
 | 				break; | 
 | 			case 15: | 
 | 				irqcfg = 0x0E; | 
 | 				break; | 
 | 			default: | 
 | 				return (1); | 
 | 			} | 
 | 			byteout(cs->hw.teles3.cfg_reg + 4, irqcfg); | 
 | 			HZDELAY(HZ / 10 + 1); | 
 | 			byteout(cs->hw.teles3.cfg_reg + 4, irqcfg | 1); | 
 | 			HZDELAY(HZ / 10 + 1); | 
 | 		} else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { | 
 | 			byteout(cs->hw.teles3.cfg_reg, 0xff); | 
 | 			HZDELAY(2); | 
 | 			byteout(cs->hw.teles3.cfg_reg, 0x00); | 
 | 			HZDELAY(2); | 
 | 		} else { | 
 | 			/* Reset off for 16.3 PnP , thanks to Georg Acher */ | 
 | 			byteout(cs->hw.teles3.isac + 0x3c, 0); | 
 | 			HZDELAY(2); | 
 | 			byteout(cs->hw.teles3.isac + 0x3c, 1); | 
 | 			HZDELAY(2); | 
 | 		} | 
 | 	} | 
 | 	return (0); | 
 | } | 
 |  | 
 | static int | 
 | Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg) | 
 | { | 
 | 	u_long flags; | 
 |  | 
 | 	switch (mt) { | 
 | 	case CARD_RESET: | 
 | 		spin_lock_irqsave(&cs->lock, flags); | 
 | 		reset_teles3(cs); | 
 | 		spin_unlock_irqrestore(&cs->lock, flags); | 
 | 		return (0); | 
 | 	case CARD_RELEASE: | 
 | 		release_io_teles3(cs); | 
 | 		return (0); | 
 | 	case CARD_INIT: | 
 | 		spin_lock_irqsave(&cs->lock, flags); | 
 | 		inithscxisac(cs, 3); | 
 | 		spin_unlock_irqrestore(&cs->lock, flags); | 
 | 		return (0); | 
 | 	case CARD_TEST: | 
 | 		return (0); | 
 | 	} | 
 | 	return (0); | 
 | } | 
 |  | 
 | #ifdef __ISAPNP__ | 
 |  | 
 | static struct isapnp_device_id teles_ids[] = { | 
 | 	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110), | 
 | 	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110), | 
 | 	  (unsigned long) "Teles 16.3 PnP" }, | 
 | 	{ ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0), | 
 | 	  ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0), | 
 | 	  (unsigned long) "Creatix 16.3 PnP" }, | 
 | 	{ ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002), | 
 | 	  ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002), | 
 | 	  (unsigned long) "Compaq ISDN S0" }, | 
 | 	{ 0, } | 
 | }; | 
 |  | 
 | static struct isapnp_device_id *ipid = &teles_ids[0]; | 
 | static struct pnp_card *pnp_c = NULL; | 
 | #endif | 
 |  | 
 | int setup_teles3(struct IsdnCard *card) | 
 | { | 
 | 	u_char val; | 
 | 	struct IsdnCardState *cs = card->cs; | 
 | 	char tmp[64]; | 
 |  | 
 | 	strcpy(tmp, teles3_revision); | 
 | 	printk(KERN_INFO "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp)); | 
 | 	if ((cs->typ != ISDN_CTYPE_16_3) && (cs->typ != ISDN_CTYPE_PNP) | 
 | 	    && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) | 
 | 		return (0); | 
 |  | 
 | #ifdef __ISAPNP__ | 
 | 	if (!card->para[1] && isapnp_present()) { | 
 | 		struct pnp_dev *pnp_d; | 
 | 		while (ipid->card_vendor) { | 
 | 			if ((pnp_c = pnp_find_card(ipid->card_vendor, | 
 | 						   ipid->card_device, pnp_c))) { | 
 | 				pnp_d = NULL; | 
 | 				if ((pnp_d = pnp_find_dev(pnp_c, | 
 | 							  ipid->vendor, ipid->function, pnp_d))) { | 
 | 					int err; | 
 |  | 
 | 					printk(KERN_INFO "HiSax: %s detected\n", | 
 | 					       (char *)ipid->driver_data); | 
 | 					pnp_disable_dev(pnp_d); | 
 | 					err = pnp_activate_dev(pnp_d); | 
 | 					if (err < 0) { | 
 | 						printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", | 
 | 						       __func__, err); | 
 | 						return (0); | 
 | 					} | 
 | 					card->para[3] = pnp_port_start(pnp_d, 2); | 
 | 					card->para[2] = pnp_port_start(pnp_d, 1); | 
 | 					card->para[1] = pnp_port_start(pnp_d, 0); | 
 | 					card->para[0] = pnp_irq(pnp_d, 0); | 
 | 					if (!card->para[0] || !card->para[1] || !card->para[2]) { | 
 | 						printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n", | 
 | 						       card->para[0], card->para[1], card->para[2]); | 
 | 						pnp_disable_dev(pnp_d); | 
 | 						return (0); | 
 | 					} | 
 | 					break; | 
 | 				} else { | 
 | 					printk(KERN_ERR "Teles PnP: PnP error card found, no device\n"); | 
 | 				} | 
 | 			} | 
 | 			ipid++; | 
 | 			pnp_c = NULL; | 
 | 		} | 
 | 		if (!ipid->card_vendor) { | 
 | 			printk(KERN_INFO "Teles PnP: no ISAPnP card found\n"); | 
 | 			return (0); | 
 | 		} | 
 | 	} | 
 | #endif | 
 | 	if (cs->typ == ISDN_CTYPE_16_3) { | 
 | 		cs->hw.teles3.cfg_reg = card->para[1]; | 
 | 		switch (cs->hw.teles3.cfg_reg) { | 
 | 		case 0x180: | 
 | 		case 0x280: | 
 | 		case 0x380: | 
 | 			cs->hw.teles3.cfg_reg |= 0xc00; | 
 | 			break; | 
 | 		} | 
 | 		cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420; | 
 | 		cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20; | 
 | 		cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820; | 
 | 	} else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { | 
 | 		cs->hw.teles3.cfg_reg = 0; | 
 | 		cs->hw.teles3.hscx[0] = card->para[1] - 0x20; | 
 | 		cs->hw.teles3.hscx[1] = card->para[1]; | 
 | 		cs->hw.teles3.isac = card->para[1] + 0x20; | 
 | 	} else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { | 
 | 		cs->hw.teles3.cfg_reg = card->para[3]; | 
 | 		cs->hw.teles3.isac = card->para[2] - 32; | 
 | 		cs->hw.teles3.hscx[0] = card->para[1] - 32; | 
 | 		cs->hw.teles3.hscx[1] = card->para[1]; | 
 | 	} else {	/* PNP */ | 
 | 		cs->hw.teles3.cfg_reg = 0; | 
 | 		cs->hw.teles3.isac = card->para[1] - 32; | 
 | 		cs->hw.teles3.hscx[0] = card->para[2] - 32; | 
 | 		cs->hw.teles3.hscx[1] = card->para[2]; | 
 | 	} | 
 | 	cs->irq = card->para[0]; | 
 | 	cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e; | 
 | 	cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e; | 
 | 	cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e; | 
 | 	if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { | 
 | 		if (!request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA")) { | 
 | 			printk(KERN_WARNING | 
 | 			       "HiSax: %s ports %x-%x already in use\n", | 
 | 			       CardType[cs->typ], | 
 | 			       cs->hw.teles3.hscx[1], | 
 | 			       cs->hw.teles3.hscx[1] + 96); | 
 | 			return (0); | 
 | 		} | 
 | 		cs->irq_flags |= IRQF_SHARED; /* cardbus can share */ | 
 | 	} else { | 
 | 		if (cs->hw.teles3.cfg_reg) { | 
 | 			if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { | 
 | 				if (!request_region(cs->hw.teles3.cfg_reg, 1, "teles3 cfg")) { | 
 | 					printk(KERN_WARNING | 
 | 					       "HiSax: %s config port %x already in use\n", | 
 | 					       CardType[card->typ], | 
 | 					       cs->hw.teles3.cfg_reg); | 
 | 					return (0); | 
 | 				} | 
 | 			} else { | 
 | 				if (!request_region(cs->hw.teles3.cfg_reg, 8, "teles3 cfg")) { | 
 | 					printk(KERN_WARNING | 
 | 					       "HiSax: %s config port %x-%x already in use\n", | 
 | 					       CardType[card->typ], | 
 | 					       cs->hw.teles3.cfg_reg, | 
 | 					       cs->hw.teles3.cfg_reg + 8); | 
 | 					return (0); | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 		if (!request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac")) { | 
 | 			printk(KERN_WARNING | 
 | 			       "HiSax: %s isac ports %x-%x already in use\n", | 
 | 			       CardType[cs->typ], | 
 | 			       cs->hw.teles3.isac + 32, | 
 | 			       cs->hw.teles3.isac + 64); | 
 | 			if (cs->hw.teles3.cfg_reg) { | 
 | 				if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { | 
 | 					release_region(cs->hw.teles3.cfg_reg, 1); | 
 | 				} else { | 
 | 					release_region(cs->hw.teles3.cfg_reg, 8); | 
 | 				} | 
 | 			} | 
 | 			return (0); | 
 | 		} | 
 | 		if (!request_region(cs->hw.teles3.hscx[0] + 32, 32, "HiSax hscx A")) { | 
 | 			printk(KERN_WARNING | 
 | 			       "HiSax: %s hscx A ports %x-%x already in use\n", | 
 | 			       CardType[cs->typ], | 
 | 			       cs->hw.teles3.hscx[0] + 32, | 
 | 			       cs->hw.teles3.hscx[0] + 64); | 
 | 			if (cs->hw.teles3.cfg_reg) { | 
 | 				if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { | 
 | 					release_region(cs->hw.teles3.cfg_reg, 1); | 
 | 				} else { | 
 | 					release_region(cs->hw.teles3.cfg_reg, 8); | 
 | 				} | 
 | 			} | 
 | 			release_ioregs(cs, 1); | 
 | 			return (0); | 
 | 		} | 
 | 		if (!request_region(cs->hw.teles3.hscx[1] + 32, 32, "HiSax hscx B")) { | 
 | 			printk(KERN_WARNING | 
 | 			       "HiSax: %s hscx B ports %x-%x already in use\n", | 
 | 			       CardType[cs->typ], | 
 | 			       cs->hw.teles3.hscx[1] + 32, | 
 | 			       cs->hw.teles3.hscx[1] + 64); | 
 | 			if (cs->hw.teles3.cfg_reg) { | 
 | 				if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { | 
 | 					release_region(cs->hw.teles3.cfg_reg, 1); | 
 | 				} else { | 
 | 					release_region(cs->hw.teles3.cfg_reg, 8); | 
 | 				} | 
 | 			} | 
 | 			release_ioregs(cs, 3); | 
 | 			return (0); | 
 | 		} | 
 | 	} | 
 | 	if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) { | 
 | 		if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) { | 
 | 			printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", | 
 | 			       cs->hw.teles3.cfg_reg + 0, val); | 
 | 			release_io_teles3(cs); | 
 | 			return (0); | 
 | 		} | 
 | 		if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) { | 
 | 			printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", | 
 | 			       cs->hw.teles3.cfg_reg + 1, val); | 
 | 			release_io_teles3(cs); | 
 | 			return (0); | 
 | 		} | 
 | 		val = bytein(cs->hw.teles3.cfg_reg + 2);/* 0x1e=without AB | 
 | 							 * 0x1f=with AB | 
 | 							 * 0x1c 16.3 ??? | 
 | 							 * 0x39 16.3 1.1 | 
 | 							 * 0x38 16.3 1.3 | 
 | 							 * 0x46 16.3 with AB + Video (Teles-Vision) | 
 | 							 */ | 
 | 		if (val != 0x46 && val != 0x39 && val != 0x38 && val != 0x1c && val != 0x1e && val != 0x1f) { | 
 | 			printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", | 
 | 			       cs->hw.teles3.cfg_reg + 2, val); | 
 | 			release_io_teles3(cs); | 
 | 			return (0); | 
 | 		} | 
 | 	} | 
 | 	printk(KERN_INFO | 
 | 	       "HiSax: %s config irq:%d isac:0x%X  cfg:0x%X\n", | 
 | 	       CardType[cs->typ], cs->irq, | 
 | 	       cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg); | 
 | 	printk(KERN_INFO | 
 | 	       "HiSax: hscx A:0x%X  hscx B:0x%X\n", | 
 | 	       cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32); | 
 |  | 
 | 	setup_isac(cs); | 
 | 	if (reset_teles3(cs)) { | 
 | 		printk(KERN_WARNING "Teles3: wrong IRQ\n"); | 
 | 		release_io_teles3(cs); | 
 | 		return (0); | 
 | 	} | 
 | 	cs->readisac = &ReadISAC; | 
 | 	cs->writeisac = &WriteISAC; | 
 | 	cs->readisacfifo = &ReadISACfifo; | 
 | 	cs->writeisacfifo = &WriteISACfifo; | 
 | 	cs->BC_Read_Reg = &ReadHSCX; | 
 | 	cs->BC_Write_Reg = &WriteHSCX; | 
 | 	cs->BC_Send_Data = &hscx_fill_fifo; | 
 | 	cs->cardmsg = &Teles_card_msg; | 
 | 	cs->irq_func = &teles3_interrupt; | 
 | 	ISACVersion(cs, "Teles3:"); | 
 | 	if (HscxVersion(cs, "Teles3:")) { | 
 | 		printk(KERN_WARNING | 
 | 		       "Teles3: wrong HSCX versions check IO address\n"); | 
 | 		release_io_teles3(cs); | 
 | 		return (0); | 
 | 	} | 
 | 	return (1); | 
 | } |