summaryrefslogtreecommitdiffstats
path: root/drivers/isdn/hisax
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/hisax
parentfb9c690a18b3d66925a65b17441c37fa14d4370b (diff)
Merge with 2.4.0-test7.
Diffstat (limited to 'drivers/isdn/hisax')
-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
35 files changed, 5915 insertions, 709 deletions
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)