summaryrefslogtreecommitdiffstats
path: root/drivers/isdn
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-08-28 22:00:09 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-08-28 22:00:09 +0000
commit1a1d77dd589de5a567fa95e36aa6999c704ceca4 (patch)
tree141e31f89f18b9fe0831f31852e0435ceaccafc5 /drivers/isdn
parentfb9c690a18b3d66925a65b17441c37fa14d4370b (diff)
Merge with 2.4.0-test7.
Diffstat (limited to 'drivers/isdn')
-rw-r--r--drivers/isdn/Config.in21
-rw-r--r--drivers/isdn/avmb1/b1.c38
-rw-r--r--drivers/isdn/avmb1/b1dma.c31
-rw-r--r--drivers/isdn/avmb1/b1pci.c8
-rw-r--r--drivers/isdn/avmb1/c4.c39
-rw-r--r--drivers/isdn/avmb1/capi.c47
-rw-r--r--drivers/isdn/avmb1/capidrv.c50
-rw-r--r--drivers/isdn/avmb1/capifs.c23
-rw-r--r--drivers/isdn/avmb1/t1isa.c35
-rw-r--r--drivers/isdn/avmb1/t1pci.c8
-rw-r--r--drivers/isdn/divert/divert_procfs.c5
-rw-r--r--drivers/isdn/eicon/Divas_mod.c172
-rw-r--r--drivers/isdn/eicon/Makefile41
-rw-r--r--drivers/isdn/eicon/adapter.h265
-rw-r--r--drivers/isdn/eicon/bri.c717
-rw-r--r--drivers/isdn/eicon/common.c896
-rw-r--r--drivers/isdn/eicon/constant.h179
-rw-r--r--drivers/isdn/eicon/divalog.h57
-rw-r--r--drivers/isdn/eicon/divas.h232
-rw-r--r--drivers/isdn/eicon/dsp_defs.h303
-rw-r--r--drivers/isdn/eicon/dspdids.h84
-rw-r--r--drivers/isdn/eicon/eicon.h387
-rw-r--r--drivers/isdn/eicon/eicon_dsp.h130
-rw-r--r--drivers/isdn/eicon/eicon_idi.c520
-rw-r--r--drivers/isdn/eicon/eicon_idi.h185
-rw-r--r--drivers/isdn/eicon/eicon_io.c553
-rw-r--r--drivers/isdn/eicon/eicon_isa.c62
-rw-r--r--drivers/isdn/eicon/eicon_isa.h35
-rw-r--r--drivers/isdn/eicon/eicon_mod.c660
-rw-r--r--drivers/isdn/eicon/eicon_pci.c983
-rw-r--r--drivers/isdn/eicon/eicon_pci.h151
-rw-r--r--drivers/isdn/eicon/fcheck.c31
-rw-r--r--drivers/isdn/eicon/fourbri.c583
-rw-r--r--drivers/isdn/eicon/fpga.c158
-rw-r--r--drivers/isdn/eicon/idi.c870
-rw-r--r--drivers/isdn/eicon/idi.h146
-rw-r--r--drivers/isdn/eicon/kprintf.c538
-rw-r--r--drivers/isdn/eicon/lincfg.c410
-rw-r--r--drivers/isdn/eicon/linchr.c274
-rw-r--r--drivers/isdn/eicon/linio.c750
-rw-r--r--drivers/isdn/eicon/linsys.c170
-rw-r--r--drivers/isdn/eicon/log.c179
-rw-r--r--drivers/isdn/eicon/md5sums.asc16
-rw-r--r--drivers/isdn/eicon/pc.h320
-rw-r--r--drivers/isdn/eicon/pc_maint.h165
-rw-r--r--drivers/isdn/eicon/pr_pc.h86
-rw-r--r--drivers/isdn/eicon/pri.c533
-rw-r--r--drivers/isdn/eicon/sys.h119
-rw-r--r--drivers/isdn/eicon/uxio.h220
-rw-r--r--drivers/isdn/eicon/xlog.c183
-rw-r--r--drivers/isdn/hisax/Makefile16
-rw-r--r--drivers/isdn/hisax/avm_pci.c36
-rw-r--r--drivers/isdn/hisax/bkm_a4t.c25
-rw-r--r--drivers/isdn/hisax/bkm_a8.c289
-rw-r--r--drivers/isdn/hisax/bkm_ax.h16
-rw-r--r--drivers/isdn/hisax/callc.c37
-rw-r--r--drivers/isdn/hisax/cert.c6
-rw-r--r--drivers/isdn/hisax/config.c156
-rw-r--r--drivers/isdn/hisax/diva.c46
-rw-r--r--drivers/isdn/hisax/elsa.c33
-rw-r--r--drivers/isdn/hisax/gazel.c38
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.c4
-rw-r--r--drivers/isdn/hisax/hfc_pci.c30
-rw-r--r--drivers/isdn/hisax/hisax.h77
-rw-r--r--drivers/isdn/hisax/icc.c685
-rw-r--r--drivers/isdn/hisax/icc.h73
-rw-r--r--drivers/isdn/hisax/isar.c43
-rw-r--r--drivers/isdn/hisax/isar.h2
-rw-r--r--drivers/isdn/hisax/isdnl1.c163
-rw-r--r--drivers/isdn/hisax/isdnl3.c5
-rw-r--r--drivers/isdn/hisax/l3_1tr6.c6
-rw-r--r--drivers/isdn/hisax/l3dss1.c118
-rw-r--r--drivers/isdn/hisax/l3ni1.c3171
-rw-r--r--drivers/isdn/hisax/l3ni1.h136
-rw-r--r--drivers/isdn/hisax/md5sums.asc38
-rw-r--r--drivers/isdn/hisax/netjet.c265
-rw-r--r--drivers/isdn/hisax/netjet.h77
-rw-r--r--drivers/isdn/hisax/niccy.c22
-rw-r--r--drivers/isdn/hisax/nj_s.c257
-rw-r--r--drivers/isdn/hisax/nj_u.c260
-rw-r--r--drivers/isdn/hisax/q931.c341
-rw-r--r--drivers/isdn/hisax/sedlbauer.c68
-rw-r--r--drivers/isdn/hisax/tei.c12
-rw-r--r--drivers/isdn/hisax/telespci.c17
-rw-r--r--drivers/isdn/hisax/w6692.c56
-rw-r--r--drivers/isdn/hysdn/Makefile3
-rw-r--r--drivers/isdn/hysdn/boardergo.c22
-rw-r--r--drivers/isdn/hysdn/hycapi.c859
-rw-r--r--drivers/isdn/hysdn/hysdn_boot.c9
-rw-r--r--drivers/isdn/hysdn/hysdn_defs.h106
-rw-r--r--drivers/isdn/hysdn/hysdn_init.c37
-rw-r--r--drivers/isdn/hysdn/hysdn_net.c25
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c15
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c15
-rw-r--r--drivers/isdn/hysdn/hysdn_sched.c27
-rw-r--r--drivers/isdn/hysdn/ince1pc.h234
-rw-r--r--drivers/isdn/icn/icn.c8
-rw-r--r--drivers/isdn/isdn_common.c57
-rw-r--r--drivers/isdn/isdn_net.c4
-rw-r--r--drivers/isdn/isdn_ppp.h2
-rw-r--r--drivers/isdn/pcbit/capi.c9
-rw-r--r--drivers/isdn/pcbit/drv.c10
-rw-r--r--drivers/isdn/pcbit/layer2.c28
-rw-r--r--drivers/isdn/pcbit/layer2.h37
-rw-r--r--drivers/isdn/pcbit/module.c6
-rw-r--r--drivers/isdn/sc/timer.c2
106 files changed, 16978 insertions, 3829 deletions
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in
index e4ba2cf1f..2062f753c 100644
--- a/drivers/isdn/Config.in
+++ b/drivers/isdn/Config.in
@@ -37,6 +37,7 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
bool ' Disable keypad protocol option' CONFIG_HISAX_NO_KEYPAD
fi
bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
+ bool ' HiSax Support for US NI1' CONFIG_HISAX_NI1
comment ' HiSax supported cards'
bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0
bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
@@ -55,6 +56,7 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
bool ' USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
bool ' MIC card' CONFIG_HISAX_MIC
bool ' NETjet card' CONFIG_HISAX_NETJET
+ bool ' NETspider U card' CONFIG_HISAX_NETJET_U
bool ' Niccy PnP/PCI card' CONFIG_HISAX_NICCY
bool ' Siemens I-Surf card' CONFIG_HISAX_ISURF
bool ' HST Saphir card' CONFIG_HISAX_HSTSAPHIR
@@ -83,7 +85,15 @@ if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
fi
dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
- bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
+ if [ "$CONFIG_ISDN_DRV_EICON_STANDALONE" != "y" ]; then
+ if [ "$CONFIG_PCI" = "y" ]; then
+ bool ' Eicon PCI DIVA Server BRI/PRI/4BRI support' CONFIG_ISDN_DRV_EICON_PCI
+ fi
+ bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
+ fi
+ if [ "$CONFIG_PCI" = "y" ]; then
+ bool ' build eicon driver type standalone' CONFIG_ISDN_DRV_EICON_STANDALONE
+ fi
fi
dep_tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI $CONFIG_ISDN
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
@@ -109,8 +119,13 @@ if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
fi
if [ "$CONFIG_PROC_FS" != "n" ]; then
-if [ "$CONFIG_MODULES" != "n" ]; then
- bool 'Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)' CONFIG_HYSDN
+ if [ "$CONFIG_MODULES" != "n" ]; then
+ bool 'Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)' CONFIG_HYSDN
+ fi
fi
+if [ "$CONFIG_HYSDN" != "n" ]; then
+ if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
+ bool ' HYSDN CAPI 2.0 support' CONFIG_HYSDN_CAPI
+ fi
fi
endmenu
diff --git a/drivers/isdn/avmb1/b1.c b/drivers/isdn/avmb1/b1.c
index ff13e1636..747b5ea7f 100644
--- a/drivers/isdn/avmb1/b1.c
+++ b/drivers/isdn/avmb1/b1.c
@@ -1,11 +1,17 @@
/*
- * $Id: b1.c,v 1.14 2000/06/19 16:51:53 keil Exp $
+ * $Id: b1.c,v 1.16 2000/08/04 15:36:31 calle Exp $
*
* Common module for AVM B1 cards.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1.c,v $
+ * Revision 1.16 2000/08/04 15:36:31 calle
+ * copied wrong from file to file :-(
+ *
+ * Revision 1.15 2000/08/04 12:20:08 calle
+ * - Fix unsigned/signed warning in the right way ...
+ *
* Revision 1.14 2000/06/19 16:51:53 keil
* don't free skb in irq context
*
@@ -95,7 +101,7 @@
#include "capicmd.h"
#include "capiutil.h"
-static char *revision = "$Revision: 1.14 $";
+static char *revision = "$Revision: 1.16 $";
/* ------------------------------------------------------------- */
@@ -597,25 +603,29 @@ void b1_handle_interrupt(avmcard * card)
ctrl->ready(ctrl);
break;
- case RECEIVE_TASK_READY:
+ case RECEIVE_TASK_READY:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = b1_get_slice(card->port, card->msgbuf);
- card->msgbuf[MsgLen--] = 0;
- while ( MsgLen >= 0
- && ( card->msgbuf[MsgLen] == '\n'
- || card->msgbuf[MsgLen] == '\r'))
- card->msgbuf[MsgLen--] = 0;
+ card->msgbuf[MsgLen] = 0;
+ while ( MsgLen > 0
+ && ( card->msgbuf[MsgLen-1] == '\n'
+ || card->msgbuf[MsgLen-1] == '\r')) {
+ card->msgbuf[MsgLen-1] = 0;
+ MsgLen--;
+ }
printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
card->name, ApplId, card->msgbuf);
break;
- case RECEIVE_DEBUGMSG:
+ case RECEIVE_DEBUGMSG:
MsgLen = b1_get_slice(card->port, card->msgbuf);
- card->msgbuf[MsgLen--] = 0;
- while ( MsgLen >= 0
- && ( card->msgbuf[MsgLen] == '\n'
- || card->msgbuf[MsgLen] == '\r'))
- card->msgbuf[MsgLen--] = 0;
+ card->msgbuf[MsgLen] = 0;
+ while ( MsgLen > 0
+ && ( card->msgbuf[MsgLen-1] == '\n'
+ || card->msgbuf[MsgLen-1] == '\r')) {
+ card->msgbuf[MsgLen-1] = 0;
+ MsgLen--;
+ }
printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
break;
diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c
index 42a77acf5..3bd6a01c0 100644
--- a/drivers/isdn/avmb1/b1dma.c
+++ b/drivers/isdn/avmb1/b1dma.c
@@ -1,11 +1,14 @@
/*
- * $Id: b1dma.c,v 1.6 2000/06/29 13:59:06 calle Exp $
+ * $Id: b1dma.c,v 1.7 2000/08/04 12:20:08 calle Exp $
*
* Common module for AVM B1 cards that support dma with AMCC
*
* (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1dma.c,v $
+ * Revision 1.7 2000/08/04 12:20:08 calle
+ * - Fix unsigned/signed warning in the right way ...
+ *
* Revision 1.6 2000/06/29 13:59:06 calle
* Bugfix: reinit txdma without interrupt will confuse some AMCC chips.
*
@@ -44,7 +47,7 @@
#include "capicmd.h"
#include "capiutil.h"
-static char *revision = "$Revision: 1.6 $";
+static char *revision = "$Revision: 1.7 $";
/* ------------------------------------------------------------- */
@@ -561,22 +564,26 @@ static void b1dma_handle_rx(avmcard *card)
case RECEIVE_TASK_READY:
ApplId = (unsigned) _get_word(&p);
MsgLen = _get_slice(&p, card->msgbuf);
- card->msgbuf[MsgLen--] = 0;
- while ( MsgLen >= 0
- && ( card->msgbuf[MsgLen] == '\n'
- || card->msgbuf[MsgLen] == '\r'))
- card->msgbuf[MsgLen--] = 0;
+ card->msgbuf[MsgLen] = 0;
+ while ( MsgLen > 0
+ && ( card->msgbuf[MsgLen-1] == '\n'
+ || card->msgbuf[MsgLen-1] == '\r')) {
+ card->msgbuf[MsgLen-1] = 0;
+ MsgLen--;
+ }
printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
card->name, ApplId, card->msgbuf);
break;
case RECEIVE_DEBUGMSG:
MsgLen = _get_slice(&p, card->msgbuf);
- card->msgbuf[MsgLen--] = 0;
- while ( MsgLen >= 0
- && ( card->msgbuf[MsgLen] == '\n'
- || card->msgbuf[MsgLen] == '\r'))
- card->msgbuf[MsgLen--] = 0;
+ card->msgbuf[MsgLen] = 0;
+ while ( MsgLen > 0
+ && ( card->msgbuf[MsgLen-1] == '\n'
+ || card->msgbuf[MsgLen-1] == '\r')) {
+ card->msgbuf[MsgLen-1] = 0;
+ MsgLen--;
+ }
printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
break;
diff --git a/drivers/isdn/avmb1/b1pci.c b/drivers/isdn/avmb1/b1pci.c
index fb7b5f755..69bab9557 100644
--- a/drivers/isdn/avmb1/b1pci.c
+++ b/drivers/isdn/avmb1/b1pci.c
@@ -1,11 +1,14 @@
/*
- * $Id: b1pci.c,v 1.26 2000/07/20 10:21:21 calle Exp $
+ * $Id: b1pci.c,v 1.27 2000/08/08 09:24:19 calle Exp $
*
* Module for AVM B1 PCI-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1pci.c,v $
+ * Revision 1.27 2000/08/08 09:24:19 calle
+ * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI
+ *
* Revision 1.26 2000/07/20 10:21:21 calle
* Bugfix: driver will not be unregistered, if not cards were detected.
* this result in an oops in kcapi.c
@@ -91,13 +94,12 @@
#include <linux/pci.h>
#include <linux/capi.h>
#include <asm/io.h>
-#include <linux/isdn.h>
#include "capicmd.h"
#include "capiutil.h"
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.26 $";
+static char *revision = "$Revision: 1.27 $";
/* ------------------------------------------------------------- */
diff --git a/drivers/isdn/avmb1/c4.c b/drivers/isdn/avmb1/c4.c
index 64de830c2..d814eec1a 100644
--- a/drivers/isdn/avmb1/c4.c
+++ b/drivers/isdn/avmb1/c4.c
@@ -1,11 +1,20 @@
/*
- * $Id: c4.c,v 1.13 2000/07/20 10:21:21 calle Exp $
+ * $Id: c4.c,v 1.16 2000/08/20 07:30:13 keil Exp $
*
* Module for AVM C4 card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: c4.c,v $
+ * Revision 1.16 2000/08/20 07:30:13 keil
+ * changes for 2.4
+ *
+ * Revision 1.15 2000/08/08 09:24:19 calle
+ * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI
+ *
+ * Revision 1.14 2000/08/04 12:20:08 calle
+ * - Fix unsigned/signed warning in the right way ...
+ *
* Revision 1.13 2000/07/20 10:21:21 calle
* Bugfix: driver will not be unregistered, if not cards were detected.
* this result in an oops in kcapi.c
@@ -63,15 +72,15 @@
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/capi.h>
-#include <linux/isdn.h>
#include <asm/io.h>
#include <asm/uaccess.h>
+#include <linux/netdevice.h>
#include "capicmd.h"
#include "capiutil.h"
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.13 $";
+static char *revision = "$Revision: 1.16 $";
#undef CONFIG_C4_DEBUG
#undef CONFIG_C4_POLLDEBUG
@@ -682,22 +691,26 @@ static void c4_handle_rx(avmcard *card)
case RECEIVE_TASK_READY:
ApplId = (unsigned) _get_word(&p);
MsgLen = _get_slice(&p, card->msgbuf);
- card->msgbuf[MsgLen--] = 0;
- while ( MsgLen >= 0
- && ( card->msgbuf[MsgLen] == '\n'
- || card->msgbuf[MsgLen] == '\r'))
- card->msgbuf[MsgLen--] = 0;
+ card->msgbuf[MsgLen] = 0;
+ while ( MsgLen > 0
+ && ( card->msgbuf[MsgLen-1] == '\n'
+ || card->msgbuf[MsgLen-1] == '\r')) {
+ card->msgbuf[MsgLen-1] = 0;
+ MsgLen--;
+ }
printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
card->name, ApplId, card->msgbuf);
break;
case RECEIVE_DEBUGMSG:
MsgLen = _get_slice(&p, card->msgbuf);
- card->msgbuf[MsgLen--] = 0;
- while ( MsgLen >= 0
- && ( card->msgbuf[MsgLen] == '\n'
- || card->msgbuf[MsgLen] == '\r'))
- card->msgbuf[MsgLen--] = 0;
+ card->msgbuf[MsgLen] = 0;
+ while ( MsgLen > 0
+ && ( card->msgbuf[MsgLen-1] == '\n'
+ || card->msgbuf[MsgLen-1] == '\r')) {
+ card->msgbuf[MsgLen-1] = 0;
+ MsgLen--;
+ }
printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
break;
diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c
index a4223e878..0b7cc80d2 100644
--- a/drivers/isdn/avmb1/capi.c
+++ b/drivers/isdn/avmb1/capi.c
@@ -1,11 +1,14 @@
/*
- * $Id: capi.c,v 1.38 2000/07/24 08:49:09 calle Exp $
+ * $Id: capi.c,v 1.39 2000/07/24 13:42:50 calle Exp $
*
* CAPI 2.0 Interface for Linux
*
* Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capi.c,v $
+ * Revision 1.39 2000/07/24 13:42:50 calle
+ * - lock_kernel/unlock_kernel for _release functions. (from 2.4)
+ *
* Revision 1.38 2000/07/24 08:49:09 calle
* - Bugfix: capiminor_del_all_ack completely wrong :-(
*
@@ -216,7 +219,7 @@
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
#include <linux/slab.h>
-static char *revision = "$Revision: 1.38 $";
+static char *revision = "$Revision: 1.39 $";
MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
@@ -325,11 +328,11 @@ static struct capidev *capidev_openlist = 0;
static struct capiminor *minors = 0;
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-static kmem_cache_t *capidev_cachep = 0;
-static kmem_cache_t *capincci_cachep = 0;
+static kmem_cache_t *capidev_cachep = 0;
+static kmem_cache_t *capincci_cachep = 0;
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-static kmem_cache_t *capiminor_cachep = 0;
-static kmem_cache_t *capidh_cachep = 0;
+static kmem_cache_t *capiminor_cachep = 0;
+static kmem_cache_t *capidh_cachep = 0;
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -1239,7 +1242,7 @@ capi_release(struct inode *inode, struct file *file)
capincci_free(cdev, 0xffffffff);
capidev_free(cdev);
file->private_data = NULL;
-
+
MOD_DEC_USE_COUNT;
#ifdef _DEBUG_REFCOUNT
printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(THIS_MODULE));
@@ -1251,13 +1254,13 @@ capi_release(struct inode *inode, struct file *file)
static struct file_operations capi_fops =
{
owner: THIS_MODULE,
- llseek: capi_llseek,
- read: capi_read,
- write: capi_write,
- poll: capi_poll,
- ioctl: capi_ioctl,
- open: capi_open,
- release: capi_release,
+ llseek: capi_llseek,
+ read: capi_read,
+ write: capi_write,
+ poll: capi_poll,
+ ioctl: capi_ioctl,
+ open: capi_open,
+ release: capi_release,
};
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -1980,9 +1983,9 @@ static void alloc_exit(void)
static int alloc_init(void)
{
- capidev_cachep = kmem_cache_create("capi20_dev",
+ capidev_cachep = kmem_cache_create("capi20_dev",
sizeof(struct capidev),
- 0,
+ 0,
SLAB_HWCACHE_ALIGN,
NULL, NULL);
if (!capidev_cachep) {
@@ -1990,9 +1993,9 @@ static int alloc_init(void)
return -ENOMEM;
}
- capincci_cachep = kmem_cache_create("capi20_ncci",
+ capincci_cachep = kmem_cache_create("capi20_ncci",
sizeof(struct capincci),
- 0,
+ 0,
SLAB_HWCACHE_ALIGN,
NULL, NULL);
if (!capincci_cachep) {
@@ -2000,18 +2003,18 @@ static int alloc_init(void)
return -ENOMEM;
}
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- capidh_cachep = kmem_cache_create("capi20_dh",
+ capidh_cachep = kmem_cache_create("capi20_dh",
sizeof(struct datahandle_queue),
- 0,
+ 0,
SLAB_HWCACHE_ALIGN,
NULL, NULL);
if (!capidh_cachep) {
alloc_exit();
return -ENOMEM;
}
- capiminor_cachep = kmem_cache_create("capi20_minor",
+ capiminor_cachep = kmem_cache_create("capi20_minor",
sizeof(struct capiminor),
- 0,
+ 0,
SLAB_HWCACHE_ALIGN,
NULL, NULL);
if (!capiminor_cachep) {
diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c
index 0b04920f8..58b2eb9c6 100644
--- a/drivers/isdn/avmb1/capidrv.c
+++ b/drivers/isdn/avmb1/capidrv.c
@@ -2183,50 +2183,6 @@ static void enable_dchannel_trace(capidrv_contr *card)
send_message(card, &cmdcmsg);
}
-static void disable_dchannel_trace(capidrv_contr *card)
-{
- __u8 manufacturer[CAPI_MANUFACTURER_LEN];
- capi_version version;
- __u16 contr = card->contrnr;
- __u16 errcode;
- __u16 avmversion[3];
-
- errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer);
- if (errcode != CAPI_NOERROR) {
- printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
- card->name, errcode);
- return;
- }
- if (strstr(manufacturer, "AVM") == 0) {
- printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
- card->name, manufacturer);
- return;
- }
- errcode = (*capifuncs->capi_get_version)(contr, &version);
- if (errcode != CAPI_NOERROR) {
- printk(KERN_ERR "%s: can't get version (0x%x)\n",
- card->name, errcode);
- return;
- }
- avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
- avmversion[1] = (version.majormanuversion << 4) & 0xf0;
- avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
- avmversion[2] |= version.minormanuversion & 0x0f;
-
- if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
- printk(KERN_INFO "%s: D2 trace disabled\n", card->name);
- } else {
- printk(KERN_INFO "%s: D3 trace disabled\n", card->name);
- }
- capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
- card->msgid++,
- contr,
- 0x214D5641, /* ManuID */
- 0, /* Class */
- 1, /* Function */
- (_cstruct)"\004\000\000\000\000");
- send_message(card, &cmdcmsg);
-}
static void send_listen(capidrv_contr *card)
{
@@ -2288,15 +2244,15 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
card->interface.writecmd = 0;
card->interface.readstat = if_readstat;
card->interface.features = ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L2_TRANS |
- ISDN_FEATURE_L3_TRANS |
+ ISDN_FEATURE_L2_TRANS |
+ ISDN_FEATURE_L3_TRANS |
ISDN_FEATURE_P_UNKNOWN |
ISDN_FEATURE_L2_X75I |
ISDN_FEATURE_L2_X75UI |
ISDN_FEATURE_L2_X75BUI;
if (profp->support1 & (1<<2))
card->interface.features |= ISDN_FEATURE_L2_V11096 |
- ISDN_FEATURE_L2_V11019 |
+ ISDN_FEATURE_L2_V11019 |
ISDN_FEATURE_L2_V11038;
if (profp->support1 & (1<<8))
card->interface.features |= ISDN_FEATURE_L2_MODEM;
diff --git a/drivers/isdn/avmb1/capifs.c b/drivers/isdn/avmb1/capifs.c
index ec4f9c559..64ef8436c 100644
--- a/drivers/isdn/avmb1/capifs.c
+++ b/drivers/isdn/avmb1/capifs.c
@@ -1,11 +1,20 @@
/*
- * $Id: capifs.c,v 1.6 2000/04/03 13:29:25 calle Exp $
+ * $Id: capifs.c,v 1.9 2000/08/20 07:30:13 keil Exp $
*
* (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
*
* Heavily based on devpts filesystem from H. Peter Anvin
*
* $Log: capifs.c,v $
+ * Revision 1.9 2000/08/20 07:30:13 keil
+ * changes for 2.4
+ *
+ * Revision 1.8 2000/07/20 10:23:13 calle
+ * Include isdn_compat.h for people that don't use -p option of std2kern.
+ *
+ * Revision 1.7 2000/06/18 16:09:54 keil
+ * more changes for 2.4
+ *
* Revision 1.6 2000/04/03 13:29:25 calle
* make Tim Waugh happy (module unload races in 2.3.99-pre3).
* no real problem there, but now it is much cleaner ...
@@ -60,7 +69,7 @@
MODULE_AUTHOR("Carsten Paeth <calle@calle.de>");
-static char *revision = "$Revision: 1.6 $";
+static char *revision = "$Revision: 1.9 $";
struct capifs_ncci {
struct inode *inode;
@@ -130,12 +139,12 @@ static int capifs_root_readdir(struct file *filp, void *dirent, filldir_t filldi
switch(nr)
{
case 0:
- if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0)
+ if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0)
return 0;
filp->f_pos = ++nr;
/* fall through */
case 1:
- if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0)
+ if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0)
return 0;
filp->f_pos = ++nr;
/* fall through */
@@ -147,7 +156,7 @@ static int capifs_root_readdir(struct file *filp, void *dirent, filldir_t filldi
char *p = numbuf;
if (np->type) *p++ = np->type;
sprintf(p, "%u", np->num);
- if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 )
+ if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr, DT_UNKNOWN) < 0 )
return 0;
}
filp->f_pos = ++nr;
@@ -228,9 +237,9 @@ static void capifs_put_super(struct super_block *sb)
for ( i = 0 ; i < sbi->max_ncci ; i++ ) {
if ( (inode = sbi->nccis[i].inode) ) {
- if ( atomic_read(&inode->i_count) != 1 )
+ if (atomic_read(&inode->i_count) != 1 )
printk("capifs_put_super: badness: entry %d count %d\n",
- i, atomic_read(&inode->i_count));
+ i, (unsigned)atomic_read(&inode->i_count));
inode->i_nlink--;
iput(inode);
}
diff --git a/drivers/isdn/avmb1/t1isa.c b/drivers/isdn/avmb1/t1isa.c
index b87f7293e..b6ec1aa52 100644
--- a/drivers/isdn/avmb1/t1isa.c
+++ b/drivers/isdn/avmb1/t1isa.c
@@ -1,11 +1,17 @@
/*
- * $Id: t1isa.c,v 1.11 2000/04/03 13:29:25 calle Exp $
+ * $Id: t1isa.c,v 1.13 2000/08/04 15:36:31 calle Exp $
*
* Module for AVM T1 HEMA-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: t1isa.c,v $
+ * Revision 1.13 2000/08/04 15:36:31 calle
+ * copied wrong from file to file :-(
+ *
+ * Revision 1.12 2000/08/04 12:20:08 calle
+ * - Fix unsigned/signed warning in the right way ...
+ *
* Revision 1.11 2000/04/03 13:29:25 calle
* make Tim Waugh happy (module unload races in 2.3.99-pre3).
* no real problem there, but now it is much cleaner ...
@@ -85,7 +91,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.11 $";
+static char *revision = "$Revision: 1.13 $";
/* ------------------------------------------------------------- */
@@ -282,25 +288,30 @@ static void t1_handle_interrupt(avmcard * card)
case RECEIVE_TASK_READY:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = t1_get_slice(card->port, card->msgbuf);
- card->msgbuf[MsgLen--] = 0;
- while ( MsgLen >= 0
- && ( card->msgbuf[MsgLen] == '\n'
- || card->msgbuf[MsgLen] == '\r'))
- card->msgbuf[MsgLen--] = 0;
+ card->msgbuf[MsgLen] = 0;
+ while ( MsgLen > 0
+ && ( card->msgbuf[MsgLen-1] == '\n'
+ || card->msgbuf[MsgLen-1] == '\r')) {
+ card->msgbuf[MsgLen-1] = 0;
+ MsgLen--;
+ }
printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
card->name, ApplId, card->msgbuf);
break;
case RECEIVE_DEBUGMSG:
MsgLen = t1_get_slice(card->port, card->msgbuf);
- card->msgbuf[MsgLen--] = 0;
- while ( MsgLen >= 0
- && ( card->msgbuf[MsgLen] == '\n'
- || card->msgbuf[MsgLen] == '\r'))
- card->msgbuf[MsgLen--] = 0;
+ card->msgbuf[MsgLen] = 0;
+ while ( MsgLen > 0
+ && ( card->msgbuf[MsgLen-1] == '\n'
+ || card->msgbuf[MsgLen-1] == '\r')) {
+ card->msgbuf[MsgLen-1] = 0;
+ MsgLen--;
+ }
printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
break;
+
case 0xff:
printk(KERN_ERR "%s: card reseted ?\n", card->name);
return;
diff --git a/drivers/isdn/avmb1/t1pci.c b/drivers/isdn/avmb1/t1pci.c
index 6248419be..d2303feab 100644
--- a/drivers/isdn/avmb1/t1pci.c
+++ b/drivers/isdn/avmb1/t1pci.c
@@ -1,11 +1,14 @@
/*
- * $Id: t1pci.c,v 1.10 2000/07/20 10:21:21 calle Exp $
+ * $Id: t1pci.c,v 1.11 2000/08/08 09:24:19 calle Exp $
*
* Module for AVM T1 PCI-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: t1pci.c,v $
+ * Revision 1.11 2000/08/08 09:24:19 calle
+ * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI
+ *
* Revision 1.10 2000/07/20 10:21:21 calle
* Bugfix: driver will not be unregistered, if not cards were detected.
* this result in an oops in kcapi.c
@@ -60,13 +63,12 @@
#include <linux/pci.h>
#include <linux/capi.h>
#include <asm/io.h>
-#include <linux/isdn.h>
#include "capicmd.h"
#include "capiutil.h"
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.10 $";
+static char *revision = "$Revision: 1.11 $";
#undef CONFIG_T1PCI_DEBUG
#undef CONFIG_T1PCI_POLLDEBUG
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index bd065a48d..5b08e8025 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -1,5 +1,5 @@
/*
- * $Id: divert_procfs.c,v 1.8 2000/03/03 16:37:11 kai Exp $
+ * $Id: divert_procfs.c,v 1.9 2000/08/20 07:40:14 keil Exp $
*
* Filesystem handling for the diversion supplementary services.
*
@@ -20,6 +20,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: divert_procfs.c,v $
+ * Revision 1.9 2000/08/20 07:40:14 keil
+ * changes from 2.4
+ *
* Revision 1.8 2000/03/03 16:37:11 kai
* incorporated some cosmetic changes from the official kernel tree back
* into CVS
diff --git a/drivers/isdn/eicon/Divas_mod.c b/drivers/isdn/eicon/Divas_mod.c
new file mode 100644
index 000000000..8cb2a0409
--- /dev/null
+++ b/drivers/isdn/eicon/Divas_mod.c
@@ -0,0 +1,172 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.15
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#undef N_DATA
+
+#include <linux/kernel.h>
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <errno.h>
+
+#include "adapter.h"
+#include "uxio.h"
+
+#ifdef MODULE
+#include "idi.h"
+void EtdM_DIDD_Write(DESCRIPTOR *, int);
+EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Read);
+EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Write);
+EXPORT_SYMBOL_NOVERS(DivasPrintf);
+#define Divas_init init_module
+#endif
+
+extern char *file_check(void);
+
+int DivasCardsDiscover(void);
+
+int
+Divas_init(void)
+{
+ printk(KERN_DEBUG "DIVA Server Driver - initialising\n");
+
+ printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.12 (%s)\n",file_check());
+
+
+#if !defined(CONFIG_PCI)
+ printk(KERN_WARNING "CONFIG_PCI is not defined!\n");
+ return -ENODEV;
+#endif
+
+ if (pci_present())
+ {
+ if (DivasCardsDiscover() < 0)
+ {
+ printk(KERN_WARNING "Divas: Not loaded\n");
+ return -ENODEV;
+ }
+ }
+ else
+ {
+ printk(KERN_WARNING "Divas: No PCI bus present\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+ card_t *pCard;
+ word wCardIndex;
+ extern int Divas_major;
+
+ printk(KERN_DEBUG "DIVA Server Driver - unloading\n");
+
+ pCard = DivasCards;
+ for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++)
+ {
+ if ((pCard->hw) && (pCard->hw->in_use))
+ {
+
+ (*pCard->card_reset)(pCard);
+
+ UxIsrRemove(pCard->hw, pCard);
+ UxCardHandleFree(pCard->hw);
+
+ if(pCard->e_tbl != NULL)
+ {
+ kfree(pCard->e_tbl);
+ }
+
+
+ if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B)
+ {
+ release_region(pCard->hw->io_base,0x20);
+ release_region(pCard->hw->reset_base,0x80);
+ }
+
+ // If this is a 4BRI ...
+ if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q)
+ {
+ // Skip over the next 3 virtual adapters
+ wCardIndex += 3;
+
+ // But free their handles
+ pCard++;
+ UxCardHandleFree(pCard->hw);
+
+ if(pCard->e_tbl != NULL)
+ {
+ kfree(pCard->e_tbl);
+ }
+
+ pCard++;
+ UxCardHandleFree(pCard->hw);
+
+ if(pCard->e_tbl != NULL)
+ {
+ kfree(pCard->e_tbl);
+ }
+
+ pCard++;
+ UxCardHandleFree(pCard->hw);
+
+ if(pCard->e_tbl != NULL)
+ {
+ kfree(pCard->e_tbl);
+ }
+ }
+ }
+ pCard++;
+ }
+
+ unregister_chrdev(Divas_major, "Divas");
+}
+
+void mod_inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+void mod_dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+#else
+Divas_setup(char *str, int *ints)
+{
+}
+#endif
+
diff --git a/drivers/isdn/eicon/Makefile b/drivers/isdn/eicon/Makefile
index 306aac0e8..63c557492 100644
--- a/drivers/isdn/eicon/Makefile
+++ b/drivers/isdn/eicon/Makefile
@@ -1,8 +1,37 @@
L_OBJS :=
M_OBJS :=
-O_OBJS := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o
+LX_OBJS :=
+MX_OBJS :=
+O_OBJS :=
+OX_OBJS :=
+L_TARGET :=
+O_TARGET :=
+
+ifeq ($(CONFIG_ISDN_DRV_EICON_STANDALONE),y)
+
+ ifeq ($(CONFIG_PCI),y)
+ O_OBJS += common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o fourbri.o
+ O_OBJS += lincfg.o linchr.o linsys.o linio.o
+ O_OBJS += fcheck.o
+ OX_OBJS += Divas_mod.o
+ endif
+
+else
+
+ OX_OBJS += eicon_mod.o
+ O_OBJS := eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o
+ O_OBJS += fcheck.o
+ ifeq ($(CONFIG_PCI),y)
+ ifeq ($(CONFIG_ISDN_DRV_EICON_PCI),y)
+ O_OBJS += common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o fourbri.o
+ O_OBJS += lincfg.o linchr.o linsys.o linio.o
+ endif
+ endif
+
+endif
O_TARGET :=
+
ifeq ($(CONFIG_ISDN_DRV_EICON),y)
O_TARGET += eicon.o
else
@@ -10,4 +39,14 @@ else
M_OBJS = eicon.o
endif
+
include $(TOPDIR)/Rules.make
+
+MD5FILES += common.c idi.c bri.c pri.c log.c xlog.c kprintf.c fpga.c \
+ fourbri.c fcheck.c
+
+FCHECK = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
+
+fcheck.o: $(MD5FILES)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D FILECHECK=$(FCHECK) -c -o fcheck.o fcheck.c
+
diff --git a/drivers/isdn/eicon/adapter.h b/drivers/isdn/eicon/adapter.h
new file mode 100644
index 000000000..cabba68be
--- /dev/null
+++ b/drivers/isdn/eicon/adapter.h
@@ -0,0 +1,265 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.7
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/* Main internal include file for Diva Server driver */
+
+#if !defined(ADAPTER_H)
+#define ADAPTER_H
+
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#undef ID_MASK
+#include "pc.h"
+
+#define XMOREC 0x1f
+#define XMOREF 0x20
+#define XBUSY 0x40
+#define RMORE 0x80
+
+ /* structure for all information we have to keep on a per */
+ /* adapater basis */
+
+typedef struct adapter_s ADAPTER;
+
+struct adapter_s {
+ void * io;
+
+ byte IdTable[256];
+ byte ReadyInt;
+
+ byte (* ram_in)(ADAPTER * a, void * adr);
+ word (* ram_inw)(ADAPTER * a, void * adr);
+ void (* ram_in_buffer)(ADAPTER * a, void * adr, void * P, word length);
+ void (* ram_look_ahead)(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e);
+
+ void (* ram_out)(ADAPTER * a, void * adr, byte data);
+ void (* ram_outw)(ADAPTER * a, void * adr, word data);
+ void (* ram_out_buffer)(ADAPTER * a, void * adr, void * P, word length);
+
+ void (* ram_inc)(ADAPTER * a, void * adr);
+};
+
+typedef struct card card_t;
+
+typedef int card_load_fn_t(card_t *card, dia_load_t *load);
+typedef int card_config_fn_t(card_t *card, dia_config_t *config);
+typedef int card_start_fn_t(card_t *card, byte *channels);
+typedef int card_reset_fn_t(card_t *card);
+typedef int card_mem_get_fn_t(card_t *card, mem_block_t *mem_block);
+
+#define MAX_PENTITIES 256 /* Number of entities primary adapter */
+#define MAX_ENTITIES 16 /* Number of entities standard adapter */
+
+typedef struct e_info_s E_INFO;
+
+struct e_info_s
+{
+ ENTITY *e; /* entity pointer */
+ byte next; /* chaining index */
+ word assign_ref; /* assign reference */
+};
+
+/* DIVA card info (details hidden from user) */
+
+typedef struct ux_diva_card_s ux_diva_card_t;
+
+/* card info */
+
+struct card
+{
+ ADAPTER a; /* per-adapter information */
+ dia_card_t cfg; /* card configuration */
+ int state; /* State of the adapter */
+ dword serial_no; /* serial number */
+ int test_int_pend; /* set for interrupt testing */
+ ux_diva_card_t *hw; /* O/S-specific handle */
+ card_reset_fn_t *card_reset; /* call this to reset card */
+ card_load_fn_t *card_load; /* call this to load card */
+ card_config_fn_t *card_config; /* call this to config card */
+ card_start_fn_t *card_start; /* call this to start card */
+ card_mem_get_fn_t *card_mem_get; /* call this to get card memory */
+ E_INFO *e_tbl; /* table of ENTITY pointers */
+ byte e_head; /* list of active ENTITIES */
+ byte e_tail; /* list of active ENTITIES */
+ int e_count; /* # of active ENTITIES */
+ int e_max; /* total # of ENTITIES */
+ byte assign; /* assign queue entry */
+ PBUFFER RBuffer; /* Copy of receive lookahead buffer */
+ int log_types; /* bit-mask of active logs */
+ word xlog_offset; /* offset to XLOG buffer on card */
+ void (*out)(ADAPTER *a);
+ byte (*dpc)(ADAPTER * a);
+ byte (*test_int)(ADAPTER * a);
+ void (*clear_int)(ADAPTER * a);
+ void (*reset_int)(card_t *c);
+ int is_live;
+
+ int (*card_isr)(card_t *card);
+
+ int int_pend; /* interrupt pending */
+ long interrupt_reentered;
+ long dpc_reentered;
+ int set_xlog_request;
+
+} ;
+
+/* card information */
+
+#define MAX_CARDS 20 /* max number of cards on a system */
+
+extern
+card_t DivasCards[];
+
+extern
+int DivasCardNext;
+
+extern
+dia_config_t DivasCardConfigs[];
+
+extern
+byte DivasFlavourConfig[];
+
+/*------------------------------------------------------------------*/
+/* public functions of IDI common code */
+/*------------------------------------------------------------------*/
+
+void DivasOut(ADAPTER * a);
+byte DivasDpc(ADAPTER * a);
+byte DivasTestInt(ADAPTER * a);
+void DivasClearInt(ADAPTER * a);
+
+/*------------------------------------------------------------------*/
+/* public functions of configuration platform-specific code */
+/*------------------------------------------------------------------*/
+
+int DivasConfigGet(dia_card_t *card);
+
+/*------------------------------------------------------------------*/
+/* public functions of LOG related code */
+/*------------------------------------------------------------------*/
+
+void DivasXlogReq(int card_num);
+int DivasXlogRetrieve(card_t *card);
+void DivasLog(dia_log_t *log);
+void DivasLogIdi(card_t *card, ENTITY *e, int request);
+
+/*------------------------------------------------------------------*/
+/* public functions to initialise cards for each type supported */
+/*------------------------------------------------------------------*/
+
+int DivasPriInit(card_t *card, dia_card_t *cfg);
+
+int DivasBriInit(card_t *card, dia_card_t *cfg);
+int Divas4BriInit(card_t *card, dia_card_t *cfg);
+void DivasBriPatch(card_t *card);
+
+/*------------------------------------------------------------------*/
+/* public functions of log common code */
+/*------------------------------------------------------------------*/
+
+extern char *DivasLogFifoRead(void);
+extern void DivasLogFifoWrite(char *entry, int length);
+extern int DivasLogFifoEmpty(void);
+extern int DivasLogFifoFull(void);
+extern void DivasLogAdd(void *buffer, int length);
+
+/*------------------------------------------------------------------*/
+/* public functions of misc. platform-specific code */
+/*------------------------------------------------------------------*/
+
+int DivasDpcSchedule(void);
+void DivasDoDpc(void *);
+void DivasDoRequestDpc(void *pData);
+int DivasScheduleRequestDpc(void);
+
+/* table of IDI request functions */
+
+extern
+IDI_CALL DivasIdiRequest[];
+
+/*
+ * intialisation entry point
+ */
+
+int DivasInit(void);
+
+/*
+ * Get information on the number and type of cards present
+ */
+
+extern
+int DivasCardsDiscover(void);
+
+/*
+ * initialise a new card
+ */
+
+int DivasCardNew(dia_card_t *card);
+
+/*
+ * configure specified card
+ */
+
+int DivasCardConfig(dia_config_t *config);
+
+/*
+ * load specified binary code onto card
+ */
+
+int DivasCardLoad(dia_load_t *load);
+
+/*
+ * start specified card running
+ */
+
+int DivasCardStart(int card_id);
+
+/*
+ * ISR for card
+ * Returns 0 if specified card was interrupting
+ */
+
+int DivasIsr(void *arg);
+
+/*
+ * Get number of active cards
+ */
+
+int DivasGetNum(void);
+
+/*
+ * Get list of active cards
+ */
+
+int DivasGetList(dia_card_list_t *card_list);
+
+/* definitions common to several card types */
+
+#define DIVAS_SHARED_OFFSET (0x1000)
+
+#endif /* ADAPTER_H */
diff --git a/drivers/isdn/eicon/bri.c b/drivers/isdn/eicon/bri.c
new file mode 100644
index 000000000..5a8afc11d
--- /dev/null
+++ b/drivers/isdn/eicon/bri.c
@@ -0,0 +1,717 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.8
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <sys/types.h>
+
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "dsp_defs.h"
+
+#include "adapter.h"
+#include "uxio.h"
+
+#define PCI_COMMAND 0x04
+#define PCI_STATUS 0x06
+#define PCI_LATENCY 0x0D
+#define PCI_BADDR0 0x10
+#define PCI_BADDR1 0x14
+#define PCI_BADDR2 0x18
+
+#define DIVAS_SIGNATURE 0x4447
+
+/* offset to start of MAINT area (used by xlog) */
+
+#define DIVAS_MAINT_OFFSET 0xff00 /* value for BRI card */
+
+#define PROTCAP_TELINDUS 0x1
+#define PROTCAP_V90D 0x8
+
+word GetProtFeatureValue(char *sw_id);
+byte io_in(ADAPTER *a, void *adr);
+word io_inw(ADAPTER *a, void *adr);
+void io_in_buffer(ADAPTER *a, void *adr, void *P, word length);
+void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e);
+void io_out(ADAPTER *a, void *adr, byte data);
+void io_outw(ADAPTER *a, void *adr, word data);
+void io_out_buffer(ADAPTER *a, void *adr, void *P, word length);
+void io_inc(ADAPTER *a, void *adr);
+
+static int diva_server_bri_test_int(card_t *card);
+
+#define PLX_IOBASE 0
+#define DIVAS_IOBASE 1
+
+#define REG_DATA 0x00
+#define REG_ADDRLO 0x04
+#define REG_ADDRHI 0x0C
+#define REG_IOCTRL 0x10
+
+#define M_PCI_RESET 0x10
+
+byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset);
+word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset);
+void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte);
+void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word);
+
+int DivasBRIInitPCI(card_t *card, dia_card_t *cfg);
+int bri_ISR (card_t* card);
+
+static
+int diva_server_bri_reset(card_t *card)
+{
+ byte *DivasIOBase;
+ word i;
+ dword dwWait;
+
+ UxCardLog(0);
+
+ DPRINTF(("divas: resetting BRI adapter"));
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0);
+
+ for (i=0; i < 50000; i++)
+ ;
+
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0);
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0);
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0);
+
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x0000);
+
+ for (i=0; i<0x8000; i++)
+ {
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0);
+ }
+
+ for (dwWait=0; dwWait < 0x00FFFFFF; dwWait++)
+ ;
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return 0;
+}
+
+static
+void diva_server_bri_reset_int(card_t *card)
+{
+ byte *DivasIOBase = NULL;
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08);
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return;
+}
+
+static
+int diva_server_bri_start(card_t *card, byte *channels)
+{
+ byte *DivasIOBase, *PLXIOBase;
+ word wSig = 0;
+ word i;
+ dword dwSerialNum;
+ byte bPLX9060 = FALSE;
+
+ DPRINTF(("divas: starting Diva Server BRI card"));
+
+ card->is_live = FALSE;
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E);
+
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA , 0);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA , 0);
+
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08);
+
+ /* wait for signature to indicate card has started */
+ for (i = 0; i < 300; i++)
+ {
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E);
+ wSig = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA);
+
+ if (wSig == DIVAS_SIGNATURE)
+ {
+ DPRINTF(("divas: card started after %d ms", i * 10));
+ break;
+ }
+ UxPause(10);
+ }
+
+ if (wSig != DIVAS_SIGNATURE)
+ {
+ DPRINTF(("divas: card failed to start (Sig=0x%x)", wSig));
+ UxCardMemDetach(card->hw, DivasIOBase);
+ return -1;
+ }
+
+ card->is_live = TRUE;
+
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x3F6);
+ *channels = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA);
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE);
+
+ bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) | UxCardPortIoInW(card->hw, PLXIOBase, 0x6E);
+
+ if (bPLX9060)
+ {
+ dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x1E) << 16) |
+ (UxCardPortIoInW(card->hw, PLXIOBase, 0x22));
+ DPRINTF(("divas: PLX9060 in use. Serial number 0x%04X", dwSerialNum));
+ }
+ else
+ {
+ dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x22) << 16) |
+ (UxCardPortIoInW(card->hw, PLXIOBase, 0x26));
+ DPRINTF(("divas: PLX9050 in use. Serial number 0x%04X", dwSerialNum));
+ }
+
+ UxCardMemDetach(card->hw, PLXIOBase);
+
+ card->serial_no = dwSerialNum;
+
+ diva_server_bri_test_int(card);
+
+ return 0;
+}
+
+static
+int diva_server_bri_load(card_t *card, dia_load_t *load)
+{
+ byte *DivasIOBase;
+ dword r3000_base;
+ dword dwAddr, dwLength, i;
+ word wTest, aWord;
+
+ DPRINTF(("divas: loading Diva Server BRI card"));
+
+ switch (load->code_type)
+ {
+ case DIA_CPU_CODE:
+ DPRINTF(("divas: loading RISC %s", &load->code[0x80]));
+
+ card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]);
+ DPRINTF(("divas: features 0x%x", card->hw->features));
+ if (card->hw->features == 0xFFFF)
+ {
+ DPRINTF(("divas: invalid feature string failed load\n"));
+ return -1;
+ }
+
+ r3000_base = 0;
+ break;
+
+ case DIA_DSP_CODE:
+ DPRINTF(("divas: DSP code \"%s\"", load->code));
+
+ if ((card->hw->features) && (!(card->hw->features & PROTCAP_TELINDUS)))
+ {
+ DPRINTF(("divas: only Telindus style binaries supported"));
+ return -1;
+ }
+
+ if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+ {
+ DPRINTF(("divas: V.90 DSP binary"));
+ r3000_base = (0xBF790000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC));
+ }
+ else
+ {
+ DPRINTF(("divas: non-V.90 DSP binary"));
+ r3000_base = (0xBF7A0000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC));
+ }
+ DPRINTF(("divas: loading at 0x%x", r3000_base));
+ break;
+
+ case DIA_TABLE_CODE:
+ DPRINTF(("divas: TABLE code"));
+ if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+ {
+ r3000_base = 0xBF790000 + sizeof(dword);
+ }
+ else
+ {
+ r3000_base = 0xBF7A0000 + sizeof(dword);
+ }
+
+ break;
+
+ case DIA_DLOAD_CNT:
+ DPRINTF(("divas: COUNT code"));
+ if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+ {
+ r3000_base = 0xBF790000;
+ }
+ else
+ {
+ r3000_base = 0xBF7A0000;
+ }
+ break;
+
+ default:
+ DPRINTF(("divas: unknown code type %d", load->code_type));
+ return -1;
+ break;
+ }
+
+ DPRINTF(("divas: Writing %d bytes to adapter, address 0x%x", load->length, r3000_base));
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ DPRINTF(("divas: Attached to 0x%04X", DivasIOBase));
+
+ dwLength = load->length;
+
+ for (i=0; i < dwLength; i++)
+ {
+ dwAddr = r3000_base + i;
+
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16);
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr);
+
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, load->code[i]);
+ }
+
+ DPRINTF(("divas: Verifying"));
+
+ for (i=0; i<dwLength; i++)
+ {
+ dwAddr = r3000_base + i;
+
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16);
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr);
+
+ wTest = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA);
+
+ aWord = load->code[i];
+
+ if (wTest != aWord)
+ {
+ DPRINTF(("divas: load verify failed on byte %d", i));
+ DPRINTF(("divas: RAM 0x%x File 0x%x",wTest,aWord));
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return -1;
+ }
+ }
+
+ DPRINTF(("divas: Loaded and verified. Detaching from adapter"));
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ UxCardLog(0);
+
+ return 0;
+}
+
+static
+int diva_server_bri_config(card_t *card, dia_config_t *config)
+{
+ byte *DivasIOBase, i;
+
+ DPRINTF(("divas: configuring Diva Server BRI card"));
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 8);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->tei);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 9);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->nt2);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 10);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 11);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->watchdog);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 12);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->permanent);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 13);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 14);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->stable_l2);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 15);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->no_order_check);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 16);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 17);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 18);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->low_channel);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 19);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->prot_version);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 20);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->crc4);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 21);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+
+ if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+ {
+ DPRINTF(("divas: Signifying V.90"));
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 4);
+ }
+ else
+ {
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+ }
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 23);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, card->serial_no & 0xFF);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 24);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 8) & 0xFF);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 25);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 16) & 0xFF);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 26);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 21);
+
+ for (i=0; i<32; i++)
+ {
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 32+i);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].oad[i]);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 64+i);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].osa[i]);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 96+i);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].spid[i]);
+
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 128+i);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].oad[i]);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 160+i);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].osa[i]);
+
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 192+i);
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].spid[i]);
+ }
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return 0;
+}
+
+void DivasBriPatch(card_t *card)
+{
+ dword PLXIOBase = 0;
+ dword DivasIOBase = 0;
+
+ PLXIOBase = card->cfg.reset_base;
+ DivasIOBase = card->cfg.io_base;
+
+ if(card->hw == NULL)
+ {
+ DPRINTF(("Divas: BRI PATCH (PLX chip) card->hw is null"));
+ return;
+ }
+
+ if (PLXIOBase == 0)
+ {
+ DPRINTF(("Divas: BRI (PLX chip) cannot be patched. The BRI adapter may"));
+ DPRINTF(("Divas: not function properly. If you do encounter problems,"));
+ DPRINTF(("Divas: ensure that your machine is using the latest BIOS."));
+ return;
+ }
+
+ DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase));
+ DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase));
+
+ if (PLXIOBase & 0x80)
+ {
+ dword dwSize, dwSerialNum, dwCmd;
+ boolean_t bPLX9060;
+ word wSerHi, wSerLo;
+
+ DPRINTF(("Divas: Patch required"));
+ dwCmd = 0;
+ UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd);
+
+ PLXIOBase &= ~0x80;
+ UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &PLXIOBase);
+
+ dwSize = 0xFFFFFFFF;
+ UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &dwSize);
+ UxPciConfigRead(card->hw, 4, PCI_BADDR1, &dwSize);
+
+ dwSize = (~ (dwSize & ~7)) + 1;
+
+ DivasIOBase = PLXIOBase + dwSize;
+
+ card->cfg.reset_base = PLXIOBase;
+ card->cfg.io_base = DivasIOBase;
+ UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &card->cfg.reset_base);
+ UxPciConfigWrite(card->hw, 4, PCI_BADDR2, &card->cfg.io_base);
+
+ dwCmd = 5;
+ UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd);
+
+ bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) |
+ UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E);
+
+ if (bPLX9060)
+ {
+ wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E);
+ wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
+ dwSerialNum = (wSerHi << 16) | wSerLo;
+ UxCardLog(0);
+ }
+ else
+ {
+ wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
+ wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26);
+ dwSerialNum = (wSerHi << 16) | wSerLo;
+ UxCardLog(0);
+ }
+ }
+ else
+ {
+ word wSerHi, wSerLo;
+ boolean_t bPLX9060;
+ dword dwSerialNum;
+
+ DPRINTF(("divas: No patch required"));
+
+ bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) |
+ UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E);
+
+ if (bPLX9060)
+ {
+ wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E);
+ wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
+ dwSerialNum = (wSerHi << 16) | wSerLo;
+ }
+ else
+ {
+ wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
+ wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26);
+ dwSerialNum = (wSerHi << 16) | wSerLo;
+ }
+ }
+ DPRINTF(("Divas: After patching:"));
+ DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase));
+ DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase));
+
+}
+
+#define TEST_INT_DIVAS_BRI 0x12
+static
+int diva_server_bri_test_int(card_t *card)
+{
+ boolean_t bPLX9060 = FALSE;
+ byte *PLXIOBase = NULL, *DivasIOBase = NULL;
+
+ DPRINTF(("divas: test interrupt for Diva Server BRI card"));
+
+ PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE);
+
+ bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) || UxCardPortIoInW(card->hw, PLXIOBase, 0x6E);
+
+ if (bPLX9060)
+ { /* PLX9060 */
+ UxCardPortIoOut(card->hw, PLXIOBase, 0x69, 0x09);
+ }
+ else
+ { /* PLX9050 */
+ UxCardPortIoOut(card->hw, PLXIOBase, 0x4C, 0x41);
+ }
+
+ card->test_int_pend = TEST_INT_DIVAS_BRI;
+
+ UxCardMemDetach(card->hw, PLXIOBase);
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x89);
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return 0;
+}
+
+static
+int diva_server_bri_mem_get(card_t *card, mem_block_t *mem_block)
+{
+ dword user_addr = mem_block->addr;
+ word length = 0;
+ dword addr;
+ word i;
+ byte *DivasIOBase;
+
+ DPRINTF(("divas: Retrieving memory from 0x%x", user_addr));
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ addr = user_addr;
+
+ for (i=0; i < (16 * 8); i++)
+ {
+ addr = user_addr + i;
+
+ UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, addr >> 16);
+ UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, (word) addr);
+
+ mem_block->data[i] = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA);
+ length++;
+ }
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return length;
+}
+
+int DivasBriInit(card_t *card, dia_card_t *cfg)
+{
+ DPRINTF(("divas: initialise Diva Server BRI card"));
+
+ if (DivasBRIInitPCI(card, cfg) == -1)
+ {
+ return -1;
+ }
+
+ card->card_reset = diva_server_bri_reset;
+ card->card_start = diva_server_bri_start;
+ card->card_load = diva_server_bri_load;
+ card->card_config = diva_server_bri_config;
+ card->reset_int = diva_server_bri_reset_int;
+ card->card_mem_get = diva_server_bri_mem_get;
+
+ card->xlog_offset = DIVAS_MAINT_OFFSET;
+
+ card->out = DivasOut;
+ card->test_int = DivasTestInt;
+ card->dpc = DivasDpc;
+ card->clear_int = DivasClearInt;
+ card->card_isr = bri_ISR;
+
+ card->a.ram_out = io_out;
+ card->a.ram_outw = io_outw;
+ card->a.ram_out_buffer = io_out_buffer;
+ card->a.ram_inc = io_inc;
+
+ card->a.ram_in = io_in;
+ card->a.ram_inw = io_inw;
+ card->a.ram_in_buffer = io_in_buffer;
+ card->a.ram_look_ahead = io_look_ahead;
+
+ return 0;
+}
+
+word GetProtFeatureValue(char *sw_id)
+{
+ word features = 0;
+
+ while ((*sw_id) && (sw_id[0] != '['))
+ sw_id++;
+
+ if (sw_id == NULL)
+ {
+ DPRINTF(("divas: no feature string present"));
+ features = -1;
+ }
+ else
+ {
+ byte i, shifter;
+
+ sw_id += 3;
+
+ for (i=0, shifter=12; i<4; i++, shifter-=4)
+ {
+ if ((sw_id[i] >= '0') && (sw_id[i] <= '9'))
+ {
+ features |= (sw_id[i] - '0') << shifter;
+ }
+ else if ((sw_id[i] >= 'a') && (sw_id[i] <= 'f'))
+ {
+ features |= (sw_id[i] - 'a' + 10) << shifter;
+ }
+ else if ((sw_id[i] >= 'A') && (sw_id[i] <= 'F'))
+ {
+ features |= (sw_id[i] - 'A' + 10) << shifter;
+ }
+ else
+ {
+ DPRINTF(("divas: invalid feature string"));
+ return -1;
+ }
+ }
+ }
+
+ return features;
+}
+
+
+int bri_ISR (card_t* card)
+{
+ int served = 0;
+ byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01)
+ {
+ served = 1;
+ card->int_pend += 1;
+ DivasDpcSchedule(); /* ISR DPC */
+ UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08);
+ }
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return (served != 0);
+}
+
+
diff --git a/drivers/isdn/eicon/common.c b/drivers/isdn/eicon/common.c
new file mode 100644
index 000000000..4a4f77d9f
--- /dev/null
+++ b/drivers/isdn/eicon/common.c
@@ -0,0 +1,896 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.15
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include "sys.h"
+#include "idi.h"
+#include "constant.h"
+#include "divas.h"
+#include "pc.h"
+#include "pr_pc.h"
+
+#include "uxio.h"
+#include <sys/types.h>
+
+#define MAX_ADDR_LEN
+
+#define DIVAS_LOAD_CMD 0x02
+#define DIVAS_START_CMD 0x03
+#define DIVAS_IRQ_RESET 0xC18
+#define DIVAS_IRQ_RESET_VAL 0xFE
+
+#define PCI_COMMAND 0x04
+#define PCI_STATUS 0x06
+#define PCI_LATENCY 0x0D
+#define PCI_INTERRUPT 0x3C
+
+#define TEST_INT_DIVAS 0x11
+#define TEST_INT_DIVAS_BRI 0x12
+#define TEST_INT_DIVAS_Q 0x13
+
+#define DIVAS_RESET 0x81
+#define DIVAS_LED1 0x04
+#define DIVAS_LED2 0x08
+#define DIVAS_LED3 0x20
+#define DIVAS_LED4 0x40
+
+#define DIVAS_SIGNATURE 0x4447
+
+#define MP_PROTOCOL_ADDR 0xA0011000
+
+#define PLX_IOBASE 0
+#define DIVAS_IOBASE 1
+
+typedef struct {
+ dword cmd;
+ dword addr;
+ dword len;
+ dword err;
+ dword live;
+ dword reserved[(0x1020>>2)-6];
+ dword signature;
+ byte data[1];
+} diva_server_boot_t;
+
+int DivasCardNext;
+card_t DivasCards[MAX_CARDS];
+
+dia_config_t *DivasConfig(card_t *, dia_config_t *);
+
+static
+DESCRIPTOR DIDD_Table[16];
+static
+int DIDD_Length = 0;
+
+void EtdM_DIDD_Read( DESCRIPTOR *table, int *tablelength )
+{
+ int table_size = sizeof(DIDD_Table);
+
+ bcopy((caddr_t)DIDD_Table, (caddr_t)table, table_size);
+
+ *tablelength = DIDD_Length;
+
+ return;
+}
+
+static
+void EtdM_DIDD_Write(DESCRIPTOR *table, int tablelength)
+{
+ int table_size = sizeof(DIDD_Table);
+
+ bcopy((caddr_t)table, (caddr_t)DIDD_Table, table_size);
+
+ DIDD_Length = tablelength;
+
+ return;
+}
+
+static
+void init_idi_tab(void)
+{
+ int length = 0;
+
+ DESCRIPTOR d[16];
+
+ EtdM_DIDD_Read(d, &length);
+
+ d[length].type = IDI_DIMAINT; /* identify the DIMAINT entry */
+ d[length].channels = 0; /* zero channels associated with dimaint*/
+ d[length].features = 0; /* no features associated with dimaint */
+ d[length].request = (IDI_CALL) DivasPrintf;
+ length++;
+
+ EtdM_DIDD_Write(d, length);
+
+ return;
+}
+
+/*
+ * I/O routines for memory mapped cards
+ */
+
+byte mem_in(ADAPTER *a, void *adr)
+{
+ card_t *card = a->io;
+ unsigned char *b, *m;
+ byte value;
+
+ m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+ m += (unsigned int) adr;
+
+ value = UxCardMemIn(card->hw, m);
+
+ UxCardMemDetach(card->hw, b);
+
+ return value;
+}
+
+word mem_inw(ADAPTER *a, void *adr)
+{
+ card_t *card = a->io;
+ unsigned char *b, *m;
+ word value;
+
+ m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+ m += (unsigned int) adr;
+
+ value = UxCardMemInW(card->hw, m);
+
+ UxCardMemDetach(card->hw, b);
+
+ return value;
+}
+
+void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length)
+{
+ card_t *card = a->io;
+ unsigned char *b, *m;
+
+ m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+ m += (unsigned int) adr;
+
+ UxCardMemInBuffer(card->hw, m, P, length);
+
+ UxCardMemDetach(card->hw, b);
+
+ return;
+}
+
+void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e)
+{
+ card_t *card = a->io;
+ unsigned char *b, *m;
+
+ m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+ m += (dword) &RBuffer->length;
+ card->RBuffer.length = UxCardMemInW(card->hw, m);
+
+ m = b;
+ m += (dword) &RBuffer->P;
+ UxCardMemInBuffer(card->hw, m, card->RBuffer.P, card->RBuffer.length);
+
+ e->RBuffer = (DBUFFER *) &card->RBuffer;
+
+ UxCardMemDetach(card->hw, b);
+
+ return;
+}
+
+void mem_out(ADAPTER *a, void *adr, byte data)
+{
+ card_t *card = a->io;
+ unsigned char *b, *m;
+
+ m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+ m += (unsigned int) adr;
+
+ UxCardMemOut(card->hw, m, data);
+
+ UxCardMemDetach(card->hw, b);
+
+ return;
+}
+
+void mem_outw(ADAPTER *a, void *adr, word data)
+{
+ card_t *card = a->io;
+ unsigned char *b, *m;
+
+ m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+ m += (unsigned int) adr;
+
+ UxCardMemOutW(card->hw, m, data);
+
+ UxCardMemDetach(card->hw, b);
+
+ return;
+}
+
+void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length)
+{
+ card_t *card = a->io;
+ unsigned char *b, *m;
+
+ m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+ m += (unsigned int) adr;
+
+ UxCardMemOutBuffer(card->hw, m, P, length);
+
+ UxCardMemDetach(card->hw, b);
+
+ return;
+}
+
+void mem_inc(ADAPTER *a, void *adr)
+{
+ word value;
+ card_t *card = a->io;
+ unsigned char *b, *m;
+
+ m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+ m += (unsigned int) adr;
+
+ value = UxCardMemInW(card->hw, m);
+ value++;
+ UxCardMemOutW(card->hw, m, value);
+
+ UxCardMemDetach(card->hw, b);
+
+ return;
+}
+
+/*
+ * I/O routines for I/O mapped cards
+ */
+
+byte io_in(ADAPTER *a, void *adr)
+{
+ card_t *card = a->io;
+ byte value;
+ byte *DivasIOBase = NULL;
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ value = UxCardIoIn(card->hw, DivasIOBase, adr);
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return value;
+}
+
+word io_inw(ADAPTER *a, void *adr)
+{
+ card_t *card = a->io;
+ word value;
+ byte *DivasIOBase = NULL;
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ value = UxCardIoInW(card->hw, DivasIOBase, adr);
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return value;
+}
+
+void io_in_buffer(ADAPTER *a, void *adr, void *P, word length)
+{
+ card_t *card = a->io;
+ byte *DivasIOBase = NULL;
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ UxCardIoInBuffer(card->hw, DivasIOBase, adr, P,length);
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return;
+}
+
+void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e)
+{
+ card_t *card = a->io;
+ byte *DivasIOBase = NULL;
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ card->RBuffer.length = UxCardIoInW(card->hw, DivasIOBase, (byte *) RBuffer);
+
+ UxCardIoInBuffer(card->hw, DivasIOBase, &RBuffer->P, card->RBuffer.P, card->RBuffer.length);
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ e->RBuffer = (DBUFFER *) &card->RBuffer;
+
+ return;
+}
+
+void io_out(ADAPTER *a, void *adr, byte data)
+{
+ card_t *card = a->io;
+ byte *DivasIOBase = NULL;
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ UxCardIoOut(card->hw, DivasIOBase, adr, data);
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return;
+}
+
+void io_outw(ADAPTER *a, void *adr, word data)
+{
+ card_t *card = a->io;
+ byte *DivasIOBase = NULL;
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ UxCardIoOutW(card->hw, DivasIOBase, adr, data);
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return;
+}
+
+void io_out_buffer(ADAPTER *a, void *adr, void *P, word length)
+{
+ card_t *card = a->io;
+ byte *DivasIOBase = NULL;
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ UxCardIoOutBuffer(card->hw, DivasIOBase, adr, P, length);
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return;
+}
+
+void io_inc(ADAPTER *a, void *adr)
+{
+ word value;
+ card_t *card = a->io;
+ byte *DivasIOBase;
+
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+ value = UxCardIoInW(card->hw, DivasIOBase, adr);
+
+ value++;
+
+ UxCardIoOutW(card->hw, DivasIOBase, adr, value);
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return;
+}
+
+static
+void test_int(card_t *card)
+
+{
+ byte *shared, *DivasIOBase;
+
+ switch (card->test_int_pend)
+ {
+ case TEST_INT_DIVAS:
+ DPRINTF(("divas: test interrupt pending"));
+ shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+ if (UxCardMemIn(card->hw, &shared[0x3FE]))
+ {
+ UxCardMemOut(card->hw,
+ &(((struct pr_ram *)shared)->RcOutput), 0);
+ UxCardMemDetach(card->hw, shared);
+ (*card->reset_int)(card);
+ shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+ UxCardMemOut(card->hw, &shared[0x3FE], 0);
+ DPRINTF(("divas: test interrupt cleared"));
+ }
+
+ UxCardMemDetach(card->hw, shared);
+
+ card->test_int_pend = 0;
+ break;
+
+ case TEST_INT_DIVAS_BRI:
+ DPRINTF(("divas: BRI test interrupt pending"));
+ (*card->reset_int)(card);
+ DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+ UxCardIoOutW(card->hw, DivasIOBase, (void *) 0x3FE, 0);
+ UxCardMemDetach(card->hw, DivasIOBase);
+ DPRINTF(("divas: test interrupt cleared"));
+ card->test_int_pend = 0;
+ break;
+
+ case TEST_INT_DIVAS_Q:
+ DPRINTF(("divas: 4BRI test interrupt pending"));
+ (*card->reset_int)(card);
+ card->test_int_pend = 0;
+ break;
+
+ default:
+ DPRINTF(("divas: unknown test interrupt pending"));
+ return;
+ }
+ return;
+}
+
+void card_isr (void *dev_id)
+{
+ card_t *card = (card_t *) dev_id;
+ ADAPTER *a = &card->a;
+ int ipl;
+
+ if (card->test_int_pend)
+ {
+ ipl = UxCardLock(card->hw);
+ card->int_pend=0;
+ test_int(card);
+ UxCardUnlock(card->hw,ipl);
+ return;
+ }
+
+ if(card->card_isr)
+ {
+ (*(card->card_isr))(card);
+ }
+ else
+ {
+ ipl = UxCardLock(card->hw);
+
+ if ((card->test_int)(a))
+ {
+ (card->reset_int)(card);
+ }
+
+ UxCardUnlock(card->hw,ipl);
+
+ }
+
+}
+
+int DivasCardNew(dia_card_t *card_info)
+{
+ card_t *card;
+ byte b;
+ static boolean_t first_call = TRUE;
+ boolean_t NeedISRandReset = FALSE;
+
+ DPRINTF(("divas: new card "));
+
+ if (first_call)
+ {
+ first_call = FALSE;
+ init_idi_tab();
+ }
+
+ DivasConfigGet(card_info);
+
+ if (DivasCardNext == DIM(DivasCards))
+ {
+ KDPRINTF((KERN_WARNING "Divas: no space available for new card"));
+ return -1;
+ }
+
+ card = &DivasCards[DivasCardNext];
+
+ card->state = DIA_UNKNOWN;
+
+ card->cfg = *card_info;
+
+ card->a.io = card;
+
+ if (UxCardHandleGet(&card->hw, card_info))
+ {
+ KDPRINTF((KERN_WARNING "Divas: cannot get OS specific handle for card"));
+ return -1;
+ }
+
+ if (card_info->card_type == DIA_CARD_TYPE_DIVA_SERVER_B)
+ {
+ DivasBriPatch(card);
+ card_info->io_base = card->cfg.io_base;
+ }
+
+ switch (card_info->card_type)
+ {
+ case DIA_CARD_TYPE_DIVA_SERVER:
+ if (DivasPriInit(card, card_info))
+ {
+ return -1;
+ }
+ NeedISRandReset = TRUE;
+ break;
+
+ case DIA_CARD_TYPE_DIVA_SERVER_B:
+ if (DivasBriInit(card, card_info))
+ {
+ return -1;
+ }
+ NeedISRandReset = TRUE;
+ break;
+
+ case DIA_CARD_TYPE_DIVA_SERVER_Q:
+ if (Divas4BriInit(card, card_info))
+ {
+ return -1;
+ }
+
+ if (card_info->name[6] == '0')
+ {
+ NeedISRandReset = TRUE;
+ }
+ else // Need to set paramater for ISR anyway
+ {
+ card->hw->user_isr_arg = card;
+ card->hw->user_isr = card_isr;
+ }
+ break;
+
+ default:
+ KDPRINTF((KERN_WARNING "Divas: unsupported card type (%d)", card_info->card_type));
+ return -1;
+ }
+
+ if (NeedISRandReset)
+ {
+ if (UxIsrInstall(card->hw, card_isr, card))
+ {
+ KDPRINTF((KERN_WARNING "Divas: Install ISR failed (IRQ %d)", card->cfg.irq));
+ UxCardHandleFree(card->hw);
+ return -1;
+ }
+
+ b = card->cfg.irq;
+
+ UxPciConfigWrite(card->hw, sizeof(b), PCI_INTERRUPT, &b);
+
+ if (card_info->card_type != DIA_CARD_TYPE_DIVA_SERVER_Q)
+ {
+ if ((*card->card_reset)(card))
+ {
+ KDPRINTF((KERN_WARNING "Divas: Adapter reset failed"));
+ return -1;
+ }
+ card->state = DIA_RESET;
+ }
+
+ NeedISRandReset = FALSE;
+ }
+
+ DivasCardNext++;
+
+ return 0;
+}
+
+void *get_card(int card_id)
+{
+ int i;
+
+ for (i=0; i < DivasCardNext; i++)
+ {
+ if (DivasCards[i].cfg.card_id == card_id)
+ {
+ return(&DivasCards[i]);
+ }
+ }
+
+ DPRINTF(("divas: get_card() : no such card id (%d)", card_id));
+
+ return NULL;
+}
+
+int DivasCardConfig(dia_config_t *config)
+{
+ card_t *card;
+ int status;
+
+ DPRINTF(("divas: configuring card"));
+
+ card = get_card(config->card_id);
+ if (!card)
+ {
+ return -1;
+ }
+
+ config = DivasConfig(card, config);
+
+ status = (*card->card_config)(card, config);
+
+ if (!status)
+ {
+ card->state = DIA_CONFIGURED;
+ }
+ return status;
+}
+
+int DivasCardLoad(dia_load_t *load)
+{
+ card_t *card;
+ int status;
+
+ card = get_card(load->card_id);
+ if (!card)
+ {
+ return -1;
+ }
+
+ if (card->state == DIA_RUNNING)
+ {
+ (*card->card_reset)(card);
+ }
+
+ status = (*card->card_load)(card, load);
+ if (!status)
+ {
+ card->state = DIA_LOADED;
+ }
+ return status;
+}
+
+static int idi_register(card_t *card, byte channels)
+{
+ DESCRIPTOR d[16];
+ int length, num_entities;
+
+ DPRINTF(("divas: registering card with IDI"));
+
+ num_entities = (channels > 2) ? MAX_PENTITIES : MAX_ENTITIES;
+ card->e_tbl = UxAlloc(sizeof(E_INFO) * num_entities);
+
+ if (!card->e_tbl)
+ {
+ KDPRINTF((KERN_WARNING "Divas: IDI register failed - no memory available"));
+ return -1;
+ }
+
+ bzero(card->e_tbl, sizeof(E_INFO) * num_entities);
+ card->e_max = num_entities;
+
+ EtdM_DIDD_Read(d, &length);
+
+ if (length == DIM(d))
+ {
+ KDPRINTF((KERN_WARNING "Divas: IDI register failed - table full"));
+ return -1;
+ }
+
+ switch (card->cfg.card_type)
+ {
+ case DIA_CARD_TYPE_DIVA_SERVER:
+ d[length].type = IDI_ADAPTER_PR;
+ d[length].serial = card->serial_no;
+ break;
+
+ case DIA_CARD_TYPE_DIVA_SERVER_B:
+ d[length].type = IDI_ADAPTER_MAESTRA;
+ d[length].serial = card->serial_no;
+ break;
+
+ // 4BRI is treated as 4 BRI adapters
+ case DIA_CARD_TYPE_DIVA_SERVER_Q:
+ d[length].type = IDI_ADAPTER_MAESTRA;
+ d[length].serial = card->cfg.serial;
+ }
+
+ d[length].features = 0;
+ d[length].features |= DI_FAX3|DI_MODEM|DI_POST|DI_V110|DI_V120;
+
+ if ( card->hw->features & PROTCAP_MANIF )
+ {
+ d[length].features |= DI_MANAGE ;
+ }
+ if ( card->hw->features & PROTCAP_V_42 )
+ {
+ d[length].features |= DI_V_42 ;
+ }
+ if ( card->hw->features & PROTCAP_EXTD_FAX )
+ {
+ d[length].features |= DI_EXTD_FAX ;
+ }
+
+ d[length].channels = channels;
+ d[length].request = DivasIdiRequest[card - DivasCards];
+
+ length++;
+
+ EtdM_DIDD_Write(d, length);
+
+ return 0;
+}
+
+int DivasCardStart(int card_id)
+{
+ card_t *card;
+ byte channels;
+ int status;
+
+ DPRINTF(("divas: starting card"));
+
+ card = get_card(card_id);
+ if (!card)
+ {
+ return -1;
+ }
+
+ status = (*card->card_start)(card, &channels);
+ if (status)
+ {
+ return status;
+ }
+
+ /* 4BRI == 4 x BRI so call idi_register 4 times each with 2 channels */
+ if (card->cfg.card_type == DIA_CARD_TYPE_DIVA_SERVER_Q)
+ {
+ int i;
+ card_t *FourBRISlave;
+
+ for (i=3; i >= 0; i--)
+ {
+ FourBRISlave = get_card(card_id - i); /* 0, 1, 2, 3 */
+ if (FourBRISlave)
+ {
+ idi_register(FourBRISlave, 2);
+ FourBRISlave->state = DIA_RUNNING;
+ }
+ }
+ card->serial_no = card->cfg.serial;
+
+ DPRINTF(("divas: card id %d (4BRI), serial no. 0x%x ready with %d channels",
+ card_id - 3, card->serial_no, (int) channels));
+ }
+ else
+ {
+ status = idi_register(card, channels);
+ if (!status)
+ {
+ card->state = DIA_RUNNING;
+ DPRINTF(("divas: card id %d, serial no. 0x%x ready with %d channels",
+ card_id, card->serial_no, (int) channels));
+ }
+ }
+
+ return status;
+}
+
+int DivasGetMem(mem_block_t *mem_block)
+{
+ card_t *card;
+ word card_id = mem_block->card_id;
+
+ card = get_card(card_id);
+ if (!card)
+ {
+ return 0;
+ }
+
+ return (*card->card_mem_get)(card, mem_block);
+}
+
+
+/*
+ * Deleyed Procedure Call for handling interrupts from card
+ */
+
+void DivaDoCardDpc(card_t *card)
+{
+ ADAPTER *a;
+
+ a = &card->a;
+
+ if(UxInterlockedIncrement(card->hw, &card->dpc_reentered) > 1)
+ {
+ return;
+ }
+
+ do{
+ if((*(card->test_int))(a))
+ {
+ (*(card->dpc))(a);
+ (*(card->clear_int))(a);
+ }
+ (*(card->out))(a);
+ }while(UxInterlockedDecrement(card->hw, &card->dpc_reentered));
+
+}
+
+void DivasDoDpc(void *pData)
+{
+ card_t *card = DivasCards;
+ int i = DivasCardNext;
+
+ while(i--)
+ {
+ DivaDoCardDpc(card++);
+ }
+}
+
+void DivasDoRequestDpc(void *pData)
+{
+ DivasDoDpc(pData);
+}
+
+/*
+ * DivasGetNum
+ * Returns the number of active adapters
+ */
+
+int DivasGetNum(void)
+{
+ return(DivasCardNext);
+}
+
+/*
+ * DivasGetList
+ * Returns a list of active adapters
+ */
+int DivasGetList(dia_card_list_t *card_list)
+{
+ int i;
+
+ bzero(card_list, sizeof(dia_card_list_t));
+
+ for(i = 0; i < DivasCardNext; i++)
+ {
+ card_list->card_type = DivasCards[i].cfg.card_type;
+ card_list->card_slot = DivasCards[i].cfg.slot;
+ card_list->state = DivasCards[i].state;
+ card_list++;
+ }
+
+ return 0;
+
+}
+
+/*
+ * control logging for specified card
+ */
+
+void DivasLog(dia_log_t *log)
+{
+ card_t *card;
+
+ card = get_card(log->card_id);
+ if (!card)
+ {
+ return;
+ }
+
+ card->log_types = log->log_types;
+
+ return;
+}
+
diff --git a/drivers/isdn/eicon/constant.h b/drivers/isdn/eicon/constant.h
new file mode 100644
index 000000000..ea92f05ad
--- /dev/null
+++ b/drivers/isdn/eicon/constant.h
@@ -0,0 +1,179 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+/*------------------------------------------------------------------*/
+/* Q.931 information elements maximum length */
+/* excluding the identifier, including the length field */
+/*------------------------------------------------------------------*/
+
+#define MAX_LEN_BC 13
+#define MAX_LEN_LLC 19 /* ctr3 */
+#define MAX_LEN_HLC 6 /* ctr3 */
+#define MAX_LEN_UUI 200 /* Hicom USBS req */
+#define MAX_LEN_NUM 24
+#define MAX_LEN_DSP 83 /* ctr3 */
+#define MAX_LEN_NI 4
+#define MAX_LEN_PI 5
+#define MAX_LEN_SIN 3
+#define MAX_LEN_CST 4
+#define MAX_LEN_SIG 2
+#define MAX_LEN_SPID 32
+#define MAX_LEN_EID 3
+#define MAX_LEN_CHI 35 /* ctr3 */
+#define MAX_LEN_CAU 33
+#define MAX_LEN_FTY 130
+#define MAX_LEN_KEY 83 /* ctr3 */
+#define MAX_LEN_RSI 4
+#define MAX_LEN_CAI 11
+#define MAX_NUM_SPID 4
+#define MAX_LEN_USERID 9
+#define MAX_LEN_APPLID 5
+#define MAX_LEN_NTTCIF 15
+
+/*------------------------------------------------------------------*/
+/* decision return values */
+/*------------------------------------------------------------------*/
+
+#define YES 1
+#define NO 0
+
+
+/*-------------------------------------------------------------------*/
+/* w element coding */
+/*-------------------------------------------------------------------*/
+
+#define NTTCIF 0x01
+#define BC 0x04
+#define CAU 0x08
+#define CAD 0x0c
+#define CAI 0x10
+#define CST 0x14
+#define CHI 0x18
+#define LLI 0x19
+#define CHA 0x1a
+#define FTY 0x1c
+#define PI 0x1e
+#define NFAC 0x20
+#define TC 0x24
+#define ATT_EID 0x26
+#define NI 0x27
+#define DSP 0x28
+#define DT 0x29
+#define KEY 0x2c
+#define KP 0x2c
+#define UID 0x2d
+#define SIG 0x34
+#define FI 0x39
+#define SPID 0x3a
+#define EID 0x3b
+#define DSPF 0x3c
+#define ECAD 0x4c
+#define OAD 0x6c
+#define OSA 0x6d
+#define DAD 0x70
+#define CPN 0x70
+#define DSA 0x71
+#define RDX 0x73
+#define RAD 0x74
+#define RDN 0x74
+#define RSI 0x79
+#define SCR 0x7A /* internal unscreened CPN */
+#define MIE 0x7a /* internal management info element */
+#define LLC 0x7c
+#define HLC 0x7d
+#define UUI 0x7e
+#define ESC 0x7f
+
+#define SHIFT 0x90
+#define MORE 0xa0
+#define CL 0xb0
+
+/* information elements used on the spid interface */
+#define SPID_CMD 0xc0
+#define SPID_LINK 0x10
+#define SPID_DN 0x70
+#define SPID_BC 0x04
+#define SPID_SWITCH 0x11
+
+/*------------------------------------------------------------------*/
+/* global configuration parameters, defined in exec.c */
+/* these parameters are configured with program loading */
+/*------------------------------------------------------------------*/
+
+#define PROT_1TR6 0
+#define PROT_ETSI 1
+#define PROT_FRANC 2
+#define PROT_BELG 3
+#define PROT_SWED 4
+#define PROT_NI 5
+#define PROT_5ESS 6
+#define PROT_JAPAN 7
+#define PROT_ATEL 8
+#define PROT_US 9
+#define PROT_ITALY 10
+#define PROT_TWAN 11
+#define PROT_AUSTRAL 12
+
+#define INIT_PROT_1TR6 0x80|PROT_1TR6
+#define INIT_PROT_ETSI 0x80|PROT_ETSI
+#define INIT_PROT_FRANC 0x80|PROT_FRANC
+#define INIT_PROT_BELG 0x80|PROT_BELG
+#define INIT_PROT_SWED 0x80|PROT_SWED
+#define INIT_PROT_NI 0x80|PROT_NI
+#define INIT_PROT_5ESS 0x80|PROT_5ESS
+#define INIT_PROT_JAPAN 0x80|PROT_JAPAN
+#define INIT_PROT_ATEL 0x80|PROT_ATEL
+#define INIT_PROT_ITALY 0x80|PROT_ITALY
+#define INIT_PROT_TWAN 0x80|PROT_TWAN
+#define INIT_PROT_AUSTRAL 0x80|PROT_AUSTRAL
+
+
+/* -----------------------------------------------------------**
+** The PROTOCOL_FEATURE_STRING in feature.h (included **
+** in prstart.sx and astart.sx) defines capabilities and **
+** features of the actual protocol code. It's used as a bit **
+** mask. **
+** The following Bits are defined: **
+** -----------------------------------------------------------*/
+
+#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */
+#define PROTCAP_MANIF 0x0002 /* Management interface implemented */
+#define PROTCAP_V_42 0x0004 /* V42 implemented */
+#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */
+#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */
+#define PROTCAP_FREE4 0x0020 /* not used */
+#define PROTCAP_FREE5 0x0040 /* not used */
+#define PROTCAP_FREE6 0x0080 /* not used */
+#define PROTCAP_FREE7 0x0100 /* not used */
+#define PROTCAP_FREE8 0x0200 /* not used */
+#define PROTCAP_FREE9 0x0400 /* not used */
+#define PROTCAP_FREE10 0x0800 /* not used */
+#define PROTCAP_FREE11 0x1000 /* not used */
+#define PROTCAP_FREE12 0x2000 /* not used */
+#define PROTCAP_FREE13 0x4000 /* not used */
+#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */
diff --git a/drivers/isdn/eicon/divalog.h b/drivers/isdn/eicon/divalog.h
new file mode 100644
index 000000000..93bd56ae9
--- /dev/null
+++ b/drivers/isdn/eicon/divalog.h
@@ -0,0 +1,57 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/*
+ * Include file for defining the kernel loggger messages
+ * These definitions are shared between the klog driver and the
+ * klogd daemon process
+ */
+
+#if !defined(_KLOGMSG_H)
+#define _KLOGMSG_H
+
+/* define a type for a log entry */
+
+#define KLOG_TEXT_MSG (0)
+#define KLOG_XLOG_MSG (1)
+#define KLOG_XTXT_MSG (2)
+#define KLOG_IDI_REQ (4)
+#define KLOG_IDI_CALLBACK (5)
+#define KLOG_CAPI_MSG (6)
+
+typedef struct
+{
+ unsigned long time_stamp; /* in ms since last system boot */
+ int card; /* card number (-1 for all) */
+ unsigned int type; /* type of log message (0 is text) */
+ unsigned int length; /* message length (non-text messages only) */
+ unsigned short code; /* message code (non-text messages only) */
+ char buffer[110];/* text/data to log */
+} klog_t;
+
+void DivasLogAdd(void *buffer, int length);
+#endif /* of _KLOGMSG_H */
diff --git a/drivers/isdn/eicon/divas.h b/drivers/isdn/eicon/divas.h
new file mode 100644
index 000000000..2fcd8349b
--- /dev/null
+++ b/drivers/isdn/eicon/divas.h
@@ -0,0 +1,232 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.5
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/* External Diva Server driver include file */
+
+#if !defined(DIVAS_H)
+#define DIVAS_H
+
+#include "sys.h"
+
+
+/* IOCTL commands */
+
+#define DIA_IOCTL_INIT (0)
+#define DIA_IOCTL_LOAD (1)
+#define DIA_IOCTL_CONFIG (2)
+#define DIA_IOCTL_START (3)
+#define DIA_IOCTL_GET_NUM (4)
+#define DIA_IOCTL_GET_LIST (5)
+#define DIA_IOCTL_LOG (6)
+#define DIA_IOCTL_DETECT (7)
+#define DIA_IOCTL_SPACE (8)
+#define DIA_IOCTL_GET_MEM (9)
+#define DIA_IOCTL_FLAVOUR (10)
+#define DIA_IOCTL_XLOG_REQ (11)
+
+/* Error codes */
+
+#define XLOG_ERR_CARD_NUM (13)
+#define XLOG_ERR_DONE (14)
+#define XLOG_ERR_CMD (15)
+#define XLOG_ERR_TIMEOUT (16)
+#define XLOG_ERR_CARD_STATE (17)
+#define XLOG_ERR_UNKNOWN (18)
+#define XLOG_OK (0)
+
+/* Adapter states */
+
+#define DIA_UNKNOWN (0)
+#define DIA_RESET (1)
+#define DIA_LOADED (2)
+#define DIA_CONFIGURED (3)
+#define DIA_RUNNING (4)
+
+/* Stucture for getting card specific information from active cad driver */
+
+typedef struct
+{
+ int card_type;
+ int card_slot;
+ int state;
+} dia_card_list_t;
+
+/* use following to select which logging to have active */
+
+#define DIVAS_LOG_DEBUG (1 << 0)
+#define DIVAS_LOG_XLOG (1 << 1)
+#define DIVAS_LOG_IDI (1 << 2)
+#define DIVAS_LOG_CAPI (1 << 3)
+
+/* stucture for DIA_IOCTL_LOG to get information from adapter */
+
+typedef struct
+{
+ int card_id;
+ int log_types; /* bit mask of log types: use DIVAS_LOG_XXX */
+} dia_log_t;
+
+/* list of cards supported by this driver */
+
+#define DIA_CARD_TYPE_DIVA_SERVER (0) /* Diva Server PRI */
+#define DIA_CARD_TYPE_DIVA_SERVER_B (1) /* Diva Server BRI */
+#define DIA_CARD_TYPE_DIVA_SERVER_Q (2) /* Diva Server 4-BRI */
+
+/* bus types */
+
+#define DIA_BUS_TYPE_ISA (0)
+#define DIA_BUS_TYPE_ISA_PNP (1)
+#define DIA_BUS_TYPE_PCI (2)
+#define DIA_BUS_TYPE_MCA (3)
+
+/* types of memory used (index for memory array below) */
+
+#define DIVAS_RAM_MEMORY 0
+#define DIVAS_REG_MEMORY 1
+#define DIVAS_CFG_MEMORY 2
+#define DIVAS_SHARED_MEMORY 3
+#define DIVAS_CTL_MEMORY 4
+/*
+ * card config information
+ * passed as parameter to DIA_IOCTL_INIT ioctl to initialise new card
+ */
+
+typedef struct
+{
+ int card_id; /* unique id assigned to this card */
+ int card_type; /* use DIA_CARD_TYPE_xxx above */
+ int bus_type; /* use DIA_BUS_TYPE_xxx above */
+ int bus_num; /* bus number (instance number of bus type) */
+ int func_num; /* adapter function number (PCI register) */
+ int slot; /* slot number in bus */
+ unsigned char irq; /* IRQ number */
+ int reset_base; /* Reset register for I/O mapped cards */
+ int io_base; /* I/O base for I/O mapped cards */
+ void *memory[5]; /* memory base addresses for memory mapped cards */
+ char name[9]; /* name of adapter */
+ int serial; /* serial number */
+ unsigned char int_priority; /* Interrupt priority */
+} dia_card_t;
+
+/*
+ * protocol configuration information
+ * passed as parameter to DIA_IOCTL_CONFIG ioctl to configure card
+ */
+
+typedef struct
+{
+ int card_id; /* to identify particular card */
+ unsigned char tei;
+ unsigned char nt2;
+ unsigned char watchdog;
+ unsigned char permanent;
+ unsigned char x_interface;
+ unsigned char stable_l2;
+ unsigned char no_order_check;
+ unsigned char handset_type;
+ unsigned char sig_flags;
+ unsigned char low_channel;
+ unsigned char prot_version;
+ unsigned char crc4;
+ struct
+ {
+ unsigned char oad[32];
+ unsigned char osa[32];
+ unsigned char spid[32];
+ }terminal[2];
+} dia_config_t;
+
+/*
+ * code configuration
+ * passed as parameter to DIA_IOCTL_LOAD ioctl
+ * one of these ioctl per code file to load
+ */
+
+typedef struct
+{
+ int card_id; /* card to load */
+ enum
+ {
+ DIA_CPU_CODE, /* CPU code */
+ DIA_DSP_CODE, /* DSP code */
+ DIA_CONT_CODE, /* continuation of code */
+ DIA_TABLE_CODE, /* code table */
+ DIA_DLOAD_CNT, /* number of downloads*/
+ DIA_FPGA_CODE
+ } code_type; /* code for CPU or DSP ? */
+ int length; /* length of code */
+ unsigned char *code; /* pointer (in user-space) to code */
+} dia_load_t;
+
+/*
+ * start configuration
+ * passed as parameter to DIA_IOCTL_START ioctl
+ */
+
+typedef struct
+{
+ int card_id; /* card to start */
+} dia_start_t;
+
+/* used for retrieving memory from the card */
+
+typedef struct {
+ word card_id;
+ dword addr;
+ byte data[16 * 8];
+} mem_block_t;
+
+/* DIVA Server specific addresses */
+
+#define DIVAS_CPU_START_ADDR (0x0)
+#define ORG_MAX_PROTOCOL_CODE_SIZE 0x000A0000
+#define ORG_MAX_DSP_CODE_SIZE (0x000F0000 - ORG_MAX_PROTOCOL_CODE_SIZE)
+#define ORG_DSP_CODE_BASE (0xBF7F0000 - ORG_MAX_DSP_CODE_SIZE)
+#define DIVAS_DSP_START_ADDR (0xBF7A0000)
+#define DIVAS_SHARED_OFFSET (0x1000)
+#define MP_DSP_CODE_BASE 0xa03a0000
+#define MQ_PROTCODE_OFFSET 0x100000
+#define MQ_SM_OFFSET 0X0f0000
+
+#define V90D_MAX_PROTOCOL_CODE_SIZE 0x00090000
+#define V90D_MAX_DSP_CODE_SIZE (0x000F0000 - V90D_MAX_PROTOCOL_CODE_SIZE)
+#define V90D_DSP_CODE_BASE (0xBF7F0000 - V90D_MAX_DSP_CODE_SIZE)
+
+#define MQ_ORG_MAX_PROTOCOL_CODE_SIZE 0x000a0000 /* max 640K Protocol-Code */
+#define MQ_ORG_MAX_DSP_CODE_SIZE 0x00050000 /* max 320K DSP-Code */
+#define MQ_ORG_DSP_CODE_BASE (MQ_MAX_DSP_DOWNLOAD_ADDR \
+ - MQ_ORG_MAX_DSP_CODE_SIZE)
+#define MQ_V90D_MAX_PROTOCOL_CODE_SIZE 0x00090000 /* max 576K Protocol-Code */
+#define MQ_V90D_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code if V.90D included */
+#define MQ_MAX_DSP_DOWNLOAD_ADDR 0xa03f0000
+#define MQ_V90D_DSP_CODE_BASE (MQ_MAX_DSP_DOWNLOAD_ADDR \
+ - MQ_V90D_MAX_DSP_CODE_SIZE)
+
+
+#define ALIGNMENT_MASK_MAESTRA 0xfffffffc
+
+#endif /* DIVAS_H */
diff --git a/drivers/isdn/eicon/dsp_defs.h b/drivers/isdn/eicon/dsp_defs.h
new file mode 100644
index 000000000..ee7c1429e
--- /dev/null
+++ b/drivers/isdn/eicon/dsp_defs.h
@@ -0,0 +1,303 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#ifndef DSP_DEFS_H_
+#define DSP_DEFS_H_
+
+#ifndef DSPDIDS_H_
+#include "dspdids.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*---------------------------------------------------------------------------*/
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef TRUE
+#define TRUE (0 == 0)
+#endif
+#ifndef FALSE
+#define FALSE (0 != 0)
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+
+#define DSP_MEMORY_TYPE_EXTERNAL_DM 0
+#define DSP_MEMORY_TYPE_EXTERNAL_PM 1
+#define DSP_MEMORY_TYPE_INTERNAL_DM 2
+#define DSP_MEMORY_TYPE_INTERNAL_PM 3
+
+#define DSP_DOWNLOAD_FLAG_BOOTABLE 0x0001
+#define DSP_DOWNLOAD_FLAG_2181 0x0002
+#define DSP_DOWNLOAD_FLAG_TIMECRITICAL 0x0004
+#define DSP_DOWNLOAD_FLAG_COMPAND 0x0008
+
+#define DSP_MEMORY_BLOCK_COUNT 16
+
+#define DSP_SEGMENT_PM_FLAG 0x0001
+#define DSP_SEGMENT_SHARED_FLAG 0x0002
+
+#define DSP_SEGMENT_EXTERNAL_DM DSP_MEMORY_TYPE_EXTERNAL_DM
+#define DSP_SEGMENT_EXTERNAL_PM DSP_MEMORY_TYPE_EXTERNAL_PM
+#define DSP_SEGMENT_INTERNAL_DM DSP_MEMORY_TYPE_INTERNAL_DM
+#define DSP_SEGMENT_INTERNAL_PM DSP_MEMORY_TYPE_INTERNAL_PM
+#define DSP_SEGMENT_FIRST_RELOCATABLE 4
+
+#define DSP_DATA_BLOCK_PM_FLAG 0x0001
+#define DSP_DATA_BLOCK_DWORD_FLAG 0x0002
+#define DSP_DATA_BLOCK_RESOLVE_FLAG 0x0004
+
+#define DSP_RELOC_NONE 0x00
+#define DSP_RELOC_SEGMENT_MASK 0x3f
+#define DSP_RELOC_TYPE_MASK 0xc0
+#define DSP_RELOC_TYPE_0 0x00 /* relocation of address in DM word / high part of PM word */
+#define DSP_RELOC_TYPE_1 0x40 /* relocation of address in low part of PM data word */
+#define DSP_RELOC_TYPE_2 0x80 /* relocation of address in standard command */
+#define DSP_RELOC_TYPE_3 0xc0 /* relocation of address in call/jump on flag in */
+
+#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48
+#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100
+
+#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48
+#define DSP_FILE_FORMAT_VERSION_BCD 0x0100
+
+
+typedef struct tag_dsp_combifile_header
+{
+ char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE];
+ word format_version_bcd;
+ word header_size;
+ word combifile_description_size;
+ word directory_entries;
+ word directory_size;
+ word download_count;
+ word usage_mask_size;
+} t_dsp_combifile_header;
+
+typedef struct tag_dsp_combifile_directory_entry
+{
+ word card_type_number;
+ word file_set_number;
+} t_dsp_combifile_directory_entry;
+
+typedef struct tag_dsp_file_header
+{
+ char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE];
+ word format_version_bcd;
+ word download_id;
+ word download_flags;
+ word required_processing_power;
+ word interface_channel_count;
+ word header_size;
+ word download_description_size;
+ word memory_block_table_size;
+ word memory_block_count;
+ word segment_table_size;
+ word segment_count;
+ word symbol_table_size;
+ word symbol_count;
+ word total_data_size_dm;
+ word data_block_count_dm;
+ word total_data_size_pm;
+ word data_block_count_pm;
+} t_dsp_file_header;
+
+typedef struct tag_dsp_memory_block_desc
+{
+ word alias_memory_block;
+ word memory_type;
+ word address;
+ word size; /* DSP words */
+} t_dsp_memory_block_desc;
+
+typedef struct tag_dsp_segment_desc
+{
+ word memory_block;
+ word attributes;
+ word base;
+ word size;
+ word alignment; /* ==0 -> no other legal start address than base */
+} t_dsp_segment_desc;
+
+typedef struct tag_dsp_symbol_desc
+{
+ word symbol_id;
+ word segment;
+ word offset;
+ word size; /* DSP words */
+} t_dsp_symbol_desc;
+
+typedef struct tag_dsp_data_block_header
+{
+ word attributes;
+ word segment;
+ word offset;
+ word size; /* DSP words */
+} t_dsp_data_block_header;
+
+typedef struct tag_dsp_download_desc /* be sure to keep native alignment for MAESTRA's */
+{
+ word download_id;
+ word download_flags;
+ word required_processing_power;
+ word interface_channel_count;
+ word excess_header_size;
+ word memory_block_count;
+ word segment_count;
+ word symbol_count;
+ word data_block_count_dm;
+ word data_block_count_pm;
+ byte *p_excess_header_data;
+ char *p_download_description;
+ t_dsp_memory_block_desc *p_memory_block_table;
+ t_dsp_segment_desc *p_segment_table;
+ t_dsp_symbol_desc *p_symbol_table;
+ word *p_data_blocks_dm;
+ word *p_data_blocks_pm;
+} t_dsp_download_desc;
+
+#define DSP_DOWNLOAD_INDEX_KERNEL 0
+#define DSP30TX_DOWNLOAD_INDEX_KERNEL 1
+#define DSP30RX_DOWNLOAD_INDEX_KERNEL 2
+#define DSP_MAX_DOWNLOAD_COUNT 35
+
+
+#define DSP_DOWNLOAD_MAX_SEGMENTS 16
+
+#define DSP_UDATA_REQUEST_RECONFIGURE 0
+/*
+parameters:
+ <word> reconfigure delay (in 8kHz samples)
+ <word> reconfigure code
+ <byte> reconfigure hdlc preamble flags
+*/
+
+#define DSP_RECONFIGURE_TX_FLAG 0x8000
+#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000
+#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000
+#define DSP_RECONFIGURE_HDLC_FLAG 0x1000
+#define DSP_RECONFIGURE_SYNC_FLAG 0x0800
+#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff
+#define DSP_RECONFIGURE_IDLE 0
+#define DSP_RECONFIGURE_V25 1
+#define DSP_RECONFIGURE_V21_CH2 2
+#define DSP_RECONFIGURE_V27_2400 3
+#define DSP_RECONFIGURE_V27_4800 4
+#define DSP_RECONFIGURE_V29_7200 5
+#define DSP_RECONFIGURE_V29_9600 6
+#define DSP_RECONFIGURE_V33_12000 7
+#define DSP_RECONFIGURE_V33_14400 8
+#define DSP_RECONFIGURE_V17_7200 9
+#define DSP_RECONFIGURE_V17_9600 10
+#define DSP_RECONFIGURE_V17_12000 11
+#define DSP_RECONFIGURE_V17_14400 12
+
+/*
+data indications if transparent framer
+ <byte> data 0
+ <byte> data 1
+ ...
+
+data indications if HDLC framer
+ <byte> data 0
+ <byte> data 1
+ ...
+ <byte> CRC 0
+ <byte> CRC 1
+ <byte> preamble flags
+*/
+
+#define DSP_UDATA_INDICATION_SYNC 0
+/*
+returns:
+ <word> time of sync (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_DCD_OFF 1
+/*
+returns:
+ <word> time of DCD off (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_DCD_ON 2
+/*
+returns:
+ <word> time of DCD on (sampled from counter at 8kHz)
+ <byte> connected norm
+ <word> connected options
+ <dword> connected speed (bit/s)
+*/
+
+#define DSP_UDATA_INDICATION_CTS_OFF 3
+/*
+returns:
+ <word> time of CTS off (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_CTS_ON 4
+/*
+returns:
+ <word> time of CTS on (sampled from counter at 8kHz)
+ <byte> connected norm
+ <word> connected options
+ <dword> connected speed (bit/s)
+*/
+
+#define DSP_CONNECTED_NORM_UNSPECIFIED 0
+#define DSP_CONNECTED_NORM_V21 1
+#define DSP_CONNECTED_NORM_V23 2
+#define DSP_CONNECTED_NORM_V22 3
+#define DSP_CONNECTED_NORM_V22_BIS 4
+#define DSP_CONNECTED_NORM_V32_BIS 5
+#define DSP_CONNECTED_NORM_V34 6
+#define DSP_CONNECTED_NORM_V8 7
+#define DSP_CONNECTED_NORM_BELL_212A 8
+#define DSP_CONNECTED_NORM_BELL_103 9
+#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10
+#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11
+#define DSP_CONNECTED_NORM_TFAST 12
+#define DSP_CONNECTED_NORM_V21_CH2 13
+#define DSP_CONNECTED_NORM_V27_TER 14
+#define DSP_CONNECTED_NORM_V29 15
+#define DSP_CONNECTED_NORM_V33 16
+#define DSP_CONNECTED_NORM_V17 17
+
+#define DSP_CONNECTED_OPTION_TRELLIS 0x0001
+
+
+/*---------------------------------------------------------------------------*/
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*---------------------------------------------------------------------------*/
diff --git a/drivers/isdn/eicon/dspdids.h b/drivers/isdn/eicon/dspdids.h
new file mode 100644
index 000000000..1ac6a9bc6
--- /dev/null
+++ b/drivers/isdn/eicon/dspdids.h
@@ -0,0 +1,84 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#ifndef DSPDIDS_H_
+#define DSPDIDS_H_
+
+
+/*---------------------------------------------------------------------------*/
+
+#define DSP_DID_INVALID 0
+#define DSP_DID_DIVA 1
+#define DSP_DID_DIVA_PRO 2
+#define DSP_DID_DIVA_PRO_20 3
+#define DSP_DID_DIVA_PRO_PCCARD 4
+#define DSP_DID_DIVA_SERVER_BRI_1M 5
+#define DSP_DID_DIVA_SERVER_BRI_2M 6
+#define DSP_DID_DIVA_SERVER_PRI_2M_TX 7
+#define DSP_DID_DIVA_SERVER_PRI_2M_RX 8
+#define DSP_DID_DIVA_SERVER_PRI_30M 9
+#define DSP_DID_TASK_HSCX 100
+#define DSP_DID_TASK_HSCX_PRI_2M_TX 101
+#define DSP_DID_TASK_HSCX_PRI_2M_RX 102
+#define DSP_DID_TASK_V110KRNL 200
+#define DSP_DID_OVERLAY_V1100 201
+#define DSP_DID_OVERLAY_V1101 202
+#define DSP_DID_OVERLAY_V1102 203
+#define DSP_DID_OVERLAY_V1103 204
+#define DSP_DID_OVERLAY_V1104 205
+#define DSP_DID_OVERLAY_V1105 206
+#define DSP_DID_OVERLAY_V1106 207
+#define DSP_DID_OVERLAY_V1107 208
+#define DSP_DID_OVERLAY_V1108 209
+#define DSP_DID_OVERLAY_V1109 210
+#define DSP_DID_TASK_V110_PRI_2M_TX 220
+#define DSP_DID_TASK_V110_PRI_2M_RX 221
+#define DSP_DID_TASK_MODEM 300
+#define DSP_DID_TASK_FAX05 400
+#define DSP_DID_TASK_VOICE 500
+#define DSP_DID_TASK_TIKRNL81 600
+#define DSP_DID_OVERLAY_DIAL 601
+#define DSP_DID_OVERLAY_V22 602
+#define DSP_DID_OVERLAY_V32 603
+#define DSP_DID_OVERLAY_FSK 604
+#define DSP_DID_OVERLAY_FAX 605
+#define DSP_DID_OVERLAY_VXX 606
+#define DSP_DID_OVERLAY_V8 607
+#define DSP_DID_OVERLAY_INFO 608
+#define DSP_DID_OVERLAY_V34 609
+#define DSP_DID_OVERLAY_DFX 610
+#define DSP_DID_PARTIAL_OVERLAY_DIAL 611
+#define DSP_DID_PARTIAL_OVERLAY_FSK 612
+#define DSP_DID_PARTIAL_OVERLAY_FAX 613
+#define DSP_DID_TASK_TIKRNL05 700
+
+
+/*---------------------------------------------------------------------------*/
+
+#endif
+
+/*---------------------------------------------------------------------------*/
diff --git a/drivers/isdn/eicon/eicon.h b/drivers/isdn/eicon/eicon.h
index 5ad164518..42e9b3b95 100644
--- a/drivers/isdn/eicon/eicon.h
+++ b/drivers/isdn/eicon/eicon.h
@@ -1,4 +1,4 @@
-/* $Id: eicon.h,v 1.19 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon.h,v 1.23 2000/06/21 11:28:42 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
*
@@ -20,86 +20,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: eicon.h,v $
- * Revision 1.19 2000/01/23 21:21:23 armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.18 1999/11/25 11:43:27 armin
- * Fixed statectrl and connect message.
- * X.75 fix and HDLC/transparent with autoconnect.
- * Minor cleanup.
- *
- * Revision 1.17 1999/10/26 21:15:33 armin
- * using define for checking phone number len to avoid buffer overflow.
- *
- * Revision 1.16 1999/10/08 22:09:33 armin
- * Some fixes of cards interface handling.
- * Bugfix of NULL pointer occurence.
- * Changed a few log outputs.
- *
- * Revision 1.15 1999/09/26 14:17:53 armin
- * Improved debug and log via readstat()
- *
- * Revision 1.14 1999/09/08 20:17:31 armin
- * Added microchannel patch from Erik Weber.
- *
- * Revision 1.13 1999/09/06 07:29:35 fritz
- * Changed my mail-address.
- *
- * Revision 1.12 1999/09/04 06:20:05 keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.11 1999/08/29 17:23:44 armin
- * New setup compat.
- * Bugfix if compile as not module.
- *
- * Revision 1.10 1999/08/22 20:26:41 calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- * define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.9 1999/08/18 20:16:57 armin
- * Added XLOG function for all cards.
- * Bugfix of alloc_skb NULL pointer.
- *
- * Revision 1.8 1999/07/25 15:12:01 armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.7 1999/07/11 17:16:23 armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.6 1999/06/09 19:31:24 armin
- * Wrong PLX size for request_region() corrected.
- * Added first MCA code from Erik Weber.
- *
- * Revision 1.5 1999/03/29 11:19:41 armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.4 1999/03/02 12:37:42 armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.3 1999/01/24 20:14:07 armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.2 1999/01/10 18:46:04 armin
- * Bug with wrong values in HLC fixed.
- * Bytes to send are counted and limited now.
- *
- * Revision 1.1 1999/01/01 18:09:41 armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
*/
@@ -124,6 +44,8 @@
#define EICON_IOCTL_TEST 98
#define EICON_IOCTL_DEBUGVAR 99
+#define EICON_IOCTL_DIA_OFFSET 100
+
/* Bus types */
#define EICON_BUS_ISA 1
#define EICON_BUS_MCA 2
@@ -185,39 +107,10 @@ typedef struct {
unsigned char code[1]; /* Rest (bootstrap- and firmware code) will be allocated */
} eicon_isa_codebuf;
-/* Struct for downloading protocol via ioctl for PCI cards */
-typedef struct {
- /* start-up parameters */
- unsigned char tei;
- unsigned char nt2;
- unsigned char WatchDog;
- unsigned char Permanent;
- unsigned char XInterface;
- unsigned char StableL2;
- unsigned char NoOrderCheck;
- unsigned char HandsetType;
- unsigned char LowChannel;
- unsigned char ProtVersion;
- unsigned char Crc4;
- unsigned char NoHscx30Mode; /* switch PRI into No HSCX30 test mode */
- unsigned char Loopback; /* switch card into Loopback mode */
- struct q931_link_s
- {
- unsigned char oad[32];
- unsigned char osa[32];
- unsigned char spid[32];
- } l[2];
- unsigned long protocol_len;
- unsigned int dsp_code_num;
- unsigned long dsp_code_len[9];
- unsigned char code[1]; /* Rest (protocol- and dsp code) will be allocated */
-} eicon_pci_codebuf;
-
/* Data for downloading protocol via ioctl */
typedef union {
eicon_isa_codebuf isa;
eicon_isa_codebuf mca;
- eicon_pci_codebuf pci;
} eicon_codebuf;
/* Data for Management interface */
@@ -228,6 +121,7 @@ typedef struct {
unsigned char data[700];
} eicon_manifbuf;
+#define TRACE_OK (1)
#ifdef __KERNEL__
@@ -265,206 +159,34 @@ typedef struct {
#include "eicon_isa.h"
+#include "idi.h"
+
+typedef struct {
+ __u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */
+ __u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */
+ __u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */
+ __u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */
+ __u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */
+ __u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */
+ __u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */
+ __u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */
+ __u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */
+ __u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */
+ __u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */
+ __u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */
+ __u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */
+ __u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */
+ __u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */
+ __u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */
+ __u8 B[1]; /* buffer space for Req,Ind and Rc */
+} eicon_pr_ram;
+
/* Macro for delay via schedule() */
#define SLEEP(j) { \
set_current_state(TASK_UNINTERRUPTIBLE); \
schedule_timeout(j); \
}
-#endif /* KERNEL */
-
-#define DIVAS_SHARED_OFFSET (0x1000)
-
-#define MIPS_BUFFER_SZ 128
-#define MIPS_MAINT_OFFS 0xff00
-
-#define XLOG_ERR_CARD_NUM (13)
-#define XLOG_ERR_DONE (14)
-#define XLOG_ERR_CMD (15)
-#define XLOG_ERR_TIMEOUT (16)
-#define XLOG_ERR_CARD_STATE (17)
-#define XLOG_ERR_UNKNOWN (18)
-#define XLOG_OK (0)
-
-#define TRACE_OK (1)
-
-typedef struct {
- __u8 Id __attribute__ ((packed));
- __u8 uX __attribute__ ((packed));
- __u8 listen __attribute__ ((packed));
- __u8 active __attribute__ ((packed));
- __u8 sin[3] __attribute__ ((packed));
- __u8 bc[6] __attribute__ ((packed));
- __u8 llc[6] __attribute__ ((packed));
- __u8 hlc[6] __attribute__ ((packed));
- __u8 oad[20] __attribute__ ((packed));
-}DSigStruc;
-
-typedef struct {
- __u32 cx_b1 __attribute__ ((packed));
- __u32 cx_b2 __attribute__ ((packed));
- __u32 cr_b1 __attribute__ ((packed));
- __u32 cr_b2 __attribute__ ((packed));
- __u32 px_b1 __attribute__ ((packed));
- __u32 px_b2 __attribute__ ((packed));
- __u32 pr_b1 __attribute__ ((packed));
- __u32 pr_b2 __attribute__ ((packed));
- __u16 er_b1 __attribute__ ((packed));
- __u16 er_b2 __attribute__ ((packed));
-}BL1Struc;
-
-typedef struct {
- __u32 XTotal __attribute__ ((packed));
- __u32 RTotal __attribute__ ((packed));
- __u16 XError __attribute__ ((packed));
- __u16 RError __attribute__ ((packed));
-}L2Struc;
-
-typedef struct {
- __u16 free_n;
-}OSStruc;
-
-typedef union
-{
- DSigStruc DSigStats;
- BL1Struc BL1Stats;
- L2Struc L2Stats;
- OSStruc OSStats;
- __u8 b[MIPS_BUFFER_SZ];
- __u16 w[MIPS_BUFFER_SZ>>1];
- __u16 l[MIPS_BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
- __u32 d[MIPS_BUFFER_SZ>>2];
-} MIPS_BUFFER;
-
-typedef struct
-{
- __u8 req __attribute__ ((packed));
- __u8 rc __attribute__ ((packed));
- __u8 reserved[2] __attribute__ ((packed)); /* R3000 alignment ... */
- __u8 *mem __attribute__ ((packed));
- __u16 length __attribute__ ((packed)); /* used to be short */
- __u16 port __attribute__ ((packed));
- __u8 fill[4] __attribute__ ((packed)); /* data at offset 16 */
- MIPS_BUFFER data __attribute__ ((packed));
-} mi_pc_maint_t;
-
-typedef struct
-{
- __u16 command;
- mi_pc_maint_t pcm;
-}xlogreq_t;
-
-typedef struct{
- __u16 code __attribute__ ((packed)); /* used to be short */
- __u16 timeh __attribute__ ((packed));
- __u16 timel __attribute__ ((packed));
- char buffer[MIPS_BUFFER_SZ - 6];
-}xlog_entry_t;
-
-
-#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48
-#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100
-
-#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48
-#define DSP_FILE_FORMAT_VERSION_BCD 0x0100
-
-typedef struct tag_dsp_combifile_header
-{
- char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed));
- __u16 format_version_bcd __attribute__ ((packed));
- __u16 header_size __attribute__ ((packed));
- __u16 combifile_description_size __attribute__ ((packed));
- __u16 directory_entries __attribute__ ((packed));
- __u16 directory_size __attribute__ ((packed));
- __u16 download_count __attribute__ ((packed));
- __u16 usage_mask_size __attribute__ ((packed));
-} t_dsp_combifile_header;
-
-typedef struct tag_dsp_combifile_directory_entry
-{
- __u16 card_type_number __attribute__ ((packed));
- __u16 file_set_number __attribute__ ((packed));
-} t_dsp_combifile_directory_entry;
-
-typedef struct tag_dsp_file_header
-{
- char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed));
- __u16 format_version_bcd __attribute__ ((packed));
- __u16 download_id __attribute__ ((packed));
- __u16 download_flags __attribute__ ((packed));
- __u16 required_processing_power __attribute__ ((packed));
- __u16 interface_channel_count __attribute__ ((packed));
- __u16 header_size __attribute__ ((packed));
- __u16 download_description_size __attribute__ ((packed));
- __u16 memory_block_table_size __attribute__ ((packed));
- __u16 memory_block_count __attribute__ ((packed));
- __u16 segment_table_size __attribute__ ((packed));
- __u16 segment_count __attribute__ ((packed));
- __u16 symbol_table_size __attribute__ ((packed));
- __u16 symbol_count __attribute__ ((packed));
- __u16 total_data_size_dm __attribute__ ((packed));
- __u16 data_block_count_dm __attribute__ ((packed));
- __u16 total_data_size_pm __attribute__ ((packed));
- __u16 data_block_count_pm __attribute__ ((packed));
-} t_dsp_file_header;
-
-typedef struct tag_dsp_memory_block_desc
-{
- __u16 alias_memory_block;
- __u16 memory_type;
- __u16 address;
- __u16 size; /* DSP words */
-} t_dsp_memory_block_desc;
-
-typedef struct tag_dsp_segment_desc
-{
- __u16 memory_block;
- __u16 attributes;
- __u16 base;
- __u16 size;
- __u16 alignment; /* ==0 -> no other legal start address than base */
-} t_dsp_segment_desc;
-
-typedef struct tag_dsp_symbol_desc
-{
- __u16 symbol_id;
- __u16 segment;
- __u16 offset;
- __u16 size; /* DSP words */
-} t_dsp_symbol_desc;
-
-typedef struct tag_dsp_data_block_header
-{
- __u16 attributes;
- __u16 segment;
- __u16 offset;
- __u16 size; /* DSP words */
-} t_dsp_data_block_header;
-
-typedef struct tag_dsp_download_desc /* be sure to keep native alignment for MAESTRA's */
-{
- __u16 download_id;
- __u16 download_flags;
- __u16 required_processing_power;
- __u16 interface_channel_count;
- __u16 excess_header_size;
- __u16 memory_block_count;
- __u16 segment_count;
- __u16 symbol_count;
- __u16 data_block_count_dm;
- __u16 data_block_count_pm;
- __u8 * p_excess_header_data __attribute__ ((packed));
- char * p_download_description __attribute__ ((packed));
- t_dsp_memory_block_desc *p_memory_block_table __attribute__ ((packed));
- t_dsp_segment_desc *p_segment_table __attribute__ ((packed));
- t_dsp_symbol_desc *p_symbol_table __attribute__ ((packed));
- __u16 * p_data_blocks_dm __attribute__ ((packed));
- __u16 * p_data_blocks_pm __attribute__ ((packed));
-} t_dsp_download_desc;
-
-
-#ifdef __KERNEL__
-
typedef struct {
__u8 Req; /* pending request */
__u8 Rc; /* return code received */
@@ -508,6 +230,7 @@ typedef struct {
unsigned short statectrl; /* State controling bits */
unsigned short eazmask; /* EAZ-Mask for this Channel */
int queued; /* User-Data Bytes in TX queue */
+ int pqueued; /* User-Data Packets in TX queue */
int waitq; /* User-Data Bytes in wait queue */
int waitpq; /* User-Data Bytes in packet queue */
struct sk_buff *tskb1; /* temp skb 1 */
@@ -518,7 +241,9 @@ typedef struct {
T30_s *fax; /* pointer to fax data in LL */
eicon_ch_fax_buf fax2; /* fax related struct */
#endif
- entity e; /* Entity */
+ entity e; /* Native Entity */
+ ENTITY de; /* Divas D Entity */
+ ENTITY be; /* Divas B Entity */
char cpn[32]; /* remember cpn */
char oad[32]; /* remember oad */
char dsa[32]; /* remember dsa */
@@ -542,8 +267,6 @@ typedef struct {
#define EICON_FLAGS_MVALID 8 /* Cards membase is valid */
#define EICON_FLAGS_LOADED 8 /* Firmware loaded */
-#define EICON_BCH 2 /* # of channels per card */
-
/* D-Channel states */
#define EICON_STATE_NULL 0
#define EICON_STATE_ICALL 1
@@ -565,9 +288,6 @@ typedef struct {
#define EICON_MAX_QUEUE 2138
-#define EICON_LOCK_TX 0
-#define EICON_LOCK_RX 1
-
typedef union {
eicon_isa_card isa;
eicon_pci_card pci;
@@ -593,17 +313,12 @@ typedef struct {
__u8 more;
} eicon_indhdr;
-typedef struct msn_entry {
- char eaz;
- char msn[16];
- struct msn_entry * next;
-} msn_entry;
-
/*
* Per card driver data
*/
typedef struct eicon_card {
eicon_hwif hwif; /* Hardware dependant interface */
+ DESCRIPTOR *d; /* IDI Descriptor */
u_char ptype; /* Protocol type (1TR6 or Euro) */
u_char bus; /* Bustype (ISA, MCA, PCI) */
u_char type; /* Cardtype (EICON_CTYPE_...) */
@@ -621,49 +336,23 @@ typedef struct eicon_card {
struct tq_struct snd_tq; /* Task struct for xmit bh */
struct tq_struct rcv_tq; /* Task struct for rcv bh */
struct tq_struct ack_tq; /* Task struct for ack bh */
- msn_entry *msn_list;
eicon_chan* IdTable[256]; /* Table to find entity */
__u16 ref_in;
__u16 ref_out;
int nchannels; /* Number of B-Channels */
int ReadyInt; /* Ready Interrupt */
eicon_chan *bch; /* B-Channel status/control */
- char status_buf[256]; /* Buffer for status messages */
- char *status_buf_read;
- char *status_buf_write;
- char *status_buf_end;
+ DBUFFER *dbuf; /* Dbuffer for Diva Server */
+ BUFFERS *sbuf; /* Buffer for Diva Server */
+ char *sbufp; /* Data Buffer for Diva Server */
isdn_if interface; /* Interface to upper layer */
- char regname[35]; /* Name used for request_region */
+ char regname[35]; /* Drivers card name */
#ifdef CONFIG_MCA
int mca_slot; /* # of cards MCA slot */
int mca_io; /* MCA cards IO port */
#endif /* CONFIG_MCA */
} eicon_card;
-/* -----------------------------------------------------------**
-** The PROTOCOL_FEATURE_STRING **
-** defines capabilities and **
-** features of the actual protocol code. It's used as a bit **
-** mask. **
-** The following Bits are defined: **
-** -----------------------------------------------------------*/
-#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */
-#define PROTCAP_MANIF 0x0002 /* Management interface implemented */
-#define PROTCAP_V_42 0x0004 /* V42 implemented */
-#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */
-#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */
-#define PROTCAP_FREE4 0x0020 /* not used */
-#define PROTCAP_FREE5 0x0040 /* not used */
-#define PROTCAP_FREE6 0x0080 /* not used */
-#define PROTCAP_FREE7 0x0100 /* not used */
-#define PROTCAP_FREE8 0x0200 /* not used */
-#define PROTCAP_FREE9 0x0400 /* not used */
-#define PROTCAP_FREE10 0x0800 /* not used */
-#define PROTCAP_FREE11 0x1000 /* not used */
-#define PROTCAP_FREE12 0x2000 /* not used */
-#define PROTCAP_FREE13 0x4000 /* not used */
-#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */
-
#include "eicon_idi.h"
extern eicon_card *cards;
@@ -688,13 +377,11 @@ extern __inline__ void eicon_schedule_ack(eicon_card *card)
mark_bh(IMMEDIATE_BH);
}
-extern char *eicon_find_eaz(eicon_card *, char);
-extern int eicon_addcard(int, int, int, char *);
+extern int eicon_addcard(int, int, int, char *, int);
extern void eicon_io_transmit(eicon_card *card);
extern void eicon_irq(int irq, void *dev_id, struct pt_regs *regs);
extern void eicon_io_rcv_dispatch(eicon_card *ccard);
extern void eicon_io_ack_dispatch(eicon_card *ccard);
-extern int eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq);
#ifdef CONFIG_MCA
extern int eicon_mca_find_card(int, int, int, char *);
extern int eicon_mca_probe(int, int, int, int, char *);
@@ -705,6 +392,8 @@ extern ulong DebugVar;
extern void eicon_log(eicon_card * card, int level, const char *fmt, ...);
extern void eicon_putstatus(eicon_card * card, char * buf);
+extern spinlock_t eicon_lock;
+
#endif /* __KERNEL__ */
#endif /* eicon_h */
diff --git a/drivers/isdn/eicon/eicon_dsp.h b/drivers/isdn/eicon/eicon_dsp.h
index 420d73f6e..1470fa7e6 100644
--- a/drivers/isdn/eicon/eicon_dsp.h
+++ b/drivers/isdn/eicon/eicon_dsp.h
@@ -1,4 +1,4 @@
-/* $Id: eicon_dsp.h,v 1.5 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_dsp.h,v 1.7 2000/05/07 08:51:04 armin Exp $
*
* ISDN lowlevel-module for Eicon active cards.
* DSP definitions
@@ -20,75 +20,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: eicon_dsp.h,v $
- * Revision 1.5 2000/01/23 21:21:23 armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.4 1999/07/25 15:12:02 armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.3 1999/07/11 17:16:24 armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.2 1999/03/29 11:19:42 armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.1 1999/03/02 12:18:54 armin
- * First checkin of DSP defines for audio features.
- *
*
*/
#ifndef DSP_H
#define DSP_H
-#define DSP_UDATA_REQUEST_RECONFIGURE 0
-/*
-parameters:
- <word> reconfigure delay (in 8kHz samples)
- <word> reconfigure code
- <byte> reconfigure hdlc preamble flags
-*/
+#include "dsp_defs.h"
-#define DSP_RECONFIGURE_TX_FLAG 0x8000
-#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000
-#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000
-#define DSP_RECONFIGURE_HDLC_FLAG 0x1000
-#define DSP_RECONFIGURE_SYNC_FLAG 0x0800
-#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff
-#define DSP_RECONFIGURE_IDLE 0
-#define DSP_RECONFIGURE_V25 1
-#define DSP_RECONFIGURE_V21_CH2 2
-#define DSP_RECONFIGURE_V27_2400 3
-#define DSP_RECONFIGURE_V27_4800 4
-#define DSP_RECONFIGURE_V29_7200 5
-#define DSP_RECONFIGURE_V29_9600 6
-#define DSP_RECONFIGURE_V33_12000 7
-#define DSP_RECONFIGURE_V33_14400 8
-#define DSP_RECONFIGURE_V17_7200 9
-#define DSP_RECONFIGURE_V17_9600 10
-#define DSP_RECONFIGURE_V17_12000 11
-#define DSP_RECONFIGURE_V17_14400 12
-
-/*
-data indications if transparent framer
- <byte> data 0
- <byte> data 1
- ...
-
-data indications if HDLC framer
- <byte> data 0
- <byte> data 1
- ...
- <byte> CRC 0
- <byte> CRC 1
- <byte> preamble flags
-*/
#define DSP_UDATA_REQUEST_SWITCH_FRAMER 1
/*
@@ -122,49 +61,6 @@ parameters:
- none -
*/
-
-#define DSP_UDATA_INDICATION_SYNC 0
-/*
-returns:
- <word> time of sync (sampled from counter at 8kHz)
-*/
-
-#define DSP_UDATA_INDICATION_DCD_OFF 1
-/*
-returns:
- <word> time of DCD off (sampled from counter at 8kHz)
-*/
-
-#define DSP_UDATA_INDICATION_DCD_ON 2
-/*
-returns:
- <word> time of DCD on (sampled from counter at 8kHz)
- <byte> connected norm
- <word> connected options
- <dword> connected speed (bit/s, max of tx and rx speed)
- <word> roundtrip delay (ms)
- <dword> connected speed tx (bit/s)
- <dword> connected speed rx (bit/s)
-*/
-
-#define DSP_UDATA_INDICATION_CTS_OFF 3
-/*
-returns:
- <word> time of CTS off (sampled from counter at 8kHz)
-*/
-
-#define DSP_UDATA_INDICATION_CTS_ON 4
-/*
-returns:
- <word> time of CTS on (sampled from counter at 8kHz)
- <byte> connected norm
- <word> connected options
- <dword> connected speed (bit/s, max of tx and rx speed)
- <word> roundtrip delay (ms)
- <dword> connected speed tx (bit/s)
- <dword> connected speed rx (bit/s)
-*/
-
typedef struct eicon_dsp_ind {
__u16 time __attribute__ ((packed));
__u8 norm __attribute__ ((packed));
@@ -175,32 +71,11 @@ typedef struct eicon_dsp_ind {
__u32 rxspeed __attribute__ ((packed));
} eicon_dsp_ind;
-#define DSP_CONNECTED_NORM_UNSPECIFIED 0
-#define DSP_CONNECTED_NORM_V21 1
-#define DSP_CONNECTED_NORM_V23 2
-#define DSP_CONNECTED_NORM_V22 3
-#define DSP_CONNECTED_NORM_V22_BIS 4
-#define DSP_CONNECTED_NORM_V32_BIS 5
-#define DSP_CONNECTED_NORM_V34 6
-#define DSP_CONNECTED_NORM_V8 7
-#define DSP_CONNECTED_NORM_BELL_212A 8
-#define DSP_CONNECTED_NORM_BELL_103 9
-#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10
-#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11
-#define DSP_CONNECTED_NORM_V90 12
-#define DSP_CONNECTED_NORM_V21_CH2 13
-#define DSP_CONNECTED_NORM_V27_TER 14
-#define DSP_CONNECTED_NORM_V29 15
-#define DSP_CONNECTED_NORM_V33 16
-#define DSP_CONNECTED_NORM_V17 17
-
-#define DSP_CONNECTED_OPTION_TRELLIS 0x0001
#define DSP_CONNECTED_OPTION_V42_TRANS 0x0002
#define DSP_CONNECTED_OPTION_V42_LAPM 0x0004
#define DSP_CONNECTED_OPTION_SHORT_TRAIN 0x0008
#define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010
-
#define DSP_UDATA_INDICATION_DISCONNECT 5
/*
returns:
@@ -214,7 +89,6 @@ returns:
#define DSP_DISCONNECT_CAUSE_CLEARDOWN 0x04
#define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT 0x05
-
#define DSP_UDATA_INDICATION_TX_CONFIRMATION 6
/*
returns:
diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c
index 9cef520bc..5b63311da 100644
--- a/drivers/isdn/eicon/eicon_idi.c
+++ b/drivers/isdn/eicon/eicon_idi.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.33 2000/03/06 15:45:17 armin Exp $
+/* $Id: eicon_idi.c,v 1.41 2000/08/12 18:00:47 armin Exp $
*
* ISDN lowlevel-module for Eicon active cards.
* IDI interface
@@ -25,135 +25,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: eicon_idi.c,v $
- * Revision 1.33 2000/03/06 15:45:17 armin
- * Fixed incomplete number handling with BRI PtP connection.
- *
- * Revision 1.32 2000/03/04 17:04:21 armin
- * Fix of statemachine, B-connect before D-connect,
- * thanks to Helmut Adams <adams@ipcon.de>
- * Minor change in send-data packet handling.
- *
- * Revision 1.31 2000/02/22 16:26:40 armin
- * Fixed membase error message.
- * Fixed missing log buffer struct.
- *
- * Revision 1.30 2000/02/16 16:08:46 armin
- * Fixed virtual channel handling of IDI.
- *
- * Revision 1.29 2000/01/23 21:21:23 armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.28 2000/01/20 19:55:34 keil
- * Add FAX Class 1 support
- *
- * Revision 1.27 1999/11/29 13:12:03 armin
- * Autoconnect on L2_TRANS doesn't work with link_level correctly,
- * changed back to former mode.
- *
- * Revision 1.26 1999/11/25 11:43:27 armin
- * Fixed statectrl and connect message.
- * X.75 fix and HDLC/transparent with autoconnect.
- * Minor cleanup.
- *
- * Revision 1.25 1999/11/18 20:30:55 armin
- * removed old workaround for ISA cards.
- *
- * Revision 1.24 1999/10/26 21:15:33 armin
- * using define for checking phone number len to avoid buffer overflow.
- *
- * Revision 1.23 1999/10/11 18:13:25 armin
- * Added fax capabilities for Eicon Diva Server cards.
- *
- * Revision 1.22 1999/10/08 22:09:33 armin
- * Some fixes of cards interface handling.
- * Bugfix of NULL pointer occurence.
- * Changed a few log outputs.
- *
- * Revision 1.21 1999/09/26 14:17:53 armin
- * Improved debug and log via readstat()
- *
- * Revision 1.20 1999/09/21 20:35:43 armin
- * added more error checking.
- *
- * Revision 1.19 1999/09/21 20:06:40 armin
- * Added pointer checks.
- *
- * Revision 1.18 1999/09/07 12:48:05 armin
- * Prepared for sub-address usage.
- *
- * Revision 1.17 1999/09/07 12:35:39 armin
- * Better checking and channel Id handling.
- *
- * Revision 1.16 1999/09/04 13:44:19 armin
- * Fix of V.42 analog Modem negotiation handling.
- *
- * Revision 1.15 1999/08/28 21:32:50 armin
- * Prepared for fax related functions.
- * Now compilable without errors/warnings.
- *
- * Revision 1.14 1999/08/28 20:24:40 armin
- * Corrected octet 3/3a in CPN/OAD information element.
- * Thanks to John Simpson <xfl23@dial.pipex.com>
- *
- * Revision 1.13 1999/08/22 20:26:44 calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- * define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.12 1999/08/18 20:16:59 armin
- * Added XLOG function for all cards.
- * Bugfix of alloc_skb NULL pointer.
- *
- * Revision 1.11 1999/07/25 15:12:03 armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.10 1999/07/11 17:16:24 armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.9 1999/03/29 11:19:42 armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.8 1999/03/02 12:37:43 armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.7 1999/02/03 18:34:35 armin
- * Channel selection for outgoing calls w/o CHI.
- * Added channel # in debug messages.
- * L2 Transparent should work with 800 byte/packet now.
- *
- * Revision 1.6 1999/01/26 07:18:59 armin
- * Bug with wrong added CPN fixed.
- *
- * Revision 1.5 1999/01/24 20:14:11 armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.4 1999/01/10 18:46:05 armin
- * Bug with wrong values in HLC fixed.
- * Bytes to send are counted and limited now.
- *
- * Revision 1.3 1999/01/05 14:49:34 armin
- * Added experimental usage of full BC and HLC for
- * speech, 3.1kHz audio, fax gr.2/3
- *
- * Revision 1.2 1999/01/04 13:19:29 armin
- * Channel status with listen-request wrong - fixed.
- *
- * Revision 1.1 1999/01/01 18:09:41 armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
*/
#include <linux/config.h>
@@ -161,25 +32,14 @@
#include "eicon.h"
#include "eicon_idi.h"
#include "eicon_dsp.h"
+#include "uxio.h"
#undef EICON_FULL_SERVICE_OKTETT
-char *eicon_idi_revision = "$Revision: 1.33 $";
+char *eicon_idi_revision = "$Revision: 1.41 $";
eicon_manifbuf *manbuf;
-static char BC_Speech[3] = { 0x80, 0x90, 0xa3 };
-static char BC_31khz[3] = { 0x90, 0x90, 0xa3 };
-static char BC_64k[2] = { 0x88, 0x90 };
-static char BC_video[3] = { 0x91, 0x90, 0xa5 };
-
-#ifdef EICON_FULL_SERVICE_OKTETT
-/*
-static char HLC_telephony[2] = { 0x91, 0x81 };
-*/
-static char HLC_faxg3[2] = { 0x91, 0x84 };
-#endif
-
int eicon_idi_manage_assign(eicon_card *card);
int eicon_idi_manage_remove(eicon_card *card);
int idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer);
@@ -209,7 +69,7 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
reqbuf->XBuffer.P[l++] = 0; /* end */
reqbuf->Req = ASSIGN;
reqbuf->ReqCh = 0;
- reqbuf->ReqId = 0;
+ reqbuf->ReqId = DSIG_ID;
reqbuf->XBuffer.length = l;
reqbuf->Reference = 0; /* Sig Entity */
}
@@ -221,6 +81,9 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
reqbuf->XBuffer.P[l++] = LLC;
reqbuf->XBuffer.P[l++] = 2;
switch(chan->l2prot) {
+ case ISDN_PROTO_L2_V11096:
+ case ISDN_PROTO_L2_V11019:
+ case ISDN_PROTO_L2_V11038:
case ISDN_PROTO_L2_TRANS:
reqbuf->XBuffer.P[l++] = 2; /* transparent */
break;
@@ -262,7 +125,7 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
reqbuf->XBuffer.P[l++] = 0; /* end */
reqbuf->Req = ASSIGN;
reqbuf->ReqCh = 0;
- reqbuf->ReqId = 0x20;
+ reqbuf->ReqId = NL_ID;
reqbuf->XBuffer.length = l;
reqbuf->Reference = 1; /* Net Entity */
}
@@ -282,6 +145,21 @@ idi_put_req(eicon_REQ *reqbuf, int rq, int signet, int Ch)
}
int
+idi_put_suspend_req(eicon_REQ *reqbuf, eicon_chan *chan)
+{
+ reqbuf->Req = SUSPEND;
+ reqbuf->ReqCh = 0;
+ reqbuf->ReqId = 1;
+ reqbuf->XBuffer.P[0] = CAI;
+ reqbuf->XBuffer.P[1] = 1;
+ reqbuf->XBuffer.P[2] = chan->No;
+ reqbuf->XBuffer.P[3] = 0;
+ reqbuf->XBuffer.length = 4;
+ reqbuf->Reference = 0; /* Sig Entity */
+ return(0);
+}
+
+int
idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan)
{
int l = 9;
@@ -295,7 +173,7 @@ idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan)
reqbuf->XBuffer.P[4] = 0;
reqbuf->XBuffer.P[5] = 0;
reqbuf->XBuffer.P[6] = 32;
- reqbuf->XBuffer.P[7] = 3;
+ reqbuf->XBuffer.P[7] = 0;
switch(chan->l2prot) {
case ISDN_PROTO_L2_X75I:
case ISDN_PROTO_L2_X75UI:
@@ -391,6 +269,12 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
case HANGUP:
idi_put_req(reqbuf, HANGUP, 0, 0);
break;
+ case SUSPEND:
+ idi_put_suspend_req(reqbuf, chan);
+ break;
+ case RESUME:
+ idi_put_req(reqbuf, RESUME, 0 ,0);
+ break;
case REJECT:
idi_put_req(reqbuf, REJECT, 0 ,0);
break;
@@ -400,17 +284,20 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
case CALL_RES:
idi_call_res_req(reqbuf, chan);
break;
- case IDI_N_CONNECT|0x700:
- idi_put_req(reqbuf, IDI_N_CONNECT, 1, 0);
+ case CALL_HOLD:
+ idi_put_req(reqbuf, CALL_HOLD, 0, 0);
+ break;
+ case N_CONNECT|0x700:
+ idi_put_req(reqbuf, N_CONNECT, 1, 0);
break;
- case IDI_N_CONNECT_ACK|0x700:
- idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1, 0);
+ case N_CONNECT_ACK|0x700:
+ idi_put_req(reqbuf, N_CONNECT_ACK, 1, 0);
break;
- case IDI_N_DISC|0x700:
- idi_put_req(reqbuf, IDI_N_DISC, 1, chan->e.IndCh);
+ case N_DISC|0x700:
+ idi_put_req(reqbuf, N_DISC, 1, chan->e.IndCh);
break;
- case IDI_N_DISC_ACK|0x700:
- idi_put_req(reqbuf, IDI_N_DISC_ACK, 1, chan->e.IndCh);
+ case N_DISC_ACK|0x700:
+ idi_put_req(reqbuf, N_DISC_ACK, 1, chan->e.IndCh);
break;
default:
eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No);
@@ -492,7 +379,7 @@ idi_hangup(eicon_card *card, eicon_chan *chan)
if ((chan->fsm_state == EICON_STATE_ACTIVE) ||
(chan->fsm_state == EICON_STATE_WMCONN)) {
- if (chan->e.B2Id) idi_do_req(card, chan, IDI_N_DISC, 1);
+ if (chan->e.B2Id) idi_do_req(card, chan, N_DISC, 1);
}
if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1);
if (chan->fsm_state != EICON_STATE_NULL) {
@@ -508,6 +395,32 @@ idi_hangup(eicon_card *card, eicon_chan *chan)
}
int
+capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm)
+{
+ if ((cm->para[0] != 3) || (cm->para[1] != 0))
+ return -1;
+ if (cm->para[2] < 3)
+ return -1;
+ if (cm->para[4] != 0)
+ return -1;
+ switch(cm->para[3]) {
+ case 4: /* Suspend */
+ eicon_log(card, 8, "idi_req: Ch%d: Call Suspend\n", chan->No);
+ if (cm->para[5]) {
+ idi_do_req(card, chan, SUSPEND, 0);
+ } else {
+ idi_do_req(card, chan, CALL_HOLD, 0);
+ }
+ break;
+ case 5: /* Resume */
+ eicon_log(card, 8, "idi_req: Ch%d: Call Resume\n", chan->No);
+ idi_do_req(card, chan, RESUME, 0);
+ break;
+ }
+ return 0;
+}
+
+int
idi_connect_res(eicon_card *card, eicon_chan *chan)
{
if ((!card) || (!chan))
@@ -612,7 +525,14 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
reqbuf->XBuffer.P[l++] = *sub++ & 0x7f;
}
- if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) {
+ if (si2 > 2) {
+ reqbuf->XBuffer.P[l++] = SHIFT|6;
+ reqbuf->XBuffer.P[l++] = SIN;
+ reqbuf->XBuffer.P[l++] = 2;
+ reqbuf->XBuffer.P[l++] = si1;
+ reqbuf->XBuffer.P[l++] = si2;
+ }
+ else if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) {
reqbuf->XBuffer.P[l++] = BC;
reqbuf->XBuffer.P[l++] = tmp;
for(i=0; i<tmp;i++)
@@ -632,7 +552,7 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
reqbuf->XBuffer.P[l++] = 0;
reqbuf->XBuffer.P[l++] = 0;
reqbuf->XBuffer.P[l++] = 32;
- reqbuf->XBuffer.P[l++] = 3;
+ reqbuf->XBuffer.P[l++] = 0;
switch(chan->l2prot) {
case ISDN_PROTO_L2_X75I:
case ISDN_PROTO_L2_X75UI:
@@ -859,7 +779,7 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi
}
for(i=0; i < wlen; i++)
message->llc[i] = buffer[pos++];
- eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0],
+ eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d ...\n", chan->No, message->llc[0],
message->llc[1],message->llc[2],message->llc[3]);
break;
case HLC:
@@ -869,7 +789,7 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi
}
for(i=0; i < wlen; i++)
message->hlc[i] = buffer[pos++];
- eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No,
+ eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x ...\n", chan->No,
message->hlc[0], message->hlc[1],
message->hlc[2], message->hlc[3], message->hlc[4]);
break;
@@ -1061,31 +981,55 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi
}
void
-idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *si1, unsigned char *si2)
+idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *sin, unsigned char *si1, unsigned char *si2)
{
- si1[0] = 0;
- si2[0] = 0;
- if (memcmp(bc, BC_Speech, 3) == 0) { /* Speech */
- si1[0] = 1;
+ si1[0] = 0;
+ si2[0] = 0;
+
+ switch (bc[0] & 0x7f) {
+ case 0x00: /* Speech */
+ si1[0] = 1;
#ifdef EICON_FULL_SERVICE_OKTETT
- si2[0] = 1;
+ si1[0] = sin[0];
+ si2[0] = sin[1];
#endif
- }
- if (memcmp(bc, BC_31khz, 3) == 0) { /* 3.1kHz audio */
- si1[0] = 1;
+ break;
+ case 0x10: /* 3.1 Khz audio */
+ si1[0] = 1;
#ifdef EICON_FULL_SERVICE_OKTETT
- si2[0] = 2;
- if (memcmp(hlc, HLC_faxg3, 2) == 0) { /* Fax Gr.2/3 */
- si1[0] = 2;
- }
+ si1[0] = sin[0];
+ si2[0] = sin[1];
#endif
- }
- if (memcmp(bc, BC_64k, 2) == 0) { /* unrestricted 64 kbits */
- si1[0] = 7;
- }
- if (memcmp(bc, BC_video, 3) == 0) { /* video */
- si1[0] = 4;
- }
+ break;
+ case 0x08: /* Unrestricted digital information */
+ si1[0] = 7;
+ si2[0] = sin[1];
+ break;
+ case 0x09: /* Restricted digital information */
+ si1[0] = 2;
+ break;
+ case 0x11:
+ /* Unrestr. digital information with
+ * tones/announcements ( or 7 kHz audio
+ */
+ si1[0] = 3;
+ break;
+ case 0x18: /* Video */
+ si1[0] = 4;
+ break;
+ }
+ switch (bc[1] & 0x7f) {
+ case 0x40: /* packed mode */
+ si1[0] = 8;
+ break;
+ case 0x10: /* 64 kbit */
+ case 0x11: /* 2*64 kbit */
+ case 0x13: /* 384 kbit */
+ case 0x15: /* 1536 kbit */
+ case 0x17: /* 1920 kbit */
+ /* moderate = bc[1] & 0x7f; */
+ break;
+ }
}
/********************* FAX stuff ***************************/
@@ -1225,7 +1169,7 @@ idi_send_edata(eicon_card *card, eicon_chan *chan)
reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ));
- reqbuf->Req = IDI_N_EDATA;
+ reqbuf->Req = N_EDATA;
reqbuf->ReqCh = chan->e.IndCh;
reqbuf->ReqId = 1;
@@ -1359,7 +1303,7 @@ idi_fax_send_header(eicon_card *card, eicon_chan *chan, int header)
eicon_log(card, 128, "sSFF-Head: pagelength = %d\n", page->pagelength);
break;
}
- idi_send_data(card, chan, 0, skb, 0);
+ idi_send_data(card, chan, 0, skb, 0, 0);
}
void
@@ -1913,7 +1857,7 @@ idi_fax_send_outbuf(eicon_card *ccard, eicon_chan *chan, eicon_OBJBUFFER *OutBuf
OutBuf->Len = 0;
OutBuf->Next = OutBuf->Data;
- return(idi_send_data(ccard, chan, 0, skb, 1));
+ return(idi_send_data(ccard, chan, 0, skb, 1, 0));
}
int
@@ -1958,6 +1902,8 @@ idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
if (chan->queued + skb->len > 1200)
return 0;
+ if (chan->pqueued > 1)
+ return 0;
InBuf.Data = skb->data;
InBuf.Size = skb->len;
@@ -2183,6 +2129,7 @@ idi_fax_hangup(eicon_card *ccard, eicon_chan *chan)
}
if ((chan->fax->code > 1) && (chan->fax->code < 120))
chan->fax->code += 120;
+ eicon_log(ccard, 8, "idi_fax: Ch%d: Hangup (code=%d)\n", chan->No, chan->fax->code);
chan->fax->r_code = ISDN_TTY_FAX_HNG;
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_FAXIND;
@@ -2224,7 +2171,7 @@ idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int
reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ));
- reqbuf->Req = IDI_N_UDATA;
+ reqbuf->Req = N_UDATA;
reqbuf->ReqCh = chan->e.IndCh;
reqbuf->ReqId = 1;
@@ -2418,12 +2365,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
while((skb2 = skb_dequeue(&chan->e.X))) {
dev_kfree_skb(skb2);
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eicon_lock, flags);
chan->queued = 0;
+ chan->pqueued = 0;
chan->waitq = 0;
chan->waitpq = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
if (message.e_cau[0] & 0x7f) {
cmd.driver = ccard->myid;
cmd.arg = chan->No;
@@ -2433,10 +2380,6 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
ccard->interface.statcallb(&cmd);
}
chan->cause[0] = 0;
-#ifdef CONFIG_ISDN_TTY_FAX
- if (!chan->e.B2Id)
- chan->fax = 0;
-#endif
if (((chan->fsm_state == EICON_STATE_ACTIVE) ||
(chan->fsm_state == EICON_STATE_WMCONN)) ||
((chan->l2prot == ISDN_PROTO_L2_FAX) &&
@@ -2446,6 +2389,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
if (chan->e.B2Id)
idi_do_req(ccard, chan, REMOVE, 1);
chan->statectrl &= ~WAITING_FOR_HANGUP;
+ chan->statectrl &= ~IN_HOLD;
if (chan->statectrl & HAVE_CONN_REQ) {
eicon_log(ccard, 32, "idi_req: Ch%d: queueing delayed conn_req\n", chan->No);
chan->statectrl &= ~HAVE_CONN_REQ;
@@ -2463,6 +2407,9 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
cmd.command = ISDN_STAT_DHUP;
ccard->interface.statcallb(&cmd);
eicon_idi_listen_req(ccard, chan);
+#ifdef CONFIG_ISDN_TTY_FAX
+ chan->fax = 0;
+#endif
}
}
break;
@@ -2475,7 +2422,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
break;
}
chan->fsm_state = EICON_STATE_ICALL;
- idi_bc2si(message.bc, message.hlc, &chan->si1, &chan->si2);
+ idi_bc2si(message.bc, message.hlc, message.sin, &chan->si1, &chan->si2);
strcpy(chan->cpn, message.cpn + 1);
strcpy(chan->oad, message.oad);
strcpy(chan->dsa, message.dsa);
@@ -2553,12 +2500,15 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
case ISDN_PROTO_L2_MODEM:
/* do nothing, wait for connect */
break;
+ case ISDN_PROTO_L2_V11096:
+ case ISDN_PROTO_L2_V11019:
+ case ISDN_PROTO_L2_V11038:
case ISDN_PROTO_L2_TRANS:
- idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
+ idi_do_req(ccard, chan, N_CONNECT, 1);
break;
default:
/* On most incoming calls we use automatic connect */
- /* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */
+ /* idi_do_req(ccard, chan, N_CONNECT, 1); */
}
} else {
if (chan->fsm_state != EICON_STATE_ACTIVE)
@@ -2568,33 +2518,50 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
case CALL_CON:
eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No);
if (chan->fsm_state == EICON_STATE_OCALL) {
- chan->fsm_state = EICON_STATE_OBWAIT;
- cmd.driver = ccard->myid;
- cmd.command = ISDN_STAT_DCONN;
- cmd.arg = chan->No;
- ccard->interface.statcallb(&cmd);
-
/* check if old NetID has been removed */
if (chan->e.B2Id) {
eicon_log(ccard, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n",
chan->No, chan->e.B2Id);
idi_do_req(ccard, chan, REMOVE, 1);
}
-
- idi_do_req(ccard, chan, ASSIGN, 1);
- idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
#ifdef CONFIG_ISDN_TTY_FAX
if (chan->l2prot == ISDN_PROTO_L2_FAX) {
- if (chan->fax)
+ if (chan->fax) {
chan->fax->phase = ISDN_FAX_PHASE_A;
+ } else {
+ eicon_log(ccard, 1, "idi_ind: Call_Con with NULL fax struct, ERROR\n");
+ idi_hangup(ccard, chan);
+ break;
+ }
}
#endif
+ chan->fsm_state = EICON_STATE_OBWAIT;
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_DCONN;
+ cmd.arg = chan->No;
+ ccard->interface.statcallb(&cmd);
+
+ idi_do_req(ccard, chan, ASSIGN, 1);
+ idi_do_req(ccard, chan, N_CONNECT, 1);
} else
- idi_hangup(ccard, chan);
+ idi_hangup(ccard, chan);
break;
case AOC_IND:
eicon_log(ccard, 8, "idi_ind: Ch%d: Advice of Charge\n", chan->No);
break;
+ case CALL_HOLD_ACK:
+ chan->statectrl |= IN_HOLD;
+ eicon_log(ccard, 8, "idi_ind: Ch%d: Call Hold Ack\n", chan->No);
+ break;
+ case SUSPEND_REJ:
+ eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Rejected\n", chan->No);
+ break;
+ case SUSPEND:
+ eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Ack\n", chan->No);
+ break;
+ case RESUME:
+ eicon_log(ccard, 8, "idi_ind: Ch%d: Resume Ack\n", chan->No);
+ break;
default:
eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind);
}
@@ -2613,7 +2580,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
}
else
switch(ind->Ind) {
- case IDI_N_CONNECT_ACK:
+ case N_CONNECT_ACK:
eicon_log(ccard, 16, "idi_ind: Ch%d: N_Connect_Ack\n", chan->No);
if (chan->l2prot == ISDN_PROTO_L2_MODEM) {
chan->fsm_state = EICON_STATE_WMCONN;
@@ -2634,7 +2601,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
}
}
else {
- eicon_log(ccard, 1, "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n");
+ eicon_log(ccard, 1, "idi_ind: N_Connect_Ack with NULL fax struct, ERROR\n");
}
#endif
break;
@@ -2646,10 +2613,10 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
strcpy(cmd.parm.num, "64000");
ccard->interface.statcallb(&cmd);
break;
- case IDI_N_CONNECT:
+ case N_CONNECT:
eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No);
chan->e.IndCh = ind->IndCh;
- if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1);
+ if (chan->e.B2Id) idi_do_req(ccard, chan, N_CONNECT_ACK, 1);
if (chan->l2prot == ISDN_PROTO_L2_FAX) {
break;
}
@@ -2664,43 +2631,47 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
strcpy(cmd.parm.num, "64000");
ccard->interface.statcallb(&cmd);
break;
- case IDI_N_DISC:
- eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC\n", chan->No);
+ case N_DISC:
+ eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc\n", chan->No);
if (chan->e.B2Id) {
while((skb2 = skb_dequeue(&chan->e.X))) {
dev_kfree_skb(skb2);
}
- idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1);
+ idi_do_req(ccard, chan, N_DISC_ACK, 1);
idi_do_req(ccard, chan, REMOVE, 1);
}
#ifdef CONFIG_ISDN_TTY_FAX
- if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+ if ((chan->l2prot == ISDN_PROTO_L2_FAX) && (chan->fax)){
idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
idi_fax_hangup(ccard, chan);
}
#endif
chan->e.IndCh = 0;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eicon_lock, flags);
chan->queued = 0;
+ chan->pqueued = 0;
chan->waitq = 0;
chan->waitpq = 0;
- restore_flags(flags);
- idi_do_req(ccard, chan, HANGUP, 0);
+ spin_unlock_irqrestore(&eicon_lock, flags);
+ if (!(chan->statectrl & IN_HOLD)) {
+ idi_do_req(ccard, chan, HANGUP, 0);
+ }
if (chan->fsm_state == EICON_STATE_ACTIVE) {
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_BHUP;
cmd.arg = chan->No;
ccard->interface.statcallb(&cmd);
chan->fsm_state = EICON_STATE_NULL;
- chan->statectrl |= WAITING_FOR_HANGUP;
+ if (!(chan->statectrl & IN_HOLD)) {
+ chan->statectrl |= WAITING_FOR_HANGUP;
+ }
}
#ifdef CONFIG_ISDN_TTY_FAX
chan->fax = 0;
#endif
break;
- case IDI_N_DISC_ACK:
- eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC_ACK\n", chan->No);
+ case N_DISC_ACK:
+ eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc_Ack\n", chan->No);
#ifdef CONFIG_ISDN_TTY_FAX
if (chan->l2prot == ISDN_PROTO_L2_FAX) {
idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
@@ -2708,10 +2679,10 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
}
#endif
break;
- case IDI_N_DATA_ACK:
- eicon_log(ccard, 128, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No);
+ case N_DATA_ACK:
+ eicon_log(ccard, 128, "idi_ind: Ch%d: N_Data_Ack\n", chan->No);
break;
- case IDI_N_DATA:
+ case N_DATA:
skb_pull(skb, sizeof(eicon_IND) - 1);
eicon_log(ccard, 128, "idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len);
if (chan->l2prot == ISDN_PROTO_L2_FAX) {
@@ -2723,11 +2694,11 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
free_buff = 0;
}
break;
- case IDI_N_UDATA:
+ case N_UDATA:
idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
break;
#ifdef CONFIG_ISDN_TTY_FAX
- case IDI_N_EDATA:
+ case N_EDATA:
idi_edata_action(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
break;
#endif
@@ -2747,6 +2718,8 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
{
ulong flags;
isdn_ctrl cmd;
+ int tqueued = 0;
+ int twaitpq = 0;
if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) {
/* I dont know why this happens, should not ! */
@@ -2770,16 +2743,15 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
ack->Reference, chan->e.ref);
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eicon_lock, flags);
ccard->IdTable[ack->RcId] = NULL;
- eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
- ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
if (!chan->e.ReqCh)
chan->e.D3Id = 0;
else
chan->e.B2Id = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
+ eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
+ ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
return 1;
}
@@ -2790,25 +2762,21 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
} else {
/* Network layer */
switch(chan->e.Req & 0x0f) {
- case IDI_N_CONNECT:
+ case N_CONNECT:
chan->e.IndCh = ack->RcCh;
eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
ack->RcId, ack->RcCh, ack->Reference);
break;
- case IDI_N_MDATA:
- case IDI_N_DATA:
- if ((chan->e.Req & 0x0f) == IDI_N_DATA) {
- if (chan->queued) {
- cmd.driver = ccard->myid;
- cmd.command = ISDN_STAT_BSENT;
- cmd.arg = chan->No;
- cmd.parm.length = chan->waitpq;
- ccard->interface.statcallb(&cmd);
- }
- save_flags(flags);
- cli();
+ case N_MDATA:
+ case N_DATA:
+ tqueued = chan->queued;
+ twaitpq = chan->waitpq;
+ if ((chan->e.Req & 0x0f) == N_DATA) {
+ spin_lock_irqsave(&eicon_lock, flags);
chan->waitpq = 0;
- restore_flags(flags);
+ if(chan->pqueued)
+ chan->pqueued--;
+ spin_unlock_irqrestore(&eicon_lock, flags);
#ifdef CONFIG_ISDN_TTY_FAX
if (chan->l2prot == ISDN_PROTO_L2_FAX) {
if (((chan->queued - chan->waitq) < 1) &&
@@ -2828,11 +2796,17 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
}
#endif
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eicon_lock, flags);
chan->queued -= chan->waitq;
if (chan->queued < 0) chan->queued = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
+ if (((chan->e.Req & 0x0f) == N_DATA) && (tqueued)) {
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_BSENT;
+ cmd.arg = chan->No;
+ cmd.parm.length = twaitpq;
+ ccard->interface.statcallb(&cmd);
+ }
break;
default:
eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
@@ -2858,11 +2832,10 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
return;
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eicon_lock, flags);
if ((chan = ccard->IdTable[ack->RcId]) != NULL)
dCh = chan->No;
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
switch (ack->Rc) {
case OK_FC:
@@ -2890,8 +2863,7 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
eicon_log(ccard, 1, "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n",
chan->No, chan->e.D3Id, chan->e.B2Id);
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eicon_lock, flags);
for(j = 0; j < ccard->nchannels + 1; j++) {
if ((ccard->bch[j].e.ref == ack->Reference) &&
(ccard->bch[j].e.Req == ASSIGN)) {
@@ -2901,12 +2873,12 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
ccard->bch[j].e.B2Id = ack->RcId;
ccard->IdTable[ack->RcId] = &ccard->bch[j];
chan = &ccard->bch[j];
- eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j,
- ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
break;
}
- }
- restore_flags(flags);
+ }
+ spin_unlock_irqrestore(&eicon_lock, flags);
+ eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j,
+ ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
if (j > ccard->nchannels) {
eicon_log(ccard, 24, "idi_ack: Ch??: ref %d not found for Id %d\n",
ack->Reference, ack->RcId);
@@ -2917,6 +2889,7 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
case UNKNOWN_COMMAND:
case WRONG_COMMAND:
case WRONG_ID:
+ case ADAPTER_DEAD:
case WRONG_CH:
case UNKNOWN_IE:
case WRONG_IE:
@@ -2949,19 +2922,18 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
ccard->interface.statcallb(&cmd);
}
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eicon_lock, flags);
if (chan) {
chan->e.ref = 0;
chan->e.busy = 0;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
dev_kfree_skb(skb);
eicon_schedule_tx(ccard);
}
int
-idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que)
+idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk)
{
struct sk_buff *xmit_skb;
struct sk_buff *skb2;
@@ -2985,13 +2957,14 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb,
return -1;
if (!len)
return 0;
- if (chan->queued + len > EICON_MAX_QUEUE)
+
+ if ((chk) && (chan->pqueued > 1))
return 0;
- eicon_log(card, 128, "idi_snd: Ch%d: %d bytes\n", chan->No, len);
+ eicon_log(card, 128, "idi_snd: Ch%d: %d bytes (Pqueue=%d)\n",
+ chan->No, len, chan->pqueued);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eicon_lock, flags);
while(offset < len) {
plen = ((len - offset) > 270) ? 270 : len - offset;
@@ -3000,7 +2973,7 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb,
skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
if ((!xmit_skb) || (!skb2)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No);
if (xmit_skb)
dev_kfree_skb(skb);
@@ -3013,13 +2986,10 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb,
chan2->ptr = chan;
reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ));
- if (((len - offset) > 270) &&
- (chan->l2prot != ISDN_PROTO_L2_MODEM) &&
- (chan->l2prot != ISDN_PROTO_L2_FAX) &&
- (chan->l2prot != ISDN_PROTO_L2_TRANS)) {
- reqbuf->Req = IDI_N_MDATA;
+ if ((len - offset) > 270) {
+ reqbuf->Req = N_MDATA;
} else {
- reqbuf->Req = IDI_N_DATA;
+ reqbuf->Req = N_DATA;
/* if (ack) reqbuf->Req |= N_D_BIT; */
}
reqbuf->ReqCh = chan->e.IndCh;
@@ -3033,9 +3003,11 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb,
offset += plen;
}
- if (que)
+ if (que) {
chan->queued += len;
- restore_flags(flags);
+ chan->pqueued++;
+ }
+ spin_unlock_irqrestore(&eicon_lock, flags);
eicon_schedule_tx(card);
dev_kfree_skb(skb);
return len;
@@ -3073,7 +3045,7 @@ eicon_idi_manage_assign(eicon_card *card)
reqbuf->XBuffer.P[0] = 0;
reqbuf->Req = ASSIGN;
reqbuf->ReqCh = 0;
- reqbuf->ReqId = 0xe0;
+ reqbuf->ReqId = MAN_ID;
reqbuf->XBuffer.length = 1;
reqbuf->Reference = 2; /* Man Entity */
@@ -3199,7 +3171,7 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
reqbuf->XBuffer.P[1] = manbuf->length[0] + 1;
reqbuf->XBuffer.P[l++] = 0;
- reqbuf->Req = (manbuf->count) ? manbuf->count : 0x02; /* Request */
+ reqbuf->Req = (manbuf->count) ? manbuf->count : MAN_READ;
reqbuf->ReqCh = 0;
reqbuf->ReqId = 1;
reqbuf->XBuffer.length = l;
diff --git a/drivers/isdn/eicon/eicon_idi.h b/drivers/isdn/eicon/eicon_idi.h
index 2fe6167a4..a11039219 100644
--- a/drivers/isdn/eicon/eicon_idi.h
+++ b/drivers/isdn/eicon/eicon_idi.h
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.h,v 1.9 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_idi.h,v 1.11 2000/05/07 08:51:04 armin Exp $
*
* ISDN lowlevel-module for the Eicon active cards.
* IDI-Interface
@@ -20,168 +20,30 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: eicon_idi.h,v $
- * Revision 1.9 2000/01/23 21:21:23 armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.8 1999/11/25 11:43:27 armin
- * Fixed statectrl and connect message.
- * X.75 fix and HDLC/transparent with autoconnect.
- * Minor cleanup.
- *
- * Revision 1.7 1999/08/22 20:26:46 calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- * define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.6 1999/07/25 15:12:04 armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.5 1999/07/11 17:16:26 armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.4 1999/03/29 11:19:44 armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.3 1999/03/02 12:37:45 armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.2 1999/01/24 20:14:18 armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.1 1999/01/01 18:09:42 armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
*
*/
-#ifndef IDI_H
-#define IDI_H
+#ifndef E_IDI_H
+#define E_IDI_H
#include <linux/config.h>
-#define ASSIGN 0x01
-#define REMOVE 0xff
-
-#define CALL_REQ 1 /* call request */
-#define CALL_CON 1 /* call confirmation */
-#define CALL_IND 2 /* incoming call connected */
-#define LISTEN_REQ 2 /* listen request */
-#define HANGUP 3 /* hangup request/indication */
-#define SUSPEND 4 /* call suspend request/confirm */
-#define RESUME 5 /* call resume request/confirm */
-#define SUSPEND_REJ 6 /* suspend rejected indication */
-#define USER_DATA 8 /* user data for user to user signaling */
-#define CONGESTION 9 /* network congestion indication */
-#define INDICATE_REQ 10 /* request to indicate an incoming call */
-#define INDICATE_IND 10 /* indicates that there is an incoming call */
-#define CALL_RES 11 /* accept an incoming call */
-#define CALL_ALERT 12 /* send ALERT for incoming call */
-#define INFO_REQ 13 /* INFO request */
-#define INFO_IND 13 /* INFO indication */
-#define REJECT 14 /* reject an incoming call */
-#define RESOURCES 15 /* reserve B-Channel hardware resources */
-#define TEL_CTRL 16 /* Telephone control request/indication */
-#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */
-#define FAC_REG_REQ 18 /* connection idependent fac registration */
-#define FAC_REG_ACK 19 /* fac registration acknowledge */
-#define FAC_REG_REJ 20 /* fac registration reject */
-#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */
-#define AOC_IND 26/* Advice of Charge */
-
-#define IDI_N_MDATA (0x01)
-#define IDI_N_CONNECT (0x02)
-#define IDI_N_CONNECT_ACK (0x03)
-#define IDI_N_DISC (0x04)
-#define IDI_N_DISC_ACK (0x05)
-#define IDI_N_RESET (0x06)
-#define IDI_N_RESET_ACK (0x07)
-#define IDI_N_DATA (0x08)
-#define IDI_N_EDATA (0x09)
-#define IDI_N_UDATA (0x0a)
-#define IDI_N_BDATA (0x0b)
-#define IDI_N_DATA_ACK (0x0c)
-#define IDI_N_EDATA_ACK (0x0d)
+#undef N_DATA
+#undef ID_MASK
-#define N_Q_BIT 0x10 /* Q-bit for req/ind */
-#define N_M_BIT 0x20 /* M-bit for req/ind */
-#define N_D_BIT 0x40 /* D-bit for req/ind */
+#include "pc.h"
+#define AOC_IND 26 /* Advice of Charge */
+#define PI 0x1e /* Progress Indicator */
+#define NI 0x27 /* Notification Indicator */
-#define SHIFT 0x90 /* codeset shift */
-#define MORE 0xa0 /* more data */
-#define CL 0xb0 /* congestion level */
-
- /* codeset 0 */
-
-#define BC 0x04 /* Bearer Capability */
-#define CAU 0x08 /* cause */
-#define CAD 0x0c /* Connected address */
-#define CAI 0x10 /* call identity */
-#define CHI 0x18 /* channel identification */
-#define LLI 0x19 /* logical link id */
-#define CHA 0x1a /* charge advice */
-#define FTY 0x1c
-#define PI 0x1e /* Progress Indicator */
-#define NI 0x27 /* Notification Indicator */
-#define DT 0x29 /* ETSI date/time */
-#define KEY 0x2c /* keypad information element */
-#define DSP 0x28 /* display */
-#define OAD 0x6c /* origination address */
-#define OSA 0x6d /* origination sub-address */
-#define CPN 0x70 /* called party number */
-#define DSA 0x71 /* destination sub-address */
-#define RDN 0x74 /* redirecting number */
-#define LLC 0x7c /* low layer compatibility */
-#define HLC 0x7d /* high layer compatibility */
-#define UUI 0x7e /* user user information */
-#define ESC 0x7f /* escape extension */
-
-#define DLC 0x20 /* data link layer configuration */
-#define NLC 0x21 /* network layer configuration */
-
- /* codeset 6 */
-
-#define SIN 0x01 /* service indicator */
-#define CIF 0x02 /* charging information */
-#define DATE 0x03 /* date */
-#define CPS 0x07 /* called party status */
-
-/*------------------------------------------------------------------*/
-/* return code coding */
-/*------------------------------------------------------------------*/
-
-#define UNKNOWN_COMMAND 0x01 /* unknown command */
-#define WRONG_COMMAND 0x02 /* wrong command */
-#define WRONG_ID 0x03 /* unknown task/entity id */
-#define WRONG_CH 0x04 /* wrong task/entity id */
-#define UNKNOWN_IE 0x05 /* unknown information el. */
-#define WRONG_IE 0x06 /* wrong information el. */
-#define OUT_OF_RESOURCES 0x07 /* card out of res. */
-#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */
-#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */
-#define ASSIGN_OK 0xef /* ASSIGN OK */
-#define OK_FC 0xfc /* Flow-Control RC */
-#define READY_INT 0xfd /* Ready interrupt */
-#define TIMER_INT 0xfe /* timer interrupt */
-#define OK 0xff /* command accepted */
-
-/*------------------------------------------------------------------*/
+#define CALL_HOLD 0x22
+#define CALL_HOLD_ACK 0x24
/* defines for statectrl */
#define WAITING_FOR_HANGUP 0x01
#define HAVE_CONN_REQ 0x02
+#define IN_HOLD 0x04
typedef struct {
char cpn[32];
@@ -242,26 +104,6 @@ typedef struct {
} eicon_IND;
typedef struct {
- __u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */
- __u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */
- __u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */
- __u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */
- __u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */
- __u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */
- __u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */
- __u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */
- __u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */
- __u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */
- __u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */
- __u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */
- __u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */
- __u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */
- __u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */
- __u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */
- __u8 B[1]; /* buffer space for Req,Ind and Rc */
-} eicon_pr_ram;
-
-typedef struct {
__u8 *Data;
unsigned int Size;
unsigned int Len;
@@ -278,8 +120,9 @@ extern int idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb);
extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb);
extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb);
-extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que);
+extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk);
extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value);
+extern int capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm);
#ifdef CONFIG_ISDN_TTY_FAX
extern void idi_fax_cmd(eicon_card *card, eicon_chan *chan);
extern int idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb);
diff --git a/drivers/isdn/eicon/eicon_io.c b/drivers/isdn/eicon/eicon_io.c
index 4f4180ed6..6f294e8b7 100644
--- a/drivers/isdn/eicon/eicon_io.c
+++ b/drivers/isdn/eicon/eicon_io.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_io.c,v 1.10 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_io.c,v 1.13 2000/05/07 08:51:04 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
* Code for communicating with hardware.
@@ -23,52 +23,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: eicon_io.c,v $
- * Revision 1.10 2000/01/23 21:21:23 armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.9 1999/11/18 20:55:25 armin
- * Ready_Int fix of ISA cards.
- *
- * Revision 1.8 1999/10/08 22:09:34 armin
- * Some fixes of cards interface handling.
- * Bugfix of NULL pointer occurence.
- * Changed a few log outputs.
- *
- * Revision 1.7 1999/09/26 14:17:53 armin
- * Improved debug and log via readstat()
- *
- * Revision 1.6 1999/09/21 20:35:43 armin
- * added more error checking.
- *
- * Revision 1.5 1999/08/31 11:20:11 paul
- * various spelling corrections (new checksums may be needed, Karsten!)
- *
- * Revision 1.4 1999/08/22 20:26:47 calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- * define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.3 1999/08/18 20:17:01 armin
- * Added XLOG function for all cards.
- * Bugfix of alloc_skb NULL pointer.
- *
- * Revision 1.2 1999/07/25 15:12:05 armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.1 1999/03/29 11:19:45 armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- *
*/
#include <linux/config.h>
#include "eicon.h"
+#include "uxio.h"
void
eicon_io_rcv_dispatch(eicon_card *ccard) {
@@ -85,12 +45,12 @@ eicon_io_rcv_dispatch(eicon_card *ccard) {
while((skb = skb_dequeue(&ccard->rcvq))) {
ind = (eicon_IND *)skb->data;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eicon_lock, flags);
if ((chan = ccard->IdTable[ind->IndId]) == NULL) {
+ spin_unlock_irqrestore(&eicon_lock, flags);
if (DebugVar & 1) {
switch(ind->Ind) {
- case IDI_N_DISC_ACK:
+ case N_DISC_ACK:
/* doesn't matter if this happens */
break;
default:
@@ -99,11 +59,10 @@ eicon_io_rcv_dispatch(eicon_card *ccard) {
ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
}
}
- restore_flags(flags);
dev_kfree_skb(skb);
continue;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
if (chan->e.complete) { /* check for rec-buffer chaining */
if (ind->MLength == ind->RBuffer.length) {
@@ -119,12 +78,9 @@ eicon_io_rcv_dispatch(eicon_card *ccard) {
}
}
else {
- save_flags(flags);
- cli();
if (!(skb2 = skb_dequeue(&chan->e.R))) {
chan->e.complete = 1;
eicon_log(ccard, 1, "eicon: buffer incomplete, but 0 in queue\n");
- restore_flags(flags);
dev_kfree_skb(skb);
continue;
}
@@ -133,7 +89,6 @@ eicon_io_rcv_dispatch(eicon_card *ccard) {
GFP_ATOMIC);
if (!skb_new) {
eicon_log(ccard, 1, "eicon_io: skb_alloc failed in rcv_dispatch()\n");
- restore_flags(flags);
dev_kfree_skb(skb);
dev_kfree_skb(skb2);
continue;
@@ -152,14 +107,12 @@ eicon_io_rcv_dispatch(eicon_card *ccard) {
dev_kfree_skb(skb2);
if (ind->MLength == ind->RBuffer.length) {
chan->e.complete = 2;
- restore_flags(flags);
idi_handle_ind(ccard, skb_new);
continue;
}
else {
chan->e.complete = 0;
skb_queue_tail(&chan->e.R, skb_new);
- restore_flags(flags);
continue;
}
}
@@ -181,242 +134,120 @@ eicon_io_ack_dispatch(eicon_card *ccard) {
/*
- * IO-Functions for different card-types
+ * IO-Functions for ISA cards
*/
u8 ram_inb(eicon_card *card, void *adr) {
- eicon_pci_card *pcard;
- eicon_isa_card *icard;
u32 addr = (u32) adr;
- pcard = &card->hwif.pci;
- icard = &card->hwif.isa;
-
- switch(card->type) {
- case EICON_CTYPE_MAESTRA:
- outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
- return(inb((u16)pcard->PCIreg + M_DATA));
- case EICON_CTYPE_MAESTRAP:
- case EICON_CTYPE_S2M:
- case EICON_CTYPE_S:
- case EICON_CTYPE_SX:
- case EICON_CTYPE_SCOM:
- case EICON_CTYPE_QUADRO:
- return(readb(addr));
- }
- return(0);
+ return(readb(addr));
}
u16 ram_inw(eicon_card *card, void *adr) {
- eicon_pci_card *pcard;
- eicon_isa_card *icard;
u32 addr = (u32) adr;
-
- pcard = &card->hwif.pci;
- icard = &card->hwif.isa;
-
- switch(card->type) {
- case EICON_CTYPE_MAESTRA:
- outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
- return(inw((u16)pcard->PCIreg + M_DATA));
- case EICON_CTYPE_MAESTRAP:
- case EICON_CTYPE_S2M:
- case EICON_CTYPE_S:
- case EICON_CTYPE_SX:
- case EICON_CTYPE_SCOM:
- case EICON_CTYPE_QUADRO:
- return(readw(addr));
- }
- return(0);
+
+ return(readw(addr));
}
void ram_outb(eicon_card *card, void *adr, u8 data) {
- eicon_pci_card *pcard;
- eicon_isa_card *icard;
u32 addr = (u32) adr;
- pcard = &card->hwif.pci;
- icard = &card->hwif.isa;
-
- switch(card->type) {
- case EICON_CTYPE_MAESTRA:
- outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
- outb((u8)data, (u16)pcard->PCIreg + M_DATA);
- break;
- case EICON_CTYPE_MAESTRAP:
- case EICON_CTYPE_S2M:
- case EICON_CTYPE_S:
- case EICON_CTYPE_SX:
- case EICON_CTYPE_SCOM:
- case EICON_CTYPE_QUADRO:
- writeb(data, addr);
- break;
- }
+ writeb(data, addr);
}
void ram_outw(eicon_card *card, void *adr , u16 data) {
- eicon_pci_card *pcard;
- eicon_isa_card *icard;
u32 addr = (u32) adr;
- pcard = &card->hwif.pci;
- icard = &card->hwif.isa;
-
- switch(card->type) {
- case EICON_CTYPE_MAESTRA:
- outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
- outw((u16)data, (u16)pcard->PCIreg + M_DATA);
- break;
- case EICON_CTYPE_MAESTRAP:
- case EICON_CTYPE_S2M:
- case EICON_CTYPE_S:
- case EICON_CTYPE_SX:
- case EICON_CTYPE_SCOM:
- case EICON_CTYPE_QUADRO:
- writew(data, addr);
- break;
- }
+ writew(data, addr);
}
void ram_copyfromcard(eicon_card *card, void *adrto, void *adr, int len) {
- int i;
- switch(card->type) {
- case EICON_CTYPE_MAESTRA:
- for(i = 0; i < len; i++) {
- writeb(ram_inb(card, adr + i), adrto + i);
- }
- break;
- case EICON_CTYPE_MAESTRAP:
- memcpy(adrto, adr, len);
- break;
- case EICON_CTYPE_S2M:
- case EICON_CTYPE_S:
- case EICON_CTYPE_SX:
- case EICON_CTYPE_SCOM:
- case EICON_CTYPE_QUADRO:
- memcpy_fromio(adrto, adr, len);
- break;
- }
+ memcpy_fromio(adrto, adr, len);
}
void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) {
- int i;
- switch(card->type) {
- case EICON_CTYPE_MAESTRA:
- for(i = 0; i < len; i++) {
- ram_outb(card, adrto + i, readb(adr + i));
- }
- break;
- case EICON_CTYPE_MAESTRAP:
- memcpy(adrto, adr, len);
- break;
- case EICON_CTYPE_S2M:
- case EICON_CTYPE_S:
- case EICON_CTYPE_SX:
- case EICON_CTYPE_SCOM:
- case EICON_CTYPE_QUADRO:
- memcpy_toio(adrto, adr, len);
- break;
- }
+ memcpy_toio(adrto, adr, len);
}
+
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
/*
- * XLOG
+ * IDI-Callback function
*/
-int
-eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq)
+void
+eicon_idi_callback(ENTITY *de)
{
- int timeout, i;
- int divas_shared_offset = 0;
+ eicon_card *ccard = (eicon_card *)de->R;
+ struct sk_buff *skb;
+ eicon_RC *ack;
+ eicon_IND *ind;
int len = 0;
- int stype = 0;
- __u32 time = 0;
- mi_pc_maint_t *pcm = &xlogreq->pcm;
- eicon_pci_card *pci_card = &card->hwif.pci;
- eicon_isa_card *isa_card = &card->hwif.isa;
- eicon_pr_ram *prram = 0;
- char *ram;
- switch(card->type) {
- case EICON_CTYPE_MAESTRAP:
- ram = (char *)pci_card->PCIram;
- prram = (eicon_pr_ram *)ram;
- divas_shared_offset = DIVAS_SHARED_OFFSET;
- len = sizeof(mi_pc_maint_t);
- break;
- case EICON_CTYPE_MAESTRA:
- prram = 0;
- divas_shared_offset = 0;
- len = sizeof(mi_pc_maint_t);
- break;
- case EICON_CTYPE_S:
- case EICON_CTYPE_SX:
- case EICON_CTYPE_SCOM:
- case EICON_CTYPE_QUADRO:
- case EICON_CTYPE_S2M:
- prram = (eicon_pr_ram *)isa_card->shmem;
- divas_shared_offset = 0xfb80;
- len = sizeof(mi_pc_maint_t) - 78;
- stype = 1;
- break;
- default:
- return -ENODEV;
- }
-
- memset(&(xlogreq->pcm), 0, sizeof(mi_pc_maint_t));
-
- xlogreq->pcm.rc = 0;
- xlogreq->pcm.req = 1; /* DO_LOG */
-
- ram = ((char *)prram) + MIPS_MAINT_OFFS - divas_shared_offset;
-
- ram_outb(card, ram+1, pcm->rc);
- ram_outb(card, ram+0, pcm->req);
-
- timeout = jiffies + 50;
- while (timeout > jiffies) {
- pcm->rc = ram_inb(card, ram+1);
- pcm->req = ram_inb(card, ram+0);
- if (!pcm->req) break;
- SLEEP(10);
- }
-
- if (pcm->req) {
- return XLOG_ERR_TIMEOUT;
- }
-
- if (pcm->rc != OK) {
- return XLOG_ERR_DONE;
- }
-
- ram_copyfromcard(card, pcm, ram, len);
-
- if (stype) {
- for (i=0; i<8; i++)
- ((__u8 *)pcm)[11-i] = ((__u8 *)pcm)[9-i];
- time = (__u32)pcm->data.w[2] * 3600 * 1000 +
- (__u32)pcm->data.w[1] * 1000 +
- (__u32)pcm->data.b[1] * 20 +
- (__u32)pcm->data.b[0] ;
- pcm->data.w[1] = (__u16) (time >> 16);
- pcm->data.w[2] = (__u16) (time & 0x0000ffff);
- pcm->data.w[0] = 2;
+ if (de->complete == 255) {
+ /* Return Code */
+ skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
+ if (!skb) {
+ eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n");
+ } else {
+ ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
+ ack->Rc = de->Rc;
+ if (de->Rc == ASSIGN_OK) {
+ ack->RcId = de->Id;
+ de->user[1] = de->Id;
+ } else {
+ ack->RcId = de->user[1];
+ }
+ ack->RcCh = de->RcCh;
+ ack->Reference = de->user[0];
+ skb_queue_tail(&ccard->rackq, skb);
+ eicon_schedule_ack(ccard);
+ eicon_log(ccard, 128, "idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x\n",
+ de->user[0], de->Rc, ack->RcId, de->RLength, de->complete);
+ }
+ } else {
+ /* Indication */
+ if (de->complete) {
+ len = de->RLength;
+ } else {
+ len = 270;
+ if (de->RLength <= 270)
+ eicon_log(ccard, 1, "eicon_cbk: ind not complete but <= 270\n");
+ }
+ skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
+ if (!skb) {
+ eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n");
+ } else {
+ ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
+ ind->Ind = de->Ind;
+ ind->IndId = de->user[1];
+ ind->IndCh = de->IndCh;
+ ind->MInd = de->Ind;
+ ind->RBuffer.length = len;
+ ind->MLength = de->RLength;
+ memcpy(&ind->RBuffer.P, &de->RBuffer->P, len);
+ skb_queue_tail(&ccard->rcvq, skb);
+ eicon_schedule_rx(ccard);
+ eicon_log(ccard, 128, "idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x\n",
+ de->user[0], de->Ind, ind->IndId, de->RLength, de->complete);
+ }
}
- return XLOG_OK;
+ de->RNum = 0;
+ de->RNR = 0;
+ de->Rc = 0;
+ de->Ind = 0;
}
+#endif /* CONFIG_ISDN_DRV_EICON_PCI */
/*
* Transmit-Function
*/
void
eicon_io_transmit(eicon_card *ccard) {
- eicon_pci_card *pci_card;
eicon_isa_card *isa_card;
struct sk_buff *skb;
struct sk_buff *skb2;
unsigned long flags;
- char *ram, *reg, *cfg;
eicon_pr_ram *prram = 0;
eicon_isa_com *com = 0;
eicon_REQ *ReqOut = 0;
@@ -426,10 +257,11 @@ eicon_io_transmit(eicon_card *ccard) {
int ReqCount;
int scom = 0;
int tmp = 0;
+ int tmpid = 0;
int quloop = 1;
int dlev = 0;
+ ENTITY *ep = 0;
- pci_card = &ccard->hwif.pci;
isa_card = &ccard->hwif.isa;
if (!ccard) {
@@ -451,20 +283,17 @@ eicon_io_transmit(eicon_card *ccard) {
prram = (eicon_pr_ram *)isa_card->shmem;
break;
#endif
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
case EICON_CTYPE_MAESTRAP:
- scom = 0;
- ram = (char *)pci_card->PCIram;
- reg = (char *)pci_card->PCIreg;
- cfg = (char *)pci_card->PCIcfg;
- prram = (eicon_pr_ram *)ram;
+ scom = 2;
+ break;
+ case EICON_CTYPE_MAESTRAQ:
+ scom = 2;
break;
case EICON_CTYPE_MAESTRA:
- scom = 0;
- ram = (char *)pci_card->PCIram;
- reg = (char *)pci_card->PCIreg;
- cfg = (char *)pci_card->PCIcfg;
- prram = 0;
+ scom = 2;
break;
+#endif
default:
eicon_log(ccard, 1, "eicon_transmit: unsupported card-type!\n");
return;
@@ -474,69 +303,91 @@ eicon_io_transmit(eicon_card *ccard) {
if (!(skb2 = skb_dequeue(&ccard->sndq)))
quloop = 0;
while(quloop) {
- save_flags(flags);
- cli();
- if (scom) {
+ spin_lock_irqsave(&eicon_lock, flags);
+ switch (scom) {
+ case 1:
if ((ram_inb(ccard, &com->Req)) || (ccard->ReadyInt)) {
if (!ccard->ReadyInt) {
tmp = ram_inb(ccard, &com->ReadyInt) + 1;
ram_outb(ccard, &com->ReadyInt, tmp);
ccard->ReadyInt++;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
skb_queue_head(&ccard->sndq, skb2);
eicon_log(ccard, 32, "eicon: transmit: Card not ready\n");
return;
}
- } else {
+ break;
+ case 0:
if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
skb_queue_head(&ccard->sndq, skb2);
eicon_log(ccard, 32, "eicon: transmit: Card not ready\n");
return;
}
+ break;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
+
chan2 = (eicon_chan_ptr *)skb2->data;
chan = chan2->ptr;
if (!chan->e.busy) {
if((skb = skb_dequeue(&chan->e.X))) {
- save_flags(flags);
- cli();
+
reqbuf = (eicon_REQ *)skb->data;
if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) {
eicon_log(ccard, 16, "eicon: transmit: error Id=0 on %d (Net)\n", chan->No);
} else {
- if (scom) {
+ spin_lock_irqsave(&eicon_lock, flags);
+
+ switch (scom) {
+ case 1:
ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length);
ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
ram_outb(ccard, &com->ReqCh, reqbuf->ReqCh);
-
- } else {
+ break;
+ case 0:
/* get address of next available request buffer */
ReqOut = (eicon_REQ *)&prram->B[ram_inw(ccard, &prram->NextReq)];
ram_outw(ccard, &ReqOut->XBuffer.length, reqbuf->XBuffer.length);
ram_copytocard(ccard, &ReqOut->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
ram_outb(ccard, &ReqOut->ReqCh, reqbuf->ReqCh);
ram_outb(ccard, &ReqOut->Req, reqbuf->Req);
+ break;
}
+
dlev = 160;
+
if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */
if (!reqbuf->Reference) { /* Signal Layer */
- if (scom)
+ switch (scom) {
+ case 1:
ram_outb(ccard, &com->ReqId, chan->e.D3Id);
- else
+ break;
+ case 0:
ram_outb(ccard, &ReqOut->ReqId, chan->e.D3Id);
-
+ break;
+ case 2:
+ ep = &chan->de;
+ break;
+ }
+ tmpid = chan->e.D3Id;
chan->e.ReqCh = 0;
}
else { /* Net Layer */
- if (scom)
+ switch(scom) {
+ case 1:
ram_outb(ccard, &com->ReqId, chan->e.B2Id);
- else
+ break;
+ case 0:
ram_outb(ccard, &ReqOut->ReqId, chan->e.B2Id);
-
+ break;
+ case 2:
+ ep = &chan->be;
+ break;
+ }
+ tmpid = chan->e.B2Id;
chan->e.ReqCh = 1;
if (((reqbuf->Req & 0x0f) == 0x08) ||
((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */
@@ -548,51 +399,106 @@ eicon_io_transmit(eicon_card *ccard) {
} else { /* It is an ASSIGN */
- if (scom)
+ switch(scom) {
+ case 1:
ram_outb(ccard, &com->ReqId, reqbuf->ReqId);
- else
+ break;
+ case 0:
ram_outb(ccard, &ReqOut->ReqId, reqbuf->ReqId);
+ break;
+ case 2:
+ if (!reqbuf->Reference)
+ ep = &chan->de;
+ else
+ ep = &chan->be;
+ ep->Id = reqbuf->ReqId;
+ break;
+ }
+ tmpid = reqbuf->ReqId;
if (!reqbuf->Reference)
chan->e.ReqCh = 0;
else
chan->e.ReqCh = 1;
}
- if (scom)
+
+ switch(scom) {
+ case 1:
chan->e.ref = ccard->ref_out++;
- else
+ break;
+ case 0:
chan->e.ref = ram_inw(ccard, &ReqOut->Reference);
+ break;
+ case 2:
+ chan->e.ref = chan->No;
+ break;
+ }
chan->e.Req = reqbuf->Req;
ReqCount++;
- if (scom)
+
+ switch (scom) {
+ case 1:
ram_outb(ccard, &com->Req, reqbuf->Req);
- else
+ break;
+ case 0:
ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next));
+ break;
+ case 2:
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+ if (!ep) break;
+ ep->callback = eicon_idi_callback;
+ ep->R = (BUFFERS *)ccard;
+ ep->user[0] = (word)chan->No;
+ ep->user[1] = (word)tmpid;
+ ep->XNum = 1;
+ ep->RNum = 0;
+ ep->RNR = 0;
+ ep->Rc = 0;
+ ep->Ind = 0;
+ ep->X->PLength = reqbuf->XBuffer.length;
+ memcpy(ep->X->P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
+ ep->ReqCh = reqbuf->ReqCh;
+ ep->Req = reqbuf->Req;
+#endif
+ break;
+ }
chan->e.busy = 1;
+ spin_unlock_irqrestore(&eicon_lock, flags);
eicon_log(ccard, dlev, "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n",
- reqbuf->Req,
- (scom) ? ram_inb(ccard, &com->ReqId) :
- ram_inb(ccard, &ReqOut->ReqId),
+ reqbuf->Req, tmpid,
reqbuf->ReqCh, reqbuf->XBuffer.length,
chan->e.ref);
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+ if (scom == 2) {
+ if (ep) {
+ ccard->d->request(ep);
+ if (ep->Rc)
+ eicon_idi_callback(ep);
+ }
+ }
+#endif
}
- restore_flags(flags);
dev_kfree_skb(skb);
}
dev_kfree_skb(skb2);
}
else {
- skb_queue_tail(&ccard->sackq, skb2);
- eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No);
+ skb_queue_tail(&ccard->sackq, skb2);
+ eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No);
}
- if (scom)
- quloop = 0;
- else
- if (!(skb2 = skb_dequeue(&ccard->sndq)))
+ switch(scom) {
+ case 1:
quloop = 0;
+ break;
+ case 0:
+ case 2:
+ if (!(skb2 = skb_dequeue(&ccard->sndq)))
+ quloop = 0;
+ break;
+ }
}
if (!scom)
@@ -603,18 +509,14 @@ eicon_io_transmit(eicon_card *ccard) {
}
}
-
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
/*
* IRQ handler
*/
void
eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
eicon_card *ccard = (eicon_card *)dev_id;
- eicon_pci_card *pci_card;
eicon_isa_card *isa_card;
- char *ram = 0;
- char *reg = 0;
- char *cfg = 0;
eicon_pr_ram *prram = 0;
eicon_isa_com *com = 0;
eicon_RC *RcIn;
@@ -646,11 +548,9 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
}
}
- pci_card = &ccard->hwif.pci;
isa_card = &ccard->hwif.isa;
switch(ccard->type) {
-#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
@@ -664,23 +564,6 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
prram = (eicon_pr_ram *)isa_card->shmem;
irqprobe = &isa_card->irqprobe;
break;
-#endif
- case EICON_CTYPE_MAESTRAP:
- scom = 0;
- ram = (char *)pci_card->PCIram;
- reg = (char *)pci_card->PCIreg;
- cfg = (char *)pci_card->PCIcfg;
- irqprobe = &pci_card->irqprobe;
- prram = (eicon_pr_ram *)ram;
- break;
- case EICON_CTYPE_MAESTRA:
- scom = 0;
- ram = (char *)pci_card->PCIram;
- reg = (char *)pci_card->PCIreg;
- cfg = (char *)pci_card->PCIcfg;
- irqprobe = &pci_card->irqprobe;
- prram = 0;
- break;
default:
eicon_log(ccard, 1, "eicon_irq: unsupported card-type!\n");
return;
@@ -688,7 +571,6 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
if (*irqprobe) {
switch(ccard->type) {
-#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
@@ -706,26 +588,11 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
}
(*irqprobe)++;
break;
-#endif
- case EICON_CTYPE_MAESTRAP:
- if (readb(&ram[0x3fe])) {
- writeb(0, &prram->RcOutput);
- writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
- writew(0, &cfg[MP_IRQ_RESET + 2]);
- writeb(0, &ram[0x3fe]);
- }
- *irqprobe = 0;
- break;
- case EICON_CTYPE_MAESTRA:
- outb(0x08, pci_card->PCIreg + M_RESET);
- *irqprobe = 0;
- break;
}
return;
}
switch(ccard->type) {
-#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
@@ -736,20 +603,6 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
return;
}
break;
-#endif
- case EICON_CTYPE_MAESTRAP:
- if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */
- eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
- return;
- }
- break;
- case EICON_CTYPE_MAESTRA:
- outw(0x3fe, pci_card->PCIreg + M_ADDR);
- if (!(inb(pci_card->PCIreg + M_DATA))) { /* card did not interrupt */
- eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
- return;
- }
- break;
}
if (scom) {
@@ -891,7 +744,6 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
/* clear interrupt */
switch(ccard->type) {
-#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_QUADRO:
writeb(0, isa_card->intack);
writeb(0, &com[0x401]);
@@ -902,19 +754,8 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
case EICON_CTYPE_S2M:
writeb(0, isa_card->intack);
break;
-#endif
- case EICON_CTYPE_MAESTRAP:
- writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
- writew(0, &cfg[MP_IRQ_RESET + 2]);
- writeb(0, &ram[0x3fe]);
- break;
- case EICON_CTYPE_MAESTRA:
- outb(0x08, pci_card->PCIreg + M_RESET);
- outw(0x3fe, pci_card->PCIreg + M_ADDR);
- outb(0, pci_card->PCIreg + M_DATA);
- break;
}
return;
}
-
+#endif
diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c
index 265e07e08..1d2ece7cd 100644
--- a/drivers/isdn/eicon/eicon_isa.c
+++ b/drivers/isdn/eicon/eicon_isa.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.c,v 1.14 2000/02/22 16:26:40 armin Exp $
+/* $Id: eicon_isa.c,v 1.16 2000/06/12 12:44:02 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
* Hardware-specific code for old ISA cards.
@@ -21,62 +21,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: eicon_isa.c,v $
- * Revision 1.14 2000/02/22 16:26:40 armin
- * Fixed membase error message.
- * Fixed missing log buffer struct.
- *
- * Revision 1.13 2000/01/23 21:21:23 armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.12 1999/11/27 12:56:19 armin
- * Forgot some iomem changes for last ioremap compat.
- *
- * Revision 1.11 1999/11/25 11:33:09 armin
- * Microchannel fix from Erik Weber (exrz73@ibm.net).
- *
- * Revision 1.10 1999/11/18 21:14:30 armin
- * New ISA memory mapped IO
- *
- * Revision 1.9 1999/09/08 20:17:31 armin
- * Added microchannel patch from Erik Weber (exrz73@ibm.net).
- *
- * Revision 1.8 1999/09/06 07:29:35 fritz
- * Changed my mail-address.
- *
- * Revision 1.7 1999/08/22 20:26:48 calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- * define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.6 1999/07/25 15:12:06 armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.5 1999/04/01 12:48:33 armin
- * Changed some log outputs.
- *
- * Revision 1.4 1999/03/29 11:19:46 armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.3 1999/03/02 12:37:45 armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.2 1999/01/24 20:14:19 armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.1 1999/01/01 18:09:43 armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
*/
#include <linux/config.h>
@@ -87,7 +31,7 @@
#define release_shmem release_region
#define request_shmem request_region
-char *eicon_isa_revision = "$Revision: 1.14 $";
+char *eicon_isa_revision = "$Revision: 1.16 $";
#undef EICON_MCA_DEBUG
@@ -357,7 +301,7 @@ eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) {
printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]);
if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) {
tmp = eicon_addcard(card->type, card->physmem, card->irq,
- ((eicon_card *)card->card)->regname);
+ ((eicon_card *)card->card)->regname, 0);
printk(KERN_INFO "Eicon: %d adapters added\n", tmp);
}
return 0;
diff --git a/drivers/isdn/eicon/eicon_isa.h b/drivers/isdn/eicon/eicon_isa.h
index b53adfcbf..1c8034f77 100644
--- a/drivers/isdn/eicon/eicon_isa.h
+++ b/drivers/isdn/eicon/eicon_isa.h
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.h,v 1.8 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_isa.h,v 1.10 2000/05/07 08:51:04 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
*
@@ -20,38 +20,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: eicon_isa.h,v $
- * Revision 1.8 2000/01/23 21:21:23 armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.7 1999/11/18 21:14:30 armin
- * New ISA memory mapped IO
- *
- * Revision 1.6 1999/11/15 19:37:04 keil
- * need config.h
- *
- * Revision 1.5 1999/09/08 20:17:31 armin
- * Added microchannel patch from Erik Weber.
- *
- * Revision 1.4 1999/09/06 07:29:35 fritz
- * Changed my mail-address.
- *
- * Revision 1.3 1999/03/29 11:19:47 armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.2 1999/03/02 12:37:46 armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.1 1999/01/01 18:09:44 armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
*/
#ifndef eicon_isa_h
@@ -138,7 +106,6 @@ typedef struct {
unsigned char mvalid; /* Flag: Memory is valid */
unsigned char ivalid; /* Flag: IRQ is valid */
unsigned char master; /* Flag: Card ist Quadro 1/4 */
- void* generic; /* Ptr to generic card struct */
} eicon_isa_card;
/* Offsets for special locations on standard cards */
diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c
index 9bc91d6f4..f3af22b27 100644
--- a/drivers/isdn/eicon/eicon_mod.c
+++ b/drivers/isdn/eicon/eicon_mod.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_mod.c,v 1.25 2000/02/22 16:26:40 armin Exp $
+/* $Id: eicon_mod.c,v 1.35 2000/08/12 18:00:47 armin Exp $
*
* ISDN lowlevel-module for Eicon active cards.
*
@@ -9,8 +9,6 @@
* Thanks to Eicon Technology GmbH & Co. oHG for
* documents, informations and hardware.
*
- * Deutsche Telekom AG for S2M support.
- *
* Deutsche Mailbox Saar-Lor-Lux GmbH
* for sponsoring and testing fax
* capabilities with Diva Server cards.
@@ -30,105 +28,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: eicon_mod.c,v $
- * Revision 1.25 2000/02/22 16:26:40 armin
- * Fixed membase error message.
- * Fixed missing log buffer struct.
- *
- * Revision 1.24 2000/01/23 21:21:23 armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.23 2000/01/20 19:55:34 keil
- * Add FAX Class 1 support
- *
- * Revision 1.22 1999/11/27 12:56:19 armin
- * Forgot some iomem changes for last ioremap compat.
- *
- * Revision 1.21 1999/11/25 11:35:10 armin
- * Microchannel fix from Erik Weber (exrz73@ibm.net).
- * Minor cleanup.
- *
- * Revision 1.20 1999/11/18 21:14:30 armin
- * New ISA memory mapped IO
- *
- * Revision 1.19 1999/11/12 13:21:44 armin
- * Bugfix of undefined reference with CONFIG_MCA
- *
- * Revision 1.18 1999/10/11 18:13:25 armin
- * Added fax capabilities for Eicon Diva Server cards.
- *
- * Revision 1.17 1999/10/08 22:09:34 armin
- * Some fixes of cards interface handling.
- * Bugfix of NULL pointer occurence.
- * Changed a few log outputs.
- *
- * Revision 1.16 1999/09/26 14:17:53 armin
- * Improved debug and log via readstat()
- *
- * Revision 1.15 1999/09/08 20:17:31 armin
- * Added microchannel patch from Erik Weber (exrz73@ibm.net).
- *
- * Revision 1.14 1999/09/06 07:29:35 fritz
- * Changed my mail-address.
- *
- * Revision 1.13 1999/09/04 17:37:59 armin
- * Removed not used define, did not work and caused error
- * in 2.3.16
- *
- * Revision 1.12 1999/08/31 11:20:14 paul
- * various spelling corrections (new checksums may be needed, Karsten!)
- *
- * Revision 1.11 1999/08/29 17:23:45 armin
- * New setup compat.
- * Bugfix if compile as not module.
- *
- * Revision 1.10 1999/08/28 21:32:53 armin
- * Prepared for fax related functions.
- * Now compilable without errors/warnings.
- *
- * Revision 1.9 1999/08/18 20:17:02 armin
- * Added XLOG function for all cards.
- * Bugfix of alloc_skb NULL pointer.
- *
- * Revision 1.8 1999/07/25 15:12:08 armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.7 1999/07/11 17:16:27 armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.6 1999/06/09 19:31:26 armin
- * Wrong PLX size for request_region() corrected.
- * Added first MCA code from Erik Weber.
- *
- * Revision 1.5 1999/04/01 12:48:35 armin
- * Changed some log outputs.
- *
- * Revision 1.4 1999/03/29 11:19:47 armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.3 1999/03/02 12:37:47 armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.2 1999/01/24 20:14:21 armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.1 1999/01/01 18:09:44 armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
*/
-#define DRIVERPATCH ""
+#define DRIVERNAME "Eicon active ISDN driver"
+#define DRIVERRELEASE "2.0"
+#define DRIVERPATCH ".14"
+
#include <linux/config.h>
#include <linux/module.h>
@@ -139,17 +44,30 @@
#include "eicon.h"
+#include "../avmb1/capicmd.h" /* this should be moved in a common place */
+
+#undef N_DATA
+#include "adapter.h"
+#include "uxio.h"
+
#define INCLUDE_INLINE_FUNCS
static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains
start of card-list */
-static char *eicon_revision = "$Revision: 1.25 $";
+static char *eicon_revision = "$Revision: 1.35 $";
extern char *eicon_pci_revision;
extern char *eicon_isa_revision;
extern char *eicon_idi_revision;
+extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile,
+ unsigned int command, unsigned long arg);
+extern void eicon_pci_init_conf(eicon_card *card);
+void mod_inc_use_count(void);
+void mod_dec_use_count(void);
+extern char *file_check(void);
+
#ifdef MODULE
#define MOD_USE_COUNT (GET_USE_COUNT (&__this_module))
#endif
@@ -158,6 +76,11 @@ extern char *eicon_idi_revision;
ulong DebugVar;
+spinlock_t eicon_lock;
+
+DESCRIPTOR idi_d[16];
+int idi_dlength;
+
/* Parameters to be set by insmod */
#ifdef CONFIG_ISDN_DRV_EICON_ISA
static int membase = -1;
@@ -189,23 +112,6 @@ char *eicon_ctype_name[] = {
"DIVA Server PRI/PCI"
};
-static int
-getrel(char *p)
-{
- int v = 0;
- char *tmp = 0;
-
- if ((tmp = strchr(p, '.')))
- p = tmp + 1;
- while (p[0] >= '0' && p[0] <= '9') {
- v = ((v < 0) ? 0 : (v * 10)) + (int) (p[0] - '0');
- p++;
- }
- return v;
-
-
-}
-
static char *
eicon_getrev(const char *revision)
{
@@ -229,68 +135,26 @@ find_channel(eicon_card *card, int channel)
return NULL;
}
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
/*
- * Free MSN list
+ * Find pcicard with given card number
*/
-static void
-eicon_clear_msn(eicon_card *card)
+static inline eicon_card *
+eicon_findnpcicard(int driverid)
{
- struct msn_entry *p = card->msn_list;
- struct msn_entry *q;
- unsigned long flags;
+ eicon_card *p = cards;
- save_flags(flags);
- cli();
- card->msn_list = NULL;
- restore_flags(flags);
while (p) {
- q = p->next;
- kfree(p);
- p = q;
+ if ((p->regname[strlen(p->regname)-1] == (driverid + '0')) &&
+ (p->bus == EICON_BUS_PCI))
+ return p;
+ p = p->next;
}
+ return (eicon_card *) 0;
}
-
-/*
- * Find an MSN entry in the list.
- * If ia5 != 0, return IA5-encoded EAZ, else
- * return a bitmask with corresponding bit set.
- */
-static __u16
-eicon_find_msn(eicon_card *card, char *msn, int ia5)
-{
- struct msn_entry *p = card->msn_list;
- __u8 eaz = '0';
-
- while (p) {
- if (!strcmp(p->msn, msn)) {
- eaz = p->eaz;
- break;
- }
- p = p->next;
- }
- if (!ia5)
- return (1 << (eaz - '0'));
- else
- return eaz;
-}
-
-/*
- * Find an EAZ entry in the list.
- * return a string with corresponding msn.
- */
-char *
-eicon_find_eaz(eicon_card *card, char eaz)
-{
- struct msn_entry *p = card->msn_list;
-
- while (p) {
- if (p->eaz == eaz)
- return(p->msn);
- p = p->next;
- }
- return("\0");
-}
-
+#endif
+#endif /* CONFIG_PCI */
static void
eicon_rcv_dispatch(struct eicon_card *card)
@@ -337,39 +201,18 @@ eicon_transmit(struct eicon_card *card)
}
}
-static int eicon_xlog(eicon_card *card, xlogreq_t *xlogreq)
-{
- xlogreq_t *xlr;
- int ret_val;
-
- if (!(xlr = kmalloc(sizeof(xlogreq_t), GFP_KERNEL))) {
- eicon_log(card, 1, "idi_err: alloc_xlogreq_t failed\n");
- return -ENOMEM;
- }
- if (copy_from_user(xlr, xlogreq, sizeof(xlogreq_t))) {
- kfree(xlr);
- return -EFAULT;
- }
-
- ret_val = eicon_get_xlog(card, xlr);
-
- if (copy_to_user(xlogreq, xlr, sizeof(xlogreq_t))) {
- kfree(xlr);
- return -EFAULT;
- }
- kfree(xlr);
-
- return ret_val;
-}
-
static int
eicon_command(eicon_card * card, isdn_ctrl * c)
{
ulong a;
eicon_chan *chan;
eicon_cdef cdef;
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+ dia_start_t dstart;
+#endif
+#endif
isdn_ctrl cmd;
- char tmp[17];
int ret = 0;
unsigned long flags;
@@ -383,16 +226,15 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
case EICON_IOCTL_GETVER:
return(EICON_CTRL_VERSION);
case EICON_IOCTL_GETTYPE:
+ if (card->bus == EICON_BUS_PCI) {
+ copy_to_user((char *)a, &card->hwif.pci.master, sizeof(int));
+ }
return(card->type);
case EICON_IOCTL_GETMMIO:
switch (card->bus) {
case EICON_BUS_ISA:
case EICON_BUS_MCA:
return (int)card->hwif.isa.shmem;
-#if CONFIG_PCI
- case EICON_BUS_PCI:
- return card->hwif.pci.PCIram;
-#endif
default:
eicon_log(card, 1,
"eicon: Illegal BUS type %d\n",
@@ -433,10 +275,6 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
case EICON_BUS_ISA:
case EICON_BUS_MCA:
return card->hwif.isa.irq;
-#if CONFIG_PCI
- case EICON_BUS_PCI:
- return card->hwif.pci.irq;
-#endif
default:
eicon_log(card, 1,
"eicon: Illegal BUS type %d\n",
@@ -514,7 +352,9 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
case EICON_IOCTL_MANIF:
if (!card->flags & EICON_FLAGS_RUNNING)
return -ENODEV;
- if (!card->Feature & PROTCAP_MANIF)
+ if (!card->d)
+ return -ENODEV;
+ if (!card->d->features & DI_MANAGE)
return -ENODEV;
ret = eicon_idi_manage(
card,
@@ -522,49 +362,12 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
return ret;
case EICON_IOCTL_GETXLOG:
- if (!card->flags & EICON_FLAGS_RUNNING)
- return XLOG_ERR_CARD_STATE;
- ret = eicon_xlog(card, (xlogreq_t *)a);
- return ret;
-#if CONFIG_PCI
- case EICON_IOCTL_LOADPCI:
- if (card->flags & EICON_FLAGS_RUNNING)
- return -EBUSY;
- if (card->bus == EICON_BUS_PCI) {
- switch(card->type) {
- case EICON_CTYPE_MAESTRA:
- ret = eicon_pci_load_bri(
- &(card->hwif.pci),
- &(((eicon_codebuf *)a)->pci));
- break;
-
- case EICON_CTYPE_MAESTRAP:
- ret = eicon_pci_load_pri(
- &(card->hwif.pci),
- &(((eicon_codebuf *)a)->pci));
- break;
- }
- if (!ret) {
- card->flags |= EICON_FLAGS_LOADED;
- card->flags |= EICON_FLAGS_RUNNING;
- if (card->hwif.pci.channels > 1) {
- cmd.command = ISDN_STAT_ADDCH;
- cmd.driver = card->myid;
- cmd.arg = card->hwif.pci.channels - 1;
- card->interface.statcallb(&cmd);
- }
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = card->myid;
- cmd.arg = 0;
- card->interface.statcallb(&cmd);
- }
- return ret;
- } else return -ENODEV;
-#endif
+ return -ENODEV;
+
case EICON_IOCTL_ADDCARD:
if ((ret = copy_from_user(&cdef, (char *)a, sizeof(cdef))))
return -EFAULT;
- if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id)))
+ if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id, 0)))
return -EIO;
return 0;
case EICON_IOCTL_DEBUGVAR:
@@ -574,11 +377,77 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
#ifdef MODULE
case EICON_IOCTL_FREEIT:
while (MOD_USE_COUNT > 0) MOD_DEC_USE_COUNT;
- MOD_INC_USE_COUNT;
+ mod_inc_use_count();
return 0;
#endif
- default:
+ case EICON_IOCTL_LOADPCI:
+ eicon_log(card, 1, "Eicon: Wrong version of load-utility,\n");
+ eicon_log(card, 1, "Eicon: re-compile eiconctrl !\n");
+ eicon_log(card, 1, "Eicon: Maybe update of utility is necessary !\n");
return -EINVAL;
+ default:
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+ if (c->arg < EICON_IOCTL_DIA_OFFSET)
+ return -EINVAL;
+ if (copy_from_user(&dstart, (char *)a, sizeof(dstart)))
+ return -1;
+ if (!(card = eicon_findnpcicard(dstart.card_id)))
+ return -EINVAL;
+ ret = do_ioctl(NULL, NULL,
+ c->arg - EICON_IOCTL_DIA_OFFSET,
+ (unsigned long) a);
+ if (((c->arg - EICON_IOCTL_DIA_OFFSET)==DIA_IOCTL_START) && (!ret)) {
+ if (card->type != EICON_CTYPE_MAESTRAQ) {
+ EtdM_DIDD_Read(idi_d, &idi_dlength);
+ card->d = &idi_d[idi_dlength - 1];
+ card->flags |= EICON_FLAGS_LOADED;
+ card->flags |= EICON_FLAGS_RUNNING;
+ eicon_pci_init_conf(card);
+ if (card->d->channels > 1) {
+ cmd.command = ISDN_STAT_ADDCH;
+ cmd.driver = card->myid;
+ cmd.arg = card->d->channels - 1;
+ card->interface.statcallb(&cmd);
+ }
+ cmd.command = ISDN_STAT_RUN;
+ cmd.driver = card->myid;
+ cmd.arg = 0;
+ card->interface.statcallb(&cmd);
+ eicon_log(card, 1, "Eicon: %s started, %d channels (feat. 0x%x, SerNo. %d)\n",
+ (card->type == EICON_CTYPE_MAESTRA) ? "BRI" : "PRI",
+ card->d->channels, card->d->features, card->d->serial);
+ } else {
+ int i;
+ EtdM_DIDD_Read(idi_d, &idi_dlength);
+ for(i = 3; i >= 0; i--) {
+ if (!(card = eicon_findnpcicard(dstart.card_id - i)))
+ return -EINVAL;
+
+ card->flags |= EICON_FLAGS_LOADED;
+ card->flags |= EICON_FLAGS_RUNNING;
+ card->d = &idi_d[idi_dlength - (i+1)];
+ eicon_pci_init_conf(card);
+ if (card->d->channels > 1) {
+ cmd.command = ISDN_STAT_ADDCH;
+ cmd.driver = card->myid;
+ cmd.arg = card->d->channels - 1;
+ card->interface.statcallb(&cmd);
+ }
+ cmd.command = ISDN_STAT_RUN;
+ cmd.driver = card->myid;
+ cmd.arg = 0;
+ card->interface.statcallb(&cmd);
+ eicon_log(card, 1, "Eicon: %d/4BRI started, %d channels (feat. 0x%x, SerNo. %d)\n",
+ 4-i, card->d->channels, card->d->features, card->d->serial);
+ }
+ }
+ }
+ return ret;
+#else
+ return -EINVAL;
+#endif
+#endif /* CONFIG_PCI */
}
break;
case ISDN_CMD_DIAL:
@@ -586,20 +455,15 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x1f)))
break;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eicon_lock, flags);
if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
eicon_log(card, 1, "Dial on channel %d with state %d\n",
chan->No, chan->fsm_state);
return -EBUSY;
}
- if (card->ptype == ISDN_PTYPE_EURO)
- tmp[0] = eicon_find_msn(card, c->parm.setup.eazmsn, 1);
- else
- tmp[0] = c->parm.setup.eazmsn[0];
chan->fsm_state = EICON_STATE_OCALL;
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
ret = idi_connect_req(card, chan, c->parm.setup.phone,
c->parm.setup.eazmsn,
@@ -637,19 +501,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x1f)))
break;
- if (strlen(c->parm.num)) {
- if (card->ptype == ISDN_PTYPE_EURO) {
- chan->eazmask = eicon_find_msn(card, c->parm.num, 0);
- }
- if (card->ptype == ISDN_PTYPE_1TR6) {
- int i;
- chan->eazmask = 0;
- for (i = 0; i < strlen(c->parm.num); i++)
- if (isdigit(c->parm.num[i]))
- chan->eazmask |= (1 << (c->parm.num[i] - '0'));
- }
- } else
- chan->eazmask = 0x3ff;
+ chan->eazmask = 0x3ff;
eicon_idi_listen_req(card, chan);
return 0;
case ISDN_CMD_CLREAZ:
@@ -680,8 +532,10 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
break;
chan->l3prot = (c->arg >> 8);
#ifdef CONFIG_ISDN_TTY_FAX
- if (chan->l3prot == ISDN_PROTO_L3_FCLASS2)
+ if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) {
chan->fax = c->parm.fax;
+ eicon_log(card, 128, "idi_cmd: Ch%d: SETL3 struct fax=0x%x\n",chan->No, chan->fax);
+ }
#endif
return 0;
case ISDN_CMD_GETL3:
@@ -706,10 +560,14 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
eicon_log(card, 1, "eicon CMD_GETSIL not implemented\n");
return 0;
case ISDN_CMD_LOCK:
- MOD_INC_USE_COUNT;
+#ifdef MODULE
+ mod_inc_use_count();
+#endif
return 0;
case ISDN_CMD_UNLOCK:
- MOD_DEC_USE_COUNT;
+#ifdef MODULE
+ mod_dec_use_count();
+#endif
return 0;
#ifdef CONFIG_ISDN_TTY_FAX
case ISDN_CMD_FAXCMD:
@@ -729,6 +587,23 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
break;
idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num);
return 0;
+ case CAPI_PUT_MESSAGE:
+ if (!card->flags & EICON_FLAGS_RUNNING)
+ return -ENODEV;
+ if (!(chan = find_channel(card, c->arg & 0x1f)))
+ break;
+ if (c->parm.cmsg.Length < 8)
+ break;
+ switch(c->parm.cmsg.Command) {
+ case CAPI_FACILITY:
+ if (c->parm.cmsg.Subcommand == CAPI_REQ)
+ return(capipmsg(card, chan, &c->parm.cmsg));
+ break;
+ case CAPI_MANUFACTURER:
+ default:
+ break;
+ }
+ return 0;
}
return -EINVAL;
@@ -787,8 +662,7 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel)
if (!card->flags & EICON_FLAGS_RUNNING)
return -ENODEV;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eicon_lock, flags);
while((skb = skb_dequeue(&card->statq))) {
if ((skb->len + count) > len)
@@ -811,12 +685,12 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel)
} else {
skb_pull(skb, cnt);
skb_queue_head(&card->statq, skb);
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
return count;
}
}
card->statq_entries = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
return count;
}
printk(KERN_ERR
@@ -848,7 +722,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
}
else
#endif
- ret = idi_send_data(card, chan, ack, skb, 1);
+ ret = idi_send_data(card, chan, ack, skb, 1, 1);
return (ret);
} else {
return -ENODEV;
@@ -895,12 +769,11 @@ eicon_putstatus(eicon_card * card, char * buf)
return;
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eicon_lock, flags);
count = strlen(buf);
skb = alloc_skb(count, GFP_ATOMIC);
if (!skb) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
printk(KERN_ERR "eicon: could not alloc skb in putstatus\n");
return;
}
@@ -918,7 +791,7 @@ eicon_putstatus(eicon_card * card, char * buf)
} else
card->statq_entries++;
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
if (count) {
cmd.command = ISDN_STAT_STAVAIL;
cmd.driver = card->myid;
@@ -967,7 +840,7 @@ eicon_log(eicon_card * card, int level, const char *fmt, ...)
* link it into cards-list.
*/
static void
-eicon_alloccard(int Type, int membase, int irq, char *id)
+eicon_alloccard(int Type, int membase, int irq, char *id, int card_id)
{
int i;
int j;
@@ -976,9 +849,6 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
char qid[5];
#endif
eicon_card *card;
-#if CONFIG_PCI
- eicon_pci_card *pcic;
-#endif
qloop = (Type == EICON_CTYPE_QUADRO)?2:0;
for (i = 0; i <= qloop; i++) {
@@ -1088,9 +958,9 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->interface.channels = 1;
break;
#endif
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
case EICON_CTYPE_MAESTRA:
- (eicon_pci_card *)pcic = (eicon_pci_card *)membase;
card->bus = EICON_BUS_PCI;
card->interface.features |=
ISDN_FEATURE_L2_V11096 |
@@ -1101,11 +971,26 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
ISDN_FEATURE_L3_TRANSDSP |
ISDN_FEATURE_L3_FCLASS2;
card->hwif.pci.card = (void *)card;
- card->hwif.pci.PCIreg = pcic->PCIreg;
- card->hwif.pci.PCIcfg = pcic->PCIcfg;
- card->hwif.pci.master = 1;
- card->hwif.pci.mvalid = pcic->mvalid;
- card->hwif.pci.ivalid = 0;
+ card->hwif.pci.master = card_id;
+ card->hwif.pci.irq = irq;
+ card->hwif.pci.type = Type;
+ card->flags = 0;
+ card->nchannels = 2;
+ card->interface.channels = 1;
+ break;
+
+ case EICON_CTYPE_MAESTRAQ:
+ card->bus = EICON_BUS_PCI;
+ card->interface.features |=
+ ISDN_FEATURE_L2_V11096 |
+ ISDN_FEATURE_L2_V11019 |
+ ISDN_FEATURE_L2_V11038 |
+ ISDN_FEATURE_L2_MODEM |
+ ISDN_FEATURE_L2_FAX |
+ ISDN_FEATURE_L3_TRANSDSP |
+ ISDN_FEATURE_L3_FCLASS2;
+ card->hwif.pci.card = (void *)card;
+ card->hwif.pci.master = card_id;
card->hwif.pci.irq = irq;
card->hwif.pci.type = Type;
card->flags = 0;
@@ -1114,7 +999,6 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
break;
case EICON_CTYPE_MAESTRAP:
- (eicon_pci_card *)pcic = (eicon_pci_card *)membase;
card->bus = EICON_BUS_PCI;
card->interface.features |=
ISDN_FEATURE_L2_V11096 |
@@ -1125,13 +1009,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
ISDN_FEATURE_L3_TRANSDSP |
ISDN_FEATURE_L3_FCLASS2;
card->hwif.pci.card = (void *)card;
- card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem;
- card->hwif.pci.PCIreg = pcic->PCIreg;
- card->hwif.pci.PCIram = pcic->PCIram;
- card->hwif.pci.PCIcfg = pcic->PCIcfg;
- card->hwif.pci.master = 1;
- card->hwif.pci.mvalid = pcic->mvalid;
- card->hwif.pci.ivalid = 0;
+ card->hwif.pci.master = card_id;
card->hwif.pci.irq = irq;
card->hwif.pci.type = Type;
card->flags = 0;
@@ -1139,6 +1017,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->interface.channels = 1;
break;
#endif
+#endif
#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_ISABRI:
if (membase == -1)
@@ -1197,6 +1076,53 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
skb_queue_head_init(&card->bch[j].e.X);
skb_queue_head_init(&card->bch[j].e.R);
}
+
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+ /* *** Diva Server *** */
+ if (!(card->dbuf = (DBUFFER *) kmalloc((sizeof(DBUFFER) * (card->nchannels + 1))*2
+ , GFP_KERNEL))) {
+ eicon_log(card, 1,
+ "eicon: (%s) Could not allocate DBUFFER-struct.\n", id);
+ kfree(card);
+ kfree(card->bch);
+ return;
+ }
+ if (!(card->sbuf = (BUFFERS *) kmalloc((sizeof(BUFFERS) * (card->nchannels + 1)) * 2, GFP_KERNEL))) {
+ eicon_log(card, 1,
+ "eicon: (%s) Could not allocate BUFFERS-struct.\n", id);
+ kfree(card);
+ kfree(card->bch);
+ kfree(card->dbuf);
+ return;
+ }
+ if (!(card->sbufp = (char *) kmalloc((270 * (card->nchannels + 1)) * 2, GFP_KERNEL))) {
+ eicon_log(card, 1,
+ "eicon: (%s) Could not allocate BUFFERSP-struct.\n", id);
+ kfree(card);
+ kfree(card->bch);
+ kfree(card->dbuf);
+ kfree(card->sbuf);
+ return;
+ }
+ for (j=0; j< (card->nchannels + 1); j++) {
+ memset((char *)&card->dbuf[j], 0, sizeof(DBUFFER));
+ card->bch[j].de.RBuffer = (DBUFFER *)&card->dbuf[j];
+ memset((char *)&card->dbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS));
+ card->bch[j].be.RBuffer = (DBUFFER *)&card->dbuf[j+(card->nchannels+1)];
+
+ memset((char *)&card->sbuf[j], 0, sizeof(BUFFERS));
+ card->bch[j].de.X = (BUFFERS *)&card->sbuf[j];
+ memset((char *)&card->sbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS));
+ card->bch[j].be.X = (BUFFERS *)&card->sbuf[j+(card->nchannels+1)];
+
+ memset((char *)&card->sbufp[j], 0, 270);
+ card->bch[j].de.X->P = (char *)&card->sbufp[j * 270];
+ memset((char *)&card->sbufp[j+(card->nchannels+1)], 0, 270);
+ card->bch[j].be.X->P = (char *)&card->sbufp[(j+(card->nchannels+1)) * 270];
+ }
+ /* *** */
+#endif /* CONFIG_ISDN_DRV_EICON_PCI */
+
card->next = cards;
cards = card;
}
@@ -1220,10 +1146,7 @@ eicon_registercard(eicon_card * card)
#endif /* CONFIG_MCA */
#endif
case EICON_BUS_PCI:
-#if CONFIG_PCI
- eicon_pci_printpar(&card->hwif.pci);
break;
-#endif
default:
eicon_log(card, 1,
"eicon_registercard: Illegal BUS type %d\n",
@@ -1260,10 +1183,7 @@ unregister_card(eicon_card * card)
break;
#endif
case EICON_BUS_PCI:
-#if CONFIG_PCI
- eicon_pci_release(&card->hwif.pci);
break;
-#endif
default:
eicon_log(card, 1,
"eicon: Invalid BUS type %d\n",
@@ -1295,13 +1215,17 @@ eicon_freecard(eicon_card *card) {
while((skb = skb_dequeue(&card->statq)))
dev_kfree_skb(skb);
- eicon_clear_msn(card);
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+ kfree(card->sbufp);
+ kfree(card->sbuf);
+ kfree(card->dbuf);
+#endif
kfree(card->bch);
kfree(card);
}
int
-eicon_addcard(int Type, int membase, int irq, char *id)
+eicon_addcard(int Type, int membase, int irq, char *id, int card_id)
{
eicon_card *p;
eicon_card *q = NULL;
@@ -1314,7 +1238,7 @@ eicon_addcard(int Type, int membase, int irq, char *id)
if ((Type = eicon_isa_find_card(membase, irq, id)) < 0)
return 0;
#endif
- eicon_alloccard(Type, membase, irq, id);
+ eicon_alloccard(Type, membase, irq, id, card_id);
p = cards;
while (p) {
registered = 0;
@@ -1333,12 +1257,14 @@ eicon_addcard(int Type, int membase, int irq, char *id)
break;
#endif
case EICON_BUS_PCI:
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
if (eicon_registercard(p))
break;
registered = 1;
break;
#endif
+#endif
default:
printk(KERN_ERR
"eicon: addcard: Invalid BUS type %d\n",
@@ -1371,8 +1297,6 @@ eicon_addcard(int Type, int membase, int irq, char *id)
return (added - failed);
}
-#define DRIVERNAME "Eicon active ISDN driver"
-#define DRIVERRELEASE "1"
#ifdef MODULE
#define eicon_init init_module
@@ -1382,35 +1306,30 @@ int
eicon_init(void)
{
int card_count = 0;
- int release = 0;
char tmprev[50];
DebugVar = 1;
+ eicon_lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
printk(KERN_INFO "%s Rev: ", DRIVERNAME);
strcpy(tmprev, eicon_revision);
printk("%s/", eicon_getrev(tmprev));
- release += getrel(tmprev);
strcpy(tmprev, eicon_pci_revision);
-#if CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
printk("%s/", eicon_getrev(tmprev));
#else
printk("---/");
#endif
- release += getrel(tmprev);
strcpy(tmprev, eicon_isa_revision);
#ifdef CONFIG_ISDN_DRV_EICON_ISA
printk("%s/", eicon_getrev(tmprev));
#else
printk("---/");
#endif
- release += getrel(tmprev);
strcpy(tmprev, eicon_idi_revision);
printk("%s\n", eicon_getrev(tmprev));
- release += getrel(tmprev);
- sprintf(tmprev,"%d", release);
- printk(KERN_INFO "%s Release: %s.%s%s\n", DRIVERNAME,
- DRIVERRELEASE, tmprev, DRIVERPATCH);
+ printk(KERN_INFO "%s Release: %s%s (%s)\n", DRIVERNAME,
+ DRIVERRELEASE, DRIVERPATCH, file_check());
#ifdef CONFIG_ISDN_DRV_EICON_ISA
#ifdef CONFIG_MCA
@@ -1427,18 +1346,23 @@ eicon_init(void)
card_count++;
};
#else
- card_count = eicon_addcard(0, membase, irq, id);
+ card_count = eicon_addcard(0, membase, irq, id, 0);
#endif /* CONFIG_MCA */
#endif /* CONFIG_ISDN_DRV_EICON_ISA */
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+ DivasCardsDiscover();
card_count += eicon_pci_find_card(id);
#endif
+#endif
+
if (!cards) {
#ifdef MODULE
-#ifndef CONFIG_PCI
+#ifndef CONFIG_ISDN_DRV_EICON_PCI
#ifndef CONFIG_ISDN_DRV_EICON_ISA
printk(KERN_INFO "Eicon: Driver is neither ISA nor PCI compiled !\n");
+ printk(KERN_INFO "Eicon: Driver not loaded !\n");
#else
printk(KERN_INFO "Eicon: No cards defined, driver not loaded !\n");
#endif
@@ -1451,17 +1375,47 @@ eicon_init(void)
} else
printk(KERN_INFO "Eicon: %d card%s added\n", card_count,
(card_count>1)?"s":"");
- /* No symbols to export, hide all symbols */
- EXPORT_NO_SYMBOLS;
return 0;
}
+
#ifdef MODULE
+
+void mod_inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+void mod_dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+void EtdM_DIDD_Write(DESCRIPTOR *, int);
+EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Read);
+EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Write);
+EXPORT_SYMBOL_NOVERS(DivasPrintf);
+#else
+int DivasCardNext;
+card_t DivasCards[1];
+#endif
+
void
cleanup_module(void)
{
+#if CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+ card_t *pCard;
+ word wCardIndex;
+ extern int Divas_major;
+ int iTmp = 0;
+#endif
+#endif
+
eicon_card *card = cards;
eicon_card *last;
+
while (card) {
#ifdef CONFIG_ISDN_DRV_EICON_ISA
#ifdef CONFIG_MCA
@@ -1481,6 +1435,54 @@ cleanup_module(void)
card = card->next;
eicon_freecard(last);
}
+
+#if CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+ pCard = DivasCards;
+ for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++)
+ {
+ if ((pCard->hw) && (pCard->hw->in_use))
+ {
+ (*pCard->card_reset)(pCard);
+
+ UxIsrRemove(pCard->hw, pCard);
+ UxCardHandleFree(pCard->hw);
+
+ if(pCard->e_tbl != NULL)
+ {
+ kfree(pCard->e_tbl);
+ }
+
+ if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B)
+ {
+ release_region(pCard->hw->io_base,0x20);
+ release_region(pCard->hw->reset_base,0x80);
+ }
+
+ // If this is a 4BRI ...
+ if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q)
+ {
+ // Skip over the next 3 virtual adapters
+ wCardIndex += 3;
+
+ // But free their handles
+ for (iTmp = 0; iTmp < 3; iTmp++)
+ {
+ pCard++;
+ UxCardHandleFree(pCard->hw);
+
+ if(pCard->e_tbl != NULL)
+ {
+ kfree(pCard->e_tbl);
+ }
+ }
+ }
+ }
+ pCard++;
+ }
+ unregister_chrdev(Divas_major, "Divas");
+#endif
+#endif /* CONFIG_PCI */
printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
}
@@ -1675,7 +1677,7 @@ int eicon_mca_probe(int slot, /* slot-nr where the card was detected */
return ENODEV;
};
/* matching membase & irq */
- if ( 1 == eicon_addcard(type, membase, irq, id)) {
+ if ( 1 == eicon_addcard(type, membase, irq, id, 0)) {
mca_set_adapter_name(slot, eicon_mca_adapters[a_idx].name);
mca_set_adapter_procfn(slot, (MCA_ProcFn) eicon_info, cards);
diff --git a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c
index e696b5584..6cb3bca6d 100644
--- a/drivers/isdn/eicon/eicon_pci.c
+++ b/drivers/isdn/eicon/eicon_pci.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_pci.c,v 1.11 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_pci.c,v 1.15 2000/06/12 12:44:02 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
* Hardware-specific code for PCI cards.
@@ -9,8 +9,6 @@
* Thanks to Eicon Technology GmbH & Co. oHG for
* documents, informations and hardware.
*
- * Deutsche Telekom AG for S2M support.
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -25,53 +23,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: eicon_pci.c,v $
- * Revision 1.11 2000/01/23 21:21:23 armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.10 1999/08/22 20:26:49 calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- * define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.9 1999/08/11 21:01:11 keil
- * new PCI codefix
- *
- * Revision 1.8 1999/08/10 16:02:20 calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 1.7 1999/06/09 19:31:29 armin
- * Wrong PLX size for request_region() corrected.
- * Added first MCA code from Erik Weber.
- *
- * Revision 1.6 1999/04/01 12:48:37 armin
- * Changed some log outputs.
- *
- * Revision 1.5 1999/03/29 11:19:49 armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.4 1999/03/02 12:37:48 armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.3 1999/01/24 20:14:24 armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.2 1999/01/10 18:46:06 armin
- * Bug with wrong values in HLC fixed.
- * Bytes to send are counted and limited now.
- *
- * Revision 1.1 1999/01/01 18:09:45 armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
*/
#include <linux/config.h>
@@ -80,896 +31,90 @@
#include "eicon.h"
#include "eicon_pci.h"
+#undef N_DATA
+#include "adapter.h"
+#include "uxio.h"
-char *eicon_pci_revision = "$Revision: 1.11 $";
+char *eicon_pci_revision = "$Revision: 1.15 $";
#if CONFIG_PCI /* intire stuff is only for PCI */
-
-#undef EICON_PCI_DEBUG
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
int eicon_pci_find_card(char *ID)
{
- if (pci_present()) {
- struct pci_dev *pdev = NULL;
- int pci_nextindex=0, pci_cards=0, pci_akt=0;
- int pci_type = PCI_MAESTRA;
- int NoMorePCICards = FALSE;
- char *ram, *reg, *cfg;
- unsigned int pram=0, preg=0, pcfg=0;
- char did[12];
- eicon_pci_card *aparms;
-
- if (!(aparms = (eicon_pci_card *) kmalloc(sizeof(eicon_pci_card), GFP_KERNEL))) {
- printk(KERN_WARNING
- "eicon_pci: Could not allocate card-struct.\n");
- return 0;
- }
-
- for (pci_cards = 0; pci_cards < 0x0f; pci_cards++)
- {
- do {
- if ((pdev = pci_find_device(PCI_VENDOR_EICON,
- pci_type,
- pdev)))
+ int pci_cards = 0;
+ int card_id = 0;
+ int had_q = 0;
+ int ctype = 0;
+ char did[20];
+ card_t *pCard;
+ word wCardIndex;
+
+ pCard = DivasCards;
+ for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++)
{
- pci_nextindex++;
- break;
- }
- else {
- pci_nextindex = 0;
- switch (pci_type) /* switch to next card type */
- {
- case PCI_MAESTRA:
- pci_type = PCI_MAESTRAQ; break;
- case PCI_MAESTRAQ:
- pci_type = PCI_MAESTRAQ_U; break;
- case PCI_MAESTRAQ_U:
- pci_type = PCI_MAESTRAP; break;
- default:
- case PCI_MAESTRAP:
- NoMorePCICards = TRUE;
- }
- }
- }
- while (!NoMorePCICards);
- if (NoMorePCICards)
- {
- if (pci_cards < 1) {
- printk(KERN_INFO "Eicon: No supported PCI cards found.\n");
- kfree(aparms);
- return 0;
- }
- else
- {
- printk(KERN_INFO "Eicon: %d PCI card%s registered.\n",
- pci_cards, (pci_cards > 1) ? "s":"");
- kfree(aparms);
- return (pci_cards);
- }
- }
-
- pci_enable_device(pdev); /* XXX handle error return */
-
- pci_akt = 0;
- switch(pci_type)
- {
- case PCI_MAESTRA:
- printk(KERN_INFO "Eicon: DIVA Server BRI/PCI detected !\n");
- aparms->type = EICON_CTYPE_MAESTRA;
-
- aparms->irq = pdev->irq;
- preg = pci_resource_start(pdev, 2);
- pcfg = pci_resource_start(pdev, 1);
-
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq);
- printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", preg);
- printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", pcfg);
-#endif
- pci_akt = 1;
- break;
-
- case PCI_MAESTRAQ:
- case PCI_MAESTRAQ_U:
- printk(KERN_ERR "Eicon: DIVA Server 4BRI/PCI detected but not supported !\n");
- pci_cards--;
- pci_akt = 0;
- break;
-
- case PCI_MAESTRAP:
- printk(KERN_INFO "Eicon: DIVA Server PRI/PCI detected !\n");
- aparms->type = EICON_CTYPE_MAESTRAP; /*includes 9M,30M*/
- aparms->irq = pdev->irq;
- pram = pci_resource_start(pdev, 0);
- preg = pci_resource_start(pdev, 2);
- pcfg = pci_resource_start(pdev, 4);
-
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq);
- printk(KERN_DEBUG "eicon_pci: ram=0x%x\n",
- (pram));
- printk(KERN_DEBUG "eicon_pci: reg=0x%x\n",
- (preg));
- printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n",
- (pcfg));
-#endif
- pci_akt = 1;
- break;
- default:
- printk(KERN_ERR "eicon_pci: Unknown PCI card detected !\n");
- pci_cards--;
- pci_akt = 0;
- break;
- }
-
- if (pci_akt) {
- /* remapping memory */
- switch(pci_type)
+ if ((pCard->hw) && (pCard->hw->in_use))
{
- case PCI_MAESTRA:
- aparms->PCIreg = (unsigned int) preg;
- aparms->PCIcfg = (unsigned int) pcfg;
- if (check_region((aparms->PCIreg), 0x20)) {
- printk(KERN_WARNING "eicon_pci: reg port already in use !\n");
- aparms->PCIreg = 0;
- break;
- } else {
- request_region(aparms->PCIreg, 0x20, "eicon reg");
+ switch(pCard->hw->card_type) {
+ case DIA_CARD_TYPE_DIVA_SERVER:
+ ctype = EICON_CTYPE_MAESTRAP;
+ card_id++;
+ had_q = 0;
+ break;
+ case DIA_CARD_TYPE_DIVA_SERVER_B:
+ ctype = EICON_CTYPE_MAESTRA;
+ card_id++;
+ had_q = 0;
+ break;
+ case DIA_CARD_TYPE_DIVA_SERVER_Q:
+ ctype = EICON_CTYPE_MAESTRAQ;
+ if (!had_q)
+ card_id++;
+ if (++had_q >=4)
+ had_q = 0;
+ break;
+ default:
+ printk(KERN_ERR "eicon_pci: unknown card type %d !\n",
+ pCard->hw->card_type);
+ goto err;
}
- if (check_region((aparms->PCIcfg), 0x80)) {
- printk(KERN_WARNING "eicon_pci: cfg port already in use !\n");
- aparms->PCIcfg = 0;
- release_region(aparms->PCIreg, 0x20);
- break;
- } else {
- request_region(aparms->PCIcfg, 0x80, "eicon cfg");
- }
- break;
- case PCI_MAESTRAQ:
- case PCI_MAESTRAQ_U:
- case PCI_MAESTRAP:
- aparms->shmem = (eicon_pci_shmem *) ioremap(pram, 0x10000);
- ram = (u8 *) ((u32)aparms->shmem + MP_SHARED_RAM_OFFSET);
- reg = ioremap(preg, 0x4000);
- cfg = ioremap(pcfg, 0x1000);
- aparms->PCIram = (unsigned int) ram;
- aparms->PCIreg = (unsigned int) reg;
- aparms->PCIcfg = (unsigned int) cfg;
- break;
- }
- if ((!aparms->PCIreg) || (!aparms->PCIcfg)) {
- printk(KERN_ERR "eicon_pci: Card could not be added !\n");
- pci_cards--;
- } else {
- aparms->mvalid = 1;
-
sprintf(did, "%s%d", (strlen(ID) < 1) ? "eicon":ID, pci_cards);
-
- printk(KERN_INFO "%s: DriverID: '%s'\n",eicon_ctype_name[aparms->type] , did);
-
- if (!(eicon_addcard(aparms->type, (int) aparms, aparms->irq, did))) {
+ if ((!ctype) || (!(eicon_addcard(ctype, 0, pCard->hw->irq, did, card_id)))) {
printk(KERN_ERR "eicon_pci: Card could not be added !\n");
- pci_cards--;
+ } else {
+ pci_cards++;
+ printk(KERN_INFO "%s: DriverID='%s' CardID=%d\n",
+ eicon_ctype_name[ctype], did, card_id);
}
+err:
}
+ pCard++;
}
-
- }
- } else
- printk(KERN_ERR "eicon_pci: Kernel compiled with PCI but no PCI-bios found !\n");
- return 0;
-}
-
-/*
- * Checks protocol file id for "F#xxxx" string fragment to
- * extract the features, supported by this protocol version.
- * binary representation of the feature string value is returned
- * in *value. The function returns 0 if feature string was not
- * found or has a wrong format, else 1.
- */
-static int GetProtFeatureValue(char *sw_id, int *value)
-{
- __u8 i, offset;
-
- while (*sw_id)
- {
- if ((sw_id[0] == 'F') && (sw_id[1] == '#'))
- {
- sw_id = &sw_id[2];
- for (i=0, *value=0; i<4; i++, sw_id++)
- {
- if ((*sw_id >= '0') && (*sw_id <= '9'))
- {
- offset = '0';
- }
- else if ((*sw_id >= 'A') && (*sw_id <= 'F'))
- {
- offset = 'A' + 10;
- }
- else if ((*sw_id >= 'a') && (*sw_id <= 'f'))
- {
- offset = 'a' + 10;
- }
- else
- {
- return 0;
- }
- *value |= (*sw_id - offset) << (4*(3-i));
- }
- return 1;
- }
- else
- {
- sw_id++;
- }
- }
- return 0;
+ return pci_cards;
}
-
void
-eicon_pci_printpar(eicon_pci_card *card) {
- switch (card->type) {
- case EICON_CTYPE_MAESTRA:
- printk(KERN_INFO "%s at 0x%x / 0x%x, irq %d\n",
- eicon_ctype_name[card->type],
- (unsigned int)card->PCIreg,
- (unsigned int)card->PCIcfg,
- card->irq);
- break;
- case EICON_CTYPE_MAESTRAQ:
- case EICON_CTYPE_MAESTRAQ_U:
- case EICON_CTYPE_MAESTRAP:
- printk(KERN_INFO "%s at 0x%x, irq %d\n",
- eicon_ctype_name[card->type],
- (unsigned int)card->shmem,
- card->irq);
-#ifdef EICON_PCI_DEBUG
- printk(KERN_INFO "eicon_pci: remapped ram= 0x%x\n",(unsigned int)card->PCIram);
- printk(KERN_INFO "eicon_pci: remapped reg= 0x%x\n",(unsigned int)card->PCIreg);
- printk(KERN_INFO "eicon_pci: remapped cfg= 0x%x\n",(unsigned int)card->PCIcfg);
-#endif
- break;
- }
-}
-
-
-static void
-eicon_pci_release_shmem(eicon_pci_card *card) {
- if (!card->master)
- return;
- if (card->mvalid) {
- switch (card->type) {
- case EICON_CTYPE_MAESTRA:
- /* reset board */
- outb(0, card->PCIcfg + 0x4c); /* disable interrupts from PLX */
- outb(0, card->PCIreg + M_RESET);
- SLEEP(20);
- outb(0, card->PCIreg + M_ADDRH);
- outw(0, card->PCIreg + M_ADDR);
- outw(0, card->PCIreg + M_DATA);
-
- release_region(card->PCIreg, 0x20);
- release_region(card->PCIcfg, 0x80);
- break;
- case EICON_CTYPE_MAESTRAQ:
- case EICON_CTYPE_MAESTRAQ_U:
- case EICON_CTYPE_MAESTRAP:
- /* reset board */
- writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET);
- SLEEP(20);
- writeb(0, card->PCIreg + MP_RESET);
- SLEEP(20);
-
- iounmap((void *)card->shmem);
- iounmap((void *)card->PCIreg);
- iounmap((void *)card->PCIcfg);
- break;
- }
- }
- card->mvalid = 0;
-}
-
-static void
-eicon_pci_release_irq(eicon_pci_card *card) {
- if (!card->master)
- return;
- if (card->ivalid)
- free_irq(card->irq, card);
- card->ivalid = 0;
-}
-
-void
-eicon_pci_release(eicon_pci_card *card) {
- eicon_pci_release_irq(card);
- eicon_pci_release_shmem(card);
-}
-
-/*
- * Upload buffer content to adapters shared memory
- * on verify error, 1 is returned and a message is printed on screen
- * else 0 is returned
- * Can serve IO-Type and Memory type adapters
- */
-int eicon_upload(t_dsp_download_space *p_para,
- __u16 length, /* byte count */
- __u8 *buffer,
- int verify)
+eicon_pci_init_conf(eicon_card *card)
{
- __u32 i, dwdata = 0, val = 0, timeout;
- __u16 data;
- eicon_pci_boot *boot = 0;
-
- switch (p_para->type) /* actions depend on type of union */
- {
- case DL_PARA_IO_TYPE:
- for (i=0; i<length; i+=2)
- {
- outb ((u8) ((p_para->dat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH);
- outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR);
- /* outw (((u16 *)code)[i >> 1], p_para->dat.io.ioDATA); */
- outw (*(u16 *)&buffer[i], p_para->dat.io.ioDATA);
- }
- if (verify) /* check written block */
- {
- for (i=0; i<length; i+=2)
- {
- outb ((u8) ((p_para->dat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH);
- outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR);
- data = inw(p_para->dat.io.ioDATA);
- if (data != *(u16 *)&buffer[i])
- {
- p_para->dat.io.r3addr += i;
- p_para->dat.io.BadData = data;
- p_para->dat.io.GoodData = *(u16 *)&buffer[i];
- return 1;
- }
- }
- }
- break;
-
- case DL_PARA_MEM_TYPE:
- boot = p_para->dat.mem.boot;
- writel(p_para->dat.mem.r3addr, &boot->addr);
- for (i=0; i<length; i+=4)
- {
- writel(((u32 *)buffer)[i >> 2], &boot->data[i]);
- }
- if (verify) /* check written block */
- {
- for (i=0; i<length; i+=4)
- {
- dwdata = readl(&boot->data[i]);
- if (((u32 *)buffer)[i >> 2] != dwdata)
- {
- p_para->dat.mem.r3addr += i;
- p_para->dat.mem.BadData = dwdata;
- p_para->dat.mem.GoodData = ((u32 *)buffer)[i >> 2];
- return 1;
- }
- }
- }
- writel(((length + 3) / 4), &boot->len); /* len in dwords */
- writel(2, &boot->cmd);
-
- timeout = jiffies + 20;
- while (timeout > jiffies) {
- val = readl(&boot->cmd);
- if (!val) break;
- SLEEP(2);
- }
- if (val)
- {
- p_para->dat.mem.timeout = 1;
- return 1;
- }
- break;
- }
- return 0;
-}
-
-
-/* show header information of code file */
-static
-int eicon_pci_print_hdr(unsigned char *code, int offset)
-{
- unsigned char hdr[80];
- int i, fvalue = 0;
-
- i = 0;
- while ((i < (sizeof(hdr) -1))
- && (code[offset + i] != '\0')
- && (code[offset + i] != '\r')
- && (code[offset + i] != '\n'))
- {
- hdr[i] = code[offset + i];
- i++;
- }
- hdr[i] = '\0';
- printk(KERN_DEBUG "Eicon: loading %s\n", hdr);
- if (GetProtFeatureValue(hdr, &fvalue)) return(fvalue);
- else return(0);
-}
-
-
-/*
- * Configure a card, download code into BRI card,
- * check if we get interrupts and return 0 on succes.
- * Return -ERRNO on failure.
- */
-int
-eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb) {
- int i,j;
- int timeout;
- unsigned int offset, offp=0, size, length;
- int signature = 0;
- int FeatureValue = 0;
- eicon_pci_codebuf cbuf;
- t_dsp_download_space dl_para;
- t_dsp_download_desc dsp_download_table;
- unsigned char *code;
- unsigned int reg;
- unsigned int cfg;
-
- if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf)))
- return -EFAULT;
-
- reg = card->PCIreg;
- cfg = card->PCIcfg;
-
- /* reset board */
- outb(0, reg + M_RESET);
- SLEEP(10);
- outb(0, reg + M_ADDRH);
- outw(0, reg + M_ADDR);
- outw(0, reg + M_DATA);
-
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: reset card\n");
-#endif
-
- /* clear shared memory */
- outb(0xff, reg + M_ADDRH);
- outw(0, reg + M_ADDR);
- for(i = 0; i < 0xffff; i++) outw(0, reg + M_DATA);
- SLEEP(10);
-
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: clear shared memory\n");
-#endif
-
- /* download protocol and dsp file */
-
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: downloading firmware...\n");
-#endif
-
- /* Allocate code-buffer */
- if (!(code = kmalloc(400, GFP_KERNEL))) {
- printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n");
- return -ENOMEM;
- }
-
- /* prepare protocol upload */
- dl_para.type = DL_PARA_IO_TYPE;
- dl_para.dat.io.ioADDR = reg + M_ADDR;
- dl_para.dat.io.ioADDRH = reg + M_ADDRH;
- dl_para.dat.io.ioDATA = reg + M_DATA;
-
- for (j = 0; j <= cbuf.dsp_code_num; j++)
- {
- if (j == 0) size = cbuf.protocol_len;
- else size = cbuf.dsp_code_len[j];
-
- offset = 0;
-
- if (j == 0) dl_para.dat.io.r3addr = 0;
- if (j == 1) dl_para.dat.io.r3addr = M_DSP_CODE_BASE +
- ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc);
- if (j == 2) dl_para.dat.io.r3addr = M_DSP_CODE_BASE;
- if (j == 3) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + sizeof(__u32);
-
- do /* download block of up to 400 bytes */
- {
- length = ((size - offset) >= 400) ? 400 : (size - offset);
-
- if (copy_from_user(code, (&cb->code) + offp + offset, length)) {
- kfree(code);
- return -EFAULT;
- }
-
- if ((offset == 0) && (j < 2)) {
- FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80);
-#ifdef EICON_PCI_DEBUG
- if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%04x.\n", FeatureValue);
-#endif
- if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) {
- printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n");
- kfree(code);
- return -EFAULT;
- }
- ((eicon_card *)card->card)->Feature = FeatureValue;
- }
-
- if (eicon_upload(&dl_para, length, code, 1))
- {
- printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr);
- kfree(code);
- return -EIO;
- }
- /* move onto next block */
- offset += length;
- dl_para.dat.io.r3addr += length;
- } while (offset < size);
-
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "Eicon: %d bytes loaded.\n", offset);
-#endif
- offp += size;
- }
- kfree(code);
-
- /* clear signature */
- outb(0xff, reg + M_ADDRH);
- outw(0x1e, reg + M_ADDR);
- outw(0, reg + M_DATA);
-
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n");
-#endif
- /* copy configuration data into shared memory */
- outw(8, reg + M_ADDR); outb(cbuf.tei, reg + M_DATA);
- outw(9, reg + M_ADDR); outb(cbuf.nt2, reg + M_DATA);
- outw(10,reg + M_ADDR); outb(0, reg + M_DATA);
- outw(11,reg + M_ADDR); outb(cbuf.WatchDog, reg + M_DATA);
- outw(12,reg + M_ADDR); outb(cbuf.Permanent, reg + M_DATA);
- outw(13,reg + M_ADDR); outb(0, reg + M_DATA); /* XInterface */
- outw(14,reg + M_ADDR); outb(cbuf.StableL2, reg + M_DATA);
- outw(15,reg + M_ADDR); outb(cbuf.NoOrderCheck, reg + M_DATA);
- outw(16,reg + M_ADDR); outb(0, reg + M_DATA); /* HandsetType */
- outw(17,reg + M_ADDR); outb(0, reg + M_DATA); /* SigFlags */
- outw(18,reg + M_ADDR); outb(cbuf.LowChannel, reg + M_DATA);
- outw(19,reg + M_ADDR); outb(cbuf.ProtVersion, reg + M_DATA);
- outw(20,reg + M_ADDR); outb(cbuf.Crc4, reg + M_DATA);
- outw(21,reg + M_ADDR); outb((cbuf.Loopback) ? 2:0, reg + M_DATA);
-
- for (i=0;i<32;i++)
- {
- outw( 32+i, reg + M_ADDR); outb(cbuf.l[0].oad[i], reg + M_DATA);
- outw( 64+i, reg + M_ADDR); outb(cbuf.l[0].osa[i], reg + M_DATA);
- outw( 96+i, reg + M_ADDR); outb(cbuf.l[0].spid[i], reg + M_DATA);
- outw(128+i, reg + M_ADDR); outb(cbuf.l[1].oad[i], reg + M_DATA);
- outw(160+i, reg + M_ADDR); outb(cbuf.l[1].osa[i], reg + M_DATA);
- outw(192+i, reg + M_ADDR); outb(cbuf.l[1].spid[i], reg + M_DATA);
+ int j;
+
+ /* initializing some variables */
+ card->ReadyInt = 0;
+
+ for(j = 0; j < 256; j++)
+ card->IdTable[j] = NULL;
+
+ for(j = 0; j < (card->d->channels + 1); j++) {
+ card->bch[j].e.busy = 0;
+ card->bch[j].e.D3Id = 0;
+ card->bch[j].e.B2Id = 0;
+ card->bch[j].e.ref = 0;
+ card->bch[j].e.Req = 0;
+ card->bch[j].e.complete = 1;
+ card->bch[j].fsm_state = EICON_STATE_NULL;
}
-
-#ifdef EICON_PCI_DEBUG
- printk(KERN_ERR "eicon_pci: starting CPU...\n");
-#endif
- /* let the CPU run */
- outw(0x08, reg + M_RESET);
-
- timeout = jiffies + (5*HZ);
- while (timeout > jiffies) {
- outw(0x1e, reg + M_ADDR);
- signature = inw(reg + M_DATA);
- if (signature == DIVAS_SIGNATURE) break;
- SLEEP(2);
- }
- if (signature != DIVAS_SIGNATURE)
- {
-#ifdef EICON_PCI_DEBUG
- printk(KERN_ERR "eicon_pci: signature 0x%x expected 0x%x\n",signature,DIVAS_SIGNATURE);
-#endif
- printk(KERN_ERR "eicon_pci: Timeout, protocol code not running !\n");
- return -EIO;
- }
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n");
-#endif
-
- /* get serial number and number of channels supported by card */
- outb(0xff, reg + M_ADDRH);
- outw(0x3f6, reg + M_ADDR);
- card->channels = inw(reg + M_DATA);
- card->serial = (u32)inw(cfg + 0x22) << 16 | (u32)inw(cfg + 0x26);
- printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels);
- printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial);
-
- /* test interrupt */
- card->irqprobe = 1;
-
- if (!card->ivalid) {
- if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card))
- {
- printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq);
- return -EIO;
- }
- }
- card->ivalid = 1;
-
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: testing interrupt\n");
-#endif
- /* Trigger an interrupt and check if it is delivered */
- outb(0x41, cfg + 0x4c); /* enable PLX for interrupts */
- outb(0x89, reg + M_RESET); /* place int request */
-
- timeout = jiffies + 20;
- while (timeout > jiffies) {
- if (card->irqprobe != 1) break;
- SLEEP(5);
- }
- if (card->irqprobe == 1) {
- free_irq(card->irq, card);
- card->ivalid = 0;
- printk(KERN_ERR "eicon_pci: Getting no interrupts !\n");
- return -EIO;
- }
-
- /* initializing some variables */
- ((eicon_card *)card->card)->ReadyInt = 0;
- for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;
- for(j=0; j< (card->channels + 1); j++) {
- ((eicon_card *)card->card)->bch[j].e.busy = 0;
- ((eicon_card *)card->card)->bch[j].e.D3Id = 0;
- ((eicon_card *)card->card)->bch[j].e.B2Id = 0;
- ((eicon_card *)card->card)->bch[j].e.ref = 0;
- ((eicon_card *)card->card)->bch[j].e.Req = 0;
- ((eicon_card *)card->card)->bch[j].e.complete = 1;
- ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;
- }
-
- printk(KERN_INFO "Eicon: Card successfully started\n");
-
- return 0;
}
-
-/*
- * Configure a card, download code into PRI card,
- * check if we get interrupts and return 0 on succes.
- * Return -ERRNO on failure.
- */
-int
-eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb) {
- eicon_pci_boot *boot;
- eicon_pr_ram *prram;
- int i,j;
- int timeout;
- int FeatureValue = 0;
- unsigned int offset, offp=0, size, length;
- unsigned long int signature = 0;
- t_dsp_download_space dl_para;
- t_dsp_download_desc dsp_download_table;
- eicon_pci_codebuf cbuf;
- unsigned char *code;
- unsigned char req_int;
- char *ram, *reg, *cfg;
-
- if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf)))
- return -EFAULT;
-
- boot = &card->shmem->boot;
- ram = (char *)card->PCIram;
- reg = (char *)card->PCIreg;
- cfg = (char *)card->PCIcfg;
- prram = (eicon_pr_ram *)ram;
-
- /* reset board */
- writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET);
- SLEEP(20);
- writeb(0, card->PCIreg + MP_RESET);
- SLEEP(20);
-
- /* set command count to 0 */
- writel(0, &boot->reserved);
-
- /* check if CPU increments the life word */
- i = readw(&boot->live);
- SLEEP(20);
- if (i == readw(&boot->live)) {
- printk(KERN_ERR "eicon_pci: card is reset, but CPU not running !\n");
- return -EIO;
- }
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: reset card OK (CPU running)\n");
#endif
-
- /* download firmware : DSP and Protocol */
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: downloading firmware...\n");
-#endif
-
- /* Allocate code-buffer */
- if (!(code = kmalloc(400, GFP_KERNEL))) {
- printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n");
- return -ENOMEM;
- }
-
- /* prepare protocol upload */
- dl_para.type = DL_PARA_MEM_TYPE;
- dl_para.dat.mem.boot = boot;
-
- for (j = 0; j <= cbuf.dsp_code_num; j++)
- {
- if (j==0) size = cbuf.protocol_len;
- else size = cbuf.dsp_code_len[j];
-
- if (j==1) writel(MP_DSP_ADDR, &boot->addr); /* DSP code entry point */
-
- if (j == 0) dl_para.dat.io.r3addr = MP_PROTOCOL_ADDR;
- if (j == 1) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE +
- ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc);
- if (j == 2) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE;
- if (j == 3) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + sizeof(__u32);
-
- offset = 0;
- do /* download block of up to 400 bytes */
- {
- length = ((size - offset) >= 400) ? 400 : (size - offset);
-
- if (copy_from_user(code, (&cb->code) + offp + offset, length)) {
- kfree(code);
- return -EFAULT;
- }
-
- if ((offset == 0) && (j < 2)) {
- FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80);
-#ifdef EICON_PCI_DEBUG
- if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%x.\n", FeatureValue);
-#endif
- if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) {
- printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n");
- kfree(code);
- return -EFAULT;
- }
- ((eicon_card *)card->card)->Feature = FeatureValue;
- }
-
- if (eicon_upload(&dl_para, length, code, 1))
- {
- if (dl_para.dat.mem.timeout == 0)
- printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr);
- else
- printk(KERN_ERR "eicon_pci: timeout, no ACK to load !\n");
- kfree(code);
- return -EIO;
- }
-
- /* move onto next block */
- offset += length;
- dl_para.dat.mem.r3addr += length;
- } while (offset < size);
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: %d bytes loaded.\n", offset);
-#endif
- offp += size;
- }
- kfree(code);
-
- /* initialize the adapter data structure */
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n");
-#endif
- /* clear out config space */
- for (i = 0; i < 256; i++) writeb(0, &ram[i]);
-
- /* copy configuration down to the card */
- writeb(cbuf.tei, &ram[8]);
- writeb(cbuf.nt2, &ram[9]);
- writeb(0, &ram[10]);
- writeb(cbuf.WatchDog, &ram[11]);
- writeb(cbuf.Permanent, &ram[12]);
- writeb(cbuf.XInterface, &ram[13]);
- writeb(cbuf.StableL2, &ram[14]);
- writeb(cbuf.NoOrderCheck, &ram[15]);
- writeb(cbuf.HandsetType, &ram[16]);
- writeb(0, &ram[17]);
- writeb(cbuf.LowChannel, &ram[18]);
- writeb(cbuf.ProtVersion, &ram[19]);
- writeb(cbuf.Crc4, &ram[20]);
- for (i = 0; i < 32; i++)
- {
- writeb(cbuf.l[0].oad[i], &ram[32 + i]);
- writeb(cbuf.l[0].osa[i], &ram[64 + i]);
- writeb(cbuf.l[0].spid[i], &ram[96 + i]);
- writeb(cbuf.l[1].oad[i], &ram[128 + i]);
- writeb(cbuf.l[1].osa[i], &ram[160 + i]);
- writeb(cbuf.l[1].spid[i], &ram[192 + i]);
- }
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: configured card OK\n");
-#endif
-
- /* start adapter */
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: tell card to start...\n");
-#endif
- writel(MP_PROTOCOL_ADDR, &boot->addr); /* RISC code entry point */
- writel(3, &boot->cmd); /* DIVAS_START_CMD */
-
- /* wait till card ACKs */
- timeout = jiffies + (5*HZ);
- while (timeout > jiffies) {
- signature = readl(&boot->signature);
- if ((signature >> 16) == DIVAS_SIGNATURE) break;
- SLEEP(2);
- }
- if ((signature >> 16) != DIVAS_SIGNATURE)
- {
-#ifdef EICON_PCI_DEBUG
- printk(KERN_ERR "eicon_pci: signature 0x%lx expected 0x%x\n",(signature >> 16),DIVAS_SIGNATURE);
-#endif
- printk(KERN_ERR "eicon_pci: timeout, protocol code not running !\n");
- return -EIO;
- }
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n");
-#endif
-
- /* get serial number and number of channels supported by card */
- card->channels = readb(&ram[0x3f6]);
- card->serial = readl(&ram[0x3f0]);
- printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels);
- printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial);
-
- /* test interrupt */
- readb(&ram[0x3fe]);
- writeb(0, &ram[0x3fe]); /* reset any pending interrupt */
- readb(&ram[0x3fe]);
-
- writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
- writew(0, &cfg[MP_IRQ_RESET + 2]);
-
- card->irqprobe = 1;
-
- if (!card->ivalid) {
- if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card))
- {
- printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq);
- return -EIO;
- }
- }
- card->ivalid = 1;
-
- req_int = readb(&prram->ReadyInt);
-#ifdef EICON_PCI_DEBUG
- printk(KERN_DEBUG "eicon_pci: testing interrupt\n");
-#endif
- req_int++;
- /* Trigger an interrupt and check if it is delivered */
- writeb(req_int, &prram->ReadyInt);
-
- timeout = jiffies + 20;
- while (timeout > jiffies) {
- if (card->irqprobe != 1) break;
- SLEEP(2);
- }
- if (card->irqprobe == 1) {
- free_irq(card->irq, card);
- card->ivalid = 0;
- printk(KERN_ERR "eicon_pci: Getting no interrupts !\n");
- return -EIO;
- }
-
- /* initializing some variables */
- ((eicon_card *)card->card)->ReadyInt = 0;
- for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;
- for(j=0; j< (card->channels + 1); j++) {
- ((eicon_card *)card->card)->bch[j].e.busy = 0;
- ((eicon_card *)card->card)->bch[j].e.D3Id = 0;
- ((eicon_card *)card->card)->bch[j].e.B2Id = 0;
- ((eicon_card *)card->card)->bch[j].e.ref = 0;
- ((eicon_card *)card->card)->bch[j].e.Req = 0;
- ((eicon_card *)card->card)->bch[j].e.complete = 1;
- ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;
- }
-
- printk(KERN_INFO "Eicon: Card successfully started\n");
-
- return 0;
-}
-
#endif /* CONFIG_PCI */
diff --git a/drivers/isdn/eicon/eicon_pci.h b/drivers/isdn/eicon/eicon_pci.h
index 384cc422c..17fd4183a 100644
--- a/drivers/isdn/eicon/eicon_pci.h
+++ b/drivers/isdn/eicon/eicon_pci.h
@@ -1,4 +1,4 @@
-/* $Id: eicon_pci.h,v 1.4 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_pci.h,v 1.6 2000/05/07 08:51:04 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards (PCI part).
*
@@ -19,26 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: eicon_pci.h,v $
- * Revision 1.4 2000/01/23 21:21:23 armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.3 1999/03/29 11:19:51 armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.2 1999/03/02 12:37:50 armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.1 1999/01/01 18:09:46 armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
*/
#ifndef eicon_pci_h
@@ -46,147 +26,20 @@
#ifdef __KERNEL__
-
-#define PCI_VENDOR_EICON 0x1133
-#define PCI_DIVA_PRO20 0xe001 /* Not supported */
-#define PCI_DIVA20 0xe002 /* Not supported */
-#define PCI_DIVA_PRO20_U 0xe003 /* Not supported */
-#define PCI_DIVA20_U 0xe004 /* Not supported */
-#define PCI_MAESTRA 0xe010
-#define PCI_MAESTRAQ 0xe012
-#define PCI_MAESTRAQ_U 0xe013
-#define PCI_MAESTRAP 0xe014
-
-#define DIVA_PRO20 1
-#define DIVA20 2
-#define DIVA_PRO20_U 3
-#define DIVA20_U 4
-#define MAESTRA 5
-#define MAESTRAQ 6
-#define MAESTRAQ_U 7
-#define MAESTRAP 8
-
-#define TRUE 1
-#define FALSE 0
-
-#define DIVAS_SIGNATURE 0x4447
-
-
-/* MAESTRA BRI PCI */
-
-#define M_RESET 0x10 /* offset of reset register */
-#define M_DATA 0x00 /* offset of data register */
-#define M_ADDR 0x04 /* offset of address register */
-#define M_ADDRH 0x0c /* offset of high address register */
-
-#define M_DSP_CODE_LEN 0xbf7d0000
-#define M_DSP_CODE 0xbf7d0004 /* max 128K DSP-Code */
-#define M_DSP_CODE_BASE 0xbf7a0000
-#define M_MAX_DSP_CODE_SIZE 0x00050000 /* max 320K DSP-Code (Telindus) */
-
-
-
-/* MAESTRA PRI PCI */
-
-#define MP_SHARED_RAM_OFFSET 0x1000 /* offset of shared RAM base in the DRAM memory bar */
-
-#define MP_IRQ_RESET 0xc18 /* offset of interrupt status register in the CONFIG memory bar */
-#define MP_IRQ_RESET_VAL 0xfe /* value to clear an interrupt */
-
-#define MP_PROTOCOL_ADDR 0xa0011000 /* load address of protocol code */
-#define MP_DSP_ADDR 0xa03c0000 /* load address of DSP code */
-#define MP_MAX_PROTOCOL_CODE_SIZE 0x000a0000 /* max 640K Protocol-Code */
-#define MP_DSP_CODE_BASE 0xa03a0000
-#define MP_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code */
-
-#define MP_RESET 0x20 /* offset of RESET register in the DEVICES memory bar */
-
-/* RESET register bits */
-#define _MP_S2M_RESET 0x10 /* active lo */
-#define _MP_LED2 0x08 /* 1 = on */
-#define _MP_LED1 0x04 /* 1 = on */
-#define _MP_DSP_RESET 0x02 /* active lo */
-#define _MP_RISC_RESET 0x81 /* active hi, bit 7 for compatibility with old boards */
-
-/* boot interface structure */
-typedef struct {
- __u32 cmd __attribute__ ((packed));
- __u32 addr __attribute__ ((packed));
- __u32 len __attribute__ ((packed));
- __u32 err __attribute__ ((packed));
- __u32 live __attribute__ ((packed));
- __u32 reserved[(0x1020>>2)-6] __attribute__ ((packed));
- __u32 signature __attribute__ ((packed));
- __u8 data[1]; /* real interface description */
-} eicon_pci_boot;
-
-
-#define DL_PARA_IO_TYPE 0
-#define DL_PARA_MEM_TYPE 1
-
-typedef struct tag_dsp_download_space
-{
- __u16 type; /* see definitions above to differ union elements */
- union
- {
- struct
- {
- __u32 r3addr;
- __u16 ioADDR;
- __u16 ioADDRH;
- __u16 ioDATA;
- __u16 BadData; /* in case of verify error */
- __u16 GoodData;
- } io; /* for io based adapters */
- struct
- {
- __u32 r3addr;
- eicon_pci_boot *boot;
- __u32 BadData; /* in case of verify error */
- __u32 GoodData;
- __u16 timeout;
- } mem; /* for memory based adapters */
- } dat;
-} t_dsp_download_space;
-
-
-/* Shared memory */
-typedef union {
- eicon_pci_boot boot;
-} eicon_pci_shmem;
-
/*
* card's description
*/
typedef struct {
- int ramsize;
int irq; /* IRQ */
- unsigned int PCIram;
- unsigned int PCIreg;
- unsigned int PCIcfg;
- long int serial; /* Serial No. */
int channels; /* No. of supported channels */
void* card;
- eicon_pci_shmem* shmem; /* Shared-memory area */
- unsigned char* intack; /* Int-Acknowledge */
- unsigned char* stopcpu; /* Writing here stops CPU */
- unsigned char* startcpu; /* Writing here starts CPU */
unsigned char type; /* card type */
- unsigned char irqprobe; /* Flag: IRQ-probing */
- unsigned char mvalid; /* Flag: Memory is valid */
- unsigned char ivalid; /* Flag: IRQ is valid */
unsigned char master; /* Flag: Card is Quadro 1/4 */
- void* generic; /* Ptr to generic card struct */
} eicon_pci_card;
-
-
-extern int eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb);
-extern int eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb);
-extern void eicon_pci_release(eicon_pci_card *card);
-extern void eicon_pci_printpar(eicon_pci_card *card);
extern int eicon_pci_find_card(char *ID);
#endif /* __KERNEL__ */
#endif /* eicon_pci_h */
+
diff --git a/drivers/isdn/eicon/fcheck.c b/drivers/isdn/eicon/fcheck.c
new file mode 100644
index 000000000..c86f7d3df
--- /dev/null
+++ b/drivers/isdn/eicon/fcheck.c
@@ -0,0 +1,31 @@
+/* $Id: fcheck.c,v 1.3 2000/06/12 12:44:02 armin Exp $
+ *
+ * (c) 2000 Cytronics & Melware
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ * For changes and modifications please read
+ * ../../../Documentation/isdn/README.eicon
+ *
+ *
+ */
+
+#include <linux/kernel.h>
+
+char *
+file_check(void) {
+
+#ifdef FILECHECK
+#if FILECHECK == 0
+ return("verified");
+#endif
+#if FILECHECK == 1
+ return("modified");
+#endif
+#if FILECHECK == 127
+ return("verification failed");
+#endif
+#else
+ return("not verified");
+#endif
+}
+
diff --git a/drivers/isdn/eicon/fourbri.c b/drivers/isdn/eicon/fourbri.c
new file mode 100644
index 000000000..5fe9817e0
--- /dev/null
+++ b/drivers/isdn/eicon/fourbri.c
@@ -0,0 +1,583 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.7
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/* Diva Server 4BRI specific part of initialisation */
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "dsp_defs.h"
+#include "constant.h"
+#include "adapter.h"
+#include "uxio.h"
+
+#define TEST_INT_DIVAS_Q 0x13
+
+#define DIVAS_MAINT_OFFSET 0xff00 /* value for 4BRI card */
+#define MQ_BOARD_DSP_OFFSET 0x00a00000
+#define MQ_DSP1_ADDR_OFFSET 0x00000008
+#define MQ_DSP_JUNK_OFFSET 0x00000400
+#define MQ_DSP1_DATA_OFFSET 0x00000000
+#define MQ_BOARD_ISAC_DSP_RESET 0x00800028
+#define MQ_BREG_RISC 0x1200 /* RISC Reset */
+#define MQ_ISAC_DSP_RESET 0x0028 /* ISAC and DSP reset address offset */
+#define MQ_RISC_COLD_RESET_MASK 0x0001 /* RISC Cold reset */
+#define MQ_RISC_WARM_RESET_MASK 0x0002 /* RISC Warm reset */
+#define MQ_IRQ_REQ_ON 0x1
+#define MQ_IRQ_REQ_OFF 0x0
+#define MQ_BREG_IRQ_TEST 0x0608
+#define PLX9054_INTCSR 0x69
+#define PLX9054_INT_ENA 0x09
+
+#define DIVAS_IOBASE 0x01
+#define M_PCI_RESET 0x10
+
+byte mem_in(ADAPTER *a, void *adr);
+word mem_inw(ADAPTER *a, void *adr);
+void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length);
+void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e);
+void mem_out(ADAPTER *a, void *adr, byte data);
+void mem_outw(ADAPTER *a, void *adr, word data);
+void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length);
+void mem_inc(ADAPTER *a, void *adr);
+
+int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg);
+int fourbri_ISR (card_t* card);
+
+int FPGA_Download(word, dword, byte *, byte *, int);
+extern byte FPGA_Bytes[];
+extern void *get_card(int);
+
+byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset);
+void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte);
+word GetProtFeatureValue(char *sw_id);
+
+void memcp(byte *dst, byte *src, dword dwLen);
+int memcm(byte *dst, byte *src, dword dwLen);
+
+static int diva_server_4bri_reset(card_t *card)
+{
+ byte *ctl;
+
+ DPRINTF(("divas: reset Diva Server 4BRI"));
+
+ ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+
+ /* stop RISC, DSP's and ISAC */
+ UxCardMemOut(card->hw, &ctl[MQ_BREG_RISC], 0);
+ UxCardMemOut(card->hw, &ctl[MQ_ISAC_DSP_RESET], 0);
+
+ UxCardMemDetach(card->hw, ctl);
+
+ return 0;
+}
+
+static int diva_server_4bri_config(card_t *card, dia_config_t *config)
+{
+ byte *shared;
+ int i, j;
+
+ DPRINTF(("divas: configure Diva Server 4BRI"));
+
+ shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+ for (i=0; i<256; i++)
+ {
+ UxCardMemOut(card->hw, &shared[i], 0);
+ }
+
+ UxCardMemOut(card->hw, &shared[ 8], config->tei);
+ UxCardMemOut(card->hw, &shared[ 9], config->nt2);
+ UxCardMemOut(card->hw, &shared[10], 0);
+ UxCardMemOut(card->hw, &shared[11], config->watchdog);
+ UxCardMemOut(card->hw, &shared[12], config->permanent);
+ UxCardMemOut(card->hw, &shared[13], config->x_interface);
+ UxCardMemOut(card->hw, &shared[14], config->stable_l2);
+ UxCardMemOut(card->hw, &shared[15], config->no_order_check);
+ UxCardMemOut(card->hw, &shared[16], config->handset_type);
+ UxCardMemOut(card->hw, &shared[17], 0);
+ UxCardMemOut(card->hw, &shared[18], config->low_channel);
+ UxCardMemOut(card->hw, &shared[19], config->prot_version);
+ UxCardMemOut(card->hw, &shared[20], config->crc4);
+
+ if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+ {
+ DPRINTF(("divas: Signifying V.90"));
+ UxCardMemOut(card->hw, &shared[22], 4);
+ }
+ else
+ {
+ UxCardMemOut(card->hw, &shared[22], 0);
+ }
+
+ for (i=0; i<2; i++)
+ {
+ for (j=0; j<32; j++)
+ {
+ UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]);
+ }
+
+ for (j=0; j<32; j++)
+ {
+ UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]);
+ }
+
+ for (j=0; j<32; j++)
+ {
+ UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]);
+ }
+ }
+
+ UxCardMemDetach(card->hw, shared);
+
+ return 0;
+}
+
+static
+void diva_server_4bri_reset_int(card_t *card)
+{
+ byte *ctl;
+
+ ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+
+ UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF);
+
+ UxCardMemDetach(card->hw, ctl);
+
+ return;
+}
+
+
+static int diva_server_4bri_test_int(card_t *card)
+{
+ byte *ctl, i;
+ byte *reg;
+
+ DPRINTF(("divas: test interrupt for Diva Server 4BRI"));
+
+ /* We get the last (dummy) adapter in so we need to go back to the first */
+
+ card = get_card(card->cfg.card_id - 3);
+
+ /* Enable interrupts on PLX chip */
+
+ reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY);
+
+ UxCardPortIoOut(card->hw, reg, PLX9054_INTCSR, PLX9054_INT_ENA);
+
+ UxCardMemDetach(card->hw, reg);
+
+ /* Set the test interrupt flag */
+ card->test_int_pend = TEST_INT_DIVAS_Q;
+
+ /* Now to trigger the interrupt */
+
+ ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+
+ UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_ON);
+
+ UxCardMemDetach(card->hw, ctl);
+
+ for (i = 0; i < 50; i++)
+ {
+ if (!card->test_int_pend)
+ {
+ break;
+ }
+ UxPause(10);
+ }
+
+ if (card->test_int_pend)
+ {
+ DPRINTF(("active: timeout waiting for card to interrupt"));
+ return (-1);
+ }
+
+ return 0;
+}
+
+
+static void print_hdr(unsigned char *code, int offset)
+{
+ unsigned char hdr[80];
+ int i;
+
+ i = 0;
+
+ while ((i < (DIM(hdr) -1)) &&
+ (code[offset + i] != '\0') &&
+ (code[offset + i] != '\r') &&
+ (code[offset + i] != '\n'))
+ {
+ hdr[i] = code[offset + i];
+ i++;
+ }
+
+ hdr[i] = '\0';
+
+ DPRINTF(("divas: loading %s", hdr));
+}
+
+static int diva_server_4bri_load(card_t *card, dia_load_t *load)
+{
+ byte *pRAM=NULL;
+ int download_offset=0;
+ card_t *FirstCard;
+ byte sw_id[80];
+
+ DPRINTF(("divas: loading Diva Server 4BRI[%d]", load->card_id));
+
+ switch(load->code_type)
+ {
+ case DIA_CPU_CODE:
+ DPRINTF(("divas: RISC code"));
+ print_hdr(load->code, 0x80);
+ card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]);
+ download_offset = 0; // Protocol code written to offset 0
+ pRAM = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+ break;
+
+ case DIA_DSP_CODE:
+ DPRINTF(("divas: DSP code"));
+ print_hdr(load->code, 0x0);
+ FirstCard = get_card(load->card_id - 3);
+ if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+ {
+ download_offset = MQ_V90D_DSP_CODE_BASE;
+ }
+ else
+ {
+ download_offset = MQ_ORG_DSP_CODE_BASE;
+ }
+ pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY);
+ download_offset += (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC);
+
+ break;
+
+ case DIA_TABLE_CODE:
+ DPRINTF(("divas: TABLE code"));
+ FirstCard = get_card(load->card_id - 3);
+ if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+ {
+ download_offset = MQ_V90D_DSP_CODE_BASE + sizeof(dword);
+ }
+ else
+ {
+ download_offset = MQ_ORG_DSP_CODE_BASE + sizeof(dword);
+ }
+ pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY);
+ break;
+
+ case DIA_CONT_CODE:
+ DPRINTF(("divas: continuation code"));
+ break;
+
+ case DIA_DLOAD_CNT:
+ DPRINTF(("divas: COUNT code"));
+ FirstCard = get_card(load->card_id - 3);
+ if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+ {
+ download_offset = MQ_V90D_DSP_CODE_BASE;
+ }
+ else
+ {
+ download_offset = MQ_ORG_DSP_CODE_BASE;
+ }
+ pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY);
+ break;
+
+ case DIA_FPGA_CODE:
+ DPRINTF(("divas: 4BRI FPGA download - %d bytes", load->length));
+ if (FPGA_Download(IDI_ADAPTER_MAESTRAQ,
+ card->hw->io_base,
+ sw_id,
+ load->code,
+ load->length
+ ) == -1)
+ {
+ DPRINTF(("divas: FPGA download failed"));
+ return -1;
+ }
+
+ /* NOW reset the 4BRI */
+ diva_server_4bri_reset(card);
+ return 0; // No need for anything further loading
+
+ default:
+ DPRINTF(("divas: unknown code type"));
+ return -1;
+ }
+
+ memcp(pRAM + (download_offset & 0x3FFFFF), load->code, load->length);
+
+ {
+ int mism_off;
+ if ((mism_off = memcm(pRAM + (download_offset & 0x3FFFFF), load->code, load->length)))
+ {
+ DPRINTF(("divas: memory mismatch at offset %d", mism_off));
+ UxCardMemDetach(card->hw, pRAM);
+ return -1;
+ }
+ }
+
+ UxCardMemDetach(card->hw, pRAM);
+
+ return 0;
+}
+
+static int diva_server_4bri_start(card_t *card, byte *channels)
+{
+ byte *ctl;
+ byte *shared, i;
+ int adapter_num;
+
+ DPRINTF(("divas: start Diva Server 4BRI"));
+ *channels = 0;
+ card->is_live = FALSE;
+
+ ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+
+ UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_COLD_RESET_MASK);
+
+ UxPause(2);
+
+ UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_WARM_RESET_MASK | MQ_RISC_COLD_RESET_MASK);
+
+ UxPause(10);
+
+ UxCardMemDetach(card->hw, ctl);
+
+ shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+ for ( i = 0 ; i < 300 ; ++i )
+ {
+ UxPause (10) ;
+
+ if ( UxCardMemInW(card->hw, &shared[0x1E]) == 0x4447 )
+ {
+ DPRINTF(("divas: Protocol startup time %d.%02d seconds",
+ (i / 100), (i % 100) ));
+
+ break;
+ }
+ }
+
+ if (i==300)
+ {
+ DPRINTF(("divas: Timeout starting card"));
+ DPRINTF(("divas: Signature == 0x%04X", UxCardMemInW(card->hw, &shared[0x1E])));
+
+ UxCardMemDetach(card->hw, shared);
+ return -1;
+ }
+
+ UxCardMemDetach(card->hw, shared);
+
+ for (adapter_num=3; adapter_num >= 0; adapter_num--)
+ {
+ card_t *qbri_card;
+
+ qbri_card = get_card(card->cfg.card_id - adapter_num);
+
+ if (qbri_card)
+ {
+ qbri_card->is_live = TRUE;
+ shared = UxCardMemAttach(qbri_card->hw, DIVAS_SHARED_MEMORY);
+ *channels += UxCardMemIn(qbri_card->hw, &shared[0x3F6]);
+ UxCardMemDetach(qbri_card->hw, shared);
+ }
+ else
+ {
+ DPRINTF(("divas: Couldn't get card info %d", card->cfg.card_id));
+ }
+ }
+
+ diva_server_4bri_test_int(card);
+
+ return 0;
+}
+
+static
+int diva_server_4bri_mem_get(card_t *card, mem_block_t *mem_block)
+
+{
+ byte *a;
+ byte *card_addr;
+ word length = 0;
+ int i;
+
+ a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+ card_addr = a;
+ card_addr += mem_block->addr;
+
+ for (i=0; i < sizeof(mem_block->data); i++)
+ {
+ mem_block->data[i] = UxCardMemIn(card->hw, card_addr);
+ card_addr++;
+ length++;
+ }
+
+ UxCardMemDetach(card->hw, a);
+
+ return length;
+}
+
+/*
+ * Initialise 4BRI specific entry points
+ */
+
+int Divas4BriInit(card_t *card, dia_card_t *cfg)
+{
+// byte sw_id[80];
+// extern int FPGA_Done;
+
+ DPRINTF(("divas: initialise Diva Server 4BRI"));
+
+ if (Divas4BRIInitPCI(card, cfg) == -1)
+ {
+ return -1;
+ }
+
+ /* Need to download the FPGA */
+/* if (!FPGA_Done)
+ {
+ int retVal;
+
+ retVal=FPGA_Download(IDI_ADAPTER_MAESTRAQ,
+ cfg->io_base,
+ sw_id,
+ FPGA_Bytes
+ );
+ if(retVal==-1)
+ {
+
+ DPRINTF(("divas: FPGA Download Failed"));
+ return -1;
+
+ }
+ FPGA_Done = 1;
+ } */
+
+ card->card_reset = diva_server_4bri_reset;
+ card->card_load = diva_server_4bri_load;
+ card->card_config = diva_server_4bri_config;
+ card->card_start = diva_server_4bri_start;
+ card->reset_int = diva_server_4bri_reset_int;
+ card->card_mem_get = diva_server_4bri_mem_get;
+
+ card->xlog_offset = DIVAS_MAINT_OFFSET;
+
+ card->out = DivasOut;
+ card->test_int = DivasTestInt;
+ card->dpc = DivasDpc;
+ card->clear_int = DivasClearInt;
+ card->card_isr = fourbri_ISR;
+
+ card->a.ram_out = mem_out;
+ card->a.ram_outw = mem_outw;
+ card->a.ram_out_buffer = mem_out_buffer;
+ card->a.ram_inc = mem_inc;
+
+ card->a.ram_in = mem_in;
+ card->a.ram_inw = mem_inw;
+ card->a.ram_in_buffer = mem_in_buffer;
+ card->a.ram_look_ahead = mem_look_ahead;
+
+ return 0;
+}
+
+void memcp(byte *dst, byte *src, dword dwLen)
+{
+ while (dwLen)
+ {
+ *dst = *src;
+ dst++; src++;
+ dwLen--;
+ }
+}
+
+int memcm(byte *dst, byte *src, dword dwLen)
+{
+ int offset = 0;
+
+ while (offset < dwLen)
+ {
+ if(*dst != *src)
+ return (offset+1);
+
+ offset++;
+ src++;
+ dst++;
+ }
+
+ return 0;
+}
+
+
+
+/*int fourbri_ISR (card_t* card)
+{
+ int served = 0;
+ byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+
+ if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01)
+ {
+ served = 1;
+ card->int_pend += 1;
+ DivasDpcSchedule();
+ UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08);
+ }
+
+ UxCardMemDetach(card->hw, DivasIOBase);
+
+ return (served != 0);
+}*/
+
+
+int fourbri_ISR (card_t* card)
+{
+ int served = 0;
+ byte *ctl;
+ byte *reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY);
+
+ if (UxCardPortIoIn(card->hw, reg, PLX9054_INTCSR) & 0x80)
+ {
+ served = 1;
+ card->int_pend += 1;
+ DivasDpcSchedule(); /* ISR DPC */
+
+ ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+ UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF);
+ UxCardMemDetach(card->hw, ctl);
+ }
+
+ UxCardMemDetach(card->hw, reg);
+ return (served != 0);
+}
diff --git a/drivers/isdn/eicon/fpga.c b/drivers/isdn/eicon/fpga.c
new file mode 100644
index 000000000..b5f21678e
--- /dev/null
+++ b/drivers/isdn/eicon/fpga.c
@@ -0,0 +1,158 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include "sys.h"
+#include "idi.h"
+#include "uxio.h"
+
+#define FPGA_PORT 0x6E
+#define FPGA_DLOAD_BUFLEN 256
+#define NAME_OFFSET 0x10
+#define NAME_MAXLEN 12
+#define DATE_OFFSET 0x2c
+#define DATE_MAXLEN 10
+
+word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset);
+void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word);
+void UxPause(long int);
+
+/*-------------------------------------------------------------------------*/
+/* Loads the FPGA configuration file onto the hardware. */
+/* Function returns 0 on success, else an error number. */
+/* On success, an identifier string is returned in the buffer */
+/* */
+/* A buffer of FPGA_BUFSIZE, a handle to the already opened bitstream */
+/* file and a file read function has to be provided by the operating */
+/* system part. */
+/* ----------------------------------------------------------------------- */
+int FPGA_Download( word cardtype,
+ dword RegBase,
+ byte *strbuf,
+ byte FPGA_SRC[],
+ int FPGA_LEN
+ )
+{
+ word i, j, k;
+ word baseval, Mask_PROGRAM, Mask_DONE, Mask_CCLK, Mask_DIN;
+ dword addr;
+ byte *pFPGA;
+
+ //--- check for legal cardtype
+ switch (cardtype)
+ {
+ case IDI_ADAPTER_MAESTRAQ:
+ addr = RegBase ; // address where to access FPGA
+ Mask_PROGRAM = 0x0001; // FPGA pins at address
+ Mask_DONE = 0x0002;
+ Mask_CCLK = 0x0100;
+ Mask_DIN = 0x0400;
+ baseval = 0x000d; // PROGRAM hi, CCLK lo, DIN lo by default
+ break;
+
+ default:
+
+ DPRINTF(("divas: FPGA Download ,Illegal Card"));
+ return -1; // illegal card
+ }
+
+ //--- generate id string from file content
+ for (j=NAME_OFFSET, k=0; j<(NAME_OFFSET+NAME_MAXLEN); j++, k++) //name
+ {
+ if (!FPGA_SRC[j]) break;
+ strbuf[k] = FPGA_SRC[j];
+ }
+ strbuf[k++] = ' ';
+ for (j=DATE_OFFSET; j<(DATE_OFFSET+DATE_MAXLEN); j++, k++) // date
+ {
+ if (!FPGA_SRC[j]) break;
+ strbuf[k] = FPGA_SRC[j];
+ }
+ strbuf[k] = 0;
+
+ DPRINTF(("divas: FPGA Download - %s", strbuf));
+
+ //--- prepare download, Pulse PROGRAM pin down.
+ UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval &~Mask_PROGRAM); // PROGRAM low pulse
+ UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // release
+ UxPause(50); // wait until FPGA finised internal memory clear
+
+ //--- check done pin, must be low
+ if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE)
+ {
+ DPRINTF(("divas: FPGA_ERR_DONE_WRONG_LEVEL"));
+ return -1;
+ }
+
+ pFPGA = FPGA_SRC;
+
+ i = 0;
+ /* Move past the header */
+ while ((FPGA_SRC[i] != 0xFF) && (i < FPGA_LEN))
+ {
+ i++;
+ }
+
+ // We've hit the 0xFF so move on to the next byte
+ // i++;
+ DPRINTF(("divas: FPGA Code starts at offset %d", i));
+
+ //--- put data onto the FPGA
+ for (;i<FPGA_LEN; i++)
+ {
+ //--- put byte onto FPGA
+ for (j=0; j<8; j++)
+ {
+ if (FPGA_SRC[i] &(0x80>>j)) baseval |= Mask_DIN; // write a hi
+ else baseval &=~Mask_DIN; // write a lo
+ UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval);
+ UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK); // set CCLK hi
+ UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // set CCLK lo
+ }
+ }
+
+ //--- add some additional startup clock cycles and check done pin
+ for (i=0; i<5; i++)
+ {
+ UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK); // set CCLK hi
+ UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // set CCLK lo
+ }
+
+ UxPause(100);
+
+ if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE)
+ {
+ DPRINTF(("divas: FPGA download successful"));
+ }
+ else
+ {
+ DPRINTF(("divas: FPGA download failed - 0x%x", UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT)));
+ return -1;
+ }
+
+return 0;
+}
+
diff --git a/drivers/isdn/eicon/idi.c b/drivers/isdn/eicon/idi.c
new file mode 100644
index 000000000..f9b8a0ee3
--- /dev/null
+++ b/drivers/isdn/eicon/idi.c
@@ -0,0 +1,870 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.8
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/*
+ * Core driver for Diva Server cards
+ * Implements the IDI interface
+ */
+
+#include "idi.h"
+#include "adapter.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "sys.h"
+#include "uxio.h"
+
+/* IDI request functions */
+
+static void request(card_t *card, ENTITY *e);
+
+static void req_0(ENTITY *e) { request(&DivasCards[ 0], e); }
+static void req_1(ENTITY *e) { request(&DivasCards[ 1], e); }
+static void req_2(ENTITY *e) { request(&DivasCards[ 2], e); }
+static void req_3(ENTITY *e) { request(&DivasCards[ 3], e); }
+static void req_4(ENTITY *e) { request(&DivasCards[ 4], e); }
+static void req_5(ENTITY *e) { request(&DivasCards[ 5], e); }
+static void req_6(ENTITY *e) { request(&DivasCards[ 6], e); }
+static void req_7(ENTITY *e) { request(&DivasCards[ 7], e); }
+static void req_8(ENTITY *e) { request(&DivasCards[ 8], e); }
+static void req_9(ENTITY *e) { request(&DivasCards[ 9], e); }
+static void req_10(ENTITY *e) { request(&DivasCards[10], e); }
+static void req_11(ENTITY *e) { request(&DivasCards[11], e); }
+static void req_12(ENTITY *e) { request(&DivasCards[12], e); }
+static void req_13(ENTITY *e) { request(&DivasCards[13], e); }
+static void req_14(ENTITY *e) { request(&DivasCards[14], e); }
+static void req_15(ENTITY *e) { request(&DivasCards[15], e); }
+
+IDI_CALL DivasIdiRequest[16] =
+{
+ &req_0, &req_1, &req_2, &req_3,
+ &req_4, &req_5, &req_6, &req_7,
+ &req_8, &req_9, &req_10, &req_11,
+ &req_12, &req_13, &req_14, &req_15
+};
+
+#define PR_RAM ((struct pr_ram *)0)
+#define RAM ((struct dual *)0)
+
+/*------------------------------------------------------------------*/
+/* local function prototypes */
+/*------------------------------------------------------------------*/
+
+static byte isdn_rc(ADAPTER *, byte, byte, byte, word);
+static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word);
+
+/*
+ * IDI related functions
+ */
+
+static
+ENTITY *entity_ptr(ADAPTER *a, byte e_no)
+{
+ card_t *card;
+
+ card = a->io;
+
+ return card->e_tbl[e_no].e;
+}
+
+static
+void CALLBACK(ADAPTER *a, ENTITY *e)
+{
+ card_t *card = a->io;
+
+ if (card->log_types & DIVAS_LOG_IDI)
+ {
+ DivasLogIdi(card, e, FALSE);
+ }
+
+ (*e->callback)(e);
+}
+
+static
+void *PTR_P(ADAPTER *a, ENTITY *e, void *P)
+{
+ return(P);
+}
+
+static
+void *PTR_R(ADAPTER *a, ENTITY *e)
+{
+ return((void*)e->R);
+}
+
+static
+void *PTR_X(ADAPTER *a, ENTITY *e)
+{
+ return((void*)e->X);
+}
+
+static
+void free_entity(ADAPTER *a, byte e_no)
+{
+ card_t *card;
+ int ipl;
+
+ card = a->io;
+
+ ipl = UxCardLock(card->hw);
+
+ card->e_tbl[e_no].e = NULL;
+ card->e_count--;
+
+ UxCardUnlock(card->hw, ipl);
+
+ return;
+}
+
+static
+void assign_queue(ADAPTER * a, byte e_no, word ref)
+{
+ card_t *card;
+ int ipl;
+
+ card = a->io;
+
+ ipl = UxCardLock(card->hw);
+
+ card->e_tbl[e_no].assign_ref = ref;
+ card->e_tbl[e_no].next = card->assign;
+ card->assign = e_no;
+
+ UxCardUnlock(card->hw, ipl);
+
+ return;
+}
+
+static
+byte get_assign(ADAPTER *a, word ref)
+{
+ card_t *card;
+ byte e_no;
+ int ipl;
+
+ card = a->io;
+
+ ipl = UxCardLock(card->hw);
+
+ e_no = (byte)card->assign;
+ while (e_no)
+ {
+ if (card->e_tbl[e_no].assign_ref == ref)
+ {
+ break;
+ }
+ e_no = card->e_tbl[e_no].next;
+ }
+
+ UxCardUnlock(card->hw, ipl);
+
+ return e_no;
+}
+
+static
+void req_queue(ADAPTER * a, byte e_no)
+{
+ card_t *card;
+ int ipl;
+
+ card = a->io;
+
+ ipl = UxCardLock(card->hw);
+
+ card->e_tbl[e_no].next = 0;
+
+ if (card->e_head)
+ {
+ card->e_tbl[card->e_tail].next = e_no;
+ card->e_tail = e_no;
+ }
+ else
+ {
+ card->e_head = e_no;
+ card->e_tail = e_no;
+ }
+
+ UxCardUnlock(card->hw, ipl);
+
+ return;
+}
+
+static
+byte look_req(ADAPTER * a)
+{
+ card_t *card;
+
+ card = a->io;
+
+ return(card->e_head);
+}
+
+static
+void next_req(ADAPTER * a)
+{
+ card_t *card;
+ int ipl;
+
+
+ card = a->io;
+
+ ipl = UxCardLock(card->hw);
+
+ card->e_head = card->e_tbl[card->e_head].next;
+ if (!card->e_head)
+ {
+ card->e_tail = 0;
+ }
+
+ UxCardUnlock(card->hw, ipl);
+
+ return;
+}
+
+
+/*
+ * IDI request function for active cards
+ */
+
+static
+void request(card_t *card, ENTITY *e)
+{
+ word *special_req;
+ int i;
+ int ipl;
+
+ if (card->log_types & DIVAS_LOG_IDI)
+ {
+ DivasLogIdi(card, e, TRUE);
+ }
+
+ if (!e->Req)
+ {
+ special_req = (word *) e;
+
+ switch (*special_req)
+ {
+ case REQ_REMOVE:
+ return;
+
+ case REQ_NAME:
+ for (i=0; i < DIM(card->cfg.name); i++)
+ {
+ ((struct get_name_s *) e)->name[i] = card->cfg.name[i];
+ }
+ return;
+
+ case REQ_SERIAL:
+ case REQ_XLOG:
+ DPRINTF(("IDI: attempted REQ_SERIAL or REQ_XLOG"));
+ return;
+
+ default:
+ return;
+ }
+ }
+
+ ipl = UxCardLock(card->hw);
+
+ if (!(e->Id & 0x1f))
+ {
+ DPRINTF(("IDI: ASSIGN req"));
+
+ for (i = 1; i < card->e_max; i++)
+ {
+ if (!card->e_tbl[i].e)
+ {
+ break;
+ }
+ }
+
+ if (i == card->e_max)
+ {
+ DPRINTF(("IDI: request all ids in use (IDI req ignored)"));
+ UxCardUnlock(card->hw, ipl);
+ e->Rc = OUT_OF_RESOURCES;
+ return;
+ }
+
+ card->e_tbl[i].e = e;
+ card->e_count++;
+
+ e->No = (byte) i;
+ e->More = 0;
+ e->RCurrent = 0xff;
+ }
+ else
+ {
+ i = e->No;
+ }
+
+ if (e->More & XBUSY)
+ {
+ DPRINTF(("IDI: request - entity is busy"));
+ UxCardUnlock(card->hw, ipl);
+ return;
+ }
+
+ e->More |= XBUSY;
+ e->More &= ~ XMOREF;
+ e->XCurrent = 0;
+ e->XOffset = 0;
+
+ card->e_tbl[i].next = 0;
+
+ if(card->e_head)
+ {
+ card->e_tbl[card->e_tail].next = i;
+ card->e_tail = i;
+ }
+ else
+ {
+ card->e_head = i;
+ card->e_tail = i;
+ }
+
+ UxCardUnlock(card->hw, ipl);
+
+ DivasScheduleRequestDpc();
+
+ return;
+}
+
+static byte pr_ready(ADAPTER * a)
+{
+ byte ReadyCount;
+
+ ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) -
+ a->ram_in(a, &PR_RAM->ReqInput));
+
+ if(!ReadyCount) {
+ if(!a->ReadyInt) {
+ a->ram_inc(a, &PR_RAM->ReadyInt);
+ a->ReadyInt++;
+ }
+ }
+ return ReadyCount;
+}
+
+/*------------------------------------------------------------------*/
+/* output function */
+/*------------------------------------------------------------------*/
+
+void DivasOut(ADAPTER * a)
+{
+ byte e_no;
+ ENTITY * this = NULL;
+ BUFFERS *X;
+ word length;
+ word i;
+ word clength;
+ REQ * ReqOut;
+ byte more;
+ byte ReadyCount;
+ byte ReqCount;
+ byte Id;
+
+ /* while a request is pending ... */
+ e_no = look_req(a);
+ if(!e_no)
+ {
+ return;
+ }
+
+ ReadyCount = pr_ready(a);
+ if(!ReadyCount)
+ {
+ DPRINTF(("IDI: card not ready for next request"));
+ return;
+ }
+
+ ReqCount = 0;
+ while(e_no && ReadyCount) {
+
+ next_req(a);
+
+ this = entity_ptr(a, e_no);
+
+#ifdef USE_EXTENDED_DEBUGS
+ if ( !this )
+ {
+ ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+ DBG_FTL(("!A%d ==> NULL entity ptr - try to ignore", (int)io->ANum))
+ e_no = look_req(a) ;
+ ReadyCount-- ;
+ continue ;
+ }
+ {
+ ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+ DPRINTF(("IDI: >A%d Id=0x%x Req=0x%x", io->ANum, this->Id, this->Req))
+ }
+#else
+ DPRINTF(("IDI: >REQ=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh));
+#endif
+
+ /* get address of next available request buffer */
+ ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)];
+
+ /* now copy the data from the current data buffer into the */
+ /* adapters request buffer */
+ length = 0;
+ i = this->XCurrent;
+ X = PTR_X(a,this);
+ while(i<this->XNum && length<270) {
+ clength = MIN((word)(270-length),X[i].PLength-this->XOffset);
+ a->ram_out_buffer(a,
+ &ReqOut->XBuffer.P[length],
+ PTR_P(a,this,&X[i].P[this->XOffset]),
+ clength);
+
+ length +=clength;
+ this->XOffset +=clength;
+ if(this->XOffset==X[i].PLength) {
+ this->XCurrent = (byte)++i;
+ this->XOffset = 0;
+ }
+ }
+
+ a->ram_outw(a, &ReqOut->XBuffer.length, length);
+ a->ram_out(a, &ReqOut->ReqId, this->Id);
+ a->ram_out(a, &ReqOut->ReqCh, this->ReqCh);
+
+ /* if its a specific request (no ASSIGN) ... */
+
+ if(this->Id &0x1f) {
+
+ /* if buffers are left in the list of data buffers do */
+ /* do chaining (LL_MDATA, N_MDATA) */
+
+ this->More++;
+ if(i<this->XNum && this->MInd) {
+ a->ram_out(a, &ReqOut->Req, this->MInd);
+ more = TRUE;
+ }
+ else {
+ this->More |=XMOREF;
+ a->ram_out(a, &ReqOut->Req, this->Req);
+ more = FALSE;
+ }
+
+ /* if we did chaining, this entity is put back into the */
+ /* request queue */
+
+ if(more) {
+ req_queue(a,this->No);
+ }
+ }
+
+ /* else it's a ASSIGN */
+
+ else {
+
+ /* save the request code used for buffer chaining */
+
+ this->MInd = 0;
+ if (this->Id==BLLC_ID) this->MInd = LL_MDATA;
+ if (this->Id==NL_ID ||
+ this->Id==TASK_ID ||
+ this->Id==MAN_ID
+ ) this->MInd = N_MDATA;
+
+ /* send the ASSIGN */
+
+ this->More |=XMOREF;
+ a->ram_out(a, &ReqOut->Req, this->Req);
+
+ /* save the reference of the ASSIGN */
+
+ assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference));
+ }
+ a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next));
+ ReadyCount--;
+ ReqCount++;
+
+ e_no = look_req(a);
+ }
+
+ /* send the filled request buffers to the ISDN adapter */
+
+ a->ram_out(a, &PR_RAM->ReqInput,
+ (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount));
+
+ /* if it is a 'unreturncoded' UREMOVE request, remove the */
+ /* Id from our table after sending the request */
+ if(this->Req==UREMOVE && this->Id) {
+ Id = this->Id;
+ e_no = a->IdTable[Id];
+ free_entity(a, e_no);
+ a->IdTable[Id] = 0;
+ this->Id = 0;
+ }
+
+}
+
+/*------------------------------------------------------------------*/
+/* isdn interrupt handler */
+/*------------------------------------------------------------------*/
+
+byte DivasDpc(ADAPTER * a)
+{
+ byte Count;
+ RC * RcIn;
+ IND * IndIn;
+ byte c;
+ byte RNRId;
+ byte Rc;
+ byte Ind;
+
+ /* if return codes are available ... */
+ if((Count = a->ram_in(a, &PR_RAM->RcOutput))) {
+
+ DPRINTF(("IDI: #Rc=%x",Count));
+
+ /* get the buffer address of the first return code */
+ RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)];
+
+ /* for all return codes do ... */
+ while(Count--) {
+
+ if((Rc=a->ram_in(a, &RcIn->Rc))) {
+
+ /* call return code handler, if it is not our return code */
+ /* the handler returns 2 */
+ /* for all return codes we process, we clear the Rc field */
+ isdn_rc(a,
+ Rc,
+ a->ram_in(a, &RcIn->RcId),
+ a->ram_in(a, &RcIn->RcCh),
+ a->ram_inw(a, &RcIn->Reference));
+
+ a->ram_out(a, &RcIn->Rc, 0);
+ }
+
+ /* get buffer address of next return code */
+ RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)];
+ }
+
+ /* clear all return codes (no chaining!) */
+ a->ram_out(a, &PR_RAM->RcOutput ,0);
+
+ /* call output function */
+ DivasOut(a);
+ }
+
+ /* clear RNR flag */
+ RNRId = 0;
+
+ /* if indications are available ... */
+ if((Count = a->ram_in(a, &PR_RAM->IndOutput))) {
+
+ DPRINTF(("IDI: #Ind=%x",Count));
+
+ /* get the buffer address of the first indication */
+ IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)];
+
+ /* for all indications do ... */
+ while(Count--) {
+
+ /* if the application marks an indication as RNR, all */
+ /* indications from the same Id delivered in this interrupt */
+ /* are marked RNR */
+ if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) {
+ a->ram_out(a, &IndIn->Ind, 0);
+ a->ram_out(a, &IndIn->RNR, TRUE);
+ }
+ else {
+ Ind = a->ram_in(a, &IndIn->Ind);
+ if(Ind) {
+ RNRId = 0;
+
+ /* call indication handler, a return value of 2 means chain */
+ /* a return value of 1 means RNR */
+ /* for all indications we process, we clear the Ind field */
+ c = isdn_ind(a,
+ Ind,
+ a->ram_in(a, &IndIn->IndId),
+ a->ram_in(a, &IndIn->IndCh),
+ &IndIn->RBuffer,
+ a->ram_in(a, &IndIn->MInd),
+ a->ram_inw(a, &IndIn->MLength));
+
+ if(c==1) {
+ DPRINTF(("IDI: RNR"));
+ a->ram_out(a, &IndIn->Ind, 0);
+ RNRId = a->ram_in(a, &IndIn->IndId);
+ a->ram_out(a, &IndIn->RNR, TRUE);
+ }
+ }
+ }
+
+ /* get buffer address of next indication */
+ IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)];
+ }
+
+ a->ram_out(a, &PR_RAM->IndOutput, 0);
+ }
+ return FALSE;
+}
+
+byte DivasTestInt(ADAPTER * a)
+{
+ return a->ram_in(a,(void *)0x3fe);
+}
+
+void DivasClearInt(ADAPTER * a)
+{
+ a->ram_out(a,(void *)0x3fe,0);
+}
+
+/*------------------------------------------------------------------*/
+/* return code handler */
+/*------------------------------------------------------------------*/
+
+static
+byte isdn_rc(ADAPTER * a,
+ byte Rc,
+ byte Id,
+ byte Ch,
+ word Ref)
+{
+ ENTITY * this;
+ byte e_no;
+
+#ifdef USE_EXTENDED_DEBUGS
+ {
+ ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+ DPRINTF(("IDI: <A%d Id=0x%x Rc=0x%x", io->ANum, Id, Rc))
+ }
+#else
+ DPRINTF(("IDI: <RC(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch));
+#endif
+
+ /* check for ready interrupt */
+ if(Rc==READY_INT) {
+ if(a->ReadyInt) {
+ a->ReadyInt--;
+ return 0;
+ }
+ return 2;
+ }
+
+ /* if we know this Id ... */
+ e_no = a->IdTable[Id];
+ if(e_no) {
+
+ this = entity_ptr(a,e_no);
+
+ this->RcCh = Ch;
+
+ /* if it is a return code to a REMOVE request, remove the */
+ /* Id from our table */
+ if(this->Req==REMOVE && Rc==OK) {
+ free_entity(a, e_no);
+ a->IdTable[Id] = 0;
+ this->Id = 0;
+/**************************************************************/
+ if ((this->More & XMOREC) > 1) {
+ this->More &= ~XMOREC;
+ this->More |= 1;
+ DPRINTF(("isdn_rc, Id=%x, correct More on REMOVE", Id));
+ }
+ }
+
+ if (Rc==OK_FC) {
+ this->Rc = Rc;
+ this->More = (this->More & (~XBUSY | XMOREC)) | 1;
+ this->complete = 0xFF;
+ CALLBACK(a, this);
+ return 0;
+ }
+ if(this->More &XMOREC)
+ this->More--;
+
+ /* call the application callback function */
+ if(this->More &XMOREF && !(this->More &XMOREC)) {
+ this->Rc = Rc;
+ this->More &=~XBUSY;
+ this->complete=0xff;
+ CALLBACK(a, this);
+ }
+ return 0;
+ }
+
+ /* if it's an ASSIGN return code check if it's a return */
+ /* code to an ASSIGN request from us */
+ if((Rc &0xf0)==ASSIGN_RC) {
+
+ e_no = get_assign(a, Ref);
+
+ if(e_no) {
+
+ this = entity_ptr(a,e_no);
+
+ this->Id = Id;
+
+ /* call the application callback function */
+ this->Rc = Rc;
+ this->More &=~XBUSY;
+ this->complete=0xff;
+ CALLBACK(a, this);
+
+ if(Rc==ASSIGN_OK) {
+ a->IdTable[Id] = e_no;
+ }
+ else
+ {
+ free_entity(a, e_no);
+ a->IdTable[Id] = 0;
+ this->Id = 0;
+ }
+ return 1;
+ }
+ }
+ return 2;
+}
+
+/*------------------------------------------------------------------*/
+/* indication handler */
+/*------------------------------------------------------------------*/
+
+static
+byte isdn_ind(ADAPTER * a,
+ byte Ind,
+ byte Id,
+ byte Ch,
+ PBUFFER * RBuffer,
+ byte MInd,
+ word MLength)
+{
+ ENTITY * this;
+ word clength;
+ word offset;
+ BUFFERS *R;
+
+#ifdef USE_EXTENDED_DEBUGS
+ {
+ ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+ DPRINTF(("IDI: <A%d Id=0x%x Ind=0x%x", io->ANum, Id, Ind))
+ }
+#else
+ DPRINTF(("IDI: <IND(Ind=%x,Id=%x,Ch=%x)",Ind,Id,Ch));
+#endif
+
+ if(a->IdTable[Id]) {
+
+ this = entity_ptr(a,a->IdTable[Id]);
+
+ this->IndCh = Ch;
+
+ /* if the Receive More flag is not yet set, this is the */
+ /* first buffer of the packet */
+ if(this->RCurrent==0xff) {
+
+ /* check for receive buffer chaining */
+ if(Ind==this->MInd) {
+ this->complete = 0;
+ this->Ind = MInd;
+ }
+ else {
+ this->complete = 1;
+ this->Ind = Ind;
+ }
+
+ /* call the application callback function for the receive */
+ /* look ahead */
+ this->RLength = MLength;
+
+ a->ram_look_ahead(a, RBuffer, this);
+
+ this->RNum = 0;
+ CALLBACK(a, this);
+
+ /* map entity ptr, selector could be re-mapped by call to */
+ /* IDI from within callback */
+ this = entity_ptr(a,a->IdTable[Id]);
+
+ /* check for RNR */
+ if(this->RNR==1) {
+ this->RNR = 0;
+ return 1;
+ }
+
+ /* if no buffers are provided by the application, the */
+ /* application want to copy the data itself including */
+ /* N_MDATA/LL_MDATA chaining */
+ if(!this->RNR && !this->RNum) {
+ return 0;
+ }
+
+ /* if there is no RNR, set the More flag */
+ this->RCurrent = 0;
+ this->ROffset = 0;
+ }
+
+ if(this->RNR==2) {
+ if(Ind!=this->MInd) {
+ this->RCurrent = 0xff;
+ this->RNR = 0;
+ }
+ return 0;
+ }
+ /* if we have received buffers from the application, copy */
+ /* the data into these buffers */
+ offset = 0;
+ R = PTR_R(a,this);
+ do {
+ if(this->ROffset==R[this->RCurrent].PLength) {
+ this->ROffset = 0;
+ this->RCurrent++;
+ }
+ clength = MIN(a->ram_inw(a, &RBuffer->length)-offset,
+ R[this->RCurrent].PLength-this->ROffset);
+ if(R[this->RCurrent].P) {
+ a->ram_in_buffer(a,
+ &RBuffer->P[offset],
+ PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]),
+ clength);
+ }
+ offset +=clength;
+ this->ROffset +=clength;
+ } while(offset<(a->ram_inw(a, &RBuffer->length)));
+
+ /* if it's the last buffer of the packet, call the */
+ /* application callback function for the receive complete */
+ /* call */
+ if(Ind!=this->MInd) {
+ R[this->RCurrent].PLength = this->ROffset;
+ if(this->ROffset) this->RCurrent++;
+ this->RNum = this->RCurrent;
+ this->RCurrent = 0xff;
+ this->Ind = Ind;
+ this->complete = 2;
+ CALLBACK(a, this);
+ }
+ return 0;
+ }
+ return 2;
+}
diff --git a/drivers/isdn/eicon/idi.h b/drivers/isdn/eicon/idi.h
new file mode 100644
index 000000000..0819665fe
--- /dev/null
+++ b/drivers/isdn/eicon/idi.h
@@ -0,0 +1,146 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/* External IDI interface */
+
+#if !defined(IDI_H)
+#define IDI_H
+
+#include "sys.h"
+
+/* typedefs for our data structures */
+
+typedef struct get_name_s GET_NAME;
+typedef struct entity_s ENTITY;
+typedef struct buffers_s BUFFERS;
+
+/* IDI request/callback function pointer */
+
+typedef void (* IDI_CALL)(ENTITY *);
+
+typedef struct {
+ word length; /* length of data/parameter field */
+ byte P[270]; /* data/parameter field */
+} DBUFFER;
+
+#define REQ_NAME 0x0100
+#define BOARD_NAME_LENGTH 9
+struct get_name_s {
+ word command; /* command = 0x0100 */
+ byte name[BOARD_NAME_LENGTH];
+};
+
+#define REQ_REMOVE 0x0000 /* pointer to word which is 0 */
+#define REQ_SERIAL 0x0200
+struct get_serial_s {
+ word command; /* command = 0x0200 */
+ dword serial; /* serial number */
+};
+
+#define REQ_POSTCALL 0x0300
+struct postcall_s {
+ word command; /* command = 0x0300 */
+ word dummy; /* not used */
+ IDI_CALL callback; /* routine adress to call back */
+ ENTITY *contxt; /* ptr to entity to use */
+};
+
+#define REQ_XLOG 0x0400 /* structure is card dependent/defined locally */
+
+struct buffers_s {
+ word PLength;
+ byte *P;
+};
+
+struct entity_s {
+ byte Req; /* pending request */
+ byte Rc; /* return code received */
+ byte Ind; /* indication received */
+ byte ReqCh; /* channel of current Req */
+ byte RcCh; /* channel of current Rc */
+ byte IndCh; /* channel of current Ind */
+ byte Id; /* ID used by this entity */
+ byte GlobalId; /* reserved field */
+ byte XNum; /* number of X-buffers */
+ byte RNum; /* number of R-buffers */
+ BUFFERS *X; /* pointer to X-buffer list */
+ BUFFERS *R; /* pointer to R-buffer list */
+ word RLength; /* length of current R-data */
+ DBUFFER *RBuffer; /* buffer of current R-data */
+ byte RNR; /* receive not ready flag */
+ byte complete; /* receive complete status */
+ IDI_CALL callback;
+
+ word user[2];
+
+ /* fields used by the driver internally */
+ byte No; /* entity number */
+ byte reserved2; /* reserved field */
+ byte More; /* R/X More flags */
+ byte MInd; /* MDATA coding for this ID */
+ byte XCurrent; /* current transmit buffer */
+ byte RCurrent; /* current receive buffer */
+ word XOffset; /* offset in x-buffer */
+ word ROffset; /* offset in r-buffer */
+};
+
+typedef struct {
+ byte type;
+ byte channels;
+ word features;
+ dword serial;
+ IDI_CALL request;
+} DESCRIPTOR;
+
+extern void EtdM_DIDD_Read(DESCRIPTOR *, int *);
+
+ /* descriptor type field coding */
+#define IDI_ADAPTER_S 1
+#define IDI_ADAPTER_PR 2
+#define IDI_ADAPTER_DIVA 3
+#define IDI_ADAPTER_MAESTRA 4
+#define IDI_ADAPTER_MAESTRAQ 5
+#define IDI_ADAPTER_MAESTRAP 6
+#define IDI_VADAPTER 0x40
+#define IDI_DRIVER 0x80
+#define IDI_DIMAINT 0xff
+
+/* feature bit mask values */
+
+#define DI_VOICE 0x0 /* obsolete define */
+#define DI_FAX3 0x1
+#define DI_MODEM 0x2
+#define DI_POST 0x4
+#define DI_V110 0x8
+#define DI_V120 0x10
+#define DI_POTS 0x20
+#define DI_CODEC 0x40
+#define DI_MANAGE 0x80
+#define DI_V_42 0x0100
+#define DI_EXTD_FAX 0x0200 /* Extended FAX (ECM, 2D, T.6, Polling) */
+
+#endif /* IDI_H */
diff --git a/drivers/isdn/eicon/kprintf.c b/drivers/isdn/eicon/kprintf.c
new file mode 100644
index 000000000..3282b7fc5
--- /dev/null
+++ b/drivers/isdn/eicon/kprintf.c
@@ -0,0 +1,538 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.3
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/*
+ * Source file for kernel interface to kernel log facility
+ */
+
+
+#include "sys.h"
+#include <stdarg.h>
+#undef MAX
+#undef MIN
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include "divas.h"
+#include "divalog.h"
+#include "uxio.h"
+
+/*
+ * Implementation of printf and sprintf for kernel
+ */
+
+#define MAX_BUFF (80) /* limit size of temporary buffers */
+
+#define WRITE_CHAR(BUFFER, SIZE, C) \
+ if (--(SIZE) < 0) { (BUFFER)--; *(BUFFER) = '\0'; return; } *(BUFFER)++ = (C)
+
+
+/*
+ * convert a number to decimal ASCII
+ */
+
+static
+void do_decimal( char *temp,
+ int temp_len,
+ unsigned int value,
+ char *s)
+
+{
+ int i;
+
+ temp[0] = '\0';
+
+ for (i = 1; i < temp_len; i++)
+ {
+ temp[i] = (char) ((value % 10) + (int) '0');
+ value /= 10;
+ }
+
+ for (i = (temp_len - 1); temp[i] == '0'; i--)
+ {
+ ;
+ }
+
+ if (i == 0)
+ {
+ i++;
+ }
+
+ while (i >= 0)
+ {
+ *s++ = temp[i--];
+ }
+
+ return;
+}
+
+/*
+ * convert a number to octal ASCII
+ */
+
+static
+void do_octal( char *temp,
+ unsigned int value,
+ char *s)
+
+{
+ int i;
+
+ temp[0] = '\0';
+
+ for (i = 1; i <= 11; i++)
+ {
+ temp[i] = (char) ((value & 07) + (int) '0');
+ value >>= 3;
+ }
+ temp[11] &= '3';
+
+ for (i = 11; temp[i] == '0'; i--)
+ {
+ ;
+ }
+
+ if (i == 0)
+ {
+ i++;
+ }
+
+ while (i >= 0)
+ {
+ *s++ = temp[i--];
+ }
+
+ return;
+}
+
+/*
+ * convert a number to hex ASCII
+ */
+
+static
+void do_hex( char *temp,
+ unsigned int value,
+ char *s)
+
+{
+ int i;
+ static
+ char *dec_to_hex = "0123456789abcdef";
+
+ temp[0] = '\0';
+
+ for (i = 1; i <= 8; i++)
+ {
+ temp[i] = dec_to_hex[value & 0x0f];
+ value >>= 4;
+ }
+
+ for (i = 8; temp[i] == '0'; i--)
+ {
+ ;
+ }
+
+ if (i == 0)
+ {
+ i++;
+ }
+
+ while (i >= 0)
+ {
+ *s++ = temp[i--];
+ }
+
+ return;
+}
+
+/*
+ * convert a buffer to ASCII HEX
+ */
+
+static
+void do_buffer( char *buffer,
+ int length,
+ char *s)
+
+{
+ static
+ char hex_char [] = "0123456789abcdef";
+ char *b = buffer;
+ int hex_byte;
+ int nybble;
+
+ length = (length >= ((MAX_BUFF / 3) + 1)) ? (MAX_BUFF / 3) : length;
+
+ while (length)
+ {
+ hex_byte = (int) *b++;
+ nybble = (hex_byte >> 4) & 0xf;
+ *s++ = hex_char[nybble];
+ nybble = hex_byte & 0xf;
+ *s++ = hex_char[nybble];
+ *s++ = ' ';
+ length--;
+ }
+ *s = '\0';
+
+ return;
+}
+
+/*
+ * Body of sprintf function: behaves just like standard sprintf, except we
+ * have an extra argument (buffer size) which we use to ensure we don't
+ * overflow
+ */
+
+void Divas_vsprintf( char *buffer,
+ int size,
+ char *fmt,
+ va_list argptr)
+
+{
+ char c; /* single character buffer */
+ int i; /* handy scratch counter */
+ int f; /* format character (after %) */
+ char *str; /* pointer into string */
+ char temp[20]; /* temp buffer used in printing numbers */
+ char string[MAX_BUFF]; /* output from number conversion */
+ int length; /* length of string "str" */
+ char fill; /* fill character ' ' or '0' */
+ boolean_t leftjust; /* TRUE if left justified, else right justified */
+ int fmax, fmin; /* field specifiers % MIN . MAX s */
+ int leading; /* number of leading/trailing fill characters */
+ char sign; /* set to '-' for negative decimals */
+ int number; /* numeric argument */
+
+ char *buff_ptr; /* pointer to user's buffer of hex data */
+ int buff_len; /* length of hex data */
+
+ /* make sure we have somthing to write into */
+
+ if ((!buffer) || (size <= 0))
+ {
+ return;
+ }
+
+ while (TRUE)
+ {
+ /* echo characters until end or '%' encountered */
+
+ while ((c = *fmt++) != '%')
+ {
+ if (!c)
+ {
+ *buffer = '\0';
+ return;
+ }
+ WRITE_CHAR(buffer, size, c);
+ }
+
+ /* echo %% as % */
+
+ if (*fmt == '%')
+ {
+ WRITE_CHAR(buffer, size, *fmt);
+ continue;
+ }
+
+ /* %- turns on left-justify */
+
+ if ((leftjust = (boolean_t) ((*fmt == '-') ? TRUE : FALSE)))
+ {
+ fmt++;
+ }
+
+ /* %0 turns on zero filling */
+
+ if (*fmt == '0')
+ {
+ fill = '0';
+ }
+ else
+ {
+ fill = ' ';
+ }
+
+ /* minium field width specifier for %d, u, x, c, s */
+
+ fmin = 0;
+
+ if (*fmt == '*')
+ {
+ fmin = va_arg(argptr, int);
+ fmt++;
+ }
+ else
+ {
+ while ('0' <= *fmt && *fmt <= '9')
+ {
+ fmin = (fmin * 10) + (*fmt++ - '0');
+ }
+ }
+
+ /* maximum string width specifier for %s */
+
+ fmax = 0;
+
+ if (*fmt == '.')
+ {
+ if (*(++fmt) == '*')
+ {
+ fmax = va_arg(argptr, int);
+ fmt++;
+ }
+ else
+ {
+ while ('0' <= *fmt && *fmt <= '9')
+ {
+ fmax = (fmax * 10) + (*fmt++ - '0');
+ }
+ }
+ }
+
+ /* skip over 'l' option (ints are assumed same size as longs) */
+
+ if (*fmt == 'l')
+ {
+ fmt++;
+ }
+
+ /* get the format chacater */
+
+ if (!(f = *fmt++))
+ {
+ WRITE_CHAR(buffer, size, '%');
+ *buffer = '\0';
+ return;
+ }
+
+ sign = '\0'; /* sign == '-' for negative decimal */
+
+ str = string;
+
+ switch (f)
+ {
+ case 'c' :
+ string[0] = (char) va_arg(argptr, int);
+ string[1] = '\0';
+ fmax = 0;
+ fill = ' ';
+ break;
+
+ case 's' :
+ str = va_arg(argptr, char *);
+ fill = ' ';
+ break;
+
+ case 'D' :
+ case 'd' :
+ number = va_arg(argptr, int);
+ if (number < 0)
+ {
+ sign = '-';
+ number = -number;
+ }
+ do_decimal(temp, DIM(temp), (unsigned int) number, str);
+ fmax = 0;
+ break;
+
+ case 'U' :
+ case 'u' :
+ number = va_arg(argptr, int);
+ do_decimal(temp, DIM(temp), (unsigned int) number, str);
+ fmax = 0;
+ break;
+
+ case 'O' :
+ case 'o' :
+ number = va_arg(argptr, int);
+ do_octal(temp, (unsigned int) number, str);
+ fmax = 0;
+ break;
+
+ case 'X' :
+ case 'x' :
+ number = va_arg(argptr, int);
+ do_hex(temp, (unsigned int) number, str);
+ fmax = 0;
+ break;
+
+ case 'H' :
+ case 'h' :
+ buff_ptr = va_arg(argptr, char *);
+ buff_len = va_arg(argptr, int);
+ do_buffer(buff_ptr, buff_len, str);
+ fmax = 0;
+ break;
+
+ default :
+ WRITE_CHAR(buffer, size, ((char) f));
+ break;
+ }
+
+ /* get the length of the string */
+
+ length = 0;
+ while (str[length])
+ {
+ length++;
+ }
+
+ /* make sure we have fmax and fmin values that are O.K. */
+
+ if (fmin > DIM(string) || fmin < 0)
+ {
+ fmin = 0;
+ }
+
+ if (fmax > DIM(string) || fmax < 0)
+ {
+ fmax = 0;
+ }
+
+ /* figure out how many leading characters thare are */
+
+ leading = 0;
+
+ if (fmax || fmin)
+ {
+ if (fmax)
+ {
+ if (length > fmax)
+ {
+ length = fmax;
+ }
+ }
+
+ if (fmin)
+ {
+ leading = fmin - length;
+ }
+
+ if (sign == '-')
+ {
+ leading--;
+ }
+ }
+
+ /* output sign now, if fill is numeric */
+
+ if (sign == '-' && fill == '0')
+ {
+ WRITE_CHAR(buffer, size, '-');
+ }
+
+ /* if right justified, output fill characters */
+
+ if (!leftjust)
+ {
+ for (i = 0; i < leading; i++)
+ {
+ WRITE_CHAR(buffer, size, fill);
+ }
+ }
+
+ /* output sign now, if fill is spaces */
+
+ if (sign == '-' && fill == ' ')
+ {
+ WRITE_CHAR(buffer, size, '-');
+ }
+
+ /* now the actual value */
+
+ for (i = 0; i < length; i++)
+ {
+ WRITE_CHAR(buffer, size, str[i]);
+ }
+
+ /* if left justified, fill out with the fill character */
+
+ if (leftjust)
+ {
+ for (i = 0; i < leading; i++)
+ {
+ WRITE_CHAR(buffer, size, fill);
+ }
+ }
+ }
+}
+
+/*
+ * sprintf for kernel
+ *
+ * call our vsprintf assuming user has a big buffer....
+ */
+
+void DivasSprintf(char *buffer, char *fmt, ...)
+
+{
+ va_list argptr; /* pointer to additional args */
+
+ va_start(argptr, fmt);
+
+ Divas_vsprintf(buffer, 1024, fmt, argptr);
+
+ va_end(argptr);
+
+ return;
+}
+
+void DivasPrintf(char *fmt, ...)
+
+{
+ klog_t log; /* log entry buffer */
+
+ va_list argptr; /* pointer to additional args */
+
+ va_start(argptr, fmt);
+
+ /* clear log entry */
+
+ bzero((caddr_t) &log, sizeof(klog_t));
+
+ log.card = -1;
+ log.type = KLOG_TEXT_MSG;
+
+ /* time stamp the entry */
+
+ log.time_stamp = UxTimeGet();
+
+ /* call vsprintf to format the user's information */
+
+ Divas_vsprintf(log.buffer, DIM(log.buffer), fmt, argptr);
+
+ va_end(argptr);
+
+ /* send to the log streams driver and return */
+
+ DivasLogAdd(&log, sizeof(klog_t));
+
+ return;
+}
diff --git a/drivers/isdn/eicon/lincfg.c b/drivers/isdn/eicon/lincfg.c
new file mode 100644
index 000000000..3d2a8bfb1
--- /dev/null
+++ b/drivers/isdn/eicon/lincfg.c
@@ -0,0 +1,410 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.9
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include <linux/fs.h>
+#undef N_DATA /* Because we have our own definition */
+
+#include <asm/segment.h>
+#include <asm/io.h>
+
+#include "sys.h"
+#include "idi.h"
+#include "constant.h"
+#include "divas.h"
+#undef ID_MASK
+#include "pc.h"
+#include "pr_pc.h"
+
+#include "adapter.h"
+#include "uxio.h"
+
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+
+#define HW_ID_EICON_PCI 0x1133
+#define HW_ID_DIVA_SERVER_P 0xE014
+#define HW_ID_DIVA_SERVER_B_ST 0xE010
+#define HW_ID_DIVA_SERVER_B_U 0xE013
+#define HW_ID_DIVA_SERVER_Q 0xE012
+
+struct file_operations Divas_fops;
+int Divas_major;
+
+extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile,
+ unsigned int command, unsigned long arg);
+extern unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable);
+extern ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset);
+extern int do_open(struct inode *, struct file *);
+extern int do_release(struct inode *, struct file *);
+
+int FPGA_Done=0;
+
+int DivasCardsDiscover(void)
+{
+ word wNumCards = 0, wDeviceIndex = 0;
+ byte byBus, byFunc;
+ word wPCIConsultation, PCItmp;
+ dword j, i;
+ unsigned int PCIserial;
+ dia_card_t Card;
+ byte *b;
+
+ while (wDeviceIndex < 10)
+ {
+ wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI,
+ HW_ID_DIVA_SERVER_Q,
+ wDeviceIndex,
+ &byBus, &byFunc);
+
+ if (wPCIConsultation == PCIBIOS_SUCCESSFUL)
+ {
+
+ dword dwRAM, dwDivasIOBase, dwCFG, dwCTL;
+ byte byIRQ;
+
+ printk(KERN_DEBUG "Divas: DIVA Server 4BRI Found\n");
+ pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2,(unsigned int *) &dwRAM);
+ dwRAM &= 0xFFC00000;
+
+ pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1,(unsigned int *) &dwDivasIOBase);
+ dwDivasIOBase &= 0xFFFFFF00;
+
+ pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0,(unsigned int *) &dwCFG);
+ dwCFG &= 0xFFFFFF00;
+
+ pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_3,(unsigned int *) &dwCTL);
+ dwCTL &= 0xFFFFE000;
+
+
+ pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+ /* Retrieve the serial number */
+
+ pcibios_write_config_word(byBus,byFunc,0x4E,0x00FC);
+
+ for (j=0, PCItmp=0; j<10000 && !PCItmp; j++)
+ {
+ pcibios_read_config_word(byBus,byFunc,0x4E, &PCItmp);
+ PCItmp &= 0x8000; // extract done flag
+ }
+
+ pcibios_read_config_dword(byBus,byFunc,0x50, &PCIserial);
+
+
+ Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x400000);
+ Card.memory[DIVAS_CTL_MEMORY] = ioremap(dwCTL, 0x2000);
+ Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x100);
+ Card.io_base=dwDivasIOBase;
+
+ Card.irq = byIRQ;
+
+ Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_Q;
+ Card.bus_type = DIA_BUS_TYPE_PCI;
+
+ FPGA_Done = 0;
+
+ /* Create four virtual card structures as we want to treat
+ the 4Bri card as 4 Bri cards*/
+ for(i=0;i<4;i++)
+ {
+
+ b=Card.memory[DIVAS_RAM_MEMORY];
+ b+=(MQ_PROTCODE_OFFSET) * (i==0?0:1);
+ DPRINTF(("divas: offset = 0x%x", i* MQ_PROTCODE_OFFSET));
+ Card.memory[DIVAS_RAM_MEMORY]=b;
+
+ b = Card.memory[DIVAS_RAM_MEMORY];
+ b += MQ_SM_OFFSET;
+ Card.memory[DIVAS_SHARED_MEMORY] = b;
+
+ Card.bus_num = byBus;
+ Card.func_num = byFunc;
+ Card.slot = -1;
+
+
+ /* Fill in Name */
+ Card.name[0] = 'D';
+ Card.name[1] = 'I';
+ Card.name[2] = 'V';
+ Card.name[3] = 'A';
+ Card.name[4] = 'S';
+ Card.name[5] = 'Q';
+ Card.name[6] = '0' + i;
+ Card.name[7] = '\0';
+
+ Card.serial = PCIserial;
+
+ Card.card_id = wNumCards;
+
+ if (DivasCardNew(&Card) != 0)
+ {
+ // Force for loop to terminate
+ i = 4;
+ continue;
+ }
+ wNumCards++;
+
+ }//for
+ }
+ wDeviceIndex++;
+ }
+
+ wDeviceIndex = 0;
+
+ while (wDeviceIndex < 10)
+ {
+ wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI,
+ HW_ID_DIVA_SERVER_B_ST,
+ wDeviceIndex,
+ &byBus, &byFunc);
+
+ if (wPCIConsultation == PCIBIOS_SUCCESSFUL)
+ {
+ dword dwPLXIOBase, dwDivasIOBase;
+ byte byIRQ;
+
+ printk(KERN_DEBUG "Divas: DIVA Server BRI (S/T) Found\n");
+ pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase);
+ dwPLXIOBase &= 0xFFFFFF80;
+
+ pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase);
+ dwDivasIOBase &= 0xFFFFFFFC;
+
+ pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+
+ Card.card_id = wNumCards;
+ Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B;
+ Card.bus_type = DIA_BUS_TYPE_PCI;
+ Card.irq = byIRQ;
+ Card.reset_base = dwPLXIOBase;
+ Card.io_base = dwDivasIOBase;
+ Card.bus_num = byBus;
+ Card.func_num = byFunc;
+ Card.slot = -1;
+ Card.name[0] = 'D';
+ Card.name[1] = 'I';
+ Card.name[2] = 'V';
+ Card.name[3] = 'A';
+ Card.name[4] = 'S';
+ Card.name[5] = 'B';
+ Card.name[6] = '\0';
+
+ if (check_region(Card.io_base, 0x20))
+ {
+ printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F);
+ wDeviceIndex++;
+ continue;
+ }
+
+ if (check_region(Card.reset_base, 0x80))
+ {
+ printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F);
+ wDeviceIndex++;
+ continue;
+ }
+
+ if (DivasCardNew(&Card) != 0)
+ {
+ wDeviceIndex++;
+ continue;
+ }
+ wNumCards++;
+ }
+
+ wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI,
+ HW_ID_DIVA_SERVER_B_U,
+ wDeviceIndex,
+ &byBus, &byFunc);
+
+ if (wPCIConsultation == PCIBIOS_SUCCESSFUL)
+ {
+ dword dwPLXIOBase, dwDivasIOBase;
+ byte byIRQ;
+
+ printk(KERN_DEBUG "Divas: DIVA Server BRI (U) Found\n");
+
+ pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase);
+ dwPLXIOBase &= 0xFFFFFF80;
+
+ pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase);
+ dwDivasIOBase &= 0xFFFFFFFC;
+
+ pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+
+ Card.card_id = wNumCards;
+ Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B;
+ Card.bus_type = DIA_BUS_TYPE_PCI;
+ Card.irq = byIRQ;
+ Card.reset_base = dwPLXIOBase;
+ Card.io_base = dwDivasIOBase;
+ Card.bus_num = byBus;
+ Card.func_num = byFunc;
+ Card.slot = -1;
+ Card.name[0] = 'D';
+ Card.name[1] = 'I';
+ Card.name[2] = 'V';
+ Card.name[3] = 'A';
+ Card.name[4] = 'S';
+ Card.name[5] = 'B';
+ Card.name[6] = '\0';
+
+ if (check_region(Card.io_base, 0x20))
+ {
+ printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F);
+ wDeviceIndex++;
+ continue;
+ }
+
+ if (check_region(Card.reset_base, 0x80))
+ {
+ printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F);
+ wDeviceIndex++;
+ continue;
+ }
+
+ if (DivasCardNew(&Card) != 0)
+ {
+ wDeviceIndex++;
+ continue;
+ }
+ wNumCards++;
+ }
+
+ wDeviceIndex++;
+ }
+
+ wDeviceIndex = 0;
+
+ while (wDeviceIndex < 10)
+ {
+ wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI,
+ HW_ID_DIVA_SERVER_P,
+ wDeviceIndex,
+ &byBus, &byFunc);
+
+ if (wPCIConsultation == PCIBIOS_SUCCESSFUL)
+ {
+ dword dwRAM, dwREG, dwCFG;
+ byte byIRQ;
+
+ printk(KERN_DEBUG "Divas: DIVA Server PRI Found\n");
+
+ pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0, (unsigned int *) &dwRAM);
+ dwRAM &= 0xFFFFF000;
+
+ pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwREG);
+ dwREG &= 0xFFFFF000;
+
+ pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_4, (unsigned int *) &dwCFG);
+ dwCFG &= 0xFFFFF000;
+
+ pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+
+ Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x10000);
+ Card.memory[DIVAS_REG_MEMORY] = ioremap(dwREG, 0x4000);
+ Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x1000);
+ Card.memory[DIVAS_SHARED_MEMORY] = Card.memory[DIVAS_RAM_MEMORY] + DIVAS_SHARED_OFFSET;
+
+/* pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase);
+ dwPLXIOBase &= 0xFFFFFFFc;
+
+ pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase);
+ dwDivasIOBase &= 0xFFFFFF80;
+
+ pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+*/
+ Card.card_id = wNumCards;
+ Card.card_type = DIA_CARD_TYPE_DIVA_SERVER;
+ Card.bus_type = DIA_BUS_TYPE_PCI;
+ Card.irq = byIRQ;
+/* Card.reset_base = dwPLXIOBase;
+ Card.io_base = dwDivasIOBase;*/
+ Card.bus_num = byBus;
+ Card.func_num = byFunc;
+ Card.slot = -1;
+ Card.name[0] = 'D';
+ Card.name[1] = 'I';
+ Card.name[2] = 'V';
+ Card.name[3] = 'A';
+ Card.name[4] = 'S';
+ Card.name[5] = 'P';
+ Card.name[6] = '\0';
+
+ if (DivasCardNew(&Card) != 0)
+ {
+ wDeviceIndex++;
+ continue;
+ }
+ wNumCards++;
+ }
+
+ wDeviceIndex++;
+ }
+
+
+ printk(KERN_INFO "Divas: %d cards detected\n", wNumCards);
+
+ if(wNumCards == 0)
+ {
+ return -1;
+ }
+
+ Divas_fops.ioctl = do_ioctl;
+ Divas_fops.poll = do_poll;
+ Divas_fops.read = do_read;
+ Divas_fops.open = do_open;
+ Divas_fops.release = do_release;
+
+ Divas_major = register_chrdev(0, "Divas", &Divas_fops);
+
+ if (Divas_major < 0)
+ {
+ printk(KERN_WARNING "Divas: Unable to register character driver\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Error return -1 */
+int DivasConfigGet(dia_card_t *card)
+{
+ /* Retrieve Config from O/S? Not in Linux */
+ return 0;
+}
+
+dia_config_t *DivasConfig(card_t *card, dia_config_t *config)
+{
+ /* If config retrieved from OS then copy the data into a dia_config_t structure here
+ and return the pointer here. If the config 'came from above' then just
+
+ return config;
+ */
+
+ return config;
+}
+
diff --git a/drivers/isdn/eicon/linchr.c b/drivers/isdn/eicon/linchr.c
new file mode 100644
index 000000000..782429523
--- /dev/null
+++ b/drivers/isdn/eicon/linchr.c
@@ -0,0 +1,274 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.12
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/malloc.h>
+
+#undef N_DATA
+
+#include "adapter.h"
+#include "divas.h"
+#include "divalog.h"
+
+extern int DivasCardNext;
+void UxPause(long ms);
+void bcopy(void *pSource, void *pDest, dword dwLength);
+int DivasGetMem(mem_block_t *);
+
+#define DIA_IOCTL_UNLOCK 12
+void UnlockDivas(void);
+
+int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile,
+ unsigned int command, unsigned long arg)
+{
+ dia_load_t *pDivaLoad;
+ dia_start_t *pDivaStart;
+ dia_config_t *pDivaConfig;
+ dia_log_t *pDivaLog;
+ byte *pUserCards, card_i;
+ word wCardNum;
+ mem_block_t *mem_block;
+
+ switch (command)
+ {
+ case DIA_IOCTL_CONFIG:
+ pDivaConfig = (dia_config_t *) arg;
+
+ if (!verify_area(VERIFY_READ, pDivaConfig, sizeof(dia_config_t)))
+ {
+ DivasCardConfig(pDivaConfig);
+ }
+ else
+ {
+ printk(KERN_WARNING "Divas: Unable to complete CONFIG ioctl (verify area failed)\n");
+ return -1;
+ }
+ return 0;
+
+ case DIA_IOCTL_DETECT:
+ pUserCards = (byte *) arg;
+
+ if (!verify_area(VERIFY_WRITE, pUserCards, 20))
+ {
+ put_user(DivasCardNext, pUserCards++);
+
+ for (card_i=1; card_i < 20; card_i++)
+ {
+ put_user((byte) DivasCards[card_i - 1].cfg.card_type, pUserCards++);
+ }
+ }
+ else
+ {
+ printk(KERN_WARNING "Divas: Unable to complete DETECT ioctl (verify area failed)\n");
+ return -1;
+ }
+ return 0;
+
+ case DIA_IOCTL_START:
+ pDivaStart = (dia_start_t *) arg;
+
+ if (!verify_area(VERIFY_READ, pDivaStart, sizeof(dia_start_t)))
+ {
+ return DivasCardStart(pDivaStart->card_id);
+ }
+ else
+ {
+ printk(KERN_WARNING "Divas: Unable to complete START ioctl (verify area failed)\n");
+ return -1;
+ }
+
+
+ case DIA_IOCTL_FLAVOUR:
+ return 0;
+
+ case DIA_IOCTL_LOAD:
+ pDivaLoad = (dia_load_t *) arg;
+ if (!verify_area(VERIFY_READ, pDivaLoad->code,pDivaLoad->length))
+ {
+ if (DivasCardLoad(pDivaLoad))
+ {
+ printk(KERN_WARNING "Divas: Error loading DIVA Server adapter\n");
+ return -EINVAL;
+ }
+ }
+ else
+ {
+ printk(KERN_WARNING "Divas: Error in LOAD parameters (verify failed)\n");
+ return -EINVAL;
+ }
+ return 0;
+
+ case DIA_IOCTL_LOG:
+ pDivaLog = (dia_log_t *) arg;
+
+ if (!verify_area(VERIFY_READ, pDivaLog, sizeof(dia_log_t)))
+ {
+ DivasLog(pDivaLog);
+ }
+ else
+ {
+ printk(KERN_WARNING "Divas: Unable to complete LOG ioctl (verify area failed)\n");
+ return -1;
+ }
+ return 0;
+
+ case DIA_IOCTL_XLOG_REQ:
+
+ if (!verify_area(VERIFY_READ, (void *)arg, sizeof(word)))
+ {
+ wCardNum = * (word *) arg;
+ DivasXlogReq(wCardNum);
+ }
+ else
+ {
+ printk(KERN_WARNING "Divas: Unable to complete XLOG_REQ ioctl (verify area failed)\n");
+ return -1;
+ }
+ return 0;
+
+ case DIA_IOCTL_GET_NUM:
+
+ if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(int)))
+ {
+ * (int *) arg = DivasCardNext;
+ }
+ else
+ {
+ printk(KERN_WARNING "Divas: Unable to complete GET_NUM ioctl (verify area failed)\n");
+ return -1;
+ }
+ return 0;
+
+ case DIA_IOCTL_GET_LIST:
+ DPRINTF(("divas: DIA_IOCTL_GET_LIST"));
+
+ if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(dia_card_list_t)))
+ {
+ DivasGetList((dia_card_list_t *)arg);
+ }
+ else
+ {
+ printk(KERN_WARNING "Divas: Unable to complete GET_LIST ioctl (verify area failed)\n");
+ return -1;
+ }
+ return 0;
+
+ case DIA_IOCTL_GET_MEM:
+ mem_block = (mem_block_t *) arg;
+
+ if (!verify_area(VERIFY_WRITE, mem_block, sizeof(mem_block_t)))
+ {
+ DivasGetMem(mem_block);
+ }
+ else
+ {
+ printk(KERN_WARNING "Divas: Unable to complete GET_MEM ioctl (verify area failed)\n");
+ return -1;
+ }
+ return 0;
+
+ case DIA_IOCTL_UNLOCK:
+ UnlockDivas();
+ return 0;
+
+ default:
+ printk(KERN_WARNING "Divas: Unknown IOCTL Received by DIVA Server Driver(%d)\n", command);
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+
+unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable)
+{
+ word wMask = 0;
+
+ if (!DivasLogFifoEmpty())
+ {
+ wMask |= POLLIN | POLLRDNORM;
+ }
+
+ return wMask;
+}
+
+ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset)
+{
+ klog_t *pClientLogBuffer = (klog_t *) pUserBuffer;
+ klog_t *pHeadItem;
+
+ if (BufferSize < sizeof(klog_t))
+ {
+ printk(KERN_WARNING "Divas: Divalog buffer specifed a size that is too small (%d - %d required)\n",
+ BufferSize, sizeof(klog_t));
+ return 0;
+ }
+
+ pHeadItem = (klog_t *) DivasLogFifoRead();
+
+ if (pHeadItem)
+ {
+ bcopy(pHeadItem, pClientLogBuffer, sizeof(klog_t));
+ kfree(pHeadItem);
+ return sizeof(klog_t);
+ }
+
+ return 0;
+}
+int private_usage_count;
+extern void mod_inc_use_count(void);
+extern void mod_dec_use_count(void);
+
+int do_open(struct inode *pInode, struct file *pFile)
+{
+#if defined(MODULE)
+ mod_inc_use_count();
+ private_usage_count++;
+#endif
+ return 0;
+}
+
+int do_release(struct inode *pInode, struct file *pFile)
+{
+#if defined(MODULE)
+ mod_dec_use_count();
+ private_usage_count--;
+#endif
+ return 0;
+}
+
+void UnlockDivas(void)
+{
+ while (private_usage_count > 0)
+ {
+ private_usage_count--;
+#if defined(MODULE)
+ mod_dec_use_count();
+#endif
+ }
+}
diff --git a/drivers/isdn/eicon/linio.c b/drivers/isdn/eicon/linio.c
new file mode 100644
index 000000000..74c599069
--- /dev/null
+++ b/drivers/isdn/eicon/linio.c
@@ -0,0 +1,750 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.16
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#define N_DATA
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/malloc.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#undef N_DATA
+
+#include "uxio.h"
+
+static
+int log_on=0;
+
+int Divasdevflag = 0;
+
+//spinlock_t diva_lock = SPIN_LOCK_UNLOCKED;
+
+static
+ux_diva_card_t card_pool[MAX_CARDS];
+
+void UxPause(long int ms)
+{
+ int timeout = jiffies + ((ms * HZ) / 1000);
+
+ while (time_before(jiffies, timeout));
+}
+
+int UxCardHandleGet(ux_diva_card_t **card, dia_card_t *cfg)
+{
+ int i;
+ ux_diva_card_t *c;
+
+ if (cfg->bus_type != DIA_BUS_TYPE_PCI)
+ {
+ DPRINTF(("divas hw: type not PCI (%d)", cfg->bus_type));
+ return -1;
+ }
+
+ for (i = 0; (i < DIM(card_pool)) && (card_pool[i].in_use); i++)
+ {
+ ;
+ }
+
+ if (i == DIM(card_pool))
+ {
+ DPRINTF(("divas hw: card_pool exhausted"));
+ return -1;
+ }
+
+ c = *card = &card_pool[i];
+
+ switch (cfg->bus_type)
+ {
+ case DIA_BUS_TYPE_PCI:
+ c->bus_num = cfg->bus_num;
+ c->func_num = cfg->func_num;
+ c->io_base = cfg->io_base;
+ c->reset_base = cfg->reset_base;
+ c->card_type = cfg->card_type;
+ c->mapped = NULL;
+ c->slot = cfg->slot;
+ c->irq = (int) cfg->irq;
+ c->pDRAM = cfg->memory[DIVAS_RAM_MEMORY];
+ c->pDEVICES = cfg->memory[DIVAS_REG_MEMORY];
+ c->pCONFIG = cfg->memory[DIVAS_CFG_MEMORY];
+ c->pSHARED = cfg->memory[DIVAS_SHARED_MEMORY];
+ c->pCONTROL = cfg->memory[DIVAS_CTL_MEMORY];
+
+ /* c->bus_type = DIA_BUS_TYPE_PCI;
+ c->bus_num = cfg->bus_num & 0x3f;
+ c->slot = cfg->slot;
+ c->irq = (int) cfg->irq;
+ c->int_priority = (int) cfg->int_priority;
+ c->card_type = cfg->card_type;
+ c->io_base = cfg->io_base;
+ c->reset_base = cfg->reset_base;
+ c->pDRAM = cfg->memory[DIVAS_RAM_MEMORY];
+ c->pDEVICES = cfg->memory[DIVAS_REG_MEMORY];
+ c->pCONFIG = cfg->memory[DIVAS_CFG_MEMORY];
+ c->pSHARED = cfg->memory[DIVAS_SHARED_MEMORY];
+ DPRINTF(("divas hw: pDRAM is 0x%x", c->pDRAM));
+ DPRINTF(("divas hw: pSHARED is 0x%x", c->pSHARED));
+ DPRINTF(("divas hw: pCONFIG is 0x%x", c->pCONFIG));
+ c->cm_key = cm_getbrdkey("Divas", cfg->card_id);*/
+ break;
+ default:
+ break;
+ }
+
+ c->in_use = TRUE;
+
+ return 0;
+}
+
+void UxCardHandleFree(ux_diva_card_t *card)
+{
+ card->in_use = FALSE;
+}
+
+
+#define PLX_IOBASE 0
+#define DIVAS_IOBASE 1
+void *UxCardMemAttach(ux_diva_card_t *card, int id)
+{
+ if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER)
+ {
+ switch (id)
+ {
+ case DIVAS_SHARED_MEMORY:
+ card->mapped = card->pSHARED;
+ return card->pSHARED;
+ break;
+ case DIVAS_RAM_MEMORY:
+ card->mapped = card->pDRAM;
+ return card->pDRAM;
+ break;
+ case DIVAS_REG_MEMORY:
+ card->mapped = card->pDEVICES;
+ return card->pDEVICES;
+ break;
+ case DIVAS_CFG_MEMORY:
+ card->mapped = card->pCONFIG;
+ return card->pCONFIG;
+ break;
+ default:
+ ASSERT(FALSE);
+ card->mapped = NULL;
+ return (void *) 0;
+ }
+ }
+ else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_B)
+ {
+ switch (id)
+ {
+ case PLX_IOBASE:
+ return (void *) card->reset_base;
+ break;
+ case DIVAS_IOBASE:
+ return (void *) card->io_base;
+ break;
+ default:
+ ASSERT(FALSE);
+ return 0;
+ }
+ }
+
+ else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q)
+ {
+ switch (id)
+ {
+ case DIVAS_SHARED_MEMORY:
+ card->mapped = card->pSHARED;
+ return card->pSHARED;
+ break;
+ case DIVAS_RAM_MEMORY:
+ card->mapped = card->pDRAM;
+ return card->pDRAM;
+ break;
+ case DIVAS_REG_MEMORY:
+ card->mapped = (void *) card->io_base;
+ return (void *) card->io_base;
+ break;
+ case DIVAS_CTL_MEMORY:
+ card->mapped = card->pCONTROL;
+ return card->pCONTROL;
+ break;
+ default:
+ // ASSERT(FALSE);
+ DPRINTF(("divas: Trying to attach to mem %d", id));
+ card->mapped = NULL;
+ return (void *) 0;
+ }
+ } else
+ DPRINTF(("divas: Tried to attach to unknown card"));
+
+ /* Unknown card type */
+ return NULL;
+}
+
+void UxCardMemDetach(ux_diva_card_t *card, void *address)
+{
+ return; // Just a place holder. No un-mapping done.
+}
+
+void UxCardLog(int turn_on)
+{
+ log_on = turn_on;
+}
+
+/*
+ * Control Register I/O Routines to be performed on Attached I/O ports
+ */
+
+void UxCardPortIoOut(ux_diva_card_t *card, void *AttachedBase, int offset, byte the_byte)
+{
+ word base = (word) (dword) AttachedBase;
+
+ base += offset;
+
+ outb(the_byte, base);
+}
+
+void UxCardPortIoOutW(ux_diva_card_t *card, void *AttachedBase, int offset, word the_word)
+{
+ word base = (word) (dword) AttachedBase;
+
+ base += offset;
+
+ outw(the_word, base);
+}
+
+void UxCardPortIoOutD(ux_diva_card_t *card, void *AttachedBase, int offset, dword the_dword)
+{
+ word base = (word) (dword) AttachedBase;
+
+ base += offset;
+
+ outl(the_dword, base);
+}
+
+byte UxCardPortIoIn(ux_diva_card_t *card, void *AttachedBase, int offset)
+{
+ word base = (word) (dword) AttachedBase;
+
+ base += offset;
+
+ return inb(base);
+}
+
+word UxCardPortIoInW(ux_diva_card_t *card, void *AttachedBase, int offset)
+{
+ word base = (word) (dword) AttachedBase;
+
+ base += offset;
+
+ return inw(base);
+}
+
+/*
+ * Memory mapped card I/O functions
+ */
+
+byte UxCardMemIn(ux_diva_card_t *card, void *address)
+{
+ byte b;
+ volatile byte* t = (byte*)address;
+
+ b = *t;
+
+ if (log_on)
+ {
+ byte *a = address;
+ a -= (int) card->mapped;
+ DPRINTF(("divas hw: read 0x%02x from 0x%x (memory mapped)", b & 0xff, a));
+ }
+
+ return(b);
+}
+
+word UxCardMemInW(ux_diva_card_t *card, void *address)
+{
+ word w;
+ volatile word* t = (word*)address;
+
+ w = *t;
+
+ if (log_on)
+ {
+ byte *a = address;
+ a -= (int) card->mapped;
+ DPRINTF(("divas hw: read 0x%04x from 0x%x (memory mapped)", w & 0xffff, a));
+ }
+
+ return (w);
+}
+
+dword UxCardMemInD(ux_diva_card_t *card, void *address)
+{
+ dword dw;
+ volatile dword* t = (dword*)address;
+
+ dw = *t;
+
+ if (log_on)
+ {
+ byte *a = address;
+ a -= (int) card->mapped;
+ DPRINTF(("divas hw: read 0x%08x from 0x%x (memory mapped)", dw, a));
+ }
+
+ return (dw);
+}
+
+void UxCardMemInBuffer(ux_diva_card_t *card, void *address, void *buffer, int length)
+{
+ volatile byte *pSource = address;
+ byte *pDest = buffer;
+
+ while (length--)
+ {
+ *pDest++ = *pSource++;
+ }
+
+ if (log_on)
+ {
+ byte *a = address;
+ a -= (int) card->mapped;
+ pDest = buffer;
+ DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (memory mapped)",
+ pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff,
+ pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff,
+ a));
+ }
+
+ return;
+}
+
+void UxCardMemOut(ux_diva_card_t *card, void *address, byte data)
+{
+ volatile byte* t = (byte*)address;
+
+ if (log_on)
+ {
+ byte *a = address;
+ a -= (int) card->mapped;
+ DPRINTF(("divas hw: wrote 0x%02x to 0x%x (memory mapped)", data & 0xff, a));
+ }
+
+ *t = data;
+
+ return;
+}
+
+void UxCardMemOutW(ux_diva_card_t *card, void *address, word data)
+{
+ volatile word* t = (word*)address;
+
+ if (log_on)
+ {
+ byte *a = address;
+ a -= (int) card->mapped;
+ DPRINTF(("divas hw: wrote 0x%04x to 0x%x (memory mapped)", data & 0xffff, a));
+ }
+
+ *t = data;
+ return;
+}
+
+void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data)
+{
+ volatile dword* t = (dword*)address;
+
+ if (log_on)
+ {
+ byte *a = address;
+ a -= (int) card->mapped;
+ DPRINTF(("divas hw: wrote 0x%08x to 0x%x (memory mapped)", data, a));
+ }
+
+ *t = data;
+ return;
+}
+
+void UxCardMemOutBuffer(ux_diva_card_t *card, void *address, void *buffer, int length)
+{
+ byte *pSource = buffer;
+ byte *pDest = address;
+
+ while (length--)
+ {
+ *pDest++ = *pSource++;
+ }
+
+ if (log_on)
+ {
+ byte *a = address;
+ a -= (int) card->mapped;
+ pDest = buffer;
+ DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (memory mapped)",
+ pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff,
+ pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff,
+ a));
+ }
+
+ return;
+}
+
+/*
+ * Memory mapped card I/O functions
+ */
+
+byte UxCardIoIn(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address)
+
+{
+ byte the_byte;
+
+ outb(0xFF, card->io_base + 0xC);
+ outw((word) (dword) address, card->io_base + 4);
+
+ the_byte = inb(card->io_base);
+
+ if (log_on)
+ {
+ DPRINTF(("divas hw: read 0x%02x from 0x%x (I/O mapped)",
+ the_byte & 0xff, address));
+ }
+
+ return the_byte;
+}
+
+word UxCardIoInW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address)
+
+{
+ word the_word;
+
+ outb(0xFF, card->io_base + 0xC);
+ outw((word) (dword) address, card->io_base + 4);
+ the_word = inw(card->io_base);
+
+ if (log_on)
+ {
+ DPRINTF(("divas hw: read 0x%04x from 0x%x (I/O mapped)",
+ the_word & 0xffff, address));
+ }
+
+ return the_word;
+}
+
+dword UxCardIoInD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address)
+
+{
+ dword the_dword;
+
+ outb(0xFF, card->io_base + 0xC);
+ outw((word) (dword) address, card->io_base + 4);
+ the_dword = inl(card->io_base);
+
+ if (log_on)
+ {
+ DPRINTF(("divas hw: read 0x%08x from 0x%x (I/O mapped)",
+ the_dword, address));
+ }
+
+ return the_dword;
+}
+
+void UxCardIoInBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length)
+
+{
+ byte *pSource = address;
+ byte *pDest = buffer;
+
+ if ((word) (dword) address & 0x1)
+ {
+ outb(0xFF, card->io_base + 0xC);
+ outw((word) (dword) pSource, card->io_base + 4);
+ *pDest = (byte) inb(card->io_base);
+ pDest++;
+ pSource++;
+ length--;
+ if (!length)
+ {
+ return;
+ }
+ }
+
+ outb(0xFF, card->io_base + 0xC);
+ outw((word) (dword) pSource, card->io_base + 4);
+ insw(card->io_base, (word *)pDest,length%2 ? (length+1)>>1 : length>>1);
+
+ if (log_on)
+ {
+ pDest = buffer;
+ DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (I/O mapped)",
+ pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff,
+ pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff,
+ address));
+ }
+
+ return;
+}
+
+/* Output */
+
+void UxCardIoOut(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, byte data)
+{
+ if (log_on)
+ {
+ DPRINTF(("divas hw: wrote 0x%02x to 0x%x (I/O mapped)",
+ data & 0xff, address));
+ }
+
+ outb(0xFF, card->io_base + 0xC);
+ outw((word) (dword) address, card->io_base + 4);
+ outb((byte) data & 0xFF, card->io_base);
+
+ return;
+}
+
+void UxCardIoOutW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, word data)
+{
+ if (log_on)
+ {
+ DPRINTF(("divas hw: wrote 0x%04x to 0x%x (I/O mapped)",
+ data & 0xffff, address));
+ }
+
+ outb(0xFF, card->io_base + 0xC);
+ outw((word) (dword) address, card->io_base + 4);
+ outw((word) data & 0xFFFF, card->io_base);
+
+ return;
+}
+
+void UxCardIoOutD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, dword data)
+{
+ if (log_on)
+ {
+ DPRINTF(("divas hw: wrote 0x%08x to 0x%x (I/O mapped)", data, address));
+ }
+
+ outb(0xFF, card->io_base + 0xC);
+ outw((word) (dword) address, card->io_base + 4);
+ outl((dword) data & 0xFFFFFFFF, card->io_base);
+
+ return;
+}
+
+void UxCardIoOutBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length)
+
+{
+ byte *pSource = buffer;
+ byte *pDest = address;
+
+ if ((word) (dword) address & 1)
+ {
+ outb(0xFF, card->io_base + 0xC);
+ outw((word) (dword) pDest, card->io_base + 4);
+ outb(*pSource, card->io_base);
+ pSource++;
+ pDest++;
+ length--;
+ if (!length)
+ {
+ return;
+ }
+ }
+
+ outb(0xFF, card->io_base + 0xC);
+ outw((word) (dword) pDest, card->io_base + 4);
+ outsw(card->io_base, (word *)pSource, length%2 ? (length+1)>>1 : length>>1);
+
+ if (log_on)
+ {
+ pDest = buffer;
+ DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (I/O mapped)",
+ pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff,
+ pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff,
+ address));
+ }
+
+ return;
+}
+
+void Divasintr(int arg, void *unused, struct pt_regs *unused_regs)
+{
+ int i;
+ card_t *card = NULL;
+ ux_diva_card_t *ux_ref = NULL;
+
+ for (i = 0; i < DivasCardNext; i++)
+ {
+
+ if (arg == DivasCards[i].cfg.irq)
+ {
+ card = &DivasCards[i];
+ ux_ref = card->hw;
+
+ if ((ux_ref) && (card->is_live))
+ {
+ (*ux_ref->user_isr)(ux_ref->user_isr_arg);
+ }
+ else
+ {
+ DPRINTF(("divas: ISR couldn't locate card"));
+ }
+ }
+ }
+
+ return;
+}
+
+
+int UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg)
+{
+ int result;
+
+ card->user_isr = isr_fn;
+ card->user_isr_arg = isr_arg;
+
+ result = request_irq(card->irq, Divasintr, SA_INTERRUPT | SA_SHIRQ, "Divas", (void *) isr_arg);
+
+ return result;
+}
+
+void UxIsrRemove(ux_diva_card_t *card, void *dev_id)
+{
+ free_irq(card->irq, card->user_isr_arg);
+}
+
+void UxPciConfigWrite(ux_diva_card_t *card, int size, int offset, void *value)
+{
+ switch (size)
+ {
+ case sizeof(byte):
+ pcibios_write_config_byte(card->bus_num, card->func_num, offset, * (byte *) value);
+ break;
+ case sizeof(word):
+ pcibios_write_config_word(card->bus_num, card->func_num, offset, * (word *) value);
+ break;
+ case sizeof(dword):
+ pcibios_write_config_dword(card->bus_num, card->func_num, offset, * (dword *) value);
+ break;
+ default:
+ printk(KERN_WARNING "Divas: Invalid size in UxPciConfigWrite\n");
+ }
+}
+
+void UxPciConfigRead(ux_diva_card_t *card, int size, int offset, void *value)
+{
+ switch (size)
+ {
+ case sizeof(byte):
+ pcibios_read_config_byte(card->bus_num, card->func_num, offset, (byte *) value);
+ break;
+ case sizeof(word):
+ pcibios_read_config_word(card->bus_num, card->func_num, offset, (word *) value);
+ break;
+ case sizeof(dword):
+ pcibios_read_config_dword(card->bus_num, card->func_num, offset, (unsigned int *) value);
+ break;
+ default:
+ printk(KERN_WARNING "Divas: Invalid size in UxPciConfigRead\n");
+ }
+}
+
+void *UxAlloc(unsigned int size)
+{
+ void *m;
+
+ m = kmalloc(size, GFP_ATOMIC);
+
+ return m;
+}
+
+void UxFree(void *ptr)
+{
+ kfree(ptr);
+}
+
+int UxCardLock(ux_diva_card_t *card)
+{
+ unsigned long flags;
+
+ //spin_lock_irqsave(&diva_lock, flags);
+
+ save_flags(flags);
+ cli();
+ return flags;
+
+}
+
+void UxCardUnlock(ux_diva_card_t *card, int ipl)
+{
+ //spin_unlock_irqrestore(&diva_lock, ipl);
+
+ restore_flags(ipl);
+
+}
+
+dword UxTimeGet(void)
+{
+ return jiffies;
+}
+
+long UxInterlockedIncrement(ux_diva_card_t *card, long *dst)
+{
+ register volatile long *p;
+ register long ret;
+ int ipl;
+
+ p =dst;
+
+ ipl = UxCardLock(card);
+
+ *p += 1;
+ ret = *p;
+
+ UxCardUnlock(card,ipl);
+
+ return(ret);
+
+}
+
+long UxInterlockedDecrement(ux_diva_card_t *card, long *dst)
+{
+ register volatile long *p;
+ register long ret;
+ int ipl;
+
+ p =dst;
+
+ ipl = UxCardLock(card);
+
+ *p -= 1;
+ ret = *p;
+
+ UxCardUnlock(card,ipl);
+
+ return(ret);
+
+}
diff --git a/drivers/isdn/eicon/linsys.c b/drivers/isdn/eicon/linsys.c
new file mode 100644
index 000000000..3f167ed7b
--- /dev/null
+++ b/drivers/isdn/eicon/linsys.c
@@ -0,0 +1,170 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.10
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include <linux/sched.h>
+#undef N_DATA
+#include <linux/tqueue.h>
+
+#include <linux/smp.h>
+struct pt_regs;
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include "sys.h"
+#include "divas.h"
+#include "adapter.h"
+#include "divalog.h"
+
+#include "uxio.h"
+
+#ifdef MODULE
+void bcopy(void *pSource, void *pDest, dword dwLength)
+{
+ memcpy(pDest, pSource, dwLength);
+}
+#endif
+
+void bzero(void *pDataArea, dword dwLength)
+{
+ memset(pDataArea, 0, dwLength);
+}
+
+int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg)
+{
+ /* Use UxPciConfigWrite routines to initialise PCI config space */
+
+/* wPCIcommand = 0x03;
+ cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand);
+
+ wPCIcommand = 0x280;
+ cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand);
+
+ bPCIcommand = 0x30;
+ cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand);
+*/
+ return 0;
+}
+
+int DivasPRIInitPCI(card_t *card, dia_card_t *cfg)
+{
+ /* Use UxPciConfigWrite routines to initialise PCI config space */
+
+/* wPCIcommand = 0x03;
+ cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand);
+
+ wPCIcommand = 0x280;
+ cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand);
+
+ bPCIcommand = 0x30;
+ cm_write_devconfig8(CMKey, PCI_LATENCY, &bPCIcommand);*/
+
+ return 0;
+}
+
+int DivasBRIInitPCI(card_t *card, dia_card_t *cfg)
+{
+ /* Need to set these platform dependent values after patching */
+
+ card->hw->reset_base = card->cfg.reset_base;
+ card->hw->io_base = card->cfg.io_base;
+
+ request_region(card->hw->reset_base,0x80,"Divas");
+ request_region(card->hw->io_base,0x20,"Divas");
+
+
+ /* Same as for PRI */
+ return DivasPRIInitPCI(card, cfg);
+}
+
+/* ######################### Stubs of routines that are not done yet ################## */
+/*void DivasLogIdi(card_t *card, ENTITY *e, int request)
+{
+}
+*/
+
+int DivasDpcSchedule(void)
+{
+ static struct tq_struct DivasTask;
+
+ DivasTask.routine = DivasDoDpc;
+ DivasTask.data = (void *) 0;
+
+ queue_task(&DivasTask, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+
+ return 0;
+}
+
+int DivasScheduleRequestDpc(void)
+{
+ static struct tq_struct DivasTask;
+
+ DivasTask.routine = DivasDoRequestDpc;
+ DivasTask.data = (void *) 0;
+
+ queue_task(&DivasTask, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+
+ return 0;
+}
+
+void DivasLogAdd(void *buffer, int length)
+{
+ static
+ boolean_t overflow = FALSE;
+ static
+ boolean_t busy = FALSE;
+
+ /* make sure we're not interrupting ourselves */
+
+ if (busy)
+ {
+ printk(KERN_DEBUG "Divas: Logging interrupting self !\n");
+ return;
+ }
+ busy = TRUE;
+
+ /* ignore call if daemon isn't running and we've reached limit */
+
+ if (DivasLogFifoFull())
+ {
+ if (!overflow)
+ {
+ printk(KERN_DEBUG "Divas: Trace buffer full\n");
+ overflow = TRUE;
+ }
+ busy = FALSE;
+ return;
+ }
+
+ DivasLogFifoWrite(buffer, length);
+
+ busy = FALSE;
+ return;
+}
+
+/* #################################################################################### */
diff --git a/drivers/isdn/eicon/log.c b/drivers/isdn/eicon/log.c
new file mode 100644
index 000000000..1d847f0a8
--- /dev/null
+++ b/drivers/isdn/eicon/log.c
@@ -0,0 +1,179 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.5
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/*
+ * Source file for diva log facility
+ */
+
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#include "adapter.h"
+#include "divalog.h"
+
+#include "uxio.h"
+
+/*Counter to monitor number of messages */
+static int m_count;
+
+#define MAX_BUFFERED_MSGS (1000)
+
+/* Our Linked List Structure to hold message */
+typedef struct klog_link{
+ klog_t klog;
+ struct klog_link *next;
+}KNODE;
+
+/* First & Last structures in list*/
+KNODE *head;
+KNODE *tail;
+
+/*
+ * retrieve message from FIFO buffer
+ * returns NULL if buffer empty
+ * otherwise returns pointer to entry
+ */
+
+char *DivasLogFifoRead(void)
+
+{
+ KNODE *old_head;
+
+ if(head==NULL)
+ {
+ /* Buffer Empty - No Messages */
+ return NULL;
+ }
+
+ m_count--;
+ /* Keep track of message to be read & increment to next message*/
+ old_head = head;
+ head = head->next;
+ /*Return ptr to Msg */
+ return((char *)old_head);
+}
+
+/*
+ * write message into FIFO buffer
+ */
+
+void DivasLogFifoWrite(char *entry, int length)
+
+{
+ KNODE *new_klog;
+
+ if(head == NULL)
+ {
+ /* No Entries in Log */
+ tail=NULL;
+ m_count=0;
+ new_klog=UxAlloc(sizeof(KNODE));
+
+ if(new_klog==NULL)
+ {
+ return;
+ }
+
+ m_count++;
+ bzero(new_klog,sizeof(KNODE));
+
+ /* Set head & tail to point to the new Msg Struct */
+ head=tail=new_klog;
+ tail->next=NULL;
+ }
+ else
+ {
+ new_klog=UxAlloc(sizeof(KNODE));
+
+ if(new_klog==NULL)
+ {
+ return;
+ }
+
+ m_count++;
+ bzero(new_klog,sizeof(KNODE));
+
+ /* Let last Msg Struct point to new Msg Struct & inc tail */
+ tail->next=new_klog;
+ tail=new_klog;
+ tail->next=NULL;
+ }
+
+ if (length > sizeof(klog_t))
+ {
+ length = sizeof(klog_t);
+ }
+
+ bcopy(entry,&tail->klog,length);
+
+ return;
+}
+
+/*
+ * DivaslogFifoEmpty:return TRUE if FIFO buffer is empty,otherwise FALSE
+ */
+int DivasLogFifoEmpty(void)
+{
+ return (m_count == 0);
+}
+
+/*
+ *DivasLogFifoFull:return TRUE if FIFO buffer is full,otherwise FALSE
+ */
+int DivasLogFifoFull(void)
+{
+ return (m_count == MAX_BUFFERED_MSGS);
+}
+
+/*
+ * generate an IDI log entry
+ */
+
+void DivasLogIdi(card_t *card, ENTITY *e, int request)
+
+{
+ klog_t klog;
+
+ bzero(&klog, sizeof(klog));
+
+ klog.time_stamp = UxTimeGet();
+
+ klog.length = sizeof(ENTITY) > sizeof(klog.buffer) ?
+ sizeof(klog.buffer) : sizeof(ENTITY);
+
+ klog.card = (int) (card - DivasCards);
+
+ klog.type = request ? KLOG_IDI_REQ : KLOG_IDI_CALLBACK;
+ klog.code = 0;
+ bcopy(e, klog.buffer, klog.length);
+
+ /* send to the log driver and return */
+
+ DivasLogAdd(&klog, sizeof(klog));
+
+ return;
+}
diff --git a/drivers/isdn/eicon/md5sums.asc b/drivers/isdn/eicon/md5sums.asc
new file mode 100644
index 000000000..aa1cd9065
--- /dev/null
+++ b/drivers/isdn/eicon/md5sums.asc
@@ -0,0 +1,16 @@
+# These are valid md5sums to detect modifications
+# in eicon driver files provided by Eicon Technology.
+# For changes and modifications in these files please
+# read ../../../Documentation/isdn/README.eicon
+#
+9b0e381d4558af3a6eba66843e1ee5d9 common.c
+dbb92cba52db31ff8325a252b3f595c3 idi.c
+15687687ef82f099966ed42772001cd3 bri.c
+c3e3b720c3351b66635bd548195e29e8 pri.c
+b0a6d2ab49bcfcfd1825860f178a84b4 log.c
+673746176316b72271a09c0a27287a01 xlog.c
+07e1bbabdb4d69880db196ef31bfb241 kprintf.c
+b60b40ad630f26b7923369df95b4d1b9 fpga.c
+5013ecca0a38a8fcc4a61642754f2076 fourbri.c
+1501ae468a0c5eaab1e60720fa723a67 fcheck.c
+# end of md5sums
diff --git a/drivers/isdn/eicon/pc.h b/drivers/isdn/eicon/pc.h
new file mode 100644
index 000000000..412a61faa
--- /dev/null
+++ b/drivers/isdn/eicon/pc.h
@@ -0,0 +1,320 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#ifndef PC_H_INCLUDED
+#define PC_H_INCLUDED
+
+
+#define byte unsigned char
+#define word unsigned short
+#define dword unsigned long
+#if !defined(MIN)
+#define MIN(a,b) ((a)>(b) ? (b) : (a))
+#endif
+#if !defined(MAX)
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#endif
+
+/*------------------------------------------------------------------*/
+/* buffer definition */
+/*------------------------------------------------------------------*/
+
+typedef struct {
+ word length; /* length of data/parameter field */
+ byte P[270]; /* data/parameter field */
+} PBUFFER;
+
+/*------------------------------------------------------------------*/
+/* dual port ram structure */
+/*------------------------------------------------------------------*/
+
+struct dual
+{
+ byte Req; /* request register */
+ byte ReqId; /* request task/entity identification */
+ byte Rc; /* return code register */
+ byte RcId; /* return code task/entity identification */
+ byte Ind; /* Indication register */
+ byte IndId; /* Indication task/entity identification */
+ byte IMask; /* Interrupt Mask Flag */
+ byte RNR; /* Receiver Not Ready (set by PC) */
+ byte XLock; /* XBuffer locked Flag */
+ byte Int; /* ISDN-S interrupt */
+ byte ReqCh; /* Channel field for layer-3 Requests */
+ byte RcCh; /* Channel field for layer-3 Returncodes */
+ byte IndCh; /* Channel field for layer-3 Indications */
+ byte MInd; /* more data indication field */
+ word MLength; /* more data total packet length */
+ byte ReadyInt; /* request field for ready interrupt */
+ byte SWReg; /* Software register for special purposes */
+ byte Reserved[11]; /* reserved space */
+ byte InterfaceType; /* interface type 1=16K interface */
+ word Signature; /* ISDN-S adapter Signature (GD) */
+ PBUFFER XBuffer; /* Transmit Buffer */
+ PBUFFER RBuffer; /* Receive Buffer */
+};
+
+/*------------------------------------------------------------------*/
+/* SWReg Values (0 means no command) */
+/*------------------------------------------------------------------*/
+#define SWREG_DIE_WITH_LEDON 0x01
+#define SWREG_HALT_CPU 0x02 /* Push CPU into a while(1) loop */
+
+/*------------------------------------------------------------------*/
+/* Id Fields Coding */
+/*------------------------------------------------------------------*/
+
+#define ID_MASK 0xe0 /* Mask for the ID field */
+#define GL_ERR_ID 0x1f /* ID for error reporting on global requests*/
+
+#define DSIG_ID 0x00 /* ID for D-channel signaling */
+#define NL_ID 0x20 /* ID for network-layer access (B or D) */
+#define BLLC_ID 0x60 /* ID for B-channel link level access */
+#define TASK_ID 0x80 /* ID for dynamic user tasks */
+#define TIMER_ID 0xa0 /* ID for timer task */
+#define TEL_ID 0xc0 /* ID for telephone support */
+#define MAN_ID 0xe0 /* ID for management */
+
+/*------------------------------------------------------------------*/
+/* ASSIGN and REMOVE requests are the same for all entities */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN 0x01
+#define UREMOVE 0xfe /* without returncode */
+#define REMOVE 0xff
+
+/*------------------------------------------------------------------*/
+/* Timer Interrupt Task Interface */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN_TIM 0x01
+#define REMOVE_TIM 0xff
+
+/*------------------------------------------------------------------*/
+/* dynamic user task interface */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN_TSK 0x01
+#define REMOVE_TSK 0xff
+
+#define LOAD 0xf0
+#define RELOCATE 0xf1
+#define START 0xf2
+#define LOAD2 0xf3
+#define RELOCATE2 0xf4
+
+/*------------------------------------------------------------------*/
+/* dynamic user task messages */
+/*------------------------------------------------------------------*/
+
+#define TSK_B2 0x0000
+#define TSK_WAKEUP 0x2000
+#define TSK_TIMER 0x4000
+#define TSK_TSK 0x6000
+#define TSK_PC 0xe000
+
+/*------------------------------------------------------------------*/
+/* LL management primitives */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN_LL 1 /* assign logical link */
+#define REMOVE_LL 0xff /* remove logical link */
+
+/*------------------------------------------------------------------*/
+/* LL service primitives */
+/*------------------------------------------------------------------*/
+
+#define LL_UDATA 1 /* link unit data request/indication */
+#define LL_ESTABLISH 2 /* link establish request/indication */
+#define LL_RELEASE 3 /* link release request/indication */
+#define LL_DATA 4 /* data request/indication */
+#define LL_LOCAL 5 /* switch to local operation (COM only) */
+#define LL_DATA_PEND 5 /* data pending indication (SDLC SHM only) */
+#define LL_REMOTE 6 /* switch to remote operation (COM only) */
+#define LL_TEST 8 /* link test request */
+#define LL_MDATA 9 /* more data request/indication */
+#define LL_BUDATA 10 /* broadcast unit data request/indication */
+#define LL_XID 12 /* XID command request/indication */
+#define LL_XID_R 13 /* XID response request/indication */
+
+/*------------------------------------------------------------------*/
+/* NL service primitives */
+/*------------------------------------------------------------------*/
+
+#define N_MDATA 1 /* more data to come REQ/IND */
+#define N_CONNECT 2 /* OSI N-CONNECT REQ/IND */
+#define N_CONNECT_ACK 3 /* OSI N-CONNECT CON/RES */
+#define N_DISC 4 /* OSI N-DISC REQ/IND */
+#define N_DISC_ACK 5 /* OSI N-DISC CON/RES */
+#define N_RESET 6 /* OSI N-RESET REQ/IND */
+#define N_RESET_ACK 7 /* OSI N-RESET CON/RES */
+#define N_DATA 8 /* OSI N-DATA REQ/IND */
+#define N_EDATA 9 /* OSI N-EXPEDITED DATA REQ/IND */
+#define N_UDATA 10 /* OSI D-UNIT-DATA REQ/IND */
+#define N_BDATA 11 /* BROADCAST-DATA REQ/IND */
+#define N_DATA_ACK 12 /* data ack ind for D-bit procedure */
+#define N_EDATA_ACK 13 /* data ack ind for INTERRUPT */
+
+#define N_Q_BIT 0x10 /* Q-bit for req/ind */
+#define N_M_BIT 0x20 /* M-bit for req/ind */
+#define N_D_BIT 0x40 /* D-bit for req/ind */
+
+/*------------------------------------------------------------------*/
+/* Signaling management primitives */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN_SIG 1 /* assign signaling task */
+#define UREMOVE_SIG 0xfe /* remove signaling task without returncode */
+#define REMOVE_SIG 0xff /* remove signaling task */
+
+/*------------------------------------------------------------------*/
+/* Signaling service primitives */
+/*------------------------------------------------------------------*/
+
+#define CALL_REQ 1 /* call request */
+#define CALL_CON 1 /* call confirmation */
+#define CALL_IND 2 /* incoming call connected */
+#define LISTEN_REQ 2 /* listen request */
+#define HANGUP 3 /* hangup request/indication */
+#define SUSPEND 4 /* call suspend request/confirm */
+#define RESUME 5 /* call resume request/confirm */
+#define SUSPEND_REJ 6 /* suspend rejected indication */
+#define USER_DATA 8 /* user data for user to user signaling */
+#define CONGESTION 9 /* network congestion indication */
+#define INDICATE_REQ 10 /* request to indicate an incoming call */
+#define INDICATE_IND 10 /* indicates that there is an incoming call */
+#define CALL_RES 11 /* accept an incoming call */
+#define CALL_ALERT 12 /* send ALERT for incoming call */
+#define INFO_REQ 13 /* INFO request */
+#define INFO_IND 13 /* INFO indication */
+#define REJECT 14 /* reject an incoming call */
+#define RESOURCES 15 /* reserve B-Channel hardware resources */
+#define TEL_CTRL 16 /* Telephone control request/indication */
+#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */
+#define FAC_REG_REQ 18 /* connection idependent fac registration */
+#define FAC_REG_ACK 19 /* fac registration acknowledge */
+#define FAC_REG_REJ 20 /* fac registration reject */
+#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */
+#define FACILITY_REQ 22 /* send a Facility Message type */
+#define FACILITY_IND 22 /* Facility Message type indication */
+#define SIG_CTRL 29 /* Control for signalling hardware */
+#define DSP_CTRL 30 /* Control for DSPs */
+#define LAW_REQ 31 /* Law config request for (returns info_i) */
+
+
+/*------------------------------------------------------------------*/
+/* management service primitives */
+/*------------------------------------------------------------------*/
+
+#define MAN_READ 2
+#define MAN_WRITE 3
+#define MAN_EXECUTE 4
+#define MAN_EVENT_ON 5
+#define MAN_EVENT_OFF 6
+#define MAN_LOCK 7
+#define MAN_UNLOCK 8
+
+#define MAN_INFO_IND 2
+#define MAN_EVENT_IND 3
+#define MAN_TRACE_IND 4
+
+#define MAN_ESC 0x80
+
+/*------------------------------------------------------------------*/
+/* return code coding */
+/*------------------------------------------------------------------*/
+
+#define UNKNOWN_COMMAND 0x01 /* unknown command */
+#define WRONG_COMMAND 0x02 /* wrong command */
+#define WRONG_ID 0x03 /* unknown task/entity id */
+#define WRONG_CH 0x04 /* wrong task/entity id */
+#define UNKNOWN_IE 0x05 /* unknown information el. */
+#define WRONG_IE 0x06 /* wrong information el. */
+#define OUT_OF_RESOURCES 0x07 /* ISDN-S card out of res. */
+#define ADAPTER_DEAD 0x08 /* ISDN card CPU halted */
+#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */
+#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */
+#define ASSIGN_OK 0xef /* ASSIGN OK */
+#define OK_FC 0xfc /* Flow-Control RC */
+#define READY_INT 0xfd /* Ready interrupt */
+#define TIMER_INT 0xfe /* timer interrupt */
+#define OK 0xff /* command accepted */
+
+/*------------------------------------------------------------------*/
+/* information elements */
+/*------------------------------------------------------------------*/
+
+#define SHIFT 0x90 /* codeset shift */
+#define MORE 0xa0 /* more data */
+#define CL 0xb0 /* congestion level */
+
+ /* codeset 0 */
+
+#define BC 0x04 /* Bearer Capability */
+#define CAU 0x08 /* cause */
+#define CAD 0x0c /* Connected address */
+#define CAI 0x10 /* call identity */
+#define CHI 0x18 /* channel identification */
+#define LLI 0x19 /* logical link id */
+#define CHA 0x1a /* charge advice */
+#define DT 0x29 /* ETSI date/time */
+#define KEY 0x2c /* keypad information element */
+#define FTY 0x1c /* facility information element */
+#define DSP 0x28 /* display */
+#define OAD 0x6c /* origination address */
+#define OSA 0x6d /* origination sub-address */
+#define CPN 0x70 /* called party number */
+#define DSA 0x71 /* destination sub-address */
+#define RDX 0x73 /* redirected number extended */
+#define RDN 0x74 /* redirected number */
+#define LLC 0x7c /* low layer compatibility */
+#define HLC 0x7d /* high layer compatibility */
+#define UUI 0x7e /* user user information */
+#define ESC 0x7f /* escape extension */
+
+#define DLC 0x20 /* data link layer configuration */
+#define NLC 0x21 /* network layer configuration */
+
+ /* codeset 6 */
+
+#define SIN 0x01 /* service indicator */
+#define CIF 0x02 /* charging information */
+#define DATE 0x03 /* date */
+#define CPS 0x07 /* called party status */
+
+/*------------------------------------------------------------------*/
+/* TEL_CTRL contents */
+/*------------------------------------------------------------------*/
+
+#define RING_ON 0x01
+#define RING_OFF 0x02
+#define HANDS_FREE_ON 0x03
+#define HANDS_FREE_OFF 0x04
+#define ON_HOOK 0x80
+#define OFF_HOOK 0x90
+
+#endif
diff --git a/drivers/isdn/eicon/pc_maint.h b/drivers/isdn/eicon/pc_maint.h
new file mode 100644
index 000000000..e6e902f00
--- /dev/null
+++ b/drivers/isdn/eicon/pc_maint.h
@@ -0,0 +1,165 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#ifndef PC_MAINT_H
+#define PC_MAINT_H
+
+#if !defined(MIPS_SCOM)
+#define BUFFER_SZ 48
+#define MAINT_OFFS 0x380
+#else
+#define BUFFER_SZ 128
+#define MAINT_OFFS 0xff00
+#endif
+
+#define MIPS_BUFFER_SZ 128
+#define MIPS_MAINT_OFFS 0xff00
+
+#define DO_LOG 1
+#define MEMR 2
+#define MEMW 3
+#define IOR 4
+#define IOW 5
+#define B1TEST 6
+#define B2TEST 7
+#define BTESTOFF 8
+#define DSIG_STATS 9
+#define B_CH_STATS 10
+#define D_CH_STATS 11
+#define BL1_STATS 12
+#define BL1_STATS_C 13
+#define GET_VERSION 14
+#define OS_STATS 15
+#define XLOG_SET_MASK 16
+#define XLOG_GET_MASK 17
+#define DSP_READ 20
+#define DSP_WRITE 21
+
+#define OK 0xff
+#define MORE_EVENTS 0xfe
+#define NO_EVENT 1
+
+struct DSigStruc
+{
+ byte Id;
+ byte uX;
+ byte listen;
+ byte active;
+ byte sin[3];
+ byte bc[6];
+ byte llc[6];
+ byte hlc[6];
+ byte oad[20];
+};
+
+struct BL1Struc {
+ dword cx_b1;
+ dword cx_b2;
+ dword cr_b1;
+ dword cr_b2;
+ dword px_b1;
+ dword px_b2;
+ dword pr_b1;
+ dword pr_b2;
+ word er_b1;
+ word er_b2;
+};
+
+struct L2Struc {
+ dword XTotal;
+ dword RTotal;
+ word XError;
+ word RError;
+};
+
+struct OSStruc {
+ word free_n;
+};
+
+typedef union
+{
+ struct DSigStruc DSigStats;
+ struct BL1Struc BL1Stats;
+ struct L2Struc L2Stats;
+ struct OSStruc OSStats;
+ byte b[BUFFER_SZ];
+ word w[BUFFER_SZ>>1];
+ word l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
+ dword d[BUFFER_SZ>>2];
+} BUFFER;
+
+typedef union
+{
+ struct DSigStruc DSigStats;
+ struct BL1Struc BL1Stats;
+ struct L2Struc L2Stats;
+ struct OSStruc OSStats;
+ byte b[MIPS_BUFFER_SZ];
+ word w[MIPS_BUFFER_SZ>>1];
+ word l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
+ dword d[MIPS_BUFFER_SZ>>2];
+} MIPS_BUFFER;
+
+
+#if !defined(MIPS_SCOM)
+struct pc_maint
+{
+ byte req;
+ byte rc;
+ byte *mem; /*far*/
+ short length;
+ word port;
+ byte fill[6];
+ BUFFER data;
+};
+#else
+struct pc_maint
+{
+ byte req;
+ byte rc;
+ byte reserved[2]; /* R3000 alignment ... */
+ byte far *mem;
+ short length;
+ word port;
+ byte fill[4]; /* data at offset 16 */
+ BUFFER data;
+};
+#endif
+
+struct mi_pc_maint
+{
+ byte req;
+ byte rc;
+ byte reserved[2]; /* R3000 alignment ... */
+ byte *mem; /*far*/
+ short length;
+ word port;
+ byte fill[4]; /* data at offset 16 */
+ MIPS_BUFFER data;
+};
+
+#endif /* PC_MAINT_H */
diff --git a/drivers/isdn/eicon/pr_pc.h b/drivers/isdn/eicon/pr_pc.h
new file mode 100644
index 000000000..f01ad4499
--- /dev/null
+++ b/drivers/isdn/eicon/pr_pc.h
@@ -0,0 +1,86 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#if !defined(PR_PC_H)
+#define PR_PC_H
+
+struct pr_ram {
+ word NextReq; /* pointer to next Req Buffer */
+ word NextRc; /* pointer to next Rc Buffer */
+ word NextInd; /* pointer to next Ind Buffer */
+ byte ReqInput; /* number of Req Buffers sent */
+ byte ReqOutput; /* number of Req Buffers returned */
+ byte ReqReserved; /* number of Req Buffers reserved */
+ byte Int; /* ISDN-P interrupt */
+ byte XLock; /* Lock field for arbitration */
+ byte RcOutput; /* number of Rc buffers received */
+ byte IndOutput; /* number of Ind buffers received */
+ byte IMask; /* Interrupt Mask Flag */
+ byte Reserved1[2]; /* reserved field, do not use */
+ byte ReadyInt; /* request field for ready interrupt */
+ byte Reserved2[12]; /* reserved field, do not use */
+ byte InterfaceType; /* interface type 1=16K interface */
+ word Signature; /* ISDN-P initialized indication */
+ byte B[1]; /* buffer space for Req,Ind and Rc */
+};
+
+typedef struct {
+ word next;
+ byte Req;
+ byte ReqId;
+ byte ReqCh;
+ byte Reserved1;
+ word Reference;
+ byte Reserved[8];
+ PBUFFER XBuffer;
+} REQ;
+
+typedef struct {
+ word next;
+ byte Rc;
+ byte RcId;
+ byte RcCh;
+ byte Reserved1;
+ word Reference;
+ byte Reserved2[8];
+} RC;
+
+typedef struct {
+ word next;
+ byte Ind;
+ byte IndId;
+ byte IndCh;
+ byte MInd;
+ word MLength;
+ word Reference;
+ byte RNR;
+ byte Reserved;
+ dword Ack;
+ PBUFFER RBuffer;
+} IND;
+
+#endif
diff --git a/drivers/isdn/eicon/pri.c b/drivers/isdn/eicon/pri.c
new file mode 100644
index 000000000..a6a63945e
--- /dev/null
+++ b/drivers/isdn/eicon/pri.c
@@ -0,0 +1,533 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.5
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/* Diva Server PRI specific part of initialisation */
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "dsp_defs.h"
+
+#include "adapter.h"
+#include "uxio.h"
+
+#define DIVAS_LOAD_CMD 0x02
+#define DIVAS_START_CMD 0x03
+#define DIVAS_IRQ_RESET 0xC18
+#define DIVAS_IRQ_RESET_VAL 0xFE
+
+#define TEST_INT_DIVAS 0x11
+#define TEST_INT_DIVAS_BRI 0x12
+
+#define DIVAS_RESET 0x81
+#define DIVAS_LED1 0x04
+#define DIVAS_LED2 0x08
+#define DIVAS_LED3 0x20
+#define DIVAS_LED4 0x40
+
+#define DIVAS_RESET_REG 0x20
+
+#define DIVAS_SIGNATURE 0x4447
+
+/* offset to start of MAINT area (used by xlog) */
+
+#define DIVAS_MAINT_OFFSET 0xef00 /* value for PRI card */
+
+#define MP_PROTOCOL_ADDR 0xA0011000
+#define MP_DSP_CODE_BASE 0xa03a0000
+
+typedef struct {
+ dword cmd;
+ dword addr;
+ dword len;
+ dword err;
+ dword live;
+ dword reserved[(0x1020>>2)-6];
+ dword signature;
+ byte data[1];
+} diva_server_boot_t;
+
+byte mem_in(ADAPTER *a, void *adr);
+word mem_inw(ADAPTER *a, void *adr);
+void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length);
+void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e);
+void mem_out(ADAPTER *a, void *adr, byte data);
+void mem_outw(ADAPTER *a, void *adr, word data);
+void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length);
+void mem_inc(ADAPTER *a, void *adr);
+
+int DivasPRIInitPCI(card_t *card, dia_card_t *cfg);
+int pri_ISR (card_t* card);
+
+static int diva_server_reset(card_t *card)
+{
+ byte *reg;
+ diva_server_boot_t *boot = NULL;
+ dword live = 0;
+ int i = 0;
+ dword dwWait;
+
+ DPRINTF(("divas: reset Diva Server PRI"));
+
+ reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY);
+
+ UxCardMemOut(card->hw, &reg[DIVAS_RESET_REG], DIVAS_RESET |
+ DIVAS_LED1 | DIVAS_LED2 | DIVAS_LED3 | DIVAS_LED4);
+
+ for (dwWait = 0x000fffff; dwWait; dwWait--)
+ ;
+
+ UxCardMemOut(card->hw, &reg[DIVAS_RESET_REG], 0x00);
+
+ for (dwWait = 0x000fffff; dwWait; dwWait--)
+ ;
+
+ UxCardMemDetach(card->hw, reg);
+
+ boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+ UxCardMemOutD(card->hw, boot->reserved, 0);
+
+ live = UxCardMemInD(card->hw, &boot->live);
+
+ for (i=0; i<5; i++)
+ {
+ if (live != UxCardMemInD(card->hw, &boot->live))
+ {
+ break;
+ }
+ UxPause(10);
+ }
+
+ if (i == 5)
+ {
+ UxCardMemDetach(card->hw, boot);
+
+ DPRINTF(("divas: card is reset but CPU not running"));
+ return -1;
+ }
+
+ UxCardMemDetach(card->hw, boot);
+
+ DPRINTF(("divas: card reset after %d ms", i * 10));
+
+ return 0;
+}
+
+static int diva_server_config(card_t *card, dia_config_t *config)
+{
+ byte *shared;
+ int i, j;
+
+ DPRINTF(("divas: configure Diva Server PRI"));
+
+ shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+ UxCardLog(0);
+ for (i=0; i<256; i++)
+ {
+ UxCardMemOut(card->hw, &shared[i], 0);
+ }
+
+ UxCardMemOut(card->hw, &shared[ 8], config->tei);
+ UxCardMemOut(card->hw, &shared[ 9], config->nt2);
+ UxCardMemOut(card->hw, &shared[10], 0);
+ UxCardMemOut(card->hw, &shared[11], config->watchdog);
+ UxCardMemOut(card->hw, &shared[12], config->permanent);
+ UxCardMemOut(card->hw, &shared[13], config->x_interface);
+ UxCardMemOut(card->hw, &shared[14], config->stable_l2);
+ UxCardMemOut(card->hw, &shared[15], config->no_order_check);
+ UxCardMemOut(card->hw, &shared[16], config->handset_type);
+ UxCardMemOut(card->hw, &shared[17], 0);
+ UxCardMemOut(card->hw, &shared[18], config->low_channel);
+ UxCardMemOut(card->hw, &shared[19], config->prot_version);
+ UxCardMemOut(card->hw, &shared[20], config->crc4);
+
+ for (i=0; i<2; i++)
+ {
+ for (j=0; j<32; j++)
+ {
+ UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]);
+ }
+
+ for (j=0; j<32; j++)
+ {
+ UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]);
+ }
+
+ for (j=0; j<32; j++)
+ {
+ UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]);
+ }
+ }
+
+ UxCardMemDetach(card->hw, shared);
+
+ return 0;
+}
+
+static
+void diva_server_reset_int(card_t *card)
+{
+ byte *cfg;
+
+ cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY);
+
+ UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET], DIVAS_IRQ_RESET_VAL);
+ UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET + 2], 0);
+ UxCardMemDetach(card->hw, cfg);
+
+ return;
+}
+
+
+static int diva_server_test_int(card_t *card)
+{
+ int i;
+ byte *shared;
+ byte req_int;
+
+ DPRINTF(("divas: test interrupt for Diva Server PRI"));
+
+ shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+ UxCardMemIn(card->hw, &shared[0x3FE]);
+ UxCardMemOut(card->hw, &shared[0x3FE], 0);
+ UxCardMemIn(card->hw, &shared[0x3FE]);
+
+ UxCardMemDetach(card->hw, shared);
+
+ diva_server_reset_int(card);
+
+ shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+ card->test_int_pend = TEST_INT_DIVAS;
+
+ req_int = UxCardMemIn(card->hw, &(((struct pr_ram *)shared)->ReadyInt));
+
+ req_int++;
+
+ UxCardMemOut(card->hw, &(((struct pr_ram *)shared)->ReadyInt), req_int);
+
+ UxCardMemDetach(card->hw, shared);
+
+ UxCardLog(0);
+ for (i = 0; i < 50; i++)
+ {
+ if (!card->test_int_pend)
+ {
+ break;
+ }
+ UxPause(10);
+ }
+
+
+ if (card->test_int_pend)
+ {
+
+ DPRINTF(("active: timeout waiting for card to interrupt"));
+ return (-1);
+
+ }
+
+ return 0;
+}
+
+
+static void print_hdr(unsigned char *code, int offset)
+{
+ unsigned char hdr[80];
+ int i;
+
+ i = 0;
+
+ while ((i < (DIM(hdr) -1)) &&
+ (code[offset + i] != '\0') &&
+ (code[offset + i] != '\r') &&
+ (code[offset + i] != '\n'))
+ {
+ hdr[i] = code[offset + i];
+ i++;
+ }
+
+ hdr[i] = '\0';
+
+ DPRINTF(("divas: loading %s", hdr));
+}
+
+static int diva_server_load(card_t *card, dia_load_t *load)
+{
+ diva_server_boot_t *boot;
+ int i, offset, length;
+ dword cmd = 0;
+
+ DPRINTF(("divas: loading Diva Server PRI"));
+
+ boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+ switch(load->code_type)
+ {
+ case DIA_CPU_CODE:
+ DPRINTF(("divas: RISC code"));
+ print_hdr(load->code, 0x80);
+
+ UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR);
+ break;
+
+ case DIA_DSP_CODE:
+ DPRINTF(("divas: DSP code"));
+ print_hdr(load->code, 0x0);
+
+ UxCardMemOutD(card->hw, &boot->addr,
+ (MP_DSP_CODE_BASE + (((sizeof(dword) +
+ (sizeof(t_dsp_download_desc) * DSP_MAX_DOWNLOAD_COUNT))
+ + ~ALIGNMENT_MASK_MAESTRA) & ALIGNMENT_MASK_MAESTRA)));
+ break;
+
+ case DIA_TABLE_CODE:
+ DPRINTF(("divas: TABLE code"));
+ UxCardMemOutD(card->hw, &boot->addr,
+ (MP_DSP_CODE_BASE + sizeof(dword)));
+ break;
+
+ case DIA_CONT_CODE:
+ DPRINTF(("divas: continuation code"));
+ break;
+
+ case DIA_DLOAD_CNT:
+ DPRINTF(("divas: COUNT code"));
+ UxCardMemOutD(card->hw, &boot->addr, MP_DSP_CODE_BASE);
+ break;
+
+ default:
+ DPRINTF(("divas: unknown code type"));
+ UxCardMemDetach(card->hw, boot);
+ return -1;
+ }
+
+ UxCardLog(0);
+ offset = 0;
+
+ do
+ {
+ length = (load->length - offset >= 400) ? 400 : load->length - offset;
+
+ for (i=0; i<length; i++)
+ {
+ UxCardMemOut(card->hw, &boot->data[i], load->code[offset+i]);
+ }
+
+ for (i=0; i<length; i++)
+ {
+ if (load->code[offset + i] != UxCardMemIn(card->hw, &boot->data[i]))
+ {
+ UxCardMemDetach(card->hw, boot);
+
+ DPRINTF(("divas: card code block verify failed"));
+ return -1;
+ }
+ }
+
+ UxCardMemOutD(card->hw, &boot->len, (length + 3) / 4);
+ UxCardMemOutD(card->hw, &boot->cmd, DIVAS_LOAD_CMD);
+
+ for (i=0; i<50000; i++)
+ {
+ cmd = UxCardMemInD(card->hw, &boot->cmd);
+ if (!cmd)
+ {
+ break;
+ }
+ /*UxPause(1);*/
+ }
+
+ if (cmd)
+ {
+ DPRINTF(("divas: timeout waiting for card to ACK load (offset = %d)", offset));
+ UxCardMemDetach(card->hw, boot);
+ return -1;
+ }
+
+ offset += length;
+
+ } while (offset < load->length);
+
+ UxCardMemDetach(card->hw, boot);
+
+ DPRINTF(("divas: DIVA Server card loaded"));
+
+ return 0;
+}
+
+static int diva_server_start(card_t *card, byte *channels)
+{
+ diva_server_boot_t *boot;
+ byte *ram;
+ int i;
+ dword signature = 0;
+
+ DPRINTF(("divas: start Diva Server PRI"));
+
+ card->is_live = FALSE;
+
+ boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+ UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR);
+ UxCardMemOutD(card->hw, &boot->cmd, DIVAS_START_CMD);
+
+ UxCardLog(0);
+
+ for (i = 0; i < 300; i++)
+ {
+ signature = UxCardMemInD(card->hw, &boot->signature);
+ if ((signature >> 16) == DIVAS_SIGNATURE)
+ {
+ DPRINTF(("divas: started card after %d ms", i * 10));
+ break;
+ }
+ UxPause(10);
+ }
+
+ if ((signature >> 16) != DIVAS_SIGNATURE)
+ {
+ UxCardMemDetach(card->hw, boot);
+ DPRINTF(("divas: timeout waiting for card to run protocol code (sig = 0x%x)", signature));
+ return -1;
+ }
+
+ card->is_live = TRUE;
+
+ ram = (byte *) boot;
+ ram += DIVAS_SHARED_OFFSET;
+
+ *channels = UxCardMemIn(card->hw, &ram[0x3F6]);
+ card->serial_no = UxCardMemInD(card->hw, &ram[0x3F0]);
+
+ UxCardMemDetach(card->hw, boot);
+
+ if (diva_server_test_int(card))
+ {
+ DPRINTF(("divas: interrupt test failed"));
+ return -1;
+ }
+
+ DPRINTF(("divas: DIVA Server card started"));
+
+ return 0;
+}
+
+static
+int diva_server_mem_get(card_t *card, mem_block_t *mem_block)
+
+{
+ byte *a;
+ byte *card_addr;
+ word length = 0;
+ int i;
+
+ a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+ card_addr = a;
+ card_addr += mem_block->addr;
+
+ for (i=0; i < sizeof(mem_block->data); i++)
+ {
+ mem_block->data[i] = UxCardMemIn(card->hw, card_addr);
+ card_addr++;
+ length++;
+ }
+
+ UxCardMemDetach(card->hw, a);
+
+ return length;
+}
+
+/*
+ * Initialise PRI specific entry points
+ */
+
+int DivasPriInit(card_t *card, dia_card_t *cfg)
+{
+ DPRINTF(("divas: initialise Diva Server PRI"));
+
+ if (DivasPRIInitPCI(card, cfg) == -1)
+ {
+ return -1;
+ }
+
+ card->card_reset = diva_server_reset;
+ card->card_load = diva_server_load;
+ card->card_config = diva_server_config;
+ card->card_start = diva_server_start;
+ card->reset_int = diva_server_reset_int;
+ card->card_mem_get = diva_server_mem_get;
+
+ card->xlog_offset = DIVAS_MAINT_OFFSET;
+
+ card->out = DivasOut;
+ card->test_int = DivasTestInt;
+ card->dpc = DivasDpc;
+ card->clear_int = DivasClearInt;
+ card->card_isr = pri_ISR;
+
+ card->a.ram_out = mem_out;
+ card->a.ram_outw = mem_outw;
+ card->a.ram_out_buffer = mem_out_buffer;
+ card->a.ram_inc = mem_inc;
+
+ card->a.ram_in = mem_in;
+ card->a.ram_inw = mem_inw;
+ card->a.ram_in_buffer = mem_in_buffer;
+ card->a.ram_look_ahead = mem_look_ahead;
+
+ return 0;
+}
+
+
+int pri_ISR (card_t* card)
+{
+ int served = 0;
+ byte* cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY);
+ volatile unsigned long* isr = (unsigned long*)&cfg[DIVAS_IRQ_RESET];
+ register unsigned long val = *isr;
+
+ if (val & 0x80000000) /* our card had caused interrupt ??? */
+ {
+ served = 1;
+ card->int_pend += 1;
+ DivasDpcSchedule(); /* ISR DPC */
+
+ *isr = (unsigned long)~0x03E00000; /* Clear interrupt line */
+ }
+
+ UxCardMemDetach(card->hw, cfg);
+
+ return (served != 0);
+}
+
+
diff --git a/drivers/isdn/eicon/sys.h b/drivers/isdn/eicon/sys.h
new file mode 100644
index 000000000..0e636c547
--- /dev/null
+++ b/drivers/isdn/eicon/sys.h
@@ -0,0 +1,119 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/* Environment provided by system and miscellaneous definitions */
+
+#if !defined(SYS_H)
+#define SYS_H
+
+/* abreviations for unsigned types */
+typedef int boolean_t;
+
+typedef unsigned char byte;
+
+typedef unsigned long dword;
+typedef unsigned short word;
+
+/* abreviations for volatile types */
+
+typedef volatile byte vbyte;
+typedef volatile word vword;
+typedef volatile dword vdword;
+
+/* Booleans */
+
+#if !defined(TRUE)
+#define TRUE (1)
+#define FALSE (0)
+#endif
+
+/* NULL pointer */
+
+#if !defined(NULL)
+#define NULL ((void *) 0)
+#endif
+
+/* MIN and MAX */
+
+#if !defined(MIN)
+#define MIN(a,b) ((a)>(b) ? (b) : (a))
+#endif
+#if !defined(MAX)
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#endif
+
+/* Return the dimension of an array */
+
+#if !defined(DIM)
+#define DIM(array) (sizeof (array)/sizeof ((array)[0]))
+#endif
+
+/*
+ * Return the number of milliseconds since last boot
+ */
+
+extern dword UxTimeGet(void);
+
+extern void DivasSprintf(char *buffer, char *format, ...);
+extern void DivasPrintf(char *format, ...);
+
+/* fatal errors, asserts and tracing */
+
+void HwFatalErrorFrom(char *file, int line);
+void HwFatalError(void);
+/* void HwAssert(char *file, int line, char *condition); */
+
+#include <linux/kernel.h>
+#define _PRINTK printk
+
+#define _PRINTF DivasPrintf
+void _PRINTF(char *format, ...);
+#define PRINTF(arg_list) _PRINTF arg_list
+#if defined DTRACE
+# define DPRINTF(arg_list) _PRINTF arg_list
+# define KDPRINTF(arg_list) _PRINTF arg_list ; _PRINTK arg_list ; _PRINTK("\n");
+#else
+# define DPRINTF(arg_list) (void)0
+# define KDPRINTF(arg_list) _PRINTK arg_list ; _PRINTK("\n");
+#endif
+
+#if !defined(ASSERT)
+#if defined DEBUG || defined DBG
+# define HwFatalError() HwFatalErrorFrom(__FILE__, __LINE__)
+# define ASSERT(cond) \
+ if (!(cond)) \
+ { \
+/* HwAssert(__FILE__, __LINE__, #cond);*/ \
+ }
+#else
+# define ASSERT(cond) ((void)0)
+#endif
+#endif /* !defined(ASSERT) */
+
+#define TRACE (_PRINTF(__FILE__"@%d\n", __LINE__))
+
+#endif /* SYS_H */
diff --git a/drivers/isdn/eicon/uxio.h b/drivers/isdn/eicon/uxio.h
new file mode 100644
index 000000000..c15d93f96
--- /dev/null
+++ b/drivers/isdn/eicon/uxio.h
@@ -0,0 +1,220 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.6
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/*
+ * Interface to Unix specific code for performing card I/O
+ */
+
+#if !defined(UXIO_H)
+#define UXIO_H
+
+#include "sys.h"
+#include "adapter.h"
+
+
+struct pt_regs;
+
+/* user callback, returns zero if interrupt was from this card */
+typedef void isr_fn_t(void *);
+struct ux_diva_card_s
+{
+ word in_use;
+ int io_base;
+ int reset_base;
+ int card_type;
+ byte *mapped;
+ int bus_num;
+ int func_num;
+ int slot;
+ int irq;
+ byte *pDRAM;
+ byte *pDEVICES;
+ byte *pCONFIG;
+ byte *pSHARED;
+ byte *pCONTROL;
+ word features;
+ void *user_isr_arg;
+ isr_fn_t *user_isr;
+};
+
+void bcopy(void *pSource, void *pDest, dword dwLength);
+void bzero(void *pDataArea, dword dwLength);
+
+
+/*
+ * Get a card handle to enable card to be accessed
+ */
+
+int UxCardHandleGet( ux_diva_card_t **card,
+ dia_card_t *cfg);
+
+/*
+ * Free a card handle as no longer needed
+ */
+
+void UxCardHandleFree(ux_diva_card_t *card);
+
+/*
+ * Lock and unlock access to a card
+ */
+
+int UxCardLock(ux_diva_card_t *card);
+void UxCardUnlock(ux_diva_card_t *card, int ipl);
+
+/*
+ * Set the mapping address for PCI cards
+ */
+
+int UxCardAddrMappingSet(ux_diva_card_t *card,
+ int id,
+ void *address,
+ int size);
+
+/*
+ * Attach card to memory to enable it to be accessed
+ * Returns the mapped address
+ */
+
+void *UxCardMemAttach(ux_diva_card_t *card, int id);
+
+/*
+ * map card out of memory after completion of access
+ */
+
+void UxCardMemDetach(ux_diva_card_t *card, void *address);
+
+/*
+ * input functions for memory-mapped cards
+ */
+
+byte UxCardMemIn(ux_diva_card_t *card, void *address);
+
+word UxCardMemInW(ux_diva_card_t *card, void *address);
+
+dword UxCardMemInD(ux_diva_card_t *card, void *address);
+
+void UxCardMemInBuffer( ux_diva_card_t *card,
+ void *address,
+ void *buffer,
+ int length);
+
+/*
+ * output functions for memory-mapped cards
+ */
+
+void UxCardMemOut(ux_diva_card_t *card, void *address, byte data);
+
+void UxCardMemOutW(ux_diva_card_t *card, void *address, word data);
+
+void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data);
+
+void UxCardMemOutBuffer( ux_diva_card_t *card,
+ void *address,
+ void *buffer,
+ int length);
+
+/*
+ * input functions for I/O-mapped cards
+ */
+
+byte UxCardIoIn(ux_diva_card_t *card, void *, void *address);
+
+word UxCardIoInW(ux_diva_card_t *card, void *, void *address);
+
+dword UxCardIoInD(ux_diva_card_t *card, void *, void *address);
+
+void UxCardIoInBuffer( ux_diva_card_t *card,
+ void *, void *address,
+ void *buffer,
+ int length);
+
+/*
+ * output functions for I/O-mapped cards
+ */
+
+void UxCardIoOut(ux_diva_card_t *card, void *, void *address, byte data);
+
+void UxCardIoOutW(ux_diva_card_t *card, void *, void *address, word data);
+
+void UxCardIoOutD(ux_diva_card_t *card, void *, void *address, dword data);
+
+void UxCardIoOutBuffer( ux_diva_card_t *card,
+ void *, void *address,
+ void *buffer,
+ int length);
+
+/*
+ * Get specified PCI config
+ */
+
+void UxPciConfigRead(ux_diva_card_t *card,
+ int size,
+ int offset,
+ void *value);
+
+/*
+ * Set specified PCI config
+ */
+
+void UxPciConfigWrite(ux_diva_card_t *card,
+ int size,
+ int offset,
+ void *value);
+
+/* allocate memory, returning NULL if none available */
+
+void *UxAlloc(unsigned int size);
+
+void UxFree(void *);
+
+/*
+ * Pause for specified number of milli-seconds
+ */
+
+void UxPause(long ms);
+
+/*
+ * Install an ISR for the specified card
+ */
+
+int UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg);
+
+/*
+ * Remove an ISR for the specified card
+ */
+void UxIsrRemove(ux_diva_card_t *card, void *);
+
+/*
+ * DEBUG function to turn logging ON or OFF
+ */
+
+void UxCardLog(int turn_on);
+
+long UxInterlockedIncrement(ux_diva_card_t *card, long *dst);
+long UxInterlockedDecrement(ux_diva_card_t *card, long *dst);
+
+#endif /* of UXIO_H */
diff --git a/drivers/isdn/eicon/xlog.c b/drivers/isdn/eicon/xlog.c
new file mode 100644
index 000000000..282662cfc
--- /dev/null
+++ b/drivers/isdn/eicon/xlog.c
@@ -0,0 +1,183 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * Eicon File Revision : 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/*
+ * Unix Eicon active card driver
+ * XLOG related functions
+ */
+
+#include "sys.h"
+#include "idi.h"
+#include "pc.h"
+#include "pc_maint.h"
+#include "divalog.h"
+
+#include "adapter.h"
+#include "uxio.h"
+
+/*
+ * convert/copy XLOG info into a KLOG entry
+ */
+
+static
+void xlog_to_klog(byte *b, int size, int card_num)
+
+{
+ typedef struct
+ {
+ word code;
+ word time_hi;
+ word time_lo;
+ word xcode;
+ byte data[2];
+ } card_xlog_t;
+
+ card_xlog_t *x;
+
+ klog_t klog;
+
+ x = (card_xlog_t *) b;
+
+ bzero(&klog, sizeof(klog));
+
+ klog.time_stamp = (dword) x->time_hi;
+ klog.time_stamp = (klog.time_stamp << 16) | (dword) x->time_lo;
+
+ klog.length = size > sizeof(klog.buffer) ? sizeof(klog.buffer) : size;
+
+ klog.card = card_num;
+ if (x->code == 1)
+ {
+ klog.type = KLOG_XTXT_MSG;
+ klog.code = 0;
+ bcopy(&x->xcode, klog.buffer, klog.length);
+ }
+ else if (x->code == 2)
+ {
+ klog.type = KLOG_XLOG_MSG;
+ klog.code = x->xcode;
+ bcopy(&x->data, klog.buffer, klog.length);
+ }
+ else
+ {
+ char *c; int i;
+ klog.type = KLOG_TEXT_MSG;
+ klog.code = 0;
+ c = "divas: invalid xlog message code from card";
+ i = 0;
+ while (*c)
+ {
+ klog.buffer[i] = *c;
+ c++;
+ i++;
+ }
+ klog.buffer[i] = *c;
+ }
+
+ /* send to the log driver and return */
+
+ DivasLogAdd(&klog, sizeof(klog));
+
+ return;
+}
+
+/*
+ * send an XLOG request down to specified card
+ * if response available from previous request then read it
+ * if not then just send down new request, ready for next time
+ */
+
+void DivasXlogReq(int card_num)
+
+{
+ card_t *card;
+ ADAPTER *a;
+
+ if ((card_num < 0) || (card_num > DivasCardNext))
+ {
+ DPRINTF(("xlog: invalid card number"));
+ return;
+ }
+
+ card = &DivasCards[card_num];
+
+ if (DivasXlogRetrieve(card))
+ {
+ return;
+ }
+
+ /* send down request for next time */
+
+ a = &card->a;
+
+ a->ram_out(a, (word *) (card->xlog_offset + 1), 0);
+ a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG);
+
+ return;
+}
+
+/*
+ * retrieve XLOG request from specified card
+ * returns non-zero if new request sent to card
+ */
+
+int DivasXlogRetrieve(card_t *card)
+
+{
+ ADAPTER *a;
+ struct mi_pc_maint pcm;
+
+ a = &card->a;
+
+ /* get status of last request */
+
+ pcm.rc = a->ram_in(a, (word *)(card->xlog_offset + 1));
+
+ /* if nothing there from previous request, send down a new one */
+
+ if (pcm.rc == OK)
+ {
+ /* read in response */
+
+ a->ram_in_buffer(a, (word *) (dword) card->xlog_offset, &pcm, sizeof(pcm));
+
+ xlog_to_klog((byte *) &pcm.data, sizeof(pcm.data),
+ (int) (card - DivasCards));
+ }
+
+ /* if any response received from card, re-send request */
+
+ if (pcm.rc)
+ {
+ a->ram_out(a, (word *) (card->xlog_offset + 1), 0);
+ a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG);
+
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
index 7bc340de9..071e3b1ca 100644
--- a/drivers/isdn/hisax/Makefile
+++ b/drivers/isdn/hisax/Makefile
@@ -31,6 +31,8 @@ HFC_OBJ :=
HFC_2BDS0 :=
JADE_OBJ :=
W6692_OBJ :=
+NETJ_OBJ :=
+ICC_OBJ :=
ifeq ($(CONFIG_HISAX_16_0),y)
O_OBJS += teles0.o
@@ -124,10 +126,17 @@ ifeq ($(CONFIG_HISAX_MIC),y)
endif
ifeq ($(CONFIG_HISAX_NETJET),y)
- O_OBJS += netjet.o
+ O_OBJS += nj_s.o
+ NETJ_OBJ := netjet.o
ISAC_OBJ := isac.o
endif
+ifeq ($(CONFIG_HISAX_NETJET_U),y)
+ O_OBJS += nj_u.o
+ NETJ_OBJ := netjet.o
+ ICC_OBJ := icc.o
+endif
+
ifeq ($(CONFIG_HISAX_HFCS),y)
O_OBJS += hfcscard.o
HFC_2BDS0 := hfc_2bds0.o
@@ -189,7 +198,7 @@ ifeq ($(ISAC_OBJ), isac.o)
endif
O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(ISAR_OBJ) $(JADE_OBJ)
-O_OBJS += $(HFC_OBJ) $(HFC_2BDS0) $(W6692_OBJ)
+O_OBJS += $(HFC_OBJ) $(HFC_2BDS0) $(W6692_OBJ) $(NETJ_OBJ) $(ICC_OBJ)
OX_OBJS += config.o
O_TARGET :=
@@ -208,10 +217,9 @@ include $(TOPDIR)/Rules.make
MD5FILES += isac.c isdnl1.c isdnl2.c isdnl3.c \
tei.c callc.c cert.c l3dss1.c l3_1tr6.c \
- elsa.c diva.c
+ elsa.c diva.c sedlbauer.c
CERT = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
cert.o: $(MD5FILES) md5sums.asc
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D CERTIFICATION=$(CERT) -c -o cert.o cert.c
-
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index dabb179b5..4302585dc 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -1,4 +1,4 @@
-/* $Id: avm_pci.c,v 1.17 2000/06/26 08:59:12 keil Exp $
+/* $Id: avm_pci.c,v 1.18 2000/08/20 07:34:04 keil Exp $
*
* avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
* Thanks to AVM, Berlin for informations
@@ -17,13 +17,17 @@
#include <linux/interrupt.h>
extern const char *CardType[];
-static const char *avm_pci_rev = "$Revision: 1.15 $";
+static const char *avm_pci_rev = "$Revision: 1.18 $";
#define AVM_FRITZ_PCI 1
#define AVM_FRITZ_PNP 2
-#define PCI_VENDOR_AVM 0x1244
-#define PCI_FRITZPCI_ID 0xa00
+#ifndef PCI_VENDOR_ID_AVM
+#define PCI_VENDOR_ID_AVM 0x1244
+#endif
+#ifndef PCI_DEVICE_ID_AVM_FRITZ
+#define PCI_DEVICE_ID_AVM_FRITZ 0xa00
+#endif
#define HDLC_FIFO 0x0
#define HDLC_STATUS 0x4
@@ -293,7 +297,15 @@ hdlc_empty_fifo(struct BCState *bcs, int count)
if (cs->subtyp == AVM_FRITZ_PCI) {
outl(idx, cs->hw.avm.cfg_reg + 4);
while (cnt < count) {
+#ifdef __powerpc__
+#ifdef CONFIG_APUS
+ *ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
+#else
+ *ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
+#endif /* CONFIG_APUS */
+#else
*ptr++ = inl(cs->hw.avm.isac);
+#endif /* __powerpc__ */
cnt += 4;
}
} else {
@@ -349,7 +361,15 @@ hdlc_fill_fifo(struct BCState *bcs)
write_ctrl(bcs, 3); /* sets the correct index too */
if (cs->subtyp == AVM_FRITZ_PCI) {
while (cnt<count) {
+#ifdef __powerpc__
+#ifdef CONFIG_APUS
+ out_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++);
+#else
+ out_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++);
+#endif /* CONFIG_APUS */
+#else
outl(*ptr++, cs->hw.avm.isac);
+#endif /* __powerpc__ */
cnt += 4;
}
} else {
@@ -767,8 +787,8 @@ setup_avm_pcipnp(struct IsdnCard *card))
printk(KERN_ERR "FritzPCI: no PCI bus present\n");
return(0);
}
- if ((dev_avm = pci_find_device(PCI_VENDOR_AVM,
- PCI_FRITZPCI_ID, dev_avm))) {
+ if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
+ PCI_DEVICE_ID_AVM_FRITZ, dev_avm))) {
cs->irq = dev_avm->irq;
if (!cs->irq) {
printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
@@ -776,9 +796,9 @@ setup_avm_pcipnp(struct IsdnCard *card))
}
if (pci_enable_device(dev_avm))
return(0);
- cs->hw.avm.cfg_reg = pci_resource_start (dev_avm, 1);
+ cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
if (!cs->hw.avm.cfg_reg) {
- printk(KERN_WARNING "FritzPCI: No IO-Adr for PCI card found\n");
+ printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
return(0);
}
cs->subtyp = AVM_FRITZ_PCI;
diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c
index 17e3a19a7..75729c282 100644
--- a/drivers/isdn/hisax/bkm_a4t.c
+++ b/drivers/isdn/hisax/bkm_a4t.c
@@ -18,12 +18,12 @@
#include "hscx.h"
#include "jade.h"
#include "isdnl1.h"
-#include "bkm_ax.h"
#include <linux/pci.h>
+#include "bkm_ax.h"
extern const char *CardType[];
-const char *bkm_a4t_revision = "$Revision: 1.9 $";
+const char *bkm_a4t_revision = "$Revision: 1.11 $";
static inline u_char
@@ -287,17 +287,20 @@ __initfunc(int
printk(KERN_ERR "bkm_a4t: no PCI bus present\n");
return (0);
}
- if ((dev_a4t = pci_find_device(I20_VENDOR_ID, I20_DEVICE_ID, dev_a4t))) {
- u_int sub_sys_id = 0;
-
- if (pci_enable_device(dev_a4t))
- return (0);
- pci_read_config_dword(dev_a4t, PCI_SUBSYSTEM_VENDOR_ID,
- &sub_sys_id);
- if (sub_sys_id == ((A4T_SUBSYS_ID << 16) | A4T_SUBVEN_ID)) {
+ while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN,
+ PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) {
+ u16 sub_sys;
+ u16 sub_vendor;
+
+ sub_vendor = dev_a4t->subsystem_vendor;
+ sub_sys = dev_a4t->subsystem_device;
+ if ((sub_sys == A4T_SUBSYS_ID) && (sub_vendor == A4T_SUBVEN_ID)) {
+ if (pci_enable_device(dev_a4t))
+ return(0);
found = 1;
- pci_memaddr = pci_resource_start (dev_a4t, 0);
+ pci_memaddr = pci_resource_start(dev_a4t, 0);
cs->irq = dev_a4t->irq;
+ break;
}
}
if (!found) {
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index 61e0bde3c..6f00073c6 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -17,29 +17,16 @@
#include "ipac.h"
#include "hscx.h"
#include "isdnl1.h"
-#include "bkm_ax.h"
#include <linux/pci.h>
+#include "bkm_ax.h"
+
+#if CONFIG_PCI
#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */
extern const char *CardType[];
-const char sct_quadro_revision[] = "$Revision: 1.9 $";
-
-/* To survive the startup phase */
-typedef struct {
- u_int active; /* true/false */
- u_int base; /* ipac base address */
-} IPAC_STATE;
-
-static IPAC_STATE ipac_state[4 + 1] __initdata =
-{
- {0, 0}, /* dummy */
- {0, 0}, /* SCT_1 */
- {0, 0}, /* SCT_2 */
- {0, 0}, /* SCT_3 */
- {0, 0} /* SCT_4 */
-};
+const char sct_quadro_revision[] = "$Revision: 1.12 $";
static const char *sct_quadro_subtypes[] =
{
@@ -138,19 +125,13 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value);
}
-/* Check whether the specified ipac is already active or not */
-static int
-is_ipac_active(u_int ipac_nr)
-{
- return (ipac_state[ipac_nr].active);
-}
-
/* Set the specific ipac to active */
static void
-set_ipac_active(u_int ipac_nr, u_int active)
+set_ipac_active(struct IsdnCardState *cs, u_int active)
{
- /* set activation state */
- ipac_state[ipac_nr].active = active;
+ /* set irq mask */
+ writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK,
+ active ? 0xc0 : 0xff);
}
/*
@@ -173,13 +154,14 @@ bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
u_char ista, val, icnt = 5;
- int i;
+
if (!cs) {
printk(KERN_WARNING "HiSax: Scitel Quadro: Spurious interrupt!\n");
return;
}
ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
-
+ if (!(ista & 0x3f)) /* not this IPAC */
+ return;
Start_IPAC:
if (cs->debug & L1_DEB_IPAC)
debugl1(cs, "IPAC ISTA %02X", ista);
@@ -216,30 +198,15 @@ bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
sct_quadro_subtypes[cs->subtyp]);
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF);
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0);
-
- /* Read out all interrupt sources from currently not active ipacs */
- /* "Handle" all interrupts from currently not active ipac by reading the regs */
- for (i = SCT_1; i <= SCT_4; i++)
- if (!is_ipac_active(i)) {
- u_int base = ipac_state[i].base;
- if (readreg(base, base + 4, 0xC1)) {
- readreg(base, base + 4, 0xA0);
- readreg(base, base + 4, 0xA4);
- readreg(base, base + 4, 0x20);
- readreg(base, base + 4, 0x24);
- readreg(base, base + 4, 0x60);
- readreg(base, base + 4, 0x64);
- readreg(base, base + 4, 0xC1);
- readreg(base, base + 4, ISAC_CIR0 + 0x80);
- }
- }
}
void
release_io_sct_quadro(struct IsdnCardState *cs)
{
- /* ?? */
+ release_region(cs->hw.ax.base & 0xffffffc0, 256);
+ if (cs->subtyp == SCT_1)
+ release_region(cs->hw.ax.plx_adr, 256);
}
static void
@@ -249,11 +216,6 @@ enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
if (bEnable)
wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41));
else
- /* Issue general di only if no ipac is active */
- if (!is_ipac_active(SCT_1) &&
- !is_ipac_active(SCT_2) &&
- !is_ipac_active(SCT_3) &&
- !is_ipac_active(SCT_4))
wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41));
}
}
@@ -263,26 +225,17 @@ reset_bkm(struct IsdnCardState *cs)
{
long flags;
- if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
- if (!is_ipac_active(SCT_1) &&
- !is_ipac_active(SCT_2) &&
- !is_ipac_active(SCT_3) &&
- !is_ipac_active(SCT_4)) {
- /* Issue total reset only if no ipac is active */
- wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
-
- save_flags(flags);
- sti();
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((10 * HZ) / 1000);
-
- /* Remove the soft reset */
- wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
-
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((10 * HZ) / 1000);
- restore_flags(flags);
- }
+ if (cs->subtyp == SCT_1) {
+ wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
+ save_flags(flags);
+ sti();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((10 * HZ) / 1000);
+ /* Remove the soft reset */
+ wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((10 * HZ) / 1000);
+ restore_flags(flags);
}
}
@@ -292,20 +245,19 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
switch (mt) {
case CARD_RESET:
/* Disable ints */
- set_ipac_active(cs->subtyp, 0);
+ set_ipac_active(cs, 0);
enable_bkm_int(cs, 0);
reset_bkm(cs);
return (0);
case CARD_RELEASE:
/* Sanity */
- set_ipac_active(cs->subtyp, 0);
+ set_ipac_active(cs, 0);
enable_bkm_int(cs, 0);
- reset_bkm(cs);
release_io_sct_quadro(cs);
return (0);
case CARD_INIT:
cs->debug |= L1_DEB_IPAC;
- set_ipac_active(cs->subtyp, 1);
+ set_ipac_active(cs, 1);
inithscxisac(cs, 3);
/* Enable ints */
enable_bkm_int(cs, 1);
@@ -316,18 +268,38 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return (0);
}
+__initfunc(int
+sct_alloc_io(u_int adr, u_int len))
+{
+ if (check_region(adr, len)) {
+ printk(KERN_WARNING
+ "HiSax: Scitel port %#x-%#x already in use\n",
+ adr, adr + len);
+ return (1);
+ } else {
+ request_region(adr, len, "scitel");
+ }
+ return(0);
+}
+
static struct pci_dev *dev_a8 __initdata = NULL;
+static u16 sub_vendor_id __initdata = 0;
+static u16 sub_sys_id __initdata = 0;
+static u_char pci_bus __initdata = 0;
+static u_char pci_device_fn __initdata = 0;
+static u_char pci_irq __initdata = 0;
+
+#endif /* CONFIG_PCI */
__initfunc(int
- setup_sct_quadro(struct IsdnCard *card))
+setup_sct_quadro(struct IsdnCard *card))
{
+#if CONFIG_PCI
struct IsdnCardState *cs = card->cs;
char tmp[64];
-#if CONFIG_PCI
- u_char pci_bus = 0, pci_device_fn = 0, pci_irq = 0, pci_rev_id;
+ u_char pci_rev_id;
u_int found = 0;
u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5;
-#endif
strcpy(tmp, sct_quadro_revision);
printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
@@ -339,32 +311,61 @@ __initfunc(int
/* Identify subtype by para[0] */
if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4)
cs->subtyp = card->para[0];
- else
+ else {
printk(KERN_WARNING "HiSax: %s: Invalid subcontroller in configuration, default to 1\n",
- CardType[card->typ]);
-#if CONFIG_PCI
- if (!pci_present()) {
- printk(KERN_ERR "bkm_a4t: no PCI bus present\n");
+ CardType[card->typ]);
return (0);
}
- if ((dev_a8 = pci_find_device(PLX_VENDOR_ID, PLX_DEVICE_ID, dev_a8))) {
- u_int sub_sys_id = 0;
-
- pci_read_config_dword(dev_a8, PCI_SUBSYSTEM_VENDOR_ID,
- &sub_sys_id);
- if (sub_sys_id == ((SCT_SUBSYS_ID << 16) | SCT_SUBVEN_ID)) {
- found = 1;
- pci_ioaddr1 = dev_a8->resource[ 1].start;
- pci_irq = dev_a8->irq;
- pci_bus = dev_a8->bus->number;
- pci_device_fn = dev_a8->devfn;
- }
- }
- if (!found) {
- printk(KERN_WARNING "HiSax: %s (%s): Card not found\n",
- CardType[card->typ],
- sct_quadro_subtypes[cs->subtyp]);
+ if ((cs->subtyp != SCT_1) && ((sub_sys_id != SCT_SUBSYS_ID) ||
+ (sub_vendor_id != SCT_SUBVEN_ID)))
return (0);
+ if (cs->subtyp == SCT_1) {
+ if (!pci_present()) {
+ printk(KERN_ERR "bkm_a4t: no PCI bus present\n");
+ return (0);
+ }
+ while ((dev_a8 = pci_find_device(PCI_VENDOR_ID_PLX,
+ PCI_DEVICE_ID_PLX_9050, dev_a8))) {
+
+ sub_vendor_id = dev_a8->subsystem_vendor;
+ sub_sys_id = dev_a8->subsystem_device;
+ if ((sub_sys_id == SCT_SUBSYS_ID) &&
+ (sub_vendor_id == SCT_SUBVEN_ID)) {
+ if (pci_enable_device(dev_a8))
+ return(0);
+ pci_ioaddr1 = pci_resource_start(dev_a8, 1);
+ pci_irq = dev_a8->irq;
+ pci_bus = dev_a8->bus->number;
+ pci_device_fn = dev_a8->devfn;
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ printk(KERN_WARNING "HiSax: %s (%s): Card not found\n",
+ CardType[card->typ],
+ sct_quadro_subtypes[cs->subtyp]);
+ return (0);
+ }
+#ifdef ATTEMPT_PCI_REMAPPING
+/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_REVISION_ID, &pci_rev_id);
+ if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) {
+ printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n",
+ CardType[card->typ],
+ sct_quadro_subtypes[cs->subtyp]);
+ /* Restart PCI negotiation */
+ pcibios_write_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_1, (u_int) - 1);
+ /* Move up by 0x80 byte */
+ pci_ioaddr1 += 0x80;
+ pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
+ pcibios_write_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_1, pci_ioaddr1);
+ dev_a8->resource[ 1].start = pci_ioaddr1;
+ }
+#endif /* End HACK */
}
if (!pci_irq) { /* IRQ range check ?? */
printk(KERN_WARNING "HiSax: %s (%s): No IRQ\n",
@@ -372,25 +373,6 @@ __initfunc(int
sct_quadro_subtypes[cs->subtyp]);
return (0);
}
-#ifdef ATTEMPT_PCI_REMAPPING
-/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */
- pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_REVISION_ID, &pci_rev_id);
- if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) {
- printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n",
- CardType[card->typ],
- sct_quadro_subtypes[cs->subtyp]);
- /* Restart PCI negotiation */
- pcibios_write_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_1, (u_int) - 1);
- /* Move up by 0x80 byte */
- pci_ioaddr1 += 0x80;
- pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
- pcibios_write_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_1, pci_ioaddr1);
- dev_a8->resource[ 1].start = pci_ioaddr1;
- }
-/* End HACK */
-#endif
pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &pci_ioaddr1);
pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &pci_ioaddr2);
pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_3, &pci_ioaddr3);
@@ -417,23 +399,42 @@ __initfunc(int
/* pci_ioaddr5 is for the first subdevice only */
cs->hw.ax.plx_adr = pci_ioaddr1;
/* Enter all ipac_base addresses */
- ipac_state[SCT_1].base = pci_ioaddr5 + 0x00;
- ipac_state[SCT_2].base = pci_ioaddr4 + 0x08;
- ipac_state[SCT_3].base = pci_ioaddr3 + 0x10;
- ipac_state[SCT_4].base = pci_ioaddr2 + 0x20;
- /* For isac and hscx control path */
- cs->hw.ax.base = ipac_state[cs->subtyp].base;
+ switch(cs->subtyp) {
+ case 1:
+ cs->hw.ax.base = pci_ioaddr5 + 0x00;
+ if (sct_alloc_io(pci_ioaddr1, 256))
+ return(0);
+ if (sct_alloc_io(pci_ioaddr5, 256))
+ return(0);
+ /* disable all IPAC */
+ writereg(pci_ioaddr5, pci_ioaddr5 + 4,
+ IPAC_MASK, 0xFF);
+ writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c,
+ IPAC_MASK, 0xFF);
+ writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14,
+ IPAC_MASK, 0xFF);
+ writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24,
+ IPAC_MASK, 0xFF);
+ break;
+ case 2:
+ cs->hw.ax.base = pci_ioaddr4 + 0x08;
+ if (sct_alloc_io(pci_ioaddr4, 256))
+ return(0);
+ break;
+ case 3:
+ cs->hw.ax.base = pci_ioaddr3 + 0x10;
+ if (sct_alloc_io(pci_ioaddr3, 256))
+ return(0);
+ break;
+ case 4:
+ cs->hw.ax.base = pci_ioaddr2 + 0x20;
+ if (sct_alloc_io(pci_ioaddr2, 256))
+ return(0);
+ break;
+ }
/* For isac and hscx data path */
cs->hw.ax.data_adr = cs->hw.ax.base + 4;
-#else
- printk(KERN_WARNING "HiSax: %s (%s): NO_PCI_BIOS\n",
- CardType[card->typ],
- sct_quadro_subtypes[cs->subtyp]);
- printk(KERN_WARNING "HiSax: %s (%s): Unable to configure\n",
- CardType[card->typ],
- sct_quadro_subtypes[cs->subtyp]);
- return (0);
-#endif /* CONFIG_PCI */
+
printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4X, 0x%.4X, 0x%.4X and IRQ %d\n",
CardType[card->typ],
sct_quadro_subtypes[cs->subtyp],
@@ -444,19 +445,6 @@ __initfunc(int
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- /* Disable all currently not active ipacs */
- if (!is_ipac_active(SCT_1))
- set_ipac_active(SCT_1, 0);
- if (!is_ipac_active(SCT_2))
- set_ipac_active(SCT_2, 0);
- if (!is_ipac_active(SCT_3))
- set_ipac_active(SCT_3, 0);
- if (!is_ipac_active(SCT_4))
- set_ipac_active(SCT_4, 0);
-
- /* Perfom general reset (if possible) */
- reset_bkm(cs);
-
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
@@ -473,4 +461,7 @@ __initfunc(int
sct_quadro_subtypes[cs->subtyp],
readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
return (1);
+#else
+ printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
+#endif /* CONFIG_PCI */
}
diff --git a/drivers/isdn/hisax/bkm_ax.h b/drivers/isdn/hisax/bkm_ax.h
index 418c4bd47..e513c81a6 100644
--- a/drivers/isdn/hisax/bkm_ax.h
+++ b/drivers/isdn/hisax/bkm_ax.h
@@ -19,13 +19,21 @@
/* A4T */
-#define I20_DEVICE_ID 0x6120 /* I20 PCI device ID */
-#define I20_VENDOR_ID 0x11DE /* I20 PCI vendor ID */
+#ifndef PCI_VENDOR_ID_ZORAN
+#define PCI_VENDOR_ID_ZORAN 0x11DE
+#endif
+#ifndef PCI_DEVICE_ID_ZORAN_36120
+#define PCI_DEVICE_ID_ZORAN_36120 0x6120
+#endif
#define A4T_SUBVEN_ID 0x0871
#define A4T_SUBSYS_ID 0xFFA4
/* Scitel Quadro */
-#define PLX_DEVICE_ID 0x9050 /* Scitel Quadro PLX */
-#define PLX_VENDOR_ID 0x10B5
+#ifndef PCI_VENDOR_ID_PLX
+#define PCI_VENDOR_ID_PLX 0x10B5
+#endif
+#ifndef PCI_DEVICE_ID_PLX_9050
+#define PCI_DEVICE_ID_PLX_9050 0x9050
+#endif
#define SCT_SUBVEN_ID 0x0871
#define SCT_SUBSYS_ID 0xFFA8
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index 9ed33d0f3..4d3290392 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -366,7 +366,7 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg)
* No need to return "unknown" for calls without OAD,
* cause that's handled in linklevel now (replaced by '0')
*/
- memcpy (&ic.parm.setup, &chanp->proc->para.setup, sizeof(ic.parm.setup));
+ memcpy(&ic.parm.setup, &chanp->proc->para.setup, sizeof(setup_parm));
ret = chanp->cs->iif.statcallb(&ic);
if (chanp->debug & 1)
link_debug(chanp, 1, "statcallb ret=%d", ret);
@@ -383,12 +383,16 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg)
FsmChangeState(fi, ST_IN_PROCEED_SEND);
chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc);
if (ret == 5) {
- memcpy (&chanp->setup, &ic.parm.setup, sizeof(chanp->setup));
+ memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm));
chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
}
break;
case 2: /* Rejecting Call */
break;
+ case 3: /* incomplete number */
+ FsmDelTimer(&chanp->drel_timer, 61);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc);
+ break;
case 0: /* OK, nobody likes this call */
default: /* statcallb problems */
chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
@@ -795,6 +799,8 @@ static struct FsmNode fnlist[] HISAX_INITDATA =
{ST_IN_WAIT_LL, EV_HANGUP, lli_reject_req},
{ST_IN_WAIT_LL, EV_DISCONNECT_IND, lli_release_req},
{ST_IN_WAIT_LL, EV_RELEASE, lli_dhup_close},
+ {ST_IN_WAIT_LL, EV_SETUP_IND, lli_deliver_call},
+ {ST_IN_WAIT_LL, EV_SETUP_ERR, lli_error},
{ST_IN_ALERT_SENT, EV_SETUP_CMPL_IND, lli_init_bchan_in},
{ST_IN_ALERT_SENT, EV_ACCEPTD, lli_send_dconnect},
{ST_IN_ALERT_SENT, EV_HANGUP, lli_disconnect_reject},
@@ -956,6 +962,9 @@ dchan_l3l4(struct PStack *st, int pr, void *arg)
return;
switch (pr) {
+ case (CC_MORE_INFO | INDICATION):
+ FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
+ break;
case (CC_DISCONNECT | INDICATION):
FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
break;
@@ -1103,7 +1112,7 @@ init_chan(int chan, struct IsdnCardState *csta)
chanp->fi.printdebug = callc_debug;
FsmInitTimer(&chanp->fi, &chanp->dial_timer);
FsmInitTimer(&chanp->fi, &chanp->drel_timer);
- if (!chan || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
+ if (!chan || (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags) && chan < 2)) {
init_d_st(chanp);
} else {
chanp->d_st = csta->channel->d_st;
@@ -1176,9 +1185,12 @@ lldata_handler(struct PStack *st, int pr, void *arg)
switch (pr) {
case (DL_DATA | INDICATION):
- if (chanp->data_open)
+ if (chanp->data_open) {
+ if (chanp->debug & 0x800)
+ link_debug(chanp, 0, "lldata: %d", skb->len);
chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
- else {
+ } else {
+ link_debug(chanp, 0, "lldata: channel not open");
dev_kfree_skb(skb);
}
break;
@@ -1205,10 +1217,12 @@ lltrans_handler(struct PStack *st, int pr, void *arg)
switch (pr) {
case (PH_DATA | INDICATION):
- if (chanp->data_open)
+ if (chanp->data_open) {
+ if (chanp->debug & 0x800)
+ link_debug(chanp, 0, "lltrans: %d", skb->len);
chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
- else {
- link_debug(chanp, 0, "channel not open");
+ } else {
+ link_debug(chanp, 0, "lltrans: channel not open");
dev_kfree_skb(skb);
}
break;
@@ -1233,6 +1247,8 @@ ll_writewakeup(struct PStack *st, int len)
struct Channel *chanp = st->lli.userdata;
isdn_ctrl ic;
+ if (chanp->debug & 0x800)
+ link_debug(chanp, 0, "llwakeup: %d", len);
ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_BSENT;
ic.arg = chanp->chan;
@@ -1506,7 +1522,7 @@ HiSax_command(isdn_ctrl * ic)
link_debug(chanp, 1, "DIAL %s -> %s (%d,%d)",
ic->parm.setup.eazmsn, ic->parm.setup.phone,
ic->parm.setup.si1, ic->parm.setup.si2);
- memcpy (&chanp->setup, &ic->parm.setup, sizeof (chanp->setup));
+ memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm));
if (!strcmp(chanp->setup.eazmsn, "0"))
chanp->setup.eazmsn[0] = '\0';
/* this solution is dirty and may be change, if
@@ -1526,6 +1542,7 @@ HiSax_command(isdn_ctrl * ic)
break;
case (ISDN_CMD_ACCEPTD):
chanp = csta->channel + ic->arg;
+ memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm));
if (chanp->debug & 1)
link_debug(chanp, 1, "ACCEPTD");
FsmEvent(&chanp->fi, EV_ACCEPTD, NULL);
@@ -1722,7 +1739,7 @@ HiSax_command(isdn_ctrl * ic)
chanp = csta->channel + ic->arg;
if (chanp->debug & 1)
link_debug(chanp, 1, "REDIR");
- memcpy (&chanp->setup, &ic->parm.setup, sizeof(chanp->setup));
+ memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm));
FsmEvent(&chanp->fi, EV_REDIR, NULL);
break;
diff --git a/drivers/isdn/hisax/cert.c b/drivers/isdn/hisax/cert.c
index bf0c6465d..64f3bccc8 100644
--- a/drivers/isdn/hisax/cert.c
+++ b/drivers/isdn/hisax/cert.c
@@ -17,11 +17,9 @@ certification_check(int output) {
#if CERTIFICATION == 0
if (output) {
printk(KERN_INFO "HiSax: Approval certification valid\n");
- printk(KERN_INFO "HiSax: Approved with ELSA Quickstep series cards\n");
- printk(KERN_INFO "HiSax: Approval registration numbers:\n");
- printk(KERN_INFO "HiSax: German D133361J CETECOM ICT Services GmbH\n");
- printk(KERN_INFO "HiSax: EU (D133362J) CETECOM ICT Services GmbH\n");
+ printk(KERN_INFO "HiSax: Approved with ELSA Microlink PCI cards\n");
printk(KERN_INFO "HiSax: Approved with Eicon Technology Diva 2.01 PCI cards\n");
+ printk(KERN_INFO "HiSax: Approved with Sedlbauer Speedfax + cards\n");
}
return(0);
#endif
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index cda0fe872..4ed7e4129 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -47,7 +47,7 @@
* 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
+ * 20 Travers Technologies NETjet-S PCI card
* 21 TELES PCI no parameter
* 22 Sedlbauer Speed Star p0=irq p1=iobase
* 23 reserved
@@ -65,6 +65,7 @@
* 35 HFC 2BDS0 PCI none
* 36 Winbond 6692 PCI none
* 37 HFC 2BDS0 S+/SP p0=irq p1=iobase
+ * 38 Travers Technologies NETspider-U PCI card
*
* protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
*
@@ -76,11 +77,11 @@ const char *CardType[] =
"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)",
+ "Compaq ISA", "NETjet-S", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)",
"AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI",
"Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir",
"Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
- "HFC 2BDS0 SX",
+ "HFC 2BDS0 SX", "NETspider-U",
};
void HiSax_closecard(int cardnr);
@@ -106,7 +107,6 @@ EXPORT_SYMBOL(elsa_init_pcmcia);
#define DEFAULT_CFG {11,0x170,0,0}
int avm_a1_init_pcmcia(void*, int, int*, int);
EXPORT_SYMBOL(avm_a1_init_pcmcia);
-EXPORT_SYMBOL(HiSax_closecard);
#endif /* CONFIG_HISAX_AVM_A1_PCMCIA */
#ifdef CONFIG_HISAX_FRITZPCI
@@ -198,7 +198,7 @@ EXPORT_SYMBOL(sedl_init_pcmcia);
#ifdef CONFIG_HISAX_NETJET
#undef DEFAULT_CARD
#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_NETJET
+#define DEFAULT_CARD ISDN_CTYPE_NETJET_S
#define DEFAULT_CFG {0,0,0,0}
#endif
@@ -280,22 +280,29 @@ EXPORT_SYMBOL(sedl_init_pcmcia);
#define DEFAULT_CFG {0,0,0,0}
#endif
+#ifdef CONFIG_HISAX_NETJET_U
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_NETJET_U
+#define DEFAULT_CFG {0,0,0,0}
+#endif
+
#ifdef CONFIG_HISAX_1TR6
#define DEFAULT_PROTO ISDN_PTYPE_1TR6
#define DEFAULT_PROTO_NAME "1TR6"
#endif
-#ifdef CONFIG_HISAX_EURO
-#undef DEFAULT_PROTO
-#define DEFAULT_PROTO ISDN_PTYPE_EURO
-#undef DEFAULT_PROTO_NAME
-#define DEFAULT_PROTO_NAME "EURO"
-#endif
#ifdef CONFIG_HISAX_NI1
#undef DEFAULT_PROTO
#define DEFAULT_PROTO ISDN_PTYPE_NI1
#undef DEFAULT_PROTO_NAME
#define DEFAULT_PROTO_NAME "NI1"
#endif
+#ifdef CONFIG_HISAX_EURO
+#undef DEFAULT_PROTO
+#define DEFAULT_PROTO ISDN_PTYPE_EURO
+#undef DEFAULT_PROTO_NAME
+#define DEFAULT_PROTO_NAME "EURO"
+#endif
#ifndef DEFAULT_PROTO
#define DEFAULT_PROTO ISDN_PTYPE_UNKNOWN
#define DEFAULT_PROTO_NAME "UNKNOWN"
@@ -304,6 +311,10 @@ EXPORT_SYMBOL(sedl_init_pcmcia);
#error "HiSax: No cards configured"
#endif
+int hisax_init_pcmcia(void *, int *, struct IsdnCard *);
+EXPORT_SYMBOL(hisax_init_pcmcia);
+EXPORT_SYMBOL(HiSax_closecard);
+
#define FIRST_CARD { \
DEFAULT_CARD, \
DEFAULT_PROTO, \
@@ -400,9 +411,9 @@ HiSaxVersion(void))
printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n");
#ifdef MODULE
- printk(KERN_INFO "HiSax: Version 3.3e (module)\n");
+ printk(KERN_INFO "HiSax: Version 3.5 (module)\n");
#else
- printk(KERN_INFO "HiSax: Version 3.3e (kernel)\n");
+ printk(KERN_INFO "HiSax: Version 3.5 (kernel)\n");
#endif
strcpy(tmp, l1_revision);
printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp));
@@ -546,8 +557,8 @@ extern int setup_sportster(struct IsdnCard *card);
extern int setup_mic(struct IsdnCard *card);
#endif
-#if CARD_NETJET
-extern int setup_netjet(struct IsdnCard *card);
+#if CARD_NETJET_S
+extern int setup_netjet_s(struct IsdnCard *card);
#endif
#if CARD_HFCS
@@ -598,6 +609,10 @@ extern int setup_gazel(struct IsdnCard *card);
extern int setup_w6692(struct IsdnCard *card);
#endif
+#if CARD_NETJET_U
+extern int setup_netjet_u(struct IsdnCard *card);
+#endif
+
/*
* Find card with given driverId
*/
@@ -800,7 +815,7 @@ ll_stop(struct IsdnCardState *cs)
ic.command = ISDN_STAT_STOP;
ic.driver = cs->myid;
cs->iif.statcallb(&ic);
- CallcFreeChan(cs);
+// CallcFreeChan(cs);
}
static void
@@ -923,6 +938,8 @@ checkcard(int cardnr, char *id, int *busy_flag))
cs->busy_flag = busy_flag;
cs->irq_flags = I4L_IRQ_FLAG;
#if TEI_PER_CARD
+ if (card->protocol == ISDN_PTYPE_NI1)
+ test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
#else
test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
#endif
@@ -1067,9 +1084,9 @@ checkcard(int cardnr, char *id, int *busy_flag))
ret = setup_mic(card);
break;
#endif
-#if CARD_NETJET
- case ISDN_CTYPE_NETJET:
- ret = setup_netjet(card);
+#if CARD_NETJET_S
+ case ISDN_CTYPE_NETJET_S:
+ ret = setup_netjet_s(card);
break;
#endif
#if CARD_HFCS
@@ -1133,6 +1150,11 @@ checkcard(int cardnr, char *id, int *busy_flag))
ret = setup_w6692(card);
break;
#endif
+#if CARD_NETJET_U
+ case ISDN_CTYPE_NETJET_U:
+ ret = setup_netjet_u(card);
+ break;
+#endif
default:
printk(KERN_WARNING
"HiSax: Support for %s Card not selected\n",
@@ -1252,6 +1274,9 @@ HiSax_closecard(int cardnr)
if (cards[cardnr].cs) {
ll_stop(cards[cardnr].cs);
release_tei(cards[cardnr].cs);
+
+ CallcFreeChan(cards[cardnr].cs);
+
closecard(cardnr);
if (cards[cardnr].cs->irq)
free_irq(cards[cardnr].cs->irq, cards[cardnr].cs);
@@ -1310,10 +1335,19 @@ HiSax_reportcard(int cardnr, int sel)
__initfunc(int
HiSax_init(void))
{
- int i;
+ int i,j;
#ifdef MODULE
int nzproto = 0;
+ if (!type[0]) {
+ /* We 'll register drivers later, but init basic functions*/
+ CallcNew();
+ Isdnl3New();
+ Isdnl2New();
+ TeiNew();
+ Isdnl1New();
+ return 0;
+ }
#ifdef CONFIG_HISAX_ELSA
if (type[0] == ISDN_CTYPE_ELSA_PCMCIA) {
/* we have exported and return in this case */
@@ -1338,41 +1372,41 @@ HiSax_init(void))
#ifdef MODULE
if (id) /* If id= string used */
HiSax_id = id;
- for (i = 0; i < HISAX_MAX_CARDS; i++) {
- cards[i].typ = type[i];
+ for (i = j = 0; j < HISAX_MAX_CARDS; i++) {
+ cards[j].typ = type[i];
if (protocol[i]) {
- cards[i].protocol = protocol[i];
+ cards[j].protocol = protocol[i];
nzproto++;
}
switch (type[i]) {
case ISDN_CTYPE_16_0:
- cards[i].para[0] = irq[i];
- cards[i].para[1] = mem[i];
- cards[i].para[2] = io[i];
+ cards[j].para[0] = irq[i];
+ cards[j].para[1] = mem[i];
+ cards[j].para[2] = io[i];
break;
case ISDN_CTYPE_8_0:
- cards[i].para[0] = irq[i];
- cards[i].para[1] = mem[i];
+ cards[j].para[0] = irq[i];
+ cards[j].para[1] = mem[i];
break;
#ifdef IO0_IO1
case ISDN_CTYPE_PNP:
case ISDN_CTYPE_NICCY:
- cards[i].para[0] = irq[i];
- cards[i].para[1] = io0[i];
- cards[i].para[2] = io1[i];
+ cards[j].para[0] = irq[i];
+ cards[j].para[1] = io0[i];
+ cards[j].para[2] = io1[i];
break;
case ISDN_CTYPE_COMPAQ_ISA:
- cards[i].para[0] = irq[i];
- cards[i].para[1] = io0[i];
- cards[i].para[2] = io1[i];
- cards[i].para[3] = io[i];
+ cards[j].para[0] = irq[i];
+ cards[j].para[1] = io0[i];
+ cards[j].para[2] = io1[i];
+ cards[j].para[3] = io[i];
break;
#endif
case ISDN_CTYPE_ELSA:
case ISDN_CTYPE_HFC_PCI:
- cards[i].para[0] = io[i];
+ cards[j].para[0] = io[i];
break;
case ISDN_CTYPE_16_3:
case ISDN_CTYPE_TELESPCMCIA:
@@ -1396,26 +1430,42 @@ HiSax_init(void))
case ISDN_CTYPE_HSTSAPHIR:
case ISDN_CTYPE_GAZEL:
case ISDN_CTYPE_HFC_SX:
- cards[i].para[0] = irq[i];
- cards[i].para[1] = io[i];
+ cards[j].para[0] = irq[i];
+ cards[j].para[1] = io[i];
break;
case ISDN_CTYPE_ISURF:
- cards[i].para[0] = irq[i];
- cards[i].para[1] = io[i];
- cards[i].para[2] = mem[i];
+ cards[j].para[0] = irq[i];
+ cards[j].para[1] = io[i];
+ cards[j].para[2] = mem[i];
break;
case ISDN_CTYPE_ELSA_PCI:
- case ISDN_CTYPE_NETJET:
+ case ISDN_CTYPE_NETJET_S:
case ISDN_CTYPE_AMD7930:
case ISDN_CTYPE_TELESPCI:
case ISDN_CTYPE_W6692:
+ case ISDN_CTYPE_NETJET_U:
break;
case ISDN_CTYPE_BKM_A4T:
- break;
+ break;
case ISDN_CTYPE_SCT_QUADRO:
- cards[i].para[0] = irq[i];
+ if (irq[i]) {
+ cards[j].para[0] = irq[i];
+ } else {
+ /* QUADRO is a 4 BRI card */
+ cards[j++].para[0] = 1;
+ cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+ cards[j].protocol = protocol[i];
+ cards[j++].para[0] = 2;
+ cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+ cards[j].protocol = protocol[i];
+ cards[j++].para[0] = 3;
+ cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+ cards[j].protocol = protocol[i];
+ cards[j].para[0] = 4;
+ }
break;
}
+ j++;
}
if (!nzproto) {
printk(KERN_WARNING "HiSax: Warning - no protocol specified\n");
@@ -1620,3 +1670,21 @@ int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
return (0);
}
#endif
+
+int hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card)
+{
+ u_char ids[16];
+ int ret = -1;
+
+ cards[nrcards] = *card;
+ if (nrcards)
+ sprintf(ids, "HiSax%d", nrcards);
+ else
+ sprintf(ids, "HiSax");
+ if (!checkcard(nrcards, ids, busy_flag)) {
+ return(-1);
+ }
+ ret = nrcards;
+ nrcards++;
+ return (ret);
+}
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index 002ee0d60..f39dd7558 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -47,12 +47,18 @@ const char *Diva_revision = "$Revision: 1.21 $";
#define DIVA_IPAC_PCI 4
/* PCI stuff */
-#define PCI_VENDOR_EICON_DIEHL 0x1133
-#define PCI_DIVA20PRO_ID 0xe001
-#define PCI_DIVA20_ID 0xe002
-#define PCI_DIVA20PRO_U_ID 0xe003
-#define PCI_DIVA20_U_ID 0xe004
-#define PCI_DIVA_201 0xe005
+#ifndef PCI_VENDOR_ID_EICON
+#define PCI_VENDOR_ID_EICON 0x1133
+#endif
+#ifndef PCI_DEVICE_ID_EICON_DIVA20
+#define PCI_DEVICE_ID_EICON_DIVA20 0xe002
+#endif
+#ifndef PCI_DEVICE_ID_EICON_DIVA20_U
+#define PCI_DEVICE_ID_EICON_DIVA20_U 0xe004
+#endif
+#ifndef PCI_DEVICE_ID_EICON_DIVA201
+#define PCI_DEVICE_ID_EICON_DIVA201 0xe005
+#endif
/* CTRL (Read) */
#define DIVA_IRQ_STAT 0x01
@@ -70,10 +76,16 @@ const char *Diva_revision = "$Revision: 1.21 $";
/* Siemens PITA */
#define PITA_MISC_REG 0x1c
+#ifdef __BIG_ENDIAN
+#define PITA_PARA_SOFTRESET 0x00000001
+#define PITA_PARA_MPX_MODE 0x00000004
+#define PITA_INT0_ENABLE 0x00000200
+#else
#define PITA_PARA_SOFTRESET 0x01000000
#define PITA_PARA_MPX_MODE 0x04000000
#define PITA_INT0_ENABLE 0x00020000
-#define PITA_INT0_STATUS 0x00000002
+#endif
+#define PITA_INT0_STATUS 0x02
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
@@ -122,7 +134,7 @@ writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size
static inline u_char
memreadreg(unsigned long adr, u_char off)
{
- return(0xff & *((unsigned int *)
+ return(*((unsigned char *)
(((unsigned int *)adr) + off)));
}
@@ -870,24 +882,24 @@ setup_diva(struct IsdnCard *card))
}
cs->subtyp = 0;
- if ((dev_diva = pci_find_device(PCI_VENDOR_EICON_DIEHL,
- PCI_DIVA20_ID, dev_diva))) {
+ if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
if (pci_enable_device(dev_diva))
- return (0);
+ return(0);
cs->subtyp = DIVA_PCI;
cs->irq = dev_diva->irq;
cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
- } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_EICON_DIEHL,
- PCI_DIVA20_U_ID, dev_diva_u))) {
+ } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
if (pci_enable_device(dev_diva_u))
- return (0);
+ return(0);
cs->subtyp = DIVA_PCI;
cs->irq = dev_diva_u->irq;
cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
- } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_EICON_DIEHL,
- PCI_DIVA_201, dev_diva201))) {
+ } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
if (pci_enable_device(dev_diva201))
- return (0);
+ return(0);
cs->subtyp = DIVA_IPAC_PCI;
cs->irq = dev_diva201->irq;
cs->hw.diva.pci_cfg =
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index 70cff176b..f2357cc4b 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -29,10 +29,10 @@
extern const char *CardType[];
-const char *Elsa_revision = "$Revision: 2.20 $";
+const char *Elsa_revision = "$Revision: 2.23 $";
const char *Elsa_Types[] =
{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
- "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI",
+ "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI",
"PCMCIA-IPAC" };
const char *ITACVer[] =
@@ -66,9 +66,15 @@ const char *ITACVer[] =
#define ELSA_PCMCIA_IPAC 11
/* PCI stuff */
-#define PCI_VENDOR_ELSA 0x1048
-#define PCI_QS1000_ID 0x1000
-#define PCI_QS3000_ID 0x3000
+#ifndef PCI_VENDOR_ID_ELSA
+#define PCI_VENDOR_ID_ELSA 0x1048
+#endif
+#ifndef PCI_DEVICE_ID_ELSA_MIRCOLINK
+#define PCI_DEVICE_ID_ELSA_MIRCOLINK 0x1000
+#endif
+#ifndef PCI_DEVICE_ID_ELSA_QS3000
+#define PCI_DEVICE_ID_ELSA_QS3000 0x3000
+#endif
#define ELSA_PCI_IRQ_MASK 0x04
/* ITAC Registeradressen (only Microlink PC) */
@@ -723,7 +729,8 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV;
printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n",
cs->hw.elsa.counter);
- if (abs(cs->hw.elsa.counter - 13) < 3) {
+ if ((cs->hw.elsa.counter > 10) &&
+ (cs->hw.elsa.counter < 16)) {
printk(KERN_INFO "Elsa: timer and irq OK\n");
ret = 0;
} else {
@@ -982,18 +989,18 @@ setup_elsa(struct IsdnCard *card)
return(0);
}
cs->subtyp = 0;
- if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ELSA, PCI_QS1000_ID,
- dev_qs1000))) {
+ if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+ PCI_DEVICE_ID_ELSA_MIRCOLINK, dev_qs1000))) {
if (pci_enable_device(dev_qs1000))
- return (0);
+ return(0);
cs->subtyp = ELSA_QS1000PCI;
cs->irq = dev_qs1000->irq;
cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
- } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ELSA,
- PCI_QS3000_ID, dev_qs3000))) {
- if (pci_enable_device(dev_qs1000))
- return (0);
+ } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+ PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
+ if (pci_enable_device(dev_qs3000))
+ return(0);
cs->subtyp = ELSA_QS3000PCI;
cs->irq = dev_qs3000->irq;
cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c
index 4693318dc..eb777b184 100644
--- a/drivers/isdn/hisax/gazel.c
+++ b/drivers/isdn/hisax/gazel.c
@@ -26,10 +26,18 @@ const char *gazel_revision = "$Revision: 2.8 $";
#define R742 4
/* Gazel R685 stuff */
-#define GAZEL_MANUFACTURER 0x10b5
-#define GAZEL_R685 0x1030
-#define GAZEL_R753 0x1152
-#define GAZEL_DJINN_ITOO 0x1151
+#ifndef PCI_VENDOR_ID_PLX
+#define PCI_VENDOR_ID_PLX 0x10b5
+#endif
+#ifndef PCI_DEVICE_ID_PLX_R685
+#define PCI_DEVICE_ID_PLX_R685 0x1030
+#endif
+#ifndef PCI_DEVICE_ID_PLX_R753
+#define PCI_DEVICE_ID_PLX_R753 0x1152
+#endif
+#ifndef PCI_DEVICE_ID_PLX_DJINN_ITOO
+#define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151
+#endif
#define PLX_CNTRL 0x50 /* registre de controle PLX */
#define RESET_GAZEL 0x4
@@ -565,25 +573,25 @@ setup_gazelpci(struct IsdnCardState *cs)
printk(KERN_WARNING "Gazel: No PCI bus present\n");
return 1;
}
- seekcard = GAZEL_R685;
+ seekcard = PCI_DEVICE_ID_PLX_R685;
for (nbseek = 0; nbseek < 3; nbseek++) {
- if ((dev_tel = pci_find_device(GAZEL_MANUFACTURER, seekcard, dev_tel))) {
+ if ((dev_tel = pci_find_device(PCI_VENDOR_ID_PLX, seekcard, dev_tel))) {
if (pci_enable_device(dev_tel))
return 1;
pci_irq = dev_tel->irq;
- pci_ioaddr0 = dev_tel->resource[ 1].start;
- pci_ioaddr1 = dev_tel->resource[ 2].start;
+ pci_ioaddr0 = pci_resource_start(dev_tel, 1);
+ pci_ioaddr1 = pci_resource_start(dev_tel, 2);
found = 1;
}
if (found)
break;
else {
switch (seekcard) {
- case GAZEL_R685:
- seekcard = GAZEL_R753;
+ case PCI_DEVICE_ID_PLX_R685:
+ seekcard = PCI_DEVICE_ID_PLX_R753;
break;
- case GAZEL_R753:
- seekcard = GAZEL_DJINN_ITOO;
+ case PCI_DEVICE_ID_PLX_R753:
+ seekcard = PCI_DEVICE_ID_PLX_DJINN_ITOO;
break;
}
}
@@ -612,7 +620,7 @@ setup_gazelpci(struct IsdnCardState *cs)
cs->irq_flags |= SA_SHIRQ;
switch (seekcard) {
- case GAZEL_R685:
+ case PCI_DEVICE_ID_PLX_R685:
printk(KERN_INFO "Gazel: Card PCI R685 found\n");
cs->subtyp = R685;
cs->dc.isac.adf2 = 0x87;
@@ -623,8 +631,8 @@ setup_gazelpci(struct IsdnCardState *cs)
"Gazel: hscx A:0x%X hscx B:0x%X\n",
cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
break;
- case GAZEL_R753:
- case GAZEL_DJINN_ITOO:
+ case PCI_DEVICE_ID_PLX_R753:
+ case PCI_DEVICE_ID_PLX_DJINN_ITOO:
printk(KERN_INFO "Gazel: Card PCI R753 found\n");
cs->subtyp = R753;
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
index f28585a84..bd1442046 100644
--- a/drivers/isdn/hisax/hfc_2bs0.c
+++ b/drivers/isdn/hisax/hfc_2bs0.c
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bs0.c,v 1.14 2000/06/26 08:59:13 keil Exp $
+/* $Id: hfc_2bs0.c,v 1.15 2000/07/26 20:46:47 keil Exp $
*
* specific routines for CCD's HFC 2BS0
*
@@ -203,7 +203,7 @@ hfc_empty_fifo(struct BCState *bcs, int count)
ptr = skb_put(skb, count);
idx = 0;
cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
- while ((idx < count - 3) && WaitNoBusy(cs)) {
+ while ((idx < count) && WaitNoBusy(cs)) {
*ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
idx++;
}
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index ac673c227..c0ff9b642 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.c,v 1.30 2000/06/26 08:59:13 keil Exp $
+/* $Id: hfc_pci.c,v 1.31 2000/08/20 07:32:55 keil Exp $
* hfc_pci.c low level driver for CCD´s hfc-pci based cards
*
@@ -34,7 +34,7 @@
extern const char *CardType[];
-static const char *hfcpci_revision = "$Revision: 1.30 $";
+static const char *hfcpci_revision = "$Revision: 1.31 $";
/* table entry in the PCI devices list */
typedef struct {
@@ -44,7 +44,9 @@ typedef struct {
char *card_name;
} PCI_ENTRY;
-#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */
+#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */
+#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */
+#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */
static const PCI_ENTRY id_list[] =
{
@@ -63,7 +65,10 @@ static const PCI_ENTRY id_list[] =
{0x1051, 0x0100, "Motorola MC145575", "MC145575"},
{0x1397, 0xB100, "Seyeon", "B100"},
{0x15B0, 0x2BD0, "Zoltrix", "2BD0"},
- {0x114f, 0x71, "Digi intl.","Digicom"},
+ {0x114F, 0x70,"Digi International", "Digi DataFire Micro V IOM2 (Europe)"},
+ {0x114F, 0x71,"Digi International", "Digi DataFire Micro V (Europe)"},
+ {0x114F, 0x72,"Digi International", "Digi DataFire Micro V IOM2 (North America)"},
+ {0x114F, 0x73,"Digi International", "Digi DataFire Micro V (North America)"},
{0, 0, NULL, NULL},
};
@@ -130,7 +135,7 @@ reset_hfcpci(struct IsdnCardState *cs)
cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */
Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
- Write_hfc(cs, HFCPCI_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */
+ Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_TE); /* ST-Bit delay for TE-Mode */
cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE;
Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e); /* S/T Auto awake */
cs->hw.hfcpci.bswapped = 0; /* no exchange */
@@ -254,6 +259,9 @@ hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type * bz, u_char * bdata, int cou
(*(bdata + (zp->z1 - B_SUB_VAL)))) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count);
+#ifdef ERROR_STATISTIC
+ bcs->err_inv++;
+#endif
bz->za[new_f2].z2 = new_z2;
bz->f2 = new_f2; /* next buffer */
skb = NULL;
@@ -320,6 +328,9 @@ receive_dmsg(struct IsdnCardState *cs)
(df->data[zp->z1])) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[zp->z1]);
+#ifdef ERROR_STATISTIC
+ cs->err_rx++;
+#endif
df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */
df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1);
} else if ((skb = dev_alloc_skb(rcnt - 3))) {
@@ -506,6 +517,9 @@ hfcpci_fill_dfifo(struct IsdnCardState *cs)
if (fcnt > (MAX_D_FRAMES - 1)) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "hfcpci_fill_Dfifo more as 14 frames");
+#ifdef ERROR_STATISTIC
+ cs->err_tx++;
+#endif
return;
}
/* now determine free bytes in FIFO buffer */
@@ -740,6 +754,7 @@ hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic)
(!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) {
save_flags(flags);
cli();
+ Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_NT); /* ST-Bit delay for NT-Mode */
Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* HFC ST G0 */
udelay(10);
cs->hw.hfcpci.sctrl |= SCTRL_MODE_NT;
@@ -1625,6 +1640,9 @@ __initfunc(int
int i;
struct pci_dev *tmp_hfcpci = NULL;
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
strcpy(tmp, hfcpci_revision);
printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
#if CONFIG_PCI
@@ -1645,7 +1663,7 @@ __initfunc(int
if (tmp_hfcpci) {
if (pci_enable_device(tmp_hfcpci))
continue;
- if ((card->para[0]) && (card->para[0] != pci_resource_start(tmp_hfcpci, 0)))
+ if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK)))
continue;
else
break;
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 11d38baf2..abc215f87 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -39,8 +39,11 @@
#define HW_POWERUP 0x0008
#define HW_ACTIVATE 0x0010
#define HW_DEACTIVATE 0x0018
+
+#define HW_INFO1 0x0010
#define HW_INFO2 0x0020
#define HW_INFO3 0x0030
+#define HW_INFO4 0x0040
#define HW_INFO4_P8 0x0040
#define HW_INFO4_P10 0x0048
#define HW_RSYNC 0x0060
@@ -90,6 +93,7 @@
#define CC_SUSPEND 0x0370
#define CC_PROCEED_SEND 0x0374
#define CC_REDIR 0x0378
+#define CC_T302 0x0382
#define CC_T303 0x0383
#define CC_T304 0x0384
#define CC_T305 0x0385
@@ -100,6 +104,7 @@
#define CC_T313 0x0393
#define CC_T318 0x0398
#define CC_T319 0x0399
+#define CC_TSPID 0x03A0
#define CC_NOSETUP_RSP 0x03E0
#define CC_SETUP_ERR 0x03E1
#define CC_SUSPEND_ERR 0x03E2
@@ -108,6 +113,7 @@
#define CC_RELEASE_ERR 0x03E5
#define CC_RESTART 0x03F4
#define CC_TDSS1_IO 0x13F4 /* DSS1 IO user timer */
+#define CC_TNI1_IO 0x13F5 /* NI1 IO user timer */
/* define maximum number of possible waiting incoming calls */
#define MAX_WAITING_CALLS 2
@@ -115,13 +121,19 @@
#ifdef __KERNEL__
-/* include only l3dss1 specific process structures, but no other defines */
+/* include l3dss1 & ni1 specific process structures, but no other defines */
#ifdef CONFIG_HISAX_EURO
#define l3dss1_process
#include "l3dss1.h"
#undef l3dss1_process
#endif CONFIG_HISAX_EURO
+#ifdef CONFIG_HISAX_NI1
+ #define l3ni1_process
+ #include "l3ni1.h"
+ #undef l3ni1_process
+#endif CONFIG_HISAX_NI1
+
#define MAX_DFRAME_LEN 260
#define MAX_DFRAME_LEN_L1 300
#define HSCX_BUFMAX 4096
@@ -184,6 +196,7 @@ struct L3Timer {
#define FLG_L1_ACTTIMER 4
#define FLG_L1_T3RUN 5
#define FLG_L1_PULL_REQ 6
+#define FLG_L1_UINT 7
struct Layer1 {
void *hardware;
@@ -298,7 +311,7 @@ struct PStack {
struct Layer3 l3;
struct LLInterface lli;
struct Management ma;
- int protocol; /* EDSS1 or 1TR6 */
+ int protocol; /* EDSS1, 1TR6 or NI1 */
/* protocol specific data fields */
union
@@ -306,6 +319,9 @@ struct PStack {
#ifdef CONFIG_HISAX_EURO
dss1_stk_priv dss1; /* private dss1 data */
#endif CONFIG_HISAX_EURO
+#ifdef CONFIG_HISAX_NI1
+ ni1_stk_priv ni1; /* private ni1 data */
+#endif CONFIG_HISAX_NI1
} prot;
};
@@ -327,6 +343,9 @@ struct l3_process {
#ifdef CONFIG_HISAX_EURO
dss1_proc_priv dss1; /* private dss1 data */
#endif CONFIG_HISAX_EURO
+#ifdef CONFIG_HISAX_NI1
+ ni1_proc_priv ni1; /* private ni1 data */
+#endif CONFIG_HISAX_NI1
} prot;
};
@@ -373,10 +392,17 @@ struct isar_hw {
};
struct hdlc_stat_reg {
+#ifdef __BIG_ENDIAN
+ u_char fill __attribute__((packed));
+ u_char mode __attribute__((packed));
+ u_char xml __attribute__((packed));
+ u_char cmd __attribute__((packed));
+#else
u_char cmd __attribute__((packed));
u_char xml __attribute__((packed));
u_char mode __attribute__((packed));
u_char fill __attribute__((packed));
+#endif
};
struct hdlc_hw {
@@ -805,6 +831,22 @@ struct w6692_chip {
int ph_state;
};
+struct icc_chip {
+ int ph_state;
+ u_char *mon_tx;
+ u_char *mon_rx;
+ int mon_txp;
+ int mon_txc;
+ int mon_rxp;
+ struct arcofi_msg *arcofi_list;
+ struct timer_list arcofitimer;
+ wait_queue_head_t arcofi_wait;
+ u_char arcofi_bc;
+ u_char arcofi_state;
+ u_char mocr;
+ u_char adf2;
+};
+
#define HW_IOM1 0
#define HW_IPAC 1
#define HW_ISAR 2
@@ -815,6 +857,7 @@ struct w6692_chip {
#define FLG_LOCK_ATOMIC 7
#define FLG_ARCOFI_TIMER 8
#define FLG_ARCOFI_ERROR 9
+#define FLG_HW_L1_UINT 10
struct IsdnCardState {
unsigned char typ;
@@ -883,6 +926,7 @@ struct IsdnCardState {
struct hfcpci_chip hfcpci;
struct hfcsx_chip hfcsx;
struct w6692_chip w6692;
+ struct icc_chip icc;
} dc;
u_char *rcvbuf;
int rcvidx;
@@ -924,7 +968,7 @@ struct IsdnCardState {
#define ISDN_CTYPE_MIC 17
#define ISDN_CTYPE_ELSA_PCI 18
#define ISDN_CTYPE_COMPAQ_ISA 19
-#define ISDN_CTYPE_NETJET 20
+#define ISDN_CTYPE_NETJET_S 20
#define ISDN_CTYPE_TELESPCI 21
#define ISDN_CTYPE_SEDLBAUER_PCMCIA 22
#define ISDN_CTYPE_AMD7930 23
@@ -942,7 +986,8 @@ struct IsdnCardState {
#define ISDN_CTYPE_HFC_PCI 35
#define ISDN_CTYPE_W6692 36
#define ISDN_CTYPE_HFC_SX 37
-#define ISDN_CTYPE_COUNT 37
+#define ISDN_CTYPE_NETJET_U 38
+#define ISDN_CTYPE_COUNT 38
#ifdef ISDN_CHIP_ISAC
@@ -1091,12 +1136,12 @@ struct IsdnCardState {
#endif
#ifdef CONFIG_HISAX_NETJET
-#define CARD_NETJET 1
+#define CARD_NETJET_S 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
#else
-#define CARD_NETJET 0
+#define CARD_NETJET_S 0
#endif
#ifdef CONFIG_HISAX_HFCS
@@ -1204,17 +1249,19 @@ struct IsdnCardState {
#define CARD_W6692 0
#endif
-#define TEI_PER_CARD 0
-
-#ifdef CONFIG_HISAX_1TR6
-#undef TEI_PER_CARD
-#define TEI_PER_CARD 1
+#ifdef CONFIG_HISAX_NETJET_U
+#define CARD_NETJET_U 1
+#ifndef ISDN_CHIP_ICC
+#define ISDN_CHIP_ICC 1
+#endif
+#ifndef HISAX_UINTERFACE
+#define HISAX_UINTERFACE 1
+#endif
+#else
+#define CARD_NETJET_U 0
#endif
-#ifdef CONFIG_HISAX_EURO
-#undef TEI_PER_CARD
#define TEI_PER_CARD 1
-#endif
/* L1 Debug */
#define L1_DEB_WARN 0x01
@@ -1238,7 +1285,7 @@ extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf,
struct IsdnCard {
int typ;
- int protocol; /* EDSS1 or 1TR6 */
+ int protocol; /* EDSS1, 1TR6 or NI1 */
unsigned int para[4];
struct IsdnCardState *cs;
};
diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c
new file mode 100644
index 000000000..5f2740e9e
--- /dev/null
+++ b/drivers/isdn/hisax/icc.c
@@ -0,0 +1,685 @@
+// $Id: icc.c,v 1.3 2000/08/20 07:34:04 keil Exp $
+//-----------------------------------------------------------------------------
+//
+// ICC specific routines
+//
+// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd
+// www.traverse.com.au
+//
+// 1999.6.25 Initial implementation of routines for Siemens ISDN
+// Communication Controler PEB 2070 based on the ISAC routines
+// written by Karsten Keil.
+//
+// This file is (c) under GNU PUBLIC LICENSE
+//
+//-----------------------------------------------------------------------------
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "icc.h"
+// #include "arcofi.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+
+#define DBUSY_TIMER_VALUE 80
+#define ARCOFI_USE 0
+
+static char *ICCVer[] HISAX_INITDATA =
+{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"};
+
+void
+ICCVersion(struct IsdnCardState *cs, char *s)
+{
+ int val;
+
+ val = cs->readisac(cs, ICC_RBCH);
+ printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]);
+}
+
+static void
+ph_command(struct IsdnCardState *cs, unsigned int command)
+{
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ph_command %x", command);
+ cs->writeisac(cs, ICC_CIX0, (command << 2) | 3);
+}
+
+
+static void
+icc_new_ph(struct IsdnCardState *cs)
+{
+ switch (cs->dc.icc.ph_state) {
+ case (ICC_IND_EI1):
+ ph_command(cs, ICC_CMD_DI);
+ l1_msg(cs, HW_RESET | INDICATION, NULL);
+ break;
+ case (ICC_IND_DC):
+ l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
+ break;
+ case (ICC_IND_DR):
+ l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+ break;
+ case (ICC_IND_PU):
+ l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+ break;
+ case (ICC_IND_FJ):
+ l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+ break;
+ case (ICC_IND_AR):
+ l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+ break;
+ case (ICC_IND_AI):
+ l1_msg(cs, HW_INFO4 | INDICATION, NULL);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+icc_bh(struct IsdnCardState *cs)
+{
+ struct PStack *stptr;
+
+ if (!cs)
+ return;
+ if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
+ if (cs->debug)
+ debugl1(cs, "D-Channel Busy cleared");
+ stptr = cs->stlist;
+ while (stptr != NULL) {
+ stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
+ stptr = stptr->next;
+ }
+ }
+ if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
+ icc_new_ph(cs);
+ if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
+ DChannel_proc_rcv(cs);
+ if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
+ DChannel_proc_xmt(cs);
+#if ARCOFI_USE
+ if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
+ return;
+ if (test_and_clear_bit(D_RX_MON1, &cs->event))
+ arcofi_fsm(cs, ARCOFI_RX_END, NULL);
+ if (test_and_clear_bit(D_TX_MON1, &cs->event))
+ arcofi_fsm(cs, ARCOFI_TX_END, NULL);
+#endif
+}
+
+void
+icc_empty_fifo(struct IsdnCardState *cs, int count)
+{
+ u_char *ptr;
+ long flags;
+
+ if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+ debugl1(cs, "icc_empty_fifo");
+
+ if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "icc_empty_fifo overrun %d",
+ cs->rcvidx + count);
+ cs->writeisac(cs, ICC_CMDR, 0x80);
+ cs->rcvidx = 0;
+ return;
+ }
+ ptr = cs->rcvbuf + cs->rcvidx;
+ cs->rcvidx += count;
+ save_flags(flags);
+ cli();
+ cs->readisacfifo(cs, ptr, count);
+ cs->writeisac(cs, ICC_CMDR, 0x80);
+ restore_flags(flags);
+ if (cs->debug & L1_DEB_ISAC_FIFO) {
+ char *t = cs->dlog;
+
+ t += sprintf(t, "icc_empty_fifo cnt %d", count);
+ QuickHex(t, ptr, count);
+ debugl1(cs, cs->dlog);
+ }
+}
+
+static void
+icc_fill_fifo(struct IsdnCardState *cs)
+{
+ int count, more;
+ u_char *ptr;
+ long flags;
+
+ if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+ debugl1(cs, "icc_fill_fifo");
+
+ if (!cs->tx_skb)
+ return;
+
+ count = cs->tx_skb->len;
+ if (count <= 0)
+ return;
+
+ more = 0;
+ if (count > 32) {
+ more = !0;
+ count = 32;
+ }
+ save_flags(flags);
+ cli();
+ ptr = cs->tx_skb->data;
+ skb_pull(cs->tx_skb, count);
+ cs->tx_cnt += count;
+ cs->writeisacfifo(cs, ptr, count);
+ cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa);
+ if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+ debugl1(cs, "icc_fill_fifo dbusytimer running");
+ del_timer(&cs->dbusytimer);
+ }
+ init_timer(&cs->dbusytimer);
+ cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
+ add_timer(&cs->dbusytimer);
+ restore_flags(flags);
+ if (cs->debug & L1_DEB_ISAC_FIFO) {
+ char *t = cs->dlog;
+
+ t += sprintf(t, "icc_fill_fifo cnt %d", count);
+ QuickHex(t, ptr, count);
+ debugl1(cs, cs->dlog);
+ }
+}
+
+void
+icc_sched_event(struct IsdnCardState *cs, int event)
+{
+ test_and_set_bit(event, &cs->event);
+ queue_task(&cs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+void
+icc_interrupt(struct IsdnCardState *cs, u_char val)
+{
+ u_char exval, v1;
+ struct sk_buff *skb;
+ unsigned int count;
+ long flags;
+
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ICC interrupt %x", val);
+ if (val & 0x80) { /* RME */
+ exval = cs->readisac(cs, ICC_RSTA);
+ if ((exval & 0x70) != 0x20) {
+ if (exval & 0x40) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ICC RDO");
+#ifdef ERROR_STATISTIC
+ cs->err_rx++;
+#endif
+ }
+ if (!(exval & 0x20)) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ICC CRC error");
+#ifdef ERROR_STATISTIC
+ cs->err_crc++;
+#endif
+ }
+ cs->writeisac(cs, ICC_CMDR, 0x80);
+ } else {
+ count = cs->readisac(cs, ICC_RBCL) & 0x1f;
+ if (count == 0)
+ count = 32;
+ icc_empty_fifo(cs, count);
+ save_flags(flags);
+ cli();
+ if ((count = cs->rcvidx) > 0) {
+ cs->rcvidx = 0;
+ if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+ printk(KERN_WARNING "HiSax: D receive out of memory\n");
+ else {
+ memcpy(skb_put(skb, count), cs->rcvbuf, count);
+ skb_queue_tail(&cs->rq, skb);
+ }
+ }
+ restore_flags(flags);
+ }
+ cs->rcvidx = 0;
+ icc_sched_event(cs, D_RCVBUFREADY);
+ }
+ if (val & 0x40) { /* RPF */
+ icc_empty_fifo(cs, 32);
+ }
+ if (val & 0x20) { /* RSC */
+ /* never */
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ICC RSC interrupt");
+ }
+ if (val & 0x10) { /* XPR */
+ if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+ del_timer(&cs->dbusytimer);
+ if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+ icc_sched_event(cs, D_CLEARBUSY);
+ if (cs->tx_skb) {
+ if (cs->tx_skb->len) {
+ icc_fill_fifo(cs);
+ goto afterXPR;
+ } else {
+ dev_kfree_skb_irq(cs->tx_skb);
+ cs->tx_cnt = 0;
+ cs->tx_skb = NULL;
+ }
+ }
+ if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+ cs->tx_cnt = 0;
+ icc_fill_fifo(cs);
+ } else
+ icc_sched_event(cs, D_XMTBUFREADY);
+ }
+ afterXPR:
+ if (val & 0x04) { /* CISQ */
+ exval = cs->readisac(cs, ICC_CIR0);
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ICC CIR0 %02X", exval );
+ if (exval & 2) {
+ cs->dc.icc.ph_state = (exval >> 2) & 0xf;
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state);
+ icc_sched_event(cs, D_L1STATECHANGE);
+ }
+ if (exval & 1) {
+ exval = cs->readisac(cs, ICC_CIR1);
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ICC CIR1 %02X", exval );
+ }
+ }
+ if (val & 0x02) { /* SIN */
+ /* never */
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ICC SIN interrupt");
+ }
+ if (val & 0x01) { /* EXI */
+ exval = cs->readisac(cs, ICC_EXIR);
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ICC EXIR %02x", exval);
+ if (exval & 0x80) { /* XMR */
+ debugl1(cs, "ICC XMR");
+ printk(KERN_WARNING "HiSax: ICC XMR\n");
+ }
+ if (exval & 0x40) { /* XDU */
+ debugl1(cs, "ICC XDU");
+ printk(KERN_WARNING "HiSax: ICC XDU\n");
+#ifdef ERROR_STATISTIC
+ cs->err_tx++;
+#endif
+ if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+ del_timer(&cs->dbusytimer);
+ if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+ icc_sched_event(cs, D_CLEARBUSY);
+ if (cs->tx_skb) { /* Restart frame */
+ skb_push(cs->tx_skb, cs->tx_cnt);
+ cs->tx_cnt = 0;
+ icc_fill_fifo(cs);
+ } else {
+ printk(KERN_WARNING "HiSax: ICC XDU no skb\n");
+ debugl1(cs, "ICC XDU no skb");
+ }
+ }
+ if (exval & 0x04) { /* MOS */
+ v1 = cs->readisac(cs, ICC_MOSR);
+ if (cs->debug & L1_DEB_MONITOR)
+ debugl1(cs, "ICC MOSR %02x", v1);
+#if ARCOFI_USE
+ if (v1 & 0x08) {
+ if (!cs->dc.icc.mon_rx) {
+ if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ICC MON RX out of memory!");
+ cs->dc.icc.mocr &= 0xf0;
+ cs->dc.icc.mocr |= 0x0a;
+ cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+ goto afterMONR0;
+ } else
+ cs->dc.icc.mon_rxp = 0;
+ }
+ if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
+ cs->dc.icc.mocr &= 0xf0;
+ cs->dc.icc.mocr |= 0x0a;
+ cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+ cs->dc.icc.mon_rxp = 0;
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ICC MON RX overflow!");
+ goto afterMONR0;
+ }
+ cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0);
+ if (cs->debug & L1_DEB_MONITOR)
+ debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]);
+ if (cs->dc.icc.mon_rxp == 1) {
+ cs->dc.icc.mocr |= 0x04;
+ cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+ }
+ }
+ afterMONR0:
+ if (v1 & 0x80) {
+ if (!cs->dc.icc.mon_rx) {
+ if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ICC MON RX out of memory!");
+ cs->dc.icc.mocr &= 0x0f;
+ cs->dc.icc.mocr |= 0xa0;
+ cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+ goto afterMONR1;
+ } else
+ cs->dc.icc.mon_rxp = 0;
+ }
+ if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
+ cs->dc.icc.mocr &= 0x0f;
+ cs->dc.icc.mocr |= 0xa0;
+ cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+ cs->dc.icc.mon_rxp = 0;
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ICC MON RX overflow!");
+ goto afterMONR1;
+ }
+ cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1);
+ if (cs->debug & L1_DEB_MONITOR)
+ debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]);
+ cs->dc.icc.mocr |= 0x40;
+ cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+ }
+ afterMONR1:
+ if (v1 & 0x04) {
+ cs->dc.icc.mocr &= 0xf0;
+ cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+ cs->dc.icc.mocr |= 0x0a;
+ cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+ icc_sched_event(cs, D_RX_MON0);
+ }
+ if (v1 & 0x40) {
+ cs->dc.icc.mocr &= 0x0f;
+ cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+ cs->dc.icc.mocr |= 0xa0;
+ cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+ icc_sched_event(cs, D_RX_MON1);
+ }
+ if (v1 & 0x02) {
+ if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc &&
+ (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) &&
+ !(v1 & 0x08))) {
+ cs->dc.icc.mocr &= 0xf0;
+ cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+ cs->dc.icc.mocr |= 0x0a;
+ cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+ if (cs->dc.icc.mon_txc &&
+ (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
+ icc_sched_event(cs, D_TX_MON0);
+ goto AfterMOX0;
+ }
+ if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
+ icc_sched_event(cs, D_TX_MON0);
+ goto AfterMOX0;
+ }
+ cs->writeisac(cs, ICC_MOX0,
+ cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
+ if (cs->debug & L1_DEB_MONITOR)
+ debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]);
+ }
+ AfterMOX0:
+ if (v1 & 0x20) {
+ if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc &&
+ (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) &&
+ !(v1 & 0x80))) {
+ cs->dc.icc.mocr &= 0x0f;
+ cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+ cs->dc.icc.mocr |= 0xa0;
+ cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+ if (cs->dc.icc.mon_txc &&
+ (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
+ icc_sched_event(cs, D_TX_MON1);
+ goto AfterMOX1;
+ }
+ if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
+ icc_sched_event(cs, D_TX_MON1);
+ goto AfterMOX1;
+ }
+ cs->writeisac(cs, ICC_MOX1,
+ cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
+ if (cs->debug & L1_DEB_MONITOR)
+ debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]);
+ }
+ AfterMOX1:
+#endif
+ }
+ }
+}
+
+static void
+ICC_l1hw(struct PStack *st, int pr, void *arg)
+{
+ struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+ struct sk_buff *skb = arg;
+ int val;
+
+ switch (pr) {
+ case (PH_DATA |REQUEST):
+ if (cs->debug & DEB_DLOG_HEX)
+ LogFrame(cs, skb->data, skb->len);
+ if (cs->debug & DEB_DLOG_VERBOSE)
+ dlogframe(cs, skb, 0);
+ if (cs->tx_skb) {
+ skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG /* psa */
+ if (cs->debug & L1_DEB_LAPD)
+ Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+ } else {
+ cs->tx_skb = skb;
+ cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG /* psa */
+ if (cs->debug & L1_DEB_LAPD)
+ Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+ icc_fill_fifo(cs);
+ }
+ break;
+ case (PH_PULL |INDICATION):
+ if (cs->tx_skb) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+ skb_queue_tail(&cs->sq, skb);
+ break;
+ }
+ if (cs->debug & DEB_DLOG_HEX)
+ LogFrame(cs, skb->data, skb->len);
+ if (cs->debug & DEB_DLOG_VERBOSE)
+ dlogframe(cs, skb, 0);
+ cs->tx_skb = skb;
+ cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG /* psa */
+ if (cs->debug & L1_DEB_LAPD)
+ Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+ icc_fill_fifo(cs);
+ break;
+ case (PH_PULL | REQUEST):
+#ifdef L2FRAME_DEBUG /* psa */
+ if (cs->debug & L1_DEB_LAPD)
+ debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+ if (!cs->tx_skb) {
+ test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ } else
+ test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ case (HW_RESET | REQUEST):
+ if ((cs->dc.icc.ph_state == ICC_IND_EI1) ||
+ (cs->dc.icc.ph_state == ICC_IND_DR))
+ ph_command(cs, ICC_CMD_DI);
+ else
+ ph_command(cs, ICC_CMD_RES);
+ break;
+ case (HW_ENABLE | REQUEST):
+ ph_command(cs, ICC_CMD_DI);
+ break;
+ case (HW_INFO1 | REQUEST):
+ ph_command(cs, ICC_CMD_AR);
+ break;
+ case (HW_INFO3 | REQUEST):
+ ph_command(cs, ICC_CMD_AI);
+ break;
+ case (HW_TESTLOOP | REQUEST):
+ val = 0;
+ if (1 & (long) arg)
+ val |= 0x0c;
+ if (2 & (long) arg)
+ val |= 0x3;
+ if (test_bit(HW_IOM1, &cs->HW_Flags)) {
+ /* IOM 1 Mode */
+ if (!val) {
+ cs->writeisac(cs, ICC_SPCR, 0xa);
+ cs->writeisac(cs, ICC_ADF1, 0x2);
+ } else {
+ cs->writeisac(cs, ICC_SPCR, val);
+ cs->writeisac(cs, ICC_ADF1, 0xa);
+ }
+ } else {
+ /* IOM 2 Mode */
+ cs->writeisac(cs, ICC_SPCR, val);
+ if (val)
+ cs->writeisac(cs, ICC_ADF1, 0x8);
+ else
+ cs->writeisac(cs, ICC_ADF1, 0x0);
+ }
+ break;
+ case (HW_DEACTIVATE | RESPONSE):
+ discard_queue(&cs->rq);
+ discard_queue(&cs->sq);
+ if (cs->tx_skb) {
+ dev_kfree_skb_any(cs->tx_skb);
+ cs->tx_skb = NULL;
+ }
+ if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+ del_timer(&cs->dbusytimer);
+ if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+ icc_sched_event(cs, D_CLEARBUSY);
+ break;
+ default:
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "icc_l1hw unknown %04x", pr);
+ break;
+ }
+}
+
+void
+setstack_icc(struct PStack *st, struct IsdnCardState *cs)
+{
+ st->l1.l1hw = ICC_l1hw;
+}
+
+void
+DC_Close_icc(struct IsdnCardState *cs) {
+ if (cs->dc.icc.mon_rx) {
+ kfree(cs->dc.icc.mon_rx);
+ cs->dc.icc.mon_rx = NULL;
+ }
+ if (cs->dc.icc.mon_tx) {
+ kfree(cs->dc.icc.mon_tx);
+ cs->dc.icc.mon_tx = NULL;
+ }
+}
+
+static void
+dbusy_timer_handler(struct IsdnCardState *cs)
+{
+ struct PStack *stptr;
+ int rbch, star;
+
+ if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+ rbch = cs->readisac(cs, ICC_RBCH);
+ star = cs->readisac(cs, ICC_STAR);
+ if (cs->debug)
+ debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
+ rbch, star);
+ if (rbch & ICC_RBCH_XAC) { /* D-Channel Busy */
+ test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
+ stptr = cs->stlist;
+ while (stptr != NULL) {
+ stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
+ stptr = stptr->next;
+ }
+ } else {
+ /* discard frame; reset transceiver */
+ test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
+ if (cs->tx_skb) {
+ dev_kfree_skb_any(cs->tx_skb);
+ cs->tx_cnt = 0;
+ cs->tx_skb = NULL;
+ } else {
+ printk(KERN_WARNING "HiSax: ICC D-Channel Busy no skb\n");
+ debugl1(cs, "D-Channel Busy no skb");
+ }
+ cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */
+ cs->irq_func(cs->irq, cs, NULL);
+ }
+ }
+}
+
+HISAX_INITFUNC(void
+initicc(struct IsdnCardState *cs))
+{
+ cs->tqueue.routine = (void *) (void *) icc_bh;
+ cs->setstack_d = setstack_icc;
+ cs->DC_Close = DC_Close_icc;
+ cs->dc.icc.mon_tx = NULL;
+ cs->dc.icc.mon_rx = NULL;
+ cs->dbusytimer.function = (void *) dbusy_timer_handler;
+ cs->dbusytimer.data = (long) cs;
+ init_timer(&cs->dbusytimer);
+ cs->writeisac(cs, ICC_MASK, 0xff);
+ cs->dc.icc.mocr = 0xaa;
+ if (test_bit(HW_IOM1, &cs->HW_Flags)) {
+ /* IOM 1 Mode */
+ cs->writeisac(cs, ICC_ADF2, 0x0);
+ cs->writeisac(cs, ICC_SPCR, 0xa);
+ cs->writeisac(cs, ICC_ADF1, 0x2);
+ cs->writeisac(cs, ICC_STCR, 0x70);
+ cs->writeisac(cs, ICC_MODE, 0xc9);
+ } else {
+ /* IOM 2 Mode */
+ if (!cs->dc.icc.adf2)
+ cs->dc.icc.adf2 = 0x80;
+ cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2);
+ cs->writeisac(cs, ICC_SQXR, 0xa0);
+ cs->writeisac(cs, ICC_SPCR, 0x20);
+ cs->writeisac(cs, ICC_STCR, 0x70);
+ cs->writeisac(cs, ICC_MODE, 0xca);
+ cs->writeisac(cs, ICC_TIMR, 0x00);
+ cs->writeisac(cs, ICC_ADF1, 0x20);
+ }
+ ph_command(cs, ICC_CMD_RES);
+ cs->writeisac(cs, ICC_MASK, 0x0);
+ ph_command(cs, ICC_CMD_DI);
+}
+
+HISAX_INITFUNC(void
+clear_pending_icc_ints(struct IsdnCardState *cs))
+{
+ int val, eval;
+
+ val = cs->readisac(cs, ICC_STAR);
+ debugl1(cs, "ICC STAR %x", val);
+ val = cs->readisac(cs, ICC_MODE);
+ debugl1(cs, "ICC MODE %x", val);
+ val = cs->readisac(cs, ICC_ADF2);
+ debugl1(cs, "ICC ADF2 %x", val);
+ val = cs->readisac(cs, ICC_ISTA);
+ debugl1(cs, "ICC ISTA %x", val);
+ if (val & 0x01) {
+ eval = cs->readisac(cs, ICC_EXIR);
+ debugl1(cs, "ICC EXIR %x", eval);
+ }
+ val = cs->readisac(cs, ICC_CIR0);
+ debugl1(cs, "ICC CIR0 %x", val);
+ cs->dc.icc.ph_state = (val >> 2) & 0xf;
+ icc_sched_event(cs, D_L1STATECHANGE);
+ /* Disable all IRQ */
+ cs->writeisac(cs, ICC_MASK, 0xFF);
+}
diff --git a/drivers/isdn/hisax/icc.h b/drivers/isdn/hisax/icc.h
new file mode 100644
index 000000000..b3ecbdcf8
--- /dev/null
+++ b/drivers/isdn/hisax/icc.h
@@ -0,0 +1,73 @@
+// $Id: icc.h,v 1.2 2000/06/26 08:59:13 keil Exp $
+//-----------------------------------------------------------------------------
+//
+// ICC specific routines
+//
+// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd
+// www.traverse.com.au
+//
+// 1999.7.14 Initial implementation of routines for Siemens ISDN
+// Communication Controler PEB 2070 based on the ISAC routines
+// written by Karsten Keil.
+//
+// This file is (c) under GNU PUBLIC LICENSE
+//
+//-----------------------------------------------------------------------------
+
+
+/* All Registers original Siemens Spec */
+
+#define ICC_MASK 0x20
+#define ICC_ISTA 0x20
+#define ICC_STAR 0x21
+#define ICC_CMDR 0x21
+#define ICC_EXIR 0x24
+#define ICC_ADF2 0x39
+#define ICC_SPCR 0x30
+#define ICC_ADF1 0x38
+#define ICC_CIR0 0x31
+#define ICC_CIX0 0x31
+#define ICC_CIR1 0x33
+#define ICC_CIX1 0x33
+#define ICC_STCR 0x37
+#define ICC_MODE 0x22
+#define ICC_RSTA 0x27
+#define ICC_RBCL 0x25
+#define ICC_RBCH 0x2A
+#define ICC_TIMR 0x23
+#define ICC_SQXR 0x3b
+#define ICC_MOSR 0x3a
+#define ICC_MOCR 0x3a
+#define ICC_MOR0 0x32
+#define ICC_MOX0 0x32
+#define ICC_MOR1 0x34
+#define ICC_MOX1 0x34
+
+#define ICC_RBCH_XAC 0x80
+
+#define ICC_CMD_TIM 0x0
+#define ICC_CMD_RES 0x1
+#define ICC_CMD_DU 0x3
+#define ICC_CMD_EI1 0x4
+#define ICC_CMD_SSP 0x5
+#define ICC_CMD_DT 0x6
+#define ICC_CMD_AR 0x8
+#define ICC_CMD_ARL 0xA
+#define ICC_CMD_AI 0xC
+#define ICC_CMD_DI 0xF
+
+#define ICC_IND_DR 0x0
+#define ICC_IND_FJ 0x2
+#define ICC_IND_EI1 0x4
+#define ICC_IND_INT 0x6
+#define ICC_IND_PU 0x7
+#define ICC_IND_AR 0x8
+#define ICC_IND_ARL 0xA
+#define ICC_IND_AI 0xC
+#define ICC_IND_AIL 0xE
+#define ICC_IND_DC 0xF
+
+extern void ICCVersion(struct IsdnCardState *cs, char *s);
+extern void initicc(struct IsdnCardState *cs);
+extern void icc_interrupt(struct IsdnCardState *cs, u_char val);
+extern void clear_pending_icc_ints(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
index 6f19d6cb6..d91f86f02 100644
--- a/drivers/isdn/hisax/isar.c
+++ b/drivers/isdn/hisax/isar.c
@@ -243,6 +243,14 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf)
printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret);
goto reterror;
}
+#ifdef __BIG_ENDIAN
+ sadr = (blk_head.sadr & 0xff)*256 + blk_head.sadr/256;
+ blk_head.sadr = sadr;
+ sadr = (blk_head.len & 0xff)*256 + blk_head.len/256;
+ blk_head.len = sadr;
+ sadr = (blk_head.d_key & 0xff)*256 + blk_head.d_key/256;
+ blk_head.d_key = sadr;
+#endif /* __BIG_ENDIAN */
cnt += BLK_HEAD_SIZE;
p += BLK_HEAD_SIZE;
printk(KERN_DEBUG"isar firmware block (%#x,%5d,%#x)\n",
@@ -284,8 +292,13 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf)
#endif
sadr += noc;
while(noc) {
+#ifdef __BIG_ENDIAN
+ *mp++ = *sp % 256;
+ *mp++ = *sp / 256;
+#else
*mp++ = *sp / 256;
*mp++ = *sp % 256;
+#endif /* __BIG_ENDIAN */
sp++;
noc--;
}
@@ -528,8 +541,9 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
rcv_mbox(cs, ireg, ptr);
if (ireg->cmsb & HDLC_FED) {
if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */
- printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n",
- bcs->hw.isar.rcvidx);
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar frame to short %d",
+ bcs->hw.isar.rcvidx);
} else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2))) {
printk(KERN_WARNING "ISAR: receive out of memory\n");
} else {
@@ -538,6 +552,7 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
skb_queue_tail(&bcs->rqueue, skb);
isar_sched_event(bcs, B_RCVBUFREADY);
}
+ bcs->hw.isar.rcvidx = 0;
}
}
break;
@@ -606,13 +621,16 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
bcs->hw.isar.rcvidx += ireg->clsb;
rcv_mbox(cs, ireg, ptr);
if (ireg->cmsb & HDLC_FED) {
+ int len = bcs->hw.isar.rcvidx +
+ dle_count(bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx);
if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */
- printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n",
- bcs->hw.isar.rcvidx);
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar frame to short %d",
+ bcs->hw.isar.rcvidx);
} else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
printk(KERN_WARNING "ISAR: receive out of memory\n");
} else {
- memcpy(skb_put(skb, bcs->hw.isar.rcvidx),
+ insert_dle((u_char *)skb_put(skb, len),
bcs->hw.isar.rcvbuf,
bcs->hw.isar.rcvidx);
skb_queue_tail(&bcs->rqueue, skb);
@@ -620,8 +638,20 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
send_DLE_ETX(bcs);
isar_sched_event(bcs, B_LL_OK);
}
+ bcs->hw.isar.rcvidx = 0;
}
}
+ if (ireg->cmsb & SART_NMD) { /* ABORT */
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_rcv_frame: no more data");
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ bcs->hw.isar.rcvidx = 0;
+ send_DLE_ETX(bcs);
+ sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
+ ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
+ bcs->hw.isar.state = STFAX_ESCAPE;
+ isar_sched_event(bcs, B_LL_NOCARRIER);
+ }
break;
default:
printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode);
@@ -1044,6 +1074,9 @@ isar_pump_statev_fax(struct BCState *bcs, u_char devt) {
debugl1(cs, "pump stev RSP_DISC");
if (bcs->hw.isar.state == STFAX_ESCAPE) {
switch(bcs->hw.isar.newcmd) {
+ case 0:
+ bcs->hw.isar.state = STFAX_READY;
+ break;
case PCTRL_CMD_FTH:
case PCTRL_CMD_FTM:
p1 = 10;
diff --git a/drivers/isdn/hisax/isar.h b/drivers/isdn/hisax/isar.h
index 7726622ca..d34621834 100644
--- a/drivers/isdn/hisax/isar.h
+++ b/drivers/isdn/hisax/isar.h
@@ -186,7 +186,7 @@
#define HDLC_ERROR 0x1c
#define HDLC_ERR_FAD 0x10
#define HDLC_ERR_RER 0x08
-#define HDLC_ERR_CER 0x01
+#define HDLC_ERR_CER 0x04
#define SART_NMD 0x01
#define BSTAT_RDM0 0x1
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
index d0e734357..f523f378d 100644
--- a/drivers/isdn/hisax/isdnl1.c
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -28,7 +28,7 @@ struct Fsm l1fsm_b =
{NULL, 0, 0, NULL, NULL};
static
-struct Fsm l1fsm_d =
+struct Fsm l1fsm_s =
{NULL, 0, 0, NULL, NULL};
enum {
@@ -41,9 +41,9 @@ enum {
ST_L1_F8,
};
-#define L1D_STATE_COUNT (ST_L1_F8+1)
+#define L1S_STATE_COUNT (ST_L1_F8+1)
-static char *strL1DState[] =
+static char *strL1SState[] =
{
"ST_L1_F2",
"ST_L1_F3",
@@ -54,6 +54,29 @@ static char *strL1DState[] =
"ST_L1_F8",
};
+#ifdef HISAX_UINTERFACE
+static
+struct Fsm l1fsm_u =
+{NULL, 0, 0, NULL, NULL};
+
+enum {
+ ST_L1_RESET,
+ ST_L1_DEACT,
+ ST_L1_SYNC2,
+ ST_L1_TRANS,
+};
+
+#define L1U_STATE_COUNT (ST_L1_TRANS+1)
+
+static char *strL1UState[] =
+{
+ "ST_L1_RESET",
+ "ST_L1_DEACT",
+ "ST_L1_SYNC2",
+ "ST_L1_TRANS",
+};
+#endif
+
enum {
ST_L1_NULL,
ST_L1_WAIT_ACT,
@@ -432,7 +455,7 @@ l1_deact_cnf(struct FsmInst *fi, int event, void *arg)
}
static void
-l1_deact_req(struct FsmInst *fi, int event, void *arg)
+l1_deact_req_s(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
@@ -442,7 +465,7 @@ l1_deact_req(struct FsmInst *fi, int event, void *arg)
}
static void
-l1_power_up(struct FsmInst *fi, int event, void *arg)
+l1_power_up_s(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
@@ -472,7 +495,12 @@ l1_info2_ind(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
- FsmChangeState(fi, ST_L1_F6);
+#ifdef HISAX_UINTERFACE
+ if (test_bit(FLG_L1_UINT, &st->l1.Flags))
+ FsmChangeState(fi, ST_L1_SYNC2);
+ else
+#endif
+ FsmChangeState(fi, ST_L1_F6);
st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
}
@@ -481,7 +509,12 @@ l1_info4_ind(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
- FsmChangeState(fi, ST_L1_F7);
+#ifdef HISAX_UINTERFACE
+ if (test_bit(FLG_L1_UINT, &st->l1.Flags))
+ FsmChangeState(fi, ST_L1_TRANS);
+ else
+#endif
+ FsmChangeState(fi, ST_L1_F7);
st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags))
FsmDelTimer(&st->l1.timer, 4);
@@ -501,6 +534,10 @@ l1_timer3(struct FsmInst *fi, int event, void *arg)
test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags);
if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
L1deactivated(st->l1.hardware);
+
+#ifdef HISAX_UINTERFACE
+ if (!test_bit(FLG_L1_UINT, &st->l1.Flags))
+#endif
if (st->l1.l1m.state != ST_L1_F6) {
FsmChangeState(fi, ST_L1_F3);
st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
@@ -529,7 +566,7 @@ l1_timer_deact(struct FsmInst *fi, int event, void *arg)
}
static void
-l1_activate(struct FsmInst *fi, int event, void *arg)
+l1_activate_s(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
@@ -547,9 +584,9 @@ l1_activate_no(struct FsmInst *fi, int event, void *arg)
}
}
-static struct FsmNode L1DFnList[] HISAX_INITDATA =
+static struct FsmNode L1SFnList[] HISAX_INITDATA =
{
- {ST_L1_F3, EV_PH_ACTIVATE, l1_activate},
+ {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s},
{ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no},
{ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no},
{ST_L1_F3, EV_RESET_IND, l1_reset},
@@ -564,10 +601,10 @@ static struct FsmNode L1DFnList[] HISAX_INITDATA =
{ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf},
{ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf},
{ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf},
- {ST_L1_F6, EV_DEACT_IND, l1_deact_req},
- {ST_L1_F7, EV_DEACT_IND, l1_deact_req},
- {ST_L1_F8, EV_DEACT_IND, l1_deact_req},
- {ST_L1_F3, EV_POWER_UP, l1_power_up},
+ {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s},
+ {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s},
+ {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s},
+ {ST_L1_F3, EV_POWER_UP, l1_power_up_s},
{ST_L1_F4, EV_RSYNC_IND, l1_go_F5},
{ST_L1_F6, EV_RSYNC_IND, l1_go_F8},
{ST_L1_F7, EV_RSYNC_IND, l1_go_F8},
@@ -595,7 +632,68 @@ static struct FsmNode L1DFnList[] HISAX_INITDATA =
{ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact},
};
-#define L1D_FN_COUNT (sizeof(L1DFnList)/sizeof(struct FsmNode))
+#define L1S_FN_COUNT (sizeof(L1SFnList)/sizeof(struct FsmNode))
+
+#ifdef HISAX_UINTERFACE
+static void
+l1_deact_req_u(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ FsmChangeState(fi, ST_L1_RESET);
+ FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
+ test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
+ st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
+}
+
+static void
+l1_power_up_u(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
+ test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags);
+}
+
+static void
+l1_info0_ind(struct FsmInst *fi, int event, void *arg)
+{
+ FsmChangeState(fi, ST_L1_DEACT);
+}
+
+static void
+l1_activate_u(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ st->l1.l1hw(st, HW_INFO1 | REQUEST, NULL);
+}
+
+static struct FsmNode L1UFnList[] HISAX_INITDATA =
+{
+ {ST_L1_RESET, EV_DEACT_IND, l1_deact_req_u},
+ {ST_L1_DEACT, EV_DEACT_IND, l1_deact_req_u},
+ {ST_L1_SYNC2, EV_DEACT_IND, l1_deact_req_u},
+ {ST_L1_TRANS, EV_DEACT_IND, l1_deact_req_u},
+ {ST_L1_DEACT, EV_PH_ACTIVATE, l1_activate_u},
+ {ST_L1_DEACT, EV_POWER_UP, l1_power_up_u},
+ {ST_L1_DEACT, EV_INFO2_IND, l1_info2_ind},
+ {ST_L1_TRANS, EV_INFO2_IND, l1_info2_ind},
+ {ST_L1_RESET, EV_DEACT_CNF, l1_info0_ind},
+ {ST_L1_DEACT, EV_INFO4_IND, l1_info4_ind},
+ {ST_L1_SYNC2, EV_INFO4_IND, l1_info4_ind},
+ {ST_L1_RESET, EV_INFO4_IND, l1_info4_ind},
+ {ST_L1_DEACT, EV_TIMER3, l1_timer3},
+ {ST_L1_SYNC2, EV_TIMER3, l1_timer3},
+ {ST_L1_TRANS, EV_TIMER_ACT, l1_timer_act},
+ {ST_L1_DEACT, EV_TIMER_DEACT, l1_timer_deact},
+ {ST_L1_SYNC2, EV_TIMER_DEACT, l1_timer_deact},
+ {ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact},
+};
+
+#define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode))
+
+#endif
static void
l1b_activate(struct FsmInst *fi, int event, void *arg)
@@ -645,11 +743,18 @@ static struct FsmNode L1BFnList[] HISAX_INITDATA =
HISAX_INITFUNC(void Isdnl1New(void))
{
- l1fsm_d.state_count = L1D_STATE_COUNT;
- l1fsm_d.event_count = L1_EVENT_COUNT;
- l1fsm_d.strEvent = strL1Event;
- l1fsm_d.strState = strL1DState;
- FsmNew(&l1fsm_d, L1DFnList, L1D_FN_COUNT);
+#ifdef HISAX_UINTERFACE
+ l1fsm_u.state_count = L1U_STATE_COUNT;
+ l1fsm_u.event_count = L1_EVENT_COUNT;
+ l1fsm_u.strEvent = strL1Event;
+ l1fsm_u.strState = strL1UState;
+ FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT);
+#endif
+ l1fsm_s.state_count = L1S_STATE_COUNT;
+ l1fsm_s.event_count = L1_EVENT_COUNT;
+ l1fsm_s.strEvent = strL1Event;
+ l1fsm_s.strState = strL1SState;
+ FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT);
l1fsm_b.state_count = L1B_STATE_COUNT;
l1fsm_b.event_count = L1_EVENT_COUNT;
l1fsm_b.strEvent = strL1Event;
@@ -659,7 +764,10 @@ HISAX_INITFUNC(void Isdnl1New(void))
void Isdnl1Free(void)
{
- FsmFree(&l1fsm_d);
+#ifdef HISAX_UINTERFACE
+ FsmFree(&l1fsm_u);
+#endif
+ FsmFree(&l1fsm_s);
FsmFree(&l1fsm_b);
}
@@ -677,7 +785,7 @@ dch_l2l1(struct PStack *st, int pr, void *arg)
case (PH_ACTIVATE | REQUEST):
if (cs->debug)
debugl1(cs, "PH_ACTIVATE_REQ %s",
- strL1DState[st->l1.l1m.state]);
+ st->l1.l1m.fsm->strState[st->l1.l1m.state]);
if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags))
st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
else {
@@ -757,8 +865,16 @@ setstack_HiSax(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.hardware = cs;
st->protocol = cs->protocol;
- st->l1.l1m.fsm = &l1fsm_d;
+ st->l1.l1m.fsm = &l1fsm_s;
st->l1.l1m.state = ST_L1_F3;
+ st->l1.Flags = 0;
+#ifdef HISAX_UINTERFACE
+ if (test_bit(FLG_HW_L1_UINT, &cs->HW_Flags)) {
+ st->l1.l1m.fsm = &l1fsm_u;
+ st->l1.l1m.state = ST_L1_RESET;
+ st->l1.Flags = FLG_L1_UINT;
+ }
+#endif
st->l1.l1m.debug = cs->debug;
st->l1.l1m.userdata = st;
st->l1.l1m.userint = 0;
@@ -768,7 +884,6 @@ setstack_HiSax(struct PStack *st, struct IsdnCardState *cs)
setstack_manager(st);
st->l1.stlistp = &(cs->stlist);
st->l2.l2l1 = dch_l2l1;
- st->l1.Flags = 0;
cs->setstack_d(st, cs);
}
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
index c20706553..b4e473670 100644
--- a/drivers/isdn/hisax/isdnl3.c
+++ b/drivers/isdn/hisax/isdnl3.c
@@ -234,7 +234,7 @@ no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic)
extern void setstack_dss1(struct PStack *st);
#endif
-#ifdef CONFIG_HISAX_NI1
+#ifdef CONFIG_HISAX_NI1
extern void setstack_ni1(struct PStack *st);
#endif
@@ -356,7 +356,7 @@ setstack_l3dc(struct PStack *st, struct Channel *chanp)
setstack_dss1(st);
} else
#endif
-#ifdef CONFIG_HISAX_NI1
+#ifdef CONFIG_HISAX_NI1
if (st->protocol == ISDN_PTYPE_NI1) {
setstack_ni1(st);
} else
@@ -544,7 +544,6 @@ static struct FsmNode L3FnList[] HISAX_INITDATA =
void
l3_msg(struct PStack *st, int pr, void *arg)
{
-
switch (pr) {
case (DL_DATA | REQUEST):
if (st->l3.l3m.state == ST_L3_LC_ESTAB) {
diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c
index ee56447c8..831d788b5 100644
--- a/drivers/isdn/hisax/l3_1tr6.c
+++ b/drivers/isdn/hisax/l3_1tr6.c
@@ -1,4 +1,4 @@
-/* $Id: l3_1tr6.c,v 2.11 2000/06/26 08:59:14 keil Exp $
+/* $Id: l3_1tr6.c,v 2.12 2000/08/20 07:31:30 keil Exp $
*
* German 1TR6 D-channel protocol
*
@@ -17,7 +17,7 @@
#include <linux/ctype.h>
extern char *HiSax_getrev(const char *revision);
-const char *l3_1tr6_revision = "$Revision: 2.11 $";
+const char *l3_1tr6_revision = "$Revision: 2.12 $";
#define MsgHead(ptr, cref, mty, dis) \
*ptr++ = dis; \
@@ -883,7 +883,7 @@ down1tr6(struct PStack *st, int pr, void *arg)
} else {
proc->chan = chan;
chan->proc = proc;
- memcpy (&proc->para.setup, &chan->setup, sizeof (chan->setup));
+ memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
proc->callref = cr;
}
} else {
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index 32ae7576f..8778bf3a0 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -721,6 +721,9 @@ check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist)
u_char *p, ie;
int l, newpos, oldpos;
int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0;
+ u_char codeset = 0;
+ u_char old_codeset = 0;
+ u_char codelock = 1;
p = skb->data;
/* skip cr */
@@ -729,20 +732,34 @@ check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist)
p += l;
mt = *p++;
oldpos = 0;
-/* shift codeset procedure not implemented in the moment */
while ((p - skb->data) < skb->len) {
- if ((newpos = ie_in_set(pc, *p, cl))) {
- if (newpos > 0) {
- if (newpos < oldpos)
- err_seq++;
+ if ((*p & 0xf0) == 0x90) { /* shift codeset */
+ old_codeset = codeset;
+ codeset = *p & 7;
+ if (*p & 0x08)
+ codelock = 0;
+ else
+ codelock = 1;
+ if (pc->debug & L3_DEB_CHECK)
+ l3_debug(pc->st, "check IE shift%scodeset %d->%d",
+ codelock ? " locking ": " ", old_codeset, codeset);
+ p++;
+ continue;
+ }
+ if (!codeset) { /* only codeset 0 */
+ if ((newpos = ie_in_set(pc, *p, cl))) {
+ if (newpos > 0) {
+ if (newpos < oldpos)
+ err_seq++;
+ else
+ oldpos = newpos;
+ }
+ } else {
+ if (ie_in_set(pc, *p, comp_required))
+ err_compr++;
else
- oldpos = newpos;
+ err_ureg++;
}
- } else {
- if (ie_in_set(pc, *p, comp_required))
- err_compr++;
- else
- err_ureg++;
}
ie = *p++;
if (ie & 0x80) {
@@ -752,12 +769,19 @@ check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist)
p += l;
l += 2;
}
- if (l > getmax_ie_len(ie))
+ if (!codeset && (l > getmax_ie_len(ie)))
err_len++;
+ if (!codelock) {
+ if (pc->debug & L3_DEB_CHECK)
+ l3_debug(pc->st, "check IE shift back codeset %d->%d",
+ codeset, old_codeset);
+ codeset = old_codeset;
+ codelock = 1;
+ }
}
if (err_compr | err_ureg | err_len | err_seq) {
if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "check_infoelements mt %x %d/%d/%d/%d",
+ l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d",
mt, err_compr, err_ureg, err_len, err_seq);
if (err_compr)
return(ERR_IE_COMPREHENSION);
@@ -959,7 +983,7 @@ l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
#if EXT_BEARER_CAPS
-u_char *
+static u_char *
EncodeASyncParams(u_char * p, u_char si2)
{ // 7c 06 88 90 21 42 00 bb
@@ -1024,7 +1048,7 @@ EncodeASyncParams(u_char * p, u_char si2)
return p + 3;
}
-u_char
+static u_char
EncodeSyncParams(u_char si2, u_char ai)
{
@@ -1889,6 +1913,16 @@ l3dss1_proceed_req(struct l3_process *pc, u_char pr,
pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc);
}
+static void
+l3dss1_setup_ack_req(struct l3_process *pc, u_char pr,
+ void *arg)
+{
+ newl3state(pc, 25);
+ L3DelTimer(&pc->timer);
+ L3AddTimer(&pc->timer, T302, CC_T302);
+ l3dss1_message(pc, MT_SETUP_ACKNOWLEDGE);
+}
+
/********************************************/
/* deliver a incoming display message to HL */
/********************************************/
@@ -1926,7 +1960,7 @@ l3dss1_progress(struct l3_process *pc, u_char pr, void *arg)
if (p[1] != 2) {
err = 1;
pc->para.cause = 100;
- } else if (p[2] & 0x60) {
+ } else if (!(p[2] & 0x70)) {
switch (p[2]) {
case 0x80:
case 0x81:
@@ -2030,9 +2064,22 @@ l3dss1_information(struct l3_process *pc, u_char pr, void *arg)
{
int ret;
struct sk_buff *skb = arg;
+ u_char *p;
+ char tmp[32];
ret = check_infoelements(pc, skb, ie_INFORMATION);
- l3dss1_std_ie_err(pc, ret);
+ if (ret)
+ l3dss1_std_ie_err(pc, ret);
+ if (pc->state == 25) { /* overlap receiving */
+ L3DelTimer(&pc->timer);
+ p = skb->data;
+ if ((p = findie(p, skb->len, 0x70, 0))) {
+ iecpy(tmp, p, 1);
+ strcat(pc->para.setup.eazmsn, tmp);
+ pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+ }
+ L3AddTimer(&pc->timer, T302, CC_T302);
+ }
}
/******************************/
@@ -2258,6 +2305,16 @@ l3dss1_dummy(struct l3_process *pc, u_char pr, void *arg)
}
static void
+l3dss1_t302(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ pc->para.loc = 0;
+ pc->para.cause = 28; /* invalid number */
+ l3dss1_disconnect_req(pc, pr, NULL);
+ pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+}
+
+static void
l3dss1_t303(struct l3_process *pc, u_char pr, void *arg)
{
if (pc->N303 > 0) {
@@ -2276,6 +2333,7 @@ static void
l3dss1_t304(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
+ pc->para.loc = 0;
pc->para.cause = 102;
l3dss1_disconnect_req(pc, pr, NULL);
pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
@@ -2315,6 +2373,7 @@ static void
l3dss1_t310(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
+ pc->para.loc = 0;
pc->para.cause = 102;
l3dss1_disconnect_req(pc, pr, NULL);
pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
@@ -2324,6 +2383,7 @@ static void
l3dss1_t313(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
+ pc->para.loc = 0;
pc->para.cause = 102;
l3dss1_disconnect_req(pc, pr, NULL);
pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
@@ -2713,32 +2773,36 @@ static struct stateentry downstatelist[] =
CC_SETUP | REQUEST, l3dss1_setup_req},
{SBIT(0),
CC_RESUME | REQUEST, l3dss1_resume_req},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10),
+ {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25),
CC_DISCONNECT | REQUEST, l3dss1_disconnect_req},
{SBIT(12),
CC_RELEASE | REQUEST, l3dss1_release_req},
{ALL_STATES,
CC_RESTART | REQUEST, l3dss1_restart},
- {SBIT(6),
+ {SBIT(6) | SBIT(25),
CC_IGNORE | REQUEST, l3dss1_reset},
- {SBIT(6),
+ {SBIT(6) | SBIT(25),
CC_REJECT | REQUEST, l3dss1_reject_req},
- {SBIT(6),
+ {SBIT(6) | SBIT(25),
CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req},
- {SBIT(6) | SBIT(9),
+ {SBIT(6),
+ CC_MORE_INFO | REQUEST, l3dss1_setup_ack_req},
+ {SBIT(25),
+ CC_MORE_INFO | REQUEST, l3dss1_dummy},
+ {SBIT(6) | SBIT(9) | SBIT(25),
CC_ALERTING | REQUEST, l3dss1_alert_req},
- {SBIT(6) | SBIT(7) | SBIT(9),
+ {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
CC_SETUP | RESPONSE, l3dss1_setup_rsp},
{SBIT(10),
CC_SUSPEND | REQUEST, l3dss1_suspend_req},
- {SBIT(6),
- CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req},
- {SBIT(7) | SBIT(9),
+ {SBIT(7) | SBIT(9) | SBIT(25),
CC_REDIR | REQUEST, l3dss1_redir_req},
{SBIT(6),
CC_REDIR | REQUEST, l3dss1_redir_req_early},
{SBIT(9) | SBIT(25),
CC_DISCONNECT | REQUEST, l3dss1_disconnect_req},
+ {SBIT(25),
+ CC_T302, l3dss1_t302},
{SBIT(1),
CC_T303, l3dss1_t303},
{SBIT(2),
@@ -3081,7 +3145,7 @@ dss1down(struct PStack *st, int pr, void *arg)
if ((proc = dss1_new_l3_process(st, cr))) {
proc->chan = chan;
chan->proc = proc;
- memcpy (&proc->para.setup, &chan->setup, sizeof (chan->setup));
+ memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
proc->callref = cr;
}
} else {
diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c
new file mode 100644
index 000000000..ec28539a7
--- /dev/null
+++ b/drivers/isdn/hisax/l3ni1.c
@@ -0,0 +1,3171 @@
+// $Id: l3ni1.c,v 2.3 2000/06/26 08:59:14 keil Exp $
+//-----------------------------------------------------------------------------
+//
+// NI1 D-channel protocol
+//
+// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd
+// www.traverse.com.au
+//
+// 2000.6.6 Initial implementation of routines for US NI1
+// Layer 3 protocol based on the EURO/DSS1 D-channel protocol
+// driver written by Karsten Keil et al. Thanks also for the
+// code provided by Ragnar Paulson and Will Scales.
+//
+// This file is (c) under GNU PUBLIC LICENSE
+//
+//-----------------------------------------------------------------------------
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl3.h"
+#include "l3ni1.h"
+#include <linux/ctype.h>
+
+extern char *HiSax_getrev(const char *revision);
+const char *ni1_revision = "$Revision: 2.3 $";
+
+#define EXT_BEARER_CAPS 1
+
+#define MsgHead(ptr, cref, mty) \
+ *ptr++ = 0x8; \
+ if (cref == -1) { \
+ *ptr++ = 0x0; \
+ } else { \
+ *ptr++ = 0x1; \
+ *ptr++ = cref^0x80; \
+ } \
+ *ptr++ = mty
+
+
+/**********************************************/
+/* get a new invoke id for remote operations. */
+/* Only a return value != 0 is valid */
+/**********************************************/
+static unsigned char new_invoke_id(struct PStack *p)
+{
+ unsigned char retval;
+ int flags,i;
+
+ i = 32; /* maximum search depth */
+
+ save_flags(flags);
+ cli();
+
+ retval = p->prot.ni1.last_invoke_id + 1; /* try new id */
+ while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) {
+ p->prot.ni1.last_invoke_id = (retval & 0xF8) + 8;
+ i--;
+ }
+ if (i) {
+ while (p->prot.ni1.invoke_used[retval >> 3] & (1 << (retval & 7)))
+ retval++;
+ } else
+ retval = 0;
+ p->prot.ni1.last_invoke_id = retval;
+ p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7));
+ restore_flags(flags);
+
+ return(retval);
+} /* new_invoke_id */
+
+/*************************/
+/* free a used invoke id */
+/*************************/
+static void free_invoke_id(struct PStack *p, unsigned char id)
+{ int flags;
+
+ if (!id) return; /* 0 = invalid value */
+
+ save_flags(flags);
+ cli();
+ p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7));
+ restore_flags(flags);
+} /* free_invoke_id */
+
+
+/**********************************************************/
+/* create a new l3 process and fill in ni1 specific data */
+/**********************************************************/
+static struct l3_process
+*ni1_new_l3_process(struct PStack *st, int cr)
+{ struct l3_process *proc;
+
+ if (!(proc = new_l3_process(st, cr)))
+ return(NULL);
+
+ proc->prot.ni1.invoke_id = 0;
+ proc->prot.ni1.remote_operation = 0;
+ proc->prot.ni1.uus1_data[0] = '\0';
+
+ return(proc);
+} /* ni1_new_l3_process */
+
+/************************************************/
+/* free a l3 process and all ni1 specific data */
+/************************************************/
+static void
+ni1_release_l3_process(struct l3_process *p)
+{
+ free_invoke_id(p->st,p->prot.ni1.invoke_id);
+ release_l3_process(p);
+} /* ni1_release_l3_process */
+
+/********************************************************/
+/* search a process with invoke id id and dummy callref */
+/********************************************************/
+static struct l3_process *
+l3ni1_search_dummy_proc(struct PStack *st, int id)
+{ struct l3_process *pc = st->l3.proc; /* start of processes */
+
+ if (!id) return(NULL);
+
+ while (pc)
+ { if ((pc->callref == -1) && (pc->prot.ni1.invoke_id == id))
+ return(pc);
+ pc = pc->next;
+ }
+ return(NULL);
+} /* l3ni1_search_dummy_proc */
+
+/*******************************************************************/
+/* called when a facility message with a dummy callref is received */
+/* and a return result is delivered. id specifies the invoke id. */
+/*******************************************************************/
+static void
+l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen)
+{ isdn_ctrl ic;
+ struct IsdnCardState *cs;
+ struct l3_process *pc = NULL;
+
+ if ((pc = l3ni1_search_dummy_proc(st, id)))
+ { L3DelTimer(&pc->timer); /* remove timer */
+
+ cs = pc->st->l1.hardware;
+ ic.driver = cs->myid;
+ ic.command = ISDN_STAT_PROT;
+ ic.arg = NI1_STAT_INVOKE_RES;
+ ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
+ ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
+ ic.parm.ni1_io.proc = pc->prot.ni1.proc;
+ ic.parm.ni1_io.timeout= 0;
+ ic.parm.ni1_io.datalen = nlen;
+ ic.parm.ni1_io.data = p;
+ free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
+ pc->prot.ni1.invoke_id = 0; /* reset id */
+
+ cs->iif.statcallb(&ic);
+ ni1_release_l3_process(pc);
+ }
+ else
+ l3_debug(st, "dummy return result id=0x%x result len=%d",id,nlen);
+} /* l3ni1_dummy_return_result */
+
+/*******************************************************************/
+/* called when a facility message with a dummy callref is received */
+/* and a return error is delivered. id specifies the invoke id. */
+/*******************************************************************/
+static void
+l3ni1_dummy_error_return(struct PStack *st, int id, ulong error)
+{ isdn_ctrl ic;
+ struct IsdnCardState *cs;
+ struct l3_process *pc = NULL;
+
+ if ((pc = l3ni1_search_dummy_proc(st, id)))
+ { L3DelTimer(&pc->timer); /* remove timer */
+
+ cs = pc->st->l1.hardware;
+ ic.driver = cs->myid;
+ ic.command = ISDN_STAT_PROT;
+ ic.arg = NI1_STAT_INVOKE_ERR;
+ ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
+ ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
+ ic.parm.ni1_io.proc = pc->prot.ni1.proc;
+ ic.parm.ni1_io.timeout= error;
+ ic.parm.ni1_io.datalen = 0;
+ ic.parm.ni1_io.data = NULL;
+ free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
+ pc->prot.ni1.invoke_id = 0; /* reset id */
+
+ cs->iif.statcallb(&ic);
+ ni1_release_l3_process(pc);
+ }
+ else
+ l3_debug(st, "dummy return error id=0x%x error=0x%lx",id,error);
+} /* l3ni1_error_return */
+
+/*******************************************************************/
+/* called when a facility message with a dummy callref is received */
+/* and a invoke is delivered. id specifies the invoke id. */
+/*******************************************************************/
+static void
+l3ni1_dummy_invoke(struct PStack *st, int cr, int id,
+ int ident, u_char *p, u_char nlen)
+{ isdn_ctrl ic;
+ struct IsdnCardState *cs;
+
+ l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d",
+ (cr == -1) ? "local" : "broadcast",id,ident,nlen);
+ if (cr >= -1) return; /* ignore local data */
+
+ cs = st->l1.hardware;
+ ic.driver = cs->myid;
+ ic.command = ISDN_STAT_PROT;
+ ic.arg = NI1_STAT_INVOKE_BRD;
+ ic.parm.ni1_io.hl_id = id;
+ ic.parm.ni1_io.ll_id = 0;
+ ic.parm.ni1_io.proc = ident;
+ ic.parm.ni1_io.timeout= 0;
+ ic.parm.ni1_io.datalen = nlen;
+ ic.parm.ni1_io.data = p;
+
+ cs->iif.statcallb(&ic);
+} /* l3ni1_dummy_invoke */
+
+static void
+l3ni1_parse_facility(struct PStack *st, struct l3_process *pc,
+ int cr, u_char * p)
+{
+ int qd_len = 0;
+ unsigned char nlen = 0, ilen, cp_tag;
+ int ident, id;
+ ulong err_ret;
+
+ if (pc)
+ st = pc->st; /* valid Stack */
+ else
+ if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */
+
+ p++;
+ qd_len = *p++;
+ if (qd_len == 0) {
+ l3_debug(st, "qd_len == 0");
+ return;
+ }
+ if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */
+ l3_debug(st, "supplementary service != 0x11");
+ return;
+ }
+ while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */
+ p++;
+ qd_len--;
+ }
+ if (qd_len < 2) {
+ l3_debug(st, "qd_len < 2");
+ return;
+ }
+ p++;
+ qd_len--;
+ if ((*p & 0xE0) != 0xA0) { /* class and form */
+ l3_debug(st, "class and form != 0xA0");
+ return;
+ }
+
+ cp_tag = *p & 0x1F; /* remember tag value */
+
+ p++;
+ qd_len--;
+ if (qd_len < 1)
+ { l3_debug(st, "qd_len < 1");
+ return;
+ }
+ if (*p & 0x80)
+ { /* length format indefinite or limited */
+ nlen = *p++ & 0x7F; /* number of len bytes or indefinite */
+ if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) ||
+ (nlen > 1))
+ { l3_debug(st, "length format error or not implemented");
+ return;
+ }
+ if (nlen == 1)
+ { nlen = *p++; /* complete length */
+ qd_len--;
+ }
+ else
+ { qd_len -= 2; /* trailing null bytes */
+ if ((*(p+qd_len)) || (*(p+qd_len+1)))
+ { l3_debug(st,"length format indefinite error");
+ return;
+ }
+ nlen = qd_len;
+ }
+ }
+ else
+ { nlen = *p++;
+ qd_len--;
+ }
+ if (qd_len < nlen)
+ { l3_debug(st, "qd_len < nlen");
+ return;
+ }
+ qd_len -= nlen;
+
+ if (nlen < 2)
+ { l3_debug(st, "nlen < 2");
+ return;
+ }
+ if (*p != 0x02)
+ { /* invoke identifier tag */
+ l3_debug(st, "invoke identifier tag !=0x02");
+ return;
+ }
+ p++;
+ nlen--;
+ if (*p & 0x80)
+ { /* length format */
+ l3_debug(st, "invoke id length format 2");
+ return;
+ }
+ ilen = *p++;
+ nlen--;
+ if (ilen > nlen || ilen == 0)
+ { l3_debug(st, "ilen > nlen || ilen == 0");
+ return;
+ }
+ nlen -= ilen;
+ id = 0;
+ while (ilen > 0)
+ { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */
+ ilen--;
+ }
+
+ switch (cp_tag) { /* component tag */
+ case 1: /* invoke */
+ if (nlen < 2) {
+ l3_debug(st, "nlen < 2 22");
+ return;
+ }
+ if (*p != 0x02) { /* operation value */
+ l3_debug(st, "operation value !=0x02");
+ return;
+ }
+ p++;
+ nlen--;
+ ilen = *p++;
+ nlen--;
+ if (ilen > nlen || ilen == 0) {
+ l3_debug(st, "ilen > nlen || ilen == 0 22");
+ return;
+ }
+ nlen -= ilen;
+ ident = 0;
+ while (ilen > 0) {
+ ident = (ident << 8) | (*p++ & 0xFF);
+ ilen--;
+ }
+
+ if (!pc)
+ {
+ l3ni1_dummy_invoke(st, cr, id, ident, p, nlen);
+ return;
+ }
+ l3_debug(st, "invoke break");
+ break;
+ case 2: /* return result */
+ /* if no process available handle separately */
+ if (!pc)
+ { if (cr == -1)
+ l3ni1_dummy_return_result(st, id, p, nlen);
+ return;
+ }
+ if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id))
+ { /* Diversion successfull */
+ free_invoke_id(st,pc->prot.ni1.invoke_id);
+ pc->prot.ni1.remote_result = 0; /* success */
+ pc->prot.ni1.invoke_id = 0;
+ pc->redir_result = pc->prot.ni1.remote_result;
+ st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successfull */
+ else
+ l3_debug(st,"return error unknown identifier");
+ break;
+ case 3: /* return error */
+ err_ret = 0;
+ if (nlen < 2)
+ { l3_debug(st, "return error nlen < 2");
+ return;
+ }
+ if (*p != 0x02)
+ { /* result tag */
+ l3_debug(st, "invoke error tag !=0x02");
+ return;
+ }
+ p++;
+ nlen--;
+ if (*p > 4)
+ { /* length format */
+ l3_debug(st, "invoke return errlen > 4 ");
+ return;
+ }
+ ilen = *p++;
+ nlen--;
+ if (ilen > nlen || ilen == 0)
+ { l3_debug(st, "error return ilen > nlen || ilen == 0");
+ return;
+ }
+ nlen -= ilen;
+ while (ilen > 0)
+ { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */
+ ilen--;
+ }
+ /* if no process available handle separately */
+ if (!pc)
+ { if (cr == -1)
+ l3ni1_dummy_error_return(st, id, err_ret);
+ return;
+ }
+ if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id))
+ { /* Deflection error */
+ free_invoke_id(st,pc->prot.ni1.invoke_id);
+ pc->prot.ni1.remote_result = err_ret; /* result */
+ pc->prot.ni1.invoke_id = 0;
+ pc->redir_result = pc->prot.ni1.remote_result;
+ st->l3.l3l4(st, CC_REDIR | INDICATION, pc);
+ } /* Deflection error */
+ else
+ l3_debug(st,"return result unknown identifier");
+ break;
+ default:
+ l3_debug(st, "facility default break tag=0x%02x",cp_tag);
+ break;
+ }
+}
+
+static void
+l3ni1_message(struct l3_process *pc, u_char mt)
+{
+ struct sk_buff *skb;
+ u_char *p;
+
+ if (!(skb = l3_alloc_skb(4)))
+ return;
+ p = skb_put(skb, 4);
+ MsgHead(p, pc->callref, mt);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause)
+{
+ struct sk_buff *skb;
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+
+ MsgHead(p, pc->callref, mt);
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = cause | 0x80;
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg)
+{
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+ struct sk_buff *skb;
+
+ MsgHead(p, pc->callref, MT_STATUS);
+
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = pc->para.cause | 0x80;
+
+ *p++ = IE_CALL_STATE;
+ *p++ = 0x1;
+ *p++ = pc->state & 0x3f;
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
+{
+ /* This routine is called if here was no SETUP made (checks in ni1up and in
+ * l3ni1_setup) and a RELEASE_COMPLETE have to be sent with an error code
+ * MT_STATUS_ENQUIRE in the NULL state is handled too
+ */
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+ struct sk_buff *skb;
+
+ switch (pc->para.cause) {
+ case 81: /* invalid callreference */
+ case 88: /* incomp destination */
+ case 96: /* mandory IE missing */
+ case 100: /* invalid IE contents */
+ case 101: /* incompatible Callstate */
+ MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = pc->para.cause | 0x80;
+ break;
+ default:
+ printk(KERN_ERR "HiSax l3ni1_msg_without_setup wrong cause %d\n",
+ pc->para.cause);
+ return;
+ }
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+ ni1_release_l3_process(pc);
+}
+
+static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
+ IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC,
+ IE_USER_USER, -1};
+static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
+ IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1};
+static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
+ IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL,
+ IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1};
+static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1};
+static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY,
+ IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
+static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL,
+ IE_CALLED_PN, -1};
+static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS |
+ IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
+static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY,
+ IE_SIGNAL, IE_USER_USER, -1};
+/* a RELEASE_COMPLETE with errors don't require special actions
+static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
+*/
+static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY,
+ IE_DISPLAY, -1};
+static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY,
+ IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS,
+ IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN,
+ IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR,
+ IE_LLC, IE_HLC, IE_USER_USER, -1};
+static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
+ IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1};
+static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE |
+ IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1};
+static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1};
+static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
+/* not used
+ * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY,
+ * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
+ * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1};
+ * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND |
+ * IE_MANDATORY, -1};
+ */
+static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1};
+static int comp_required[] = {1,2,3,5,6,7,9,10,11,14,15,-1};
+static int l3_valid_states[] = {0,1,2,3,4,6,7,8,9,10,11,12,15,17,19,25,-1};
+
+struct ie_len {
+ int ie;
+ int len;
+};
+
+static
+struct ie_len max_ie_len[] = {
+ {IE_SEGMENT, 4},
+ {IE_BEARER, 12},
+ {IE_CAUSE, 32},
+ {IE_CALL_ID, 10},
+ {IE_CALL_STATE, 3},
+ {IE_CHANNEL_ID, 34},
+ {IE_FACILITY, 255},
+ {IE_PROGRESS, 4},
+ {IE_NET_FAC, 255},
+ {IE_NOTIFY, 3},
+ {IE_DISPLAY, 82},
+ {IE_DATE, 8},
+ {IE_KEYPAD, 34},
+ {IE_SIGNAL, 3},
+ {IE_INFORATE, 6},
+ {IE_E2E_TDELAY, 11},
+ {IE_TDELAY_SEL, 5},
+ {IE_PACK_BINPARA, 3},
+ {IE_PACK_WINSIZE, 4},
+ {IE_PACK_SIZE, 4},
+ {IE_CUG, 7},
+ {IE_REV_CHARGE, 3},
+ {IE_CALLING_PN, 24},
+ {IE_CALLING_SUB, 23},
+ {IE_CALLED_PN, 24},
+ {IE_CALLED_SUB, 23},
+ {IE_REDIR_NR, 255},
+ {IE_TRANS_SEL, 255},
+ {IE_RESTART_IND, 3},
+ {IE_LLC, 18},
+ {IE_HLC, 5},
+ {IE_USER_USER, 131},
+ {-1,0},
+};
+
+static int
+getmax_ie_len(u_char ie) {
+ int i = 0;
+ while (max_ie_len[i].ie != -1) {
+ if (max_ie_len[i].ie == ie)
+ return(max_ie_len[i].len);
+ i++;
+ }
+ return(255);
+}
+
+static int
+ie_in_set(struct l3_process *pc, u_char ie, int *checklist) {
+ int ret = 1;
+
+ while (*checklist != -1) {
+ if ((*checklist & 0xff) == ie) {
+ if (ie & 0x80)
+ return(-ret);
+ else
+ return(ret);
+ }
+ ret++;
+ checklist++;
+ }
+ return(0);
+}
+
+static int
+check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist)
+{
+ int *cl = checklist;
+ u_char mt;
+ u_char *p, ie;
+ int l, newpos, oldpos;
+ int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0;
+ u_char codeset = 0;
+ u_char old_codeset = 0;
+ u_char codelock = 1;
+
+ p = skb->data;
+ /* skip cr */
+ p++;
+ l = (*p++) & 0xf;
+ p += l;
+ mt = *p++;
+ oldpos = 0;
+ while ((p - skb->data) < skb->len) {
+ if ((*p & 0xf0) == 0x90) { /* shift codeset */
+ old_codeset = codeset;
+ codeset = *p & 7;
+ if (*p & 0x08)
+ codelock = 0;
+ else
+ codelock = 1;
+ if (pc->debug & L3_DEB_CHECK)
+ l3_debug(pc->st, "check IE shift%scodeset %d->%d",
+ codelock ? " locking ": " ", old_codeset, codeset);
+ p++;
+ continue;
+ }
+ if (!codeset) { /* only codeset 0 */
+ if ((newpos = ie_in_set(pc, *p, cl))) {
+ if (newpos > 0) {
+ if (newpos < oldpos)
+ err_seq++;
+ else
+ oldpos = newpos;
+ }
+ } else {
+ if (ie_in_set(pc, *p, comp_required))
+ err_compr++;
+ else
+ err_ureg++;
+ }
+ }
+ ie = *p++;
+ if (ie & 0x80) {
+ l = 1;
+ } else {
+ l = *p++;
+ p += l;
+ l += 2;
+ }
+ if (!codeset && (l > getmax_ie_len(ie)))
+ err_len++;
+ if (!codelock) {
+ if (pc->debug & L3_DEB_CHECK)
+ l3_debug(pc->st, "check IE shift back codeset %d->%d",
+ codeset, old_codeset);
+ codeset = old_codeset;
+ codelock = 1;
+ }
+ }
+ if (err_compr | err_ureg | err_len | err_seq) {
+ if (pc->debug & L3_DEB_CHECK)
+ l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d",
+ mt, err_compr, err_ureg, err_len, err_seq);
+ if (err_compr)
+ return(ERR_IE_COMPREHENSION);
+ if (err_ureg)
+ return(ERR_IE_UNRECOGNIZED);
+ if (err_len)
+ return(ERR_IE_LENGTH);
+ if (err_seq)
+ return(ERR_IE_SEQUENCE);
+ }
+ return(0);
+}
+
+/* verify if a message type exists and contain no IE error */
+static int
+l3ni1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg)
+{
+ switch (mt) {
+ case MT_ALERTING:
+ case MT_CALL_PROCEEDING:
+ case MT_CONNECT:
+ case MT_CONNECT_ACKNOWLEDGE:
+ case MT_DISCONNECT:
+ case MT_INFORMATION:
+ case MT_FACILITY:
+ case MT_NOTIFY:
+ case MT_PROGRESS:
+ case MT_RELEASE:
+ case MT_RELEASE_COMPLETE:
+ case MT_SETUP:
+ case MT_SETUP_ACKNOWLEDGE:
+ case MT_RESUME_ACKNOWLEDGE:
+ case MT_RESUME_REJECT:
+ case MT_SUSPEND_ACKNOWLEDGE:
+ case MT_SUSPEND_REJECT:
+ case MT_USER_INFORMATION:
+ case MT_RESTART:
+ case MT_RESTART_ACKNOWLEDGE:
+ case MT_CONGESTION_CONTROL:
+ case MT_STATUS:
+ case MT_STATUS_ENQUIRY:
+ if (pc->debug & L3_DEB_CHECK)
+ l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) OK", mt);
+ break;
+ case MT_RESUME: /* RESUME only in user->net */
+ case MT_SUSPEND: /* SUSPEND only in user->net */
+ default:
+ if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN))
+ l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) fail", mt);
+ pc->para.cause = 97;
+ l3ni1_status_send(pc, 0, NULL);
+ return(1);
+ }
+ return(0);
+}
+
+static void
+l3ni1_std_ie_err(struct l3_process *pc, int ret) {
+
+ if (pc->debug & L3_DEB_CHECK)
+ l3_debug(pc->st, "check_infoelements ret %d", ret);
+ switch(ret) {
+ case 0:
+ break;
+ case ERR_IE_COMPREHENSION:
+ pc->para.cause = 96;
+ l3ni1_status_send(pc, 0, NULL);
+ break;
+ case ERR_IE_UNRECOGNIZED:
+ pc->para.cause = 99;
+ l3ni1_status_send(pc, 0, NULL);
+ break;
+ case ERR_IE_LENGTH:
+ pc->para.cause = 100;
+ l3ni1_status_send(pc, 0, NULL);
+ break;
+ case ERR_IE_SEQUENCE:
+ default:
+ break;
+ }
+}
+
+static int
+l3ni1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) {
+ u_char *p;
+
+ p = skb->data;
+ if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
+ p++;
+ if (*p != 1) { /* len for BRI = 1 */
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "wrong chid len %d", *p);
+ return (-2);
+ }
+ p++;
+ if (*p & 0x60) { /* only base rate interface */
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "wrong chid %x", *p);
+ return (-3);
+ }
+ return(*p & 0x3);
+ } else
+ return(-1);
+}
+
+static int
+l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) {
+ u_char l, i=0;
+ u_char *p;
+
+ p = skb->data;
+ pc->para.cause = 31;
+ pc->para.loc = 0;
+ if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
+ p++;
+ l = *p++;
+ if (l>30)
+ return(1);
+ if (l) {
+ pc->para.loc = *p++;
+ l--;
+ } else {
+ return(2);
+ }
+ if (l && !(pc->para.loc & 0x80)) {
+ l--;
+ p++; /* skip recommendation */
+ }
+ if (l) {
+ pc->para.cause = *p++;
+ l--;
+ if (!(pc->para.cause & 0x80))
+ return(3);
+ } else
+ return(4);
+ while (l && (i<6)) {
+ pc->para.diag[i++] = *p++;
+ l--;
+ }
+ } else
+ return(-1);
+ return(0);
+}
+
+static void
+l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd)
+{
+ struct sk_buff *skb;
+ u_char tmp[16+40];
+ u_char *p = tmp;
+ int l;
+
+ MsgHead(p, pc->callref, cmd);
+
+ if (pc->prot.ni1.uus1_data[0])
+ { *p++ = IE_USER_USER; /* UUS info element */
+ *p++ = strlen(pc->prot.ni1.uus1_data) + 1;
+ *p++ = 0x04; /* IA5 chars */
+ strcpy(p,pc->prot.ni1.uus1_data);
+ p += strlen(pc->prot.ni1.uus1_data);
+ pc->prot.ni1.uus1_data[0] = '\0';
+ }
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+} /* l3ni1_msg_with_uus */
+
+static void
+l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg)
+{
+ StopAllL3Timer(pc);
+ newl3state(pc, 19);
+ if (!pc->prot.ni1.uus1_data[0])
+ l3ni1_message(pc, MT_RELEASE);
+ else
+ l3ni1_msg_with_uus(pc, MT_RELEASE);
+ L3AddTimer(&pc->timer, T308, CC_T308_1);
+}
+
+static void
+l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int ret;
+
+ if ((ret = l3ni1_get_cause(pc, skb))>0) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "RELCMPL get_cause ret(%d)",ret);
+ } else if (ret < 0)
+ pc->para.cause = NO_CAUSE;
+ StopAllL3Timer(pc);
+ newl3state(pc, 0);
+ pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
+ ni1_release_l3_process(pc);
+}
+
+#if EXT_BEARER_CAPS
+
+static u_char *
+EncodeASyncParams(u_char * p, u_char si2)
+{ // 7c 06 88 90 21 42 00 bb
+
+ p[0] = 0;
+ p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19
+ p[2] = 0x80;
+ if (si2 & 32) // 7 data bits
+
+ p[2] += 16;
+ else // 8 data bits
+
+ p[2] += 24;
+
+ if (si2 & 16) // 2 stop bits
+
+ p[2] += 96;
+ else // 1 stop bit
+
+ p[2] += 32;
+
+ if (si2 & 8) // even parity
+
+ p[2] += 2;
+ else // no parity
+
+ p[2] += 3;
+
+ switch (si2 & 0x07) {
+ case 0:
+ p[0] = 66; // 1200 bit/s
+
+ break;
+ case 1:
+ p[0] = 88; // 1200/75 bit/s
+
+ break;
+ case 2:
+ p[0] = 87; // 75/1200 bit/s
+
+ break;
+ case 3:
+ p[0] = 67; // 2400 bit/s
+
+ break;
+ case 4:
+ p[0] = 69; // 4800 bit/s
+
+ break;
+ case 5:
+ p[0] = 72; // 9600 bit/s
+
+ break;
+ case 6:
+ p[0] = 73; // 14400 bit/s
+
+ break;
+ case 7:
+ p[0] = 75; // 19200 bit/s
+
+ break;
+ }
+ return p + 3;
+}
+
+static u_char
+EncodeSyncParams(u_char si2, u_char ai)
+{
+
+ switch (si2) {
+ case 0:
+ return ai + 2; // 1200 bit/s
+
+ case 1:
+ return ai + 24; // 1200/75 bit/s
+
+ case 2:
+ return ai + 23; // 75/1200 bit/s
+
+ case 3:
+ return ai + 3; // 2400 bit/s
+
+ case 4:
+ return ai + 5; // 4800 bit/s
+
+ case 5:
+ return ai + 8; // 9600 bit/s
+
+ case 6:
+ return ai + 9; // 14400 bit/s
+
+ case 7:
+ return ai + 11; // 19200 bit/s
+
+ case 8:
+ return ai + 14; // 48000 bit/s
+
+ case 9:
+ return ai + 15; // 56000 bit/s
+
+ case 15:
+ return ai + 40; // negotiate bit/s
+
+ default:
+ break;
+ }
+ return ai;
+}
+
+
+static u_char
+DecodeASyncParams(u_char si2, u_char * p)
+{
+ u_char info;
+
+ switch (p[5]) {
+ case 66: // 1200 bit/s
+
+ break; // si2 don't change
+
+ case 88: // 1200/75 bit/s
+
+ si2 += 1;
+ break;
+ case 87: // 75/1200 bit/s
+
+ si2 += 2;
+ break;
+ case 67: // 2400 bit/s
+
+ si2 += 3;
+ break;
+ case 69: // 4800 bit/s
+
+ si2 += 4;
+ break;
+ case 72: // 9600 bit/s
+
+ si2 += 5;
+ break;
+ case 73: // 14400 bit/s
+
+ si2 += 6;
+ break;
+ case 75: // 19200 bit/s
+
+ si2 += 7;
+ break;
+ }
+
+ info = p[7] & 0x7f;
+ if ((info & 16) && (!(info & 8))) // 7 data bits
+
+ si2 += 32; // else 8 data bits
+
+ if ((info & 96) == 96) // 2 stop bits
+
+ si2 += 16; // else 1 stop bit
+
+ if ((info & 2) && (!(info & 1))) // even parity
+
+ si2 += 8; // else no parity
+
+ return si2;
+}
+
+
+static u_char
+DecodeSyncParams(u_char si2, u_char info)
+{
+ info &= 0x7f;
+ switch (info) {
+ case 40: // bit/s negotiation failed ai := 165 not 175!
+
+ return si2 + 15;
+ case 15: // 56000 bit/s failed, ai := 0 not 169 !
+
+ return si2 + 9;
+ case 14: // 48000 bit/s
+
+ return si2 + 8;
+ case 11: // 19200 bit/s
+
+ return si2 + 7;
+ case 9: // 14400 bit/s
+
+ return si2 + 6;
+ case 8: // 9600 bit/s
+
+ return si2 + 5;
+ case 5: // 4800 bit/s
+
+ return si2 + 4;
+ case 3: // 2400 bit/s
+
+ return si2 + 3;
+ case 23: // 75/1200 bit/s
+
+ return si2 + 2;
+ case 24: // 1200/75 bit/s
+
+ return si2 + 1;
+ default: // 1200 bit/s
+
+ return si2;
+ }
+}
+
+static u_char
+DecodeSI2(struct sk_buff *skb)
+{
+ u_char *p; //, *pend=skb->data + skb->len;
+
+ if ((p = findie(skb->data, skb->len, 0x7c, 0))) {
+ switch (p[4] & 0x0f) {
+ case 0x01:
+ if (p[1] == 0x04) // sync. Bitratenadaption
+
+ return DecodeSyncParams(160, p[5]); // V.110/X.30
+
+ else if (p[1] == 0x06) // async. Bitratenadaption
+
+ return DecodeASyncParams(192, p); // V.110/X.30
+
+ break;
+ case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption
+ if (p[1] > 3)
+ return DecodeSyncParams(176, p[5]); // V.120
+ break;
+ }
+ }
+ return 0;
+}
+
+#endif
+
+
+static void
+l3ni1_setup_req(struct l3_process *pc, u_char pr,
+ void *arg)
+{
+ struct sk_buff *skb;
+ u_char tmp[128];
+ u_char *p = tmp;
+
+ u_char *teln;
+ u_char *sub;
+ u_char *sp;
+ int l;
+
+ MsgHead(p, pc->callref, MT_SETUP);
+
+ teln = pc->para.setup.phone;
+
+ *p++ = 0xa1; /* complete indicator */
+ /*
+ * Set Bearer Capability, Map info from 1TR6-convention to NI1
+ */
+ switch (pc->para.setup.si1) {
+ case 1: /* Telephony */
+ *p++ = IE_BEARER;
+ *p++ = 0x3; /* Length */
+ *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ *p++ = 0xa3; /* A-Law Audio */
+ break;
+ case 5: /* Datatransmission 64k, BTX */
+ case 7: /* Datatransmission 64k */
+ default:
+ *p++ = IE_BEARER;
+ *p++ = 0x2; /* Length */
+ *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ break;
+ }
+
+ sub = NULL;
+ sp = teln;
+ while (*sp) {
+ if ('.' == *sp) {
+ sub = sp;
+ *sp = 0;
+ } else
+ sp++;
+ }
+
+ *p++ = IE_KEYPAD;
+ *p++ = strlen(teln);
+ while (*teln)
+ *p++ = (*teln++) & 0x7F;
+
+ if (sub)
+ *sub++ = '.';
+
+#if EXT_BEARER_CAPS
+ if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30
+
+ *p++ = IE_LLC;
+ *p++ = 0x04;
+ *p++ = 0x88;
+ *p++ = 0x90;
+ *p++ = 0x21;
+ *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80);
+ } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120
+
+ *p++ = IE_LLC;
+ *p++ = 0x05;
+ *p++ = 0x88;
+ *p++ = 0x90;
+ *p++ = 0x28;
+ *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0);
+ *p++ = 0x82;
+ } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30
+
+ *p++ = IE_LLC;
+ *p++ = 0x06;
+ *p++ = 0x88;
+ *p++ = 0x90;
+ *p++ = 0x21;
+ p = EncodeASyncParams(p, pc->para.setup.si2 - 192);
+ } else {
+ switch (pc->para.setup.si1) {
+ case 1: /* Telephony */
+ *p++ = IE_LLC;
+ *p++ = 0x3; /* Length */
+ *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ *p++ = 0xa3; /* A-Law Audio */
+ break;
+ case 5: /* Datatransmission 64k, BTX */
+ case 7: /* Datatransmission 64k */
+ default:
+ *p++ = IE_LLC;
+ *p++ = 0x2; /* Length */
+ *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ break;
+ }
+ }
+#endif
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+{
+ return;
+}
+ memcpy(skb_put(skb, l), tmp, l);
+ L3DelTimer(&pc->timer);
+ L3AddTimer(&pc->timer, T303, CC_T303);
+ newl3state(pc, 1);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int id, ret;
+
+ if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
+ if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup answer with wrong chid %x", id);
+ pc->para.cause = 100;
+ l3ni1_status_send(pc, pr, NULL);
+ return;
+ }
+ pc->para.bchannel = id;
+ } else if (1 == pc->state) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
+ if (id == -1)
+ pc->para.cause = 96;
+ else
+ pc->para.cause = 100;
+ l3ni1_status_send(pc, pr, NULL);
+ return;
+ }
+ /* Now we are on none mandatory IEs */
+ ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3ni1_std_ie_err(pc, ret);
+ return;
+ }
+ L3DelTimer(&pc->timer);
+ newl3state(pc, 3);
+ L3AddTimer(&pc->timer, T310, CC_T310);
+ if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+ l3ni1_std_ie_err(pc, ret);
+ pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
+}
+
+static void
+l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int id, ret;
+
+ if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
+ if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup answer with wrong chid %x", id);
+ pc->para.cause = 100;
+ l3ni1_status_send(pc, pr, NULL);
+ return;
+ }
+ pc->para.bchannel = id;
+ } else {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
+ if (id == -1)
+ pc->para.cause = 96;
+ else
+ pc->para.cause = 100;
+ l3ni1_status_send(pc, pr, NULL);
+ return;
+ }
+ /* Now we are on none mandatory IEs */
+ ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3ni1_std_ie_err(pc, ret);
+ return;
+ }
+ L3DelTimer(&pc->timer);
+ newl3state(pc, 2);
+ L3AddTimer(&pc->timer, T304, CC_T304);
+ if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+ l3ni1_std_ie_err(pc, ret);
+ pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+}
+
+static void
+l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ u_char *p;
+ int ret;
+ u_char cause = 0;
+
+ StopAllL3Timer(pc);
+ if ((ret = l3ni1_get_cause(pc, skb))) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "DISC get_cause ret(%d)", ret);
+ if (ret < 0)
+ cause = 96;
+ else if (ret > 0)
+ cause = 100;
+ }
+ if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
+ l3ni1_parse_facility(pc->st, pc, pc->callref, p);
+ ret = check_infoelements(pc, skb, ie_DISCONNECT);
+ if (ERR_IE_COMPREHENSION == ret)
+ cause = 96;
+ else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret))
+ cause = 99;
+ ret = pc->state;
+ newl3state(pc, 12);
+ if (cause)
+ newl3state(pc, 19);
+ if (11 != ret)
+ pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
+ else if (!cause)
+ l3ni1_release_req(pc, pr, NULL);
+ if (cause) {
+ l3ni1_message_cause(pc, MT_RELEASE, cause);
+ L3AddTimer(&pc->timer, T308, CC_T308_1);
+ }
+}
+
+static void
+l3ni1_connect(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int ret;
+
+ ret = check_infoelements(pc, skb, ie_CONNECT);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3ni1_std_ie_err(pc, ret);
+ return;
+ }
+ L3DelTimer(&pc->timer); /* T310 */
+ newl3state(pc, 10);
+ pc->para.chargeinfo = 0;
+ /* here should inserted COLP handling KKe */
+ if (ret)
+ l3ni1_std_ie_err(pc, ret);
+ pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
+}
+
+static void
+l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int ret;
+
+ ret = check_infoelements(pc, skb, ie_ALERTING);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3ni1_std_ie_err(pc, ret);
+ return;
+ }
+ L3DelTimer(&pc->timer); /* T304 */
+ newl3state(pc, 4);
+ if (ret)
+ l3ni1_std_ie_err(pc, ret);
+ pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
+}
+
+static void
+l3ni1_setup(struct l3_process *pc, u_char pr, void *arg)
+{
+ u_char *p;
+ int bcfound = 0;
+ char tmp[80];
+ struct sk_buff *skb = arg;
+ int id;
+ int err = 0;
+
+ /*
+ * Bearer Capabilities
+ */
+ p = skb->data;
+ /* only the first occurence 'll be detected ! */
+ if ((p = findie(p, skb->len, 0x04, 0))) {
+ if ((p[1] < 2) || (p[1] > 11))
+ err = 1;
+ else {
+ pc->para.setup.si2 = 0;
+ switch (p[2] & 0x7f) {
+ case 0x00: /* Speech */
+ case 0x10: /* 3.1 Khz audio */
+ pc->para.setup.si1 = 1;
+ break;
+ case 0x08: /* Unrestricted digital information */
+ pc->para.setup.si1 = 7;
+/* JIM, 05.11.97 I wanna set service indicator 2 */
+#if EXT_BEARER_CAPS
+ pc->para.setup.si2 = DecodeSI2(skb);
+#endif
+ break;
+ case 0x09: /* Restricted digital information */
+ pc->para.setup.si1 = 2;
+ break;
+ case 0x11:
+ /* Unrestr. digital information with
+ * tones/announcements ( or 7 kHz audio
+ */
+ pc->para.setup.si1 = 3;
+ break;
+ case 0x18: /* Video */
+ pc->para.setup.si1 = 4;
+ break;
+ default:
+ err = 2;
+ break;
+ }
+ switch (p[3] & 0x7f) {
+ case 0x40: /* packed mode */
+ pc->para.setup.si1 = 8;
+ break;
+ case 0x10: /* 64 kbit */
+ case 0x11: /* 2*64 kbit */
+ case 0x13: /* 384 kbit */
+ case 0x15: /* 1536 kbit */
+ case 0x17: /* 1920 kbit */
+ pc->para.moderate = p[3] & 0x7f;
+ break;
+ default:
+ err = 3;
+ break;
+ }
+ }
+ if (pc->debug & L3_DEB_SI)
+ l3_debug(pc->st, "SI=%d, AI=%d",
+ pc->para.setup.si1, pc->para.setup.si2);
+ if (err) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)",
+ p[1], p[2], p[3]);
+ pc->para.cause = 100;
+ l3ni1_msg_without_setup(pc, pr, NULL);
+ return;
+ }
+ } else {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup without bearer capabilities");
+ /* ETS 300-104 1.3.3 */
+ pc->para.cause = 96;
+ l3ni1_msg_without_setup(pc, pr, NULL);
+ return;
+ }
+ /*
+ * Channel Identification
+ */
+ if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
+ if ((pc->para.bchannel = id)) {
+ if ((3 == id) && (0x10 == pc->para.moderate)) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup with wrong chid %x",
+ id);
+ pc->para.cause = 100;
+ l3ni1_msg_without_setup(pc, pr, NULL);
+ return;
+ }
+ bcfound++;
+ } else
+ { if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup without bchannel, call waiting");
+ bcfound++;
+ }
+ } else {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup with wrong chid ret %d", id);
+ if (id == -1)
+ pc->para.cause = 96;
+ else
+ pc->para.cause = 100;
+ l3ni1_msg_without_setup(pc, pr, NULL);
+ return;
+ }
+ /* Now we are on none mandatory IEs */
+ err = check_infoelements(pc, skb, ie_SETUP);
+ if (ERR_IE_COMPREHENSION == err) {
+ pc->para.cause = 96;
+ l3ni1_msg_without_setup(pc, pr, NULL);
+ return;
+ }
+ p = skb->data;
+ if ((p = findie(p, skb->len, 0x70, 0)))
+ iecpy(pc->para.setup.eazmsn, p, 1);
+ else
+ pc->para.setup.eazmsn[0] = 0;
+
+ p = skb->data;
+ if ((p = findie(p, skb->len, 0x71, 0))) {
+ /* Called party subaddress */
+ if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) {
+ tmp[0] = '.';
+ iecpy(&tmp[1], p, 2);
+ strcat(pc->para.setup.eazmsn, tmp);
+ } else if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "wrong called subaddress");
+ }
+ p = skb->data;
+ if ((p = findie(p, skb->len, 0x6c, 0))) {
+ pc->para.setup.plan = p[2];
+ if (p[2] & 0x80) {
+ iecpy(pc->para.setup.phone, p, 1);
+ pc->para.setup.screen = 0;
+ } else {
+ iecpy(pc->para.setup.phone, p, 2);
+ pc->para.setup.screen = p[3];
+ }
+ } else {
+ pc->para.setup.phone[0] = 0;
+ pc->para.setup.plan = 0;
+ pc->para.setup.screen = 0;
+ }
+ p = skb->data;
+ if ((p = findie(p, skb->len, 0x6d, 0))) {
+ /* Calling party subaddress */
+ if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) {
+ tmp[0] = '.';
+ iecpy(&tmp[1], p, 2);
+ strcat(pc->para.setup.phone, tmp);
+ } else if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "wrong calling subaddress");
+ }
+ newl3state(pc, 6);
+ if (err) /* STATUS for none mandatory IE errors after actions are taken */
+ l3ni1_std_ie_err(pc, err);
+ pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
+}
+
+static void
+l3ni1_reset(struct l3_process *pc, u_char pr, void *arg)
+{
+ ni1_release_l3_process(pc);
+}
+
+static void
+l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb;
+ u_char tmp[16+40];
+ u_char *p = tmp;
+ int l;
+ u_char cause = 16;
+
+ if (pc->para.cause != NO_CAUSE)
+ cause = pc->para.cause;
+
+ StopAllL3Timer(pc);
+
+ MsgHead(p, pc->callref, MT_DISCONNECT);
+
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = cause | 0x80;
+
+ if (pc->prot.ni1.uus1_data[0])
+ { *p++ = IE_USER_USER; /* UUS info element */
+ *p++ = strlen(pc->prot.ni1.uus1_data) + 1;
+ *p++ = 0x04; /* IA5 chars */
+ strcpy(p,pc->prot.ni1.uus1_data);
+ p += strlen(pc->prot.ni1.uus1_data);
+ pc->prot.ni1.uus1_data[0] = '\0';
+ }
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ newl3state(pc, 11);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+ L3AddTimer(&pc->timer, T305, CC_T305);
+}
+
+static void
+l3ni1_setup_rsp(struct l3_process *pc, u_char pr,
+ void *arg)
+{
+ if (!pc->para.bchannel)
+ { if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "D-chan connect for waiting call");
+ l3ni1_disconnect_req(pc, pr, arg);
+ return;
+ }
+ newl3state(pc, 8);
+ l3ni1_message(pc, MT_CONNECT);
+ L3DelTimer(&pc->timer);
+ L3AddTimer(&pc->timer, T313, CC_T313);
+}
+
+static void
+l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int ret;
+
+ ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3ni1_std_ie_err(pc, ret);
+ return;
+ }
+ newl3state(pc, 10);
+ L3DelTimer(&pc->timer);
+ if (ret)
+ l3ni1_std_ie_err(pc, ret);
+ pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
+}
+
+static void
+l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb;
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+ u_char cause = 21;
+
+ if (pc->para.cause != NO_CAUSE)
+ cause = pc->para.cause;
+
+ MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
+
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = cause | 0x80;
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+ pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ newl3state(pc, 0);
+ ni1_release_l3_process(pc);
+}
+
+static void
+l3ni1_release(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ u_char *p;
+ int ret, cause=0;
+
+ StopAllL3Timer(pc);
+ if ((ret = l3ni1_get_cause(pc, skb))>0) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "REL get_cause ret(%d)", ret);
+ } else if (ret<0)
+ pc->para.cause = NO_CAUSE;
+ if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
+ l3ni1_parse_facility(pc->st, pc, pc->callref, p);
+ }
+ if ((ret<0) && (pc->state != 11))
+ cause = 96;
+ else if (ret>0)
+ cause = 100;
+ ret = check_infoelements(pc, skb, ie_RELEASE);
+ if (ERR_IE_COMPREHENSION == ret)
+ cause = 96;
+ else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause))
+ cause = 99;
+ if (cause)
+ l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
+ else
+ l3ni1_message(pc, MT_RELEASE_COMPLETE);
+ pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ newl3state(pc, 0);
+ ni1_release_l3_process(pc);
+}
+
+static void
+l3ni1_alert_req(struct l3_process *pc, u_char pr,
+ void *arg)
+{
+ newl3state(pc, 7);
+ if (!pc->prot.ni1.uus1_data[0])
+ l3ni1_message(pc, MT_ALERTING);
+ else
+ l3ni1_msg_with_uus(pc, MT_ALERTING);
+}
+
+static void
+l3ni1_proceed_req(struct l3_process *pc, u_char pr,
+ void *arg)
+{
+ newl3state(pc, 9);
+ l3ni1_message(pc, MT_CALL_PROCEEDING);
+ pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc);
+}
+
+static void
+l3ni1_setup_ack_req(struct l3_process *pc, u_char pr,
+ void *arg)
+{
+ newl3state(pc, 25);
+ L3DelTimer(&pc->timer);
+ L3AddTimer(&pc->timer, T302, CC_T302);
+ l3ni1_message(pc, MT_SETUP_ACKNOWLEDGE);
+}
+
+/********************************************/
+/* deliver a incoming display message to HL */
+/********************************************/
+static void
+l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp)
+{ u_char len;
+ isdn_ctrl ic;
+ struct IsdnCardState *cs;
+ char *p;
+
+ if (*infp++ != IE_DISPLAY) return;
+ if ((len = *infp++) > 80) return; /* total length <= 82 */
+ if (!pc->chan) return;
+
+ p = ic.parm.display;
+ while (len--)
+ *p++ = *infp++;
+ *p = '\0';
+ ic.command = ISDN_STAT_DISPLAY;
+ cs = pc->st->l1.hardware;
+ ic.driver = cs->myid;
+ ic.arg = pc->chan->chan;
+ cs->iif.statcallb(&ic);
+} /* l3ni1_deliver_display */
+
+
+static void
+l3ni1_progress(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int err = 0;
+ u_char *p;
+
+ if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) {
+ if (p[1] != 2) {
+ err = 1;
+ pc->para.cause = 100;
+ } else if (!(p[2] & 0x70)) {
+ switch (p[2]) {
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x84:
+ case 0x85:
+ case 0x87:
+ case 0x8a:
+ switch (p[3]) {
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x88:
+ break;
+ default:
+ err = 2;
+ pc->para.cause = 100;
+ break;
+ }
+ break;
+ default:
+ err = 3;
+ pc->para.cause = 100;
+ break;
+ }
+ }
+ } else {
+ pc->para.cause = 96;
+ err = 4;
+ }
+ if (err) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "progress error %d", err);
+ l3ni1_status_send(pc, pr, NULL);
+ return;
+ }
+ /* Now we are on none mandatory IEs */
+ err = check_infoelements(pc, skb, ie_PROGRESS);
+ if (err)
+ l3ni1_std_ie_err(pc, err);
+ if (ERR_IE_COMPREHENSION != err)
+ pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc);
+}
+
+static void
+l3ni1_notify(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int err = 0;
+ u_char *p;
+
+ if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) {
+ if (p[1] != 1) {
+ err = 1;
+ pc->para.cause = 100;
+ } else {
+ switch (p[2]) {
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ break;
+ default:
+ pc->para.cause = 100;
+ err = 2;
+ break;
+ }
+ }
+ } else {
+ pc->para.cause = 96;
+ err = 3;
+ }
+ if (err) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "notify error %d", err);
+ l3ni1_status_send(pc, pr, NULL);
+ return;
+ }
+ /* Now we are on none mandatory IEs */
+ err = check_infoelements(pc, skb, ie_NOTIFY);
+ if (err)
+ l3ni1_std_ie_err(pc, err);
+ if (ERR_IE_COMPREHENSION != err)
+ pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc);
+}
+
+static void
+l3ni1_status_enq(struct l3_process *pc, u_char pr, void *arg)
+{
+ int ret;
+ struct sk_buff *skb = arg;
+
+ ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY);
+ l3ni1_std_ie_err(pc, ret);
+ pc->para.cause = 30; /* response to STATUS_ENQUIRY */
+ l3ni1_status_send(pc, pr, NULL);
+}
+
+static void
+l3ni1_information(struct l3_process *pc, u_char pr, void *arg)
+{
+ int ret;
+ struct sk_buff *skb = arg;
+ u_char *p;
+ char tmp[32];
+
+ ret = check_infoelements(pc, skb, ie_INFORMATION);
+ if (ret)
+ l3ni1_std_ie_err(pc, ret);
+ if (pc->state == 25) { /* overlap receiving */
+ L3DelTimer(&pc->timer);
+ p = skb->data;
+ if ((p = findie(p, skb->len, 0x70, 0))) {
+ iecpy(tmp, p, 1);
+ strcat(pc->para.setup.eazmsn, tmp);
+ pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+ }
+ L3AddTimer(&pc->timer, T302, CC_T302);
+ }
+}
+
+/******************************/
+/* handle deflection requests */
+/******************************/
+static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb;
+ u_char tmp[128];
+ u_char *p = tmp;
+ u_char *subp;
+ u_char len_phone = 0;
+ u_char len_sub = 0;
+ int l;
+
+
+ strcpy(pc->prot.ni1.uus1_data,pc->chan->setup.eazmsn); /* copy uus element if available */
+ if (!pc->chan->setup.phone[0])
+ { pc->para.cause = -1;
+ l3ni1_disconnect_req(pc,pr,arg); /* disconnect immediately */
+ return;
+ } /* only uus */
+
+ if (pc->prot.ni1.invoke_id)
+ free_invoke_id(pc->st,pc->prot.ni1.invoke_id);
+
+ if (!(pc->prot.ni1.invoke_id = new_invoke_id(pc->st)))
+ return;
+
+ MsgHead(p, pc->callref, MT_FACILITY);
+
+ for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */
+ if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subadress element */
+
+ *p++ = 0x1c; /* Facility info element */
+ *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */
+ *p++ = 0x91; /* remote operations protocol */
+ *p++ = 0xa1; /* invoke component */
+
+ *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */
+ *p++ = 0x02; /* invoke id tag, integer */
+ *p++ = 0x01; /* length */
+ *p++ = pc->prot.ni1.invoke_id; /* invoke id */
+ *p++ = 0x02; /* operation value tag, integer */
+ *p++ = 0x01; /* length */
+ *p++ = 0x0D; /* Call Deflect */
+
+ *p++ = 0x30; /* sequence phone number */
+ *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */
+
+ *p++ = 0x30; /* Deflected to UserNumber */
+ *p++ = len_phone+2+len_sub; /* length */
+ *p++ = 0x80; /* NumberDigits */
+ *p++ = len_phone; /* length */
+ for (l = 0; l < len_phone; l++)
+ *p++ = pc->chan->setup.phone[l];
+
+ if (len_sub)
+ { *p++ = 0x04; /* called party subadress */
+ *p++ = len_sub - 2;
+ while (*subp) *p++ = *subp++;
+ }
+
+ *p++ = 0x01; /* screening identifier */
+ *p++ = 0x01;
+ *p++ = pc->chan->setup.screen;
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l))) return;
+ memcpy(skb_put(skb, l), tmp, l);
+
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+} /* l3ni1_redir_req */
+
+/********************************************/
+/* handle deflection request in early state */
+/********************************************/
+static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg)
+{
+ l3ni1_proceed_req(pc,pr,arg);
+ l3ni1_redir_req(pc,pr,arg);
+} /* l3ni1_redir_req_early */
+
+/***********************************************/
+/* handle special commands for this protocol. */
+/* Examples are call independant services like */
+/* remote operations with dummy callref. */
+/***********************************************/
+static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic)
+{ u_char id;
+ u_char temp[265];
+ u_char *p = temp;
+ int i, l, proc_len;
+ struct sk_buff *skb;
+ struct l3_process *pc = NULL;
+
+ switch (ic->arg)
+ { case NI1_CMD_INVOKE:
+ if (ic->parm.ni1_io.datalen < 0) return(-2); /* invalid parameter */
+
+ for (proc_len = 1, i = ic->parm.ni1_io.proc >> 8; i; i++)
+ i = i >> 8; /* add one byte */
+ l = ic->parm.ni1_io.datalen + proc_len + 8; /* length excluding ie header */
+ if (l > 255)
+ return(-2); /* too long */
+
+ if (!(id = new_invoke_id(st)))
+ return(0); /* first get a invoke id -> return if no available */
+
+ i = -1;
+ MsgHead(p, i, MT_FACILITY); /* build message head */
+ *p++ = 0x1C; /* Facility IE */
+ *p++ = l; /* length of ie */
+ *p++ = 0x91; /* remote operations */
+ *p++ = 0xA1; /* invoke */
+ *p++ = l - 3; /* length of invoke */
+ *p++ = 0x02; /* invoke id tag */
+ *p++ = 0x01; /* length is 1 */
+ *p++ = id; /* invoke id */
+ *p++ = 0x02; /* operation */
+ *p++ = proc_len; /* length of operation */
+
+ for (i = proc_len; i; i--)
+ *p++ = (ic->parm.ni1_io.proc >> (i-1)) & 0xFF;
+ memcpy(p, ic->parm.ni1_io.data, ic->parm.ni1_io.datalen); /* copy data */
+ l = (p - temp) + ic->parm.ni1_io.datalen; /* total length */
+
+ if (ic->parm.ni1_io.timeout > 0)
+ if (!(pc = ni1_new_l3_process(st, -1)))
+ { free_invoke_id(st, id);
+ return(-2);
+ }
+ pc->prot.ni1.ll_id = ic->parm.ni1_io.ll_id; /* remember id */
+ pc->prot.ni1.proc = ic->parm.ni1_io.proc; /* and procedure */
+
+ if (!(skb = l3_alloc_skb(l)))
+ { free_invoke_id(st, id);
+ if (pc) ni1_release_l3_process(pc);
+ return(-2);
+ }
+ memcpy(skb_put(skb, l), temp, l);
+
+ if (pc)
+ { pc->prot.ni1.invoke_id = id; /* remember id */
+ L3AddTimer(&pc->timer, ic->parm.ni1_io.timeout, CC_TNI1_IO | REQUEST);
+ }
+
+ l3_msg(st, DL_DATA | REQUEST, skb);
+ ic->parm.ni1_io.hl_id = id; /* return id */
+ return(0);
+
+ case NI1_CMD_INVOKE_ABORT:
+ if ((pc = l3ni1_search_dummy_proc(st, ic->parm.ni1_io.hl_id)))
+ { L3DelTimer(&pc->timer); /* remove timer */
+ ni1_release_l3_process(pc);
+ return(0);
+ }
+ else
+ { l3_debug(st, "l3ni1_cmd_global abort unknown id");
+ return(-2);
+ }
+ break;
+
+ default:
+ l3_debug(st, "l3ni1_cmd_global unknown cmd 0x%lx", ic->arg);
+ return(-1);
+ } /* switch ic-> arg */
+ return(-1);
+} /* l3ni1_cmd_global */
+
+static void
+l3ni1_io_timer(struct l3_process *pc)
+{ isdn_ctrl ic;
+ struct IsdnCardState *cs = pc->st->l1.hardware;
+
+ L3DelTimer(&pc->timer); /* remove timer */
+
+ ic.driver = cs->myid;
+ ic.command = ISDN_STAT_PROT;
+ ic.arg = NI1_STAT_INVOKE_ERR;
+ ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
+ ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
+ ic.parm.ni1_io.proc = pc->prot.ni1.proc;
+ ic.parm.ni1_io.timeout= -1;
+ ic.parm.ni1_io.datalen = 0;
+ ic.parm.ni1_io.data = NULL;
+ free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
+ pc->prot.ni1.invoke_id = 0; /* reset id */
+
+ cs->iif.statcallb(&ic);
+
+ ni1_release_l3_process(pc);
+} /* l3ni1_io_timer */
+
+static void
+l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg)
+{
+ u_char *p;
+ struct sk_buff *skb = arg;
+ int callState = 0;
+ p = skb->data;
+
+ if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) {
+ p++;
+ if (1 == *p++)
+ callState = *p;
+ }
+ if (callState == 0) {
+ /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
+ * set down layer 3 without sending any message
+ */
+ pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ newl3state(pc, 0);
+ ni1_release_l3_process(pc);
+ } else {
+ pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
+ }
+}
+
+static void
+l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg)
+{
+}
+
+static void
+l3ni1_t302(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ pc->para.loc = 0;
+ pc->para.cause = 28; /* invalid number */
+ l3ni1_disconnect_req(pc, pr, NULL);
+ pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+}
+
+static void
+l3ni1_t303(struct l3_process *pc, u_char pr, void *arg)
+{
+ if (pc->N303 > 0) {
+ pc->N303--;
+ L3DelTimer(&pc->timer);
+ l3ni1_setup_req(pc, pr, arg);
+ } else {
+ L3DelTimer(&pc->timer);
+ l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102);
+ pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
+ ni1_release_l3_process(pc);
+ }
+}
+
+static void
+l3ni1_t304(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ pc->para.loc = 0;
+ pc->para.cause = 102;
+ l3ni1_disconnect_req(pc, pr, NULL);
+ pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+
+}
+
+static void
+l3ni1_t305(struct l3_process *pc, u_char pr, void *arg)
+{
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+ struct sk_buff *skb;
+ u_char cause = 16;
+
+ L3DelTimer(&pc->timer);
+ if (pc->para.cause != NO_CAUSE)
+ cause = pc->para.cause;
+
+ MsgHead(p, pc->callref, MT_RELEASE);
+
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = cause | 0x80;
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ newl3state(pc, 19);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+ L3AddTimer(&pc->timer, T308, CC_T308_1);
+}
+
+static void
+l3ni1_t310(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ pc->para.loc = 0;
+ pc->para.cause = 102;
+ l3ni1_disconnect_req(pc, pr, NULL);
+ pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+}
+
+static void
+l3ni1_t313(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ pc->para.loc = 0;
+ pc->para.cause = 102;
+ l3ni1_disconnect_req(pc, pr, NULL);
+ pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
+}
+
+static void
+l3ni1_t308_1(struct l3_process *pc, u_char pr, void *arg)
+{
+ newl3state(pc, 19);
+ L3DelTimer(&pc->timer);
+ l3ni1_message(pc, MT_RELEASE);
+ L3AddTimer(&pc->timer, T308, CC_T308_2);
+}
+
+static void
+l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
+ ni1_release_l3_process(pc);
+}
+
+static void
+l3ni1_t318(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ pc->para.cause = 102; /* Timer expiry */
+ pc->para.loc = 0; /* local */
+ pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
+ newl3state(pc, 19);
+ l3ni1_message(pc, MT_RELEASE);
+ L3AddTimer(&pc->timer, T308, CC_T308_1);
+}
+
+static void
+l3ni1_t319(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ pc->para.cause = 102; /* Timer expiry */
+ pc->para.loc = 0; /* local */
+ pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
+ newl3state(pc, 10);
+}
+
+static void
+l3ni1_restart(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ ni1_release_l3_process(pc);
+}
+
+static void
+l3ni1_status(struct l3_process *pc, u_char pr, void *arg)
+{
+ u_char *p;
+ struct sk_buff *skb = arg;
+ int ret;
+ u_char cause = 0, callState = 0;
+
+ if ((ret = l3ni1_get_cause(pc, skb))) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "STATUS get_cause ret(%d)",ret);
+ if (ret < 0)
+ cause = 96;
+ else if (ret > 0)
+ cause = 100;
+ }
+ if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) {
+ p++;
+ if (1 == *p++) {
+ callState = *p;
+ if (!ie_in_set(pc, *p, l3_valid_states))
+ cause = 100;
+ } else
+ cause = 100;
+ } else
+ cause = 96;
+ if (!cause) { /* no error before */
+ ret = check_infoelements(pc, skb, ie_STATUS);
+ if (ERR_IE_COMPREHENSION == ret)
+ cause = 96;
+ else if (ERR_IE_UNRECOGNIZED == ret)
+ cause = 99;
+ }
+ if (cause) {
+ u_char tmp;
+
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause);
+ tmp = pc->para.cause;
+ pc->para.cause = cause;
+ l3ni1_status_send(pc, 0, NULL);
+ if (cause == 99)
+ pc->para.cause = tmp;
+ else
+ return;
+ }
+ cause = pc->para.cause;
+ if (((cause & 0x7f) == 111) && (callState == 0)) {
+ /* ETS 300-104 7.6.1, 8.6.1, 10.6.1...
+ * if received MT_STATUS with cause == 111 and call
+ * state == 0, then we must set down layer 3
+ */
+ pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ newl3state(pc, 0);
+ ni1_release_l3_process(pc);
+ }
+}
+
+static void
+l3ni1_facility(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int ret;
+
+ ret = check_infoelements(pc, skb, ie_FACILITY);
+ l3ni1_std_ie_err(pc, ret);
+ {
+ u_char *p;
+ if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
+ l3ni1_parse_facility(pc->st, pc, pc->callref, p);
+ }
+}
+
+static void
+l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb;
+ u_char tmp[32];
+ u_char *p = tmp;
+ u_char i, l;
+ u_char *msg = pc->chan->setup.phone;
+
+ MsgHead(p, pc->callref, MT_SUSPEND);
+ l = *msg++;
+ if (l && (l <= 10)) { /* Max length 10 octets */
+ *p++ = IE_CALL_ID;
+ *p++ = l;
+ for (i = 0; i < l; i++)
+ *p++ = *msg++;
+ } else if (l) {
+ l3_debug(pc->st, "SUS wrong CALL_ID len %d", l);
+ return;
+ }
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+ newl3state(pc, 15);
+ L3AddTimer(&pc->timer, T319, CC_T319);
+}
+
+static void
+l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int ret;
+
+ L3DelTimer(&pc->timer);
+ newl3state(pc, 0);
+ pc->para.cause = NO_CAUSE;
+ pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
+ /* We don't handle suspend_ack for IE errors now */
+ if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "SUSPACK check ie(%d)",ret);
+ ni1_release_l3_process(pc);
+}
+
+static void
+l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int ret;
+
+ if ((ret = l3ni1_get_cause(pc, skb))) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)",ret);
+ if (ret < 0)
+ pc->para.cause = 96;
+ else
+ pc->para.cause = 100;
+ l3ni1_status_send(pc, pr, NULL);
+ return;
+ }
+ ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3ni1_std_ie_err(pc, ret);
+ return;
+ }
+ L3DelTimer(&pc->timer);
+ pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
+ newl3state(pc, 10);
+ if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+ l3ni1_std_ie_err(pc, ret);
+}
+
+static void
+l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb;
+ u_char tmp[32];
+ u_char *p = tmp;
+ u_char i, l;
+ u_char *msg = pc->para.setup.phone;
+
+ MsgHead(p, pc->callref, MT_RESUME);
+
+ l = *msg++;
+ if (l && (l <= 10)) { /* Max length 10 octets */
+ *p++ = IE_CALL_ID;
+ *p++ = l;
+ for (i = 0; i < l; i++)
+ *p++ = *msg++;
+ } else if (l) {
+ l3_debug(pc->st, "RES wrong CALL_ID len %d", l);
+ return;
+ }
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+ newl3state(pc, 17);
+ L3AddTimer(&pc->timer, T318, CC_T318);
+}
+
+static void
+l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int id, ret;
+
+ if ((id = l3ni1_get_channel_id(pc, skb)) > 0) {
+ if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "resume ack with wrong chid %x", id);
+ pc->para.cause = 100;
+ l3ni1_status_send(pc, pr, NULL);
+ return;
+ }
+ pc->para.bchannel = id;
+ } else if (1 == pc->state) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "resume ack without chid (ret %d)", id);
+ pc->para.cause = 96;
+ l3ni1_status_send(pc, pr, NULL);
+ return;
+ }
+ ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3ni1_std_ie_err(pc, ret);
+ return;
+ }
+ L3DelTimer(&pc->timer);
+ pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
+ newl3state(pc, 10);
+ if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+ l3ni1_std_ie_err(pc, ret);
+}
+
+static void
+l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int ret;
+
+ if ((ret = l3ni1_get_cause(pc, skb))) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "RES_REJ get_cause ret(%d)",ret);
+ if (ret < 0)
+ pc->para.cause = 96;
+ else
+ pc->para.cause = 100;
+ l3ni1_status_send(pc, pr, NULL);
+ return;
+ }
+ ret = check_infoelements(pc, skb, ie_RESUME_REJECT);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3ni1_std_ie_err(pc, ret);
+ return;
+ }
+ L3DelTimer(&pc->timer);
+ pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
+ newl3state(pc, 0);
+ if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+ l3ni1_std_ie_err(pc, ret);
+ ni1_release_l3_process(pc);
+}
+
+static void
+l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg)
+{
+ u_char tmp[32];
+ u_char *p;
+ u_char ri, ch = 0, chan = 0;
+ int l;
+ struct sk_buff *skb = arg;
+ struct l3_process *up;
+
+ newl3state(pc, 2);
+ L3DelTimer(&pc->timer);
+ p = skb->data;
+ if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) {
+ ri = p[2];
+ l3_debug(pc->st, "Restart %x", ri);
+ } else {
+ l3_debug(pc->st, "Restart without restart IE");
+ ri = 0x86;
+ }
+ p = skb->data;
+ if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
+ chan = p[2] & 3;
+ ch = p[2];
+ if (pc->st->l3.debug)
+ l3_debug(pc->st, "Restart for channel %d", chan);
+ }
+ newl3state(pc, 2);
+ up = pc->st->l3.proc;
+ while (up) {
+ if ((ri & 7) == 7)
+ up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
+ else if (up->para.bchannel == chan)
+ up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
+ up = up->next;
+ }
+ p = tmp;
+ MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE);
+ if (chan) {
+ *p++ = IE_CHANNEL_ID;
+ *p++ = 1;
+ *p++ = ch | 0x80;
+ }
+ *p++ = 0x79; /* RESTART Ind */
+ *p++ = 1;
+ *p++ = ri;
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ newl3state(pc, 0);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
+{
+ pc->para.cause = 0x29; /* Temporary failure */
+ pc->para.loc = 0;
+ l3ni1_disconnect_req(pc, pr, NULL);
+ pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+}
+
+static void
+l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg)
+{
+ newl3state(pc, 0);
+ pc->para.cause = 0x1b; /* Destination out of order */
+ pc->para.loc = 0;
+ pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ release_l3_process(pc);
+}
+
+static void
+l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ L3AddTimer(&pc->timer, T309, CC_T309);
+ l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL);
+}
+
+static void
+l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+
+ pc->para.cause = 0x1F; /* normal, unspecified */
+ l3ni1_status_send(pc, 0, NULL);
+}
+
+static void l3ni1_SendSpid( struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState )
+{
+ u_char * p;
+ char * pSPID;
+ struct Channel * pChan = pc->st->lli.userdata;
+ int l;
+
+ if ( skb )
+ dev_kfree_skb( skb);
+
+ if ( !( pSPID = strchr( pChan->setup.eazmsn, ':' ) ) )
+ {
+ printk( KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn );
+ newl3state( pc, 0 );
+ pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL );
+ return;
+ }
+
+ l = strlen( ++pSPID );
+ if ( !( skb = l3_alloc_skb( 5+l ) ) )
+ {
+ printk( KERN_ERR "HiSax can't get memory to send SPID\n" );
+ return;
+ }
+
+ p = skb_put( skb, 5 );
+ *p++ = PROTO_DIS_EURO;
+ *p++ = 0;
+ *p++ = MT_INFORMATION;
+ *p++ = IE_SPID;
+ *p++ = l;
+
+ memcpy( skb_put( skb, l ), pSPID, l );
+
+ newl3state( pc, iNewState );
+
+ L3DelTimer( &pc->timer );
+ L3AddTimer( &pc->timer, TSPID, CC_TSPID );
+
+ pc->st->l3.l3l2( pc->st, DL_DATA | REQUEST, skb );
+}
+
+static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg )
+{
+ l3ni1_SendSpid( pc, pr, arg, 20 );
+}
+
+void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg )
+{
+ struct sk_buff *skb = arg;
+
+ if ( skb->data[ 1 ] == 0 )
+ if ( skb->data[ 3 ] == IE_ENDPOINT_ID )
+ {
+ L3DelTimer( &pc->timer );
+ newl3state( pc, 0 );
+ l3_msg( pc->st, DL_ESTABLISH | CONFIRM, NULL );
+ }
+ dev_kfree_skb( skb);
+}
+
+static void l3ni1_spid_tout( struct l3_process *pc, u_char pr, void *arg )
+{
+ if ( pc->state < 22 )
+ l3ni1_SendSpid( pc, pr, arg, pc->state+1 );
+ else
+ {
+ L3DelTimer( &pc->timer );
+ dev_kfree_skb( arg);
+
+ printk( KERN_ERR "SPID not accepted\n" );
+ newl3state( pc, 0 );
+ pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL );
+ }
+}
+
+/* *INDENT-OFF* */
+static struct stateentry downstatelist[] =
+{
+ {SBIT(0),
+ CC_SETUP | REQUEST, l3ni1_setup_req},
+ {SBIT(0),
+ CC_RESUME | REQUEST, l3ni1_resume_req},
+ {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25),
+ CC_DISCONNECT | REQUEST, l3ni1_disconnect_req},
+ {SBIT(12),
+ CC_RELEASE | REQUEST, l3ni1_release_req},
+ {ALL_STATES,
+ CC_RESTART | REQUEST, l3ni1_restart},
+ {SBIT(6) | SBIT(25),
+ CC_IGNORE | REQUEST, l3ni1_reset},
+ {SBIT(6) | SBIT(25),
+ CC_REJECT | REQUEST, l3ni1_reject_req},
+ {SBIT(6) | SBIT(25),
+ CC_PROCEED_SEND | REQUEST, l3ni1_proceed_req},
+ {SBIT(6),
+ CC_MORE_INFO | REQUEST, l3ni1_setup_ack_req},
+ {SBIT(25),
+ CC_MORE_INFO | REQUEST, l3ni1_dummy},
+ {SBIT(6) | SBIT(9) | SBIT(25),
+ CC_ALERTING | REQUEST, l3ni1_alert_req},
+ {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
+ CC_SETUP | RESPONSE, l3ni1_setup_rsp},
+ {SBIT(10),
+ CC_SUSPEND | REQUEST, l3ni1_suspend_req},
+ {SBIT(7) | SBIT(9) | SBIT(25),
+ CC_REDIR | REQUEST, l3ni1_redir_req},
+ {SBIT(6),
+ CC_REDIR | REQUEST, l3ni1_redir_req_early},
+ {SBIT(9) | SBIT(25),
+ CC_DISCONNECT | REQUEST, l3ni1_disconnect_req},
+ {SBIT(25),
+ CC_T302, l3ni1_t302},
+ {SBIT(1),
+ CC_T303, l3ni1_t303},
+ {SBIT(2),
+ CC_T304, l3ni1_t304},
+ {SBIT(3),
+ CC_T310, l3ni1_t310},
+ {SBIT(8),
+ CC_T313, l3ni1_t313},
+ {SBIT(11),
+ CC_T305, l3ni1_t305},
+ {SBIT(15),
+ CC_T319, l3ni1_t319},
+ {SBIT(17),
+ CC_T318, l3ni1_t318},
+ {SBIT(19),
+ CC_T308_1, l3ni1_t308_1},
+ {SBIT(19),
+ CC_T308_2, l3ni1_t308_2},
+ {SBIT(10),
+ CC_T309, l3ni1_dl_release},
+ { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ),
+ CC_TSPID, l3ni1_spid_tout },
+};
+
+#define DOWNSLLEN \
+ (sizeof(downstatelist) / sizeof(struct stateentry))
+
+static struct stateentry datastatelist[] =
+{
+ {ALL_STATES,
+ MT_STATUS_ENQUIRY, l3ni1_status_enq},
+ {ALL_STATES,
+ MT_FACILITY, l3ni1_facility},
+ {SBIT(19),
+ MT_STATUS, l3ni1_release_ind},
+ {ALL_STATES,
+ MT_STATUS, l3ni1_status},
+ {SBIT(0),
+ MT_SETUP, l3ni1_setup},
+ {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) |
+ SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
+ MT_SETUP, l3ni1_dummy},
+ {SBIT(1) | SBIT(2),
+ MT_CALL_PROCEEDING, l3ni1_call_proc},
+ {SBIT(1),
+ MT_SETUP_ACKNOWLEDGE, l3ni1_setup_ack},
+ {SBIT(2) | SBIT(3),
+ MT_ALERTING, l3ni1_alerting},
+ {SBIT(2) | SBIT(3),
+ MT_PROGRESS, l3ni1_progress},
+ {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) |
+ SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
+ MT_INFORMATION, l3ni1_information},
+ {SBIT(10) | SBIT(11) | SBIT(15),
+ MT_NOTIFY, l3ni1_notify},
+ {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) |
+ SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
+ MT_RELEASE_COMPLETE, l3ni1_release_cmpl},
+ {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25),
+ MT_RELEASE, l3ni1_release},
+ {SBIT(19), MT_RELEASE, l3ni1_release_ind},
+ {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25),
+ MT_DISCONNECT, l3ni1_disconnect},
+ {SBIT(19),
+ MT_DISCONNECT, l3ni1_dummy},
+ {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4),
+ MT_CONNECT, l3ni1_connect},
+ {SBIT(8),
+ MT_CONNECT_ACKNOWLEDGE, l3ni1_connect_ack},
+ {SBIT(15),
+ MT_SUSPEND_ACKNOWLEDGE, l3ni1_suspend_ack},
+ {SBIT(15),
+ MT_SUSPEND_REJECT, l3ni1_suspend_rej},
+ {SBIT(17),
+ MT_RESUME_ACKNOWLEDGE, l3ni1_resume_ack},
+ {SBIT(17),
+ MT_RESUME_REJECT, l3ni1_resume_rej},
+};
+
+#define DATASLLEN \
+ (sizeof(datastatelist) / sizeof(struct stateentry))
+
+static struct stateentry globalmes_list[] =
+{
+ {ALL_STATES,
+ MT_STATUS, l3ni1_status},
+ {SBIT(0),
+ MT_RESTART, l3ni1_global_restart},
+/* {SBIT(1),
+ MT_RESTART_ACKNOWLEDGE, l3ni1_restart_ack},
+*/
+ { SBIT( 0 ), MT_DL_ESTABLISHED, l3ni1_spid_send },
+ { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), MT_INFORMATION, l3ni1_spid_epid },
+};
+#define GLOBALM_LEN \
+ (sizeof(globalmes_list) / sizeof(struct stateentry))
+
+static struct stateentry manstatelist[] =
+{
+ {SBIT(2),
+ DL_ESTABLISH | INDICATION, l3ni1_dl_reset},
+ {SBIT(10),
+ DL_ESTABLISH | CONFIRM, l3ni1_dl_reest_status},
+ {SBIT(10),
+ DL_RELEASE | INDICATION, l3ni1_dl_reestablish},
+ {ALL_STATES,
+ DL_RELEASE | INDICATION, l3ni1_dl_release},
+};
+
+#define MANSLLEN \
+ (sizeof(manstatelist) / sizeof(struct stateentry))
+/* *INDENT-ON* */
+
+
+static void
+global_handler(struct PStack *st, int mt, struct sk_buff *skb)
+{
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+ int i;
+ struct l3_process *proc = st->l3.global;
+
+ if ( skb )
+ proc->callref = skb->data[2]; /* cr flag */
+ else
+ proc->callref = 0;
+ for (i = 0; i < GLOBALM_LEN; i++)
+ if ((mt == globalmes_list[i].primitive) &&
+ ((1 << proc->state) & globalmes_list[i].state))
+ break;
+ if (i == GLOBALM_LEN) {
+ if (st->l3.debug & L3_DEB_STATE) {
+ l3_debug(st, "ni1 global state %d mt %x unhandled",
+ proc->state, mt);
+ }
+ MsgHead(p, proc->callref, MT_STATUS);
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = 81 |0x80; /* invalid cr */
+ *p++ = 0x14; /* CallState */
+ *p++ = 0x1;
+ *p++ = proc->state & 0x3f;
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ l3_msg(proc->st, DL_DATA | REQUEST, skb);
+ } else {
+ if (st->l3.debug & L3_DEB_STATE) {
+ l3_debug(st, "ni1 global %d mt %x",
+ proc->state, mt);
+ }
+ globalmes_list[i].rout(proc, mt, skb);
+ }
+}
+
+static void
+ni1up(struct PStack *st, int pr, void *arg)
+{
+ int i, mt, cr, cause, callState;
+ char *ptr;
+ u_char *p;
+ struct sk_buff *skb = arg;
+ struct l3_process *proc;
+
+ switch (pr) {
+ case (DL_DATA | INDICATION):
+ case (DL_UNIT_DATA | INDICATION):
+ break;
+ case (DL_ESTABLISH | INDICATION):
+ case (DL_RELEASE | INDICATION):
+ case (DL_RELEASE | CONFIRM):
+ l3_msg(st, pr, arg);
+ return;
+ break;
+
+ case (DL_ESTABLISH | CONFIRM):
+ global_handler( st, MT_DL_ESTABLISHED, NULL );
+ return;
+
+ default:
+ printk(KERN_ERR "HiSax ni1up unknown pr=%04x\n", pr);
+ return;
+ }
+ if (skb->len < 3) {
+ l3_debug(st, "ni1up frame too short(%d)", skb->len);
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ if (skb->data[0] != PROTO_DIS_EURO) {
+ if (st->l3.debug & L3_DEB_PROTERR) {
+ l3_debug(st, "ni1up%sunexpected discriminator %x message len %d",
+ (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+ skb->data[0], skb->len);
+ }
+ dev_kfree_skb(skb);
+ return;
+ }
+ cr = getcallref(skb->data);
+ if (skb->len < ((skb->data[1] & 0x0f) + 3)) {
+ l3_debug(st, "ni1up frame too short(%d)", skb->len);
+ dev_kfree_skb(skb);
+ return;
+ }
+ mt = skb->data[skb->data[1] + 2];
+ if (st->l3.debug & L3_DEB_STATE)
+ l3_debug(st, "ni1up cr %d", cr);
+ if (cr == -2) { /* wrong Callref */
+ if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "ni1up wrong Callref");
+ dev_kfree_skb(skb);
+ return;
+ } else if (cr == -1) { /* Dummy Callref */
+ if (mt == MT_FACILITY)
+ {
+ if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
+ l3ni1_parse_facility(st, NULL,
+ (pr == (DL_DATA | INDICATION)) ? -1 : -2, p);
+ dev_kfree_skb(skb);
+ return;
+ }
+ }
+ else
+ {
+ global_handler(st, mt, skb);
+ return;
+ }
+
+ if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "ni1up dummy Callref (no facility msg or ie)");
+ dev_kfree_skb(skb);
+ return;
+ } else if ((((skb->data[1] & 0x0f) == 1) && (0==(cr & 0x7f))) ||
+ (((skb->data[1] & 0x0f) == 2) && (0==(cr & 0x7fff)))) { /* Global CallRef */
+ if (st->l3.debug & L3_DEB_STATE)
+ l3_debug(st, "ni1up Global CallRef");
+ global_handler(st, mt, skb);
+ dev_kfree_skb(skb);
+ return;
+ } else if (!(proc = getl3proc(st, cr))) {
+ /* No transaction process exist, that means no call with
+ * this callreference is active
+ */
+ if (mt == MT_SETUP) {
+ /* Setup creates a new transaction process */
+ if (skb->data[2] & 0x80) {
+ /* Setup with wrong CREF flag */
+ if (st->l3.debug & L3_DEB_STATE)
+ l3_debug(st, "ni1up wrong CRef flag");
+ dev_kfree_skb(skb);
+ return;
+ }
+ if (!(proc = ni1_new_l3_process(st, cr))) {
+ /* May be to answer with RELEASE_COMPLETE and
+ * CAUSE 0x2f "Resource unavailable", but this
+ * need a new_l3_process too ... arghh
+ */
+ dev_kfree_skb(skb);
+ return;
+ }
+ } else if (mt == MT_STATUS) {
+ cause = 0;
+ if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) {
+ ptr++;
+ if (*ptr++ == 2)
+ ptr++;
+ cause = *ptr & 0x7f;
+ }
+ callState = 0;
+ if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) {
+ ptr++;
+ if (*ptr++ == 2)
+ ptr++;
+ callState = *ptr;
+ }
+ /* ETS 300-104 part 2.4.1
+ * if setup has not been made and a message type
+ * MT_STATUS is received with call state == 0,
+ * we must send nothing
+ */
+ if (callState != 0) {
+ /* ETS 300-104 part 2.4.2
+ * if setup has not been made and a message type
+ * MT_STATUS is received with call state != 0,
+ * we must send MT_RELEASE_COMPLETE cause 101
+ */
+ if ((proc = ni1_new_l3_process(st, cr))) {
+ proc->para.cause = 101;
+ l3ni1_msg_without_setup(proc, 0, NULL);
+ }
+ }
+ dev_kfree_skb(skb);
+ return;
+ } else if (mt == MT_RELEASE_COMPLETE) {
+ dev_kfree_skb(skb);
+ return;
+ } else {
+ /* ETS 300-104 part 2
+ * if setup has not been made and a message type
+ * (except MT_SETUP and RELEASE_COMPLETE) is received,
+ * we must send MT_RELEASE_COMPLETE cause 81 */
+ dev_kfree_skb(skb);
+ if ((proc = ni1_new_l3_process(st, cr))) {
+ proc->para.cause = 81;
+ l3ni1_msg_without_setup(proc, 0, NULL);
+ }
+ return;
+ }
+ }
+ if (l3ni1_check_messagetype_validity(proc, mt, skb)) {
+ dev_kfree_skb(skb);
+ return;
+ }
+ if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL)
+ l3ni1_deliver_display(proc, pr, p); /* Display IE included */
+ for (i = 0; i < DATASLLEN; i++)
+ if ((mt == datastatelist[i].primitive) &&
+ ((1 << proc->state) & datastatelist[i].state))
+ break;
+ if (i == DATASLLEN) {
+ if (st->l3.debug & L3_DEB_STATE) {
+ l3_debug(st, "ni1up%sstate %d mt %#x unhandled",
+ (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+ proc->state, mt);
+ }
+ if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) {
+ proc->para.cause = 101;
+ l3ni1_status_send(proc, pr, skb);
+ }
+ } else {
+ if (st->l3.debug & L3_DEB_STATE) {
+ l3_debug(st, "ni1up%sstate %d mt %x",
+ (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+ proc->state, mt);
+ }
+ datastatelist[i].rout(proc, pr, skb);
+ }
+ dev_kfree_skb(skb);
+ return;
+}
+
+static void
+ni1down(struct PStack *st, int pr, void *arg)
+{
+ int i, cr;
+ struct l3_process *proc;
+ struct Channel *chan;
+
+ if ((DL_ESTABLISH | REQUEST) == pr) {
+ l3_msg(st, pr, NULL);
+ return;
+ } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) {
+ chan = arg;
+ cr = newcallref();
+ cr |= 0x80;
+ if ((proc = ni1_new_l3_process(st, cr))) {
+ proc->chan = chan;
+ chan->proc = proc;
+ memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
+ proc->callref = cr;
+ }
+ } else {
+ proc = arg;
+ }
+ if (!proc) {
+ printk(KERN_ERR "HiSax ni1down without proc pr=%04x\n", pr);
+ return;
+ }
+
+ if ( pr == (CC_TNI1_IO | REQUEST)) {
+ l3ni1_io_timer(proc); /* timer expires */
+ return;
+ }
+
+ for (i = 0; i < DOWNSLLEN; i++)
+ if ((pr == downstatelist[i].primitive) &&
+ ((1 << proc->state) & downstatelist[i].state))
+ break;
+ if (i == DOWNSLLEN) {
+ if (st->l3.debug & L3_DEB_STATE) {
+ l3_debug(st, "ni1down state %d prim %#x unhandled",
+ proc->state, pr);
+ }
+ } else {
+ if (st->l3.debug & L3_DEB_STATE) {
+ l3_debug(st, "ni1down state %d prim %#x",
+ proc->state, pr);
+ }
+ downstatelist[i].rout(proc, pr, arg);
+ }
+}
+
+static void
+ni1man(struct PStack *st, int pr, void *arg)
+{
+ int i;
+ struct l3_process *proc = arg;
+
+ if (!proc) {
+ printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr);
+ return;
+ }
+ for (i = 0; i < MANSLLEN; i++)
+ if ((pr == manstatelist[i].primitive) &&
+ ((1 << proc->state) & manstatelist[i].state))
+ break;
+ if (i == MANSLLEN) {
+ if (st->l3.debug & L3_DEB_STATE) {
+ l3_debug(st, "cr %d ni1man state %d prim %#x unhandled",
+ proc->callref & 0x7f, proc->state, pr);
+ }
+ } else {
+ if (st->l3.debug & L3_DEB_STATE) {
+ l3_debug(st, "cr %d ni1man state %d prim %#x",
+ proc->callref & 0x7f, proc->state, pr);
+ }
+ manstatelist[i].rout(proc, pr, arg);
+ }
+}
+
+void
+setstack_ni1(struct PStack *st)
+{
+ char tmp[64];
+ int i;
+
+ st->lli.l4l3 = ni1down;
+ st->lli.l4l3_proto = l3ni1_cmd_global;
+ st->l2.l2l3 = ni1up;
+ st->l3.l3ml3 = ni1man;
+ st->l3.N303 = 1;
+ st->prot.ni1.last_invoke_id = 0;
+ st->prot.ni1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */
+ i = 1;
+ while (i < 32)
+ st->prot.ni1.invoke_used[i++] = 0;
+
+ if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
+ printk(KERN_ERR "HiSax can't get memory for ni1 global CR\n");
+ } else {
+ st->l3.global->state = 0;
+ st->l3.global->callref = 0;
+ st->l3.global->next = NULL;
+ st->l3.global->debug = L3_DEB_WARN;
+ st->l3.global->st = st;
+ st->l3.global->N303 = 1;
+ st->l3.global->prot.ni1.invoke_id = 0;
+
+ L3InitTimer(st->l3.global, &st->l3.global->timer);
+ }
+ strcpy(tmp, ni1_revision);
+ printk(KERN_INFO "HiSax: National ISDN-1 Rev. %s\n", HiSax_getrev(tmp));
+}
diff --git a/drivers/isdn/hisax/l3ni1.h b/drivers/isdn/hisax/l3ni1.h
new file mode 100644
index 000000000..24c919a17
--- /dev/null
+++ b/drivers/isdn/hisax/l3ni1.h
@@ -0,0 +1,136 @@
+// $Id: l3ni1.h,v 2.2 2000/06/26 08:59:14 keil Exp $
+//-----------------------------------------------------------------------------
+//
+// NI1 D-channel protocol
+//
+// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd
+// www.traverse.com.au
+//
+// 2000.6.6 Initial implementation of routines for US NI1
+// Layer 3 protocol based on the EURO/DSS1 D-channel protocol
+// driver written by Karsten Keil et al. Thanks also for the
+// code provided by Ragnar Paulson.
+//
+// This file is (c) under GNU PUBLIC LICENSE
+//
+//-----------------------------------------------------------------------------
+
+#ifndef l3ni1_process
+
+#define T302 15000
+#define T303 4000
+#define T304 30000
+#define T305 30000
+#define T308 4000
+/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
+/* This makes some tests easier and quicker */
+#define T309 40000
+#define T310 30000
+#define T313 4000
+#define T318 4000
+#define T319 4000
+#define TSPID 2000
+
+/*
+ * Message-Types
+ */
+
+#define MT_ALERTING 0x01
+#define MT_CALL_PROCEEDING 0x02
+#define MT_CONNECT 0x07
+#define MT_CONNECT_ACKNOWLEDGE 0x0f
+#define MT_PROGRESS 0x03
+#define MT_SETUP 0x05
+#define MT_SETUP_ACKNOWLEDGE 0x0d
+#define MT_RESUME 0x26
+#define MT_RESUME_ACKNOWLEDGE 0x2e
+#define MT_RESUME_REJECT 0x22
+#define MT_SUSPEND 0x25
+#define MT_SUSPEND_ACKNOWLEDGE 0x2d
+#define MT_SUSPEND_REJECT 0x21
+#define MT_USER_INFORMATION 0x20
+#define MT_DISCONNECT 0x45
+#define MT_RELEASE 0x4d
+#define MT_RELEASE_COMPLETE 0x5a
+#define MT_RESTART 0x46
+#define MT_RESTART_ACKNOWLEDGE 0x4e
+#define MT_SEGMENT 0x60
+#define MT_CONGESTION_CONTROL 0x79
+#define MT_INFORMATION 0x7b
+#define MT_FACILITY 0x62
+#define MT_NOTIFY 0x6e
+#define MT_STATUS 0x7d
+#define MT_STATUS_ENQUIRY 0x75
+#define MT_DL_ESTABLISHED 0xfe
+
+#define IE_SEGMENT 0x00
+#define IE_BEARER 0x04
+#define IE_CAUSE 0x08
+#define IE_CALL_ID 0x10
+#define IE_CALL_STATE 0x14
+#define IE_CHANNEL_ID 0x18
+#define IE_FACILITY 0x1c
+#define IE_PROGRESS 0x1e
+#define IE_NET_FAC 0x20
+#define IE_NOTIFY 0x27
+#define IE_DISPLAY 0x28
+#define IE_DATE 0x29
+#define IE_KEYPAD 0x2c
+#define IE_SIGNAL 0x34
+#define IE_SPID 0x3a
+#define IE_ENDPOINT_ID 0x3b
+#define IE_INFORATE 0x40
+#define IE_E2E_TDELAY 0x42
+#define IE_TDELAY_SEL 0x43
+#define IE_PACK_BINPARA 0x44
+#define IE_PACK_WINSIZE 0x45
+#define IE_PACK_SIZE 0x46
+#define IE_CUG 0x47
+#define IE_REV_CHARGE 0x4a
+#define IE_CONNECT_PN 0x4c
+#define IE_CONNECT_SUB 0x4d
+#define IE_CALLING_PN 0x6c
+#define IE_CALLING_SUB 0x6d
+#define IE_CALLED_PN 0x70
+#define IE_CALLED_SUB 0x71
+#define IE_REDIR_NR 0x74
+#define IE_TRANS_SEL 0x78
+#define IE_RESTART_IND 0x79
+#define IE_LLC 0x7c
+#define IE_HLC 0x7d
+#define IE_USER_USER 0x7e
+#define IE_ESCAPE 0x7f
+#define IE_SHIFT 0x90
+#define IE_MORE_DATA 0xa0
+#define IE_COMPLETE 0xa1
+#define IE_CONGESTION 0xb0
+#define IE_REPEAT 0xd0
+
+#define IE_MANDATORY 0x0100
+/* mandatory not in every case */
+#define IE_MANDATORY_1 0x0200
+
+#define ERR_IE_COMPREHENSION 1
+#define ERR_IE_UNRECOGNIZED -1
+#define ERR_IE_LENGTH -2
+#define ERR_IE_SEQUENCE -3
+
+#else /* only l3ni1_process */
+
+/* l3ni1 specific data in l3 process */
+typedef struct
+ { unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */
+ ulong ll_id; /* remebered ll id */
+ u_char remote_operation; /* handled remote operation, 0 = not active */
+ int proc; /* rememered procedure */
+ ulong remote_result; /* result of remote operation for statcallb */
+ char uus1_data[35]; /* data send during alerting or disconnect */
+ } ni1_proc_priv;
+
+/* l3dni1 specific data in protocol stack */
+typedef struct
+ { unsigned char last_invoke_id; /* last used value for invoking */
+ unsigned char invoke_used[32]; /* 256 bits for 256 values */
+ } ni1_stk_priv;
+
+#endif /* only l3dni1_process */
diff --git a/drivers/isdn/hisax/md5sums.asc b/drivers/isdn/hisax/md5sums.asc
index 3ccbfc33a..a8e65d8b2 100644
--- a/drivers/isdn/hisax/md5sums.asc
+++ b/drivers/isdn/hisax/md5sums.asc
@@ -2,30 +2,32 @@
# This are valid md5sums for certificated HiSax driver.
# The certification is valid only if the md5sums of all files match.
-# The certification is valid only for ELSA QuickStep cards and
-# Eicon Technology Diva 2.01 PCI cards in the moment.
+# The certification is valid only for ELSA Microlink PCI,
+# Eicon Technology Diva 2.01 PCI and Sedlbauer SpeedFax +
+# cards in the moment.
# Read ../../../Documentation/isdn/HiSax.cert for more informations.
#
-3fb9c99465857a4c136ae2881f4e30ba isac.c
-dd3955847bbf680b41233478fe521d88 isdnl1.c
-d362523462c424a8bce8b596ed5bdf2e isdnl2.c
-92ea268891c222963a6ca70935bf1556 isdnl3.c
-a23fbf8879c1432b04640b8b04bdf419 tei.c
-838791b14269ec94c74ba4ae89c022e6 callc.c
-bf9605b36429898f7be6630034e83230 cert.c
-a30e6253837739f6f54d9dadcd42d9f2 l3dss1.c
-a3a570781f828b6d59e6b231653133de l3_1tr6.c
-4aeba32c4c3480d2a6b9af34600b974f elsa.c
-a296edc459b508bf0346c3132815a4db diva.c
+f4573d10ffe38b49f6c94e4c966b7bab isac.c
+a29f5270c0c89626d8d6fa5dd09e7005 isdnl1.c
+fbe41751c8130a8c3c607bfe1b41cb4e isdnl2.c
+7915b7e802b98f6f4f05b931c4736ad4 isdnl3.c
+7c31c12b3c2cfde33596bd2c406f775c tei.c
+f1fbd532016f005e01decf36e5197d8f callc.c
+a1834e9b2ec068440cff2e899eff4710 cert.c
+a1f908f8b4f225c5c2f2a13842549b72 l3dss1.c
+5bcab52f9937beb352aa02093182e039 l3_1tr6.c
+030d4600ee59a2b246410d6a73977412 elsa.c
+9e800b8e05c24542d731721eb192f305 diva.c
+f32fae58dd9b2b3a73b2e5028f68dc4c sedlbauer.c
# end of md5sums
-----BEGIN PGP SIGNATURE-----
Version: 2.6.3i
Charset: noconv
-iQCVAwUBOPT2aTpxHvX/mS9tAQFJyAQAj+eY8MhPxQ2TS3rtfjK7bv8jrOGeJYu6
-P0YPnkkc09pCA6UdmYP6VSFkhtDS43HEZiGMb1MV/Y4LQ4wVDNrFDk9AyUNhP2/0
-gY+nYON6hT9ilXYqsbqoqGmh5qLaxj64p9mKu+MIgZ69CS4g7aj/OAXWB06zh7li
-MiC65PNo6k0=
-=d7xA
+iQCVAwUBOaARmDpxHvX/mS9tAQFT7wP/TEEhtP96uKKgzr2o3GpJ5rRik0Q1HbKY
+dzeA3U79QCEYqyptU09Uz96Av3dt1lNxpQyaahX419NjHH53HCaZgFCxgRxFWBYS
+M9s4aSXLPTCSNM/kWiZkzWQ2lZ7ISNk2/+fF73w4l3G+4zF5y+VotjZCPx7OJj6i
+R/L1m4vZXys=
+=6DzE
-----END PGP SIGNATURE-----
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
index fd51217bf..6be8a493d 100644
--- a/drivers/isdn/hisax/netjet.c
+++ b/drivers/isdn/hisax/netjet.c
@@ -11,7 +11,6 @@
*/
#define __NO_VERSION__
-#include <linux/config.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
@@ -19,6 +18,7 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/ppp_defs.h>
+#include "netjet.h"
#ifndef bus_to_virt
#define bus_to_virt (u_int *)
@@ -28,61 +28,12 @@
#define virt_to_bus (u_int)
#endif
-extern const char *CardType[];
-
-const char *NETjet_revision = "$Revision: 1.18 $";
-
-#define byteout(addr,val) outb(val,addr)
-#define bytein(addr) inb(addr)
-
-/* PCI stuff */
-#define PCI_VENDOR_TRAVERSE_TECH 0xe159
-#define PCI_NETJET_ID 0x0001
-
-#define NETJET_CTRL 0x00
-#define NETJET_DMACTRL 0x01
-#define NETJET_AUXCTRL 0x02
-#define NETJET_AUXDATA 0x03
-#define NETJET_IRQMASK0 0x04
-#define NETJET_IRQMASK1 0x05
-#define NETJET_IRQSTAT0 0x06
-#define NETJET_IRQSTAT1 0x07
-#define NETJET_DMA_READ_START 0x08
-#define NETJET_DMA_READ_IRQ 0x0c
-#define NETJET_DMA_READ_END 0x10
-#define NETJET_DMA_READ_ADR 0x14
-#define NETJET_DMA_WRITE_START 0x18
-#define NETJET_DMA_WRITE_IRQ 0x1c
-#define NETJET_DMA_WRITE_END 0x20
-#define NETJET_DMA_WRITE_ADR 0x24
-#define NETJET_PULSE_CNT 0x28
-
-#define NETJET_ISAC_OFF 0xc0
-#define NETJET_ISACIRQ 0x10
-#define NETJET_IRQM0_READ 0x0c
-#define NETJET_IRQM0_READ_1 0x04
-#define NETJET_IRQM0_READ_2 0x08
-#define NETJET_IRQM0_WRITE 0x03
-#define NETJET_IRQM0_WRITE_1 0x01
-#define NETJET_IRQM0_WRITE_2 0x02
-
-#define NETJET_DMA_TXSIZE 512
-#define NETJET_DMA_RXSIZE 128
-
-#define HDLC_ZERO_SEARCH 0
-#define HDLC_FLAG_SEARCH 1
-#define HDLC_FLAG_FOUND 2
-#define HDLC_FRAME_FOUND 3
-#define HDLC_NULL 4
-#define HDLC_PART 5
-#define HDLC_FULL 6
-
-#define HDLC_FLAG_VALUE 0x7e
+const char *NETjet_revision = "$Revision: 1.20 $";
/* Interface functions */
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
+u_char
+NETjet_ReadIC(struct IsdnCardState *cs, u_char offset)
{
long flags;
u_char ret;
@@ -97,8 +48,8 @@ ReadISAC(struct IsdnCardState *cs, u_char offset)
return(ret);
}
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+void
+NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value)
{
long flags;
@@ -111,8 +62,8 @@ WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
restore_flags(flags);
}
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
+void
+NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size)
{
cs->hw.njet.auxd &= 0xfc;
byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
@@ -155,8 +106,8 @@ __u16 fcstab[256] =
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
+void
+NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size)
{
cs->hw.njet.auxd &= 0xfc;
byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
@@ -242,15 +193,6 @@ mode_tiger(struct BCState *bcs, int mode, int bc)
bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
}
-static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
-{
- return(5);
-}
-
-static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
-{
-}
-
static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) {
char tmp[128];
char *t = tmp;
@@ -541,7 +483,7 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){
bcs->hw.tiger.r_bitcnt = bitcnt;
}
-static void read_tiger(struct IsdnCardState *cs) {
+void read_tiger(struct IsdnCardState *cs) {
u_int *p;
int cnt = NETJET_DMA_RXSIZE/2;
@@ -572,7 +514,7 @@ static void read_tiger(struct IsdnCardState *cs) {
static void write_raw(struct BCState *bcs, u_int *buf, int cnt);
-static void fill_dma(struct BCState *bcs)
+void netjet_fill_dma(struct BCState *bcs)
{
register u_int *p, *sp;
register int cnt;
@@ -687,7 +629,7 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag);
}
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- fill_dma(bcs);
+ netjet_fill_dma(bcs);
} else {
mask ^= 0xffffffff;
if (s_cnt < cnt) {
@@ -719,7 +661,7 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
}
}
-static void write_tiger(struct IsdnCardState *cs) {
+void write_tiger(struct IsdnCardState *cs) {
u_int *p, cnt = NETJET_DMA_TXSIZE/2;
if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) {
@@ -935,88 +877,6 @@ releasetiger(struct IsdnCardState *cs)
}
}
-static void
-netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val, sval;
- long flags;
-
- if (!cs) {
- printk(KERN_WARNING "NETjet: Spurious interrupt!\n");
- return;
- }
- if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) &
- NETJET_ISACIRQ)) {
- val = ReadISAC(cs, ISAC_ISTA);
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "tiger: i1 %x %x", sval, val);
- if (val) {
- isac_interrupt(cs, val);
- WriteISAC(cs, ISAC_MASK, 0xFF);
- WriteISAC(cs, ISAC_MASK, 0x0);
- }
- }
- save_flags(flags);
- cli();
- if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) {
- if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- restore_flags(flags);
- return;
- }
- cs->hw.njet.irqstat0 = sval;
- restore_flags(flags);
-/* debugl1(cs, "tiger: ist0 %x %x %x %x/%x pulse=%d",
- sval,
- bytein(cs->hw.njet.base + NETJET_DMACTRL),
- bytein(cs->hw.njet.base + NETJET_IRQMASK0),
- inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
- inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
- bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
-*/
-/* cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30;
-*/ byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0);
-/* byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0);
-*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ)
- read_tiger(cs);
- if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE)
- write_tiger(cs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- restore_flags(flags);
-
-/* if (!testcnt--) {
- cs->hw.njet.dmactrl = 0;
- byteout(cs->hw.njet.base + NETJET_DMACTRL,
- cs->hw.njet.dmactrl);
- byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
- }
-*/
-}
-
-static void
-reset_netjet(struct IsdnCardState *cs)
-{
- long flags;
-
- save_flags(flags);
- sti();
- cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
- byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
- cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
- byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
- restore_flags(flags);
- cs->hw.njet.auxd = 0;
- cs->hw.njet.dmactrl = 0;
- byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
- byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
-}
-
void
release_io_netjet(struct IsdnCardState *cs)
{
@@ -1026,100 +886,3 @@ release_io_netjet(struct IsdnCardState *cs)
release_region(cs->hw.njet.base, 256);
}
-
-static int
-NETjet_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- switch (mt) {
- case CARD_RESET:
- reset_netjet(cs);
- return(0);
- case CARD_RELEASE:
- release_io_netjet(cs);
- return(0);
- case CARD_INIT:
- inittiger(cs);
- clear_pending_isac_ints(cs);
- initisac(cs);
- /* Reenable all IRQ */
- cs->writeisac(cs, ISAC_MASK, 0);
- return(0);
- case CARD_TEST:
- return(0);
- }
- return(0);
-}
-
-static struct pci_dev *dev_netjet __initdata = NULL;
-
-__initfunc(int
-setup_netjet(struct IsdnCard *card))
-{
- int bytecnt;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-#if CONFIG_PCI
-#endif
- strcpy(tmp, NETjet_revision);
- printk(KERN_INFO "HiSax: Traverse Tech. NETjet driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_NETJET)
- return(0);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
-#if CONFIG_PCI
- if (!pci_present()) {
- printk(KERN_ERR "Netjet: no PCI bus present\n");
- return(0);
- }
- if ((dev_netjet = pci_find_device(PCI_VENDOR_TRAVERSE_TECH,
- PCI_NETJET_ID, dev_netjet))) {
- if (pci_enable_device(dev_netjet))
- return (0);
- cs->irq = dev_netjet->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n");
- return(0);
- }
- cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
- if (!cs->hw.njet.base) {
- printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n");
- return(0);
- }
- } else {
- printk(KERN_WARNING "NETjet: No PCI card found\n");
- return(0);
- }
- cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
- cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
- bytecnt = 256;
-#else
- printk(KERN_WARNING "NETjet: NO_PCI_BIOS\n");
- printk(KERN_WARNING "NETjet: unable to config NETJET PCI\n");
- return (0);
-#endif /* CONFIG_PCI */
- printk(KERN_INFO
- "NETjet: PCI card configured at 0x%x IRQ %d\n",
- cs->hw.njet.base, cs->irq);
- if (check_region(cs->hw.njet.base, bytecnt)) {
- printk(KERN_WARNING
- "HiSax: %s config port %x-%x already in use\n",
- CardType[card->typ],
- cs->hw.njet.base,
- cs->hw.njet.base + bytecnt);
- return (0);
- } else {
- request_region(cs->hw.njet.base, bytecnt, "netjet isdn");
- }
- reset_netjet(cs);
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &dummyrr;
- cs->BC_Write_Reg = &dummywr;
- cs->BC_Send_Data = &fill_dma;
- cs->cardmsg = &NETjet_card_msg;
- cs->irq_func = &netjet_interrupt;
- cs->irq_flags |= SA_SHIRQ;
- ISACVersion(cs, "NETjet:");
- return (1);
-}
diff --git a/drivers/isdn/hisax/netjet.h b/drivers/isdn/hisax/netjet.h
new file mode 100644
index 000000000..d7dede4ff
--- /dev/null
+++ b/drivers/isdn/hisax/netjet.h
@@ -0,0 +1,77 @@
+// $Id: netjet.h,v 2.3 2000/06/26 08:59:14 keil Exp $
+//-----------------------------------------------------------------------------
+//
+// NETjet common header file
+//
+// Author Kerstern Keil repackaged by
+// Matt Henderson - Traverse Technologies P/L www.traverse.com.au
+//
+// This file is (c) under GNU PUBLIC LICENSE
+//
+//-----------------------------------------------------------------------------
+
+extern const char *CardType[];
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+/* PCI stuff */
+#ifndef PCI_VENDOR_ID_TIGERJET
+#define PCI_VENDOR_ID_TIGERJET 0xe159
+#endif
+#ifndef PCI_DEVICE_ID_TIGERJET_300
+#define PCI_DEVICE_ID_TIGERJET_300 0x0001
+#endif
+#define NETJET_CTRL 0x00
+#define NETJET_DMACTRL 0x01
+#define NETJET_AUXCTRL 0x02
+#define NETJET_AUXDATA 0x03
+#define NETJET_IRQMASK0 0x04
+#define NETJET_IRQMASK1 0x05
+#define NETJET_IRQSTAT0 0x06
+#define NETJET_IRQSTAT1 0x07
+#define NETJET_DMA_READ_START 0x08
+#define NETJET_DMA_READ_IRQ 0x0c
+#define NETJET_DMA_READ_END 0x10
+#define NETJET_DMA_READ_ADR 0x14
+#define NETJET_DMA_WRITE_START 0x18
+#define NETJET_DMA_WRITE_IRQ 0x1c
+#define NETJET_DMA_WRITE_END 0x20
+#define NETJET_DMA_WRITE_ADR 0x24
+#define NETJET_PULSE_CNT 0x28
+
+#define NETJET_ISAC_OFF 0xc0
+#define NETJET_ISACIRQ 0x10
+#define NETJET_IRQM0_READ 0x0c
+#define NETJET_IRQM0_READ_1 0x04
+#define NETJET_IRQM0_READ_2 0x08
+#define NETJET_IRQM0_WRITE 0x03
+#define NETJET_IRQM0_WRITE_1 0x01
+#define NETJET_IRQM0_WRITE_2 0x02
+
+#define NETJET_DMA_TXSIZE 512
+#define NETJET_DMA_RXSIZE 128
+
+#define HDLC_ZERO_SEARCH 0
+#define HDLC_FLAG_SEARCH 1
+#define HDLC_FLAG_FOUND 2
+#define HDLC_FRAME_FOUND 3
+#define HDLC_NULL 4
+#define HDLC_PART 5
+#define HDLC_FULL 6
+
+#define HDLC_FLAG_VALUE 0x7e
+
+u_char NETjet_ReadIC(struct IsdnCardState *cs, u_char offset);
+void NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value);
+void NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size);
+void NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size);
+
+void read_tiger(struct IsdnCardState *cs);
+void write_tiger(struct IsdnCardState *cs);
+
+void netjet_fill_dma(struct BCState *bcs);
+void netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs);
+__initfunc(void inittiger(struct IsdnCardState *cs));
+void release_io_netjet(struct IsdnCardState *cs);
+
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
index 31f01355e..4428483b3 100644
--- a/drivers/isdn/hisax/niccy.c
+++ b/drivers/isdn/hisax/niccy.c
@@ -38,8 +38,12 @@ const char *niccy_revision = "$Revision: 1.12 $";
#define NICCY_PCI 2
/* PCI stuff */
-#define PCI_VENDOR_DR_NEUHAUS 0x1267
-#define PCI_NICCY_ID 0x1016
+#ifndef PCI_VENDOR_ID_SATSAGEM
+#define PCI_VENDOR_ID_SATSAGEM 0x1267
+#endif
+#ifndef PCI_DEVICE_ID_SATSAGEM_NICCY
+#define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016
+#endif
#define PCI_IRQ_CTRL_REG 0x38
#define PCI_IRQ_ENABLE 0x1f00
#define PCI_IRQ_DISABLE 0xff0000
@@ -284,26 +288,26 @@ setup_niccy(struct IsdnCard *card))
return(0);
}
cs->subtyp = 0;
- if ((niccy_dev = pci_find_device(PCI_VENDOR_DR_NEUHAUS,
- PCI_NICCY_ID, niccy_dev))) {
+ if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM,
+ PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) {
if (pci_enable_device(niccy_dev))
- return (0);
+ return(0);
/* get IRQ */
if (!niccy_dev->irq) {
printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
return(0);
}
cs->irq = niccy_dev->irq;
- if (!niccy_dev->resource[ 0].start) {
+ cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0);
+ if (!cs->hw.niccy.cfg_reg) {
printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
return(0);
}
- cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0);
- if (!niccy_dev->resource[ 1].start) {
+ pci_ioaddr = pci_resource_start(niccy_dev, 1);
+ if (!pci_ioaddr) {
printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
return(0);
}
- pci_ioaddr = pci_resource_start(niccy_dev, 1);
cs->subtyp = NICCY_PCI;
} else {
printk(KERN_WARNING "Niccy: No PCI card found\n");
diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
new file mode 100644
index 000000000..2acb1a6de
--- /dev/null
+++ b/drivers/isdn/hisax/nj_s.c
@@ -0,0 +1,257 @@
+// $Id: nj_s.c,v 2.3 2000/06/26 08:59:14 keil Exp $
+//
+// This file is (c) under GNU PUBLIC LICENSE
+//
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "hisax.h"
+#include "isac.h"
+#include "isdnl1.h"
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/ppp_defs.h>
+#include "netjet.h"
+
+const char *NETjet_S_revision = "$Revision: 2.3 $";
+
+static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
+{
+ return(5);
+}
+
+static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
+{
+}
+
+static void
+netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val, sval;
+ long flags;
+
+ if (!cs) {
+ printk(KERN_WARNING "NETjet-S: Spurious interrupt!\n");
+ return;
+ }
+ if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) &
+ NETJET_ISACIRQ)) {
+ val = NETjet_ReadIC(cs, ISAC_ISTA);
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "tiger: i1 %x %x", sval, val);
+ if (val) {
+ isac_interrupt(cs, val);
+ NETjet_WriteIC(cs, ISAC_MASK, 0xFF);
+ NETjet_WriteIC(cs, ISAC_MASK, 0x0);
+ }
+ }
+ save_flags(flags);
+ cli();
+ if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) {
+ if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ restore_flags(flags);
+ return;
+ }
+ cs->hw.njet.irqstat0 = sval;
+ restore_flags(flags);
+/* debugl1(cs, "tiger: ist0 %x %x %x %x/%x pulse=%d",
+ sval,
+ bytein(cs->hw.njet.base + NETJET_DMACTRL),
+ bytein(cs->hw.njet.base + NETJET_IRQMASK0),
+ inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
+ inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
+ bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
+*/
+/* cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30;
+*/ byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0);
+/* byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0);
+*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ)
+ read_tiger(cs);
+ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE)
+ write_tiger(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ restore_flags(flags);
+
+/* if (!testcnt--) {
+ cs->hw.njet.dmactrl = 0;
+ byteout(cs->hw.njet.base + NETJET_DMACTRL,
+ cs->hw.njet.dmactrl);
+ byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
+ }
+*/
+}
+
+static void
+reset_netjet_s(struct IsdnCardState *cs)
+{
+ long flags;
+
+ save_flags(flags);
+ sti();
+ cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
+ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+ cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
+ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+ restore_flags(flags);
+ cs->hw.njet.auxd = 0;
+ cs->hw.njet.dmactrl = 0;
+ byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+ byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+ byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+}
+
+static int
+NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ reset_netjet_s(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_netjet(cs);
+ return(0);
+ case CARD_INIT:
+ inittiger(cs);
+ clear_pending_isac_ints(cs);
+ initisac(cs);
+ /* Reenable all IRQ */
+ cs->writeisac(cs, ISAC_MASK, 0);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
+}
+
+static struct pci_dev *dev_netjet __initdata = NULL;
+
+__initfunc(int
+setup_netjet_s(struct IsdnCard *card))
+{
+ int bytecnt;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+ long flags;
+#if CONFIG_PCI
+#endif
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+ strcpy(tmp, NETjet_S_revision);
+ printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_NETJET_S)
+ return(0);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+ for ( ;; )
+ {
+
+#if CONFIG_PCI
+
+ if (!pci_present()) {
+ printk(KERN_ERR "Netjet: no PCI bus present\n");
+ return(0);
+ }
+ if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+ PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
+ if (pci_enable_device(dev_netjet))
+ return(0);
+ cs->irq = dev_netjet->irq;
+ if (!cs->irq) {
+ printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n");
+ return(0);
+ }
+ cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
+ if (!cs->hw.njet.base) {
+ printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ } else {
+ printk(KERN_WARNING "NETjet-S: No PCI card found\n");
+ return(0);
+ }
+
+ cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+ cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
+
+ save_flags(flags);
+ sti();
+
+ cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
+ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+
+ cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
+ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+
+ restore_flags(flags);
+
+ cs->hw.njet.auxd = 0xC0;
+ cs->hw.njet.dmactrl = 0;
+
+ byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+ byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+ byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+
+ switch ( ( ( NETjet_ReadIC( cs, ISAC_RBCH ) >> 5 ) & 3 ) )
+ {
+ case 0 :
+ break;
+
+ case 3 :
+ printk( KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" );
+ continue;
+
+ default :
+ printk( KERN_WARNING "NETjet-S: No PCI card found\n" );
+ return 0;
+ }
+ break;
+ }
+#else
+
+ printk(KERN_WARNING "NETjet-S: NO_PCI_BIOS\n");
+ printk(KERN_WARNING "NETjet-S: unable to config NETJET-S PCI\n");
+ return (0);
+
+#endif /* CONFIG_PCI */
+
+ bytecnt = 256;
+
+ printk(KERN_INFO
+ "NETjet-S: PCI card configured at 0x%x IRQ %d\n",
+ cs->hw.njet.base, cs->irq);
+ if (check_region(cs->hw.njet.base, bytecnt)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.njet.base,
+ cs->hw.njet.base + bytecnt);
+ return (0);
+ } else {
+ request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn");
+ }
+ reset_netjet_s(cs);
+ cs->readisac = &NETjet_ReadIC;
+ cs->writeisac = &NETjet_WriteIC;
+ cs->readisacfifo = &NETjet_ReadICfifo;
+ cs->writeisacfifo = &NETjet_WriteICfifo;
+ cs->BC_Read_Reg = &dummyrr;
+ cs->BC_Write_Reg = &dummywr;
+ cs->BC_Send_Data = &netjet_fill_dma;
+ cs->cardmsg = &NETjet_S_card_msg;
+ cs->irq_func = &netjet_s_interrupt;
+ cs->irq_flags |= SA_SHIRQ;
+ ISACVersion(cs, "NETjet-S:");
+ return (1);
+}
diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c
new file mode 100644
index 000000000..5ad977128
--- /dev/null
+++ b/drivers/isdn/hisax/nj_u.c
@@ -0,0 +1,260 @@
+/* $Id: nj_u.c,v 2.4 2000/06/26 11:42:16 keil Exp $
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "hisax.h"
+#include "icc.h"
+#include "isdnl1.h"
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/ppp_defs.h>
+#include "netjet.h"
+
+const char *NETjet_U_revision = "$Revision: 2.4 $";
+
+static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
+{
+ return(5);
+}
+
+static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
+{
+}
+
+static void
+netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val, sval;
+ long flags;
+
+ if (!cs) {
+ printk(KERN_WARNING "NETspider-U: Spurious interrupt!\n");
+ return;
+ }
+ if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) &
+ NETJET_ISACIRQ)) {
+ val = NETjet_ReadIC(cs, ICC_ISTA);
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "tiger: i1 %x %x", sval, val);
+ if (val) {
+ icc_interrupt(cs, val);
+ NETjet_WriteIC(cs, ICC_MASK, 0xFF);
+ NETjet_WriteIC(cs, ICC_MASK, 0x0);
+ }
+ }
+ save_flags(flags);
+ cli();
+ if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) {
+ if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ restore_flags(flags);
+ return;
+ }
+ cs->hw.njet.irqstat0 = sval;
+ restore_flags(flags);
+/* debugl1(cs, "tiger: ist0 %x %x %x %x/%x pulse=%d",
+ sval,
+ bytein(cs->hw.njet.base + NETJET_DMACTRL),
+ bytein(cs->hw.njet.base + NETJET_IRQMASK0),
+ inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
+ inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
+ bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
+*/
+/* cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30;
+*/ byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0);
+/* byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0);
+*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ)
+ read_tiger(cs);
+ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE)
+ write_tiger(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ restore_flags(flags);
+
+/* if (!testcnt--) {
+ cs->hw.njet.dmactrl = 0;
+ byteout(cs->hw.njet.base + NETJET_DMACTRL,
+ cs->hw.njet.dmactrl);
+ byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
+ }
+*/
+}
+
+static void
+reset_netjet_u(struct IsdnCardState *cs)
+{
+ long flags;
+
+ save_flags(flags);
+ sti();
+ cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
+ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+ cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
+ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+ restore_flags(flags);
+ cs->hw.njet.auxd = 0xC0;
+ cs->hw.njet.dmactrl = 0;
+ byteout(cs->hw.njet.auxa, 0);
+ byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+ byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+ byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+}
+
+static int
+NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ reset_netjet_u(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_netjet(cs);
+ return(0);
+ case CARD_INIT:
+ inittiger(cs);
+ clear_pending_icc_ints(cs);
+ initicc(cs);
+ /* Reenable all IRQ */
+ cs->writeisac(cs, ICC_MASK, 0);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
+}
+
+static struct pci_dev *dev_netjet __initdata = NULL;
+
+__initfunc(int
+setup_netjet_u(struct IsdnCard *card))
+{
+ int bytecnt;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+ long flags;
+#if CONFIG_PCI
+#endif
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+ strcpy(tmp, NETjet_U_revision);
+ printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_NETJET_U)
+ return(0);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+ for ( ;; )
+ {
+
+#if CONFIG_PCI
+
+ if (!pci_present()) {
+ printk(KERN_ERR "NETspider-U: no PCI bus present\n");
+ return(0);
+ }
+ if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+ PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
+ if (pci_enable_device(dev_netjet))
+ return(0);
+ cs->irq = dev_netjet->irq;
+ if (!cs->irq) {
+ printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n");
+ return(0);
+ }
+ cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
+ if (!cs->hw.njet.base) {
+ printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ } else {
+ printk(KERN_WARNING "NETspider-U: No PCI card found\n");
+ return(0);
+ }
+
+ cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+ cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
+
+ save_flags(flags);
+ sti();
+
+ cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
+ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+
+ cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
+ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+
+ restore_flags(flags);
+
+ cs->hw.njet.auxd = 0xC0;
+ cs->hw.njet.dmactrl = 0;
+
+ byteout(cs->hw.njet.auxa, 0);
+ byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+ byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+ byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+
+ switch ( ( ( NETjet_ReadIC( cs, ICC_RBCH ) >> 5 ) & 3 ) )
+ {
+ case 3 :
+ break;
+
+ case 0 :
+ printk( KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" );
+ continue;
+
+ default :
+ printk( KERN_WARNING "NETspider-U: No PCI card found\n" );
+ return 0;
+ }
+ break;
+ }
+#else
+
+ printk(KERN_WARNING "NETspider-U: NO_PCI_BIOS\n");
+ printk(KERN_WARNING "NETspider-U: unable to config NETspider-U PCI\n");
+ return (0);
+
+#endif /* CONFIG_PCI */
+
+ bytecnt = 256;
+
+ printk(KERN_INFO
+ "NETspider-U: PCI card configured at 0x%x IRQ %d\n",
+ cs->hw.njet.base, cs->irq);
+ if (check_region(cs->hw.njet.base, bytecnt)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.njet.base,
+ cs->hw.njet.base + bytecnt);
+ return (0);
+ } else {
+ request_region(cs->hw.njet.base, bytecnt, "netjet-u isdn");
+ }
+ reset_netjet_u(cs);
+ cs->readisac = &NETjet_ReadIC;
+ cs->writeisac = &NETjet_WriteIC;
+ cs->readisacfifo = &NETjet_ReadICfifo;
+ cs->writeisacfifo = &NETjet_WriteICfifo;
+ cs->BC_Read_Reg = &dummyrr;
+ cs->BC_Write_Reg = &dummywr;
+ cs->BC_Send_Data = &netjet_fill_dma;
+ cs->cardmsg = &NETjet_U_card_msg;
+ cs->irq_func = &netjet_u_interrupt;
+ cs->irq_flags |= SA_SHIRQ;
+ ICCVersion(cs, "NETspider-U:");
+ return (1);
+}
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
index 342e4e8fc..3f461883d 100644
--- a/drivers/isdn/hisax/q931.c
+++ b/drivers/isdn/hisax/q931.c
@@ -65,6 +65,24 @@ struct MessageType {
0xd, "SETUP ACKNOWLEDGE"
},
{
+ 0x24, "HOLD"
+ },
+ {
+ 0x28, "HOLD ACKNOWLEDGE"
+ },
+ {
+ 0x30, "HOLD REJECT"
+ },
+ {
+ 0x31, "RETRIEVE"
+ },
+ {
+ 0x33, "RETRIEVE ACKNOWLEDGE"
+ },
+ {
+ 0x37, "RETRIEVE REJECT"
+ },
+ {
0x26, "RESUME"
},
{
@@ -638,6 +656,65 @@ prbearer(char *dest, u_char * p)
return (dp - dest);
}
+
+static
+int
+prbearer_ni1(char *dest, u_char * p)
+{
+ char *dp = dest;
+ u_char len;
+
+ p++;
+ len = *p++;
+ dp += sprintf(dp, " octet 3 ");
+ dp += prbits(dp, *p, 8, 8);
+ switch (*p++) {
+ case 0x80:
+ dp += sprintf(dp, " Speech");
+ break;
+ case 0x88:
+ dp += sprintf(dp, " Unrestricted digital information");
+ break;
+ case 0x90:
+ dp += sprintf(dp, " 3.1 kHz audio");
+ break;
+ default:
+ dp += sprintf(dp, " Unknown information-transfer capability");
+ }
+ *dp++ = '\n';
+ dp += sprintf(dp, " octet 4 ");
+ dp += prbits(dp, *p, 8, 8);
+ switch (*p++) {
+ case 0x90:
+ dp += sprintf(dp, " 64 kbps, circuit mode");
+ break;
+ case 0xc0:
+ dp += sprintf(dp, " Packet mode");
+ break;
+ default:
+ dp += sprintf(dp, " Unknown transfer mode");
+ }
+ *dp++ = '\n';
+ if (len > 2) {
+ dp += sprintf(dp, " octet 5 ");
+ dp += prbits(dp, *p, 8, 8);
+ switch (*p++) {
+ case 0x21:
+ dp += sprintf(dp, " Rate adaption\n");
+ dp += sprintf(dp, " octet 5a ");
+ dp += prbits(dp, *p, 8, 8);
+ break;
+ case 0xa2:
+ dp += sprintf(dp, " u-law");
+ break;
+ default:
+ dp += sprintf(dp, " Unknown UI layer 1 protocol");
+ }
+ *dp++ = '\n';
+ }
+ return (dp - dest);
+}
+
static int
general(char *dest, u_char * p)
{
@@ -666,6 +743,33 @@ general(char *dest, u_char * p)
}
static int
+general_ni1(char *dest, u_char * p)
+{
+ char *dp = dest;
+ char ch = ' ';
+ int l, octet = 3;
+
+ p++;
+ l = *p++;
+ /* Iterate over all octets in the information element */
+ while (l--) {
+ dp += sprintf(dp, " octet %d%c ", octet, ch);
+ dp += prbits(dp, *p, 8, 8);
+ *dp++ = '\n';
+
+ /* last octet in group? */
+ if (*p++ & 0x80) {
+ octet++;
+ ch = ' ';
+ } else if (ch == ' ')
+ ch = 'a';
+ else
+ ch++;
+ }
+ return (dp - dest);
+}
+
+static int
prcharge(char *dest, u_char * p)
{
char *dp = dest;
@@ -697,6 +801,112 @@ prtext(char *dest, u_char * p)
*dp++ = '\n';
return (dp - dest);
}
+
+static int
+prfeatureind(char *dest, u_char * p)
+{
+ char *dp = dest;
+
+ p += 2; /* skip id, len */
+ dp += sprintf(dp, " octet 3 ");
+ dp += prbits(dp, *p, 8, 8);
+ *dp++ = '\n';
+ if (!(*p++ & 80)) {
+ dp += sprintf(dp, " octet 4 ");
+ dp += prbits(dp, *p++, 8, 8);
+ *dp++ = '\n';
+ }
+ dp += sprintf(dp, " Status: ");
+ switch (*p) {
+ case 0:
+ dp += sprintf(dp, "Idle");
+ break;
+ case 1:
+ dp += sprintf(dp, "Active");
+ break;
+ case 2:
+ dp += sprintf(dp, "Prompt");
+ break;
+ case 3:
+ dp += sprintf(dp, "Pending");
+ break;
+ default:
+ dp += sprintf(dp, "(Reserved)");
+ break;
+ }
+ *dp++ = '\n';
+ return (dp - dest);
+}
+
+static
+struct DTag { /* Display tags */
+ u_char nr;
+ char *descr;
+} dtaglist[] = {
+ { 0x82, "Continuation" },
+ { 0x83, "Called address" },
+ { 0x84, "Cause" },
+ { 0x85, "Progress indicator" },
+ { 0x86, "Notification indicator" },
+ { 0x87, "Prompt" },
+ { 0x88, "Accumlated digits" },
+ { 0x89, "Status" },
+ { 0x8a, "Inband" },
+ { 0x8b, "Calling address" },
+ { 0x8c, "Reason" },
+ { 0x8d, "Calling party name" },
+ { 0x8e, "Called party name" },
+ { 0x8f, "Orignal called name" },
+ { 0x90, "Redirecting name" },
+ { 0x91, "Connected name" },
+ { 0x92, "Originating restrictions" },
+ { 0x93, "Date & time of day" },
+ { 0x94, "Call Appearance ID" },
+ { 0x95, "Feature address" },
+ { 0x96, "Redirection name" },
+ { 0x9e, "Text" },
+};
+#define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag)
+
+static int
+disptext_ni1(char *dest, u_char * p)
+{
+ char *dp = dest;
+ int l, tag, len, i;
+
+ p++;
+ l = *p++ - 1;
+ if (*p++ != 0x80) {
+ dp += sprintf(dp, " Unknown display type\n");
+ return (dp - dest);
+ }
+ /* Iterate over all tag,length,text fields */
+ while (l > 0) {
+ tag = *p++;
+ len = *p++;
+ l -= len + 2;
+ /* Don't space or skip */
+ if ((tag == 0x80) || (tag == 0x81)) p++;
+ else {
+ for (i = 0; i < DTAGSIZE; i++)
+ if (tag == dtaglist[i].nr)
+ break;
+
+ /* When not found, give appropriate msg */
+ if (i != DTAGSIZE) {
+ dp += sprintf(dp, " %s: ", dtaglist[i].descr);
+ while (len--)
+ *dp++ = *p++;
+ } else {
+ dp += sprintf(dp, " (unknown display tag %2x): ", tag);
+ while (len--)
+ *dp++ = *p++;
+ }
+ dp += sprintf(dp, "\n");
+ }
+ }
+ return (dp - dest);
+}
static int
display(char *dest, u_char * p)
{
@@ -867,6 +1077,49 @@ struct InformationElement {
#define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
+static
+struct InformationElement ielist_ni1[] = {
+ { 0x04, "Bearer Capability", prbearer_ni1 },
+ { 0x08, "Cause", prcause },
+ { 0x14, "Call State", general_ni1 },
+ { 0x18, "Channel Identification", prchident },
+ { 0x1e, "Progress Indicator", general_ni1 },
+ { 0x27, "Notification Indicator", general_ni1 },
+ { 0x2c, "Keypad Facility", prtext },
+ { 0x32, "Information Request", general_ni1 },
+ { 0x34, "Signal", general_ni1 },
+ { 0x38, "Feature Activation", general_ni1 },
+ { 0x39, "Feature Indication", prfeatureind },
+ { 0x3a, "Service Profile Identification (SPID)", prtext },
+ { 0x3b, "Endpoint Identifier", general_ni1 },
+ { 0x6c, "Calling Party Number", prcalling },
+ { 0x6d, "Calling Party Subaddress", general_ni1 },
+ { 0x70, "Called Party Number", prcalled },
+ { 0x71, "Called Party Subaddress", general_ni1 },
+ { 0x74, "Redirecting Number", general_ni1 },
+ { 0x78, "Transit Network Selection", general_ni1 },
+ { 0x7c, "Low Layer Compatibility", general_ni1 },
+ { 0x7d, "High Layer Compatibility", general_ni1 },
+};
+
+
+#define IESIZE_NI1 sizeof(ielist_ni1)/sizeof(struct InformationElement)
+
+static
+struct InformationElement ielist_ni1_cs5[] = {
+ { 0x1d, "Operator system access", general_ni1 },
+ { 0x2a, "Display text", disptext_ni1 },
+};
+
+#define IESIZE_NI1_CS5 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement)
+
+static
+struct InformationElement ielist_ni1_cs6[] = {
+ { 0x7b, "Call appearance", general_ni1 },
+};
+
+#define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement)
+
static struct InformationElement we_0[] =
{
{WE0_cause, "Cause", prcause_1tr6},
@@ -1107,7 +1360,93 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
}
buf += buf[1] + 2;
}
- } else if (buf[0] == 8) { /* EURO */
+ } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */
+ /* locate message type */
+ buf++;
+ cr_l = *buf++;
+ if (cr_l)
+ cr = *buf++;
+ else
+ cr = 0;
+ mt = *buf++;
+ for (i = 0; i < MTSIZE; i++)
+ if (mtlist[i].nr == mt)
+ break;
+
+ /* display message type if it exists */
+ if (i == MTSIZE)
+ dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
+ cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+ size, mt);
+ else
+ dp += sprintf(dp, "callref %d %s size %d message type %s\n",
+ cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+ size, mtlist[i].descr);
+
+ /* display each information element */
+ while (buf < bend) {
+ /* Is it a single octet information element? */
+ if (*buf & 0x80) {
+ switch ((*buf >> 4) & 7) {
+ case 1:
+ dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
+ cs_old = cset;
+ cset = *buf & 7;
+ cs_fest = *buf & 8;
+ break;
+ default:
+ dp += sprintf(dp, " Unknown single-octet IE %x\n", *buf);
+ break;
+ }
+ buf++;
+ continue;
+ }
+ /* No, locate it in the table */
+ if (cset == 0) {
+ for (i = 0; i < IESIZE; i++)
+ if (*buf == ielist_ni1[i].nr)
+ break;
+
+ /* When not found, give appropriate msg */
+ if (i != IESIZE) {
+ dp += sprintf(dp, " %s\n", ielist_ni1[i].descr);
+ dp += ielist_ni1[i].f(dp, buf);
+ } else
+ dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
+ } else if (cset == 5) {
+ for (i = 0; i < IESIZE_NI1_CS5; i++)
+ if (*buf == ielist_ni1_cs5[i].nr)
+ break;
+
+ /* When not found, give appropriate msg */
+ if (i != IESIZE_NI1_CS5) {
+ dp += sprintf(dp, " %s\n", ielist_ni1_cs5[i].descr);
+ dp += ielist_ni1_cs5[i].f(dp, buf);
+ } else
+ dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
+ } else if (cset == 6) {
+ for (i = 0; i < IESIZE_NI1_CS6; i++)
+ if (*buf == ielist_ni1_cs6[i].nr)
+ break;
+
+ /* When not found, give appropriate msg */
+ if (i != IESIZE_NI1_CS6) {
+ dp += sprintf(dp, " %s\n", ielist_ni1_cs6[i].descr);
+ dp += ielist_ni1_cs6[i].f(dp, buf);
+ } else
+ dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
+ } else
+ dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
+
+ /* Skip to next element */
+ if (cs_fest == 8) {
+ cset = cs_old;
+ cs_old = 0;
+ cs_fest = 0;
+ }
+ buf += buf[1] + 2;
+ }
+ } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */
/* locate message type */
buf++;
cr_l = *buf++;
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index b463b154a..192c496b0 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -39,8 +39,6 @@
* For example: hisaxctrl <DriverID> 9 ISAR.BIN
*/
-#define SEDLBAUER_PCI 1
-
#define __NO_VERSION__
#include <linux/config.h>
#include "hisax.h"
@@ -53,19 +51,23 @@
extern const char *CardType[];
-const char *Sedlbauer_revision = "$Revision: 1.20 $";
+const char *Sedlbauer_revision = "$Revision: 1.23 $";
const char *Sedlbauer_Types[] =
{"None", "speed card/win", "speed star", "speed fax+",
"speed win II / ISDN PC/104", "speed star II", "speed pci",
- "speed fax+ pci"};
+ "speed fax+ pyramid", "speed fax+ pci"};
-#ifdef SEDLBAUER_PCI
-#define PCI_VENDOR_SEDLBAUER 0xe159
-#define PCI_SPEEDPCI_ID 0x02
-#define PCI_SUBVENDOR_SEDLBAUER 0x51
-#define PCI_SUB_ID_SPEEDFAXP 0x01
+#ifndef PCI_VENDOR_ID_TIGERJET
+#define PCI_VENDOR_ID_TIGERJET 0xe159
+#endif
+#ifndef PCI_DEVICE_ID_TIGERJET_100
+#define PCI_DEVICE_ID_TIGERJET_100 0x0002
#endif
+#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51
+#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53
+#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54
+#define PCI_SUB_ID_SEDLBAUER 0x01
#define SEDL_SPEED_CARD_WIN 1
#define SEDL_SPEED_STAR 2
@@ -73,7 +75,8 @@ const char *Sedlbauer_Types[] =
#define SEDL_SPEED_WIN2_PC104 4
#define SEDL_SPEED_STAR2 5
#define SEDL_SPEED_PCI 6
-#define SEDL_SPEEDFAX_PCI 7
+#define SEDL_SPEEDFAX_PYRAMID 7
+#define SEDL_SPEEDFAX_PCI 8
#define SEDL_CHIP_TEST 0
#define SEDL_CHIP_ISAC_HSCX 1
@@ -285,10 +288,10 @@ sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
if ((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && (*cs->busy_flag == 1)) {
- /* The card tends to generate interrupts while being removed
- causing us to just crash the kernel. bad. */
- printk(KERN_WARNING "Sedlbauer: card not available!\n");
- return;
+ /* The card tends to generate interrupts while being removed
+ causing us to just crash the kernel. bad. */
+ printk(KERN_WARNING "Sedlbauer: card not available!\n");
+ return;
}
val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
@@ -360,7 +363,8 @@ Start_IPAC:
goto Start_IPAC;
}
if (!icnt)
- printk(KERN_WARNING "Sedlbauer IRQ LOOP\n");
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "Sedlbauer IRQ LOOP");
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0);
}
@@ -398,7 +402,8 @@ sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs)
goto Start_ISAC;
}
if (!cnt)
- printk(KERN_WARNING "Sedlbauer IRQ LOOP\n");
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "Sedlbauer IRQ LOOP");
writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF);
@@ -508,7 +513,7 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
case CARD_TEST:
return(0);
case MDL_INFO_CONN:
- if (cs->subtyp != SEDL_SPEEDFAX_PCI)
+ if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID)
return(0);
if ((long) arg)
cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2;
@@ -517,7 +522,7 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
break;
case MDL_INFO_REL:
- if (cs->subtyp != SEDL_SPEEDFAX_PCI)
+ if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID)
return(0);
if ((long) arg)
cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2;
@@ -529,9 +534,7 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-#ifdef SEDLBAUER_PCI
static struct pci_dev *dev_sedl __initdata = NULL;
-#endif
__initfunc(int
setup_sedlbauer(struct IsdnCard *card))
@@ -569,16 +572,15 @@ setup_sedlbauer(struct IsdnCard *card))
}
} else {
/* Probe for Sedlbauer speed pci */
-#if SEDLBAUER_PCI
#if CONFIG_PCI
if (!pci_present()) {
printk(KERN_ERR "Sedlbauer: no PCI bus present\n");
return(0);
}
- if ((dev_sedl = pci_find_device(PCI_VENDOR_SEDLBAUER,
- PCI_SPEEDPCI_ID, dev_sedl))) {
+ if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+ PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
if (pci_enable_device(dev_sedl))
- return (0);
+ return(0);
cs->irq = dev_sedl->irq;
if (!cs->irq) {
printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
@@ -597,13 +599,23 @@ setup_sedlbauer(struct IsdnCard *card))
sub_vendor_id, sub_id);
printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
cs->hw.sedl.cfg_reg);
- if ((sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER) &&
- (sub_id == PCI_SUB_ID_SPEEDFAXP)) {
+ if (sub_id != PCI_SUB_ID_SEDLBAUER) {
+ printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
+ return(0);
+ }
+ if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
+ cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
+ } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
cs->subtyp = SEDL_SPEEDFAX_PCI;
- } else {
+ } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
cs->hw.sedl.chip = SEDL_CHIP_IPAC;
cs->subtyp = SEDL_SPEED_PCI;
+ } else {
+ printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
+ sub_vendor_id);
+ return(0);
}
bytecnt = 256;
cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
@@ -623,7 +635,6 @@ setup_sedlbauer(struct IsdnCard *card))
printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
return (0);
#endif /* CONFIG_PCI */
-#endif /* SEDLBAUER_PCI */
}
/* In case of the sedlbauer pcmcia card, this region is in use,
@@ -683,7 +694,6 @@ setup_sedlbauer(struct IsdnCard *card))
if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
- /* IPAC */
if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR;
cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC;
diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c
index 359e9932e..2a84aa2d2 100644
--- a/drivers/isdn/hisax/tei.c
+++ b/drivers/isdn/hisax/tei.c
@@ -154,7 +154,7 @@ tei_id_assign(struct FsmInst *fi, int event, void *arg)
if (st->ma.debug)
st->ma.tei_m.printdebug(&st->ma.tei_m,
"identity assign ri %d tei %d", ri, tei);
- if ((ost = findtei(st, tei))) { /* same tei is in use */
+ if ((ost = findtei(st, tei))) { /* same tei is in use */
if (ri != ost->ma.ri) {
st->ma.tei_m.printdebug(&st->ma.tei_m,
"possible duplicate assignment tei %d", tei);
@@ -181,10 +181,12 @@ tei_id_test_dup(struct FsmInst *fi, int event, void *arg)
if (st->ma.debug)
st->ma.tei_m.printdebug(&st->ma.tei_m,
"foreign identity assign ri %d tei %d", ri, tei);
- if ((ost = findtei(st, tei))) { /* same tei is in use */
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "possible duplicate assignment tei %d", tei);
- FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL);
+ if ((ost = findtei(st, tei))) { /* same tei is in use */
+ if (ri != ost->ma.ri) { /* and it wasn't our request */
+ st->ma.tei_m.printdebug(&st->ma.tei_m,
+ "possible duplicate assignment tei %d", tei);
+ FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL);
+ }
}
}
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
index 856b73fd9..eb17ce331 100644
--- a/drivers/isdn/hisax/telespci.c
+++ b/drivers/isdn/hisax/telespci.c
@@ -27,6 +27,12 @@ const char *telespci_revision = "$Revision: 2.13 $";
#define ZORAN_PO_GREG1 0x00010000
#define ZORAN_PO_DMASK 0xFF
+#ifndef PCI_VENDOR_ID_ZORAN
+#define PCI_VENDOR_ID_ZORAN 0x11DE
+#endif
+#ifndef PCI_DEVICE_ID_ZORAN_36120
+#define PCI_DEVICE_ID_ZORAN_36120 0x6120
+#endif
#define WRITE_ADDR_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG0)
#define READ_DATA_ISAC (ZORAN_PO_GID0 | ZORAN_PO_GREG1)
#define WRITE_DATA_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG1)
@@ -282,6 +288,9 @@ setup_telespci(struct IsdnCard *card))
struct IsdnCardState *cs = card->cs;
char tmp[64];
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
strcpy(tmp, telespci_revision);
printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_TELESPCI)
@@ -291,18 +300,18 @@ setup_telespci(struct IsdnCard *card))
printk(KERN_ERR "TelesPCI: no PCI bus present\n");
return(0);
}
- if ((dev_tel = pci_find_device (0x11DE, 0x6120, dev_tel))) {
+ if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
if (pci_enable_device(dev_tel))
- return (0);
+ return(0);
cs->irq = dev_tel->irq;
if (!cs->irq) {
printk(KERN_WARNING "Teles: No IRQ for PCI card found\n");
return(0);
}
- cs->hw.teles0.membase = (u_long) ioremap(dev_tel->resource[ 0].start,
+ cs->hw.teles0.membase = (u_long) ioremap(pci_resource_start(dev_tel, 0),
PAGE_SIZE);
printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n",
- dev_tel->resource[ 0].start, dev_tel->irq);
+ pci_resource_start(dev_tel, 0), dev_tel->irq);
} else {
printk(KERN_WARNING "TelesPCI: No PCI card found\n");
return(0);
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index cea2f61df..eca66942e 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -17,13 +17,18 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
-#define PCI_VEND_ASUSCOM 0x675
-#define PCI_DEV_ASUSCOMPCI1 0x1702
+#ifndef PCI_VENDOR_ID_ASUSCOM
+#define PCI_VENDOR_ID_ASUSCOM 0x675
+#endif
+#ifndef PCI_DEVICE_ID_ASUSCOM_TA1
+#define PCI_DEVICE_ID_ASUSCOM_TA1 0x1702
+#endif
#ifndef PCI_VENDOR_ID_WINBOND2
#define PCI_VENDOR_ID_WINBOND2 0x1050
#endif
-#define PCI_DEVICE_W6692 0x6692
-
+#ifndef PCI_DEVICE_ID_WINBOND_6692
+#define PCI_DEVICE_ID_WINBOND_6692 0x6692
+#endif
/* table entry in the PCI devices list */
typedef struct {
int vendor_id;
@@ -34,14 +39,14 @@ typedef struct {
static const PCI_ENTRY id_list[] =
{
- {PCI_VEND_ASUSCOM, PCI_DEV_ASUSCOMPCI1, "AsusCom", "TA XXX"},
- {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_W6692, "Winbond", "W6692"},
+ {PCI_VENDOR_ID_ASUSCOM, PCI_DEVICE_ID_ASUSCOM_TA1, "AsusCom", "TA XXX"},
+ {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND_6692, "Winbond", "W6692"},
{0, 0, NULL, NULL}
};
extern const char *CardType[];
-const char *w6692_revision = "$Revision: 1.4 $";
+const char *w6692_revision = "$Revision: 1.7 $";
#define DBUSY_TIMER_VALUE 80
@@ -239,7 +244,7 @@ W6692B_empty_fifo(struct BCState *bcs, int count)
if (bcs->hw.w6692.rcvidx + count > HSCX_BUFMAX) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "W6692B_empty_fifo: incoming packet too large");
- cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+ cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
bcs->hw.w6692.rcvidx = 0;
return;
}
@@ -247,14 +252,14 @@ W6692B_empty_fifo(struct BCState *bcs, int count)
bcs->hw.w6692.rcvidx += count;
save_flags(flags);
cli();
- READW6692BFIFO(cs, bcs->hw.w6692.bchan, ptr, count);
- cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+ READW6692BFIFO(cs, bcs->channel, ptr, count);
+ cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
restore_flags(flags);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
t += sprintf(t, "W6692B_empty_fifo %c cnt %d",
- bcs->hw.w6692.bchan ? 'B' : 'A', count);
+ bcs->channel + '1', count);
QuickHex(t, ptr, count);
debugl1(cs, bcs->blog);
}
@@ -290,14 +295,14 @@ W6692B_fill_fifo(struct BCState *bcs)
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
bcs->hw.w6692.count += count;
- WRITEW6692BFIFO(cs, bcs->hw.w6692.bchan, ptr, count);
- cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME));
+ WRITEW6692BFIFO(cs, bcs->channel, ptr, count);
+ cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME));
restore_flags(flags);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
t += sprintf(t, "W6692B_fill_fifo %c cnt %d",
- bcs->hw.w6692.bchan ? 'B' : 'A', count);
+ bcs->channel + '1', count);
QuickHex(t, ptr, count);
debugl1(cs, bcs->blog);
}
@@ -308,13 +313,11 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan)
{
u_char val;
u_char r;
- struct BCState *bcs = cs->bcs;
+ struct BCState *bcs;
struct sk_buff *skb;
int count;
- if (bcs->channel != bchan)
- bcs++; /* hardware bchan must match ! */
-
+ bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs+1);
val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR);
debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val);
@@ -401,7 +404,7 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan)
bcs->tx_cnt += bcs->hw.w6692.count;
bcs->hw.w6692.count = 0;
}
- cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
+ cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "W6692 B EXIR %x Lost TX", val);
}
@@ -715,18 +718,16 @@ dbusy_timer_handler(struct IsdnCardState *cs)
}
static void
-W6692Bmode(struct BCState *bcs, int mode, int bc)
+W6692Bmode(struct BCState *bcs, int mode, int bchan)
{
struct IsdnCardState *cs = bcs->cs;
- int bchan = bc;
-
- bcs->hw.w6692.bchan = bc;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "w6692 %c mode %d ichan %d",
- '1' + bchan, mode, bc);
+ '1' + bchan, mode, bchan);
bcs->mode = mode;
- bcs->channel = bc;
+ bcs->channel = bchan;
+ bcs->hw.w6692.bchan = bchan;
switch (mode) {
case (L1_MODE_NULL):
@@ -895,8 +896,6 @@ HISAX_INITFUNC(void initW6692(struct IsdnCardState *cs, int part))
cs->bcs[1].BC_SetStack = setstack_w6692;
cs->bcs[0].BC_Close = close_w6692state;
cs->bcs[1].BC_Close = close_w6692state;
- cs->bcs[0].hw.w6692.bchan = 0;
- cs->bcs[1].hw.w6692.bchan = 1;
W6692Bmode(cs->bcs, 0, 0);
W6692Bmode(cs->bcs + 1, 0, 0);
}
@@ -979,6 +978,9 @@ __initfunc(int setup_w6692(struct IsdnCard *card))
u_char pci_irq = 0;
u_int pci_ioaddr = 0;
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
strcpy(tmp, w6692_revision);
printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_W6692)
diff --git a/drivers/isdn/hysdn/Makefile b/drivers/isdn/hysdn/Makefile
index 626a6deaa..5613784b7 100644
--- a/drivers/isdn/hysdn/Makefile
+++ b/drivers/isdn/hysdn/Makefile
@@ -16,6 +16,9 @@ ifeq ($(CONFIG_PROC_FS),y)
M_OBJS += hysdn.o
O_TARGET += hysdn.o
O_OBJS += hysdn_procconf.o hysdn_proclog.o boardergo.o hysdn_boot.o hysdn_sched.o hysdn_net.o
+ ifeq ($(CONFIG_HYSDN_CAPI),y)
+ O_OBJS += hycapi.o
+ endif
OX_OBJS += hysdn_init.o
endif
endif
diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c
index 578e4a14d..54849eab1 100644
--- a/drivers/isdn/hysdn/boardergo.c
+++ b/drivers/isdn/hysdn/boardergo.c
@@ -1,4 +1,4 @@
-/* $Id: boardergo.c,v 1.1 2000/02/10 19:45:18 werner Exp $
+/* $Id: boardergo.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $
* Linux driver for HYSDN cards, specific routines for ergo type boards.
*
@@ -25,6 +25,12 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: boardergo.c,v $
+ * Revision 1.3 2000/05/17 11:41:30 ualbrecht
+ * CAPI 2.0 support added
+ *
+ * Revision 1.2 2000/04/23 14:18:36 kai
+ * merge changes from main tree
+ *
* Revision 1.1 2000/02/10 19:45:18 werner
*
* Initial release
@@ -33,6 +39,7 @@
*/
#define __NO_VERSION__
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <asm/io.h>
@@ -153,6 +160,9 @@ ergo_stopcard(hysdn_card * card)
uchar val;
hysdn_net_release(card); /* first release the net device if existing */
+#ifdef CONFIG_HYSDN_CAPI
+ hycapi_capi_stop(card);
+#endif /* CONFIG_HYSDN_CAPI */
save_flags(flags);
cli();
val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */
@@ -238,7 +248,7 @@ ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs)
uchar *dst;
tErgDpram *dpram;
int cnt = (BOOT_IMG_SIZE >> 2); /* number of words to move and swap (byte order!) */
-
+
if (card->debug_flags & LOG_POF_CARD)
hysdn_addlog(card, "ERGO: write bootldr offs=0x%lx ", offs);
@@ -334,7 +344,6 @@ ergo_writebootseq(struct HYSDN_CARD *card, uchar * buf, int len)
} /* while (nr_write) */
} /* while (len) */
-
return (0);
} /* ergo_writebootseq */
@@ -354,7 +363,6 @@ ergo_waitpofready(struct HYSDN_CARD *card)
if (card->debug_flags & LOG_POF_CARD)
hysdn_addlog(card, "ERGO: waiting for pof ready");
-
while (timecnt--) {
/* wait until timeout */
@@ -375,7 +383,6 @@ ergo_waitpofready(struct HYSDN_CARD *card)
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "ERGO: pof boot success");
-
save_flags(flags);
cli();
@@ -396,6 +403,11 @@ ergo_waitpofready(struct HYSDN_CARD *card)
card->state = CARD_STATE_BOOTERR;
return (i);
}
+#ifdef CONFIG_HYSDN_CAPI
+ if((i = hycapi_capi_create(card))) {
+ printk(KERN_WARNING "HYSDN: failed to create capi-interface.\n");
+ }
+#endif /* CONFIG_HYSDN_CAPI */
return (0); /* success */
} /* data has arrived */
sti();
diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c
new file mode 100644
index 000000000..aabb28b8d
--- /dev/null
+++ b/drivers/isdn/hysdn/hycapi.c
@@ -0,0 +1,859 @@
+/* $Id: hycapi.c,v 1.6 2000/07/25 08:07:42 ualbrecht Exp $
+ *
+ * Linux driver for HYSDN cards, CAPI2.0-Interface.
+ * written by Ulrich Albrecht (u.albrecht@hypercope.de) for Hypercope GmbH
+ *
+ * Copyright 2000 by Hypercope GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: hycapi.c,v $
+ * Revision 1.6 2000/07/25 08:07:42 ualbrecht
+ * Fixed stupid re-registering bug resulting in system-freeze
+ *
+ * Revision 1.5 2000/06/18 16:08:18 keil
+ * 2.4 PCI changes and some cosmetics
+ *
+ * Revision 1.4 2000/06/13 09:13:06 ualbrecht
+ * Changed internal application handling: Registration is now deferred
+ * until a CAPI-message is actually sent to the controller (no good
+ * wasting memory on the card if it's never used anyways).
+ * Module will now unload more gracefully.
+ *
+ * Revision 1.2 2000/05/22 10:31:22 ualbrecht
+ * Parameter-checking for app-registration fixed
+ *
+ * Revision 1.1 2000/05/17 11:34:30 ualbrecht
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+
+
+#define VER_DRIVER 0
+#define VER_CARDTYPE 1
+#define VER_HWID 2
+#define VER_SERIAL 3
+#define VER_OPTION 4
+#define VER_PROTO 5
+#define VER_PROFILE 6
+#define VER_CAPI 7
+
+#include "hysdn_defs.h"
+#include <linux/kernelcapi.h>
+
+static char hycapi_revision[]="$Revision: 1.6 $";
+
+typedef struct _hycapi_appl {
+ unsigned int ctrl_mask;
+ capi_register_params rp;
+ struct sk_buff *listen_req[CAPI_MAXCONTR];
+} hycapi_appl;
+
+static hycapi_appl hycapi_applications[CAPI_MAXAPPL];
+
+static inline int _hycapi_appCheck(int app_id, int ctrl_no)
+{
+ if((ctrl_no <= 0) || (ctrl_no > CAPI_MAXCONTR) || (app_id <= 0) ||
+ (app_id > CAPI_MAXAPPL))
+ {
+ printk(KERN_ERR "HYCAPI: Invalid request app_id %d for controller %d", app_id, ctrl_no);
+ return -1;
+ }
+ return ((hycapi_applications[app_id-1].ctrl_mask & (1 << (ctrl_no-1))) != 0);
+}
+
+struct capi_driver_interface *hy_di = NULL;
+
+/******************************
+Kernel-Capi callback reset_ctr
+******************************/
+
+void
+hycapi_reset_ctr(struct capi_ctr *ctrl)
+{
+#ifdef HYCAPI_PRINTFNAMES
+ printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n");
+#endif
+ ctrl->reseted(ctrl);
+}
+
+/******************************
+Kernel-Capi callback remove_ctr
+******************************/
+
+void
+hycapi_remove_ctr(struct capi_ctr *ctrl)
+{
+ int i;
+ hycapictrl_info *cinfo = NULL;
+ hysdn_card *card = NULL;
+#ifdef HYCAPI_PRINTFNAMES
+ printk(KERN_NOTICE "HYCAPI hycapi_remove_ctr\n");
+#endif
+ if(!hy_di) {
+ printk(KERN_ERR "No capi_driver_interface set!");
+ return;
+ }
+ cinfo = (hycapictrl_info *)(ctrl->driverdata);
+ if(!cinfo) {
+ printk(KERN_ERR "No hycapictrl_info set!");
+ return;
+ }
+ card = cinfo->card;
+ ctrl->suspend_output(ctrl);
+ for(i=0; i<CAPI_MAXAPPL;i++) {
+ if(hycapi_applications[i].listen_req[ctrl->cnr-1]) {
+ kfree_skb(hycapi_applications[i].listen_req[ctrl->cnr-1]);
+ hycapi_applications[i].listen_req[ctrl->cnr-1] = NULL;
+ }
+ }
+ hy_di->detach_ctr(ctrl);
+ ctrl->driverdata = 0;
+ kfree(card->hyctrlinfo);
+
+
+ card->hyctrlinfo = NULL;
+}
+
+/***********************************************************
+
+Queue a CAPI-message to the controller.
+
+***********************************************************/
+
+static void
+hycapi_sendmsg_internal(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+ hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
+ hysdn_card *card = cinfo->card;
+
+ spin_lock_irq(&cinfo->lock);
+#ifdef HYCAPI_PRINTFNAMES
+ printk(KERN_NOTICE "hycapi_send_message\n");
+#endif
+ cinfo->skbs[cinfo->in_idx++] = skb; /* add to buffer list */
+ if (cinfo->in_idx >= HYSDN_MAX_CAPI_SKB)
+ cinfo->in_idx = 0; /* wrap around */
+ cinfo->sk_count++; /* adjust counter */
+ if (cinfo->sk_count >= HYSDN_MAX_CAPI_SKB) {
+ /* inform upper layers we're full */
+ printk(KERN_ERR "HYSDN Card%d: CAPI-buffer overrun!\n",
+ card->myid);
+ ctrl->suspend_output(ctrl);
+ }
+ cinfo->tx_skb = skb;
+ spin_unlock_irq(&cinfo->lock);
+ queue_task(&card->irq_queue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+/***********************************************************
+hycapi_register_internal
+
+Send down the CAPI_REGISTER-Command to the controller.
+This functions will also be used if the adapter has been rebooted to
+re-register any applications in the private list.
+
+************************************************************/
+
+static void
+hycapi_register_internal(struct capi_ctr *ctrl, __u16 appl,
+ capi_register_params *rp)
+{
+ char ExtFeatureDefaults[] = "49 /0/0/0/0,*/1,*/2,*/3,*/4,*/5,*/6,*/7,*/8,*/9,*";
+ hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
+ hysdn_card *card = cinfo->card;
+ struct sk_buff *skb;
+ __u16 len;
+ __u8 _command = 0xa0, _subcommand = 0x80;
+ __u16 MessageNumber = 0x0000;
+ __u16 MessageBufferSize = 0;
+ int slen = strlen(ExtFeatureDefaults);
+#ifdef HYCAPI_PRINTFNAMES
+ printk(KERN_NOTICE "hycapi_register_appl\n");
+#endif
+ MessageBufferSize = rp->level3cnt * rp->datablkcnt * rp->datablklen;
+
+ len = CAPI_MSG_BASELEN + 8 + slen + 1;
+ if (!(skb = alloc_skb(len, GFP_ATOMIC))) {
+ printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n",
+ card->myid);
+ return;
+ }
+ memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16));
+ memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16));
+ memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command));
+ memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand));
+ memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16));
+ memcpy(skb_put(skb,sizeof(__u16)), &MessageBufferSize, sizeof(__u16));
+ memcpy(skb_put(skb,sizeof(__u16)), &(rp->level3cnt), sizeof(__u16));
+ memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablkcnt), sizeof(__u16));
+ memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablklen), sizeof(__u16));
+ memcpy(skb_put(skb,slen), ExtFeatureDefaults, slen);
+ hycapi_applications[appl-1].ctrl_mask |= (1 << (ctrl->cnr-1));
+ hycapi_send_message(ctrl, skb);
+}
+
+/************************************************************
+hycapi_restart_internal
+
+After an adapter has been rebootet, re-register all applications and
+send a LISTEN_REQ (if there has been such a thing )
+
+*************************************************************/
+
+static void hycapi_restart_internal(struct capi_ctr *ctrl)
+{
+ int i;
+ struct sk_buff *skb;
+#ifdef HYCAPI_PRINTFNAMES
+ printk(KERN_WARNING "HYSDN: hycapi_restart_internal");
+#endif
+ for(i=0; i<CAPI_MAXAPPL; i++) {
+ if(_hycapi_appCheck(i+1, ctrl->cnr) == 1) {
+ hycapi_register_internal(ctrl, i+1,
+ &hycapi_applications[i].rp);
+ if(hycapi_applications[i].listen_req[ctrl->cnr-1]) {
+ skb = skb_copy(hycapi_applications[i].listen_req[ctrl->cnr-1], GFP_ATOMIC);
+ hycapi_sendmsg_internal(ctrl, skb);
+ }
+ }
+ }
+}
+
+/*************************************************************
+Register an application.
+Error-checking is done for CAPI-compliance.
+
+The application is recorded in the internal list.
+*************************************************************/
+
+void
+hycapi_register_appl(struct capi_ctr *ctrl, __u16 appl,
+ capi_register_params *rp)
+{
+ int MaxLogicalConnections = 0, MaxBDataBlocks = 0, MaxBDataLen = 0;
+ hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
+ hysdn_card *card = cinfo->card;
+ int chk = _hycapi_appCheck(appl, ctrl->cnr);
+ if(chk < 0) {
+ return;
+ }
+ if(chk == 1) {
+ printk(KERN_INFO "HYSDN: apl %d allready registered\n", appl);
+ return;
+ }
+ MaxBDataBlocks = rp->datablkcnt > CAPI_MAXDATAWINDOW ? CAPI_MAXDATAWINDOW : rp->datablkcnt;
+ rp->datablkcnt = MaxBDataBlocks;
+ MaxBDataLen = rp->datablklen < 1024 ? 1024 : rp->datablklen ;
+ rp->datablklen = MaxBDataLen;
+
+ MaxLogicalConnections = rp->level3cnt;
+ if (MaxLogicalConnections < 0) {
+ MaxLogicalConnections = card->bchans * -MaxLogicalConnections;
+ }
+ if (MaxLogicalConnections == 0) {
+ MaxLogicalConnections = card->bchans;
+ }
+
+ rp->level3cnt = MaxLogicalConnections;
+ memcpy(&hycapi_applications[appl-1].rp,
+ rp, sizeof(capi_register_params));
+
+/* MOD_INC_USE_COUNT; */
+ ctrl->appl_registered(ctrl, appl);
+}
+
+/*********************************************************************
+
+hycapi_release_internal
+
+Send down a CAPI_RELEASE to the controller.
+*********************************************************************/
+
+static void hycapi_release_internal(struct capi_ctr *ctrl, __u16 appl)
+{
+ hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
+ hysdn_card *card = cinfo->card;
+ struct sk_buff *skb;
+ __u16 len;
+ __u8 _command = 0xa1, _subcommand = 0x80;
+ __u16 MessageNumber = 0x0000;
+#ifdef HYCAPI_PRINTFNAMES
+ printk(KERN_NOTICE "hycapi_release_appl\n");
+#endif
+ len = CAPI_MSG_BASELEN;
+ if (!(skb = alloc_skb(len, GFP_ATOMIC))) {
+ printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n",
+ card->myid);
+ return;
+ }
+ memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16));
+ memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16));
+ memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command));
+ memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand));
+ memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16));
+ hycapi_send_message(ctrl, skb);
+ hycapi_applications[appl-1].ctrl_mask &= ~(1 << (ctrl->cnr-1));
+}
+
+/******************************************************************
+hycapi_release_appl
+
+Release the application from the internal list an remove it's
+registration at controller-level
+******************************************************************/
+
+void
+hycapi_release_appl(struct capi_ctr *ctrl, __u16 appl)
+{
+ int chk;
+
+ chk = _hycapi_appCheck(appl, ctrl->cnr);
+ if(chk<0) {
+ printk(KERN_ERR "HYCAPI: Releasing invalid appl %d on controller %d\n", appl, ctrl->cnr);
+ return;
+ }
+ if(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]) {
+ kfree_skb(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]);
+ hycapi_applications[appl-1].listen_req[ctrl->cnr-1] = NULL;
+ }
+ if(chk == 1)
+ {
+ hycapi_release_internal(ctrl, appl);
+ }
+ ctrl->appl_released(ctrl, appl);
+/* MOD_DEC_USE_COUNT; */
+}
+
+
+/**************************************************************
+Kill a single controller.
+**************************************************************/
+
+int hycapi_capi_release(hysdn_card *card)
+{
+ hycapictrl_info *cinfo = card->hyctrlinfo;
+ struct capi_ctr *ctrl;
+#ifdef HYCAPI_PRINTFNAMES
+ printk(KERN_NOTICE "hycapi_capi_release\n");
+#endif
+ if(cinfo) {
+ ctrl = cinfo->capi_ctrl;
+ hycapi_remove_ctr(ctrl);
+ }
+ return 0;
+}
+
+/**************************************************************
+hycapi_capi_stop
+
+Stop CAPI-Output on a card. (e.g. during reboot)
+***************************************************************/
+
+int hycapi_capi_stop(hysdn_card *card)
+{
+ hycapictrl_info *cinfo = card->hyctrlinfo;
+ struct capi_ctr *ctrl;
+#ifdef HYCAPI_PRINTFNAMES
+ printk(KERN_NOTICE "hycapi_capi_stop\n");
+#endif
+ if(cinfo) {
+ if(cinfo->capi_ctrl) {
+ ctrl = cinfo->capi_ctrl;
+/* ctrl->suspend_output(ctrl); */
+ ctrl->reseted(ctrl);
+
+ } else {
+ printk(KERN_NOTICE "hycapi_capi_stop: cinfo but no capi_ctrl\n");
+ }
+ }
+ return 0;
+}
+
+/***************************************************************
+hycapi_send_message
+
+Send a message to the controller.
+
+Messages are parsed for their Command/Subcommand-type, and appropriate
+action's are performed.
+
+Note that we have to muck around with a 64Bit-DATA_REQ as there are
+firmware-releases that do not check the MsgLen-Indication!
+
+***************************************************************/
+
+void hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+ __u16 appl_id;
+ int _len, _len2;
+ __u8 msghead[64];
+
+ appl_id = CAPIMSG_APPID(skb->data);
+ switch(_hycapi_appCheck(appl_id, ctrl->cnr))
+ {
+ case 0:
+/* printk(KERN_INFO "Need to register\n"); */
+ hycapi_register_internal(ctrl,
+ appl_id,
+ &(hycapi_applications[appl_id-1].rp));
+ break;
+ case 1:
+ break;
+ default:
+ printk(KERN_ERR "HYCAPI: Controller mixup!\n");
+ return;
+ }
+ switch(CAPIMSG_CMD(skb->data)) {
+ case CAPI_DISCONNECT_B3_RESP:
+ ctrl->free_ncci(ctrl, appl_id,
+ CAPIMSG_NCCI(skb->data));
+ break;
+ case CAPI_DATA_B3_REQ:
+ _len = CAPIMSG_LEN(skb->data);
+ if (_len > 22) {
+ _len2 = _len - 22;
+ memcpy(msghead, skb->data, 22);
+ memcpy(skb->data + _len2, msghead, 22);
+ skb_pull(skb, _len2);
+ CAPIMSG_SETLEN(skb->data, 22);
+ }
+ break;
+ case CAPI_LISTEN_REQ:
+ if(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1])
+ {
+ kfree_skb(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1]);
+ hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = NULL;
+ }
+ if (!(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = skb_copy(skb, GFP_ATOMIC)))
+ {
+ printk(KERN_ERR "HYSDN: memory squeeze in private_listen\n");
+ }
+ break;
+ default:
+ break;
+ }
+ hycapi_sendmsg_internal(ctrl, skb);
+}
+
+/*********************************************************************
+hycapi_read_proc
+
+Informations provided in the /proc/capi-entries.
+
+*********************************************************************/
+
+int hycapi_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, struct capi_ctr *ctrl)
+{
+ hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
+ hysdn_card *card = cinfo->card;
+ int len = 0;
+ char *s;
+#ifdef HYCAPI_PRINTFNAMES
+ printk(KERN_NOTICE "hycapi_read_proc\n");
+#endif
+ len += sprintf(page+len, "%-16s %s\n", "name", cinfo->cardname);
+ len += sprintf(page+len, "%-16s 0x%x\n", "io", card->iobase);
+ len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
+
+ switch (card->brdtype) {
+ case BD_PCCARD: s = "HYSDN Hycard"; break;
+ case BD_ERGO: s = "HYSDN Ergo2"; break;
+ case BD_METRO: s = "HYSDN Metro4"; break;
+ case BD_CHAMP2: s = "HYSDN Champ2"; break;
+ case BD_PLEXUS: s = "HYSDN Plexus30"; break;
+ default: s = "???"; break;
+ }
+ len += sprintf(page+len, "%-16s %s\n", "type", s);
+ if ((s = cinfo->version[VER_DRIVER]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+ if ((s = cinfo->version[VER_CARDTYPE]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+ if ((s = cinfo->version[VER_SERIAL]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+
+ len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
+
+ if (off+count >= len)
+ *eof = 1;
+ if (len < off)
+ return 0;
+ *start = page + off;
+ return ((count < len-off) ? count : len-off);
+}
+
+/**************************************************************
+hycapi_load_firmware
+
+This does NOT load any firmware, but the callback somehow is needed
+on capi-interface registration.
+
+**************************************************************/
+
+int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+{
+#ifdef HYCAPI_PRINTFNAMES
+ printk(KERN_NOTICE "hycapi_load_firmware\n");
+#endif
+ return 0;
+}
+
+
+char *hycapi_procinfo(struct capi_ctr *ctrl)
+{
+ hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
+#ifdef HYCAPI_PRINTFNAMES
+ printk(KERN_NOTICE "hycapi_proc_info\n");
+#endif
+ if (!cinfo)
+ return "";
+ sprintf(cinfo->infobuf, "%s %s 0x%x %d %s",
+ cinfo->cardname[0] ? cinfo->cardname : "-",
+ cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+ cinfo->card ? cinfo->card->iobase : 0x0,
+ cinfo->card ? cinfo->card->irq : 0,
+ hycapi_revision
+ );
+ return cinfo->infobuf;
+}
+
+/******************************************************************
+hycapi_rx_capipkt
+
+Recieve a capi-message.
+
+All B3_DATA_IND are converted to 64K-extension compatible format.
+New nccis are created if neccessary.
+*******************************************************************/
+
+void
+hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len)
+{
+ struct sk_buff *skb;
+ hycapictrl_info *cinfo = card->hyctrlinfo;
+ struct capi_ctr *ctrl;
+ __u16 ApplId;
+ __u16 MsgLen, info;
+ __u16 len2, CapiCmd;
+ __u32 CP64[2] = {0,0};
+#ifdef HYCAPI_PRINTFNAMES
+ printk(KERN_NOTICE "hycapi_rx_capipkt\n");
+#endif
+ if(!cinfo) {
+ printk(KERN_ERR "HYSDN Card%d: no HYCAPI-controller!\n",
+ card->myid);
+ return;
+ }
+ ctrl = cinfo->capi_ctrl;
+ if(!ctrl)
+ {
+ printk(KERN_ERR "HYSDN Card%d: no CAPI-controller (1)!\n",
+ card->myid);
+ return;
+ }
+ if(len < CAPI_MSG_BASELEN) {
+ printk(KERN_ERR "HYSDN Card%d: invalid CAPI-message, lenght %d!\n",
+ card->myid, len);
+ return;
+ }
+ MsgLen = CAPIMSG_LEN(buf);
+ ApplId = CAPIMSG_APPID(buf);
+ CapiCmd = CAPIMSG_CMD(buf);
+
+ if((CapiCmd == CAPI_DATA_B3_IND) && (MsgLen < 30)) {
+ len2 = len + (30 - MsgLen);
+ if (!(skb = alloc_skb(len2, GFP_ATOMIC))) {
+ printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n",
+ card->myid);
+ return;
+ }
+ memcpy(skb_put(skb, MsgLen), buf, MsgLen);
+ memcpy(skb_put(skb, 2*sizeof(__u32)), CP64, 2* sizeof(__u32));
+ memcpy(skb_put(skb, len - MsgLen), buf + MsgLen,
+ len - MsgLen);
+ CAPIMSG_SETLEN(skb->data, 30);
+ } else {
+ if (!(skb = alloc_skb(len, GFP_ATOMIC))) {
+ printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n",
+ card->myid);
+ return;
+ }
+ memcpy(skb_put(skb, len), buf, len);
+ }
+ switch(CAPIMSG_CMD(skb->data))
+ {
+ case CAPI_CONNECT_B3_CONF:
+/* Check info-field for error-indication: */
+ info = CAPIMSG_U16(skb->data, 12);
+ switch(info)
+ {
+ case 0:
+ ctrl->new_ncci(ctrl, ApplId, CAPIMSG_NCCI(skb->data),
+ hycapi_applications[ApplId-1].rp.datablkcnt);
+
+ break;
+ case 0x0001:
+ printk(KERN_ERR "HYSDN Card%d: NCPI not supported by current "
+ "protocol. NCPI ignored.\n", card->myid);
+ break;
+ case 0x2001:
+ printk(KERN_ERR "HYSDN Card%d: Message not supported in"
+ " current state\n", card->myid);
+ break;
+ case 0x2002:
+ printk(KERN_ERR "HYSDN Card%d: illegal PLCI\n", card->myid);
+ break;
+ case 0x2004:
+ printk(KERN_ERR "HYSDN Card%d: out of NCCI\n", card->myid);
+ break;
+ case 0x3008:
+ printk(KERN_ERR "HYSDN Card%d: NCPI not supported\n",
+ card->myid);
+ break;
+ default:
+ printk(KERN_ERR "HYSDN Card%d: Info in CONNECT_B3_CONF: %d\n",
+ card->myid, info);
+ break;
+ }
+ break;
+ case CAPI_CONNECT_B3_IND:
+ ctrl->new_ncci(ctrl, ApplId,
+ CAPIMSG_NCCI(skb->data),
+ hycapi_applications[ApplId-1].rp.datablkcnt);
+ break;
+ default:
+ break;
+ }
+ ctrl->handle_capimsg(ctrl, ApplId, skb);
+}
+
+/******************************************************************
+hycapi_tx_capiack
+
+Internally acknowledge a msg sent. This will remove the msg from the
+internal queue.
+
+*******************************************************************/
+
+void hycapi_tx_capiack(hysdn_card * card)
+{
+ hycapictrl_info *cinfo = card->hyctrlinfo;
+#ifdef HYCAPI_PRINTFNAMES
+ printk(KERN_NOTICE "hycapi_tx_capiack\n");
+#endif
+ if(!cinfo) {
+ printk(KERN_ERR "HYSDN Card%d: no CAPI-controller (2)!\n",
+ card->myid);
+ return;
+ }
+ spin_lock_irq(&cinfo->lock);
+ kfree_skb(cinfo->skbs[cinfo->out_idx]); /* free skb */
+ cinfo->skbs[cinfo->out_idx++] = NULL;
+ if (cinfo->out_idx >= HYSDN_MAX_CAPI_SKB)
+ cinfo->out_idx = 0; /* wrap around */
+
+ if (cinfo->sk_count-- == HYSDN_MAX_CAPI_SKB) /* dec usage count */
+ cinfo->capi_ctrl->resume_output(cinfo->capi_ctrl);
+ spin_unlock_irq(&cinfo->lock);
+}
+
+/***************************************************************
+hycapi_tx_capiget(hysdn_card *card)
+
+This is called when polling for messages to SEND.
+
+****************************************************************/
+
+struct sk_buff *
+hycapi_tx_capiget(hysdn_card *card)
+{
+ hycapictrl_info *cinfo = card->hyctrlinfo;
+ if(!cinfo) {
+ printk(KERN_ERR "HYSDN Card%d: no CAPI-controller! (3)\n",
+ card->myid);
+ return (struct sk_buff *)NULL;
+ }
+ if (!cinfo->sk_count)
+ return (struct sk_buff *)NULL; /* nothing available */
+
+ return (cinfo->skbs[cinfo->out_idx]); /* next packet to send */
+}
+
+
+static struct capi_driver hycapi_driver = {
+ "hysdn",
+ "0.0",
+ hycapi_load_firmware,
+ hycapi_reset_ctr,
+ hycapi_remove_ctr,
+ hycapi_register_appl,
+ hycapi_release_appl,
+ hycapi_send_message,
+ hycapi_procinfo,
+ hycapi_read_proc,
+ 0, /* use standard driver_read_proc */
+ 0, /* no add_card function */
+};
+
+
+/**********************************************************
+int hycapi_init()
+
+attach the capi-driver to the kernel-capi.
+
+***********************************************************/
+
+int hycapi_init()
+{
+ struct capi_driver *driver;
+ int i;
+ if(hy_di) {
+ printk(KERN_NOTICE "HyDI allready set\n");
+ return 0;
+ }
+ driver = &hycapi_driver;
+ printk(KERN_NOTICE "HYSDN: Attaching capi-driver\n");
+ hy_di = attach_capi_driver(driver);
+ if (!hy_di) {
+ printk(KERN_ERR "HYCAPI: failed to attach capi_driver\n");
+ return(-1);
+ }
+ for(i=0;i<CAPI_MAXAPPL;i++) {
+ memset(&(hycapi_applications[i]), 0, sizeof(hycapi_appl));
+ }
+ return(0);
+}
+
+/**************************************************************
+hycapi_cleanup(void)
+
+detach the capi-driver to the kernel-capi. Actually this should
+free some more ressources. Do that later.
+**************************************************************/
+
+void
+hycapi_cleanup(void)
+{
+ struct capi_driver *driver;
+ driver = &hycapi_driver;
+ if (!hy_di) {
+ printk(KERN_ERR "HYSDN: no capi-driver to detach (???)\n");
+ return;
+ }
+ printk(KERN_NOTICE "HYSDN: Detaching capi-driver\n");
+ detach_capi_driver(driver);
+ hy_di = 0;
+ return;
+}
+
+/********************************************************************
+hycapi_capi_create(hysdn_card *card)
+
+Attach the card with it's capi-ctrl.
+*********************************************************************/
+
+static void hycapi_fill_profile(hysdn_card *card)
+{
+ hycapictrl_info *cinfo = NULL;
+ struct capi_ctr *ctrl = NULL;
+ cinfo = card->hyctrlinfo;
+ if(!cinfo) return;
+ ctrl = cinfo->capi_ctrl;
+ if(!ctrl) return;
+ strcpy(ctrl->manu, "Hypercope");
+ ctrl->version.majorversion = 2;
+ ctrl->version.minorversion = 0;
+ ctrl->version.majormanuversion = 3;
+ ctrl->version.minormanuversion = 2;
+ ctrl->profile.ncontroller = card->myid;
+ ctrl->profile.nbchannel = card->bchans;
+ ctrl->profile.goptions = GLOBAL_OPTION_INTERNAL_CONTROLLER |
+ GLOBAL_OPTION_B_CHANNEL_OPERATION;
+ ctrl->profile.support1 = B1_PROT_64KBIT_HDLC |
+ (card->faxchans ? B1_PROT_T30 : 0) |
+ B1_PROT_64KBIT_TRANSPARENT;
+ ctrl->profile.support2 = B2_PROT_ISO7776 |
+ (card->faxchans ? B2_PROT_T30 : 0) |
+ B2_PROT_TRANSPARENT;
+ ctrl->profile.support3 = B3_PROT_TRANSPARENT |
+ B3_PROT_T90NL |
+ (card->faxchans ? B3_PROT_T30 : 0) |
+ (card->faxchans ? B3_PROT_T30EXT : 0) |
+ B3_PROT_ISO8208;
+}
+
+int
+hycapi_capi_create(hysdn_card *card)
+{
+ hycapictrl_info *cinfo = NULL;
+ struct capi_ctr *ctrl = NULL;
+#ifdef HYCAPI_PRINTFNAMES
+ printk(KERN_NOTICE "hycapi_capi_create\n");
+#endif
+ if (!card->hyctrlinfo) {
+ cinfo = (hycapictrl_info *) kmalloc(sizeof(hycapictrl_info), GFP_ATOMIC);
+ if (!cinfo) {
+ printk(KERN_WARNING "HYSDN: no memory for capi-ctrl.\n");
+ return -ENOMEM;
+ }
+ memset(cinfo, 0, sizeof(hycapictrl_info));
+ card->hyctrlinfo = cinfo;
+ cinfo->card = card;
+ spin_lock_init(&cinfo->lock);
+
+ switch (card->brdtype) {
+ case BD_PCCARD: strcpy(cinfo->cardname,"HYSDN Hycard"); break;
+ case BD_ERGO: strcpy(cinfo->cardname,"HYSDN Ergo2"); break;
+ case BD_METRO: strcpy(cinfo->cardname,"HYSDN Metro4"); break;
+ case BD_CHAMP2: strcpy(cinfo->cardname,"HYSDN Champ2"); break;
+ case BD_PLEXUS: strcpy(cinfo->cardname,"HYSDN Plexus30"); break;
+ default: strcpy(cinfo->cardname,"HYSDN ???"); break;
+ }
+
+ cinfo->capi_ctrl = hy_di->attach_ctr(&hycapi_driver,
+ cinfo->cardname, cinfo);
+ ctrl = cinfo->capi_ctrl;
+ if (!ctrl) {
+ printk(KERN_ERR "%s: attach controller failed.\n",
+ hycapi_driver.name);
+ return -EBUSY;
+ }
+ /* fill in the blanks: */
+ hycapi_fill_profile(card);
+ ctrl->ready(ctrl);
+ } else {
+ /* resume output on stopped ctrl */
+ ctrl = card->hyctrlinfo->capi_ctrl;
+ if(ctrl) {
+ hycapi_fill_profile(card);
+ ctrl->ready(ctrl);
+ hycapi_restart_internal(ctrl);
+/* ctrl->resume_output(ctrl); */
+ } else {
+ printk(KERN_WARNING "HYSDN: No ctrl???? How come?\n");
+ }
+ }
+ return 0;
+}
diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c
index 030c40de6..31eaa14cb 100644
--- a/drivers/isdn/hysdn/hysdn_boot.c
+++ b/drivers/isdn/hysdn/hysdn_boot.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_boot.c,v 1.1 2000/02/10 19:45:18 werner Exp $
+/* $Id: hysdn_boot.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $
* Linux driver for HYSDN cards, specific routines for booting and pof handling.
*
@@ -21,6 +21,12 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hysdn_boot.c,v $
+ * Revision 1.3 2000/05/17 11:41:30 ualbrecht
+ * CAPI 2.0 support added
+ *
+ * Revision 1.2 2000/04/23 14:18:36 kai
+ * merge changes from main tree
+ *
* Revision 1.1 2000/02/10 19:45:18 werner
*
* Initial release
@@ -260,7 +266,6 @@ pof_write_buffer(hysdn_card * card, int datlen)
}
if ((boot->last_error = pof_handle_data(card, datlen)) < 0)
return (boot->last_error); /* an error occured */
-
boot->pof_recoffset += datlen;
if (boot->pof_recoffset >= boot->pof_reclen) {
boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h
index cac76cb26..e5ad863d4 100644
--- a/drivers/isdn/hysdn/hysdn_defs.h
+++ b/drivers/isdn/hysdn/hysdn_defs.h
@@ -1,4 +1,4 @@
-/* $Id: hysdn_defs.h,v 1.1 2000/02/10 19:44:30 werner Exp $
+/* $Id: hysdn_defs.h,v 1.3 2000/06/13 09:14:26 ualbrecht Exp $
* Linux driver for HYSDN cards, global definitions and exported vars and functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -20,6 +20,12 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hysdn_defs.h,v $
+ * Revision 1.3 2000/06/13 09:14:26 ualbrecht
+ * Removed obsolete struct for CAPI-application tracking.
+ *
+ * Revision 1.2 2000/05/17 11:41:30 ualbrecht
+ * CAPI 2.0 support added
+ *
* Revision 1.1 2000/02/10 19:44:30 werner
*
* Initial release
@@ -27,6 +33,10 @@
*
*/
+#ifndef HYSDN_DEFS_H
+#define HYSDN_DEFS_H
+
+#include <linux/config.h>
#include <linux/hysdn_if.h>
#include <linux/interrupt.h>
#include <linux/tqueue.h>
@@ -42,6 +52,54 @@
#include "ince1pc.h"
+#ifdef CONFIG_HYSDN_CAPI
+#include <linux/capi.h>
+#include "../avmb1/capicmd.h"
+#include "../avmb1/capiutil.h"
+#include "../avmb1/capilli.h"
+
+/***************************/
+/* CAPI-Profile values. */
+/***************************/
+
+#define GLOBAL_OPTION_INTERNAL_CONTROLLER 0x0001
+#define GLOBAL_OPTION_EXTERNAL_CONTROLLER 0x0002
+#define GLOBAL_OPTION_HANDSET 0x0004
+#define GLOBAL_OPTION_DTMF 0x0008
+#define GLOBAL_OPTION_SUPPL_SERVICES 0x0010
+#define GLOBAL_OPTION_CHANNEL_ALLOCATION 0x0020
+#define GLOBAL_OPTION_B_CHANNEL_OPERATION 0x0040
+
+#define B1_PROT_64KBIT_HDLC 0x0001
+#define B1_PROT_64KBIT_TRANSPARENT 0x0002
+#define B1_PROT_V110_ASYNCH 0x0004
+#define B1_PROT_V110_SYNCH 0x0008
+#define B1_PROT_T30 0x0010
+#define B1_PROT_64KBIT_INV_HDLC 0x0020
+#define B1_PROT_56KBIT_TRANSPARENT 0x0040
+
+#define B2_PROT_ISO7776 0x0001
+#define B2_PROT_TRANSPARENT 0x0002
+#define B2_PROT_SDLC 0x0004
+#define B2_PROT_LAPD 0x0008
+#define B2_PROT_T30 0x0010
+#define B2_PROT_PPP 0x0020
+#define B2_PROT_TRANSPARENT_IGNORE_B1_FRAMING_ERRORS 0x0040
+
+#define B3_PROT_TRANSPARENT 0x0001
+#define B3_PROT_T90NL 0x0002
+#define B3_PROT_ISO8208 0x0004
+#define B3_PROT_X25_DCE 0x0008
+#define B3_PROT_T30 0x0010
+#define B3_PROT_T30EXT 0x0020
+
+#define HYSDN_MAXVERSION 8
+
+/* Number of sendbuffers in CAPI-queue */
+#define HYSDN_MAX_CAPI_SKB 20
+
+#endif /* CONFIG_HYSDN_CAPI*/
+
/************************************************/
/* constants and bits for debugging/log outputs */
/************************************************/
@@ -176,8 +234,30 @@ typedef struct HYSDN_CARD {
/* init and deinit stopcard for booting, too */
void (*stopcard) (struct HYSDN_CARD *);
void (*releasehardware) (struct HYSDN_CARD *);
+#ifdef CONFIG_HYSDN_CAPI
+ struct hycapictrl_info {
+ char cardname[32];
+ spinlock_t lock;
+ int versionlen;
+ char versionbuf[1024];
+ char *version[HYSDN_MAXVERSION];
+
+ char infobuf[128]; /* for function procinfo */
+
+ struct HYSDN_CARD *card;
+ struct capi_ctr *capi_ctrl;
+ struct sk_buff *skbs[HYSDN_MAX_CAPI_SKB];
+ int in_idx, out_idx; /* indexes to buffer ring */
+ int sk_count; /* number of buffers currently in ring */
+ struct sk_buff *tx_skb; /* buffer for tx operation */
+ } *hyctrlinfo;
+#endif /* CONFIG_HYSDN_CAPI */
} hysdn_card;
+#ifdef CONFIG_HYSDN_CAPI
+typedef struct hycapictrl_info hycapictrl_info;
+#endif /* CONFIG_HYSDN_CAPI */
+
/*****************/
/* exported vars */
@@ -227,3 +307,27 @@ extern char *hysdn_net_getname(hysdn_card *); /* get name of net interface */
extern void hysdn_tx_netack(hysdn_card *); /* acknowledge a packet tx */
extern struct sk_buff *hysdn_tx_netget(hysdn_card *); /* get next network packet */
extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word); /* rxed packet from network */
+
+#ifdef CONFIG_HYSDN_CAPI
+extern struct capi_driver_interface *hy_di;
+extern int hycapi_capi_create(hysdn_card *); /* create a new capi device */
+extern int hycapi_capi_release(hysdn_card *); /* delete the device */
+extern int hycapi_capi_stop(hysdn_card *card); /* suspend */
+extern int hycapi_load_firmware(struct capi_ctr *, capiloaddata *);
+extern void hycapi_reset_ctr(struct capi_ctr *);
+extern void hycapi_remove_ctr(struct capi_ctr *);
+extern void hycapi_register_appl(struct capi_ctr *, __u16 appl,
+ capi_register_params *);
+extern void hycapi_release_appl(struct capi_ctr *, __u16 appl);
+extern void hycapi_send_message(struct capi_ctr *, struct sk_buff *skb);
+extern char *hycapi_procinfo(struct capi_ctr *);
+extern int hycapi_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, struct capi_ctr *card);
+extern void hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len);
+extern void hycapi_tx_capiack(hysdn_card * card);
+extern struct sk_buff *hycapi_tx_capiget(hysdn_card *card);
+extern int hycapi_init(void);
+extern void hycapi_cleanup(void);
+#endif /* CONFIG_HYSDN_CAPI */
+
+#endif /* HYSDN_DEFS_H */
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
index 23b79ddd9..6ae0c3a7f 100644
--- a/drivers/isdn/hysdn/hysdn_init.c
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_init.c,v 1.1 2000/02/10 19:45:18 werner Exp $
+/* $Id: hysdn_init.c,v 1.5 2000/08/20 16:46:09 keil Exp $
* Linux driver for HYSDN cards, init functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -20,6 +20,18 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hysdn_init.c,v $
+ * Revision 1.5 2000/08/20 16:46:09 keil
+ * Changes for 2.4
+ *
+ * Revision 1.4 2000/06/18 16:08:18 keil
+ * 2.4 PCI changes and some cosmetics
+ *
+ * Revision 1.3 2000/06/13 09:15:07 ualbrecht
+ * Module will now unload more gracefully.
+ *
+ * Revision 1.2 2000/05/17 11:41:30 ualbrecht
+ * CAPI 2.0 support added
+ *
* Revision 1.1 2000/02/10 19:45:18 werner
*
* Initial release
@@ -37,7 +49,7 @@
#include "hysdn_defs.h"
-static char *hysdn_init_revision = "$Revision: 1.1 $";
+static char *hysdn_init_revision = "$Revision: 1.5 $";
int cardmax; /* number of found cards */
hysdn_card *card_root = NULL; /* pointer to first card */
@@ -77,7 +89,6 @@ search_cards(void)
{
struct pci_dev *akt_pcidev = NULL;
hysdn_card *card, *card_last;
- uchar irq;
int i;
card_root = NULL;
@@ -218,6 +229,14 @@ init_module(void)
free_resources(); /* proc file_sys not created */
return (-1);
}
+#ifdef CONFIG_HYSDN_CAPI
+ if(cardmax > 0) {
+ if(hycapi_init()) {
+ printk(KERN_ERR "HYCAPI: init failed\n");
+ return(-1);
+ }
+ }
+#endif /* CONFIG_HYSDN_CAPI */
return (0); /* no error */
} /* init_module */
@@ -233,8 +252,18 @@ init_module(void)
void
cleanup_module(void)
{
-
+#ifdef CONFIG_HYSDN_CAPI
+ hysdn_card *card;
+#endif /* CONFIG_HYSDN_CAPI */
stop_cards();
+#ifdef CONFIG_HYSDN_CAPI
+ card = card_root; /* first in chain */
+ while (card) {
+ hycapi_capi_release(card);
+ card = card->next; /* remove card from chain */
+ } /* while card */
+ hycapi_cleanup();
+#endif /* CONFIG_HYSDN_CAPI */
hysdn_procconf_release();
free_resources();
printk(KERN_NOTICE "HYSDN: module unloaded\n");
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c
index 538dfe6d4..61441da10 100644
--- a/drivers/isdn/hysdn/hysdn_net.c
+++ b/drivers/isdn/hysdn/hysdn_net.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_net.c,v 1.3 2000/02/14 19:24:12 werner Exp $
+/* $Id: hysdn_net.c,v 1.7 2000/05/23 06:48:54 ualbrecht Exp $
* Linux driver for HYSDN cards, net (ethernet type) handling routines.
*
@@ -24,6 +24,19 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hysdn_net.c,v $
+ * Revision 1.7 2000/05/23 06:48:54 ualbrecht
+ * Reverted last change in dev->name assignment (broken netdevice.h in 2.3.99pre6?)
+ *
+ * Revision 1.6 2000/05/17 11:43:03 ualbrecht
+ * Fixed a NULL-pointer kernel-oops assigning the device-name
+ *
+ * Revision 1.5 2000/05/06 00:52:38 kai
+ * merged changes from kernel tree
+ * fixed timer and net_device->name breakage
+ *
+ * Revision 1.4 2000/04/23 14:18:36 kai
+ * merge changes from main tree
+ *
* Revision 1.3 2000/02/14 19:24:12 werner
*
* Removed superflous file
@@ -52,7 +65,7 @@
#include "hysdn_defs.h"
/* store the actual version for log reporting */
-char *hysdn_net_revision = "$Revision: 1.3 $";
+char *hysdn_net_revision = "$Revision: 1.7 $";
#define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */
@@ -308,7 +321,10 @@ hysdn_net_create(hysdn_card * card)
{
struct net_device *dev;
int i;
-
+ if(!card) {
+ printk(KERN_WARNING "No card-pt in hysdn_net_create!\n");
+ return (-ENOMEM);
+ }
hysdn_net_release(card); /* release an existing net device */
if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) {
printk(KERN_WARNING "HYSDN: unable to allocate mem\n");
@@ -323,6 +339,9 @@ hysdn_net_create(hysdn_card * card)
dev->base_addr = card->iobase; /* IO address */
dev->irq = card->irq; /* irq */
dev->init = net_init; /* the init function of the device */
+ if(dev->name) {
+ strcpy(dev->name, ((struct net_local *) dev)->dev_name);
+ }
if ((i = register_netdev(dev))) {
printk(KERN_WARNING "HYSDN: unable to create network device\n");
kfree(dev);
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index c28aedc1f..aa17c1014 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_procconf.c,v 1.4 2000/03/03 16:37:12 kai Exp $
+/* $Id: hysdn_procconf.c,v 1.7 2000/08/20 16:46:09 keil Exp $
* Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -20,6 +20,15 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hysdn_procconf.c,v $
+ * Revision 1.7 2000/08/20 16:46:09 keil
+ * Changes for 2.4
+ *
+ * Revision 1.6 2000/05/17 11:41:30 ualbrecht
+ * CAPI 2.0 support added
+ *
+ * Revision 1.5 2000/04/23 14:18:36 kai
+ * merge changes from main tree
+ *
* Revision 1.4 2000/03/03 16:37:12 kai
* incorporated some cosmetic changes from the official kernel tree back
* into CVS
@@ -49,7 +58,7 @@
#include "hysdn_defs.h"
-static char *hysdn_procconf_revision = "$Revision: 1.4 $";
+static char *hysdn_procconf_revision = "$Revision: 1.7 $";
#define INFO_OUT_LEN 80 /* length of info line including lf */
@@ -335,7 +344,7 @@ hysdn_conf_open(struct inode *ino, struct file *filep)
*cp++ = '\n';
/* and now the data */
- sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08x %7d %9d %3d %s",
+ sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08lx %7d %9d %3d %s",
card->myid,
card->bus,
PCI_SLOT(card->devfn),
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index ba454b9dc..a0ac125fe 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_proclog.c,v 1.4 2000/03/03 16:37:12 kai Exp $
+/* $Id: hysdn_proclog.c,v 1.7 2000/08/20 16:46:09 keil Exp $
* Linux driver for HYSDN cards, /proc/net filesystem log functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -20,6 +20,15 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hysdn_proclog.c,v $
+ * Revision 1.7 2000/08/20 16:46:09 keil
+ * Changes for 2.4
+ *
+ * Revision 1.6 2000/06/18 16:08:18 keil
+ * 2.4 PCI changes and some cosmetics
+ *
+ * Revision 1.5 2000/04/23 14:18:36 kai
+ * merge changes from main tree
+ *
* Revision 1.4 2000/03/03 16:37:12 kai
* incorporated some cosmetic changes from the official kernel tree back
* into CVS
@@ -49,8 +58,6 @@
#include "hysdn_defs.h"
-static char *hysdn_proclog_revision = "$Revision: 1.4 $";
-
/* the proc subdir for the interface is defined in the procconf module */
extern struct proc_dir_entry *hysdn_proc_entry;
@@ -456,7 +463,7 @@ hysdn_proclog_init(hysdn_card * card)
sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) {
pd->log->proc_fops = &log_fops;
- pd->log->owner = THIS_MODULE;
+ pd->log->owner = THIS_MODULE;
}
init_waitqueue_head(&(pd->rd_queue));
diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c
index 0e5f9e7ba..64b8782f0 100644
--- a/drivers/isdn/hysdn/hysdn_sched.c
+++ b/drivers/isdn/hysdn/hysdn_sched.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_sched.c,v 1.1 2000/02/10 19:45:18 werner Exp $
+/* $Id: hysdn_sched.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $
* Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc.
*
@@ -21,6 +21,12 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hysdn_sched.c,v $
+ * Revision 1.3 2000/05/17 11:41:30 ualbrecht
+ * CAPI 2.0 support added
+ *
+ * Revision 1.2 2000/04/23 14:18:36 kai
+ * merge changes from main tree
+ *
* Revision 1.1 2000/02/10 19:45:18 werner
*
* Initial release
@@ -29,6 +35,7 @@
*/
#define __NO_VERSION__
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <asm/io.h>
@@ -60,7 +67,12 @@ hysdn_sched_rx(hysdn_card * card, uchar * buf, word len, word chan)
if (card->err_log_state == ERRLOG_STATE_ON)
card->err_log_state = ERRLOG_STATE_START; /* start new fetch */
break;
-
+#ifdef CONFIG_HYSDN_CAPI
+ case CHAN_CAPI:
+/* give packet to CAPI handler */
+ hycapi_rx_capipkt(card, buf, len);
+ break;
+#endif /* CONFIG_HYSDN_CAPI */
default:
printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len);
break;
@@ -125,6 +137,17 @@ hysdn_sched_tx(hysdn_card * card, uchar * buf, word volatile *len, word volatile
} else
hysdn_tx_netack(card); /* aknowledge packet -> throw away */
} /* send a network packet if available */
+#ifdef CONFIG_HYSDN_CAPI
+ if((skb = hycapi_tx_capiget(card)) != NULL) {
+ if (skb->len <= maxlen) {
+ memcpy(buf, skb->data, skb->len);
+ *len = skb->len;
+ *chan = CHAN_CAPI;
+ hycapi_tx_capiack(card);
+ return (1); /* go and send the data */
+ }
+ }
+#endif /* CONFIG_HYSDN_CAPI */
return (0); /* nothing to send */
} /* hysdn_sched_tx */
diff --git a/drivers/isdn/hysdn/ince1pc.h b/drivers/isdn/hysdn/ince1pc.h
index c22974d85..9f9d3104d 100644
--- a/drivers/isdn/hysdn/ince1pc.h
+++ b/drivers/isdn/hysdn/ince1pc.h
@@ -1,132 +1,132 @@
-#ifndef __INCE1PC_H__
-#define __INCE1PC_H__
-
-/****************************************************************************
-
- FILE: ince1pc.h
-
- AUTHOR: M.Steinkopf
-
- PURPOSE: common definitions for both sides of the bus:
- - conventions both spoolers must know
- - channel numbers agreed upon
-
-*****************************************************************************/
-
-/* basic scalar definitions have same meanning,
- * but their declaration location depends on environment
- */
-
-/*--------------------------------------channel numbers---------------------*/
-#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */
-#define CHAN_ERRLOG 0x0005 /* error logger */
-#define CHAN_CAPI 0x0064 /* CAPI interface */
-#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */
-
-/*--------------------------------------POF ready msg-----------------------*/
- /* NOTE: after booting POF sends system ready message to PC: */
-#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */
-#define RDY_MAGIC_SIZE 4 /* size in bytes */
-
-#define MAX_N_TOK_BYTES 255
-
-#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE
-#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
-
-#define SYSR_TOK_END 0
-#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */
-#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */
-#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */
-#define SYSR_TOK_ESC 255 /* undefined data size yet */
- /* default values, if not corrected by token: */
-#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */
-#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */
-
-/* syntax of new SYSR token stream:
- * channel: CHAN_SYSTEM
- * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE
- * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
- * msg : 0 1 2 3 {4 5 6 ..}
- * S Y S R MAX_N_TOK_BYTES bytes of TokenStream
- *
- * TokenStream := empty
- * | {NonEndTokenChunk} EndToken RotlCRC
- * NonEndTokenChunk:= NonEndTokenId DataLen [Data]
- * NonEndTokenId := 0x01 .. 0xFE 1 BYTE
- * DataLen := 0x00 .. 0xFF 1 BYTE
- * Data := DataLen bytes
- * EndToken := 0x00
- * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes
- * s. RotlCRC algorithm
- *
- * RotlCRC algorithm:
- * ucSum= 0 1 uchar
- * for all NonEndTokenChunk bytes:
- * ROTL(ucSum,1) rotate left by 1
- * ucSum += Char; add current byte with swap around
- * RotlCRC= ~ucSum; invert all bits for result
- *
- * note:
- * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes!
- */
-
-/*--------------------------------------error logger------------------------*/
- /* note: pof needs final 0 ! */
-#define ERRLOG_CMD_REQ "ERRLOG ON"
-#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */
-#define ERRLOG_CMD_STOP "ERRLOG OFF"
-#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */
-
-#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */
- /* remaining text size = 55 */
-#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1)
-
+#ifndef __INCE1PC_H__
+#define __INCE1PC_H__
+
+/****************************************************************************
+
+ FILE: ince1pc.h
+
+ AUTHOR: M.Steinkopf
+
+ PURPOSE: common definitions for both sides of the bus:
+ - conventions both spoolers must know
+ - channel numbers agreed upon
+
+*****************************************************************************/
+
+/* basic scalar definitions have same meanning,
+ * but their declaration location depends on environment
+ */
+
+/*--------------------------------------channel numbers---------------------*/
+#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */
+#define CHAN_ERRLOG 0x0005 /* error logger */
+#define CHAN_CAPI 0x0064 /* CAPI interface */
+#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */
+
+/*--------------------------------------POF ready msg-----------------------*/
+ /* NOTE: after booting POF sends system ready message to PC: */
+#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */
+#define RDY_MAGIC_SIZE 4 /* size in bytes */
+
+#define MAX_N_TOK_BYTES 255
+
+#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE
+#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
+
+#define SYSR_TOK_END 0
+#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */
+#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */
+#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */
+#define SYSR_TOK_ESC 255 /* undefined data size yet */
+ /* default values, if not corrected by token: */
+#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */
+#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */
+
+/* syntax of new SYSR token stream:
+ * channel: CHAN_SYSTEM
+ * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE
+ * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
+ * msg : 0 1 2 3 {4 5 6 ..}
+ * S Y S R MAX_N_TOK_BYTES bytes of TokenStream
+ *
+ * TokenStream := empty
+ * | {NonEndTokenChunk} EndToken RotlCRC
+ * NonEndTokenChunk:= NonEndTokenId DataLen [Data]
+ * NonEndTokenId := 0x01 .. 0xFE 1 BYTE
+ * DataLen := 0x00 .. 0xFF 1 BYTE
+ * Data := DataLen bytes
+ * EndToken := 0x00
+ * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes
+ * s. RotlCRC algorithm
+ *
+ * RotlCRC algorithm:
+ * ucSum= 0 1 uchar
+ * for all NonEndTokenChunk bytes:
+ * ROTL(ucSum,1) rotate left by 1
+ * ucSum += Char; add current byte with swap around
+ * RotlCRC= ~ucSum; invert all bits for result
+ *
+ * note:
+ * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes!
+ */
+
+/*--------------------------------------error logger------------------------*/
+ /* note: pof needs final 0 ! */
+#define ERRLOG_CMD_REQ "ERRLOG ON"
+#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */
+#define ERRLOG_CMD_STOP "ERRLOG OFF"
+#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */
+
+#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */
+ /* remaining text size = 55 */
+#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1)
+
typedef struct ErrLogEntry_tag {
-
+
/*00 */ ulong ulErrType;
-
+
/*04 */ ulong ulErrSubtype;
-
+
/*08 */ uchar ucTextSize;
-
+
/*09 */ uchar ucText[ERRLOG_TEXT_SIZE];
/* ASCIIZ of len ucTextSize-1 */
-
-/*40 */
+
+/*40 */
} tErrLogEntry;
-
-#if defined(__TURBOC__)
-#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE
-#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE
-#endif /* */
-#endif /* */
-
-/*--------------------------------------DPRAM boot spooler------------------*/
- /* this is the struture used between pc and
- * hyperstone to exchange boot data
- */
-#define DPRAM_SPOOLER_DATA_SIZE 0x20
+
+#if defined(__TURBOC__)
+#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE
+#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE
+#endif /* */
+#endif /* */
+
+/*--------------------------------------DPRAM boot spooler------------------*/
+ /* this is the struture used between pc and
+ * hyperstone to exchange boot data
+ */
+#define DPRAM_SPOOLER_DATA_SIZE 0x20
typedef struct DpramBootSpooler_tag {
-
+
/*00 */ uchar Len;
-
+
/*01 */ volatile uchar RdPtr;
-
+
/*02 */ uchar WrPtr;
-
+
/*03 */ uchar Data[DPRAM_SPOOLER_DATA_SIZE];
-
-/*23 */
+
+/*23 */
} tDpramBootSpooler;
-
-#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */
-#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */
-
-/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/
- /* at DPRAM offset 0x1C00: */
-#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */
-
-
-#endif /* __INCE1PC_H__ */
+
+#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */
+#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */
+
+/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/
+ /* at DPRAM offset 0x1C00: */
+#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */
+
+
+#endif /* __INCE1PC_H__ */
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
index 727165387..74905bba0 100644
--- a/drivers/isdn/icn/icn.c
+++ b/drivers/isdn/icn/icn.c
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.62 1999/09/06 07:29:35 fritz Exp $
+/* $Id: icn.c,v 1.63 2000/05/06 00:52:39 kai Exp $
* ISDN low-level module for the ICN active ISDN-Card.
*
@@ -19,6 +19,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: icn.c,v $
+ * Revision 1.63 2000/05/06 00:52:39 kai
+ * merged changes from kernel tree
+ * fixed timer and net_device->name breakage
+ *
* Revision 1.62 1999/09/06 07:29:35 fritz
* Changed my mail-address.
*
@@ -247,7 +251,7 @@
#undef MAP_DEBUG
static char
-*revision = "$Revision: 1.62 $";
+*revision = "$Revision: 1.63 $";
static int icn_addcard(int, char *, char *);
diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
index caf46b112..5dffb2770 100644
--- a/drivers/isdn/isdn_common.c
+++ b/drivers/isdn/isdn_common.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.108 2000/06/24 15:52:47 keil Exp $
+/* $Id: isdn_common.c,v 1.111 2000/08/20 07:40:14 keil Exp $
* Linux ISDN subsystem, common used functions (linklevel).
*
@@ -48,7 +48,7 @@
isdn_dev *dev = (isdn_dev *) 0;
-static char *isdn_revision = "$Revision: 1.108 $";
+static char *isdn_revision = "$Revision: 1.111 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
@@ -1660,6 +1660,8 @@ isdn_open(struct inode *ino, struct file *filep)
uint minor = MINOR(ino->i_rdev);
int drvidx;
int chidx;
+ int retval = -ENODEV;
+
if (minor == ISDN_MINOR_STATUS) {
infostruct *p;
@@ -1670,41 +1672,47 @@ isdn_open(struct inode *ino, struct file *filep)
dev->infochain = p;
/* At opening we allow a single update */
filep->private_data = (char *) 1;
- return 0;
- } else
- return -ENOMEM;
+ retval = 0;
+ goto out;
+ } else {
+ retval = -ENOMEM;
+ goto out;
+ }
}
if (!dev->channels)
- return -ENODEV;
+ goto out;
if (minor < ISDN_MINOR_CTRL) {
printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
drvidx = isdn_minor2drv(minor);
if (drvidx < 0)
- return -ENODEV;
+ goto out;
chidx = isdn_minor2chan(minor);
if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- return -ENODEV;
+ goto out;
if (!(dev->drv[drvidx]->online & (1 << chidx)))
- return -ENODEV;
+ goto out;
isdn_lock_drivers();
- return 0;
+ retval = 0;
+ goto out;
}
if (minor <= ISDN_MINOR_CTRLMAX) {
drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
if (drvidx < 0)
- return -ENODEV;
+ goto out;
isdn_lock_drivers();
- return 0;
+ retval = 0;
+ goto out;
}
#ifdef CONFIG_ISDN_PPP
if (minor <= ISDN_MINOR_PPPMAX) {
- int ret;
- if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep)))
+ retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep);
+ if (retval == 0)
isdn_lock_drivers();
- return ret;
+ goto out;
}
#endif
- return -ENODEV;
+ out:
+ return retval;
}
static int
@@ -1724,31 +1732,28 @@ isdn_close(struct inode *ino, struct file *filep)
else
dev->infochain = (infostruct *) (p->next);
kfree(p);
- unlock_kernel();
- return 0;
+ goto out;
}
q = p;
p = (infostruct *) (p->next);
}
printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
- unlock_kernel();
- return 0;
+ goto out;
}
isdn_unlock_drivers();
- if (minor < ISDN_MINOR_CTRL) {
- unlock_kernel();
- return 0;
- }
+ if (minor < ISDN_MINOR_CTRL)
+ goto out;
if (minor <= ISDN_MINOR_CTRLMAX) {
if (dev->profd == current)
dev->profd = NULL;
- unlock_kernel();
- return 0;
+ goto out;
}
#ifdef CONFIG_ISDN_PPP
if (minor <= ISDN_MINOR_PPPMAX)
isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
#endif
+
+ out:
unlock_kernel();
return 0;
}
diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c
index 4951bb29e..d33fb5135 100644
--- a/drivers/isdn/isdn_net.c
+++ b/drivers/isdn/isdn_net.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.134 2000/06/21 09:54:29 keil Exp $
+/* $Id: isdn_net.c,v 1.135 2000/08/10 22:52:46 kai Exp $
* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
@@ -181,7 +181,7 @@ static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
int isdn_net_force_dial_lp(isdn_net_local *);
static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
-char *isdn_net_revision = "$Revision: 1.134 $";
+char *isdn_net_revision = "$Revision: 1.135 $";
/*
* Code for raw-networking over ISDN
diff --git a/drivers/isdn/isdn_ppp.h b/drivers/isdn/isdn_ppp.h
index 20ab41046..6587cf84a 100644
--- a/drivers/isdn/isdn_ppp.h
+++ b/drivers/isdn/isdn_ppp.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.h,v 1.16 2000/05/18 23:14:18 keil Exp $
+/* $Id: isdn_ppp.h,v 1.17 2000/08/10 22:52:46 kai Exp $
* header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c
index ed681f375..1a32c0825 100644
--- a/drivers/isdn/pcbit/capi.c
+++ b/drivers/isdn/pcbit/capi.c
@@ -304,7 +304,14 @@ int capi_tdata_req(struct pcbit_chan* chan, struct sk_buff *skb)
data_len = skb->len;
- skb_push(skb, 10);
+ if(skb_headroom(skb) < 10)
+ {
+ printk(KERN_CRIT "No headspace (%u) on headroom %p for capi header\n", skb_headroom(skb), skb);
+ }
+ else
+ {
+ skb_push(skb, 10);
+ }
*((u16 *) (skb->data)) = chan->callref;
skb->data[2] = chan->layer2link;
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
index 3c21adb9f..cd58e0d3b 100644
--- a/drivers/isdn/pcbit/drv.c
+++ b/drivers/isdn/pcbit/drv.c
@@ -162,7 +162,7 @@ int pcbit_init_dev(int board, int mem_base, int irq)
dev->send_seq = 0;
dev->unack_seq = 0;
- dev->hl_hdrlen = 10;
+ dev->hl_hdrlen = 16;
dev_if = kmalloc(sizeof(isdn_if), GFP_KERNEL);
@@ -186,7 +186,7 @@ int pcbit_init_dev(int board, int mem_base, int irq)
ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS );
dev_if->writebuf_skb = pcbit_xmit;
- dev_if->hl_hdrlen = 10;
+ dev_if->hl_hdrlen = 16;
dev_if->maxbufsize = MAXBUFSIZE;
dev_if->command = pcbit_command;
@@ -518,9 +518,6 @@ void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg,
struct callb_data cbdata;
int complete, err;
isdn_ctrl ictl;
-#ifdef DEBUG
- struct msg_fmt * fmsg;
-#endif
switch(msg) {
@@ -734,9 +731,6 @@ void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg,
default:
printk(KERN_DEBUG "pcbit_l3_receive: unknown message %08lx\n",
msg);
- fmsg = (struct msg_fmt *) &msg;
- printk(KERN_DEBUG "cmd=%02x sub=%02x\n",
- fmsg->cmd, fmsg->scmd);
break;
#endif
}
diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c
index 36bd6f8aa..98daf7558 100644
--- a/drivers/isdn/pcbit/layer2.c
+++ b/drivers/isdn/pcbit/layer2.c
@@ -8,6 +8,11 @@
*/
/*
+ * 19991203 - Fernando Carvalho - takion@superbofh.org
+ * Hacked to compile with egcs and run with current version of isdn modules
+*/
+
+/*
* PCBIT-D low-layer interface
*/
@@ -205,7 +210,7 @@ pcbit_transmit(struct pcbit_dev *dev)
/* Type 0 frame */
- struct msg_fmt *msg;
+ ulong msg;
if (frame->skb)
totlen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len;
@@ -214,7 +219,7 @@ pcbit_transmit(struct pcbit_dev *dev)
flen = MIN(totlen, free);
- msg = (struct msg_fmt *) &(frame->msg);
+ msg = frame->msg;
/*
* Board level 2 header
@@ -222,9 +227,9 @@ pcbit_transmit(struct pcbit_dev *dev)
pcbit_writew(dev, flen - FRAME_HDR_LEN);
- pcbit_writeb(dev, msg->cpu);
+ pcbit_writeb(dev, GET_MSG_CPU(msg));
- pcbit_writeb(dev, msg->proc);
+ pcbit_writeb(dev, GET_MSG_PROC(msg));
/* TH */
pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
@@ -244,8 +249,8 @@ pcbit_transmit(struct pcbit_dev *dev)
pcbit_writew(dev, 0);
/* C + S */
- pcbit_writeb(dev, msg->cmd);
- pcbit_writeb(dev, msg->scmd);
+ pcbit_writeb(dev, GET_MSG_CMD(msg));
+ pcbit_writeb(dev, GET_MSG_SCMD(msg));
/* NUM */
pcbit_writew(dev, frame->refnum);
@@ -312,8 +317,7 @@ void
pcbit_deliver(void *data)
{
struct frame_buf *frame;
- unsigned long flags;
- struct msg_fmt msg;
+ unsigned long flags, msg;
struct pcbit_dev *dev = (struct pcbit_dev *) data;
save_flags(flags);
@@ -323,10 +327,10 @@ pcbit_deliver(void *data)
dev->read_queue = frame->next;
restore_flags(flags);
- msg.cpu = 0;
- msg.proc = 0;
- msg.cmd = frame->skb->data[2];
- msg.scmd = frame->skb->data[3];
+ SET_MSG_CPU(msg, 0);
+ SET_MSG_PROC(msg, 0);
+ SET_MSG_CMD(msg, frame->skb->data[2]);
+ SET_MSG_SCMD(msg, frame->skb->data[3]);
frame->refnum = *((ushort *) frame->skb->data + 4);
frame->msg = *((ulong *) & msg);
diff --git a/drivers/isdn/pcbit/layer2.h b/drivers/isdn/pcbit/layer2.h
index 2f56a5844..f8984f990 100644
--- a/drivers/isdn/pcbit/layer2.h
+++ b/drivers/isdn/pcbit/layer2.h
@@ -7,6 +7,11 @@
* the GNU Public License, incorporated herein by reference.
*/
+/*
+ * 19991203 - Fernando Carvalho - takion@superbofh.org
+ * Hacked to compile with egcs and run with current version of isdn modules
+*/
+
/*
* PCBIT-D low-layer interface definitions
*/
@@ -84,21 +89,20 @@
Intel 1 2 3 4
*/
-struct msg_fmt {
-#ifdef __LITTLE_ENDIAN /* Little Endian */
- u_char scmd;
- u_char cmd;
- u_char proc;
- u_char cpu;
+#ifdef __LITTLE_ENDIAN
+#define SET_MSG_SCMD(msg, ch) (msg = (msg & 0xffffff00) | (((ch) & 0xff)))
+#define SET_MSG_CMD(msg, ch) (msg = (msg & 0xffff00ff) | (((ch) & 0xff) << 8))
+#define SET_MSG_PROC(msg, ch) (msg = (msg & 0xff00ffff) | (((ch) & 0xff) << 16))
+#define SET_MSG_CPU(msg, ch) (msg = (msg & 0x00ffffff) | (((ch) & 0xff) << 24))
+
+#define GET_MSG_SCMD(msg) ((msg) & 0xFF)
+#define GET_MSG_CMD(msg) ((msg) >> 8 & 0xFF)
+#define GET_MSG_PROC(msg) ((msg) >> 16 & 0xFF)
+#define GET_MSG_CPU(msg) ((msg) >> 24)
+
#else
#error "Non-Intel CPU"
- u_char cpu;
- u_char proc;
- u_char cmd;
- u_char scmd;
#endif
-};
-
#define MAX_QUEUED 7
@@ -107,14 +111,13 @@ struct msg_fmt {
#define SET_RUN_TIMEOUT 2*HZ /* 2 seconds */
-
struct frame_buf {
ulong msg;
- unsigned short refnum;
- unsigned short dt_len;
- unsigned short hdr_len;
+ unsigned int refnum;
+ unsigned int dt_len;
+ unsigned int hdr_len;
struct sk_buff *skb;
- unsigned short copied;
+ unsigned int copied;
struct frame_buf * next;
};
diff --git a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c
index 9d3aa8007..c85f68688 100644
--- a/drivers/isdn/pcbit/module.c
+++ b/drivers/isdn/pcbit/module.c
@@ -46,8 +46,8 @@ int pcbit_init(void)
num_boards = 0;
- printk(KERN_INFO
- "PCBIT-D device driver v 0.5 - "
+ printk(KERN_NOTICE
+ "PCBIT-D device driver v 0.5-fjpc0 19991204 - "
"Copyright (C) 1996 Universidade de Lisboa\n");
if (mem[0] || irq[0])
@@ -97,7 +97,7 @@ void cleanup_module(void)
for (board = 0; board < num_boards; board++)
pcbit_terminate(board);
- printk(KERN_INFO
+ printk(KERN_NOTICE
"PCBIT-D module unloaded\n");
}
diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c
index 7cff7a727..1c355dc28 100644
--- a/drivers/isdn/sc/timer.c
+++ b/drivers/isdn/sc/timer.c
@@ -1,5 +1,5 @@
/*
- * $Id: timer.c,v 1.2 1996/11/20 17:49:57 fritz Exp $
+ * $Id: timer.c,v 1.3 2000/05/06 00:52:39 kai Exp $
* Copyright (C) 1996 SpellCaster Telecommunications Inc.
*
* This program is free software; you can redistribute it and/or modify