diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-08-28 22:00:09 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-08-28 22:00:09 +0000 |
commit | 1a1d77dd589de5a567fa95e36aa6999c704ceca4 (patch) | |
tree | 141e31f89f18b9fe0831f31852e0435ceaccafc5 /drivers/isdn/hisax | |
parent | fb9c690a18b3d66925a65b17441c37fa14d4370b (diff) |
Merge with 2.4.0-test7.
Diffstat (limited to 'drivers/isdn/hisax')
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) |