patch-2.3.4 linux/drivers/isdn/hisax/config.c

Next file: linux/drivers/isdn/hisax/diva.c
Previous file: linux/drivers/isdn/hisax/cert.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.3/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c
@@ -1,10 +1,50 @@
-/* $Id: config.c,v 2.12 1998/02/11 17:28:02 keil Exp $
+/* $Id: config.c,v 2.23 1999/02/17 10:53:02 cpetig Exp $
 
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
  *
  * $Log: config.c,v $
+ * Revision 2.23  1999/02/17 10:53:02  cpetig
+ * Added Hisax_closecard to exported symbols.
+ * As indicated by Oliver Schoett <os@sdm.de>.
+ *
+ * If anyone is annoyed by exporting symbols deep inside the code, please
+ * contact me.
+ *
+ * Revision 2.22  1999/02/04 21:41:53  keil
+ * Fix printk msg
+ *
+ * Revision 2.21  1999/02/04 10:48:52  keil
+ * Fix readstat bug
+ *
+ * Revision 2.20  1998/11/15 23:54:28  keil
+ * changes from 2.0
+ *
+ * Revision 2.19  1998/08/13 23:36:18  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 2.18  1998/07/30 21:01:37  niemann
+ * Fixed Sedlbauer Speed Fax PCMCIA missing isdnl3new
+ *
+ * Revision 2.17  1998/07/15 15:01:26  calle
+ * Support for AVM passive PCMCIA cards:
+ *    A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0
+ *
+ * Revision 2.16  1998/05/25 14:10:03  keil
+ * HiSax 3.0
+ * X.75 and leased are working again.
+ *
+ * Revision 2.15  1998/05/25 12:57:43  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 2.14  1998/04/15 16:38:25  keil
+ * Add S0Box and Teles PCI support
+ *
+ * Revision 2.13  1998/03/09 23:19:23  keil
+ * Changes for PCMCIA
+ *
  * Revision 2.12  1998/02/11 17:28:02  keil
  * Niccy PnP/PCI support
  *
@@ -55,6 +95,12 @@
 #include <linux/timer.h>
 #include <linux/config.h>
 #include "hisax.h"
+#include <linux/module.h>
+#include <linux/kernel_stat.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#define HISAX_STATUS_BUFSIZE 4096
+#define INCLUDE_INLINE_FUNCS
 
 /*
  * This structure array contains one entry per card. An entry looks
@@ -78,42 +124,78 @@
  *   13 Teleint          p0=irq p1=iobase
  *   14 Teles 16.3c      p0=irq p1=iobase
  *   15 Sedlbauer speed  p0=irq p1=iobase
+ *   15 Sedlbauer PC/104	p0=irq p1=iobase
+ *   15 Sedlbauer speed pci	no parameter
  *   16 USR Sportster internal  p0=irq  p1=iobase
  *   17 MIC card                p0=irq  p1=iobase
  *   18 ELSA Quickstep 1000PCI  no parameter
  *   19 Compaq ISDN S0 ISA card p0=irq  p1=IO0 (HSCX)  p2=IO1 (ISAC) p3=IO2
  *   20 Travers Technologies NETjet PCI card
- *   21 reserved TELES PCI
+ *   21 TELES PCI               no parameter
  *   22 Sedlbauer Speed Star    p0=irq p1=iobase
  *   23 reserved
  *   24 Dr Neuhaus Niccy PnP/PCI card p0=irq p1=IO0 p2=IO1 (PnP only)
- *
+ *   25 Teles S0Box             p0=irq p1=iobase (from isapnp setup)
+ *   26 AVM A1 PCMCIA (Fritz)   p0=irq p1=iobase
+ *   27 AVM PnP/PCI 		p0=irq p1=iobase (PCI no parameter)
+ *   28 Sedlbauer Speed Fax+ 	p0=irq p1=iobase (from isapnp setup)
  *
  * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
  *
  *
  */
 
+const char *CardType[] =
+{"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", "Creatix/Teles PnP",
+ "AVM A1", "Elsa ML", "Elsa Quickstep", "Teles PCMCIA", "ITK ix1-micro Rev.2",
+ "Elsa PCMCIA", "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c",
+ "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI",
+ "Compaq ISA", "NETjet", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)",
+ "AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI",
+ "Sedlbauer Speed Fax +"
+};
+
 #ifdef CONFIG_HISAX_ELSA
 #define DEFAULT_CARD ISDN_CTYPE_ELSA
 #define DEFAULT_CFG {0,0,0,0}
-#ifdef MODULE
 int elsa_init_pcmcia(void*, int, int*, int);
 EXPORT_SYMBOL(elsa_init_pcmcia);
 #endif
-#endif
 #ifdef CONFIG_HISAX_AVM_A1
 #undef DEFAULT_CARD
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_A1
 #define DEFAULT_CFG {10,0x340,0,0}
 #endif
+
+#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA
+#define DEFAULT_CFG {11,0x170,0,0}
+int avm_a1_init_pcmcia(void*, int, int*, int);
+EXPORT_SYMBOL(avm_a1_init_pcmcia);
+#endif
+
+#ifdef CONFIG_HISAX_FRITZPCI
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_FRITZPCI
+#define DEFAULT_CFG {0,0,0,0}
+#endif
+
 #ifdef CONFIG_HISAX_16_3
 #undef DEFAULT_CARD
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_16_3
 #define DEFAULT_CFG {15,0x180,0,0}
 #endif
+#ifdef CONFIG_HISAX_S0BOX
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_S0BOX
+#define DEFAULT_CFG {7,0x378,0,0}
+#endif
 #ifdef CONFIG_HISAX_16_0
 #undef DEFAULT_CARD
 #undef DEFAULT_CFG
@@ -121,6 +203,13 @@
 #define DEFAULT_CFG {15,0xd0000,0xd80,0}
 #endif
 
+#ifdef CONFIG_HISAX_TELESPCI
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_TELESPCI
+#define DEFAULT_CFG {0,0,0,0}
+#endif
+
 #ifdef CONFIG_HISAX_IX1MICROR2
 #undef DEFAULT_CARD
 #undef DEFAULT_CFG
@@ -193,13 +282,6 @@
 #define DEFAULT_CFG {12,0x3e0,0,0}
 #endif
 
-#ifdef CONFIG_HISAX_DBRI
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_DBRI
-#define DEFAULT_CFG {0,0x0,0,0}
-#endif
-
 #ifdef CONFIG_HISAX_NICCY
 #undef DEFAULT_CARD
 #undef DEFAULT_CFG
@@ -232,10 +314,10 @@
 #endif
 
 #define FIRST_CARD { \
-  DEFAULT_CARD, \
-  DEFAULT_PROTO, \
-  DEFAULT_CFG, \
-  NULL, \
+	DEFAULT_CARD, \
+	DEFAULT_PROTO, \
+	DEFAULT_CFG, \
+	NULL, \
 }
 
 #define EMPTY_CARD	{0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL}
@@ -250,29 +332,20 @@
 	EMPTY_CARD,
 	EMPTY_CARD,
 	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
-	EMPTY_CARD,
 };
 
-static char HiSaxID[96] HISAX_INITDATA = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
-"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
+static char HiSaxID[64] HISAX_INITDATA = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
-"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
 char *HiSax_id HISAX_INITDATA = HiSaxID;
 #ifdef MODULE
 /* Variables for insmod */
 static int type[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+{0, 0, 0, 0, 0, 0, 0, 0};
 static int protocol[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+{0, 0, 0, 0, 0, 0, 0, 0};
 static int io[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+{0, 0, 0, 0, 0, 0, 0, 0};
 #undef IO0_IO1
 #ifdef CONFIG_HISAX_16_3
 #define IO0_IO1
@@ -283,29 +356,29 @@
 #endif
 #ifdef IO0_IO1
 static int io0[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+{0, 0, 0, 0, 0, 0, 0, 0};
 static int io1[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+{0, 0, 0, 0, 0, 0, 0, 0};
 #endif
 static int irq[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+{0, 0, 0, 0, 0, 0, 0, 0};
 static int mem[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+{0, 0, 0, 0, 0, 0, 0, 0};
 static char *id HISAX_INITDATA = HiSaxID;
 
 MODULE_AUTHOR("Karsten Keil");
-MODULE_PARM(type, "1-3i");
-MODULE_PARM(protocol, "1-2i");
+MODULE_PARM(type, "1-8i");
+MODULE_PARM(protocol, "1-8i");
 MODULE_PARM(io, "1-8i");
-MODULE_PARM(irq, "1-2i");
-MODULE_PARM(mem, "1-12i");
+MODULE_PARM(irq, "1-8i");
+MODULE_PARM(mem, "1-8i");
 MODULE_PARM(id, "s");
 #ifdef CONFIG_HISAX_16_3	/* For Creatix/Teles PnP */
 MODULE_PARM(io0, "1-8i");
 MODULE_PARM(io1, "1-8i");
-#endif
+#endif /* CONFIG_HISAX_16_3 */
 
-#endif
+#endif /* MODULE */
 
 int nrcards;
 
@@ -333,23 +406,25 @@
 HISAX_INITFUNC(void
 HiSaxVersion(void))
 {
-	char tmp[64], rev[64];
-	char *r = rev;
+	char tmp[64];
 
+	printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n");
+#ifdef MODULE
+	printk(KERN_INFO "HiSax: Version 3.1a (module)\n");
+#else
+	printk(KERN_INFO "HiSax: Version 3.1a (kernel)\n");
+#endif
 	strcpy(tmp, l1_revision);
-	r += sprintf(r, "%s/", HiSax_getrev(tmp));
+	printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp));
 	strcpy(tmp, l2_revision);
-	r += sprintf(r, "%s/", HiSax_getrev(tmp));
+	printk(KERN_INFO "HiSax: Layer2 Revision %s\n", HiSax_getrev(tmp));
+	strcpy(tmp, tei_revision);
+	printk(KERN_INFO "HiSax: TeiMgr Revision %s\n", HiSax_getrev(tmp));
 	strcpy(tmp, l3_revision);
-	r += sprintf(r, "%s/", HiSax_getrev(tmp));
+	printk(KERN_INFO "HiSax: Layer3 Revision %s\n", HiSax_getrev(tmp));
 	strcpy(tmp, lli_revision);
-	r += sprintf(r, "%s/", HiSax_getrev(tmp));
-	strcpy(tmp, tei_revision);
-	r += sprintf(r, "%s", HiSax_getrev(tmp));
-
-	printk(KERN_INFO "HiSax: Driver for Siemens chip set ISDN cards\n");
-	printk(KERN_INFO "HiSax: Version 2.8\n");
-	printk(KERN_INFO "HiSax: Revisions %s\n", rev);
+	printk(KERN_INFO "HiSax: LinkLayer Revision %s\n", HiSax_getrev(tmp));
+	certification_check(1);
 }
 
 void
@@ -375,7 +450,7 @@
 	argc = ints[0];
 	i = 0;
 	j = 1;
-	while (argc && (i < 16)) {
+	while (argc && (i < HISAX_MAX_CARDS)) {
 		if (argc) {
 			cards[i].typ = ints[j];
 			j++;
@@ -413,11 +488,759 @@
 }
 #endif
 
+#if CARD_TELES0
+extern int setup_teles0(struct IsdnCard *card);
+#endif
+
+#if CARD_TELES3
+extern int setup_teles3(struct IsdnCard *card);
+#endif
+
+#if CARD_S0BOX
+extern int setup_s0box(struct IsdnCard *card);
+#endif
+
+#if CARD_TELESPCI
+extern int setup_telespci(struct IsdnCard *card);
+#endif
+
+#if CARD_AVM_A1
+extern int setup_avm_a1(struct IsdnCard *card);
+#endif
+
+#if CARD_AVM_A1_PCMCIA
+extern int setup_avm_a1_pcmcia(struct IsdnCard *card);
+#endif
+
+#if CARD_FRITZPCI
+extern int setup_avm_pcipnp(struct IsdnCard *card);
+#endif
+
+#if CARD_ELSA
+extern int setup_elsa(struct IsdnCard *card);
+#endif
+
+#if CARD_IX1MICROR2
+extern int setup_ix1micro(struct IsdnCard *card);
+#endif
+
+#if CARD_DIEHLDIVA
+extern	int  setup_diva(struct IsdnCard *card);
+#endif
+
+#if CARD_ASUSCOM
+extern int setup_asuscom(struct IsdnCard *card);
+#endif
+
+#if CARD_TELEINT
+extern int setup_TeleInt(struct IsdnCard *card);
+#endif
+
+#if CARD_SEDLBAUER
+extern int setup_sedlbauer(struct IsdnCard *card);
+#endif
+
+#if CARD_SPORTSTER
+extern int setup_sportster(struct IsdnCard *card);
+#endif
+
+#if CARD_MIC
+extern int setup_mic(struct IsdnCard *card);
+#endif
+
+#if CARD_NETJET
+extern int setup_netjet(struct IsdnCard *card);
+#endif
+
+#if CARD_TELES3C
+extern int setup_t163c(struct IsdnCard *card);
+#endif
+
+#if CARD_AMD7930
+extern int setup_amd7930(struct IsdnCard *card);
+#endif
+
+#if CARD_NICCY
+extern int setup_niccy(struct IsdnCard *card);
+#endif
+
+/*
+ * Find card with given driverId
+ */
+static inline struct IsdnCardState
+*hisax_findcard(int driverid)
+{
+	int i;
+
+	for (i = 0; i < nrcards; i++)
+		if (cards[i].cs)
+			if (cards[i].cs->myid == driverid)
+				return (cards[i].cs);
+	return (NULL);
+}
+
+int
+HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
+{
+	int count,cnt;
+	u_char *p = buf;
+	struct IsdnCardState *cs = hisax_findcard(id);
+
+	if (cs) {
+		if (len > HISAX_STATUS_BUFSIZE) {
+			printk(KERN_WARNING "HiSax: status overflow readstat %d/%d\n",
+				len, HISAX_STATUS_BUFSIZE);
+		}
+		count = cs->status_end - cs->status_read +1;
+		if (count >= len)
+			count = len;
+		if (user)
+			copy_to_user(p, cs->status_read, count);
+		else
+			memcpy(p, cs->status_read, count);
+		cs->status_read += count;
+		if (cs->status_read > cs->status_end)
+			cs->status_read = cs->status_buf;
+		p += count;
+		count = len - count;
+		while (count) {
+			if (count > HISAX_STATUS_BUFSIZE)
+				cnt = HISAX_STATUS_BUFSIZE;
+			else
+				cnt = count;
+			if (user)
+				copy_to_user(p, cs->status_read, cnt);
+			else
+				memcpy(p, cs->status_read, cnt);
+			p += cnt;
+			cs->status_read += cnt % HISAX_STATUS_BUFSIZE;
+			count -= cnt;
+		}
+		return len;
+	} else {
+		printk(KERN_ERR
+		 "HiSax: if_readstatus called with invalid driverId!\n");
+		return -ENODEV;
+	}
+}
+
+inline int
+jiftime(char *s, long mark)
+{
+	s += 8;
+
+	*s-- = '\0';
+	*s-- = mark % 10 + '0';
+	mark /= 10;
+	*s-- = mark % 10 + '0';
+	mark /= 10;
+	*s-- = '.';
+	*s-- = mark % 10 + '0';
+	mark /= 10;
+	*s-- = mark % 6 + '0';
+	mark /= 6;
+	*s-- = ':';
+	*s-- = mark % 10 + '0';
+	mark /= 10;
+	*s-- = mark % 10 + '0';
+	return(8);
+}
+
+static u_char tmpbuf[HISAX_STATUS_BUFSIZE];
+
+void
+VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args)
+{
+/* if head == NULL the fmt contains the full info */
+
+	long flags;
+	int count, i;
+	u_char *p;
+	isdn_ctrl ic;
+	int len;
+
+	save_flags(flags);
+	cli();
+	p = tmpbuf;
+	if (head) {
+		p += jiftime(p, jiffies);
+		p += sprintf(p, " %s", head);
+		p += vsprintf(p, fmt, args);
+		*p++ = '\n';
+		*p = 0;
+		len = p - tmpbuf;
+		p = tmpbuf;
+	} else {
+		p = fmt;
+		len = strlen(fmt);
+	}
+	if (!cs) {
+		printk(KERN_WARNING "HiSax: No CardStatus for message %s", p);
+		restore_flags(flags);
+		return;
+	}
+	if (len > HISAX_STATUS_BUFSIZE) {
+		printk(KERN_WARNING "HiSax: status overflow %d/%d\n",
+			len, HISAX_STATUS_BUFSIZE);
+		restore_flags(flags);
+		return;
+	}
+	count = len;
+	i = cs->status_end - cs->status_write +1;
+	if (i >= len)
+		i = len;
+	len -= i;
+	memcpy(cs->status_write, p, i);
+	cs->status_write += i;
+	if (cs->status_write > cs->status_end)
+		cs->status_write = cs->status_buf;
+	p += i;
+	if (len) {
+		memcpy(cs->status_write, p, len);
+		cs->status_write += len;
+	}
+#ifdef KERNELSTACK_DEBUG
+	i = (ulong)&len - current->kernel_stack_page;
+	sprintf(tmpbuf, "kstack %s %lx use %ld\n", current->comm,
+		current->kernel_stack_page, i);
+	len = strlen(tmpbuf);
+	for (p = tmpbuf, i = len; i > 0; i--, p++) {
+		*cs->status_write++ = *p;
+		if (cs->status_write > cs->status_end)
+			cs->status_write = cs->status_buf;
+		count++;
+	}
+#endif
+	restore_flags(flags);
+	if (count) {
+		ic.command = ISDN_STAT_STAVAIL;
+		ic.driver = cs->myid;
+		ic.arg = count;
+		cs->iif.statcallb(&ic);
+	}
+}
+
+void
+HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	VHiSax_putstatus(cs, head, fmt, args);
+	va_end(args);
+}
+
+int
+ll_run(struct IsdnCardState *cs)
+{
+	long flags;
+	isdn_ctrl ic;
+
+	save_flags(flags);
+	cli();
+	ic.driver = cs->myid;
+	ic.command = ISDN_STAT_RUN;
+	cs->iif.statcallb(&ic);
+	restore_flags(flags);
+	return 0;
+}
+
+void
+ll_stop(struct IsdnCardState *cs)
+{
+	isdn_ctrl ic;
+
+	ic.command = ISDN_STAT_STOP;
+	ic.driver = cs->myid;
+	cs->iif.statcallb(&ic);
+	CallcFreeChan(cs);
+}
+
+static void
+ll_unload(struct IsdnCardState *cs)
+{
+	isdn_ctrl ic;
+
+	ic.command = ISDN_STAT_UNLOAD;
+	ic.driver = cs->myid;
+	cs->iif.statcallb(&ic);
+	if (cs->status_buf)
+		kfree(cs->status_buf);
+	cs->status_read = NULL;
+	cs->status_write = NULL;
+	cs->status_end = NULL;
+	kfree(cs->dlog);
+}
+
+static void
+closecard(int cardnr)
+{
+	struct IsdnCardState *csta = cards[cardnr].cs;
+
+	if (csta->bcs->BC_Close != NULL) {
+		csta->bcs->BC_Close(csta->bcs + 1);
+		csta->bcs->BC_Close(csta->bcs);
+	}
+
+	if (csta->rcvbuf) {
+		kfree(csta->rcvbuf);
+		csta->rcvbuf = NULL;
+	}
+	discard_queue(&csta->rq);
+	discard_queue(&csta->sq);
+	if (csta->tx_skb) {
+		dev_kfree_skb(csta->tx_skb);
+		csta->tx_skb = NULL;
+	}
+	if (csta->mon_rx) {
+		kfree(csta->mon_rx);
+		csta->mon_rx = NULL;
+	}
+	if (csta->mon_tx) {
+		kfree(csta->mon_tx);
+		csta->mon_tx = NULL;
+	}
+	csta->cardmsg(csta, CARD_RELEASE, NULL);
+	if (csta->dbusytimer.function != NULL)
+		del_timer(&csta->dbusytimer);
+	ll_unload(csta);
+}
+
+HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs))
+{
+	int irq_cnt, cnt = 3;
+	long flags;
+
+	save_flags(flags);
+	cli();
+	irq_cnt = kstat_irqs(cs->irq);
+	printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq,
+		irq_cnt);
+	if (cs->cardmsg(cs, CARD_SETIRQ, NULL)) {
+		printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
+			cs->irq);
+		restore_flags(flags);
+		return(1);
+	}
+	while (cnt) {
+		cs->cardmsg(cs, CARD_INIT, NULL);
+		sti();
+		current->state = TASK_INTERRUPTIBLE;
+		/* Timeout 10ms */
+		schedule_timeout((10 * HZ) / 1000);
+		restore_flags(flags);
+		printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
+			cs->irq, kstat_irqs(cs->irq));
+		if (kstat_irqs(cs->irq) == irq_cnt) {
+			printk(KERN_WARNING
+			       "%s: IRQ(%d) getting no interrupts during init %d\n",
+			       CardType[cs->typ], cs->irq, 4 - cnt);
+			if (cnt == 1) {
+				free_irq(cs->irq, cs);
+				return (2);
+			} else {
+				cs->cardmsg(cs, CARD_RESET, NULL);
+				cnt--;
+			}
+		} else {
+			cs->cardmsg(cs, CARD_TEST, NULL);
+			return(0);
+		}
+	}
+	restore_flags(flags);
+	return(3);
+}
+
+HISAX_INITFUNC(static int
+checkcard(int cardnr, char *id, int *busy_flag))
+{
+	long flags;
+	int ret = 0;
+	struct IsdnCard *card = cards + cardnr;
+	struct IsdnCardState *cs;
+
+	save_flags(flags);
+	cli();
+	if (!(cs = (struct IsdnCardState *)
+		kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) {
+		printk(KERN_WARNING
+		       "HiSax: No memory for IsdnCardState(card %d)\n",
+		       cardnr + 1);
+		restore_flags(flags);
+		return (0);
+	}
+	memset(cs, 0, sizeof(struct IsdnCardState));
+	card->cs = cs;
+	cs->cardnr = cardnr;
+	cs->debug = L1_DEB_WARN;
+	cs->HW_Flags = 0;
+	cs->busy_flag = busy_flag;
+#if TEI_PER_CARD
+#else
+	test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
+#endif
+	cs->protocol = card->protocol;
+
+	if ((card->typ > 0) && (card->typ < 31)) {
+		if (!((1 << card->typ) & SUPORTED_CARDS)) {
+			printk(KERN_WARNING
+			     "HiSax: Support for %s Card not selected\n",
+			       CardType[card->typ]);
+			restore_flags(flags);
+			return (0);
+		}
+	} else {
+		printk(KERN_WARNING
+		       "HiSax: Card Type %d out of range\n",
+		       card->typ);
+		restore_flags(flags);
+		return (0);
+	}
+	if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
+		printk(KERN_WARNING
+		       "HiSax: No memory for dlog(card %d)\n",
+		       cardnr + 1);
+		restore_flags(flags);
+		return (0);
+	}
+	if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
+		printk(KERN_WARNING
+		       "HiSax: No memory for status_buf(card %d)\n",
+		       cardnr + 1);
+		kfree(cs->dlog);
+		restore_flags(flags);
+		return (0);
+	}
+	cs->stlist = NULL;
+	cs->mon_tx = NULL;
+	cs->mon_rx = NULL;
+	cs->status_read = cs->status_buf;
+	cs->status_write = cs->status_buf;
+	cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
+	cs->typ = card->typ;
+	strcpy(cs->iif.id, id);
+	cs->iif.channels = 2;
+	cs->iif.maxbufsize = MAX_DATA_SIZE;
+	cs->iif.hl_hdrlen = MAX_HEADER_LEN;
+	cs->iif.features =
+	    ISDN_FEATURE_L2_X75I |
+	    ISDN_FEATURE_L2_HDLC |
+	    ISDN_FEATURE_L2_MODEM |
+	    ISDN_FEATURE_L2_TRANS |
+	    ISDN_FEATURE_L3_TRANS |
+#ifdef	CONFIG_HISAX_1TR6
+	    ISDN_FEATURE_P_1TR6 |
+#endif
+#ifdef	CONFIG_HISAX_EURO
+	    ISDN_FEATURE_P_EURO |
+#endif
+#ifdef        CONFIG_HISAX_NI1
+	    ISDN_FEATURE_P_NI1 |
+#endif
+	    0;
+
+	cs->iif.command = HiSax_command;
+	cs->iif.writecmd = NULL;
+	cs->iif.writebuf_skb = HiSax_writebuf_skb;
+	cs->iif.readstat = HiSax_readstatus;
+	register_isdn(&cs->iif);
+	cs->myid = cs->iif.channels;
+	printk(KERN_INFO
+	       "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
+	       (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
+	       (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
+	       (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
+	       (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
+	       "NONE", cs->iif.id, cs->myid);
+	switch (card->typ) {
+#if CARD_TELES0
+		case ISDN_CTYPE_16_0:
+		case ISDN_CTYPE_8_0:
+			ret = setup_teles0(card);
+			break;
+#endif
+#if CARD_TELES3
+		case ISDN_CTYPE_16_3:
+		case ISDN_CTYPE_PNP:
+		case ISDN_CTYPE_TELESPCMCIA:
+		case ISDN_CTYPE_COMPAQ_ISA:
+			ret = setup_teles3(card);
+			break;
+#endif
+#if CARD_S0BOX
+		case ISDN_CTYPE_S0BOX:
+			ret = setup_s0box(card);
+			break;
+#endif
+#if CARD_TELESPCI
+		case ISDN_CTYPE_TELESPCI:
+			ret = setup_telespci(card);
+			break;
+#endif
+#if CARD_AVM_A1
+		case ISDN_CTYPE_A1:
+			ret = setup_avm_a1(card);
+			break;
+#endif
+#if CARD_AVM_A1_PCMCIA
+		case ISDN_CTYPE_A1_PCMCIA:
+			ret = setup_avm_a1_pcmcia(card);
+			break;
+#endif
+#if CARD_FRITZPCI
+		case ISDN_CTYPE_FRITZPCI:
+			ret = setup_avm_pcipnp(card);
+			break;
+#endif
+#if CARD_ELSA
+		case ISDN_CTYPE_ELSA:
+		case ISDN_CTYPE_ELSA_PNP:
+		case ISDN_CTYPE_ELSA_PCMCIA:
+		case ISDN_CTYPE_ELSA_PCI:
+			ret = setup_elsa(card);
+			break;
+#endif
+#if CARD_IX1MICROR2
+		case ISDN_CTYPE_IX1MICROR2:
+			ret = setup_ix1micro(card);
+			break;
+#endif
+#if CARD_DIEHLDIVA
+		case ISDN_CTYPE_DIEHLDIVA:
+			ret = setup_diva(card);
+			break;
+#endif
+#if CARD_ASUSCOM
+		case ISDN_CTYPE_ASUSCOM:
+			ret = setup_asuscom(card);
+			break;
+#endif
+#if CARD_TELEINT
+		case ISDN_CTYPE_TELEINT:
+			ret = setup_TeleInt(card);
+			break;
+#endif
+#if CARD_SEDLBAUER
+		case ISDN_CTYPE_SEDLBAUER:
+		case ISDN_CTYPE_SEDLBAUER_PCMCIA:
+		case ISDN_CTYPE_SEDLBAUER_FAX:
+			ret = setup_sedlbauer(card);
+			break;
+#endif
+#if CARD_SPORTSTER
+		case ISDN_CTYPE_SPORTSTER:
+			ret = setup_sportster(card);
+			break;
+#endif
+#if CARD_MIC
+		case ISDN_CTYPE_MIC:
+			ret = setup_mic(card);
+			break;
+#endif
+#if CARD_NETJET
+		case ISDN_CTYPE_NETJET:
+			ret = setup_netjet(card);
+			break;
+#endif
+#if CARD_TELES3C
+		case ISDN_CTYPE_TELES3C:
+			ret = setup_t163c(card);
+			break;
+#endif
+#if CARD_NICCY
+		case ISDN_CTYPE_NICCY:
+			ret = setup_niccy(card);
+			break;
+#endif
+#if CARD_AMD7930
+		case ISDN_CTYPE_AMD7930:
+			ret = setup_amd7930(card);
+			break;
+#endif
+		default:
+			printk(KERN_WARNING "HiSax: Unknown Card Typ %d\n",
+			       card->typ);
+			ll_unload(cs);
+			restore_flags(flags);
+			return (0);
+	}
+	if (!ret) {
+		ll_unload(cs);
+		restore_flags(flags);
+		return (0);
+	}
+	if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
+		printk(KERN_WARNING
+		       "HiSax: No memory for isac rcvbuf\n");
+		return (1);
+	}
+	cs->rcvidx = 0;
+	cs->tx_skb = NULL;
+	cs->tx_cnt = 0;
+	cs->event = 0;
+	cs->tqueue.next = 0;
+	cs->tqueue.sync = 0;
+	cs->tqueue.data = cs;
+
+	skb_queue_head_init(&cs->rq);
+	skb_queue_head_init(&cs->sq);
+
+	init_bcstate(cs, 0);
+	init_bcstate(cs, 1);
+	ret = init_card(cs);
+	if (ret) {
+		closecard(cardnr);
+		restore_flags(flags);
+		return (0);
+	}
+	init_tei(cs, cs->protocol);
+	CallcNewChan(cs);
+	/* ISAR needs firmware download first */
+	if (!test_bit(HW_ISAR, &cs->HW_Flags))
+		ll_run(cs);
+	restore_flags(flags);
+	return (1);
+}
+
+HISAX_INITFUNC(void
+HiSax_shiftcards(int idx))
+{
+	int i;
+
+	for (i = idx; i < (HISAX_MAX_CARDS - 1); i++)
+		memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
+}
+
+HISAX_INITFUNC(int
+HiSax_inithardware(int *busy_flag))
+{
+	int foundcards = 0;
+	int i = 0;
+	int t = ',';
+	int flg = 0;
+	char *id;
+	char *next_id = HiSax_id;
+	char ids[20];
+
+	if (strchr(HiSax_id, ','))
+		t = ',';
+	else if (strchr(HiSax_id, '%'))
+		t = '%';
+
+	while (i < nrcards) {
+		if (cards[i].typ < 1)
+			break;
+		id = next_id;
+		if ((next_id = strchr(id, t))) {
+			*next_id++ = 0;
+			strcpy(ids, id);
+			flg = i + 1;
+		} else {
+			next_id = id;
+			if (flg >= i)
+				strcpy(ids, id);
+			else
+				sprintf(ids, "%s%d", id, i);
+		}
+		if (checkcard(i, ids, busy_flag)) {
+			foundcards++;
+			i++;
+		} else {
+			printk(KERN_WARNING "HiSax: Card %s not installed !\n",
+			       CardType[cards[i].typ]);
+			if (cards[i].cs)
+				kfree((void *) cards[i].cs);
+			cards[i].cs = NULL;
+			HiSax_shiftcards(i);
+		}
+	}
+	return foundcards;
+}
+
+void
+HiSax_closecard(int cardnr)
+{
+	int 	i,last=nrcards - 1;
+
+	if (cardnr>last)
+		return;
+	if (cards[cardnr].cs) {
+		ll_stop(cards[cardnr].cs);
+		release_tei(cards[cardnr].cs);
+		closecard(cardnr);
+		free_irq(cards[cardnr].cs->irq, cards[cardnr].cs);
+		kfree((void *) cards[cardnr].cs);
+		cards[cardnr].cs = NULL;
+	}
+	i = cardnr;
+	while (i!=last) {
+		cards[i] = cards[i+1];
+		i++;
+	}
+	nrcards--;
+}
+
+EXPORT_SYMBOL(HiSax_closecard);
+
+void
+HiSax_reportcard(int cardnr)
+{
+	struct IsdnCardState *cs = cards[cardnr].cs;
+	struct PStack *stptr;
+	struct l3_process *pc;
+	int j, i = 1;
+
+	printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1);
+	printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]);
+	printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug);
+	printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n",
+		(ulong) & HiSax_reportcard);
+	printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs);
+	printk(KERN_DEBUG "HiSax: HW_Flags %x bc0 flg %x bc0 flg %x\n",
+		cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag);
+	printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n",
+		cs->bcs[0].mode, cs->bcs[0].channel);
+	printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n",
+		cs->bcs[1].mode, cs->bcs[1].channel);
+	printk(KERN_DEBUG "HiSax: cs stl 0x%lX\n", (ulong) & (cs->stlist));
+	stptr = cs->stlist;
+	while (stptr != NULL) {
+		printk(KERN_DEBUG "HiSax: dst%d 0x%lX\n", i, (ulong) stptr);
+		printk(KERN_DEBUG "HiSax: dst%d stp 0x%lX\n", i, (ulong) stptr->l1.stlistp);
+		printk(KERN_DEBUG "HiSax:   tei %d sapi %d\n",
+		       stptr->l2.tei, stptr->l2.sap);
+		printk(KERN_DEBUG "HiSax:      man 0x%lX\n", (ulong) stptr->ma.layer);
+		pc = stptr->l3.proc;
+		while (pc) {
+			printk(KERN_DEBUG "HiSax: l3proc %x 0x%lX\n", pc->callref,
+			       (ulong) pc);
+			printk(KERN_DEBUG "HiSax:    state %d  st 0x%lX chan 0x%lX\n",
+			    pc->state, (ulong) pc->st, (ulong) pc->chan);
+			pc = pc->next;
+		}
+		stptr = stptr->next;
+		i++;
+	}
+	for (j = 0; j < 2; j++) {
+		printk(KERN_DEBUG "HiSax: ch%d 0x%lX\n", j,
+		       (ulong) & cs->channel[j]);
+		stptr = cs->channel[j].b_st;
+		i = 1;
+		while (stptr != NULL) {
+			printk(KERN_DEBUG "HiSax:  b_st%d 0x%lX\n", i, (ulong) stptr);
+			printk(KERN_DEBUG "HiSax:    man 0x%lX\n", (ulong) stptr->ma.layer);
+			stptr = stptr->next;
+			i++;
+		}
+	}
+}
+
+
 __initfunc(int
 HiSax_init(void))
 {
 	int i;
-	
+
 #ifdef MODULE
 	int nzproto = 0;
 #ifdef CONFIG_HISAX_ELSA
@@ -432,13 +1255,19 @@
 		return 0;
 	}
 #endif
+#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
+	if (type[0] == ISDN_CTYPE_A1_PCMCIA) {
+		/* we have to export  and return in this case */
+		return 0;
+	}
+#endif
 #endif
-	HiSaxVersion();
 	nrcards = 0;
+	HiSaxVersion();
 #ifdef MODULE
 	if (id)			/* If id= string used */
 		HiSax_id = id;
-	for (i = 0; i < 16; i++) {
+	for (i = 0; i < HISAX_MAX_CARDS; i++) {
 		cards[i].typ = type[i];
 		if (protocol[i]) {
 			cards[i].protocol = protocol[i];
@@ -476,6 +1305,7 @@
 			case ISDN_CTYPE_16_3:
 			case ISDN_CTYPE_TELESPCMCIA:
 			case ISDN_CTYPE_A1:
+			case ISDN_CTYPE_A1_PCMCIA:
 			case ISDN_CTYPE_ELSA_PNP:
 			case ISDN_CTYPE_ELSA_PCMCIA:
 			case ISDN_CTYPE_IX1MICROR2:
@@ -484,16 +1314,19 @@
 			case ISDN_CTYPE_TELEINT:
 			case ISDN_CTYPE_SEDLBAUER:
 			case ISDN_CTYPE_SEDLBAUER_PCMCIA:
+			case ISDN_CTYPE_SEDLBAUER_FAX:
 			case ISDN_CTYPE_SPORTSTER:
 			case ISDN_CTYPE_MIC:
 			case ISDN_CTYPE_TELES3C:
+			case ISDN_CTYPE_S0BOX:
+			case ISDN_CTYPE_FRITZPCI:
 				cards[i].para[0] = irq[i];
 				cards[i].para[1] = io[i];
 				break;
 			case ISDN_CTYPE_ELSA_PCI:
 			case ISDN_CTYPE_NETJET:
 			case ISDN_CTYPE_AMD7930:
-			case ISDN_CTYPE_DBRI:
+			case ISDN_CTYPE_TELESPCI:
 				break;
 		}
 	}
@@ -507,13 +1340,14 @@
 		HiSax_id = HiSaxID;
 	if (!HiSaxID[0])
 		strcpy(HiSaxID, "HiSax");
-	for (i = 0; i < 16; i++)
+	for (i = 0; i < HISAX_MAX_CARDS; i++)
 		if (cards[i].typ > 0)
 			nrcards++;
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
 	       nrcards, (nrcards > 1) ? "s" : "");
 
 	CallcNew();
+	Isdnl3New();
 	Isdnl2New();
 	TeiNew();
 	Isdnl1New();
@@ -522,7 +1356,6 @@
 		/* No symbols to export, hide all symbols */
 
 #ifdef MODULE
-		EXPORT_NO_SYMBOLS;
 		printk(KERN_INFO "HiSax: module installed\n");
 #endif
 		return (0);
@@ -530,6 +1363,7 @@
 		Isdnl1Free();
 		TeiFree();
 		Isdnl2Free();
+		Isdnl3Free();
 		CallcFree();
 		return -EIO;
 	}
@@ -539,13 +1373,27 @@
 void
 cleanup_module(void)
 {
-	HiSax_closehardware();
+	int cardnr = nrcards -1;
+	long flags;
+
+	save_flags(flags);
+	cli();
+	while(cardnr>=0)
+		HiSax_closecard(cardnr--);
+	Isdnl1Free();
+	TeiFree();
+	Isdnl2Free();
+	Isdnl3Free();
+	CallcFree();
+	restore_flags(flags);
 	printk(KERN_INFO "HiSax module removed\n");
 }
+#endif
 
 #ifdef CONFIG_HISAX_ELSA
 int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
 {
+#ifdef MODULE
 	int i;
 	int nzproto = 0;
 
@@ -553,10 +1401,10 @@
 	HiSaxVersion();
 	if (id)			/* If id= string used */
 		HiSax_id = id;
-	/* Initialize all 16 structs, even though we only accept
+	/* Initialize all 8 structs, even though we only accept
 	   two pcmcia cards
 	   */
-	for (i = 0; i < 16; i++) {
+	for (i = 0; i < HISAX_MAX_CARDS; i++) {
 		cards[i].para[0] = irq[i];
 		cards[i].para[1] = io[i];
 		cards[i].typ = type[i];
@@ -575,7 +1423,7 @@
 		HiSax_id = HiSaxID;
 	if (!HiSaxID[0])
 		strcpy(HiSaxID, "HiSax");
-	for (i = 0; i < 16; i++)
+	for (i = 0; i < HISAX_MAX_CARDS; i++)
 		if (cards[i].typ > 0)
 			nrcards++;
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
@@ -583,16 +1431,71 @@
 
 	Isdnl1New();
 	CallcNew();
+	Isdnl3New();
 	Isdnl2New();
 	TeiNew();
 	HiSax_inithardware(busy_flag);
 	printk(KERN_NOTICE "HiSax: module installed\n");
+#endif
 	return (0);
 }
 #endif
+
 #ifdef CONFIG_HISAX_SEDLBAUER
 int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
 {
+#ifdef MODULE
+	int i;
+	int nzproto = 0;
+
+	nrcards = 0;
+	HiSaxVersion();
+	if (id)			/* If id= string used */
+		HiSax_id = id;
+	/* Initialize all 8 structs, even though we only accept
+	   two pcmcia cards
+	   */
+	for (i = 0; i < HISAX_MAX_CARDS; i++) {
+		cards[i].para[0] = irq[i];
+		cards[i].para[1] = io[i];
+		cards[i].typ = type[i];
+		if (protocol[i]) {
+			cards[i].protocol = protocol[i];
+			nzproto++;
+		}
+	}
+	cards[0].para[0] = pcm_irq;
+	cards[0].para[1] = (int)pcm_iob;
+	cards[0].protocol = prot;
+	cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
+	nzproto = 1;
+
+	if (!HiSax_id)
+		HiSax_id = HiSaxID;
+	if (!HiSaxID[0])
+		strcpy(HiSaxID, "HiSax");
+	for (i = 0; i < HISAX_MAX_CARDS; i++)
+		if (cards[i].typ > 0)
+			nrcards++;
+	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
+	       nrcards, (nrcards > 1) ? "s" : "");
+
+	CallcNew();
+	Isdnl3New();
+	Isdnl2New();
+	Isdnl1New();
+	TeiNew();
+	HiSax_inithardware(busy_flag);
+	printk(KERN_NOTICE "HiSax: module installed\n");
+#endif
+	return (0);
+}
+#endif
+
+#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
+int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
+{
+#ifdef MODULE
 	int i;
 	int nzproto = 0;
 
@@ -615,14 +1518,14 @@
 	cards[0].para[0] = pcm_irq;
 	cards[0].para[1] = (int)pcm_iob;
 	cards[0].protocol = prot;
-	cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
+	cards[0].typ = ISDN_CTYPE_A1_PCMCIA;
 	nzproto = 1;
 
 	if (!HiSax_id)
 		HiSax_id = HiSaxID;
 	if (!HiSaxID[0])
 		strcpy(HiSaxID, "HiSax");
-	for (i = 0; i < 16; i++)
+	for (i = 0; i < HISAX_MAX_CARDS; i++)
 		if (cards[i].typ > 0)
 			nrcards++;
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
@@ -630,11 +1533,12 @@
 
 	Isdnl1New();
 	CallcNew();
+	Isdnl3New();
 	Isdnl2New();
 	TeiNew();
 	HiSax_inithardware(busy_flag);
 	printk(KERN_NOTICE "HiSax: module installed\n");
+#endif
 	return (0);
 }
 #endif
-#endif 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)