summaryrefslogtreecommitdiffstats
path: root/drivers/isdn
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn')
-rw-r--r--drivers/isdn/Config.in30
-rw-r--r--drivers/isdn/Makefile28
-rw-r--r--drivers/isdn/act2000/.cvsignore2
-rw-r--r--drivers/isdn/act2000/Makefile15
-rw-r--r--drivers/isdn/act2000/act2000.h239
-rw-r--r--drivers/isdn/act2000/act2000_isa.c525
-rw-r--r--drivers/isdn/act2000/act2000_isa.h149
-rw-r--r--drivers/isdn/act2000/capi.c1218
-rw-r--r--drivers/isdn/act2000/capi.h406
-rw-r--r--drivers/isdn/act2000/module.c953
-rw-r--r--drivers/isdn/avmb1/b1capi.c406
-rw-r--r--drivers/isdn/avmb1/b1lli.c313
-rw-r--r--drivers/isdn/avmb1/b1pci.c47
-rw-r--r--drivers/isdn/avmb1/capi.c66
-rw-r--r--drivers/isdn/avmb1/capidrv.c331
-rw-r--r--drivers/isdn/avmb1/capiutil.c37
-rw-r--r--drivers/isdn/avmb1/compat.h17
-rw-r--r--drivers/isdn/hisax/Makefile95
-rw-r--r--drivers/isdn/hisax/amd7930.c768
-rw-r--r--drivers/isdn/hisax/arcofi.c51
-rw-r--r--drivers/isdn/hisax/arcofi.h17
-rw-r--r--drivers/isdn/hisax/asuscom.c292
-rw-r--r--drivers/isdn/hisax/avm_a1.c966
-rw-r--r--drivers/isdn/hisax/callc.c1743
-rw-r--r--drivers/isdn/hisax/config.c457
-rw-r--r--drivers/isdn/hisax/diva.c465
-rw-r--r--drivers/isdn/hisax/elsa.c1921
-rw-r--r--drivers/isdn/hisax/fsm.c53
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c1297
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.h131
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.c615
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.h62
-rw-r--r--drivers/isdn/hisax/hisax.h940
-rw-r--r--drivers/isdn/hisax/hscx.c280
-rw-r--r--drivers/isdn/hisax/hscx.h46
-rw-r--r--drivers/isdn/hisax/hscx_irq.c320
-rw-r--r--drivers/isdn/hisax/ipac.h35
-rw-r--r--drivers/isdn/hisax/isac.c679
-rw-r--r--drivers/isdn/hisax/isac.h74
-rw-r--r--drivers/isdn/hisax/isdnl1.c1621
-rw-r--r--drivers/isdn/hisax/isdnl1.h52
-rw-r--r--drivers/isdn/hisax/isdnl2.c1614
-rw-r--r--drivers/isdn/hisax/isdnl3.c229
-rw-r--r--drivers/isdn/hisax/isdnl3.h27
-rw-r--r--drivers/isdn/hisax/ix1_micro.c925
-rw-r--r--drivers/isdn/hisax/l3_1tr6.c610
-rw-r--r--drivers/isdn/hisax/l3_1tr6.h18
-rw-r--r--drivers/isdn/hisax/l3dss1.c1409
-rw-r--r--drivers/isdn/hisax/l3dss1.h71
-rw-r--r--drivers/isdn/hisax/lmgr.c58
-rw-r--r--drivers/isdn/hisax/mic.c284
-rw-r--r--drivers/isdn/hisax/netjet.c1108
-rw-r--r--drivers/isdn/hisax/niccy.c354
-rw-r--r--drivers/isdn/hisax/q931.c51
-rw-r--r--drivers/isdn/hisax/rawhdlc.c539
-rw-r--r--drivers/isdn/hisax/rawhdlc.h26
-rw-r--r--drivers/isdn/hisax/sedlbauer.c356
-rw-r--r--drivers/isdn/hisax/sportster.c291
-rw-r--r--drivers/isdn/hisax/tei.c599
-rw-r--r--drivers/isdn/hisax/teleint.c363
-rw-r--r--drivers/isdn/hisax/teles0.c978
-rw-r--r--drivers/isdn/hisax/teles3.c1149
-rw-r--r--drivers/isdn/hisax/teles3c.c199
-rw-r--r--drivers/isdn/icn/icn.c112
-rw-r--r--drivers/isdn/icn/icn.h17
-rw-r--r--drivers/isdn/isdn_audio.c13
-rw-r--r--drivers/isdn/isdn_cards.c8
-rw-r--r--drivers/isdn/isdn_common.c479
-rw-r--r--drivers/isdn/isdn_common.h28
-rw-r--r--drivers/isdn/isdn_concap.c108
-rw-r--r--drivers/isdn/isdn_concap.h7
-rw-r--r--drivers/isdn/isdn_net.c1120
-rw-r--r--drivers/isdn/isdn_net.h50
-rw-r--r--drivers/isdn/isdn_ppp.c490
-rw-r--r--drivers/isdn/isdn_ppp.h27
-rw-r--r--drivers/isdn/isdn_tty.c567
-rw-r--r--drivers/isdn/isdn_v110.c645
-rw-r--r--drivers/isdn/isdn_v110.h45
-rw-r--r--drivers/isdn/isdn_x25iface.c340
-rw-r--r--drivers/isdn/isdn_x25iface.h32
-rw-r--r--drivers/isdn/isdnloop/.cvsignore2
-rw-r--r--drivers/isdn/isdnloop/Makefile11
-rw-r--r--drivers/isdn/isdnloop/isdnloop.c1620
-rw-r--r--drivers/isdn/isdnloop/isdnloop.h144
-rw-r--r--drivers/isdn/pcbit/capi.c17
-rw-r--r--drivers/isdn/pcbit/drv.c7
-rw-r--r--drivers/isdn/pcbit/layer2.c8
-rw-r--r--drivers/isdn/pcbit/module.c6
-rw-r--r--drivers/isdn/sc/.cvsignore2
-rw-r--r--drivers/isdn/sc/debug.c11
-rw-r--r--drivers/isdn/sc/event.c16
-rw-r--r--drivers/isdn/sc/hardware.h5
-rw-r--r--drivers/isdn/sc/init.c4
-rw-r--r--drivers/isdn/sc/interrupt.c2
-rw-r--r--drivers/isdn/sc/message.c5
-rw-r--r--drivers/isdn/sc/packet.c10
96 files changed, 25827 insertions, 9151 deletions
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in
index 758e30d2b..3787c735f 100644
--- a/drivers/isdn/Config.in
+++ b/drivers/isdn/Config.in
@@ -9,24 +9,44 @@ if [ "$CONFIG_INET" != "n" ]; then
fi
fi
bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO
+if [ "$CONFIG_X25" != "n" ]; then
+ bool 'X.25 PLP on top of ISDN (EXPERIMENTAL)' CONFIG_ISDN_X25
+fi
dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
+dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
+ bool 'HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
+ if [ "$CONFIG_HISAX_EURO" != "n" ]; then
+ bool 'Support for german tarifinfo' CONFIG_DE_AOC
+ bool 'Support for australian Microlink service (not for std. EURO)' CONFIG_HISAX_ML
+ fi
+ bool 'HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
bool 'HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
bool 'HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+ bool 'HiSax Support for Teles 16.3c' CONFIG_HISAX_TELES3C
bool 'HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
- bool 'HiSax Support for Elsa ISA cards' CONFIG_HISAX_ELSA_PCC
- bool 'HiSax Support for Elsa PCMCIA card' CONFIG_HISAX_ELSA_PCMCIA
+ bool 'HiSax Support for Elsa cards' CONFIG_HISAX_ELSA
bool 'HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
- bool 'HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
- bool 'HiSax Support for US/NI-1' CONFIG_HISAX_NI1
- bool 'HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
+ bool 'HiSax Support for Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
+ bool 'HiSax Support for ASUSCOM cards' CONFIG_HISAX_ASUSCOM
+ bool 'HiSax Support for TELEINT cards' CONFIG_HISAX_TELEINT
+ bool 'HiSax Support for Sedlbauer speed card/win/star' CONFIG_HISAX_SEDLBAUER
+ bool 'HiSax Support for USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
+ bool 'HiSax Support for MIC card' CONFIG_HISAX_MIC
+ bool 'HiSax Support for NETjet card' CONFIG_HISAX_NETJET
+ bool 'HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY
+ if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+ bool 'HiSax Support for Am7930' CONFIG_HISAX_AMD7930
+ fi
fi
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
+ dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
fi
dep_tristate 'AVM-B1 with CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then
bool 'Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
fi
+
diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile
index c5f508217..35d56d142 100644
--- a/drivers/isdn/Makefile
+++ b/drivers/isdn/Makefile
@@ -1,6 +1,6 @@
SUB_DIRS :=
MOD_SUB_DIRS :=
-ALL_SUB_DIRS := icn pcbit hisax avmb1
+ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000
L_OBJS :=
LX_OBJS :=
@@ -13,11 +13,15 @@ O_TARGET :=
ifeq ($(CONFIG_ISDN),y)
L_TARGET := isdn.a
- L_OBJS += isdn_common.o isdn_net.o isdn_tty.o isdn_cards.o
- LX_OBJS += isdn_syms.o
+ L_OBJS += isdn_net.o isdn_tty.o isdn_cards.o isdn_v110.o
+ LX_OBJS += isdn_common.o
ifdef CONFIG_ISDN_PPP
L_OBJS += isdn_ppp.o
endif
+ ifdef CONFIG_ISDN_X25
+ L_OBJS += isdn_x25iface.o
+ L_OBJS += isdn_concap.o
+ endif
ifdef CONFIG_ISDN_AUDIO
L_OBJS += isdn_audio.o
endif
@@ -25,11 +29,15 @@ else
ifeq ($(CONFIG_ISDN),m)
M_OBJS += isdn.o
O_TARGET += isdn.o
- O_OBJS += isdn_common.o isdn_net.o isdn_tty.o
- OX_OBJS += isdn_syms.o
+ O_OBJS += isdn_net.o isdn_tty.o isdn_v110.o
+ OX_OBJS += isdn_common.o
ifdef CONFIG_ISDN_PPP
O_OBJS += isdn_ppp.o
endif
+ ifdef CONFIG_ISDN_X25
+ O_OBJS += isdn_x25iface.o
+ O_OBJS += isdn_concap.o
+ endif
ifdef CONFIG_ISDN_AUDIO
O_OBJS += isdn_audio.o
endif
@@ -96,5 +104,15 @@ else
endif
endif
+ifeq ($(CONFIG_ISDN_DRV_ACT2000),y)
+ L_OBJS += act2000/act2000.o
+ SUB_DIRS += act2000
+ MOD_SUB_DIRS += act2000
+else
+ ifeq ($(CONFIG_ISDN_DRV_ACT2000),m)
+ MOD_SUB_DIRS += act2000
+ endif
+endif
+
include $(TOPDIR)/Rules.make
diff --git a/drivers/isdn/act2000/.cvsignore b/drivers/isdn/act2000/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/drivers/isdn/act2000/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/drivers/isdn/act2000/Makefile b/drivers/isdn/act2000/Makefile
new file mode 100644
index 000000000..0e3c4a7e1
--- /dev/null
+++ b/drivers/isdn/act2000/Makefile
@@ -0,0 +1,15 @@
+L_OBJS :=
+M_OBJS :=
+O_OBJS := module.o capi.o act2000_isa.o
+
+O_TARGET :=
+ifeq ($(CONFIG_ISDN_DRV_ACT2000),y)
+ O_TARGET += act2000.o
+else
+ ifeq ($(CONFIG_ISDN_DRV_ACT2000),m)
+ O_TARGET += act2000.o
+ M_OBJS = act2000.o
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/isdn/act2000/act2000.h b/drivers/isdn/act2000/act2000.h
new file mode 100644
index 000000000..534cc42f9
--- /dev/null
+++ b/drivers/isdn/act2000/act2000.h
@@ -0,0 +1,239 @@
+/* $Id: act2000.h,v 1.5 1997/10/09 22:22:59 fritz Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ *
+ * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: act2000.h,v $
+ * Revision 1.5 1997/10/09 22:22:59 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ *
+ * Revision 1.4 1997/09/25 17:25:37 fritz
+ * Support for adding cards at runtime.
+ * Support for new Firmware.
+ *
+ * Revision 1.3 1997/09/24 23:11:43 fritz
+ * Optimized IRQ load and polling-mode.
+ *
+ * Revision 1.2 1997/09/24 19:44:12 fritz
+ * Added MSN mapping support, some cleanup.
+ *
+ * Revision 1.1 1997/09/23 18:00:05 fritz
+ * New driver for IBM Active 2000.
+ *
+ */
+
+#ifndef act2000_h
+#define act2000_h
+
+#ifdef __KERNEL__
+/* Kernel includes */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#define ACT2000_IOCTL_SETPORT 1
+#define ACT2000_IOCTL_GETPORT 2
+#define ACT2000_IOCTL_SETIRQ 3
+#define ACT2000_IOCTL_GETIRQ 4
+#define ACT2000_IOCTL_SETBUS 5
+#define ACT2000_IOCTL_GETBUS 6
+#define ACT2000_IOCTL_SETPROTO 7
+#define ACT2000_IOCTL_GETPROTO 8
+#define ACT2000_IOCTL_SETMSN 9
+#define ACT2000_IOCTL_GETMSN 10
+#define ACT2000_IOCTL_LOADBOOT 11
+#define ACT2000_IOCTL_ADDCARD 12
+
+#define ACT2000_IOCTL_TEST 98
+#define ACT2000_IOCTL_DEBUGVAR 99
+
+#define ACT2000_BUS_ISA 1
+#define ACT2000_BUS_MCA 2
+#define ACT2000_BUS_PCMCIA 3
+
+/* Struct for adding new cards */
+typedef struct act2000_cdef {
+ int bus;
+ int port;
+ int irq;
+ char id[10];
+} act2000_cdef;
+
+/* Struct for downloading firmware */
+typedef struct act2000_ddef {
+ int length; /* Length of code */
+ char *buffer; /* Ptr. to code */
+} act2000_ddef;
+
+typedef struct act2000_fwid {
+ char isdn[4];
+ char revlen[2];
+ char revision[504];
+} act2000_fwid;
+
+#if defined(__KERNEL__) || defined(__DEBUGVAR__)
+
+#ifdef __KERNEL__
+/* Kernel includes */
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/isdnif.h>
+
+#endif /* __KERNEL__ */
+
+#define ACT2000_PORTLEN 8
+
+#define ACT2000_FLAGS_RUNNING 1 /* Cards driver activated */
+#define ACT2000_FLAGS_PVALID 2 /* Cards port is valid */
+#define ACT2000_FLAGS_IVALID 4 /* Cards irq is valid */
+#define ACT2000_FLAGS_LOADED 8 /* Firmware loaded */
+
+#define ACT2000_BCH 2 /* # of channels per card */
+
+/* D-Channel states */
+#define ACT2000_STATE_NULL 0
+#define ACT2000_STATE_ICALL 1
+#define ACT2000_STATE_OCALL 2
+#define ACT2000_STATE_IWAIT 3
+#define ACT2000_STATE_OWAIT 4
+#define ACT2000_STATE_IBWAIT 5
+#define ACT2000_STATE_OBWAIT 6
+#define ACT2000_STATE_BWAIT 7
+#define ACT2000_STATE_BHWAIT 8
+#define ACT2000_STATE_BHWAIT2 9
+#define ACT2000_STATE_DHWAIT 10
+#define ACT2000_STATE_DHWAIT2 11
+#define ACT2000_STATE_BSETUP 12
+#define ACT2000_STATE_ACTIVE 13
+
+#define ACT2000_MAX_QUEUED 8000 /* 2 * maxbuff */
+
+#define ACT2000_LOCK_TX 0
+#define ACT2000_LOCK_RX 1
+
+typedef struct act2000_chan {
+ unsigned short callref; /* Call Reference */
+ unsigned short fsm_state; /* Current D-Channel state */
+ unsigned short eazmask; /* EAZ-Mask for this Channel */
+ short queued; /* User-Data Bytes in TX queue */
+ unsigned short plci;
+ unsigned short ncci;
+ unsigned char l2prot; /* Layer 2 protocol */
+ unsigned char l3prot; /* Layer 3 protocol */
+} act2000_chan;
+
+typedef struct msn_entry {
+ char eaz;
+ char msn[16];
+ struct msn_entry * next;
+} msn_entry;
+
+typedef struct irq_data_isa {
+ __u8 *rcvptr;
+ __u16 rcvidx;
+ __u16 rcvlen;
+ struct sk_buff *rcvskb;
+ __u8 rcvignore;
+ __u8 rcvhdr[8];
+} irq_data_isa;
+
+typedef union irq_data {
+ irq_data_isa isa;
+} irq_data;
+
+/*
+ * Per card driver data
+ */
+typedef struct act2000_card {
+ unsigned short port; /* Base-port-address */
+ unsigned short irq; /* Interrupt */
+ u_char ptype; /* Protocol type (1TR6 or Euro) */
+ u_char bus; /* Cardtype (ISA, MCA, PCMCIA) */
+ struct act2000_card *next; /* Pointer to next device struct */
+ int myid; /* Driver-Nr. assigned by linklevel */
+ unsigned long flags; /* Statusflags */
+ unsigned long ilock; /* Semaphores for IRQ-Routines */
+ struct sk_buff_head rcvq; /* Receive-Message queue */
+ struct sk_buff_head sndq; /* Send-Message queue */
+ struct sk_buff_head ackq; /* Data-Ack-Message queue */
+ u_char *ack_msg; /* Ptr to User Data in User skb */
+ __u16 need_b3ack; /* Flag: Need ACK for current skb */
+ struct sk_buff *sbuf; /* skb which is currently sent */
+ struct timer_list ptimer; /* Poll timer */
+ struct tq_struct snd_tq; /* Task struct for xmit bh */
+ struct tq_struct rcv_tq; /* Task struct for rcv bh */
+ struct tq_struct poll_tq; /* Task struct for polled rcv bh */
+ msn_entry *msn_list;
+ unsigned short msgnum; /* Message number fur sending */
+ act2000_chan bch[ACT2000_BCH]; /* B-Channel status/control */
+ char status_buf[256]; /* Buffer for status messages */
+ char *status_buf_read;
+ char *status_buf_write;
+ char *status_buf_end;
+ irq_data idat; /* Data used for IRQ handler */
+ isdn_if interface; /* Interface to upper layer */
+ char regname[35]; /* Name used for request_region */
+} act2000_card;
+
+extern act2000_card *cards;
+
+extern __inline__ void act2000_schedule_tx(act2000_card *card)
+{
+ queue_task(&card->snd_tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+extern __inline__ void act2000_schedule_rx(act2000_card *card)
+{
+ queue_task(&card->rcv_tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+extern __inline__ void act2000_schedule_poll(act2000_card *card)
+{
+ queue_task(&card->poll_tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+extern char *act2000_find_eaz(act2000_card *, char);
+
+#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
+#endif /* act2000_h */
diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c
new file mode 100644
index 000000000..078760a0c
--- /dev/null
+++ b/drivers/isdn/act2000/act2000_isa.c
@@ -0,0 +1,525 @@
+/* $Id: act2000_isa.c,v 1.5 1998/02/12 23:06:47 keil Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
+ *
+ * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: act2000_isa.c,v $
+ * Revision 1.5 1998/02/12 23:06:47 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.4 1997/10/09 22:23:00 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ *
+ * Revision 1.3 1997/09/25 17:25:38 fritz
+ * Support for adding cards at runtime.
+ * Support for new Firmware.
+ *
+ * Revision 1.2 1997/09/24 23:11:44 fritz
+ * Optimized IRQ load and polling-mode.
+ *
+ * Revision 1.1 1997/09/23 18:00:05 fritz
+ * New driver for IBM Active 2000.
+ *
+ */
+
+#define __NO_VERSION__
+#include "act2000.h"
+#include "act2000_isa.h"
+#include "capi.h"
+
+static act2000_card *irq2card_map[16] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static int isa_irqs[] =
+{
+ 3, 5, 7, 10, 11, 12, 15
+};
+#define ISA_NRIRQS (sizeof(isa_irqs)/sizeof(int))
+
+static void
+isa_delay(long t)
+{
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + t;
+ schedule();
+ sti();
+}
+
+/*
+ * Reset Controller, then try to read the Card's signature.
+ + Return:
+ * 1 = Signature found.
+ * 0 = Signature not found.
+ */
+static int
+isa_reset(unsigned short portbase)
+{
+ unsigned char reg;
+ int i;
+ int found;
+ int serial = 0;
+
+ found = 0;
+ if ((reg = inb(portbase + ISA_COR)) != 0xff) {
+ outb(reg | ISA_COR_RESET, portbase + ISA_COR);
+ udelay(10000);
+ outb(reg, portbase + ISA_COR);
+ udelay(10000);
+
+ for (i = 0; i < 16; i++) {
+ if (inb(portbase + ISA_ISR) & ISA_ISR_SERIAL)
+ serial |= 0x10000;
+ serial >>= 1;
+ }
+ if (serial == ISA_SER_ID)
+ found++;
+ }
+ return found;
+}
+
+int
+isa_detect(unsigned short portbase)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (!check_region(portbase, ISA_REGION))
+ ret = isa_reset(portbase);
+ restore_flags(flags);
+ return ret;
+}
+
+static void
+isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ act2000_card *card = irq2card_map[irq];
+ u_char istatus;
+
+ if (!card) {
+ printk(KERN_WARNING
+ "act2000: Spurious interrupt!\n");
+ return;
+ }
+ istatus = (inb(ISA_PORT_ISR) & 0x07);
+ if (istatus & ISA_ISR_OUT) {
+ /* RX fifo has data */
+ istatus &= ISA_ISR_OUT_MASK;
+ outb(0, ISA_PORT_SIS);
+ isa_receive(card);
+ outb(ISA_SIS_INT, ISA_PORT_SIS);
+ }
+ if (istatus & ISA_ISR_ERR) {
+ /* Error Interrupt */
+ istatus &= ISA_ISR_ERR_MASK;
+ printk(KERN_WARNING "act2000: errIRQ\n");
+ }
+ if (istatus)
+ printk(KERN_DEBUG "act2000: ?IRQ %d %02x\n", irq, istatus);
+}
+
+static void
+isa_select_irq(act2000_card * card)
+{
+ unsigned char reg;
+
+ reg = (inb(ISA_PORT_COR) & ~ISA_COR_IRQOFF) | ISA_COR_PERR;
+ switch (card->irq) {
+ case 3:
+ reg = ISA_COR_IRQ03;
+ break;
+ case 5:
+ reg = ISA_COR_IRQ05;
+ break;
+ case 7:
+ reg = ISA_COR_IRQ07;
+ break;
+ case 10:
+ reg = ISA_COR_IRQ10;
+ break;
+ case 11:
+ reg = ISA_COR_IRQ11;
+ break;
+ case 12:
+ reg = ISA_COR_IRQ12;
+ break;
+ case 15:
+ reg = ISA_COR_IRQ15;
+ break;
+ }
+ outb(reg, ISA_PORT_COR);
+}
+
+static void
+isa_enable_irq(act2000_card * card)
+{
+ isa_select_irq(card);
+ /* Enable READ irq */
+ outb(ISA_SIS_INT, ISA_PORT_SIS);
+}
+
+/*
+ * Install interrupt handler, enable irq on card.
+ * If irq is -1, choose next free irq, else irq is given explicitely.
+ */
+int
+isa_config_irq(act2000_card * card, short irq)
+{
+ int i;
+ unsigned long flags;
+
+ if (card->flags & ACT2000_FLAGS_IVALID) {
+ free_irq(card->irq, NULL);
+ irq2card_map[card->irq] = NULL;
+ }
+ card->flags &= ~ACT2000_FLAGS_IVALID;
+ outb(ISA_COR_IRQOFF, ISA_PORT_COR);
+ if (!irq)
+ return 0;
+ save_flags(flags);
+ cli();
+ if (irq == -1) {
+ /* Auto select */
+ for (i = 0; i < ISA_NRIRQS; i++) {
+ if (!request_irq(isa_irqs[i], &isa_interrupt, 0, card->regname, NULL)) {
+ card->irq = isa_irqs[i];
+ irq2card_map[card->irq] = card;
+ card->flags |= ACT2000_FLAGS_IVALID;
+ break;
+ }
+ }
+ } else {
+ /* Fixed irq */
+ if (!request_irq(irq, &isa_interrupt, 0, card->regname, NULL)) {
+ card->irq = irq;
+ irq2card_map[card->irq] = card;
+ card->flags |= ACT2000_FLAGS_IVALID;
+ }
+ }
+ restore_flags(flags);
+ if (!card->flags & ACT2000_FLAGS_IVALID) {
+ printk(KERN_WARNING
+ "act2000: Could not request irq\n");
+ return -EBUSY;
+ } else {
+ isa_select_irq(card);
+ /* Disable READ and WRITE irq */
+ outb(0, ISA_PORT_SIS);
+ outb(0, ISA_PORT_SOS);
+ }
+ return 0;
+}
+
+int
+isa_config_port(act2000_card * card, unsigned short portbase)
+{
+ if (card->flags & ACT2000_FLAGS_PVALID) {
+ release_region(card->port, ISA_REGION);
+ card->flags &= ~ACT2000_FLAGS_PVALID;
+ }
+ if (!check_region(portbase, ISA_REGION)) {
+ request_region(portbase, ACT2000_PORTLEN, card->regname);
+ card->port = portbase;
+ card->flags |= ACT2000_FLAGS_PVALID;
+ return 0;
+ }
+ return -EBUSY;
+}
+
+/*
+ * Release ressources, used by an adaptor.
+ */
+void
+isa_release(act2000_card * card)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (card->flags & ACT2000_FLAGS_IVALID) {
+ free_irq(card->irq, NULL);
+ irq2card_map[card->irq] = NULL;
+ }
+ card->flags &= ~ACT2000_FLAGS_IVALID;
+ if (card->flags & ACT2000_FLAGS_PVALID)
+ release_region(card->port, ISA_REGION);
+ card->flags &= ~ACT2000_FLAGS_PVALID;
+ restore_flags(flags);
+}
+
+static int
+isa_writeb(act2000_card * card, u_char data)
+{
+ u_char timeout = 40;
+
+ while (timeout) {
+ if (inb(ISA_PORT_SOS) & ISA_SOS_READY) {
+ outb(data, ISA_PORT_SDO);
+ return 0;
+ } else {
+ timeout--;
+ udelay(10);
+ }
+ }
+ return 1;
+}
+
+static int
+isa_readb(act2000_card * card, u_char * data)
+{
+ u_char timeout = 40;
+
+ while (timeout) {
+ if (inb(ISA_PORT_SIS) & ISA_SIS_READY) {
+ *data = inb(ISA_PORT_SDI);
+ return 0;
+ } else {
+ timeout--;
+ udelay(10);
+ }
+ }
+ return 1;
+}
+
+void
+isa_receive(act2000_card *card)
+{
+ u_char c;
+
+ if (test_and_set_bit(ACT2000_LOCK_RX, (void *) &card->ilock) != 0)
+ return;
+ while (!isa_readb(card, &c)) {
+ if (card->idat.isa.rcvidx < 8) {
+ card->idat.isa.rcvhdr[card->idat.isa.rcvidx++] = c;
+ if (card->idat.isa.rcvidx == 8) {
+ int valid = actcapi_chkhdr(card, (actcapi_msghdr *)&card->idat.isa.rcvhdr);
+
+ if (valid) {
+ card->idat.isa.rcvlen = ((actcapi_msghdr *)&card->idat.isa.rcvhdr)->len;
+ card->idat.isa.rcvskb = dev_alloc_skb(card->idat.isa.rcvlen);
+ if (card->idat.isa.rcvskb == NULL) {
+ card->idat.isa.rcvignore = 1;
+ printk(KERN_WARNING
+ "isa_receive: no memory\n");
+ test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
+ return;
+ }
+ memcpy(skb_put(card->idat.isa.rcvskb, 8), card->idat.isa.rcvhdr, 8);
+ card->idat.isa.rcvptr = skb_put(card->idat.isa.rcvskb, card->idat.isa.rcvlen - 8);
+ } else {
+ card->idat.isa.rcvidx = 0;
+ printk(KERN_WARNING
+ "isa_receive: Invalid CAPI msg\n");
+ {
+ int i; __u8 *p; __u8 *c; __u8 tmp[30];
+ for (i = 0, p = (__u8 *)&card->idat.isa.rcvhdr, c = tmp; i < 8; i++)
+ c += sprintf(c, "%02x ", *(p++));
+ printk(KERN_WARNING "isa_receive: %s\n", tmp);
+ }
+ }
+ }
+ } else {
+ if (!card->idat.isa.rcvignore)
+ *card->idat.isa.rcvptr++ = c;
+ if (++card->idat.isa.rcvidx >= card->idat.isa.rcvlen) {
+ if (!card->idat.isa.rcvignore) {
+ skb_queue_tail(&card->rcvq, card->idat.isa.rcvskb);
+ act2000_schedule_rx(card);
+ }
+ card->idat.isa.rcvidx = 0;
+ card->idat.isa.rcvlen = 8;
+ card->idat.isa.rcvignore = 0;
+ card->idat.isa.rcvskb = NULL;
+ card->idat.isa.rcvptr = card->idat.isa.rcvhdr;
+ }
+ }
+ }
+ if (!(card->flags & ACT2000_FLAGS_IVALID)) {
+ /* In polling mode, schedule myself */
+ if ((card->idat.isa.rcvidx) &&
+ (card->idat.isa.rcvignore ||
+ (card->idat.isa.rcvidx < card->idat.isa.rcvlen)))
+ act2000_schedule_poll(card);
+ }
+ test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
+}
+
+void
+isa_send(act2000_card * card)
+{
+ unsigned long flags;
+ struct sk_buff *skb;
+ actcapi_msg *msg;
+ int l;
+
+ if (test_and_set_bit(ACT2000_LOCK_TX, (void *) &card->ilock) != 0)
+ return;
+ while (1) {
+ save_flags(flags);
+ cli();
+ if (!(card->sbuf)) {
+ if ((card->sbuf = skb_dequeue(&card->sndq))) {
+ card->ack_msg = card->sbuf->data;
+ msg = (actcapi_msg *)card->sbuf->data;
+ if ((msg->hdr.cmd.cmd == 0x86) &&
+ (msg->hdr.cmd.subcmd == 0) ) {
+ /* Save flags in message */
+ card->need_b3ack = msg->msg.data_b3_req.flags;
+ msg->msg.data_b3_req.flags = 0;
+ }
+ }
+ }
+ restore_flags(flags);
+ if (!(card->sbuf)) {
+ /* No more data to send */
+ test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
+ return;
+ }
+ skb = card->sbuf;
+ l = 0;
+ while (skb->len) {
+ if (isa_writeb(card, *(skb->data))) {
+ /* Fifo is full, but more data to send */
+#if 0
+ printk(KERN_DEBUG "isa_send: %d bytes\n", l);
+#endif
+ test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
+ /* Schedule myself */
+ act2000_schedule_tx(card);
+ return;
+ }
+ skb_pull(skb, 1);
+ l++;
+ }
+ msg = (actcapi_msg *)card->ack_msg;
+ if ((msg->hdr.cmd.cmd == 0x86) &&
+ (msg->hdr.cmd.subcmd == 0) ) {
+ /*
+ * If it's user data, reset data-ptr
+ * and put skb into ackq.
+ */
+ skb->data = card->ack_msg;
+ /* Restore flags in message */
+ msg->msg.data_b3_req.flags = card->need_b3ack;
+ skb_queue_tail(&card->ackq, skb);
+ } else
+ dev_kfree_skb(skb);
+ card->sbuf = NULL;
+#if 0
+ printk(KERN_DEBUG "isa_send: %d bytes\n", l);
+#endif
+ }
+}
+
+/*
+ * Get firmware ID, check for 'ISDN' signature.
+ */
+static int
+isa_getid(act2000_card * card)
+{
+
+ act2000_fwid fid;
+ u_char *p = (u_char *) & fid;
+ int count = 0;
+
+ while (1) {
+ if (count > 510)
+ return -EPROTO;
+ if (isa_readb(card, p++))
+ break;
+ count++;
+ }
+ if (count <= 20) {
+ printk(KERN_WARNING "act2000: No Firmware-ID!\n");
+ return -ETIME;
+ }
+ *p = '\0';
+ fid.revlen[0] = '\0';
+ if (strcmp(fid.isdn, "ISDN")) {
+ printk(KERN_WARNING "act2000: Wrong Firmware-ID!\n");
+ return -EPROTO;
+ }
+ if ((p = strchr(fid.revision, '\n')))
+ *p = '\0';
+ printk(KERN_INFO "act2000: Firmware-ID: %s\n", fid.revision);
+ if (card->flags & ACT2000_FLAGS_IVALID) {
+ printk(KERN_DEBUG "Enabling Interrupts ...\n");
+ isa_enable_irq(card);
+ }
+ return 0;
+}
+
+/*
+ * Download microcode into card, check Firmware signature.
+ */
+int
+isa_download(act2000_card * card, act2000_ddef * cb)
+{
+ int length;
+ int ret;
+ int l;
+ int c;
+ long timeout;
+ u_char *b;
+ u_char *p;
+ u_char *buf;
+ act2000_ddef cblock;
+
+ if (!isa_reset(card->port))
+ return -ENXIO;
+ isa_delay(HZ / 2);
+ if ((ret = verify_area(VERIFY_READ, (void *) cb, sizeof(cblock))))
+ return ret;
+ copy_from_user(&cblock, (char *) cb, sizeof(cblock));
+ length = cblock.length;
+ p = cblock.buffer;
+ if ((ret = verify_area(VERIFY_READ, (void *) p, length)))
+ return ret;
+ buf = (u_char *) kmalloc(1024, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ timeout = 0;
+ while (length) {
+ l = (length > 1024) ? 1024 : length;
+ c = 0;
+ b = buf;
+ copy_from_user(buf, p, l);
+ while (c < l) {
+ if (isa_writeb(card, *b++)) {
+ printk(KERN_WARNING
+ "act2000: loader timed out"
+ " len=%d c=%d\n", length, c);
+ kfree(buf);
+ return -ETIME;
+ }
+ c++;
+ }
+ length -= l;
+ p += l;
+ }
+ kfree(buf);
+ isa_delay(HZ / 2);
+ return (isa_getid(card));
+}
diff --git a/drivers/isdn/act2000/act2000_isa.h b/drivers/isdn/act2000/act2000_isa.h
new file mode 100644
index 000000000..b7c01ee2b
--- /dev/null
+++ b/drivers/isdn/act2000/act2000_isa.h
@@ -0,0 +1,149 @@
+/* $Id: act2000_isa.h,v 1.1 1997/09/23 18:00:07 fritz Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
+ *
+ * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: act2000_isa.h,v $
+ * Revision 1.1 1997/09/23 18:00:07 fritz
+ * New driver for IBM Active 2000.
+ *
+ */
+
+#ifndef act2000_isa_h
+#define act2000_isa_h
+
+#define ISA_POLL_LOOP 40 /* Try to read-write before give up */
+
+typedef enum {
+ INT_NO_CHANGE = 0, /* Do not change the Mask */
+ INT_ON = 1, /* Set to Enable */
+ INT_OFF = 2, /* Set to Disable */
+} ISA_INT_T;
+
+/**************************************************************************/
+/* Configuration Register COR (RW) */
+/**************************************************************************/
+/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
+/* Soft Res| IRQM | IRQ Select | N/A | WAIT |Proc err */
+/**************************************************************************/
+#define ISA_COR 0 /* Offset for ISA config register */
+#define ISA_COR_PERR 0x01 /* Processor Error Enabled */
+#define ISA_COR_WS 0x02 /* Insert Wait State if 1 */
+#define ISA_COR_IRQOFF 0x38 /* No Interrupt */
+#define ISA_COR_IRQ07 0x30 /* IRQ 7 Enable */
+#define ISA_COR_IRQ05 0x28 /* IRQ 5 Enable */
+#define ISA_COR_IRQ03 0x20 /* IRQ 3 Enable */
+#define ISA_COR_IRQ10 0x18 /* IRQ 10 Enable */
+#define ISA_COR_IRQ11 0x10 /* IRQ 11 Enable */
+#define ISA_COR_IRQ12 0x08 /* IRQ 12 Enable */
+#define ISA_COR_IRQ15 0x00 /* IRQ 15 Enable */
+#define ISA_COR_IRQPULSE 0x40 /* 0 = Level 1 = Pulse Interrupt */
+#define ISA_COR_RESET 0x80 /* Soft Reset for Transputer */
+
+/**************************************************************************/
+/* Interrupt Source Register ISR (RO) */
+/**************************************************************************/
+/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
+/* N/A | N/A | N/A |Err sig |Ser ID |IN Intr |Out Intr| Error */
+/**************************************************************************/
+#define ISA_ISR 1 /* Offset for Interrupt Register */
+#define ISA_ISR_ERR 0x01 /* Error Interrupt */
+#define ISA_ISR_OUT 0x02 /* Output Interrupt */
+#define ISA_ISR_INP 0x04 /* Input Interrupt */
+#define ISA_ISR_SERIAL 0x08 /* Read out Serial ID after Reset */
+#define ISA_ISR_ERRSIG 0x10 /* Error Signal Input */
+#define ISA_ISR_ERR_MASK 0xfe /* Mask Error Interrupt */
+#define ISA_ISR_OUT_MASK 0xfd /* Mask Output Interrupt */
+#define ISA_ISR_INP_MASK 0xfb /* Mask Input Interrupt */
+
+/* Signature delivered after Reset at ISA_ISR_SERIAL (LSB first) */
+#define ISA_SER_ID 0x0201 /* ID for ISA Card */
+
+/**************************************************************************/
+/* EEPROM Register EPR (RW) */
+/**************************************************************************/
+/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
+/* N/A | N/A | N/A |ROM Hold| ROM CS |ROM CLK | ROM IN |ROM Out */
+/**************************************************************************/
+#define ISA_EPR 2 /* Offset for this Register */
+#define ISA_EPR_OUT 0x01 /* Rome Register Out (RO) */
+#define ISA_EPR_IN 0x02 /* Rom Register In (WR) */
+#define ISA_EPR_CLK 0x04 /* Rom Clock (WR) */
+#define ISA_EPR_CS 0x08 /* Rom Cip Select (WR) */
+#define ISA_EPR_HOLD 0x10 /* Rom Hold Signal (WR) */
+
+/**************************************************************************/
+/* EEPROM enable Register EER (unused) */
+/**************************************************************************/
+#define ISA_EER 3 /* Offset for this Register */
+
+/**************************************************************************/
+/* SLC Data Input SDI (RO) */
+/**************************************************************************/
+#define ISA_SDI 4 /* Offset for this Register */
+
+/**************************************************************************/
+/* SLC Data Output SDO (WO) */
+/**************************************************************************/
+#define ISA_SDO 5 /* Offset for this Register */
+
+/**************************************************************************/
+/* IMS C011 Mode 2 Input Status Register for INMOS CPU SIS (RW) */
+/**************************************************************************/
+/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
+/* N/A | N/A | N/A | N/A | N/A | N/A |Int Ena |Data Pre */
+/**************************************************************************/
+#define ISA_SIS 6 /* Offset for this Register */
+#define ISA_SIS_READY 0x01 /* If 1 : data is available */
+#define ISA_SIS_INT 0x02 /* Enable Interrupt for READ */
+
+/**************************************************************************/
+/* IMS C011 Mode 2 Output Status Register from INMOS CPU SOS (RW) */
+/**************************************************************************/
+/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
+/* N/A | N/A | N/A | N/A | N/A | N/A |Int Ena |Out Rdy */
+/**************************************************************************/
+#define ISA_SOS 7 /* Offset for this Register */
+#define ISA_SOS_READY 0x01 /* If 1 : we can write Data */
+#define ISA_SOS_INT 0x02 /* Enable Interrupt for WRITE */
+
+#define ISA_REGION 8 /* Number of Registers */
+
+
+/* Macros for accessing ports */
+#define ISA_PORT_COR (card->port+ISA_COR)
+#define ISA_PORT_ISR (card->port+ISA_ISR)
+#define ISA_PORT_EPR (card->port+ISA_EPR)
+#define ISA_PORT_EER (card->port+ISA_EER)
+#define ISA_PORT_SDI (card->port+ISA_SDI)
+#define ISA_PORT_SDO (card->port+ISA_SDO)
+#define ISA_PORT_SIS (card->port+ISA_SIS)
+#define ISA_PORT_SOS (card->port+ISA_SOS)
+
+/* Prototypes */
+
+extern int isa_detect(unsigned short portbase);
+extern int isa_config_irq(act2000_card * card, short irq);
+extern int isa_config_port(act2000_card * card, unsigned short portbase);
+extern int isa_download(act2000_card * card, act2000_ddef * cb);
+extern void isa_release(act2000_card * card);
+extern void isa_receive(act2000_card *card);
+extern void isa_send(act2000_card *card);
+
+#endif /* act2000_isa_h */
diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c
new file mode 100644
index 000000000..d0310bcc0
--- /dev/null
+++ b/drivers/isdn/act2000/capi.c
@@ -0,0 +1,1218 @@
+/* $Id: capi.c,v 1.7 1998/02/23 23:35:41 fritz Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ * CAPI encoder/decoder
+ *
+ * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: capi.c,v $
+ * Revision 1.7 1998/02/23 23:35:41 fritz
+ * Eliminated some compiler warnings.
+ *
+ * Revision 1.6 1998/02/12 23:06:50 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.5 1997/10/09 22:23:02 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ *
+ * Revision 1.4 1997/09/25 17:25:39 fritz
+ * Support for adding cards at runtime.
+ * Support for new Firmware.
+ *
+ * Revision 1.3 1997/09/24 19:44:14 fritz
+ * Added MSN mapping support, some cleanup.
+ *
+ * Revision 1.2 1997/09/23 19:41:24 fritz
+ * Disabled Logging of DATA_B3_IND/RESP/REQ/CONF Messages.
+ *
+ * Revision 1.1 1997/09/23 18:00:08 fritz
+ * New driver for IBM Active 2000.
+ *
+ */
+
+#define __NO_VERSION__
+#include "act2000.h"
+#include "capi.h"
+
+static actcapi_msgdsc valid_msg[] = {
+ {{ 0x86, 0x02}, "DATA_B3_IND"}, /* DATA_B3_IND/CONF must be first because of speed!!! */
+ {{ 0x86, 0x01}, "DATA_B3_CONF"},
+ {{ 0x02, 0x01}, "CONNECT_CONF"},
+ {{ 0x02, 0x02}, "CONNECT_IND"},
+ {{ 0x09, 0x01}, "CONNECT_INFO_CONF"},
+ {{ 0x03, 0x02}, "CONNECT_ACTIVE_IND"},
+ {{ 0x04, 0x01}, "DISCONNECT_CONF"},
+ {{ 0x04, 0x02}, "DISCONNECT_IND"},
+ {{ 0x05, 0x01}, "LISTEN_CONF"},
+ {{ 0x06, 0x01}, "GET_PARAMS_CONF"},
+ {{ 0x07, 0x01}, "INFO_CONF"},
+ {{ 0x07, 0x02}, "INFO_IND"},
+ {{ 0x08, 0x01}, "DATA_CONF"},
+ {{ 0x08, 0x02}, "DATA_IND"},
+ {{ 0x40, 0x01}, "SELECT_B2_PROTOCOL_CONF"},
+ {{ 0x80, 0x01}, "SELECT_B3_PROTOCOL_CONF"},
+ {{ 0x81, 0x01}, "LISTEN_B3_CONF"},
+ {{ 0x82, 0x01}, "CONNECT_B3_CONF"},
+ {{ 0x82, 0x02}, "CONNECT_B3_IND"},
+ {{ 0x83, 0x02}, "CONNECT_B3_ACTIVE_IND"},
+ {{ 0x84, 0x01}, "DISCONNECT_B3_CONF"},
+ {{ 0x84, 0x02}, "DISCONNECT_B3_IND"},
+ {{ 0x85, 0x01}, "GET_B3_PARAMS_CONF"},
+ {{ 0x01, 0x01}, "RESET_B3_CONF"},
+ {{ 0x01, 0x02}, "RESET_B3_IND"},
+ /* {{ 0x87, 0x02, "HANDSET_IND"}, not implemented */
+ {{ 0xff, 0x01}, "MANUFACTURER_CONF"},
+ {{ 0xff, 0x02}, "MANUFACTURER_IND"},
+#ifdef DEBUG_MSG
+ /* Requests */
+ {{ 0x01, 0x00}, "RESET_B3_REQ"},
+ {{ 0x02, 0x00}, "CONNECT_REQ"},
+ {{ 0x04, 0x00}, "DISCONNECT_REQ"},
+ {{ 0x05, 0x00}, "LISTEN_REQ"},
+ {{ 0x06, 0x00}, "GET_PARAMS_REQ"},
+ {{ 0x07, 0x00}, "INFO_REQ"},
+ {{ 0x08, 0x00}, "DATA_REQ"},
+ {{ 0x09, 0x00}, "CONNECT_INFO_REQ"},
+ {{ 0x40, 0x00}, "SELECT_B2_PROTOCOL_REQ"},
+ {{ 0x80, 0x00}, "SELECT_B3_PROTOCOL_REQ"},
+ {{ 0x81, 0x00}, "LISTEN_B3_REQ"},
+ {{ 0x82, 0x00}, "CONNECT_B3_REQ"},
+ {{ 0x84, 0x00}, "DISCONNECT_B3_REQ"},
+ {{ 0x85, 0x00}, "GET_B3_PARAMS_REQ"},
+ {{ 0x86, 0x00}, "DATA_B3_REQ"},
+ {{ 0xff, 0x00}, "MANUFACTURER_REQ"},
+ /* Responses */
+ {{ 0x01, 0x03}, "RESET_B3_RESP"},
+ {{ 0x02, 0x03}, "CONNECT_RESP"},
+ {{ 0x03, 0x03}, "CONNECT_ACTIVE_RESP"},
+ {{ 0x04, 0x03}, "DISCONNECT_RESP"},
+ {{ 0x07, 0x03}, "INFO_RESP"},
+ {{ 0x08, 0x03}, "DATA_RESP"},
+ {{ 0x82, 0x03}, "CONNECT_B3_RESP"},
+ {{ 0x83, 0x03}, "CONNECT_B3_ACTIVE_RESP"},
+ {{ 0x84, 0x03}, "DISCONNECT_B3_RESP"},
+ {{ 0x86, 0x03}, "DATA_B3_RESP"},
+ {{ 0xff, 0x03}, "MANUFACTURER_RESP"},
+#if 0
+/* CAPI 2.0 */
+ {{ 0x05, 0x80}, "LISTEN_REQ (CAPI 2.0)"},
+#endif
+#endif
+ {{ 0x00, 0x00}, NULL},
+};
+#define num_valid_msg (sizeof(valid_msg)/sizeof(actcapi_msgdsc))
+#define num_valid_imsg 27 /* MANUFACTURER_IND */
+
+/*
+ * Check for a valid incoming CAPI message.
+ * Return:
+ * 0 = Invalid message
+ * 1 = Valid message, no B-Channel-data
+ * 2 = Valid message, B-Channel-data
+ */
+int
+actcapi_chkhdr(act2000_card * card, actcapi_msghdr *hdr)
+{
+ int i;
+
+ if (hdr->applicationID != 1)
+ return 0;
+ if (hdr->len < 9)
+ return 0;
+ for (i = 0; i < num_valid_imsg; i++)
+ if ((hdr->cmd.cmd == valid_msg[i].cmd.cmd) &&
+ (hdr->cmd.subcmd == valid_msg[i].cmd.subcmd)) {
+ return (i?1:2);
+ }
+ return 0;
+}
+
+#define ACTCAPI_MKHDR(l, c, s) { \
+ skb = alloc_skb(l + 8, GFP_ATOMIC); \
+ if (skb) { \
+ m = (actcapi_msg *)skb_put(skb, l + 8); \
+ m->hdr.len = l + 8; \
+ m->hdr.applicationID = 1; \
+ m->hdr.cmd.cmd = c; \
+ m->hdr.cmd.subcmd = s; \
+ m->hdr.msgnum = actcapi_nextsmsg(card); \
+ } \
+}
+
+#define ACTCAPI_CHKSKB if (!skb) { \
+ printk(KERN_WARNING "actcapi: alloc_skb failed\n"); \
+ return; \
+}
+
+#define ACTCAPI_QUEUE_TX { \
+ actcapi_debug_msg(skb, 1); \
+ skb_queue_tail(&card->sndq, skb); \
+ act2000_schedule_tx(card); \
+}
+
+int
+actcapi_listen_req(act2000_card *card)
+{
+ __u16 eazmask = 0;
+ int i;
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ for (i = 0; i < ACT2000_BCH; i++)
+ eazmask |= card->bch[i].eazmask;
+ ACTCAPI_MKHDR(9, 0x05, 0x00);
+ if (!skb) {
+ printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+ return -ENOMEM;
+ }
+ m->msg.listen_req.controller = 0;
+ m->msg.listen_req.infomask = 0x3f; /* All information */
+ m->msg.listen_req.eazmask = eazmask;
+ m->msg.listen_req.simask = (eazmask)?0x86:0; /* All SI's */
+ ACTCAPI_QUEUE_TX;
+ return 0;
+}
+
+int
+actcapi_connect_req(act2000_card *card, act2000_chan *chan, char *phone,
+ char eaz, int si1, int si2)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR((11 + strlen(phone)), 0x02, 0x00);
+ if (!skb) {
+ printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+ chan->fsm_state = ACT2000_STATE_NULL;
+ return -ENOMEM;
+ }
+ m->msg.connect_req.controller = 0;
+ m->msg.connect_req.bchan = 0x83;
+ m->msg.connect_req.infomask = 0x3f;
+ m->msg.connect_req.si1 = si1;
+ m->msg.connect_req.si2 = si2;
+ m->msg.connect_req.eaz = eaz?eaz:'0';
+ m->msg.connect_req.addr.len = strlen(phone) + 1;
+ m->msg.connect_req.addr.tnp = 0x81;
+ memcpy(m->msg.connect_req.addr.num, phone, strlen(phone));
+ chan->callref = m->hdr.msgnum;
+ ACTCAPI_QUEUE_TX;
+ return 0;
+}
+
+static void
+actcapi_connect_b3_req(act2000_card *card, act2000_chan *chan)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(17, 0x82, 0x00);
+ ACTCAPI_CHKSKB;
+ m->msg.connect_b3_req.plci = chan->plci;
+ memset(&m->msg.connect_b3_req.ncpi, 0,
+ sizeof(m->msg.connect_b3_req.ncpi));
+ m->msg.connect_b3_req.ncpi.len = 13;
+ m->msg.connect_b3_req.ncpi.modulo = 8;
+ ACTCAPI_QUEUE_TX;
+}
+
+/*
+ * Set net type (1TR6) or (EDSS1)
+ */
+int
+actcapi_manufacturer_req_net(act2000_card *card)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(5, 0xff, 0x00);
+ if (!skb) {
+ printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+ return -ENOMEM;
+ }
+ m->msg.manufacturer_req_net.manuf_msg = 0x11;
+ m->msg.manufacturer_req_net.controller = 1;
+ m->msg.manufacturer_req_net.nettype = (card->ptype == ISDN_PTYPE_EURO)?1:0;
+ ACTCAPI_QUEUE_TX;
+ printk(KERN_INFO "act2000 %s: D-channel protocol now %s\n",
+ card->interface.id, (card->ptype == ISDN_PTYPE_EURO)?"euro":"1tr6");
+ card->interface.features &=
+ ~(ISDN_FEATURE_P_UNKNOWN | ISDN_FEATURE_P_EURO | ISDN_FEATURE_P_1TR6);
+ card->interface.features |=
+ ((card->ptype == ISDN_PTYPE_EURO)?ISDN_FEATURE_P_EURO:ISDN_FEATURE_P_1TR6);
+ return 0;
+}
+
+/*
+ * Switch V.42 on or off
+ */
+int
+actcapi_manufacturer_req_v42(act2000_card *card, ulong arg)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(8, 0xff, 0x00);
+ if (!skb) {
+
+ printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+ return -ENOMEM;
+ }
+ m->msg.manufacturer_req_v42.manuf_msg = 0x10;
+ m->msg.manufacturer_req_v42.controller = 0;
+ m->msg.manufacturer_req_v42.v42control = (arg?1:0);
+ ACTCAPI_QUEUE_TX;
+ return 0;
+}
+
+/*
+ * Set error-handler
+ */
+int
+actcapi_manufacturer_req_errh(act2000_card *card)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(4, 0xff, 0x00);
+ if (!skb) {
+
+ printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+ return -ENOMEM;
+ }
+ m->msg.manufacturer_req_err.manuf_msg = 0x03;
+ m->msg.manufacturer_req_err.controller = 0;
+ ACTCAPI_QUEUE_TX;
+ return 0;
+}
+
+/*
+ * Set MSN-Mapping.
+ */
+int
+actcapi_manufacturer_req_msn(act2000_card *card)
+{
+ msn_entry *p = card->msn_list;
+ actcapi_msg *m;
+ struct sk_buff *skb;
+ int len;
+
+ while (p) {
+ int i;
+
+ len = strlen(p->msn);
+ for (i = 0; i < 2; i++) {
+ ACTCAPI_MKHDR(6 + len, 0xff, 0x00);
+ if (!skb) {
+ printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+ return -ENOMEM;
+ }
+ m->msg.manufacturer_req_msn.manuf_msg = 0x13 + i;
+ m->msg.manufacturer_req_msn.controller = 0;
+ m->msg.manufacturer_req_msn.msnmap.eaz = p->eaz;
+ m->msg.manufacturer_req_msn.msnmap.len = len;
+ memcpy(m->msg.manufacturer_req_msn.msnmap.msn, p->msn, len);
+ ACTCAPI_QUEUE_TX;
+ }
+ p = p->next;
+ }
+ return 0;
+}
+
+void
+actcapi_select_b2_protocol_req(act2000_card *card, act2000_chan *chan)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(10, 0x40, 0x00);
+ ACTCAPI_CHKSKB;
+ m->msg.select_b2_protocol_req.plci = chan->plci;
+ memset(&m->msg.select_b2_protocol_req.dlpd, 0,
+ sizeof(m->msg.select_b2_protocol_req.dlpd));
+ m->msg.select_b2_protocol_req.dlpd.len = 6;
+ switch (chan->l2prot) {
+ case ISDN_PROTO_L2_TRANS:
+ m->msg.select_b2_protocol_req.protocol = 0x03;
+ m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
+ break;
+ case ISDN_PROTO_L2_HDLC:
+ m->msg.select_b2_protocol_req.protocol = 0x02;
+ m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
+ break;
+ case ISDN_PROTO_L2_X75I:
+ case ISDN_PROTO_L2_X75UI:
+ case ISDN_PROTO_L2_X75BUI:
+ m->msg.select_b2_protocol_req.protocol = 0x01;
+ m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
+ m->msg.select_b2_protocol_req.dlpd.laa = 3;
+ m->msg.select_b2_protocol_req.dlpd.lab = 1;
+ m->msg.select_b2_protocol_req.dlpd.win = 7;
+ m->msg.select_b2_protocol_req.dlpd.modulo = 8;
+ break;
+ }
+ ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_select_b3_protocol_req(act2000_card *card, act2000_chan *chan)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(17, 0x80, 0x00);
+ ACTCAPI_CHKSKB;
+ m->msg.select_b3_protocol_req.plci = chan->plci;
+ memset(&m->msg.select_b3_protocol_req.ncpd, 0,
+ sizeof(m->msg.select_b3_protocol_req.ncpd));
+ switch (chan->l3prot) {
+ case ISDN_PROTO_L3_TRANS:
+ m->msg.select_b3_protocol_req.protocol = 0x04;
+ m->msg.select_b3_protocol_req.ncpd.len = 13;
+ m->msg.select_b3_protocol_req.ncpd.modulo = 8;
+ break;
+ }
+ ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_listen_b3_req(act2000_card *card, act2000_chan *chan)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(2, 0x81, 0x00);
+ ACTCAPI_CHKSKB;
+ m->msg.listen_b3_req.plci = chan->plci;
+ ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_disconnect_req(act2000_card *card, act2000_chan *chan)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(3, 0x04, 0x00);
+ ACTCAPI_CHKSKB;
+ m->msg.disconnect_req.plci = chan->plci;
+ m->msg.disconnect_req.cause = 0;
+ ACTCAPI_QUEUE_TX;
+}
+
+void
+actcapi_disconnect_b3_req(act2000_card *card, act2000_chan *chan)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(17, 0x84, 0x00);
+ ACTCAPI_CHKSKB;
+ m->msg.disconnect_b3_req.ncci = chan->ncci;
+ memset(&m->msg.disconnect_b3_req.ncpi, 0,
+ sizeof(m->msg.disconnect_b3_req.ncpi));
+ m->msg.disconnect_b3_req.ncpi.len = 13;
+ m->msg.disconnect_b3_req.ncpi.modulo = 8;
+ chan->fsm_state = ACT2000_STATE_BHWAIT;
+ ACTCAPI_QUEUE_TX;
+}
+
+void
+actcapi_connect_resp(act2000_card *card, act2000_chan *chan, __u8 cause)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(3, 0x02, 0x03);
+ ACTCAPI_CHKSKB;
+ m->msg.connect_resp.plci = chan->plci;
+ m->msg.connect_resp.rejectcause = cause;
+ if (cause) {
+ chan->fsm_state = ACT2000_STATE_NULL;
+ chan->plci = 0x8000;
+ } else
+ chan->fsm_state = ACT2000_STATE_IWAIT;
+ ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_connect_active_resp(act2000_card *card, act2000_chan *chan)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(2, 0x03, 0x03);
+ ACTCAPI_CHKSKB;
+ m->msg.connect_resp.plci = chan->plci;
+ if (chan->fsm_state == ACT2000_STATE_IWAIT)
+ chan->fsm_state = ACT2000_STATE_IBWAIT;
+ ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_connect_b3_resp(act2000_card *card, act2000_chan *chan, __u8 rejectcause)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR((rejectcause?3:17), 0x82, 0x03);
+ ACTCAPI_CHKSKB;
+ m->msg.connect_b3_resp.ncci = chan->ncci;
+ m->msg.connect_b3_resp.rejectcause = rejectcause;
+ if (!rejectcause) {
+ memset(&m->msg.connect_b3_resp.ncpi, 0,
+ sizeof(m->msg.connect_b3_resp.ncpi));
+ m->msg.connect_b3_resp.ncpi.len = 13;
+ m->msg.connect_b3_resp.ncpi.modulo = 8;
+ chan->fsm_state = ACT2000_STATE_BWAIT;
+ }
+ ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_connect_b3_active_resp(act2000_card *card, act2000_chan *chan)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(2, 0x83, 0x03);
+ ACTCAPI_CHKSKB;
+ m->msg.connect_b3_active_resp.ncci = chan->ncci;
+ chan->fsm_state = ACT2000_STATE_ACTIVE;
+ ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_info_resp(act2000_card *card, act2000_chan *chan)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(2, 0x07, 0x03);
+ ACTCAPI_CHKSKB;
+ m->msg.info_resp.plci = chan->plci;
+ ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_disconnect_b3_resp(act2000_card *card, act2000_chan *chan)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(2, 0x84, 0x03);
+ ACTCAPI_CHKSKB;
+ m->msg.disconnect_b3_resp.ncci = chan->ncci;
+ chan->ncci = 0x8000;
+ chan->queued = 0;
+ ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_disconnect_resp(act2000_card *card, act2000_chan *chan)
+{
+ actcapi_msg *m;
+ struct sk_buff *skb;
+
+ ACTCAPI_MKHDR(2, 0x04, 0x03);
+ ACTCAPI_CHKSKB;
+ m->msg.disconnect_resp.plci = chan->plci;
+ chan->plci = 0x8000;
+ ACTCAPI_QUEUE_TX;
+}
+
+static int
+new_plci(act2000_card *card, __u16 plci)
+{
+ int i;
+ for (i = 0; i < ACT2000_BCH; i++)
+ if (card->bch[i].plci == 0x8000) {
+ card->bch[i].plci = plci;
+ return i;
+ }
+ return -1;
+}
+
+static int
+find_plci(act2000_card *card, __u16 plci)
+{
+ int i;
+ for (i = 0; i < ACT2000_BCH; i++)
+ if (card->bch[i].plci == plci)
+ return i;
+ return -1;
+}
+
+static int
+find_ncci(act2000_card *card, __u16 ncci)
+{
+ int i;
+ for (i = 0; i < ACT2000_BCH; i++)
+ if (card->bch[i].ncci == ncci)
+ return i;
+ return -1;
+}
+
+static int
+find_dialing(act2000_card *card, __u16 callref)
+{
+ int i;
+ for (i = 0; i < ACT2000_BCH; i++)
+ if ((card->bch[i].callref == callref) &&
+ (card->bch[i].fsm_state == ACT2000_STATE_OCALL))
+ return i;
+ return -1;
+}
+
+static int
+actcapi_data_b3_ind(act2000_card *card, struct sk_buff *skb) {
+ __u16 plci;
+ __u16 ncci;
+ __u16 controller;
+ __u8 blocknr;
+ int chan;
+ actcapi_msg *msg = (actcapi_msg *)skb->data;
+
+ EVAL_NCCI(msg->msg.data_b3_ind.fakencci, plci, controller, ncci);
+ chan = find_ncci(card, ncci);
+ if (chan < 0)
+ return 0;
+ if (card->bch[chan].fsm_state != ACT2000_STATE_ACTIVE)
+ return 0;
+ if (card->bch[chan].plci != plci)
+ return 0;
+ blocknr = msg->msg.data_b3_ind.blocknr;
+ skb_pull(skb, 19);
+ card->interface.rcvcallb_skb(card->myid, chan, skb);
+ if (!(skb = alloc_skb(11, GFP_ATOMIC))) {
+ printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+ return 1;
+ }
+ msg = (actcapi_msg *)skb_put(skb, 11);
+ msg->hdr.len = 11;
+ msg->hdr.applicationID = 1;
+ msg->hdr.cmd.cmd = 0x86;
+ msg->hdr.cmd.subcmd = 0x03;
+ msg->hdr.msgnum = actcapi_nextsmsg(card);
+ msg->msg.data_b3_resp.ncci = ncci;
+ msg->msg.data_b3_resp.blocknr = blocknr;
+ ACTCAPI_QUEUE_TX;
+ return 1;
+}
+
+/*
+ * Walk over ackq, unlink DATA_B3_REQ from it, if
+ * ncci and blocknr are matching.
+ * Decrement queued-bytes counter.
+ */
+static int
+handle_ack(act2000_card *card, act2000_chan *chan, __u8 blocknr) {
+ unsigned long flags;
+ struct sk_buff *skb;
+ struct sk_buff *tmp;
+ struct actcapi_msg *m;
+ int ret = 0;
+
+ save_flags(flags);
+ cli();
+ skb = skb_peek(&card->ackq);
+ restore_flags(flags);
+ if (!skb) {
+ printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
+ return 0;
+ }
+ tmp = skb;
+ while (1) {
+ m = (actcapi_msg *)tmp->data;
+ if ((((m->msg.data_b3_req.fakencci >> 8) & 0xff) == chan->ncci) &&
+ (m->msg.data_b3_req.blocknr == blocknr)) {
+ /* found corresponding DATA_B3_REQ */
+ skb_unlink(tmp);
+ chan->queued -= m->msg.data_b3_req.datalen;
+ if (m->msg.data_b3_req.flags)
+ ret = m->msg.data_b3_req.datalen;
+ dev_kfree_skb(tmp);
+ if (chan->queued < 0)
+ chan->queued = 0;
+ return ret;
+ }
+ save_flags(flags);
+ cli();
+ tmp = skb_peek((struct sk_buff_head *)tmp);
+ restore_flags(flags);
+ if ((tmp == skb) || (tmp == NULL)) {
+ /* reached end of queue */
+ printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
+ return 0;
+ }
+ }
+}
+
+void
+actcapi_dispatch(act2000_card *card)
+{
+ struct sk_buff *skb;
+ actcapi_msg *msg;
+ __u16 ccmd;
+ int chan;
+ int len;
+ act2000_chan *ctmp;
+ isdn_ctrl cmd;
+ char tmp[170];
+
+ while ((skb = skb_dequeue(&card->rcvq))) {
+ actcapi_debug_msg(skb, 0);
+ msg = (actcapi_msg *)skb->data;
+ ccmd = ((msg->hdr.cmd.cmd << 8) | msg->hdr.cmd.subcmd);
+ switch (ccmd) {
+ case 0x8602:
+ /* DATA_B3_IND */
+ if (actcapi_data_b3_ind(card, skb))
+ return;
+ break;
+ case 0x8601:
+ /* DATA_B3_CONF */
+ chan = find_ncci(card, msg->msg.data_b3_conf.ncci);
+ if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_ACTIVE)) {
+ if (msg->msg.data_b3_conf.info != 0)
+ printk(KERN_WARNING "act2000: DATA_B3_CONF: %04x\n",
+ msg->msg.data_b3_conf.info);
+ len = handle_ack(card, &card->bch[chan],
+ msg->msg.data_b3_conf.blocknr);
+ if (len) {
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_BSENT;
+ cmd.arg = chan;
+ cmd.parm.length = len;
+ card->interface.statcallb(&cmd);
+ }
+ }
+ break;
+ case 0x0201:
+ /* CONNECT_CONF */
+ chan = find_dialing(card, msg->hdr.msgnum);
+ if (chan >= 0) {
+ if (msg->msg.connect_conf.info) {
+ card->bch[chan].fsm_state = ACT2000_STATE_NULL;
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = chan;
+ card->interface.statcallb(&cmd);
+ } else {
+ card->bch[chan].fsm_state = ACT2000_STATE_OWAIT;
+ card->bch[chan].plci = msg->msg.connect_conf.plci;
+ }
+ }
+ break;
+ case 0x0202:
+ /* CONNECT_IND */
+ chan = new_plci(card, msg->msg.connect_ind.plci);
+ if (chan < 0) {
+ ctmp = (act2000_chan *)tmp;
+ ctmp->plci = msg->msg.connect_ind.plci;
+ actcapi_connect_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
+ } else {
+ card->bch[chan].fsm_state = ACT2000_STATE_ICALL;
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_ICALL;
+ cmd.arg = chan;
+ cmd.parm.setup.si1 = msg->msg.connect_ind.si1;
+ cmd.parm.setup.si2 = msg->msg.connect_ind.si2;
+ if (card->ptype == ISDN_PTYPE_EURO)
+ strcpy(cmd.parm.setup.eazmsn,
+ act2000_find_eaz(card, msg->msg.connect_ind.eaz));
+ else {
+ cmd.parm.setup.eazmsn[0] = msg->msg.connect_ind.eaz;
+ cmd.parm.setup.eazmsn[1] = 0;
+ }
+ memset(cmd.parm.setup.phone, 0, sizeof(cmd.parm.setup.phone));
+ memcpy(cmd.parm.setup.phone, msg->msg.connect_ind.addr.num,
+ msg->msg.connect_ind.addr.len - 1);
+ cmd.parm.setup.plan = msg->msg.connect_ind.addr.tnp;
+ cmd.parm.setup.screen = 0;
+ if (card->interface.statcallb(&cmd) == 2)
+ actcapi_connect_resp(card, &card->bch[chan], 0x15); /* Reject Call */
+ }
+ break;
+ case 0x0302:
+ /* CONNECT_ACTIVE_IND */
+ chan = find_plci(card, msg->msg.connect_active_ind.plci);
+ if (chan >= 0)
+ switch (card->bch[chan].fsm_state) {
+ case ACT2000_STATE_IWAIT:
+ actcapi_connect_active_resp(card, &card->bch[chan]);
+ break;
+ case ACT2000_STATE_OWAIT:
+ actcapi_connect_active_resp(card, &card->bch[chan]);
+ actcapi_select_b2_protocol_req(card, &card->bch[chan]);
+ break;
+ }
+ break;
+ case 0x8202:
+ /* CONNECT_B3_IND */
+ chan = find_plci(card, msg->msg.connect_b3_ind.plci);
+ if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_IBWAIT)) {
+ card->bch[chan].ncci = msg->msg.connect_b3_ind.ncci;
+ actcapi_connect_b3_resp(card, &card->bch[chan], 0);
+ } else {
+ ctmp = (act2000_chan *)tmp;
+ ctmp->ncci = msg->msg.connect_b3_ind.ncci;
+ actcapi_connect_b3_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
+ }
+ break;
+ case 0x8302:
+ /* CONNECT_B3_ACTIVE_IND */
+ chan = find_ncci(card, msg->msg.connect_b3_active_ind.ncci);
+ if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BWAIT)) {
+ actcapi_connect_b3_active_resp(card, &card->bch[chan]);
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_BCONN;
+ cmd.arg = chan;
+ card->interface.statcallb(&cmd);
+ }
+ break;
+ case 0x8402:
+ /* DISCONNECT_B3_IND */
+ chan = find_ncci(card, msg->msg.disconnect_b3_ind.ncci);
+ if (chan >= 0) {
+ ctmp = &card->bch[chan];
+ actcapi_disconnect_b3_resp(card, ctmp);
+ switch (ctmp->fsm_state) {
+ case ACT2000_STATE_ACTIVE:
+ ctmp->fsm_state = ACT2000_STATE_DHWAIT2;
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_BHUP;
+ cmd.arg = chan;
+ card->interface.statcallb(&cmd);
+ break;
+ case ACT2000_STATE_BHWAIT2:
+ actcapi_disconnect_req(card, ctmp);
+ ctmp->fsm_state = ACT2000_STATE_DHWAIT;
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_BHUP;
+ cmd.arg = chan;
+ card->interface.statcallb(&cmd);
+ break;
+ }
+ }
+ break;
+ case 0x0402:
+ /* DISCONNECT_IND */
+ chan = find_plci(card, msg->msg.disconnect_ind.plci);
+ if (chan >= 0) {
+ ctmp = &card->bch[chan];
+ actcapi_disconnect_resp(card, ctmp);
+ ctmp->fsm_state = ACT2000_STATE_NULL;
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = chan;
+ card->interface.statcallb(&cmd);
+ } else {
+ ctmp = (act2000_chan *)tmp;
+ ctmp->plci = msg->msg.disconnect_ind.plci;
+ actcapi_disconnect_resp(card, ctmp);
+ }
+ break;
+ case 0x4001:
+ /* SELECT_B2_PROTOCOL_CONF */
+ chan = find_plci(card, msg->msg.select_b2_protocol_conf.plci);
+ if (chan >= 0)
+ switch (card->bch[chan].fsm_state) {
+ case ACT2000_STATE_ICALL:
+ case ACT2000_STATE_OWAIT:
+ ctmp = &card->bch[chan];
+ if (msg->msg.select_b2_protocol_conf.info == 0)
+ actcapi_select_b3_protocol_req(card, ctmp);
+ else {
+ ctmp->fsm_state = ACT2000_STATE_NULL;
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = chan;
+ card->interface.statcallb(&cmd);
+ }
+ break;
+ }
+ break;
+ case 0x8001:
+ /* SELECT_B3_PROTOCOL_CONF */
+ chan = find_plci(card, msg->msg.select_b3_protocol_conf.plci);
+ if (chan >= 0)
+ switch (card->bch[chan].fsm_state) {
+ case ACT2000_STATE_ICALL:
+ case ACT2000_STATE_OWAIT:
+ ctmp = &card->bch[chan];
+ if (msg->msg.select_b3_protocol_conf.info == 0)
+ actcapi_listen_b3_req(card, ctmp);
+ else {
+ ctmp->fsm_state = ACT2000_STATE_NULL;
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = chan;
+ card->interface.statcallb(&cmd);
+ }
+ }
+ break;
+ case 0x8101:
+ /* LISTEN_B3_CONF */
+ chan = find_plci(card, msg->msg.listen_b3_conf.plci);
+ if (chan >= 0)
+ switch (card->bch[chan].fsm_state) {
+ case ACT2000_STATE_ICALL:
+ ctmp = &card->bch[chan];
+ if (msg->msg.listen_b3_conf.info == 0)
+ actcapi_connect_resp(card, ctmp, 0);
+ else {
+ ctmp->fsm_state = ACT2000_STATE_NULL;
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = chan;
+ card->interface.statcallb(&cmd);
+ }
+ break;
+ case ACT2000_STATE_OWAIT:
+ ctmp = &card->bch[chan];
+ if (msg->msg.listen_b3_conf.info == 0) {
+ actcapi_connect_b3_req(card, ctmp);
+ ctmp->fsm_state = ACT2000_STATE_OBWAIT;
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_DCONN;
+ cmd.arg = chan;
+ card->interface.statcallb(&cmd);
+ } else {
+ ctmp->fsm_state = ACT2000_STATE_NULL;
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = chan;
+ card->interface.statcallb(&cmd);
+ }
+ break;
+ }
+ break;
+ case 0x8201:
+ /* CONNECT_B3_CONF */
+ chan = find_plci(card, msg->msg.connect_b3_conf.plci);
+ if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_OBWAIT)) {
+ ctmp = &card->bch[chan];
+ if (msg->msg.connect_b3_conf.info) {
+ ctmp->fsm_state = ACT2000_STATE_NULL;
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = chan;
+ card->interface.statcallb(&cmd);
+ } else {
+ ctmp->ncci = msg->msg.connect_b3_conf.ncci;
+ ctmp->fsm_state = ACT2000_STATE_BWAIT;
+ }
+ }
+ break;
+ case 0x8401:
+ /* DISCONNECT_B3_CONF */
+ chan = find_ncci(card, msg->msg.disconnect_b3_conf.ncci);
+ if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BHWAIT))
+ card->bch[chan].fsm_state = ACT2000_STATE_BHWAIT2;
+ break;
+ case 0x0702:
+ /* INFO_IND */
+ chan = find_plci(card, msg->msg.info_ind.plci);
+ if (chan >= 0)
+ /* TODO: Eval Charging info / cause */
+ actcapi_info_resp(card, &card->bch[chan]);
+ break;
+ case 0x0401:
+ /* LISTEN_CONF */
+ case 0x0501:
+ /* LISTEN_CONF */
+ case 0xff01:
+ /* MANUFACTURER_CONF */
+ break;
+ case 0xff02:
+ /* MANUFACTURER_IND */
+ if (msg->msg.manuf_msg == 3) {
+ memset(tmp, 0, sizeof(tmp));
+ strncpy(tmp,
+ &msg->msg.manufacturer_ind_err.errstring,
+ msg->hdr.len - 16);
+ if (msg->msg.manufacturer_ind_err.errcode)
+ printk(KERN_WARNING "act2000: %s\n", tmp);
+ else {
+ printk(KERN_DEBUG "act2000: %s\n", tmp);
+ if ((!strncmp(tmp, "INFO: Trace buffer con", 22)) ||
+ (!strncmp(tmp, "INFO: Compile Date/Tim", 22))) {
+ card->flags |= ACT2000_FLAGS_RUNNING;
+ cmd.command = ISDN_STAT_RUN;
+ cmd.driver = card->myid;
+ cmd.arg = 0;
+ actcapi_manufacturer_req_net(card);
+ actcapi_manufacturer_req_msn(card);
+ actcapi_listen_req(card);
+ card->interface.statcallb(&cmd);
+ }
+ }
+ }
+ break;
+ default:
+ printk(KERN_WARNING "act2000: UNHANDLED Message %04x\n", ccmd);
+ break;
+ }
+ dev_kfree_skb(skb);
+ }
+}
+
+#ifdef DEBUG_MSG
+static void
+actcapi_debug_caddr(actcapi_addr *addr)
+{
+ char tmp[30];
+
+ printk(KERN_DEBUG " Alen = %d\n", addr->len);
+ if (addr->len > 0)
+ printk(KERN_DEBUG " Atnp = 0x%02x\n", addr->tnp);
+ if (addr->len > 1) {
+ memset(tmp, 0, 30);
+ memcpy(tmp, addr->num, addr->len - 1);
+ printk(KERN_DEBUG " Anum = '%s'\n", tmp);
+ }
+}
+
+static void
+actcapi_debug_ncpi(actcapi_ncpi *ncpi)
+{
+ printk(KERN_DEBUG " ncpi.len = %d\n", ncpi->len);
+ if (ncpi->len >= 2)
+ printk(KERN_DEBUG " ncpi.lic = 0x%04x\n", ncpi->lic);
+ if (ncpi->len >= 4)
+ printk(KERN_DEBUG " ncpi.hic = 0x%04x\n", ncpi->hic);
+ if (ncpi->len >= 6)
+ printk(KERN_DEBUG " ncpi.ltc = 0x%04x\n", ncpi->ltc);
+ if (ncpi->len >= 8)
+ printk(KERN_DEBUG " ncpi.htc = 0x%04x\n", ncpi->htc);
+ if (ncpi->len >= 10)
+ printk(KERN_DEBUG " ncpi.loc = 0x%04x\n", ncpi->loc);
+ if (ncpi->len >= 12)
+ printk(KERN_DEBUG " ncpi.hoc = 0x%04x\n", ncpi->hoc);
+ if (ncpi->len >= 13)
+ printk(KERN_DEBUG " ncpi.mod = %d\n", ncpi->modulo);
+}
+
+static void
+actcapi_debug_dlpd(actcapi_dlpd *dlpd)
+{
+ printk(KERN_DEBUG " dlpd.len = %d\n", dlpd->len);
+ if (dlpd->len >= 2)
+ printk(KERN_DEBUG " dlpd.dlen = 0x%04x\n", dlpd->dlen);
+ if (dlpd->len >= 3)
+ printk(KERN_DEBUG " dlpd.laa = 0x%02x\n", dlpd->laa);
+ if (dlpd->len >= 4)
+ printk(KERN_DEBUG " dlpd.lab = 0x%02x\n", dlpd->lab);
+ if (dlpd->len >= 5)
+ printk(KERN_DEBUG " dlpd.modulo = %d\n", dlpd->modulo);
+ if (dlpd->len >= 6)
+ printk(KERN_DEBUG " dlpd.win = %d\n", dlpd->win);
+}
+
+#ifdef DEBUG_DUMP_SKB
+static void dump_skb(struct sk_buff *skb) {
+ char tmp[80];
+ char *p = skb->data;
+ char *t = tmp;
+ int i;
+
+ for (i = 0; i < skb->len; i++) {
+ t += sprintf(t, "%02x ", *p++ & 0xff);
+ if ((i & 0x0f) == 8) {
+ printk(KERN_DEBUG "dump: %s\n", tmp);
+ t = tmp;
+ }
+ }
+ if (i & 0x07)
+ printk(KERN_DEBUG "dump: %s\n", tmp);
+}
+#endif
+
+void
+actcapi_debug_msg(struct sk_buff *skb, int direction)
+{
+ actcapi_msg *msg = (actcapi_msg *)skb->data;
+ char *descr;
+ int i;
+ char tmp[170];
+
+#ifndef DEBUG_DATA_MSG
+ if (msg->hdr.cmd.cmd == 0x86)
+ return;
+#endif
+ descr = "INVALID";
+#ifdef DEBUG_DUMP_SKB
+ dump_skb(skb);
+#endif
+ for (i = 0; i < num_valid_msg; i++)
+ if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) &&
+ (msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) {
+ descr = valid_msg[i].description;
+ break;
+ }
+ printk(KERN_DEBUG "%s %s msg\n", direction?"Outgoing":"Incoming", descr);
+ printk(KERN_DEBUG " ApplID = %d\n", msg->hdr.applicationID);
+ printk(KERN_DEBUG " Len = %d\n", msg->hdr.len);
+ printk(KERN_DEBUG " MsgNum = 0x%04x\n", msg->hdr.msgnum);
+ printk(KERN_DEBUG " Cmd = 0x%02x\n", msg->hdr.cmd.cmd);
+ printk(KERN_DEBUG " SubCmd = 0x%02x\n", msg->hdr.cmd.subcmd);
+ switch (i) {
+ case 0:
+ /* DATA B3 IND */
+ printk(KERN_DEBUG " BLOCK = 0x%02x\n",
+ msg->msg.data_b3_ind.blocknr);
+ break;
+ case 2:
+ /* CONNECT CONF */
+ printk(KERN_DEBUG " PLCI = 0x%04x\n",
+ msg->msg.connect_conf.plci);
+ printk(KERN_DEBUG " Info = 0x%04x\n",
+ msg->msg.connect_conf.info);
+ break;
+ case 3:
+ /* CONNECT IND */
+ printk(KERN_DEBUG " PLCI = 0x%04x\n",
+ msg->msg.connect_ind.plci);
+ printk(KERN_DEBUG " Contr = %d\n",
+ msg->msg.connect_ind.controller);
+ printk(KERN_DEBUG " SI1 = %d\n",
+ msg->msg.connect_ind.si1);
+ printk(KERN_DEBUG " SI2 = %d\n",
+ msg->msg.connect_ind.si2);
+ printk(KERN_DEBUG " EAZ = '%c'\n",
+ msg->msg.connect_ind.eaz);
+ actcapi_debug_caddr(&msg->msg.connect_ind.addr);
+ break;
+ case 5:
+ /* CONNECT ACTIVE IND */
+ printk(KERN_DEBUG " PLCI = 0x%04x\n",
+ msg->msg.connect_active_ind.plci);
+ actcapi_debug_caddr(&msg->msg.connect_active_ind.addr);
+ break;
+ case 8:
+ /* LISTEN CONF */
+ printk(KERN_DEBUG " Contr = %d\n",
+ msg->msg.listen_conf.controller);
+ printk(KERN_DEBUG " Info = 0x%04x\n",
+ msg->msg.listen_conf.info);
+ break;
+ case 11:
+ /* INFO IND */
+ printk(KERN_DEBUG " PLCI = 0x%04x\n",
+ msg->msg.info_ind.plci);
+ printk(KERN_DEBUG " Imsk = 0x%04x\n",
+ msg->msg.info_ind.nr.mask);
+ if (msg->hdr.len > 12) {
+ int l = msg->hdr.len - 12;
+ int j;
+ char *p = tmp;
+ for (j = 0; j < l ; j++)
+ p += sprintf(p, "%02x ", msg->msg.info_ind.el.display[j]);
+ printk(KERN_DEBUG " D = '%s'\n", tmp);
+ }
+ break;
+ case 14:
+ /* SELECT B2 PROTOCOL CONF */
+ printk(KERN_DEBUG " PLCI = 0x%04x\n",
+ msg->msg.select_b2_protocol_conf.plci);
+ printk(KERN_DEBUG " Info = 0x%04x\n",
+ msg->msg.select_b2_protocol_conf.info);
+ break;
+ case 15:
+ /* SELECT B3 PROTOCOL CONF */
+ printk(KERN_DEBUG " PLCI = 0x%04x\n",
+ msg->msg.select_b3_protocol_conf.plci);
+ printk(KERN_DEBUG " Info = 0x%04x\n",
+ msg->msg.select_b3_protocol_conf.info);
+ break;
+ case 16:
+ /* LISTEN B3 CONF */
+ printk(KERN_DEBUG " PLCI = 0x%04x\n",
+ msg->msg.listen_b3_conf.plci);
+ printk(KERN_DEBUG " Info = 0x%04x\n",
+ msg->msg.listen_b3_conf.info);
+ break;
+ case 18:
+ /* CONNECT B3 IND */
+ printk(KERN_DEBUG " NCCI = 0x%04x\n",
+ msg->msg.connect_b3_ind.ncci);
+ printk(KERN_DEBUG " PLCI = 0x%04x\n",
+ msg->msg.connect_b3_ind.plci);
+ actcapi_debug_ncpi(&msg->msg.connect_b3_ind.ncpi);
+ break;
+ case 19:
+ /* CONNECT B3 ACTIVE IND */
+ printk(KERN_DEBUG " NCCI = 0x%04x\n",
+ msg->msg.connect_b3_active_ind.ncci);
+ actcapi_debug_ncpi(&msg->msg.connect_b3_active_ind.ncpi);
+ break;
+ case 26:
+ /* MANUFACTURER IND */
+ printk(KERN_DEBUG " Mmsg = 0x%02x\n",
+ msg->msg.manufacturer_ind_err.manuf_msg);
+ switch (msg->msg.manufacturer_ind_err.manuf_msg) {
+ case 3:
+ printk(KERN_DEBUG " Contr = %d\n",
+ msg->msg.manufacturer_ind_err.controller);
+ printk(KERN_DEBUG " Code = 0x%08x\n",
+ msg->msg.manufacturer_ind_err.errcode);
+ memset(tmp, 0, sizeof(tmp));
+ strncpy(tmp, &msg->msg.manufacturer_ind_err.errstring,
+ msg->hdr.len - 16);
+ printk(KERN_DEBUG " Emsg = '%s'\n", tmp);
+ break;
+ }
+ break;
+ case 30:
+ /* LISTEN REQ */
+ printk(KERN_DEBUG " Imsk = 0x%08x\n",
+ msg->msg.listen_req.infomask);
+ printk(KERN_DEBUG " Emsk = 0x%04x\n",
+ msg->msg.listen_req.eazmask);
+ printk(KERN_DEBUG " Smsk = 0x%04x\n",
+ msg->msg.listen_req.simask);
+ break;
+ case 35:
+ /* SELECT_B2_PROTOCOL_REQ */
+ printk(KERN_DEBUG " PLCI = 0x%04x\n",
+ msg->msg.select_b2_protocol_req.plci);
+ printk(KERN_DEBUG " prot = 0x%02x\n",
+ msg->msg.select_b2_protocol_req.protocol);
+ if (msg->hdr.len >= 11)
+ printk(KERN_DEBUG "No dlpd\n");
+ else
+ actcapi_debug_dlpd(&msg->msg.select_b2_protocol_req.dlpd);
+ break;
+ case 44:
+ /* CONNECT RESP */
+ printk(KERN_DEBUG " PLCI = 0x%04x\n",
+ msg->msg.connect_resp.plci);
+ printk(KERN_DEBUG " CAUSE = 0x%02x\n",
+ msg->msg.connect_resp.rejectcause);
+ break;
+ case 45:
+ /* CONNECT ACTIVE RESP */
+ printk(KERN_DEBUG " PLCI = 0x%04x\n",
+ msg->msg.connect_active_resp.plci);
+ break;
+ }
+}
+#endif
diff --git a/drivers/isdn/act2000/capi.h b/drivers/isdn/act2000/capi.h
new file mode 100644
index 000000000..901f15ed4
--- /dev/null
+++ b/drivers/isdn/act2000/capi.h
@@ -0,0 +1,406 @@
+/* $Id: capi.h,v 1.4 1997/10/01 09:21:04 fritz Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ *
+ * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: capi.h,v $
+ * Revision 1.4 1997/10/01 09:21:04 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.3 1997/09/25 17:25:41 fritz
+ * Support for adding cards at runtime.
+ * Support for new Firmware.
+ *
+ * Revision 1.2 1997/09/24 19:44:15 fritz
+ * Added MSN mapping support, some cleanup.
+ *
+ * Revision 1.1 1997/09/23 18:00:10 fritz
+ * New driver for IBM Active 2000.
+ *
+ */
+
+#ifndef CAPI_H
+#define CAPI_H
+
+/* Command-part of a CAPI message */
+typedef struct actcapi_msgcmd {
+ __u8 cmd;
+ __u8 subcmd;
+} actcapi_msgcmd;
+
+/* CAPI message header */
+typedef struct actcapi_msghdr {
+ __u16 len;
+ __u16 applicationID;
+ actcapi_msgcmd cmd;
+ __u16 msgnum;
+} actcapi_msghdr;
+
+/* CAPI message description (for debugging) */
+typedef struct actcapi_msgdsc {
+ actcapi_msgcmd cmd;
+ char *description;
+} actcapi_msgdsc;
+
+/* CAPI Adress */
+typedef struct actcapi_addr {
+ __u8 len; /* Length of element */
+ __u8 tnp; /* Type/Numbering Plan */
+ __u8 num[20]; /* Caller ID */
+} actcapi_addr;
+
+/* CAPI INFO element mask */
+typedef union actcapi_infonr { /* info number */
+ __u16 mask; /* info-mask field */
+ struct bmask { /* bit definitions */
+ unsigned codes : 3; /* code set */
+ unsigned rsvd : 5; /* reserved */
+ unsigned svind : 1; /* single, variable length ind. */
+ unsigned wtype : 7; /* W-element type */
+ } bmask;
+} actcapi_infonr;
+
+/* CAPI INFO element */
+typedef union actcapi_infoel { /* info element */
+ __u8 len; /* length of info element */
+ __u8 display[40]; /* display contents */
+ __u8 uuinfo[40]; /* User-user info field */
+ struct cause { /* Cause information */
+ unsigned ext2 : 1; /* extension */
+ unsigned cod : 2; /* coding standard */
+ unsigned spare : 1; /* spare */
+ unsigned loc : 4; /* location */
+ unsigned ext1 : 1; /* extension */
+ unsigned cval : 7; /* Cause value */
+ } cause;
+ struct charge { /* Charging information */
+ __u8 toc; /* type of charging info */
+ __u8 unit[10]; /* charging units */
+ } charge;
+ __u8 date[20]; /* date fields */
+ __u8 stat; /* state of remote party */
+} actcapi_infoel;
+
+/* Message for EAZ<->MSN Mapping */
+typedef struct actcapi_msn {
+ __u8 eaz;
+ __u8 len; /* Length of MSN */
+ __u8 msn[15] __attribute__ ((packed));
+} actcapi_msn;
+
+typedef struct actcapi_dlpd {
+ __u8 len; /* Length of structure */
+ __u16 dlen __attribute__ ((packed)); /* Data Length */
+ __u8 laa __attribute__ ((packed)); /* Link Address A */
+ __u8 lab; /* Link Address B */
+ __u8 modulo; /* Modulo Mode */
+ __u8 win; /* Window size */
+ __u8 xid[100]; /* XID Information */
+} actcapi_dlpd;
+
+typedef struct actcapi_ncpd {
+ __u8 len; /* Length of structure */
+ __u16 lic __attribute__ ((packed));
+ __u16 hic __attribute__ ((packed));
+ __u16 ltc __attribute__ ((packed));
+ __u16 htc __attribute__ ((packed));
+ __u16 loc __attribute__ ((packed));
+ __u16 hoc __attribute__ ((packed));
+ __u8 modulo __attribute__ ((packed));
+} actcapi_ncpd;
+#define actcapi_ncpi actcapi_ncpd
+
+/*
+ * Layout of NCCI field in a B3 DATA CAPI message is different from
+ * standard at act2000:
+ *
+ * Bit 0-4 = PLCI
+ * Bit 5-7 = Controller
+ * Bit 8-15 = NCCI
+ */
+#define MAKE_NCCI(plci,contr,ncci) \
+ ((plci & 0x1f) | ((contr & 0x7) << 5) | ((ncci & 0xff) << 8))
+
+#define EVAL_NCCI(fakencci,plci,contr,ncci) { \
+ plci = fakencci & 0x1f; \
+ contr = (fakencci >> 5) & 0x7; \
+ ncci = (fakencci >> 8) & 0xff; \
+}
+
+/*
+ * Layout of PLCI field in a B3 DATA CAPI message is different from
+ * standard at act2000:
+ *
+ * Bit 0-4 = PLCI
+ * Bit 5-7 = Controller
+ * Bit 8-15 = reserved (must be 0)
+ */
+#define MAKE_PLCI(plci,contr) \
+ ((plci & 0x1f) | ((contr & 0x7) << 5))
+
+#define EVAL_PLCI(fakeplci,plci,contr) { \
+ plci = fakeplci & 0x1f; \
+ contr = (fakeplci >> 5) & 0x7; \
+}
+
+typedef struct actcapi_msg {
+ actcapi_msghdr hdr;
+ union msg {
+ __u16 manuf_msg;
+ struct manufacturer_req_net {
+ __u16 manuf_msg;
+ __u16 controller;
+ __u8 nettype;
+ } manufacturer_req_net;
+ struct manufacturer_req_v42 {
+ __u16 manuf_msg;
+ __u16 controller;
+ __u32 v42control;
+ } manufacturer_req_v42;
+ struct manufacturer_conf_v42 {
+ __u16 manuf_msg;
+ __u16 controller;
+ } manufacturer_conf_v42;
+ struct manufacturer_req_err {
+ __u16 manuf_msg;
+ __u16 controller;
+ } manufacturer_req_err;
+ struct manufacturer_ind_err {
+ __u16 manuf_msg;
+ __u16 controller;
+ __u32 errcode;
+ __u8 errstring; /* actually up to 160 */
+ } manufacturer_ind_err;
+ struct manufacturer_req_msn {
+ __u16 manuf_msg;
+ __u16 controller;
+ actcapi_msn msnmap;
+ } manufacturer_req_msn;
+ /* TODO: TraceInit-req/conf/ind/resp and
+ * TraceDump-req/conf/ind/resp
+ */
+ struct connect_req {
+ __u8 controller;
+ __u8 bchan;
+ __u32 infomask __attribute__ ((packed));
+ __u8 si1;
+ __u8 si2;
+ __u8 eaz;
+ actcapi_addr addr;
+ } connect_req;
+ struct connect_conf {
+ __u16 plci;
+ __u16 info;
+ } connect_conf;
+ struct connect_ind {
+ __u16 plci;
+ __u8 controller;
+ __u8 si1;
+ __u8 si2;
+ __u8 eaz;
+ actcapi_addr addr;
+ } connect_ind;
+ struct connect_resp {
+ __u16 plci;
+ __u8 rejectcause;
+ } connect_resp;
+ struct connect_active_ind {
+ __u16 plci;
+ actcapi_addr addr;
+ } connect_active_ind;
+ struct connect_active_resp {
+ __u16 plci;
+ } connect_active_resp;
+ struct connect_b3_req {
+ __u16 plci;
+ actcapi_ncpi ncpi;
+ } connect_b3_req;
+ struct connect_b3_conf {
+ __u16 plci;
+ __u16 ncci;
+ __u16 info;
+ } connect_b3_conf;
+ struct connect_b3_ind {
+ __u16 ncci;
+ __u16 plci;
+ actcapi_ncpi ncpi;
+ } connect_b3_ind;
+ struct connect_b3_resp {
+ __u16 ncci;
+ __u8 rejectcause;
+ actcapi_ncpi ncpi __attribute__ ((packed));
+ } connect_b3_resp;
+ struct disconnect_req {
+ __u16 plci;
+ __u8 cause;
+ } disconnect_req;
+ struct disconnect_conf {
+ __u16 plci;
+ __u16 info;
+ } disconnect_conf;
+ struct disconnect_ind {
+ __u16 plci;
+ __u16 info;
+ } disconnect_ind;
+ struct disconnect_resp {
+ __u16 plci;
+ } disconnect_resp;
+ struct connect_b3_active_ind {
+ __u16 ncci;
+ actcapi_ncpi ncpi;
+ } connect_b3_active_ind;
+ struct connect_b3_active_resp {
+ __u16 ncci;
+ } connect_b3_active_resp;
+ struct disconnect_b3_req {
+ __u16 ncci;
+ actcapi_ncpi ncpi;
+ } disconnect_b3_req;
+ struct disconnect_b3_conf {
+ __u16 ncci;
+ __u16 info;
+ } disconnect_b3_conf;
+ struct disconnect_b3_ind {
+ __u16 ncci;
+ __u16 info;
+ actcapi_ncpi ncpi;
+ } disconnect_b3_ind;
+ struct disconnect_b3_resp {
+ __u16 ncci;
+ } disconnect_b3_resp;
+ struct info_ind {
+ __u16 plci;
+ actcapi_infonr nr;
+ actcapi_infoel el;
+ } info_ind;
+ struct info_resp {
+ __u16 plci;
+ } info_resp;
+ struct listen_b3_req {
+ __u16 plci;
+ } listen_b3_req;
+ struct listen_b3_conf {
+ __u16 plci;
+ __u16 info;
+ } listen_b3_conf;
+ struct select_b2_protocol_req {
+ __u16 plci;
+ __u8 protocol;
+ actcapi_dlpd dlpd __attribute__ ((packed));
+ } select_b2_protocol_req;
+ struct select_b2_protocol_conf {
+ __u16 plci;
+ __u16 info;
+ } select_b2_protocol_conf;
+ struct select_b3_protocol_req {
+ __u16 plci;
+ __u8 protocol;
+ actcapi_ncpd ncpd __attribute__ ((packed));
+ } select_b3_protocol_req;
+ struct select_b3_protocol_conf {
+ __u16 plci;
+ __u16 info;
+ } select_b3_protocol_conf;
+#if 0
+ struct listen_req {
+ __u32 controller;
+ __u32 infomask;
+ __u32 cipmask;
+ __u32 cipmask2;
+ __u16 dummy; /* 2 Length-bytes of 2 Structs MUST always be 0!!! */
+ } listen_req;
+ struct listen_conf {
+ __u32 controller;
+ __u16 info;
+ } listen_conf;
+#else
+ struct listen_req {
+ __u8 controller;
+ __u32 infomask __attribute__ ((packed));
+ __u16 eazmask __attribute__ ((packed));
+ __u16 simask __attribute__ ((packed));
+ } listen_req;
+ struct listen_conf {
+ __u8 controller;
+ __u16 info __attribute__ ((packed));
+ } listen_conf;
+#endif
+ struct data_b3_req {
+ __u16 fakencci;
+ __u16 datalen;
+ __u32 unused;
+ __u8 blocknr;
+ __u16 flags __attribute__ ((packed));
+ } data_b3_req;
+ struct data_b3_ind {
+ __u16 fakencci;
+ __u16 datalen;
+ __u32 unused;
+ __u8 blocknr;
+ __u16 flags __attribute__ ((packed));
+ } data_b3_ind;
+ struct data_b3_resp {
+ __u16 ncci;
+ __u8 blocknr;
+ } data_b3_resp;
+ struct data_b3_conf {
+ __u16 ncci;
+ __u8 blocknr;
+ __u16 info __attribute__ ((packed));
+ } data_b3_conf;
+ } msg;
+} actcapi_msg;
+
+extern __inline__ unsigned short
+actcapi_nextsmsg(act2000_card *card)
+{
+ unsigned long flags;
+ unsigned short n;
+
+ save_flags(flags);
+ cli();
+ n = card->msgnum;
+ card->msgnum++;
+ card->msgnum &= 0x7fff;
+ restore_flags(flags);
+ return n;
+}
+#define DEBUG_MSG
+#undef DEBUG_DATA_MSG
+#undef DEBUG_DUMP_SKB
+
+extern int actcapi_chkhdr(act2000_card *, actcapi_msghdr *);
+extern int actcapi_listen_req(act2000_card *);
+extern int actcapi_manufacturer_req_net(act2000_card *);
+extern int actcapi_manufacturer_req_v42(act2000_card *, ulong);
+extern int actcapi_manufacturer_req_errh(act2000_card *);
+extern int actcapi_manufacturer_req_msn(act2000_card *);
+extern int actcapi_connect_req(act2000_card *, act2000_chan *, char *, char, int, int);
+extern void actcapi_select_b2_protocol_req(act2000_card *, act2000_chan *);
+extern void actcapi_disconnect_b3_req(act2000_card *, act2000_chan *);
+extern void actcapi_connect_resp(act2000_card *, act2000_chan *, __u8);
+extern void actcapi_dispatch(act2000_card *);
+#ifdef DEBUG_MSG
+extern void actcapi_debug_msg(struct sk_buff *skb, int);
+#else
+#define actcapi_debug_msg(skb, len)
+#endif
+#endif
diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c
new file mode 100644
index 000000000..76be187f2
--- /dev/null
+++ b/drivers/isdn/act2000/module.c
@@ -0,0 +1,953 @@
+/* $Id: module.c,v 1.7 1998/02/12 23:06:52 keil Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ *
+ * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: module.c,v $
+ * Revision 1.7 1998/02/12 23:06:52 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.6 1998/01/31 22:10:42 keil
+ * changes for 2.1.82
+ *
+ * Revision 1.5 1997/10/09 22:23:04 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ *
+ * Revision 1.4 1997/09/25 17:25:43 fritz
+ * Support for adding cards at runtime.
+ * Support for new Firmware.
+ *
+ * Revision 1.3 1997/09/24 23:11:45 fritz
+ * Optimized IRQ load and polling-mode.
+ *
+ * Revision 1.2 1997/09/24 19:44:17 fritz
+ * Added MSN mapping support, some cleanup.
+ *
+ * Revision 1.1 1997/09/23 18:00:13 fritz
+ * New driver for IBM Active 2000.
+ *
+ */
+
+#include "act2000.h"
+#include "act2000_isa.h"
+#include "capi.h"
+
+static unsigned short isa_ports[] =
+{
+ 0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380,
+ 0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60,
+};
+#define ISA_NRPORTS (sizeof(isa_ports)/sizeof(unsigned short))
+
+act2000_card *cards = (act2000_card *) NULL;
+
+/* Parameters to be set by insmod */
+static int act_bus = 0;
+static int act_port = -1; /* -1 = Autoprobe */
+static int act_irq = -1; /* -1 = Autoselect */
+static char *act_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+
+MODULE_DESCRIPTION( "Driver for IBM Active 2000 ISDN card");
+MODULE_AUTHOR( "Fritz Elfert");
+MODULE_SUPPORTED_DEVICE( "ISDN subsystem");
+MODULE_PARM_DESC(act_bus, "BusType of first card, 1=ISA, 2=MCA, 3=PCMCIA, currently only ISA");
+MODULE_PARM_DESC(membase, "Base port address of first card");
+MODULE_PARM_DESC(act_irq, "IRQ of first card (-1 = grab next free IRQ)");
+MODULE_PARM_DESC(act_id, "ID-String of first card");
+MODULE_PARM(act_bus, "i");
+MODULE_PARM(act_port, "i");
+MODULE_PARM(act_irq, "i");
+MODULE_PARM(act_id, "s");
+
+static int act2000_addcard(int, int, int, char *);
+
+static act2000_chan *
+find_channel(act2000_card *card, int channel)
+{
+ if ((channel >= 0) && (channel < ACT2000_BCH))
+ return &(card->bch[channel]);
+ printk(KERN_WARNING "act2000: Invalid channel %d\n", channel);
+ return NULL;
+}
+
+/*
+ * Free MSN list
+ */
+static void
+act2000_clear_msn(act2000_card *card)
+{
+ struct msn_entry *p = card->msn_list;
+ struct msn_entry *q;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ card->msn_list = NULL;
+ restore_flags(flags);
+ while (p) {
+ q = p->next;
+ kfree(p);
+ p = q;
+ }
+}
+
+/*
+ * Find an MSN entry in the list.
+ * If ia5 != 0, return IA5-encoded EAZ, else
+ * return a bitmask with corresponding bit set.
+ */
+static __u16
+act2000_find_msn(act2000_card *card, char *msn, int ia5)
+{
+ struct msn_entry *p = card->msn_list;
+ __u8 eaz = '0';
+
+ while (p) {
+ if (!strcmp(p->msn, msn)) {
+ eaz = p->eaz;
+ break;
+ }
+ p = p->next;
+ }
+ if (!ia5)
+ return (1 << (eaz - '0'));
+ else
+ return eaz;
+}
+
+/*
+ * Find an EAZ entry in the list.
+ * return a string with corresponding msn.
+ */
+char *
+act2000_find_eaz(act2000_card *card, char eaz)
+{
+ struct msn_entry *p = card->msn_list;
+
+ while (p) {
+ if (p->eaz == eaz)
+ return(p->msn);
+ p = p->next;
+ }
+ return("\0");
+}
+
+/*
+ * Add or delete an MSN to the MSN list
+ *
+ * First character of msneaz is EAZ, rest is MSN.
+ * If length of eazmsn is 1, delete that entry.
+ */
+static int
+act2000_set_msn(act2000_card *card, char *eazmsn)
+{
+ struct msn_entry *p = card->msn_list;
+ struct msn_entry *q = NULL;
+ unsigned long flags;
+ int i;
+
+ if (!strlen(eazmsn))
+ return 0;
+ if (strlen(eazmsn) > 16)
+ return -EINVAL;
+ for (i = 0; i < strlen(eazmsn); i++)
+ if (!isdigit(eazmsn[i]))
+ return -EINVAL;
+ if (strlen(eazmsn) == 1) {
+ /* Delete a single MSN */
+ while (p) {
+ if (p->eaz == eazmsn[0]) {
+ save_flags(flags);
+ cli();
+ if (q)
+ q->next = p->next;
+ else
+ card->msn_list = p->next;
+ restore_flags(flags);
+ kfree(p);
+ printk(KERN_DEBUG
+ "Mapping for EAZ %c deleted\n",
+ eazmsn[0]);
+ return 0;
+ }
+ q = p;
+ p = p->next;
+ }
+ return 0;
+ }
+ /* Add a single MSN */
+ while (p) {
+ /* Found in list, replace MSN */
+ if (p->eaz == eazmsn[0]) {
+ save_flags(flags);
+ cli();
+ strcpy(p->msn, &eazmsn[1]);
+ restore_flags(flags);
+ printk(KERN_DEBUG
+ "Mapping for EAZ %c changed to %s\n",
+ eazmsn[0],
+ &eazmsn[1]);
+ return 0;
+ }
+ p = p->next;
+ }
+ /* Not found in list, add new entry */
+ p = kmalloc(sizeof(msn_entry), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+ p->eaz = eazmsn[0];
+ strcpy(p->msn, &eazmsn[1]);
+ p->next = card->msn_list;
+ save_flags(flags);
+ cli();
+ card->msn_list = p;
+ restore_flags(flags);
+ printk(KERN_DEBUG
+ "Mapping %c -> %s added\n",
+ eazmsn[0],
+ &eazmsn[1]);
+ return 0;
+}
+
+static void
+act2000_transmit(struct act2000_card *card)
+{
+ switch (card->bus) {
+ case ACT2000_BUS_ISA:
+ isa_send(card);
+ break;
+ case ACT2000_BUS_PCMCIA:
+ case ACT2000_BUS_MCA:
+ default:
+ printk(KERN_WARNING
+ "act2000_transmit: Illegal bustype %d\n", card->bus);
+ }
+}
+
+static void
+act2000_receive(struct act2000_card *card)
+{
+ switch (card->bus) {
+ case ACT2000_BUS_ISA:
+ isa_receive(card);
+ break;
+ case ACT2000_BUS_PCMCIA:
+ case ACT2000_BUS_MCA:
+ default:
+ printk(KERN_WARNING
+ "act2000_receive: Illegal bustype %d\n", card->bus);
+ }
+}
+
+static void
+act2000_poll(unsigned long data)
+{
+ act2000_card * card = (act2000_card *)data;
+ unsigned long flags;
+
+ act2000_receive(card);
+ save_flags(flags);
+ cli();
+ del_timer(&card->ptimer);
+ card->ptimer.expires = jiffies + 3;
+ add_timer(&card->ptimer);
+ restore_flags(flags);
+}
+
+static int
+act2000_command(act2000_card * card, isdn_ctrl * c)
+{
+ ulong a;
+ act2000_chan *chan;
+ act2000_cdef cdef;
+ isdn_ctrl cmd;
+ char tmp[17];
+ int ret;
+ unsigned long flags;
+
+ switch (c->command) {
+ case ISDN_CMD_IOCTL:
+ memcpy(&a, c->parm.num, sizeof(ulong));
+ switch (c->arg) {
+ case ACT2000_IOCTL_LOADBOOT:
+ switch (card->bus) {
+ case ACT2000_BUS_ISA:
+ ret = isa_download(card,
+ (act2000_ddef *)a);
+ if (!ret) {
+ card->flags |= ACT2000_FLAGS_LOADED;
+ if (!(card->flags & ACT2000_FLAGS_IVALID)) {
+ card->ptimer.expires = jiffies + 3;
+ card->ptimer.function = act2000_poll;
+ card->ptimer.data = (unsigned long)card;
+ add_timer(&card->ptimer);
+ }
+ actcapi_manufacturer_req_errh(card);
+ }
+ break;
+ default:
+ printk(KERN_WARNING
+ "act2000: Illegal BUS type %d\n",
+ card->bus);
+ ret = -EIO;
+ }
+ return ret;
+ case ACT2000_IOCTL_SETPROTO:
+ card->ptype = a?ISDN_PTYPE_EURO:ISDN_PTYPE_1TR6;
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
+ return 0;
+ actcapi_manufacturer_req_net(card);
+ return 0;
+ case ACT2000_IOCTL_SETMSN:
+ if ((ret = copy_from_user(tmp, (char *)a, sizeof(tmp))))
+ return ret;
+ if ((ret = act2000_set_msn(card, tmp)))
+ return ret;
+ if (card->flags & ACT2000_FLAGS_RUNNING)
+ return(actcapi_manufacturer_req_msn(card));
+ return 0;
+ case ACT2000_IOCTL_ADDCARD:
+ if ((ret = copy_from_user(&cdef, (char *)a, sizeof(cdef))))
+ return ret;
+ if (act2000_addcard(cdef.bus, cdef.port, cdef.irq, cdef.id))
+ return -EIO;
+ return 0;
+ case ACT2000_IOCTL_TEST:
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
+ return -ENODEV;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case ISDN_CMD_DIAL:
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ if (!(chan = find_channel(card, c->arg & 0x0f)))
+ break;
+ save_flags(flags);
+ cli();
+ if (chan->fsm_state != ACT2000_STATE_NULL) {
+ restore_flags(flags);
+ printk(KERN_WARNING "Dial on channel with state %d\n",
+ chan->fsm_state);
+ return -EBUSY;
+ }
+ if (card->ptype == ISDN_PTYPE_EURO)
+ tmp[0] = act2000_find_msn(card, c->parm.setup.eazmsn, 1);
+ else
+ tmp[0] = c->parm.setup.eazmsn[0];
+ chan->fsm_state = ACT2000_STATE_OCALL;
+ chan->callref = 0xffff;
+ restore_flags(flags);
+ ret = actcapi_connect_req(card, chan, c->parm.setup.phone,
+ tmp[0], c->parm.setup.si1,
+ c->parm.setup.si2);
+ if (ret) {
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg &= 0x0f;
+ card->interface.statcallb(&cmd);
+ }
+ return ret;
+ case ISDN_CMD_ACCEPTD:
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ if (!(chan = find_channel(card, c->arg & 0x0f)))
+ break;
+ if (chan->fsm_state == ACT2000_STATE_ICALL)
+ actcapi_select_b2_protocol_req(card, chan);
+ return 0;
+ case ISDN_CMD_ACCEPTB:
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ return 0;
+ case ISDN_CMD_HANGUP:
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ if (!(chan = find_channel(card, c->arg & 0x0f)))
+ break;
+ switch (chan->fsm_state) {
+ case ACT2000_STATE_ICALL:
+ case ACT2000_STATE_BSETUP:
+ actcapi_connect_resp(card, chan, 0x15);
+ break;
+ case ACT2000_STATE_ACTIVE:
+ actcapi_disconnect_b3_req(card, chan);
+ break;
+ }
+ return 0;
+ case ISDN_CMD_SETEAZ:
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ if (!(chan = find_channel(card, c->arg & 0x0f)))
+ break;
+ if (strlen(c->parm.num)) {
+ if (card->ptype == ISDN_PTYPE_EURO) {
+ chan->eazmask = act2000_find_msn(card, c->parm.num, 0);
+ }
+ if (card->ptype == ISDN_PTYPE_1TR6) {
+ int i;
+ chan->eazmask = 0;
+ for (i = 0; i < strlen(c->parm.num); i++)
+ if (isdigit(c->parm.num[i]))
+ chan->eazmask |= (1 << (c->parm.num[i] - '0'));
+ }
+ } else
+ chan->eazmask = 0x3ff;
+ actcapi_listen_req(card);
+ return 0;
+ case ISDN_CMD_CLREAZ:
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ if (!(chan = find_channel(card, c->arg & 0x0f)))
+ break;
+ chan->eazmask = 0;
+ actcapi_listen_req(card);
+ return 0;
+ case ISDN_CMD_SETL2:
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ if (!(chan = find_channel(card, c->arg & 0x0f)))
+ break;
+ chan->l2prot = (c->arg >> 8);
+ return 0;
+ case ISDN_CMD_GETL2:
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ if (!(chan = find_channel(card, c->arg & 0x0f)))
+ break;
+ return chan->l2prot;
+ case ISDN_CMD_SETL3:
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
+ printk(KERN_WARNING "L3 protocol unknown\n");
+ return -1;
+ }
+ if (!(chan = find_channel(card, c->arg & 0x0f)))
+ break;
+ chan->l3prot = (c->arg >> 8);
+ return 0;
+ case ISDN_CMD_GETL3:
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ if (!(chan = find_channel(card, c->arg & 0x0f)))
+ break;
+ return chan->l3prot;
+ case ISDN_CMD_GETEAZ:
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ printk(KERN_DEBUG "act2000 CMD_GETEAZ not implemented\n");
+ return 0;
+ case ISDN_CMD_SETSIL:
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ printk(KERN_DEBUG "act2000 CMD_SETSIL not implemented\n");
+ return 0;
+ case ISDN_CMD_GETSIL:
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ printk(KERN_DEBUG "act2000 CMD_GETSIL not implemented\n");
+ return 0;
+ case ISDN_CMD_LOCK:
+ MOD_INC_USE_COUNT;
+ return 0;
+ case ISDN_CMD_UNLOCK:
+ MOD_DEC_USE_COUNT;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int
+act2000_sendbuf(act2000_card *card, int channel, int ack, struct sk_buff *skb)
+{
+ struct sk_buff *xmit_skb;
+ int len;
+ act2000_chan *chan;
+ actcapi_msg *msg;
+
+ if (!(chan = find_channel(card, channel)))
+ return -1;
+ if (chan->fsm_state != ACT2000_STATE_ACTIVE)
+ return -1;
+ len = skb->len;
+ if ((chan->queued + len) >= ACT2000_MAX_QUEUED)
+ return 0;
+ if (!len)
+ return 0;
+ if (skb_headroom(skb) < 19) {
+ printk(KERN_WARNING "act2000_sendbuf: Headroom only %d\n",
+ skb_headroom(skb));
+ xmit_skb = alloc_skb(len + 19, GFP_ATOMIC);
+ if (!xmit_skb) {
+ printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
+ return 0;
+ }
+ skb_reserve(xmit_skb, 19);
+ memcpy(skb_put(xmit_skb, len), skb->data, len);
+ } else {
+ xmit_skb = skb_clone(skb, GFP_ATOMIC);
+ if (!xmit_skb) {
+ printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
+ return 0;
+ }
+ }
+ dev_kfree_skb(skb);
+ msg = (actcapi_msg *)skb_push(xmit_skb, 19);
+ msg->hdr.len = 19 + len;
+ msg->hdr.applicationID = 1;
+ msg->hdr.cmd.cmd = 0x86;
+ msg->hdr.cmd.subcmd = 0x00;
+ msg->hdr.msgnum = actcapi_nextsmsg(card);
+ msg->msg.data_b3_req.datalen = len;
+ msg->msg.data_b3_req.blocknr = (msg->hdr.msgnum & 0xff);
+ msg->msg.data_b3_req.fakencci = MAKE_NCCI(chan->plci, 0, chan->ncci);
+ msg->msg.data_b3_req.flags = ack; /* Will be set to 0 on actual sending */
+ actcapi_debug_msg(xmit_skb, 1);
+ chan->queued += len;
+ skb_queue_tail(&card->sndq, xmit_skb);
+ act2000_schedule_tx(card);
+ return len;
+}
+
+
+/* Read the Status-replies from the Interface */
+static int
+act2000_readstatus(u_char * buf, int len, int user, act2000_card * card)
+{
+ int count;
+ u_char *p;
+
+ for (p = buf, count = 0; count < len; p++, count++) {
+ if (card->status_buf_read == card->status_buf_write)
+ return count;
+ if (user)
+ put_user(*card->status_buf_read++, p);
+ else
+ *p = *card->status_buf_read++;
+ if (card->status_buf_read > card->status_buf_end)
+ card->status_buf_read = card->status_buf;
+ }
+ return count;
+}
+
+static void
+act2000_putmsg(act2000_card *card, char c)
+{
+ ulong flags;
+
+ save_flags(flags);
+ cli();
+ *card->status_buf_write++ = c;
+ if (card->status_buf_write == card->status_buf_read) {
+ if (++card->status_buf_read > card->status_buf_end)
+ card->status_buf_read = card->status_buf;
+ }
+ if (card->status_buf_write > card->status_buf_end)
+ card->status_buf_write = card->status_buf;
+ restore_flags(flags);
+}
+
+static void
+act2000_logstat(struct act2000_card *card, char *str)
+{
+ char *p = str;
+ isdn_ctrl c;
+
+ while (*p)
+ act2000_putmsg(card, *p++);
+ c.command = ISDN_STAT_STAVAIL;
+ c.driver = card->myid;
+ c.arg = strlen(str);
+ card->interface.statcallb(&c);
+}
+
+/*
+ * Find card with given driverId
+ */
+static inline act2000_card *
+act2000_findcard(int driverid)
+{
+ act2000_card *p = cards;
+
+ while (p) {
+ if (p->myid == driverid)
+ return p;
+ p = p->next;
+ }
+ return (act2000_card *) 0;
+}
+
+/*
+ * Wrapper functions for interface to linklevel
+ */
+static int
+if_command(isdn_ctrl * c)
+{
+ act2000_card *card = act2000_findcard(c->driver);
+
+ if (card)
+ return (act2000_command(card, c));
+ printk(KERN_ERR
+ "act2000: if_command %d called with invalid driverId %d!\n",
+ c->command, c->driver);
+ return -ENODEV;
+}
+
+static int
+if_writecmd(const u_char * buf, int len, int user, int id, int channel)
+{
+ act2000_card *card = act2000_findcard(id);
+
+ if (card) {
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ return (len);
+ }
+ printk(KERN_ERR
+ "act2000: if_writecmd called with invalid driverId!\n");
+ return -ENODEV;
+}
+
+static int
+if_readstatus(u_char * buf, int len, int user, int id, int channel)
+{
+ act2000_card *card = act2000_findcard(id);
+
+ if (card) {
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ return (act2000_readstatus(buf, len, user, card));
+ }
+ printk(KERN_ERR
+ "act2000: if_readstatus called with invalid driverId!\n");
+ return -ENODEV;
+}
+
+static int
+if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
+{
+ act2000_card *card = act2000_findcard(id);
+
+ if (card) {
+ if (!card->flags & ACT2000_FLAGS_RUNNING)
+ return -ENODEV;
+ return (act2000_sendbuf(card, channel, ack, skb));
+ }
+ printk(KERN_ERR
+ "act2000: if_sendbuf called with invalid driverId!\n");
+ return -ENODEV;
+}
+
+
+/*
+ * Allocate a new card-struct, initialize it
+ * link it into cards-list.
+ */
+static void
+act2000_alloccard(int bus, int port, int irq, char *id)
+{
+ int i;
+ act2000_card *card;
+ if (!(card = (act2000_card *) kmalloc(sizeof(act2000_card), GFP_KERNEL))) {
+ printk(KERN_WARNING
+ "act2000: (%s) Could not allocate card-struct.\n", id);
+ return;
+ }
+ memset((char *) card, 0, sizeof(act2000_card));
+ skb_queue_head_init(&card->sndq);
+ skb_queue_head_init(&card->rcvq);
+ skb_queue_head_init(&card->ackq);
+ card->snd_tq.routine = (void *) (void *) act2000_transmit;
+ card->snd_tq.data = card;
+ card->rcv_tq.routine = (void *) (void *) actcapi_dispatch;
+ card->rcv_tq.data = card;
+ card->poll_tq.routine = (void *) (void *) act2000_receive;
+ card->poll_tq.data = card;
+ init_timer(&card->ptimer);
+ card->interface.channels = ACT2000_BCH;
+ card->interface.maxbufsize = 4000;
+ card->interface.command = if_command;
+ card->interface.writebuf_skb = if_sendbuf;
+ card->interface.writecmd = if_writecmd;
+ card->interface.readstat = if_readstatus;
+ card->interface.features =
+ ISDN_FEATURE_L2_X75I |
+ ISDN_FEATURE_L2_HDLC |
+#if 0
+/* Not yet! New Firmware is on the way ... */
+ ISDN_FEATURE_L2_TRANS |
+#endif
+ ISDN_FEATURE_L3_TRANS |
+ ISDN_FEATURE_P_UNKNOWN;
+ card->interface.hl_hdrlen = 20;
+ card->ptype = ISDN_PTYPE_EURO;
+ strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
+ for (i=0; i<ACT2000_BCH; i++) {
+ card->bch[i].plci = 0x8000;
+ card->bch[i].ncci = 0x8000;
+ card->bch[i].l2prot = ISDN_PROTO_L2_X75I;
+ card->bch[i].l3prot = ISDN_PROTO_L3_TRANS;
+ }
+ card->myid = -1;
+ card->bus = bus;
+ card->port = port;
+ card->irq = irq;
+ card->next = cards;
+ cards = card;
+}
+
+/*
+ * register card at linklevel
+ */
+static int
+act2000_registercard(act2000_card * card)
+{
+ switch (card->bus) {
+ case ACT2000_BUS_ISA:
+ break;
+ case ACT2000_BUS_MCA:
+ case ACT2000_BUS_PCMCIA:
+ default:
+ printk(KERN_WARNING
+ "act2000: Illegal BUS type %d\n",
+ card->bus);
+ return -1;
+ }
+ if (!register_isdn(&card->interface)) {
+ printk(KERN_WARNING
+ "act2000: Unable to register %s\n",
+ card->interface.id);
+ return -1;
+ }
+ card->myid = card->interface.channels;
+ sprintf(card->regname, "act2000-isdn (%s)", card->interface.id);
+ return 0;
+}
+
+static void
+unregister_card(act2000_card * card)
+{
+ isdn_ctrl cmd;
+
+ cmd.command = ISDN_STAT_UNLOAD;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ switch (card->bus) {
+ case ACT2000_BUS_ISA:
+ isa_release(card);
+ break;
+ case ACT2000_BUS_MCA:
+ case ACT2000_BUS_PCMCIA:
+ default:
+ printk(KERN_WARNING
+ "act2000: Invalid BUS type %d\n",
+ card->bus);
+ break;
+ }
+}
+
+static int
+act2000_addcard(int bus, int port, int irq, char *id)
+{
+ act2000_card *p;
+ act2000_card *q = NULL;
+ int initialized;
+ int added = 0;
+ int failed = 0;
+ int i;
+
+ if (!bus)
+ bus = ACT2000_BUS_ISA;
+ if (port != -1) {
+ /* Port defined, do fixed setup */
+ act2000_alloccard(bus, port, irq, id);
+ } else {
+ /* No port defined, perform autoprobing.
+ * This may result in more than one card detected.
+ */
+ switch (bus) {
+ case ACT2000_BUS_ISA:
+ for (i = 0; i < ISA_NRPORTS; i++)
+ if (isa_detect(isa_ports[i])) {
+ printk(KERN_INFO
+ "act2000: Detected ISA card at port 0x%x\n",
+ isa_ports[i]);
+ act2000_alloccard(bus, isa_ports[i], irq, id);
+ }
+ break;
+ case ACT2000_BUS_MCA:
+ case ACT2000_BUS_PCMCIA:
+ default:
+ printk(KERN_WARNING
+ "act2000: addcard: Invalid BUS type %d\n",
+ bus);
+ }
+ }
+ if (!cards)
+ return 1;
+ p = cards;
+ while (p) {
+ initialized = 0;
+ if (!p->interface.statcallb) {
+ /* Not yet registered.
+ * Try to register and activate it.
+ */
+ added++;
+ switch (p->bus) {
+ case ACT2000_BUS_ISA:
+ if (isa_detect(p->port)) {
+ if (act2000_registercard(p))
+ break;
+ if (isa_config_port(p, p->port)) {
+ printk(KERN_WARNING
+ "act2000: Could not request port 0x%04x\n",
+ p->port);
+ unregister_card(p);
+ p->interface.statcallb = NULL;
+ break;
+ }
+ if (isa_config_irq(p, p->irq)) {
+ printk(KERN_INFO
+ "act2000: No IRQ available, fallback to polling\n");
+ /* Fall back to polled operation */
+ p->irq = 0;
+ }
+ printk(KERN_INFO
+ "act2000: ISA"
+ "-type card at port "
+ "0x%04x ",
+ p->port);
+ if (p->irq)
+ printk("irq %d\n", p->irq);
+ else
+ printk("polled\n");
+ initialized = 1;
+ }
+ break;
+ case ACT2000_BUS_MCA:
+ case ACT2000_BUS_PCMCIA:
+ default:
+ printk(KERN_WARNING
+ "act2000: addcard: Invalid BUS type %d\n",
+ p->bus);
+ }
+ } else
+ /* Card already initialized */
+ initialized = 1;
+ if (initialized) {
+ /* Init OK, next card ... */
+ q = p;
+ p = p->next;
+ } else {
+ /* Init failed, remove card from list, free memory */
+ printk(KERN_WARNING
+ "act2000: Initialization of %s failed\n",
+ p->interface.id);
+ if (q) {
+ q->next = p->next;
+ kfree(p);
+ p = q->next;
+ } else {
+ cards = p->next;
+ kfree(p);
+ p = cards;
+ }
+ failed++;
+ }
+ }
+ return (added - failed);
+}
+
+#define DRIVERNAME "IBM Active 2000 ISDN driver"
+
+#ifdef MODULE
+#define act2000_init init_module
+#endif
+
+int
+act2000_init(void)
+{
+ printk(KERN_INFO "%s\n", DRIVERNAME);
+ if (!cards)
+ act2000_addcard(act_bus, act_port, act_irq, act_id);
+ if (!cards)
+ printk(KERN_INFO "act2000: No cards defined yet\n");
+ /* No symbols to export, hide all symbols */
+ EXPORT_NO_SYMBOLS;
+ return 0;
+}
+
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+ act2000_card *card = cards;
+ act2000_card *last;
+ while (card) {
+ unregister_card(card);
+ del_timer(&card->ptimer);
+ card = card->next;
+ }
+ card = cards;
+ while (card) {
+ last = card;
+ card = card->next;
+ act2000_clear_msn(last);
+ kfree(last);
+ }
+ printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
+}
+
+#else
+void
+act2000_setup(char *str, int *ints)
+{
+ int i, j, argc, port, irq, bus;
+
+ argc = ints[0];
+ i = 1;
+ if (argc)
+ while (argc) {
+ port = irq = -1;
+ bus = 0;
+ if (argc) {
+ bus = ints[i];
+ i++;
+ argc--;
+ }
+ if (argc) {
+ port = ints[i];
+ i++;
+ argc--;
+ }
+ if (argc) {
+ irq = ints[i];
+ i++;
+ argc--;
+ }
+ act2000_addcard(bus, port, irq, act_id);
+ }
+}
+#endif
diff --git a/drivers/isdn/avmb1/b1capi.c b/drivers/isdn/avmb1/b1capi.c
index 00be6fef7..648f19fc2 100644
--- a/drivers/isdn/avmb1/b1capi.c
+++ b/drivers/isdn/avmb1/b1capi.c
@@ -1,11 +1,39 @@
/*
- * $Id: b1capi.c,v 1.4 1997/05/27 15:17:45 fritz Exp $
+ * $Id: b1capi.c,v 1.10 1998/02/13 07:09:10 calle Exp $
*
* CAPI 2.0 Module for AVM B1-card.
*
* (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1capi.c,v $
+ * Revision 1.10 1998/02/13 07:09:10 calle
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.9 1998/01/31 11:14:39 calle
+ * merged changes to 2.0 tree, prepare 2.1.82 to work.
+ *
+ * Revision 1.8 1997/12/10 20:00:46 calle
+ * get changes from 2.0 version
+ *
+ * Revision 1.4.2.5 1997/12/07 19:59:54 calle
+ * more changes for M1/T1/B1 + config
+ *
+ * Revision 1.4.2.4 1997/11/26 16:57:20 calle
+ * more changes for B1/M1/T1.
+ *
+ * Revision 1.7 1997/10/19 14:45:40 calle
+ * fixed capi_get_version.
+ *
+ * Revision 1.6 1997/10/01 09:21:09 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.5 1997/07/12 08:22:26 calle
+ * Correct bug in CARD_NR macro, so now more than one card will work.
+ * Allow card reset, even if card is in running state.
+ *
+ *
* Revision 1.4 1997/05/27 15:17:45 fritz
* Added changes for recent 2.1.x kernels:
* changed return type of isdn_close
@@ -48,24 +76,16 @@
#include "capicmd.h"
#include "capiutil.h"
-static char *revision = "$Revision: 1.4 $";
+static char *revision = "$Revision: 1.10 $";
/* ------------------------------------------------------------- */
int showcapimsgs = 0; /* used in lli.c */
int loaddebug = 0;
-static int portbase = 0x150;
-#ifdef MODULE
-static int irq = 15;
-#ifdef HAS_NEW_SYMTAB
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
-MODULE_PARM(portbase, "i");
-MODULE_PARM(irq, "2-15i");
MODULE_PARM(showcapimsgs, "0-3i");
MODULE_PARM(loaddebug, "0-1i");
-#endif
-#endif
/* ------------------------------------------------------------- */
@@ -97,7 +117,7 @@ typedef struct avmb1_appl {
/* ------------------------------------------------------------- */
-static struct capi_version driver_version = {2, 0, 0, 9};
+static struct capi_version driver_version = {2, 0, 1, 1<<4};
static char driver_serial[CAPI_SERIAL_LEN] = "4711";
static char capi_manufakturer[64] = "AVM Berlin";
@@ -109,9 +129,9 @@ static char capi_manufakturer[64] = "AVM Berlin";
#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
-#define VALID_CARD(c) ((c) > 0 && (c) <= ncards)
+#define VALID_CARD(c) ((c) > 0 && (c) <= CAPI_MAXCONTR)
#define CARD(c) (&cards[(c)-1])
-#define CARDNR(cp) ((cards-(cp))+1)
+#define CARDNR(cp) (((cp)-cards)+1)
static avmb1_appl applications[CAPI_MAXAPPL];
static avmb1_card cards[CAPI_MAXCONTR];
@@ -126,6 +146,17 @@ static struct tq_struct tq_recv_notify;
/* -------- util functions ------------------------------------ */
+static char *cardtype2str(int cardtype)
+{
+ switch (cardtype) {
+ default:
+ case AVM_CARDTYPE_B1: return "B1";
+ case AVM_CARDTYPE_M1: return "M1";
+ case AVM_CARDTYPE_M2: return "M2";
+ case AVM_CARDTYPE_T1: return "T1";
+ }
+}
+
static inline int capi_cmd_valid(__u8 cmd)
{
switch (cmd) {
@@ -287,6 +318,8 @@ static avmb1_ncci *find_ncci(avmb1_appl * app, __u32 ncci)
return 0;
}
+
+
/* -------- Receiver ------------------------------------------ */
@@ -367,6 +400,7 @@ static void notify_up(__u16 contr)
{
struct capi_interface_user *p;
+ printk(KERN_NOTICE "b1capi: notify up contr %d\n", contr);
for (p = capi_users; p; p = p->next) {
if (p->callback)
(*p->callback) (KCI_CONTRUP, contr,
@@ -378,6 +412,7 @@ static void notify_up(__u16 contr)
static void notify_down(__u16 contr)
{
struct capi_interface_user *p;
+ printk(KERN_NOTICE "b1capi: notify down contr %d\n", contr);
for (p = capi_users; p; p = p->next) {
if (p->callback)
(*p->callback) (KCI_CONTRDOWN, contr, 0);
@@ -400,18 +435,22 @@ static void notify_handler(void *dummy)
void avmb1_card_ready(avmb1_card * card)
{
+ struct capi_profile *profp =
+ (struct capi_profile *)card->version[VER_PROFILE];
+ char *dversion = card->version[VER_DRIVER];
__u16 appl;
+ char *cardname, cname[20];
+ __u32 flag;
card->cversion.majorversion = 2;
card->cversion.minorversion = 0;
- card->cversion.majormanuversion = (card->version[VER_DRIVER][0] - '0') << 4;
- card->cversion.majormanuversion |= (card->version[VER_DRIVER][2] - '0');
- card->cversion.minormanuversion = (card->version[VER_DRIVER][3] - '0') << 4;
- card->cversion.minormanuversion |= (card->version[VER_DRIVER][5] - '0') * 10;
- card->cversion.minormanuversion |= (card->version[VER_DRIVER][6] - '0');
+ card->cversion.majormanuversion = (((dversion[0] - '0') & 0xf) << 4);
+ card->cversion.majormanuversion |= ((dversion[2] - '0') & 0xf);
+ card->cversion.minormanuversion = (dversion[3] - '0') << 4;
+ card->cversion.minormanuversion |=
+ (dversion[5] - '0') * 10 + ((dversion[6] - '0') & 0xf);
card->cardstate = CARD_RUNNING;
-
for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
if (VALID_APPLID(appl) && !APPL(appl)->releasing) {
B1_send_register(card->port, appl,
@@ -424,56 +463,190 @@ void avmb1_card_ready(avmb1_card * card)
set_bit(CARDNR(card), &notify_up_set);
queue_task(&tq_state_notify, &tq_scheduler);
+
+ flag = ((__u8 *)(profp->manu))[1];
+ switch (flag) {
+ case 0: cardname = cardtype2str(card->cardtype); break;
+ case 3: cardname = "PCMCIA B"; break;
+ case 4: cardname = "PCMCIA M1"; break;
+ case 5: cardname = "PCMCIA M2"; break;
+ case 6: cardname = "B1 V3.0"; break;
+ case 7: cardname = "B1 PCI"; break;
+ default: cardname = cname; break;
+ sprintf(cname, "AVM?%u", (unsigned int)flag);
+ break;
+ }
+ printk(KERN_NOTICE "b1capi: card %d \"%s\" ready.\n",
+ CARDNR(card), cardname);
+ flag = ((__u8 *)(profp->manu))[3];
+ if (flag)
+ printk(KERN_NOTICE "b1capi: card %d Protocol:%s%s%s%s%s%s%s\n",
+ CARDNR(card),
+ (flag & 0x01) ? " DSS1" : "",
+ (flag & 0x02) ? " CT1" : "",
+ (flag & 0x04) ? " VN3" : "",
+ (flag & 0x08) ? " NI1" : "",
+ (flag & 0x10) ? " AUSTEL" : "",
+ (flag & 0x20) ? " ESS" : "",
+ (flag & 0x40) ? " 1TR6" : ""
+ );
+ flag = ((__u8 *)(profp->manu))[5];
+ if (flag)
+ printk(KERN_NOTICE "b1capi: card %d Linetype:%s%s%s%s\n",
+ CARDNR(card),
+ (flag & 0x01) ? " point to point" : "",
+ (flag & 0x02) ? " point to multipoint" : "",
+ (flag & 0x08) ? " leased line without D-channel" : "",
+ (flag & 0x04) ? " leased line with D-channel" : ""
+ );
+}
+
+static void avmb1_card_down(avmb1_card * card, int notify)
+{
+ __u16 appl;
+
+ card->cardstate = CARD_DETECTED;
+
+ for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
+ avmb1_ncci **pp, **nextpp;
+ for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) {
+ if (NCCI2CTRL((*pp)->ncci) == card->cnr) {
+ avmb1_ncci *np = *pp;
+ *pp = np->next;
+ printk(KERN_INFO "b1capi: appl %d ncci 0x%x forced down!\n", appl, np->ncci);
+ kfree(np);
+ nextpp = pp;
+ } else {
+ nextpp = &(*pp)->next;
+ }
+ }
+ }
+ set_bit(CARDNR(card), &notify_down_set);
+ queue_task(&tq_state_notify, &tq_scheduler);
+ printk(KERN_NOTICE "b1capi: card %d down.\n", CARDNR(card));
}
/* ------------------------------------------------------------- */
-int avmb1_addcard(int port, int irq)
+
+int avmb1_registercard(int port, int irq, int cardtype, int allocio)
{
struct avmb1_card *card;
- int irqval;
+ int irqval,i;
+
+ for (i=0; i < CAPI_MAXCONTR && cards[i].cardstate != CARD_FREE; i++) ;
+
+ if (i == CAPI_MAXCONTR) {
+ printk(KERN_ERR "b1capi: out of controller slots\n");
+ return -ENFILE;
+ }
- card = &cards[ncards];
+ card = &cards[i];
memset(card, 0, sizeof(avmb1_card));
- sprintf(card->name, "avmb1-%d", ncards + 1);
+ sprintf(card->name, "avmb1-%d", CARDNR(card));
- request_region(port, AVMB1_PORTLEN, card->name);
+ if (allocio)
+ request_region(port, AVMB1_PORTLEN, card->name);
- if ((irqval = request_irq(irq, avmb1_interrupt, SA_SHIRQ, card->name, card)) != 0) {
+ if ((irqval = request_irq(irq, avmb1_interrupt,
+ SA_SHIRQ, card->name, card)) != 0) {
printk(KERN_ERR "b1capi: unable to get IRQ %d (irqval=%d).\n",
irq, irqval);
release_region((unsigned short) port, AVMB1_PORTLEN);
return -EIO;
}
+
+ card->cardstate = CARD_DETECTED;
ncards++;
- card->cnr = ncards;
+ card->cnr = CARDNR(card);
card->port = port;
card->irq = irq;
- card->cardstate = CARD_DETECTED;
- return 0;
+ card->cardtype = cardtype;
+ return card->cnr;
+}
+
+int avmb1_addcard(int port, int irq, int cardtype)
+{
+ return avmb1_registercard(port, irq, cardtype, 1);
}
-int avmb1_probecard(int port, int irq)
+int avmb1_detectcard(int port, int irq, int cardtype)
{
int rc;
- if (check_region((unsigned short) port, AVMB1_PORTLEN)) {
- printk(KERN_WARNING
- "b1capi: ports 0x%03x-0x%03x in use.\n",
- portbase, portbase + AVMB1_PORTLEN);
+ if (!B1_valid_irq(irq, cardtype)) {
+ printk(KERN_WARNING "b1capi: irq %d not valid for %s-card.\n",
+ irq, cardtype2str(cardtype));
return -EIO;
}
- if (!B1_valid_irq(irq)) {
- printk(KERN_WARNING "b1capi: irq %d not valid.\n", irq);
+ if ((rc = B1_detect(port, cardtype)) != 0) {
+ printk(KERN_NOTICE "b1capi: NO %s-card at 0x%x (%d)\n",
+ cardtype2str(cardtype), port, rc);
return -EIO;
}
- if ((rc = B1_detect(port)) != 0) {
- printk(KERN_NOTICE "b1capi: NO card at 0x%x (%d)\n", port, rc);
+ B1_reset(port);
+ switch (cardtype) {
+ default:
+ case AVM_CARDTYPE_M1:
+ case AVM_CARDTYPE_M2:
+ case AVM_CARDTYPE_B1:
+ printk(KERN_NOTICE "b1capi: AVM-%s-Controller detected at 0x%x\n", cardtype2str(cardtype), port);
+ break;
+ case AVM_CARDTYPE_T1:
+ printk(KERN_NOTICE "b1capi: AVM-%s-Controller may be at 0x%x\n", cardtype2str(cardtype), port);
+ break;
+ }
+
+ return 0;
+}
+
+int avmb1_probecard(int port, int irq, int cardtype)
+{
+ if (check_region((unsigned short) port, AVMB1_PORTLEN)) {
+ printk(KERN_WARNING
+ "b1capi: ports 0x%03x-0x%03x in use.\n",
+ port, port + AVMB1_PORTLEN);
return -EIO;
}
- B1_reset(port);
- printk(KERN_NOTICE "b1capi: AVM-B1-Controller detected at 0x%x\n", port);
+ return avmb1_detectcard(port, irq, cardtype);
+}
+
+int avmb1_unregistercard(int cnr, int freeio)
+{
+ avmb1_card * card;
+ if (!VALID_CARD(cnr))
+ return -ESRCH;
+ card = CARD(cnr);
+ if (card->cardstate == CARD_FREE)
+ return -ESRCH;
+ if (card->cardstate == CARD_RUNNING)
+ avmb1_card_down(card, freeio);
+
+ free_irq(card->irq, card);
+ if (freeio)
+ release_region(card->port, AVMB1_PORTLEN);
+ card->cardstate = CARD_FREE;
+ return 0;
+}
+
+int avmb1_resetcard(int cnr)
+{
+ avmb1_card * card;
+
+ if (!VALID_CARD(cnr))
+ return -ESRCH;
+ card = CARD(cnr);
+ if (card->cardstate == CARD_FREE)
+ return -ESRCH;
+
+ if (card->cardstate == CARD_RUNNING)
+ avmb1_card_down(card, 0);
+
+ B1_reset(card->port);
+ B1_reset(card->port);
+
+ card->cardstate = CARD_DETECTED;
return 0;
}
@@ -485,7 +658,7 @@ int avmb1_probecard(int port, int irq)
static int capi_installed(void)
{
int i;
- for (i = 0; i < ncards; i++) {
+ for (i = 0; i < CAPI_MAXCONTR; i++) {
if (cards[i].cardstate == CARD_RUNNING)
return 1;
}
@@ -512,7 +685,7 @@ static __u16 capi_register(capi_register_params * rparam, __u16 * applidp)
memcpy(&APPL(appl)->rparam, rparam, sizeof(capi_register_params));
- for (i = 0; i < ncards; i++) {
+ for (i = 0; i < CAPI_MAXCONTR; i++) {
if (cards[i].cardstate != CARD_RUNNING)
continue;
B1_send_register(cards[i].port, appl,
@@ -538,9 +711,10 @@ static __u16 capi_release(__u16 applid)
return CAPI_ILLAPPNR;
while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0)
kfree_skb(skb);
- for (i = 0; i < ncards; i++) {
- if (cards[i].cardstate != CARD_RUNNING)
+ for (i = 0; i < CAPI_MAXCONTR; i++) {
+ if (cards[i].cardstate != CARD_RUNNING) {
continue;
+ }
APPL(applid)->releasing++;
B1_send_release(cards[i].port, applid);
}
@@ -628,7 +802,7 @@ static __u16 capi_get_version(__u16 contr, struct capi_version *verp)
if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING)
return 0x2002;
- memcpy((void *) verp, CARD(contr)->version[VER_SERIAL],
+ memcpy((void *) verp, &CARD(contr)->cversion,
sizeof(capi_version));
return CAPI_NOERROR;
}
@@ -665,33 +839,52 @@ static __u16 capi_get_profile(__u16 contr, struct capi_profile *profp)
static int capi_manufacturer(unsigned int cmd, void *data)
{
unsigned long flags;
- avmb1_loaddef ldef;
- avmb1_carddef cdef;
+ avmb1_loadandconfigdef ldef;
+ avmb1_extcarddef cdef;
avmb1_resetdef rdef;
+ avmb1_getdef gdef;
avmb1_card *card;
int rc;
switch (cmd) {
case AVMB1_ADDCARD:
- if ((rc = copy_from_user((void *) &cdef, data,
- sizeof(avmb1_carddef))))
- return rc;
- if (!B1_valid_irq(cdef.irq))
- return -EINVAL;
+ case AVMB1_ADDCARD_WITH_TYPE:
+ if (cmd == AVMB1_ADDCARD) {
+ if ((rc = copy_from_user((void *) &cdef, data,
+ sizeof(avmb1_carddef))))
+ return rc;
+ cdef.cardtype = AVM_CARDTYPE_B1;
+ } else {
+ if ((rc = copy_from_user((void *) &cdef, data,
+ sizeof(avmb1_extcarddef))))
+ return rc;
+ }
- if ((rc = avmb1_probecard(cdef.port, cdef.irq)) != 0)
+ if ((rc = avmb1_probecard(cdef.port, cdef.irq, cdef.cardtype)) != 0)
return rc;
- return avmb1_addcard(cdef.port, cdef.irq);
+ return avmb1_addcard(cdef.port, cdef.irq, cdef.cardtype);
case AVMB1_LOAD:
+ case AVMB1_LOAD_AND_CONFIG:
+
+ if (cmd == AVMB1_LOAD) {
+ if ((rc = copy_from_user((void *) &ldef, data,
+ sizeof(avmb1_loaddef))))
+ return rc;
+ ldef.t4config.len = 0;
+ ldef.t4config.data = 0;
+ } else {
+ if ((rc = copy_from_user((void *) &ldef, data,
+ sizeof(avmb1_loadandconfigdef))))
+ return rc;
+ }
+ if (!VALID_CARD(ldef.contr))
+ return -ESRCH;
- if ((rc = copy_from_user((void *) &ldef, data,
- sizeof(avmb1_loaddef))))
- return rc;
- if (!VALID_CARD(ldef.contr) || ldef.t4file.len <= 0) {
+ if (ldef.t4file.len <= 0) {
if (loaddebug)
- printk(KERN_DEBUG "b1capi: load: invalid parameter contr=%d len=%d\n", ldef.contr, ldef.t4file.len);
+ printk(KERN_DEBUG "b1capi: load: invalid parameter length of t4file is %d ?\n", ldef.t4file.len);
return -EINVAL;
}
@@ -720,6 +913,20 @@ static int capi_manufacturer(unsigned int cmd, void *data)
return rc;
}
B1_disable_irq(card->port);
+
+ if (ldef.t4config.len > 0) { /* load config */
+ if (loaddebug) {
+ printk(KERN_DEBUG "b1capi: loading config to contr %d\n",
+ ldef.contr);
+ }
+ if ((rc = B1_load_config(card->port, &ldef.t4config))) {
+ B1_reset(card->port);
+ printk(KERN_ERR "b1capi: failed to load config!!\n");
+ card->cardstate = CARD_DETECTED;
+ return rc;
+ }
+ }
+
if (loaddebug) {
printk(KERN_DEBUG "b1capi: load: ready contr %d: checking\n",
ldef.contr);
@@ -737,7 +944,7 @@ static int capi_manufacturer(unsigned int cmd, void *data)
card->cardstate = CARD_INITSTATE;
save_flags(flags);
cli();
- B1_assign_irq(card->port, card->irq);
+ B1_assign_irq(card->port, card->irq, card->cardtype);
B1_enable_irq(card->port);
restore_flags(flags);
@@ -766,23 +973,31 @@ static int capi_manufacturer(unsigned int cmd, void *data)
return -EINTR;
}
return 0;
+
case AVMB1_RESETCARD:
if ((rc = copy_from_user((void *) &rdef, data,
sizeof(avmb1_resetdef))))
return rc;
- if (!VALID_CARD(rdef.contr))
- return -EINVAL;
+ return avmb1_resetcard(rdef.contr);
+
+ case AVMB1_GET_CARDINFO:
+ if ((rc = copy_from_user((void *) &gdef, data,
+ sizeof(avmb1_getdef))))
+ return rc;
- card = CARD(rdef.contr);
+ if (!VALID_CARD(gdef.contr))
+ return -ESRCH;
- if (card->cardstate == CARD_RUNNING)
- return -EBUSY;
+ card = CARD(gdef.contr);
- B1_reset(card->port);
- B1_reset(card->port);
+ gdef.cardstate = card->cardstate;
+ gdef.cardtype = card->cardtype;
+
+ if ((rc = copy_to_user(data, (void *) &gdef,
+ sizeof(avmb1_getdef))))
+ return rc;
- card->cardstate = CARD_DETECTED;
return 0;
}
return -EINVAL;
@@ -845,22 +1060,14 @@ int detach_capi_interface(struct capi_interface_user *userp)
/* -------- Init & Cleanup ------------------------------------- */
/* ------------------------------------------------------------- */
-#ifdef HAS_NEW_SYMTAB
EXPORT_SYMBOL(attach_capi_interface);
EXPORT_SYMBOL(detach_capi_interface);
EXPORT_SYMBOL(avmb1_addcard);
EXPORT_SYMBOL(avmb1_probecard);
-#else
-static struct symbol_table capidev_syms =
-{
-#include <linux/symtab_begin.h>
- X(attach_capi_interface),
- X(detach_capi_interface),
- X(avmb1_addcard),
- X(avmb1_probecard),
-#include <linux/symtab_end.h>
-};
-#endif
+EXPORT_SYMBOL(avmb1_registercard);
+EXPORT_SYMBOL(avmb1_unregistercard);
+EXPORT_SYMBOL(avmb1_resetcard);
+EXPORT_SYMBOL(avmb1_detectcard);
/*
@@ -876,11 +1083,6 @@ int avmb1_init(void)
char *p;
char rev[10];
-
-#ifndef HAS_NEW_SYMTAB
- /* No symbols to export, hide all symbols */
- register_symtab(&capidev_syms);
-#endif
skb_queue_head_init(&recv_queue);
/* init_bh(CAPI_BH, do_capi_bh); */
@@ -899,15 +1101,7 @@ int avmb1_init(void)
strcpy(rev, " ??? ");
#ifdef MODULE
- if (portbase) {
- int rc;
- if ((rc = avmb1_probecard(portbase, irq)) != 0)
- return rc;
- if ((rc = avmb1_addcard(portbase, irq)) != 0)
- return rc;
- } else {
- printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: loaded\n", rev);
- }
+ printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: loaded\n", rev);
#else
printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: started\n", rev);
#endif
@@ -929,20 +1123,20 @@ void cleanup_module(void)
strcpy(rev, " ??? ");
}
- for (i = 0; i < ncards; i++) {
- /*
- * disable card
- */
- B1_disable_irq(cards[i].port);
- B1_reset(cards[i].port);
- B1_reset(cards[i].port);
- /*
- * free kernel resources
- */
- free_irq(cards[i].irq, &cards[i]);
- release_region(cards[i].port, AVMB1_PORTLEN);
-
+ for (i = 0; i < CAPI_MAXCONTR; i++) {
+ if (cards[i].cardstate != CARD_FREE) {
+ /*
+ * disable card
+ */
+ B1_disable_irq(cards[i].port);
+ avmb1_resetcard(i+1);
+ /*
+ * free kernel resources
+ */
+ avmb1_unregistercard(i+1, 1);
+ }
}
+ schedule(); /* execute queued tasks .... */
printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: unloaded\n", rev);
}
#endif
diff --git a/drivers/isdn/avmb1/b1lli.c b/drivers/isdn/avmb1/b1lli.c
index 64292ef21..1c4c0b806 100644
--- a/drivers/isdn/avmb1/b1lli.c
+++ b/drivers/isdn/avmb1/b1lli.c
@@ -1,11 +1,35 @@
/*
- * $Id: b1lli.c,v 1.1 1997/03/04 21:50:28 calle Exp $
+ * $Id: b1lli.c,v 1.6 1998/02/13 07:09:11 calle Exp $
*
* ISDN lowlevel-module for AVM B1-card.
*
* (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1lli.c,v $
+ * Revision 1.6 1998/02/13 07:09:11 calle
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.5 1998/01/31 11:14:41 calle
+ * merged changes to 2.0 tree, prepare 2.1.82 to work.
+ *
+ * Revision 1.4 1997/12/10 20:00:48 calle
+ * get changes from 2.0 version
+ *
+ * Revision 1.1.2.2 1997/11/26 10:46:55 calle
+ * prepared for M1 (Mobile) and T1 (PMX) cards.
+ * prepared to set configuration after load to support other D-channel
+ * protocols, point-to-point and leased lines.
+ *
+ * Revision 1.3 1997/10/01 09:21:13 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.2 1997/07/13 12:22:42 calle
+ * bug fix for more than one controller in connect_req.
+ * debugoutput now with contrnr.
+ *
+ *
* Revision 1.1 1997/03/04 21:50:28 calle
* Frirst version in isdn4linux
*
@@ -66,6 +90,9 @@
* B3Length data ....
*/
+#define SEND_CONFIG 0x21 /*
+ */
+
/*
* LLI Messages from the ISDN-ControllerISDN Controller
*/
@@ -110,6 +137,9 @@
* int32 AppllID int32 0xffffffff
*/
+#define WRITE_REGISTER 0x00
+#define READ_REGISTER 0x01
+
/*
* port offsets
*/
@@ -120,7 +150,11 @@
#define B1_OUTSTAT 0x03
#define B1_RESET 0x10
#define B1_ANALYSE 0x04
+#define B1_IDENT 0x17 /* Hema card T1 */
+#define B1_IRQ_MASTER 0x12 /* Hema card T1 */
+#define B1_STAT0(cardtype) ((cardtype) == AVM_CARDTYPE_M1 ? 0x81200000l : 0x80A00000l)
+#define B1_STAT1(cardtype) (0x80E00000l)
static inline unsigned char b1outp(unsigned short base,
@@ -131,6 +165,100 @@ static inline unsigned char b1outp(unsigned short base,
return inb(base + B1_ANALYSE);
}
+static inline int B1_rx_full(unsigned short base)
+{
+ return inb(base + B1_INSTAT) & 0x1;
+}
+
+static inline unsigned char B1_get_byte(unsigned short base)
+{
+ unsigned long i = jiffies + 5 * HZ; /* maximum wait time 5 sec */
+ while (!B1_rx_full(base) && i > jiffies);
+ if (B1_rx_full(base))
+ return inb(base + B1_READ);
+ printk(KERN_CRIT "b1lli: rx not full after 5 second\n");
+ return 0;
+}
+
+static inline unsigned int B1_get_word(unsigned short base)
+{
+ unsigned int val = 0;
+ val |= B1_get_byte(base);
+ val |= (B1_get_byte(base) << 8);
+ val |= (B1_get_byte(base) << 16);
+ val |= (B1_get_byte(base) << 24);
+ return val;
+}
+
+static inline int B1_tx_empty(unsigned short base)
+{
+ return inb(base + B1_OUTSTAT) & 0x1;
+}
+
+static inline void B1_put_byte(unsigned short base, unsigned char val)
+{
+ while (!B1_tx_empty(base));
+ b1outp(base, B1_WRITE, val);
+}
+
+static inline void B1_put_word(unsigned short base, unsigned int val)
+{
+ B1_put_byte(base, val & 0xff);
+ B1_put_byte(base, (val >> 8) & 0xff);
+ B1_put_byte(base, (val >> 16) & 0xff);
+ B1_put_byte(base, (val >> 24) & 0xff);
+}
+
+static inline unsigned int B1_get_slice(unsigned short base,
+ unsigned char *dp)
+{
+ unsigned int len, i;
+
+ len = i = B1_get_word(base);
+ while (i-- > 0)
+ *dp++ = B1_get_byte(base);
+ return len;
+}
+
+static inline void B1_put_slice(unsigned short base,
+ unsigned char *dp, unsigned int len)
+{
+ B1_put_word(base, len);
+ while (len-- > 0)
+ B1_put_byte(base, *dp++);
+}
+
+static void b1_wr_reg(unsigned short base,
+ unsigned int reg,
+ unsigned int value)
+{
+ B1_put_byte(base, WRITE_REGISTER);
+ B1_put_word(base, reg);
+ B1_put_word(base, value);
+}
+
+static inline unsigned int b1_rd_reg(unsigned short base,
+ unsigned int reg)
+{
+ B1_put_byte(base, READ_REGISTER);
+ B1_put_word(base, reg);
+ return B1_get_word(base);
+
+}
+
+static inline void b1_set_test_bit(unsigned short base,
+ int cardtype,
+ int onoff)
+{
+ b1_wr_reg(base, B1_STAT0(cardtype), onoff ? 0x21 : 0x20);
+}
+
+static inline int b1_get_test_bit(unsigned short base,
+ int cardtype)
+{
+ return (b1_rd_reg(base, B1_STAT0(cardtype)) & 0x01) != 0;
+}
+
static int irq_table[16] =
{0,
0,
@@ -150,14 +278,30 @@ static int irq_table[16] =
112, /* irq 15 */
};
-int B1_valid_irq(unsigned irq)
+int B1_valid_irq(unsigned irq, int cardtype)
{
- return irq_table[irq] != 0;
+ switch (cardtype) {
+ default:
+ case AVM_CARDTYPE_M1:
+ case AVM_CARDTYPE_M2:
+ case AVM_CARDTYPE_B1:
+ return irq_table[irq] != 0;
+ case AVM_CARDTYPE_T1:
+ return irq == 5;
+ }
}
-unsigned char B1_assign_irq(unsigned short base, unsigned irq)
+unsigned char B1_assign_irq(unsigned short base, unsigned irq, int cardtype)
{
- return b1outp(base, B1_RESET, irq_table[irq]);
+ switch (cardtype) {
+ case AVM_CARDTYPE_T1:
+ return b1outp(base, B1_IRQ_MASTER, 0x08);
+ default:
+ case AVM_CARDTYPE_M1:
+ case AVM_CARDTYPE_M2:
+ case AVM_CARDTYPE_B1:
+ return b1outp(base, B1_RESET, irq_table[irq]);
+ }
}
unsigned char B1_enable_irq(unsigned short base)
@@ -182,24 +326,27 @@ void B1_reset(unsigned short base)
udelay(55 * 2 * 1000); /* 2 TIC's */
}
-int B1_detect(unsigned short base)
+int B1_detect(unsigned short base, int cardtype)
{
+ int onoff, i;
+
+ if (cardtype == AVM_CARDTYPE_T1)
+ return 0;
+
/*
* Statusregister 0000 00xx
*/
if ((inb(base + B1_INSTAT) & 0xfc)
|| (inb(base + B1_OUTSTAT) & 0xfc))
return 1;
-
/*
* Statusregister 0000 001x
*/
b1outp(base, B1_INSTAT, 0x2); /* enable irq */
- b1outp(base, B1_OUTSTAT, 0x2);
+ /* b1outp(base, B1_OUTSTAT, 0x2); */
if ((inb(base + B1_INSTAT) & 0xfe) != 0x2
- || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2)
+ /* || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2 */)
return 2;
-
/*
* Statusregister 0000 000x
*/
@@ -208,72 +355,23 @@ int B1_detect(unsigned short base)
if ((inb(base + B1_INSTAT) & 0xfe)
|| (inb(base + B1_OUTSTAT) & 0xfe))
return 3;
+
+ for (onoff = !0, i= 0; i < 10 ; i++) {
+ b1_set_test_bit(base, cardtype, onoff);
+ if (b1_get_test_bit(base, cardtype) != onoff)
+ return 4;
+ onoff = !onoff;
+ }
- return 0;
-}
+ if (cardtype == AVM_CARDTYPE_M1)
+ return 0;
-static inline int B1_rx_full(unsigned short base)
-{
- return inb(base + B1_INSTAT) & 0x1;
-}
+ if ((b1_rd_reg(base, B1_STAT1(cardtype)) & 0x0f) != 0x01)
+ return 5;
-static inline unsigned char B1_get_byte(unsigned short base)
-{
- unsigned long i = jiffies + 5 * HZ; /* maximum wait time 5 sec */
- while (!B1_rx_full(base) && i > jiffies);
- if (B1_rx_full(base))
- return inb(base + B1_READ);
- printk(KERN_CRIT "b1lli: rx not full after 5 second\n");
return 0;
}
-static inline unsigned int B1_get_word(unsigned short base)
-{
- unsigned int val = 0;
- val |= B1_get_byte(base);
- val |= (B1_get_byte(base) << 8);
- val |= (B1_get_byte(base) << 16);
- val |= (B1_get_byte(base) << 24);
- return val;
-}
-
-static inline int B1_tx_empty(unsigned short base)
-{
- return inb(base + B1_OUTSTAT) & 0x1;
-}
-
-static inline void B1_put_byte(unsigned short base, unsigned char val)
-{
- while (!B1_tx_empty(base));
- b1outp(base, B1_WRITE, val);
-}
-
-static inline void B1_put_word(unsigned short base, unsigned int val)
-{
- B1_put_byte(base, val & 0xff);
- B1_put_byte(base, (val >> 8) & 0xff);
- B1_put_byte(base, (val >> 16) & 0xff);
- B1_put_byte(base, (val >> 24) & 0xff);
-}
-
-static inline unsigned int B1_get_slice(unsigned short base,
- unsigned char *dp)
-{
- unsigned int len, i;
-
- len = i = B1_get_word(base);
- while (i-- > 0)
- *dp++ = B1_get_byte(base);
- return len;
-}
-
-static inline void B1_put_slice(unsigned short base,
- unsigned char *dp, unsigned int len)
-{
- B1_put_word(base, len);
- while (len-- > 0)
- B1_put_byte(base, *dp++);
-}
extern int loaddebug;
@@ -316,6 +414,62 @@ int B1_load_t4file(unsigned short base, avmb1_t4file * t4file)
return 0;
}
+int B1_load_config(unsigned short base, avmb1_t4file * config)
+{
+ /*
+ * Data is in user space !!!
+ */
+ unsigned char buf[256];
+ unsigned char *dp;
+ int i, j, left, retval;
+
+
+ dp = config->data;
+ left = config->len;
+ if (left) {
+ B1_put_byte(base, SEND_CONFIG);
+ B1_put_word(base, 1);
+ B1_put_byte(base, SEND_CONFIG);
+ B1_put_word(base, left);
+ }
+ while (left > sizeof(buf)) {
+ retval = copy_from_user(buf, dp, sizeof(buf));
+ if (retval)
+ return -EFAULT;
+ if (loaddebug)
+ printk(KERN_DEBUG "b1capi: conf load: %d bytes ..", sizeof(buf));
+ for (i = 0; i < sizeof(buf); ) {
+ B1_put_byte(base, SEND_CONFIG);
+ for (j=0; j < 4; j++) {
+ B1_put_byte(base, buf[i++]);
+ }
+ }
+ if (loaddebug)
+ printk("ok\n");
+ left -= sizeof(buf);
+ dp += sizeof(buf);
+ }
+ if (left) {
+ retval = copy_from_user(buf, dp, left);
+ if (retval)
+ return -EFAULT;
+ if (loaddebug)
+ printk(KERN_DEBUG "b1capi: conf load: %d bytes ..", left);
+ for (i = 0; i < left; ) {
+ B1_put_byte(base, SEND_CONFIG);
+ for (j=0; j < 4; j++) {
+ if (i < left)
+ B1_put_byte(base, buf[i++]);
+ else
+ B1_put_byte(base, 0);
+ }
+ }
+ if (loaddebug)
+ printk("ok\n");
+ }
+ return 0;
+}
+
int B1_loaded(unsigned short base)
{
int i;
@@ -428,7 +582,9 @@ void B1_send_message(unsigned short port, struct sk_buff *skb)
CAPIMSG_APPID(skb->data),
capi_cmd2str(cmd, subcmd), len);
} else {
- printk(KERN_DEBUG "b1lli: Put %s\n", capi_message2str(skb->data));
+ printk(KERN_DEBUG "b1lli: Put [0x%lx] %s\n",
+ (unsigned long) contr,
+ capi_message2str(skb->data));
}
}
@@ -447,7 +603,7 @@ void B1_send_message(unsigned short port, struct sk_buff *skb)
CAPIMSG_APPID(skb->data),
capi_cmd2str(cmd, subcmd), len);
} else {
- printk(KERN_DEBUG "b1lli: Put %s\n", capi_message2str(skb->data));
+ printk(KERN_DEBUG "b1lli: Put [0x%lx] %s\n", (unsigned long)contr, capi_message2str(skb->data));
}
}
save_flags(flags);
@@ -499,13 +655,12 @@ void B1_handle_interrupt(avmb1_card * card)
capi_cmd2str(cmd, subcmd),
MsgLen, DataB3Len);
} else {
- printk(KERN_DEBUG "b1lli: Got %s\n", capi_message2str(card->msgbuf));
+ printk(KERN_DEBUG "b1lli: Got [0x%lx] %s\n", (unsigned long)contr, capi_message2str(card->msgbuf));
}
}
if (!(skb = dev_alloc_skb(DataB3Len + MsgLen))) {
printk(KERN_ERR "b1lli: incoming packet dropped\n");
} else {
- SET_SKB_FREE(skb);
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
CAPIMSG_SETDATA(skb->data, skb->data + MsgLen);
@@ -528,14 +683,15 @@ void B1_handle_interrupt(avmb1_card * card)
capi_cmd2str(cmd, subcmd),
MsgLen);
} else {
- printk(KERN_DEBUG "b1lli: Got %s\n", capi_message2str(card->msgbuf));
+ printk(KERN_DEBUG "b1lli: Got [0x%lx] %s\n",
+ (unsigned long) contr,
+ capi_message2str(card->msgbuf));
}
}
if (!(skb = dev_alloc_skb(MsgLen))) {
printk(KERN_ERR "b1lli: incoming packet dropped\n");
} else {
- SET_SKB_FREE(skb);
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
avmb1_handle_capimsg(card, ApplId, skb);
}
@@ -581,10 +737,9 @@ void B1_handle_interrupt(avmb1_card * card)
card->versionlen = B1_get_slice(card->port, card->versionbuf);
card->cardstate = CARD_ACTIVE;
parse_version(card);
- printk(KERN_INFO "b1lli: %s-card (%s) with %s now active\n",
+ printk(KERN_INFO "b1lli: %s-card (%s) now active\n",
card->version[VER_CARDTYPE],
- card->version[VER_DRIVER],
- card->version[VER_PROTO]);
+ card->version[VER_DRIVER]);
avmb1_card_ready(card);
break;
default:
diff --git a/drivers/isdn/avmb1/b1pci.c b/drivers/isdn/avmb1/b1pci.c
index af7b58407..5a31d7992 100644
--- a/drivers/isdn/avmb1/b1pci.c
+++ b/drivers/isdn/avmb1/b1pci.c
@@ -1,11 +1,22 @@
/*
- * $Id: b1pci.c,v 1.2 1997/05/18 09:24:13 calle Exp $
+ * $Id: b1pci.c,v 1.5 1998/01/31 11:14:43 calle Exp $
*
* Module for AVM B1 PCI-card.
*
* (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1pci.c,v $
+ * Revision 1.5 1998/01/31 11:14:43 calle
+ * merged changes to 2.0 tree, prepare 2.1.82 to work.
+ *
+ * Revision 1.4 1997/12/10 20:00:50 calle
+ * get changes from 2.0 version
+ *
+ * Revision 1.3 1997/10/01 09:21:14 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
* Revision 1.2 1997/05/18 09:24:13 calle
* added verbose disconnect reason reporting to avmb1.
* some fixes in capi20 interface.
@@ -19,7 +30,6 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/skbuff.h>
#include "compat.h"
@@ -34,13 +44,11 @@
#define PCI_DEVICE_ID_AVM_B1 0x700
#endif
-static char *revision = "$Revision: 1.2 $";
+static char *revision = "$Revision: 1.5 $";
/* ------------------------------------------------------------- */
-#ifdef HAS_NEW_SYMTAB
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
-#endif
/* ------------------------------------------------------------- */
@@ -61,7 +69,7 @@ int b1pci_init(void)
char *p;
char rev[10];
int rc;
- int pci_index;
+ struct pci_dev *dev = NULL;
if ((p = strchr(revision, ':'))) {
strcpy(rev, p + 1);
@@ -72,39 +80,26 @@ int b1pci_init(void)
#ifdef CONFIG_PCI
- if (!pcibios_present()) {
- printk(KERN_ERR "b1pci: no PCI-BIOS present\n");
+ if (!pci_present()) {
+ printk(KERN_ERR "b1pci: no PCI bus present\n");
return -EIO;
}
printk(KERN_INFO "b1pci: revision %s\n", rev);
- for (pci_index = 0; pci_index < 8; pci_index++) {
- unsigned char pci_bus, pci_device_fn;
- unsigned int ioaddr;
- unsigned char irq;
-
- if (pcibios_find_device (PCI_VENDOR_ID_AVM,
- PCI_DEVICE_ID_AVM_B1, pci_index,
- &pci_bus, &pci_device_fn) != 0) {
- continue;
- }
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &irq);
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_1, &ioaddr);
- /* Strip the I/O address out of the returned value */
- ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
+ while (dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, dev)) {
+ unsigned int ioaddr = dev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
+ unsigned int irq = dev->irq;
printk(KERN_INFO
"b1pci: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
ioaddr, irq);
- if ((rc = avmb1_probecard(ioaddr, irq)) != 0) {
+ if ((rc = avmb1_probecard(ioaddr, irq, AVM_CARDTYPE_B1)) != 0) {
printk(KERN_ERR
"b1pci: no AVM-B1 at i/o %#x, irq %d detected\n",
ioaddr, irq);
return rc;
}
- if ((rc = avmb1_addcard(ioaddr, irq)) != 0)
+ if ((rc = avmb1_addcard(ioaddr, irq, AVM_CARDTYPE_B1)) < 0)
return rc;
}
return 0;
diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c
index 14a5e7d0f..67c39c675 100644
--- a/drivers/isdn/avmb1/capi.c
+++ b/drivers/isdn/avmb1/capi.c
@@ -1,11 +1,34 @@
/*
- * $Id: capi.c,v 1.4 1997/05/27 15:17:50 fritz Exp $
+ * $Id: capi.c,v 1.10 1998/02/13 07:09:13 calle Exp $
*
* CAPI 2.0 Interface for Linux
*
* Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capi.c,v $
+ * Revision 1.10 1998/02/13 07:09:13 calle
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.9 1998/01/31 11:14:44 calle
+ * merged changes to 2.0 tree, prepare 2.1.82 to work.
+ *
+ * Revision 1.8 1997/11/04 06:12:08 calle
+ * capi.c: new read/write in file_ops since 2.1.60
+ * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
+ * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
+ * compat.h: added #define LinuxVersionCode
+ *
+ * Revision 1.7 1997/10/11 10:29:34 calle
+ * llseek() parameters changed in 2.1.56.
+ *
+ * Revision 1.6 1997/10/01 09:21:15 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.5 1997/08/21 23:11:55 fritz
+ * Added changes for kernels >= 2.1.45
+ *
* Revision 1.4 1997/05/27 15:17:50 fritz
* Added changes for recent 2.1.x kernels:
* changed return type of isdn_close
@@ -45,26 +68,22 @@
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/skbuff.h>
+#include <linux/poll.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
-#include <linux/poll.h>
#include "compat.h"
#include "capiutil.h"
#include "capicmd.h"
#include "capidev.h"
-#ifdef HAS_NEW_SYMTAB
MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
-#endif
/* -------- driver information -------------------------------------- */
int capi_major = 68; /* allocated */
-#ifdef HAS_NEW_SYMTAB
MODULE_PARM(capi_major, "i");
-#endif
/* -------- global variables ---------------------------------------- */
@@ -94,21 +113,25 @@ static void capi_signal(__u16 applid, __u32 minor)
/* -------- file_operations ----------------------------------------- */
-static loff_t capi_llseek(struct file *file, loff_t offset, int origin)
+static long long capi_llseek(struct file *file,
+ long long offset, int origin)
{
return -ESPIPE;
}
-static ssize_t capi_read(struct file *file,
- char *buf, size_t count,
- loff_t *off)
+static ssize_t capi_read(struct file *file, char *buf,
+ size_t count, loff_t *ppos)
{
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct inode *inode = file->f_dentry->d_inode;
+ unsigned int minor = MINOR(inode->i_rdev);
struct capidev *cdev;
struct sk_buff *skb;
int retval;
size_t copied;
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
return -ENODEV;
@@ -149,11 +172,11 @@ static ssize_t capi_read(struct file *file,
return copied;
}
-static ssize_t capi_write(struct file *file,
- const char *buf, size_t count,
- loff_t *off)
+static ssize_t capi_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
{
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct inode *inode = file->f_dentry->d_inode;
+ unsigned int minor = MINOR(inode->i_rdev);
struct capidev *cdev;
struct sk_buff *skb;
int retval;
@@ -161,6 +184,9 @@ static ssize_t capi_write(struct file *file,
__u8 subcmd;
__u16 mlen;
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
return -ENODEV;
@@ -200,7 +226,11 @@ static unsigned int
capi_poll(struct file *file, poll_table * wait)
{
unsigned int mask = 0;
+#if (LINUX_VERSION_CODE >= 0x02012d)
unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+#else
+ unsigned int minor = MINOR(file->f_inode->i_rdev);
+#endif
struct capidev *cdev;
if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
@@ -394,7 +424,7 @@ static int capi_open(struct inode *inode, struct file *file)
return 0;
}
-static CLOSETYPE
+static int
capi_release(struct inode *inode, struct file *file)
{
unsigned int minor = MINOR(inode->i_rdev);
@@ -403,7 +433,7 @@ capi_release(struct inode *inode, struct file *file)
if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) {
printk(KERN_ERR "capi20: release minor %d ???\n", minor);
- return CLOSEVAL;
+ return 0;
}
cdev = &capidevs[minor];
@@ -421,7 +451,7 @@ capi_release(struct inode *inode, struct file *file)
cdev->is_open = 0;
MOD_DEC_USE_COUNT;
- return CLOSEVAL;
+ return 0;
}
static struct file_operations capi_fops =
diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c
index c1dfcdafe..1d4a7c2e8 100644
--- a/drivers/isdn/avmb1/capidrv.c
+++ b/drivers/isdn/avmb1/capidrv.c
@@ -1,11 +1,42 @@
/*
- * $Id: capidrv.c,v 1.3 1997/05/18 09:24:15 calle Exp $
+ * $Id: capidrv.c,v 1.11 1998/02/13 07:09:15 calle Exp $
*
* ISDN4Linux Driver, using capi20 interface (kernelcapi)
*
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capidrv.c,v $
+ * Revision 1.11 1998/02/13 07:09:15 calle
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.10 1998/02/02 19:52:23 calle
+ * Fixed vbox (audio) acceptb.
+ *
+ * Revision 1.9 1998/01/31 11:14:45 calle
+ * merged changes to 2.0 tree, prepare 2.1.82 to work.
+ *
+ * Revision 1.8 1997/11/04 06:12:09 calle
+ * capi.c: new read/write in file_ops since 2.1.60
+ * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
+ * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
+ * compat.h: added #define LinuxVersionCode
+ *
+ * Revision 1.7 1997/10/11 10:36:34 calle
+ * Added isdnlog support. patch to isdnlog needed.
+ *
+ * Revision 1.6 1997/10/11 10:25:55 calle
+ * New interface for lowlevel drivers. BSENT with nr. of bytes sent,
+ * allow sending without ACK.
+ *
+ * Revision 1.5 1997/10/01 09:21:16 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.4 1997/07/13 12:22:43 calle
+ * bug fix for more than one controller in connect_req.
+ * debugoutput now with contrnr.
+ *
* Revision 1.3 1997/05/18 09:24:15 calle
* added verbose disconnect reason reporting to avmb1.
* some fixes in capi20 interface.
@@ -48,13 +79,11 @@
#include "capicmd.h"
#include "capidrv.h"
-static char *revision = "$Revision: 1.3 $";
+static char *revision = "$Revision: 1.11 $";
int debugmode = 0;
-#ifdef HAS_NEW_SYMTAB
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
MODULE_PARM(debugmode, "i");
-#endif
/* -------- type definitions ----------------------------------------- */
@@ -116,14 +145,26 @@ struct capidrv_contr {
int oldstate;
/* */
__u16 datahandle;
+ struct ncci_datahandle_queue {
+ struct ncci_datahandle_queue *next;
+ __u16 datahandle;
+ int len;
+ } *ackqueue;
} *ncci_list;
} *plcip;
struct capidrv_ncci *nccip;
} *bchans;
struct capidrv_plci *plci_list;
+
+ /* for q931 data */
+ __u8 q931_buf[4096];
+ __u8 *q931_read;
+ __u8 *q931_write;
+ __u8 *q931_end;
};
+
struct capidrv_data {
__u16 appid;
int ncontr;
@@ -141,6 +182,9 @@ typedef struct capidrv_bchan capidrv_bchan;
static capidrv_data global;
static struct capi_interface *capifuncs;
+static void handle_dtrace_data(capidrv_contr *card,
+ int send, int level2, __u8 *data, __u16 len);
+
/* -------- convert functions ---------------------------------------- */
static inline __u32 b1prot(int l2, int l3)
@@ -167,9 +211,8 @@ static inline __u32 b2prot(int l2, int l3)
default:
return 0;
case ISDN_PROTO_L2_HDLC:
- return 1;
case ISDN_PROTO_L2_TRANS:
- return 0;
+ return 1;
}
}
@@ -410,6 +453,42 @@ static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip)
kfree(nccip);
}
+static int capidrv_add_ack(struct capidrv_ncci *nccip,
+ __u16 datahandle, int len)
+{
+ struct ncci_datahandle_queue *n, **pp;
+
+ n = (struct ncci_datahandle_queue *)
+ kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
+ if (!n) {
+ printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n");
+ return -1;
+ }
+ n->next = 0;
+ n->datahandle = datahandle;
+ n->len = len;
+ for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ;
+ *pp = n;
+ return 0;
+}
+
+static int capidrv_del_ack(struct capidrv_ncci *nccip, __u16 datahandle)
+{
+ struct ncci_datahandle_queue **pp, *p;
+ int len;
+
+ for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
+ if ((*pp)->datahandle == datahandle) {
+ p = *pp;
+ len = p->len;
+ *pp = (*pp)->next;
+ kfree(p);
+ return len;
+ }
+ }
+ return -1;
+}
+
/* -------- convert and send capi message ---------------------------- */
static void send_message(capidrv_contr * card, _cmsg * cmsg)
@@ -419,7 +498,6 @@ static void send_message(capidrv_contr * card, _cmsg * cmsg)
capi_cmsg2message(cmsg, cmsg->buf);
len = CAPIMSG_LEN(cmsg->buf);
skb = dev_alloc_skb(len);
- SET_SKB_FREE(skb);
memcpy(skb_put(skb, len), cmsg->buf, len);
(*capifuncs->capi_put_message) (global.appid, skb);
}
@@ -686,8 +764,53 @@ static void handle_controller(_cmsg * cmsg)
break;
case CAPI_MANUFACTURER_IND: /* Controller */
+ if ( cmsg->ManuID == 0x214D5641
+ && cmsg->Class == 0
+ && cmsg->Function == 1) {
+ __u8 *data = cmsg->ManuData+3;
+ __u16 len = cmsg->ManuData[0];
+ __u16 layer;
+ int direction;
+ if (len == 255) {
+ len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8));
+ data += 2;
+ }
+ len -= 2;
+ layer = ((*(data-1)) << 8) | *(data-2);
+ if (layer & 0x300)
+ direction = (layer & 0x200) ? 0 : 1;
+ else direction = (layer & 0x800) ? 0 : 1;
+ if (layer & 0x0C00) {
+ if ((layer & 0xff) == 0x80) {
+ handle_dtrace_data(card, direction, 1, data, len);
+ break;
+ }
+ } else if ((layer & 0xff) < 0x80) {
+ handle_dtrace_data(card, direction, 0, data, len);
+ break;
+ }
+ printk(KERN_INFO "capidrv: %s from controller 0x%x layer 0x%x, ignored\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrController, layer);
+ break;
+ }
goto ignored;
case CAPI_MANUFACTURER_CONF: /* Controller */
+ if (cmsg->ManuID == 0x214D5641) {
+ char *s = 0;
+ switch (cmsg->Class) {
+ case 0: break;
+ case 1: s = "unknown class"; break;
+ case 2: s = "unknown function"; break;
+ default: s = "unkown error"; break;
+ }
+ if (s)
+ printk(KERN_INFO "capidrv: %s from controller 0x%x function %d: %s\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrController,
+ cmsg->Function, s);
+ break;
+ }
goto ignored;
case CAPI_FACILITY_IND: /* Controller/plci/ncci */
goto ignored;
@@ -996,6 +1119,7 @@ static void handle_ncci(_cmsg * cmsg)
capidrv_plci *plcip;
capidrv_ncci *nccip;
isdn_ctrl cmd;
+ int len;
if (!card) {
printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
@@ -1093,11 +1217,14 @@ static void handle_ncci(_cmsg * cmsg)
if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
goto notfound;
- cmd.command = ISDN_STAT_BSENT;
- cmd.driver = card->myid;
- cmd.arg = nccip->chan;
- card->interface.statcallb(&cmd);
-
+ len = capidrv_del_ack(nccip, cmsg->DataHandle);
+ if (len < 0)
+ break;
+ cmd.command = ISDN_STAT_BSENT;
+ cmd.driver = card->myid;
+ cmd.arg = nccip->chan;
+ cmd.parm.length = len;
+ card->interface.statcallb(&cmd);
break;
case CAPI_DISCONNECT_B3_IND: /* ncci */
@@ -1206,6 +1333,60 @@ static void capidrv_signal(__u16 applid, __u32 dummy)
/* ------------------------------------------------------------------- */
+#define PUTBYTE_TO_STATUS(card, byte) \
+ do { \
+ *(card)->q931_write++ = (byte); \
+ if ((card)->q931_write > (card)->q931_end) \
+ (card)->q931_write = (card)->q931_buf; \
+ } while (0)
+
+static void handle_dtrace_data(capidrv_contr *card,
+ int send, int level2, __u8 *data, __u16 len)
+{
+ long flags;
+ __u8 *p, *end;
+ isdn_ctrl cmd;
+
+ if (!len) {
+ printk(KERN_DEBUG "avmb1_q931_data: len == %d\n", len);
+ return;
+ }
+
+ save_flags(flags);
+ cli();
+
+ if (level2) {
+ PUTBYTE_TO_STATUS(card, 'D');
+ PUTBYTE_TO_STATUS(card, '2');
+ PUTBYTE_TO_STATUS(card, send ? '>' : '<');
+ PUTBYTE_TO_STATUS(card, ':');
+ } else {
+ PUTBYTE_TO_STATUS(card, 'D');
+ PUTBYTE_TO_STATUS(card, '3');
+ PUTBYTE_TO_STATUS(card, send ? '>' : '<');
+ PUTBYTE_TO_STATUS(card, ':');
+ }
+
+ for (p = data, end = data+len; p < end; p++) {
+ __u8 w;
+ PUTBYTE_TO_STATUS(card, ' ');
+ w = (*p >> 4) & 0xf;
+ PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
+ w = *p & 0xf;
+ PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
+ }
+ PUTBYTE_TO_STATUS(card, '\n');
+
+ restore_flags(flags);
+
+ cmd.command = ISDN_STAT_STAVAIL;
+ cmd.driver = card->myid;
+ cmd.arg = len*3+5;
+ card->interface.statcallb(&cmd);
+}
+
+/* ------------------------------------------------------------------- */
+
static _cmsg cmdcmsg;
static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card)
@@ -1270,7 +1451,7 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
capi_fill_CONNECT_REQ(&cmdcmsg,
global.appid,
card->msgid++,
- 1, /* adr */
+ card->contrnr, /* adr */
si2cip(bchan->si1, bchan->si2), /* cipvalue */
called, /* CalledPartyNumber */
calling, /* CallingPartyNumber */
@@ -1471,7 +1652,7 @@ static int if_command(isdn_ctrl * c)
static _cmsg sendcmsg;
-static int if_sendbuf(int id, int channel, struct sk_buff *skb)
+static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
{
capidrv_contr *card = findcontrbydriverid(id);
capidrv_bchan *bchan;
@@ -1479,6 +1660,7 @@ static int if_sendbuf(int id, int channel, struct sk_buff *skb)
int len = skb->len;
size_t msglen;
__u16 errcode;
+ __u16 datahandle;
if (!card) {
printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
@@ -1492,51 +1674,128 @@ static int if_sendbuf(int id, int channel, struct sk_buff *skb)
card->name, channel);
return 0;
}
+ datahandle = nccip->datahandle;
capi_fill_DATA_B3_REQ(&sendcmsg, global.appid, card->msgid++,
nccip->ncci, /* adr */
(__u32) skb->data, /* Data */
skb->len, /* DataLength */
- nccip->datahandle++, /* DataHandle */
+ datahandle, /* DataHandle */
0 /* Flags */
);
+
+ if (capidrv_add_ack(nccip, datahandle, doack ? skb->len : -1) < 0)
+ return 0;
+
capi_cmsg2message(&sendcmsg, sendcmsg.buf);
msglen = CAPIMSG_LEN(sendcmsg.buf);
if (skb_headroom(skb) < msglen) {
struct sk_buff *nskb = dev_alloc_skb(msglen + skb->len);
if (!nskb) {
printk(KERN_ERR "capidrv: if_sendbuf: no memory\n");
+ (void)capidrv_del_ack(nccip, datahandle);
return 0;
}
#if 0
printk(KERN_DEBUG "capidrv: only %d bytes headroom\n",
skb_headroom(skb));
#endif
- SET_SKB_FREE(nskb);
memcpy(skb_put(nskb, msglen), sendcmsg.buf, msglen);
memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
errcode = (*capifuncs->capi_put_message) (global.appid, nskb);
- switch (errcode) {
- case CAPI_NOERROR:
+ if (errcode == CAPI_NOERROR) {
dev_kfree_skb(skb);
+ nccip->datahandle++;
return len;
- case CAPI_SENDQUEUEFULL:
- dev_kfree_skb(nskb);
- return 0;
- default:
- return -1;
}
+ (void)capidrv_del_ack(nccip, datahandle);
+ dev_kfree_skb(nskb);
+ return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
} else {
memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen);
errcode = (*capifuncs->capi_put_message) (global.appid, skb);
- switch (errcode) {
- case CAPI_NOERROR:
+ if (errcode == CAPI_NOERROR) {
+ nccip->datahandle++;
return len;
- case CAPI_SENDQUEUEFULL:
- return 0;
- default:
- return -1;
}
+ (void)capidrv_del_ack(nccip, datahandle);
+ return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
+ }
+}
+
+static int if_readstat(__u8 *buf, int len, int user, int id, int channel)
+{
+ capidrv_contr *card = findcontrbydriverid(id);
+ int count;
+ __u8 *p;
+
+ if (!card) {
+ printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n",
+ id);
+ return -ENODEV;
+ }
+
+ for (p=buf, count=0; count < len; p++, count++) {
+ if (user)
+ put_user(*card->q931_read++, p);
+ else
+ *p = *card->q931_read++;
+ if (card->q931_read > card->q931_end)
+ card->q931_read = card->q931_buf;
+ }
+ return count;
+
+}
+
+static void enable_dchannel_trace(capidrv_contr *card)
+{
+ __u8 manufacturer[CAPI_MANUFACTURER_LEN];
+ capi_version version;
+ __u16 contr = card->contrnr;
+ __u16 errcode;
+ __u16 avmversion[3];
+
+ errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer);
+ if (errcode != CAPI_NOERROR) {
+ printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
+ card->name, errcode);
+ return;
+ }
+ if (strstr(manufacturer, "AVM") == 0) {
+ printk(KERN_ERR "%s: not from AVM, no d-channel trace possible\n",
+ card->name);
+ return;
+ }
+ errcode = (*capifuncs->capi_get_version)(contr, &version);
+ if (errcode != CAPI_NOERROR) {
+ printk(KERN_ERR "%s: can't get version (0x%x)\n",
+ card->name, errcode);
+ return;
+ }
+ avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
+ avmversion[1] = (version.majormanuversion << 4) & 0xf0;
+ avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
+ avmversion[2] |= version.minormanuversion & 0x0f;
+
+ if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
+ printk(KERN_INFO "%s: D2 trace enabled\n", card->name);
+ capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
+ card->msgid++,
+ contr,
+ 0x214D5641, /* ManuID */
+ 0, /* Class */
+ 1, /* Function */
+ (_cstruct)"\004\200\014\000\000");
+ } else {
+ printk(KERN_INFO "%s: D3 trace enabled\n", card->name);
+ capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
+ card->msgid++,
+ contr,
+ 0x214D5641, /* ManuID */
+ 0, /* Class */
+ 1, /* Function */
+ (_cstruct)"\004\002\003\000\000");
}
+ send_message(card, &cmdcmsg);
}
static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
@@ -1568,7 +1827,7 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
card->interface.command = if_command;
card->interface.writebuf_skb = if_sendbuf;
card->interface.writecmd = 0;
- card->interface.readstat = 0;
+ card->interface.readstat = if_readstat;
card->interface.features = ISDN_FEATURE_L2_X75I |
ISDN_FEATURE_L2_X75UI |
ISDN_FEATURE_L2_X75BUI |
@@ -1581,6 +1840,9 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
card->next = global.contr_list;
global.contr_list = card;
global.ncontr++;
+ card->q931_read = card->q931_buf;
+ card->q931_write = card->q931_buf;
+ card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
if (!register_isdn(&card->interface)) {
global.contr_list = global.contr_list->next;
@@ -1600,7 +1862,7 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
cmd.command = ISDN_STAT_RUN;
card->interface.statcallb(&cmd);
- card->cipmask = 1; /* any */
+ card->cipmask = 0x1FFF03FF; /* any */
card->cipmask2 = 0;
capi_fill_LISTEN_REQ(&cmdcmsg, global.appid,
@@ -1616,6 +1878,8 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
printk(KERN_INFO "%s: now up (%d B channels)\n",
card->name, card->nbchan);
+ enable_dchannel_trace(card);
+
return 0;
}
@@ -1694,11 +1958,6 @@ int capidrv_init(void)
if (!capifuncs)
return -EIO;
-#ifndef HAS_NEW_SYMTAB
- /* No symbols to export, hide all symbols */
- register_symtab(NULL);
-#endif
-
if ((p = strchr(revision, ':'))) {
strcpy(rev, p + 1);
p = strchr(rev, '$');
diff --git a/drivers/isdn/avmb1/capiutil.c b/drivers/isdn/avmb1/capiutil.c
index 9eb60afed..8eb7d3ae1 100644
--- a/drivers/isdn/avmb1/capiutil.c
+++ b/drivers/isdn/avmb1/capiutil.c
@@ -1,5 +1,5 @@
/*
- * $Id: capiutil.c,v 1.3 1997/05/18 09:24:18 calle Exp $
+ * $Id: capiutil.c,v 1.6 1997/11/04 06:12:12 calle Exp $
*
* CAPI 2.0 convert capi message to capi message struct
*
@@ -7,6 +7,20 @@
* Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capiutil.c,v $
+ * Revision 1.6 1997/11/04 06:12:12 calle
+ * capi.c: new read/write in file_ops since 2.1.60
+ * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
+ * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
+ * compat.h: added #define LinuxVersionCode
+ *
+ * Revision 1.5 1997/10/01 09:21:19 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.4 1997/08/10 07:43:55 calle
+ * forgot to export symbol capi_info2str for 2.1.x
+ *
* Revision 1.3 1997/05/18 09:24:18 calle
* added verbose disconnect reason reporting to avmb1.
* some fixes in capi20 interface.
@@ -26,13 +40,13 @@
*
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/segment.h>
+#include <linux/config.h>
#include "compat.h"
#include "capiutil.h"
@@ -936,35 +950,18 @@ char *capi_cmsg2str(_cmsg * cmsg)
}
-#ifdef HAS_NEW_SYMTAB
EXPORT_SYMBOL(capi_cmsg2message);
EXPORT_SYMBOL(capi_message2cmsg);
EXPORT_SYMBOL(capi_cmsg_header);
EXPORT_SYMBOL(capi_cmd2str);
EXPORT_SYMBOL(capi_cmsg2str);
EXPORT_SYMBOL(capi_message2str);
-#else
-static struct symbol_table capifunc_syms =
-{
-#include <linux/symtab_begin.h>
- X(capi_cmsg2message),
- X(capi_message2cmsg),
- X(capi_cmsg_header),
- X(capi_cmd2str),
- X(capi_cmsg2str),
- X(capi_message2str),
- X(capi_info2str),
-#include <linux/symtab_end.h>
-};
-#endif
+EXPORT_SYMBOL(capi_info2str);
#ifdef MODULE
int init_module(void)
{
-#ifndef HAS_NEW_SYMTAB
- register_symtab(&capifunc_syms);
-#endif
return 0;
}
diff --git a/drivers/isdn/avmb1/compat.h b/drivers/isdn/avmb1/compat.h
index 551b20d60..41ad2b626 100644
--- a/drivers/isdn/avmb1/compat.h
+++ b/drivers/isdn/avmb1/compat.h
@@ -1,11 +1,22 @@
/*
- * $Id: compat.h,v 1.1 1997/03/04 21:50:36 calle Exp $
+ * $Id: compat.h,v 1.3 1997/11/04 06:12:15 calle Exp $
*
* Headerfile for Compartibility between different kernel versions
*
* (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: compat.h,v $
+ * Revision 1.3 1997/11/04 06:12:15 calle
+ * capi.c: new read/write in file_ops since 2.1.60
+ * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
+ * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
+ * compat.h: added #define LinuxVersionCode
+ *
+ * Revision 1.2 1997/10/01 09:21:22 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
* Revision 1.1 1997/03/04 21:50:36 calle
* Frirst version in isdn4linux
*
@@ -23,8 +34,8 @@
#include <linux/version.h>
#include <linux/isdnif.h>
-#if LINUX_VERSION_CODE >= 0x020112 /* 2.1.18 */
-#define HAS_NEW_SYMTAB
+#ifndef LinuxVersionCode
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
#endif
#endif /* __COMPAT_H__ */
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
index 2cc325b1f..a8e1f83ef 100644
--- a/drivers/isdn/hisax/Makefile
+++ b/drivers/isdn/hisax/Makefile
@@ -1,7 +1,14 @@
L_OBJS :=
M_OBJS :=
-O_OBJS := isdnl1.o config.o tei.o isdnl2.o isdnl3.o \
- q931.o callc.o fsm.o
+LX_OBJS :=
+MX_OBJS :=
+O_OBJS :=
+OX_OBJS :=
+L_TARGET :=
+O_TARGET :=
+
+O_OBJS := isdnl1.o tei.o isdnl2.o isdnl3.o \
+ lmgr.o q931.o callc.o fsm.o
# EXTRA_CFLAGS += -S
@@ -17,31 +24,105 @@ ifeq ($(CONFIG_HISAX_1TR6),y)
O_OBJS += l3_1tr6.o
endif
+ISAC_OBJ :=
+ARCOFI_OBJ :=
+HSCX_OBJ :=
+HFC_OBJ :=
+HFC_2BDS0 :=
+RAWHDLC_OBJ :=
+
ifeq ($(CONFIG_HISAX_16_0),y)
O_OBJS += teles0.o
+ ISAC_OBJ := isac.o
+ HSCX_OBJ := hscx.o
endif
ifeq ($(CONFIG_HISAX_16_3),y)
O_OBJS += teles3.o
+ ISAC_OBJ := isac.o
+ HSCX_OBJ := hscx.o
endif
ifeq ($(CONFIG_HISAX_AVM_A1),y)
O_OBJS += avm_a1.o
+ ISAC_OBJ := isac.o
+ HSCX_OBJ := hscx.o
endif
-ifeq ($(CONFIG_HISAX_ELSA_PCC),y)
- O_OBJS += elsa.o
-endif
-
-ifeq ($(CONFIG_HISAX_ELSA_PCMCIA),y)
+ifeq ($(CONFIG_HISAX_ELSA),y)
O_OBJS += elsa.o
+ ISAC_OBJ := isac.o
+ HSCX_OBJ := hscx.o
+ ARCOFI_OBJ := arcofi.o
endif
ifeq ($(CONFIG_HISAX_IX1MICROR2),y)
O_OBJS += ix1_micro.o
+ ISAC_OBJ := isac.o
+ HSCX_OBJ := hscx.o
+endif
+
+ifeq ($(CONFIG_HISAX_DIEHLDIVA),y)
+ O_OBJS += diva.o
+ ISAC_OBJ := isac.o
+ HSCX_OBJ := hscx.o
+endif
+
+ifeq ($(CONFIG_HISAX_ASUSCOM),y)
+ O_OBJS += asuscom.o
+ ISAC_OBJ := isac.o
+ HSCX_OBJ := hscx.o
+endif
+
+ifeq ($(CONFIG_HISAX_TELEINT),y)
+ O_OBJS += teleint.o
+ ISAC_OBJ := isac.o
+ HFC_OBJ := hfc_2bs0.o
+endif
+
+ifeq ($(CONFIG_HISAX_SEDLBAUER),y)
+ O_OBJS += sedlbauer.o
+ ISAC_OBJ := isac.o
+ HSCX_OBJ := hscx.o
endif
+ifeq ($(CONFIG_HISAX_SPORTSTER),y)
+ O_OBJS += sportster.o
+ ISAC_OBJ := isac.o
+ HSCX_OBJ := hscx.o
+endif
+
+ifeq ($(CONFIG_HISAX_MIC),y)
+ O_OBJS += mic.o
+ ISAC_OBJ := isac.o
+ HSCX_OBJ := hscx.o
+endif
+
+ifeq ($(CONFIG_HISAX_NETJET),y)
+ O_OBJS += netjet.o
+ ISAC_OBJ := isac.o
+endif
+
+ifeq ($(CONFIG_HISAX_TELES3C),y)
+ O_OBJS += teles3c.o
+ HFC_2BDS0 := hfc_2bds0.o
+endif
+ifeq ($(CONFIG_HISAX_AMD7930),y)
+ O_OBJS += amd7930.o
+ RAWHDLC_OBJ := rawhdlc.o
+endif
+
+ifeq ($(CONFIG_HISAX_NICCY),y)
+ O_OBJS += niccy.o
+ ISAC_OBJ := isac.o
+ HSCX_OBJ := hscx.o
+endif
+
+O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(HFC_OBJ) $(ARCOFI_OBJ) $(HFC_2BDS0) $(RAWHDLC_OBJ)
+OX_OBJS += config.o
+
O_TARGET :=
+
ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
O_TARGET += hisax.o
else
diff --git a/drivers/isdn/hisax/amd7930.c b/drivers/isdn/hisax/amd7930.c
new file mode 100644
index 000000000..202599948
--- /dev/null
+++ b/drivers/isdn/hisax/amd7930.c
@@ -0,0 +1,768 @@
+/* $Id: amd7930.c,v 1.2 1998/02/12 23:07:10 keil Exp $
+ *
+ * HiSax ISDN driver - chip specific routines for AMD 7930
+ *
+ * Author Brent Baccala (baccala@FreeSoft.org)
+ *
+ *
+ *
+ * $Log: amd7930.c,v $
+ * Revision 1.2 1998/02/12 23:07:10 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.1 1998/02/03 23:20:51 keil
+ * New files for SPARC isdn support
+ *
+ * Revision 1.1 1998/01/08 04:17:12 baccala
+ * ISDN comes to the Sparc. Key points:
+ *
+ * - Existing ISDN HiSax driver provides all the smarts
+ * - it compiles, runs, talks to an isolated phone switch, connects
+ * to a Cisco, pings go through
+ * - AMD 7930 support only (no DBRI yet)
+ * - no US NI-1 support (may not work on US phone system - untested)
+ * - periodic packet loss, apparently due to lost interrupts
+ * - ISDN sometimes freezes, requiring reboot before it will work again
+ *
+ * The code is unreliable enough to be consider alpha
+ *
+ *
+ * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the
+ * SparcStation 1+. The chip provides microphone and speaker interfaces
+ * which provide mono-channel audio at 8K samples per second via either
+ * 8-bit A-law or 8-bit mu-law encoding. Also, the chip features an
+ * ISDN BRI Line Interface Unit (LIU), I.430 S/T physical interface,
+ * which performs basic D channel LAPD processing and provides raw
+ * B channel data. The digital audio channel, the two ISDN B channels,
+ * and two 64 Kbps channels to the microprocessor are all interconnected
+ * via a multiplexer.
+ *
+ * This driver interfaces to the Linux HiSax ISDN driver, which performs
+ * all high-level Q.921 and Q.931 ISDN functions. The file is not
+ * itself a hardware driver; rather it uses functions exported by
+ * the AMD7930 driver in the sparcaudio subsystem (drivers/sbus/audio),
+ * allowing the chip to be simultaneously used for both audio and ISDN data.
+ * The hardware driver does _no_ buffering, but provides several callbacks
+ * which are called during interrupt service and should therefore run quickly.
+ *
+ * D channel transmission is performed by passing the hardware driver the
+ * address and size of an skb's data area, then waiting for a callback
+ * to signal successful transmission of the packet. A task is then
+ * queued to notify the HiSax driver that another packet may be transmitted.
+ *
+ * D channel reception is quite simple, mainly because of:
+ * 1) the slow speed of the D channel - 16 kbps, and
+ * 2) the presence of an 8- or 32-byte (depending on chip version) FIFO
+ * to buffer the D channel data on the chip
+ * Worst case scenario of back-to-back packets with the 8 byte buffer
+ * at 16 kbps yields an service time of 4 ms - long enough to preclude
+ * the need for fancy buffering. We queue a background task that copies
+ * data out of the receive buffer into an skb, and the hardware driver
+ * simply does nothing until we're done with the receive buffer and
+ * reset it for a new packet.
+ *
+ * B channel processing is more complex, because of:
+ * 1) the faster speed - 64 kbps,
+ * 2) the lack of any on-chip buffering (it interrupts for every byte), and
+ * 3) the lack of any chip support for HDLC encapsulation
+ *
+ * The HiSax driver can put each B channel into one of three modes -
+ * L1_MODE_NULL (channel disabled), L1_MODE_TRANS (transparent data relay),
+ * and L1_MODE_HDLC (HDLC encapsulation by low-level driver).
+ * L1_MODE_HDLC is the most common, used for almost all "pure" digital
+ * data sessions. L1_MODE_TRANS is used for ISDN audio.
+ *
+ * HDLC B channel transmission is performed via a large buffer into
+ * which the skb is copied while performing HDLC bit-stuffing. A CRC
+ * is computed and attached to the end of the buffer, which is then
+ * passed to the low-level routines for raw transmission. Once
+ * transmission is complete, the hardware driver is set to enter HDLC
+ * idle by successive transmission of mark (all 1) bytes, waiting for
+ * the ISDN driver to prepare another packet for transmission and
+ * deliver it.
+ *
+ * HDLC B channel reception is performed via an X-byte ring buffer
+ * divided into N sections of X/N bytes each. Defaults: X=256 bytes, N=4.
+ * As the hardware driver notifies us that each section is full, we
+ * hand it the next section and schedule a background task to peruse
+ * the received section, bit-by-bit, with an HDLC decoder. As
+ * packets are detected, they are copied into a large buffer while
+ * decoding HDLC bit-stuffing. The ending CRC is verified, and if
+ * it is correct, we alloc a new skb of the correct length (which we
+ * now know), copy the packet into it, and hand it to the upper layers.
+ * Optimization: for large packets, we hand the buffer (which also
+ * happens to be an skb) directly to the upper layer after an skb_trim,
+ * and alloc a new large buffer for future packets, thus avoiding a copy.
+ * Then we return to HDLC processing; state is saved between calls.
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "../../sbus/audio/amd7930.h"
+#include "isac.h"
+#include "isdnl1.h"
+#include "rawhdlc.h"
+#include <linux/interrupt.h>
+
+static const char *amd7930_revision = "$Revision: 1.2 $";
+
+#define RCV_BUFSIZE 1024 /* Size of raw receive buffer in bytes */
+#define RCV_BUFBLKS 4 /* Number of blocks to divide buffer into
+ * (must divide RCV_BUFSIZE) */
+
+static void Bchan_fill_fifo(struct BCState *, struct sk_buff *);
+
+static void
+Bchan_xmt_bh(struct BCState *bcs)
+{
+ struct sk_buff *skb;
+
+ if (bcs->hw.amd7930.tx_skb != NULL) {
+ dev_kfree_skb(bcs->hw.amd7930.tx_skb);
+ bcs->hw.amd7930.tx_skb = NULL;
+ }
+
+ if ((skb = skb_dequeue(&bcs->squeue))) {
+ Bchan_fill_fifo(bcs, skb);
+ } else {
+ clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ bcs->event |= 1 << B_XMTBUFREADY;
+ queue_task(&bcs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+}
+
+static void
+Bchan_xmit_callback(struct BCState *bcs)
+{
+ queue_task(&bcs->hw.amd7930.tq_xmt, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+/* B channel transmission: two modes (three, if you count L1_MODE_NULL)
+ *
+ * L1_MODE_HDLC - We need to do HDLC encapsulation before transmiting
+ * the packet (i.e. make_raw_hdlc_data). Since this can be a
+ * time-consuming operation, our completion callback just schedules
+ * a bottom half to do encapsulation for the next packet. In between,
+ * the link will just idle
+ *
+ * L1_MODE_TRANS - Data goes through, well, transparent. No HDLC encap,
+ * and we can't just let the link idle, so the "bottom half" actually
+ * gets called during the top half (it's our callback routine in this case),
+ * but it's a lot faster now since we don't call make_raw_hdlc_data
+ */
+
+static void
+Bchan_fill_fifo(struct BCState *bcs, struct sk_buff *skb)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ int len;
+
+ if ((cs->debug & L1_DEB_HSCX) || (cs->debug & L1_DEB_HSCX_FIFO)) {
+ char tmp[1024];
+ char *t = tmp;
+
+ t += sprintf(t, "amd7930_fill_fifo %c cnt %d",
+ bcs->channel ? 'B' : 'A', skb->len);
+ if (cs->debug & L1_DEB_HSCX_FIFO)
+ QuickHex(t, skb->data, skb->len);
+ debugl1(cs, tmp);
+ }
+
+ if (bcs->mode == L1_MODE_HDLC) {
+ len = make_raw_hdlc_data(skb->data, skb->len,
+ bcs->hw.amd7930.tx_buff, RAW_BUFMAX);
+ if (len > 0)
+ amd7930_bxmit(0, bcs->channel,
+ bcs->hw.amd7930.tx_buff, len,
+ (void *) &Bchan_xmit_callback,
+ (void *) bcs);
+ dev_kfree_skb(skb);
+ } else if (bcs->mode == L1_MODE_TRANS) {
+ amd7930_bxmit(0, bcs->channel,
+ bcs->hw.amd7930.tx_buff, skb->len,
+ (void *) &Bchan_xmt_bh,
+ (void *) bcs);
+ bcs->hw.amd7930.tx_skb = skb;
+ } else {
+ dev_kfree_skb(skb);
+ }
+}
+
+static void
+Bchan_mode(struct BCState *bcs, int mode, int bc)
+{
+ struct IsdnCardState *cs = bcs->cs;
+
+ if (cs->debug & L1_DEB_HSCX) {
+ char tmp[40];
+ sprintf(tmp, "AMD 7930 mode %d bchan %d/%d",
+ mode, bc, bcs->channel);
+ debugl1(cs, tmp);
+ }
+ bcs->mode = mode;
+}
+
+/* Bchan_l2l1 is the entry point for upper layer routines that want to
+ * transmit on the B channel. PH_DATA_REQ is a normal packet that
+ * we either start transmitting (if idle) or queue (if busy).
+ * PH_PULL_REQ can be called to request a callback message (PH_PULL_CNF)
+ * once the link is idle. After a "pull" callback, the upper layer
+ * routines can use PH_PULL_IND to send data.
+ */
+
+static void
+Bchan_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+
+ switch (pr) {
+ case (PH_DATA_REQ):
+ if (test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
+ skb_queue_tail(&st->l1.bcs->squeue, skb);
+ } else {
+ test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ Bchan_fill_fifo(st->l1.bcs, skb);
+ }
+ break;
+ case (PH_PULL_IND):
+ if (test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
+ printk(KERN_WARNING "amd7930: this shouldn't happen\n");
+ break;
+ }
+ test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ Bchan_fill_fifo(st->l1.bcs, skb);
+ break;
+ case (PH_PULL_REQ):
+ if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
+ clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ st->l1.l1l2(st, PH_PULL_CNF, NULL);
+ } else
+ set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ }
+}
+
+/* Receiver callback and bottom half - decodes HDLC at leisure (if
+ * L1_MODE_HDLC) and passes newly received skb on via bcs->rqueue. If
+ * a large packet is received, stick rv_skb (the buffer that the
+ * packet has been decoded into) on the receive queue and alloc a new
+ * (large) skb to act as buffer for future receives. If a small
+ * packet is received, leave rv_skb alone, alloc a new skb of the
+ * correct size, and copy the packet into it
+ */
+
+static void
+Bchan_recv_callback(struct BCState *bcs)
+{
+ struct amd7930_hw *hw = &bcs->hw.amd7930;
+
+ hw->rv_buff_in += RCV_BUFSIZE/RCV_BUFBLKS;
+ hw->rv_buff_in %= RCV_BUFSIZE;
+
+ if (hw->rv_buff_in != hw->rv_buff_out) {
+ amd7930_brecv(0, bcs->channel,
+ hw->rv_buff + hw->rv_buff_in,
+ RCV_BUFSIZE/RCV_BUFBLKS,
+ (void *) &Bchan_recv_callback, (void *) bcs);
+ }
+
+ queue_task(&hw->tq_rcv, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static void
+Bchan_rcv_bh(struct BCState *bcs)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ struct amd7930_hw *hw = &bcs->hw.amd7930;
+ struct sk_buff *skb;
+ int len;
+
+ if (cs->debug & L1_DEB_HSCX) {
+ char tmp[1024];
+
+ sprintf(tmp, "amd7930_Bchan_rcv (%d/%d)",
+ hw->rv_buff_in, hw->rv_buff_out);
+ debugl1(cs, tmp);
+ QuickHex(tmp, hw->rv_buff + hw->rv_buff_out,
+ RCV_BUFSIZE/RCV_BUFBLKS);
+ debugl1(cs, tmp);
+ }
+
+ do {
+ if (bcs->mode == L1_MODE_HDLC) {
+ while ((len = read_raw_hdlc_data(hw->hdlc_state,
+ hw->rv_buff + hw->rv_buff_out, RCV_BUFSIZE/RCV_BUFBLKS,
+ hw->rv_skb->tail, HSCX_BUFMAX))) {
+ if (len > 0 && (cs->debug & L1_DEB_HSCX_FIFO)) {
+ char tmp[1024];
+ char *t = tmp;
+
+ t += sprintf(t, "amd7930_Bchan_rcv %c cnt %d", bcs->channel ? 'B' : 'A', len);
+ QuickHex(t, hw->rv_skb->tail, len);
+ debugl1(cs, tmp);
+ }
+
+ if (len > HSCX_BUFMAX/2) {
+ /* Large packet received */
+
+ if (!(skb = dev_alloc_skb(HSCX_BUFMAX))) {
+ printk(KERN_WARNING "amd7930: receive out of memory");
+ } else {
+ skb_put(hw->rv_skb, len);
+ skb_queue_tail(&bcs->rqueue, hw->rv_skb);
+ hw->rv_skb = skb;
+ bcs->event |= 1 << B_RCVBUFREADY;
+ queue_task(&bcs->tqueue, &tq_immediate);
+ }
+ } else if (len > 0) {
+ /* Small packet received */
+
+ if (!(skb = dev_alloc_skb(len))) {
+ printk(KERN_WARNING "amd7930: receive out of memory\n");
+ } else {
+ memcpy(skb_put(skb, len), hw->rv_skb->tail, len);
+ skb_queue_tail(&bcs->rqueue, skb);
+ bcs->event |= 1 << B_RCVBUFREADY;
+ queue_task(&bcs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ } else {
+ /* Reception Error */
+ /* printk("amd7930: B channel receive error\n"); */
+ }
+ }
+ } else if (bcs->mode == L1_MODE_TRANS) {
+ if (!(skb = dev_alloc_skb(RCV_BUFSIZE/RCV_BUFBLKS))) {
+ printk(KERN_WARNING "amd7930: receive out of memory\n");
+ } else {
+ memcpy(skb_put(skb, RCV_BUFSIZE/RCV_BUFBLKS),
+ hw->rv_buff + hw->rv_buff_out,
+ RCV_BUFSIZE/RCV_BUFBLKS);
+ skb_queue_tail(&bcs->rqueue, skb);
+ bcs->event |= 1 << B_RCVBUFREADY;
+ queue_task(&bcs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ }
+
+ if (hw->rv_buff_in == hw->rv_buff_out) {
+ /* Buffer was filled up - need to restart receiver */
+ amd7930_brecv(0, bcs->channel,
+ hw->rv_buff + hw->rv_buff_in,
+ RCV_BUFSIZE/RCV_BUFBLKS,
+ (void *) &Bchan_recv_callback,
+ (void *) bcs);
+ }
+
+ hw->rv_buff_out += RCV_BUFSIZE/RCV_BUFBLKS;
+ hw->rv_buff_out %= RCV_BUFSIZE;
+
+ } while (hw->rv_buff_in != hw->rv_buff_out);
+}
+
+static void
+Bchan_close(struct BCState *bcs)
+{
+ struct sk_buff *skb;
+
+ Bchan_mode(bcs, 0, 0);
+ amd7930_bclose(0, bcs->channel);
+
+ if (test_bit(BC_FLG_INIT, &bcs->Flag)) {
+ while ((skb = skb_dequeue(&bcs->rqueue))) {
+ dev_kfree_skb(skb);
+ }
+ while ((skb = skb_dequeue(&bcs->squeue))) {
+ dev_kfree_skb(skb);
+ }
+ }
+ test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+}
+
+static int
+Bchan_open(struct BCState *bcs)
+{
+ struct amd7930_hw *hw = &bcs->hw.amd7930;
+
+ if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+ skb_queue_head_init(&bcs->rqueue);
+ skb_queue_head_init(&bcs->squeue);
+ }
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+
+ amd7930_bopen(0, bcs->channel, 0xff);
+ hw->rv_buff_in = 0;
+ hw->rv_buff_out = 0;
+ hw->tx_skb = NULL;
+ init_hdlc_state(hw->hdlc_state, 0);
+ amd7930_brecv(0, bcs->channel,
+ hw->rv_buff + hw->rv_buff_in, RCV_BUFSIZE/RCV_BUFBLKS,
+ (void *) &Bchan_recv_callback, (void *) bcs);
+
+ bcs->event = 0;
+ bcs->tx_cnt = 0;
+ return (0);
+}
+
+static void
+Bchan_init(struct BCState *bcs)
+{
+ if (!(bcs->hw.amd7930.tx_buff = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for amd7930.tx_buff\n");
+ return;
+ }
+ if (!(bcs->hw.amd7930.rv_buff = kmalloc(RCV_BUFSIZE, GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for amd7930.rv_buff\n");
+ return;
+ }
+ if (!(bcs->hw.amd7930.rv_skb = dev_alloc_skb(HSCX_BUFMAX))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for amd7930.rv_skb\n");
+ return;
+ }
+ if (!(bcs->hw.amd7930.hdlc_state = kmalloc(sizeof(struct hdlc_state),
+ GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for amd7930.hdlc_state\n");
+ return;
+ }
+
+ bcs->hw.amd7930.tq_rcv.sync = 0;
+ bcs->hw.amd7930.tq_rcv.routine = (void (*)(void *)) &Bchan_rcv_bh;
+ bcs->hw.amd7930.tq_rcv.data = (void *) bcs;
+
+ bcs->hw.amd7930.tq_xmt.sync = 0;
+ bcs->hw.amd7930.tq_xmt.routine = (void (*)(void *)) &Bchan_xmt_bh;
+ bcs->hw.amd7930.tq_xmt.data = (void *) bcs;
+}
+
+static void
+Bchan_manl1(struct PStack *st, int pr,
+ void *arg)
+{
+ switch (pr) {
+ case (PH_ACTIVATE_REQ):
+ test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ Bchan_mode(st->l1.bcs, st->l1.mode, st->l1.bc);
+ st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
+ break;
+ case (PH_DEACTIVATE_REQ):
+ if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
+ Bchan_mode(st->l1.bcs, 0, 0);
+ test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ break;
+ }
+}
+
+int
+setstack_amd7930(struct PStack *st, struct BCState *bcs)
+{
+ if (Bchan_open(bcs))
+ return (-1);
+ st->l1.bcs = bcs;
+ st->l2.l2l1 = Bchan_l2l1;
+ st->ma.manl1 = Bchan_manl1;
+ setstack_manager(st);
+ bcs->st = st;
+ return (0);
+}
+
+
+static void
+amd7930_drecv_callback(void *arg, int error, unsigned int count)
+{
+ struct IsdnCardState *cs = (struct IsdnCardState *) arg;
+ static struct tq_struct task;
+ struct sk_buff *skb;
+
+ /* NOTE: This function is called directly from an interrupt handler */
+
+ if (1) {
+ 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);
+ }
+
+ task.routine = (void *) DChannel_proc_rcv;
+ task.data = (void *) cs;
+ queue_task(&task, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+
+ if (cs->debug & L1_DEB_ISAC_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "amd7930 Drecv cnt %d", count);
+ if (error) t += sprintf(t, " ERR %x", error);
+ QuickHex(t, cs->rcvbuf, count);
+ debugl1(cs, tmp);
+ }
+
+ amd7930_drecv(0, cs->rcvbuf, MAX_DFRAME_LEN,
+ &amd7930_drecv_callback, cs);
+}
+
+static void
+amd7930_dxmit_callback(void *arg, int error)
+{
+ struct IsdnCardState *cs = (struct IsdnCardState *) arg;
+ static struct tq_struct task;
+
+ /* NOTE: This function is called directly from an interrupt handler */
+
+ /* may wish to do retransmission here, if error indicates collision */
+
+ if (cs->debug & L1_DEB_ISAC_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "amd7930 Dxmit cnt %d", cs->tx_skb->len);
+ if (error) t += sprintf(t, " ERR %x", error);
+ QuickHex(t, cs->tx_skb->data, cs->tx_skb->len);
+ debugl1(cs, tmp);
+ }
+
+ cs->tx_skb = NULL;
+
+ task.routine = (void *) DChannel_proc_xmt;
+ task.data = (void *) cs;
+ queue_task(&task, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static void
+amd7930_Dchan_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+ struct sk_buff *skb = arg;
+ char str[64];
+
+ switch (pr) {
+ case (PH_DATA_REQ):
+ 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 {
+ if ((cs->dlogflag) && (!(skb->data[2] & 1))) {
+ /* I-FRAME */
+ LogFrame(cs, skb->data, skb->len);
+ sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+ dlogframe(cs, skb->data+4, skb->len-4,
+ str);
+ }
+ 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
+ amd7930_dxmit(0, skb->data, skb->len,
+ &amd7930_dxmit_callback, cs);
+ }
+ break;
+ case (PH_PULL_IND):
+ 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->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */
+ LogFrame(cs, skb->data, skb->len);
+ sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+ dlogframe(cs, skb->data + 4, skb->len - 4,
+ str);
+ }
+ 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
+ amd7930_dxmit(0, cs->tx_skb->data, cs->tx_skb->len,
+ &amd7930_dxmit_callback, cs);
+ break;
+ case (PH_PULL_REQ):
+#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_CNF, NULL);
+ } else
+ test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ }
+}
+
+int
+setDstack_amd7930(struct PStack *st, struct IsdnCardState *cs)
+{
+ st->l2.l2l1 = amd7930_Dchan_l2l1;
+ if (! cs->rcvbuf) {
+ printk("setDstack_amd7930: No cs->rcvbuf!\n");
+ } else {
+ amd7930_drecv(0, cs->rcvbuf, MAX_DFRAME_LEN,
+ &amd7930_drecv_callback, cs);
+ }
+ return (0);
+}
+
+static void
+manl1_msg(struct IsdnCardState *cs, int msg, void *arg) {
+ struct PStack *st;
+
+ st = cs->stlist;
+ while (st) {
+ st->ma.manl1(st, msg, arg);
+ st = st->next;
+ }
+}
+
+static void
+amd7930_new_ph(struct IsdnCardState *cs)
+{
+ switch (amd7930_get_liu_state(0)) {
+ case 3:
+ manl1_msg(cs, PH_POWERUP_CNF, NULL);
+ break;
+
+ case 7:
+ manl1_msg(cs, PH_I4_P8_IND, NULL);
+ break;
+
+ case 8:
+ manl1_msg(cs, PH_RSYNC_IND, NULL);
+ break;
+ }
+}
+
+/* amd7930 LIU state change callback */
+
+static void
+amd7930_liu_callback(struct IsdnCardState *cs)
+{
+ static struct tq_struct task;
+
+ if (!cs)
+ return;
+
+ if (cs->debug & L1_DEB_ISAC) {
+ char tmp[32];
+ sprintf(tmp, "amd7930_liu state %d", amd7930_get_liu_state(0));
+ debugl1(cs, tmp);
+ }
+
+ task.sync = 0;
+ task.routine = (void *) &amd7930_new_ph;
+ task.data = (void *) cs;
+ queue_task(&task, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+void
+amd7930_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
+{
+ u_char val;
+ char tmp[32];
+
+ if (cs->debug & L1_DEB_ISAC) {
+ char tmp[32];
+ sprintf(tmp, "amd7930_l1cmd msg %x", msg);
+ debugl1(cs, tmp);
+ }
+
+ switch(msg) {
+ case PH_RESET_REQ:
+ if (amd7930_get_liu_state(0) <= 3)
+ amd7930_liu_activate(0,0);
+ else
+ amd7930_liu_deactivate(0);
+ break;
+ case PH_ENABLE_REQ:
+ break;
+ case PH_INFO3_REQ:
+ amd7930_liu_activate(0,0);
+ break;
+ case PH_TESTLOOP_REQ:
+ break;
+ default:
+ if (cs->debug & L1_DEB_WARN) {
+ sprintf(tmp, "amd7930_l1cmd unknown %4x", msg);
+ debugl1(cs, tmp);
+ }
+ break;
+ }
+}
+
+static void init_amd7930(struct IsdnCardState *cs)
+{
+ Bchan_init(&cs->bcs[0]);
+ Bchan_init(&cs->bcs[1]);
+ cs->bcs[0].BC_SetStack = setstack_amd7930;
+ cs->bcs[1].BC_SetStack = setstack_amd7930;
+ cs->bcs[0].BC_Close = Bchan_close;
+ cs->bcs[1].BC_Close = Bchan_close;
+ Bchan_mode(cs->bcs, 0, 0);
+ Bchan_mode(cs->bcs + 1, 0, 0);
+}
+
+void
+release_amd7930(struct IsdnCardState *cs)
+{
+}
+
+static int
+amd7930_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ return(0);
+ case CARD_RELEASE:
+ release_amd7930(cs);
+ return(0);
+ case CARD_SETIRQ:
+ return(0);
+ case CARD_INIT:
+ cs->l1cmd = amd7930_l1cmd;
+ amd7930_liu_init(0, &amd7930_liu_callback, (void *)cs);
+ init_amd7930(cs);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
+}
+
+__initfunc(int
+setup_amd7930(struct IsdnCard *card))
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, amd7930_revision);
+ printk(KERN_INFO "HiSax: AMD7930 driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_AMD7930)
+ return (0);
+
+ cs->irq = amd7930_get_irqnum(0);
+ if (cs->irq == 0)
+ return (0);
+
+ cs->cardmsg = &amd7930_card_msg;
+
+ return (1);
+}
diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c
new file mode 100644
index 000000000..dad1711c3
--- /dev/null
+++ b/drivers/isdn/hisax/arcofi.c
@@ -0,0 +1,51 @@
+/* $Id: arcofi.c,v 1.1 1997/10/29 18:51:20 keil Exp $
+
+ * arcofi.h Ansteuerung ARCOFI 2165
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ *
+ * $Log: arcofi.c,v $
+ * Revision 1.1 1997/10/29 18:51:20 keil
+ * New files
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl1.h"
+#include "isac.h"
+
+int
+send_arcofi(struct IsdnCardState *cs, const u_char *msg) {
+ u_char val;
+ char tmp[32];
+ long flags;
+ int cnt=2;
+
+ cs->mon_txp = 0;
+ cs->mon_txc = msg[0];
+ memcpy(cs->mon_tx, &msg[1], cs->mon_txc);
+ cs->mocr &= 0x0f;
+ cs->mocr |= 0xa0;
+ test_and_clear_bit(HW_MON1_TX_END, &cs->HW_Flags);
+ cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ val = cs->readisac(cs, ISAC_MOSR);
+ cs->writeisac(cs, ISAC_MOX1, cs->mon_tx[cs->mon_txp++]);
+ cs->mocr |= 0x10;
+ cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ save_flags(flags);
+ sti();
+ while (cnt && !test_bit(HW_MON1_TX_END, &cs->HW_Flags)) {
+ cnt--;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */
+ schedule();
+ }
+ restore_flags(flags);
+ sprintf(tmp, "arcofi tout %d", cnt);
+ debugl1(cs, tmp);
+ return(cnt);
+}
+
diff --git a/drivers/isdn/hisax/arcofi.h b/drivers/isdn/hisax/arcofi.h
new file mode 100644
index 000000000..5e1bb9e99
--- /dev/null
+++ b/drivers/isdn/hisax/arcofi.h
@@ -0,0 +1,17 @@
+/* $Id: arcofi.h,v 1.1 1997/10/29 18:51:20 keil Exp $
+
+ * arcofi.h Ansteuerung ARCOFI 2165
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ *
+ * $Log: arcofi.h,v $
+ * Revision 1.1 1997/10/29 18:51:20 keil
+ * New files
+ *
+ */
+
+#define ARCOFI_USE 1
+
+extern int send_arcofi(struct IsdnCardState *cs, const u_char *msg);
diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
new file mode 100644
index 000000000..c84917446
--- /dev/null
+++ b/drivers/isdn/hisax/asuscom.c
@@ -0,0 +1,292 @@
+/* $Id: asuscom.c,v 1.2 1998/02/02 13:27:06 keil Exp $
+
+ * asuscom.c low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to ASUSCOM NETWORK INC. Taiwan and Dynalink NL for informations
+ *
+ *
+ * $Log: asuscom.c,v $
+ * Revision 1.2 1998/02/02 13:27:06 keil
+ * New
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+
+const char *Asuscom_revision = "$Revision: 1.2 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define ASUS_ISAC 0
+#define ASUS_HSCX 1
+#define ASUS_ADR 2
+#define ASUS_CTRL_U7 3
+#define ASUS_CTRL_POTS 5
+
+/* CARD_ADR (Write) */
+#define ASUS_RESET 0x80 /* Bit 7 Reset-Leitung */
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+ register u_char ret;
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(ale, off);
+ ret = bytein(adr);
+ restore_flags(flags);
+ return (ret);
+}
+
+static inline void
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+ /* fifo read without cli because it's allready done */
+
+ byteout(ale, off);
+ insb(adr, data, size);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(ale, off);
+ byteout(adr, data);
+ restore_flags(flags);
+}
+
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+ /* fifo write without cli because it's allready done */
+ byteout(ale, off);
+ outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+ return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+ return (readreg(cs->hw.asus.adr,
+ cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+ writereg(cs->hw.asus.adr,
+ cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0), value);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.asus.adr, \
+ cs->hw.asus.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.asus.adr, \
+ cs->hw.asus.hscx, reg + (nr ? 0x40 : 0), data)
+
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.asus.adr, \
+ cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.asus.adr, \
+ cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val, stat = 0;
+
+ if (!cs) {
+ printk(KERN_WARNING "ISDNLink: Spurious interrupt!\n");
+ return;
+ }
+ val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
+ Start_HSCX:
+ if (val) {
+ hscx_int_main(cs, val);
+ stat |= 1;
+ }
+ val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
+ Start_ISAC:
+ if (val) {
+ isac_interrupt(cs, val);
+ stat |= 2;
+ }
+ val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
+ if (val) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX IntStat after IntRoutine");
+ goto Start_HSCX;
+ }
+ val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
+ if (val) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ISAC IntStat after IntRoutine");
+ goto Start_ISAC;
+ }
+ if (stat & 1) {
+ writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0xFF);
+ writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0xFF);
+ writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0x0);
+ writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0x0);
+ }
+ if (stat & 2) {
+ writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0);
+ }
+}
+
+void
+release_io_asuscom(struct IsdnCardState *cs)
+{
+ int bytecnt = 8;
+
+ if (cs->hw.asus.cfg_reg)
+ release_region(cs->hw.asus.cfg_reg, bytecnt);
+}
+
+static void
+reset_asuscom(struct IsdnCardState *cs)
+{
+ long flags;
+
+ byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */
+ save_flags(flags);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ byteout(cs->hw.asus.adr, 0); /* Reset Off */
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ restore_flags(flags);
+}
+
+static int
+Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ reset_asuscom(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_asuscom(cs);
+ return(0);
+ case CARD_SETIRQ:
+ return(request_irq(cs->irq, &asuscom_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs));
+ case CARD_INIT:
+ clear_pending_isac_ints(cs);
+ clear_pending_hscx_ints(cs);
+ initisac(cs);
+ inithscx(cs);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
+}
+
+__initfunc(int
+setup_asuscom(struct IsdnCard *card))
+{
+ int bytecnt;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, Asuscom_revision);
+ printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_ASUSCOM)
+ return (0);
+
+ bytecnt = 8;
+ cs->hw.asus.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR;
+ cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC;
+ cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX;
+ cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7;
+ cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS;
+
+ if (check_region((cs->hw.asus.cfg_reg), bytecnt)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.asus.cfg_reg,
+ cs->hw.asus.cfg_reg + bytecnt);
+ return (0);
+ } else {
+ request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn");
+ }
+
+ printk(KERN_INFO
+ "ISDNLink: defined at 0x%x IRQ %d\n",
+ cs->hw.asus.cfg_reg,
+ cs->irq);
+ printk(KERN_INFO "ISDNLink: resetting card\n");
+ reset_asuscom(cs);
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ cs->BC_Read_Reg = &ReadHSCX;
+ cs->BC_Write_Reg = &WriteHSCX;
+ cs->BC_Send_Data = &hscx_fill_fifo;
+ cs->cardmsg = &Asus_card_msg;
+ ISACVersion(cs, "ISDNLink:");
+ if (HscxVersion(cs, "ISDNLink:")) {
+ printk(KERN_WARNING
+ "ISDNLink: wrong HSCX versions check IO address\n");
+ release_io_asuscom(cs);
+ return (0);
+ }
+ return (1);
+}
diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c
index e6c775546..464bc33fd 100644
--- a/drivers/isdn/hisax/avm_a1.c
+++ b/drivers/isdn/hisax/avm_a1.c
@@ -1,4 +1,4 @@
-/* $Id: avm_a1.c,v 1.6 1997/04/13 19:54:07 keil Exp $
+/* $Id: avm_a1.c,v 2.7 1998/02/02 13:29:37 keil Exp $
* avm_a1.c low level stuff for AVM A1 (Fritz) isdn cards
*
@@ -6,6 +6,30 @@
*
*
* $Log: avm_a1.c,v $
+ * Revision 2.7 1998/02/02 13:29:37 keil
+ * fast io
+ *
+ * Revision 2.6 1998/01/13 23:09:46 keil
+ * really disable timer
+ *
+ * Revision 2.5 1998/01/02 06:50:29 calle
+ * Perodic timer of A1 now disabled, no need for linux driver.
+ *
+ * Revision 2.4 1997/11/08 21:35:42 keil
+ * new l1 init
+ *
+ * Revision 2.3 1997/11/06 17:13:32 keil
+ * New 2.1 init code
+ *
+ * Revision 2.2 1997/10/29 18:55:48 keil
+ * changes for 2.1.60 (irq2dev_map)
+ *
+ * Revision 2.1 1997/07/27 21:47:13 keil
+ * new interface structures
+ *
+ * Revision 2.0 1997/06/26 11:02:48 keil
+ * New Layer and card interface
+ *
* Revision 1.6 1997/04/13 19:54:07 keil
* Change in IRQ check delay for SMP
*
@@ -27,17 +51,20 @@
*
*/
#define __NO_VERSION__
-#include "siemens.h"
#include "hisax.h"
-#include "avm_a1.h"
+#include "isac.h"
+#include "hscx.h"
#include "isdnl1.h"
-#include <linux/kernel_stat.h>
extern const char *CardType[];
-const char *avm_revision = "$Revision: 1.6 $";
+const char *avm_revision = "$Revision: 2.7 $";
+
+#define AVM_A1_STAT_ISAC 0x01
+#define AVM_A1_STAT_HSCX 0x02
+#define AVM_A1_STAT_TIMER 0x04
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
static inline u_char
readreg(unsigned int adr, u_char off)
@@ -55,906 +82,303 @@ writereg(unsigned int adr, u_char off, u_char data)
static inline void
read_fifo(unsigned int adr, u_char * data, int size)
{
- insb(adr - 0x400, data, size);
+ insb(adr, data, size);
}
static void
write_fifo(unsigned int adr, u_char * data, int size)
{
- outsb(adr - 0x400, data, size);
-}
-
-static inline void
-waitforCEC(int adr)
-{
- int to = 50;
-
- while ((readreg(adr, HSCX_STAR) & 0x04) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "AVM A1: waitforCEC timeout\n");
+ outsb(adr, data, size);
}
+/* Interface functions */
-static inline void
-waitforXFW(int adr)
-{
- int to = 50;
-
- while ((!(readreg(adr, HSCX_STAR) & 0x44) == 0x40) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "AVM A1: waitforXFW timeout\n");
-}
-
-static inline void
-writehscxCMDR(int adr, u_char data)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
{
- long flags;
-
- save_flags(flags);
- cli();
- waitforCEC(adr);
- writereg(adr, HSCX_CMDR, data);
- restore_flags(flags);
+ return (readreg(cs->hw.avm.isac, offset));
}
-/*
- * fast interrupt here
- */
-
static void
-hscxreport(struct IsdnCardState *sp, int hscx)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
- printk(KERN_DEBUG "HSCX %d\n", hscx);
- printk(KERN_DEBUG "ISTA %x\n", readreg(sp->hscx[hscx], HSCX_ISTA));
- printk(KERN_DEBUG "STAR %x\n", readreg(sp->hscx[hscx], HSCX_STAR));
- printk(KERN_DEBUG "EXIR %x\n", readreg(sp->hscx[hscx], HSCX_EXIR));
+ writereg(cs->hw.avm.isac, offset, value);
}
-void
-avm_a1_report(struct IsdnCardState *sp)
-{
- printk(KERN_DEBUG "ISAC\n");
- printk(KERN_DEBUG "ISTA %x\n", readreg(sp->isac, ISAC_ISTA));
- printk(KERN_DEBUG "STAR %x\n", readreg(sp->isac, ISAC_STAR));
- printk(KERN_DEBUG "EXIR %x\n", readreg(sp->isac, ISAC_EXIR));
- hscxreport(sp, 0);
- hscxreport(sp, 1);
-}
-
-/*
- * HSCX stuff goes here
- */
-
static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
- u_char *ptr;
- struct IsdnCardState *sp = hsp->sp;
- long flags;
-
- if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
- debugl1(sp, "hscx_empty_fifo");
-
- if (hsp->rcvidx + count > HSCX_BUFMAX) {
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "hscx_empty_fifo: incoming packet too large");
- writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
- hsp->rcvidx = 0;
- return;
- }
- ptr = hsp->rcvbuf + hsp->rcvidx;
- hsp->rcvidx += count;
- save_flags(flags);
- cli();
- read_fifo(sp->hscx[hsp->hscx], ptr, count);
- writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
- restore_flags(flags);
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "hscx_empty_fifo %c cnt %d",
- hsp->hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ read_fifo(cs->hw.avm.isacfifo, data, size);
}
static void
-hscx_fill_fifo(struct HscxState *hsp)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
- struct IsdnCardState *sp = hsp->sp;
- int more, count;
- u_char *ptr;
- long flags;
-
- if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
- debugl1(sp, "hscx_fill_fifo");
-
- if (!hsp->tx_skb)
- return;
- if (hsp->tx_skb->len <= 0)
- return;
-
- more = (hsp->mode == 1) ? 1 : 0;
- if (hsp->tx_skb->len > 32) {
- more = !0;
- count = 32;
- } else
- count = hsp->tx_skb->len;
-
- waitforXFW(sp->hscx[hsp->hscx]);
- save_flags(flags);
- cli();
- ptr = hsp->tx_skb->data;
- skb_pull(hsp->tx_skb, count);
- hsp->tx_cnt -= count;
- hsp->count += count;
- write_fifo(sp->hscx[hsp->hscx], ptr, count);
- writehscxCMDR(sp->hscx[hsp->hscx], more ? 0x8 : 0xa);
- restore_flags(flags);
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "hscx_fill_fifo %c cnt %d",
- hsp->hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ write_fifo(cs->hw.avm.isacfifo, data, size);
}
-static inline void
-hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
- u_char r;
- struct HscxState *hsp = sp->hs + hscx;
- struct sk_buff *skb;
- int count;
- char tmp[32];
-
- if (!hsp->init)
- return;
-
- if (val & 0x80) { /* RME */
-
- r = readreg(sp->hscx[hsp->hscx], HSCX_RSTA);
- if ((r & 0xf0) != 0xa0) {
- if (!r & 0x80)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "HSCX invalid frame");
- if ((r & 0x40) && hsp->mode)
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX RDO mode=%d",
- hsp->mode);
- debugl1(sp, tmp);
- }
- if (!r & 0x20)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "HSCX CRC error");
- writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
- } else {
- count = readreg(sp->hscx[hsp->hscx], HSCX_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- hscx_empty_fifo(hsp, count);
- if ((count = hsp->rcvidx - 1) > 0) {
- if (!(skb = dev_alloc_skb(count)))
- printk(KERN_WARNING "AVM: receive out of memory\n");
- else {
- memcpy(skb_put(skb, count), hsp->rcvbuf, count);
- skb_queue_tail(&hsp->rqueue, skb);
- }
- }
- }
- hsp->rcvidx = 0;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- hscx_empty_fifo(hsp, 32);
- if (hsp->mode == 1) {
- /* receive audio data */
- if (!(skb = dev_alloc_skb(32)))
- printk(KERN_WARNING "AVM: receive out of memory\n");
- else {
- memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
- skb_queue_tail(&hsp->rqueue, skb);
- }
- hsp->rcvidx = 0;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- }
- if (val & 0x10) { /* XPR */
- if (hsp->tx_skb)
- if (hsp->tx_skb->len) {
- hscx_fill_fifo(hsp);
- return;
- } else {
- SET_SKB_FREE(hsp->tx_skb);
- dev_kfree_skb(hsp->tx_skb);
- hsp->count = 0;
- if (hsp->st->l4.l1writewakeup)
- hsp->st->l4.l1writewakeup(hsp->st);
- hsp->tx_skb = NULL;
- }
- if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
- hsp->count = 0;
- hscx_fill_fifo(hsp);
- } else
- hscx_sched_event(hsp, HSCX_XMTBUFREADY);
- }
+ return (readreg(cs->hw.avm.hscx[hscx], offset));
}
-/*
- * ISAC stuff goes here
- */
-
static void
-isac_empty_fifo(struct IsdnCardState *sp, int count)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
- u_char *ptr;
- long flags;
-
- if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
- if (sp->debug & L1_DEB_ISAC)
- debugl1(sp, "isac_empty_fifo");
-
- if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
- if (sp->debug & L1_DEB_WARN) {
- char tmp[40];
- sprintf(tmp, "isac_empty_fifo overrun %d",
- sp->rcvidx + count);
- debugl1(sp, tmp);
- }
- writereg(sp->isac, ISAC_CMDR, 0x80);
- sp->rcvidx = 0;
- return;
- }
- ptr = sp->rcvbuf + sp->rcvidx;
- sp->rcvidx += count;
- save_flags(flags);
- cli();
- read_fifo(sp->isac, ptr, count);
- writereg(sp->isac, ISAC_CMDR, 0x80);
- restore_flags(flags);
- if (sp->debug & L1_DEB_ISAC_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "isac_empty_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ writereg(cs->hw.avm.hscx[hscx], offset, value);
}
-static void
-isac_fill_fifo(struct IsdnCardState *sp)
-{
- int count, more;
- u_char *ptr;
- long flags;
-
- if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
- debugl1(sp, "isac_fill_fifo");
-
- if (!sp->tx_skb)
- return;
-
- count = sp->tx_skb->len;
- if (count <= 0)
- return;
-
- more = 0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- save_flags(flags);
- cli();
- ptr = sp->tx_skb->data;
- skb_pull(sp->tx_skb, count);
- sp->tx_cnt += count;
- write_fifo(sp->isac, ptr, count);
- writereg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa);
- restore_flags(flags);
- if (sp->debug & L1_DEB_ISAC_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "isac_fill_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
-}
-
-static void
-ph_command(struct IsdnCardState *sp, unsigned int command)
-{
- if (sp->debug & L1_DEB_ISAC) {
- char tmp[32];
- sprintf(tmp, "ph_command %d", command);
- debugl1(sp, tmp);
- }
- writereg(sp->isac, ISAC_CIX0, (command << 2) | 3);
-}
-
-
-static inline void
-isac_interrupt(struct IsdnCardState *sp, u_char val)
-{
- u_char exval;
- struct sk_buff *skb;
- unsigned int count;
- char tmp[32];
-
- if (sp->debug & L1_DEB_ISAC) {
- sprintf(tmp, "ISAC interrupt %x", val);
- debugl1(sp, tmp);
- }
- if (val & 0x80) { /* RME */
- exval = readreg(sp->isac, ISAC_RSTA);
- if ((exval & 0x70) != 0x20) {
- if (exval & 0x40)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC RDO");
- if (!exval & 0x20)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC CRC error");
- writereg(sp->isac, ISAC_CMDR, 0x80);
- } else {
- count = readreg(sp->isac, ISAC_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- isac_empty_fifo(sp, count);
- if ((count = sp->rcvidx) > 0) {
- if (!(skb = alloc_skb(count, GFP_ATOMIC)))
- printk(KERN_WARNING "AVM: D receive out of memory\n");
- else {
- memcpy(skb_put(skb, count), sp->rcvbuf, count);
- skb_queue_tail(&sp->rq, skb);
- }
- }
- }
- sp->rcvidx = 0;
- isac_sched_event(sp, ISAC_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- isac_empty_fifo(sp, 32);
- }
- if (val & 0x20) { /* RSC */
- /* never */
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC RSC interrupt");
- }
- if (val & 0x10) { /* XPR */
- if (sp->tx_skb)
- if (sp->tx_skb->len) {
- isac_fill_fifo(sp);
- goto afterXPR;
- } else {
- SET_SKB_FREE(sp->tx_skb);
- dev_kfree_skb(sp->tx_skb);
- sp->tx_cnt = 0;
- sp->tx_skb = NULL;
- }
- if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
- sp->tx_cnt = 0;
- isac_fill_fifo(sp);
- } else
- isac_sched_event(sp, ISAC_XMTBUFREADY);
- }
- afterXPR:
- if (val & 0x04) { /* CISQ */
- sp->ph_state = (readreg(sp->isac, ISAC_CIX0) >> 2)
- & 0xf;
- if (sp->debug & L1_DEB_ISAC) {
- sprintf(tmp, "l1state %d", sp->ph_state);
- debugl1(sp, tmp);
- }
- isac_new_ph(sp);
- }
- if (val & 0x02) { /* SIN */
- /* never */
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC SIN interrupt");
- }
- if (val & 0x01) { /* EXI */
- exval = readreg(sp->isac, ISAC_EXIR);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "ISAC EXIR %02x", exval);
- debugl1(sp, tmp);
- }
- }
-}
-
-static inline void
-hscx_int_main(struct IsdnCardState *sp, u_char val)
-{
-
- u_char exval;
- struct HscxState *hsp;
- char tmp[32];
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+#define READHSCX(cs, nr, reg) readreg(cs->hw.avm.hscx[nr], reg)
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.avm.hscx[nr], reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
- if (val & 0x01) {
- hsp = sp->hs + 1;
- exval = readreg(sp->hscx[1], HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (hsp->tx_skb) {
- skb_push(hsp->tx_skb, hsp->count);
- hsp->tx_cnt += hsp->count;
- hsp->count = 0;
- }
- writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
- debugl1(sp, tmp);
- }
- }
- } else if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX B EXIR %x", exval);
- debugl1(sp, tmp);
- }
- }
- if (val & 0xf8) {
- if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX B interrupt %x", val);
- debugl1(sp, tmp);
- }
- hscx_interrupt(sp, val, 1);
- }
- if (val & 0x02) {
- hsp = sp->hs;
- exval = readreg(sp->hscx[0], HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (hsp->tx_skb) {
- skb_push(hsp->tx_skb, hsp->count);
- hsp->tx_cnt += hsp->count;
- hsp->count = 0;
- }
- writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
- debugl1(sp, tmp);
- }
- }
- } else if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX A EXIR %x", exval);
- debugl1(sp, tmp);
- }
- }
- if (val & 0x04) {
- exval = readreg(sp->hscx[0], HSCX_ISTA);
- if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX A interrupt %x", exval);
- debugl1(sp, tmp);
- }
- hscx_interrupt(sp, exval, 0);
- }
-}
+#include "hscx_irq.c"
static void
avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
- struct IsdnCardState *sp;
+ struct IsdnCardState *cs = dev_id;
u_char val, sval, stat = 0;
char tmp[32];
- sp = (struct IsdnCardState *) dev_id;
-
- if (!sp) {
+ if (!cs) {
printk(KERN_WARNING "AVM A1: Spurious interrupt!\n");
return;
}
- while (((sval = bytein(sp->cfg_reg)) & 0xf) != 0x7) {
+ while (((sval = bytein(cs->hw.avm.cfg_reg)) & 0xf) != 0x7) {
if (!(sval & AVM_A1_STAT_TIMER)) {
- byteout(sp->cfg_reg, 0x14);
- byteout(sp->cfg_reg, 0x18);
- sval = bytein(sp->cfg_reg);
- } else if (sp->debug & L1_DEB_INTSTAT) {
+ byteout(cs->hw.avm.cfg_reg, 0x1E);
+ sval = bytein(cs->hw.avm.cfg_reg);
+ } else if (cs->debug & L1_DEB_INTSTAT) {
sprintf(tmp, "avm IntStatus %x", sval);
- debugl1(sp, tmp);
+ debugl1(cs, tmp);
}
if (!(sval & AVM_A1_STAT_HSCX)) {
- val = readreg(sp->hscx[1], HSCX_ISTA);
+ val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA);
if (val) {
- hscx_int_main(sp, val);
+ hscx_int_main(cs, val);
stat |= 1;
}
}
if (!(sval & AVM_A1_STAT_ISAC)) {
- val = readreg(sp->isac, ISAC_ISTA);
+ val = readreg(cs->hw.avm.isac, ISAC_ISTA);
if (val) {
- isac_interrupt(sp, val);
+ isac_interrupt(cs, val);
stat |= 2;
}
}
}
if (stat & 1) {
- writereg(sp->hscx[0], HSCX_MASK, 0xFF);
- writereg(sp->hscx[1], HSCX_MASK, 0xFF);
- writereg(sp->hscx[0], HSCX_MASK, 0x0);
- writereg(sp->hscx[1], HSCX_MASK, 0x0);
+ writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF);
+ writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF);
+ writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0);
+ writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0);
}
if (stat & 2) {
- writereg(sp->isac, ISAC_MASK, 0xFF);
- writereg(sp->isac, ISAC_MASK, 0x0);
+ writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.avm.isac, ISAC_MASK, 0x0);
}
}
-
-static void
-initisac(struct IsdnCardState *sp)
-{
- unsigned int adr = sp->isac;
-
- /* 16.3 IOM 2 Mode */
- writereg(adr, ISAC_MASK, 0xff);
- writereg(adr, ISAC_ADF2, 0x80);
- writereg(adr, ISAC_SQXR, 0x2f);
- writereg(adr, ISAC_SPCR, 0x0);
- writereg(adr, ISAC_ADF1, 0x2);
- writereg(adr, ISAC_STCR, 0x70);
- writereg(adr, ISAC_MODE, 0xc9);
- writereg(adr, ISAC_TIMR, 0x0);
- writereg(adr, ISAC_ADF1, 0x0);
- writereg(adr, ISAC_CMDR, 0x41);
- writereg(adr, ISAC_CIX0, (1 << 2) | 3);
- writereg(adr, ISAC_MASK, 0xff);
- writereg(adr, ISAC_MASK, 0x0);
-}
-
-static void
-modehscx(struct HscxState *hs, int mode, int ichan)
-{
- struct IsdnCardState *sp = hs->sp;
- int hscx = hs->hscx;
-
- if (sp->debug & L1_DEB_HSCX) {
- char tmp[40];
- sprintf(tmp, "hscx %c mode %d ichan %d",
- 'A' + hscx, mode, ichan);
- debugl1(sp, tmp);
- }
- hs->mode = mode;
- writereg(sp->hscx[hscx], HSCX_CCR1, 0x85);
- writereg(sp->hscx[hscx], HSCX_XAD1, 0xFF);
- writereg(sp->hscx[hscx], HSCX_XAD2, 0xFF);
- writereg(sp->hscx[hscx], HSCX_RAH2, 0xFF);
- writereg(sp->hscx[hscx], HSCX_XBCH, 0x0);
- writereg(sp->hscx[hscx], HSCX_RLCR, 0x0);
-
- switch (mode) {
- case (0):
- writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
- writereg(sp->hscx[hscx], HSCX_TSAX, 0xff);
- writereg(sp->hscx[hscx], HSCX_TSAR, 0xff);
- writereg(sp->hscx[hscx], HSCX_XCCR, 7);
- writereg(sp->hscx[hscx], HSCX_RCCR, 7);
- writereg(sp->hscx[hscx], HSCX_MODE, 0x84);
- break;
- case (1):
- if (ichan == 0) {
- writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
- writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
- writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
- writereg(sp->hscx[hscx], HSCX_XCCR, 7);
- writereg(sp->hscx[hscx], HSCX_RCCR, 7);
- } else {
- writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
- writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
- writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
- writereg(sp->hscx[hscx], HSCX_XCCR, 7);
- writereg(sp->hscx[hscx], HSCX_RCCR, 7);
- }
- writereg(sp->hscx[hscx], HSCX_MODE, 0xe4);
- writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
- break;
- case (2):
- if (ichan == 0) {
- writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
- writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
- writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
- writereg(sp->hscx[hscx], HSCX_XCCR, 7);
- writereg(sp->hscx[hscx], HSCX_RCCR, 7);
- } else {
- writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
- writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
- writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
- writereg(sp->hscx[hscx], HSCX_XCCR, 7);
- writereg(sp->hscx[hscx], HSCX_RCCR, 7);
- }
- writereg(sp->hscx[hscx], HSCX_MODE, 0x8c);
- writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
- break;
- }
- writereg(sp->hscx[hscx], HSCX_ISTA, 0x00);
-}
-
inline static void
-release_ioregs(struct IsdnCard *card, int mask)
+release_ioregs(struct IsdnCardState *cs, int mask)
{
- release_region(card->sp->cfg_reg, 8);
+ release_region(cs->hw.avm.cfg_reg, 8);
if (mask & 1)
- release_region(card->sp->isac, 32);
+ release_region(cs->hw.avm.isac + 32, 32);
if (mask & 2)
- release_region(card->sp->isac - 0x400, 1);
+ release_region(cs->hw.avm.isacfifo, 1);
if (mask & 4)
- release_region(card->sp->hscx[0], 32);
+ release_region(cs->hw.avm.hscx[0] + 32, 32);
if (mask & 8)
- release_region(card->sp->hscx[0] - 0x400, 1);
+ release_region(cs->hw.avm.hscxfifo[0], 1);
if (mask & 0x10)
- release_region(card->sp->hscx[1], 32);
+ release_region(cs->hw.avm.hscx[1] + 32, 32);
if (mask & 0x20)
- release_region(card->sp->hscx[1] - 0x400, 1);
+ release_region(cs->hw.avm.hscxfifo[1], 1);
}
-void
-release_io_avm_a1(struct IsdnCard *card)
+static int
+AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
- release_ioregs(card, 0x3f);
+ switch (mt) {
+ case CARD_RESET:
+ return(0);
+ case CARD_RELEASE:
+ release_ioregs(cs, 0x3f);
+ return(0);
+ case CARD_SETIRQ:
+ return(request_irq(cs->irq, &avm_a1_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs));
+ case CARD_INIT:
+ clear_pending_isac_ints(cs);
+ clear_pending_hscx_ints(cs);
+ initisac(cs);
+ inithscx(cs);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
}
-static void
-clear_pending_ints(struct IsdnCardState *sp)
+__initfunc(int
+setup_avm_a1(struct IsdnCard *card))
{
- int val;
- char tmp[64];
-
- val = readreg(sp->hscx[1], HSCX_ISTA);
- sprintf(tmp, "HSCX B ISTA %x", val);
- debugl1(sp, tmp);
- if (val & 0x01) {
- val = readreg(sp->hscx[1], HSCX_EXIR);
- sprintf(tmp, "HSCX B EXIR %x", val);
- debugl1(sp, tmp);
- } else if (val & 0x02) {
- val = readreg(sp->hscx[0], HSCX_EXIR);
- sprintf(tmp, "HSCX A EXIR %x", val);
- debugl1(sp, tmp);
- }
- val = readreg(sp->hscx[0], HSCX_ISTA);
- sprintf(tmp, "HSCX A ISTA %x", val);
- debugl1(sp, tmp);
- val = readreg(sp->hscx[1], HSCX_STAR);
- sprintf(tmp, "HSCX B STAR %x", val);
- debugl1(sp, tmp);
- val = readreg(sp->hscx[0], HSCX_STAR);
- sprintf(tmp, "HSCX A STAR %x", val);
- debugl1(sp, tmp);
- val = readreg(sp->isac, ISAC_STAR);
- sprintf(tmp, "ISAC STAR %x", val);
- debugl1(sp, tmp);
- val = readreg(sp->isac, ISAC_MODE);
- sprintf(tmp, "ISAC MODE %x", val);
- debugl1(sp, tmp);
- val = readreg(sp->isac, ISAC_ADF2);
- sprintf(tmp, "ISAC ADF2 %x", val);
- debugl1(sp, tmp);
- val = readreg(sp->isac, ISAC_ISTA);
- sprintf(tmp, "ISAC ISTA %x", val);
- debugl1(sp, tmp);
- if (val & 0x01) {
- val = readreg(sp->isac, ISAC_EXIR);
- sprintf(tmp, "ISAC EXIR %x", val);
- debugl1(sp, tmp);
- } else if (val & 0x04) {
- val = readreg(sp->isac, ISAC_CIR0);
- sprintf(tmp, "ISAC CIR0 %x", val);
- debugl1(sp, tmp);
- }
- writereg(sp->isac, ISAC_MASK, 0);
- writereg(sp->isac, ISAC_CMDR, 0x41);
-}
-
-int
-initavm_a1(struct IsdnCardState *sp)
-{
- int ret;
- int loop = 0;
- char tmp[40];
-
- sp->counter = kstat_irqs(sp->irq);
- sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
- debugl1(sp, tmp);
- clear_pending_ints(sp);
- ret = get_irq(sp->cardnr, &avm_a1_interrupt);
- if (ret) {
- initisac(sp);
- sp->modehscx(sp->hs, 0, 0);
- sp->modehscx(sp->hs + 1, 0, 0);
- while (loop++ < 10) {
- /* At least 1-3 irqs must happen
- * (one from HSCX A, one from HSCX B, 3rd from ISAC)
- */
- if (kstat_irqs(sp->irq) > sp->counter)
- break;
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + 1;
- schedule();
- }
- sprintf(tmp, "IRQ %d count %d", sp->irq,
- kstat_irqs(sp->irq));
- debugl1(sp, tmp);
- if (kstat_irqs(sp->irq) == sp->counter) {
- printk(KERN_WARNING
- "AVM A1: IRQ(%d) getting no interrupts during init\n",
- sp->irq);
- free_irq(sp->irq, sp);
- return (0);
- }
- }
- return (ret);
-}
-
-int
-setup_avm_a1(struct IsdnCard *card)
-{
- u_char val, verA, verB;
- struct IsdnCardState *sp = card->sp;
+ u_char val;
+ struct IsdnCardState *cs = card->cs;
long flags;
char tmp[64];
strcpy(tmp, avm_revision);
- printk(KERN_NOTICE "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp));
- if (sp->typ != ISDN_CTYPE_A1)
+ printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_A1)
return (0);
- sp->cfg_reg = card->para[1] + 0x1800;
- sp->isac = card->para[1] + 0x1400;
- sp->hscx[0] = card->para[1] + 0x400;
- sp->hscx[1] = card->para[1] + 0xc00;
- sp->irq = card->para[0];
- if (check_region((sp->cfg_reg), 8)) {
+ cs->hw.avm.cfg_reg = card->para[1] + 0x1800;
+ cs->hw.avm.isac = card->para[1] + 0x1400 - 0x20;
+ cs->hw.avm.hscx[0] = card->para[1] + 0x400 - 0x20;
+ cs->hw.avm.hscx[1] = card->para[1] + 0xc00 - 0x20;
+ cs->hw.avm.isacfifo = card->para[1] + 0x1000;
+ cs->hw.avm.hscxfifo[0] = card->para[1];
+ cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800;
+ cs->irq = card->para[0];
+ if (check_region((cs->hw.avm.cfg_reg), 8)) {
printk(KERN_WARNING
"HiSax: %s config port %x-%x already in use\n",
CardType[card->typ],
- sp->cfg_reg,
- sp->cfg_reg + 8);
+ cs->hw.avm.cfg_reg,
+ cs->hw.avm.cfg_reg + 8);
return (0);
} else {
- request_region(sp->cfg_reg, 8, "avm cfg");
+ request_region(cs->hw.avm.cfg_reg, 8, "avm cfg");
}
- if (check_region((sp->isac), 32)) {
+ if (check_region((cs->hw.avm.isac + 32), 32)) {
printk(KERN_WARNING
"HiSax: %s isac ports %x-%x already in use\n",
- CardType[sp->typ],
- sp->isac,
- sp->isac + 32);
- release_ioregs(card, 0);
+ CardType[cs->typ],
+ cs->hw.avm.isac + 32,
+ cs->hw.avm.isac + 64);
+ release_ioregs(cs, 0);
return (0);
} else {
- request_region(sp->isac, 32, "HiSax isac");
+ request_region(cs->hw.avm.isac + 32, 32, "HiSax isac");
}
- if (check_region((sp->isac - 0x400), 1)) {
+ if (check_region((cs->hw.avm.isacfifo), 1)) {
printk(KERN_WARNING
"HiSax: %s isac fifo port %x already in use\n",
- CardType[sp->typ],
- sp->isac - 0x400);
- release_ioregs(card, 1);
+ CardType[cs->typ],
+ cs->hw.avm.isacfifo);
+ release_ioregs(cs, 1);
return (0);
} else {
- request_region(sp->isac - 0x400, 1, "HiSax isac fifo");
+ request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo");
}
- if (check_region((sp->hscx[0]), 32)) {
+ if (check_region((cs->hw.avm.hscx[0]) + 32, 32)) {
printk(KERN_WARNING
"HiSax: %s hscx A ports %x-%x already in use\n",
- CardType[sp->typ],
- sp->hscx[0],
- sp->hscx[0] + 32);
- release_ioregs(card, 3);
+ CardType[cs->typ],
+ cs->hw.avm.hscx[0] + 32,
+ cs->hw.avm.hscx[0] + 64);
+ release_ioregs(cs, 3);
return (0);
} else {
- request_region(sp->hscx[0], 32, "HiSax hscx A");
+ request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A");
}
- if (check_region((sp->hscx[0] - 0x400), 1)) {
+ if (check_region(cs->hw.avm.hscxfifo[0], 1)) {
printk(KERN_WARNING
"HiSax: %s hscx A fifo port %x already in use\n",
- CardType[sp->typ],
- sp->hscx[0] - 0x400);
- release_ioregs(card, 7);
+ CardType[cs->typ],
+ cs->hw.avm.hscxfifo[0]);
+ release_ioregs(cs, 7);
return (0);
} else {
- request_region(sp->hscx[0] - 0x400, 1, "HiSax hscx A fifo");
+ request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo");
}
- if (check_region((sp->hscx[1]), 32)) {
+ if (check_region(cs->hw.avm.hscx[1] + 32, 32)) {
printk(KERN_WARNING
"HiSax: %s hscx B ports %x-%x already in use\n",
- CardType[sp->typ],
- sp->hscx[1],
- sp->hscx[1] + 32);
- release_ioregs(card, 0xf);
+ CardType[cs->typ],
+ cs->hw.avm.hscx[1] + 32,
+ cs->hw.avm.hscx[1] + 64);
+ release_ioregs(cs, 0xf);
return (0);
} else {
- request_region(sp->hscx[1], 32, "HiSax hscx B");
+ request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B");
}
- if (check_region((sp->hscx[1] - 0x400), 1)) {
+ if (check_region(cs->hw.avm.hscxfifo[1], 1)) {
printk(KERN_WARNING
"HiSax: %s hscx B fifo port %x already in use\n",
- CardType[sp->typ],
- sp->hscx[1] - 0x400);
- release_ioregs(card, 0x1f);
+ CardType[cs->typ],
+ cs->hw.avm.hscxfifo[1]);
+ release_ioregs(cs, 0x1f);
return (0);
} else {
- request_region(sp->hscx[1] - 0x400, 1, "HiSax hscx B fifo");
+ request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo");
}
save_flags(flags);
- byteout(sp->cfg_reg, 0x0);
+ byteout(cs->hw.avm.cfg_reg, 0x0);
sti();
HZDELAY(HZ / 5 + 1);
- byteout(sp->cfg_reg, 0x1);
+ byteout(cs->hw.avm.cfg_reg, 0x1);
HZDELAY(HZ / 5 + 1);
- byteout(sp->cfg_reg, 0x0);
+ byteout(cs->hw.avm.cfg_reg, 0x0);
HZDELAY(HZ / 5 + 1);
- val = sp->irq;
+ val = cs->irq;
if (val == 9)
val = 2;
- byteout(sp->cfg_reg + 1, val);
+ byteout(cs->hw.avm.cfg_reg + 1, val);
HZDELAY(HZ / 5 + 1);
- byteout(sp->cfg_reg, 0x0);
+ byteout(cs->hw.avm.cfg_reg, 0x0);
HZDELAY(HZ / 5 + 1);
restore_flags(flags);
- val = bytein(sp->cfg_reg);
+ val = bytein(cs->hw.avm.cfg_reg);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
- sp->cfg_reg, val);
- val = bytein(sp->cfg_reg + 3);
+ cs->hw.avm.cfg_reg, val);
+ val = bytein(cs->hw.avm.cfg_reg + 3);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
- sp->cfg_reg + 3, val);
- val = bytein(sp->cfg_reg + 2);
+ cs->hw.avm.cfg_reg + 3, val);
+ val = bytein(cs->hw.avm.cfg_reg + 2);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
- sp->cfg_reg + 2, val);
- byteout(sp->cfg_reg, 0x14);
- byteout(sp->cfg_reg, 0x18);
- val = bytein(sp->cfg_reg);
+ cs->hw.avm.cfg_reg + 2, val);
+ byteout(cs->hw.avm.cfg_reg, 0x1E);
+ val = bytein(cs->hw.avm.cfg_reg);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
- sp->cfg_reg, val);
-
- printk(KERN_NOTICE
- "HiSax: %s config irq:%d cfg:%x\n",
- CardType[sp->typ], sp->irq,
- sp->cfg_reg);
- printk(KERN_NOTICE
- "HiSax: isac:%x/%x\n",
- sp->isac, sp->isac - 0x400);
- printk(KERN_NOTICE
- "HiSax: hscx A:%x/%x hscx B:%x/%x\n",
- sp->hscx[0], sp->hscx[0] - 0x400,
- sp->hscx[1], sp->hscx[1] - 0x400);
- verA = readreg(sp->hscx[0], HSCX_VSTR) & 0xf;
- verB = readreg(sp->hscx[1], HSCX_VSTR) & 0xf;
- printk(KERN_INFO "AVM A1: HSCX version A: %s B: %s\n",
- HscxVersion(verA), HscxVersion(verB));
- val = readreg(sp->isac, ISAC_RBCH);
- printk(KERN_INFO "AVM A1: ISAC %s\n",
- ISACVersion(val));
- if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
+ cs->hw.avm.cfg_reg, val);
+
+ printk(KERN_INFO
+ "HiSax: %s config irq:%d cfg:0x%X\n",
+ CardType[cs->typ], cs->irq,
+ cs->hw.avm.cfg_reg);
+ printk(KERN_INFO
+ "HiSax: isac:0x%X/0x%X\n",
+ cs->hw.avm.isac + 32, cs->hw.avm.isacfifo);
+ printk(KERN_INFO
+ "HiSax: hscx A:0x%X/0x%X hscx B:0x%X/0x%X\n",
+ cs->hw.avm.hscx[0] + 32, cs->hw.avm.hscxfifo[0],
+ cs->hw.avm.hscx[1] + 32, cs->hw.avm.hscxfifo[1]);
+
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ cs->BC_Read_Reg = &ReadHSCX;
+ cs->BC_Write_Reg = &WriteHSCX;
+ cs->BC_Send_Data = &hscx_fill_fifo;
+ cs->cardmsg = &AVM_card_msg;
+ ISACVersion(cs, "AVM A1:");
+ if (HscxVersion(cs, "AVM A1:")) {
printk(KERN_WARNING
"AVM A1: wrong HSCX versions check IO address\n");
- release_io_avm_a1(card);
+ release_ioregs(cs, 0x3f);
return (0);
}
- sp->modehscx = &modehscx;
- sp->ph_command = &ph_command;
- sp->hscx_fill_fifo = &hscx_fill_fifo;
- sp->isac_fill_fifo = &isac_fill_fifo;
return (1);
}
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index fbf045574..6924e3f9e 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 1.30 1997/05/29 10:40:43 keil Exp $
+/* $Id: callc.c,v 2.13 1998/02/12 23:07:16 keil Exp $
* Author Karsten Keil (keil@temic-ech.spacenet.de)
* based on the teles driver from Jan den Ouden
@@ -7,96 +7,54 @@
* Fritz Elfert
*
* $Log: callc.c,v $
- * Revision 1.30 1997/05/29 10:40:43 keil
- * chanp->impair was uninitialised
+ * Revision 2.13 1998/02/12 23:07:16 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
*
- * Revision 1.29 1997/04/23 20:09:49 fritz
- * Removed tmp, used by removed debugging code.
+ * Revision 2.12 1998/02/09 10:55:54 keil
+ * New leased line mode
*
- * Revision 1.28 1997/04/21 13:42:25 keil
- * Remove unneeded debug
+ * Revision 2.11 1998/02/02 13:35:19 keil
+ * config B-channel delay
*
- * Revision 1.27 1997/04/16 14:21:01 keil
- * remove unused variable
+ * Revision 2.10 1997/11/06 17:09:15 keil
+ * New 2.1 init code
*
- * Revision 1.26 1997/04/13 19:55:21 keil
- * Changes in debugging code
+ * Revision 2.9 1997/10/29 19:01:58 keil
+ * new LL interface
*
- * Revision 1.25 1997/04/06 22:54:08 keil
- * Using SKB's
+ * Revision 2.8 1997/10/10 20:56:44 fritz
+ * New HL interface.
*
- * Revision 1.24 1997/03/05 11:28:03 keil
- * fixed undefined l2tei procedure
- * a layer1 release delete now the drel timer
+ * Revision 2.7 1997/10/01 09:21:28 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
*
- * Revision 1.23 1997/03/04 23:07:42 keil
- * bugfix dial parameter
+ * Revision 2.6 1997/09/11 17:26:58 keil
+ * Open B-channel if here are incomming packets
*
- * Revision 1.22 1997/02/27 13:51:55 keil
- * Reset B-channel (dlc) statemachine in every release
+ * Revision 2.5 1997/08/07 17:46:05 keil
+ * Fix Incomming Call without broadcast
*
- * Revision 1.21 1997/02/19 09:24:27 keil
- * Bugfix: Hangup to LL if a ttyI rings
+ * Revision 2.4 1997/08/03 14:37:58 keil
+ * Activate Layer2 in PtP mode
*
- * Revision 1.20 1997/02/17 00:32:47 keil
- * Bugfix: No Busy reported to LL
+ * Revision 2.3 1997/07/31 19:23:40 keil
+ * LAYER2_WATCHING for PtP
*
- * Revision 1.19 1997/02/14 12:23:10 fritz
- * Added support for new insmod parameter handling.
+ * Revision 2.2 1997/07/31 11:48:18 keil
+ * experimental REJECT after ALERTING
*
- * Revision 1.18 1997/02/11 01:36:58 keil
- * Changed setup-interface (incoming and outgoing), cause reporting
+ * Revision 2.1 1997/07/30 17:12:59 keil
+ * more changes for 'One TEI per card'
*
- * Revision 1.17 1997/02/09 00:23:10 keil
- * new interface handling, one interface per card
- * some changes in debug and leased line mode
+ * Revision 2.0 1997/07/27 21:12:21 keil
+ * CRef based L3; new channel handling; many other stuff
*
- * Revision 1.16 1997/01/27 23:17:03 keil
- * delete timers while unloading
+ * Revision 1.31 1997/06/26 11:09:23 keil
+ * New managment and minor changes
*
- * Revision 1.15 1997/01/27 16:00:38 keil
- * D-channel shutdown delay; improved callback
- *
- * Revision 1.14 1997/01/21 22:16:39 keil
- * new statemachine; leased line support; cleanup for 2.0
- *
- * Revision 1.13 1996/12/08 19:51:17 keil
- * bugfixes from Pekka Sarnila
- *
- * Revision 1.12 1996/11/26 20:20:03 keil
- * fixed warning while compile
- *
- * Revision 1.11 1996/11/26 18:43:17 keil
- * change ioctl 555 --> 55 (555 didn't work)
- *
- * Revision 1.10 1996/11/26 18:06:07 keil
- * fixed missing break statement,ioctl 555 reset modcount
- *
- * Revision 1.9 1996/11/18 20:23:19 keil
- * log writebuf channel not open changed
- *
- * Revision 1.8 1996/11/06 17:43:17 keil
- * more changes for 2.1.X;block fixed ST_PRO_W
- *
- * Revision 1.7 1996/11/06 15:13:51 keil
- * typo 0x64 --->64 in debug code
- *
- * Revision 1.6 1996/11/05 19:40:33 keil
- * X.75 windowsize
- *
- * Revision 1.5 1996/10/30 10:11:06 keil
- * debugging LOCK changed;ST_REL_W EV_HANGUP added
- *
- * Revision 1.4 1996/10/27 22:20:16 keil
- * alerting bugfixes
- * no static b-channel<->channel mapping
- *
- * Revision 1.2 1996/10/16 21:29:45 keil
- * compile bug as "not module"
- * Callback with euro
- *
- * Revision 1.1 1996/10/13 20:04:50 keil
- * Initial revision
+ * old logs removed /KKe
*
*/
@@ -104,53 +62,63 @@
#include "hisax.h"
#ifdef MODULE
-#if (LINUX_VERSION_CODE < 0x020111)
-extern long mod_use_count_;
-#define MOD_USE_COUNT mod_use_count_
-#else
#define MOD_USE_COUNT ((&__this_module)->usecount)
-#endif
#endif /* MODULE */
-const char *l4_revision = "$Revision: 1.30 $";
+const char *lli_revision = "$Revision: 2.13 $";
extern struct IsdnCard cards[];
extern int nrcards;
extern void HiSax_mod_dec_use_count(void);
extern void HiSax_mod_inc_use_count(void);
-static int init_ds(struct Channel *chanp, int incoming);
-static void release_ds(struct Channel *chanp);
+static int init_b_st(struct Channel *chanp, int incoming);
+static void release_b_st(struct Channel *chanp);
static struct Fsm callcfsm =
-{NULL, 0, 0};
+{NULL, 0, 0, NULL, NULL};
static struct Fsm lcfsm =
-{NULL, 0, 0};
+{NULL, 0, 0, NULL, NULL};
static int chancount = 0;
-/* Flags for remembering action done in l4 */
-
-#define FLG_START_D 0x0001
-#define FLG_ESTAB_D 0x0002
-#define FLG_CALL_SEND 0x0004
-#define FLG_CALL_REC 0x0008
-#define FLG_CALL_ALERT 0x0010
-#define FLG_START_B 0x0020
-#define FLG_CONNECT_B 0x0040
-#define FLG_LL_DCONN 0x0080
-#define FLG_LL_BCONN 0x0100
-#define FLG_DISC_SEND 0x0200
-#define FLG_DISC_REC 0x0400
-#define FLG_REL_REC 0x0800
-
-#define SETBIT(flg, item) flg |= item
-#define RESBIT(flg, item) flg &= (~item)
+/* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */
+#define ALERT_REJECT 1
+
+/* Value to delay the sending of the first B-channel paket after CONNECT
+ * here is no value given by ITU, but experience shows that 300 ms will
+ * work on many networks, if you or your other side is behind local exchanges
+ * a greater value may be recommented. If the delay is to short the first paket
+ * will be lost and autodetect on many comercial routers goes wrong !
+ * You can adjust this value on runtime with
+ * hisaxctrl <id> 2 <value>
+ * value is in milliseconds
+ */
+#define DEFAULT_B_DELAY 300
+
+/* Flags for remembering action done in lli */
+
+#define FLG_START_D 0
+#define FLG_ESTAB_D 1
+#define FLG_CALL_SEND 2
+#define FLG_CALL_REC 3
+#define FLG_CALL_ALERT 4
+#define FLG_START_B 5
+#define FLG_CONNECT_B 6
+#define FLG_LL_DCONN 7
+#define FLG_LL_BCONN 8
+#define FLG_DISC_SEND 9
+#define FLG_DISC_REC 10
+#define FLG_REL_REC 11
+#define FLG_DO_ALERT 12
+#define FLG_DO_HANGUP 13
+#define FLG_DO_CONNECT 14
+#define FLG_DO_ESTAB 15
/*
* Because of callback it's a good idea to delay the shutdown of the d-channel
*/
-#define DREL_TIMER_VALUE 30000
+#define DREL_TIMER_VALUE 10000
/*
* Find card with given driverId
@@ -162,9 +130,9 @@ hisax_findcard(int driverid)
int i;
for (i = 0; i < nrcards; i++)
- if (cards[i].sp)
- if (cards[i].sp->myid == driverid)
- return (cards[i].sp);
+ if (cards[i].cs)
+ if (cards[i].cs->myid == driverid)
+ return (cards[i].cs);
return (struct IsdnCardState *) 0;
}
@@ -176,7 +144,7 @@ link_debug(struct Channel *chanp, char *s, int direction)
jiftime(tm, jiffies);
sprintf(tmp, "%s Channel %d %s %s\n", tm, chanp->chan,
direction ? "LL->HL" : "HL->LL", s);
- HiSax_putstatus(chanp->sp, tmp);
+ HiSax_putstatus(chanp->cs, tmp);
}
@@ -233,7 +201,7 @@ enum {
EV_SETUP_CMPL_IND, /* 10 */
EV_BC_EST, /* 11 */
EV_WRITEBUF, /* 12 */
- EV_DATAIN, /* 13 */
+ EV_ESTABLISH, /* 13 */
EV_HANGUP, /* 14 */
EV_BC_REL, /* 15 */
EV_CINF, /* 16 */
@@ -263,7 +231,7 @@ static char *strEvent[] =
"EV_SETUP_CMPL_IND",
"EV_BC_EST",
"EV_WRITEBUF",
- "EV_DATAIN",
+ "EV_ESTABLISH",
"EV_HANGUP",
"EV_BC_REL",
"EV_CINF",
@@ -283,7 +251,6 @@ enum {
ST_LC_ESTABLISH_WAIT,
ST_LC_CONNECTED,
ST_LC_FLUSH_WAIT,
- ST_LC_FLUSH_DELAY,
ST_LC_RELEASE_WAIT,
};
@@ -297,7 +264,6 @@ static char *strLcState[] =
"ST_LC_ESTABLISH_WAIT",
"ST_LC_CONNECTED",
"ST_LC_FLUSH_WAIT",
- "ST_LC_FLUSH_DELAY",
"ST_LC_RELEASE_WAIT",
};
@@ -307,9 +273,7 @@ enum {
EV_LC_PH_DEACTIVATE,
EV_LC_DL_ESTABLISH,
EV_LC_TIMER,
- EV_LC_DL_FLUSH,
EV_LC_DL_RELEASE,
- EV_LC_FLUSH,
EV_LC_RELEASE,
};
@@ -322,9 +286,7 @@ static char *strLcEvent[] =
"EV_LC_PH_DEACTIVATE",
"EV_LC_DL_ESTABLISH",
"EV_LC_TIMER",
- "EV_LC_DL_FLUSH",
"EV_LC_DL_RELEASE",
- "EV_LC_FLUSH",
"EV_LC_RELEASE",
};
@@ -332,788 +294,962 @@ static char *strLcEvent[] =
#define LC_B 1
static inline void
-l4_deliver_cause(struct Channel *chanp)
+lli_deliver_cause(struct Channel *chanp)
{
isdn_ctrl ic;
- if (chanp->para.cause < 0)
+ if (chanp->proc->para.cause < 0)
return;
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_CAUSE;
ic.arg = chanp->chan;
- if (chanp->sp->protocol == ISDN_PTYPE_EURO)
- sprintf(ic.parm.num, "E%02X%02X", chanp->para.loc & 0x7f,
- chanp->para.cause & 0x7f);
+ if (chanp->cs->protocol == ISDN_PTYPE_EURO)
+ sprintf(ic.parm.num, "E%02X%02X", chanp->proc->para.loc & 0x7f,
+ chanp->proc->para.cause & 0x7f);
else
- sprintf(ic.parm.num, "%02X%02X", chanp->para.loc & 0x7f,
- chanp->para.cause & 0x7f);
- chanp->sp->iif.statcallb(&ic);
+ sprintf(ic.parm.num, "%02X%02X", chanp->proc->para.loc & 0x7f,
+ chanp->proc->para.cause & 0x7f);
+ chanp->cs->iif.statcallb(&ic);
+}
+
+static void
+lli_d_established(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
+ if (chanp->leased) {
+ isdn_ctrl ic;
+ int ret;
+ char txt[32];
+
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) chanp->chan);
+ FsmChangeState(fi, ST_IN_WAIT_LL);
+ test_and_set_bit(FLG_CALL_REC, &chanp->Flags);
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_ICALL_LEASED", 0);
+ ic.driver = chanp->cs->myid;
+ ic.command = ISDN_STAT_ICALL;
+ ic.arg = chanp->chan;
+ ic.parm.setup.si1 = 7;
+ ic.parm.setup.si2 = 0;
+ ic.parm.setup.plan = 0;
+ ic.parm.setup.screen = 0;
+ sprintf(ic.parm.setup.eazmsn,"%d", chanp->chan + 1);
+ sprintf(ic.parm.setup.phone,"LEASED%d", chanp->cs->myid);
+ ret = chanp->cs->iif.statcallb(&ic);
+ if (chanp->debug & 1) {
+ sprintf(txt, "statcallb ret=%d", ret);
+ link_debug(chanp, txt, 1);
+ }
+ if (!ret) {
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
+ FsmChangeState(fi, ST_NULL);
+ }
+ } else if (fi->state == ST_WAIT_DSHUTDOWN)
+ FsmChangeState(fi, ST_NULL);
+}
+
+static void
+lli_d_released(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ test_and_clear_bit(FLG_START_D, &chanp->Flags);
}
/*
* Dial out
*/
static void
-l4_prep_dialout(struct FsmInst *fi, int event, void *arg)
+lli_prep_dialout(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
FsmChangeState(fi, ST_OUT_WAIT_D);
FsmDelTimer(&chanp->drel_timer, 60);
FsmDelTimer(&chanp->dial_timer, 73);
-
chanp->l2_active_protocol = chanp->l2_protocol;
chanp->incoming = 0;
- chanp->lc_b.l2_start = !0;
+ chanp->lc_b->l2_start = !0;
switch (chanp->l2_active_protocol) {
case (ISDN_PROTO_L2_X75I):
- chanp->lc_b.l2_establish = !0;
+ chanp->lc_b->l2_establish = !0;
break;
case (ISDN_PROTO_L2_HDLC):
case (ISDN_PROTO_L2_TRANS):
- chanp->lc_b.l2_establish = 0;
+ chanp->lc_b->l2_establish = 0;
break;
default:
- printk(KERN_WARNING "l4_prep_dialout unknown protocol\n");
+ printk(KERN_WARNING "lli_prep_dialout unknown protocol\n");
break;
}
- if (chanp->Flags & FLG_ESTAB_D) {
+ if (test_bit(FLG_ESTAB_D, &chanp->Flags)) {
FsmEvent(fi, EV_DLEST, NULL);
} else {
- chanp->Flags = FLG_START_D;
+ chanp->Flags = 0;
+ test_and_set_bit(FLG_START_D, &chanp->Flags);
if (chanp->leased) {
- chanp->lc_d.l2_establish = 0;
+ chanp->lc_d->l2_establish = 0;
}
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
+ FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
}
}
static void
-l4_do_dialout(struct FsmInst *fi, int event, void *arg)
+lli_do_dialout(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
FsmChangeState(fi, ST_OUT_DIAL);
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) chanp->chan);
if (chanp->leased) {
- chanp->para.bchannel = (chanp->chan & 1) + 1;
FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
} else {
- SETBIT(chanp->Flags, FLG_ESTAB_D);
- chanp->para.callref = chanp->outcallref;
- chanp->outcallref++;
- if (chanp->outcallref == 128)
- chanp->outcallref = 64;
- chanp->is.l4.l4l3(&chanp->is, CC_SETUP_REQ, NULL);
- SETBIT(chanp->Flags, FLG_CALL_SEND);
+ test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_REQ, chanp);
+ test_and_set_bit(FLG_CALL_SEND, &chanp->Flags);
}
}
static void
-l4_init_bchan_out(struct FsmInst *fi, int event, void *arg)
+lli_init_bchan_out(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
FsmChangeState(fi, ST_WAIT_BCONN);
- SETBIT(chanp->Flags, FLG_LL_DCONN);
+ test_and_set_bit(FLG_LL_DCONN, &chanp->Flags);
if (chanp->debug & 1)
link_debug(chanp, "STAT_DCONN", 0);
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_DCONN;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
- init_ds(chanp, 0);
- SETBIT(chanp->Flags, FLG_START_B);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
+ chanp->cs->iif.statcallb(&ic);
+ init_b_st(chanp, 0);
+ test_and_set_bit(FLG_START_B, &chanp->Flags);
+ FsmEvent(&chanp->lc_b->lcfi, EV_LC_ESTABLISH, NULL);
}
static void
-l4_go_active(struct FsmInst *fi, int event, void *arg)
+lli_go_active(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
FsmChangeState(fi, ST_ACTIVE);
chanp->data_open = !0;
- SETBIT(chanp->Flags, FLG_CONNECT_B);
+ test_and_set_bit(FLG_CONNECT_B, &chanp->Flags);
if (chanp->debug & 1)
link_debug(chanp, "STAT_BCONN", 0);
- SETBIT(chanp->Flags, FLG_LL_BCONN);
- ic.driver = chanp->sp->myid;
+ test_and_set_bit(FLG_LL_BCONN, &chanp->Flags);
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_BCONN;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ chanp->cs->iif.statcallb(&ic);
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) chanp->chan);
}
/* incomming call */
static void
-l4_start_dchan(struct FsmInst *fi, int event, void *arg)
+lli_start_dchan(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
FsmChangeState(fi, ST_IN_WAIT_D);
FsmDelTimer(&chanp->drel_timer, 61);
- if (chanp->Flags & FLG_ESTAB_D) {
+ if (event == EV_ACCEPTD)
+ test_and_set_bit(FLG_DO_CONNECT, &chanp->Flags);
+ else if (event == EV_HANGUP) {
+ test_and_set_bit(FLG_DO_HANGUP, &chanp->Flags);
+#ifdef ALERT_REJECT
+ test_and_set_bit(FLG_DO_ALERT, &chanp->Flags);
+#endif
+ }
+ if (test_bit(FLG_ESTAB_D, &chanp->Flags)) {
FsmEvent(fi, EV_DLEST, NULL);
- } else {
- chanp->Flags = FLG_START_D;
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
- }
+ } else if (!test_and_set_bit(FLG_START_D, &chanp->Flags))
+ FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
}
static void
-l4_deliver_call(struct FsmInst *fi, int event, void *arg)
+lli_deliver_call(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
int ret;
char txt[32];
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) chanp->chan);
/*
* Report incoming calls only once to linklevel, use CallFlags
* which is set to 3 with each broadcast message in isdnl1.c
* and resetted if a interface answered the STAT_ICALL.
*/
- if ((chanp->sp) && (chanp->sp->CallFlags == 3)) {
+ if (1) { /* for only one TEI */
FsmChangeState(fi, ST_IN_WAIT_LL);
- SETBIT(chanp->Flags, FLG_ESTAB_D);
- SETBIT(chanp->Flags, FLG_CALL_REC);
+ test_and_set_bit(FLG_CALL_REC, &chanp->Flags);
if (chanp->debug & 1)
link_debug(chanp, "STAT_ICALL", 0);
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_ICALL;
ic.arg = chanp->chan;
/*
* No need to return "unknown" for calls without OAD,
* cause that's handled in linklevel now (replaced by '0')
*/
- ic.parm.setup = chanp->para.setup;
- ret = chanp->sp->iif.statcallb(&ic);
+ ic.parm.setup = chanp->proc->para.setup;
+ ret = chanp->cs->iif.statcallb(&ic);
if (chanp->debug & 1) {
sprintf(txt, "statcallb ret=%d", ret);
link_debug(chanp, txt, 1);
}
- if (ret) /* if a interface knows this call, reset the CallFlag
- * to avoid a second Call report to the linklevel
- */
- chanp->sp->CallFlags &= ~(chanp->chan + 1);
switch (ret) {
case 1: /* OK, anybody likes this call */
- FsmChangeState(fi, ST_IN_ALERT_SEND);
- SETBIT(chanp->Flags, FLG_CALL_ALERT);
- chanp->is.l4.l4l3(&chanp->is, CC_ALERTING_REQ, NULL);
+ FsmDelTimer(&chanp->drel_timer, 61);
+ if (test_bit(FLG_ESTAB_D, &chanp->Flags)) {
+ FsmChangeState(fi, ST_IN_ALERT_SEND);
+ test_and_set_bit(FLG_CALL_ALERT, &chanp->Flags);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING_REQ, chanp->proc);
+ } else {
+ test_and_set_bit(FLG_DO_ALERT, &chanp->Flags);
+ FsmChangeState(fi, ST_IN_WAIT_D);
+ test_and_set_bit(FLG_START_D, &chanp->Flags);
+ FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
+ }
break;
case 2: /* Rejecting Call */
- RESBIT(chanp->Flags, FLG_CALL_REC);
+ test_and_clear_bit(FLG_CALL_REC, &chanp->Flags);
break;
case 0: /* OK, nobody likes this call */
default: /* statcallb problems */
- chanp->is.l4.l4l3(&chanp->is, CC_IGNORE, NULL);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE, chanp->proc);
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
FsmChangeState(fi, ST_NULL);
- chanp->Flags = FLG_ESTAB_D;
- FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 61);
+#ifndef LAYER2_WATCHING
+ if (test_bit(FLG_ESTAB_D, &chanp->Flags))
+ FsmRestartTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 61);
+#endif
break;
}
} else {
- chanp->is.l4.l4l3(&chanp->is, CC_IGNORE, NULL);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE, chanp->proc);
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
+ FsmChangeState(fi, ST_NULL);
+#ifndef LAYER2_WATCHING
+ if (test_bit(FLG_ESTAB_D, &chanp->Flags))
+ FsmRestartTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 62);
+#endif
+ }
+}
+
+static void
+lli_establish_d(struct FsmInst *fi, int event, void *arg)
+{
+ /* This establish the D-channel for pending L3 messages
+ * without blocking th channel
+ */
+ struct Channel *chanp = fi->userdata;
+
+ test_and_set_bit(FLG_DO_ESTAB, &chanp->Flags);
+ FsmChangeState(fi, ST_IN_WAIT_D);
+ test_and_set_bit(FLG_START_D, &chanp->Flags);
+ FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
+}
+
+static void
+lli_do_action(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
+ if (chanp->leased) {
+ FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
+ test_and_clear_bit(FLG_DO_ALERT, &chanp->Flags);
+ test_and_clear_bit(FLG_DO_CONNECT, &chanp->Flags);
+ FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL);
+ } else if (test_and_clear_bit(FLG_DO_CONNECT, &chanp->Flags) &&
+ !test_bit(FLG_DO_HANGUP, &chanp->Flags)) {
+ FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
+ test_and_clear_bit(FLG_DO_ALERT, &chanp->Flags);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_RSP, chanp->proc);
+ } else if (test_and_clear_bit(FLG_DO_ALERT, &chanp->Flags)) {
+ if (test_bit(FLG_DO_HANGUP, &chanp->Flags))
+ FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63);
+ FsmChangeState(fi, ST_IN_ALERT_SEND);
+ test_and_set_bit(FLG_CALL_ALERT, &chanp->Flags);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING_REQ, chanp->proc);
+ } else if (test_and_clear_bit(FLG_DO_HANGUP, &chanp->Flags)) {
+ FsmChangeState(fi, ST_WAIT_DRELEASE);
+ chanp->proc->para.cause = 0x15; /* Call Rejected */
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT_REQ, chanp->proc);
+ test_and_set_bit(FLG_DISC_SEND, &chanp->Flags);
+ } else if (test_and_clear_bit(FLG_DO_ESTAB, &chanp->Flags)) {
FsmChangeState(fi, ST_NULL);
- chanp->Flags = FLG_ESTAB_D;
- FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 62);
+ chanp->Flags = 0;
+ test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_ESTABLISH, chanp->proc);
+ chanp->proc = NULL;
+#ifndef LAYER2_WATCHING
+ FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60);
+#endif
}
}
static void
-l4_send_dconnect(struct FsmInst *fi, int event, void *arg)
+lli_send_dconnect(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
- chanp->is.l4.l4l3(&chanp->is, CC_SETUP_RSP, NULL);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_RSP, chanp->proc);
}
static void
-l4_init_bchan_in(struct FsmInst *fi, int event, void *arg)
+lli_init_bchan_in(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
FsmChangeState(fi, ST_WAIT_BCONN);
- SETBIT(chanp->Flags, FLG_LL_DCONN);
+ test_and_set_bit(FLG_LL_DCONN, &chanp->Flags);
if (chanp->debug & 1)
link_debug(chanp, "STAT_DCONN", 0);
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_DCONN;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ chanp->cs->iif.statcallb(&ic);
chanp->l2_active_protocol = chanp->l2_protocol;
chanp->incoming = !0;
- chanp->lc_b.l2_start = 0;
+ chanp->lc_b->l2_start = 0;
switch (chanp->l2_active_protocol) {
case (ISDN_PROTO_L2_X75I):
- chanp->lc_b.l2_establish = !0;
+ chanp->lc_b->l2_establish = !0;
break;
case (ISDN_PROTO_L2_HDLC):
case (ISDN_PROTO_L2_TRANS):
- chanp->lc_b.l2_establish = 0;
+ chanp->lc_b->l2_establish = 0;
break;
default:
- printk(KERN_WARNING "r9 unknown protocol\n");
+ printk(KERN_WARNING "bchannel unknown protocol\n");
break;
}
- init_ds(chanp, !0);
- SETBIT(chanp->Flags, FLG_START_B);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
+ init_b_st(chanp, !0);
+ test_and_set_bit(FLG_START_B, &chanp->Flags);
+ FsmEvent(&chanp->lc_b->lcfi, EV_LC_ESTABLISH, NULL);
}
/* Call clearing */
static void
-l4_reject_call(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_WAIT_DRELEASE);
- chanp->para.cause = 0x15; /* Call Rejected */
- chanp->is.l4.l4l3(&chanp->is, CC_REJECT_REQ, NULL);
- SETBIT(chanp->Flags, FLG_DISC_SEND);
-}
-
-static void
-l4_cancel_call(struct FsmInst *fi, int event, void *arg)
+lli_cancel_call(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
FsmChangeState(fi, ST_WAIT_DRELEASE);
- if (chanp->Flags & FLG_LL_BCONN) {
+ if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
if (chanp->debug & 1)
link_debug(chanp, "STAT_BHUP", 0);
- RESBIT(chanp->Flags, FLG_LL_BCONN);
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_BHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
- }
- if (chanp->Flags & FLG_START_B) {
- release_ds(chanp);
- RESBIT(chanp->Flags, FLG_START_B);
+ chanp->cs->iif.statcallb(&ic);
}
- chanp->para.cause = 0x10; /* Normal Call Clearing */
- chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
- SETBIT(chanp->Flags, FLG_DISC_SEND);
+ if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
+ release_b_st(chanp);
+ chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT_REQ, chanp->proc);
+ test_and_set_bit(FLG_DISC_SEND, &chanp->Flags);
}
static void
-l4_shutdown_d(struct FsmInst *fi, int event, void *arg)
+lli_shutdown_d(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
- FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
FsmDelTimer(&chanp->drel_timer, 62);
- RESBIT(chanp->Flags, FLG_ESTAB_D);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+#ifdef LAYER2_WATCHING
+ FsmChangeState(fi, ST_NULL);
+#else
+ if (!test_bit(FLG_TWO_DCHAN, &chanp->cs->HW_Flags)) {
+ if (chanp->chan) {
+ if (chanp->cs->channel[0].fi.state != ST_NULL)
+ return;
+ } else {
+ if (chanp->cs->channel[1].fi.state != ST_NULL)
+ return;
+ }
+ }
+ FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
+ test_and_clear_bit(FLG_ESTAB_D, &chanp->Flags);
+ FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL);
+#endif
}
static void
-l4_timeout_d(struct FsmInst *fi, int event, void *arg)
+lli_timeout_d(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
- if (chanp->Flags & FLG_LL_DCONN) {
+ if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) {
if (chanp->debug & 1)
link_debug(chanp, "STAT_DHUP", 0);
- RESBIT(chanp->Flags, FLG_LL_DCONN);
- l4_deliver_cause(chanp);
- ic.driver = chanp->sp->myid;
+ lli_deliver_cause(chanp);
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_DHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ chanp->cs->iif.statcallb(&ic);
}
FsmChangeState(fi, ST_NULL);
- chanp->Flags = FLG_ESTAB_D;
+ chanp->Flags = 0;
+ test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
+#ifndef LAYER2_WATCHING
FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60);
+#endif
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
}
static void
-l4_go_null(struct FsmInst *fi, int event, void *arg)
+lli_go_null(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
FsmChangeState(fi, ST_NULL);
chanp->Flags = 0;
FsmDelTimer(&chanp->drel_timer, 63);
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
}
static void
-l4_disconn_bchan(struct FsmInst *fi, int event, void *arg)
+lli_disconn_bchan(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
chanp->data_open = 0;
FsmChangeState(fi, ST_WAIT_BRELEASE);
- RESBIT(chanp->Flags, FLG_CONNECT_B);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+ test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags);
+ FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
}
static void
-l4_send_d_disc(struct FsmInst *fi, int event, void *arg)
+lli_send_d_disc(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
-
- if (chanp->Flags & (FLG_DISC_REC | FLG_REL_REC))
+ if (test_bit(FLG_DISC_REC, &chanp->Flags) ||
+ test_bit(FLG_REL_REC, &chanp->Flags))
return;
FsmChangeState(fi, ST_WAIT_DRELEASE);
- if (chanp->Flags & FLG_LL_BCONN) {
+ if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
if (chanp->debug & 1)
link_debug(chanp, "STAT_BHUP", 0);
- RESBIT(chanp->Flags, FLG_LL_BCONN);
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_BHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ chanp->cs->iif.statcallb(&ic);
}
- if (chanp->Flags & FLG_START_B) {
- release_ds(chanp);
- RESBIT(chanp->Flags, FLG_START_B);
+ if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
+ release_b_st(chanp);
+ if (chanp->leased) {
+ ic.command = ISDN_STAT_CAUSE;
+ ic.arg = chanp->chan;
+ sprintf(ic.parm.num, "L0010");
+ chanp->cs->iif.statcallb(&ic);
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_DHUP", 0);
+ ic.driver = chanp->cs->myid;
+ ic.command = ISDN_STAT_DHUP;
+ ic.arg = chanp->chan;
+ chanp->cs->iif.statcallb(&ic);
+ FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
+ test_and_clear_bit(FLG_ESTAB_D, &chanp->Flags);
+ FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL);
+ } else {
+ if (test_and_clear_bit(FLG_DO_HANGUP, &chanp->Flags))
+ chanp->proc->para.cause = 0x15; /* Call Reject */
+ else
+ chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT_REQ, chanp->proc);
+ test_and_set_bit(FLG_DISC_SEND, &chanp->Flags);
}
- chanp->para.cause = 0x10; /* Normal Call Clearing */
- chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
- SETBIT(chanp->Flags, FLG_DISC_SEND);
}
static void
-l4_released_bchan(struct FsmInst *fi, int event, void *arg)
+lli_released_bchan(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
FsmChangeState(fi, ST_WAIT_DCOMMAND);
chanp->data_open = 0;
- if (chanp->Flags & FLG_LL_BCONN) {
+ if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
if (chanp->debug & 1)
link_debug(chanp, "STAT_BHUP", 0);
- RESBIT(chanp->Flags, FLG_LL_BCONN);
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_BHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ chanp->cs->iif.statcallb(&ic);
}
- release_ds(chanp);
- RESBIT(chanp->Flags, FLG_START_B);
+ release_b_st(chanp);
+ test_and_clear_bit(FLG_START_B, &chanp->Flags);
}
static void
-l4_release_bchan(struct FsmInst *fi, int event, void *arg)
+lli_release_bchan(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
chanp->data_open = 0;
- SETBIT(chanp->Flags, FLG_DISC_REC);
+ test_and_set_bit(FLG_DISC_REC, &chanp->Flags);
FsmChangeState(fi, ST_WAIT_BREL_DISC);
- RESBIT(chanp->Flags, FLG_CONNECT_B);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+ test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags);
+ FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
}
static void
-l4_received_d_rel(struct FsmInst *fi, int event, void *arg)
+lli_received_d_rel(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
chanp->data_open = 0;
- FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
- SETBIT(chanp->Flags, FLG_REL_REC);
- if (chanp->Flags & FLG_CONNECT_B) {
- chanp->lc_b.l2_establish = 0; /* direct reset in lc_b.lcfi */
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
- RESBIT(chanp->Flags, FLG_CONNECT_B);
+ FsmChangeState(fi, ST_NULL);
+ test_and_set_bit(FLG_REL_REC, &chanp->Flags);
+ if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) {
+ chanp->lc_b->l2_establish = 0; /* direct reset in lc_b->lcfi */
+ FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
}
- if (chanp->Flags & FLG_LL_BCONN) {
+ if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
if (chanp->debug & 1)
link_debug(chanp, "STAT_BHUP", 0);
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_BHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
- RESBIT(chanp->Flags, FLG_LL_BCONN);
- }
- if (chanp->Flags & FLG_START_B) {
- release_ds(chanp);
- RESBIT(chanp->Flags, FLG_START_B);
+ chanp->cs->iif.statcallb(&ic);
}
- if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND | FLG_CALL_ALERT)) {
+ if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
+ release_b_st(chanp);
+ if (test_bit(FLG_LL_DCONN, &chanp->Flags) ||
+ test_bit(FLG_CALL_SEND, &chanp->Flags) ||
+ test_bit(FLG_CALL_ALERT, &chanp->Flags)) {
if (chanp->debug & 1)
link_debug(chanp, "STAT_DHUP", 0);
- l4_deliver_cause(chanp);
- ic.driver = chanp->sp->myid;
+ lli_deliver_cause(chanp);
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_DHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ chanp->cs->iif.statcallb(&ic);
}
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_FLUSH, NULL);
- RESBIT(chanp->Flags, FLG_ESTAB_D);
- RESBIT(chanp->Flags, FLG_DISC_SEND);
- RESBIT(chanp->Flags, FLG_CALL_REC);
- RESBIT(chanp->Flags, FLG_CALL_ALERT);
- RESBIT(chanp->Flags, FLG_LL_DCONN);
- RESBIT(chanp->Flags, FLG_CALL_SEND);
+ test_and_clear_bit(FLG_DISC_SEND, &chanp->Flags);
+ test_and_clear_bit(FLG_CALL_REC, &chanp->Flags);
+ test_and_clear_bit(FLG_CALL_ALERT, &chanp->Flags);
+ test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
+ test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags);
+ lli_timeout_d(fi, event, arg);
}
static void
-l4_received_d_relcnf(struct FsmInst *fi, int event, void *arg)
+lli_received_d_relcnf(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
chanp->data_open = 0;
- FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
- if (chanp->Flags & FLG_CONNECT_B) {
- chanp->lc_b.l2_establish = 0; /* direct reset in lc_b.lcfi */
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
- RESBIT(chanp->Flags, FLG_CONNECT_B);
+ FsmChangeState(fi, ST_NULL);
+ if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) {
+ chanp->lc_b->l2_establish = 0; /* direct reset in lc_b->lcfi */
+ FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
}
- if (chanp->Flags & FLG_LL_BCONN) {
+ if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
if (chanp->debug & 1)
link_debug(chanp, "STAT_BHUP", 0);
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_BHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
- RESBIT(chanp->Flags, FLG_LL_BCONN);
+ chanp->cs->iif.statcallb(&ic);
}
- if (chanp->Flags & FLG_START_B) {
- release_ds(chanp);
- RESBIT(chanp->Flags, FLG_START_B);
- }
- if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND | FLG_CALL_ALERT)) {
+ if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
+ release_b_st(chanp);
+ if (test_bit(FLG_LL_DCONN, &chanp->Flags) ||
+ test_bit(FLG_CALL_SEND, &chanp->Flags) ||
+ test_bit(FLG_CALL_ALERT, &chanp->Flags)) {
if (chanp->debug & 1)
link_debug(chanp, "STAT_DHUP", 0);
- l4_deliver_cause(chanp);
- ic.driver = chanp->sp->myid;
+ lli_deliver_cause(chanp);
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_DHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ chanp->cs->iif.statcallb(&ic);
}
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
- RESBIT(chanp->Flags, FLG_ESTAB_D);
- RESBIT(chanp->Flags, FLG_DISC_SEND);
- RESBIT(chanp->Flags, FLG_CALL_REC);
- RESBIT(chanp->Flags, FLG_CALL_ALERT);
- RESBIT(chanp->Flags, FLG_LL_DCONN);
- RESBIT(chanp->Flags, FLG_CALL_SEND);
+ test_and_clear_bit(FLG_DISC_SEND, &chanp->Flags);
+ test_and_clear_bit(FLG_CALL_REC, &chanp->Flags);
+ test_and_clear_bit(FLG_CALL_ALERT, &chanp->Flags);
+ test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
+ test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags);
+ lli_timeout_d(fi, event, arg);
}
static void
-l4_received_d_disc(struct FsmInst *fi, int event, void *arg)
+lli_received_d_disc(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
chanp->data_open = 0;
FsmChangeState(fi, ST_WAIT_D_REL_CNF);
- SETBIT(chanp->Flags, FLG_DISC_REC);
- if (chanp->Flags & FLG_LL_BCONN) {
+ test_and_set_bit(FLG_DISC_REC, &chanp->Flags);
+ if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
if (chanp->debug & 1)
link_debug(chanp, "STAT_BHUP", 0);
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_BHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
- RESBIT(chanp->Flags, FLG_LL_BCONN);
- }
- if (chanp->Flags & FLG_START_B) {
- release_ds(chanp);
- RESBIT(chanp->Flags, FLG_START_B);
+ chanp->cs->iif.statcallb(&ic);
}
- if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND | FLG_CALL_ALERT)) {
+ if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
+ release_b_st(chanp);
+ if (test_bit(FLG_LL_DCONN, &chanp->Flags) ||
+ test_bit(FLG_CALL_SEND, &chanp->Flags) ||
+ test_bit(FLG_CALL_ALERT, &chanp->Flags)) {
if (chanp->debug & 1)
link_debug(chanp, "STAT_DHUP", 0);
- l4_deliver_cause(chanp);
- ic.driver = chanp->sp->myid;
+ lli_deliver_cause(chanp);
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_DHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ chanp->cs->iif.statcallb(&ic);
}
- RESBIT(chanp->Flags, FLG_LL_DCONN);
- RESBIT(chanp->Flags, FLG_CALL_SEND);
- RESBIT(chanp->Flags, FLG_CALL_ALERT);
- chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
+ test_and_clear_bit(FLG_CALL_ALERT, &chanp->Flags);
+ test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
+ test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE_REQ, chanp->proc);
}
/* processing charge info */
static void
-l4_charge_info(struct FsmInst *fi, int event, void *arg)
+lli_charge_info(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_CINF;
ic.arg = chanp->chan;
- sprintf(ic.parm.num, "%d", chanp->para.chargeinfo);
- chanp->sp->iif.statcallb(&ic);
+ sprintf(ic.parm.num, "%d", chanp->proc->para.chargeinfo);
+ chanp->cs->iif.statcallb(&ic);
}
/* error procedures */
static void
-l4_no_dchan(struct FsmInst *fi, int event, void *arg)
+lli_no_dchan(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
if (chanp->debug & 1)
link_debug(chanp, "STAT_NODCH", 0);
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_NODCH;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ chanp->cs->iif.statcallb(&ic);
chanp->Flags = 0;
FsmChangeState(fi, ST_NULL);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+ FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL);
}
static void
-l4_no_dchan_ready(struct FsmInst *fi, int event, void *arg)
+lli_no_dchan_ready(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
if (chanp->debug & 1)
link_debug(chanp, "STAT_DHUP", 0);
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_DHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ chanp->cs->iif.statcallb(&ic);
}
static void
-l4_no_dchan_in(struct FsmInst *fi, int event, void *arg)
+lli_no_dchan_in(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
- chanp->is.l4.l4l3(&chanp->is, CC_DLRL, NULL);
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_DHUP", 0);
+ ic.driver = chanp->cs->myid;
+ ic.command = ISDN_STAT_DHUP;
+ ic.arg = chanp->chan;
+ chanp->cs->iif.statcallb(&ic);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_DLRL, chanp->proc);
chanp->Flags = 0;
FsmChangeState(fi, ST_NULL);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+ FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL);
}
static void
-l4_no_setup_rsp(struct FsmInst *fi, int event, void *arg)
+lli_no_setup_rsp(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
- chanp->Flags = 0;
FsmChangeState(fi, ST_NULL);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+ test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags);
if (chanp->debug & 1)
link_debug(chanp, "STAT_DHUP", 0);
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_DHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ chanp->cs->iif.statcallb(&ic);
+ lli_shutdown_d(fi, event, arg);
}
static void
-l4_setup_err(struct FsmInst *fi, int event, void *arg)
+lli_setup_err(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
FsmChangeState(fi, ST_WAIT_DRELEASE);
- if (chanp->Flags & FLG_LL_DCONN) {
+ if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) {
if (chanp->debug & 1)
link_debug(chanp, "STAT_DHUP", 0);
- RESBIT(chanp->Flags, FLG_LL_DCONN);
- l4_deliver_cause(chanp);
- ic.driver = chanp->sp->myid;
+ lli_deliver_cause(chanp);
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_DHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ chanp->cs->iif.statcallb(&ic);
}
- SETBIT(chanp->Flags, FLG_DISC_SEND); /* DISCONN was sent from L3 */
+ test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); /* DISCONN was sent from L3 */
}
static void
-l4_connect_err(struct FsmInst *fi, int event, void *arg)
+lli_connect_err(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
FsmChangeState(fi, ST_WAIT_DRELEASE);
- if (chanp->Flags & FLG_LL_DCONN) {
+ if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) {
if (chanp->debug & 1)
link_debug(chanp, "STAT_DHUP", 0);
- RESBIT(chanp->Flags, FLG_LL_DCONN);
- l4_deliver_cause(chanp);
- ic.driver = chanp->sp->myid;
+ lli_deliver_cause(chanp);
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_DHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ chanp->cs->iif.statcallb(&ic);
}
- SETBIT(chanp->Flags, FLG_DISC_SEND); /* DISCONN was sent from L3 */
+ test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); /* DISCONN was sent from L3 */
}
static void
-l4_active_dlrl(struct FsmInst *fi, int event, void *arg)
+lli_got_dlrl(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
chanp->data_open = 0;
FsmChangeState(fi, ST_NULL);
- if (chanp->Flags & FLG_CONNECT_B) {
- chanp->lc_b.l2_establish = 0; /* direct reset in lc_b.lcfi */
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
- RESBIT(chanp->Flags, FLG_CONNECT_B);
+ if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) {
+ chanp->lc_b->l2_establish = 0; /* direct reset in lc_b->lcfi */
+ FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
}
- if (chanp->Flags & FLG_LL_BCONN) {
+ if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
if (chanp->debug & 1)
link_debug(chanp, "STAT_BHUP", 0);
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_BHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
- RESBIT(chanp->Flags, FLG_LL_BCONN);
- }
- if (chanp->Flags & FLG_START_B) {
- release_ds(chanp);
- RESBIT(chanp->Flags, FLG_START_B);
+ chanp->cs->iif.statcallb(&ic);
}
- if (chanp->Flags & FLG_LL_DCONN) {
- if (chanp->debug & 1)
- link_debug(chanp, "STAT_DHUP", 0);
- RESBIT(chanp->Flags, FLG_LL_DCONN);
- if (chanp->sp->protocol == ISDN_PTYPE_EURO) {
- chanp->para.cause = 0x2f;
- chanp->para.loc = 0;
- } else {
- chanp->para.cause = 0x70;
- chanp->para.loc = 0;
- }
- l4_deliver_cause(chanp);
- ic.driver = chanp->sp->myid;
+ if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
+ release_b_st(chanp);
+ if (chanp->leased) {
+ ic.driver = chanp->cs->myid;
+ ic.command = ISDN_STAT_CAUSE;
+ ic.arg = chanp->chan;
+ sprintf(ic.parm.num, "L%02X%02X", 0, 0x2f);
+ chanp->cs->iif.statcallb(&ic);
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_DHUP;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ chanp->cs->iif.statcallb(&ic);
+ chanp->Flags = 0;
+ } else {
+ if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_DHUP", 0);
+ if (chanp->cs->protocol == ISDN_PTYPE_EURO) {
+ chanp->proc->para.cause = 0x2f;
+ chanp->proc->para.loc = 0;
+ } else {
+ chanp->proc->para.cause = 0x70;
+ chanp->proc->para.loc = 0;
+ }
+ lli_deliver_cause(chanp);
+ ic.driver = chanp->cs->myid;
+ ic.command = ISDN_STAT_DHUP;
+ ic.arg = chanp->chan;
+ chanp->cs->iif.statcallb(&ic);
+ }
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_DLRL, chanp->proc);
+ chanp->Flags = 0;
+ FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL);
}
- chanp->Flags = 0;
- chanp->is.l4.l4l3(&chanp->is, CC_DLRL, NULL);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
}
+
/* *INDENT-OFF* */
-static struct FsmNode fnlist[] =
-{
- {ST_NULL, EV_DIAL, l4_prep_dialout},
- {ST_NULL, EV_SETUP_IND, l4_start_dchan},
- {ST_NULL, EV_SHUTDOWN_D, l4_shutdown_d},
- {ST_NULL, EV_DLRL, l4_go_null},
- {ST_OUT_WAIT_D, EV_DLEST, l4_do_dialout},
- {ST_OUT_WAIT_D, EV_DLRL, l4_no_dchan},
- {ST_OUT_WAIT_D, EV_HANGUP, l4_no_dchan},
- {ST_IN_WAIT_D, EV_DLEST, l4_deliver_call},
- {ST_IN_WAIT_D, EV_DLRL, l4_no_dchan_in},
- {ST_IN_WAIT_D, EV_HANGUP, l4_no_dchan_in},
- {ST_OUT_DIAL, EV_SETUP_CNF, l4_init_bchan_out},
- {ST_OUT_DIAL, EV_HANGUP, l4_cancel_call},
- {ST_OUT_DIAL, EV_DISCONNECT_IND, l4_received_d_disc},
- {ST_OUT_DIAL, EV_RELEASE_IND, l4_received_d_rel},
- {ST_OUT_DIAL, EV_RELEASE_CNF, l4_received_d_relcnf},
- {ST_OUT_DIAL, EV_NOSETUP_RSP, l4_no_setup_rsp},
- {ST_OUT_DIAL, EV_SETUP_ERR, l4_setup_err},
- {ST_IN_WAIT_LL, EV_SETUP_CMPL_IND, l4_init_bchan_in},
- {ST_IN_WAIT_LL, EV_ACCEPTD, l4_send_dconnect},
- {ST_IN_WAIT_LL, EV_HANGUP, l4_reject_call},
- {ST_IN_WAIT_LL, EV_DISCONNECT_IND, l4_received_d_disc},
- {ST_IN_WAIT_LL, EV_RELEASE_IND, l4_received_d_rel},
- {ST_IN_WAIT_LL, EV_RELEASE_CNF, l4_received_d_relcnf},
- {ST_IN_ALERT_SEND, EV_SETUP_CMPL_IND, l4_init_bchan_in},
- {ST_IN_ALERT_SEND, EV_ACCEPTD, l4_send_dconnect},
- {ST_IN_ALERT_SEND, EV_HANGUP, l4_send_d_disc},
- {ST_IN_ALERT_SEND, EV_DISCONNECT_IND, l4_received_d_disc},
- {ST_IN_ALERT_SEND, EV_RELEASE_IND, l4_received_d_rel},
- {ST_IN_ALERT_SEND, EV_RELEASE_CNF, l4_received_d_relcnf},
- {ST_IN_WAIT_CONN_ACK, EV_SETUP_CMPL_IND, l4_init_bchan_in},
- {ST_IN_WAIT_CONN_ACK, EV_HANGUP, l4_send_d_disc},
- {ST_IN_WAIT_CONN_ACK, EV_DISCONNECT_IND, l4_received_d_disc},
- {ST_IN_WAIT_CONN_ACK, EV_RELEASE_IND, l4_received_d_rel},
- {ST_IN_WAIT_CONN_ACK, EV_RELEASE_CNF, l4_received_d_relcnf},
- {ST_IN_WAIT_CONN_ACK, EV_CONNECT_ERR, l4_connect_err},
- {ST_WAIT_BCONN, EV_BC_EST, l4_go_active},
- {ST_WAIT_BCONN, EV_BC_REL, l4_send_d_disc},
- {ST_WAIT_BCONN, EV_HANGUP, l4_send_d_disc},
- {ST_WAIT_BCONN, EV_DISCONNECT_IND, l4_received_d_disc},
- {ST_WAIT_BCONN, EV_RELEASE_IND, l4_received_d_rel},
- {ST_WAIT_BCONN, EV_RELEASE_CNF, l4_received_d_relcnf},
- {ST_ACTIVE, EV_CINF, l4_charge_info},
- {ST_ACTIVE, EV_BC_REL, l4_released_bchan},
- {ST_ACTIVE, EV_HANGUP, l4_disconn_bchan},
- {ST_ACTIVE, EV_DISCONNECT_IND, l4_release_bchan},
- {ST_ACTIVE, EV_RELEASE_CNF, l4_received_d_relcnf},
- {ST_ACTIVE, EV_RELEASE_IND, l4_received_d_rel},
- {ST_ACTIVE, EV_DLRL, l4_active_dlrl},
- {ST_WAIT_BRELEASE, EV_BC_REL, l4_send_d_disc},
- {ST_WAIT_BRELEASE, EV_DISCONNECT_IND, l4_received_d_disc},
- {ST_WAIT_BRELEASE, EV_RELEASE_CNF, l4_received_d_relcnf},
- {ST_WAIT_BRELEASE, EV_RELEASE_IND, l4_received_d_rel},
- {ST_WAIT_BREL_DISC, EV_BC_REL, l4_received_d_disc},
- {ST_WAIT_BREL_DISC, EV_RELEASE_CNF, l4_received_d_relcnf},
- {ST_WAIT_BREL_DISC, EV_RELEASE_IND, l4_received_d_rel},
- {ST_WAIT_DCOMMAND, EV_HANGUP, l4_send_d_disc},
- {ST_WAIT_DCOMMAND, EV_DISCONNECT_IND, l4_received_d_disc},
- {ST_WAIT_DCOMMAND, EV_RELEASE_CNF, l4_received_d_relcnf},
- {ST_WAIT_DCOMMAND, EV_RELEASE_IND, l4_received_d_rel},
- {ST_WAIT_DRELEASE, EV_RELEASE_IND, l4_timeout_d},
- {ST_WAIT_DRELEASE, EV_RELEASE_CNF, l4_timeout_d},
- {ST_WAIT_DRELEASE, EV_RELEASE_ERR, l4_timeout_d},
- {ST_WAIT_DRELEASE, EV_DIAL, l4_no_dchan_ready},
- {ST_WAIT_D_REL_CNF, EV_RELEASE_CNF, l4_timeout_d},
- {ST_WAIT_D_REL_CNF, EV_RELEASE_ERR, l4_timeout_d},
- {ST_WAIT_D_REL_CNF, EV_DIAL, l4_no_dchan_ready},
- {ST_WAIT_DSHUTDOWN, EV_DLRL, l4_go_null},
- {ST_WAIT_DSHUTDOWN, EV_DIAL, l4_prep_dialout},
- {ST_WAIT_DSHUTDOWN, EV_SETUP_IND, l4_start_dchan},
+static struct FsmNode fnlist[] HISAX_INITDATA =
+{
+ {ST_NULL, EV_DIAL, lli_prep_dialout},
+ {ST_NULL, EV_SETUP_IND, lli_deliver_call},
+ {ST_NULL, EV_SHUTDOWN_D, lli_shutdown_d},
+ {ST_NULL, EV_DLRL, lli_go_null},
+ {ST_NULL, EV_DLEST, lli_d_established},
+ {ST_NULL, EV_ESTABLISH, lli_establish_d},
+ {ST_OUT_WAIT_D, EV_DLEST, lli_do_dialout},
+ {ST_OUT_WAIT_D, EV_DLRL, lli_no_dchan},
+ {ST_OUT_WAIT_D, EV_HANGUP, lli_no_dchan},
+ {ST_IN_WAIT_D, EV_DLEST, lli_do_action},
+ {ST_IN_WAIT_D, EV_DLRL, lli_no_dchan_in},
+ {ST_IN_WAIT_D, EV_ACCEPTD, lli_start_dchan},
+ {ST_IN_WAIT_D, EV_HANGUP, lli_start_dchan},
+ {ST_OUT_DIAL, EV_SETUP_CNF, lli_init_bchan_out},
+ {ST_OUT_DIAL, EV_HANGUP, lli_cancel_call},
+ {ST_OUT_DIAL, EV_DISCONNECT_IND, lli_received_d_disc},
+ {ST_OUT_DIAL, EV_RELEASE_IND, lli_received_d_rel},
+ {ST_OUT_DIAL, EV_RELEASE_CNF, lli_received_d_relcnf},
+ {ST_OUT_DIAL, EV_NOSETUP_RSP, lli_no_setup_rsp},
+ {ST_OUT_DIAL, EV_SETUP_ERR, lli_setup_err},
+ {ST_OUT_DIAL, EV_DLRL, lli_got_dlrl},
+ {ST_IN_WAIT_LL, EV_DLEST, lli_d_established},
+ {ST_IN_WAIT_LL, EV_DLRL, lli_d_released},
+ {ST_IN_WAIT_LL, EV_ACCEPTD, lli_start_dchan},
+ {ST_IN_WAIT_LL, EV_HANGUP, lli_start_dchan},
+ {ST_IN_WAIT_LL, EV_DISCONNECT_IND, lli_received_d_disc},
+ {ST_IN_WAIT_LL, EV_RELEASE_IND, lli_received_d_rel},
+ {ST_IN_WAIT_LL, EV_RELEASE_CNF, lli_received_d_relcnf},
+ {ST_IN_ALERT_SEND, EV_SETUP_CMPL_IND, lli_init_bchan_in},
+ {ST_IN_ALERT_SEND, EV_ACCEPTD, lli_send_dconnect},
+ {ST_IN_ALERT_SEND, EV_HANGUP, lli_send_d_disc},
+ {ST_IN_ALERT_SEND, EV_DISCONNECT_IND, lli_received_d_disc},
+ {ST_IN_ALERT_SEND, EV_RELEASE_IND, lli_received_d_rel},
+ {ST_IN_ALERT_SEND, EV_RELEASE_CNF, lli_received_d_relcnf},
+ {ST_IN_ALERT_SEND, EV_DLRL, lli_got_dlrl},
+ {ST_IN_WAIT_CONN_ACK, EV_SETUP_CMPL_IND, lli_init_bchan_in},
+ {ST_IN_WAIT_CONN_ACK, EV_HANGUP, lli_send_d_disc},
+ {ST_IN_WAIT_CONN_ACK, EV_DISCONNECT_IND, lli_received_d_disc},
+ {ST_IN_WAIT_CONN_ACK, EV_RELEASE_IND, lli_received_d_rel},
+ {ST_IN_WAIT_CONN_ACK, EV_RELEASE_CNF, lli_received_d_relcnf},
+ {ST_IN_WAIT_CONN_ACK, EV_CONNECT_ERR, lli_connect_err},
+ {ST_IN_WAIT_CONN_ACK, EV_DLRL, lli_got_dlrl},
+ {ST_WAIT_BCONN, EV_BC_EST, lli_go_active},
+ {ST_WAIT_BCONN, EV_BC_REL, lli_send_d_disc},
+ {ST_WAIT_BCONN, EV_HANGUP, lli_send_d_disc},
+ {ST_WAIT_BCONN, EV_DISCONNECT_IND, lli_received_d_disc},
+ {ST_WAIT_BCONN, EV_RELEASE_IND, lli_received_d_rel},
+ {ST_WAIT_BCONN, EV_RELEASE_CNF, lli_received_d_relcnf},
+ {ST_WAIT_BCONN, EV_DLRL, lli_got_dlrl},
+ {ST_WAIT_BCONN, EV_CINF, lli_charge_info},
+ {ST_ACTIVE, EV_CINF, lli_charge_info},
+ {ST_ACTIVE, EV_BC_REL, lli_released_bchan},
+ {ST_ACTIVE, EV_HANGUP, lli_disconn_bchan},
+ {ST_ACTIVE, EV_DISCONNECT_IND, lli_release_bchan},
+ {ST_ACTIVE, EV_RELEASE_CNF, lli_received_d_relcnf},
+ {ST_ACTIVE, EV_RELEASE_IND, lli_received_d_rel},
+ {ST_ACTIVE, EV_DLRL, lli_got_dlrl},
+ {ST_WAIT_BRELEASE, EV_BC_REL, lli_send_d_disc},
+ {ST_WAIT_BRELEASE, EV_DISCONNECT_IND, lli_received_d_disc},
+ {ST_WAIT_BRELEASE, EV_RELEASE_CNF, lli_received_d_relcnf},
+ {ST_WAIT_BRELEASE, EV_RELEASE_IND, lli_received_d_rel},
+ {ST_WAIT_BRELEASE, EV_DLRL, lli_got_dlrl},
+ {ST_WAIT_BREL_DISC, EV_BC_REL, lli_received_d_disc},
+ {ST_WAIT_BREL_DISC, EV_RELEASE_CNF, lli_received_d_relcnf},
+ {ST_WAIT_BREL_DISC, EV_RELEASE_IND, lli_received_d_rel},
+ {ST_WAIT_BREL_DISC, EV_DLRL, lli_got_dlrl},
+ {ST_WAIT_DCOMMAND, EV_HANGUP, lli_send_d_disc},
+ {ST_WAIT_DCOMMAND, EV_DISCONNECT_IND, lli_received_d_disc},
+ {ST_WAIT_DCOMMAND, EV_RELEASE_CNF, lli_received_d_relcnf},
+ {ST_WAIT_DCOMMAND, EV_RELEASE_IND, lli_received_d_rel},
+ {ST_WAIT_DCOMMAND, EV_DLRL, lli_got_dlrl},
+ {ST_WAIT_DRELEASE, EV_RELEASE_IND, lli_timeout_d},
+ {ST_WAIT_DRELEASE, EV_RELEASE_CNF, lli_timeout_d},
+ {ST_WAIT_DRELEASE, EV_RELEASE_ERR, lli_timeout_d},
+ {ST_WAIT_DRELEASE, EV_DIAL, lli_no_dchan_ready},
+ {ST_WAIT_DRELEASE, EV_DLRL, lli_got_dlrl},
+ {ST_WAIT_D_REL_CNF, EV_RELEASE_CNF, lli_timeout_d},
+ {ST_WAIT_D_REL_CNF, EV_RELEASE_ERR, lli_timeout_d},
+/* ETS 300-104 16.1 */
+ {ST_WAIT_D_REL_CNF, EV_RELEASE_IND, lli_timeout_d},
+ {ST_WAIT_D_REL_CNF, EV_DIAL, lli_no_dchan_ready},
+ {ST_WAIT_D_REL_CNF, EV_DLRL, lli_got_dlrl},
+ {ST_WAIT_DSHUTDOWN, EV_DLRL, lli_go_null},
+ {ST_WAIT_DSHUTDOWN, EV_DLEST, lli_d_established},
+ {ST_WAIT_DSHUTDOWN, EV_DIAL, lli_prep_dialout},
+ {ST_WAIT_DSHUTDOWN, EV_SETUP_IND, lli_deliver_call},
};
/* *INDENT-ON* */
-
-
#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
static void
-lc_r1(struct FsmInst *fi, int event, void *arg)
+lc_activate_l1(struct FsmInst *fi, int event, void *arg)
{
struct LcFsm *lf = fi->userdata;
+ FsmDelTimer(&lf->act_timer, 50);
FsmChangeState(fi, ST_LC_ACTIVATE_WAIT);
- FsmAddTimer(&lf->act_timer, 1000, EV_LC_TIMER, NULL, 50);
- lf->st->ma.manl1(lf->st, PH_ACTIVATE, NULL);
+ /* This timeout is to avoid a hang if no L1 activation is possible */
+ FsmAddTimer(&lf->act_timer, 30000, EV_LC_TIMER, NULL, 50);
+ lf->st->ma.manl1(lf->st, PH_ACTIVATE_REQ, NULL);
+}
+static void
+lc_activated_from_l1(struct FsmInst *fi, int event, void *arg)
+{
+ struct LcFsm *lf = fi->userdata;
+
+ if (lf->l2_establish)
+ FsmChangeState(fi, ST_LC_DELAY);
+ else {
+ FsmChangeState(fi, ST_LC_CONNECTED);
+ lf->lccall(lf, LC_ESTABLISH, NULL);
+ }
}
static void
-lc_r6(struct FsmInst *fi, int event, void *arg)
+lc_l1_activated(struct FsmInst *fi, int event, void *arg)
{
struct LcFsm *lf = fi->userdata;
FsmDelTimer(&lf->act_timer, 50);
FsmChangeState(fi, ST_LC_DELAY);
- FsmAddTimer(&lf->act_timer, 40, EV_LC_TIMER, NULL, 51);
+ /* This timer is needed for delay the first paket on a channel
+ to be shure that the other side is ready too */
+ if (lf->delay)
+ FsmAddTimer(&lf->act_timer, lf->delay, EV_LC_TIMER, NULL, 51);
+ else
+ FsmEvent(fi, EV_LC_TIMER, NULL);
}
static void
-lc_r2(struct FsmInst *fi, int event, void *arg)
+lc_start_l2(struct FsmInst *fi, int event, void *arg)
{
struct LcFsm *lf = fi->userdata;
- if (lf->l2_establish) {
+/* if (!lf->st->l1.act_state)
+ lf->st->l1.act_state = 2;
+*/ if (lf->l2_establish) {
FsmChangeState(fi, ST_LC_ESTABLISH_WAIT);
if (lf->l2_start)
lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL);
@@ -1124,107 +1260,97 @@ lc_r2(struct FsmInst *fi, int event, void *arg)
}
static void
-lc_r3(struct FsmInst *fi, int event, void *arg)
+lc_connected(struct FsmInst *fi, int event, void *arg)
{
struct LcFsm *lf = fi->userdata;
+ FsmDelTimer(&lf->act_timer, 50);
FsmChangeState(fi, ST_LC_CONNECTED);
lf->lccall(lf, LC_ESTABLISH, NULL);
}
static void
-lc_r7(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- FsmChangeState(fi, ST_LC_FLUSH_WAIT);
- lf->st->ma.manl2(lf->st, DL_FLUSH, NULL);
-}
-
-static void
-lc_r4(struct FsmInst *fi, int event, void *arg)
+lc_release_l2(struct FsmInst *fi, int event, void *arg)
{
struct LcFsm *lf = fi->userdata;
if (lf->l2_establish) {
FsmChangeState(fi, ST_LC_RELEASE_WAIT);
lf->st->ma.manl2(lf->st, DL_RELEASE, NULL);
- /* This timer is for releasing the channel even
- * there is a hang in layer 2 ; 5 sec are a try
- */
- FsmAddTimer(&lf->act_timer, 5000, EV_LC_TIMER, NULL, 53);
} else {
FsmChangeState(fi, ST_LC_NULL);
- lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
+ lf->st->ma.manl1(lf->st, PH_DEACTIVATE_REQ, NULL);
lf->lccall(lf, LC_RELEASE, NULL);
}
}
static void
-lc_r4_1(struct FsmInst *fi, int event, void *arg)
+lc_l2_released(struct FsmInst *fi, int event, void *arg)
{
struct LcFsm *lf = fi->userdata;
- FsmChangeState(fi, ST_LC_FLUSH_DELAY);
- FsmAddTimer(&lf->act_timer, 50, EV_LC_TIMER, NULL, 52);
+ FsmChangeState(fi, ST_LC_RELEASE_WAIT);
+ FsmDelTimer(&lf->act_timer, 51);
+ /* This delay is needed for send out the UA frame before
+ * PH_DEACTIVATE the interface
+ */
+ FsmAddTimer(&lf->act_timer, 20, EV_LC_TIMER, NULL, 54);
}
static void
-lc_r5_1(struct FsmInst *fi, int event, void *arg)
+lc_release_l1(struct FsmInst *fi, int event, void *arg)
{
struct LcFsm *lf = fi->userdata;
- FsmChangeState(fi, ST_LC_RELEASE_WAIT);
- /* This delay is needed for send out the UA frame before
- * PH_DEACTIVATE the interface
- */
- FsmAddTimer(&lf->act_timer, 10, EV_LC_TIMER, NULL, 54);
+ FsmDelTimer(&lf->act_timer, 54);
+ FsmChangeState(fi, ST_LC_NULL);
+ lf->st->ma.manl1(lf->st, PH_DEACTIVATE_REQ, NULL);
+ lf->lccall(lf, LC_RELEASE, NULL);
}
static void
-lc_r5(struct FsmInst *fi, int event, void *arg)
+lc_l1_deactivated(struct FsmInst *fi, int event, void *arg)
{
struct LcFsm *lf = fi->userdata;
FsmDelTimer(&lf->act_timer, 54);
FsmChangeState(fi, ST_LC_NULL);
- lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
lf->lccall(lf, LC_RELEASE, NULL);
}
/* *INDENT-OFF* */
-static struct FsmNode LcFnList[] =
-{
- {ST_LC_NULL, EV_LC_ESTABLISH, lc_r1},
- {ST_LC_ACTIVATE_WAIT, EV_LC_PH_ACTIVATE, lc_r6},
- {ST_LC_DELAY, EV_LC_TIMER, lc_r2},
- {ST_LC_DELAY, EV_LC_DL_ESTABLISH, lc_r3},
- {ST_LC_ESTABLISH_WAIT, EV_LC_DL_ESTABLISH, lc_r3},
- {ST_LC_ESTABLISH_WAIT, EV_LC_RELEASE, lc_r5},
- {ST_LC_CONNECTED, EV_LC_FLUSH, lc_r7},
- {ST_LC_CONNECTED, EV_LC_RELEASE, lc_r4},
- {ST_LC_CONNECTED, EV_LC_DL_RELEASE, lc_r5_1},
- {ST_LC_FLUSH_WAIT, EV_LC_DL_FLUSH, lc_r4_1},
- {ST_LC_FLUSH_DELAY, EV_LC_TIMER, lc_r4},
- {ST_LC_RELEASE_WAIT, EV_LC_DL_RELEASE, lc_r5},
- {ST_LC_RELEASE_WAIT, EV_LC_TIMER, lc_r5},
- {ST_LC_ACTIVATE_WAIT, EV_LC_TIMER, lc_r5},
- {ST_LC_ESTABLISH_WAIT, EV_LC_DL_RELEASE, lc_r5},
+static struct FsmNode LcFnList[] HISAX_INITDATA =
+{
+ {ST_LC_NULL, EV_LC_ESTABLISH, lc_activate_l1},
+ {ST_LC_NULL, EV_LC_PH_ACTIVATE, lc_activated_from_l1},
+ {ST_LC_NULL, EV_LC_DL_ESTABLISH, lc_connected},
+ {ST_LC_ACTIVATE_WAIT, EV_LC_PH_ACTIVATE, lc_l1_activated},
+ {ST_LC_ACTIVATE_WAIT, EV_LC_TIMER, lc_release_l1},
+ {ST_LC_ACTIVATE_WAIT, EV_LC_PH_DEACTIVATE, lc_l1_deactivated},
+ {ST_LC_DELAY, EV_LC_ESTABLISH, lc_start_l2},
+ {ST_LC_DELAY, EV_LC_TIMER, lc_start_l2},
+ {ST_LC_DELAY, EV_LC_DL_ESTABLISH, lc_connected},
+ {ST_LC_DELAY, EV_LC_PH_DEACTIVATE, lc_l1_deactivated},
+ {ST_LC_ESTABLISH_WAIT, EV_LC_DL_ESTABLISH, lc_connected},
+ {ST_LC_ESTABLISH_WAIT, EV_LC_RELEASE, lc_release_l1},
+ {ST_LC_ESTABLISH_WAIT, EV_LC_DL_RELEASE, lc_release_l1},
+ {ST_LC_ESTABLISH_WAIT, EV_LC_PH_DEACTIVATE, lc_l1_deactivated},
+ {ST_LC_CONNECTED, EV_LC_ESTABLISH, lc_connected},
+ {ST_LC_CONNECTED, EV_LC_RELEASE, lc_release_l2},
+ {ST_LC_CONNECTED, EV_LC_DL_RELEASE, lc_l2_released},
+ {ST_LC_CONNECTED, EV_LC_PH_DEACTIVATE, lc_l1_deactivated},
+ {ST_LC_FLUSH_WAIT, EV_LC_TIMER, lc_release_l2},
+ {ST_LC_FLUSH_WAIT, EV_LC_PH_DEACTIVATE, lc_l1_deactivated},
+ {ST_LC_RELEASE_WAIT, EV_LC_DL_RELEASE, lc_release_l1},
+ {ST_LC_RELEASE_WAIT, EV_LC_TIMER, lc_release_l1},
+ {ST_LC_FLUSH_WAIT, EV_LC_PH_DEACTIVATE, lc_l1_deactivated},
};
/* *INDENT-ON* */
-
-
-
-
-
-
-
-
#define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode))
-void
-CallcNew(void)
+HISAX_INITFUNC(void
+CallcNew(void))
{
callcfsm.state_count = STATE_COUNT;
callcfsm.event_count = EVENT_COUNT;
@@ -1247,17 +1373,11 @@ CallcFree(void)
}
static void
-release_ds(struct Channel *chanp)
+release_b_st(struct Channel *chanp)
{
- struct PStack *st = &chanp->ds;
- struct IsdnCardState *sp;
- struct HscxState *hsp;
-
- sp = st->l1.hardware;
- hsp = sp->hs + chanp->hscx;
-
- close_hscxstate(hsp);
+ struct PStack *st = chanp->b_st;
+ chanp->bcs->BC_Close(chanp->bcs);
switch (chanp->l2_active_protocol) {
case (ISDN_PROTO_L2_X75I):
releasestack_isdnl2(st);
@@ -1268,90 +1388,145 @@ release_ds(struct Channel *chanp)
break;
}
/* Reset B-Channel Statemachine */
- FsmDelTimer(&chanp->lc_b.act_timer, 79);
- FsmChangeState(&chanp->lc_b.lcfi, ST_LC_NULL);
+ FsmDelTimer(&chanp->lc_b->act_timer, 79);
+ FsmChangeState(&chanp->lc_b->lcfi, ST_LC_NULL);
}
static void
-cc_l1man(struct PStack *st, int pr, void *arg)
+dc_l1man(struct PStack *st, int pr, void *arg)
{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
+ struct Channel *chanp;
+ chanp = (struct Channel *) st->lli.userdata;
switch (pr) {
- case (PH_ACTIVATE):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_ACTIVATE, NULL);
+ case (PH_ACTIVATE_CNF):
+ case (PH_ACTIVATE_IND):
+ FsmEvent(&chanp->lc_d->lcfi, EV_LC_PH_ACTIVATE, NULL);
break;
- case (PH_DEACTIVATE):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_DEACTIVATE, NULL);
+ case (PH_DEACTIVATE_IND):
+ FsmEvent(&chanp->lc_d->lcfi, EV_LC_PH_DEACTIVATE, NULL);
break;
}
}
static void
-cc_l2man(struct PStack *st, int pr, void *arg)
+dc_l2man(struct PStack *st, int pr, void *arg)
{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
+ struct Channel *chanp = (struct Channel *) st->lli.userdata;
switch (pr) {
case (DL_ESTABLISH):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_ESTABLISH, NULL);
+ FsmEvent(&chanp->lc_d->lcfi, EV_LC_DL_ESTABLISH, NULL);
break;
case (DL_RELEASE):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_RELEASE, NULL);
- break;
- case (DL_FLUSH):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_FLUSH, NULL);
+ FsmEvent(&chanp->lc_d->lcfi, EV_LC_DL_RELEASE, NULL);
break;
}
}
static void
-dcc_l1man(struct PStack *st, int pr, void *arg)
+bc_l1man(struct PStack *st, int pr, void *arg)
{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
+ struct Channel *chanp = (struct Channel *) st->lli.userdata;
switch (pr) {
- case (PH_ACTIVATE):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_ACTIVATE, NULL);
+ case (PH_ACTIVATE_IND):
+ case (PH_ACTIVATE_CNF):
+ FsmEvent(&chanp->lc_b->lcfi, EV_LC_PH_ACTIVATE, NULL);
break;
- case (PH_DEACTIVATE):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_DEACTIVATE, NULL);
+ case (PH_DEACTIVATE_IND):
+ FsmEvent(&chanp->lc_b->lcfi, EV_LC_PH_DEACTIVATE, NULL);
break;
}
}
static void
-dcc_l2man(struct PStack *st, int pr, void *arg)
+bc_l2man(struct PStack *st, int pr, void *arg)
{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
+ struct Channel *chanp = (struct Channel *) st->lli.userdata;
switch (pr) {
case (DL_ESTABLISH):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_ESTABLISH, NULL);
+ FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_ESTABLISH, NULL);
break;
case (DL_RELEASE):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_RELEASE, NULL);
+ FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_RELEASE, NULL);
break;
}
}
-static void
-l2tei_dummy(struct PStack *st, int pr, void *arg)
+struct Channel
+*selectfreechannel(struct PStack *st)
{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
- char tmp[64], tm[32];
+ struct IsdnCardState *cs = st->l1.hardware;
+ struct Channel *chanp = st->lli.userdata;
+ int i;
- jiftime(tm, jiffies);
- sprintf(tmp, "%s Channel %d Warning! Dummy l2tei called pr=%d\n", tm, chanp->chan, pr);
- HiSax_putstatus(chanp->sp, tmp);
+ if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags))
+ i=1;
+ else
+ i=0;
+ while (i<2) {
+ if (chanp->fi.state == ST_NULL)
+ return (chanp);
+ chanp++;
+ i++;
+ }
+ return (NULL);
+}
+
+int
+is_activ(struct PStack *st)
+{
+ struct IsdnCardState *cs = st->l1.hardware;
+ struct Channel *chanp = st->lli.userdata;
+ int i;
+
+ if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags))
+ i=1;
+ else
+ i=0;
+ while (i<2) {
+ if (test_bit(FLG_ESTAB_D, &chanp->Flags))
+ return (1);
+ chanp++;
+ i++;
+ }
+ return (0);
}
static void
-ll_handler(struct PStack *st, int pr, void *arg)
+ll_handler(struct l3_process *pc, int pr, void *arg)
{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
+ struct Channel *chanp;
char tmp[64], tm[32];
+ if (pr == CC_SETUP_IND) {
+ if (!(chanp = selectfreechannel(pc->st))) {
+ pc->st->lli.l4l3(pc->st, CC_DLRL, pc);
+ return;
+ } else {
+ chanp->proc = pc;
+ pc->chan = chanp;
+ FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
+ return;
+ }
+ } else if (pr == CC_ESTABLISH) {
+ if (is_activ(pc->st)) {
+ pc->st->lli.l4l3(pc->st, CC_ESTABLISH, pc);
+ return;
+ } else if (!(chanp = selectfreechannel(pc->st))) {
+ pc->st->lli.l4l3(pc->st, CC_DLRL, pc);
+ return;
+ } else {
+ chanp->proc = pc;
+ FsmEvent(&chanp->fi, EV_ESTABLISH, NULL);
+ return;
+ }
+
+
+ }
+ chanp = pc->chan;
switch (pr) {
case (CC_DISCONNECT_IND):
FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
@@ -1359,9 +1534,6 @@ ll_handler(struct PStack *st, int pr, void *arg)
case (CC_RELEASE_CNF):
FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
break;
- case (CC_SETUP_IND):
- FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
- break;
case (CC_RELEASE_IND):
FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL);
break;
@@ -1386,49 +1558,51 @@ ll_handler(struct PStack *st, int pr, void *arg)
case (CC_RELEASE_ERR):
FsmEvent(&chanp->fi, EV_RELEASE_ERR, NULL);
break;
+ case (CC_PROCEEDING_IND):
+ case (CC_ALERTING_IND):
+ break;
default:
- if (chanp->debug & 2048) {
+ if (chanp->debug & 0x800) {
jiftime(tm, jiffies);
sprintf(tmp, "%s Channel %d L3->L4 unknown primitiv %d\n",
tm, chanp->chan, pr);
- HiSax_putstatus(chanp->sp, tmp);
+ HiSax_putstatus(chanp->cs, tmp);
}
}
}
static void
-init_is(struct Channel *chanp, unsigned int ces)
+init_d_st(struct Channel *chanp)
{
- struct PStack *st = &chanp->is;
- struct IsdnCardState *sp = chanp->sp;
+ struct PStack *st = chanp->d_st;
+ struct IsdnCardState *cs = chanp->cs;
char tmp[128];
- setstack_HiSax(st, sp);
+ HiSax_addlist(cs, st);
+ setstack_HiSax(st, cs);
st->l2.sap = 0;
- st->l2.tei = 255;
- st->l2.ces = ces;
- st->l2.extended = !0;
- st->l2.laptype = LAPD;
+ st->l2.tei = -1;
+ st->l2.flag = 0;
+ test_and_set_bit(FLG_MOD128, &st->l2.flag);
+ test_and_set_bit(FLG_LAPD, &st->l2.flag);
+ test_and_set_bit(FLG_ORIG, &st->l2.flag);
+ st->l2.maxlen = MAX_DFRAME_LEN;
st->l2.window = 1;
- st->l2.orig = !0;
- st->l2.t200 = 1000; /* 1000 milliseconds */
- if (st->protocol == ISDN_PTYPE_1TR6) {
- st->l2.n200 = 3; /* try 3 times */
- st->l2.t203 = 10000; /* 10000 milliseconds */
- } else {
- st->l2.n200 = 4; /* try 4 times */
- st->l2.t203 = 5000; /* 5000 milliseconds */
- }
+ st->l2.T200 = 1000; /* 1000 milliseconds */
+ st->l2.N200 = 3; /* try 3 times */
+ if (st->protocol == ISDN_PTYPE_1TR6)
+ st->l2.T203 = 10000; /* 10000 milliseconds */
+ else
+ st->l2.T203 = 10000; /* 5000 milliseconds */
+
sprintf(tmp, "Channel %d q.921", chanp->chan);
setstack_isdnl2(st, tmp);
setstack_isdnl3(st, chanp);
- st->l4.userdata = chanp;
- st->l4.l2writewakeup = NULL;
+ st->lli.userdata = chanp;
+ st->lli.l2writewakeup = NULL;
st->l3.l3l4 = ll_handler;
- st->l1.l1man = cc_l1man;
- st->l2.l2man = cc_l2man;
- st->pa = &chanp->para;
- HiSax_addlist(sp, st);
+ st->l1.l1man = dc_l1man;
+ st->l2.l2man = dc_l2man;
}
static void
@@ -1439,7 +1613,7 @@ callc_debug(struct FsmInst *fi, char *s)
jiftime(tm, jiffies);
sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s);
- HiSax_putstatus(chanp->sp, str);
+ HiSax_putstatus(chanp->cs, str);
}
static void
@@ -1449,8 +1623,8 @@ lc_debug(struct FsmInst *fi, char *s)
struct LcFsm *lf = fi->userdata;
jiftime(tm, jiffies);
- sprintf(str, "%s Channel %d lc %s\n", tm, lf->ch->chan, s);
- HiSax_putstatus(lf->ch->sp, str);
+ sprintf(str, "%s Channel %d dc %s\n", tm, lf->ch->chan, s);
+ HiSax_putstatus(lf->ch->cs, str);
}
static void
@@ -1460,22 +1634,35 @@ dlc_debug(struct FsmInst *fi, char *s)
struct LcFsm *lf = fi->userdata;
jiftime(tm, jiffies);
- sprintf(str, "%s Channel %d dlc %s\n", tm, lf->ch->chan, s);
- HiSax_putstatus(lf->ch->sp, str);
+ sprintf(str, "%s Channel %d bc %s\n", tm, lf->ch->chan, s);
+ HiSax_putstatus(lf->ch->cs, str);
}
static void
lccall_d(struct LcFsm *lf, int pr, void *arg)
{
- struct Channel *chanp = lf->ch;
+ struct IsdnCardState *cs = lf->st->l1.hardware;
+ struct Channel *chanp;
+ int i;
- switch (pr) {
- case (LC_ESTABLISH):
- FsmEvent(&chanp->fi, EV_DLEST, NULL);
- break;
- case (LC_RELEASE):
- FsmEvent(&chanp->fi, EV_DLRL, NULL);
- break;
+ if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags)) {
+ chanp = lf->ch;
+ i = 1;
+ } else {
+ chanp = cs->channel;
+ i = 0;
+ }
+ while (i < 2) {
+ switch (pr) {
+ case (LC_ESTABLISH):
+ FsmEvent(&chanp->fi, EV_DLEST, NULL);
+ break;
+ case (LC_RELEASE):
+ FsmEvent(&chanp->fi, EV_DLRL, NULL);
+ break;
+ }
+ chanp++;
+ i++;
}
}
@@ -1495,20 +1682,19 @@ lccall_b(struct LcFsm *lf, int pr, void *arg)
}
static void
-init_chan(int chan, struct IsdnCardState *csta, int hscx,
- unsigned int ces)
+init_chan(int chan, struct IsdnCardState *csta)
{
struct Channel *chanp = csta->channel + chan;
- chanp->sp = csta;
- chanp->hscx = hscx;
+ chanp->cs = csta;
+ chanp->bcs = csta->bcs + chan;
chanp->chan = chan;
chanp->incoming = 0;
chanp->debug = 0;
chanp->Flags = 0;
chanp->leased = 0;
- chanp->impair = 0;
- init_is(chanp, ces);
+ chanp->b_st = kmalloc(sizeof(struct PStack), GFP_ATOMIC);
+ chanp->b_st->next = NULL;
chanp->fi.fsm = &callcfsm;
chanp->fi.state = ST_NULL;
@@ -1517,58 +1703,72 @@ init_chan(int chan, struct IsdnCardState *csta, int hscx,
chanp->fi.printdebug = callc_debug;
FsmInitTimer(&chanp->fi, &chanp->dial_timer);
FsmInitTimer(&chanp->fi, &chanp->drel_timer);
-
- chanp->lc_d.lcfi.fsm = &lcfsm;
- chanp->lc_d.lcfi.state = ST_LC_NULL;
- chanp->lc_d.lcfi.debug = 0;
- chanp->lc_d.lcfi.userdata = &chanp->lc_d;
- chanp->lc_d.lcfi.printdebug = lc_debug;
- chanp->lc_d.type = LC_D;
- chanp->lc_d.ch = chanp;
- chanp->lc_d.st = &chanp->is;
- chanp->lc_d.l2_establish = !0;
- chanp->lc_d.l2_start = !0;
- chanp->lc_d.lccall = lccall_d;
- FsmInitTimer(&chanp->lc_d.lcfi, &chanp->lc_d.act_timer);
-
- chanp->lc_b.lcfi.fsm = &lcfsm;
- chanp->lc_b.lcfi.state = ST_LC_NULL;
- chanp->lc_b.lcfi.debug = 0;
- chanp->lc_b.lcfi.userdata = &chanp->lc_b;
- chanp->lc_b.lcfi.printdebug = dlc_debug;
- chanp->lc_b.type = LC_B;
- chanp->lc_b.ch = chanp;
- chanp->lc_b.st = &chanp->ds;
- chanp->lc_b.l2_establish = !0;
- chanp->lc_b.l2_start = !0;
- chanp->lc_b.lccall = lccall_b;
- FsmInitTimer(&chanp->lc_b.lcfi, &chanp->lc_b.act_timer);
- chanp->outcallref = 64;
+ if (!chan || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
+ chanp->d_st = kmalloc(sizeof(struct PStack), GFP_ATOMIC);
+ chanp->d_st->next = NULL;
+ init_d_st(chanp);
+ chanp->lc_d = kmalloc(sizeof(struct LcFsm), GFP_ATOMIC);
+ chanp->lc_d->lcfi.fsm = &lcfsm;
+ chanp->lc_d->lcfi.state = ST_LC_NULL;
+ chanp->lc_d->lcfi.debug = 0;
+ chanp->lc_d->lcfi.userdata = chanp->lc_d;
+ chanp->lc_d->lcfi.printdebug = lc_debug;
+ chanp->lc_d->type = LC_D;
+ chanp->lc_d->delay = 0;
+ chanp->lc_d->ch = chanp;
+ chanp->lc_d->st = chanp->d_st;
+ chanp->lc_d->l2_establish = !0;
+ chanp->lc_d->l2_start = !0;
+ chanp->lc_d->lccall = lccall_d;
+ FsmInitTimer(&chanp->lc_d->lcfi, &chanp->lc_d->act_timer);
+ } else {
+ chanp->d_st = csta->channel->d_st;
+ chanp->lc_d = csta->channel->lc_d;
+ }
+ chanp->lc_b = kmalloc(sizeof(struct LcFsm), GFP_ATOMIC);
+ chanp->lc_b->lcfi.fsm = &lcfsm;
+ chanp->lc_b->lcfi.state = ST_LC_NULL;
+ chanp->lc_b->lcfi.debug = 0;
+ chanp->lc_b->lcfi.userdata = chanp->lc_b;
+ chanp->lc_b->lcfi.printdebug = dlc_debug;
+ chanp->lc_b->type = LC_B;
+ chanp->lc_b->delay = DEFAULT_B_DELAY;
+ chanp->lc_b->ch = chanp;
+ chanp->lc_b->st = chanp->b_st;
+ chanp->lc_b->l2_establish = !0;
+ chanp->lc_b->l2_start = !0;
+ chanp->lc_b->lccall = lccall_b;
+ FsmInitTimer(&chanp->lc_b->lcfi, &chanp->lc_b->act_timer);
chanp->data_open = 0;
}
int
CallcNewChan(struct IsdnCardState *csta)
{
- int ces;
-
chancount += 2;
- ces = randomces();
- init_chan(0, csta, 1, ces++);
- ces %= 0xffff;
- init_chan(1, csta, 0, ces++);
+ init_chan(0, csta);
+ init_chan(1, csta);
printk(KERN_INFO "HiSax: 2 channels added\n");
+#ifdef LAYER2_WATCHING
+ printk(KERN_INFO "LAYER2 ESTABLISH\n");
+ test_and_set_bit(FLG_START_D, &csta->channel->Flags);
+ FsmEvent(&csta->channel->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
+#endif
return (2);
}
static void
-release_is(struct Channel *chanp)
+release_d_st(struct Channel *chanp)
{
- struct PStack *st = &chanp->is;
+ struct PStack *st = chanp->d_st;
+ if (!st)
+ return;
releasestack_isdnl2(st);
releasestack_isdnl3(st);
HiSax_rmlist(st->l1.hardware, st);
+ kfree(st);
+ chanp->d_st = NULL;
}
void
@@ -1579,27 +1779,45 @@ CallcFreeChan(struct IsdnCardState *csta)
for (i = 0; i < 2; i++) {
FsmDelTimer(&csta->channel[i].drel_timer, 74);
FsmDelTimer(&csta->channel[i].dial_timer, 75);
- FsmDelTimer(&csta->channel[i].lc_b.act_timer, 76);
- FsmDelTimer(&csta->channel[i].lc_d.act_timer, 77);
- if (csta->channel[i].Flags & FLG_START_B) {
- release_ds(csta->channel + i);
+ FsmDelTimer(&csta->channel[i].lc_d->act_timer, 77);
+ FsmDelTimer(&csta->channel[i].lc_b->act_timer, 76);
+ if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags))
+ release_d_st(csta->channel + i);
+ if (csta->channel[i].b_st) {
+ if (test_and_clear_bit(FLG_START_B, &csta->channel[i].Flags))
+ release_b_st(csta->channel + i);
+ kfree(csta->channel[i].b_st);
+ csta->channel[i].b_st = NULL;
+ } else
+ printk(KERN_WARNING "CallcFreeChan b_st ch%d allready freed\n", i);
+ if (csta->channel[i].lc_b) {
+ kfree(csta->channel[i].lc_b);
+ csta->channel[i].b_st = NULL;
}
- release_is(csta->channel + i);
+ if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
+ release_d_st(csta->channel + i);
+ FsmDelTimer(&csta->channel[i].lc_d->act_timer, 77);
+ if (csta->channel[i].lc_d) {
+ kfree(csta->channel[i].lc_d);
+ csta->channel[i].d_st = NULL;
+ } else
+ printk(KERN_WARNING "CallcFreeChan lc_d ch%d allready freed\n", i);
+ } else
+ csta->channel[i].d_st = NULL;
}
}
static void
lldata_handler(struct PStack *st, int pr, void *arg)
{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
+ struct Channel *chanp = (struct Channel *) st->lli.userdata;
struct sk_buff *skb = arg;
switch (pr) {
case (DL_DATA):
if (chanp->data_open)
- chanp->sp->iif.rcvcallb_skb(chanp->sp->myid, chanp->chan, skb);
+ chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
else {
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
}
break;
@@ -1613,16 +1831,22 @@ lldata_handler(struct PStack *st, int pr, void *arg)
static void
lltrans_handler(struct PStack *st, int pr, void *arg)
{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
+ struct Channel *chanp = (struct Channel *) st->lli.userdata;
struct sk_buff *skb = arg;
switch (pr) {
- case (PH_DATA):
+ case (PH_DATA_IND):
if (chanp->data_open)
- chanp->sp->iif.rcvcallb_skb(chanp->sp->myid, chanp->chan, skb);
+ chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
else {
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
+ if (chanp->lc_b->lcfi.state == ST_LC_DELAY)
+ FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_ESTABLISH, NULL);
+ if (chanp->data_open) {
+ link_debug(chanp, "channel now open", 0);
+ chanp->cs->iif.rcvcallb_skb(chanp->cs->myid,
+ chanp->chan, skb);
+ } else
+ dev_kfree_skb(skb);
}
break;
default:
@@ -1633,73 +1857,79 @@ lltrans_handler(struct PStack *st, int pr, void *arg)
}
static void
-ll_writewakeup(struct PStack *st)
+ll_writewakeup(struct PStack *st, int len)
{
- struct Channel *chanp = st->l4.userdata;
+ struct Channel *chanp = st->lli.userdata;
isdn_ctrl ic;
- ic.driver = chanp->sp->myid;
+ ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_BSENT;
ic.arg = chanp->chan;
- chanp->sp->iif.statcallb(&ic);
+ ic.parm.length = len;
+ chanp->cs->iif.statcallb(&ic);
}
static int
-init_ds(struct Channel *chanp, int incoming)
+init_b_st(struct Channel *chanp, int incoming)
{
- struct PStack *st = &chanp->ds;
- struct IsdnCardState *sp = chanp->sp;
- struct HscxState *hsp = sp->hs + chanp->hscx;
+ struct PStack *st = chanp->b_st;
+ struct IsdnCardState *cs = chanp->cs;
char tmp[128];
- st->l1.hardware = sp;
-
- hsp->mode = 2;
-
- if (setstack_hscx(st, hsp))
+ st->l1.hardware = cs;
+ chanp->bcs->mode = 2;
+ if (chanp->bcs->BC_SetStack(st, chanp->bcs))
return (-1);
-
- st->l2.extended = 0;
- st->l2.laptype = LAPB;
- st->l2.orig = !incoming;
- st->l2.t200 = 1000; /* 1000 milliseconds */
+ st->l2.flag = 0;
+ test_and_set_bit(FLG_LAPB, &st->l2.flag);
+ st->l2.maxlen = MAX_DATA_SIZE;
+ if (!incoming)
+ test_and_set_bit(FLG_ORIG, &st->l2.flag);
+ st->l2.T200 = 1000; /* 1000 milliseconds */
st->l2.window = 7;
- st->l2.n200 = 4; /* try 4 times */
- st->l2.t203 = 5000; /* 5000 milliseconds */
-
+ st->l2.N200 = 4; /* try 4 times */
+ st->l2.T203 = 5000; /* 5000 milliseconds */
st->l3.debug = 0;
switch (chanp->l2_active_protocol) {
case (ISDN_PROTO_L2_X75I):
sprintf(tmp, "Channel %d x.75", chanp->chan);
setstack_isdnl2(st, tmp);
st->l2.l2l3 = lldata_handler;
- st->l1.l1man = dcc_l1man;
- st->l2.l2man = dcc_l2man;
- st->l2.l2tei = l2tei_dummy;
- st->l4.userdata = chanp;
- st->l4.l1writewakeup = NULL;
- st->l4.l2writewakeup = ll_writewakeup;
+ st->l1.l1man = bc_l1man;
+ st->l2.l2man = bc_l2man;
+ st->lli.userdata = chanp;
+ st->lli.l1writewakeup = NULL;
+ st->lli.l2writewakeup = ll_writewakeup;
st->l2.l2m.debug = chanp->debug & 16;
st->l2.debug = chanp->debug & 64;
st->ma.manl2(st, MDL_NOTEIPROC, NULL);
- st->l1.hscxmode = 2; /* Packet-Mode ? */
- st->l1.hscxchannel = chanp->para.bchannel - 1;
+ st->l1.mode = L1_MODE_HDLC;
+ if (chanp->leased)
+ st->l1.bc = chanp->chan & 1;
+ else
+ st->l1.bc = chanp->proc->para.bchannel - 1;
break;
case (ISDN_PROTO_L2_HDLC):
st->l1.l1l2 = lltrans_handler;
- st->l1.l1man = dcc_l1man;
- st->l4.userdata = chanp;
- st->l4.l1writewakeup = ll_writewakeup;
- st->l1.hscxmode = 2;
- st->l1.hscxchannel = chanp->para.bchannel - 1;
+ st->l1.l1man = bc_l1man;
+ st->lli.userdata = chanp;
+ st->lli.l1writewakeup = ll_writewakeup;
+ st->l1.mode = L1_MODE_HDLC;
+ if (chanp->leased)
+ st->l1.bc = chanp->chan & 1;
+ else
+ st->l1.bc = chanp->proc->para.bchannel - 1;
break;
case (ISDN_PROTO_L2_TRANS):
st->l1.l1l2 = lltrans_handler;
- st->l1.l1man = dcc_l1man;
- st->l4.userdata = chanp;
- st->l4.l1writewakeup = ll_writewakeup;
- st->l1.hscxmode = 1;
- st->l1.hscxchannel = chanp->para.bchannel - 1;
+ st->l1.l1man = bc_l1man;
+ st->lli.userdata = chanp;
+ st->lli.l1writewakeup = ll_writewakeup;
+ st->l1.mode = L1_MODE_TRANS;
+ if (chanp->leased)
+ st->l1.bc = chanp->chan & 1;
+ else
+ st->l1.bc = chanp->proc->para.bchannel - 1;
break;
}
return (0);
@@ -1719,15 +1949,17 @@ distr_debug(struct IsdnCardState *csta, int debugflags)
for (i = 0; i < 2; i++) {
chanp[i].debug = debugflags;
chanp[i].fi.debug = debugflags & 2;
- chanp[i].is.l2.l2m.debug = debugflags & 8;
- chanp[i].ds.l2.l2m.debug = debugflags & 16;
- chanp[i].is.l2.debug = debugflags & 32;
- chanp[i].ds.l2.debug = debugflags & 64;
- chanp[i].lc_d.lcfi.debug = debugflags & 128;
- chanp[i].lc_b.lcfi.debug = debugflags & 256;
+ chanp[i].d_st->l2.l2m.debug = debugflags & 8;
+ chanp[i].b_st->l2.l2m.debug = debugflags & 0x10;
+ chanp[i].d_st->l2.debug = debugflags & 0x20;
+ chanp[i].b_st->l2.debug = debugflags & 0x40;
+ chanp[i].lc_d->lcfi.debug = debugflags & 0x80;
+ chanp[i].lc_b->lcfi.debug = debugflags & 0x100;
+ chanp[i].b_st->ma.tei_m.debug = debugflags & 0x200;
+ chanp[i].b_st->ma.debug = debugflags & 0x200;
+ chanp[i].d_st->l1.l1m.debug = debugflags & 0x1000;
}
csta->dlogflag = debugflags & 4;
- csta->teistack->l2.l2m.debug = debugflags & 512;
}
int
@@ -1748,8 +1980,11 @@ HiSax_command(isdn_ctrl * ic)
switch (ic->command) {
case (ISDN_CMD_SETEAZ):
chanp = csta->channel + ic->arg;
- if (chanp->debug & 1)
- link_debug(chanp, "SETEAZ", 1);
+ if (chanp->debug & 1) {
+ sprintf(tmp, "SETEAZ card %d %s", csta->cardnr + 1,
+ ic->parm.num);
+ link_debug(chanp, tmp, 1);
+ }
break;
case (ISDN_CMD_SETL2):
chanp = csta->channel + (ic->arg & 0xff);
@@ -1768,9 +2003,9 @@ HiSax_command(isdn_ctrl * ic)
ic->parm.setup.si1, ic->parm.setup.si2);
link_debug(chanp, tmp, 1);
}
- chanp->para.setup = ic->parm.setup;
- if (!strcmp(chanp->para.setup.eazmsn, "0"))
- chanp->para.setup.eazmsn[0] = '\0';
+ chanp->setup = ic->parm.setup;
+ if (!strcmp(chanp->setup.eazmsn, "0"))
+ chanp->setup.eazmsn[0] = '\0';
/* this solution is dirty and may be change, if
* we make a callreference based callmanager */
if (chanp->fi.state == ST_NULL) {
@@ -1817,7 +2052,7 @@ HiSax_command(isdn_ctrl * ic)
case (ISDN_CMD_LOCK):
HiSax_mod_inc_use_count();
#ifdef MODULE
- if (csta->channel[0].debug & 1024) {
+ if (csta->channel[0].debug & 0x400) {
jiftime(tmp, jiffies);
i = strlen(tmp);
sprintf(tmp + i, " LOCK modcnt %lx\n", MOD_USE_COUNT);
@@ -1828,7 +2063,7 @@ HiSax_command(isdn_ctrl * ic)
case (ISDN_CMD_UNLOCK):
HiSax_mod_dec_use_count();
#ifdef MODULE
- if (csta->channel[0].debug & 1024) {
+ if (csta->channel[0].debug & 0x400) {
jiftime(tmp, jiffies);
i = strlen(tmp);
sprintf(tmp + i, " UNLOCK modcnt %lx\n", MOD_USE_COUNT);
@@ -1852,16 +2087,13 @@ HiSax_command(isdn_ctrl * ic)
printk(KERN_DEBUG "HiSax: %s", tmp);
break;
case (2):
- num = *(unsigned int *) ic->parm.num;
- i = num >> 8;
- if (i >= 2)
- break;
- chanp = csta->channel + i;
- chanp->impair = num & 0xff;
- if (chanp->debug & 1) {
- sprintf(tmp, "IMPAIR %x", chanp->impair);
- link_debug(chanp, tmp, 1);
- }
+ num = *(unsigned int *) ic->parm.num;
+ csta->channel[0].lc_b->delay = num;
+ csta->channel[1].lc_b->delay = num;
+ sprintf(tmp, "delay card %d set to %d ms\n",
+ csta->cardnr + 1, num);
+ HiSax_putstatus(csta, tmp);
+ printk(KERN_DEBUG "HiSax: %s", tmp);
break;
case (3):
for (i = 0; i < *(unsigned int *) ic->parm.num; i++)
@@ -1872,35 +2104,47 @@ HiSax_command(isdn_ctrl * ic)
HiSax_mod_inc_use_count();
break;
case (5): /* set card in leased mode */
- csta->channel[0].leased = 1;
- csta->channel[1].leased = 1;
- sprintf(tmp, "card %d set into leased mode\n",
- csta->cardnr + 1);
- HiSax_putstatus(csta, tmp);
+ num = *(unsigned int *) ic->parm.num;
+ if ((num <1) || (num > 2)) {
+ sprintf(tmp, "Set LEASED wrong channel %d\n",
+ num);
+ HiSax_putstatus(csta, tmp);
+ printk(KERN_WARNING "HiSax: %s", tmp);
+ } else {
+ num--;
+ csta->channel[num].leased = 1;
+ csta->channel[num].lc_d->l2_establish = 0;
+ sprintf(tmp, "card %d channel %d set leased mode\n",
+ csta->cardnr + 1, num + 1);
+ HiSax_putstatus(csta, tmp);
+ FsmEvent(&csta->channel[num].lc_d->lcfi, EV_LC_ESTABLISH, NULL);
+ }
+ break;
+ case (6): /* set B-channel test loop */
+ num = *(unsigned int *) ic->parm.num;
+ if (csta->stlist)
+ csta->stlist->ma.manl1(csta->stlist,
+ PH_TESTLOOP_REQ, (void *) num);
break;
#ifdef MODULE
case (55):
-#if (LINUX_VERSION_CODE < 0x020111)
- MOD_USE_COUNT = MOD_VISITED;
-#else
MOD_USE_COUNT = 0;
-#endif
HiSax_mod_inc_use_count();
break;
#endif /* MODULE */
case (11):
csta->debug = *(unsigned int *) ic->parm.num;
sprintf(tmp, "l1 debugging flags card %d set to %x\n",
- csta->cardnr + 1, csta->debug);
- HiSax_putstatus(cards[0].sp, tmp);
+ csta->cardnr + 1, csta->debug);
+ HiSax_putstatus(cards[0].cs, tmp);
printk(KERN_DEBUG "HiSax: %s", tmp);
break;
case (13):
- csta->channel[0].is.l3.debug = *(unsigned int *) ic->parm.num;
- csta->channel[1].is.l3.debug = *(unsigned int *) ic->parm.num;
+ csta->channel[0].d_st->l3.debug = *(unsigned int *) ic->parm.num;
+ csta->channel[1].d_st->l3.debug = *(unsigned int *) ic->parm.num;
sprintf(tmp, "l3 debugging flags card %d set to %x\n",
csta->cardnr + 1, *(unsigned int *) ic->parm.num);
- HiSax_putstatus(cards[0].sp, tmp);
+ HiSax_putstatus(cards[0].cs, tmp);
printk(KERN_DEBUG "HiSax: %s", tmp);
break;
default:
@@ -1917,7 +2161,7 @@ HiSax_command(isdn_ctrl * ic)
}
int
-HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb)
+HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
{
struct IsdnCardState *csta = hisax_findcard(id);
struct Channel *chanp;
@@ -1933,7 +2177,7 @@ HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb)
return -ENODEV;
}
chanp = csta->channel + chan;
- st = &chanp->ds;
+ st = chanp->b_st;
if (!chanp->data_open) {
link_debug(chanp, "writebuf: channel not open", 1);
return -EIO;
@@ -1945,11 +2189,11 @@ HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb)
return -EINVAL;
}
if (len) {
- if ((len + csta->hs[chanp->hscx].tx_cnt) > MAX_DATA_MEM) {
+ if ((len + chanp->bcs->tx_cnt) > MAX_DATA_MEM) {
/* Must return 0 here, since this is not an error
* but a temporary lack of resources.
*/
- if (chanp->debug & 2048) {
+ if (chanp->debug & 0x800) {
sprintf(tmp, "writebuf: no buffers for %d bytes", len);
link_debug(chanp, tmp, 1);
}
@@ -1959,12 +2203,13 @@ HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb)
cli();
nskb = skb_clone(skb, GFP_ATOMIC);
if (nskb) {
- if (chanp->lc_b.l2_establish) {
- csta->hs[chanp->hscx].tx_cnt += len + st->l2.ihsize;
- chanp->ds.l3.l3l2(&chanp->ds, DL_DATA, nskb);
- } else {
- csta->hs[chanp->hscx].tx_cnt += len;
- chanp->ds.l2.l2l1(&chanp->ds, PH_DATA, nskb);
+ if (!ack)
+ nskb->pkt_type = PACKET_NOACK;
+ if (chanp->lc_b->l2_establish)
+ st->l3.l3l2(st, DL_DATA, nskb);
+ else {
+ chanp->bcs->tx_cnt += len;
+ st->l2.l2l1(st, PH_DATA_REQ, nskb);
}
dev_kfree_skb(skb);
} else
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 7379c8a77..67e308e43 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1,58 +1,53 @@
-/* $Id: config.c,v 1.15 1997/04/06 22:57:24 keil Exp $
+/* $Id: config.c,v 2.12 1998/02/11 17:28:02 keil Exp $
* Author Karsten Keil (keil@temic-ech.spacenet.de)
* based on the teles driver from Jan den Ouden
*
*
* $Log: config.c,v $
- * Revision 1.15 1997/04/06 22:57:24 keil
- * Hisax version 2.1
+ * Revision 2.12 1998/02/11 17:28:02 keil
+ * Niccy PnP/PCI support
*
- * Revision 1.14 1997/03/25 23:11:22 keil
- * US NI-1 protocol
+ * Revision 2.11 1998/02/09 21:26:13 keil
+ * fix export module for 2.1
*
- * Revision 1.13 1997/03/23 21:45:49 keil
- * Add support for ELSA PCMCIA
+ * Revision 2.10 1998/02/09 18:46:05 keil
+ * Support for Sedlbauer PCMCIA (Marcus Niemann)
*
- * Revision 1.12 1997/03/11 21:01:43 keil
- * nzproto is only used with modules
+ * Revision 2.9 1998/02/03 23:31:28 keil
+ * add AMD7930 support
*
- * Revision 1.11 1997/02/14 12:23:12 fritz
- * Added support for new insmod parameter handling.
+ * Revision 2.8 1998/02/02 13:32:59 keil
+ * New card support
*
- * Revision 1.10 1997/02/14 09:22:09 keil
- * Final 2.0 version
+ * Revision 2.7 1998/01/31 21:41:44 keil
+ * changes for newer 2.1 kernels
*
- * Revision 1.9 1997/02/10 11:45:09 fritz
- * More changes for Kernel 2.1.X compatibility.
+ * Revision 2.6 1997/11/08 21:35:43 keil
+ * new l1 init
*
- * Revision 1.8 1997/02/09 00:28:05 keil
- * new interface handling, one interface per card
- * default protocol now works again
+ * Revision 2.5 1997/11/06 17:15:08 keil
+ * New 2.1 init; PCMCIA wrapper changes
*
- * Revision 1.7 1997/01/27 15:56:57 keil
- * Teles PCMCIA ITK ix1 micro added
+ * Revision 2.4 1997/10/29 19:07:52 keil
+ * changes for 2.1
*
- * Revision 1.6 1997/01/21 22:17:56 keil
- * new module load syntax
+ * Revision 2.3 1997/10/01 09:21:33 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
*
- * Revision 1.5 1997/01/09 18:28:20 keil
- * cosmetic cleanups
+ * Revision 2.2 1997/09/11 17:24:46 keil
+ * Add new cards
*
- * Revision 1.4 1996/11/05 19:35:17 keil
- * using config.h; some spelling fixes
- *
- * Revision 1.3 1996/10/23 17:23:28 keil
- * default config changes
- *
- * Revision 1.2 1996/10/23 11:58:48 fritz
- * Changed default setup to reflect user's selection of supported
- * cards/protocols.
- *
- * Revision 1.1 1996/10/13 20:04:51 keil
- * Initial revision
+ * Revision 2.1 1997/07/27 21:41:35 keil
+ * version change
*
+ * Revision 2.0 1997/06/26 11:06:28 keil
+ * New card and L1 interface.
+ * Eicon.Diehl Diva and Dynalink IS64PH support
*
+ * old changes removed /KKe
*
*/
#include <linux/types.h>
@@ -68,16 +63,30 @@
* { type, protocol, p0, p1, p2, NULL }
*
* type
- * 1 Teles 16.0 p0=irq p1=membase p2=iobase
- * 2 Teles 8.0 p0=irq p1=membase
- * 3 Teles 16.3 p0=irq p1=iobase
- * 4 Creatix PNP p0=irq p1=IO0 (ISAC) p2=IO1 (HSCX)
- * 5 AVM A1 (Fritz) p0=irq p1=iobase
- * 6 ELSA PC [p0=iobase] or nothing (autodetect)
- * 7 ELSA Quickstep p0=irq p1=iobase
- * ELSA PCMCIA p0=irq p1=iobase
- * 8 Teles PCMCIA p0=irq p1=iobase
- * 9 ITK ix1-micro p0=irq p1=iobase
+ * 1 Teles 16.0 p0=irq p1=membase p2=iobase
+ * 2 Teles 8.0 p0=irq p1=membase
+ * 3 Teles 16.3 p0=irq p1=iobase
+ * 4 Creatix PNP p0=irq p1=IO0 (ISAC) p2=IO1 (HSCX)
+ * 5 AVM A1 (Fritz) p0=irq p1=iobase
+ * 6 ELSA PC [p0=iobase] or nothing (autodetect)
+ * 7 ELSA Quickstep p0=irq p1=iobase
+ * 8 Teles PCMCIA p0=irq p1=iobase
+ * 9 ITK ix1-micro p0=irq p1=iobase
+ * 10 ELSA PCMCIA p0=irq p1=iobase
+ * 11 Eicon.Diehl Diva p0=irq p1=iobase
+ * 12 Asuscom ISDNLink p0=irq p1=iobase
+ * 13 Teleint p0=irq p1=iobase
+ * 14 Teles 16.3c p0=irq p1=iobase
+ * 15 Sedlbauer speed p0=irq p1=iobase
+ * 16 USR Sportster internal p0=irq p1=iobase
+ * 17 MIC card p0=irq p1=iobase
+ * 18 ELSA Quickstep 1000PCI no parameter
+ * 19 Compaq ISDN S0 ISA card p0=irq p1=IO0 (HSCX) p2=IO1 (ISAC) p3=IO2
+ * 20 Travers Technologies NETjet PCI card
+ * 21 reserved TELES PCI
+ * 22 Sedlbauer Speed Star p0=irq p1=iobase
+ * 23 reserved
+ * 24 Dr Neuhaus Niccy PnP/PCI card p0=irq p1=IO0 p2=IO1 (PnP only)
*
*
* protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
@@ -85,38 +94,108 @@
*
*/
-#ifdef CONFIG_HISAX_ELSA_PCC
+#ifdef CONFIG_HISAX_ELSA
#define DEFAULT_CARD ISDN_CTYPE_ELSA
-#define DEFAULT_CFG {0,0,0}
-#endif
-#ifdef CONFIG_HISAX_ELSA_PCMCIA
-#define DEFAULT_CARD ISDN_CTYPE_ELSA_QS1000
-#define DEFAULT_CFG {3,0x2f8,0}
+#define DEFAULT_CFG {0,0,0,0}
+int elsa_init_pcmcia(void*, int, int*, int);
+EXPORT_SYMBOL(elsa_init_pcmcia);
#endif
#ifdef CONFIG_HISAX_AVM_A1
#undef DEFAULT_CARD
#undef DEFAULT_CFG
#define DEFAULT_CARD ISDN_CTYPE_A1
-#define DEFAULT_CFG {10,0x340,0}
+#define DEFAULT_CFG {10,0x340,0,0}
#endif
#ifdef CONFIG_HISAX_16_3
#undef DEFAULT_CARD
#undef DEFAULT_CFG
#define DEFAULT_CARD ISDN_CTYPE_16_3
-#define DEFAULT_CFG {15,0x180,0}
+#define DEFAULT_CFG {15,0x180,0,0}
#endif
#ifdef CONFIG_HISAX_16_0
#undef DEFAULT_CARD
#undef DEFAULT_CFG
#define DEFAULT_CARD ISDN_CTYPE_16_0
-#define DEFAULT_CFG {15,0xd0000,0xd80}
+#define DEFAULT_CFG {15,0xd0000,0xd80,0}
#endif
#ifdef CONFIG_HISAX_IX1MICROR2
#undef DEFAULT_CARD
#undef DEFAULT_CFG
#define DEFAULT_CARD ISDN_CTYPE_IX1MICROR2
-#define DEFAULT_CFG {5,0x390,0}
+#define DEFAULT_CFG {5,0x390,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_DIEHLDIVA
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_DIEHLDIVA
+#define DEFAULT_CFG {0,0x0,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_ASUSCOM
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_ASUSCOM
+#define DEFAULT_CFG {5,0x200,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_TELEINT
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_TELEINT
+#define DEFAULT_CFG {5,0x300,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_SEDLBAUER
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_SEDLBAUER
+#define DEFAULT_CFG {11,0x270,0,0}
+int sedl_init_pcmcia(void*, int, int*, int);
+EXPORT_SYMBOL(sedl_init_pcmcia);
+#endif
+
+#ifdef CONFIG_HISAX_SPORTSTER
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_SPORTSTER
+#define DEFAULT_CFG {7,0x268,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_MIC
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_MIC
+#define DEFAULT_CFG {12,0x3e0,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_NETJET
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_NETJET
+#define DEFAULT_CFG {0,0,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_TELES3C
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_TELES3C
+#define DEFAULT_CFG {5,0x500,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_AMD7930
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_AMD7930
+#define DEFAULT_CFG {12,0x3e0,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_NICCY
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_NICCY
+#define DEFAULT_CFG {0,0x0,0,0}
#endif
#ifdef CONFIG_HISAX_1TR6
@@ -150,7 +229,7 @@
NULL, \
}
-#define EMPTY_CARD {0, DEFAULT_PROTO, {0, 0, 0}, NULL}
+#define EMPTY_CARD {0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL}
struct IsdnCard cards[] =
{
@@ -172,55 +251,63 @@ struct IsdnCard cards[] =
EMPTY_CARD,
};
-static char HiSaxID[96] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
+static char HiSaxID[96] HISAX_INITDATA = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
-char *HiSax_id = HiSaxID;
+char *HiSax_id HISAX_INITDATA = HiSaxID;
#ifdef MODULE
/* Variables for insmod */
-static int type[] =
+static int type[] HISAX_INITDATA =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static int protocol[] =
+static int protocol[] HISAX_INITDATA =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static int io[] =
+static int io[] HISAX_INITDATA =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-#ifdef CONFIG_HISAX_16_3 /* For Creatix/Teles PnP */
-static int io0[] =
+#undef IO0_IO1
+#ifdef CONFIG_HISAX_16_3
+#define IO0_IO1
+#endif
+#ifdef CONFIG_HISAX_NICCY
+#undef IO0_IO1
+#define IO0_IO1
+#endif
+#ifdef IO0_IO1
+static int io0[] HISAX_INITDATA =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static int io1[] =
+static int io1[] HISAX_INITDATA =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
#endif
-static int irq[] =
+static int irq[] HISAX_INITDATA =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static int mem[] =
+static int mem[] HISAX_INITDATA =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static char *id = HiSaxID;
+static char *id HISAX_INITDATA = HiSaxID;
-#if (LINUX_VERSION_CODE > 0x020111)
MODULE_AUTHOR("Karsten Keil");
-MODULE_PARM(type, "1-16i");
-MODULE_PARM(protocol, "1-16i");
-MODULE_PARM(io, "1-16i");
-MODULE_PARM(irq, "1-16i");
-MODULE_PARM(mem, "1-16i");
+MODULE_PARM(type, "1-3i");
+MODULE_PARM(protocol, "1-2i");
+MODULE_PARM(io, "1-8i");
+MODULE_PARM(irq, "1-2i");
+MODULE_PARM(mem, "1-12i");
MODULE_PARM(id, "s");
#ifdef CONFIG_HISAX_16_3 /* For Creatix/Teles PnP */
-MODULE_PARM(io0, "1-16i");
-MODULE_PARM(io1, "1-16i");
-#endif
+MODULE_PARM(io0, "1-8i");
+MODULE_PARM(io1, "1-8i");
#endif
#endif
+int nrcards;
+
extern char *l1_revision;
extern char *l2_revision;
extern char *l3_revision;
-extern char *l4_revision;
+extern char *lli_revision;
extern char *tei_revision;
-char *
-HiSax_getrev(const char *revision)
+HISAX_INITFUNC(char *
+HiSax_getrev(const char *revision))
{
char *rev;
char *p;
@@ -234,7 +321,27 @@ HiSax_getrev(const char *revision)
return rev;
}
-int nrcards;
+HISAX_INITFUNC(void
+HiSaxVersion(void))
+{
+ char tmp[64], rev[64];
+ char *r = rev;
+
+ strcpy(tmp, l1_revision);
+ r += sprintf(r, "%s/", HiSax_getrev(tmp));
+ strcpy(tmp, l2_revision);
+ r += sprintf(r, "%s/", HiSax_getrev(tmp));
+ strcpy(tmp, l3_revision);
+ r += sprintf(r, "%s/", HiSax_getrev(tmp));
+ strcpy(tmp, lli_revision);
+ r += sprintf(r, "%s/", HiSax_getrev(tmp));
+ strcpy(tmp, tei_revision);
+ r += sprintf(r, "%s", HiSax_getrev(tmp));
+
+ printk(KERN_INFO "HiSax: Driver for Siemens chip set ISDN cards\n");
+ printk(KERN_INFO "HiSax: Version 2.8\n");
+ printk(KERN_INFO "HiSax: Revisions %s\n", rev);
+}
void
HiSax_mod_dec_use_count(void)
@@ -251,8 +358,8 @@ HiSax_mod_inc_use_count(void)
#ifdef MODULE
#define HiSax_init init_module
#else
-void
-HiSax_setup(char *str, int *ints)
+__initfunc(void
+HiSax_setup(char *str, int *ints))
{
int i, j, argc;
@@ -297,31 +404,28 @@ HiSax_setup(char *str, int *ints)
}
#endif
-int
-HiSax_init(void)
+__initfunc(int
+HiSax_init(void))
{
int i;
- char tmp[64], rev[64];
- char *r = rev;
+
#ifdef MODULE
int nzproto = 0;
+#ifdef CONFIG_HISAX_ELSA
+ if (type[0] == ISDN_CTYPE_ELSA_PCMCIA) {
+ /* we have exported and return in this case */
+ return 0;
+ }
+#endif
+#ifdef CONFIG_HISAX_SEDLBAUER
+ if (type[0] == ISDN_CTYPE_SEDLBAUER_PCMCIA) {
+ /* we have to export and return in this case */
+ return 0;
+ }
+#endif
#endif
+ HiSaxVersion();
nrcards = 0;
- strcpy(tmp, l1_revision);
- r += sprintf(r, "%s/", HiSax_getrev(tmp));
- strcpy(tmp, l2_revision);
- r += sprintf(r, "%s/", HiSax_getrev(tmp));
- strcpy(tmp, l3_revision);
- r += sprintf(r, "%s/", HiSax_getrev(tmp));
- strcpy(tmp, l4_revision);
- r += sprintf(r, "%s/", HiSax_getrev(tmp));
- strcpy(tmp, tei_revision);
- r += sprintf(r, "%s", HiSax_getrev(tmp));
-
- printk(KERN_NOTICE "HiSax: Driver for Siemens chip set ISDN cards\n");
- printk(KERN_NOTICE "HiSax: Version 2.1\n");
- printk(KERN_NOTICE "HiSax: Revisions %s\n", rev);
-
#ifdef MODULE
if (id) /* If id= string used */
HiSax_id = id;
@@ -343,37 +447,44 @@ HiSax_init(void)
cards[i].para[1] = mem[i];
break;
- case ISDN_CTYPE_16_3:
- case ISDN_CTYPE_TELESPCMCIA:
- cards[i].para[0] = irq[i];
- cards[i].para[1] = io[i];
- break;
-
-#ifdef CONFIG_HISAX_16_3 /* For Creatix/Teles PnP */
+#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];
break;
-#endif
- case ISDN_CTYPE_A1:
+ case ISDN_CTYPE_COMPAQ_ISA:
cards[i].para[0] = irq[i];
- cards[i].para[1] = io[i];
+ cards[i].para[1] = io0[i];
+ cards[i].para[2] = io1[i];
+ cards[i].para[3] = io[i];
break;
-
+#endif
case ISDN_CTYPE_ELSA:
cards[i].para[0] = io[i];
break;
- case ISDN_CTYPE_ELSA_QS1000:
- cards[i].para[0] = irq[i];
- cards[i].para[1] = io[i];
- break;
-
+ case ISDN_CTYPE_16_3:
+ case ISDN_CTYPE_TELESPCMCIA:
+ case ISDN_CTYPE_A1:
+ case ISDN_CTYPE_ELSA_PNP:
+ case ISDN_CTYPE_ELSA_PCMCIA:
case ISDN_CTYPE_IX1MICROR2:
+ case ISDN_CTYPE_DIEHLDIVA:
+ case ISDN_CTYPE_ASUSCOM:
+ case ISDN_CTYPE_TELEINT:
+ case ISDN_CTYPE_SEDLBAUER:
+ case ISDN_CTYPE_SEDLBAUER_PCMCIA:
+ case ISDN_CTYPE_SPORTSTER:
+ case ISDN_CTYPE_MIC:
+ case ISDN_CTYPE_TELES3C:
cards[i].para[0] = irq[i];
cards[i].para[1] = io[i];
break;
-
+ case ISDN_CTYPE_ELSA_PCI:
+ case ISDN_CTYPE_NETJET:
+ case ISDN_CTYPE_AMD7930:
+ break;
}
}
if (!nzproto) {
@@ -394,20 +505,20 @@ HiSax_init(void)
CallcNew();
Isdnl2New();
- if (HiSax_inithardware()) {
+ TeiNew();
+ Isdnl1New();
+ if (HiSax_inithardware(NULL)) {
/* Install only, if at least one card found */
/* No symbols to export, hide all symbols */
#ifdef MODULE
-#if (LINUX_VERSION_CODE < 0x020111)
- register_symtab(NULL);
-#else
EXPORT_NO_SYMBOLS;
-#endif
- printk(KERN_NOTICE "HiSax: module installed\n");
+ printk(KERN_INFO "HiSax: module installed\n");
#endif
return (0);
} else {
+ Isdnl1Free();
+ TeiFree();
Isdnl2Free();
CallcFree();
return -EIO;
@@ -419,7 +530,101 @@ void
cleanup_module(void)
{
HiSax_closehardware();
- printk(KERN_NOTICE "HiSax module removed\n");
+ printk(KERN_INFO "HiSax module removed\n");
}
+#ifdef CONFIG_HISAX_ELSA
+int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
+{
+ int i;
+ int nzproto = 0;
+
+ nrcards = 0;
+ HiSaxVersion();
+ if (id) /* If id= string used */
+ HiSax_id = id;
+ /* Initialize all 16 structs, even though we only accept
+ two pcmcia cards
+ */
+ for (i = 0; i < 16; i++) {
+ cards[i].para[0] = irq[i];
+ cards[i].para[1] = io[i];
+ cards[i].typ = type[i];
+ if (protocol[i]) {
+ cards[i].protocol = protocol[i];
+ nzproto++;
+ }
+ }
+ cards[0].para[0] = pcm_irq;
+ cards[0].para[1] = (int)pcm_iob;
+ cards[0].protocol = prot;
+ cards[0].typ = 10;
+ nzproto = 1;
+
+ if (!HiSax_id)
+ HiSax_id = HiSaxID;
+ if (!HiSaxID[0])
+ strcpy(HiSaxID, "HiSax");
+ for (i = 0; i < 16; i++)
+ if (cards[i].typ > 0)
+ nrcards++;
+ printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
+ nrcards, (nrcards > 1) ? "s" : "");
+
+ Isdnl1New();
+ CallcNew();
+ Isdnl2New();
+ TeiNew();
+ HiSax_inithardware(busy_flag);
+ printk(KERN_NOTICE "HiSax: module installed\n");
+ return (0);
+}
+#endif
+#ifdef CONFIG_HISAX_SEDLBAUER
+int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
+{
+ int i;
+ int nzproto = 0;
+
+ nrcards = 0;
+ HiSaxVersion();
+ if (id) /* If id= string used */
+ HiSax_id = id;
+ /* Initialize all 16 structs, even though we only accept
+ two pcmcia cards
+ */
+ for (i = 0; i < 16; i++) {
+ cards[i].para[0] = irq[i];
+ cards[i].para[1] = io[i];
+ cards[i].typ = type[i];
+ if (protocol[i]) {
+ cards[i].protocol = protocol[i];
+ nzproto++;
+ }
+ }
+ cards[0].para[0] = pcm_irq;
+ cards[0].para[1] = (int)pcm_iob;
+ cards[0].protocol = prot;
+ cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
+ nzproto = 1;
+
+ if (!HiSax_id)
+ HiSax_id = HiSaxID;
+ if (!HiSaxID[0])
+ strcpy(HiSaxID, "HiSax");
+ for (i = 0; i < 16; i++)
+ if (cards[i].typ > 0)
+ nrcards++;
+ printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
+ nrcards, (nrcards > 1) ? "s" : "");
+
+ Isdnl1New();
+ CallcNew();
+ Isdnl2New();
+ TeiNew();
+ HiSax_inithardware(busy_flag);
+ printk(KERN_NOTICE "HiSax: module installed\n");
+ return (0);
+}
#endif
+#endif
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
new file mode 100644
index 000000000..fa3a45b72
--- /dev/null
+++ b/drivers/isdn/hisax/diva.c
@@ -0,0 +1,465 @@
+/* $Id: diva.c,v 1.5 1998/02/02 13:29:38 keil Exp $
+
+ * diva.c low level stuff for Eicon.Diehl Diva Family ISDN cards
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to Eicon Technology Diehl GmbH & Co. oHG for documents and informations
+ *
+ *
+ * $Log: diva.c,v $
+ * Revision 1.5 1998/02/02 13:29:38 keil
+ * fast io
+ *
+ * Revision 1.4 1997/11/08 21:35:44 keil
+ * new l1 init
+ *
+ * Revision 1.3 1997/11/06 17:13:33 keil
+ * New 2.1 init code
+ *
+ * Revision 1.2 1997/10/29 18:55:55 keil
+ * changes for 2.1.60 (irq2dev_map)
+ *
+ * Revision 1.1 1997/09/18 17:11:20 keil
+ * first version
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+#include <linux/pci.h>
+#include <linux/bios32.h>
+
+extern const char *CardType[];
+
+const char *Diva_revision = "$Revision: 1.5 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define DIVA_HSCX_DATA 0
+#define DIVA_HSCX_ADR 4
+#define DIVA_ISA_ISAC_DATA 2
+#define DIVA_ISA_ISAC_ADR 6
+#define DIVA_ISA_CTRL 7
+
+#define DIVA_PCI_ISAC_DATA 8
+#define DIVA_PCI_ISAC_ADR 0xc
+#define DIVA_PCI_CTRL 0x10
+
+/* SUB Types */
+#define DIVA_ISA 1
+#define DIVA_PCI 2
+
+/* 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
+
+/* CTRL (Read) */
+#define DIVA_IRQ_STAT 0x01
+#define DIVA_EEPROM_SDA 0x02
+/* CTRL (Write) */
+#define DIVA_IRQ_REQ 0x01
+#define DIVA_RESET 0x08
+#define DIVA_EEPROM_CLK 0x40
+#define DIVA_PCI_LED_A 0x10
+#define DIVA_PCI_LED_B 0x20
+#define DIVA_ISA_LED_A 0x20
+#define DIVA_ISA_LED_B 0x40
+#define DIVA_IRQ_CLR 0x80
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+ register u_char ret;
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(ale, off);
+ ret = bytein(adr);
+ restore_flags(flags);
+ return (ret);
+}
+
+static inline void
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+ /* fifo read without cli because it's allready done */
+
+ byteout(ale, off);
+ insb(adr, data, size);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(ale, off);
+ byteout(adr, data);
+ restore_flags(flags);
+}
+
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
+{
+ /* fifo write without cli because it's allready done */
+ byteout(ale, off);
+ outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+ return(readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
+{
+ readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
+{
+ writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+ return(readreg(cs->hw.diva.hscx_adr,
+ cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+ writereg(cs->hw.diva.hscx_adr,
+ cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0), value);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.diva.hscx_adr, \
+ cs->hw.diva.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.diva.hscx_adr, \
+ cs->hw.diva.hscx, reg + (nr ? 0x40 : 0), data)
+
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.diva.hscx_adr, \
+ cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.diva.hscx_adr, \
+ cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+diva_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val, sval, stat = 0;
+ int cnt=8;
+
+ if (!cs) {
+ printk(KERN_WARNING "Diva: Spurious interrupt!\n");
+ return;
+ }
+ while (((sval = bytein(cs->hw.diva.ctrl)) & DIVA_IRQ_REQ) && cnt) {
+ val = readreg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_ISTA + 0x40);
+ if (val) {
+ hscx_int_main(cs, val);
+ stat |= 1;
+ }
+ val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA);
+ if (val) {
+ isac_interrupt(cs, val);
+ stat |= 2;
+ }
+ cnt--;
+ }
+ if (!cnt)
+ printk(KERN_WARNING "Diva: IRQ LOOP\n");
+ if (stat & 1) {
+ writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0xFF);
+ writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0xFF);
+ writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0x0);
+ writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0x0);
+ }
+ if (stat & 2) {
+ writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0x0);
+ }
+}
+
+void
+release_io_diva(struct IsdnCardState *cs)
+{
+ int bytecnt;
+
+ del_timer(&cs->hw.diva.tl);
+ if (cs->subtyp == DIVA_ISA)
+ bytecnt = 8;
+ else
+ bytecnt = 32;
+ if (cs->hw.diva.cfg_reg) {
+ byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */
+ release_region(cs->hw.diva.cfg_reg, bytecnt);
+ }
+}
+
+static void
+reset_diva(struct IsdnCardState *cs)
+{
+ long flags;
+
+ save_flags(flags);
+ sti();
+ cs->hw.diva.ctrl_reg = 0; /* Reset On */
+ byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */
+ schedule();
+ cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */
+ byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */
+ schedule();
+ if (cs->subtyp == DIVA_ISA)
+ cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A;
+ else
+ cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A;
+ byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
+}
+
+#define DIVA_ASSIGN 1
+
+static void
+diva_led_handler(struct IsdnCardState *cs)
+{
+ int blink = 0;
+
+ del_timer(&cs->hw.diva.tl);
+ if (cs->hw.diva.status & DIVA_ASSIGN)
+ cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ?
+ DIVA_ISA_LED_A : DIVA_PCI_LED_A;
+ else {
+ cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ?
+ DIVA_ISA_LED_A : DIVA_PCI_LED_A;
+ blink = 250;
+ }
+ if (cs->hw.diva.status & 0xf000)
+ cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ?
+ DIVA_ISA_LED_B : DIVA_PCI_LED_B;
+ else if (cs->hw.diva.status & 0x0f00) {
+ cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ?
+ DIVA_ISA_LED_B : DIVA_PCI_LED_B;
+ blink = 500;
+ } else
+ cs->hw.diva.ctrl_reg &= ~((DIVA_ISA == cs->subtyp) ?
+ DIVA_ISA_LED_B : DIVA_PCI_LED_B);
+
+ byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
+ if (blink) {
+ init_timer(&cs->hw.diva.tl);
+ cs->hw.diva.tl.expires = jiffies + ((blink * HZ) / 1000);
+ add_timer(&cs->hw.diva.tl);
+ }
+}
+
+static int
+Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ reset_diva(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_diva(cs);
+ return(0);
+ case CARD_SETIRQ:
+ return(request_irq(cs->irq, &diva_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs));
+ case CARD_INIT:
+ clear_pending_isac_ints(cs);
+ clear_pending_hscx_ints(cs);
+ initisac(cs);
+ inithscx(cs);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ case MDL_REMOVE_REQ:
+ cs->hw.diva.status = 0;
+ break;
+ case MDL_ASSIGN_REQ:
+ cs->hw.diva.status |= DIVA_ASSIGN;
+ break;
+ case MDL_INFO_SETUP:
+ if ((int)arg)
+ cs->hw.diva.status |= 0x0200;
+ else
+ cs->hw.diva.status |= 0x0100;
+ break;
+ case MDL_INFO_CONN:
+ if ((int)arg)
+ cs->hw.diva.status |= 0x2000;
+ else
+ cs->hw.diva.status |= 0x1000;
+ break;
+ case MDL_INFO_REL:
+ if ((int)arg) {
+ cs->hw.diva.status &= ~0x2000;
+ cs->hw.diva.status &= ~0x0200;
+ } else {
+ cs->hw.diva.status &= ~0x1000;
+ cs->hw.diva.status &= ~0x0100;
+ }
+ break;
+ }
+ diva_led_handler(cs);
+ return(0);
+}
+
+
+
+static int pci_index __initdata = 0;
+
+__initfunc(int
+setup_diva(struct IsdnCard *card))
+{
+ int bytecnt;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, Diva_revision);
+ printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
+ return(0);
+ cs->hw.diva.status = 0;
+ if (card->para[1]) {
+ cs->subtyp = DIVA_ISA;
+ cs->hw.diva.ctrl_reg = 0;
+ cs->hw.diva.cfg_reg = card->para[1];
+ cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
+ cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
+ cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
+ cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
+ cs->irq = card->para[0];
+ bytecnt = 8;
+ } else {
+#if CONFIG_PCI
+ u_char pci_bus, pci_device_fn, pci_irq;
+ u_int pci_ioaddr;
+
+ cs->subtyp = 0;
+ for (; pci_index < 0xff; pci_index++) {
+ if (pcibios_find_device(PCI_VENDOR_EICON_DIEHL,
+ PCI_DIVA20_ID, pci_index, &pci_bus, &pci_device_fn)
+ == PCIBIOS_SUCCESSFUL)
+ cs->subtyp = DIVA_PCI;
+ else if (pcibios_find_device(PCI_VENDOR_EICON_DIEHL,
+ PCI_DIVA20_ID, pci_index, &pci_bus, &pci_device_fn)
+ == PCIBIOS_SUCCESSFUL)
+ cs->subtyp = DIVA_PCI;
+ else
+ break;
+ /* get IRQ */
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq);
+
+ /* get IO address */
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_2, &pci_ioaddr);
+ if (cs->subtyp)
+ break;
+ }
+ if (!cs->subtyp) {
+ printk(KERN_WARNING "Diva: No PCI card found\n");
+ return(0);
+ }
+ if (!pci_irq) {
+ printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
+ return(0);
+ }
+
+ if (!pci_ioaddr) {
+ printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ pci_ioaddr &= ~3; /* remove io/mem flag */
+ cs->hw.diva.cfg_reg = pci_ioaddr;
+ cs->hw.diva.ctrl = pci_ioaddr + DIVA_PCI_CTRL;
+ cs->hw.diva.isac = pci_ioaddr + DIVA_PCI_ISAC_DATA;
+ cs->hw.diva.hscx = pci_ioaddr + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr = pci_ioaddr + DIVA_PCI_ISAC_ADR;
+ cs->hw.diva.hscx_adr = pci_ioaddr + DIVA_HSCX_ADR;
+ cs->irq = pci_irq;
+ bytecnt = 32;
+#else
+ printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n");
+ printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
+ return (0);
+#endif /* CONFIG_PCI */
+ }
+
+ printk(KERN_INFO
+ "Diva: %s card configured at 0x%x IRQ %d\n",
+ (cs->subtyp == DIVA_ISA) ? "ISA" : "PCI",
+ cs->hw.diva.cfg_reg, cs->irq);
+ if (check_region(cs->hw.diva.cfg_reg, bytecnt)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.diva.cfg_reg,
+ cs->hw.diva.cfg_reg + bytecnt);
+ return (0);
+ } else {
+ request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn");
+ }
+
+ reset_diva(cs);
+ cs->hw.diva.tl.function = (void *) diva_led_handler;
+ cs->hw.diva.tl.data = (long) cs;
+ init_timer(&cs->hw.diva.tl);
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ cs->BC_Read_Reg = &ReadHSCX;
+ cs->BC_Write_Reg = &WriteHSCX;
+ cs->BC_Send_Data = &hscx_fill_fifo;
+ cs->cardmsg = &Diva_card_msg;
+
+ ISACVersion(cs, "Diva:");
+ if (HscxVersion(cs, "Diva:")) {
+ printk(KERN_WARNING
+ "Diva: wrong HSCX versions check IO address\n");
+ release_io_diva(cs);
+ return (0);
+ }
+ return (1);
+}
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index 5cea59d9d..6a9966431 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -1,4 +1,4 @@
-/* $Id: elsa.c,v 1.14 1997/04/13 19:53:25 keil Exp $
+/* $Id: elsa.c,v 2.6 1998/02/02 13:29:40 keil Exp $
* elsa.c low level stuff for Elsa isdn cards
*
@@ -8,1241 +8,726 @@
*
*
* $Log: elsa.c,v $
- * Revision 1.14 1997/04/13 19:53:25 keil
- * Fixed QS1000 init, change in IRQ check delay for SMP
+ * Revision 2.6 1998/02/02 13:29:40 keil
+ * fast io
*
- * Revision 1.13 1997/04/07 22:58:07 keil
- * need include config.h
- *
- * Revision 1.12 1997/04/06 22:54:14 keil
- * Using SKB's
+ * Revision 2.5 1998/01/31 21:41:45 keil
+ * changes for newer 2.1 kernels
*
- * Revision 1.11 1997/03/23 21:45:46 keil
- * Add support for ELSA PCMCIA
+ * Revision 2.4 1997/11/08 21:35:46 keil
+ * new l1 init
*
- * Revision 1.10 1997/03/12 21:42:19 keil
- * Bugfix: IRQ hangs with QS1000
+ * Revision 2.3 1997/11/06 17:15:09 keil
+ * New 2.1 init; PCMCIA wrapper changes
*
- * Revision 1.9 1997/03/04 15:57:39 keil
- * bugfix IRQ reset Quickstep, ELSA PC changes, some stuff for new cards
+ * Revision 2.2 1997/10/29 18:57:09 keil
+ * changes for 2.1.60, arcofi support
*
- * Revision 1.8 1997/01/27 15:51:48 keil
- * SMP proof,cosmetics
+ * Revision 2.1 1997/07/27 21:47:08 keil
+ * new interface structures
*
- * Revision 1.7 1997/01/21 22:20:48 keil
- * Elsa Quickstep support
+ * Revision 2.0 1997/06/26 11:02:40 keil
+ * New Layer and card interface
*
- * Revision 1.6 1997/01/09 18:22:46 keil
- * one more PCC-8 fix
- *
- * Revision 1.5 1996/12/08 19:46:14 keil
- * PCC-8 correct IRQs; starting ARCOFI support
- *
- * Revision 1.4 1996/11/18 20:50:54 keil
- * with PCF Pro release 16 Byte IO
- *
- * Revision 1.3 1996/11/18 15:33:04 keil
- * PCC and PCFPro support
+ * Revision 1.14 1997/04/13 19:53:25 keil
+ * Fixed QS1000 init, change in IRQ check delay for SMP
*
- * Revision 1.2 1996/10/27 22:08:03 keil
- * cosmetic changes
+ * Revision 1.13 1997/04/07 22:58:07 keil
+ * need include config.h
*
- * Revision 1.1 1996/10/13 20:04:52 keil
- * Initial revision
+ * Revision 1.12 1997/04/06 22:54:14 keil
+ * Using SKB's
*
+ * old changes removed KKe
*
*/
-#define ARCOFI_USE 0
-
#define __NO_VERSION__
#include <linux/config.h>
-#include "siemens.h"
#include "hisax.h"
-#include "elsa.h"
+#include "arcofi.h"
+#include "isac.h"
+#include "ipac.h"
+#include "hscx.h"
#include "isdnl1.h"
-#include <linux/kernel_stat.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
extern const char *CardType[];
-const char *Elsa_revision = "$Revision: 1.14 $";
+const char *Elsa_revision = "$Revision: 2.6 $";
const char *Elsa_Types[] =
{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
- "PCMCIA", "QS 1000", "QS 3000"};
+ "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI"};
const char *ITACVer[] =
{"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2",
"B1", "A1"};
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define ELSA_ISAC 0
+#define ELSA_ISAC_PCM 1
+#define ELSA_ITAC 1
+#define ELSA_HSCX 2
+#define ELSA_ALE 3
+#define ELSA_ALE_PCM 4
+#define ELSA_CONTROL 4
+#define ELSA_CONFIG 5
+#define ELSA_START_TIMER 6
+#define ELSA_TRIG_IRQ 7
+
+#define ELSA_PC 1
+#define ELSA_PCC8 2
+#define ELSA_PCC16 3
+#define ELSA_PCF 4
+#define ELSA_PCFPRO 5
+#define ELSA_PCMCIA 6
+#define ELSA_QS1000 7
+#define ELSA_QS3000 8
+#define ELSA_QS1000PCI 9
+
+/* PCI stuff */
+#define PCI_VENDOR_ELSA 0x1048
+#define PCI_QS1000_ID 0x1000
+
+
+/* ITAC Registeradressen (only Microlink PC) */
+#define ITAC_SYS 0x34
+#define ITAC_ISEN 0x48
+#define ITAC_RFIE 0x4A
+#define ITAC_XFIE 0x4C
+#define ITAC_SCIE 0x4E
+#define ITAC_STIE 0x46
+
+/*** ***
+ *** Makros als Befehle fuer die Kartenregister ***
+ *** (mehrere Befehle werden durch Bit-Oderung kombiniert) ***
+ *** ***/
+
+/* Config-Register (Read) */
+#define ELSA_TIMER_RUN 0x02 /* Bit 1 des Config-Reg */
+#define ELSA_TIMER_RUN_PCC8 0x01 /* Bit 0 des Config-Reg bei PCC */
+#define ELSA_IRQ_IDX 0x38 /* Bit 3,4,5 des Config-Reg */
+#define ELSA_IRQ_IDX_PCC8 0x30 /* Bit 4,5 des Config-Reg */
+#define ELSA_IRQ_IDX_PC 0x0c /* Bit 2,3 des Config-Reg */
+
+/* Control-Register (Write) */
+#define ELSA_LINE_LED 0x02 /* Bit 1 Gelbe LED */
+#define ELSA_STAT_LED 0x08 /* Bit 3 Gruene LED */
+#define ELSA_ISDN_RESET 0x20 /* Bit 5 Reset-Leitung */
+#define ELSA_ENA_TIMER_INT 0x80 /* Bit 7 Freigabe Timer Interrupt */
+
+/* ALE-Register (Read) */
+#define ELSA_HW_RELEASE 0x07 /* Bit 0-2 Hardwarerkennung */
+#define ELSA_S0_POWER_BAD 0x08 /* Bit 3 S0-Bus Spannung fehlt */
+
+/* Status Flags */
+#define ELSA_TIMER_AKTIV 1
+#define ELSA_BAD_PWR 2
+#define ELSA_ASSIGN 4
static inline u_char
-readhscx(unsigned int adr, int hscx, u_char off)
+readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
long flags;
save_flags(flags);
cli();
- byteout(adr + CARD_ALE, off + (hscx ? 0x60 : 0x20));
- ret = bytein(adr + CARD_HSCX);
+ byteout(ale, off);
+ ret = bytein(adr);
restore_flags(flags);
return (ret);
}
static inline void
-read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
{
/* fifo read without cli because it's allready done */
- byteout(adr + CARD_ALE, (hscx ? 0x40 : 0));
- insb(adr + CARD_HSCX, data, size);
+ byteout(ale, off);
+ insb(adr, data, size);
}
static inline void
-writehscx(unsigned int adr, int hscx, u_char off, u_char data)
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
long flags;
save_flags(flags);
cli();
- byteout(adr + CARD_ALE, off + (hscx ? 0x60 : 0x20));
- byteout(adr + CARD_HSCX, data);
+ byteout(ale, off);
+ byteout(adr, data);
restore_flags(flags);
}
static inline void
-write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
{
/* fifo write without cli because it's allready done */
- byteout(adr + CARD_ALE, (hscx ? 0x40 : 0));
- outsb(adr + CARD_HSCX, data, size);
-}
-
-static inline u_char
-readisac(unsigned int adr, u_char off)
-{
- register u_char ret;
- long flags;
-
- save_flags(flags);
- cli();
- byteout(adr + CARD_ALE, off + 0x20);
- ret = bytein(adr + CARD_ISAC);
- restore_flags(flags);
- return (ret);
+ byteout(ale, off);
+ outsb(adr, data, size);
}
-static inline void
-read_fifo_isac(unsigned int adr, u_char * data, int size)
-{
- /* fifo read without cli because it's allready done */
-
- byteout(adr + CARD_ALE, 0);
- insb(adr + CARD_ISAC, data, size);
-}
-
-
-static inline void
-writeisac(unsigned int adr, u_char off, u_char data)
-{
- long flags;
+/* Interface functions */
- save_flags(flags);
- cli();
- byteout(adr + CARD_ALE, off + 0x20);
- byteout(adr + CARD_ISAC, data);
- restore_flags(flags);
-}
-
-static inline void
-write_fifo_isac(unsigned int adr, u_char * data, int size)
-{
- /* fifo write without cli because it's allready done */
-
- byteout(adr + CARD_ALE, 0);
- outsb(adr + CARD_ISAC, data, size);
-}
-
-#ifdef CONFIG_HISAX_ELSA_PCC
-static inline u_char
-readitac(unsigned int adr, u_char off)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
{
- register u_char ret;
- long flags;
-
- save_flags(flags);
- cli();
- byteout(adr + CARD_ALE, off);
- ret = bytein(adr + CARD_ITAC);
- restore_flags(flags);
- return (ret);
+ return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset));
}
-static inline void
-writeitac(unsigned int adr, u_char off, u_char data)
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
- long flags;
-
- save_flags(flags);
- cli();
- byteout(adr + CARD_ALE, off);
- byteout(adr + CARD_ITAC, data);
- restore_flags(flags);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset, value);
}
-static inline int
-TimerRun(struct IsdnCardState *sp)
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
- register u_char val;
-
- val = bytein(sp->cfg_reg + CARD_CONFIG);
- if (sp->subtyp == ELSA_QS1000)
- return (0 == (val & TIMER_RUN));
- else if (sp->subtyp == ELSA_PCC8)
- return (val & TIMER_RUN_PCC8);
- return (val & TIMER_RUN);
+ readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size);
}
-static inline void
-elsa_led_handler(struct IsdnCardState *sp)
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
-
- u_char outval = 0xf0;
- int stat = 0, cval;
-
-
- if ((sp->ph_state == 0) || (sp->ph_state == 15)) {
- stat = 1;
- } else {
- if (sp->hs[0].mode != 0)
- stat |= 2;
- if (sp->hs[1].mode != 0)
- stat |= 4;
- }
- cval = (sp->counter >> 6) & 3;
- switch (cval) {
- case 0:
- if (!stat)
- outval |= STAT_LED;
- else if (stat == 1)
- outval |= LINE_LED | STAT_LED;
- else {
- if (stat & 2)
- outval |= STAT_LED;
- if (stat & 4)
- outval |= LINE_LED;
- }
- break;
- case 1:
- if (!stat)
- outval |= LINE_LED;
- else if (stat == 1)
- outval |= LINE_LED | STAT_LED;
- else {
- if (stat & 2)
- outval |= STAT_LED;
- if (stat & 4)
- outval |= LINE_LED;
- }
- break;
- case 2:
- if (!stat)
- outval |= STAT_LED;
- else if (stat == 1)
- outval |= 0;
- else {
- if (stat & 2)
- outval |= STAT_LED;
- if (stat & 4)
- outval |= LINE_LED;
- }
- break;
- case 3:
- if (!stat)
- outval |= LINE_LED;
- break;
- }
- byteout(sp->cfg_reg + CARD_CONTROL, outval);
+ writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size);
}
-#endif
-static inline void
-waitforCEC(int adr, int hscx)
+static u_char
+ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
{
- int to = 50;
-
- while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "Elsa: waitforCEC timeout\n");
+ return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset+0x80));
}
-
-static inline void
-waitforXFW(int adr, int hscx)
+static void
+WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
- int to = 50;
-
- while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "Elsa: waitforXFW timeout\n");
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset|0x80, value);
}
-static inline void
-writehscxCMDR(int adr, int hscx, u_char data)
+static void
+ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
{
- long flags;
-
- save_flags(flags);
- cli();
- waitforCEC(adr, hscx);
- writehscx(adr, hscx, HSCX_CMDR, data);
- restore_flags(flags);
+ readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size);
}
-/*
- * fast interrupt here
- */
-
-
static void
-hscxreport(struct IsdnCardState *sp, int hscx)
+WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
{
- printk(KERN_DEBUG "HSCX %d\n", hscx);
- printk(KERN_DEBUG "ISTA %x\n", readhscx(sp->cfg_reg, hscx, HSCX_ISTA));
- printk(KERN_DEBUG "STAR %x\n", readhscx(sp->cfg_reg, hscx, HSCX_STAR));
- printk(KERN_DEBUG "EXIR %x\n", readhscx(sp->cfg_reg, hscx, HSCX_EXIR));
+ writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size);
}
-void
-elsa_report(struct IsdnCardState *sp)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
- printk(KERN_DEBUG "ISAC\n");
- printk(KERN_DEBUG "ISTA %x\n", readisac(sp->cfg_reg, ISAC_ISTA));
- printk(KERN_DEBUG "STAR %x\n", readisac(sp->cfg_reg, ISAC_STAR));
- printk(KERN_DEBUG "EXIR %x\n", readisac(sp->cfg_reg, ISAC_EXIR));
- hscxreport(sp, 0);
- hscxreport(sp, 1);
+ return (readreg(cs->hw.elsa.ale,
+ cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0)));
}
-/*
- * HSCX stuff goes here
- */
-
static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
- u_char *ptr;
- struct IsdnCardState *sp = hsp->sp;
- long flags;
-
- if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
- debugl1(sp, "hscx_empty_fifo");
-
- if (hsp->rcvidx + count > HSCX_BUFMAX) {
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "hscx_empty_fifo: incoming packet too large");
- writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
- hsp->rcvidx = 0;
- return;
- }
- ptr = hsp->rcvbuf + hsp->rcvidx;
- hsp->rcvidx += count;
- save_flags(flags);
- cli();
- read_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count);
- writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
- restore_flags(flags);
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "hscx_empty_fifo %c cnt %d",
- hsp->hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ writereg(cs->hw.elsa.ale,
+ cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0), value);
}
-static void
-hscx_fill_fifo(struct HscxState *hsp)
+static inline u_char
+readitac(struct IsdnCardState *cs, u_char off)
{
- struct IsdnCardState *sp = hsp->sp;
- int more, count;
- u_char *ptr;
+ register u_char ret;
long flags;
-
- if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
- debugl1(sp, "hscx_fill_fifo");
-
- if (!hsp->tx_skb)
- return;
- if (hsp->tx_skb->len <= 0)
- return;
-
- more = (hsp->mode == 1) ? 1 : 0;
- if (hsp->tx_skb->len > 32) {
- more = !0;
- count = 32;
- } else
- count = hsp->tx_skb->len;
-
- waitforXFW(sp->cfg_reg, hsp->hscx);
save_flags(flags);
cli();
- ptr = hsp->tx_skb->data;
- skb_pull(hsp->tx_skb, count);
- hsp->tx_cnt -= count;
- hsp->count += count;
- write_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count);
- writehscxCMDR(sp->cfg_reg, hsp->hscx, more ? 0x8 : 0xa);
+ byteout(cs->hw.elsa.ale, off);
+ ret = bytein(cs->hw.elsa.itac);
restore_flags(flags);
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "hscx_fill_fifo %c cnt %d",
- hsp->hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ return (ret);
}
static inline void
-hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
-{
- u_char r;
- struct HscxState *hsp = sp->hs + hscx;
- struct sk_buff *skb;
- int count;
- char tmp[32];
-
- if (!hsp->init)
- return;
-
- if (val & 0x80) { /* RME */
-
- r = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RSTA);
- if ((r & 0xf0) != 0xa0) {
- if (!r & 0x80)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "HSCX invalid frame");
- if ((r & 0x40) && hsp->mode)
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX RDO mode=%d",
- hsp->mode);
- debugl1(sp, tmp);
- }
- if (!r & 0x20)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "HSCX CRC error");
- writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
- } else {
- count = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- hscx_empty_fifo(hsp, count);
- if ((count = hsp->rcvidx - 1) > 0) {
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- sprintf(tmp, "HX Frame %d", count);
- debugl1(sp, tmp);
- }
- if (!(skb = dev_alloc_skb(count)))
- printk(KERN_WARNING "Elsa: receive out of memory\n");
- else {
- memcpy(skb_put(skb, count), hsp->rcvbuf, count);
- skb_queue_tail(&hsp->rqueue, skb);
- }
- }
- }
- hsp->rcvidx = 0;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- hscx_empty_fifo(hsp, 32);
- if (hsp->mode == 1) {
- /* receive audio data */
- if (!(skb = dev_alloc_skb(32)))
- printk(KERN_WARNING "elsa: receive out of memory\n");
- else {
- memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
- skb_queue_tail(&hsp->rqueue, skb);
- }
- hsp->rcvidx = 0;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- }
- if (val & 0x10) { /* XPR */
- if (hsp->tx_skb)
- if (hsp->tx_skb->len) {
- hscx_fill_fifo(hsp);
- return;
- } else {
- SET_SKB_FREE(hsp->tx_skb);
- dev_kfree_skb(hsp->tx_skb);
- hsp->count = 0;
- if (hsp->st->l4.l1writewakeup)
- hsp->st->l4.l1writewakeup(hsp->st);
- hsp->tx_skb = NULL;
- }
- if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
- hsp->count = 0;
- hscx_fill_fifo(hsp);
- } else
- hscx_sched_event(hsp, HSCX_XMTBUFREADY);
- }
-}
-
-/*
- * ISAC stuff goes here
- */
-
-static void
-isac_empty_fifo(struct IsdnCardState *sp, int count)
+writeitac(struct IsdnCardState *cs, u_char off, u_char data)
{
- u_char *ptr;
long flags;
- if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
- debugl1(sp, "isac_empty_fifo");
-
- if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
- if (sp->debug & L1_DEB_WARN) {
- char tmp[40];
- sprintf(tmp, "isac_empty_fifo overrun %d",
- sp->rcvidx + count);
- debugl1(sp, tmp);
- }
- writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
- sp->rcvidx = 0;
- return;
- }
- ptr = sp->rcvbuf + sp->rcvidx;
- sp->rcvidx += count;
save_flags(flags);
cli();
- read_fifo_isac(sp->cfg_reg, ptr, count);
- writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
+ byteout(cs->hw.elsa.ale, off);
+ byteout(cs->hw.elsa.itac, data);
restore_flags(flags);
- if (sp->debug & L1_DEB_ISAC_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "isac_empty_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
}
-static void
-isac_fill_fifo(struct IsdnCardState *sp)
+static inline int
+TimerRun(struct IsdnCardState *cs)
{
- int count, more;
- u_char *ptr;
- long flags;
-
- if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
- debugl1(sp, "isac_fill_fifo");
-
- if (!sp->tx_skb)
- return;
-
- count = sp->tx_skb->len;
- if (count <= 0)
- return;
-
- more = 0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- save_flags(flags);
- cli();
- ptr = sp->tx_skb->data;
- skb_pull(sp->tx_skb, count);
- sp->tx_cnt += count;
- write_fifo_isac(sp->cfg_reg, ptr, count);
- writeisac(sp->cfg_reg, ISAC_CMDR, more ? 0x8 : 0xa);
- restore_flags(flags);
- if (sp->debug & L1_DEB_ISAC_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "isac_fill_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
-}
-
-static void
-ph_command(struct IsdnCardState *sp, unsigned int command)
-{
- if (sp->debug & L1_DEB_ISAC) {
- char tmp[32];
- sprintf(tmp, "ph_command %d", command);
- debugl1(sp, tmp);
- }
- writeisac(sp->cfg_reg, ISAC_CIX0, (command << 2) | 3);
+ register u_char v;
+
+ v = bytein(cs->hw.elsa.cfg);
+ if ((cs->subtyp == ELSA_QS1000) || (cs->subtyp == ELSA_QS3000))
+ return (0 == (v & ELSA_TIMER_RUN));
+ else if (cs->subtyp == ELSA_PCC8)
+ return (v & ELSA_TIMER_RUN_PCC8);
+ return (v & ELSA_TIMER_RUN);
}
+/*
+ * fast interrupt HSCX stuff goes here
+ */
-static inline void
-isac_interrupt(struct IsdnCardState *sp, u_char val)
-{
- u_char exval, v1;
- struct sk_buff *skb;
- unsigned int count;
- char tmp[32];
-#if ARCOFI_USE
- struct BufHeader *ibh;
- u_char *ptr;
-#endif
+#define READHSCX(cs, nr, reg) readreg(cs->hw.elsa.ale, \
+ cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.elsa.ale, \
+ cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0), data)
- if (sp->debug & L1_DEB_ISAC) {
- sprintf(tmp, "ISAC interrupt %x", val);
- debugl1(sp, tmp);
- }
- if (val & 0x80) { /* RME */
- exval = readisac(sp->cfg_reg, ISAC_RSTA);
- if ((exval & 0x70) != 0x20) {
- if (exval & 0x40)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC RDO");
- if (!exval & 0x20)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC CRC error");
- writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
- } else {
- count = readisac(sp->cfg_reg, ISAC_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- isac_empty_fifo(sp, count);
- if ((count = sp->rcvidx) > 0) {
- sp->rcvidx = 0;
- if (!(skb = alloc_skb(count, GFP_ATOMIC)))
- printk(KERN_WARNING "Elsa: D receive out of memory\n");
- else {
- memcpy(skb_put(skb, count), sp->rcvbuf, count);
- skb_queue_tail(&sp->rq, skb);
- }
- }
- }
- sp->rcvidx = 0;
- isac_sched_event(sp, ISAC_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- isac_empty_fifo(sp, 32);
- }
- if (val & 0x20) { /* RSC */
- /* never */
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC RSC interrupt");
- }
- if (val & 0x10) { /* XPR */
- if (sp->tx_skb)
- if (sp->tx_skb->len) {
- isac_fill_fifo(sp);
- goto afterXPR;
- } else {
- SET_SKB_FREE(sp->tx_skb);
- dev_kfree_skb(sp->tx_skb);
- sp->tx_cnt = 0;
- sp->tx_skb = NULL;
- }
- if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
- sp->tx_cnt = 0;
- isac_fill_fifo(sp);
- } else
- isac_sched_event(sp, ISAC_XMTBUFREADY);
- }
- afterXPR:
- if (val & 0x04) { /* CISQ */
- sp->ph_state = (readisac(sp->cfg_reg, ISAC_CIX0) >> 2)
- & 0xf;
- if (sp->debug & L1_DEB_ISAC) {
- sprintf(tmp, "l1state %d", sp->ph_state);
- debugl1(sp, tmp);
- }
- isac_new_ph(sp);
- }
- if (val & 0x02) { /* SIN */
- /* never */
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC SIN interrupt");
- }
- if (val & 0x01) { /* EXI */
- exval = readisac(sp->cfg_reg, ISAC_EXIR);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "ISAC EXIR %02x", exval);
- debugl1(sp, tmp);
- }
- if (exval & 0x08) {
- v1 = readisac(sp->cfg_reg, ISAC_MOSR);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "ISAC MOSR %02x", v1);
- debugl1(sp, tmp);
- }
-#if ARCOFI_USE
- if (v1 & 0x08) {
- if (!sp->mon_rx)
- if (BufPoolGet(&(sp->mon_rx), &(sp->rbufpool),
- GFP_ATOMIC, (void *) 1, 3)) {
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC MON RX out of buffers!");
- writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
- goto afterMONR0;
- } else
- sp->mon_rxp = 0;
- ibh = sp->mon_rx;
- ptr = DATAPTR(ibh);
- ptr += sp->mon_rxp;
- sp->mon_rxp++;
- if (sp->mon_rxp >= 3072) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
- sp->mon_rxp = 0;
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC MON RX overflow!");
- goto afterMONR0;
- }
- *ptr = readisac(sp->cfg_reg, ISAC_MOR0);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "ISAC MOR0 %02x", *ptr);
- debugl1(sp, tmp);
- }
- }
- afterMONR0:
- if (v1 & 0x80) {
- if (!sp->mon_rx)
- if (BufPoolGet(&(sp->mon_rx), &(sp->rbufpool),
- GFP_ATOMIC, (void *) 1, 3)) {
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC MON RX out of buffers!");
- writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
- goto afterMONR1;
- } else
- sp->mon_rxp = 0;
- ibh = sp->mon_rx;
- ptr = DATAPTR(ibh);
- ptr += sp->mon_rxp;
- sp->mon_rxp++;
- if (sp->mon_rxp >= 3072) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
- sp->mon_rxp = 0;
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC MON RX overflow!");
- goto afterMONR1;
- }
- *ptr = readisac(sp->cfg_reg, ISAC_MOR1);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "ISAC MOR1 %02x", *ptr);
- debugl1(sp, tmp);
- }
- }
- afterMONR1:
- if (v1 & 0x04) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
- sp->mon_rx->datasize = sp->mon_rxp;
- sp->mon_flg |= MON0_RX;
- }
- if (v1 & 0x40) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
- sp->mon_rx->datasize = sp->mon_rxp;
- sp->mon_flg |= MON1_RX;
- }
- if (v1 == 0x02) {
- ibh = sp->mon_tx;
- if (!ibh) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
- goto AfterMOX0;
- }
- count = ibh->datasize - sp->mon_txp;
- if (count <= 0) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0x0f);
- BufPoolRelease(sp->mon_tx);
- sp->mon_tx = NULL;
- sp->mon_txp = 0;
- sp->mon_flg |= MON0_TX;
- goto AfterMOX0;
- }
- ptr = DATAPTR(ibh);
- ptr += sp->mon_txp;
- sp->mon_txp++;
- writeisac(sp->cfg_reg, ISAC_MOX0, *ptr);
- }
- AfterMOX0:
- if (v1 == 0x20) {
- ibh = sp->mon_tx;
- if (!ibh) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
- goto AfterMOX1;
- }
- count = ibh->datasize - sp->mon_txp;
- if (count <= 0) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0xf0);
- BufPoolRelease(sp->mon_tx);
- sp->mon_tx = NULL;
- sp->mon_txp = 0;
- sp->mon_flg |= MON1_TX;
- goto AfterMOX1;
- }
- ptr = DATAPTR(ibh);
- ptr += sp->mon_txp;
- sp->mon_txp++;
- writeisac(sp->cfg_reg, ISAC_MOX1, *ptr);
- }
- AfterMOX1:
-#endif
- }
- }
-}
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.elsa.ale, \
+ cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt)
-static inline void
-hscx_int_main(struct IsdnCardState *sp, u_char val)
-{
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.elsa.ale, \
+ cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt)
- u_char exval;
- struct HscxState *hsp;
- char tmp[32];
-
- if (val & 0x01) {
- hsp = sp->hs + 1;
- exval = readhscx(sp->cfg_reg, 1, HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (hsp->tx_skb) {
- skb_push(hsp->tx_skb, hsp->count);
- hsp->tx_cnt += hsp->count;
- hsp->count = 0;
- }
- writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x01);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
- debugl1(sp, tmp);
- }
- }
- } else if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX B EXIR %x", exval);
- debugl1(sp, tmp);
- }
- }
- if (val & 0xf8) {
- if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX B interrupt %x", val);
- debugl1(sp, tmp);
- }
- hscx_interrupt(sp, val, 1);
- }
- if (val & 0x02) {
- hsp = sp->hs;
- exval = readhscx(sp->cfg_reg, 0, HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (hsp->tx_skb) {
- skb_push(hsp->tx_skb, hsp->count);
- hsp->tx_cnt += hsp->count;
- hsp->count = 0;
- }
- writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x01);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
- debugl1(sp, tmp);
- }
- }
- } else if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX A EXIR %x", exval);
- debugl1(sp, tmp);
- }
- }
- if (val & 0x04) {
- exval = readhscx(sp->cfg_reg, 0, HSCX_ISTA);
- if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX A interrupt %x", exval);
- debugl1(sp, tmp);
- }
- hscx_interrupt(sp, exval, 0);
- }
-}
+#include "hscx_irq.c"
static void
elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
- struct IsdnCardState *sp;
+ struct IsdnCardState *cs = dev_id;
u_char val;
+ int icnt=20;
- sp = (struct IsdnCardState *) dev_id;
-
- if (!sp) {
+ if (!cs) {
printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
return;
}
-#ifdef CONFIG_HISAX_ELSA_PCC
- INT_RESTART:
- if (!TimerRun(sp)) {
- /* Timer Restart */
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- if (!(sp->counter++ & 0x3f)) {
- /* Call LEDs all 64 tics */
- elsa_led_handler(sp);
- }
- }
-#endif
- val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
+ val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
if (val) {
- hscx_int_main(sp, val);
+ hscx_int_main(cs, val);
}
- val = readisac(sp->cfg_reg, ISAC_ISTA);
+ val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA);
Start_ISAC:
if (val) {
- isac_interrupt(sp, val);
+ isac_interrupt(cs, val);
}
-#ifdef CONFIG_HISAX_ELSA_PCC
- if (!TimerRun(sp))
- goto INT_RESTART;
-#endif
- val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
- if (val) {
- if (sp->debug & L1_DEB_HSCX)
- debugl1(sp, "HSCX IntStat after IntRoutine");
+ val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
+ if (val && icnt) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX IntStat after IntRoutine");
+ icnt--;
goto Start_HSCX;
}
- val = readisac(sp->cfg_reg, ISAC_ISTA);
- if (val) {
- if (sp->debug & L1_DEB_ISAC)
- debugl1(sp, "ISAC IntStat after IntRoutine");
+ val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA);
+ if (val && icnt) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ISAC IntStat after IntRoutine");
+ icnt--;
goto Start_ISAC;
}
- writehscx(sp->cfg_reg, 0, HSCX_MASK, 0xFF);
- writehscx(sp->cfg_reg, 1, HSCX_MASK, 0xFF);
- writeisac(sp->cfg_reg, ISAC_MASK, 0xFF);
-#ifdef CONFIG_HISAX_ELSA_PCC
- if (sp->subtyp == ELSA_QS1000) {
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
+ if (!icnt)
+ printk(KERN_WARNING"ELSA IRQ LOOP\n");
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0xFF);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0xFF);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0xFF);
+ if (cs->hw.elsa.status & ELSA_TIMER_AKTIV) {
+ if (!TimerRun(cs)) {
+ /* Timer Restart */
+ byteout(cs->hw.elsa.timer, 0);
+ cs->hw.elsa.counter++;
+ }
}
-#endif
- writehscx(sp->cfg_reg, 0, HSCX_MASK, 0x0);
- writehscx(sp->cfg_reg, 1, HSCX_MASK, 0x0);
- writeisac(sp->cfg_reg, ISAC_MASK, 0x0);
+ if (cs->hw.elsa.trig)
+ byteout(cs->hw.elsa.trig, 0x00);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0x0);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0x0);
}
-
static void
-initisac(struct IsdnCardState *sp)
+elsa_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
{
- unsigned int adr = sp->cfg_reg;
-
- /* Elsa IOM 2 Mode */
- writeisac(adr, ISAC_MASK, 0xff);
- writeisac(adr, ISAC_ADF2, 0x80);
- writeisac(adr, ISAC_SQXR, 0x2f);
- writeisac(adr, ISAC_SPCR, 0x00);
- writeisac(adr, ISAC_STCR, 0x70);
- writeisac(adr, ISAC_MODE, 0xc9);
- writeisac(adr, ISAC_TIMR, 0x00);
- writeisac(adr, ISAC_ADF1, 0x00);
- writeisac(adr, ISAC_CIX0, (1 << 2) | 3);
- writeisac(adr, ISAC_MASK, 0xff);
- writeisac(adr, ISAC_MASK, 0x0);
-}
+ struct IsdnCardState *cs = dev_id;
+ u_char ista,val;
+ char tmp[64];
+ int icnt=20;
-static void
-modehscx(struct HscxState *hs, int mode, int ichan)
-{
- struct IsdnCardState *sp = hs->sp;
- int hscx = hs->hscx;
-
- if (sp->debug & L1_DEB_HSCX) {
- char tmp[40];
- sprintf(tmp, "hscx %c mode %d ichan %d",
- 'A' + hscx, mode, ichan);
- debugl1(sp, tmp);
+ if (!cs) {
+ printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
+ return;
}
- hs->mode = mode;
- writehscx(sp->cfg_reg, hscx, HSCX_CCR1, 0x85);
- writehscx(sp->cfg_reg, hscx, HSCX_XAD1, 0xFF);
- writehscx(sp->cfg_reg, hscx, HSCX_XAD2, 0xFF);
- writehscx(sp->cfg_reg, hscx, HSCX_RAH2, 0xFF);
- writehscx(sp->cfg_reg, hscx, HSCX_XBCH, 0x0);
- writehscx(sp->cfg_reg, hscx, HSCX_RLCR, 0x0);
- writehscx(sp->cfg_reg, hscx, HSCX_CCR2, 0x30);
-
- switch (mode) {
- case (0):
- writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0xff);
- writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0xff);
- writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
- writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
- writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0x84);
- break;
- case (1):
- if (ichan == 0) {
- writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x2f);
- writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x2f);
- } else {
- writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x3);
- writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x3);
- }
- writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
- writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
- writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0xe4);
- writehscx(sp->cfg_reg, hscx, HSCX_CMDR, 0x41);
- break;
- case (2):
- if (ichan == 0) {
- writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x2f);
- writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x2f);
- } else {
- writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x3);
- writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x3);
- }
- writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
- writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
- writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0x8c);
- writehscx(sp->cfg_reg, hscx, HSCX_CMDR, 0x41);
- break;
+ if ((cs->typ == ISDN_CTYPE_ELSA_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 "Elsa: card not available!\n");
+ return;
+ }
+ ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA);
+Start_IPAC:
+ if (cs->debug & L1_DEB_IPAC) {
+ sprintf(tmp, "IPAC ISTA %02X", ista);
+ debugl1(cs, tmp);
+ }
+ if (ista & 0x0f) {
+ val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
+ if (ista & 0x01)
+ val |= 0x01;
+ if (ista & 0x04)
+ val |= 0x02;
+ if (ista & 0x08)
+ val |= 0x04;
+ if (val)
+ hscx_int_main(cs, val);
+ }
+ if (ista & 0x20) {
+ val = 0xfe & readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA + 0x80);
+ if (val) {
+ isac_interrupt(cs, val);
+ }
+ }
+ if (ista & 0x10) {
+ val = 0x01;
+ isac_interrupt(cs, val);
}
- writehscx(sp->cfg_reg, hscx, HSCX_ISTA, 0x00);
+ ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA);
+ if ((ista & 0x3f) && icnt) {
+ icnt--;
+ goto Start_IPAC;
+ }
+ if (!icnt)
+ printk(KERN_WARNING "ELSA IRQ LOOP\n");
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xFF);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xC0);
}
void
-release_io_elsa(struct IsdnCard *card)
+release_io_elsa(struct IsdnCardState *cs)
{
int bytecnt = 8;
- if (card->sp->subtyp == ELSA_PCFPRO)
+ del_timer(&cs->hw.elsa.tl);
+ if (cs->hw.elsa.ctrl)
+ byteout(cs->hw.elsa.ctrl, 0); /* LEDs Out */
+ if ((cs->subtyp == ELSA_PCFPRO) ||
+ (cs->subtyp == ELSA_QS3000) ||
+ (cs->subtyp == ELSA_PCF))
bytecnt = 16;
- if (card->sp->cfg_reg)
- release_region(card->sp->cfg_reg, bytecnt);
-}
-
-static void
-reset_elsa(struct IsdnCardState *sp)
-{
-#ifdef CONFIG_HISAX_ELSA_PCC
- /* Wait 1 Timer */
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- while (TimerRun(sp));
- byteout(sp->cfg_reg + CARD_CONTROL, 0x00); /* Reset On */
- /* Wait 1 Timer */
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- while (TimerRun(sp));
- byteout(sp->cfg_reg + CARD_CONTROL, ISDN_RESET); /* Reset Off */
- /* Wait 1 Timer */
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- while (TimerRun(sp));
- byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
-#endif
+ if (cs->subtyp == ELSA_QS1000PCI) {
+ byteout(cs->hw.elsa.cfg + 0x4c, 0x01); /* disable IRQ */
+ bytecnt = 2;
+ release_region(cs->hw.elsa.cfg, 0x80);
+ }
+ if (cs->hw.elsa.base)
+ release_region(cs->hw.elsa.base, bytecnt);
}
static void
-clear_pending_ints(struct IsdnCardState *sp)
+reset_elsa(struct IsdnCardState *cs)
{
-#ifdef CONFIG_HISAX_ELSA_PCMCIA
- int val;
- char tmp[64];
+ long flags;
- val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
- sprintf(tmp, "HSCX B ISTA %x", val);
- debugl1(sp, tmp);
- if (val & 0x01) {
- val = readhscx(sp->cfg_reg, 1, HSCX_EXIR);
- sprintf(tmp, "HSCX B EXIR %x", val);
- debugl1(sp, tmp);
- } else if (val & 0x02) {
- val = readhscx(sp->cfg_reg, 0, HSCX_EXIR);
- sprintf(tmp, "HSCX A EXIR %x", val);
- debugl1(sp, tmp);
+ if (cs->hw.elsa.timer) {
+ /* Wait 1 Timer */
+ byteout(cs->hw.elsa.timer, 0);
+ while (TimerRun(cs));
+ cs->hw.elsa.ctrl_reg |= 0x50;
+ cs->hw.elsa.ctrl_reg &= ~ELSA_ISDN_RESET; /* Reset On */
+ byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+ /* Wait 1 Timer */
+ byteout(cs->hw.elsa.timer, 0);
+ while (TimerRun(cs));
+ cs->hw.elsa.ctrl_reg |= ELSA_ISDN_RESET; /* Reset Off */
+ byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+ /* Wait 1 Timer */
+ byteout(cs->hw.elsa.timer, 0);
+ while (TimerRun(cs));
+ if (cs->hw.elsa.trig)
+ byteout(cs->hw.elsa.trig, 0xff);
}
- val = readhscx(sp->cfg_reg, 0, HSCX_ISTA);
- sprintf(tmp, "HSCX A ISTA %x", val);
- debugl1(sp, tmp);
- val = readhscx(sp->cfg_reg, 1, HSCX_STAR);
- sprintf(tmp, "HSCX B STAR %x", val);
- debugl1(sp, tmp);
- val = readhscx(sp->cfg_reg, 0, HSCX_STAR);
- sprintf(tmp, "HSCX A STAR %x", val);
- debugl1(sp, tmp);
- val = readisac(sp->cfg_reg, ISAC_STAR);
- sprintf(tmp, "ISAC STAR %x", val);
- debugl1(sp, tmp);
- val = readisac(sp->cfg_reg, ISAC_MODE);
- sprintf(tmp, "ISAC MODE %x", val);
- debugl1(sp, tmp);
- val = readisac(sp->cfg_reg, ISAC_ADF2);
- sprintf(tmp, "ISAC ADF2 %x", val);
- debugl1(sp, tmp);
- val = readisac(sp->cfg_reg, ISAC_ISTA);
- sprintf(tmp, "ISAC ISTA %x", val);
- debugl1(sp, tmp);
- if (val & 0x01) {
- val = readisac(sp->cfg_reg, ISAC_EXIR);
- sprintf(tmp, "ISAC EXIR %x", val);
- debugl1(sp, tmp);
- } else if (val & 0x04) {
- val = readisac(sp->cfg_reg, ISAC_CIR0);
- sprintf(tmp, "ISAC CIR0 %x", val);
- debugl1(sp, tmp);
- }
-#endif
- writehscx(sp->cfg_reg, 0, HSCX_MASK, 0xFF);
- writehscx(sp->cfg_reg, 1, HSCX_MASK, 0xFF);
- writeisac(sp->cfg_reg, ISAC_MASK, 0xFF);
-#ifdef CONFIG_HISAX_ELSA_PCC
- if (sp->subtyp == ELSA_QS1000) {
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
+ if (cs->subtyp == ELSA_QS1000PCI) {
+ save_flags(flags);
+ sti();
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */
+ schedule();
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */
+ schedule();
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0);
+ schedule();
+ restore_flags(flags);
+ byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */
}
-#endif
- writehscx(sp->cfg_reg, 0, HSCX_MASK, 0x0);
- writehscx(sp->cfg_reg, 1, HSCX_MASK, 0x0);
- writeisac(sp->cfg_reg, ISAC_MASK, 0x0);
- writeisac(sp->cfg_reg, ISAC_CMDR, 0x41);
+}
+
+const u_char ARCOFI_VERSION[] = {2,0xa0,0};
+const u_char ARCOFI_COP_5[] = {4,0xa1,0x25,0xbb,0x4a}; /* GTX */
+const u_char ARCOFI_COP_6[] = {6,0xa1,0x26,0,0,0x82,0x7c}; /* GRL GRH */
+const u_char ARCOFI_COP_7[] = {4,0xa1,0x27,0x80,0x80}; /* GZ */
+const u_char ARCOFI_COP_8[] = {10,0xa1,0x28,0x49,0x31,0x8,0x13,0x6e,0x88,0x2a,0x61}; /* TX */
+const u_char ARCOFI_COP_9[] = {10,0xa1,0x29,0x80,0xcb,0x9e,0x88,0x00,0xc8,0xd8,0x80}; /* RX */
+const u_char ARCOFI_XOP_0[] = {2,0xa1,0x30}; /* PWR Down */
+const u_char ARCOFI_XOP_1[] = {2,0xa1,0x31}; /* PWR Down */
+const u_char ARCOFI_XOP_F[] = {2,0xa1,0x3f}; /* PWR Down */
+const u_char ARCOFI_SOP_F[] = {10,0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12};
+
+static void
+init_arcofi(struct IsdnCardState *cs) {
+ send_arcofi(cs, ARCOFI_COP_5);
+ send_arcofi(cs, ARCOFI_COP_6);
+ send_arcofi(cs, ARCOFI_COP_7);
+ send_arcofi(cs, ARCOFI_COP_8);
+ send_arcofi(cs, ARCOFI_COP_9);
+ send_arcofi(cs, ARCOFI_SOP_F);
+ send_arcofi(cs, ARCOFI_XOP_F);
}
static void
-check_arcofi(struct IsdnCardState *sp)
+check_arcofi(struct IsdnCardState *cs)
{
-#if 0
- u_char val;
+#if ARCOFI_USE
+ int arcofi_present = 0;
char tmp[40];
char *t;
- long flags;
u_char *p;
- if (BufPoolGet(&(sp->mon_tx), &(sp->sbufpool),
- GFP_ATOMIC, (void *) 1, 3)) {
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC MON TX out of buffers!");
- return;
- } else
- sp->mon_txp = 0;
- p = DATAPTR(sp->mon_tx);
- *p++ = 0xa0;
- *p++ = 0x0;
- sp->mon_tx->datasize = 2;
- sp->mon_txp = 1;
- sp->mon_flg = 0;
- writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
- val = readisac(sp->cfg_reg, ISAC_MOSR);
- writeisac(sp->cfg_reg, ISAC_MOX1, 0xa0);
- writeisac(sp->cfg_reg, ISAC_MOCR, 0xb0);
- save_flags(flags);
- sti();
- HZDELAY(3);
- restore_flags(flags);
- if (sp->mon_flg & MON1_TX) {
- if (sp->mon_flg & MON1_RX) {
- sprintf(tmp, "Arcofi response received %d bytes", sp->mon_rx->datasize);
- debugl1(sp, tmp);
- p = DATAPTR(sp->mon_rx);
+ if (!cs->mon_tx)
+ if (!(cs->mon_tx=kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ISAC MON TX out of buffers!");
+ return;
+ }
+ send_arcofi(cs, ARCOFI_VERSION);
+ if (test_and_clear_bit(HW_MON1_TX_END, &cs->HW_Flags)) {
+ if (test_and_clear_bit(HW_MON1_RX_END, &cs->HW_Flags)) {
+ sprintf(tmp, "Arcofi response received %d bytes", cs->mon_rxp);
+ debugl1(cs, tmp);
+ p = cs->mon_rx;
t = tmp;
t += sprintf(tmp, "Arcofi data");
- QuickHex(t, p, sp->mon_rx->datasize);
- debugl1(sp, tmp);
- BufPoolRelease(sp->mon_rx);
- sp->mon_rx = NULL;
- sp->mon_rxp = 0;
- sp->mon_flg = 0;
+ QuickHex(t, p, cs->mon_rxp);
+ debugl1(cs, tmp);
+ if ((cs->mon_rxp == 2) && (cs->mon_rx[0] == 0xa0)) {
+ switch(cs->mon_rx[1]) {
+ case 0x80:
+ debugl1(cs, "Arcofi 2160 detected");
+ arcofi_present = 1;
+ break;
+ case 0x82:
+ debugl1(cs, "Arcofi 2165 detected");
+ arcofi_present = 2;
+ break;
+ case 0x84:
+ debugl1(cs, "Arcofi 2163 detected");
+ arcofi_present = 3;
+ break;
+ default:
+ debugl1(cs, "unknown Arcofi response");
+ break;
+ }
+ } else
+ debugl1(cs, "undefined Monitor response");
+ cs->mon_rxp = 0;
}
- } else if (sp->mon_tx) {
- BufPoolRelease(sp->mon_tx);
- sp->mon_tx = NULL;
- sp->mon_txp = 0;
+ } else if (cs->mon_tx) {
sprintf(tmp, "Arcofi not detected");
- debugl1(sp, tmp);
+ debugl1(cs, tmp);
+ }
+ if (arcofi_present) {
+ if (cs->subtyp==ELSA_QS1000) {
+ cs->subtyp = ELSA_QS3000;
+ printk(KERN_INFO
+ "Elsa: %s detected modem at 0x%x\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base+8);
+ release_region(cs->hw.elsa.base, 8);
+ if (check_region(cs->hw.elsa.base, 16)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base + 8,
+ cs->hw.elsa.base + 16);
+ } else
+ request_region(cs->hw.elsa.base, 16,
+ "elsa isdn modem");
+ } else if (cs->subtyp==ELSA_PCC16) {
+ cs->subtyp = ELSA_PCF;
+ printk(KERN_INFO
+ "Elsa: %s detected modem at 0x%x\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base+8);
+ release_region(cs->hw.elsa.base, 8);
+ if (check_region(cs->hw.elsa.base, 16)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base + 8,
+ cs->hw.elsa.base + 16);
+ } else
+ request_region(cs->hw.elsa.base, 16,
+ "elsa isdn modem");
+ } else
+ printk(KERN_INFO
+ "Elsa: %s detected modem at 0x%x\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base+8);
+ init_arcofi(cs);
}
- sp->mon_flg = 0;
#endif
}
-int
-initelsa(struct IsdnCardState *sp)
+static void
+elsa_led_handler(struct IsdnCardState *cs)
{
- int ret, irq_cnt, cnt = 3;
- long flags;
+ int blink = 0;
- irq_cnt = kstat_irqs(sp->irq);
- printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq, irq_cnt);
- ret = get_irq(sp->cardnr, &elsa_interrupt);
-#ifdef CONFIG_HISAX_ELSA_PCC
- byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
-#endif
- while (ret && cnt) {
- sp->counter = 0;
- clear_pending_ints(sp);
- initisac(sp);
- sp->modehscx(sp->hs, 0, 0);
- sp->modehscx(sp->hs + 1, 0, 0);
- save_flags(flags);
- sp->counter = 0;
- sti();
-#ifdef CONFIG_HISAX_ELSA_PCC
- byteout(sp->cfg_reg + CARD_CONTROL, ISDN_RESET | ENABLE_TIM_INT);
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + (110 * HZ) / 1000; /* Timeout 110ms */
- schedule();
- restore_flags(flags);
- printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n",
- sp->counter);
- if (abs(sp->counter - 13) < 3) {
- printk(KERN_INFO "Elsa: timer and irq OK\n");
- } else {
- printk(KERN_WARNING
- "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n",
- sp->counter, sp->irq);
- }
-#endif
- printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq,
- kstat_irqs(sp->irq));
- if (kstat_irqs(sp->irq) == irq_cnt) {
- printk(KERN_WARNING
- "Elsa: IRQ(%d) getting no interrupts during init %d\n",
- sp->irq, 4 - cnt);
- if (cnt == 1) {
- free_irq(sp->irq, sp);
- return (0);
+ if ((cs->subtyp == ELSA_PCMCIA) &&
+ (cs->subtyp == ELSA_QS1000PCI))
+ return;
+ del_timer(&cs->hw.elsa.tl);
+ if (cs->hw.elsa.status & ELSA_ASSIGN)
+ cs->hw.elsa.ctrl_reg |= ELSA_STAT_LED;
+ else if (cs->hw.elsa.status & ELSA_BAD_PWR)
+ cs->hw.elsa.ctrl_reg &= ~ELSA_STAT_LED;
+ else {
+ cs->hw.elsa.ctrl_reg ^= ELSA_STAT_LED;
+ blink = 250;
+ }
+ if (cs->hw.elsa.status & 0xf000)
+ cs->hw.elsa.ctrl_reg |= ELSA_LINE_LED;
+ else if (cs->hw.elsa.status & 0x0f00) {
+ cs->hw.elsa.ctrl_reg ^= ELSA_LINE_LED;
+ blink = 500;
+ } else
+ cs->hw.elsa.ctrl_reg &= ~ELSA_LINE_LED;
+
+ byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+ if (blink) {
+ init_timer(&cs->hw.elsa.tl);
+ cs->hw.elsa.tl.expires = jiffies + ((blink * HZ) / 1000);
+ add_timer(&cs->hw.elsa.tl);
+ }
+}
+
+static int
+Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ int pwr, ret = 0;
+ long flags;
+
+ switch (mt) {
+ case CARD_RESET:
+ reset_elsa(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_elsa(cs);
+ return(0);
+ case CARD_SETIRQ:
+ if (cs->subtyp == ELSA_QS1000PCI)
+ ret = request_irq(cs->irq, &elsa_interrupt_ipac,
+ I4L_IRQ_FLAG, "HiSax", cs);
+ else
+ ret = request_irq(cs->irq, &elsa_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs);
+ return(ret);
+ case CARD_INIT:
+ if (cs->hw.elsa.trig)
+ byteout(cs->hw.elsa.trig, 0xff);
+ clear_pending_isac_ints(cs);
+ clear_pending_hscx_ints(cs);
+ initisac(cs);
+ inithscx(cs);
+ if (cs->subtyp == ELSA_QS1000) {
+ byteout(cs->hw.elsa.timer, 0);
+ byteout(cs->hw.elsa.trig, 0xff);
+ }
+ return(0);
+ case CARD_TEST:
+ if ((cs->subtyp != ELSA_PCMCIA) &&
+ (cs->subtyp != ELSA_QS1000PCI)) {
+ save_flags(flags);
+ cs->hw.elsa.counter = 0;
+ sti();
+ cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT;
+ cs->hw.elsa.status |= ELSA_TIMER_AKTIV;
+ byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+ byteout(cs->hw.elsa.timer, 0);
+ } else
+ return(0);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + (110 * HZ) / 1000; /* Timeout 110ms */
+ schedule();
+ restore_flags(flags);
+ cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
+ byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+ 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) {
+ printk(KERN_INFO "Elsa: timer and irq OK\n");
+ ret = 0;
} else {
- reset_elsa(sp);
- cnt--;
+ printk(KERN_WARNING
+ "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n",
+ cs->hw.elsa.counter, cs->irq);
+ ret = 1;
}
- } else {
- check_arcofi(sp);
- cnt = 0;
- }
+ check_arcofi(cs);
+ elsa_led_handler(cs);
+ return(ret);
+ case MDL_REMOVE_REQ:
+ cs->hw.elsa.status &= 0;
+ break;
+ case MDL_ASSIGN_REQ:
+ cs->hw.elsa.status |= ELSA_ASSIGN;
+ break;
+ case MDL_INFO_SETUP:
+ if ((int) arg)
+ cs->hw.elsa.status |= 0x0200;
+ else
+ cs->hw.elsa.status |= 0x0100;
+ break;
+ case MDL_INFO_CONN:
+ if ((int) arg)
+ cs->hw.elsa.status |= 0x2000;
+ else
+ cs->hw.elsa.status |= 0x1000;
+ break;
+ case MDL_INFO_REL:
+ if ((int) arg) {
+ cs->hw.elsa.status &= ~0x2000;
+ cs->hw.elsa.status &= ~0x0200;
+ } else {
+ cs->hw.elsa.status &= ~0x1000;
+ cs->hw.elsa.status &= ~0x0100;
+ }
+ break;
+ case CARD_AUX_IND:
+ break;
}
- sp->counter = 0;
- return (ret);
+ pwr = bytein(cs->hw.elsa.ale);
+ if (pwr & 0x08)
+ cs->hw.elsa.status |= ELSA_BAD_PWR;
+ else
+ cs->hw.elsa.status &= ~ELSA_BAD_PWR;
+ elsa_led_handler(cs);
+ return(ret);
}
-#ifdef CONFIG_HISAX_ELSA_PCC
static unsigned char
-probe_elsa_adr(unsigned int adr)
+probe_elsa_adr(unsigned int adr, int typ)
{
int i, in1, in2, p16_1 = 0, p16_2 = 0, p8_1 = 0, p8_2 = 0, pc_1 = 0,
pc_2 = 0, pfp_1 = 0, pfp_2 = 0;
long flags;
- if (check_region(adr, 8)) {
+ /* In case of the elsa pcmcia card, this region is in use,
+ reserved for us by the card manager. So we do not check it
+ here, it would fail. */
+ if (typ != ISDN_CTYPE_ELSA_PCMCIA && check_region(adr, 8)) {
printk(KERN_WARNING
"Elsa: Probing Port 0x%x: already in use\n",
adr);
@@ -1251,8 +736,8 @@ probe_elsa_adr(unsigned int adr)
save_flags(flags);
cli();
for (i = 0; i < 16; i++) {
- in1 = inb(adr + CARD_CONFIG); /* 'toggelt' bei */
- in2 = inb(adr + CARD_CONFIG); /* jedem Zugriff */
+ in1 = inb(adr + ELSA_CONFIG); /* 'toggelt' bei */
+ in2 = inb(adr + ELSA_CONFIG); /* jedem Zugriff */
p16_1 += 0x04 & in1;
p16_2 += 0x04 & in2;
p8_1 += 0x02 & in1;
@@ -1283,205 +768,295 @@ probe_elsa_adr(unsigned int adr)
}
static unsigned int
-probe_elsa(struct IsdnCardState *sp)
+probe_elsa(struct IsdnCardState *cs)
{
int i;
unsigned int CARD_portlist[] =
{0x160, 0x170, 0x260, 0x360, 0};
for (i = 0; CARD_portlist[i]; i++) {
- if ((sp->subtyp = probe_elsa_adr(CARD_portlist[i])))
+ if ((cs->subtyp = probe_elsa_adr(CARD_portlist[i], cs->typ)))
break;
}
return (CARD_portlist[i]);
}
-#endif
+
+static int pci_index __initdata = 0;
int
setup_elsa(struct IsdnCard *card)
{
-#ifdef CONFIG_HISAX_ELSA_PCC
long flags;
-#endif
int bytecnt;
- u_char val, verA, verB;
- struct IsdnCardState *sp = card->sp;
+ u_char val;
+ struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, Elsa_revision);
- printk(KERN_NOTICE "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
-#ifdef CONFIG_HISAX_ELSA_PCC
- if (sp->typ == ISDN_CTYPE_ELSA) {
- sp->cfg_reg = card->para[0];
+ printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
+ cs->hw.elsa.ctrl_reg = 0;
+ cs->hw.elsa.status = 0;
+ if (cs->typ == ISDN_CTYPE_ELSA) {
+ cs->hw.elsa.base = card->para[0];
printk(KERN_INFO "Elsa: Microlink IO probing\n");
- if (sp->cfg_reg) {
- if (!(sp->subtyp = probe_elsa_adr(sp->cfg_reg))) {
+ if (cs->hw.elsa.base) {
+ if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
+ cs->typ))) {
printk(KERN_WARNING
"Elsa: no Elsa Microlink at 0x%x\n",
- sp->cfg_reg);
+ cs->hw.elsa.base);
return (0);
}
} else
- sp->cfg_reg = probe_elsa(sp);
- if (sp->cfg_reg) {
- val = bytein(sp->cfg_reg + CARD_CONFIG);
- if (sp->subtyp == ELSA_PC) {
+ cs->hw.elsa.base = probe_elsa(cs);
+ if (cs->hw.elsa.base) {
+ cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+ cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+ cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+ cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+ val = bytein(cs->hw.elsa.cfg);
+ if (cs->subtyp == ELSA_PC) {
const u_char CARD_IrqTab[8] =
{7, 3, 5, 9, 0, 0, 0, 0};
- sp->irq = CARD_IrqTab[(val & IRQ_INDEX_PC) >> 2];
- } else if (sp->subtyp == ELSA_PCC8) {
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
+ } else if (cs->subtyp == ELSA_PCC8) {
const u_char CARD_IrqTab[8] =
{7, 3, 5, 9, 0, 0, 0, 0};
- sp->irq = CARD_IrqTab[(val & IRQ_INDEX_PCC8) >> 4];
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
} else {
const u_char CARD_IrqTab[8] =
{15, 10, 15, 3, 11, 5, 11, 9};
- sp->irq = CARD_IrqTab[(val & IRQ_INDEX) >> 3];
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
}
- val = bytein(sp->cfg_reg + CARD_ALE) & 0x7;
+ val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
if (val < 3)
val |= 8;
val += 'A' - 3;
if (val == 'B' || val == 'C')
val ^= 1;
- if ((sp->subtyp == ELSA_PCFPRO) && (val = 'G'))
+ if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
val = 'C';
printk(KERN_INFO
"Elsa: %s found at 0x%x Rev.:%c IRQ %d\n",
- Elsa_Types[sp->subtyp],
- sp->cfg_reg,
- val, sp->irq);
- val = bytein(sp->cfg_reg + CARD_ALE) & 0x08;
- if (val)
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ val, cs->irq);
+ val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
+ if (val) {
printk(KERN_WARNING
"Elsa: Microlink S0 bus power bad\n");
+ cs->hw.elsa.status |= ELSA_BAD_PWR;
+ }
} else {
printk(KERN_WARNING
"No Elsa Microlink found\n");
return (0);
}
- } else if (sp->typ == ISDN_CTYPE_ELSA_QS1000) {
- sp->cfg_reg = card->para[1];
- sp->irq = card->para[0];
- sp->subtyp = ELSA_QS1000;
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
+ cs->hw.elsa.base = card->para[1];
+ cs->irq = card->para[0];
+ cs->subtyp = ELSA_QS1000;
+ cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+ cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+ cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
printk(KERN_INFO
- "Elsa: %s found at 0x%x IRQ %d\n",
- Elsa_Types[sp->subtyp],
- sp->cfg_reg,
- sp->irq);
- } else
- return (0);
-#endif
-#ifdef CONFIG_HISAX_ELSA_PCMCIA
- if (sp->typ == ISDN_CTYPE_ELSA_QS1000) {
- sp->cfg_reg = card->para[1];
- sp->irq = card->para[0];
- sp->subtyp = ELSA_PCMCIA;
+ "Elsa: %s defined at 0x%x IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->irq);
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) {
+ cs->hw.elsa.base = card->para[1];
+ cs->irq = card->para[0];
+ cs->subtyp = ELSA_PCMCIA;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ cs->hw.elsa.timer = 0;
+ cs->hw.elsa.trig = 0;
+ cs->hw.elsa.ctrl = 0;
printk(KERN_INFO
- "Elsa: %s found at 0x%x IRQ %d\n",
- Elsa_Types[sp->subtyp],
- sp->cfg_reg,
- sp->irq);
- } else
+ "Elsa: %s defined at 0x%x IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->irq);
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
+#if CONFIG_PCI
+ u_char pci_bus, pci_device_fn, pci_irq;
+ u_int pci_ioaddr;
+
+ cs->subtyp = 0;
+ for (; pci_index < 0xff; pci_index++) {
+ if (pcibios_find_device(PCI_VENDOR_ELSA,
+ PCI_QS1000_ID, pci_index, &pci_bus, &pci_device_fn)
+ == PCIBIOS_SUCCESSFUL)
+ cs->subtyp = ELSA_QS1000PCI;
+ else
+ break;
+ /* get IRQ */
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq);
+
+ /* get IO address */
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_1, &pci_ioaddr);
+ pci_ioaddr &= ~3; /* remove io/mem flag */
+ cs->hw.elsa.cfg = pci_ioaddr;
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_3, &pci_ioaddr);
+ if (cs->subtyp)
+ break;
+ }
+ if (!cs->subtyp) {
+ printk(KERN_WARNING "Elsa: No PCI card found\n");
+ return(0);
+ }
+ if (!pci_irq) {
+ printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
+ return(0);
+ }
+
+ if (!pci_ioaddr) {
+ printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ pci_ioaddr &= ~3; /* remove io/mem flag */
+ cs->hw.elsa.base = pci_ioaddr;
+ cs->hw.elsa.ale = pci_ioaddr;
+ cs->hw.elsa.isac = pci_ioaddr +1;
+ cs->hw.elsa.hscx = pci_ioaddr +1;
+ cs->irq = pci_irq;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ cs->hw.elsa.timer = 0;
+ cs->hw.elsa.trig = 0;
+ printk(KERN_INFO
+ "Elsa: %s defined at 0x%x/0x%x IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->hw.elsa.cfg,
+ cs->irq);
+#else
+ printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n");
+ printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n");
+ return (0);
+#endif /* CONFIG_PCI */
+ } else
return (0);
-#endif
- switch (sp->subtyp) {
+ switch (cs->subtyp) {
case ELSA_PC:
- bytecnt = 8;
- break;
case ELSA_PCC8:
- bytecnt = 8;
- break;
- case ELSA_PCFPRO:
- bytecnt = 16;
- break;
case ELSA_PCC16:
+ case ELSA_QS1000:
+ case ELSA_PCMCIA:
bytecnt = 8;
break;
+ case ELSA_PCFPRO:
case ELSA_PCF:
bytecnt = 16;
break;
- case ELSA_QS1000:
- bytecnt = 8;
- break;
- case ELSA_PCMCIA:
- bytecnt = 8;
+ case ELSA_QS1000PCI:
+ bytecnt = 2;
break;
default:
printk(KERN_WARNING
- "Unknown ELSA subtype %d\n", sp->subtyp);
+ "Unknown ELSA subtype %d\n", cs->subtyp);
return (0);
}
-
- if (check_region((sp->cfg_reg), bytecnt)) {
+ /* In case of the elsa pcmcia card, this region is in use,
+ reserved for us by the card manager. So we do not check it
+ here, it would fail. */
+ if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && check_region(cs->hw.elsa.base, bytecnt)) {
printk(KERN_WARNING
"HiSax: %s config port %x-%x already in use\n",
CardType[card->typ],
- sp->cfg_reg,
- sp->cfg_reg + bytecnt);
+ cs->hw.elsa.base,
+ cs->hw.elsa.base + bytecnt);
return (0);
} else {
- request_region(sp->cfg_reg, bytecnt, "elsa isdn");
+ request_region(cs->hw.elsa.base, bytecnt, "elsa isdn");
}
-
- /* Teste Timer */
-#ifdef CONFIG_HISAX_ELSA_PCC
- byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- if (!TimerRun(sp)) {
- byteout(sp->cfg_reg + CARD_START_TIMER, 0); /* 2. Versuch */
- if (!TimerRun(sp)) {
+ if (cs->subtyp == ELSA_QS1000PCI) {
+ if (check_region(cs->hw.elsa.cfg, 0x80)) {
printk(KERN_WARNING
- "Elsa: timer do not start\n");
- release_io_elsa(card);
+ "HiSax: %s pci port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.elsa.cfg,
+ cs->hw.elsa.cfg + 0x80);
+ release_region(cs->hw.elsa.base, bytecnt);
return (0);
+ } else {
+ request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci");
}
}
- save_flags(flags);
- sti();
- HZDELAY(1); /* wait >=10 ms */
- restore_flags(flags);
- if (TimerRun(sp)) {
- printk(KERN_WARNING "Elsa: timer do not run down\n");
- release_io_elsa(card);
- return (0);
+ cs->hw.elsa.tl.function = (void *) elsa_led_handler;
+ cs->hw.elsa.tl.data = (long) cs;
+ init_timer(&cs->hw.elsa.tl);
+ /* Teste Timer */
+ if (cs->hw.elsa.timer) {
+ byteout(cs->hw.elsa.trig, 0xff);
+ byteout(cs->hw.elsa.timer, 0);
+ if (!TimerRun(cs)) {
+ byteout(cs->hw.elsa.timer, 0); /* 2. Versuch */
+ if (!TimerRun(cs)) {
+ printk(KERN_WARNING
+ "Elsa: timer do not start\n");
+ release_io_elsa(cs);
+ return (0);
+ }
+ }
+ save_flags(flags);
+ sti();
+ HZDELAY(1); /* wait >=10 ms */
+ restore_flags(flags);
+ if (TimerRun(cs)) {
+ printk(KERN_WARNING "Elsa: timer do not run down\n");
+ release_io_elsa(cs);
+ return (0);
+ }
+ printk(KERN_INFO "Elsa: timer OK; resetting card\n");
}
- printk(KERN_INFO "Elsa: timer OK; resetting card\n");
- reset_elsa(sp);
-#endif
- verA = readhscx(sp->cfg_reg, 0, HSCX_VSTR) & 0xf;
- verB = readhscx(sp->cfg_reg, 1, HSCX_VSTR) & 0xf;
- printk(KERN_INFO "Elsa: HSCX version A: %s B: %s\n",
- HscxVersion(verA), HscxVersion(verB));
- val = readisac(sp->cfg_reg, ISAC_RBCH);
- printk(KERN_INFO "Elsa: ISAC %s\n",
- ISACVersion(val));
-
-#ifdef CONFIG_HISAX_ELSA_PCMCIA
- if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
- printk(KERN_WARNING
- "Elsa: wrong HSCX versions check IO address\n");
- release_io_elsa(card);
- return (0);
+ reset_elsa(cs);
+ cs->BC_Read_Reg = &ReadHSCX;
+ cs->BC_Write_Reg = &WriteHSCX;
+ cs->BC_Send_Data = &hscx_fill_fifo;
+ cs->cardmsg = &Elsa_card_msg;
+ if (cs->subtyp == ELSA_QS1000PCI) {
+ cs->readisac = &ReadISAC_IPAC;
+ cs->writeisac = &WriteISAC_IPAC;
+ cs->readisacfifo = &ReadISACfifo_IPAC;
+ cs->writeisacfifo = &WriteISACfifo_IPAC;
+ val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ID);
+ printk(KERN_INFO "Elsa: IPAC version %x\n", val);
+ } else {
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ ISACVersion(cs, "Elsa:");
+ if (HscxVersion(cs, "Elsa:")) {
+ printk(KERN_WARNING
+ "Elsa: wrong HSCX versions check IO address\n");
+ release_io_elsa(cs);
+ return (0);
+ }
}
-#endif
-
-#ifdef CONFIG_HISAX_ELSA_PCC
- if (sp->subtyp == ELSA_PC) {
- val = readitac(sp->cfg_reg, ITAC_SYS);
+ if (cs->subtyp == ELSA_PC) {
+ val = readitac(cs, ITAC_SYS);
printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]);
- writeitac(sp->cfg_reg, ITAC_ISEN, 0);
- writeitac(sp->cfg_reg, ITAC_RFIE, 0);
- writeitac(sp->cfg_reg, ITAC_XFIE, 0);
- writeitac(sp->cfg_reg, ITAC_SCIE, 0);
- writeitac(sp->cfg_reg, ITAC_STIE, 0);
+ writeitac(cs, ITAC_ISEN, 0);
+ writeitac(cs, ITAC_RFIE, 0);
+ writeitac(cs, ITAC_XFIE, 0);
+ writeitac(cs, ITAC_SCIE, 0);
+ writeitac(cs, ITAC_STIE, 0);
}
-#endif
- sp->modehscx = &modehscx;
- sp->ph_command = &ph_command;
- sp->hscx_fill_fifo = &hscx_fill_fifo;
- sp->isac_fill_fifo = &isac_fill_fifo;
-
return (1);
}
+
diff --git a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c
index d0bb2f14f..ae0662f3f 100644
--- a/drivers/isdn/hisax/fsm.c
+++ b/drivers/isdn/hisax/fsm.c
@@ -1,4 +1,4 @@
-/* $Id: fsm.c,v 1.4 1997/04/06 22:56:42 keil Exp $
+/* $Id: fsm.c,v 1.7 1997/11/06 17:09:13 keil Exp $
* Author Karsten Keil (keil@temic-ech.spacenet.de)
* based on the teles driver from Jan den Ouden
@@ -7,6 +7,15 @@
* Fritz Elfert
*
* $Log: fsm.c,v $
+ * Revision 1.7 1997/11/06 17:09:13 keil
+ * New 2.1 init code
+ *
+ * Revision 1.6 1997/07/27 21:42:25 keil
+ * proof Fsm routines
+ *
+ * Revision 1.5 1997/06/26 11:10:05 keil
+ * Restart timer function added
+ *
* Revision 1.4 1997/04/06 22:56:42 keil
* Some cosmetic changes
*
@@ -26,9 +35,9 @@
#define FSM_TIMER_DEBUG 0
-void
+HISAX_INITFUNC(void
FsmNew(struct Fsm *fsm,
- struct FsmNode *fnlist, int fncount)
+ struct FsmNode *fnlist, int fncount))
{
int i;
@@ -36,9 +45,14 @@ FsmNew(struct Fsm *fsm,
kmalloc(4L * fsm->state_count * fsm->event_count, GFP_KERNEL);
memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count);
- for (i = 0; i < fncount; i++)
- fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
- fnlist[i].state] = (int) fnlist[i].routine;
+ for (i = 0; i < fncount; i++)
+ if ((fnlist[i].state>=fsm->state_count) || (fnlist[i].event>=fsm->event_count)) {
+ printk(KERN_ERR "FsmNew Error line %d st(%d/%d) ev(%d/%d)\n",
+ i,fnlist[i].state,fsm->state_count,
+ fnlist[i].event,fsm->event_count);
+ } else
+ fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
+ fnlist[i].state] = (int) fnlist[i].routine;
}
void
@@ -53,6 +67,11 @@ FsmEvent(struct FsmInst *fi, int event, void *arg)
void (*r) (struct FsmInst *, int, void *);
char str[80];
+ if ((fi->state>=fi->fsm->state_count) || (event >= fi->fsm->event_count)) {
+ printk(KERN_ERR "FsmEvent Error st(%d/%d) ev(%d/%d)\n",
+ fi->state,fi->fsm->state_count,event,fi->fsm->event_count);
+ return(1);
+ }
r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
if (r) {
if (fi->debug) {
@@ -155,10 +174,26 @@ FsmAddTimer(struct FsmTimer *ft,
return 0;
}
-int
-FsmTimerRunning(struct FsmTimer *ft)
+void
+FsmRestartTimer(struct FsmTimer *ft,
+ int millisec, int event, void *arg, int where)
{
- return (ft->tl.next != NULL);
+
+#if FSM_TIMER_DEBUG
+ if (ft->fi->debug) {
+ char str[40];
+ sprintf(str, "FsmRestartTimer %lx %d %d", (long) ft, millisec, where);
+ ft->fi->printdebug(ft->fi, str);
+ }
+#endif
+
+ if (ft->tl.next || ft->tl.prev)
+ del_timer(&ft->tl);
+ init_timer(&ft->tl);
+ ft->event = event;
+ ft->arg = arg;
+ ft->tl.expires = jiffies + (millisec * HZ) / 1000;
+ add_timer(&ft->tl);
}
void
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
new file mode 100644
index 000000000..734ec8bd3
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -0,0 +1,1297 @@
+/* $Id: hfc_2bds0.c,v 1.3 1998/02/12 23:07:22 keil Exp $
+ *
+ * specific routines for CCD's HFC 2BDS0
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hfc_2bds0.c,v $
+ * Revision 1.3 1998/02/12 23:07:22 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.2 1998/02/02 13:26:13 keil
+ * New
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hfc_2bds0.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+/*
+#define KDEBUG_DEF
+#include "kdebug.h"
+*/
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+static void
+dummyf(struct IsdnCardState *cs, u_char * data, int size)
+{
+ printk(KERN_WARNING "HiSax: hfcd dummy fifo called\n");
+}
+
+static inline u_char
+ReadReg(struct IsdnCardState *cs, int data, u_char reg)
+{
+ register u_char ret;
+
+ if (data) {
+ if (cs->hw.hfcD.cip != reg) {
+ cs->hw.hfcD.cip = reg;
+ byteout(cs->hw.hfcD.addr | 1, reg);
+ }
+ ret = bytein(cs->hw.hfcD.addr);
+#if HFC_REG_DEBUG
+ if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) {
+ char tmp[32];
+ sprintf(tmp, "t3c RD %02x %02x", reg, ret);
+ debugl1(cs, tmp);
+ }
+#endif
+ } else
+ ret = bytein(cs->hw.hfcD.addr | 1);
+ return (ret);
+}
+
+static inline void
+WriteReg(struct IsdnCardState *cs, int data, u_char reg, u_char value)
+{
+ if (cs->hw.hfcD.cip != reg) {
+ cs->hw.hfcD.cip = reg;
+ byteout(cs->hw.hfcD.addr | 1, reg);
+ }
+ if (data)
+ byteout(cs->hw.hfcD.addr, value);
+#if HFC_REG_DEBUG
+ if (cs->debug & L1_DEB_HSCX_FIFO && (data != HFCD_DATA_NODEB)) {
+ char tmp[16];
+ sprintf(tmp, "t3c W%c %02x %02x", data ? 'D' : 'C', reg, value);
+ debugl1(cs, tmp);
+ }
+#endif
+}
+
+/* Interface functions */
+
+static u_char
+readreghfcd(struct IsdnCardState *cs, u_char offset)
+{
+ return(ReadReg(cs, HFCD_DATA, offset));
+}
+
+static void
+writereghfcd(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ WriteReg(cs, HFCD_DATA, offset, value);
+}
+
+void
+set_cs_func(struct IsdnCardState *cs)
+{
+ cs->readisac = &readreghfcd;
+ cs->writeisac = &writereghfcd;
+ cs->readisacfifo = &dummyf;
+ cs->writeisacfifo = &dummyf;
+ cs->BC_Read_Reg = &ReadReg;
+ cs->BC_Write_Reg = &WriteReg;
+}
+
+static inline int
+WaitForBusy(struct IsdnCardState *cs)
+{
+ int to = 130;
+
+ while (!(ReadReg(cs, HFCD_DATA, HFCD_STAT) & HFCD_BUSY) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "HiSax: WaitForBusy timeout\n");
+ return (to);
+}
+
+static inline int
+WaitNoBusy(struct IsdnCardState *cs)
+{
+ long flags;
+ int to = 130;
+
+ while ((ReadReg(cs, HFCD_STATUS, HFCD_STATUS) & HFCD_BUSY) && to) {
+ save_flags(flags);
+ sti();
+ udelay(1);
+ to--;
+ restore_flags(flags);
+ }
+ if (!to)
+ printk(KERN_WARNING "HiSax: WaitNoBusy timeout\n");
+ return (to);
+}
+
+static int
+SelFiFo(struct IsdnCardState *cs, u_char FiFo)
+{
+ u_char cip;
+ long flags;
+
+
+ if (cs->hw.hfcD.fifo == FiFo)
+ return(1);
+ save_flags(flags);
+ cli();
+ switch(FiFo) {
+ case 0: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B1;
+ break;
+ case 1: cip = HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_B1;
+ break;
+ case 2: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B2;
+ break;
+ case 3: cip = HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_B2;
+ break;
+ case 4: cip = HFCD_FIFO | HFCD_Z1 | HFCD_SEND;
+ break;
+ case 5: cip = HFCD_FIFO | HFCD_Z1 | HFCD_REC;
+ break;
+ default:
+ restore_flags(flags);
+ debugl1(cs, "SelFiFo Error");
+ return(0);
+ }
+ cs->hw.hfcD.fifo = FiFo;
+ WaitNoBusy(cs);
+ cs->BC_Write_Reg(cs, HFCD_DATA, cip, 0);
+ sti();
+ WaitForBusy(cs);
+ restore_flags(flags);
+ return(2);
+}
+static int
+GetFreeFifoBytes_B(struct BCState *bcs)
+{
+ int s;
+
+ if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2)
+ return (bcs->cs->hw.hfcD.bfifosize);
+ s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2];
+ if (s <= 0)
+ s += bcs->cs->hw.hfcD.bfifosize;
+ s = bcs->cs->hw.hfcD.bfifosize - s;
+ return (s);
+}
+
+static int
+GetFreeFifoBytes_D(struct IsdnCardState *cs)
+{
+ int s;
+
+ if (cs->hw.hfcD.f1 == cs->hw.hfcD.f2)
+ return (cs->hw.hfcD.dfifosize);
+ s = cs->hw.hfcD.send[cs->hw.hfcD.f1] - cs->hw.hfcD.send[cs->hw.hfcD.f2];
+ if (s <= 0)
+ s += cs->hw.hfcD.dfifosize;
+ s = cs->hw.hfcD.dfifosize - s;
+ return (s);
+}
+
+static int
+ReadZReg(struct IsdnCardState *cs, u_char reg)
+{
+ int val;
+
+ WaitNoBusy(cs);
+ val = 256 * ReadReg(cs, HFCD_DATA, reg | HFCB_Z_HIGH);
+ WaitNoBusy(cs);
+ val += ReadReg(cs, HFCD_DATA, reg | HFCB_Z_LOW);
+ return (val);
+}
+
+static void
+hfc_sched_event(struct BCState *bcs, int event)
+{
+ bcs->event |= 1 << event;
+ queue_task(&bcs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static struct sk_buff
+*hfc_empty_fifo(struct BCState *bcs, int count)
+{
+ u_char *ptr;
+ struct sk_buff *skb;
+ struct IsdnCardState *cs = bcs->cs;
+ int idx;
+ int chksum;
+ long flags;
+ u_char stat, cip;
+ char tmp[64];
+
+ if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+ debugl1(cs, "hfc_empty_fifo");
+ idx = 0;
+ save_flags(flags);
+ if (count > HSCX_BUFMAX + 3) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "hfc_empty_fifo: incoming packet too large");
+ cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
+ while (idx++ < count) {
+ cli();
+ WaitNoBusy(cs);
+ ReadReg(cs, HFCD_DATA_NODEB, cip);
+ sti();
+ }
+ skb = NULL;
+ } else if (count < 4) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "hfc_empty_fifo: incoming packet too small");
+ cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
+ cli();
+ while ((idx++ < count) && WaitNoBusy(cs))
+ ReadReg(cs, HFCD_DATA_NODEB, cip);
+ skb = NULL;
+ } else if (!(skb = dev_alloc_skb(count - 3)))
+ printk(KERN_WARNING "HFC: receive out of memory\n");
+ else {
+ ptr = skb_put(skb, count - 3);
+ idx = 0;
+ cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
+ cli();
+ while (idx < (count - 3)) {
+ cli();
+ if (!WaitNoBusy(cs))
+ break;
+ *ptr = ReadReg(cs, HFCD_DATA_NODEB, cip);
+ sti();
+ ptr++;
+ idx++;
+ }
+ if (idx != count - 3) {
+ sti();
+ debugl1(cs, "RFIFO BUSY error");
+ printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
+ dev_kfree_skb(skb);
+ skb = NULL;
+ } else {
+ cli();
+ WaitNoBusy(cs);
+ chksum = (ReadReg(cs, HFCD_DATA, cip) << 8);
+ WaitNoBusy(cs);
+ chksum += ReadReg(cs, HFCD_DATA, cip);
+ WaitNoBusy(cs);
+ stat = ReadReg(cs, HFCD_DATA, cip);
+ sti();
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "hfc_empty_fifo %d chksum %x stat %x",
+ bcs->channel, chksum, stat);
+ debugl1(cs, tmp);
+ }
+ if (stat) {
+ debugl1(cs, "FIFO CRC error");
+ dev_kfree_skb(skb);
+ skb = NULL;
+ }
+ }
+ }
+ sti();
+ WaitForBusy(cs);
+ cli();
+ WaitNoBusy(cs);
+ stat = ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F2_INC |
+ HFCB_REC | HFCB_CHANNEL(bcs->channel));
+ sti();
+ WaitForBusy(cs);
+ restore_flags(flags);
+ return (skb);
+}
+
+static void
+hfc_fill_fifo(struct BCState *bcs)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ long flags;
+ int idx, fcnt;
+ int count;
+ u_char cip;
+ char tmp[64];
+
+
+ if (!bcs->hw.hfc.tx_skb)
+ return;
+ if (bcs->hw.hfc.tx_skb->len <= 0)
+ return;
+
+ save_flags(flags);
+ cli();
+ SelFiFo(cs, HFCB_SEND | HFCB_CHANNEL(bcs->channel));
+ cip = HFCB_FIFO | HFCB_F1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel);
+ WaitNoBusy(cs);
+ bcs->hw.hfc.f1 = ReadReg(cs, HFCD_DATA, cip);
+ WaitNoBusy(cs);
+ cip = HFCB_FIFO | HFCB_F2 | HFCB_SEND | HFCB_CHANNEL(bcs->channel);
+ WaitNoBusy(cs);
+ bcs->hw.hfc.f2 = ReadReg(cs, HFCD_DATA, cip);
+ bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel));
+ sti();
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
+ bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,
+ bcs->hw.hfc.send[bcs->hw.hfc.f1]);
+ debugl1(cs, tmp);
+ }
+ fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;
+ if (fcnt < 0)
+ fcnt += 32;
+ if (fcnt > 30) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc_fill_fifo more as 30 frames");
+ restore_flags(flags);
+ return;
+ }
+ count = GetFreeFifoBytes_B(bcs);
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "hfc_fill_fifo %d count(%d/%d),%lx",
+ bcs->channel, bcs->hw.hfc.tx_skb->len,
+ count, current->state);
+ debugl1(cs, tmp);
+ }
+ if (count < bcs->hw.hfc.tx_skb->len) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc_fill_fifo no fifo mem");
+ restore_flags(flags);
+ return;
+ }
+ cip = HFCB_FIFO | HFCB_FIFO_IN | HFCB_SEND | HFCB_CHANNEL(bcs->channel);
+ idx = 0;
+ cli();
+ WaitForBusy(cs);
+ WaitNoBusy(cs);
+ WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->hw.hfc.tx_skb->data[idx++]);
+ while (idx < bcs->hw.hfc.tx_skb->len) {
+ cli();
+ if (!WaitNoBusy(cs))
+ break;
+ WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->hw.hfc.tx_skb->data[idx]);
+ sti();
+ idx++;
+ }
+ if (idx != bcs->hw.hfc.tx_skb->len) {
+ sti();
+ debugl1(cs, "FIFO Send BUSY error");
+ printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel);
+ } else {
+ bcs->tx_cnt -= bcs->hw.hfc.tx_skb->len;
+ if (bcs->st->lli.l1writewakeup &&
+ (PACKET_NOACK != bcs->hw.hfc.tx_skb->pkt_type))
+ bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hfc.tx_skb->len);
+ dev_kfree_skb(bcs->hw.hfc.tx_skb);
+ bcs->hw.hfc.tx_skb = NULL;
+ }
+ WaitForBusy(cs);
+ cli();
+ WaitNoBusy(cs);
+ ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F1_INC | HFCB_SEND | HFCB_CHANNEL(bcs->channel));
+ sti();
+ WaitForBusy(cs);
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ restore_flags(flags);
+ return;
+}
+
+static void
+hfc_send_data(struct BCState *bcs)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ char tmp[32];
+
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfc_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else {
+ sprintf(tmp,"send_data %d blocked", bcs->channel);
+ debugl1(cs, tmp);
+ }
+}
+
+void
+main_rec_2bds0(struct BCState *bcs)
+{
+ long flags;
+ struct IsdnCardState *cs = bcs->cs;
+ int z1, z2, rcnt;
+ u_char f1, f2, cip;
+ int receive, count = 5;
+ struct sk_buff *skb;
+ char tmp[64];
+
+ save_flags(flags);
+ Begin:
+ count--;
+ cli();
+ if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ sprintf(tmp,"rec_data %d blocked", bcs->channel);
+ debugl1(cs, tmp);
+ restore_flags(flags);
+ return;
+ }
+ SelFiFo(cs, HFCB_REC | HFCB_CHANNEL(bcs->channel));
+ cip = HFCB_FIFO | HFCB_F1 | HFCB_REC | HFCB_CHANNEL(bcs->channel);
+ WaitNoBusy(cs);
+ f1 = ReadReg(cs, HFCD_DATA, cip);
+ cip = HFCB_FIFO | HFCB_F2 | HFCB_REC | HFCB_CHANNEL(bcs->channel);
+ WaitNoBusy(cs);
+ f2 = ReadReg(cs, HFCD_DATA, cip);
+ sti();
+ if (f1 != f2) {
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "hfc rec %d f1(%d) f2(%d)",
+ bcs->channel, f1, f2);
+ debugl1(cs, tmp);
+ }
+ cli();
+ z1 = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_CHANNEL(bcs->channel));
+ z2 = ReadZReg(cs, HFCB_FIFO | HFCB_Z2 | HFCB_REC | HFCB_CHANNEL(bcs->channel));
+ sti();
+ rcnt = z1 - z2;
+ if (rcnt < 0)
+ rcnt += cs->hw.hfcD.bfifosize;
+ rcnt++;
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
+ bcs->channel, z1, z2, rcnt);
+ debugl1(cs, tmp);
+ }
+ if ((skb = hfc_empty_fifo(bcs, rcnt))) {
+ cli();
+ skb_queue_tail(&bcs->rqueue, skb);
+ sti();
+ hfc_sched_event(bcs, B_RCVBUFREADY);
+ }
+ rcnt = f1 -f2;
+ if (rcnt<0)
+ rcnt += 32;
+ if (rcnt>1)
+ receive = 1;
+ else
+ receive = 0;
+ } else
+ receive = 0;
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ if (count && receive)
+ goto Begin;
+ restore_flags(flags);
+ return;
+}
+
+void
+mode_2bs0(struct BCState *bcs, int mode, int bc)
+{
+ struct IsdnCardState *cs = bcs->cs;
+
+ if (cs->debug & L1_DEB_HSCX) {
+ char tmp[40];
+ sprintf(tmp, "HFCD bchannel mode %d bchan %d/%d",
+ mode, bc, bcs->channel);
+ debugl1(cs, tmp);
+ }
+ bcs->mode = mode;
+ bcs->channel = bc;
+ switch (mode) {
+ case (L1_MODE_NULL):
+ if (bc) {
+ cs->hw.hfcD.conn |= 0x18;
+ cs->hw.hfcD.sctrl &= ~SCTRL_B2_ENA;
+ } else {
+ cs->hw.hfcD.conn |= 0x3;
+ cs->hw.hfcD.sctrl &= ~SCTRL_B1_ENA;
+ }
+ break;
+ case (L1_MODE_TRANS):
+ if (bc) {
+ cs->hw.hfcD.ctmt |= 2;
+ cs->hw.hfcD.conn &= ~0x18;
+ cs->hw.hfcD.sctrl |= SCTRL_B2_ENA;
+ } else {
+ cs->hw.hfcD.ctmt |= 1;
+ cs->hw.hfcD.conn &= ~0x3;
+ cs->hw.hfcD.sctrl |= SCTRL_B1_ENA;
+ }
+ break;
+ case (L1_MODE_HDLC):
+ if (bc) {
+ cs->hw.hfcD.ctmt &= ~2;
+ cs->hw.hfcD.conn &= ~0x18;
+ cs->hw.hfcD.sctrl |= SCTRL_B2_ENA;
+ } else {
+ cs->hw.hfcD.ctmt &= ~1;
+ cs->hw.hfcD.conn &= ~0x3;
+ cs->hw.hfcD.sctrl |= SCTRL_B1_ENA;
+ }
+ break;
+ }
+ WriteReg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl);
+ WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
+ WriteReg(cs, HFCD_DATA, HFCD_CONN, cs->hw.hfcD.conn);
+}
+
+static void
+hfc_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ long flags;
+
+ switch (pr) {
+ case (PH_DATA_REQ):
+ save_flags(flags);
+ cli();
+ if (st->l1.bcs->hw.hfc.tx_skb) {
+ skb_queue_tail(&st->l1.bcs->squeue, skb);
+ restore_flags(flags);
+ } else {
+ st->l1.bcs->hw.hfc.tx_skb = skb;
+/* test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+*/ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+ restore_flags(flags);
+ }
+ break;
+ case (PH_PULL_IND):
+ if (st->l1.bcs->hw.hfc.tx_skb) {
+ printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
+ break;
+ }
+ save_flags(flags);
+ cli();
+/* test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+*/ st->l1.bcs->hw.hfc.tx_skb = skb;
+ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+ restore_flags(flags);
+ break;
+ case (PH_PULL_REQ):
+ if (!st->l1.bcs->hw.hfc.tx_skb) {
+ test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ st->l1.l1l2(st, PH_PULL_CNF, NULL);
+ } else
+ test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ }
+}
+
+void
+close_2bs0(struct BCState *bcs)
+{
+ struct sk_buff *skb;
+
+ mode_2bs0(bcs, 0, 0);
+ if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+ while ((skb = skb_dequeue(&bcs->rqueue))) {
+ dev_kfree_skb(skb);
+ }
+ while ((skb = skb_dequeue(&bcs->squeue))) {
+ dev_kfree_skb(skb);
+ }
+ if (bcs->hw.hfc.tx_skb) {
+ dev_kfree_skb(bcs->hw.hfc.tx_skb);
+ bcs->hw.hfc.tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ }
+ }
+}
+
+static int
+open_hfcstate(struct IsdnCardState *cs,
+ int bc)
+{
+ struct BCState *bcs = cs->bcs + bc;
+
+ if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+ skb_queue_head_init(&bcs->rqueue);
+ skb_queue_head_init(&bcs->squeue);
+ }
+ bcs->hw.hfc.tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ bcs->event = 0;
+ bcs->tx_cnt = 0;
+ return (0);
+}
+
+static void
+hfc_manl1(struct PStack *st, int pr,
+ void *arg)
+{
+ switch (pr) {
+ case (PH_ACTIVATE_REQ):
+ test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ mode_2bs0(st->l1.bcs, st->l1.mode, st->l1.bc);
+ st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
+ break;
+ case (PH_DEACTIVATE_REQ):
+ if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
+ mode_2bs0(st->l1.bcs, 0, 0);
+ test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ break;
+ }
+}
+
+int
+setstack_2b(struct PStack *st, struct BCState *bcs)
+{
+ if (open_hfcstate(st->l1.hardware, bcs->channel))
+ return (-1);
+ st->l1.bcs = bcs;
+ st->l2.l2l1 = hfc_l2l1;
+ st->ma.manl1 = hfc_manl1;
+ setstack_manager(st);
+ bcs->st = st;
+ return (0);
+}
+
+static void
+manl1_msg(struct IsdnCardState *cs, int msg, void *arg) {
+ struct PStack *st;
+
+ st = cs->stlist;
+ while (st) {
+ st->ma.manl1(st, msg, arg);
+ st = st->next;
+ }
+}
+
+static void
+hfcd_bh(struct IsdnCardState *cs)
+{
+/* struct PStack *stptr;
+*/
+ if (!cs)
+ return;
+#if 0
+ 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_CNF, NULL);
+ stptr = stptr->next;
+ }
+ }
+#endif
+ if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+ switch (cs->ph_state) {
+ case (0):
+ manl1_msg(cs, PH_RESET_IND, NULL);
+ break;
+ case (3):
+ manl1_msg(cs, PH_DEACT_IND, NULL);
+ break;
+ case (8):
+ manl1_msg(cs, PH_RSYNC_IND, NULL);
+ break;
+ case (6):
+ manl1_msg(cs, PH_INFO2_IND, NULL);
+ break;
+ case (7):
+ manl1_msg(cs, PH_I4_P8_IND, NULL);
+ break;
+ default:
+ break;
+ }
+ }
+ 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);
+}
+
+void
+sched_event_D(struct IsdnCardState *cs, int event)
+{
+ test_and_set_bit(event, &cs->event);
+ queue_task(&cs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static
+int receive_dmsg(struct IsdnCardState *cs)
+{
+ struct sk_buff *skb;
+ long flags;
+ int idx;
+ int rcnt, z1, z2;
+ u_char stat, cip, f1, f2;
+ int chksum;
+ int count=5;
+ u_char *ptr;
+ char tmp[64];
+
+ save_flags(flags);
+ cli();
+ if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ debugl1(cs, "rec_dmsg blocked");
+ restore_flags(flags);
+ return(1);
+ }
+ SelFiFo(cs, 4 | HFCD_REC);
+ cip = HFCD_FIFO | HFCD_F1 | HFCD_REC;
+ WaitNoBusy(cs);
+ f1 = cs->readisac(cs, cip) & 0xf;
+ cip = HFCD_FIFO | HFCD_F2 | HFCD_REC;
+ WaitNoBusy(cs);
+ f2 = cs->readisac(cs, cip) & 0xf;
+ while ((f1 != f2) && count--) {
+ z1 = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_REC);
+ z2 = ReadZReg(cs, HFCD_FIFO | HFCD_Z2 | HFCD_REC);
+ rcnt = z1 - z2;
+ if (rcnt < 0)
+ rcnt += cs->hw.hfcD.dfifosize;
+ rcnt++;
+ if (cs->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "hfcd recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)",
+ f1, f2, z1, z2, rcnt);
+ debugl1(cs, tmp);
+ }
+ sti();
+ idx = 0;
+ cip = HFCD_FIFO | HFCD_FIFO_OUT | HFCD_REC;
+ if (rcnt > MAX_DFRAME_LEN + 3) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "empty_fifo d: incoming packet too large");
+ while (idx < rcnt) {
+ cli();
+ if (!(WaitNoBusy(cs)))
+ break;
+ ReadReg(cs, HFCD_DATA_NODEB, cip);
+ sti();
+ idx++;
+ }
+ } else if (rcnt < 4) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "empty_fifo d: incoming packet too small");
+ cli();
+ while ((idx++ < rcnt) && WaitNoBusy(cs))
+ ReadReg(cs, HFCD_DATA_NODEB, cip);
+ } else if ((skb = dev_alloc_skb(rcnt - 3))) {
+ ptr = skb_put(skb, rcnt - 3);
+ while (idx < (rcnt - 3)) {
+ cli();
+ if (!(WaitNoBusy(cs)))
+ break;
+ *ptr = ReadReg(cs, HFCD_DATA_NODEB, cip);
+ sti();
+ idx++;
+ ptr++;
+ }
+ if (idx != (rcnt - 3)) {
+ sti();
+ debugl1(cs, "RFIFO D BUSY error");
+ printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n");
+ dev_kfree_skb(skb);
+ skb = NULL;
+ } else {
+ cli();
+ WaitNoBusy(cs);
+ chksum = (ReadReg(cs, HFCD_DATA, cip) << 8);
+ WaitNoBusy(cs);
+ chksum += ReadReg(cs, HFCD_DATA, cip);
+ WaitNoBusy(cs);
+ stat = ReadReg(cs, HFCD_DATA, cip);
+ sti();
+ if (cs->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "empty_dfifo chksum %x stat %x",
+ chksum, stat);
+ debugl1(cs, tmp);
+ }
+ if (stat) {
+ debugl1(cs, "FIFO CRC error");
+ dev_kfree_skb(skb);
+ skb = NULL;
+ } else {
+ skb_queue_tail(&cs->rq, skb);
+ sched_event_D(cs, D_RCVBUFREADY);
+ }
+ }
+ } else
+ printk(KERN_WARNING "HFC: D receive out of memory\n");
+ sti();
+ WaitForBusy(cs);
+ cip = HFCD_FIFO | HFCD_F2_INC | HFCD_REC;
+ cli();
+ WaitNoBusy(cs);
+ stat = ReadReg(cs, HFCD_DATA, cip);
+ sti();
+ WaitForBusy(cs);
+ cip = HFCD_FIFO | HFCD_F2 | HFCD_REC;
+ cli();
+ WaitNoBusy(cs);
+ f2 = cs->readisac(cs, cip) & 0xf;
+ }
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ restore_flags(flags);
+ return(1);
+}
+
+static void
+hfc_fill_dfifo(struct IsdnCardState *cs)
+{
+ long flags;
+ int idx, fcnt;
+ int count;
+ u_char cip;
+ char tmp[64];
+
+ if (!cs->tx_skb)
+ return;
+ if (cs->tx_skb->len <= 0)
+ return;
+
+ save_flags(flags);
+ cli();
+ SelFiFo(cs, 4 | HFCD_SEND);
+ cip = HFCD_FIFO | HFCD_F1 | HFCD_SEND;
+ WaitNoBusy(cs);
+ cs->hw.hfcD.f1 = ReadReg(cs, HFCD_DATA, cip) & 0xf;
+ WaitNoBusy(cs);
+ cip = HFCD_FIFO | HFCD_F2 | HFCD_SEND;
+ cs->hw.hfcD.f2 = ReadReg(cs, HFCD_DATA, cip) & 0xf;
+ cs->hw.hfcD.send[cs->hw.hfcD.f1] = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_SEND);
+ sti();
+ if (cs->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "hfc_fill_Dfifo f1(%d) f2(%d) z1(%x)",
+ cs->hw.hfcD.f1, cs->hw.hfcD.f2,
+ cs->hw.hfcD.send[cs->hw.hfcD.f1]);
+ debugl1(cs, tmp);
+ }
+ fcnt = cs->hw.hfcD.f1 - cs->hw.hfcD.f2;
+ if (fcnt < 0)
+ fcnt += 16;
+ if (fcnt > 14) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc_fill_Dfifo more as 14 frames");
+ restore_flags(flags);
+ return;
+ }
+ count = GetFreeFifoBytes_D(cs);
+ if (cs->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "hfc_fill_Dfifo count(%d/%d)",
+ cs->tx_skb->len, count);
+ debugl1(cs, tmp);
+ }
+ if (count < cs->tx_skb->len) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "hfc_fill_Dfifo no fifo mem");
+ restore_flags(flags);
+ return;
+ }
+ cip = HFCD_FIFO | HFCD_FIFO_IN | HFCD_SEND;
+ idx = 0;
+ cli();
+ WaitForBusy(cs);
+ WaitNoBusy(cs);
+ WriteReg(cs, HFCD_DATA_NODEB, cip, cs->tx_skb->data[idx++]);
+ while (idx < cs->tx_skb->len) {
+ cli();
+ if (!(WaitNoBusy(cs)))
+ break;
+ WriteReg(cs, HFCD_DATA_NODEB, cip, cs->tx_skb->data[idx]);
+ sti();
+ idx++;
+ }
+ if (idx != cs->tx_skb->len) {
+ sti();
+ debugl1(cs, "DFIFO Send BUSY error");
+ printk(KERN_WARNING "HFC S DFIFO channel BUSY Error\n");
+ }
+ WaitForBusy(cs);
+ cli();
+ WaitNoBusy(cs);
+ ReadReg(cs, HFCD_DATA, HFCD_FIFO | HFCD_F1_INC | HFCD_SEND);
+ dev_kfree_skb(cs->tx_skb);
+ cs->tx_skb = NULL;
+ sti();
+ WaitForBusy(cs);
+ restore_flags(flags);
+ return;
+}
+
+static
+struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel)
+{
+ if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
+ return(&cs->bcs[0]);
+ else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
+ return(&cs->bcs[1]);
+ else
+ return(NULL);
+}
+
+void
+hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
+{
+ u_char exval;
+ struct BCState *bcs;
+ char tmp[32];
+ int count=15;
+ long flags;
+
+ if (cs->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "HFCD irq %x %s", val,
+ test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
+ "locked" : "unlocked");
+ debugl1(cs, tmp);
+ }
+ val &= cs->hw.hfcD.int_m1;
+ if (val & 0x40) { /* TE state machine irq */
+ exval = cs->readisac(cs, HFCD_STATES) & 0xf;
+ if (cs->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "ph_state chg %d->%d", cs->ph_state,
+ exval);
+ debugl1(cs, tmp);
+ }
+ cs->ph_state = exval;
+ sched_event_D(cs, D_L1STATECHANGE);
+ val &= ~0x40;
+ }
+ while (val) {
+ save_flags(flags);
+ cli();
+ if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ cs->hw.hfcD.int_s1 |= val;
+ restore_flags(flags);
+ return;
+ }
+ if (cs->hw.hfcD.int_s1 & 0x18) {
+ exval = val;
+ val = cs->hw.hfcD.int_s1;
+ cs->hw.hfcD.int_s1 = exval;
+ }
+ if (val & 0x08) {
+ if (!(bcs=Sel_BCS(cs, 0))) {
+ if (cs->debug)
+ debugl1(cs, "hfcd spurious 0x08 IRQ");
+ } else
+ main_rec_2bds0(bcs);
+ }
+ if (val & 0x10) {
+ if (!(bcs=Sel_BCS(cs, 1))) {
+ if (cs->debug)
+ debugl1(cs, "hfcd spurious 0x10 IRQ");
+ } else
+ main_rec_2bds0(bcs);
+ }
+ if (val & 0x01) {
+ if (!(bcs=Sel_BCS(cs, 0))) {
+ if (cs->debug)
+ debugl1(cs, "hfcd spurious 0x01 IRQ");
+ } else {
+ if (bcs->hw.hfc.tx_skb) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfc_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else {
+ sprintf(tmp,"fill_data %d blocked", bcs->channel);
+ debugl1(cs, tmp);
+ }
+ } else {
+ if ((bcs->hw.hfc.tx_skb = skb_dequeue(&bcs->squeue))) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfc_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else {
+ sprintf(tmp,"fill_data %d blocked", bcs->channel);
+ debugl1(cs, tmp);
+ }
+ } else {
+ hfc_sched_event(bcs, B_XMTBUFREADY);
+ }
+ }
+ }
+ }
+ if (val & 0x02) {
+ if (!(bcs=Sel_BCS(cs, 1))) {
+ if (cs->debug)
+ debugl1(cs, "hfcd spurious 0x02 IRQ");
+ } else {
+ if (bcs->hw.hfc.tx_skb) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfc_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else {
+ sprintf(tmp,"fill_data %d blocked", bcs->channel);
+ debugl1(cs, tmp);
+ }
+ } else {
+ if ((bcs->hw.hfc.tx_skb = skb_dequeue(&bcs->squeue))) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfc_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else {
+ sprintf(tmp,"fill_data %d blocked", bcs->channel);
+ debugl1(cs, tmp);
+ }
+ } else {
+ hfc_sched_event(bcs, B_XMTBUFREADY);
+ }
+ }
+ }
+ }
+ if (val & 0x20) { /* receive dframe */
+ receive_dmsg(cs);
+ }
+ if (val & 0x04) { /* dframe transmitted */
+ 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))
+ sched_event_D(cs, D_CLEARBUSY);
+ if (cs->tx_skb)
+ if (cs->tx_skb->len) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfc_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else {
+ debugl1(cs, "hfc_fill_dfifo irq blocked");
+ }
+ goto afterXPR;
+ } else {
+ dev_kfree_skb(cs->tx_skb);
+ cs->tx_cnt = 0;
+ cs->tx_skb = NULL;
+ }
+ if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+ cs->tx_cnt = 0;
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfc_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else {
+ debugl1(cs, "hfc_fill_dfifo irq blocked");
+ }
+ } else
+ sched_event_D(cs, D_XMTBUFREADY);
+ }
+ afterXPR:
+ if (cs->hw.hfcD.int_s1 && count--) {
+ val = cs->hw.hfcD.int_s1;
+ cs->hw.hfcD.int_s1 = 0;
+ if (cs->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "HFCD irq %x loop %d", val, 15-count);
+ debugl1(cs, tmp);
+ }
+ } else
+ val = 0;
+ restore_flags(flags);
+ }
+}
+
+static void
+HFCD_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+ struct sk_buff *skb = arg;
+ char str[64];
+ switch (pr) {
+ case (PH_DATA_REQ):
+ 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 {
+ if ((cs->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */
+ LogFrame(cs, skb->data, skb->len);
+ sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+ dlogframe(cs, skb->data + 4, skb->len - 4,
+ str);
+ }
+ 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
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfc_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "hfc_fill_dfifo blocked");
+
+ }
+ break;
+ case (PH_PULL_IND):
+ 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->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */
+ LogFrame(cs, skb->data, skb->len);
+ sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+ dlogframe(cs, skb->data + 4, skb->len - 4,
+ str);
+ }
+ 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
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfc_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "hfc_fill_dfifo blocked");
+ break;
+ case (PH_PULL_REQ):
+#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_CNF, NULL);
+ } else
+ test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ }
+}
+
+void
+hfcd_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
+{
+ char tmp[32];
+ switch(msg) {
+ case PH_RESET_REQ:
+ cs->writeisac(cs, HFCD_STATES, HFCD_LOAD_STATE | 3); /* HFC ST 3 */
+ udelay(6);
+ cs->writeisac(cs, HFCD_STATES, 3); /* HFC ST 2 */
+ cs->hw.hfcD.mst_m |= HFCD_MASTER;
+ cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+ cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION);
+ manl1_msg(cs, PH_POWERUP_CNF, NULL);
+ break;
+ case PH_ENABLE_REQ:
+ cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION);
+ break;
+ case PH_DEACT_ACK:
+ cs->hw.hfcD.mst_m &= ~HFCD_MASTER;
+ cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+ break;
+ case PH_INFO3_REQ:
+ cs->hw.hfcD.mst_m |= HFCD_MASTER;
+ cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+ break;
+#if 0
+ case PH_TESTLOOP_REQ:
+ u_char val = 0;
+ if (1 & (int) arg)
+ val |= 0x0c;
+ if (2 & (int) arg)
+ val |= 0x3;
+ if (test_bit(HW_IOM1, &cs->HW_Flags)) {
+ /* IOM 1 Mode */
+ if (!val) {
+ cs->writeisac(cs, ISAC_SPCR, 0xa);
+ cs->writeisac(cs, ISAC_ADF1, 0x2);
+ } else {
+ cs->writeisac(cs, ISAC_SPCR, val);
+ cs->writeisac(cs, ISAC_ADF1, 0xa);
+ }
+ } else {
+ /* IOM 2 Mode */
+ cs->writeisac(cs, ISAC_SPCR, val);
+ if (val)
+ cs->writeisac(cs, ISAC_ADF1, 0x8);
+ else
+ cs->writeisac(cs, ISAC_ADF1, 0x0);
+ }
+ break;
+#endif
+ default:
+ if (cs->debug & L1_DEB_WARN) {
+ sprintf(tmp, "hfcd_l1cmd unknown %4x", msg);
+ debugl1(cs, tmp);
+ }
+ break;
+ }
+}
+
+void
+setstack_hfcd(struct PStack *st, struct IsdnCardState *cs)
+{
+ st->l2.l2l1 = HFCD_l2l1;
+}
+
+static void
+hfc_dbusy_timer(struct IsdnCardState *cs)
+{
+#if 0
+ struct PStack *stptr;
+ if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+ if (cs->debug)
+ debugl1(cs, "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_IND, NULL);
+ stptr = stptr->next;
+ }
+ }
+#endif
+}
+
+__initfunc(unsigned int
+*init_send_hfcd(int cnt))
+{
+ int i, *send;
+
+ if (!(send = kmalloc(cnt * sizeof(unsigned int), GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for hfcd.send\n");
+ return(NULL);
+ }
+ for (i = 0; i < cnt; i++)
+ send[i] = 0x1fff;
+ return(send);
+}
+
+__initfunc(void
+init2bds0(struct IsdnCardState *cs))
+{
+ cs->setstack_d = setstack_hfcd;
+ cs->l1cmd = hfcd_l1cmd;
+ cs->dbusytimer.function = (void *) hfc_dbusy_timer;
+ cs->dbusytimer.data = (long) cs;
+ init_timer(&cs->dbusytimer);
+ cs->tqueue.routine = (void *) (void *) hfcd_bh;
+ if (!cs->hw.hfcD.send)
+ cs->hw.hfcD.send = init_send_hfcd(16);
+ if (!cs->bcs[0].hw.hfc.send)
+ cs->bcs[0].hw.hfc.send = init_send_hfcd(32);
+ if (!cs->bcs[1].hw.hfc.send)
+ cs->bcs[1].hw.hfc.send = init_send_hfcd(32);
+ cs->BC_Send_Data = &hfc_send_data;
+ cs->bcs[0].BC_SetStack = setstack_2b;
+ cs->bcs[1].BC_SetStack = setstack_2b;
+ cs->bcs[0].BC_Close = close_2bs0;
+ cs->bcs[1].BC_Close = close_2bs0;
+ mode_2bs0(cs->bcs, 0, 0);
+ mode_2bs0(cs->bcs + 1, 0, 1);
+}
+
+void
+release2bds0(struct IsdnCardState *cs)
+{
+ if (cs->bcs[0].hw.hfc.send) {
+ kfree(cs->bcs[0].hw.hfc.send);
+ cs->bcs[0].hw.hfc.send = NULL;
+ }
+ if (cs->bcs[1].hw.hfc.send) {
+ kfree(cs->bcs[1].hw.hfc.send);
+ cs->bcs[1].hw.hfc.send = NULL;
+ }
+ if (cs->hw.hfcD.send) {
+ kfree(cs->hw.hfcD.send);
+ cs->hw.hfcD.send = NULL;
+ }
+}
diff --git a/drivers/isdn/hisax/hfc_2bds0.h b/drivers/isdn/hisax/hfc_2bds0.h
new file mode 100644
index 000000000..d11e8b503
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_2bds0.h
@@ -0,0 +1,131 @@
+/* $Id: hfc_2bds0.h,v 1.2 1998/02/02 13:26:15 keil Exp $
+
+ * specific defines for CCD's HFC 2BDS0
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hfc_2bds0.h,v $
+ * Revision 1.2 1998/02/02 13:26:15 keil
+ * New
+ *
+ *
+ *
+ */
+
+#define HFCD_CIRM 0x18
+#define HFCD_CTMT 0x19
+#define HFCD_INT_M1 0x1A
+#define HFCD_INT_M2 0x1B
+#define HFCD_INT_S1 0x1E
+#define HFCD_STAT 0x1C
+#define HFCD_STAT_DISB 0x1D
+#define HFCD_STATES 0x30
+#define HFCD_SCTRL 0x31
+#define HFCD_TEST 0x32
+#define HFCD_SQ 0x34
+#define HFCD_CLKDEL 0x37
+#define HFCD_MST_MODE 0x2E
+#define HFCD_CONN 0x2F
+
+#define HFCD_FIFO 0x80
+#define HFCD_Z1 0x10
+#define HFCD_Z2 0x18
+#define HFCD_Z_LOW 0x00
+#define HFCD_Z_HIGH 0x04
+#define HFCD_F1_INC 0x12
+#define HFCD_FIFO_IN 0x16
+#define HFCD_F1 0x1a
+#define HFCD_F2 0x1e
+#define HFCD_F2_INC 0x22
+#define HFCD_FIFO_OUT 0x26
+#define HFCD_REC 0x01
+#define HFCD_SEND 0x00
+
+#define HFCB_FIFO 0x80
+#define HFCB_Z1 0x00
+#define HFCB_Z2 0x08
+#define HFCB_Z_LOW 0x00
+#define HFCB_Z_HIGH 0x04
+#define HFCB_F1_INC 0x28
+#define HFCB_FIFO_IN 0x2c
+#define HFCB_F1 0x30
+#define HFCB_F2 0x34
+#define HFCB_F2_INC 0x38
+#define HFCB_FIFO_OUT 0x3c
+#define HFCB_REC 0x01
+#define HFCB_SEND 0x00
+#define HFCB_B1 0x00
+#define HFCB_B2 0x02
+#define HFCB_CHANNEL(ch) (ch ? HFCB_B2 : HFCB_B1)
+
+#define HFCD_STATUS 0
+#define HFCD_DATA 1
+#define HFCD_DATA_NODEB 2
+
+/* Status (READ) */
+#define HFCD_BUSY 0x01
+#define HFCD_BUSY_NBUSY 0x04
+#define HFCD_TIMER_ELAP 0x10
+#define HFCD_STATINT 0x20
+#define HFCD_FRAMEINT 0x40
+#define HFCD_ANYINT 0x80
+
+/* CTMT (Write) */
+#define HFCD_CLTIMER 0x80
+#define HFCD_TIM25 0x00
+#define HFCD_TIM50 0x08
+#define HFCD_TIM400 0x10
+#define HFCD_TIM800 0x18
+#define HFCD_AUTO_TIMER 0x20
+#define HFCD_TRANSB2 0x02
+#define HFCD_TRANSB1 0x01
+
+/* CIRM (Write) */
+#define HFCD_RESET 0x08
+#define HFCD_MEM8K 0x10
+#define HFCD_INTA 0x01
+#define HFCD_INTB 0x02
+#define HFCD_INTC 0x03
+#define HFCD_INTD 0x04
+#define HFCD_INTE 0x05
+#define HFCD_INTF 0x06
+
+/* INT_M1;INT_S1 */
+#define HFCD_INTS_B1TRANS 0x01
+#define HFCD_INTS_B2TRANS 0x02
+#define HFCD_INTS_DTRANS 0x04
+#define HFCD_INTS_B1REC 0x08
+#define HFCD_INTS_B2REC 0x10
+#define HFCD_INTS_DREC 0x20
+#define HFCD_INTS_L1STATE 0x40
+#define HFCD_INTS_TIMER 0x80
+
+/* INT_M2 */
+#define HFCD_IRQ_ENABLE 0x08
+
+/* STATES */
+#define HFCD_LOAD_STATE 0x10
+#define HFCD_ACTIVATE 0x20
+#define HFCD_DO_ACTION 0x40
+
+/* HFCD_MST_MODE */
+#define HFCD_MASTER 0x01
+
+/* HFCD_SCTRL */
+#define SCTRL_B1_ENA 0x01
+#define SCTRL_B2_ENA 0x02
+#define SCTRL_LOW_PRIO 0x08
+#define SCTRL_SQ_ENA 0x10
+#define SCTRL_TEST 0x20
+#define SCTRL_NONE_CAP 0x40
+#define SCTRL_PWR_DOWN 0x80
+
+/* HFCD_TEST */
+#define HFCD_AUTO_AWAKE 0x01
+
+extern void main_irq_2bds0(struct BCState *bcs);
+extern void init2bds0(struct IsdnCardState *cs);
+extern void release2bds0(struct IsdnCardState *cs);
+extern void hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val);
+extern void set_cs_func(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
new file mode 100644
index 000000000..2d9ce5bd5
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_2bs0.c
@@ -0,0 +1,615 @@
+/* $Id: hfc_2bs0.c,v 1.4 1998/02/12 23:07:29 keil Exp $
+
+ * specific routines for CCD's HFC 2BS0
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hfc_2bs0.c,v $
+ * Revision 1.4 1998/02/12 23:07:29 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.3 1997/11/06 17:13:35 keil
+ * New 2.1 init code
+ *
+ * Revision 1.2 1997/10/29 19:04:47 keil
+ * changes for 2.1
+ *
+ * Revision 1.1 1997/09/11 17:31:33 keil
+ * Common part for HFC 2BS0 based cards
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hfc_2bs0.h"
+#include "isac.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+
+static inline int
+WaitForBusy(struct IsdnCardState *cs)
+{
+ int to = 130;
+ long flags;
+ u_char val;
+
+ save_flags(flags);
+ cli();
+ while (!(cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
+ val = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2 |
+ (cs->hw.hfc.cip & 3));
+ udelay(1);
+ to--;
+ }
+ restore_flags(flags);
+ if (!to) {
+ printk(KERN_WARNING "HiSax: waitforBusy timeout\n");
+ return (0);
+ } else
+ return (to);
+}
+
+static inline int
+WaitNoBusy(struct IsdnCardState *cs)
+{
+ int to = 125;
+
+ while ((cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to) {
+ printk(KERN_WARNING "HiSax: waitforBusy timeout\n");
+ return (0);
+ } else
+ return (to);
+}
+
+int
+GetFreeFifoBytes(struct BCState *bcs)
+{
+ int s;
+
+ if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2)
+ return (bcs->cs->hw.hfc.fifosize);
+ s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2];
+ if (s <= 0)
+ s += bcs->cs->hw.hfc.fifosize;
+ s = bcs->cs->hw.hfc.fifosize - s;
+ return (s);
+}
+
+int
+ReadZReg(struct BCState *bcs, u_char reg)
+{
+ int val;
+
+ WaitNoBusy(bcs->cs);
+ val = 256 * bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_HIGH);
+ WaitNoBusy(bcs->cs);
+ val += bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_LOW);
+ return (val);
+}
+
+void
+hfc_sched_event(struct BCState *bcs, int event)
+{
+ bcs->event |= 1 << event;
+ queue_task(&bcs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static void
+hfc_clear_fifo(struct BCState *bcs)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ long flags;
+ int idx, cnt;
+ int rcnt, z1, z2;
+ u_char cip, f1, f2;
+ char tmp[64];
+
+ if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+ debugl1(cs, "hfc_clear_fifo");
+ save_flags(flags);
+ cli();
+ cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
+ if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
+ cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
+ WaitForBusy(cs);
+ }
+ WaitNoBusy(cs);
+ f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
+ WaitNoBusy(cs);
+ f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
+ z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
+ cnt = 32;
+ while (((f1 != f2) || (z1 != z2)) && cnt--) {
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "hfc clear %d f1(%d) f2(%d)",
+ bcs->channel, f1, f2);
+ debugl1(cs, tmp);
+ }
+ rcnt = z1 - z2;
+ if (rcnt < 0)
+ rcnt += cs->hw.hfc.fifosize;
+ if (rcnt)
+ rcnt++;
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "hfc clear %d z1(%x) z2(%x) cnt(%d)",
+ bcs->channel, z1, z2, rcnt);
+ debugl1(cs, tmp);
+ }
+ cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
+ idx = 0;
+ while ((idx < rcnt) && WaitNoBusy(cs)) {
+ cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
+ idx++;
+ }
+ if (f1 != f2) {
+ WaitNoBusy(cs);
+ cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+ HFC_CHANNEL(bcs->channel));
+ WaitForBusy(cs);
+ }
+ cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
+ WaitNoBusy(cs);
+ f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
+ WaitNoBusy(cs);
+ f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
+ z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
+ }
+ restore_flags(flags);
+ return;
+}
+
+
+static struct sk_buff
+*
+hfc_empty_fifo(struct BCState *bcs, int count)
+{
+ u_char *ptr;
+ struct sk_buff *skb;
+ struct IsdnCardState *cs = bcs->cs;
+ int idx;
+ int chksum;
+ u_char stat, cip;
+ char tmp[64];
+
+ if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+ debugl1(cs, "hfc_empty_fifo");
+ idx = 0;
+ if (count > HSCX_BUFMAX + 3) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "hfc_empty_fifo: incoming packet too large");
+ cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
+ while ((idx++ < count) && WaitNoBusy(cs))
+ cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
+ WaitNoBusy(cs);
+ stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+ HFC_CHANNEL(bcs->channel));
+ WaitForBusy(cs);
+ return (NULL);
+ }
+ if (count < 4) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "hfc_empty_fifo: incoming packet too small");
+ cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
+ while ((idx++ < count) && WaitNoBusy(cs))
+ cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
+ WaitNoBusy(cs);
+ stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+ HFC_CHANNEL(bcs->channel));
+ WaitForBusy(cs);
+ return (NULL);
+ }
+ if (!(skb = dev_alloc_skb(count - 3)))
+ printk(KERN_WARNING "HFC: receive out of memory\n");
+ else {
+ ptr = skb_put(skb, count - 3);
+ idx = 0;
+ cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
+ while ((idx < count - 3) && WaitNoBusy(cs)) {
+ *ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
+ idx++;
+ }
+ if (idx != count - 3) {
+ debugl1(cs, "RFIFO BUSY error");
+ printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
+ dev_kfree_skb(skb);
+ WaitNoBusy(cs);
+ stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+ HFC_CHANNEL(bcs->channel));
+ WaitForBusy(cs);
+ return (NULL);
+ }
+ WaitNoBusy(cs);
+ chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8);
+ WaitNoBusy(cs);
+ chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ WaitNoBusy(cs);
+ stat = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "hfc_empty_fifo %d chksum %x stat %x",
+ bcs->channel, chksum, stat);
+ debugl1(cs, tmp);
+ }
+ if (stat) {
+ debugl1(cs, "FIFO CRC error");
+ dev_kfree_skb(skb);
+ skb = NULL;
+ }
+ WaitNoBusy(cs);
+ stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+ HFC_CHANNEL(bcs->channel));
+ WaitForBusy(cs);
+ }
+ return (skb);
+}
+
+static void
+hfc_fill_fifo(struct BCState *bcs)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ long flags;
+ int idx, fcnt;
+ int count;
+ u_char cip;
+ char tmp[64];
+
+ if (!bcs->hw.hfc.tx_skb)
+ return;
+ if (bcs->hw.hfc.tx_skb->len <= 0)
+ return;
+
+ save_flags(flags);
+ cli();
+ cip = HFC_CIP | HFC_F1 | HFC_SEND | HFC_CHANNEL(bcs->channel);
+ if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
+ cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
+ WaitForBusy(cs);
+ }
+ WaitNoBusy(cs);
+ bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel);
+ WaitNoBusy(cs);
+ bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel));
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
+ bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,
+ bcs->hw.hfc.send[bcs->hw.hfc.f1]);
+ debugl1(cs, tmp);
+ }
+ fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;
+ if (fcnt < 0)
+ fcnt += 32;
+ if (fcnt > 30) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc_fill_fifo more as 30 frames");
+ restore_flags(flags);
+ return;
+ }
+ count = GetFreeFifoBytes(bcs);
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "hfc_fill_fifo %d count(%d/%d)",
+ bcs->channel, bcs->hw.hfc.tx_skb->len,
+ count);
+ debugl1(cs, tmp);
+ }
+ if (count < bcs->hw.hfc.tx_skb->len) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc_fill_fifo no fifo mem");
+ restore_flags(flags);
+ return;
+ }
+ cip = HFC_CIP | HFC_FIFO_IN | HFC_SEND | HFC_CHANNEL(bcs->channel);
+ idx = 0;
+ while ((idx < bcs->hw.hfc.tx_skb->len) && WaitNoBusy(cs))
+ cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->hw.hfc.tx_skb->data[idx++]);
+ if (idx != bcs->hw.hfc.tx_skb->len) {
+ debugl1(cs, "FIFO Send BUSY error");
+ printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel);
+ } else {
+ count = bcs->hw.hfc.tx_skb->len;
+ bcs->tx_cnt -= count;
+ if (PACKET_NOACK == bcs->hw.hfc.tx_skb->pkt_type)
+ count = -1;
+ dev_kfree_skb(bcs->hw.hfc.tx_skb);
+ bcs->hw.hfc.tx_skb = NULL;
+ WaitForBusy(cs);
+ WaitNoBusy(cs);
+ cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel));
+ if (bcs->st->lli.l1writewakeup && (count >= 0))
+ bcs->st->lli.l1writewakeup(bcs->st, count);
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ }
+ restore_flags(flags);
+ return;
+}
+
+void
+main_irq_hfc(struct BCState *bcs)
+{
+ long flags;
+ struct IsdnCardState *cs = bcs->cs;
+ int z1, z2, rcnt;
+ u_char f1, f2, cip;
+ int receive, transmit, count = 5;
+ struct sk_buff *skb;
+ char tmp[64];
+
+ save_flags(flags);
+ Begin:
+ cli();
+ count--;
+ cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
+ if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
+ cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
+ WaitForBusy(cs);
+ }
+ WaitNoBusy(cs);
+ f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
+ WaitNoBusy(cs);
+ f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ if (f1 != f2) {
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "hfc rec %d f1(%d) f2(%d)",
+ bcs->channel, f1, f2);
+ debugl1(cs, tmp);
+ }
+ WaitForBusy(cs);
+ z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
+ z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
+ rcnt = z1 - z2;
+ if (rcnt < 0)
+ rcnt += cs->hw.hfc.fifosize;
+ rcnt++;
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
+ bcs->channel, z1, z2, rcnt);
+ debugl1(cs, tmp);
+ }
+/* sti(); */
+ if ((skb = hfc_empty_fifo(bcs, rcnt))) {
+ skb_queue_tail(&bcs->rqueue, skb);
+ hfc_sched_event(bcs, B_RCVBUFREADY);
+ }
+ receive = 1;
+ } else
+ receive = 0;
+ restore_flags(flags);
+ udelay(1);
+ cli();
+ if (bcs->hw.hfc.tx_skb) {
+ transmit = 1;
+ test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+ hfc_fill_fifo(bcs);
+ if (test_bit(BC_FLG_BUSY, &bcs->Flag))
+ transmit = 0;
+ } else {
+ if ((bcs->hw.hfc.tx_skb = skb_dequeue(&bcs->squeue))) {
+ transmit = 1;
+ test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+ hfc_fill_fifo(bcs);
+ if (test_bit(BC_FLG_BUSY, &bcs->Flag))
+ transmit = 0;
+ } else {
+ transmit = 0;
+ hfc_sched_event(bcs, B_XMTBUFREADY);
+ }
+ }
+ restore_flags(flags);
+ if ((receive || transmit) && count)
+ goto Begin;
+ return;
+}
+
+void
+mode_hfc(struct BCState *bcs, int mode, int bc)
+{
+ struct IsdnCardState *cs = bcs->cs;
+
+ if (cs->debug & L1_DEB_HSCX) {
+ char tmp[40];
+ sprintf(tmp, "HFC 2BS0 mode %d bchan %d/%d",
+ mode, bc, bcs->channel);
+ debugl1(cs, tmp);
+ }
+ bcs->mode = mode;
+
+ switch (mode) {
+ case (L1_MODE_NULL):
+ if (bc)
+ cs->hw.hfc.isac_spcr &= ~0x03;
+ else
+ cs->hw.hfc.isac_spcr &= ~0x0c;
+ break;
+ case (L1_MODE_TRANS):
+ if (bc) {
+ cs->hw.hfc.ctmt |= 1;
+ cs->hw.hfc.isac_spcr &= ~0x03;
+ cs->hw.hfc.isac_spcr |= 0x02;
+ } else {
+ cs->hw.hfc.ctmt |= 2;
+ cs->hw.hfc.isac_spcr &= ~0x0c;
+ cs->hw.hfc.isac_spcr |= 0x08;
+ }
+ break;
+ case (L1_MODE_HDLC):
+ if (bc) {
+ cs->hw.hfc.ctmt &= ~1;
+ cs->hw.hfc.isac_spcr &= ~0x03;
+ cs->hw.hfc.isac_spcr |= 0x02;
+ } else {
+ cs->hw.hfc.ctmt &= ~2;
+ cs->hw.hfc.isac_spcr &= ~0x0c;
+ cs->hw.hfc.isac_spcr |= 0x08;
+ }
+ break;
+ }
+ cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
+ cs->writeisac(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr);
+ if (mode)
+ hfc_clear_fifo(bcs);
+}
+
+static void
+hfc_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ long flags;
+
+ switch (pr) {
+ case (PH_DATA_REQ):
+ save_flags(flags);
+ cli();
+ if (st->l1.bcs->hw.hfc.tx_skb) {
+ skb_queue_tail(&st->l1.bcs->squeue, skb);
+ restore_flags(flags);
+ } else {
+ st->l1.bcs->hw.hfc.tx_skb = skb;
+ test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+ restore_flags(flags);
+ }
+ break;
+ case (PH_PULL_IND):
+ if (st->l1.bcs->hw.hfc.tx_skb) {
+ printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
+ break;
+ }
+ save_flags(flags);
+ cli();
+ test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ st->l1.bcs->hw.hfc.tx_skb = skb;
+ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+ restore_flags(flags);
+ break;
+ case (PH_PULL_REQ):
+ if (!st->l1.bcs->hw.hfc.tx_skb) {
+ test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ st->l1.l1l2(st, PH_PULL_CNF, NULL);
+ } else
+ test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ }
+}
+
+void
+close_hfcstate(struct BCState *bcs)
+{
+ struct sk_buff *skb;
+
+ mode_hfc(bcs, 0, 0);
+ if (test_bit(BC_FLG_INIT, &bcs->Flag)) {
+ while ((skb = skb_dequeue(&bcs->rqueue))) {
+ dev_kfree_skb(skb);
+ }
+ while ((skb = skb_dequeue(&bcs->squeue))) {
+ dev_kfree_skb(skb);
+ }
+ if (bcs->hw.hfc.tx_skb) {
+ dev_kfree_skb(bcs->hw.hfc.tx_skb);
+ bcs->hw.hfc.tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ }
+ }
+ test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+}
+
+static int
+open_hfcstate(struct IsdnCardState *cs,
+ int bc)
+{
+ struct BCState *bcs = cs->bcs + bc;
+
+ if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+ skb_queue_head_init(&bcs->rqueue);
+ skb_queue_head_init(&bcs->squeue);
+ }
+ bcs->hw.hfc.tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ bcs->event = 0;
+ bcs->tx_cnt = 0;
+ return (0);
+}
+
+static void
+hfc_manl1(struct PStack *st, int pr,
+ void *arg)
+{
+ switch (pr) {
+ case (PH_ACTIVATE_REQ):
+ test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ mode_hfc(st->l1.bcs, st->l1.mode, st->l1.bc);
+ st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
+ break;
+ case (PH_DEACTIVATE_REQ):
+ if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
+ mode_hfc(st->l1.bcs, 0, 0);
+ test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ break;
+ }
+}
+
+int
+setstack_hfc(struct PStack *st, struct BCState *bcs)
+{
+ if (open_hfcstate(st->l1.hardware, bcs->channel))
+ return (-1);
+ st->l1.bcs = bcs;
+ st->l2.l2l1 = hfc_l2l1;
+ st->ma.manl1 = hfc_manl1;
+ setstack_manager(st);
+ bcs->st = st;
+ return (0);
+}
+
+__initfunc(void
+init_send(struct BCState *bcs))
+{
+ int i;
+
+ if (!(bcs->hw.hfc.send = kmalloc(32 * sizeof(unsigned int), GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for hfc.send\n");
+ return;
+ }
+ for (i = 0; i < 32; i++)
+ bcs->hw.hfc.send[i] = 0x1fff;
+}
+
+__initfunc(void
+inithfc(struct IsdnCardState *cs))
+{
+ init_send(&cs->bcs[0]);
+ init_send(&cs->bcs[1]);
+ cs->BC_Send_Data = &hfc_fill_fifo;
+ cs->bcs[0].BC_SetStack = setstack_hfc;
+ cs->bcs[1].BC_SetStack = setstack_hfc;
+ cs->bcs[0].BC_Close = close_hfcstate;
+ cs->bcs[1].BC_Close = close_hfcstate;
+ mode_hfc(cs->bcs, 0, 0);
+ mode_hfc(cs->bcs + 1, 0, 0);
+}
+
+void
+releasehfc(struct IsdnCardState *cs)
+{
+ if (cs->bcs[0].hw.hfc.send) {
+ kfree(cs->bcs[0].hw.hfc.send);
+ cs->bcs[0].hw.hfc.send = NULL;
+ }
+ if (cs->bcs[1].hw.hfc.send) {
+ kfree(cs->bcs[1].hw.hfc.send);
+ cs->bcs[1].hw.hfc.send = NULL;
+ }
+}
diff --git a/drivers/isdn/hisax/hfc_2bs0.h b/drivers/isdn/hisax/hfc_2bs0.h
new file mode 100644
index 000000000..cce8e4a35
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_2bs0.h
@@ -0,0 +1,62 @@
+/* $Id: hfc_2bs0.h,v 1.1 1997/09/11 17:31:34 keil Exp $
+
+ * specific defines for CCD's HFC 2BS0
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hfc_2bs0.h,v $
+ * Revision 1.1 1997/09/11 17:31:34 keil
+ * Common part for HFC 2BS0 based cards
+ *
+ *
+ */
+
+#define HFC_CTMT 0xe0
+#define HFC_CIRM 0xc0
+#define HFC_CIP 0x80
+#define HFC_Z1 0x00
+#define HFC_Z2 0x08
+#define HFC_Z_LOW 0x00
+#define HFC_Z_HIGH 0x04
+#define HFC_F1_INC 0x28
+#define HFC_FIFO_IN 0x2c
+#define HFC_F1 0x30
+#define HFC_F2 0x34
+#define HFC_F2_INC 0x38
+#define HFC_FIFO_OUT 0x3c
+#define HFC_B1 0x00
+#define HFC_B2 0x02
+#define HFC_REC 0x01
+#define HFC_SEND 0x00
+#define HFC_CHANNEL(ch) (ch ? HFC_B2 : HFC_B1)
+
+#define HFC_STATUS 0
+#define HFC_DATA 1
+#define HFC_DATA_NODEB 2
+
+/* Status (READ) */
+#define HFC_BUSY 0x01
+#define HFC_TIMINT 0x02
+#define HFC_EXTINT 0x04
+
+/* CTMT (Write) */
+#define HFC_CLTIMER 0x10
+#define HFC_TIM50MS 0x08
+#define HFC_TIMIRQE 0x04
+#define HFC_TRANSB2 0x02
+#define HFC_TRANSB1 0x01
+
+/* CIRM (Write) */
+#define HFC_RESET 0x08
+#define HFC_MEM8K 0x10
+#define HFC_INTA 0x01
+#define HFC_INTB 0x02
+#define HFC_INTC 0x03
+#define HFC_INTD 0x04
+#define HFC_INTE 0x05
+#define HFC_INTF 0x06
+
+extern void main_irq_hfc(struct BCState *bcs);
+extern void inithfc(struct IsdnCardState *cs);
+extern void releasehfc(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index efe7d5329..f5b15e2bf 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -1,52 +1,59 @@
-/* $Id: hisax.h,v 1.13 1997/04/06 22:54:12 keil Exp $
+/* $Id: hisax.h,v 2.14 1998/02/11 17:28:04 keil Exp $
* Basic declarations, defines and prototypes
*
* $Log: hisax.h,v $
- * Revision 1.13 1997/04/06 22:54:12 keil
- * Using SKB's
+ * Revision 2.14 1998/02/11 17:28:04 keil
+ * Niccy PnP/PCI support
*
- * Revision 1.12 1997/03/23 21:45:45 keil
- * Add support for ELSA PCMCIA
+ * Revision 2.13 1998/02/09 18:46:02 keil
+ * Support for Sedlbauer PCMCIA (Marcus Niemann)
*
- * Revision 1.11 1997/02/11 01:36:02 keil
- * New Param structure
+ * Revision 2.12 1998/02/03 23:31:30 keil
+ * add AMD7930 support
*
- * Revision 1.10 1997/02/09 00:23:52 keil
- * new interface handling, one interface per card
+ * Revision 2.11 1998/02/02 13:33:00 keil
+ * New card support
*
- * Revision 1.9 1997/01/27 23:18:44 keil
- * prototype for releasestack_isdnl3
+ * Revision 2.10 1997/11/08 21:37:52 keil
+ * new l1 init;new Compaq card
*
- * Revision 1.8 1997/01/27 16:02:37 keil
- * new cards, callc timers, HZDELAY macro, HiSax_getrev prototype
+ * Revision 2.9 1997/11/06 17:09:09 keil
+ * New 2.1 init code
*
- * Revision 1.7 1997/01/21 22:22:14 keil
- * changes for 2.0; Elsa Quickstep support
+ * Revision 2.8 1997/10/29 19:04:13 keil
+ * new L1; changes for 2.1
*
- * Revision 1.6 1997/01/04 13:48:28 keil
- * primitiv for MDL_REMOVE added
+ * Revision 2.7 1997/10/10 20:56:47 fritz
+ * New HL interface.
*
- * Revision 1.5 1996/12/08 19:49:19 keil
- * Monitor channel support
+ * Revision 2.6 1997/09/11 17:25:51 keil
+ * Add new cards
*
- * Revision 1.4 1996/11/18 15:35:39 keil
- * some changes for ELSA cards
+ * Revision 2.5 1997/08/03 14:36:31 keil
+ * Implement RESTART procedure
*
- * Revision 1.3 1996/11/05 19:37:23 keil
- * using config.h
+ * Revision 2.4 1997/07/31 19:25:20 keil
+ * PTP_DATA_LINK support
*
- * Revision 1.2 1996/10/27 22:21:52 keil
- * CallFlags for broadcast messages
+ * Revision 2.3 1997/07/31 11:50:17 keil
+ * ONE TEI and FIXED TEI handling
*
- * Revision 1.1 1996/10/13 20:03:46 keil
- * Initial revision
+ * Revision 2.2 1997/07/30 17:13:02 keil
+ * more changes for 'One TEI per card'
*
+ * Revision 2.1 1997/07/27 21:45:13 keil
+ * new main structures
*
+ * Revision 2.0 1997/06/26 11:06:27 keil
+ * New card and L1 interface.
+ * Eicon.Diehl Diva and Dynalink IS64PH support
+ *
+ * old changes removed KKe
*
*/
-#include <linux/module.h>
#include <linux/config.h>
+#include <linux/module.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -64,140 +71,136 @@
#include <linux/wait.h>
#include <linux/isdnif.h>
#include <linux/tty.h>
-
-#define PH_ACTIVATE 1
-#define PH_DATA 2
-#define PH_DEACTIVATE 3
-
-#define MDL_ASSIGN 4
-#define DL_UNIT_DATA 5
-#define SC_STARTUP 6
-#define CC_ESTABLISH 7
-#define DL_ESTABLISH 8
-#define DL_DATA 9
-#define CC_S_STATUS_ENQ 10
-
-#define CC_CONNECT 15
-#define CC_CONNECT_ACKNOWLEDGE 16
-#define CO_EOF 17
-#define SC_DISCONNECT 18
-#define CO_DTMF 19
-#define DL_RELEASE 20
-#define DL_FLUSH 21
-
-#define CO_ALARM 22
-#define CC_REJECT 23
-
-#define CC_SETUP_REQ 24
-#define CC_SETUP_CNF 25
-#define CC_SETUP_IND 26
-#define CC_SETUP_RSP 27
-#define CC_SETUP_COMPLETE_IND 28
-
-#define CC_DISCONNECT_REQ 29
-#define CC_DISCONNECT_IND 30
-
-#define CC_RELEASE_CNF 31
-#define CC_RELEASE_IND 32
-#define CC_RELEASE_REQ 33
-
-#define CC_REJECT_REQ 34
-
-#define CC_PROCEEDING_IND 35
-
-#define CC_DLRL 36
-#define CC_DLEST 37
-
-#define CC_ALERTING_REQ 38
-#define CC_ALERTING_IND 39
-
-#define DL_STOP 40
-#define DL_START 41
-
-#define MDL_NOTEIPROC 46
-
-#define LC_ESTABLISH 47
-#define LC_RELEASE 48
-
-#define PH_REQUEST_PULL 49
-#define PH_PULL_ACK 50
-#define PH_DATA_PULLED 51
-#define CC_INFO_CHARGE 52
-
-#define CC_MORE_INFO 53
-#define CC_IGNORE 54
-
-#define MDL_REMOVE 56
-#define MDL_VERIFY 57
-
-#define CC_T303 60
-#define CC_T304 61
-#define CC_T305 62
-#define CC_T308_1 64
-#define CC_T308_2 65
-#define CC_T310 66
-#define CC_T313 67
-#define CC_T318 68
-#define CC_T319 69
-
-#define CC_NOSETUP_RSP_ERR 70
-#define CC_SETUP_ERR 71
-#define CC_CONNECT_ERR 72
-#define CC_RELEASE_ERR 73
-
-/*
- * 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 IE_CAUSE 0x08
-
-struct HscxIoctlArg {
- int channel;
- int mode;
- int transbufsize;
-};
+#include <linux/init.h>
+
+#define PH_ACTIVATE_REQ 0x0010
+#define PH_ACTIVATE_CNF 0x0011
+#define PH_ACTIVATE_IND 0x0012
+#define PH_DEACTIVATE_REQ 0x0020
+#define PH_DEACTIVATE_CNF 0x0021
+#define PH_DEACTIVATE_IND 0x0022
+#define PH_DEACT_REQ 0x0024
+#define PH_DEACT_CNF 0x0025
+#define PH_DEACT_IND 0x0026
+#define PH_DEACT_ACK 0x0027
+#define PH_TESTLOOP_REQ 0x0030
+#define PH_PAUSE_CNF 0x0035
+#define PH_PAUSE_IND 0x0036
+#define PH_PULL_REQ 0x0038
+#define PH_PULL_CNF 0x0039
+#define PH_PULL_IND 0x003A
+#define PH_DATA_REQ 0x0040
+#define PH_DATA_IND 0x0042
+
+#define PH_INFO3_REQ 0x0008
+#define PH_INFO2_IND 0x000A
+#define PH_ENABLE_REQ 0x0004
+#define PH_RSYNC_IND 0x0006
+#define PH_RESET_REQ 0x0000
+#define PH_RESET_IND 0x0002
+#define PH_POWERUP_CNF 0x0003
+#define PH_ACTIV_REQ 0x000C
+#define PH_I4_P8_IND 0x000D
+#define PH_I4_P10_IND 0x000F
+
+#define MDL_ASSIGN_REQ 0x0050
+#define MDL_ASSIGN_IND 0x0052
+#define MDL_REMOVE_REQ 0x0054
+#define MDL_ERROR_REQ 0x0058
+#define MDL_ERROR_IND 0x005A
+#define CARD_AUX_IND 0x005E
+
+#define DL_UNIT_DATA 6
+#define CC_ESTABLISH 7
+#define DL_ESTABLISH 8
+#define DL_DATA 9
+
+#define CC_CONNECT 15
+#define DL_RELEASE 20
+#define DL_FLUSH 21
+
+#define CC_REJECT 23
+
+#define CC_SETUP_REQ 24
+#define CC_SETUP_CNF 25
+#define CC_SETUP_IND 26
+#define CC_SETUP_RSP 27
+#define CC_SETUP_COMPLETE_IND 28
+
+#define CC_DISCONNECT_REQ 29
+#define CC_DISCONNECT_IND 30
+
+#define CC_RELEASE_CNF 31
+#define CC_RELEASE_IND 32
+#define CC_RELEASE_REQ 33
+
+#define CC_REJECT_REQ 34
+
+#define CC_PROCEEDING_IND 35
+
+#define CC_DLRL 36
+#define CC_DLEST 37
+
+#define CC_ALERTING_REQ 38
+#define CC_ALERTING_IND 39
+
+#define DL_STOP 40
+#define DL_START 41
+
+#define MDL_INFO_SETUP 42
+#define MDL_INFO_CONN 43
+#define MDL_INFO_REL 44
+#define MDL_NOTEIPROC 46
+
+#define LC_ESTABLISH 47
+#define LC_RELEASE 48
+
+#define CC_INFO_CHARGE 52
+
+#define CC_MORE_INFO 53
+#define CC_IGNORE 54
+#define CC_RESTART 55
+
+
+#define CC_T303 60
+#define CC_T304 61
+#define CC_T305 62
+#define CC_T308_1 64
+#define CC_T308_2 65
+#define CC_T310 66
+#define CC_T313 67
+#define CC_T318 68
+#define CC_T319 69
+
+#define CC_NOSETUP_RSP_ERR 70
+#define CC_SETUP_ERR 71
+#define CC_CONNECT_ERR 72
+#define CC_RELEASE_ERR 73
+
+#define CARD_RESET 0x1001
+#define CARD_SETIRQ 0x1002
+#define CARD_INIT 0x1003
+#define CARD_RELEASE 0x1004
+#define CARD_TEST 0x1005
#ifdef __KERNEL__
-#undef DEBUG_MAGIC
-
-#define MAX_DFRAME_LEN 3072
+#define MAX_DFRAME_LEN 260
#define HSCX_BUFMAX 4096
#define MAX_DATA_SIZE (HSCX_BUFMAX - 4)
-#define MAX_DATA_MEM (HSCX_BUFMAX * 2)
+#define MAX_DATA_MEM (HSCX_BUFMAX + 64)
+#define RAW_BUFMAX (((HSCX_BUFMAX*6)/5) + 5)
#define MAX_HEADER_LEN 4
#define MAX_WINDOW 8
+#define MAX_MON_FRAME 32
+
+/* #define I4L_IRQ_FLAG SA_INTERRUPT */
+#define I4L_IRQ_FLAG 0
/*
* Statemachine
*/
+
struct Fsm {
int *jumpmatrix;
int state_count, event_count;
@@ -226,73 +229,107 @@ struct FsmTimer {
};
struct L3Timer {
- struct PStack *st;
+ struct l3_process *pc;
struct timer_list tl;
int event;
};
+#define FLG_L1_ACTIVATING 1
+#define FLG_L1_ACTIVATED 2
+#define FLG_L1_DEACTTIMER 3
+#define FLG_L1_ACTTIMER 4
+#define FLG_L1_T3RUN 5
+#define FLG_L1_PULL_REQ 6
+
struct Layer1 {
void *hardware;
- int hscx;
+ struct BCState *bcs;
struct PStack **stlistp;
- int act_state;
+ int Flags;
+ struct FsmInst l1m;
+ struct FsmTimer timer;
void (*l1l2) (struct PStack *, int, void *);
void (*l1man) (struct PStack *, int, void *);
- int hscxmode, hscxchannel, requestpull;
+ void (*l1tei) (struct PStack *, int, void *);
+ int mode, bc;
};
+#define GROUP_TEI 127
+#define TEI_SAPI 63
+#define CTRL_SAPI 0
+#define PACKET_NOACK 250
+
+/* Layer2 Flags */
+
+#define FLG_LAPB 0
+#define FLG_LAPD 1
+#define FLG_ORIG 2
+#define FLG_MOD128 3
+#define FLG_PEND_REL 4
+#define FLG_L3_INIT 5
+#define FLG_T200_RUN 6
+#define FLG_ACK_PEND 7
+#define FLG_REJEXC 8
+#define FLG_OWN_BUSY 9
+#define FLG_PEER_BUSY 10
+#define FLG_DCHAN_BUSY 11
+
struct Layer2 {
- int sap, tei, ces;
- int extended, laptype;
- int uihsize, ihsize;
+ int tei;
+ int tei_wanted;
+ int sap;
+ int maxlen;
+ unsigned int flag;
int vs, va, vr;
- struct sk_buff_head i_queue;
- int window, orig;
- int rejexp;
- int debug;
- struct sk_buff *windowar[MAX_WINDOW];
+ int rc;
+ int window;
int sow;
- struct FsmInst l2m;
+ struct sk_buff *windowar[MAX_WINDOW];
+ struct sk_buff_head i_queue;
+ struct sk_buff_head ui_queue;
void (*l2l1) (struct PStack *, int, void *);
- void (*l2l1discardq) (struct PStack *, int, void *, int);
void (*l2man) (struct PStack *, int, void *);
void (*l2l3) (struct PStack *, int, void *);
void (*l2tei) (struct PStack *, int, void *);
- struct FsmTimer t200_timer, t203_timer;
- int t200, n200, t203;
- int rc, t200_running;
+ struct FsmInst l2m;
+ struct FsmTimer t200, t203;
+ int T200, N200, T203;
+ int debug;
char debug_id[32];
};
struct Layer3 {
- void (*l3l4) (struct PStack *, int, void *);
+ void (*l3l4) (struct l3_process *, int, void *);
void (*l3l2) (struct PStack *, int, void *);
- int state, callref;
- struct L3Timer timer;
- int t303, t304, t305, t308, t310, t313, t318, t319;
- int n_t303;
+ struct l3_process *proc;
+ struct l3_process *global;
+ int N303;
int debug;
- int channr;
};
-struct Layer4 {
+struct LLInterface {
void (*l4l3) (struct PStack *, int, void *);
void *userdata;
- void (*l1writewakeup) (struct PStack *);
- void (*l2writewakeup) (struct PStack *);
+ void (*l1writewakeup) (struct PStack *, int);
+ void (*l2writewakeup) (struct PStack *, int);
};
+
struct Management {
+ int ri;
+ struct FsmInst tei_m;
+ struct FsmTimer t202;
+ int T202, N202, debug;
+ void (*layer) (struct PStack *, int, void *);
void (*manl1) (struct PStack *, int, void *);
void (*manl2) (struct PStack *, int, void *);
- void (*teil2) (struct PStack *, int, void *);
};
+
struct Param {
int cause;
int loc;
int bchannel;
- int callref; /* Callreferenz Number */
setup_parm setup; /* from isdnif.h numbers and Serviceindicator */
int chargeinfo; /* Charge Info - only for 1tr6 in
* the moment
@@ -300,39 +337,114 @@ struct Param {
int spv; /* SPV Flag */
};
+
struct PStack {
struct PStack *next;
struct Layer1 l1;
struct Layer2 l2;
struct Layer3 l3;
- struct Layer4 l4;
+ struct LLInterface lli;
struct Management ma;
- struct Param *pa;
int protocol; /* EDSS1 or 1TR6 */
};
-struct HscxState {
- int inuse, init, active;
- struct IsdnCardState *sp;
- int hscx, mode;
- u_char *rcvbuf; /* B-Channel receive Buffer */
- int rcvidx; /* B-Channel receive Buffer Index */
- struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
+struct l3_process {
+ int callref;
+ int state;
+ struct L3Timer timer;
+ int N303;
+ int debug;
+ struct Param para;
+ struct Channel *chan;
+ struct PStack *st;
+ struct l3_process *next;
+};
+
+struct hscx_hw {
+ int rcvidx;
+ int count; /* Current skb sent count */
+ u_char *rcvbuf; /* B-Channel receive Buffer */
+ struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
+};
+
+struct hfcB_hw {
+ unsigned int *send;
+ int f1;
+ int f2;
+ struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
+};
+
+struct tiger_hw {
+ struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
+ u_int *send;
+ u_int *s_irq;
+ u_int *s_end;
+ u_int *sendp;
+ u_int *rec;
+ int free;
+ u_char *rcvbuf;
+ u_char *sendbuf;
+ u_char *sp;
+ int sendcnt;
+ u_int s_tot;
+ u_int r_bitcnt;
+ u_int r_tot;
+ u_int r_err;
+ u_int r_fcs;
+ u_char r_state;
+ u_char r_one;
+ u_char r_val;
+ u_char s_state;
+};
+
+struct amd7930_hw {
+ u_char *tx_buff;
+ u_char *rv_buff;
+ int rv_buff_in;
+ int rv_buff_out;
+ struct sk_buff *rv_skb;
+ struct hdlc_state *hdlc_state;
+ struct tq_struct tq_rcv;
+ struct tq_struct tq_xmt;
+ struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
+};
+
+#define BC_FLG_INIT 1
+#define BC_FLG_ACTIV 2
+#define BC_FLG_BUSY 3
+#define BC_FLG_NOFRAME 4
+#define BC_FLG_HALF 5
+#define BC_FLG_EMPTY 6
+
+#define L1_MODE_NULL 0
+#define L1_MODE_TRANS 1
+#define L1_MODE_HDLC 2
+
+struct BCState {
+ int channel;
+ int mode;
+ int Flag;
+ struct IsdnCardState *cs;
int tx_cnt; /* B-Channel transmit counter */
- int count; /* Current skb sent count */
struct sk_buff_head rqueue; /* B-Channel receive Queue */
- struct sk_buff_head squeue; /* B-Channel receive Queue */
+ struct sk_buff_head squeue; /* B-Channel send Queue */
struct PStack *st;
struct tq_struct tqueue;
int event;
-#ifdef DEBUG_MAGIC
- int magic; /* 301270 */
-#endif
+ int (*BC_SetStack) (struct PStack *, struct BCState *);
+ void (*BC_Close) (struct BCState *);
+ union {
+ struct hscx_hw hscx;
+ struct hfcB_hw hfc;
+ struct tiger_hw tiger;
+ struct amd7930_hw amd7930;
+ } hw;
};
struct LcFsm {
- struct FsmInst lcfi;
int type;
+ int delay;
+ struct FsmInst lcfi;
struct Channel *ch;
void (*lccall) (struct LcFsm *, int, void *);
struct PStack *st;
@@ -343,52 +455,209 @@ struct LcFsm {
};
struct Channel {
- struct PStack ds, is;
- struct IsdnCardState *sp;
- int hscx;
+ struct PStack *b_st, *d_st;
+ struct IsdnCardState *cs;
+ struct BCState *bcs;
int chan;
int incoming;
struct FsmInst fi;
- struct LcFsm lc_d, lc_b;
- struct Param para;
+ struct LcFsm *lc_d;
+ struct LcFsm *lc_b;
struct FsmTimer drel_timer, dial_timer;
int debug;
-#ifdef DEBUG_MAGIC
- int magic; /* 301272 */
-#endif
int l2_protocol, l2_active_protocol;
- int l2_primitive, l2_headersize;
int data_open;
- int outcallref;
- int impair;
+ struct l3_process *proc;
+ setup_parm setup; /* from isdnif.h numbers and Serviceindicator */
int Flags; /* for remembering action done in l4 */
int leased;
};
-struct IsdnCardState {
-#ifdef DEBUG_MAGIC
- int magic;
-#endif
- unsigned char typ;
- unsigned char subtyp;
- int protocol;
- unsigned int irq;
+struct elsa_hw {
+ unsigned int base;
+ unsigned int cfg;
+ unsigned int ctrl;
+ unsigned int ale;
+ unsigned int isac;
+ unsigned int itac;
+ unsigned int hscx;
+ unsigned int trig;
+ unsigned int timer;
+ unsigned int counter;
+ unsigned int status;
+ struct timer_list tl;
+ u_char ctrl_reg;
+};
+
+struct teles3_hw {
+ unsigned int cfg_reg;
+ unsigned int isac;
+ unsigned int hscx[2];
+ unsigned int isacfifo;
+ unsigned int hscxfifo[2];
+};
+
+struct teles0_hw {
unsigned int cfg_reg;
unsigned int membase;
+};
+
+struct avm_hw {
+ unsigned int cfg_reg;
unsigned int isac;
unsigned int hscx[2];
+ unsigned int isacfifo;
+ unsigned int hscxfifo[2];
unsigned int counter;
+};
+
+struct ix1_hw {
+ unsigned int cfg_reg;
+ unsigned int isac_ale;
+ unsigned int isac;
+ unsigned int hscx_ale;
+ unsigned int hscx;
+};
+
+struct diva_hw {
+ unsigned int cfg_reg;
+ unsigned int ctrl;
+ unsigned int isac_adr;
+ unsigned int isac;
+ unsigned int hscx_adr;
+ unsigned int hscx;
+ unsigned int status;
+ struct timer_list tl;
+ u_char ctrl_reg;
+};
+
+struct asus_hw {
+ unsigned int cfg_reg;
+ unsigned int adr;
+ unsigned int isac;
+ unsigned int hscx;
+ unsigned int u7;
+ unsigned int pots;
+};
+
+
+struct hfc_hw {
+ unsigned int addr;
+ unsigned int fifosize;
+ unsigned char cirm;
+ unsigned char ctmt;
+ unsigned char cip;
+ u_char isac_spcr;
+ struct timer_list timer;
+};
+
+struct sedl_hw {
+ unsigned int cfg_reg;
+ unsigned int adr;
+ unsigned int isac;
+ unsigned int hscx;
+ unsigned int reset_on;
+ unsigned int reset_off;
+};
+
+struct spt_hw {
+ unsigned int cfg_reg;
+ unsigned int isac;
+ unsigned int hscx[2];
+ unsigned char res_irq;
+};
+
+struct mic_hw {
+ unsigned int cfg_reg;
+ unsigned int adr;
+ unsigned int isac;
+ unsigned int hscx;
+};
+
+struct njet_hw {
+ unsigned int base;
+ unsigned int isac;
+ unsigned int auxa;
+ unsigned char auxd;
+ unsigned char dmactrl;
+ unsigned char ctrl_reg;
+ unsigned char irqmask0;
+ unsigned char irqstat0;
+ unsigned char last_is0;
+};
+
+struct hfcD_hw {
+ unsigned int addr;
+ unsigned int bfifosize;
+ unsigned int dfifosize;
+ unsigned char cirm;
+ unsigned char ctmt;
+ unsigned char cip;
+ unsigned char conn;
+ unsigned char mst_m;
+ unsigned char int_m1;
+ unsigned char int_m2;
+ unsigned char int_s1;
+ unsigned char sctrl;
+ unsigned char stat;
+ unsigned char fifo;
+ unsigned char f1;
+ unsigned char f2;
+ unsigned int *send;
+ struct timer_list timer;
+};
+
+#define HW_IOM1 0
+#define HW_IPAC 1
+#define FLG_TWO_DCHAN 4
+#define FLG_L1_DBUSY 5
+#define FLG_DBUSY_TIMER 6
+#define FLG_LOCK_ATOMIC 7
+#define HW_MON0_RX_END 8
+#define HW_MON1_RX_END 9
+#define HW_MON0_TX_END 10
+#define HW_MON1_TX_END 11
+
+struct IsdnCardState {
+ unsigned char typ;
+ unsigned char subtyp;
+ int protocol;
+ unsigned int irq;
+ int HW_Flags;
+ int *busy_flag;
+ union {
+ struct elsa_hw elsa;
+ struct teles0_hw teles0;
+ struct teles3_hw teles3;
+ struct avm_hw avm;
+ struct ix1_hw ix1;
+ struct diva_hw diva;
+ struct asus_hw asus;
+ struct hfc_hw hfc;
+ struct sedl_hw sedl;
+ struct spt_hw spt;
+ struct mic_hw mic;
+ struct njet_hw njet;
+ struct hfcD_hw hfcD;
+ struct ix1_hw niccy;
+ } hw;
int myid;
isdn_if iif;
u_char *status_buf;
u_char *status_read;
u_char *status_write;
u_char *status_end;
- void (*ph_command) (struct IsdnCardState *, unsigned int);
- void (*modehscx) (struct HscxState *, int, int);
- void (*hscx_fill_fifo) (struct HscxState *);
- void (*isac_fill_fifo) (struct IsdnCardState *);
+ u_char (*readisac) (struct IsdnCardState *, u_char);
+ void (*writeisac) (struct IsdnCardState *, u_char, u_char);
+ void (*readisacfifo) (struct IsdnCardState *, u_char *, int);
+ void (*writeisacfifo) (struct IsdnCardState *, u_char *, int);
+ u_char (*BC_Read_Reg) (struct IsdnCardState *, int, u_char);
+ void (*BC_Write_Reg) (struct IsdnCardState *, int, u_char, u_char);
+ void (*BC_Send_Data) (struct BCState *);
+ int (*cardmsg) (struct IsdnCardState *, int, void *);
+ void (*l1cmd) (struct IsdnCardState *, int, void *);
struct Channel channel[2];
+ struct BCState bcs[2];
struct PStack *stlist;
u_char *rcvbuf;
int rcvidx;
@@ -396,16 +665,20 @@ struct IsdnCardState {
int tx_cnt;
int event;
struct tq_struct tqueue;
- int ph_active;
+ struct timer_list dbusytimer;
struct sk_buff_head rq, sq; /* D-channel queues */
- int cardnr;
int ph_state;
- struct PStack *teistack;
- struct HscxState hs[2];
+ int cardnr;
int dlogflag;
char *dlogspace;
int debug;
- unsigned int CallFlags;
+ u_char *mon_tx;
+ u_char *mon_rx;
+ int mon_txp;
+ int mon_txc;
+ int mon_rxp;
+ u_char mocr;
+ void (*setstack_d) (struct PStack *, struct IsdnCardState *);
};
#define MON0_RX 1
@@ -419,99 +692,246 @@ struct IsdnCardState {
#define ISDN_CTYPE_PNP 4
#define ISDN_CTYPE_A1 5
#define ISDN_CTYPE_ELSA 6
-#define ISDN_CTYPE_ELSA_QS1000 7
+#define ISDN_CTYPE_ELSA_PNP 7
#define ISDN_CTYPE_TELESPCMCIA 8
#define ISDN_CTYPE_IX1MICROR2 9
+#define ISDN_CTYPE_ELSA_PCMCIA 10
+#define ISDN_CTYPE_DIEHLDIVA 11
+#define ISDN_CTYPE_ASUSCOM 12
+#define ISDN_CTYPE_TELEINT 13
+#define ISDN_CTYPE_TELES3C 14
+#define ISDN_CTYPE_SEDLBAUER 15
+#define ISDN_CTYPE_SPORTSTER 16
+#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_TELESPCI 21
+#define ISDN_CTYPE_SEDLBAUER_PCMCIA 22
+#define ISDN_CTYPE_AMD7930 23
+#define ISDN_CTYPE_NICCY 24
+
+#define ISDN_CTYPE_COUNT 24
+
+#ifdef ISDN_CHIP_ISAC
+#undef ISDN_CHIP_ISAC
+#endif
-#define ISDN_CTYPE_COUNT 9
+#define HISAX_INITFUNC(__arginit) __initfunc(__arginit)
+#define HISAX_INITDATA __initdata
#ifdef CONFIG_HISAX_16_0
#define CARD_TELES0 (1<< ISDN_CTYPE_16_0) | (1<< ISDN_CTYPE_8_0)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
#else
#define CARD_TELES0 0
#endif
#ifdef CONFIG_HISAX_16_3
#define CARD_TELES3 (1<< ISDN_CTYPE_16_3) | (1<< ISDN_CTYPE_PNP) | \
- (1<< ISDN_CTYPE_TELESPCMCIA)
+ (1<< ISDN_CTYPE_TELESPCMCIA) | (1<< ISDN_CTYPE_COMPAQ_ISA)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
#else
#define CARD_TELES3 0
#endif
#ifdef CONFIG_HISAX_AVM_A1
#define CARD_AVM_A1 (1<< ISDN_CTYPE_A1)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
#else
#define CARD_AVM_A1 0
#endif
-#ifdef CONFIG_HISAX_ELSA_PCC
-#define CARD_ELSA (1<< ISDN_CTYPE_ELSA) | (1<< ISDN_CTYPE_ELSA_QS1000)
+#ifdef CONFIG_HISAX_ELSA
+#define CARD_ELSA (1<< ISDN_CTYPE_ELSA) | (1<< ISDN_CTYPE_ELSA_PNP) | \
+ (1<< ISDN_CTYPE_ELSA_PCMCIA) | (1<< ISDN_CTYPE_ELSA_PCI)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#undef HISAX_INITFUNC
+#define HISAX_INITFUNC(__arginit) __arginit
+#undef HISAX_INITDATA
+#define HISAX_INITDATA
#else
#define CARD_ELSA 0
#endif
-#ifdef CONFIG_HISAX_ELSA_PCMCIA
-#if CARD_ELSA
-#error "You can't use a ELSA ISA card and a ELSA PCMCIA card with the same driver"
-#else
-#undef CARD_ELSA
-#define CARD_ELSA (1<< ISDN_CTYPE_ELSA_QS1000)
-#endif
-#endif
#ifdef CONFIG_HISAX_IX1MICROR2
#define CARD_IX1MICROR2 (1 << ISDN_CTYPE_IX1MICROR2)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
#else
#define CARD_IX1MICROR2 0
#endif
+#ifdef CONFIG_HISAX_DIEHLDIVA
+#define CARD_DIEHLDIVA (1 << ISDN_CTYPE_DIEHLDIVA)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_DIEHLDIVA 0
+#endif
+
+#ifdef CONFIG_HISAX_ASUSCOM
+#define CARD_ASUSCOM (1 << ISDN_CTYPE_ASUSCOM)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_ASUSCOM 0
+#endif
+
+#ifdef CONFIG_HISAX_TELEINT
+#define CARD_TELEINT (1 << ISDN_CTYPE_TELEINT)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_TELEINT 0
+#endif
+
+#ifdef CONFIG_HISAX_SEDLBAUER
+#define CARD_SEDLBAUER (1 << ISDN_CTYPE_SEDLBAUER) | (1 << ISDN_CTYPE_SEDLBAUER_PCMCIA)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_SEDLBAUER 0
+#endif
+
+#ifdef CONFIG_HISAX_SPORTSTER
+#define CARD_SPORTSTER (1 << ISDN_CTYPE_SPORTSTER)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_SPORTSTER 0
+#endif
+
+#ifdef CONFIG_HISAX_MIC
+#define CARD_MIC (1 << ISDN_CTYPE_MIC)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_MIC 0
+#endif
+
+#ifdef CONFIG_HISAX_NETJET
+#define CARD_NETJET (1 << ISDN_CTYPE_NETJET)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_NETJET 0
+#endif
+
+#ifdef CONFIG_HISAX_TELES3C
+#define CARD_TELES3C (1<< ISDN_CTYPE_TELES3C)
+#else
+#define CARD_TELES3C 0
+#endif
+
+#ifdef CONFIG_HISAX_AMD7930
+#define CARD_AMD7930 (1 << ISDN_CTYPE_AMD7930)
+#else
+#define CARD_AMD7930 0
+#endif
+
+#ifdef CONFIG_HISAX_NICCY
+#define CARD_NICCY (1 << ISDN_CTYPE_NICCY)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_NICCY 0
+#endif
+
+
#define SUPORTED_CARDS (CARD_TELES0 | CARD_TELES3 | CARD_AVM_A1 | CARD_ELSA \
- | CARD_IX1MICROR2)
+ | CARD_IX1MICROR2 | CARD_DIEHLDIVA | CARD_ASUSCOM \
+ | CARD_TELEINT | CARD_SEDLBAUER | CARD_SPORTSTER \
+ | CARD_MIC | CARD_NETJET | CARD_TELES3C | CARD_AMD7930 \
+ | CARD_NICCY)
+
+#define TEI_PER_CARD 0
+
+#ifdef CONFIG_HISAX_1TR6
+#undef TEI_PER_CARD
+#define TEI_PER_CARD 1
+#endif
+
+#ifdef CONFIG_HISAX_EURO
+#undef TEI_PER_CARD
+#define TEI_PER_CARD 1
+#define HISAX_EURO_SENDCOMPLETE 1
+#ifdef CONFIG_HISAX_ML
+#undef HISAX_EURO_SENDCOMPLETE
+#endif
+#undef HISAX_DE_AOC
+#ifdef CONFIG_DE_AOC
+#define HISAX_DE_AOC 1
+#endif
+#endif
+
+#if TEI_PER_CARD
+#undef TEI_FIXED
+#endif
+
+#undef PTP_DATA_LINK
+
+#ifdef PTP_DATA_LINK
+#undef TEI_FIXED
+#define TEI_FIXED 0
+#define LAYER2_WATCHING
+#endif
struct IsdnCard {
int typ;
int protocol; /* EDSS1 or 1TR6 */
- unsigned int para[3];
- struct IsdnCardState *sp;
+ unsigned int para[4];
+ struct IsdnCardState *cs;
};
-
-#define LAPD 0
-#define LAPB 1
-
-void l2down(struct PStack *st, u_char pr, struct sk_buff *skb);
-void l2up(struct PStack *st, u_char pr, struct sk_buff *skb);
-void acceptph(struct PStack *st, struct sk_buff *skb);
void setstack_isdnl2(struct PStack *st, char *debug_id);
-int HiSax_inithardware(void);
+int HiSax_inithardware(int *);
void HiSax_closehardware(void);
-void setstack_HiSax(struct PStack *st, struct IsdnCardState *sp);
-unsigned int randomces(void);
+void setstack_HiSax(struct PStack *st, struct IsdnCardState *cs);
+unsigned int random_ri(void);
void setstack_isdnl3(struct PStack *st, struct Channel *chanp);
void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st);
void releasestack_isdnl2(struct PStack *st);
void releasestack_isdnl3(struct PStack *st);
void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st);
-void newcallref(struct PStack *st);
-int setstack_hscx(struct PStack *st, struct HscxState *hs);
u_char *findie(u_char * p, int size, u_char ie, int wanted_set);
int getcallref(u_char * p);
+int newcallref(void);
void FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount);
void FsmFree(struct Fsm *fsm);
int FsmEvent(struct FsmInst *fi, int event, void *arg);
void FsmChangeState(struct FsmInst *fi, int newstate);
void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
-int FsmAddTimer(struct FsmTimer *ft, int millisec,
- int event, void *arg, int where);
+int FsmAddTimer(struct FsmTimer *ft, int millisec, int event,
+ void *arg, int where);
+void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event,
+ void *arg, int where);
void FsmDelTimer(struct FsmTimer *ft, int where);
-int FsmTimerRunning(struct FsmTimer *ft);
void jiftime(char *s, long mark);
int HiSax_command(isdn_ctrl * ic);
-int HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb);
+int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb);
void HiSax_putstatus(struct IsdnCardState *csta, char *buf);
void HiSax_reportcard(int cardnr);
int QuickHex(char *txt, u_char * p, int cnt);
@@ -520,10 +940,12 @@ void dlogframe(struct IsdnCardState *sp, u_char * p, int size, char *comment);
void iecpy(u_char * dest, u_char * iestart, int ieoffset);
void setstack_transl2(struct PStack *st);
void releasestack_transl2(struct PStack *st);
-void close_hscxstate(struct HscxState *);
void setstack_tei(struct PStack *st);
-
-#endif /* __KERNEL__ */
+void setstack_manager(struct PStack *st);
+#ifdef ISDN_CHIP_ISAC
+void setstack_isac(struct PStack *st, struct IsdnCardState *cs);
+#endif /* ISDN_CHIP_ISAC */
+#endif /* __KERNEL__ */
#define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);}
@@ -533,8 +955,12 @@ void CallcNew(void);
void CallcFree(void);
int CallcNewChan(struct IsdnCardState *csta);
void CallcFreeChan(struct IsdnCardState *csta);
+void Isdnl1New(void);
+void Isdnl1Free(void);
void Isdnl2New(void);
void Isdnl2Free(void);
void init_tei(struct IsdnCardState *sp, int protocol);
void release_tei(struct IsdnCardState *sp);
char *HiSax_getrev(const char *revision);
+void TeiNew(void);
+void TeiFree(void);
diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c
new file mode 100644
index 000000000..c44cc54df
--- /dev/null
+++ b/drivers/isdn/hisax/hscx.c
@@ -0,0 +1,280 @@
+/* $Id: hscx.c,v 1.7 1998/02/12 23:07:36 keil Exp $
+
+ * hscx.c HSCX specific routines
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hscx.c,v $
+ * Revision 1.7 1998/02/12 23:07:36 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.6 1998/02/02 13:41:12 keil
+ * new init
+ *
+ * Revision 1.5 1997/11/06 17:09:34 keil
+ * New 2.1 init code
+ *
+ * Revision 1.4 1997/10/29 19:01:06 keil
+ * changes for 2.1
+ *
+ * Revision 1.3 1997/07/27 21:38:34 keil
+ * new B-channel interface
+ *
+ * Revision 1.2 1997/06/26 11:16:17 keil
+ * first version
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hscx.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+
+static char *HSCXVer[] HISAX_INITDATA =
+{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
+ "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
+
+HISAX_INITFUNC(int
+HscxVersion(struct IsdnCardState *cs, char *s))
+{
+ int verA, verB;
+
+ verA = cs->BC_Read_Reg(cs, 0, HSCX_VSTR) & 0xf;
+ verB = cs->BC_Read_Reg(cs, 1, HSCX_VSTR) & 0xf;
+ printk(KERN_INFO "%s HSCX version A: %s B: %s\n", s,
+ HSCXVer[verA], HSCXVer[verB]);
+ if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf))
+ return (1);
+ else
+ return (0);
+}
+
+void
+modehscx(struct BCState *bcs, int mode, int bc)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ int hscx = bcs->channel;
+
+ if (cs->debug & L1_DEB_HSCX) {
+ char tmp[40];
+ sprintf(tmp, "hscx %c mode %d ichan %d",
+ 'A' + hscx, mode, bc);
+ debugl1(cs, tmp);
+ }
+ bcs->mode = mode;
+ cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, 0x85);
+ cs->BC_Write_Reg(cs, hscx, HSCX_XAD1, 0xFF);
+ cs->BC_Write_Reg(cs, hscx, HSCX_XAD2, 0xFF);
+ cs->BC_Write_Reg(cs, hscx, HSCX_RAH2, 0xFF);
+ cs->BC_Write_Reg(cs, hscx, HSCX_XBCH, 0x0);
+ cs->BC_Write_Reg(cs, hscx, HSCX_RLCR, 0x0);
+ cs->BC_Write_Reg(cs, hscx, HSCX_CCR2, 0x30);
+ cs->BC_Write_Reg(cs, hscx, HSCX_XCCR, 7);
+ cs->BC_Write_Reg(cs, hscx, HSCX_RCCR, 7);
+
+ /* Switch IOM 1 SSI */
+ if (test_bit(HW_IOM1, &cs->HW_Flags) && (hscx == 0))
+ bc = 1 - bc;
+
+ if (bc == 0) {
+ cs->BC_Write_Reg(cs, hscx, HSCX_TSAX,
+ test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : 0x2f);
+ cs->BC_Write_Reg(cs, hscx, HSCX_TSAR,
+ test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : 0x2f);
+ } else {
+ cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0x3);
+ cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x3);
+ }
+ switch (mode) {
+ case (L1_MODE_NULL):
+ cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0xff);
+ cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0xff);
+ cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x84);
+ break;
+ case (L1_MODE_TRANS):
+ cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0xe4);
+ break;
+ case (L1_MODE_HDLC):
+ cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x8c);
+ break;
+ }
+ if (mode)
+ cs->BC_Write_Reg(cs, hscx, HSCX_CMDR, 0x41);
+ cs->BC_Write_Reg(cs, hscx, HSCX_ISTA, 0x00);
+}
+
+void
+hscx_sched_event(struct BCState *bcs, int event)
+{
+ bcs->event |= 1 << event;
+ queue_task(&bcs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static void
+hscx_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ long flags;
+
+ switch (pr) {
+ case (PH_DATA_REQ):
+ save_flags(flags);
+ cli();
+ if (st->l1.bcs->hw.hscx.tx_skb) {
+ skb_queue_tail(&st->l1.bcs->squeue, skb);
+ restore_flags(flags);
+ } else {
+ st->l1.bcs->hw.hscx.tx_skb = skb;
+ test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ st->l1.bcs->hw.hscx.count = 0;
+ restore_flags(flags);
+ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+ }
+ break;
+ case (PH_PULL_IND):
+ if (st->l1.bcs->hw.hscx.tx_skb) {
+ printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n");
+ break;
+ }
+ test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ st->l1.bcs->hw.hscx.tx_skb = skb;
+ st->l1.bcs->hw.hscx.count = 0;
+ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+ break;
+ case (PH_PULL_REQ):
+ if (!st->l1.bcs->hw.hscx.tx_skb) {
+ test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ st->l1.l1l2(st, PH_PULL_CNF, NULL);
+ } else
+ test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ }
+
+}
+
+void
+close_hscxstate(struct BCState *bcs)
+{
+ struct sk_buff *skb;
+
+ modehscx(bcs, 0, 0);
+ if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+ if (bcs->hw.hscx.rcvbuf) {
+ kfree(bcs->hw.hscx.rcvbuf);
+ bcs->hw.hscx.rcvbuf = NULL;
+ }
+ while ((skb = skb_dequeue(&bcs->rqueue))) {
+ dev_kfree_skb(skb);
+ }
+ while ((skb = skb_dequeue(&bcs->squeue))) {
+ dev_kfree_skb(skb);
+ }
+ if (bcs->hw.hscx.tx_skb) {
+ dev_kfree_skb(bcs->hw.hscx.tx_skb);
+ bcs->hw.hscx.tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ }
+ }
+}
+
+static int
+open_hscxstate(struct IsdnCardState *cs,
+ int bc)
+{
+ struct BCState *bcs = cs->bcs + bc;
+
+ if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+ if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for hscx.rcvbuf\n");
+ return (1);
+ }
+ skb_queue_head_init(&bcs->rqueue);
+ skb_queue_head_init(&bcs->squeue);
+ }
+ bcs->hw.hscx.tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ bcs->event = 0;
+ bcs->hw.hscx.rcvidx = 0;
+ bcs->tx_cnt = 0;
+ return (0);
+}
+
+static void
+hscx_manl1(struct PStack *st, int pr,
+ void *arg)
+{
+ switch (pr) {
+ case (PH_ACTIVATE_REQ):
+ test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ modehscx(st->l1.bcs, st->l1.mode, st->l1.bc);
+ st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
+ break;
+ case (PH_DEACTIVATE_REQ):
+ if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
+ modehscx(st->l1.bcs, 0, 0);
+ test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ break;
+ }
+}
+
+int
+setstack_hscx(struct PStack *st, struct BCState *bcs)
+{
+ if (open_hscxstate(st->l1.hardware, bcs->channel))
+ return (-1);
+ st->l1.bcs = bcs;
+ st->l2.l2l1 = hscx_l2l1;
+ st->ma.manl1 = hscx_manl1;
+ setstack_manager(st);
+ bcs->st = st;
+ return (0);
+}
+
+HISAX_INITFUNC(void
+clear_pending_hscx_ints(struct IsdnCardState *cs))
+{
+ int val;
+ char tmp[64];
+
+ val = cs->BC_Read_Reg(cs, 1, HSCX_ISTA);
+ sprintf(tmp, "HSCX B ISTA %x", val);
+ debugl1(cs, tmp);
+ if (val & 0x01) {
+ val = cs->BC_Read_Reg(cs, 1, HSCX_EXIR);
+ sprintf(tmp, "HSCX B EXIR %x", val);
+ debugl1(cs, tmp);
+ } else if (val & 0x02) {
+ val = cs->BC_Read_Reg(cs, 0, HSCX_EXIR);
+ sprintf(tmp, "HSCX A EXIR %x", val);
+ debugl1(cs, tmp);
+ }
+ val = cs->BC_Read_Reg(cs, 0, HSCX_ISTA);
+ sprintf(tmp, "HSCX A ISTA %x", val);
+ debugl1(cs, tmp);
+ val = cs->BC_Read_Reg(cs, 1, HSCX_STAR);
+ sprintf(tmp, "HSCX B STAR %x", val);
+ debugl1(cs, tmp);
+ val = cs->BC_Read_Reg(cs, 0, HSCX_STAR);
+ sprintf(tmp, "HSCX A STAR %x", val);
+ debugl1(cs, tmp);
+ cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0xFF);
+ cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF);
+ cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0);
+ cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0);
+}
+
+HISAX_INITFUNC(void
+inithscx(struct IsdnCardState *cs))
+{
+ cs->bcs[0].BC_SetStack = setstack_hscx;
+ cs->bcs[1].BC_SetStack = setstack_hscx;
+ cs->bcs[0].BC_Close = close_hscxstate;
+ cs->bcs[1].BC_Close = close_hscxstate;
+ modehscx(cs->bcs, 0, 0);
+ modehscx(cs->bcs + 1, 0, 0);
+}
diff --git a/drivers/isdn/hisax/hscx.h b/drivers/isdn/hisax/hscx.h
new file mode 100644
index 000000000..ac2d38086
--- /dev/null
+++ b/drivers/isdn/hisax/hscx.h
@@ -0,0 +1,46 @@
+/* $Id: hscx.h,v 1.3 1997/07/27 21:38:35 keil Exp $
+
+ * hscx.h HSCX specific defines
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hscx.h,v $
+ * Revision 1.3 1997/07/27 21:38:35 keil
+ * new B-channel interface
+ *
+ * Revision 1.2 1997/06/26 11:16:18 keil
+ * first version
+ *
+ *
+ */
+
+/* All Registers original Siemens Spec */
+
+#define HSCX_ISTA 0x20
+#define HSCX_CCR1 0x2f
+#define HSCX_CCR2 0x2c
+#define HSCX_TSAR 0x31
+#define HSCX_TSAX 0x30
+#define HSCX_XCCR 0x32
+#define HSCX_RCCR 0x33
+#define HSCX_MODE 0x22
+#define HSCX_CMDR 0x21
+#define HSCX_EXIR 0x24
+#define HSCX_XAD1 0x24
+#define HSCX_XAD2 0x25
+#define HSCX_RAH2 0x27
+#define HSCX_RSTA 0x27
+#define HSCX_TIMR 0x23
+#define HSCX_STAR 0x21
+#define HSCX_RBCL 0x25
+#define HSCX_XBCH 0x2d
+#define HSCX_VSTR 0x2e
+#define HSCX_RLCR 0x2e
+#define HSCX_MASK 0x20
+
+extern int HscxVersion(struct IsdnCardState *cs, char *s);
+extern void hscx_sched_event(struct BCState *bcs, int event);
+extern void modehscx(struct BCState *bcs, int mode, int bc);
+extern void clear_pending_hscx_ints(struct IsdnCardState *cs);
+extern void inithscx(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c
new file mode 100644
index 000000000..64e80e7b2
--- /dev/null
+++ b/drivers/isdn/hisax/hscx_irq.c
@@ -0,0 +1,320 @@
+/* $Id: hscx_irq.c,v 1.7 1998/02/12 23:07:37 keil Exp $
+
+ * hscx_irq.c low level b-channel stuff for Siemens HSCX
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * This is an include file for fast inline IRQ stuff
+ *
+ * $Log: hscx_irq.c,v $
+ * Revision 1.7 1998/02/12 23:07:37 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.6 1997/10/29 19:01:07 keil
+ * changes for 2.1
+ *
+ * Revision 1.5 1997/10/01 09:21:35 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.4 1997/08/15 17:48:02 keil
+ * cosmetic
+ *
+ * Revision 1.3 1997/07/27 21:38:36 keil
+ * new B-channel interface
+ *
+ * Revision 1.2 1997/06/26 11:16:19 keil
+ * first version
+ *
+ *
+ */
+
+
+static inline void
+waitforCEC(struct IsdnCardState *cs, int hscx)
+{
+ int to = 50;
+
+ while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "HiSax: waitforCEC timeout\n");
+}
+
+
+static inline void
+waitforXFW(struct IsdnCardState *cs, int hscx)
+{
+ int to = 50;
+
+ while ((!(READHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "HiSax: waitforXFW timeout\n");
+}
+
+static inline void
+WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ waitforCEC(cs, hscx);
+ WRITEHSCX(cs, hscx, HSCX_CMDR, data);
+ restore_flags(flags);
+}
+
+
+
+static void
+hscx_empty_fifo(struct BCState *bcs, int count)
+{
+ u_char *ptr;
+ struct IsdnCardState *cs = bcs->cs;
+ long flags;
+
+ if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+ debugl1(cs, "hscx_empty_fifo");
+
+ if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "hscx_empty_fifo: incoming packet too large");
+ WriteHSCXCMDR(cs, bcs->channel, 0x80);
+ bcs->hw.hscx.rcvidx = 0;
+ return;
+ }
+ ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+ bcs->hw.hscx.rcvidx += count;
+ save_flags(flags);
+ cli();
+ READHSCXFIFO(cs, bcs->channel, ptr, count);
+ WriteHSCXCMDR(cs, bcs->channel, 0x80);
+ restore_flags(flags);
+ if (cs->debug & L1_DEB_HSCX_FIFO) {
+ char tmp[256];
+ char *t = tmp;
+
+ t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+ bcs->channel ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(cs, tmp);
+ }
+}
+
+static void
+hscx_fill_fifo(struct BCState *bcs)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ int more, count;
+ int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
+ u_char *ptr;
+ long flags;
+
+
+ if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+ debugl1(cs, "hscx_fill_fifo");
+
+ if (!bcs->hw.hscx.tx_skb)
+ return;
+ if (bcs->hw.hscx.tx_skb->len <= 0)
+ return;
+
+ more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
+ if (bcs->hw.hscx.tx_skb->len > fifo_size) {
+ more = !0;
+ count = fifo_size;
+ } else
+ count = bcs->hw.hscx.tx_skb->len;
+
+ waitforXFW(cs, bcs->channel);
+ save_flags(flags);
+ cli();
+ ptr = bcs->hw.hscx.tx_skb->data;
+ skb_pull(bcs->hw.hscx.tx_skb, count);
+ bcs->tx_cnt -= count;
+ bcs->hw.hscx.count += count;
+ WRITEHSCXFIFO(cs, bcs->channel, ptr, count);
+ WriteHSCXCMDR(cs, bcs->channel, more ? 0x8 : 0xa);
+ restore_flags(flags);
+ if (cs->debug & L1_DEB_HSCX_FIFO) {
+ char tmp[256];
+ char *t = tmp;
+
+ t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+ bcs->channel ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(cs, tmp);
+ }
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
+{
+ u_char r;
+ struct BCState *bcs = cs->bcs + hscx;
+ struct sk_buff *skb;
+ int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
+ int count;
+ char tmp[32];
+
+ if (!test_bit(BC_FLG_INIT, &bcs->Flag))
+ return;
+
+ if (val & 0x80) { /* RME */
+ r = READHSCX(cs, hscx, HSCX_RSTA);
+ if ((r & 0xf0) != 0xa0) {
+ if (!(r & 0x80))
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "HSCX invalid frame");
+ if ((r & 0x40) && bcs->mode)
+ if (cs->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX RDO mode=%d",
+ bcs->mode);
+ debugl1(cs, tmp);
+ }
+ if (!(r & 0x20))
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "HSCX CRC error");
+ WriteHSCXCMDR(cs, hscx, 0x80);
+ } else {
+ count = READHSCX(cs, hscx, HSCX_RBCL) & (
+ test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f);
+ if (count == 0)
+ count = fifo_size;
+ hscx_empty_fifo(bcs, count);
+ if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
+ if (cs->debug & L1_DEB_HSCX_FIFO) {
+ sprintf(tmp, "HX Frame %d", count);
+ debugl1(cs, tmp);
+ }
+ if (!(skb = dev_alloc_skb(count)))
+ printk(KERN_WARNING "HSCX: receive out of memory\n");
+ else {
+ memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
+ skb_queue_tail(&bcs->rqueue, skb);
+ }
+ }
+ }
+ bcs->hw.hscx.rcvidx = 0;
+ hscx_sched_event(bcs, B_RCVBUFREADY);
+ }
+ if (val & 0x40) { /* RPF */
+ hscx_empty_fifo(bcs, fifo_size);
+ if (bcs->mode == L1_MODE_TRANS) {
+ /* receive audio data */
+ if (!(skb = dev_alloc_skb(fifo_size)))
+ printk(KERN_WARNING "HiSax: receive out of memory\n");
+ else {
+ memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
+ skb_queue_tail(&bcs->rqueue, skb);
+ }
+ bcs->hw.hscx.rcvidx = 0;
+ hscx_sched_event(bcs, B_RCVBUFREADY);
+ }
+ }
+ if (val & 0x10) { /* XPR */
+ if (bcs->hw.hscx.tx_skb)
+ if (bcs->hw.hscx.tx_skb->len) {
+ hscx_fill_fifo(bcs);
+ return;
+ } else {
+ if (bcs->st->lli.l1writewakeup &&
+ (PACKET_NOACK != bcs->hw.hscx.tx_skb->pkt_type))
+ bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
+ dev_kfree_skb(bcs->hw.hscx.tx_skb);
+ bcs->hw.hscx.count = 0;
+ bcs->hw.hscx.tx_skb = NULL;
+ }
+ if ((bcs->hw.hscx.tx_skb = skb_dequeue(&bcs->squeue))) {
+ bcs->hw.hscx.count = 0;
+ test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+ hscx_fill_fifo(bcs);
+ } else {
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ hscx_sched_event(bcs, B_XMTBUFREADY);
+ }
+ }
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *cs, u_char val)
+{
+
+ u_char exval;
+ struct BCState *bcs;
+ char tmp[32];
+
+ if (val & 0x01) {
+ bcs = cs->bcs + 1;
+ exval = READHSCX(cs, 1, HSCX_EXIR);
+ if (exval == 0x40) {
+ if (bcs->mode == 1)
+ hscx_fill_fifo(bcs);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (bcs->hw.hscx.tx_skb) {
+ skb_push(bcs->hw.hscx.tx_skb, bcs->hw.hscx.count);
+ bcs->tx_cnt += bcs->hw.hscx.count;
+ bcs->hw.hscx.count = 0;
+ }
+ WriteHSCXCMDR(cs, bcs->channel, 0x01);
+ if (cs->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+ debugl1(cs, tmp);
+ }
+ }
+ } else if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX B EXIR %x", exval);
+ debugl1(cs, tmp);
+ }
+ }
+ if (val & 0xf8) {
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX B interrupt %x", val);
+ debugl1(cs, tmp);
+ }
+ hscx_interrupt(cs, val, 1);
+ }
+ if (val & 0x02) {
+ bcs = cs->bcs;
+ exval = READHSCX(cs, 0, HSCX_EXIR);
+ if (exval == 0x40) {
+ if (bcs->mode == L1_MODE_TRANS)
+ hscx_fill_fifo(bcs);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (bcs->hw.hscx.tx_skb) {
+ skb_push(bcs->hw.hscx.tx_skb, bcs->hw.hscx.count);
+ bcs->tx_cnt += bcs->hw.hscx.count;
+ bcs->hw.hscx.count = 0;
+ }
+ WriteHSCXCMDR(cs, bcs->channel, 0x01);
+ if (cs->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+ debugl1(cs, tmp);
+ }
+ }
+ } else if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX A EXIR %x", exval);
+ debugl1(cs, tmp);
+ }
+ }
+ if (val & 0x04) {
+ exval = READHSCX(cs, 0, HSCX_ISTA);
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX A interrupt %x", exval);
+ debugl1(cs, tmp);
+ }
+ hscx_interrupt(cs, exval, 0);
+ }
+}
diff --git a/drivers/isdn/hisax/ipac.h b/drivers/isdn/hisax/ipac.h
new file mode 100644
index 000000000..6d856ec6c
--- /dev/null
+++ b/drivers/isdn/hisax/ipac.h
@@ -0,0 +1,35 @@
+/* $Id: ipac.h,v 1.2 1997/10/29 18:51:21 keil Exp $
+
+ * ipac.h IPAC specific defines
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: ipac.h,v $
+ * Revision 1.2 1997/10/29 18:51:21 keil
+ * New files
+ *
+ * Revision 1.1.2.1 1997/10/17 22:10:48 keil
+ * new files on 2.0
+ *
+ *
+ *
+ */
+
+
+/* All Registers original Siemens Spec */
+
+#define IPAC_CONF 0xC0
+#define IPAC_MASK 0xC1
+#define IPAC_ISTA 0xC1
+#define IPAC_ID 0xC2
+#define IPAC_ACFG 0xC3
+#define IPAC_AOE 0xC4
+#define IPAC_ARX 0xC5
+#define IPAC_PITA1 0xC6
+#define IPAC_PITA2 0xC7
+#define IPAC_POTA1 0xC8
+#define IPAC_POTA2 0xC9
+#define IPAC_PCFG 0xCA
+#define IPAC_SCFG 0xCB
+#define IPAC_TIMR2 0xCC
diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c
new file mode 100644
index 000000000..9a2624ef4
--- /dev/null
+++ b/drivers/isdn/hisax/isac.c
@@ -0,0 +1,679 @@
+/* $Id: isac.c,v 1.12 1998/02/12 23:07:40 keil Exp $
+
+ * isac.c ISAC specific routines
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: isac.c,v $
+ * Revision 1.12 1998/02/12 23:07:40 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.11 1998/02/09 10:54:49 keil
+ * fixes for leased mode
+ *
+ * Revision 1.10 1998/02/02 13:37:37 keil
+ * new init
+ *
+ * Revision 1.9 1997/11/06 17:09:07 keil
+ * New 2.1 init code
+ *
+ * Revision 1.8 1997/10/29 19:00:03 keil
+ * new layer1,changes for 2.1
+ *
+ * Revision 1.7 1997/10/01 09:21:37 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.6 1997/08/15 17:47:08 keil
+ * avoid oops because a uninitialised timer
+ *
+ * Revision 1.5 1997/08/07 17:48:49 keil
+ * fix wrong parenthesis
+ *
+ * Revision 1.4 1997/07/30 17:11:59 keil
+ * fixed Timer3
+ *
+ * Revision 1.3 1997/07/27 21:37:40 keil
+ * T3 implemented; supervisor l1timer; B-channel TEST_LOOP
+ *
+ * Revision 1.2 1997/06/26 11:16:15 keil
+ * first version
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+
+#define DBUSY_TIMER_VALUE 80
+#define ARCOFI_USE 1
+
+static char *ISACVer[] HISAX_INITDATA =
+{"2086/2186 V1.1", "2085 B1", "2085 B2",
+ "2085 V2.3"};
+
+void
+ISACVersion(struct IsdnCardState *cs, char *s)
+{
+ int val;
+
+ val = cs->readisac(cs, ISAC_RBCH);
+ printk(KERN_INFO "%s ISAC version : %s\n", s, ISACVer[(val >> 5) & 3]);
+}
+
+static void
+ph_command(struct IsdnCardState *cs, unsigned int command)
+{
+ if (cs->debug & L1_DEB_ISAC) {
+ char tmp[32];
+ sprintf(tmp, "ph_command %x", command);
+ debugl1(cs, tmp);
+ }
+ cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3);
+}
+
+static void
+manl1_msg(struct IsdnCardState *cs, int msg, void *arg) {
+ struct PStack *st;
+
+ st = cs->stlist;
+ while (st) {
+ st->ma.manl1(st, msg, arg);
+ st = st->next;
+ }
+}
+
+static void
+isac_new_ph(struct IsdnCardState *cs)
+{
+ switch (cs->ph_state) {
+ case (ISAC_IND_RS):
+ case (ISAC_IND_EI):
+ ph_command(cs, ISAC_CMD_DUI);
+ manl1_msg(cs, PH_RESET_IND, NULL);
+ break;
+ case (ISAC_IND_DID):
+ manl1_msg(cs, PH_DEACT_CNF, NULL);
+ break;
+ case (ISAC_IND_DR):
+ manl1_msg(cs, PH_DEACT_IND, NULL);
+ break;
+ case (ISAC_IND_PU):
+ manl1_msg(cs, PH_POWERUP_CNF, NULL);
+ break;
+ case (ISAC_IND_RSY):
+ manl1_msg(cs, PH_RSYNC_IND, NULL);
+ break;
+ case (ISAC_IND_ARD):
+ manl1_msg(cs, PH_INFO2_IND, NULL);
+ break;
+ case (ISAC_IND_AI8):
+ manl1_msg(cs, PH_I4_P8_IND, NULL);
+ break;
+ case (ISAC_IND_AI10):
+ manl1_msg(cs, PH_I4_P10_IND, NULL);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+isac_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_CNF, NULL);
+ stptr = stptr->next;
+ }
+ }
+ if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
+ isac_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 (test_and_clear_bit(D_RX_MON0, &cs->event))
+ test_and_set_bit(HW_MON0_TX_END, &cs->HW_Flags);
+ if (test_and_clear_bit(D_RX_MON1, &cs->event))
+ test_and_set_bit(HW_MON1_TX_END, &cs->HW_Flags);
+ if (test_and_clear_bit(D_TX_MON0, &cs->event))
+ test_and_set_bit(HW_MON0_RX_END, &cs->HW_Flags);
+ if (test_and_clear_bit(D_TX_MON1, &cs->event))
+ test_and_set_bit(HW_MON1_RX_END, &cs->HW_Flags);
+}
+
+void
+isac_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, "isac_empty_fifo");
+
+ if ((cs->rcvidx + count) >= MAX_DFRAME_LEN) {
+ if (cs->debug & L1_DEB_WARN) {
+ char tmp[40];
+ sprintf(tmp, "isac_empty_fifo overrun %d",
+ cs->rcvidx + count);
+ debugl1(cs, tmp);
+ }
+ cs->writeisac(cs, ISAC_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, ISAC_CMDR, 0x80);
+ restore_flags(flags);
+ if (cs->debug & L1_DEB_ISAC_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "isac_empty_fifo cnt %d", count);
+ QuickHex(t, ptr, count);
+ debugl1(cs, tmp);
+ }
+}
+
+static void
+isac_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, "isac_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, ISAC_CMDR, more ? 0x8 : 0xa);
+ restore_flags(flags);
+ if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+ debugl1(cs, "isac_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);
+ if (cs->debug & L1_DEB_ISAC_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "isac_fill_fifo cnt %d", count);
+ QuickHex(t, ptr, count);
+ debugl1(cs, tmp);
+ }
+}
+
+void
+isac_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
+isac_interrupt(struct IsdnCardState *cs, u_char val)
+{
+ u_char exval, v1;
+ struct sk_buff *skb;
+ unsigned int count;
+ long flags;
+ char tmp[32];
+
+ if (cs->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "ISAC interrupt %x", val);
+ debugl1(cs, tmp);
+ }
+ if (val & 0x80) { /* RME */
+ exval = cs->readisac(cs, ISAC_RSTA);
+ if ((exval & 0x70) != 0x20) {
+ if (exval & 0x40)
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ISAC RDO");
+ if (!(exval & 0x20))
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ISAC CRC error");
+ cs->writeisac(cs, ISAC_CMDR, 0x80);
+ } else {
+ count = cs->readisac(cs, ISAC_RBCL) & 0x1f;
+ if (count == 0)
+ count = 32;
+ isac_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;
+ isac_sched_event(cs, D_RCVBUFREADY);
+ }
+ if (val & 0x40) { /* RPF */
+ isac_empty_fifo(cs, 32);
+ }
+ if (val & 0x20) { /* RSC */
+ /* never */
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ISAC 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))
+ isac_sched_event(cs, D_CLEARBUSY);
+ if (cs->tx_skb)
+ if (cs->tx_skb->len) {
+ isac_fill_fifo(cs);
+ goto afterXPR;
+ } else {
+ dev_kfree_skb(cs->tx_skb);
+ cs->tx_cnt = 0;
+ cs->tx_skb = NULL;
+ }
+ if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+ cs->tx_cnt = 0;
+ isac_fill_fifo(cs);
+ } else
+ isac_sched_event(cs, D_XMTBUFREADY);
+ }
+ afterXPR:
+ if (val & 0x04) { /* CISQ */
+ cs->ph_state = (cs->readisac(cs, ISAC_CIX0) >> 2) & 0xf;
+ if (cs->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "ph_state change %x", cs->ph_state);
+ debugl1(cs, tmp);
+ }
+ isac_sched_event(cs, D_L1STATECHANGE);
+ }
+ if (val & 0x02) { /* SIN */
+ /* never */
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ISAC SIN interrupt");
+ }
+ if (val & 0x01) { /* EXI */
+ exval = cs->readisac(cs, ISAC_EXIR);
+ if (cs->debug & L1_DEB_WARN) {
+ sprintf(tmp, "ISAC EXIR %02x", exval);
+ debugl1(cs, tmp);
+ }
+ if (exval & 0x04) {
+ v1 = cs->readisac(cs, ISAC_MOSR);
+ if (cs->debug & L1_DEB_WARN) {
+ sprintf(tmp, "ISAC MOSR %02x", v1);
+ debugl1(cs, tmp);
+ }
+#if ARCOFI_USE
+ if (v1 & 0x08) {
+ if (!cs->mon_rx)
+ if (!(cs->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ISAC MON RX out of memory!");
+ cs->mocr &= 0xf0;
+ cs->mocr |= 0x0a;
+ cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ goto afterMONR0;
+ } else
+ cs->mon_rxp = 0;
+ if (cs->mon_rxp >= MAX_MON_FRAME) {
+ cs->mocr &= 0xf0;
+ cs->mocr |= 0x0a;
+ cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ cs->mon_rxp = 0;
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ISAC MON RX overflow!");
+ goto afterMONR0;
+ }
+ cs->mon_rx[cs->mon_rxp++] = cs->readisac(cs, ISAC_MOR0);
+ if (cs->debug & L1_DEB_WARN) {
+ sprintf(tmp, "ISAC MOR0 %02x", cs->mon_rx[cs->mon_rxp -1]);
+ debugl1(cs, tmp);
+ }
+ if (cs->mon_rxp == 1) {
+ cs->mocr |= 0x04;
+ cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ }
+ }
+ afterMONR0:
+ if (v1 & 0x80) {
+ if (!cs->mon_rx)
+ if (!(cs->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ISAC MON RX out of memory!");
+ cs->mocr &= 0x0f;
+ cs->mocr |= 0xa0;
+ cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ goto afterMONR1;
+ } else
+ cs->mon_rxp = 0;
+ if (cs->mon_rxp >= MAX_MON_FRAME) {
+ cs->mocr &= 0x0f;
+ cs->mocr |= 0xa0;
+ cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ cs->mon_rxp = 0;
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ISAC MON RX overflow!");
+ goto afterMONR1;
+ }
+ cs->mon_rx[cs->mon_rxp++] = cs->readisac(cs, ISAC_MOR1);
+ if (cs->debug & L1_DEB_WARN) {
+ sprintf(tmp, "ISAC MOR1 %02x", cs->mon_rx[cs->mon_rxp -1]);
+ debugl1(cs, tmp);
+ }
+ if (cs->mon_rxp == 1) {
+ cs->mocr |= 0x40;
+ cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ }
+ }
+ afterMONR1:
+ if (v1 & 0x04) {
+ cs->mocr &= 0xf0;
+ cs->mocr |= 0x0a;
+ cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ isac_sched_event(cs, D_RX_MON0);
+ }
+ if (v1 & 0x40) {
+ cs->mocr &= 0x0f;
+ cs->mocr |= 0xa0;
+ cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ isac_sched_event(cs, D_RX_MON1);
+ }
+ if (v1 & 0x02) {
+ if (!cs->mon_tx) {
+ cs->mocr &= 0xf0;
+ cs->mocr |= 0x0a;
+ cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ goto AfterMOX0;
+ }
+ if (cs->mon_txp >= cs->mon_txc) {
+ if (cs->mon_txc)
+ isac_sched_event(cs, D_TX_MON0);
+ goto AfterMOX0;
+ }
+ cs->writeisac(cs, ISAC_MOX0,
+ cs->mon_tx[cs->mon_txp++]);
+ if (cs->debug & L1_DEB_WARN) {
+ sprintf(tmp, "ISAC %02x -> MOX0", cs->mon_tx[cs->mon_txp -1]);
+ debugl1(cs, tmp);
+ }
+ }
+ AfterMOX0:
+ if (v1 & 0x20) {
+ if (!cs->mon_tx) {
+ cs->mocr &= 0x0f;
+ cs->mocr |= 0xa0;
+ cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ goto AfterMOX1;
+ }
+ if (cs->mon_txp >= cs->mon_txc) {
+ if (cs->mon_txc)
+ isac_sched_event(cs, D_TX_MON1);
+ goto AfterMOX1;
+ }
+ cs->writeisac(cs, ISAC_MOX1,
+ cs->mon_tx[cs->mon_txp++]);
+ if (cs->debug & L1_DEB_WARN) {
+ sprintf(tmp, "ISAC %02x -> MOX1", cs->mon_tx[cs->mon_txp -1]);
+ debugl1(cs, tmp);
+ }
+ }
+ AfterMOX1:
+#endif
+ }
+ }
+}
+
+static void
+ISAC_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+ struct sk_buff *skb = arg;
+ char str[64];
+
+ switch (pr) {
+ case (PH_DATA_REQ):
+ 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 {
+ if ((cs->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */
+ LogFrame(cs, skb->data, skb->len);
+ sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+ dlogframe(cs, skb->data + 4, skb->len - 4,
+ str);
+ }
+ 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
+ isac_fill_fifo(cs);
+ }
+ break;
+ case (PH_PULL_IND):
+ 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->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */
+ LogFrame(cs, skb->data, skb->len);
+ sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+ dlogframe(cs, skb->data + 4, skb->len - 4,
+ str);
+ }
+ 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
+ isac_fill_fifo(cs);
+ break;
+ case (PH_PULL_REQ):
+#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_CNF, NULL);
+ } else
+ test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ }
+}
+
+void
+isac_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
+{
+ u_char val;
+ char tmp[32];
+
+ switch(msg) {
+ case PH_RESET_REQ:
+ if ((cs->ph_state == ISAC_IND_EI) ||
+ (cs->ph_state == ISAC_IND_DR) ||
+ (cs->ph_state == ISAC_IND_RS))
+ ph_command(cs, ISAC_CMD_TIM);
+ else
+ ph_command(cs, ISAC_CMD_RS);
+ break;
+ case PH_ENABLE_REQ:
+ ph_command(cs, ISAC_CMD_TIM);
+ break;
+ case PH_INFO3_REQ:
+ ph_command(cs, ISAC_CMD_AR8);
+ break;
+ case PH_TESTLOOP_REQ:
+ val = 0;
+ if (1 & (int) arg)
+ val |= 0x0c;
+ if (2 & (int) arg)
+ val |= 0x3;
+ if (test_bit(HW_IOM1, &cs->HW_Flags)) {
+ /* IOM 1 Mode */
+ if (!val) {
+ cs->writeisac(cs, ISAC_SPCR, 0xa);
+ cs->writeisac(cs, ISAC_ADF1, 0x2);
+ } else {
+ cs->writeisac(cs, ISAC_SPCR, val);
+ cs->writeisac(cs, ISAC_ADF1, 0xa);
+ }
+ } else {
+ /* IOM 2 Mode */
+ cs->writeisac(cs, ISAC_SPCR, val);
+ if (val)
+ cs->writeisac(cs, ISAC_ADF1, 0x8);
+ else
+ cs->writeisac(cs, ISAC_ADF1, 0x0);
+ }
+ break;
+ default:
+ if (cs->debug & L1_DEB_WARN) {
+ sprintf(tmp, "isac_l1cmd unknown %4x", msg);
+ debugl1(cs, tmp);
+ }
+ break;
+ }
+}
+
+void
+setstack_isac(struct PStack *st, struct IsdnCardState *cs)
+{
+ st->l2.l2l1 = ISAC_l2l1;
+}
+
+static void
+dbusy_timer_handler(struct IsdnCardState *cs)
+{
+ struct PStack *stptr;
+
+ if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+ if (cs->debug)
+ debugl1(cs, "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_IND, NULL);
+ stptr = stptr->next;
+ }
+ }
+}
+
+HISAX_INITFUNC(void
+initisac(struct IsdnCardState *cs))
+{
+ cs->tqueue.routine = (void *) (void *) isac_bh;
+ cs->l1cmd = isac_l1cmd;
+ cs->setstack_d = setstack_isac;
+ cs->dbusytimer.function = (void *) dbusy_timer_handler;
+ cs->dbusytimer.data = (long) cs;
+ init_timer(&cs->dbusytimer);
+ cs->writeisac(cs, ISAC_MASK, 0xff);
+ cs->mocr = 0xaa;
+ if (test_bit(HW_IOM1, &cs->HW_Flags)) {
+ /* IOM 1 Mode */
+ cs->writeisac(cs, ISAC_ADF2, 0x0);
+ cs->writeisac(cs, ISAC_SPCR, 0xa);
+ cs->writeisac(cs, ISAC_ADF1, 0x2);
+ cs->writeisac(cs, ISAC_STCR, 0x70);
+ cs->writeisac(cs, ISAC_MODE, 0xc9);
+ } else {
+ /* IOM 2 Mode */
+ cs->writeisac(cs, ISAC_ADF2, 0x80);
+ cs->writeisac(cs, ISAC_SQXR, 0x2f);
+ cs->writeisac(cs, ISAC_SPCR, 0x00);
+ cs->writeisac(cs, ISAC_STCR, 0x70);
+ cs->writeisac(cs, ISAC_MODE, 0xc9);
+ cs->writeisac(cs, ISAC_TIMR, 0x00);
+ cs->writeisac(cs, ISAC_ADF1, 0x00);
+ }
+ ph_command(cs, ISAC_CMD_RS);
+ cs->writeisac(cs, ISAC_MASK, 0x0);
+}
+
+HISAX_INITFUNC(void
+clear_pending_isac_ints(struct IsdnCardState *cs))
+{
+ int val;
+ char tmp[64];
+
+ val = cs->readisac(cs, ISAC_STAR);
+ sprintf(tmp, "ISAC STAR %x", val);
+ debugl1(cs, tmp);
+ val = cs->readisac(cs, ISAC_MODE);
+ sprintf(tmp, "ISAC MODE %x", val);
+ debugl1(cs, tmp);
+ val = cs->readisac(cs, ISAC_ADF2);
+ sprintf(tmp, "ISAC ADF2 %x", val);
+ debugl1(cs, tmp);
+ val = cs->readisac(cs, ISAC_ISTA);
+ sprintf(tmp, "ISAC ISTA %x", val);
+ debugl1(cs, tmp);
+ if (val & 0x01) {
+ val = cs->readisac(cs, ISAC_EXIR);
+ sprintf(tmp, "ISAC EXIR %x", val);
+ debugl1(cs, tmp);
+ } else if (val & 0x04) {
+ val = cs->readisac(cs, ISAC_CIR0);
+ sprintf(tmp, "ISAC CIR0 %x", val);
+ debugl1(cs, tmp);
+ cs->ph_state = (val >> 2) & 0xf;
+ } else {
+ cs->ph_state = (cs->readisac(cs, ISAC_CIX0) >> 2) & 0xf;
+ }
+ isac_sched_event(cs, D_L1STATECHANGE);
+ cs->writeisac(cs, ISAC_MASK, 0xFF);
+ cs->writeisac(cs, ISAC_MASK, 0);
+ cs->writeisac(cs, ISAC_CMDR, 0x41);
+}
diff --git a/drivers/isdn/hisax/isac.h b/drivers/isdn/hisax/isac.h
new file mode 100644
index 000000000..ac4d55647
--- /dev/null
+++ b/drivers/isdn/hisax/isac.h
@@ -0,0 +1,74 @@
+/* $Id: isac.h,v 1.4 1997/10/29 19:09:34 keil Exp $
+
+ * isac.h ISAC specific defines
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: isac.h,v $
+ * Revision 1.4 1997/10/29 19:09:34 keil
+ * new L1
+ *
+ * Revision 1.3 1997/07/27 21:37:41 keil
+ * T3 implemented; supervisor l1timer; B-channel TEST_LOOP
+ *
+ * Revision 1.2 1997/06/26 11:16:16 keil
+ * first version
+ *
+ *
+ */
+
+
+/* All Registers original Siemens Spec */
+
+#define ISAC_MASK 0x20
+#define ISAC_ISTA 0x20
+#define ISAC_STAR 0x21
+#define ISAC_CMDR 0x21
+#define ISAC_EXIR 0x24
+#define ISAC_RBCH 0x2a
+#define ISAC_ADF2 0x39
+#define ISAC_SPCR 0x30
+#define ISAC_ADF1 0x38
+#define ISAC_CIR0 0x31
+#define ISAC_CIX0 0x31
+#define ISAC_STCR 0x37
+#define ISAC_MODE 0x22
+#define ISAC_RSTA 0x27
+#define ISAC_RBCL 0x25
+#define ISAC_TIMR 0x23
+#define ISAC_SQXR 0x3b
+#define ISAC_MOSR 0x3a
+#define ISAC_MOCR 0x3a
+#define ISAC_MOR0 0x32
+#define ISAC_MOX0 0x32
+#define ISAC_MOR1 0x34
+#define ISAC_MOX1 0x34
+
+#define ISAC_CMD_TIM 0x0
+#define ISAC_CMD_RS 0x1
+#define ISAC_CMD_SCZ 0x4
+#define ISAC_CMD_SSZ 0x2
+#define ISAC_CMD_AR8 0x8
+#define ISAC_CMD_AR10 0x9
+#define ISAC_CMD_ARL 0xA
+#define ISAC_CMD_DUI 0xF
+
+#define ISAC_IND_RS 0x1
+#define ISAC_IND_PU 0x7
+#define ISAC_IND_DR 0x0
+#define ISAC_IND_SD 0x2
+#define ISAC_IND_DIS 0x3
+#define ISAC_IND_EI 0x6
+#define ISAC_IND_RSY 0x4
+#define ISAC_IND_ARD 0x8
+#define ISAC_IND_TI 0xA
+#define ISAC_IND_ATI 0xB
+#define ISAC_IND_AI8 0xC
+#define ISAC_IND_AI10 0xD
+#define ISAC_IND_DID 0xF
+
+extern void ISACVersion(struct IsdnCardState *cs, char *s);
+extern void initisac(struct IsdnCardState *cs);
+extern void isac_interrupt(struct IsdnCardState *cs, u_char val);
+extern void clear_pending_isac_ints(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
index 655e6a417..8c4431b04 100644
--- a/drivers/isdn/hisax/isdnl1.c
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -1,4 +1,4 @@
-/* $Id: isdnl1.c,v 1.15 1997/05/27 15:17:55 fritz Exp $
+/* $Id: isdnl1.c,v 2.18 1998/02/12 23:07:42 keil Exp $
* isdnl1.c common low level stuff for Siemens Chipsetbased isdn cards
* based on the teles driver from Jan den Ouden
@@ -11,131 +11,239 @@
*
*
* $Log: isdnl1.c,v $
- * Revision 1.15 1997/05/27 15:17:55 fritz
- * Added changes for recent 2.1.x kernels:
- * changed return type of isdn_close
- * queue_task_* -> queue_task
- * clear/set_bit -> test_and_... where apropriate.
- * changed type of hard_header_cache parameter.
+ * Revision 2.18 1998/02/12 23:07:42 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 2.17 1998/02/11 17:28:07 keil
+ * Niccy PnP/PCI support
+ *
+ * Revision 2.16 1998/02/09 18:46:08 keil
+ * Support for Sedlbauer PCMCIA (Marcus Niemann)
*
- * Revision 1.14 1997/04/07 23:00:08 keil
- * GFP_KERNEL ---> GFP_ATOMIC
+ * Revision 2.15 1998/02/09 10:54:51 keil
+ * fixes for leased mode
*
- * Revision 1.13 1997/04/06 22:55:50 keil
- * Using SKB's
+ * Revision 2.14 1998/02/03 23:31:31 keil
+ * add AMD7930 support
*
- * Revision 1.12 1997/03/26 13:43:57 keil
- * small cosmetics
+ * Revision 2.13 1998/02/02 13:33:02 keil
+ * New card support
*
- * Revision 1.11 1997/03/25 23:11:23 keil
- * US NI-1 protocol
+ * Revision 2.12 1998/01/31 21:41:48 keil
+ * changes for newer 2.1 kernels
*
- * Revision 1.10 1997/03/13 14:45:05 keil
- * using IRQ proof queue_task
+ * Revision 2.11 1997/11/12 15:01:23 keil
+ * COMPAQ_ISA changes
*
- * Revision 1.9 1997/03/12 21:44:21 keil
- * change Interrupt routine from atomic quick to normal
+ * Revision 2.10 1997/11/08 21:35:48 keil
+ * new l1 init
*
- * Revision 1.8 1997/02/09 00:24:31 keil
- * new interface handling, one interface per card
+ * Revision 2.9 1997/11/06 17:09:18 keil
+ * New 2.1 init code
*
- * Revision 1.7 1997/01/27 15:56:03 keil
- * PCMCIA Teles card and ITK ix1 micro added
+ * Revision 2.8 1997/10/29 19:00:05 keil
+ * new layer1,changes for 2.1
*
- * Revision 1.6 1997/01/21 22:20:00 keil
- * changes for D-channel log; Elsa Quickstep support
+ * Revision 2.7 1997/10/10 20:56:50 fritz
+ * New HL interface.
*
- * Revision 1.5 1997/01/10 12:51:19 keil
- * cleanup; set newversion
+ * Revision 2.6 1997/09/12 10:05:16 keil
+ * ISDN_CTRL_DEBUG define
*
- * Revision 1.4 1996/12/08 19:44:53 keil
- * L2FRAME_DEBUG and other changes from Pekka Sarnila
+ * Revision 2.5 1997/09/11 17:24:45 keil
+ * Add new cards
*
- * Revision 1.3 1996/11/18 15:34:47 keil
- * fix HSCX version code
+ * Revision 2.4 1997/08/15 17:47:09 keil
+ * avoid oops because a uninitialised timer
*
- * Revision 1.2 1996/10/27 22:16:54 keil
- * ISAC/HSCX version lookup
+ * Revision 2.3 1997/08/01 11:16:40 keil
+ * cosmetics
*
- * Revision 1.1 1996/10/13 20:04:53 keil
- * Initial revision
+ * Revision 2.2 1997/07/30 17:11:08 keil
+ * L1deactivated exported
*
+ * Revision 2.1 1997/07/27 21:35:38 keil
+ * new layer1 interface
+ *
+ * Revision 2.0 1997/06/26 11:02:53 keil
+ * New Layer and card interface
+ *
+ * Revision 1.15 1997/05/27 15:17:55 fritz
+ * Added changes for recent 2.1.x kernels:
+ * changed return type of isdn_close
+ * queue_task_* -> queue_task
+ * clear/set_bit -> test_and_... where apropriate.
+ * changed type of hard_header_cache parameter.
*
+ * old changes removed KKe
*
*/
-const char *l1_revision = "$Revision: 1.15 $";
+const char *l1_revision = "$Revision: 2.18 $";
#define __NO_VERSION__
#include <linux/config.h>
#include "hisax.h"
#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+#if (LINUX_VERSION_CODE < 0x020150) /* 2.1.80 */
+#define kstat_irqs( PAR ) kstat.interrupts( (PAR) )
+#endif
+
+
#if CARD_TELES0
-#include "teles0.h"
+extern int setup_teles0(struct IsdnCard *card);
#endif
#if CARD_TELES3
-#include "teles3.h"
+extern int setup_teles3(struct IsdnCard *card);
#endif
#if CARD_AVM_A1
-#include "avm_a1.h"
+extern int setup_avm_a1(struct IsdnCard *card);
#endif
#if CARD_ELSA
-#include "elsa.h"
+extern int setup_elsa(struct IsdnCard *card);
#endif
#if CARD_IX1MICROR2
-#include "ix1_micro.h"
+extern int setup_ix1micro(struct IsdnCard *card);
#endif
-/* #define I4L_IRQ_FLAG SA_INTERRUPT */
-#define I4L_IRQ_FLAG 0
+#if CARD_DIEHLDIVA
+extern int setup_diva(struct IsdnCard *card);
+#endif
-#define HISAX_STATUS_BUFSIZE 4096
+#if CARD_ASUSCOM
+extern int setup_asuscom(struct IsdnCard *card);
+#endif
-#define INCLUDE_INLINE_FUNCS
-#include <linux/tqueue.h>
-#include <linux/interrupt.h>
+#if CARD_TELEINT
+extern int setup_TeleInt(struct IsdnCard *card);
+#endif
-const char *CardType[] =
-{"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3",
- "Creatix/Teles PnP", "AVM A1", "Elsa ML",
-#ifdef CONFIG_HISAX_ELSA_PCMCIA
- "Elsa PCMCIA",
-#else
- "Elsa Quickstep",
+#if CARD_SEDLBAUER
+extern int setup_sedlbauer(struct IsdnCard *card);
+#endif
+
+#if CARD_SPORTSTER
+extern int setup_sportster(struct IsdnCard *card);
+#endif
+
+#if CARD_MIC
+extern int setup_mic(struct IsdnCard *card);
#endif
- "Teles PCMCIA", "ITK ix1-micro Rev.2"};
-static char *HSCXVer[] =
-{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
- "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
+#if CARD_NETJET
+extern int setup_netjet(struct IsdnCard *card);
+#endif
+
+#if CARD_TELES3C
+extern int setup_t163c(struct IsdnCard *card);
+#endif
+
+#if CARD_AMD7930
+extern int setup_amd7930(struct IsdnCard *card);
+#endif
+
+#if CARD_NICCY
+extern int setup_niccy(struct IsdnCard *card);
+#endif
-static char *ISACVer[] =
-{"2086/2186 V1.1", "2085 B1", "2085 B2",
- "2085 V2.3"};
+#define HISAX_STATUS_BUFSIZE 4096
+#define ISDN_CTRL_DEBUG 1
+#define INCLUDE_INLINE_FUNCS
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+const char *CardType[] =
+{"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", "Creatix/Teles PnP",
+ "AVM A1", "Elsa ML", "Elsa Quickstep", "Teles PCMCIA", "ITK ix1-micro Rev.2",
+ "Elsa PCMCIA", "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c",
+ "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI",
+ "Compaq ISA", "NETjet", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)",
+ "AMD 7930", "NICCY"
+};
extern struct IsdnCard cards[];
extern int nrcards;
extern char *HiSax_id;
+extern struct IsdnBuffers *tracebuf;
+
+#define TIMER3_VALUE 7
+
+static
+struct Fsm l1fsm =
+{NULL, 0, 0, NULL, NULL};
+
+enum {
+ ST_L1_F2,
+ ST_L1_F3,
+ ST_L1_F4,
+ ST_L1_F5,
+ ST_L1_F6,
+ ST_L1_F7,
+ ST_L1_F8,
+};
+
+#define L1_STATE_COUNT (ST_L1_F8+1)
+
+static char *strL1State[] =
+{
+ "ST_L1_F2",
+ "ST_L1_F3",
+ "ST_L1_F4",
+ "ST_L1_F5",
+ "ST_L1_F6",
+ "ST_L1_F7",
+ "ST_L1_F8",
+};
+
+enum {
+ EV_PH_ACTIVATE,
+ EV_RESET_IND,
+ EV_DEACT_CNF,
+ EV_DEACT_IND,
+ EV_POWER_UP,
+ EV_RSYNC_IND,
+ EV_INFO2_IND,
+ EV_INFO4_IND,
+ EV_TIMER_DEACT,
+ EV_TIMER_ACT,
+ EV_TIMER3,
+};
+
+#define L1_EVENT_COUNT (EV_TIMER3 + 1)
+
+static char *strL1Event[] =
+{
+ "EV_PH_ACTIVATE",
+ "EV_RESET_IND",
+ "EV_DEACT_CNF",
+ "EV_DEACT_IND",
+ "EV_POWER_UP",
+ "EV_RSYNC_IND",
+ "EV_INFO2_IND",
+ "EV_INFO4_IND",
+ "EV_TIMER_DEACT",
+ "EV_TIMER_ACT",
+ "EV_TIMER3",
+};
/*
* Find card with given driverId
*/
static inline struct IsdnCardState
-*
-hisax_findcard(int driverid)
+*hisax_findcard(int driverid)
{
int i;
for (i = 0; i < nrcards; i++)
- if (cards[i].sp)
- if (cards[i].sp->myid == driverid)
- return (cards[i].sp);
- return (struct IsdnCardState *) 0;
+ if (cards[i].cs)
+ if (cards[i].cs->myid == driverid)
+ return (cards[i].cs);
+ return (NULL);
}
int
@@ -162,6 +270,7 @@ HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
}
}
+#if ISDN_CTRL_DEBUG
void
HiSax_putstatus(struct IsdnCardState *csta, char *buf)
{
@@ -194,6 +303,23 @@ HiSax_putstatus(struct IsdnCardState *csta, char *buf)
csta->iif.statcallb(&ic);
}
}
+#else
+#define KDEBUG_DEF
+#include "../kdebug.h"
+
+static int DbgLineNr=0,DbgSequenzNr=1;
+
+void
+HiSax_putstatus(struct IsdnCardState *csta, char *buf)
+{
+ char tmp[512];
+
+ if (DbgLineNr==23)
+ DbgLineNr=0;
+ sprintf(tmp, "%5d %s",DbgSequenzNr++,buf);
+ gput_str(tmp,0,DbgLineNr++);
+}
+#endif
int
ll_run(struct IsdnCardState *csta)
@@ -238,228 +364,119 @@ ll_unload(struct IsdnCardState *csta)
}
void
-debugl1(struct IsdnCardState *sp, char *msg)
+debugl1(struct IsdnCardState *cs, char *msg)
{
char tmp[256], tm[32];
jiftime(tm, jiffies);
- sprintf(tmp, "%s Card %d %s\n", tm, sp->cardnr + 1, msg);
- HiSax_putstatus(sp, tmp);
-}
-
-/*
- * HSCX stuff goes here
- */
-
-
-char *
-HscxVersion(u_char v)
-{
- return (HSCXVer[v & 0xf]);
-}
-
-void
-hscx_sched_event(struct HscxState *hsp, int event)
-{
- hsp->event |= 1 << event;
- queue_task(&hsp->tqueue, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
+ sprintf(tmp, "%s Card %d %s\n", tm, cs->cardnr + 1, msg);
+ HiSax_putstatus(cs, tmp);
}
-/*
- * ISAC stuff goes here
- */
-
-char *
-ISACVersion(u_char v)
+static void
+l1m_debug(struct FsmInst *fi, char *s)
{
- return (ISACVer[(v >> 5) & 3]);
+ struct PStack *st = fi->userdata;
+
+ debugl1(st->l1.hardware, s);
}
void
-isac_sched_event(struct IsdnCardState *sp, int event)
-{
- sp->event |= 1 << event;
- queue_task(&sp->tqueue, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-}
-
-int
-act_wanted(struct IsdnCardState *sp)
+L1activated(struct IsdnCardState *cs)
{
struct PStack *st;
- st = sp->stlist;
- while (st)
- if (st->l1.act_state)
- return (!0);
+ st = cs->stlist;
+ while (st) {
+ if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
+ st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
else
- st = st->next;
- return (0);
-}
-
-void
-isac_new_ph(struct IsdnCardState *sp)
-{
- int enq;
-
- enq = act_wanted(sp);
-
- switch (sp->ph_state) {
- case (6):
- sp->ph_active = 0;
- sp->ph_command(sp, 15);
- break;
- case (15):
- sp->ph_active = 0;
- if (enq)
- sp->ph_command(sp, 0);
- break;
- case (0):
- sp->ph_active = 0;
- if (enq)
- sp->ph_command(sp, 0);
-#if 0
- else
- sp->ph_command(sp, 15);
-#endif
- break;
- case (7):
- sp->ph_active = 0;
- if (enq)
- sp->ph_command(sp, 9);
- break;
- case (12):
- sp->ph_command(sp, 8);
- sp->ph_active = 5;
- isac_sched_event(sp, ISAC_PHCHANGE);
- if (!sp->tx_skb)
- sp->tx_skb = skb_dequeue(&sp->sq);
- if (sp->tx_skb) {
- sp->tx_cnt = 0;
- sp->isac_fill_fifo(sp);
- }
- break;
- case (13):
- sp->ph_command(sp, 9);
- sp->ph_active = 5;
- isac_sched_event(sp, ISAC_PHCHANGE);
- if (!sp->tx_skb)
- sp->tx_skb = skb_dequeue(&sp->sq);
- if (sp->tx_skb) {
- sp->tx_cnt = 0;
- sp->isac_fill_fifo(sp);
- }
- break;
- case (4):
- case (8):
- sp->ph_active = 0;
- break;
- default:
- sp->ph_active = 0;
- break;
- }
-}
-
-static void
-restart_ph(struct IsdnCardState *sp)
-{
- if (!sp->ph_active) {
- if ((sp->ph_state == 6) || (sp->ph_state == 0)) {
- sp->ph_command(sp, 0);
- sp->ph_active = 2;
- } else {
- sp->ph_command(sp, 1);
- sp->ph_active = 1;
- }
- } else if (sp->ph_active == 2) {
- sp->ph_command(sp, 1);
- sp->ph_active = 1;
+ st->l1.l1man(st, PH_ACTIVATE_IND, NULL);
+ st = st->next;
}
}
-
-static void
-act_ivated(struct IsdnCardState *sp)
+void
+L1deactivated(struct IsdnCardState *cs)
{
struct PStack *st;
- st = sp->stlist;
+ st = cs->stlist;
while (st) {
- if (st->l1.act_state == 1) {
- st->l1.act_state = 2;
- st->l1.l1man(st, PH_ACTIVATE, NULL);
- }
+ if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+ st->l1.l1l2(st, PH_PAUSE_CNF, NULL);
+ st->l1.l1man(st, PH_DEACTIVATE_IND, NULL);
st = st->next;
}
+ test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags);
}
-static void
-process_new_ph(struct IsdnCardState *sp)
-{
- if (sp->ph_active == 5)
- act_ivated(sp);
-}
-
-static void
-process_xmt(struct IsdnCardState *sp)
+void
+DChannel_proc_xmt(struct IsdnCardState *cs)
{
struct PStack *stptr;
- if (sp->tx_skb)
+ if (cs->tx_skb)
return;
- stptr = sp->stlist;
+ stptr = cs->stlist;
while (stptr != NULL)
- if (stptr->l1.requestpull) {
- stptr->l1.requestpull = 0;
- stptr->l1.l1l2(stptr, PH_PULL_ACK, NULL);
+ if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) {
+ stptr->l1.l1l2(stptr, PH_PULL_CNF, NULL);
break;
} else
stptr = stptr->next;
}
-static void
-process_rcv(struct IsdnCardState *sp)
+void
+DChannel_proc_rcv(struct IsdnCardState *cs)
{
struct sk_buff *skb, *nskb;
- struct PStack *stptr;
- int found, broadc;
+ struct PStack *stptr = cs->stlist;
+ int found, tei, sapi;
char tmp[64];
- while ((skb = skb_dequeue(&sp->rq))) {
+ if (stptr)
+ if (test_bit(FLG_L1_ACTTIMER, &stptr->l1.Flags))
+ FsmEvent(&stptr->l1.l1m, EV_TIMER_ACT, NULL);
+ while ((skb = skb_dequeue(&cs->rq))) {
#ifdef L2FRAME_DEBUG /* psa */
- if (sp->debug & L1_DEB_LAPD)
- Logl2Frame(sp, skb, "PH_DATA", 1);
+ if (cs->debug & L1_DEB_LAPD)
+ Logl2Frame(cs, skb, "PH_DATA", 1);
#endif
- stptr = sp->stlist;
- broadc = (skb->data[1] >> 1) == 127;
-
- if (broadc) {
- if (!(skb->data[0] >> 2)) { /* sapi 0 */
- sp->CallFlags = 3;
- if (sp->dlogflag) {
- LogFrame(sp, skb->data, skb->len);
- dlogframe(sp, skb->data + 3, skb->len - 3,
+ stptr = cs->stlist;
+ sapi = skb->data[0] >> 2;
+ tei = skb->data[1] >> 1;
+
+ if (tei == GROUP_TEI) {
+ if (sapi == CTRL_SAPI) { /* sapi 0 */
+ if (cs->dlogflag) {
+ LogFrame(cs, skb->data, skb->len);
+ dlogframe(cs, skb->data + 3, skb->len - 3,
"Q.931 frame network->user broadcast");
}
- }
- while (stptr != NULL) {
- if ((skb->data[0] >> 2) == stptr->l2.sap)
+ while (stptr != NULL) {
if ((nskb = skb_clone(skb, GFP_ATOMIC)))
- stptr->l1.l1l2(stptr, PH_DATA, nskb);
+ stptr->l1.l1l2(stptr, PH_DATA_IND, nskb);
else
printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n");
- stptr = stptr->next;
+ stptr = stptr->next;
+ }
+ } else if (sapi == TEI_SAPI) {
+ while (stptr != NULL) {
+ if ((nskb = skb_clone(skb, GFP_ATOMIC)))
+ stptr->l1.l1tei(stptr, PH_DATA_IND, nskb);
+ else
+ printk(KERN_WARNING "HiSax: tei broadcast buffer shortage\n");
+ stptr = stptr->next;
+ }
}
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
- } else {
+ } else if (sapi == CTRL_SAPI) {
found = 0;
while (stptr != NULL)
- if (((skb->data[0] >> 2) == stptr->l2.sap) &&
- ((skb->data[1] >> 1) == stptr->l2.tei)) {
- stptr->l1.l1l2(stptr, PH_DATA, skb);
+ if (tei == stptr->l2.tei) {
+ stptr->l1.l1l2(stptr, PH_DATA_IND, skb);
found = !0;
break;
} else
@@ -474,167 +491,70 @@ process_rcv(struct IsdnCardState *sp)
sprintf(tmp,
"Q.931 frame network->user with tei %d (not for us)",
skb->data[1] >> 1);
- LogFrame(sp, skb->data, skb->len);
- dlogframe(sp, skb->data + 4, skb->len - 4, tmp);
+ LogFrame(cs, skb->data, skb->len);
+ dlogframe(cs, skb->data + 4, skb->len - 4, tmp);
}
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
}
}
-
- }
-
-}
-
-static void
-isac_bh(struct IsdnCardState *sp)
-{
- if (!sp)
- return;
-
- if (test_and_clear_bit(ISAC_PHCHANGE, &sp->event))
- process_new_ph(sp);
- if (test_and_clear_bit(ISAC_RCVBUFREADY, &sp->event))
- process_rcv(sp);
- if (test_and_clear_bit(ISAC_XMTBUFREADY, &sp->event))
- process_xmt(sp);
-}
-
-static void
-l2l1(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
- struct sk_buff *skb = arg;
- char str[64];
-
- switch (pr) {
- case (PH_DATA):
- if (sp->tx_skb) {
- skb_queue_tail(&sp->sq, skb);
-#ifdef L2FRAME_DEBUG /* psa */
- if (sp->debug & L1_DEB_LAPD)
- Logl2Frame(sp, skb, "PH_DATA Queued", 0);
-#endif
- } else {
- if ((sp->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */
- LogFrame(sp, skb->data, skb->len);
- sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
- dlogframe(sp, skb->data + st->l2.ihsize, skb->len - st->l2.ihsize,
- str);
- }
- sp->tx_skb = skb;
- sp->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (sp->debug & L1_DEB_LAPD)
- Logl2Frame(sp, skb, "PH_DATA", 0);
-#endif
- sp->isac_fill_fifo(sp);
- }
- break;
- case (PH_DATA_PULLED):
- if (sp->tx_skb) {
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, " l2l1 tx_skb exist this shouldn't happen");
- break;
- }
- if ((sp->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */
- LogFrame(sp, skb->data, skb->len);
- sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
- dlogframe(sp, skb->data + st->l2.ihsize, skb->len - st->l2.ihsize,
- str);
- }
- sp->tx_skb = skb;
- sp->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (sp->debug & L1_DEB_LAPD)
- Logl2Frame(sp, skb, "PH_DATA_PULLED", 0);
-#endif
- sp->isac_fill_fifo(sp);
- break;
- case (PH_REQUEST_PULL):
-#ifdef L2FRAME_DEBUG /* psa */
- if (sp->debug & L1_DEB_LAPD)
- debugl1(sp, "-> PH_REQUEST_PULL");
-#endif
- if (!sp->tx_skb) {
- st->l1.requestpull = 0;
- st->l1.l1l2(st, PH_PULL_ACK, NULL);
- } else
- st->l1.requestpull = !0;
- break;
}
}
-
static void
-hscx_process_xmt(struct HscxState *hsp)
+BChannel_proc_xmt(struct BCState *bcs)
{
- struct PStack *st = hsp->st;
+ struct PStack *st = bcs->st;
- if (hsp->tx_skb)
+ if (test_bit(BC_FLG_BUSY, &bcs->Flag))
return;
- if (st->l1.requestpull) {
- st->l1.requestpull = 0;
- st->l1.l1l2(st, PH_PULL_ACK, NULL);
- }
- if (!hsp->active)
- if ((!hsp->tx_skb) && (!skb_queue_len(&hsp->squeue)))
- hsp->sp->modehscx(hsp, 0, 0);
+ if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags))
+ st->l1.l1l2(st, PH_PULL_CNF, NULL);
+ if (!test_bit(BC_FLG_ACTIV, &bcs->Flag))
+ if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue)))
+ st->ma.manl1(st, PH_DEACTIVATE_CNF, 0);
}
static void
-hscx_process_rcv(struct HscxState *hsp)
+BChannel_proc_rcv(struct BCState *bcs)
{
struct sk_buff *skb;
-#ifdef DEBUG_MAGIC
- if (hsp->magic != 301270) {
- printk(KERN_DEBUG "hscx_process_rcv magic not 301270\n");
- return;
- }
-#endif
- while ((skb = skb_dequeue(&hsp->rqueue))) {
- hsp->st->l1.l1l2(hsp->st, PH_DATA, skb);
+ while ((skb = skb_dequeue(&bcs->rqueue))) {
+ bcs->st->l1.l1l2(bcs->st, PH_DATA_IND, skb);
}
}
static void
-hscx_bh(struct HscxState *hsp)
+BChannel_bh(struct BCState *bcs)
{
-
- if (!hsp)
+ if (!bcs)
return;
-
- if (test_and_clear_bit(HSCX_RCVBUFREADY, &hsp->event))
- hscx_process_rcv(hsp);
- if (test_and_clear_bit(HSCX_XMTBUFREADY, &hsp->event))
- hscx_process_xmt(hsp);
-
+ if (test_and_clear_bit(B_RCVBUFREADY, &bcs->event))
+ BChannel_proc_rcv(bcs);
+ if (test_and_clear_bit(B_XMTBUFREADY, &bcs->event))
+ BChannel_proc_xmt(bcs);
}
-/*
- * interrupt stuff ends here
- */
-
void
-HiSax_addlist(struct IsdnCardState *sp,
+HiSax_addlist(struct IsdnCardState *cs,
struct PStack *st)
{
- st->next = sp->stlist;
- sp->stlist = st;
+ st->next = cs->stlist;
+ cs->stlist = st;
}
void
-HiSax_rmlist(struct IsdnCardState *sp,
+HiSax_rmlist(struct IsdnCardState *cs,
struct PStack *st)
{
struct PStack *p;
- if (sp->stlist == st)
- sp->stlist = st->next;
+ FsmDelTimer(&st->l1.timer, 0);
+ if (cs->stlist == st)
+ cs->stlist = st->next;
else {
- p = sp->stlist;
+ p = cs->stlist;
while (p)
if (p->next == st) {
p->next = st->next;
@@ -644,248 +564,117 @@ HiSax_rmlist(struct IsdnCardState *sp,
}
}
-static void
-check_ph_act(struct IsdnCardState *sp)
-{
- struct PStack *st = sp->stlist;
-
- while (st) {
- if (st->l1.act_state)
- return;
- st = st->next;
- }
- if (sp->ph_active == 5)
- sp->ph_active = 4;
-}
-
-static void
-HiSax_manl1(struct PStack *st, int pr,
- void *arg)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
- long flags;
- char tmp[32];
-
- switch (pr) {
- case (PH_ACTIVATE):
- if (sp->debug) {
- sprintf(tmp, "PH_ACT ph_active %d", sp->ph_active);
- debugl1(sp, tmp);
- }
- save_flags(flags);
- cli();
- if (sp->ph_active & 4) {
- sp->ph_active = 5;
- st->l1.act_state = 2;
- restore_flags(flags);
- st->l1.l1man(st, PH_ACTIVATE, NULL);
- } else {
- st->l1.act_state = 1;
- if (sp->ph_active == 0)
- restart_ph(sp);
- restore_flags(flags);
- }
- break;
- case (PH_DEACTIVATE):
- st->l1.act_state = 0;
- if (sp->debug) {
- sprintf(tmp, "PH_DEACT ph_active %d", sp->ph_active);
- debugl1(sp, tmp);
- }
- check_ph_act(sp);
- break;
- }
-}
-
-static void
-HiSax_l2l1discardq(struct PStack *st, int pr,
- void *heldby, int releasetoo)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
- struct sk_buff *skb;
-
-#ifdef DEBUG_MAGIC
- if (sp->magic != 301271) {
- printk(KERN_DEBUG "isac_discardq magic not 301271\n");
- return;
- }
-#endif
-
- while ((skb = skb_dequeue(&sp->sq))) {
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
- }
-}
-
void
-setstack_HiSax(struct PStack *st, struct IsdnCardState *sp)
+init_bcstate(struct IsdnCardState *cs,
+ int bc)
{
- st->l1.hardware = sp;
- st->protocol = sp->protocol;
-
- setstack_tei(st);
-
- st->l1.stlistp = &(sp->stlist);
- st->l1.act_state = 0;
- st->l2.l2l1 = l2l1;
- st->l2.l2l1discardq = HiSax_l2l1discardq;
- st->ma.manl1 = HiSax_manl1;
- st->l1.requestpull = 0;
-}
-
-void
-init_hscxstate(struct IsdnCardState *sp,
- int hscx)
-{
- struct HscxState *hsp = sp->hs + hscx;
-
- hsp->sp = sp;
- hsp->hscx = hscx;
-
- hsp->tqueue.next = 0;
- hsp->tqueue.sync = 0;
- hsp->tqueue.routine = (void *) (void *) hscx_bh;
- hsp->tqueue.data = hsp;
-
- hsp->inuse = 0;
- hsp->init = 0;
- hsp->active = 0;
-
-#ifdef DEBUG_MAGIC
- hsp->magic = 301270;
-#endif
-}
-
-int
-get_irq(int cardnr, void *routine)
-{
- struct IsdnCard *card = cards + cardnr;
- long flags;
-
- save_flags(flags);
- cli();
- if (request_irq(card->sp->irq, routine,
- I4L_IRQ_FLAG, "HiSax", card->sp)) {
- printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
- card->sp->irq);
- restore_flags(flags);
- return (0);
- }
- restore_flags(flags);
- return (1);
-}
-
-static void
-release_irq(int cardnr)
-{
- struct IsdnCard *card = cards + cardnr;
-
- free_irq(card->sp->irq, card->sp);
-}
-
-void
-close_hscxstate(struct HscxState *hs)
-{
- struct sk_buff *skb;
-
- hs->sp->modehscx(hs, 0, 0);
- hs->inuse = 0;
- if (hs->init) {
- if (hs->rcvbuf) {
- kfree(hs->rcvbuf);
- hs->rcvbuf = NULL;
- }
- while ((skb = skb_dequeue(&hs->rqueue))) {
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
- }
- while ((skb = skb_dequeue(&hs->squeue))) {
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
- }
- if (hs->tx_skb) {
- SET_SKB_FREE(hs->tx_skb);
- dev_kfree_skb(hs->tx_skb);
- hs->tx_skb = NULL;
- }
- }
- hs->init = 0;
+ struct BCState *bcs = cs->bcs + bc;
+
+ bcs->cs = cs;
+ bcs->channel = bc;
+ bcs->tqueue.next = 0;
+ bcs->tqueue.sync = 0;
+ bcs->tqueue.routine = (void *) (void *) BChannel_bh;
+ bcs->tqueue.data = bcs;
+ bcs->BC_SetStack = NULL;
+ bcs->BC_Close = NULL;
+ bcs->Flag = 0;
}
static void
closecard(int cardnr)
{
- struct IsdnCardState *csta = cards[cardnr].sp;
+ struct IsdnCardState *csta = cards[cardnr].cs;
struct sk_buff *skb;
-
- close_hscxstate(csta->hs + 1);
- close_hscxstate(csta->hs);
+
+ if (csta->bcs->BC_Close != NULL) {
+ csta->bcs->BC_Close(csta->bcs + 1);
+ csta->bcs->BC_Close(csta->bcs);
+ }
if (csta->rcvbuf) {
kfree(csta->rcvbuf);
csta->rcvbuf = NULL;
}
while ((skb = skb_dequeue(&csta->rq))) {
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
}
while ((skb = skb_dequeue(&csta->sq))) {
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
}
if (csta->tx_skb) {
- SET_SKB_FREE(csta->tx_skb);
dev_kfree_skb(csta->tx_skb);
csta->tx_skb = NULL;
}
- switch (csta->typ) {
-#if CARD_TELES0
- case ISDN_CTYPE_16_0:
- case ISDN_CTYPE_8_0:
- release_io_teles0(cards + cardnr);
- break;
-#endif
-#if CARD_TELES3
- case ISDN_CTYPE_PNP:
- case ISDN_CTYPE_16_3:
- case ISDN_CTYPE_TELESPCMCIA:
- release_io_teles3(cards + cardnr);
- break;
-#endif
-#if CARD_AVM_A1
- case ISDN_CTYPE_A1:
- release_io_avm_a1(cards + cardnr);
- break;
-#endif
-#if CARD_ELSA
- case ISDN_CTYPE_ELSA:
- case ISDN_CTYPE_ELSA_QS1000:
- release_io_elsa(cards + cardnr);
- break;
-#endif
-#if CARD_IX1MICROR2
- case ISDN_CTYPE_IX1MICROR2:
- release_io_ix1micro(cards + cardnr);
- break;
-#endif
- default:
- break;
+ if (csta->mon_rx) {
+ kfree(csta->mon_rx);
+ csta->mon_rx = NULL;
}
+ if (csta->mon_tx) {
+ kfree(csta->mon_tx);
+ csta->mon_tx = NULL;
+ }
+ csta->cardmsg(csta, CARD_RELEASE, NULL);
+ del_timer(&csta->dbusytimer);
ll_unload(csta);
}
-static int
-checkcard(int cardnr, char *id)
+HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs))
+{
+ int irq_cnt, cnt = 3;
+ long flags;
+
+ save_flags(flags);
+ cli();
+ irq_cnt = kstat_irqs(cs->irq);
+ printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq,
+ irq_cnt);
+ if (cs->cardmsg(cs, CARD_SETIRQ, NULL)) {
+ printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
+ cs->irq);
+ return(1);
+ }
+ while (cnt) {
+ cs->cardmsg(cs, CARD_INIT, NULL);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ /* Timeout 10ms */
+ current->timeout = jiffies + (10 * HZ) / 1000;
+ schedule();
+ restore_flags(flags);
+ printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
+ cs->irq, kstat_irqs(cs->irq));
+ if (kstat_irqs(cs->irq) == irq_cnt) {
+ printk(KERN_WARNING
+ "%s: IRQ(%d) getting no interrupts during init %d\n",
+ CardType[cs->typ], cs->irq, 4 - cnt);
+ if (cnt == 1) {
+ free_irq(cs->irq, cs);
+ return (2);
+ } else {
+ cs->cardmsg(cs, CARD_RESET, NULL);
+ cnt--;
+ }
+ } else {
+ cs->cardmsg(cs, CARD_TEST, NULL);
+ return(0);
+ }
+ }
+ restore_flags(flags);
+ return(3);
+}
+
+HISAX_INITFUNC(static int
+checkcard(int cardnr, char *id, int *busy_flag))
{
long flags;
int ret = 0;
struct IsdnCard *card = cards + cardnr;
- struct IsdnCardState *sp;
+ struct IsdnCardState *cs;
save_flags(flags);
cli();
- if (!(sp = (struct IsdnCardState *)
+ if (!(cs = (struct IsdnCardState *)
kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for IsdnCardState(card %d)\n",
@@ -893,10 +682,16 @@ checkcard(int cardnr, char *id)
restore_flags(flags);
return (0);
}
- card->sp = sp;
- sp->cardnr = cardnr;
- sp->cfg_reg = 0;
- sp->protocol = card->protocol;
+ card->cs = cs;
+ cs->cardnr = cardnr;
+ cs->debug = L1_DEB_WARN;
+ cs->HW_Flags = 0;
+ cs->busy_flag = busy_flag;
+#if TEI_PER_CARD
+#else
+ test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
+#endif
+ cs->protocol = card->protocol;
if ((card->typ > 0) && (card->typ < 31)) {
if (!((1 << card->typ) & SUPORTED_CARDS)) {
@@ -913,31 +708,34 @@ checkcard(int cardnr, char *id)
restore_flags(flags);
return (0);
}
- if (!(sp->dlogspace = kmalloc(4096, GFP_ATOMIC))) {
+ if (!(cs->dlogspace = kmalloc(4096, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for dlogspace(card %d)\n",
cardnr + 1);
restore_flags(flags);
return (0);
}
- if (!(sp->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
+ if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for status_buf(card %d)\n",
cardnr + 1);
- kfree(sp->dlogspace);
+ kfree(cs->dlogspace);
restore_flags(flags);
return (0);
}
- sp->status_read = sp->status_buf;
- sp->status_write = sp->status_buf;
- sp->status_end = sp->status_buf + HISAX_STATUS_BUFSIZE - 1;
- sp->typ = card->typ;
- sp->CallFlags = 0;
- strcpy(sp->iif.id, id);
- sp->iif.channels = 2;
- sp->iif.maxbufsize = MAX_DATA_SIZE;
- sp->iif.hl_hdrlen = MAX_HEADER_LEN;
- sp->iif.features =
+ cs->stlist = NULL;
+ cs->dlogflag = 0;
+ cs->mon_tx = NULL;
+ cs->mon_rx = NULL;
+ cs->status_read = cs->status_buf;
+ cs->status_write = cs->status_buf;
+ cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
+ cs->typ = card->typ;
+ strcpy(cs->iif.id, id);
+ cs->iif.channels = 2;
+ cs->iif.maxbufsize = MAX_DATA_SIZE;
+ cs->iif.hl_hdrlen = MAX_HEADER_LEN;
+ cs->iif.features =
ISDN_FEATURE_L2_X75I |
ISDN_FEATURE_L2_HDLC |
ISDN_FEATURE_L2_TRANS |
@@ -953,21 +751,19 @@ checkcard(int cardnr, char *id)
#endif
0;
- sp->iif.command = HiSax_command;
- sp->iif.writebuf = NULL;
- sp->iif.writecmd = NULL;
- sp->iif.writebuf_skb = HiSax_writebuf_skb;
- sp->iif.readstat = HiSax_readstatus;
- register_isdn(&sp->iif);
- sp->myid = sp->iif.channels;
- restore_flags(flags);
- printk(KERN_NOTICE
+ cs->iif.command = HiSax_command;
+ cs->iif.writecmd = NULL;
+ cs->iif.writebuf_skb = HiSax_writebuf_skb;
+ cs->iif.readstat = HiSax_readstatus;
+ register_isdn(&cs->iif);
+ cs->myid = cs->iif.channels;
+ printk(KERN_INFO
"HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
(card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
(card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
(card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
(card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
- "NONE", sp->iif.id, sp->myid);
+ "NONE", cs->iif.id, cs->myid);
switch (card->typ) {
#if CARD_TELES0
case ISDN_CTYPE_16_0:
@@ -979,6 +775,7 @@ checkcard(int cardnr, char *id)
case ISDN_CTYPE_16_3:
case ISDN_CTYPE_PNP:
case ISDN_CTYPE_TELESPCMCIA:
+ case ISDN_CTYPE_COMPAQ_ISA:
ret = setup_teles3(card);
break;
#endif
@@ -989,7 +786,9 @@ checkcard(int cardnr, char *id)
#endif
#if CARD_ELSA
case ISDN_CTYPE_ELSA:
- case ISDN_CTYPE_ELSA_QS1000:
+ case ISDN_CTYPE_ELSA_PNP:
+ case ISDN_CTYPE_ELSA_PCMCIA:
+ case ISDN_CTYPE_ELSA_PCI:
ret = setup_elsa(card);
break;
#endif
@@ -998,90 +797,103 @@ checkcard(int cardnr, char *id)
ret = setup_ix1micro(card);
break;
#endif
- default:
- printk(KERN_WARNING "HiSax: Unknown Card Typ %d\n",
- card->typ);
- ll_unload(sp);
- return (0);
- }
- if (!ret) {
- ll_unload(sp);
- return (0);
- }
- if (!(sp->rcvbuf = kmalloc(MAX_DFRAME_LEN, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for isac rcvbuf\n");
- return (1);
- }
- sp->rcvidx = 0;
- sp->tx_skb = NULL;
- sp->tx_cnt = 0;
- sp->event = 0;
- sp->tqueue.next = 0;
- sp->tqueue.sync = 0;
- sp->tqueue.routine = (void *) (void *) isac_bh;
- sp->tqueue.data = sp;
-
- skb_queue_head_init(&sp->rq);
- skb_queue_head_init(&sp->sq);
-
- sp->stlist = NULL;
- sp->ph_active = 0;
- sp->dlogflag = 0;
- sp->debug = L1_DEB_WARN;
-#ifdef DEBUG_MAGIC
- sp->magic = 301271;
+#if CARD_DIEHLDIVA
+ case ISDN_CTYPE_DIEHLDIVA:
+ ret = setup_diva(card);
+ break;
#endif
-
- init_hscxstate(sp, 0);
- init_hscxstate(sp, 1);
-
- switch (card->typ) {
-#if CARD_TELES0
- case ISDN_CTYPE_16_0:
- case ISDN_CTYPE_8_0:
- ret = initteles0(sp);
+#if CARD_ASUSCOM
+ case ISDN_CTYPE_ASUSCOM:
+ ret = setup_asuscom(card);
break;
#endif
-#if CARD_TELES3
- case ISDN_CTYPE_16_3:
- case ISDN_CTYPE_PNP:
- case ISDN_CTYPE_TELESPCMCIA:
- ret = initteles3(sp);
+#if CARD_TELEINT
+ case ISDN_CTYPE_TELEINT:
+ ret = setup_TeleInt(card);
break;
#endif
-#if CARD_AVM_A1
- case ISDN_CTYPE_A1:
- ret = initavm_a1(sp);
+#if CARD_SEDLBAUER
+ case ISDN_CTYPE_SEDLBAUER:
+ case ISDN_CTYPE_SEDLBAUER_PCMCIA:
+ ret = setup_sedlbauer(card);
break;
#endif
-#if CARD_ELSA
- case ISDN_CTYPE_ELSA:
- case ISDN_CTYPE_ELSA_QS1000:
- ret = initelsa(sp);
+#if CARD_SPORTSTER
+ case ISDN_CTYPE_SPORTSTER:
+ ret = setup_sportster(card);
break;
#endif
-#if CARD_IX1MICROR2
- case ISDN_CTYPE_IX1MICROR2:
- ret = initix1micro(sp);
+#if CARD_MIC
+ case ISDN_CTYPE_MIC:
+ ret = setup_mic(card);
break;
#endif
- default:
- ret = 0;
+#if CARD_NETJET
+ case ISDN_CTYPE_NETJET:
+ ret = setup_netjet(card);
+ break;
+#endif
+#if CARD_TELES3C
+ case ISDN_CTYPE_TELES3C:
+ ret = setup_t163c(card);
+ break;
+#endif
+#if CARD_NICCY
+ case ISDN_CTYPE_NICCY:
+ ret = setup_niccy(card);
+ break;
+#endif
+#if CARD_AMD7930
+ case ISDN_CTYPE_AMD7930:
+ ret = setup_amd7930(card);
break;
+#endif
+ default:
+ printk(KERN_WARNING "HiSax: Unknown Card Typ %d\n",
+ card->typ);
+ ll_unload(cs);
+ restore_flags(flags);
+ return (0);
}
if (!ret) {
+ ll_unload(cs);
+ restore_flags(flags);
+ return (0);
+ }
+ if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN, GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for isac rcvbuf\n");
+ return (1);
+ }
+ cs->rcvidx = 0;
+ cs->tx_skb = NULL;
+ cs->tx_cnt = 0;
+ cs->event = 0;
+ cs->tqueue.next = 0;
+ cs->tqueue.sync = 0;
+ cs->tqueue.data = cs;
+
+ skb_queue_head_init(&cs->rq);
+ skb_queue_head_init(&cs->sq);
+
+ init_bcstate(cs, 0);
+ init_bcstate(cs, 1);
+ ret = init_card(cs);
+ if (ret) {
closecard(cardnr);
+ restore_flags(flags);
return (0);
}
- init_tei(sp, sp->protocol);
- CallcNewChan(sp);
- ll_run(sp);
+ init_tei(cs, cs->protocol);
+ CallcNewChan(cs);
+ ll_run(cs);
+ cs->l1cmd(cs, PH_RESET_REQ, NULL);
+ restore_flags(flags);
return (1);
}
-void
-HiSax_shiftcards(int idx)
+HISAX_INITFUNC(void
+HiSax_shiftcards(int idx))
{
int i;
@@ -1089,8 +901,8 @@ HiSax_shiftcards(int idx)
memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
}
-int
-HiSax_inithardware(void)
+HISAX_INITFUNC(int
+HiSax_inithardware(int *busy_flag))
{
int foundcards = 0;
int i = 0;
@@ -1120,15 +932,15 @@ HiSax_inithardware(void)
else
sprintf(ids, "%s%d", id, i);
}
- if (checkcard(i, ids)) {
+ if (checkcard(i, ids, busy_flag)) {
foundcards++;
i++;
} else {
printk(KERN_WARNING "HiSax: Card %s not installed !\n",
CardType[cards[i].typ]);
- if (cards[i].sp)
- kfree((void *) cards[i].sp);
- cards[i].sp = NULL;
+ if (cards[i].cs)
+ kfree((void *) cards[i].cs);
+ cards[i].cs = NULL;
HiSax_shiftcards(i);
}
}
@@ -1144,159 +956,66 @@ HiSax_closehardware(void)
save_flags(flags);
cli();
for (i = 0; i < nrcards; i++)
- if (cards[i].sp) {
- ll_stop(cards[i].sp);
- CallcFreeChan(cards[i].sp);
- release_tei(cards[i].sp);
- release_irq(i);
+ if (cards[i].cs) {
+ ll_stop(cards[i].cs);
+ release_tei(cards[i].cs);
closecard(i);
- kfree((void *) cards[i].sp);
- cards[i].sp = NULL;
+ free_irq(cards[i].cs->irq, cards[i].cs);
+ kfree((void *) cards[i].cs);
+ cards[i].cs = NULL;
}
+ Isdnl1Free();
+ TeiFree();
Isdnl2Free();
CallcFree();
restore_flags(flags);
}
-static void
-hscx_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct sk_buff *skb = arg;
- struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
- struct HscxState *hsp = sp->hs + st->l1.hscx;
- long flags;
-
- switch (pr) {
- case (PH_DATA):
- save_flags(flags);
- cli();
- if (hsp->tx_skb) {
- skb_queue_tail(&hsp->squeue, skb);
- restore_flags(flags);
- } else {
- restore_flags(flags);
- hsp->tx_skb = skb;
- hsp->count = 0;
- sp->hscx_fill_fifo(hsp);
- }
- break;
- case (PH_DATA_PULLED):
- if (hsp->tx_skb) {
- printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n");
- break;
- }
- hsp->tx_skb = skb;
- hsp->count = 0;
- sp->hscx_fill_fifo(hsp);
- break;
- case (PH_REQUEST_PULL):
- if (!hsp->tx_skb) {
- st->l1.requestpull = 0;
- st->l1.l1l2(st, PH_PULL_ACK, NULL);
- } else
- st->l1.requestpull = !0;
- break;
- }
-
-}
-extern struct IsdnBuffers *tracebuf;
-
-static void
-hscx_l2l1discardq(struct PStack *st, int pr, void *heldby,
- int releasetoo)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
- struct HscxState *hsp = sp->hs + st->l1.hscx;
- struct sk_buff *skb;
-
-#ifdef DEBUG_MAGIC
- if (hsp->magic != 301270) {
- printk(KERN_DEBUG "hscx_discardq magic not 301270\n");
- return;
- }
-#endif
-
- while ((skb = skb_dequeue(&hsp->squeue))) {
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
- }
-}
-
-static int
-open_hscxstate(struct IsdnCardState *sp,
- int hscx)
-{
- struct HscxState *hsp = sp->hs + hscx;
-
- if (!hsp->init) {
- if (!(hsp->rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for hscx_rcvbuf\n");
- return (1);
- }
- skb_queue_head_init(&hsp->rqueue);
- skb_queue_head_init(&hsp->squeue);
- }
- hsp->init = !0;
-
- hsp->tx_skb = NULL;
- hsp->event = 0;
- hsp->rcvidx = 0;
- hsp->tx_cnt = 0;
- return (0);
-}
-
-static void
-hscx_manl1(struct PStack *st, int pr,
- void *arg)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
- struct HscxState *hsp = sp->hs + st->l1.hscx;
-
- switch (pr) {
- case (PH_ACTIVATE):
- hsp->active = !0;
- sp->modehscx(hsp, st->l1.hscxmode, st->l1.hscxchannel);
- st->l1.l1man(st, PH_ACTIVATE, NULL);
- break;
- case (PH_DEACTIVATE):
- if (!hsp->tx_skb)
- sp->modehscx(hsp, 0, 0);
-
- hsp->active = 0;
- break;
- }
-}
-
-int
-setstack_hscx(struct PStack *st, struct HscxState *hs)
-{
- if (open_hscxstate(st->l1.hardware, hs->hscx))
- return (-1);
-
- st->l1.hscx = hs->hscx;
- st->l2.l2l1 = hscx_l2l1;
- st->ma.manl1 = hscx_manl1;
- st->l2.l2l1discardq = hscx_l2l1discardq;
-
- st->l1.act_state = 0;
- st->l1.requestpull = 0;
-
- hs->st = st;
- return (0);
-}
-
void
HiSax_reportcard(int cardnr)
{
- struct IsdnCardState *sp = cards[cardnr].sp;
+ struct IsdnCardState *cs = cards[cardnr].cs;
+ struct PStack *stptr;
+ struct l3_process *pc;
+ int j, i = 1;
printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1);
- printk(KERN_DEBUG "HiSax: Type %s\n", CardType[sp->typ]);
- printk(KERN_DEBUG "HiSax: debuglevel %x\n", sp->debug);
+ printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]);
+ printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug);
printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n",
(ulong) & HiSax_reportcard);
+ printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs);
+ printk(KERN_DEBUG "HiSax: cs stl 0x%lX\n", (ulong) & (cs->stlist));
+ stptr = cs->stlist;
+ while (stptr != NULL) {
+ printk(KERN_DEBUG "HiSax: dst%d 0x%lX\n", i, (ulong) stptr);
+ printk(KERN_DEBUG "HiSax: dst%d stp 0x%lX\n", i, (ulong) stptr->l1.stlistp);
+ printk(KERN_DEBUG "HiSax: tei %d sapi %d\n",
+ stptr->l2.tei, stptr->l2.sap);
+ printk(KERN_DEBUG "HiSax: man 0x%lX\n", (ulong) stptr->ma.layer);
+ pc = stptr->l3.proc;
+ while (pc) {
+ printk(KERN_DEBUG "HiSax: l3proc %x 0x%lX\n", pc->callref,
+ (ulong) pc);
+ printk(KERN_DEBUG "HiSax: state %d st 0x%lX chan 0x%lX\n",
+ pc->state, (ulong) pc->st, (ulong) pc->chan);
+ pc = pc->next;
+ }
+ stptr = stptr->next;
+ i++;
+ }
+ for (j = 0; j < 2; j++) {
+ printk(KERN_DEBUG "HiSax: ch%d 0x%lX\n", j,
+ (ulong) & cs->channel[j]);
+ stptr = cs->channel[j].b_st;
+ i = 1;
+ while (stptr != NULL) {
+ printk(KERN_DEBUG "HiSax: b_st%d 0x%lX\n", i, (ulong) stptr);
+ printk(KERN_DEBUG "HiSax: man 0x%lX\n", (ulong) stptr->ma.layer);
+ stptr = stptr->next;
+ i++;
+ }
+ }
}
#ifdef L2FRAME_DEBUG /* psa */
@@ -1366,7 +1085,7 @@ l2frames(u_char * ptr)
}
void
-Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir)
+Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir)
{
char tmp[132];
u_char *ptr;
@@ -1374,13 +1093,293 @@ Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir)
ptr = skb->data;
if (ptr[0] & 1 || !(ptr[1] & 1))
- debugl1(sp, "Addres not LAPD");
+ debugl1(cs, "Addres not LAPD");
else {
sprintf(tmp, "%s %s: %s%c (sapi %d, tei %d)",
(dir ? "<-" : "->"), buf, l2frames(ptr),
((ptr[0] & 2) >> 1) == dir ? 'C' : 'R', ptr[0] >> 2, ptr[1] >> 1);
- debugl1(sp, tmp);
+ debugl1(cs, tmp);
}
}
-
#endif
+
+static void
+l1_reset(struct FsmInst *fi, int event, void *arg)
+{
+ FsmChangeState(fi, ST_L1_F3);
+}
+
+static void
+l1_deact_cnf(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct IsdnCardState *cs = st->l1.hardware;
+
+ FsmChangeState(fi, ST_L1_F3);
+ if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
+ cs->l1cmd(cs, PH_ENABLE_REQ, NULL);
+}
+
+static void
+l1_deact_req(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ FsmChangeState(fi, ST_L1_F3);
+ if (!test_bit(FLG_L1_T3RUN, &st->l1.Flags)) {
+ FsmDelTimer(&st->l1.timer, 1);
+ FsmAddTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
+ test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
+ }
+}
+
+static void
+l1_power_up(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct IsdnCardState *cs = st->l1.hardware;
+
+ if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) {
+ FsmChangeState(fi, ST_L1_F4);
+ cs->l1cmd(cs, PH_INFO3_REQ, NULL);
+ FsmDelTimer(&st->l1.timer, 1);
+ FsmAddTimer(&st->l1.timer, TIMER3_VALUE * HZ, EV_TIMER3, NULL, 2);
+ test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags);
+ } else
+ FsmChangeState(fi, ST_L1_F3);
+}
+
+static void
+l1_go_F5(struct FsmInst *fi, int event, void *arg)
+{
+ FsmChangeState(fi, ST_L1_F5);
+}
+
+static void
+l1_go_F8(struct FsmInst *fi, int event, void *arg)
+{
+ FsmChangeState(fi, ST_L1_F8);
+}
+
+static void
+l1_info2_ind(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct IsdnCardState *cs = st->l1.hardware;
+
+ FsmChangeState(fi, ST_L1_F6);
+ cs->l1cmd(cs, PH_INFO3_REQ, NULL);
+}
+
+static void
+l1_info4_ind(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct IsdnCardState *cs = st->l1.hardware;
+
+ FsmChangeState(fi, ST_L1_F7);
+ cs->l1cmd(cs, PH_INFO3_REQ, NULL);
+ if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags))
+ FsmDelTimer(&st->l1.timer, 4);
+ if (!test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) {
+ if (test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags))
+ FsmDelTimer(&st->l1.timer, 3);
+ FsmAddTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2);
+ test_and_set_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
+ }
+}
+
+static void
+l1_timer3(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct IsdnCardState *cs = st->l1.hardware;
+
+ test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags);
+ if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
+ L1deactivated(cs);
+ if (st->l1.l1m.state != ST_L1_F6)
+ FsmChangeState(fi, ST_L1_F3);
+}
+
+static void
+l1_timer_act(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct IsdnCardState *cs = st->l1.hardware;
+
+ test_and_clear_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
+ test_and_set_bit(FLG_L1_ACTIVATED, &st->l1.Flags);
+ L1activated(cs);
+}
+
+static void
+l1_timer_deact(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct IsdnCardState *cs = st->l1.hardware;
+
+ test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
+ test_and_clear_bit(FLG_L1_ACTIVATED, &st->l1.Flags);
+ L1deactivated(cs);
+ cs->l1cmd(cs, PH_DEACT_ACK, NULL);
+}
+
+static void
+l1_activate(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct IsdnCardState *cs = st->l1.hardware;
+
+ cs->l1cmd(cs, PH_RESET_REQ, NULL);
+}
+
+static struct FsmNode L1FnList[] HISAX_INITDATA =
+{
+ {ST_L1_F3, EV_PH_ACTIVATE, l1_activate},
+ {ST_L1_F3, EV_RESET_IND, l1_reset},
+ {ST_L1_F4, EV_RESET_IND, l1_reset},
+ {ST_L1_F5, EV_RESET_IND, l1_reset},
+ {ST_L1_F6, EV_RESET_IND, l1_reset},
+ {ST_L1_F7, EV_RESET_IND, l1_reset},
+ {ST_L1_F8, EV_RESET_IND, l1_reset},
+ {ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf},
+ {ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf},
+ {ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf},
+ {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_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},
+ {ST_L1_F3, EV_INFO2_IND, l1_info2_ind},
+ {ST_L1_F4, EV_INFO2_IND, l1_info2_ind},
+ {ST_L1_F5, EV_INFO2_IND, l1_info2_ind},
+ {ST_L1_F7, EV_INFO2_IND, l1_info2_ind},
+ {ST_L1_F8, EV_INFO2_IND, l1_info2_ind},
+ {ST_L1_F3, EV_INFO4_IND, l1_info4_ind},
+ {ST_L1_F4, EV_INFO4_IND, l1_info4_ind},
+ {ST_L1_F5, EV_INFO4_IND, l1_info4_ind},
+ {ST_L1_F6, EV_INFO4_IND, l1_info4_ind},
+ {ST_L1_F8, EV_INFO4_IND, l1_info4_ind},
+ {ST_L1_F3, EV_TIMER3, l1_timer3},
+ {ST_L1_F4, EV_TIMER3, l1_timer3},
+ {ST_L1_F5, EV_TIMER3, l1_timer3},
+ {ST_L1_F6, EV_TIMER3, l1_timer3},
+ {ST_L1_F8, EV_TIMER3, l1_timer3},
+ {ST_L1_F7, EV_TIMER_ACT, l1_timer_act},
+ {ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact},
+ {ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact},
+ {ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact},
+ {ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact},
+ {ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact},
+ {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact},
+};
+
+#define L1_FN_COUNT (sizeof(L1FnList)/sizeof(struct FsmNode))
+
+HISAX_INITFUNC(void Isdnl1New(void))
+{
+ l1fsm.state_count = L1_STATE_COUNT;
+ l1fsm.event_count = L1_EVENT_COUNT;
+ l1fsm.strEvent = strL1Event;
+ l1fsm.strState = strL1State;
+ FsmNew(&l1fsm, L1FnList, L1_FN_COUNT);
+}
+
+void Isdnl1Free(void)
+{
+ FsmFree(&l1fsm);
+}
+
+static void
+dch_manl1(struct PStack *st, int pr,
+ void *arg)
+{
+ struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+ char tmp[32];
+
+ switch (pr) {
+ case PH_ACTIVATE_REQ:
+ if (cs->debug) {
+ sprintf(tmp, "PH_ACTIVATE_REQ %s",
+ strL1State[st->l1.l1m.state]);
+ debugl1(cs, tmp);
+ }
+ if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags))
+ st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
+ else {
+ test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags);
+ FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg);
+ }
+ break;
+ case PH_DEACTIVATE_REQ:
+ if (cs->debug) {
+ sprintf(tmp, "PH_DEACTIVATE_REQ %s",
+ strL1State[st->l1.l1m.state]);
+ debugl1(cs, tmp);
+ }
+ break;
+ case PH_TESTLOOP_REQ:
+ if (1 & (int) arg)
+ debugl1(cs, "PH_TEST_LOOP B1");
+ if (2 & (int) arg)
+ debugl1(cs, "PH_TEST_LOOP B2");
+ if (!(3 & (int) arg))
+ debugl1(cs, "PH_TEST_LOOP DISABLED");
+ cs->l1cmd(cs, PH_TESTLOOP_REQ, arg);
+ break;
+ case PH_RESET_IND:
+ FsmEvent(&st->l1.l1m, EV_RESET_IND, arg);
+ break;
+ case PH_DEACT_CNF:
+ FsmEvent(&st->l1.l1m, EV_DEACT_CNF, arg);
+ break;
+ case PH_DEACT_IND:
+ FsmEvent(&st->l1.l1m, EV_DEACT_IND, arg);
+ break;
+ case PH_POWERUP_CNF:
+ FsmEvent(&st->l1.l1m, EV_POWER_UP, arg);
+ break;
+ case PH_RSYNC_IND:
+ FsmEvent(&st->l1.l1m, EV_RSYNC_IND, arg);
+ break;
+ case PH_INFO2_IND:
+ FsmEvent(&st->l1.l1m, EV_INFO2_IND, arg);
+ break;
+ case PH_I4_P8_IND:
+ case PH_I4_P10_IND:
+ FsmEvent(&st->l1.l1m, EV_INFO4_IND, arg);
+ break;
+ default:
+ if (cs->debug) {
+ sprintf(tmp, "dch_manl1 msg %04X unhandled", pr);
+ debugl1(cs, tmp);
+ }
+ break;
+ }
+}
+
+void
+setstack_HiSax(struct PStack *st, struct IsdnCardState *cs)
+{
+ st->l1.hardware = cs;
+ st->protocol = cs->protocol;
+ st->l1.l1m.fsm = &l1fsm;
+ st->l1.l1m.state = ST_L1_F3;
+ st->l1.l1m.debug = cs->debug;
+ st->l1.l1m.userdata = st;
+ st->l1.l1m.userint = 0;
+ st->l1.l1m.printdebug = l1m_debug;
+ FsmInitTimer(&st->l1.l1m, &st->l1.timer);
+ setstack_tei(st);
+ setstack_manager(st);
+ st->l1.stlistp = &(cs->stlist);
+ st->ma.manl1 = dch_manl1;
+ st->l1.Flags = 0;
+ cs->setstack_d(st, cs);
+}
diff --git a/drivers/isdn/hisax/isdnl1.h b/drivers/isdn/hisax/isdnl1.h
index d01d70123..71f081a07 100644
--- a/drivers/isdn/hisax/isdnl1.h
+++ b/drivers/isdn/hisax/isdnl1.h
@@ -1,18 +1,23 @@
-/* $Id: isdnl1.h,v 1.4 1997/04/06 22:55:52 keil Exp $
- *
+/* $Id: isdnl1.h,v 2.5 1998/02/02 13:36:58 keil Exp $
+
* $Log: isdnl1.h,v $
- * Revision 1.4 1997/04/06 22:55:52 keil
- * Using SKB's
+ * Revision 2.5 1998/02/02 13:36:58 keil
+ * more debug
+ *
+ * Revision 2.4 1997/11/08 21:35:49 keil
+ * new l1 init
*
- * Revision 1.3 1996/12/08 19:41:55 keil
- * L2FRAME_DEBUG
+ * Revision 2.3 1997/10/29 19:07:53 keil
+ * changes for 2.1
*
- * Revision 1.2 1996/10/27 22:26:27 keil
- * ISAC/HSCX version functions
+ * Revision 2.2 1997/07/30 17:11:09 keil
+ * L1deactivated exported
*
- * Revision 1.1 1996/10/13 20:03:47 keil
- * Initial revision
+ * Revision 2.1 1997/07/27 21:43:58 keil
+ * new l1 interface
*
+ * Revision 2.0 1997/06/26 11:02:55 keil
+ * New Layer and card interface
*
*
*/
@@ -29,22 +34,25 @@
#define L1_DEB_HSCX 0x10
#define L1_DEB_HSCX_FIFO 0x20
#define L1_DEB_LAPD 0x40
+#define L1_DEB_IPAC 0x80
+#define L1_DEB_RECEIVE_FRAME 0x100
+#define D_RCVBUFREADY 0
+#define D_XMTBUFREADY 1
+#define D_L1STATECHANGE 2
+#define D_CLEARBUSY 3
+#define D_RX_MON0 4
+#define D_RX_MON1 5
+#define D_TX_MON0 6
+#define D_TX_MON1 7
-#define ISAC_RCVBUFREADY 0
-#define ISAC_XMTBUFREADY 1
-#define ISAC_PHCHANGE 2
-
-#define HSCX_RCVBUFREADY 0
-#define HSCX_XMTBUFREADY 1
+#define B_RCVBUFREADY 0
+#define B_XMTBUFREADY 1
extern void debugl1(struct IsdnCardState *sp, char *msg);
-extern char *HscxVersion(u_char v);
-extern char *ISACVersion(u_char v);
-extern void hscx_sched_event(struct HscxState *hsp, int event);
-extern void isac_sched_event(struct IsdnCardState *sp, int event);
-extern void isac_new_ph(struct IsdnCardState *sp);
-extern int get_irq(int cardnr, void *routine);
+extern void DChannel_proc_xmt(struct IsdnCardState *cs);
+extern void DChannel_proc_rcv(struct IsdnCardState *cs);
+
#ifdef L2FRAME_DEBUG
extern void Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir);
diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c
index 9c58eef90..eadfa4c8a 100644
--- a/drivers/isdn/hisax/isdnl2.c
+++ b/drivers/isdn/hisax/isdnl2.c
@@ -1,4 +1,4 @@
-/* $Id: isdnl2.c,v 1.10 1997/05/06 09:38:13 keil Exp $
+/* $Id: isdnl2.c,v 2.7 1998/02/12 23:07:47 keil Exp $
* Author Karsten Keil (keil@temic-ech.spacenet.de)
* based on the teles driver from Jan den Ouden
@@ -7,56 +7,51 @@
* Fritz Elfert
*
* $Log: isdnl2.c,v $
- * Revision 1.10 1997/05/06 09:38:13 keil
- * Bugfixes: - clear ack queue entries after resend
- * - acknowlege each frame to linklevel
- * - UA for SABM is Response, not command
- * - only RR was send as supervisor frame (X.75 hangs after a
- * sequence error)
+ * Revision 2.7 1998/02/12 23:07:47 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
*
- * Revision 1.9 1997/04/07 23:02:11 keil
- * missing braces
+ * Revision 2.6 1998/02/02 13:36:15 keil
+ * bugfix X.75 win calculation
*
- * Revision 1.8 1997/04/06 22:59:59 keil
- * Using SKB's; changing function names; some minor changes
+ * Revision 2.5 1997/11/06 17:09:22 keil
+ * New 2.1 init code
*
- * Revision 1.7 1997/02/09 00:25:44 keil
- * new interface handling, one interface per card
+ * Revision 2.4 1997/10/29 19:02:01 keil
+ * new LL interface
*
- * Revision 1.6 1997/01/21 22:23:42 keil
- * D-channel log changed
+ * Revision 2.3 1997/10/01 09:21:39 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
*
- * Revision 1.5 1997/01/04 13:47:06 keil
- * handling of MDL_REMOVE added (Thanks to Sim Yskes)
+ * Revision 2.2 1997/07/31 11:49:05 keil
+ * Eroor handling for no TEI assign
*
- * Revision 1.4 1996/12/08 19:51:51 keil
- * many fixes from Pekka Sarnila
+ * Revision 2.1 1997/07/27 21:34:38 keil
+ * cosmetics
*
- * Revision 1.3 1996/11/05 19:39:12 keil
- * X.75 bugfixes Thank to Martin Maurer
- *
- * Revision 1.2 1996/10/30 10:20:58 keil
- * X.75 answer of SABMX fixed to response address (AVM X.75 problem)
- *
- * Revision 1.1 1996/10/13 20:04:54 keil
- * Initial revision
+ * Revision 2.0 1997/06/26 11:07:29 keil
+ * New q.921 and X.75 Layer2
*
*
+ * Old log removed KKe
*
*/
#define __NO_VERSION__
#include "hisax.h"
#include "isdnl2.h"
-const char *l2_revision = "$Revision: 1.10 $";
+const char *l2_revision = "$Revision: 2.7 $";
static void l2m_debug(struct FsmInst *fi, char *s);
+static
struct Fsm l2fsm =
{NULL, 0, 0, NULL, NULL};
enum {
ST_L2_1,
+ ST_L2_2,
ST_L2_3,
ST_L2_4,
ST_L2_5,
@@ -70,6 +65,7 @@ enum {
static char *strL2State[] =
{
"ST_L2_1",
+ "ST_L2_2",
"ST_L2_3",
"ST_L2_4",
"ST_L2_5",
@@ -81,53 +77,53 @@ static char *strL2State[] =
enum {
EV_L2_UI,
EV_L2_SABMX,
- EV_L2_UA,
EV_L2_DISC,
- EV_L2_I,
- EV_L2_RR,
- EV_L2_REJ,
+ EV_L2_DM,
+ EV_L2_UA,
EV_L2_FRMR,
+ EV_L2_SUPER,
+ EV_L2_I,
EV_L2_DL_DATA,
+ EV_L2_ACK_PULL,
+ EV_L2_DL_UNIT_DATA,
EV_L2_DL_ESTABLISH,
+ EV_L2_DL_RELEASE,
EV_L2_MDL_ASSIGN,
EV_L2_MDL_REMOVE,
- EV_L2_DL_UNIT_DATA,
- EV_L2_DL_RELEASE,
+ EV_L2_MDL_ERROR,
EV_L2_MDL_NOTEIPROC,
+ EV_L1_DEACTIVATE,
EV_L2_T200,
- EV_L2_ACK_PULL,
EV_L2_T203,
- EV_L2_RNR,
};
-#define L2_EVENT_COUNT (EV_L2_RNR+1)
+#define L2_EVENT_COUNT (EV_L2_T203+1)
static char *strL2Event[] =
{
"EV_L2_UI",
"EV_L2_SABMX",
- "EV_L2_UA",
"EV_L2_DISC",
- "EV_L2_I",
- "EV_L2_RR",
- "EV_L2_REJ",
+ "EV_L2_DM",
+ "EV_L2_UA",
"EV_L2_FRMR",
+ "EV_L2_SUPER",
+ "EV_L2_I",
"EV_L2_DL_DATA",
+ "EV_L2_ACK_PULL",
+ "EV_L2_DL_UNIT_DATA",
"EV_L2_DL_ESTABLISH",
+ "EV_L2_DL_RELEASE",
"EV_L2_MDL_ASSIGN",
"EV_L2_MDL_REMOVE",
- "EV_L2_DL_UNIT_DATA",
- "EV_L2_DL_RELEASE",
+ "EV_L2_MDL_ERROR",
"EV_L2_MDL_NOTEIPROC",
+ "EV_L1_DEACTIVATE",
"EV_L2_T200",
- "EV_L2_ACK_PULL",
"EV_L2_T203",
- "EV_L2_RNR",
};
-int errcount = 0;
-
-static int l2addrsize(struct Layer2 *tsp);
+static int l2addrsize(struct Layer2 *l2);
static void
InitWin(struct Layer2 *l2)
@@ -143,11 +139,9 @@ ReleaseWin(struct Layer2 *l2)
{
int i, cnt = 0;
-
for (i = 0; i < MAX_WINDOW; i++) {
if (l2->windowar[i]) {
cnt++;
- SET_SKB_FREE(l2->windowar[i]);
dev_kfree_skb(l2->windowar[i]);
l2->windowar[i] = NULL;
}
@@ -156,13 +150,15 @@ ReleaseWin(struct Layer2 *l2)
printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt);
}
-static int
+inline int
cansend(struct PStack *st)
{
int p1;
- p1 = (st->l2.va + st->l2.window) % (st->l2.extended ? 128 : 8);
- return (st->l2.vs != p1);
+ p1 = st->l2.vs - st->l2.va;
+ if (p1 < 0)
+ p1 += (test_bit(FLG_MOD128, &st->l2.flag) ? 128 : 8);
+ return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag));
}
static void
@@ -171,40 +167,54 @@ discard_i_queue(struct PStack *st)
struct sk_buff *skb;
while ((skb = skb_dequeue(&st->l2.i_queue))) {
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
}
}
-int
-l2headersize(struct Layer2 *tsp, int ui)
+static void
+discard_ui_queue(struct PStack *st)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&st->l2.ui_queue))) {
+ dev_kfree_skb(skb);
+ }
+}
+
+inline void
+clear_exception(struct Layer2 *l2)
{
- return ((tsp->extended && (!ui) ? 2 : 1) + (tsp->laptype == LAPD ? 2 : 1));
+ test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+ test_and_clear_bit(FLG_REJEXC, &l2->flag);
+ test_and_clear_bit(FLG_OWN_BUSY, &l2->flag);
+ test_and_clear_bit(FLG_PEER_BUSY, &l2->flag);
}
-int
-l2addrsize(struct Layer2 *tsp)
+inline int
+l2headersize(struct Layer2 *l2, int ui)
{
- return (tsp->laptype == LAPD ? 2 : 1);
+ return (((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) +
+ (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1));
+}
+
+inline int
+l2addrsize(struct Layer2 *l2)
+{
+ return (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1);
}
static int
-sethdraddr(struct Layer2 *tsp,
- u_char * header, int rsp)
+sethdraddr(struct Layer2 *l2, u_char * header, int rsp)
{
u_char *ptr = header;
- int crbit;
+ int crbit = rsp;
- if (tsp->laptype == LAPD) {
- crbit = rsp;
- if (!tsp->orig)
- crbit = !crbit;
- *ptr++ = (tsp->sap << 2) | (crbit ? 2 : 0);
- *ptr++ = (tsp->tei << 1) | 1;
+ if (test_bit(FLG_LAPD, &l2->flag)) {
+ *ptr++ = (l2->sap << 2) | (rsp ? 2 : 0);
+ *ptr++ = (l2->tei << 1) | 1;
return (2);
} else {
- crbit = rsp;
- if (tsp->orig)
+ if (test_bit(FLG_ORIG, &l2->flag))
crbit = !crbit;
if (crbit)
*ptr++ = 1;
@@ -218,79 +228,107 @@ static void
enqueue_ui(struct PStack *st,
struct sk_buff *skb)
{
- st->l2.l2l1(st, PH_DATA, skb);
+ st->l2.l2l1(st, PH_DATA_REQ, skb);
}
static void
enqueue_super(struct PStack *st,
struct sk_buff *skb)
{
- st->l2.l2l1(st, PH_DATA, skb);
+ st->l2.l2l1(st, PH_DATA_REQ, skb);
}
-static int
-legalnr(struct PStack *st, int nr)
+inline int
+IsUI(u_char * data, int ext)
{
- struct Layer2 *l2 = &st->l2;
- int lnr, lvs;
+ return ((data[0] & 0xef) == UI);
+}
- lvs = (l2->vs >= l2->va) ? l2->vs : (l2->vs + l2->extended ? 128 : 8);
- lnr = (nr >= l2->va) ? nr : (nr + l2->extended ? 128 : 8);
- return (lnr <= lvs);
+inline int
+IsUA(u_char * data, int ext)
+{
+ return ((data[0] & 0xef) == UA);
}
-static void
-setva(struct PStack *st, int nr)
+inline int
+IsDM(u_char * data, int ext)
{
- struct Layer2 *l2 = &st->l2;
+ return ((data[0] & 0xef) == DM);
+}
- if (l2->va != nr) {
- while (l2->va != nr) {
- l2->va = (l2->va + 1) % (l2->extended ? 128 : 8);
- SET_SKB_FREE(l2->windowar[l2->sow]);
- dev_kfree_skb(l2->windowar[l2->sow]);
- l2->windowar[l2->sow] = NULL;
- l2->sow = (l2->sow + 1) % l2->window;
- if (st->l4.l2writewakeup)
- st->l4.l2writewakeup(st);
- }
- }
+inline int
+IsDISC(u_char * data, int ext)
+{
+ return ((data[0] & 0xef) == DISC);
}
-static void
-l2s1(struct FsmInst *fi, int event, void *arg)
+inline int
+IsRR(u_char * data, int ext)
{
- struct PStack *st = fi->userdata;
+ if (ext)
+ return (data[0] == RR);
+ else
+ return ((data[0] & 0xf) == 1);
+}
- st->l2.l2tei(st, MDL_ASSIGN, (void *) st->l2.ces);
- FsmChangeState(fi, ST_L2_3);
+inline int
+IsSABMX(u_char * data, int ext)
+{
+ u_char d = data[0] & ~0x10;
+
+ return (ext ? d == SABME : d == SABM);
}
-static void
-l2_send_ui(struct FsmInst *fi, int event, void *arg)
+inline int
+IsREJ(u_char * data, int ext)
{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- u_char header[MAX_HEADER_LEN];
- int i;
+ return (ext ? data[0] == REJ : (data[0] & 0xf) == REJ);
+}
- i = sethdraddr(&(st->l2), header, CMD);
- header[i++] = UI;
- memcpy(skb_push(skb, i), header, i);
- enqueue_ui(st, skb);
+inline int
+IsFRMR(u_char * data, int ext)
+{
+ return ((data[0] & 0xef) == FRMR);
}
-static void
-l2_receive_ui(struct FsmInst *fi, int event, void *arg)
+inline int
+IsRNR(u_char * data, int ext)
{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
+ return (ext ? data[0] == RNR : (data[0] & 0xf) == RNR);
+}
- skb_pull(skb, l2headersize(&st->l2, 1));
- st->l2.l2l3(st, DL_UNIT_DATA, skb);
+static int
+legalnr(struct PStack *st, int nr)
+{
+ struct Layer2 *l2 = &st->l2;
+ int lnr, lvs;
+
+ lvs = (l2->vs >= l2->va) ? l2->vs :
+ (l2->vs + (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8));
+ lnr = (nr >= l2->va) ? nr : (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8);
+ return (lnr <= lvs);
}
-inline void
+static void
+setva(struct PStack *st, int nr)
+{
+ struct Layer2 *l2 = &st->l2;
+ int len;
+
+ while (l2->va != nr) {
+ l2->va = (l2->va + 1) % (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8);
+ len = l2->windowar[l2->sow]->len;
+ if (PACKET_NOACK == l2->windowar[l2->sow]->pkt_type)
+ len = -1;
+ dev_kfree_skb(l2->windowar[l2->sow]);
+ l2->windowar[l2->sow] = NULL;
+ l2->sow = (l2->sow + 1) % l2->window;
+ if (st->lli.l2writewakeup && (len >=0))
+ st->lli.l2writewakeup(st, len);
+ }
+}
+
+static void
send_uframe(struct PStack *st, u_char cmd, u_char cr)
{
struct sk_buff *skb;
@@ -307,53 +345,156 @@ send_uframe(struct PStack *st, u_char cmd, u_char cr)
enqueue_super(st, skb);
}
+inline u_char
+get_PollFlag(struct PStack * st, struct sk_buff * skb)
+{
+ return (skb->data[l2addrsize(&(st->l2))] & 0x10);
+}
+
+inline void
+FreeSkb(struct sk_buff *skb)
+{
+ dev_kfree_skb(skb);
+}
+
+
+inline u_char
+get_PollFlagFree(struct PStack *st, struct sk_buff *skb)
+{
+ u_char PF;
+
+ PF = get_PollFlag(st, skb);
+ FreeSkb(skb);
+ return (PF);
+}
+
static void
establishlink(struct FsmInst *fi)
{
struct PStack *st = fi->userdata;
u_char cmd;
- FsmChangeState(fi, ST_L2_5);
+ clear_exception(&st->l2);
st->l2.rc = 0;
+ cmd = (test_bit(FLG_MOD128, &st->l2.flag) ? SABME : SABM) | 0x10;
+ send_uframe(st, cmd, CMD);
+ FsmDelTimer(&st->l2.t203, 1);
+ FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 1);
+ test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
+ FsmChangeState(fi, ST_L2_5);
+}
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 1))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 1");
+static void
+l2_mdl_error(struct FsmInst *fi, int event, void *arg)
+{
+ struct sk_buff *skb = arg;
+ struct PStack *st = fi->userdata;
+ switch (event) {
+ case EV_L2_UA:
+ if (get_PollFlagFree(st, skb))
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'C');
+ else
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'D');
+ break;
+ case EV_L2_DM:
+ if (get_PollFlagFree(st, skb))
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'B');
+ else {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'E');
+ establishlink(fi);
+ test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
+ }
+ break;
+ }
+}
- cmd = (st->l2.extended ? SABME : SABM) | 0x10;
- send_uframe(st, cmd, CMD);
+static void
+l2_dl_establish(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ int state = fi->state;
+
+ FsmChangeState(fi, ST_L2_3);
+ if (state == ST_L2_1)
+ st->l2.l2tei(st, MDL_ASSIGN_IND, NULL);
}
static void
-l2_establish(struct FsmInst *fi, int event, void *arg)
+l2_send_ui(struct PStack *st)
{
- establishlink(fi);
+ struct sk_buff *skb;
+ u_char header[MAX_HEADER_LEN];
+ int i;
+
+ i = sethdraddr(&(st->l2), header, CMD);
+ header[i++] = UI;
+ while ((skb = skb_dequeue(&st->l2.ui_queue))) {
+ memcpy(skb_push(skb, i), header, i);
+ enqueue_ui(st, skb);
+ }
}
static void
-l2_send_disconn(struct FsmInst *fi, int event, void *arg)
+l2_put_ui(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
-
- FsmChangeState(fi, ST_L2_6);
+ struct sk_buff *skb = arg;
- FsmDelTimer(&st->l2.t203_timer, 1);
- if (st->l2.t200_running) {
- FsmDelTimer(&st->l2.t200_timer, 2);
- st->l2.t200_running = 0;
+ skb_queue_tail(&st->l2.ui_queue, skb);
+ if (fi->state == ST_L2_1) {
+ FsmChangeState(fi, ST_L2_2);
+ st->l2.l2tei(st, MDL_ASSIGN_IND, NULL);
}
- st->l2.rc = 0;
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 2))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 2");
+ if (fi->state > ST_L2_3)
+ l2_send_ui(st);
+}
+static void
+l2_got_ui(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
- if (!((chanp->impair == 2) && (st->l2.laptype == LAPB)))
- send_uframe(st, DISC | 0x10, CMD);
+ skb_pull(skb, l2headersize(&st->l2, 1));
+ if (skb->len > st->l2.maxlen) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'O');
+ FreeSkb(skb);
+ } else
+ st->l2.l2l3(st, DL_UNIT_DATA, skb);
+}
+
+static void
+l2_establish(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ if (fi->state != ST_L2_4)
+ discard_i_queue(st);
+ if (fi->state != ST_L2_5)
+ establishlink(fi);
+ test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
+}
+
+static void
+l2_dl_release(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ if (fi->state == ST_L2_4) {
+ st->l2.l2man(st, DL_RELEASE, NULL);
+ return;
+ } else if (fi->state == ST_L2_5) {
+ test_and_set_bit(FLG_PEND_REL, &st->l2.flag);
+ return;
+ }
discard_i_queue(st);
+ FsmChangeState(fi, ST_L2_6);
+ st->l2.rc = 0;
+ send_uframe(st, DISC | 0x10, CMD);
+ FsmDelTimer(&st->l2.t203, 1);
+ FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 2);
+ test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
}
static void
@@ -361,46 +502,59 @@ l2_got_SABMX(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
- int est = 1, state;
+ int est = 1, state, rsp;
u_char PollFlag;
state = fi->state;
-
- skb_pull(skb, l2addrsize(&(st->l2)));
- PollFlag = *skb->data & 0x10;
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
-
- if (ST_L2_4 != state)
+ rsp = *skb->data & 0x2;
+ if (test_bit(FLG_ORIG, &st->l2.flag))
+ rsp = !rsp;
+ if (rsp) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+ FreeSkb(skb);
+ if ((state == ST_L2_7) || (state == ST_L2_8))
+ establishlink(fi);
+ return;
+ }
+ if (skb->len != (l2addrsize(&st->l2) + 1)) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+ FreeSkb(skb);
+ if ((state == ST_L2_7) || (state == ST_L2_8))
+ establishlink(fi);
+ return;
+ }
+ PollFlag = get_PollFlagFree(st, skb);
+ if (ST_L2_6 == state) {
+ send_uframe(st, DM | PollFlag, RSP);
+ return;
+ } else
+ send_uframe(st, UA | PollFlag, RSP);
+ if (ST_L2_5 == state)
+ return;
+ if (ST_L2_4 != state) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'F');
if (st->l2.vs != st->l2.va) {
discard_i_queue(st);
est = 1;
} else
est = 0;
-
+ }
+ clear_exception(&st->l2);
st->l2.vs = 0;
st->l2.va = 0;
st->l2.vr = 0;
st->l2.sow = 0;
- if (ST_L2_7 != state)
- FsmChangeState(fi, ST_L2_7);
-
- send_uframe(st, UA | PollFlag, RSP);
-
- if (st->l2.t200_running) {
- FsmDelTimer(&st->l2.t200_timer, 15);
- st->l2.t200_running = 0;
- }
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 3");
+ FsmChangeState(fi, ST_L2_7);
+ if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+ FsmDelTimer(&st->l2.t200, 2);
+ FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
if (est)
st->l2.l2man(st, DL_ESTABLISH, NULL);
if (ST_L2_8 == state)
if (skb_queue_len(&st->l2.i_queue) && cansend(st))
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+ st->l2.l2l1(st, PH_PULL_REQ, NULL);
}
static void
@@ -408,87 +562,152 @@ l2_got_disconn(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
- struct Channel *chanp = st->l4.userdata;
- u_char PollFlag;
-
- skb_pull(skb, l2addrsize(&(st->l2)));
- PollFlag = *skb->data & 0x10;
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
+ u_char PollFlag, cmd = UA;
+ int state, rel = 1, cst = 1, rsp;
- FsmChangeState(fi, ST_L2_4);
+ state = fi->state;
+ rsp = *skb->data & 0x2;
+ if (test_bit(FLG_ORIG, &st->l2.flag))
+ rsp = !rsp;
- FsmDelTimer(&st->l2.t203_timer, 3);
- if (st->l2.t200_running) {
- FsmDelTimer(&st->l2.t200_timer, 4);
- st->l2.t200_running = 0;
+ if (rsp) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+ FreeSkb(skb);
+ if ((state == ST_L2_7) || (state == ST_L2_8))
+ establishlink(fi);
+ return;
+ }
+ if (skb->len != (l2addrsize(&st->l2) + 1)) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+ FreeSkb(skb);
+ if ((state == ST_L2_7) || (state == ST_L2_8))
+ establishlink(fi);
+ return;
}
- if (!((chanp->impair == 1) && (st->l2.laptype == LAPB)))
- send_uframe(st, UA | PollFlag, RSP);
-
- st->l2.l2man(st, DL_RELEASE, NULL);
+ PollFlag = get_PollFlagFree(st, skb);
+ if ((state == ST_L2_4) || (state == ST_L2_5)) {
+ rel = 0;
+ cst = 0;
+ cmd = DM;
+ } else if (state == ST_L2_6) {
+ rel = 0;
+ cst = 0;
+ }
+ if (cst) {
+ FsmChangeState(fi, ST_L2_4);
+ FsmDelTimer(&st->l2.t203, 3);
+ if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+ FsmDelTimer(&st->l2.t200, 2);
+ }
+ send_uframe(st, cmd | PollFlag, RSP);
+ if (rel)
+ st->l2.l2man(st, DL_RELEASE, NULL);
}
+
static void
-l2_got_st4_disc(struct FsmInst *fi, int event, void *arg)
+l2_got_ua(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
- struct Channel *chanp = st->l4.userdata;
- u_char PollFlag;
+ u_char PollFlag, est = 1;
+ int state,rsp;
- skb_pull(skb, l2addrsize(&(st->l2)));
- PollFlag = *skb->data & 0x10;
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
+ state = fi->state;
+ rsp = *skb->data & 0x2;
+ if (test_bit(FLG_ORIG, &st->l2.flag))
+ rsp = !rsp;
- if (!((chanp->impair == 1) && (st->l2.laptype == LAPB)))
- send_uframe(st, DM | (PollFlag ? 0x10 : 0x0), RSP);
+ if (!rsp) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+ FreeSkb(skb);
+ if ((state == ST_L2_7) || (state == ST_L2_8))
+ establishlink(fi);
+ return;
+ }
+ if (skb->len != (l2addrsize(&st->l2) + 1)) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+ FreeSkb(skb);
+ if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8))
+ establishlink(fi);
+ return;
+ }
+ PollFlag = get_PollFlag(st, skb);
+ if (!PollFlag) {
+ l2_mdl_error(fi, event, arg);
+ return;
+ }
+ FreeSkb(skb);
+ if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+ FsmDelTimer(&st->l2.t200, 2);
+ if (fi->state == ST_L2_5) {
+ if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag)) {
+ discard_i_queue(st);
+ st->l2.rc = 0;
+ send_uframe(st, DISC | 0x10, CMD);
+ FsmChangeState(fi, ST_L2_6);
+ FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 4);
+ test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
+ } else {
+ if (!test_and_clear_bit(FLG_L3_INIT, &st->l2.flag))
+ if (st->l2.vs != st->l2.va)
+ discard_i_queue(st);
+ else
+ est = 0;
+ st->l2.vs = 0;
+ st->l2.va = 0;
+ st->l2.vr = 0;
+ st->l2.sow = 0;
+ FsmChangeState(fi, ST_L2_7);
+ FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4);
+ if (est)
+ st->l2.l2man(st, DL_ESTABLISH, NULL);
+ }
+ } else { /* ST_L2_6 */
+ st->l2.l2man(st, DL_RELEASE, NULL);
+ FsmChangeState(fi, ST_L2_4);
+ }
}
static void
-l2_got_ua_establish(struct FsmInst *fi, int event, void *arg)
+l2_got_dm(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
- u_char f;
+ u_char PollFlag;
+ int state,rsp;
- skb_pull(skb, l2addrsize(&(st->l2)));
- f = *skb->data & 0x10;
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
- if (f) {
- st->l2.vs = 0;
- st->l2.va = 0;
- st->l2.vr = 0;
- st->l2.sow = 0;
- FsmChangeState(fi, ST_L2_7);
-
- FsmDelTimer(&st->l2.t200_timer, 5);
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 4))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 4");
+ state = fi->state;
+ rsp = *skb->data & 0x2;
+ if (test_bit(FLG_ORIG, &st->l2.flag))
+ rsp = !rsp;
- st->l2.l2man(st, DL_ESTABLISH, NULL);
+ if (!rsp) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+ FreeSkb(skb);
+ if ((state == ST_L2_7) || (state == ST_L2_8))
+ establishlink(fi);
+ return;
+ }
+ if (skb->len != (l2addrsize(&st->l2) + 1)) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+ FreeSkb(skb);
+ if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8))
+ establishlink(fi);
+ return;
}
-}
-
-static void
-l2_got_ua_disconn(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- u_char f;
-
- skb_pull(skb, l2addrsize(&(st->l2)));
- f = *skb->data & 0x10;
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
- if (f) {
- FsmDelTimer(&st->l2.t200_timer, 6);
- FsmChangeState(fi, ST_L2_4);
+ PollFlag = get_PollFlagFree(st, skb);
+ if (!PollFlag) {
+ establishlink(fi);
+ test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
+ } else {
+ if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+ FsmDelTimer(&st->l2.t200, 2);
+ if (fi->state == ST_L2_5 && !test_bit(FLG_L3_INIT, &st->l2.flag))
+ discard_i_queue(st);
st->l2.l2man(st, DL_RELEASE, NULL);
+ FsmChangeState(fi, ST_L2_4);
}
}
@@ -502,7 +721,7 @@ enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf)
l2 = &st->l2;
i = sethdraddr(l2, tmp, cr);
- if (l2->extended) {
+ if (test_bit(FLG_MOD128, &l2->flag)) {
tmp[i++] = typ;
tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0);
} else
@@ -516,77 +735,133 @@ enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf)
}
inline void
-enquiry_response(struct PStack *st, u_char typ, u_char final)
+enquiry_response(struct PStack *st)
{
- enquiry_cr(st, typ, RSP, final);
+ if (test_bit(FLG_OWN_BUSY, &st->l2.flag))
+ enquiry_cr(st, RNR, RSP, 1);
+ else
+ enquiry_cr(st, RR, RSP, 1);
+ test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
}
inline void
-enquiry_command(struct PStack *st, u_char typ, u_char poll)
+transmit_enquiry(struct PStack *st)
{
- enquiry_cr(st, typ, CMD, poll);
+ if (test_bit(FLG_OWN_BUSY, &st->l2.flag))
+ enquiry_cr(st, RNR, CMD, 1);
+ else
+ enquiry_cr(st, RR, CMD, 1);
+ test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
+ FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 12);
+ test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
}
+
static void
nrerrorrecovery(struct FsmInst *fi)
{
- /* should log error here */
+ struct PStack *st = fi->userdata;
+
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'J');
establishlink(fi);
}
static void
-l2_got_st7_RR(struct FsmInst *fi, int event, void *arg)
+invoke_retransmission(struct PStack *st, int nr)
+{
+ struct Layer2 *l2 = &st->l2;
+ int p1;
+ long flags;
+
+ if (l2->vs != nr) {
+ save_flags(flags);
+ cli();
+ while (l2->vs != nr) {
+ l2->vs = l2->vs - 1;
+ if (l2->vs < 0)
+ l2->vs += (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8);
+ p1 = l2->vs - l2->va;
+ if (p1 < 0)
+ p1 += (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8);
+ p1 = (p1 + l2->sow) % l2->window;
+ skb_queue_head(&l2->i_queue, l2->windowar[p1]);
+ l2->windowar[p1] = NULL;
+ }
+ restore_flags(flags);
+ st->l2.l2l1(st, PH_PULL_REQ, NULL);
+ }
+}
+
+static void
+l2_got_st7_super(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
struct sk_buff *skb = arg;
- int PollFlag, seq, rsp;
- struct Layer2 *l2;
+ int PollFlag, nr, rsp, typ = RR;
+ struct Layer2 *l2 = &st->l2;
- l2 = &st->l2;
- if (l2->laptype == LAPD)
- rsp = *skb->data & 0x2;
- else
- rsp = *skb->data == 0x3;
- if (l2->orig)
+ rsp = *skb->data & 0x2;
+ if (test_bit(FLG_ORIG, &l2->flag))
rsp = !rsp;
skb_pull(skb, l2addrsize(l2));
- if (l2->extended) {
- PollFlag = (skb->data[1] & 0x1) == 0x1;
- seq = skb->data[1] >> 1;
+ if (IsRNR(skb->data, test_bit(FLG_MOD128, &l2->flag))) {
+ test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
+ typ = RNR;
+ } else
+ test_and_clear_bit(FLG_PEER_BUSY, &l2->flag);
+ if (IsREJ(skb->data, test_bit(FLG_MOD128, &l2->flag)))
+ typ = REJ;
+ if (test_bit(FLG_MOD128, &l2->flag)) {
+ if (skb->len == 2) {
+ PollFlag = (skb->data[1] & 0x1) == 0x1;
+ nr = skb->data[1] >> 1;
+ } else {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+ FreeSkb(skb);
+ establishlink(fi);
+ return;
+ }
} else {
- PollFlag = (skb->data[0] & 0x10);
- seq = (skb->data[0] >> 5) & 0x7;
+ if (skb->len == 1) {
+ PollFlag = (skb->data[0] & 0x10);
+ nr = (skb->data[0] >> 5) & 0x7;
+ } else {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+ FreeSkb(skb);
+ establishlink(fi);
+ return;
+ }
}
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
+ FreeSkb(skb);
- if (!((chanp->impair == 4) && (st->l2.laptype == LAPB)))
- if ((!rsp) && PollFlag)
- enquiry_response(st, RR, PollFlag);
-
- if (legalnr(st, seq)) {
- if (seq == l2->vs) {
- setva(st, seq);
- FsmDelTimer(&l2->t200_timer, 7);
- l2->t200_running = 0;
- FsmDelTimer(&l2->t203_timer, 8);
- if (FsmAddTimer(&l2->t203_timer, l2->t203, EV_L2_T203, NULL, 5))
- if (l2->l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 5");
-
- if (skb_queue_len(&st->l2.i_queue))
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- } else if (l2->va != seq) {
- setva(st, seq);
- FsmDelTimer(&st->l2.t200_timer, 9);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 6))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 6");
- if (skb_queue_len(&st->l2.i_queue))
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+ if ((!rsp) && PollFlag)
+ enquiry_response(st);
+ if (rsp && PollFlag)
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'A');
+ if (legalnr(st, nr)) {
+ if (typ == REJ) {
+ setva(st, nr);
+ invoke_retransmission(st, nr);
+ if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+ FsmDelTimer(&st->l2.t200, 9);
+ if (FsmAddTimer(&st->l2.t203, st->l2.T203,
+ EV_L2_T203, NULL, 6))
+ l2m_debug(&st->l2.l2m, "Restart T203 ST7 REJ");
+ } else if ((nr == l2->vs) && (typ == RR)) {
+ setva(st, nr);
+ if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+ FsmDelTimer(&st->l2.t200, 9);
+ FsmRestartTimer(&st->l2.t203, st->l2.T203,
+ EV_L2_T203, NULL, 7);
+ } else if ((l2->va != nr) || (typ == RNR)) {
+ setva(st, nr);
+ FsmDelTimer(&st->l2.t203, 9);
+ FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 6);
+ test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
}
+ if (skb_queue_len(&st->l2.i_queue) && (typ == RR))
+ st->l2.l2l1(st, PH_PULL_REQ, NULL);
} else
nrerrorrecovery(fi);
@@ -602,122 +877,121 @@ l2_feed_iqueue(struct FsmInst *fi, int event, void *arg)
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
- skb_queue_tail(&st->l2.i_queue, skb);
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+ if (test_bit(FLG_LAPB, &st->l2.flag))
+ st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0);
+ if (!((fi->state == ST_L2_5) && test_bit(FLG_L3_INIT, &st->l2.flag)))
+ skb_queue_tail(&st->l2.i_queue, skb);
+ if (fi->state == ST_L2_7)
+ st->l2.l2l1(st, PH_PULL_REQ, NULL);
}
-static int
-icommandreceived(struct FsmInst *fi, int event, void *arg, int *nr)
+static void
+l2_got_iframe(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
struct sk_buff *skb = arg;
struct IsdnCardState *sp = st->l1.hardware;
struct Layer2 *l2 = &(st->l2);
- int i, p, seq, wasok;
+ int PollFlag, ns, nr, i, hs, rsp;
char str[64];
+ rsp = *skb->data & 0x2;
+ if (test_bit(FLG_ORIG, &l2->flag))
+ rsp = !rsp;
+
+ if (rsp) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+ FreeSkb(skb);
+ establishlink(fi);
+ return;
+ }
i = l2addrsize(l2);
- if (l2->extended) {
- p = (skb->data[i + 1] & 0x1) == 0x1;
- seq = skb->data[i] >> 1;
- *nr = (skb->data[i + 1] >> 1) & 0x7f;
+ if (test_bit(FLG_MOD128, &l2->flag)) {
+ if (skb->len <= (i + 1)) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+ FreeSkb(skb);
+ establishlink(fi);
+ return;
+ } else if ((skb->len - i - 1) > l2->maxlen) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'O');
+ FreeSkb(skb);
+ establishlink(fi);
+ return;
+ }
+ PollFlag = ((skb->data[i + 1] & 0x1) == 0x1);
+ ns = skb->data[i] >> 1;
+ nr = (skb->data[i + 1] >> 1) & 0x7f;
} else {
- p = (skb->data[i] & 0x10);
- seq = (skb->data[i] >> 1) & 0x7;
- *nr = (skb->data[i] >> 5) & 0x7;
+ if (skb->len <= i) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+ FreeSkb(skb);
+ establishlink(fi);
+ return;
+ } else if ((skb->len - i) > l2->maxlen) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'O');
+ FreeSkb(skb);
+ establishlink(fi);
+ return;
+ }
+ PollFlag = (skb->data[i] & 0x10);
+ ns = (skb->data[i] >> 1) & 0x7;
+ nr = (skb->data[i] >> 5) & 0x7;
}
-
- if (l2->vr == seq) {
- wasok = !0;
-
- l2->vr = (l2->vr + 1) % (l2->extended ? 128 : 8);
- l2->rejexp = 0;
-
- if (st->l2.laptype == LAPD)
+ if (test_bit(FLG_OWN_BUSY, &l2->flag)) {
+ FreeSkb(skb);
+ enquiry_response(st);
+ } else if (l2->vr == ns) {
+ l2->vr = (l2->vr + 1) % (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8);
+ test_and_clear_bit(FLG_REJEXC, &l2->flag);
+ if (test_bit(FLG_LAPD, &l2->flag))
if (sp->dlogflag) {
+ hs = l2headersize(l2, 0);
LogFrame(st->l1.hardware, skb->data, skb->len);
sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei);
- dlogframe(st->l1.hardware, skb->data + l2->ihsize,
- skb->len - l2->ihsize, str);
+ dlogframe(st->l1.hardware, skb->data + hs,
+ skb->len - hs, str);
}
- if (!((chanp->impair == 3) && (st->l2.laptype == LAPB)))
- if (p || (!skb_queue_len(&st->l2.i_queue)))
- enquiry_response(st, RR, p);
+ if (PollFlag)
+ enquiry_response(st);
+ else
+ test_and_set_bit(FLG_ACK_PEND, &l2->flag);
skb_pull(skb, l2headersize(l2, 0));
+ st->l2.l2l3(st, DL_DATA, skb);
} else {
/* n(s)!=v(r) */
- wasok = 0;
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
- if (st->l2.rejexp) {
- if (p)
- if (!((chanp->impair == 3) && (st->l2.laptype == LAPB)))
- enquiry_response(st, RR, p);
+ FreeSkb(skb);
+ if (test_and_set_bit(FLG_REJEXC, &l2->flag)) {
+ if (PollFlag)
+ enquiry_response(st);
} else {
- st->l2.rejexp = !0;
- enquiry_command(st, REJ, 1);
+ enquiry_cr(st, REJ, RSP, PollFlag);
+ test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
}
}
- return wasok;
-}
-
-static void
-l2_got_st7_data(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- int nr, wasok;
-
- wasok = icommandreceived(fi, event, arg, &nr);
-
- if (legalnr(st, nr)) {
- if (nr == st->l2.vs) {
- setva(st, nr);
- FsmDelTimer(&st->l2.t200_timer, 10);
- st->l2.t200_running = 0;
- FsmDelTimer(&st->l2.t203_timer, 11);
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 7))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 5");
-
- if (skb_queue_len(&st->l2.i_queue))
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- } else if (nr != st->l2.va) {
- setva(st, nr);
- FsmDelTimer(&st->l2.t200_timer, 12);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 8))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 6");
-
- if (skb_queue_len(&st->l2.i_queue))
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- }
- } else
- nrerrorrecovery(fi);
-
- if (wasok)
- st->l2.l2l3(st, DL_DATA, skb);
-}
-
-static void
-l2_got_st8_data(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- int nr, wasok;
-
- wasok = icommandreceived(fi, event, arg, &nr);
if (legalnr(st, nr)) {
setva(st, nr);
- if (skb_queue_len(&st->l2.i_queue))
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- } else
+ if (!test_bit(FLG_PEER_BUSY, &st->l2.flag) && (fi->state == ST_L2_7)) {
+ if (nr == st->l2.vs) {
+ if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+ FsmDelTimer(&st->l2.t200, 10);
+ FsmRestartTimer(&st->l2.t203, st->l2.T203,
+ EV_L2_T203, NULL, 7);
+ } else if (nr != st->l2.va) {
+ FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200,
+ NULL, 8);
+ test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
+ }
+ }
+ } else {
nrerrorrecovery(fi);
+ return;
+ }
- if (wasok)
- st->l2.l2l3(st, DL_DATA, skb);
+ if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7))
+ st->l2.l2l1(st, PH_PULL_REQ, NULL);
+ if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag))
+ enquiry_cr(st, RR, RSP, 0);
}
static void
@@ -726,69 +1000,14 @@ l2_got_tei(struct FsmInst *fi, int event, void *arg)
struct PStack *st = fi->userdata;
st->l2.tei = (int) arg;
- establishlink(fi);
-}
-
-static void
-invoke_retransmission(struct PStack *st, int nr)
-{
- struct Layer2 *l2 = &st->l2;
- int p1;
-
- if (l2->vs != nr) {
- while (l2->vs != nr) {
-
- l2->vs = l2->vs - 1;
- if (l2->vs < 0)
- l2->vs += l2->extended ? 128 : 8;
- p1 = l2->vs - l2->va;
- if (p1 < 0)
- p1 += l2->extended ? 128 : 8;
- p1 = (p1 + l2->sow) % l2->window;
-
- skb_queue_head(&l2->i_queue, l2->windowar[p1]);
- l2->windowar[p1] = NULL;
- }
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- }
-}
-
-static void
-l2_got_st7_rej(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- int PollFlag, seq, rsp;
- struct Layer2 *l2;
-
- l2 = &st->l2;
- if (l2->laptype == LAPD)
- rsp = *skb->data & 0x2;
- else
- rsp = *skb->data == 0x3;
- if (l2->orig)
- rsp = !rsp;
-
- skb_pull(skb, l2addrsize(l2));
- if (l2->extended) {
- PollFlag = (skb->data[1] & 0x1) == 0x1;
- seq = skb->data[1] >> 1;
- } else {
- PollFlag = (skb->data[0] & 0x10);
- seq = (skb->data[0] >> 5) & 0x7;
- }
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
-
- if ((!rsp) && PollFlag)
- enquiry_response(st, RR, PollFlag);
-
- if (!legalnr(st, seq))
- return;
-
- setva(st, seq);
- invoke_retransmission(st, seq);
+ if (fi->state == ST_L2_3) {
+ establishlink(fi);
+ test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
+ } else
+ FsmChangeState(fi, ST_L2_4);
+ if (skb_queue_len(&st->l2.ui_queue))
+ l2_send_ui(st);
}
static void
@@ -801,21 +1020,21 @@ static void
l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
- u_char cmd;
- if (st->l2.rc == st->l2.n200) {
+ if (test_bit(FLG_LAPD, &st->l2.flag) &&
+ test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
+ FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
+ } else if (st->l2.rc == st->l2.N200) {
FsmChangeState(fi, ST_L2_4);
- st->l2.l2tei(st, MDL_VERIFY, (void *) st->l2.tei);
+ test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
+ discard_i_queue(st);
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'G');
st->l2.l2man(st, DL_RELEASE, NULL);
} else {
st->l2.rc++;
-
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 9))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 7");
-
- cmd = (st->l2.extended ? SABME : SABM) | 0x10;
- send_uframe(st, cmd, CMD);
+ FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
+ send_uframe(st, (test_bit(FLG_MOD128, &st->l2.flag) ? SABME : SABM)
+ | 0x10, CMD);
}
}
@@ -823,30 +1042,65 @@ static void
l2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
- if (st->l2.rc == st->l2.n200) {
+ if (test_bit(FLG_LAPD, &st->l2.flag) &&
+ test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
+ FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
+ } else if (st->l2.rc == st->l2.N200) {
FsmChangeState(fi, ST_L2_4);
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'H');
st->l2.l2man(st, DL_RELEASE, NULL);
} else {
st->l2.rc++;
+ FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200,
+ NULL, 9);
+ send_uframe(st, DISC | 0x10, CMD);
+ }
+}
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 10))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 8");
+static void
+l2_st78_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ if (test_bit(FLG_LAPD, &st->l2.flag) &&
+ test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
+ FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
+ return;
+ }
+ test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
+ if (fi->state == ST_L2_7) {
+ st->l2.rc = 0;
+ FsmChangeState(fi, ST_L2_8);
+ }
+ if (st->l2.rc == st->l2.N200) {
+ establishlink(fi);
+ } else {
+ transmit_enquiry(st);
+ st->l2.rc++;
+ }
+}
- if (!((chanp->impair == 2) && (st->l2.laptype == LAPB)))
- send_uframe(st, DISC | 0x10, CMD);
+static void
+l2_st7_tout_203(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ if (test_bit(FLG_LAPD, &st->l2.flag) &&
+ test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
+ FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 9);
+ return;
}
+ FsmChangeState(fi, ST_L2_8);
+ transmit_enquiry(st);
+ st->l2.rc = 0;
}
static void
l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
- struct sk_buff *skb;
+ struct sk_buff *skb, *oskb;
struct Layer2 *l2 = &st->l2;
u_char header[MAX_HEADER_LEN];
int p1, i;
@@ -860,19 +1114,18 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
p1 = l2->vs - l2->va;
if (p1 < 0)
- p1 += l2->extended ? 128 : 8;
+ p1 += test_bit(FLG_MOD128, &l2->flag) ? 128 : 8;
p1 = (p1 + l2->sow) % l2->window;
if (l2->windowar[p1]) {
printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n",
p1);
- SET_SKB_FREE(l2->windowar[p1]);
dev_kfree_skb(l2->windowar[p1]);
}
l2->windowar[p1] = skb_clone(skb, GFP_ATOMIC);
i = sethdraddr(&st->l2, header, CMD);
- if (l2->extended) {
+ if (test_bit(FLG_MOD128, &l2->flag)) {
header[i++] = l2->vs << 1;
header[i++] = l2->vr << 1;
l2->vs = (l2->vs + 1) % 128;
@@ -880,88 +1133,86 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
header[i++] = (l2->vr << 5) | (l2->vs << 1);
l2->vs = (l2->vs + 1) % 8;
}
-
- memcpy(skb_push(skb, i), header, i);
- st->l2.l2l1(st, PH_DATA_PULLED, skb);
- if (!st->l2.t200_running) {
- FsmDelTimer(&st->l2.t203_timer, 13);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 11))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 9");
-
- st->l2.t200_running = !0;
+ p1 = skb->data - skb->head;
+ if (p1 >= i)
+ memcpy(skb_push(skb, i), header, i);
+ else {
+ printk(KERN_WARNING
+ "isdl2 pull_iqueue skb header(%d/%d) too short\n", i, p1);
+ oskb = skb;
+ skb = alloc_skb(oskb->len + i, GFP_ATOMIC);
+ memcpy(skb_put(skb, i), header, i);
+ memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len);
+ FreeSkb(oskb);
+ }
+ st->l2.l2l1(st, PH_PULL_IND, skb);
+ test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
+ if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) {
+ FsmDelTimer(&st->l2.t203, 13);
+ FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11);
}
if (skb_queue_len(&l2->i_queue) && cansend(st))
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-}
-
-static void
-transmit_enquiry(struct PStack *st)
-{
-
- enquiry_command(st, RR, 1);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 12))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 10");
-
- st->l2.t200_running = !0;
-}
-
-static void
-l2_st7_tout_200(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.t200_running = 0;
-
- st->l2.rc = 1;
- FsmChangeState(fi, ST_L2_8);
- transmit_enquiry(st);
+ st->l2.l2l1(st, PH_PULL_REQ, NULL);
}
static void
-l2_got_st8_rr_rej(struct FsmInst *fi, int event, void *arg)
+l2_got_st8_super(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
- int PollFlag, seq, rsp;
- struct Layer2 *l2;
+ int PollFlag, nr, rsp, rnr = 0;
+ struct Layer2 *l2 = &st->l2;
- l2 = &st->l2;
- if (l2->laptype == LAPD)
- rsp = *skb->data & 0x2;
- else
- rsp = *skb->data == 0x3;
- if (l2->orig)
+ rsp = *skb->data & 0x2;
+ if (test_bit(FLG_ORIG, &l2->flag))
rsp = !rsp;
-
skb_pull(skb, l2addrsize(l2));
- if (l2->extended) {
- PollFlag = (skb->data[1] & 0x1) == 0x1;
- seq = skb->data[1] >> 1;
+
+ if (IsRNR(skb->data, test_bit(FLG_MOD128, &l2->flag))) {
+ test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
+ rnr = 1;
+ } else
+ test_and_clear_bit(FLG_PEER_BUSY, &l2->flag);
+ if (test_bit(FLG_MOD128, &l2->flag)) {
+ if (skb->len == 2) {
+ PollFlag = (skb->data[1] & 0x1) == 0x1;
+ nr = skb->data[1] >> 1;
+ } else {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+ FreeSkb(skb);
+ establishlink(fi);
+ return;
+ }
} else {
- PollFlag = (skb->data[0] & 0x10);
- seq = (skb->data[0] >> 5) & 0x7;
+ if (skb->len == 1) {
+ PollFlag = (skb->data[0] & 0x10);
+ nr = (skb->data[0] >> 5) & 0x7;
+ } else {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+ FreeSkb(skb);
+ establishlink(fi);
+ return;
+ }
}
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
+ FreeSkb(skb);
if (rsp && PollFlag) {
- if (legalnr(st, seq)) {
+ if (legalnr(st, nr)) {
+ setva(st, nr);
+ if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+ FsmDelTimer(&st->l2.t200, 7);
+ FsmDelTimer(&l2->t203, 8);
+ if (rnr) {
+ FsmRestartTimer(&l2->t200, l2->T200,
+ EV_L2_T200, NULL, 14);
+ test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
+ } else
+ FsmAddTimer(&l2->t203, l2->T203,
+ EV_L2_T203, NULL, 5);
+ invoke_retransmission(st, nr);
FsmChangeState(fi, ST_L2_7);
- setva(st, seq);
- if (st->l2.t200_running) {
- FsmDelTimer(&st->l2.t200_timer, 14);
- st->l2.t200_running = 0;
- }
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 13))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 11");
-
- invoke_retransmission(st, seq);
-
if (skb_queue_len(&l2->i_queue) && cansend(st))
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+ st->l2.l2l1(st, PH_PULL_REQ, NULL);
else if (fi->userint & LC_FLUSH_WAIT) {
fi->userint &= ~LC_FLUSH_WAIT;
st->l2.l2man(st, DL_FLUSH, NULL);
@@ -969,57 +1220,46 @@ l2_got_st8_rr_rej(struct FsmInst *fi, int event, void *arg)
}
} else {
if (!rsp && PollFlag)
- enquiry_response(st, RR, PollFlag);
- if (legalnr(st, seq)) {
- setva(st, seq);
+ enquiry_response(st);
+ if (legalnr(st, nr)) {
+ setva(st, nr);
}
}
}
static void
-l2_st7_tout_203(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.rc = 0;
- FsmChangeState(fi, ST_L2_8);
- transmit_enquiry(st);
-}
-
-static void
-l2_st8_tout_200(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (st->l2.rc == st->l2.n200) {
- establishlink(fi);
- } else {
- st->l2.rc++;
- transmit_enquiry(st);
- }
-}
-
-static void
l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
char tmp[64];
- skb_pull(skb, l2addrsize(&st->l2));
- if (st->l2.l2m.debug) {
- if (st->l2.extended)
+ skb_pull(skb, l2addrsize(&st->l2) + 1);
+ if (test_bit(FLG_MOD128, &st->l2.flag)) {
+ if (skb->len < 5)
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+ else {
sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x",
skb->data[0], skb->data[1], skb->data[2],
skb->data[3], skb->data[4]);
- else
+ l2m_debug(&st->l2.l2m, tmp);
+ }
+ } else {
+ if (skb->len < 3)
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+ else {
sprintf(tmp, "FRMR information %2x %2x %2x",
skb->data[0], skb->data[1], skb->data[2]);
-
- l2m_debug(&st->l2.l2m, tmp);
+ l2m_debug(&st->l2.l2m, tmp);
+ }
}
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
+ if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */
+ (IsUA(skb->data, 0) && (fi->state == ST_L2_7))) {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'K');
+ establishlink(fi);
+ test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
+ }
+ FreeSkb(skb);
}
static void
@@ -1027,135 +1267,126 @@ l2_tei_remove(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
-/*TODO
- if( DL_RELEASE.req outstanding ) {
- ... issue DL_RELEASE.confirm
- } else {
- if( fi->state != ST_L2_4 ) {
- ... issue DL_RELEASE.indication
- }
- }
- TODO */
- discard_i_queue(st); /* There is no UI queue in layer 2 */
- st->l2.tei = 255;
- if (st->l2.t200_running) {
- FsmDelTimer(&st->l2.t200_timer, 18);
- st->l2.t200_running = 0;
- }
- FsmDelTimer(&st->l2.t203_timer, 19);
- st->l2.l2man(st, DL_RELEASE, NULL); /* TEMP */
+ discard_i_queue(st);
+ discard_ui_queue(st);
+ st->l2.tei = -1;
+ if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+ FsmDelTimer(&st->l2.t200, 18);
+ FsmDelTimer(&st->l2.t203, 19);
+ if (fi->state != ST_L2_4)
+ st->l2.l2man(st, DL_RELEASE, NULL);
FsmChangeState(fi, ST_L2_1);
}
-inline int
-IsUI(u_char * data, int ext)
-{
- return ((data[0] & 0xef) == UI);
-}
-
-inline int
-IsUA(u_char * data, int ext)
-{
- return ((data[0] & 0xef) == UA);
-}
-
-inline int
-IsDISC(u_char * data, int ext)
-{
- return ((data[0] & 0xef) == DISC);
-}
-
-inline int
-IsRR(u_char * data, int ext)
-{
- if (ext)
- return (data[0] == RR);
- else
- return ((data[0] & 0xf) == 1);
-}
-
-inline int
-IsI(u_char * data, int ext)
-{
- return ((data[0] & 0x1) == 0x0);
-}
-
-inline int
-IsSABMX(u_char * data, int ext)
+static void
+l2_persistant_da(struct FsmInst *fi, int event, void *arg)
{
- u_char d = data[0] & ~0x10;
+ struct PStack *st = fi->userdata;
- return (ext ? d == SABME : d == SABM);
-}
-
-inline int
-IsREJ(u_char * data, int ext)
-{
- return (ext ? data[0] == REJ : (data[0] & 0xf) == 0x9);
-}
-
-inline int
-IsFRMR(u_char * data, int ext)
-{
- return ((data[0] & 0xef) == FRMR);
-}
-
-inline int
-IsRNR(u_char * data, int ext)
-{
- if (ext)
- return (data[0] == RNR);
- else
- return ((data[0] & 0xf) == 5);
+ discard_i_queue(st);
+ discard_ui_queue(st);
+ if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+ FsmDelTimer(&st->l2.t200, 18);
+ FsmDelTimer(&st->l2.t203, 19);
+ test_and_clear_bit(FLG_PEND_REL, &st->l2.flag);
+ clear_exception(&st->l2);
+ switch (fi->state) {
+ case ST_L2_3:
+ st->l2.l2man(st, DL_RELEASE, NULL);
+ case ST_L2_2:
+ FsmChangeState(fi, ST_L2_1);
+ break;
+ case ST_L2_5:
+ case ST_L2_6:
+ case ST_L2_7:
+ case ST_L2_8:
+ st->l2.l2man(st, DL_RELEASE, NULL);
+ FsmChangeState(fi, ST_L2_4);
+ break;
+ }
}
-static struct FsmNode L2FnList[] =
+static struct FsmNode L2FnList[] HISAX_INITDATA =
{
- {ST_L2_1, EV_L2_DL_ESTABLISH, l2s1},
{ST_L2_1, EV_L2_MDL_NOTEIPROC, l2_no_tei},
- {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei},
- {ST_L2_4, EV_L2_DL_UNIT_DATA, l2_send_ui},
+ {ST_L2_1, EV_L2_DL_ESTABLISH, l2_dl_establish},
+ {ST_L2_2, EV_L2_DL_ESTABLISH, l2_dl_establish},
{ST_L2_4, EV_L2_DL_ESTABLISH, l2_establish},
- {ST_L2_7, EV_L2_DL_UNIT_DATA, l2_send_ui},
+ {ST_L2_5, EV_L2_DL_ESTABLISH, l2_establish},
+ {ST_L2_7, EV_L2_DL_ESTABLISH, l2_establish},
+ {ST_L2_8, EV_L2_DL_ESTABLISH, l2_establish},
+ {ST_L2_4, EV_L2_DL_RELEASE, l2_dl_release},
+ {ST_L2_5, EV_L2_DL_RELEASE, l2_dl_release},
+ {ST_L2_7, EV_L2_DL_RELEASE, l2_dl_release},
+ {ST_L2_8, EV_L2_DL_RELEASE, l2_dl_release},
+ {ST_L2_5, EV_L2_DL_DATA, l2_feed_iqueue},
{ST_L2_7, EV_L2_DL_DATA, l2_feed_iqueue},
- {ST_L2_7, EV_L2_DL_RELEASE, l2_send_disconn},
- {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
{ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue},
- {ST_L2_8, EV_L2_DL_RELEASE, l2_send_disconn},
-
- {ST_L2_1, EV_L2_UI, l2_receive_ui},
- {ST_L2_4, EV_L2_UI, l2_receive_ui},
+ {ST_L2_1, EV_L2_DL_UNIT_DATA, l2_put_ui},
+ {ST_L2_2, EV_L2_DL_UNIT_DATA, l2_put_ui},
+ {ST_L2_3, EV_L2_DL_UNIT_DATA, l2_put_ui},
+ {ST_L2_4, EV_L2_DL_UNIT_DATA, l2_put_ui},
+ {ST_L2_5, EV_L2_DL_UNIT_DATA, l2_put_ui},
+ {ST_L2_6, EV_L2_DL_UNIT_DATA, l2_put_ui},
+ {ST_L2_7, EV_L2_DL_UNIT_DATA, l2_put_ui},
+ {ST_L2_8, EV_L2_DL_UNIT_DATA, l2_put_ui},
+ {ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei},
+ {ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei},
+ {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei},
+ {ST_L2_2, EV_L2_MDL_ERROR, l2_tei_remove},
+ {ST_L2_3, EV_L2_MDL_ERROR, l2_tei_remove},
+ {ST_L2_4, EV_L2_MDL_REMOVE, l2_tei_remove},
+ {ST_L2_5, EV_L2_MDL_REMOVE, l2_tei_remove},
+ {ST_L2_6, EV_L2_MDL_REMOVE, l2_tei_remove},
+ {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove},
+ {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove},
{ST_L2_4, EV_L2_SABMX, l2_got_SABMX},
- {ST_L2_4, EV_L2_DISC, l2_got_st4_disc},
- {ST_L2_5, EV_L2_UA, l2_got_ua_establish},
- {ST_L2_6, EV_L2_UA, l2_got_ua_disconn},
- {ST_L2_7, EV_L2_UI, l2_receive_ui},
- {ST_L2_7, EV_L2_DISC, l2_got_disconn},
- {ST_L2_7, EV_L2_I, l2_got_st7_data},
- {ST_L2_7, EV_L2_RR, l2_got_st7_RR},
- {ST_L2_7, EV_L2_REJ, l2_got_st7_rej},
+ {ST_L2_5, EV_L2_SABMX, l2_got_SABMX},
+ {ST_L2_6, EV_L2_SABMX, l2_got_SABMX},
{ST_L2_7, EV_L2_SABMX, l2_got_SABMX},
- {ST_L2_7, EV_L2_FRMR, l2_got_FRMR},
- {ST_L2_8, EV_L2_RR, l2_got_st8_rr_rej},
- {ST_L2_8, EV_L2_REJ, l2_got_st8_rr_rej},
{ST_L2_8, EV_L2_SABMX, l2_got_SABMX},
+ {ST_L2_4, EV_L2_DISC, l2_got_disconn},
+ {ST_L2_5, EV_L2_DISC, l2_got_disconn},
+ {ST_L2_6, EV_L2_DISC, l2_got_disconn},
+ {ST_L2_7, EV_L2_DISC, l2_got_disconn},
{ST_L2_8, EV_L2_DISC, l2_got_disconn},
+ {ST_L2_4, EV_L2_UA, l2_mdl_error},
+ {ST_L2_5, EV_L2_UA, l2_got_ua},
+ {ST_L2_6, EV_L2_UA, l2_got_ua},
+ {ST_L2_7, EV_L2_UA, l2_mdl_error},
+ {ST_L2_8, EV_L2_UA, l2_mdl_error},
+ {ST_L2_4, EV_L2_DM, l2_got_dm},
+ {ST_L2_5, EV_L2_DM, l2_got_dm},
+ {ST_L2_6, EV_L2_DM, l2_got_dm},
+ {ST_L2_7, EV_L2_DM, l2_mdl_error},
+ {ST_L2_8, EV_L2_DM, l2_mdl_error},
+ {ST_L2_1, EV_L2_UI, l2_got_ui},
+ {ST_L2_2, EV_L2_UI, l2_got_ui},
+ {ST_L2_3, EV_L2_UI, l2_got_ui},
+ {ST_L2_4, EV_L2_UI, l2_got_ui},
+ {ST_L2_5, EV_L2_UI, l2_got_ui},
+ {ST_L2_6, EV_L2_UI, l2_got_ui},
+ {ST_L2_7, EV_L2_UI, l2_got_ui},
+ {ST_L2_8, EV_L2_UI, l2_got_ui},
+ {ST_L2_7, EV_L2_FRMR, l2_got_FRMR},
{ST_L2_8, EV_L2_FRMR, l2_got_FRMR},
- {ST_L2_8, EV_L2_I, l2_got_st8_data},
-
+ {ST_L2_7, EV_L2_SUPER, l2_got_st7_super},
+ {ST_L2_8, EV_L2_SUPER, l2_got_st8_super},
+ {ST_L2_7, EV_L2_I, l2_got_iframe},
+ {ST_L2_8, EV_L2_I, l2_got_iframe},
{ST_L2_5, EV_L2_T200, l2_st5_tout_200},
{ST_L2_6, EV_L2_T200, l2_st6_tout_200},
- {ST_L2_7, EV_L2_T200, l2_st7_tout_200},
+ {ST_L2_7, EV_L2_T200, l2_st78_tout_200},
+ {ST_L2_8, EV_L2_T200, l2_st78_tout_200},
{ST_L2_7, EV_L2_T203, l2_st7_tout_203},
- {ST_L2_8, EV_L2_T200, l2_st8_tout_200},
-
- {ST_L2_1, EV_L2_MDL_REMOVE, l2_tei_remove},
- {ST_L2_3, EV_L2_MDL_REMOVE, l2_tei_remove},
- {ST_L2_4, EV_L2_MDL_REMOVE, l2_tei_remove},
- {ST_L2_5, EV_L2_MDL_REMOVE, l2_tei_remove},
- {ST_L2_6, EV_L2_MDL_REMOVE, l2_tei_remove},
- {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove},
- {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove},
+ {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
+ {ST_L2_2, EV_L1_DEACTIVATE, l2_persistant_da},
+ {ST_L2_3, EV_L1_DEACTIVATE, l2_persistant_da},
+ {ST_L2_4, EV_L1_DEACTIVATE, l2_persistant_da},
+ {ST_L2_5, EV_L1_DEACTIVATE, l2_persistant_da},
+ {ST_L2_6, EV_L1_DEACTIVATE, l2_persistant_da},
+ {ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da},
+ {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da},
};
#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
@@ -1165,40 +1396,53 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg)
{
struct sk_buff *skb = arg;
u_char *datap;
- int ret = !0;
+ int ret = 1, len;
switch (pr) {
- case (PH_DATA):
+ case (PH_DATA_IND):
datap = skb->data;
- datap += l2addrsize(&st->l2);
-
- if (IsI(datap, st->l2.extended))
+ len = l2addrsize(&st->l2);
+ if (skb->len > len)
+ datap += len;
+ else {
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+ FreeSkb(skb);
+ return;
+ }
+ if (!(*datap & 1)) /* I-Frame */
ret = FsmEvent(&st->l2.l2m, EV_L2_I, skb);
- else if (IsRR(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_RR, skb);
- else if (IsUI(datap, st->l2.extended))
+ else if ((*datap & 3) == 1) /* S-Frame */
+ ret = FsmEvent(&st->l2.l2m, EV_L2_SUPER, skb);
+ else if (IsUI(datap, test_bit(FLG_MOD128, &st->l2.flag)))
ret = FsmEvent(&st->l2.l2m, EV_L2_UI, skb);
- else if (IsSABMX(datap, st->l2.extended))
+ else if (IsSABMX(datap, test_bit(FLG_MOD128, &st->l2.flag)))
ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, skb);
- else if (IsUA(datap, st->l2.extended))
+ else if (IsUA(datap, test_bit(FLG_MOD128, &st->l2.flag)))
ret = FsmEvent(&st->l2.l2m, EV_L2_UA, skb);
- else if (IsDISC(datap, st->l2.extended))
+ else if (IsDISC(datap, test_bit(FLG_MOD128, &st->l2.flag)))
ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, skb);
- else if (IsREJ(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_REJ, skb);
- else if (IsFRMR(datap, st->l2.extended))
+ else if (IsDM(datap, test_bit(FLG_MOD128, &st->l2.flag)))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_DM, skb);
+ else if (IsFRMR(datap, test_bit(FLG_MOD128, &st->l2.flag)))
ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb);
- else if (IsRNR(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_RNR, skb);
-
+ else {
+ ret = 0;
+ st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+ FreeSkb(skb);
+ }
if (ret) {
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
+ FreeSkb(skb);
}
break;
- case (PH_PULL_ACK):
+ case (PH_PULL_CNF):
FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
break;
+ case (PH_PAUSE_IND):
+ test_and_set_bit(FLG_DCHAN_BUSY, &st->l2.flag);
+ break;
+ case (PH_PAUSE_CNF):
+ test_and_clear_bit(FLG_DCHAN_BUSY, &st->l2.flag);
+ break;
}
}
@@ -1208,13 +1452,11 @@ isdnl2_l3l2(struct PStack *st, int pr, void *arg)
switch (pr) {
case (DL_DATA):
if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) {
- SET_SKB_FREE(((struct sk_buff *) arg));
dev_kfree_skb((struct sk_buff *) arg);
}
break;
case (DL_UNIT_DATA):
if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) {
- SET_SKB_FREE(((struct sk_buff *) arg));
dev_kfree_skb((struct sk_buff *) arg);
}
break;
@@ -1237,28 +1479,28 @@ isdnl2_manl2(struct PStack *st, int pr, void *arg)
case (DL_FLUSH):
(&st->l2.l2m)->userint |= LC_FLUSH_WAIT;
break;
- }
-}
-
-static void
-isdnl2_teil2(struct PStack *st, int pr, void *arg)
-{
- switch (pr) {
- case (MDL_ASSIGN):
+ case (PH_DEACTIVATE_IND):
+ FsmEvent(&st->l2.l2m, EV_L1_DEACTIVATE, arg);
+ break;
+ case (MDL_ASSIGN_REQ):
FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
break;
- case (MDL_REMOVE):
+ case (MDL_REMOVE_REQ):
FsmEvent(&st->l2.l2m, EV_L2_MDL_REMOVE, arg);
break;
+ case (MDL_ERROR_REQ):
+ FsmEvent(&st->l2.l2m, EV_L2_MDL_ERROR, arg);
+ break;
}
}
void
releasestack_isdnl2(struct PStack *st)
{
- FsmDelTimer(&st->l2.t200_timer, 15);
- FsmDelTimer(&st->l2.t203_timer, 16);
+ FsmDelTimer(&st->l2.t200, 15);
+ FsmDelTimer(&st->l2.t203, 16);
discard_i_queue(st);
+ discard_ui_queue(st);
ReleaseWin(&st->l2);
}
@@ -1279,13 +1521,10 @@ setstack_isdnl2(struct PStack *st, char *debug_id)
st->l1.l1l2 = isdnl2_l1l2;
st->l3.l3l2 = isdnl2_l3l2;
st->ma.manl2 = isdnl2_manl2;
- st->ma.teil2 = isdnl2_teil2;
- st->l2.uihsize = l2headersize(&st->l2, !0);
- st->l2.ihsize = l2headersize(&st->l2, 0);
skb_queue_head_init(&st->l2.i_queue);
+ skb_queue_head_init(&st->l2.ui_queue);
InitWin(&st->l2);
- st->l2.rejexp = 0;
st->l2.debug = 0;
st->l2.l2m.fsm = &l2fsm;
@@ -1296,9 +1535,8 @@ setstack_isdnl2(struct PStack *st, char *debug_id)
st->l2.l2m.printdebug = l2m_debug;
strcpy(st->l2.debug_id, debug_id);
- FsmInitTimer(&st->l2.l2m, &st->l2.t200_timer);
- FsmInitTimer(&st->l2.l2m, &st->l2.t203_timer);
- st->l2.t200_running = 0;
+ FsmInitTimer(&st->l2.l2m, &st->l2.t200);
+ FsmInitTimer(&st->l2.l2m, &st->l2.t203);
}
void
@@ -1311,8 +1549,8 @@ releasestack_transl2(struct PStack *st)
{
}
-void
-Isdnl2New(void)
+HISAX_INITFUNC(void
+Isdnl2New(void))
{
l2fsm.state_count = L2_STATE_COUNT;
l2fsm.event_count = L2_EVENT_COUNT;
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
index 73b66c73b..026d8eb76 100644
--- a/drivers/isdn/hisax/isdnl3.c
+++ b/drivers/isdn/hisax/isdnl3.c
@@ -1,4 +1,4 @@
-/* $Id: isdnl3.c,v 1.10 1997/04/06 22:54:16 keil Exp $
+/* $Id: isdnl3.c,v 2.5 1998/02/12 23:07:52 keil Exp $
* Author Karsten Keil (keil@temic-ech.spacenet.de)
* based on the teles driver from Jan den Ouden
@@ -7,38 +7,39 @@
* Fritz Elfert
*
* $Log: isdnl3.c,v $
- * Revision 1.10 1997/04/06 22:54:16 keil
- * Using SKB's
- *
- * Revision 1.9 1997/03/25 23:11:25 keil
- * US NI-1 protocol
+ * Revision 2.5 1998/02/12 23:07:52 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
*
- * Revision 1.8 1997/03/21 18:53:44 keil
- * Report no protocol error to syslog too
+ * Revision 2.4 1997/11/06 17:09:25 keil
+ * New 2.1 init code
*
- * Revision 1.7 1997/03/17 18:34:38 keil
- * fixed oops if no protocol selected during config
+ * Revision 2.3 1997/10/29 19:07:53 keil
+ * changes for 2.1
*
- * Revision 1.6 1997/02/16 01:04:08 fritz
- * Bugfix: Changed timer handling caused hang with 2.1.X
+ * Revision 2.2 1997/10/01 09:21:41 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
*
- * Revision 1.5 1997/02/09 00:26:27 keil
- * new interface handling, one interface per card
- * leased line changes
+ * Revision 2.1 1997/08/03 14:36:32 keil
+ * Implement RESTART procedure
*
- * Revision 1.4 1997/01/27 23:17:44 keil
- * delete timers while unloading
+ * Revision 2.0 1997/07/27 21:15:42 keil
+ * New Callref based layer3
*
- * Revision 1.3 1997/01/21 22:31:12 keil
- * new statemachine; L3 timers
+ * Revision 1.11 1997/06/26 11:11:44 keil
+ * SET_SKBFREE now on creation of a SKB
*
- * Revision 1.2 1996/11/05 19:42:04 keil
- * using config.h
+ * Revision 1.10 1997/04/06 22:54:16 keil
+ * Using SKB's
*
- * Revision 1.1 1996/10/13 20:04:54 keil
- * Initial revision
+ * Revision 1.9 1997/03/25 23:11:25 keil
+ * US NI-1 protocol
*
+ * Revision 1.8 1997/03/21 18:53:44 keil
+ * Report no protocol error to syslog too
*
+ * Remove old logs /KKe
*
*/
#define __NO_VERSION__
@@ -46,7 +47,72 @@
#include "isdnl3.h"
#include <linux/config.h>
-const char *l3_revision = "$Revision: 1.10 $";
+const char *l3_revision = "$Revision: 2.5 $";
+
+u_char *
+findie(u_char * p, int size, u_char ie, int wanted_set)
+{
+ int l, codeset, maincodeset;
+ u_char *pend = p + size;
+
+ /* skip protocol discriminator, callref and message type */
+ p++;
+ l = (*p++) & 0xf;
+ p += l;
+ p++;
+ codeset = 0;
+ maincodeset = 0;
+ /* while there are bytes left... */
+ while (p < pend) {
+ if ((*p & 0xf0) == 0x90) {
+ codeset = *p & 0x07;
+ if (!(*p & 0x08))
+ maincodeset = codeset;
+ }
+ if (*p & 0x80)
+ p++;
+ else {
+ if (codeset == wanted_set) {
+ if (*p == ie)
+ return (p);
+ if (*p > ie)
+ return (NULL);
+ }
+ p++;
+ l = *p++;
+ p += l;
+ codeset = maincodeset;
+ }
+ }
+ return (NULL);
+}
+
+int
+getcallref(u_char * p)
+{
+ int l, m = 1, cr = 0;
+ p++; /* prot discr */
+ l = 0xf & *p++; /* callref length */
+ if (!l) /* dummy CallRef */
+ return(-1);
+ while (l--) {
+ cr += m * (*p++);
+ m *= 8;
+ }
+ return (cr);
+}
+
+static int OrigCallRef = 0;
+
+int
+newcallref(void)
+{
+ if (OrigCallRef == 127)
+ OrigCallRef = 1;
+ else
+ OrigCallRef++;
+ return (OrigCallRef);
+}
void
l3_debug(struct PStack *st, char *s)
@@ -54,34 +120,33 @@ l3_debug(struct PStack *st, char *s)
char str[256], tm[32];
jiftime(tm, jiffies);
- sprintf(str, "%s Channel %d l3 %s\n", tm, st->l3.channr, s);
+ sprintf(str, "%s l3 %s\n", tm, s);
HiSax_putstatus(st->l1.hardware, str);
}
-
-
void
-newl3state(struct PStack *st, int state)
+newl3state(struct l3_process *pc, int state)
{
char tmp[80];
- if (st->l3.debug & L3_DEB_STATE) {
- sprintf(tmp, "newstate %d --> %d", st->l3.state, state);
- l3_debug(st, tmp);
+ if (pc->debug & L3_DEB_STATE) {
+ sprintf(tmp, "newstate cr %d %d --> %d", pc->callref,
+ pc->state, state);
+ l3_debug(pc->st, tmp);
}
- st->l3.state = state;
+ pc->state = state;
}
static void
L3ExpireTimer(struct L3Timer *t)
{
- t->st->l4.l4l3(t->st, t->event, NULL);
+ t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc);
}
void
-L3InitTimer(struct PStack *st, struct L3Timer *t)
+L3InitTimer(struct l3_process *pc, struct L3Timer *t)
{
- t->st = st;
+ t->pc = pc;
t->tl.function = (void *) L3ExpireTimer;
t->tl.data = (long) t;
init_timer(&t->tl);
@@ -109,9 +174,9 @@ L3AddTimer(struct L3Timer *t,
}
void
-StopAllL3Timer(struct PStack *st)
+StopAllL3Timer(struct l3_process *pc)
{
- L3DelTimer(&st->l3.timer);
+ L3DelTimer(&pc->timer);
}
struct sk_buff *
@@ -132,9 +197,8 @@ no_l3_proto(struct PStack *st, int pr, void *arg)
{
struct sk_buff *skb = arg;
- l3_debug(st, "no protocol");
+ HiSax_putstatus(st->l1.hardware, "L3 no D protocol\n");
if (skb) {
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
}
}
@@ -151,14 +215,78 @@ extern void setstack_ni1(struct PStack *st);
extern void setstack_1tr6(struct PStack *st);
#endif
+struct l3_process
+*getl3proc(struct PStack *st, int cr)
+{
+ struct l3_process *p = st->l3.proc;
+
+ while (p)
+ if (p->callref == cr)
+ return (p);
+ else
+ p = p->next;
+ return (NULL);
+}
+
+struct l3_process
+*new_l3_process(struct PStack *st, int cr)
+{
+ struct l3_process *p, *np;
+
+ if (!(p = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
+ printk(KERN_ERR "HiSax can't get memory for cr %d\n", cr);
+ return (NULL);
+ }
+ if (!st->l3.proc)
+ st->l3.proc = p;
+ else {
+ np = st->l3.proc;
+ while (np->next)
+ np = np->next;
+ np->next = p;
+ }
+ p->next = NULL;
+ p->debug = L3_DEB_WARN;
+ p->callref = cr;
+ p->state = 0;
+ p->chan = NULL;
+ p->st = st;
+ p->N303 = st->l3.N303;
+ L3InitTimer(p, &p->timer);
+ return (p);
+};
+
+void
+release_l3_process(struct l3_process *p)
+{
+ struct l3_process *np, *pp = NULL;
+
+ if (!p)
+ return;
+ np = p->st->l3.proc;
+ while (np) {
+ if (np == p) {
+ StopAllL3Timer(p);
+ if (pp)
+ pp->next = np->next;
+ else
+ p->st->l3.proc = np->next;
+ kfree(p);
+ return;
+ }
+ pp = np;
+ np = np->next;
+ }
+ printk(KERN_ERR "HiSax internal L3 error CR not in list\n");
+};
+
void
setstack_isdnl3(struct PStack *st, struct Channel *chanp)
{
char tmp[64];
- st->l3.debug = L3_DEB_WARN;
- st->l3.channr = chanp->chan;
- L3InitTimer(st, &st->l3.timer);
+ st->l3.proc = NULL;
+ st->l3.global = NULL;
#ifdef CONFIG_HISAX_EURO
if (st->protocol == ISDN_PTYPE_EURO) {
@@ -176,11 +304,11 @@ setstack_isdnl3(struct PStack *st, struct Channel *chanp)
} else
#endif
if (st->protocol == ISDN_PTYPE_LEASED) {
- st->l4.l4l3 = no_l3_proto;
+ st->lli.l4l3 = no_l3_proto;
st->l2.l2l3 = no_l3_proto;
- printk(KERN_NOTICE "HiSax: Leased line mode\n");
+ printk(KERN_INFO "HiSax: Leased line mode\n");
} else {
- st->l4.l4l3 = no_l3_proto;
+ st->lli.l4l3 = no_l3_proto;
st->l2.l2l3 = no_l3_proto;
sprintf(tmp, "protocol %s not supported",
(st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
@@ -188,15 +316,18 @@ setstack_isdnl3(struct PStack *st, struct Channel *chanp)
(st->protocol == ISDN_PTYPE_NI1) ? "ni1" :
"unknown");
printk(KERN_WARNING "HiSax: %s\n", tmp);
- l3_debug(st, tmp);
st->protocol = -1;
}
- st->l3.state = 0;
- st->l3.callref = 0;
}
void
releasestack_isdnl3(struct PStack *st)
{
- StopAllL3Timer(st);
+ while (st->l3.proc)
+ release_l3_process(st->l3.proc);
+ if (st->l3.global) {
+ StopAllL3Timer(st->l3.global);
+ kfree(st->l3.global);
+ st->l3.global = NULL;
+ }
}
diff --git a/drivers/isdn/hisax/isdnl3.h b/drivers/isdn/hisax/isdnl3.h
index bed989a18..2ff582b4a 100644
--- a/drivers/isdn/hisax/isdnl3.h
+++ b/drivers/isdn/hisax/isdnl3.h
@@ -1,6 +1,12 @@
-/* $Id: isdnl3.h,v 1.3 1997/04/06 22:54:17 keil Exp $
- *
+/* $Id: isdnl3.h,v 2.0 1997/07/27 21:15:42 keil Exp $
+
* $Log: isdnl3.h,v $
+ * Revision 2.0 1997/07/27 21:15:42 keil
+ * New Callref based layer3
+ *
+ * Revision 1.4 1997/06/26 11:20:57 keil
+ * ?
+ *
* Revision 1.3 1997/04/06 22:54:17 keil
* Using SKB's
*
@@ -24,15 +30,18 @@
#define L3_DEB_CHARGE 0x08
struct stateentry {
- int state;
- u_char primitive;
- void (*rout) (struct PStack *, u_char, void *);
+ int state;
+ u_char primitive;
+ void (*rout) (struct l3_process *, u_char, void *);
};
extern void l3_debug(struct PStack *st, char *s);
-extern void newl3state(struct PStack *st, int state);
-extern void L3InitTimer(struct PStack *st, struct L3Timer *t);
+extern void newl3state(struct l3_process *pc, int state);
+extern void L3InitTimer(struct l3_process *pc, struct L3Timer *t);
extern void L3DelTimer(struct L3Timer *t);
-extern int L3AddTimer(struct L3Timer *t, int millisec, int event);
-extern void StopAllL3Timer(struct PStack *st);
+extern int L3AddTimer(struct L3Timer *t, int millisec, int event);
+extern void StopAllL3Timer(struct l3_process *pc);
extern struct sk_buff *l3_alloc_skb(int len);
+extern struct l3_process *new_l3_process(struct PStack *st, int cr);
+extern void release_l3_process(struct l3_process *p);
+extern struct l3_process *getl3proc(struct PStack *st, int cr);
diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c
index f5f5e857a..0c075546b 100644
--- a/drivers/isdn/hisax/ix1_micro.c
+++ b/drivers/isdn/hisax/ix1_micro.c
@@ -1,4 +1,4 @@
-/* $Id: ix1_micro.c,v 1.3 1997/04/13 19:54:02 keil Exp $
+/* $Id: ix1_micro.c,v 2.6 1998/02/11 17:28:09 keil Exp $
* ix1_micro.c low level stuff for ITK ix1-micro Rev.2 isdn cards
* derived from the original file teles3.c from Karsten Keil
@@ -11,6 +11,27 @@
* Beat Doebeli
*
* $Log: ix1_micro.c,v $
+ * Revision 2.6 1998/02/11 17:28:09 keil
+ * Niccy PnP/PCI support
+ *
+ * Revision 2.5 1998/02/02 13:29:42 keil
+ * fast io
+ *
+ * Revision 2.4 1997/11/08 21:35:50 keil
+ * new l1 init
+ *
+ * Revision 2.3 1997/11/06 17:09:35 keil
+ * New 2.1 init code
+ *
+ * Revision 2.2 1997/10/29 18:55:51 keil
+ * changes for 2.1.60 (irq2dev_map)
+ *
+ * Revision 2.1 1997/07/27 21:47:09 keil
+ * new interface structures
+ *
+ * Revision 2.0 1997/06/26 11:02:50 keil
+ * New Layer and card interface
+ *
* Revision 1.3 1997/04/13 19:54:02 keil
* Change in IRQ check delay for SMP
*
@@ -54,17 +75,16 @@
#define __NO_VERSION__
-#include "siemens.h"
#include "hisax.h"
-#include "teles3.h"
+#include "isac.h"
+#include "hscx.h"
#include "isdnl1.h"
-#include <linux/kernel_stat.h>
extern const char *CardType[];
-const char *ix1_revision = "$Revision: 1.3 $";
+const char *ix1_revision = "$Revision: 2.6 $";
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
#define SPECIAL_PORT_OFFSET 3
@@ -73,865 +93,250 @@ const char *ix1_revision = "$Revision: 1.3 $";
#define HSCX_COMMAND_OFFSET 2
#define HSCX_DATA_OFFSET 1
-#define ISAC_FIFOSIZE 16
-#define HSCX_FIFOSIZE 16
-
#define TIMEOUT 50
static inline u_char
-IsacReadReg(unsigned int adr, u_char off)
-{
- byteout(adr + ISAC_COMMAND_OFFSET, off + 0x20);
- return bytein(adr + ISAC_DATA_OFFSET);
-}
-
-static inline void
-IsacWriteReg(unsigned int adr, u_char off, u_char data)
-{
- byteout(adr + ISAC_COMMAND_OFFSET, off + 0x20);
- byteout(adr + ISAC_DATA_OFFSET, data);
-}
-
-#define HSCX_OFFSET(WhichHscx,offset) \
-( (WhichHscx) ? (offset+0x60) : (offset+0x20) )
-
-static inline u_char
-HscxReadReg(unsigned int adr, int WhichHscx, u_char off)
+readreg(unsigned int ale, unsigned int adr, u_char off)
{
- byteout(adr + HSCX_COMMAND_OFFSET, HSCX_OFFSET(WhichHscx, off));
- return bytein(adr + HSCX_DATA_OFFSET);
-}
-
-static inline void
-HscxWriteReg(unsigned int adr, int WhichHscx, u_char off, u_char data)
-{
- byteout(adr + HSCX_COMMAND_OFFSET, HSCX_OFFSET(WhichHscx, off));
- byteout(adr + HSCX_DATA_OFFSET, data);
-}
-
-
-static inline void
-IsacReadFifo(unsigned int adr, u_char * data, int size)
-{
- byteout(adr + ISAC_COMMAND_OFFSET, 0);
- while (size--)
- *data++ = bytein(adr + ISAC_DATA_OFFSET);
-}
-
-static void
-IsacWriteFifo(unsigned int adr, u_char * data, int size)
-{
- byteout(adr + ISAC_COMMAND_OFFSET, 0);
- while (size--) {
- byteout(adr + ISAC_DATA_OFFSET, *data);
- data++;
- }
-}
-
-static inline void
-HscxReadFifo(unsigned int adr, int WhichHscx, u_char * data, int size)
-{
- byteout(adr + HSCX_COMMAND_OFFSET, (WhichHscx) ? 0x40 : 0x00);
- while (size--)
- *data++ = bytein(adr + HSCX_DATA_OFFSET);
-}
+ register u_char ret;
+ long flags;
-static void
-HscxWriteFifo(unsigned int adr, int WhichHscx, u_char * data, int size)
-{
- byteout(adr + HSCX_COMMAND_OFFSET, (WhichHscx) ? 0x40 : 0x00);
- while (size--) {
- byteout(adr + HSCX_DATA_OFFSET, *data);
- data++;
- }
+ save_flags(flags);
+ cli();
+ byteout(ale, off);
+ ret = bytein(adr);
+ restore_flags(flags);
+ return (ret);
}
static inline void
-waitforCEC(int adr, int WhichHscx)
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
{
- int to = TIMEOUT;
+ /* fifo read without cli because it's allready done */
- while ((HscxReadReg(adr, WhichHscx, HSCX_STAR) & 0x04) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "ix1-Micro: waitforCEC timeout\n");
+ byteout(ale, off);
+ insb(adr, data, size);
}
static inline void
-waitforXFW(int adr, int WhichHscx)
-{
- int to = TIMEOUT;
-
- while ((!(HscxReadReg(adr, WhichHscx, HSCX_STAR) & 0x44) == 0x40) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "ix1-Micro: waitforXFW timeout\n");
-}
-
-static inline void
-writehscxCMDR(int adr, int WhichHscx, u_char data)
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
long flags;
save_flags(flags);
cli();
- waitforCEC(adr, WhichHscx);
- HscxWriteReg(adr, WhichHscx, HSCX_CMDR, data);
+ byteout(ale, off);
+ byteout(adr, data);
restore_flags(flags);
}
-/*
- * fast interrupt here
- */
-
-static void
-hscxreport(struct IsdnCardState *sp, int hscx)
-{
- printk(KERN_DEBUG "HSCX %d\n", hscx);
- printk(KERN_DEBUG "ISTA %x\n", HscxReadReg(sp->hscx[hscx], hscx, HSCX_ISTA));
- printk(KERN_DEBUG "STAR %x\n", HscxReadReg(sp->hscx[hscx], hscx, HSCX_STAR));
- printk(KERN_DEBUG "EXIR %x\n", HscxReadReg(sp->hscx[hscx], hscx, HSCX_EXIR));
-}
-
-void
-ix1micro_report(struct IsdnCardState *sp)
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
{
- printk(KERN_DEBUG "ISAC\n");
- printk(KERN_DEBUG "ISTA %x\n", IsacReadReg(sp->isac, ISAC_ISTA));
- printk(KERN_DEBUG "STAR %x\n", IsacReadReg(sp->isac, ISAC_STAR));
- printk(KERN_DEBUG "EXIR %x\n", IsacReadReg(sp->isac, ISAC_EXIR));
- hscxreport(sp, 0);
- hscxreport(sp, 1);
+ /* fifo write without cli because it's allready done */
+ byteout(ale, off);
+ outsb(adr, data, size);
}
-/*
- * HSCX stuff goes here
- */
+/* Interface functions */
-static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
{
- u_char *ptr;
- struct IsdnCardState *sp = hsp->sp;
- long flags;
-
- if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
- debugl1(sp, "hscx_empty_fifo");
-
- if (hsp->rcvidx + count > HSCX_BUFMAX) {
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "hscx_empty_fifo: incoming packet too large");
- writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80);
- hsp->rcvidx = 0;
- return;
- }
- ptr = hsp->rcvbuf + hsp->rcvidx;
- hsp->rcvidx += count;
- save_flags(flags);
- cli();
- HscxReadFifo(sp->hscx[hsp->hscx], hsp->hscx, ptr, count);
- writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80);
- restore_flags(flags);
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "hscx_empty_fifo %c cnt %d",
- hsp->hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset));
}
static void
-hscx_fill_fifo(struct HscxState *hsp)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
- struct IsdnCardState *sp = hsp->sp;
- int more, count;
- u_char *ptr;
- long flags;
-
- if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
- debugl1(sp, "hscx_fill_fifo");
-
- if (!hsp->tx_skb)
- return;
- if (hsp->tx_skb->len <= 0)
- return;
-
- more = (hsp->mode == 1) ? 1 : 0;
- if (hsp->tx_skb->len > 32) {
- more = !0;
- count = 32;
- } else
- count = hsp->tx_skb->len;
-
- waitforXFW(sp->hscx[hsp->hscx], hsp->hscx);
- save_flags(flags);
- cli();
- ptr = hsp->tx_skb->data;
- skb_pull(hsp->tx_skb, count);
- hsp->tx_cnt -= count;
- hsp->count += count;
- HscxWriteFifo(sp->hscx[hsp->hscx], hsp->hscx, ptr, count);
- writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, more ? 0x8 : 0xa);
- restore_flags(flags);
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "hscx_fill_fifo %c cnt %d",
- hsp->hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value);
}
-static inline void
-hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
- u_char r;
- struct HscxState *hsp = sp->hs + hscx;
- struct sk_buff *skb;
- int count;
- char tmp[32];
-
- if (!hsp->init)
- return;
-
- if (val & 0x80) { /* RME */
-
- r = HscxReadReg(sp->hscx[hsp->hscx], hscx, HSCX_RSTA);
- if ((r & 0xf0) != 0xa0) {
- if (!r & 0x80)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "HSCX invalid frame");
- if ((r & 0x40) && hsp->mode)
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX RDO mode=%d",
- hsp->mode);
- debugl1(sp, tmp);
- }
- if (!r & 0x20)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "HSCX CRC error");
- writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80);
- } else {
- count = HscxReadReg(sp->hscx[hsp->hscx], hscx, HSCX_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- hscx_empty_fifo(hsp, count);
- if ((count = hsp->rcvidx - 1) > 0) {
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- sprintf(tmp, "HX Frame %d", count);
- debugl1(sp, tmp);
- }
- if (!(skb = dev_alloc_skb(count)))
- printk(KERN_WARNING "IX1: receive out of memory\n");
- else {
- memcpy(skb_put(skb, count), hsp->rcvbuf, count);
- skb_queue_tail(&hsp->rqueue, skb);
- }
- }
- }
- hsp->rcvidx = 0;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- hscx_empty_fifo(hsp, 32);
- if (hsp->mode == 1) {
- /* receive audio data */
- if (!(skb = dev_alloc_skb(32)))
- printk(KERN_WARNING "IX1: receive out of memory\n");
- else {
- memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
- skb_queue_tail(&hsp->rqueue, skb);
- }
- hsp->rcvidx = 0;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- }
- if (val & 0x10) { /* XPR */
- if (hsp->tx_skb)
- if (hsp->tx_skb->len) {
- hscx_fill_fifo(hsp);
- return;
- } else {
- SET_SKB_FREE(hsp->tx_skb);
- dev_kfree_skb(hsp->tx_skb);
- hsp->count = 0;
- if (hsp->st->l4.l1writewakeup)
- hsp->st->l4.l1writewakeup(hsp->st);
- hsp->tx_skb = NULL;
- }
- if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
- hsp->count = 0;
- hscx_fill_fifo(hsp);
- } else
- hscx_sched_event(hsp, HSCX_XMTBUFREADY);
- }
+ readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
}
-/*
- * ISAC stuff goes here
- */
-
static void
-isac_empty_fifo(struct IsdnCardState *sp, int count)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
- u_char *ptr;
- long flags;
-
- if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
- if (sp->debug & L1_DEB_ISAC)
- debugl1(sp, "isac_empty_fifo");
-
- if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
- if (sp->debug & L1_DEB_WARN) {
- char tmp[40];
- sprintf(tmp, "isac_empty_fifo overrun %d",
- sp->rcvidx + count);
- debugl1(sp, tmp);
- }
- IsacWriteReg(sp->isac, ISAC_CMDR, 0x80);
- sp->rcvidx = 0;
- return;
- }
- ptr = sp->rcvbuf + sp->rcvidx;
- sp->rcvidx += count;
- save_flags(flags);
- cli();
- IsacReadFifo(sp->isac, ptr, count);
- IsacWriteReg(sp->isac, ISAC_CMDR, 0x80);
- restore_flags(flags);
- if (sp->debug & L1_DEB_ISAC_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "isac_empty_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
}
-static void
-isac_fill_fifo(struct IsdnCardState *sp)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
- int count, more;
- u_char *ptr;
- long flags;
-
- if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
- debugl1(sp, "isac_fill_fifo");
-
- if (!sp->tx_skb)
- return;
-
- count = sp->tx_skb->len;
- if (count <= 0)
- return;
-
- more = 0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- save_flags(flags);
- cli();
- ptr = sp->tx_skb->data;
- skb_pull(sp->tx_skb, count);
- sp->tx_cnt += count;
- IsacWriteFifo(sp->isac, ptr, count);
- IsacWriteReg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa);
- restore_flags(flags);
- if (sp->debug & L1_DEB_ISAC_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "isac_fill_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ return (readreg(cs->hw.ix1.hscx_ale,
+ cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0)));
}
static void
-ph_command(struct IsdnCardState *sp, unsigned int command)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
- if (sp->debug & L1_DEB_ISAC) {
- char tmp[32];
- sprintf(tmp, "ph_command %d", command);
- debugl1(sp, tmp);
- }
- IsacWriteReg(sp->isac, ISAC_CIX0, (command << 2) | 3);
+ writereg(cs->hw.ix1.hscx_ale,
+ cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value);
}
+#define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \
+ cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \
+ cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data)
-static inline void
-isac_interrupt(struct IsdnCardState *sp, u_char val)
-{
- u_char exval;
- struct sk_buff *skb;
- unsigned int count;
- char tmp[32];
-
- if (sp->debug & L1_DEB_ISAC) {
- sprintf(tmp, "ISAC interrupt %x", val);
- debugl1(sp, tmp);
- }
- if (val & 0x80) { /* RME */
- exval = IsacReadReg(sp->isac, ISAC_RSTA);
- if ((exval & 0x70) != 0x20) {
- if (exval & 0x40)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC RDO");
- if (!exval & 0x20)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC CRC error");
- IsacWriteReg(sp->isac, ISAC_CMDR, 0x80);
- } else {
- count = IsacReadReg(sp->isac, ISAC_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- isac_empty_fifo(sp, count);
- if ((count = sp->rcvidx) > 0) {
- sp->rcvidx = 0;
- if (!(skb = alloc_skb(count, GFP_ATOMIC)))
- printk(KERN_WARNING "IX1: D receive out of memory\n");
- else {
- memcpy(skb_put(skb, count), sp->rcvbuf, count);
- skb_queue_tail(&sp->rq, skb);
- }
- }
- }
- sp->rcvidx = 0;
- isac_sched_event(sp, ISAC_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- isac_empty_fifo(sp, 32);
- }
- if (val & 0x20) { /* RSC */
- /* never */
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC RSC interrupt");
- }
- if (val & 0x10) { /* XPR */
- if (sp->tx_skb)
- if (sp->tx_skb->len) {
- isac_fill_fifo(sp);
- goto afterXPR;
- } else {
- SET_SKB_FREE(sp->tx_skb);
- dev_kfree_skb(sp->tx_skb);
- sp->tx_cnt = 0;
- sp->tx_skb = NULL;
- }
- if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
- sp->tx_cnt = 0;
- isac_fill_fifo(sp);
- } else
- isac_sched_event(sp, ISAC_XMTBUFREADY);
- }
- afterXPR:
- if (val & 0x04) { /* CISQ */
- sp->ph_state = (IsacReadReg(sp->isac, ISAC_CIX0) >> 2)
- & 0xf;
- if (sp->debug & L1_DEB_ISAC) {
- sprintf(tmp, "l1state %d", sp->ph_state);
- debugl1(sp, tmp);
- }
- isac_new_ph(sp);
- }
- if (val & 0x02) { /* SIN */
- /* never */
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC SIN interrupt");
- }
- if (val & 0x01) { /* EXI */
- exval = IsacReadReg(sp->isac, ISAC_EXIR);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "ISAC EXIR %02x", exval);
- debugl1(sp, tmp);
- }
- }
-}
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \
+ cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
-static inline void
-hscx_int_main(struct IsdnCardState *sp, u_char val)
-{
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \
+ cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
- u_char exval;
- struct HscxState *hsp;
- char tmp[32];
-
-
- if (val & 0x01) {
- hsp = sp->hs + 1;
- exval = HscxReadReg(sp->hscx[1], 1, HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (hsp->tx_skb) {
- skb_push(hsp->tx_skb, hsp->count);
- hsp->tx_cnt += hsp->count;
- hsp->count = 0;
- }
- writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x01);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
- debugl1(sp, tmp);
- }
- }
- } else if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX B EXIR %x", exval);
- debugl1(sp, tmp);
- }
- }
- if (val & 0xf8) {
- if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX B interrupt %x", val);
- debugl1(sp, tmp);
- }
- hscx_interrupt(sp, val, 1);
- }
- if (val & 0x02) {
- hsp = sp->hs;
- exval = HscxReadReg(sp->hscx[0], 0, HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (hsp->tx_skb) {
- skb_push(hsp->tx_skb, hsp->count);
- hsp->tx_cnt += hsp->count;
- hsp->count = 0;
- }
- writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x01);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
- debugl1(sp, tmp);
- }
- }
- } else if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX A EXIR %x", exval);
- debugl1(sp, tmp);
- }
- }
- if (val & 0x04) {
- exval = HscxReadReg(sp->hscx[0], 0, HSCX_ISTA);
- if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX A interrupt %x", exval);
- debugl1(sp, tmp);
- }
- hscx_interrupt(sp, exval, 0);
- }
-}
+#include "hscx_irq.c"
static void
ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
- struct IsdnCardState *sp;
+ struct IsdnCardState *cs = dev_id;
u_char val, stat = 0;
- sp = (struct IsdnCardState *) dev_id;
-
- if (!sp) {
- printk(KERN_WARNING "Teles: Spurious interrupt!\n");
+ if (!cs) {
+ printk(KERN_WARNING "IX1: Spurious interrupt!\n");
return;
}
- val = HscxReadReg(sp->hscx[1], 1, HSCX_ISTA);
+ val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
if (val) {
- hscx_int_main(sp, val);
+ hscx_int_main(cs, val);
stat |= 1;
}
- val = IsacReadReg(sp->isac, ISAC_ISTA);
+ val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
Start_ISAC:
if (val) {
- isac_interrupt(sp, val);
+ isac_interrupt(cs, val);
stat |= 2;
}
- val = HscxReadReg(sp->hscx[1], 1, HSCX_ISTA);
+ val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
if (val) {
- if (sp->debug & L1_DEB_HSCX)
- debugl1(sp, "HSCX IntStat after IntRoutine");
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
- val = IsacReadReg(sp->isac, ISAC_ISTA);
+ val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
if (val) {
- if (sp->debug & L1_DEB_ISAC)
- debugl1(sp, "ISAC IntStat after IntRoutine");
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
if (stat & 1) {
- HscxWriteReg(sp->hscx[0], 0, HSCX_MASK, 0xFF);
- HscxWriteReg(sp->hscx[1], 1, HSCX_MASK, 0xFF);
- HscxWriteReg(sp->hscx[0], 0, HSCX_MASK, 0x0);
- HscxWriteReg(sp->hscx[1], 1, HSCX_MASK, 0x0);
+ writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF);
+ writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF);
+ writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0);
+ writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0);
}
if (stat & 2) {
- IsacWriteReg(sp->isac, ISAC_MASK, 0xFF);
- IsacWriteReg(sp->isac, ISAC_MASK, 0x0);
- }
-}
-
-
-static void
-initisac(struct IsdnCardState *sp)
-{
- unsigned int adr = sp->isac;
-
- /* 16.3 IOM 2 Mode */
- IsacWriteReg(adr, ISAC_MASK, 0xff);
- IsacWriteReg(adr, ISAC_ADF2, 0x80);
- IsacWriteReg(adr, ISAC_SQXR, 0x2f);
- IsacWriteReg(adr, ISAC_SPCR, 0x0);
- IsacWriteReg(adr, ISAC_ADF1, 0x2);
- IsacWriteReg(adr, ISAC_STCR, 0x70);
- IsacWriteReg(adr, ISAC_MODE, 0xc9);
- IsacWriteReg(adr, ISAC_TIMR, 0x0);
- IsacWriteReg(adr, ISAC_ADF1, 0x0);
- IsacWriteReg(adr, ISAC_CMDR, 0x41);
- IsacWriteReg(adr, ISAC_CIX0, (1 << 2) | 3);
- IsacWriteReg(adr, ISAC_MASK, 0xff);
- IsacWriteReg(adr, ISAC_MASK, 0x0);
-}
-
-static void
-modehscx(struct HscxState *hs, int mode, int ichan)
-{
- struct IsdnCardState *sp = hs->sp;
- int hscx = hs->hscx;
-
- if (sp->debug & L1_DEB_HSCX) {
- char tmp[40];
- sprintf(tmp, "hscx %c mode %d ichan %d",
- 'A' + hscx, mode, ichan);
- debugl1(sp, tmp);
+ writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0);
}
- hs->mode = mode;
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR1, 0x85);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XAD1, 0xFF);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XAD2, 0xFF);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RAH2, 0xFF);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XBCH, 0x0);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RLCR, 0x0);
-
- switch (mode) {
- case 0:
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0xff);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0xff);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_MODE, 0x84);
- break;
- case 1:
- if (ichan == 0) {
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x2f);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x2f);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
- } else {
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x3);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x3);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
- }
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_MODE, 0xe4);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CMDR, 0x41);
- break;
- case 2:
- if (ichan == 0) {
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x2f);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x2f);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
- } else {
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x3);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x3);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
- }
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_MODE, 0x8c);
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CMDR, 0x41);
- break;
- }
- HscxWriteReg(sp->hscx[hscx], hscx, HSCX_ISTA, 0x00);
}
void
-release_io_ix1micro(struct IsdnCard *card)
+release_io_ix1micro(struct IsdnCardState *cs)
{
- if (card->sp->cfg_reg)
- release_region(card->sp->cfg_reg, 4);
+ if (cs->hw.ix1.cfg_reg)
+ release_region(cs->hw.ix1.cfg_reg, 4);
}
static void
-clear_pending_ints(struct IsdnCardState *sp)
+ix1_reset(struct IsdnCardState *cs)
{
- int val;
- char tmp[64];
+ long flags;
+ int cnt;
- val = HscxReadReg(sp->hscx[1], 1, HSCX_ISTA);
- sprintf(tmp, "HSCX B ISTA %x", val);
- debugl1(sp, tmp);
- if (val & 0x01) {
- val = HscxReadReg(sp->hscx[1], 1, HSCX_EXIR);
- sprintf(tmp, "HSCX B EXIR %x", val);
- debugl1(sp, tmp);
- } else if (val & 0x02) {
- val = HscxReadReg(sp->hscx[0], 0, HSCX_EXIR);
- sprintf(tmp, "HSCX A EXIR %x", val);
- debugl1(sp, tmp);
- }
- val = HscxReadReg(sp->hscx[0], 0, HSCX_ISTA);
- sprintf(tmp, "HSCX A ISTA %x", val);
- debugl1(sp, tmp);
- val = HscxReadReg(sp->hscx[1], 1, HSCX_STAR);
- sprintf(tmp, "HSCX B STAR %x", val);
- debugl1(sp, tmp);
- val = HscxReadReg(sp->hscx[0], 0, HSCX_STAR);
- sprintf(tmp, "HSCX A STAR %x", val);
- debugl1(sp, tmp);
- val = IsacReadReg(sp->isac, ISAC_STAR);
- sprintf(tmp, "ISAC STAR %x", val);
- debugl1(sp, tmp);
- val = IsacReadReg(sp->isac, ISAC_MODE);
- sprintf(tmp, "ISAC MODE %x", val);
- debugl1(sp, tmp);
- val = IsacReadReg(sp->isac, ISAC_ADF2);
- sprintf(tmp, "ISAC ADF2 %x", val);
- debugl1(sp, tmp);
- val = IsacReadReg(sp->isac, ISAC_ISTA);
- sprintf(tmp, "ISAC ISTA %x", val);
- debugl1(sp, tmp);
- if (val & 0x01) {
- val = IsacReadReg(sp->isac, ISAC_EXIR);
- sprintf(tmp, "ISAC EXIR %x", val);
- debugl1(sp, tmp);
- } else if (val & 0x04) {
- val = IsacReadReg(sp->isac, ISAC_CIR0);
- sprintf(tmp, "ISAC CIR0 %x", val);
- debugl1(sp, tmp);
+ /* reset isac */
+ save_flags(flags);
+ cnt = 3 * (HZ / 10) + 1;
+ sti();
+ while (cnt--) {
+ byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 1);
+ HZDELAY(1); /* wait >=10 ms */
}
- IsacWriteReg(sp->isac, ISAC_MASK, 0);
- IsacWriteReg(sp->isac, ISAC_CMDR, 0x41);
+ byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0);
+ restore_flags(flags);
}
-int
-initix1micro(struct IsdnCardState *sp)
+static int
+ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
- int ret;
- int loop = 0;
- char tmp[40];
-
- sp->counter = kstat_irqs(sp->irq);
- sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
- debugl1(sp, tmp);
- clear_pending_ints(sp);
- ret = get_irq(sp->cardnr, &ix1micro_interrupt);
- if (ret) {
- initisac(sp);
- sp->modehscx(sp->hs, 0, 0);
- sp->modehscx(sp->hs + 1, 0, 0);
- while (loop++ < 10) {
- /* At least 1-3 irqs must happen
- * (one from HSCX A, one from HSCX B, 3rd from ISAC)
- */
- if (kstat_irqs(sp->irq) > sp->counter)
- break;
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + 1;
- schedule();
- }
- sprintf(tmp, "IRQ %d count %d", sp->irq,
- kstat_irqs(sp->irq));
- debugl1(sp, tmp);
- if (kstat_irqs(sp->irq) == sp->counter) {
- printk(KERN_WARNING
- "ix1-Micro: IRQ(%d) getting no interrupts during init\n",
- sp->irq);
- free_irq(sp->irq, sp);
- return (0);
- }
- }
- return (ret);
+ switch (mt) {
+ case CARD_RESET:
+ ix1_reset(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_ix1micro(cs);
+ return(0);
+ case CARD_SETIRQ:
+ return(request_irq(cs->irq, &ix1micro_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs));
+ case CARD_INIT:
+ clear_pending_isac_ints(cs);
+ clear_pending_hscx_ints(cs);
+ initisac(cs);
+ inithscx(cs);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
}
-int
-setup_ix1micro(struct IsdnCard *card)
+
+__initfunc(int
+setup_ix1micro(struct IsdnCard *card))
{
- u_char val, verA, verB;
- struct IsdnCardState *sp = card->sp;
- long flags;
+ struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, ix1_revision);
- printk(KERN_NOTICE "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp));
- if (sp->typ != ISDN_CTYPE_IX1MICROR2)
+ printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_IX1MICROR2)
return (0);
/* IO-Ports */
- sp->isac = sp->hscx[0] = sp->hscx[1] = sp->cfg_reg = card->para[1];
- sp->irq = card->para[0];
- if (sp->cfg_reg) {
- if (check_region((sp->cfg_reg), 4)) {
+ cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET;
+ cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET;
+ cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET;
+ cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET;
+ cs->hw.ix1.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ if (cs->hw.ix1.cfg_reg) {
+ if (check_region((cs->hw.ix1.cfg_reg), 4)) {
printk(KERN_WARNING
"HiSax: %s config port %x-%x already in use\n",
CardType[card->typ],
- sp->cfg_reg,
- sp->cfg_reg + 4);
+ cs->hw.ix1.cfg_reg,
+ cs->hw.ix1.cfg_reg + 4);
return (0);
} else
- request_region(sp->cfg_reg, 4, "ix1micro cfg");
- }
- /* reset isac */
- save_flags(flags);
- val = 3 * (HZ / 10) + 1;
- sti();
- while (val--) {
- byteout(sp->cfg_reg + SPECIAL_PORT_OFFSET, 1);
- HZDELAY(1); /* wait >=10 ms */
- }
- byteout(sp->cfg_reg + SPECIAL_PORT_OFFSET, 0);
- restore_flags(flags);
-
- printk(KERN_NOTICE
- "HiSax: %s config irq:%d io:0x%x\n",
- CardType[sp->typ], sp->irq,
- sp->cfg_reg);
- verA = HscxReadReg(sp->hscx[0], 0, HSCX_VSTR) & 0xf;
- verB = HscxReadReg(sp->hscx[1], 1, HSCX_VSTR) & 0xf;
- printk(KERN_INFO "ix1-Micro: HSCX version A: %s B: %s\n",
- HscxVersion(verA), HscxVersion(verB));
- val = IsacReadReg(sp->isac, ISAC_RBCH);
- printk(KERN_INFO "ix1-Micro: ISAC %s\n",
- ISACVersion(val));
- if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
+ request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg");
+ }
+ printk(KERN_INFO
+ "HiSax: %s config irq:%d io:0x%X\n",
+ CardType[cs->typ], cs->irq,
+ cs->hw.ix1.cfg_reg);
+ ix1_reset(cs);
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ cs->BC_Read_Reg = &ReadHSCX;
+ cs->BC_Write_Reg = &WriteHSCX;
+ cs->BC_Send_Data = &hscx_fill_fifo;
+ cs->cardmsg = &ix1_card_msg;
+ ISACVersion(cs, "ix1-Micro:");
+ if (HscxVersion(cs, "ix1-Micro:")) {
printk(KERN_WARNING
"ix1-Micro: wrong HSCX versions check IO address\n");
- release_io_ix1micro(card);
+ release_io_ix1micro(cs);
return (0);
}
- sp->modehscx = &modehscx;
- sp->ph_command = &ph_command;
- sp->hscx_fill_fifo = &hscx_fill_fifo;
- sp->isac_fill_fifo = &isac_fill_fifo;
return (1);
}
diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c
index c3ee6a73f..d60a5da66 100644
--- a/drivers/isdn/hisax/l3_1tr6.c
+++ b/drivers/isdn/hisax/l3_1tr6.c
@@ -1,4 +1,4 @@
-/* $Id: l3_1tr6.c,v 1.11 1997/04/06 22:54:18 keil Exp $
+/* $Id: l3_1tr6.c,v 2.4 1998/02/12 23:07:57 keil Exp $
* German 1TR6 D-channel protocol
*
@@ -6,39 +6,28 @@
*
*
* $Log: l3_1tr6.c,v $
- * Revision 1.11 1997/04/06 22:54:18 keil
- * Using SKB's
- *
- * Revision 1.10 1997/03/13 20:37:58 keil
- * channel request added
- *
- * Revision 1.9 1997/02/11 01:37:40 keil
- * Changed setup-interface (incoming and outgoing)
- *
- * Revision 1.8 1997/01/27 23:20:21 keil
- * report revision only ones
- *
- * Revision 1.7 1997/01/21 22:30:07 keil
- * new statemachine; L3 timers
+ * Revision 2.4 1998/02/12 23:07:57 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
*
- * Revision 1.6 1996/12/14 21:07:20 keil
- * additional states for CC_REJECT
+ * Revision 2.3 1997/11/06 17:12:24 keil
+ * KERN_NOTICE --> KERN_INFO
*
- * Revision 1.5 1996/12/08 19:55:17 keil
- * change CC_REJECT_REQ routine
+ * Revision 2.2 1997/10/29 19:03:00 keil
+ * changes for 2.1
*
- * Revision 1.4 1996/10/30 10:18:01 keil
- * bugfixes in debugging output
+ * Revision 2.1 1997/08/03 15:28:09 keil
+ * release L3 empty processes
*
- * Revision 1.3 1996/10/27 22:15:37 keil
- * bugfix reject handling
+ * Revision 2.0 1997/07/27 21:15:45 keil
+ * New Callref based layer3
*
- * Revision 1.2 1996/10/13 23:08:56 keil
- * added missing state for callback reject
+ * Revision 1.12 1997/06/26 11:11:45 keil
+ * SET_SKBFREE now on creation of a SKB
*
- * Revision 1.1 1996/10/13 20:04:55 keil
- * Initial revision
+ * Revision 1.11 1997/04/06 22:54:18 keil
+ * Using SKB's
*
+ * Old Log removed /KKe
*
*/
@@ -49,16 +38,16 @@
#include <linux/ctype.h>
extern char *HiSax_getrev(const char *revision);
-const char *l3_1tr6_revision = "$Revision: 1.11 $";
+const char *l3_1tr6_revision = "$Revision: 2.4 $";
#define MsgHead(ptr, cref, mty, dis) \
*ptr++ = dis; \
*ptr++ = 0x1; \
- *ptr++ = cref; \
+ *ptr++ = cref ^ 0x80; \
*ptr++ = mty
static void
-l3_1TR6_message(struct PStack *st, u_char mt, u_char pd)
+l3_1TR6_message(struct l3_process *pc, u_char mt, u_char pd)
{
struct sk_buff *skb;
u_char *p;
@@ -66,12 +55,71 @@ l3_1TR6_message(struct PStack *st, u_char mt, u_char pd)
if (!(skb = l3_alloc_skb(4)))
return;
p = skb_put(skb, 4);
- MsgHead(p, st->l3.callref, mt, pd);
- st->l3.l3l2(st, DL_DATA, skb);
+ MsgHead(p, pc->callref, mt, pd);
+ pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+}
+
+static int
+l31tr6_check_messagetype_validity(int mt, int pd) {
+/* verify if a message type exists */
+
+ if (pd == PROTO_DIS_N0)
+ switch(mt) {
+ case MT_N0_REG_IND:
+ case MT_N0_CANC_IND:
+ case MT_N0_FAC_STA:
+ case MT_N0_STA_ACK:
+ case MT_N0_STA_REJ:
+ case MT_N0_FAC_INF:
+ case MT_N0_INF_ACK:
+ case MT_N0_INF_REJ:
+ case MT_N0_CLOSE:
+ case MT_N0_CLO_ACK:
+ return(1);
+ default:
+ return(0);
+ }
+ else if (pd == PROTO_DIS_N1)
+ switch(mt) {
+ case MT_N1_ESC:
+ case MT_N1_ALERT:
+ case MT_N1_CALL_SENT:
+ case MT_N1_CONN:
+ case MT_N1_CONN_ACK:
+ case MT_N1_SETUP:
+ case MT_N1_SETUP_ACK:
+ case MT_N1_RES:
+ case MT_N1_RES_ACK:
+ case MT_N1_RES_REJ:
+ case MT_N1_SUSP:
+ case MT_N1_SUSP_ACK:
+ case MT_N1_SUSP_REJ:
+ case MT_N1_USER_INFO:
+ case MT_N1_DET:
+ case MT_N1_DISC:
+ case MT_N1_REL:
+ case MT_N1_REL_ACK:
+ case MT_N1_CANC_ACK:
+ case MT_N1_CANC_REJ:
+ case MT_N1_CON_CON:
+ case MT_N1_FAC:
+ case MT_N1_FAC_ACK:
+ case MT_N1_FAC_CAN:
+ case MT_N1_FAC_REG:
+ case MT_N1_FAC_REJ:
+ case MT_N1_INFO:
+ case MT_N1_REG_ACK:
+ case MT_N1_REG_REJ:
+ case MT_N1_STAT:
+ return (1);
+ default:
+ return(0);
+ }
+ return(0);
}
static void
-l3_1tr6_setup_req(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_setup_req(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb;
u_char tmp[128];
@@ -81,16 +129,13 @@ l3_1tr6_setup_req(struct PStack *st, u_char pr, void *arg)
u_char channel = 0;
int l;
-
- st->l3.callref = st->pa->callref;
- MsgHead(p, st->l3.callref, MT_N1_SETUP, PROTO_DIS_N1);
-
- teln = st->pa->setup.phone;
- st->pa->spv = 0;
+ MsgHead(p, pc->callref, MT_N1_SETUP, PROTO_DIS_N1);
+ teln = pc->para.setup.phone;
+ pc->para.spv = 0;
if (!isdigit(*teln)) {
switch (0x5f & *teln) {
case 'S':
- st->pa->spv = 1;
+ pc->para.spv = 1;
break;
case 'C':
channel = 0x08;
@@ -103,8 +148,8 @@ l3_1tr6_setup_req(struct PStack *st, u_char pr, void *arg)
channel |= 0x02;
break;
default:
- if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "Wrong MSN Code");
+ if (pc->st->l3.debug & L3_DEB_WARN)
+ l3_debug(pc->st, "Wrong MSN Code");
break;
}
teln++;
@@ -114,22 +159,22 @@ l3_1tr6_setup_req(struct PStack *st, u_char pr, void *arg)
*p++ = 1;
*p++ = channel;
}
- if (st->pa->spv) { /* SPV ? */
+ if (pc->para.spv) { /* SPV ? */
/* NSF SPV */
*p++ = WE0_netSpecFac;
*p++ = 4; /* Laenge */
*p++ = 0;
*p++ = FAC_SPV; /* SPV */
- *p++ = st->pa->setup.si1; /* 0 for all Services */
- *p++ = st->pa->setup.si2; /* 0 for all Services */
+ *p++ = pc->para.setup.si1; /* 0 for all Services */
+ *p++ = pc->para.setup.si2; /* 0 for all Services */
*p++ = WE0_netSpecFac;
*p++ = 4; /* Laenge */
*p++ = 0;
*p++ = FAC_Activate; /* aktiviere SPV (default) */
- *p++ = st->pa->setup.si1; /* 0 for all Services */
- *p++ = st->pa->setup.si2; /* 0 for all Services */
+ *p++ = pc->para.setup.si1; /* 0 for all Services */
+ *p++ = pc->para.setup.si2; /* 0 for all Services */
}
- eaz = st->pa->setup.eazmsn;
+ eaz = pc->para.setup.eazmsn;
if (*eaz) {
*p++ = WE0_origAddr;
*p++ = strlen(eaz) + 1;
@@ -149,22 +194,21 @@ l3_1tr6_setup_req(struct PStack *st, u_char pr, void *arg)
/* Codesatz 6 fuer Service */
*p++ = WE6_serviceInd;
*p++ = 2; /* len=2 info,info2 */
- *p++ = st->pa->setup.si1;
- *p++ = st->pa->setup.si2;
+ *p++ = pc->para.setup.si1;
+ *p++ = pc->para.setup.si2;
l = p - tmp;
if (!(skb = l3_alloc_skb(l)))
return;
memcpy(skb_put(skb, l), tmp, l);
- L3DelTimer(&st->l3.timer);
- L3AddTimer(&st->l3.timer, st->l3.t303, CC_T303);
- newl3state(st, 1);
- st->l3.l3l2(st, DL_DATA, skb);
-
+ L3DelTimer(&pc->timer);
+ L3AddTimer(&pc->timer, T303, CC_T303);
+ newl3state(pc, 1);
+ pc->st->l3.l3l2(pc->st, DL_DATA, skb);
}
static void
-l3_1tr6_setup(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg)
{
u_char *p;
int bcfound = 0;
@@ -172,110 +216,105 @@ l3_1tr6_setup(struct PStack *st, u_char pr, void *arg)
struct sk_buff *skb = arg;
p = skb->data;
- st->pa->callref = getcallref(p);
- st->l3.callref = 0x80 + st->pa->callref;
/* Channel Identification */
p = skb->data;
if ((p = findie(p, skb->len, WE0_chanID, 0))) {
- st->pa->bchannel = p[2] & 0x3;
+ pc->para.bchannel = p[2] & 0x3;
bcfound++;
- } else if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "setup without bchannel");
+ } else if (pc->st->l3.debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup without bchannel");
p = skb->data;
if ((p = findie(p, skb->len, WE6_serviceInd, 6))) {
- st->pa->setup.si1 = p[2];
- st->pa->setup.si2 = p[3];
- } else if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "setup without service indicator");
+ pc->para.setup.si1 = p[2];
+ pc->para.setup.si2 = p[3];
+ } else if (pc->st->l3.debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup without service indicator");
p = skb->data;
if ((p = findie(p, skb->len, WE0_destAddr, 0)))
- iecpy(st->pa->setup.eazmsn, p, 1);
+ iecpy(pc->para.setup.eazmsn, p, 1);
else
- st->pa->setup.eazmsn[0] = 0;
+ pc->para.setup.eazmsn[0] = 0;
p = skb->data;
if ((p = findie(p, skb->len, WE0_origAddr, 0))) {
- iecpy(st->pa->setup.phone, p, 1);
+ iecpy(pc->para.setup.phone, p, 1);
} else
- st->pa->setup.phone[0] = 0;
+ pc->para.setup.phone[0] = 0;
p = skb->data;
- st->pa->spv = 0;
+ pc->para.spv = 0;
if ((p = findie(p, skb->len, WE0_netSpecFac, 0))) {
if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
- st->pa->spv = 1;
+ pc->para.spv = 1;
}
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
/* Signal all services, linklevel takes care of Service-Indicator */
if (bcfound) {
- if ((st->pa->setup.si1 != 7) && (st->l3.debug & L3_DEB_WARN)) {
+ if ((pc->para.setup.si1 != 7) && (pc->st->l3.debug & L3_DEB_WARN)) {
sprintf(tmp, "non-digital call: %s -> %s",
- st->pa->setup.phone,
- st->pa->setup.eazmsn);
- l3_debug(st, tmp);
+ pc->para.setup.phone,
+ pc->para.setup.eazmsn);
+ l3_debug(pc->st, tmp);
}
- newl3state(st, 6);
- st->l3.l3l4(st, CC_SETUP_IND, NULL);
- }
+ newl3state(pc, 6);
+ pc->st->l3.l3l4(pc, CC_SETUP_IND, NULL);
+ } else
+ release_l3_process(pc);
}
static void
-l3_1tr6_setup_ack(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg)
{
u_char *p;
struct sk_buff *skb = arg;
- L3DelTimer(&st->l3.timer);
+ L3DelTimer(&pc->timer);
p = skb->data;
- newl3state(st, 2);
+ newl3state(pc, 2);
if ((p = findie(p, skb->len, WE0_chanID, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- } else if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "setup answer without bchannel");
- SET_SKB_FREE(skb);
+ pc->para.bchannel = p[2] & 0x3;
+ } else if (pc->st->l3.debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup answer without bchannel");
dev_kfree_skb(skb);
- L3AddTimer(&st->l3.timer, st->l3.t304, CC_T304);
- st->l3.l3l4(st, CC_MORE_INFO, NULL);
+ L3AddTimer(&pc->timer, T304, CC_T304);
+ pc->st->l3.l3l4(pc, CC_MORE_INFO, NULL);
}
static void
-l3_1tr6_call_sent(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg)
{
u_char *p;
struct sk_buff *skb = arg;
- L3DelTimer(&st->l3.timer);
+ L3DelTimer(&pc->timer);
p = skb->data;
if ((p = findie(p, skb->len, WE0_chanID, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- } else if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "setup answer without bchannel");
- SET_SKB_FREE(skb);
+ pc->para.bchannel = p[2] & 0x3;
+ } else if (pc->st->l3.debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup answer without bchannel");
dev_kfree_skb(skb);
- L3AddTimer(&st->l3.timer, st->l3.t310, CC_T310);
- newl3state(st, 3);
- st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
+ L3AddTimer(&pc->timer, T310, CC_T310);
+ newl3state(pc, 3);
+ pc->st->l3.l3l4(pc, CC_PROCEEDING_IND, NULL);
}
static void
-l3_1tr6_alert(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
- L3DelTimer(&st->l3.timer); /* T304 */
- newl3state(st, 4);
- st->l3.l3l4(st, CC_ALERTING_IND, NULL);
+ L3DelTimer(&pc->timer); /* T304 */
+ newl3state(pc, 4);
+ pc->st->l3.l3l4(pc, CC_ALERTING_IND, NULL);
}
static void
-l3_1tr6_info(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg)
{
u_char *p;
int i, tmpcharge = 0;
@@ -289,45 +328,42 @@ l3_1tr6_info(struct PStack *st, u_char pr, void *arg)
tmpcharge *= 10;
tmpcharge += a_charge[i] & 0xf;
}
- if (tmpcharge > st->pa->chargeinfo) {
- st->pa->chargeinfo = tmpcharge;
- st->l3.l3l4(st, CC_INFO_CHARGE, NULL);
+ if (tmpcharge > pc->para.chargeinfo) {
+ pc->para.chargeinfo = tmpcharge;
+ pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL);
}
- if (st->l3.debug & L3_DEB_CHARGE) {
- sprintf(tmp, "charging info %d", st->pa->chargeinfo);
- l3_debug(st, tmp);
+ if (pc->st->l3.debug & L3_DEB_CHARGE) {
+ sprintf(tmp, "charging info %d", pc->para.chargeinfo);
+ l3_debug(pc->st, tmp);
}
- } else if (st->l3.debug & L3_DEB_CHARGE)
- l3_debug(st, "charging info not found");
- SET_SKB_FREE(skb);
+ } else if (pc->st->l3.debug & L3_DEB_CHARGE)
+ l3_debug(pc->st, "charging info not found");
dev_kfree_skb(skb);
}
static void
-l3_1tr6_info_s2(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_info_s2(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
}
static void
-l3_1tr6_connect(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
- L3DelTimer(&st->l3.timer); /* T310 */
- newl3state(st, 10);
- SET_SKB_FREE(skb);
+ L3DelTimer(&pc->timer); /* T310 */
+ newl3state(pc, 10);
dev_kfree_skb(skb);
- st->pa->chargeinfo = 0;
- st->l3.l3l4(st, CC_SETUP_CNF, NULL);
+ pc->para.chargeinfo = 0;
+ pc->st->l3.l3l4(pc, CC_SETUP_CNF, NULL);
}
static void
-l3_1tr6_rel(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_rel(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
u_char *p;
@@ -335,47 +371,47 @@ l3_1tr6_rel(struct PStack *st, u_char pr, void *arg)
p = skb->data;
if ((p = findie(p, skb->len, WE0_cause, 0))) {
if (p[1] > 0) {
- st->pa->cause = p[2];
+ pc->para.cause = p[2];
if (p[1] > 1)
- st->pa->loc = p[3];
+ pc->para.loc = p[3];
else
- st->pa->loc = 0;
+ pc->para.loc = 0;
} else {
- st->pa->cause = 0;
- st->pa->loc = 0;
+ pc->para.cause = 0;
+ pc->para.loc = 0;
}
} else
- st->pa->cause = -1;
- SET_SKB_FREE(skb);
+ pc->para.cause = -1;
dev_kfree_skb(skb);
- StopAllL3Timer(st);
- newl3state(st, 0);
- l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1);
- st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+ StopAllL3Timer(pc);
+ newl3state(pc, 0);
+ l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1);
+ pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL);
+ release_l3_process(pc);
}
static void
-l3_1tr6_rel_ack(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
- StopAllL3Timer(st);
- newl3state(st, 0);
- st->pa->cause = -1;
- st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
+ StopAllL3Timer(pc);
+ newl3state(pc, 0);
+ pc->para.cause = -1;
+ pc->st->l3.l3l4(pc, CC_RELEASE_CNF, NULL);
+ release_l3_process(pc);
}
static void
-l3_1tr6_disc(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
u_char *p;
int i, tmpcharge = 0;
char a_charge[8], tmp[32];
- StopAllL3Timer(st);
+ StopAllL3Timer(pc);
p = skb->data;
if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) {
iecpy(a_charge, p, 1);
@@ -383,104 +419,102 @@ l3_1tr6_disc(struct PStack *st, u_char pr, void *arg)
tmpcharge *= 10;
tmpcharge += a_charge[i] & 0xf;
}
- if (tmpcharge > st->pa->chargeinfo) {
- st->pa->chargeinfo = tmpcharge;
- st->l3.l3l4(st, CC_INFO_CHARGE, NULL);
+ if (tmpcharge > pc->para.chargeinfo) {
+ pc->para.chargeinfo = tmpcharge;
+ pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL);
}
- if (st->l3.debug & L3_DEB_CHARGE) {
- sprintf(tmp, "charging info %d", st->pa->chargeinfo);
- l3_debug(st, tmp);
+ if (pc->st->l3.debug & L3_DEB_CHARGE) {
+ sprintf(tmp, "charging info %d", pc->para.chargeinfo);
+ l3_debug(pc->st, tmp);
}
- } else if (st->l3.debug & L3_DEB_CHARGE)
- l3_debug(st, "charging info not found");
+ } else if (pc->st->l3.debug & L3_DEB_CHARGE)
+ l3_debug(pc->st, "charging info not found");
p = skb->data;
if ((p = findie(p, skb->len, WE0_cause, 0))) {
if (p[1] > 0) {
- st->pa->cause = p[2];
+ pc->para.cause = p[2];
if (p[1] > 1)
- st->pa->loc = p[3];
+ pc->para.loc = p[3];
else
- st->pa->loc = 0;
+ pc->para.loc = 0;
} else {
- st->pa->cause = 0;
- st->pa->loc = 0;
+ pc->para.cause = 0;
+ pc->para.loc = 0;
}
} else {
- if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "cause not found");
- st->pa->cause = -1;
+ if (pc->st->l3.debug & L3_DEB_WARN)
+ l3_debug(pc->st, "cause not found");
+ pc->para.cause = -1;
}
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
- newl3state(st, 12);
- st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
+ newl3state(pc, 12);
+ pc->st->l3.l3l4(pc, CC_DISCONNECT_IND, NULL);
}
static void
-l3_1tr6_connect_ack(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
- newl3state(st, 10);
- st->pa->chargeinfo = 0;
- L3DelTimer(&st->l3.timer);
- st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
+ newl3state(pc, 10);
+ pc->para.chargeinfo = 0;
+ L3DelTimer(&pc->timer);
+ pc->st->l3.l3l4(pc, CC_SETUP_COMPLETE_IND, NULL);
}
static void
-l3_1tr6_alert_req(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_alert_req(struct l3_process *pc, u_char pr, void *arg)
{
- newl3state(st, 7);
- l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1);
+ newl3state(pc, 7);
+ l3_1TR6_message(pc, MT_N1_ALERT, PROTO_DIS_N1);
}
static void
-l3_1tr6_setup_rsp(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_setup_rsp(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb;
u_char tmp[24];
u_char *p = tmp;
int l;
- MsgHead(p, st->l3.callref, MT_N1_CONN, PROTO_DIS_N1);
- if (st->pa->spv) { /* SPV ? */
+ MsgHead(p, pc->callref, MT_N1_CONN, PROTO_DIS_N1);
+ if (pc->para.spv) { /* SPV ? */
/* NSF SPV */
*p++ = WE0_netSpecFac;
*p++ = 4; /* Laenge */
*p++ = 0;
*p++ = FAC_SPV; /* SPV */
- *p++ = st->pa->setup.si1;
- *p++ = st->pa->setup.si2;
+ *p++ = pc->para.setup.si1;
+ *p++ = pc->para.setup.si2;
*p++ = WE0_netSpecFac;
*p++ = 4; /* Laenge */
*p++ = 0;
*p++ = FAC_Activate; /* aktiviere SPV */
- *p++ = st->pa->setup.si1;
- *p++ = st->pa->setup.si2;
+ *p++ = pc->para.setup.si1;
+ *p++ = pc->para.setup.si2;
}
- newl3state(st, 8);
+ newl3state(pc, 8);
l = p - tmp;
if (!(skb = l3_alloc_skb(l)))
return;
memcpy(skb_put(skb, l), tmp, l);
- st->l3.l3l2(st, DL_DATA, skb);
- L3DelTimer(&st->l3.timer);
- L3AddTimer(&st->l3.timer, st->l3.t313, CC_T313);
+ pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+ L3DelTimer(&pc->timer);
+ L3AddTimer(&pc->timer, T313, CC_T313);
}
static void
-l3_1tr6_reset(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_reset(struct l3_process *pc, u_char pr, void *arg)
{
- newl3state(st, 0);
+ release_l3_process(pc);
}
static void
-l3_1tr6_disconnect_req(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb;
u_char tmp[16];
@@ -489,8 +523,8 @@ l3_1tr6_disconnect_req(struct PStack *st, u_char pr, void *arg)
u_char cause = 0x10;
u_char clen = 1;
- if (st->pa->cause > 0)
- cause = st->pa->cause;
+ if (pc->para.cause > 0)
+ cause = pc->para.cause;
/* Map DSS1 causes */
switch (cause & 0x7f) {
case 0x10:
@@ -500,57 +534,55 @@ l3_1tr6_disconnect_req(struct PStack *st, u_char pr, void *arg)
cause = CAUSE_CallRejected;
break;
}
- StopAllL3Timer(st);
- MsgHead(p, st->l3.callref, MT_N1_DISC, PROTO_DIS_N1);
+ StopAllL3Timer(pc);
+ MsgHead(p, pc->callref, MT_N1_DISC, PROTO_DIS_N1);
*p++ = WE0_cause;
*p++ = clen; /* Laenge */
if (clen)
*p++ = cause | 0x80;
- newl3state(st, 11);
+ newl3state(pc, 11);
l = p - tmp;
if (!(skb = l3_alloc_skb(l)))
return;
memcpy(skb_put(skb, l), tmp, l);
- st->l3.l3l2(st, DL_DATA, skb);
- L3AddTimer(&st->l3.timer, st->l3.t305, CC_T305);
+ pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+ L3AddTimer(&pc->timer, T305, CC_T305);
}
static void
-l3_1tr6_release_req(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg)
{
- StopAllL3Timer(st);
- newl3state(st, 19);
- l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1);
- L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1);
+ StopAllL3Timer(pc);
+ newl3state(pc, 19);
+ l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1);
+ L3AddTimer(&pc->timer, T308, CC_T308_1);
}
static void
-l3_1tr6_t303(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_t303(struct l3_process *pc, u_char pr, void *arg)
{
- if (st->l3.n_t303 > 0) {
- st->l3.n_t303--;
- L3DelTimer(&st->l3.timer);
- l3_1tr6_setup_req(st, pr, arg);
+ if (pc->N303 > 0) {
+ pc->N303--;
+ L3DelTimer(&pc->timer);
+ l3_1tr6_setup_req(pc, pr, arg);
} else {
- L3DelTimer(&st->l3.timer);
- st->l3.l3l4(st, CC_NOSETUP_RSP_ERR, NULL);
- st->l3.n_t303 = 1;
- newl3state(st, 0);
+ L3DelTimer(&pc->timer);
+ pc->st->l3.l3l4(pc, CC_NOSETUP_RSP_ERR, NULL);
+ release_l3_process(pc);
}
}
static void
-l3_1tr6_t304(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_t304(struct l3_process *pc, u_char pr, void *arg)
{
- L3DelTimer(&st->l3.timer);
- st->pa->cause = 0xE6;
- l3_1tr6_disconnect_req(st, pr, NULL);
- st->l3.l3l4(st, CC_SETUP_ERR, NULL);
-
+ L3DelTimer(&pc->timer);
+ pc->para.cause = 0xE6;
+ l3_1tr6_disconnect_req(pc, pr, NULL);
+ pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL);
}
static void
-l3_1tr6_t305(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_t305(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb;
u_char tmp[16];
@@ -559,9 +591,9 @@ l3_1tr6_t305(struct PStack *st, u_char pr, void *arg)
u_char cause = 0x90;
u_char clen = 1;
- L3DelTimer(&st->l3.timer);
- if (st->pa->cause > 0)
- cause = st->pa->cause;
+ L3DelTimer(&pc->timer);
+ if (pc->para.cause > 0)
+ cause = pc->para.cause;
/* Map DSS1 causes */
switch (cause & 0x7f) {
case 0x10:
@@ -571,53 +603,53 @@ l3_1tr6_t305(struct PStack *st, u_char pr, void *arg)
cause = CAUSE_CallRejected;
break;
}
- MsgHead(p, st->l3.callref, MT_N1_REL, PROTO_DIS_N1);
+ MsgHead(p, pc->callref, MT_N1_REL, PROTO_DIS_N1);
*p++ = WE0_cause;
*p++ = clen; /* Laenge */
if (clen)
*p++ = cause;
- newl3state(st, 19);
+ newl3state(pc, 19);
l = p - tmp;
if (!(skb = l3_alloc_skb(l)))
return;
memcpy(skb_put(skb, l), tmp, l);
- st->l3.l3l2(st, DL_DATA, skb);
- L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1);
+ pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+ L3AddTimer(&pc->timer, T308, CC_T308_1);
}
static void
-l3_1tr6_t310(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_t310(struct l3_process *pc, u_char pr, void *arg)
{
- L3DelTimer(&st->l3.timer);
- st->pa->cause = 0xE6;
- l3_1tr6_disconnect_req(st, pr, NULL);
- st->l3.l3l4(st, CC_SETUP_ERR, NULL);
+ L3DelTimer(&pc->timer);
+ pc->para.cause = 0xE6;
+ l3_1tr6_disconnect_req(pc, pr, NULL);
+ pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL);
}
static void
-l3_1tr6_t313(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_t313(struct l3_process *pc, u_char pr, void *arg)
{
- L3DelTimer(&st->l3.timer);
- st->pa->cause = 0xE6;
- l3_1tr6_disconnect_req(st, pr, NULL);
- st->l3.l3l4(st, CC_CONNECT_ERR, NULL);
+ L3DelTimer(&pc->timer);
+ pc->para.cause = 0xE6;
+ l3_1tr6_disconnect_req(pc, pr, NULL);
+ pc->st->l3.l3l4(pc, CC_CONNECT_ERR, NULL);
}
static void
-l3_1tr6_t308_1(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_t308_1(struct l3_process *pc, u_char pr, void *arg)
{
- L3DelTimer(&st->l3.timer);
- l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1);
- L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_2);
- newl3state(st, 19);
+ L3DelTimer(&pc->timer);
+ l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1);
+ L3AddTimer(&pc->timer, T308, CC_T308_2);
+ newl3state(pc, 19);
}
static void
-l3_1tr6_t308_2(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg)
{
- L3DelTimer(&st->l3.timer);
- st->l3.l3l4(st, CC_RELEASE_ERR, NULL);
- newl3state(st, 0);
+ L3DelTimer(&pc->timer);
+ pc->st->l3.l3l4(pc, CC_RELEASE_ERR, NULL);
+ release_l3_process(pc);
}
/* *INDENT-OFF* */
static struct stateentry downstl[] =
@@ -688,49 +720,79 @@ static struct stateentry datastln1[] =
+
static int datastln1_len = sizeof(datastln1) /
sizeof(struct stateentry);
static void
up1tr6(struct PStack *st, int pr, void *arg)
{
- int i, mt;
+ int i, mt, cr;
+ struct l3_process *proc;
struct sk_buff *skb = arg;
char tmp[80];
+ if (skb->len < 4) {
+ if (st->l3.debug & L3_DEB_PROTERR) {
+ sprintf(tmp, "up1tr6 len only %d", skb->len);
+ l3_debug(st, tmp);
+ }
+ dev_kfree_skb(skb);
+ return;
+ }
if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) {
if (st->l3.debug & L3_DEB_PROTERR) {
- sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d state %d",
+ sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d",
(pr == DL_DATA) ? " " : "(broadcast) ",
- skb->data[0], skb->len, st->l3.state);
+ skb->data[0], skb->len);
+ l3_debug(st, tmp);
+ }
+ dev_kfree_skb(skb);
+ return;
+ }
+ if (skb->data[1] != 1) {
+ if (st->l3.debug & L3_DEB_PROTERR) {
+ sprintf(tmp, "up1tr6 CR len not 1");
l3_debug(st, tmp);
}
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
return;
}
- mt = skb->data[skb->data[1] + 2];
+ cr = skb->data[2];
+ mt = skb->data[3];
if (skb->data[0] == PROTO_DIS_N0) {
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
if (st->l3.debug & L3_DEB_STATE) {
- sprintf(tmp, "up1tr6%s N0 state %d mt %x unhandled",
- (pr == DL_DATA) ? " " : "(broadcast) ",
- st->l3.state, mt);
+ sprintf(tmp, "up1tr6%s N0 mt %x unhandled",
+ (pr == DL_DATA) ? " " : "(broadcast) ", mt);
l3_debug(st, tmp);
}
} else if (skb->data[0] == PROTO_DIS_N1) {
+ if (!(proc = getl3proc(st, cr))) {
+ if ((mt == MT_N1_SETUP) && (cr < 128)) {
+ if (!(proc = new_l3_process(st, cr))) {
+ if (st->l3.debug & L3_DEB_PROTERR) {
+ sprintf(tmp, "up1tr6 no roc mem");
+ l3_debug(st, tmp);
+ }
+ dev_kfree_skb(skb);
+ return;
+ }
+ } else {
+ dev_kfree_skb(skb);
+ return;
+ }
+ }
for (i = 0; i < datastln1_len; i++)
if ((mt == datastln1[i].primitive) &&
- ((1 << st->l3.state) & datastln1[i].state))
+ ((1 << proc->state) & datastln1[i].state))
break;
if (i == datastln1_len) {
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp, "up1tr6%sstate %d mt %x unhandled",
(pr == DL_DATA) ? " " : "(broadcast) ",
- st->l3.state, mt);
+ proc->state, mt);
l3_debug(st, tmp);
}
return;
@@ -738,10 +800,10 @@ up1tr6(struct PStack *st, int pr, void *arg)
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp, "up1tr6%sstate %d mt %x",
(pr == DL_DATA) ? " " : "(broadcast) ",
- st->l3.state, mt);
+ proc->state, mt);
l3_debug(st, tmp);
}
- datastln1[i].rout(st, pr, skb);
+ datastln1[i].rout(proc, pr, skb);
}
}
}
@@ -749,26 +811,44 @@ up1tr6(struct PStack *st, int pr, void *arg)
static void
down1tr6(struct PStack *st, int pr, void *arg)
{
- int i;
+ int i, cr;
+ struct l3_process *proc;
+ struct Channel *chan;
char tmp[80];
+ if (CC_SETUP_REQ == pr) {
+ chan = arg;
+ cr = newcallref();
+ cr |= 0x80;
+ if (!(proc = new_l3_process(st, cr))) {
+ return;
+ } else {
+ proc->chan = chan;
+ chan->proc = proc;
+ proc->para.setup = chan->setup;
+ proc->callref = cr;
+ }
+ } else {
+ proc = arg;
+ }
+
for (i = 0; i < downstl_len; i++)
if ((pr == downstl[i].primitive) &&
- ((1 << st->l3.state) & downstl[i].state))
+ ((1 << proc->state) & downstl[i].state))
break;
if (i == downstl_len) {
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp, "down1tr6 state %d prim %d unhandled",
- st->l3.state, pr);
+ proc->state, pr);
l3_debug(st, tmp);
}
} else {
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp, "down1tr6 state %d prim %d",
- st->l3.state, pr);
+ proc->state, pr);
l3_debug(st, tmp);
}
- downstl[i].rout(st, pr, arg);
+ downstl[i].rout(proc, pr, arg);
}
}
@@ -777,20 +857,10 @@ setstack_1tr6(struct PStack *st)
{
char tmp[64];
- st->l4.l4l3 = down1tr6;
+ st->lli.l4l3 = down1tr6;
st->l2.l2l3 = up1tr6;
- st->l3.t303 = 4000;
- st->l3.t304 = 20000;
- st->l3.t305 = 4000;
- st->l3.t308 = 4000;
- st->l3.t310 = 120000;
- st->l3.t313 = 4000;
- st->l3.t318 = 4000;
- st->l3.t319 = 4000;
- st->l3.n_t303 = 0;
-
- if (st->l3.channr & 1) {
- strcpy(tmp, l3_1tr6_revision);
- printk(KERN_NOTICE "HiSax: 1TR6 Rev. %s\n", HiSax_getrev(tmp));
- }
+ st->l3.N303 = 0;
+
+ strcpy(tmp, l3_1tr6_revision);
+ printk(KERN_INFO "HiSax: 1TR6 Rev. %s\n", HiSax_getrev(tmp));
}
diff --git a/drivers/isdn/hisax/l3_1tr6.h b/drivers/isdn/hisax/l3_1tr6.h
index 6e2fee72f..90d08793e 100644
--- a/drivers/isdn/hisax/l3_1tr6.h
+++ b/drivers/isdn/hisax/l3_1tr6.h
@@ -1,13 +1,14 @@
-/* $Id: l3_1tr6.h,v 1.1 1996/10/13 20:03:48 keil Exp $
+/* $Id: l3_1tr6.h,v 2.0 1997/07/27 21:15:47 keil Exp $
*
* German 1TR6 D-channel protocol defines
*
* $Log: l3_1tr6.h,v $
+ * Revision 2.0 1997/07/27 21:15:47 keil
+ * New Callref based layer3
+ *
* Revision 1.1 1996/10/13 20:03:48 keil
* Initial revision
*
- *
- *
*/
#ifndef l3_1tr6
#define l3_1tr6
@@ -29,7 +30,6 @@
#define MT_N0_CLOSE 0x75
#define MT_N0_CLO_ACK 0x77
-
/*
* MsgType N1
*/
@@ -65,8 +65,6 @@
#define MT_N1_REG_REJ 0x6F
#define MT_N1_STAT 0x63
-
-
/*
* W Elemente
*/
@@ -156,5 +154,13 @@
#define CAUSE_RemoteUserResumed 0x73
#define CAUSE_UserInfoDiscarded 0x7F
+#define T303 4000
+#define T304 20000
+#define T305 4000
+#define T308 4000
+#define T310 120000
+#define T313 4000
+#define T318 4000
+#define T319 4000
#endif
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index d60898734..f8b97fd73 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.c,v 1.15 1997/04/17 11:50:48 keil Exp $
+/* $Id: l3dss1.c,v 2.7 1998/02/12 23:08:01 keil Exp $
* EURO/DSS1 D-channel protocol
*
@@ -9,71 +9,272 @@
* Fritz Elfert
*
* $Log: l3dss1.c,v $
- * Revision 1.15 1997/04/17 11:50:48 keil
- * pa->loc was undefined, if it was not send by the exchange
- *
- * Revision 1.14 1997/04/06 22:54:20 keil
- * Using SKB's
- *
- * Revision 1.13 1997/03/13 20:37:28 keil
- * CLIR and channel request added
- *
- * Revision 1.12 1997/02/17 00:34:26 keil
- * Bugfix: Wrong cause delivered
- *
- * Revision 1.11 1997/02/16 12:12:47 fritz
- * Bugfix: SI2 was nont initialized on incoming calls.
- *
- * Revision 1.10 1997/02/11 01:37:24 keil
- * Changed setup-interface (incoming and outgoing)
- *
- * Revision 1.9 1997/01/27 23:20:52 keil
- * report revision only ones
+ * Revision 2.7 1998/02/12 23:08:01 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
*
- * Revision 1.8 1997/01/21 22:29:41 keil
- * new statemachine; L3 timers
+ * Revision 2.6 1998/02/03 23:26:35 keil
+ * V110 extensions from Thomas Pfeiffer
*
- * Revision 1.7 1996/12/14 21:06:59 keil
- * additional states for CC_REJECT
+ * Revision 2.5 1998/02/02 13:34:28 keil
+ * Support australian Microlink net and german AOCD
*
- * Revision 1.6 1996/12/08 22:59:16 keil
- * fixed calling party number without octet 3a
+ * Revision 2.4 1997/11/06 17:12:25 keil
+ * KERN_NOTICE --> KERN_INFO
*
- * Revision 1.5 1996/12/08 19:53:31 keil
- * fixes from Pekka Sarnila
+ * Revision 2.3 1997/10/29 19:03:01 keil
+ * changes for 2.1
*
- * Revision 1.4 1996/11/05 19:44:36 keil
- * some fixes from Henner Eisen
+ * Revision 2.2 1997/08/07 17:44:36 keil
+ * Fix RESTART
*
- * Revision 1.3 1996/10/30 10:18:01 keil
- * bugfixes in debugging output
+ * Revision 2.1 1997/08/03 14:36:33 keil
+ * Implement RESTART procedure
*
- * Revision 1.2 1996/10/27 22:15:16 keil
- * bugfix reject handling
+ * Revision 2.0 1997/07/27 21:15:43 keil
+ * New Callref based layer3
*
- * Revision 1.1 1996/10/13 20:04:55 keil
- * Initial revision
+ * Revision 1.17 1997/06/26 11:11:46 keil
+ * SET_SKBFREE now on creation of a SKB
*
+ * Revision 1.15 1997/04/17 11:50:48 keil
+ * pa->loc was undefined, if it was not send by the exchange
*
+ * Old log removed /KKe
*
*/
#define __NO_VERSION__
#include "hisax.h"
#include "isdnl3.h"
+#include "l3dss1.h"
#include <linux/ctype.h>
extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 1.15 $";
+const char *dss1_revision = "$Revision: 2.7 $";
+
+#define EXT_BEARER_CAPS 1
#define MsgHead(ptr, cref, mty) \
*ptr++ = 0x8; \
*ptr++ = 0x1; \
- *ptr++ = cref; \
+ *ptr++ = cref^0x80; \
*ptr++ = mty
+
+#ifdef HISAX_DE_AOC
static void
-l3dss1_message(struct PStack *st, u_char mt)
+l3dss1_parse_facility(struct l3_process *pc, u_char *p)
+{
+ int qd_len = 0;
+ char tmp[32];
+
+ p++;
+ qd_len = *p++;
+ if (qd_len == 0) {
+ l3_debug(pc->st, "qd_len == 0");
+ return;
+ }
+ if((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */
+ l3_debug(pc->st, "supplementary service != 0x11");
+ return;
+ }
+ while(qd_len > 0 && !(*p & 0x80)) { /* extension ? */
+ p++; qd_len--;
+ }
+ if(qd_len < 2) {
+ l3_debug(pc->st, "qd_len < 2");
+ return;
+ }
+ p++; qd_len--;
+ if((*p & 0xE0) != 0xA0) { /* class and form */
+ l3_debug(pc->st, "class and form != 0xA0");
+ return;
+ }
+ switch(*p & 0x1F) { /* component tag */
+ case 1: /* invoke */
+ {
+ unsigned char nlen, ilen;
+ int ident;
+
+ p++; qd_len--;
+ if(qd_len < 1) {
+ l3_debug(pc->st, "qd_len < 1");
+ break;
+ }
+ if(*p & 0x80) { /* length format */
+ l3_debug(pc->st, "*p & 0x80 length format");
+ break;
+ }
+ nlen = *p++; qd_len--;
+ if(qd_len < nlen) {
+ l3_debug(pc->st, "qd_len < nlen");
+ return;
+ }
+ qd_len -= nlen;
+
+ if(nlen < 2) {
+ l3_debug(pc->st, "nlen < 2");
+ return;
+ }
+ if(*p != 0x02) { /* invoke identifier tag */
+ l3_debug(pc->st, "invoke identifier tag !=0x02");
+ return;
+ }
+ p++; nlen--;
+ if(*p & 0x80) { /* length format */
+ l3_debug(pc->st, "*p & 0x80 length format 2");
+ break;
+ }
+ ilen = *p++; nlen--;
+ if(ilen > nlen || ilen == 0) {
+ l3_debug(pc->st, "ilen > nlen || ilen == 0");
+ return;
+ }
+ nlen -= ilen;
+ ident = 0;
+ while(ilen > 0) {
+ ident = (ident << 8) | (*p++ & 0xFF); /* invoke identifier */
+ ilen--;
+ }
+
+ if(nlen < 2) {
+ l3_debug(pc->st, "nlen < 2 22");
+ return;
+ }
+ if(*p != 0x02) { /* operation value */
+ l3_debug(pc->st, "operation value !=0x02");
+ return;
+ }
+ p++; nlen--;
+ ilen = *p++; nlen--;
+ if(ilen > nlen || ilen == 0) {
+ l3_debug(pc->st, "ilen > nlen || ilen == 0 22");
+ return;
+ }
+ nlen -= ilen;
+ ident = 0;
+ while(ilen > 0) {
+ ident = (ident << 8) | (*p++ & 0xFF);
+ ilen--;
+ }
+
+ #define FOO1(s,a,b) \
+ while(nlen > 1) { \
+ int ilen = p[1]; \
+ if(nlen < ilen+2) { \
+ l3_debug(pc->st, "FOO1 nlen < ilen+2"); \
+ return; \
+ } \
+ nlen -= ilen+2; \
+ if((*p & 0xFF) == (a)) { \
+ int nlen = ilen; \
+ p += 2; \
+ b; \
+ } else { \
+ p += ilen+2; \
+ } \
+ }
+
+ switch(ident) {
+ default:
+ break;
+ case 0x22: /* during */
+ FOO1("1A",0x30,FOO1("1C",0xA1,FOO1("1D",0x30,FOO1("1E",0x02,({
+ ident = 0;
+ while(ilen > 0) {
+ ident = (ident<<8) | *p++;
+ ilen--;
+ }
+ if (ident > pc->para.chargeinfo) {
+ pc->para.chargeinfo = ident;
+ pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL);
+ }
+ if (pc->st->l3.debug & L3_DEB_CHARGE) {
+ if (*(p+2) == 0) {
+ sprintf(tmp, "charging info during %d", pc->para.chargeinfo);
+ l3_debug(pc->st, tmp);
+ }
+ else {
+ sprintf(tmp, "charging info final %d", pc->para.chargeinfo);
+ l3_debug(pc->st, tmp);
+ }
+ }
+ })))))
+ break;
+ case 0x24: /* final */
+ FOO1("2A",0x30,FOO1("2B",0x30,FOO1("2C",0xA1,FOO1("2D",0x30,FOO1("2E",0x02,({
+ ident = 0;
+ while(ilen > 0) {
+ ident = (ident<<8) | *p++;
+ ilen--;
+ }
+ if (ident > pc->para.chargeinfo) {
+ pc->para.chargeinfo = ident;
+ pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL);
+ }
+ if (pc->st->l3.debug & L3_DEB_CHARGE) {
+ sprintf(tmp, "charging info final %d", pc->para.chargeinfo);
+ l3_debug(pc->st, tmp);
+ }
+ }))))))
+ break;
+ }
+ #undef FOO1
+
+ }
+ break;
+ case 2: /* return result */
+ l3_debug(pc->st, "return result break");
+ break;
+ case 3: /* return error */
+ l3_debug(pc->st, "return error break");
+ break;
+ default:
+ l3_debug(pc->st, "default break");
+ break;
+ }
+}
+#endif
+
+static int
+l3dss1_check_messagetype_validity(int mt) {
+/* verify if a message type exists */
+ switch(mt) {
+ case MT_ALERTING:
+ case MT_CALL_PROCEEDING:
+ case MT_CONNECT:
+ case MT_CONNECT_ACKNOWLEDGE:
+ case MT_PROGRESS:
+ case MT_SETUP:
+ case MT_SETUP_ACKNOWLEDGE:
+ case MT_RESUME:
+ case MT_RESUME_ACKNOWLEDGE:
+ case MT_RESUME_REJECT:
+ case MT_SUSPEND:
+ case MT_SUSPEND_ACKNOWLEDGE:
+ case MT_SUSPEND_REJECT:
+ case MT_USER_INFORMATION:
+ case MT_DISCONNECT:
+ case MT_RELEASE:
+ case MT_RELEASE_COMPLETE:
+ case MT_RESTART:
+ case MT_RESTART_ACKNOWLEDGE:
+ case MT_SEGMENT:
+ case MT_CONGESTION_CONTROL:
+ case MT_INFORMATION:
+ case MT_FACILITY:
+ case MT_NOTIFY:
+ case MT_STATUS:
+ case MT_STATUS_ENQUIRY:
+ return(1);
+ default:
+ return(0);
+ }
+ return(0);
+}
+
+static void
+l3dss1_message(struct l3_process *pc, u_char mt)
{
struct sk_buff *skb;
u_char *p;
@@ -81,63 +282,226 @@ l3dss1_message(struct PStack *st, u_char mt)
if (!(skb = l3_alloc_skb(4)))
return;
p = skb_put(skb, 4);
- MsgHead(p, st->l3.callref, mt);
- st->l3.l3l2(st, DL_DATA, skb);
+ MsgHead(p, pc->callref, mt);
+ pc->st->l3.l3l2(pc->st, DL_DATA, skb);
}
static void
-l3dss1_release_req(struct PStack *st, u_char pr, void *arg)
+l3dss1_release_req(struct l3_process *pc, u_char pr, void *arg)
{
- StopAllL3Timer(st);
- newl3state(st, 19);
- l3dss1_message(st, MT_RELEASE);
- L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1);
+ StopAllL3Timer(pc);
+ newl3state(pc, 19);
+ l3dss1_message(pc, MT_RELEASE);
+ L3AddTimer(&pc->timer, T308, CC_T308_1);
}
static void
-l3dss1_release_cmpl(struct PStack *st, u_char pr, void *arg)
+l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
{
u_char *p;
struct sk_buff *skb = arg;
int cause = -1;
p = skb->data;
- st->pa->loc = 0;
+ pc->para.loc = 0;
if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
p++;
if (*p++ == 2)
- st->pa->loc = *p++;
+ pc->para.loc = *p++;
cause = *p & 0x7f;
}
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
- StopAllL3Timer(st);
- st->pa->cause = cause;
- newl3state(st, 0);
- st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
+ StopAllL3Timer(pc);
+ pc->para.cause = cause;
+ newl3state(pc, 0);
+ pc->st->l3.l3l4(pc, CC_RELEASE_CNF, NULL);
+ release_l3_process(pc);
+}
+
+#ifdef EXT_BEARER_CAPS
+
+u_char *EncodeASyncParams(u_char *p, u_char si2)
+{ // 7c 06 88 90 21 42 00 bb
+
+ p[0] = p[1] = 0; 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;
+}
+
+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 bleibt gleich
+ 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 aushandeln --- hat nicht geklappt, ai wird 165 statt 175!
+ return si2 + 15;
+ case 15: // 56000 bit/s --- hat nicht geklappt, ai wird 0 statt 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
+ return DecodeSyncParams(176, p[5]); // V.120
+ break;
+ }
+ }
+ return 0;
+}
+
+#endif
+
+
static void
-l3dss1_setup_req(struct PStack *st, u_char pr,
+l3dss1_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 channel = 0;
- u_char screen = 0;
+ u_char screen = 0x80;
u_char *teln;
u_char *msn;
+ u_char *sub;
+ u_char *sp;
int l;
- st->l3.callref = st->pa->callref;
- MsgHead(p, st->l3.callref, MT_SETUP);
+ MsgHead(p, pc->callref, MT_SETUP);
/*
* Set Bearer Capability, Map info from 1TR6-convention to EDSS1
*/
+#ifdef HISAX_EURO_SENDCOMPLETE
*p++ = 0xa1; /* complete indicator */
- switch (st->pa->setup.si1) {
+#endif
+ switch (pc->para.setup.si1) {
case 1: /* Telephony */
*p++ = 0x4; /* BC-IE-code */
*p++ = 0x3; /* Length */
@@ -157,7 +521,7 @@ l3dss1_setup_req(struct PStack *st, u_char pr,
/*
* What about info2? Mapping to High-Layer-Compatibility?
*/
- teln = st->pa->setup.phone;
+ teln = pc->para.setup.phone;
if (*teln) {
/* parse number for special things */
if (!isdigit(*teln)) {
@@ -179,19 +543,28 @@ l3dss1_setup_req(struct PStack *st, u_char pr,
screen = 0x80;
break;
default:
- if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "Wrong MSN Code");
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "Wrong MSN Code");
break;
}
teln++;
}
}
if (channel) {
- *p++ = 0x18; /* channel indicator */
+ *p++ = IE_CHANNEL_ID;
*p++ = 1;
*p++ = channel;
}
- msn = st->pa->setup.eazmsn;
+ msn = pc->para.setup.eazmsn;
+ sub = NULL;
+ sp = msn;
+ while (*sp) {
+ if ('.' == *sp) {
+ sub = sp;
+ *sp = 0;
+ } else
+ sp++;
+ }
if (*msn) {
*p++ = 0x6c;
*p++ = strlen(msn) + (screen ? 2 : 1);
@@ -204,241 +577,372 @@ l3dss1_setup_req(struct PStack *st, u_char pr,
while (*msn)
*p++ = *msn++ & 0x7f;
}
+ if (sub) {
+ *sub++ = '.';
+ *p++ = 0x6d; /* Calling party subaddress */
+ *p++ = strlen(sub) + 2;
+ *p++ = 0x80; /* NSAP coded */
+ *p++ = 0x50; /* local IDI format */
+ while (*sub)
+ *p++ = *sub++ & 0x7f;
+ }
+ sub = NULL;
+ sp = teln;
+ while (*sp) {
+ if ('.' == *sp) {
+ sub = sp;
+ *sp = 0;
+ } else
+ sp++;
+ }
*p++ = 0x70;
*p++ = strlen(teln) + 1;
/* Classify as AnyPref. */
*p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
-
while (*teln)
*p++ = *teln++ & 0x7f;
+ if (sub) {
+ *sub++ = '.';
+ *p++ = 0x71; /* Called party subaddress */
+ *p++ = strlen(sub) + 2;
+ *p++ = 0x80; /* NSAP coded */
+ *p++ = 0x50; /* local IDI format */
+ while (*sub)
+ *p++ = *sub++ & 0x7f;
+ }
+
+#ifdef EXT_BEARER_CAPS
+ if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175))
+ { // sync. Bitratenadaption, V.110/X.30
+ *p++ = 0x7c; *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++ = 0x7c; *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++ = 0x7c; *p++ = 0x06; *p++ = 0x88; *p++ = 0x90; *p++ = 0x21;
+ p = EncodeASyncParams(p, pc->para.setup.si2 - 192);
+ }
+#endif
l = p - tmp;
if (!(skb = l3_alloc_skb(l)))
return;
memcpy(skb_put(skb, l), tmp, l);
- L3DelTimer(&st->l3.timer);
- L3AddTimer(&st->l3.timer, st->l3.t303, CC_T303);
- newl3state(st, 1);
- st->l3.l3l2(st, DL_DATA, skb);
-
+ L3DelTimer(&pc->timer);
+ L3AddTimer(&pc->timer, T303, CC_T303);
+ newl3state(pc, 1);
+ pc->st->l3.l3l2(pc->st, DL_DATA, skb);
}
static void
-l3dss1_call_proc(struct PStack *st, u_char pr, void *arg)
+l3dss1_call_proc(struct l3_process *pc, u_char pr, void *arg)
{
u_char *p;
struct sk_buff *skb = arg;
- L3DelTimer(&st->l3.timer);
+ L3DelTimer(&pc->timer);
p = skb->data;
- if ((p = findie(p, skb->len, 0x18, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- if ((!st->pa->bchannel) && (st->l3.debug & L3_DEB_WARN))
- l3_debug(st, "setup answer without bchannel");
- } else if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "setup answer without bchannel");
- SET_SKB_FREE(skb);
+ if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
+ pc->para.bchannel = p[2] & 0x3;
+ if ((!pc->para.bchannel) && (pc->debug & L3_DEB_WARN))
+ l3_debug(pc->st, "setup answer without bchannel");
+ } else if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup answer without bchannel");
dev_kfree_skb(skb);
- newl3state(st, 3);
- L3AddTimer(&st->l3.timer, st->l3.t310, CC_T310);
- st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
+ newl3state(pc, 3);
+ L3AddTimer(&pc->timer, T310, CC_T310);
+ pc->st->l3.l3l4(pc, CC_PROCEEDING_IND, NULL);
}
static void
-l3dss1_setup_ack(struct PStack *st, u_char pr, void *arg)
+l3dss1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
{
u_char *p;
struct sk_buff *skb = arg;
- L3DelTimer(&st->l3.timer);
+ L3DelTimer(&pc->timer);
p = skb->data;
- if ((p = findie(p, skb->len, 0x18, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- if ((!st->pa->bchannel) && (st->l3.debug & L3_DEB_WARN))
- l3_debug(st, "setup answer without bchannel");
- } else if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "setup answer without bchannel");
- SET_SKB_FREE(skb);
+ if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
+ pc->para.bchannel = p[2] & 0x3;
+ if ((!pc->para.bchannel) && (pc->debug & L3_DEB_WARN))
+ l3_debug(pc->st, "setup answer without bchannel");
+ } else if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup answer without bchannel");
dev_kfree_skb(skb);
- newl3state(st, 2);
- L3AddTimer(&st->l3.timer, st->l3.t304, CC_T304);
- st->l3.l3l4(st, CC_MORE_INFO, NULL);
+ newl3state(pc, 2);
+ L3AddTimer(&pc->timer, T304, CC_T304);
+ pc->st->l3.l3l4(pc, CC_MORE_INFO, NULL);
}
static void
-l3dss1_disconnect(struct PStack *st, u_char pr, void *arg)
+l3dss1_disconnect(struct l3_process *pc, u_char pr, void *arg)
{
u_char *p;
struct sk_buff *skb = arg;
int cause = -1;
- StopAllL3Timer(st);
+ StopAllL3Timer(pc);
p = skb->data;
- st->pa->loc = 0;
+ pc->para.loc = 0;
if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
p++;
if (*p++ == 2)
- st->pa->loc = *p++;
+ pc->para.loc = *p++;
cause = *p & 0x7f;
}
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
- newl3state(st, 12);
- st->pa->cause = cause;
- st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
+ newl3state(pc, 12);
+ pc->para.cause = cause;
+ pc->st->l3.l3l4(pc, CC_DISCONNECT_IND, NULL);
}
static void
-l3dss1_connect(struct PStack *st, u_char pr, void *arg)
+l3dss1_connect(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
- L3DelTimer(&st->l3.timer); /* T310 */
- newl3state(st, 10);
- st->l3.l3l4(st, CC_SETUP_CNF, NULL);
+ L3DelTimer(&pc->timer); /* T310 */
+ newl3state(pc, 10);
+ pc->para.chargeinfo = 0;
+ pc->st->l3.l3l4(pc, CC_SETUP_CNF, NULL);
}
static void
-l3dss1_alerting(struct PStack *st, u_char pr, void *arg)
+l3dss1_alerting(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
- L3DelTimer(&st->l3.timer); /* T304 */
- newl3state(st, 4);
- st->l3.l3l4(st, CC_ALERTING_IND, NULL);
+ L3DelTimer(&pc->timer); /* T304 */
+ newl3state(pc, 4);
+ pc->st->l3.l3l4(pc, CC_ALERTING_IND, NULL);
}
static void
-l3dss1_setup(struct PStack *st, u_char pr, void *arg)
+l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
{
- u_char *p;
+ /* This routine is called if here was no SETUP made (checks in dss1up and in
+ * l3dss1_setup) and a RELEASE_COMPLETE have to be sent with an error code
+ * It is called after it is veryfied that Layer2 is up.
+ * The cause value is allready in pc->para.cause
+ * 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: /* 0x51 invalid callreference */
+ case 96: /* 0x60 mandory IE missing */
+ case 101: /* 0x65 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 internal error l3dss1_msg_without_setup\n");
+ return;
+ }
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+ release_l3_process(pc);
+}
+
+static void
+l3dss1_setup(struct l3_process *pc, u_char pr, void *arg)
+{
+ u_char *p, *ptmp[8];
+ int i;
int bcfound = 0;
char tmp[80];
struct sk_buff *skb = arg;
+ /* ETS 300-104 1.3.4 and 1.3.5
+ * we need to detect unknown inform. element from 0 to 7
+ */
p = skb->data;
- st->pa->callref = getcallref(p);
- st->l3.callref = 0x80 + st->pa->callref;
+ for(i = 0; i < 8; i++)
+ ptmp[i] = skb->data;
+ if (findie(ptmp[1], skb->len, 0x01, 0)
+ || findie(ptmp[2], skb->len, 0x02, 0)
+ || findie(ptmp[3], skb->len, 0x03, 0)
+ || findie(ptmp[5], skb->len, 0x05, 0)
+ || findie(ptmp[6], skb->len, 0x06, 0)
+ || findie(ptmp[7], skb->len, 0x07, 0)) {
+ /* if ie is < 8 and not 0 nor 4, send RELEASE_COMPLETE
+ * cause 0x60
+ */
+ pc->para.cause = 0x60;
+ dev_kfree_skb(skb);
+ if (pc->state == 0)
+ pc->st->l3.l3l4(pc, CC_ESTABLISH, NULL);
+ else
+ l3dss1_msg_without_setup(pc, pr, NULL);
+ return;
+ }
/*
* Channel Identification
*/
p = skb->data;
- if ((p = findie(p, skb->len, 0x18, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- if (st->pa->bchannel)
+ if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
+ pc->para.bchannel = p[2] & 0x3;
+ if (pc->para.bchannel)
bcfound++;
- else if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "setup without bchannel");
- } else if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "setup without bchannel");
+ else if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup without bchannel");
+ } else if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup without bchannel");
/*
* Bearer Capabilities
*/
p = skb->data;
if ((p = findie(p, skb->len, 0x04, 0))) {
- st->pa->setup.si2 = 0;
+ pc->para.setup.si2 = 0;
switch (p[2] & 0x1f) {
case 0x00:
/* Speech */
case 0x10:
/* 3.1 Khz audio */
- st->pa->setup.si1 = 1;
+ pc->para.setup.si1 = 1;
break;
case 0x08:
/* Unrestricted digital information */
- st->pa->setup.si1 = 7;
+ pc->para.setup.si1 = 7;
+/* JIM, 05.11.97 I wanna set service indicator 2 */
+#ifdef EXT_BEARER_CAPS
+ pc->para.setup.si2 = DecodeSI2(skb);
+ printk(KERN_DEBUG "HiSax: SI=%d, AI=%d\n",
+ pc->para.setup.si1, pc->para.setup.si2);
+#endif
break;
case 0x09:
/* Restricted digital information */
- st->pa->setup.si1 = 2;
+ pc->para.setup.si1 = 2;
break;
case 0x11:
/* Unrestr. digital information with tones/announcements */
- st->pa->setup.si1 = 3;
+ pc->para.setup.si1 = 3;
break;
case 0x18:
/* Video */
- st->pa->setup.si1 = 4;
+ pc->para.setup.si1 = 4;
break;
default:
- st->pa->setup.si1 = 0;
+ pc->para.setup.si1 = 0;
}
- } else if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "setup without bearer capabilities");
+ } else {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup without bearer capabilities");
+ /* ETS 300-104 1.3.3 */
+ pc->para.cause = 0x60;
+ dev_kfree_skb(skb);
+ if (pc->state == 0)
+ pc->st->l3.l3l4(pc, CC_ESTABLISH, NULL);
+ else
+ l3dss1_msg_without_setup(pc, pr, NULL);
+ return;
+ }
p = skb->data;
if ((p = findie(p, skb->len, 0x70, 0)))
- iecpy(st->pa->setup.eazmsn, p, 1);
+ iecpy(pc->para.setup.eazmsn, p, 1);
else
- st->pa->setup.eazmsn[0] = 0;
+ 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))) {
- st->pa->setup.plan = p[2];
+ pc->para.setup.plan = p[2];
if (p[2] & 0x80) {
- iecpy(st->pa->setup.phone, p, 1);
- st->pa->setup.screen = 0;
+ iecpy(pc->para.setup.phone, p, 1);
+ pc->para.setup.screen = 0;
} else {
- iecpy(st->pa->setup.phone, p, 2);
- st->pa->setup.screen = p[3];
+ iecpy(pc->para.setup.phone, p, 2);
+ pc->para.setup.screen = p[3];
}
} else {
- st->pa->setup.phone[0] = 0;
- st->pa->setup.plan = 0;
- st->pa->setup.screen = 0;
+ 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");
}
- SET_SKB_FREE(skb);
+
dev_kfree_skb(skb);
if (bcfound) {
- if ((st->pa->setup.si1 != 7) && (st->l3.debug & L3_DEB_WARN)) {
+ if ((pc->para.setup.si1 != 7) && (pc->debug & L3_DEB_WARN)) {
sprintf(tmp, "non-digital call: %s -> %s",
- st->pa->setup.phone,
- st->pa->setup.eazmsn);
- l3_debug(st, tmp);
+ pc->para.setup.phone, pc->para.setup.eazmsn);
+ l3_debug(pc->st, tmp);
}
- newl3state(st, 6);
- st->l3.l3l4(st, CC_SETUP_IND, NULL);
- }
+ newl3state(pc, 6);
+ pc->st->l3.l3l4(pc, CC_SETUP_IND, NULL);
+ } else
+ release_l3_process(pc);
}
static void
-l3dss1_reset(struct PStack *st, u_char pr, void *arg)
+l3dss1_reset(struct l3_process *pc, u_char pr, void *arg)
{
- StopAllL3Timer(st);
- newl3state(st, 0);
+ release_l3_process(pc);
}
static void
-l3dss1_setup_rsp(struct PStack *st, u_char pr,
+l3dss1_setup_rsp(struct l3_process *pc, u_char pr,
void *arg)
{
- newl3state(st, 8);
- l3dss1_message(st, MT_CONNECT);
- L3DelTimer(&st->l3.timer);
- L3AddTimer(&st->l3.timer, st->l3.t313, CC_T313);
+ newl3state(pc, 8);
+ l3dss1_message(pc, MT_CONNECT);
+ L3DelTimer(&pc->timer);
+ L3AddTimer(&pc->timer, T313, CC_T313);
}
static void
-l3dss1_connect_ack(struct PStack *st, u_char pr, void *arg)
+l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
- newl3state(st, 10);
- L3DelTimer(&st->l3.timer);
- st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
+ newl3state(pc, 10);
+ L3DelTimer(&pc->timer);
+ pc->st->l3.l3l4(pc, CC_SETUP_COMPLETE_IND, NULL);
}
static void
-l3dss1_disconnect_req(struct PStack *st, u_char pr, void *arg)
+l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb;
u_char tmp[16];
@@ -446,12 +950,12 @@ l3dss1_disconnect_req(struct PStack *st, u_char pr, void *arg)
int l;
u_char cause = 0x10;
- if (st->pa->cause > 0)
- cause = st->pa->cause;
+ if (pc->para.cause > 0)
+ cause = pc->para.cause;
- StopAllL3Timer(st);
+ StopAllL3Timer(pc);
- MsgHead(p, st->l3.callref, MT_DISCONNECT);
+ MsgHead(p, pc->callref, MT_DISCONNECT);
*p++ = IE_CAUSE;
*p++ = 0x2;
@@ -462,13 +966,13 @@ l3dss1_disconnect_req(struct PStack *st, u_char pr, void *arg)
if (!(skb = l3_alloc_skb(l)))
return;
memcpy(skb_put(skb, l), tmp, l);
- newl3state(st, 11);
- st->l3.l3l2(st, DL_DATA, skb);
- L3AddTimer(&st->l3.timer, st->l3.t305, CC_T305);
+ newl3state(pc, 11);
+ pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+ L3AddTimer(&pc->timer, T305, CC_T305);
}
static void
-l3dss1_reject_req(struct PStack *st, u_char pr, void *arg)
+l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb;
u_char tmp[16];
@@ -476,10 +980,10 @@ l3dss1_reject_req(struct PStack *st, u_char pr, void *arg)
int l;
u_char cause = 0x95;
- if (st->pa->cause > 0)
- cause = st->pa->cause;
+ if (pc->para.cause > 0)
+ cause = pc->para.cause;
- MsgHead(p, st->l3.callref, MT_RELEASE_COMPLETE);
+ MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
*p++ = IE_CAUSE;
*p++ = 0x2;
@@ -490,13 +994,14 @@ l3dss1_reject_req(struct PStack *st, u_char pr, void *arg)
if (!(skb = l3_alloc_skb(l)))
return;
memcpy(skb_put(skb, l), tmp, l);
- newl3state(st, 0);
- st->l3.l3l2(st, DL_DATA, skb);
- st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+ pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+ pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL);
+ newl3state(pc, 0);
+ release_l3_process(pc);
}
static void
-l3dss1_release(struct PStack *st, u_char pr, void *arg)
+l3dss1_release(struct l3_process *pc, u_char pr, void *arg)
{
u_char *p;
struct sk_buff *skb = arg;
@@ -506,38 +1011,45 @@ l3dss1_release(struct PStack *st, u_char pr, void *arg)
if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
p++;
if (*p++ == 2)
- st->pa->loc = *p++;
+ pc->para.loc = *p++;
cause = *p & 0x7f;
}
- SET_SKB_FREE(skb);
+ p = skb->data;
+ if ((p = findie(p, skb->len, IE_FACILITY, 0))) {
+#ifdef HISAX_DE_AOC
+ l3dss1_parse_facility(pc,p);
+#else
+ p = NULL;
+#endif
+ }
dev_kfree_skb(skb);
- StopAllL3Timer(st);
- st->pa->cause = cause;
- newl3state(st, 0);
- l3dss1_message(st, MT_RELEASE_COMPLETE);
- st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+ StopAllL3Timer(pc);
+ pc->para.cause = cause;
+ l3dss1_message(pc, MT_RELEASE_COMPLETE);
+ pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL);
+ newl3state(pc, 0);
+ release_l3_process(pc);
}
static void
-l3dss1_alert_req(struct PStack *st, u_char pr,
+l3dss1_alert_req(struct l3_process *pc, u_char pr,
void *arg)
{
- newl3state(st, 7);
- l3dss1_message(st, MT_ALERTING);
+ newl3state(pc, 7);
+ l3dss1_message(pc, MT_ALERTING);
}
static void
-l3dss1_status_enq(struct PStack *st, u_char pr, void *arg)
+l3dss1_status_enq(struct l3_process *pc, u_char pr, void *arg)
{
u_char tmp[16];
u_char *p = tmp;
int l;
struct sk_buff *skb = arg;
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
- MsgHead(p, st->l3.callref, MT_STATUS);
+ MsgHead(p, pc->callref, MT_STATUS);
*p++ = IE_CAUSE;
*p++ = 0x2;
@@ -546,42 +1058,96 @@ l3dss1_status_enq(struct PStack *st, u_char pr, void *arg)
*p++ = 0x14; /* CallState */
*p++ = 0x1;
- *p++ = st->l3.state & 0x3f;
+ *p++ = pc->state & 0x3f;
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+}
+
+static void
+l3dss1_status_req(struct l3_process *pc, u_char pr, void *arg)
+{
+ /* ETS 300-104 7.4.1, 8.4.1, 10.3.1, 11.4.1, 12.4.1, 13.4.1, 14.4.1...
+ if setup has been made and a non expected message type is received, we must send MT_STATUS cause 0x62 */
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+ struct sk_buff *skb = arg;
+
+ dev_kfree_skb(skb);
+
+ MsgHead(p, pc->callref, MT_STATUS);
+
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = 0x62 | 0x80; /* status sending */
+
+ *p++ = 0x14; /* CallState */
+ *p++ = 0x1;
+ *p++ = pc->state & 0x3f;
l = p - tmp;
if (!(skb = l3_alloc_skb(l)))
return;
memcpy(skb_put(skb, l), tmp, l);
- st->l3.l3l2(st, DL_DATA, skb);
+ pc->st->l3.l3l2(pc->st, DL_DATA, skb);
}
static void
-l3dss1_t303(struct PStack *st, u_char pr, void *arg)
+l3dss1_release_ind(struct l3_process *pc, u_char pr, void *arg)
{
- if (st->l3.n_t303 > 0) {
- st->l3.n_t303--;
- L3DelTimer(&st->l3.timer);
- l3dss1_setup_req(st, pr, 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, CC_RELEASE_IND, NULL);
+ newl3state(pc, 0);
+ release_l3_process(pc);
} else {
- newl3state(st, 0);
- L3DelTimer(&st->l3.timer);
- st->l3.l3l4(st, CC_NOSETUP_RSP_ERR, NULL);
- st->l3.n_t303 = 1;
+ pc->st->l3.l3l4(pc, CC_IGNORE, NULL);
}
}
static void
-l3dss1_t304(struct PStack *st, u_char pr, void *arg)
+l3dss1_t303(struct l3_process *pc, u_char pr, void *arg)
{
- L3DelTimer(&st->l3.timer);
- st->pa->cause = 0xE6;
- l3dss1_disconnect_req(st, pr, NULL);
- st->l3.l3l4(st, CC_SETUP_ERR, NULL);
+ if (pc->N303 > 0) {
+ pc->N303--;
+ L3DelTimer(&pc->timer);
+ l3dss1_setup_req(pc, pr, arg);
+ } else {
+ L3DelTimer(&pc->timer);
+ pc->st->l3.l3l4(pc, CC_NOSETUP_RSP_ERR, NULL);
+ release_l3_process(pc);
+ }
+}
+
+static void
+l3dss1_t304(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ pc->para.cause = 0xE6;
+ l3dss1_disconnect_req(pc, pr, NULL);
+ pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL);
}
static void
-l3dss1_t305(struct PStack *st, u_char pr, void *arg)
+l3dss1_t305(struct l3_process *pc, u_char pr, void *arg)
{
u_char tmp[16];
u_char *p = tmp;
@@ -589,11 +1155,11 @@ l3dss1_t305(struct PStack *st, u_char pr, void *arg)
struct sk_buff *skb;
u_char cause = 0x90;
- L3DelTimer(&st->l3.timer);
- if (st->pa->cause > 0)
- cause = st->pa->cause;
+ L3DelTimer(&pc->timer);
+ if (pc->para.cause > 0)
+ cause = pc->para.cause | 0x80;
- MsgHead(p, st->l3.callref, MT_RELEASE);
+ MsgHead(p, pc->callref, MT_RELEASE);
*p++ = IE_CAUSE;
*p++ = 0x2;
@@ -604,49 +1170,180 @@ l3dss1_t305(struct PStack *st, u_char pr, void *arg)
if (!(skb = l3_alloc_skb(l)))
return;
memcpy(skb_put(skb, l), tmp, l);
- newl3state(st, 19);
- st->l3.l3l2(st, DL_DATA, skb);
- L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1);
+ newl3state(pc, 19);
+ pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+ L3AddTimer(&pc->timer, T308, CC_T308_1);
+}
+
+static void
+l3dss1_t310(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ pc->para.cause = 0xE6;
+ l3dss1_disconnect_req(pc, pr, NULL);
+ pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL);
+}
+
+static void
+l3dss1_t313(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ pc->para.cause = 0xE6;
+ l3dss1_disconnect_req(pc, pr, NULL);
+ pc->st->l3.l3l4(pc, CC_CONNECT_ERR, NULL);
+}
+
+static void
+l3dss1_t308_1(struct l3_process *pc, u_char pr, void *arg)
+{
+ newl3state(pc, 19);
+ L3DelTimer(&pc->timer);
+ l3dss1_message(pc, MT_RELEASE);
+ L3AddTimer(&pc->timer, T308, CC_T308_2);
+}
+
+static void
+l3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ pc->st->l3.l3l4(pc, CC_RELEASE_ERR, NULL);
+ release_l3_process(pc);
}
static void
-l3dss1_t310(struct PStack *st, u_char pr, void *arg)
+l3dss1_restart(struct l3_process *pc, u_char pr, void *arg)
{
- L3DelTimer(&st->l3.timer);
- st->pa->cause = 0xE6;
- l3dss1_disconnect_req(st, pr, NULL);
- st->l3.l3l4(st, CC_SETUP_ERR, NULL);
+ L3DelTimer(&pc->timer);
+ pc->st->l3.l3l4(pc, CC_DLRL, NULL);
+ release_l3_process(pc);
}
static void
-l3dss1_t313(struct PStack *st, u_char pr, void *arg)
+l3dss1_status(struct l3_process *pc, u_char pr, void *arg)
{
- L3DelTimer(&st->l3.timer);
- st->pa->cause = 0xE6;
- l3dss1_disconnect_req(st, pr, NULL);
- st->l3.l3l4(st, CC_CONNECT_ERR, NULL);
+ u_char *p;
+ char tmp[64], *t;
+ int l;
+ struct sk_buff *skb = arg;
+ int cause, callState;
+
+ cause = callState = -1;
+ p = skb->data;
+ t = tmp;
+ if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
+ p++;
+ l = *p++;
+ t += sprintf(t,"Status CR %x Cause:", pc->callref);
+ while (l--) {
+ cause = *p;
+ t += sprintf(t," %2x",*p++);
+ }
+ } else
+ sprintf(t,"Status CR %x no Cause", pc->callref);
+ l3_debug(pc->st, tmp);
+ p = skb->data;
+ t = tmp;
+ t += sprintf(t,"Status state %x ", pc->state);
+ if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) {
+ p++;
+ if (1== *p++) {
+ callState = *p;
+ t += sprintf(t,"peer state %x" , *p);
+ }
+ else
+ t += sprintf(t,"peer state len error");
+ } else
+ sprintf(t,"no peer state");
+ l3_debug(pc->st, tmp);
+ if(((cause & 0x7f) == 0x6f) && (callState == 0)) {
+ /* ETS 300-104 7.6.1, 8.6.1, 10.6.1...
+ * if received MT_STATUS with cause == 0x6f and call
+ * state == 0, then we must set down layer 3
+ */
+ l3dss1_release_ind(pc, pr, arg);
+ } else
+ dev_kfree_skb(skb);
}
static void
-l3dss1_t308_1(struct PStack *st, u_char pr, void *arg)
+l3dss1_facility(struct l3_process *pc, u_char pr, void *arg)
{
- newl3state(st, 19);
- L3DelTimer(&st->l3.timer);
- l3dss1_message(st, MT_RELEASE);
- L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_2);
+ u_char *p;
+ struct sk_buff *skb = arg;
+
+ p = skb->data;
+ if ((p = findie(p, skb->len, IE_FACILITY, 0))) {
+#ifdef HISAX_DE_AOC
+ l3dss1_parse_facility(pc,p);
+#else
+ p = NULL;
+#endif
+ }
}
+
+
static void
-l3dss1_t308_2(struct PStack *st, u_char pr, void *arg)
+l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg)
{
- newl3state(st, 0);
- L3DelTimer(&st->l3.timer);
- st->l3.l3l4(st, CC_RELEASE_ERR, NULL);
+ u_char tmp[32];
+ u_char *p;
+ u_char ri, 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];
+ sprintf(tmp, "Restart %x", ri);
+ } else {
+ sprintf(tmp, "Restart without restart IE");
+ ri = 0x86;
+ }
+ l3_debug(pc->st, tmp);
+ p = skb->data;
+ if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
+ chan = p[2] & 3;
+ sprintf(tmp, "Restart for channel %d", chan);
+ l3_debug(pc->st, tmp);
+ }
+ dev_kfree_skb(skb);
+ newl3state(pc, 2);
+ up = pc->st->l3.proc;
+ while (up) {
+ if ((ri & 7)==7)
+ up->st->lli.l4l3(up->st, CC_RESTART, up);
+ else if (up->para.bchannel == chan)
+ up->st->lli.l4l3(up->st, CC_RESTART, up);
+ up = up->next;
+ }
+ p = tmp;
+ MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE);
+ if (chan) {
+ *p++ = IE_CHANNEL_ID;
+ *p++ = 1;
+ *p++ = chan | 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);
+ pc->st->l3.l3l2(pc->st, DL_DATA, skb);
}
+
/* *INDENT-OFF* */
static struct stateentry downstatelist[] =
{
{SBIT(0),
+ CC_ESTABLISH, l3dss1_msg_without_setup},
+ {SBIT(0),
CC_SETUP_REQ, l3dss1_setup_req},
{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(10),
CC_DISCONNECT_REQ, l3dss1_disconnect_req},
@@ -654,6 +1351,8 @@ static struct stateentry downstatelist[] =
CC_RELEASE_REQ, l3dss1_release_req},
{ALL_STATES,
CC_DLRL, l3dss1_reset},
+ {ALL_STATES,
+ CC_RESTART, l3dss1_restart},
{SBIT(6),
CC_IGNORE, l3dss1_reset},
{SBIT(6),
@@ -685,63 +1384,216 @@ static struct stateentry datastatelist[] =
{
{ALL_STATES,
MT_STATUS_ENQUIRY, l3dss1_status_enq},
+ {ALL_STATES,
+ MT_FACILITY, l3dss1_facility},
+ {SBIT(19),
+ MT_STATUS, l3dss1_release_ind},
+ {ALL_STATES,
+ MT_STATUS, l3dss1_status},
{SBIT(0) | SBIT(6),
MT_SETUP, l3dss1_setup},
{SBIT(1) | SBIT(2),
MT_CALL_PROCEEDING, l3dss1_call_proc},
+ {SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19),
+ MT_CALL_PROCEEDING, l3dss1_status_req},
{SBIT(1),
MT_SETUP_ACKNOWLEDGE, l3dss1_setup_ack},
+ {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19),
+ MT_SETUP_ACKNOWLEDGE, l3dss1_status_req},
{SBIT(1) | SBIT(2) | SBIT(3),
MT_ALERTING, l3dss1_alerting},
+ {SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19),
+ MT_ALERTING, l3dss1_status_req},
{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),
MT_RELEASE_COMPLETE, l3dss1_release_cmpl},
- {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(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) |
+ SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) /*| SBIT(19)*/,
MT_RELEASE, l3dss1_release},
+ {SBIT(19), MT_RELEASE, l3dss1_release_ind},
{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10),
MT_DISCONNECT, l3dss1_disconnect},
+ {SBIT(11),
+ MT_DISCONNECT, l3dss1_release_req},
{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4),
MT_CONNECT, l3dss1_connect},
+ {SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19),
+ MT_CONNECT, l3dss1_status_req},
+ {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(11) | SBIT(19),
+ MT_CONNECT_ACKNOWLEDGE, l3dss1_status_req},
{SBIT(8),
MT_CONNECT_ACKNOWLEDGE, l3dss1_connect_ack},
+ {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19),
+ MT_INVALID, l3dss1_status_req},
};
-/* *INDENT-ON* */
+static int datasllen = sizeof(datastatelist) / sizeof(struct stateentry);
-static int datasllen = sizeof(datastatelist) /
-sizeof(struct stateentry);
+static struct stateentry globalmes_list[] =
+{
+ {ALL_STATES,
+ MT_STATUS, l3dss1_status},
+ {SBIT(0),
+ MT_RESTART, l3dss1_global_restart},
+/* {SBIT(1),
+ MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack},
+*/
+};
+static int globalm_len = sizeof(globalmes_list) / sizeof(struct stateentry);
+
+#if 0
+static struct stateentry globalcmd_list[] =
+{
+ {ALL_STATES,
+ CC_STATUS, l3dss1_status_req},
+ {SBIT(0),
+ CC_RESTART, l3dss1_restart_req},
+};
+
+static int globalc_len = sizeof(globalcmd_list) / sizeof(struct stateentry);
+#endif
+/* *INDENT-ON* */
+
+static void
+global_handler(struct PStack *st, int mt, struct sk_buff *skb)
+{
+ int i;
+ char tmp[64];
+ struct l3_process *proc = st->l3.global;
+
+ 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) {
+ dev_kfree_skb(skb);
+ if (st->l3.debug & L3_DEB_STATE) {
+ sprintf(tmp, "dss1 global state %d mt %x unhandled",
+ proc->state, mt);
+ l3_debug(st, tmp);
+ }
+ return;
+ } else {
+ if (st->l3.debug & L3_DEB_STATE) {
+ sprintf(tmp, "dss1 global %d mt %x",
+ proc->state, mt);
+ l3_debug(st, tmp);
+ }
+ globalmes_list[i].rout(proc, mt, skb);
+ }
+}
static void
dss1up(struct PStack *st, int pr, void *arg)
{
- int i, mt;
+ int i, mt, cr, cause, callState;
+ char *ptr;
struct sk_buff *skb = arg;
+ struct l3_process *proc;
char tmp[80];
if (skb->data[0] != PROTO_DIS_EURO) {
if (st->l3.debug & L3_DEB_PROTERR) {
- sprintf(tmp, "dss1up%sunexpected discriminator %x message len %d state %d",
+ sprintf(tmp, "dss1up%sunexpected discriminator %x message len %d",
(pr == DL_DATA) ? " " : "(broadcast) ",
- skb->data[0], skb->len, st->l3.state);
+ skb->data[0], skb->len);
l3_debug(st, tmp);
}
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
return;
}
+ cr = getcallref(skb->data);
mt = skb->data[skb->data[1] + 2];
+ if (!cr) { /* Global CallRef */
+ global_handler(st, mt, skb);
+ return;
+ } else if (cr == -1) { /* Dummy Callref */
+ 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 (!(proc = 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;
+ }
+ if (callState == 0) {
+ /* 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
+ */
+ dev_kfree_skb(skb);
+ return;
+ } else {
+ /* 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
+ */
+ dev_kfree_skb(skb);
+ if ((proc = new_l3_process(st, cr))) {
+ proc->para.cause = 0x65; /* 101 */
+ proc->st->l3.l3l4(proc, CC_ESTABLISH, NULL);
+ }
+ 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 = new_l3_process(st, cr))) {
+ proc->para.cause = 0x51; /* 81 */
+ proc->st->l3.l3l4(proc, CC_ESTABLISH, NULL);
+ }
+ return;
+ }
+ } else if (!l3dss1_check_messagetype_validity(mt)) {
+ /* ETS 300-104 7.4.2, 8.4.2, 10.3.2, 11.4.2, 12.4.2, 13.4.2,
+ * 14.4.2...
+ * if setup has been made and invalid message type is received,
+ * we must send MT_STATUS cause 0x62
+ */
+ mt = MT_INVALID; /* sorry, not clean, but do the right thing ;-) */
+ }
+
for (i = 0; i < datasllen; i++)
if ((mt == datastatelist[i].primitive) &&
- ((1 << st->l3.state) & datastatelist[i].state))
+ ((1 << proc->state) & datastatelist[i].state))
break;
if (i == datasllen) {
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp, "dss1up%sstate %d mt %x unhandled",
(pr == DL_DATA) ? " " : "(broadcast) ",
- st->l3.state, mt);
+ proc->state, mt);
l3_debug(st, tmp);
}
return;
@@ -749,36 +1601,55 @@ dss1up(struct PStack *st, int pr, void *arg)
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp, "dss1up%sstate %d mt %x",
(pr == DL_DATA) ? " " : "(broadcast) ",
- st->l3.state, mt);
+ proc->state, mt);
l3_debug(st, tmp);
}
- datastatelist[i].rout(st, pr, skb);
+ datastatelist[i].rout(proc, pr, skb);
}
}
static void
dss1down(struct PStack *st, int pr, void *arg)
{
- int i;
+ int i, cr;
+ struct l3_process *proc;
+ struct Channel *chan;
char tmp[80];
+ if (CC_SETUP_REQ == pr) {
+ chan = arg;
+ cr = newcallref();
+ cr |= 0x80;
+ if ((proc = new_l3_process(st, cr))) {
+ proc->chan = chan;
+ chan->proc = proc;
+ proc->para.setup = chan->setup;
+ proc->callref = cr;
+ }
+ } else {
+ proc = arg;
+ }
+ if (!proc) {
+ printk(KERN_ERR "HiSax internal error dss1down without proc\n");
+ return;
+ }
for (i = 0; i < downsllen; i++)
if ((pr == downstatelist[i].primitive) &&
- ((1 << st->l3.state) & downstatelist[i].state))
+ ((1 << proc->state) & downstatelist[i].state))
break;
if (i == downsllen) {
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp, "dss1down state %d prim %d unhandled",
- st->l3.state, pr);
+ proc->state, pr);
l3_debug(st, tmp);
}
} else {
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp, "dss1down state %d prim %d",
- st->l3.state, pr);
+ proc->state, pr);
l3_debug(st, tmp);
}
- downstatelist[i].rout(st, pr, arg);
+ downstatelist[i].rout(proc, pr, arg);
}
}
@@ -787,20 +1658,20 @@ setstack_dss1(struct PStack *st)
{
char tmp[64];
- st->l4.l4l3 = dss1down;
+ st->lli.l4l3 = dss1down;
st->l2.l2l3 = dss1up;
- st->l3.t303 = 4000;
- st->l3.t304 = 30000;
- st->l3.t305 = 30000;
- st->l3.t308 = 4000;
- st->l3.t310 = 30000;
- st->l3.t313 = 4000;
- st->l3.t318 = 4000;
- st->l3.t319 = 4000;
- st->l3.n_t303 = 1;
-
- if (st->l3.channr & 1) {
- strcpy(tmp, dss1_revision);
- printk(KERN_NOTICE "HiSax: DSS1 Rev. %s\n", HiSax_getrev(tmp));
+ st->l3.N303 = 1;
+ if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
+ printk(KERN_ERR "HiSax can't get memory for dss1 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;
+ L3InitTimer(st->l3.global, &st->l3.global->timer);
}
+ strcpy(tmp, dss1_revision);
+ printk(KERN_INFO "HiSax: DSS1 Rev. %s\n", HiSax_getrev(tmp));
}
diff --git a/drivers/isdn/hisax/l3dss1.h b/drivers/isdn/hisax/l3dss1.h
new file mode 100644
index 000000000..8508c3109
--- /dev/null
+++ b/drivers/isdn/hisax/l3dss1.h
@@ -0,0 +1,71 @@
+/* $Id: l3dss1.h,v 1.5 1998/02/02 13:34:30 keil Exp $
+ *
+ * DSS1 (Euro) D-channel protocol defines
+ *
+ * $Log: l3dss1.h,v $
+ * Revision 1.5 1998/02/02 13:34:30 keil
+ * Support australian Microlink net and german AOCD
+ *
+ * Revision 1.4 1997/10/29 19:07:54 keil
+ * changes for 2.1
+ *
+ * Revision 1.3 1997/08/07 17:44:37 keil
+ * Fix RESTART
+ *
+ * Revision 1.2 1997/08/03 14:36:34 keil
+ * Implement RESTART procedure
+ *
+ * Revision 1.1 1997/07/27 21:08:38 keil
+ * new
+ *
+ *
+ *
+ */
+#define T303 4000
+#define T304 30000
+#define T305 30000
+#define T308 4000
+#define T310 30000
+#define T313 4000
+#define T318 4000
+#define T319 4000
+
+/*
+ * 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_INVALID 0xff
+
+#define IE_CAUSE 0x08
+#define IE_BEARER 0x04
+#define IE_FACILITY 0x1c
+#define IE_CALL_STATE 0x14
+#define IE_CHANNEL_ID 0x18
+#define IE_RESTART_IND 0x79
diff --git a/drivers/isdn/hisax/lmgr.c b/drivers/isdn/hisax/lmgr.c
new file mode 100644
index 000000000..b3e9819b2
--- /dev/null
+++ b/drivers/isdn/hisax/lmgr.c
@@ -0,0 +1,58 @@
+/* $Id: lmgr.c,v 1.2 1997/10/29 19:09:34 keil Exp $
+
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * Layermanagement module
+ *
+ * $Log: lmgr.c,v $
+ * Revision 1.2 1997/10/29 19:09:34 keil
+ * new L1
+ *
+ * Revision 1.1 1997/06/26 11:17:25 keil
+ * first version
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+
+static void
+error_handling_dchan(struct PStack *st, int Error)
+{
+ switch (Error) {
+ case 'C':
+ case 'D':
+ case 'G':
+ case 'H':
+ st->l2.l2tei(st, MDL_ERROR_REQ, NULL);
+ break;
+ }
+}
+
+static void
+hisax_manager(struct PStack *st, int pr, void *arg)
+{
+ char tm[32], str[256];
+ int Code;
+
+ switch (pr) {
+ case MDL_ERROR_IND:
+ Code = (int) arg;
+ jiftime(tm, jiffies);
+ sprintf(str, "%s manager: MDL_ERROR %c %s\n", tm,
+ Code, test_bit(FLG_LAPD, &st->l2.flag) ?
+ "D-channel" : "B-channel");
+ HiSax_putstatus(st->l1.hardware, str);
+ if (test_bit(FLG_LAPD, &st->l2.flag))
+ error_handling_dchan(st, Code);
+ break;
+ }
+}
+
+void
+setstack_manager(struct PStack *st)
+{
+ st->ma.layer = hisax_manager;
+}
diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c
new file mode 100644
index 000000000..8bf4757c9
--- /dev/null
+++ b/drivers/isdn/hisax/mic.c
@@ -0,0 +1,284 @@
+/* $Id: mic.c,v 1.6 1998/02/17 15:39:57 keil Exp $
+
+ * mic.c low level stuff for mic cards
+ *
+ * Copyright (C) 1997
+ *
+ * Author Stephan von Krawczynski <skraw@ithnet.com>
+ *
+ *
+ * $Log: mic.c,v $
+ * Revision 1.6 1998/02/17 15:39:57 keil
+ * fix reset problem
+ *
+ * Revision 1.5 1998/02/02 13:29:43 keil
+ * fast io
+ *
+ * Revision 1.4 1997/11/08 21:35:51 keil
+ * new l1 init
+ *
+ * Revision 1.3 1997/11/06 17:09:11 keil
+ * New 2.1 init code
+ *
+ * Revision 1.2 1997/10/29 18:51:17 keil
+ * New files
+ *
+ * Revision 1.1.2.1 1997/10/17 22:10:54 keil
+ * new files on 2.0
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+
+const char *mic_revision = "$Revision: 1.6 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define MIC_ISAC 2
+#define MIC_HSCX 1
+#define MIC_ADR 7
+
+/* CARD_ADR (Write) */
+#define MIC_RESET 0x3 /* same as DOS driver */
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+ register u_char ret;
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(ale, off);
+ ret = bytein(adr);
+ restore_flags(flags);
+
+ return (ret);
+}
+
+static inline void
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+ /* fifo read without cli because it's allready done */
+
+ byteout(ale, off);
+ insb(adr, data, size);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(ale, off);
+ byteout(adr, data);
+ restore_flags(flags);
+}
+
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+ /* fifo write without cli because it's allready done */
+ byteout(ale, off);
+ outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+ return (readreg(cs->hw.mic.adr, cs->hw.mic.isac, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ writereg(cs->hw.mic.adr, cs->hw.mic.isac, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ readfifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ writefifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+ return (readreg(cs->hw.mic.adr,
+ cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+ writereg(cs->hw.mic.adr,
+ cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0), value);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.mic.adr, \
+ cs->hw.mic.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.mic.adr, \
+ cs->hw.mic.hscx, reg + (nr ? 0x40 : 0), data)
+
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.mic.adr, \
+ cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.mic.adr, \
+ cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+mic_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val, stat = 0;
+
+ if (!cs) {
+ printk(KERN_WARNING "mic: Spurious interrupt!\n");
+ return;
+ }
+ val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
+ Start_HSCX:
+ if (val) {
+ hscx_int_main(cs, val);
+ stat |= 1;
+ }
+ val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
+ Start_ISAC:
+ if (val) {
+ isac_interrupt(cs, val);
+ stat |= 2;
+ }
+ val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
+ if (val) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX IntStat after IntRoutine");
+ goto Start_HSCX;
+ }
+ val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
+ if (val) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ISAC IntStat after IntRoutine");
+ goto Start_ISAC;
+ }
+ if (stat & 1) {
+ writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0xFF);
+ writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0xFF);
+ writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0x0);
+ writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0x0);
+ }
+ if (stat & 2) {
+ writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0);
+ }
+}
+
+void
+release_io_mic(struct IsdnCardState *cs)
+{
+ int bytecnt = 8;
+
+ if (cs->hw.mic.cfg_reg)
+ release_region(cs->hw.mic.cfg_reg, bytecnt);
+}
+
+static int
+mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ return(0);
+ case CARD_RELEASE:
+ release_io_mic(cs);
+ return(0);
+ case CARD_SETIRQ:
+ return(request_irq(cs->irq, &mic_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs));
+ case CARD_INIT:
+ inithscx(cs); /* /RTSA := ISAC RST */
+ clear_pending_isac_ints(cs);
+ clear_pending_hscx_ints(cs);
+ initisac(cs);
+ inithscx(cs);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
+}
+
+__initfunc(int
+setup_mic(struct IsdnCard *card))
+{
+ int bytecnt;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, mic_revision);
+ printk(KERN_INFO "HiSax: mic driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_MIC)
+ return (0);
+
+ bytecnt = 8;
+ cs->hw.mic.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR;
+ cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC;
+ cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX;
+
+ if (check_region((cs->hw.mic.cfg_reg), bytecnt)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.mic.cfg_reg,
+ cs->hw.mic.cfg_reg + bytecnt);
+ return (0);
+ } else {
+ request_region(cs->hw.mic.cfg_reg, bytecnt, "mic isdn");
+ }
+
+ printk(KERN_INFO
+ "mic: defined at 0x%x IRQ %d\n",
+ cs->hw.mic.cfg_reg,
+ cs->irq);
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ cs->BC_Read_Reg = &ReadHSCX;
+ cs->BC_Write_Reg = &WriteHSCX;
+ cs->BC_Send_Data = &hscx_fill_fifo;
+ cs->cardmsg = &mic_card_msg;
+ ISACVersion(cs, "mic:");
+ if (HscxVersion(cs, "mic:")) {
+ printk(KERN_WARNING
+ "mic: wrong HSCX versions check IO address\n");
+ release_io_mic(cs);
+ return (0);
+ }
+ return (1);
+}
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
new file mode 100644
index 000000000..0686598e2
--- /dev/null
+++ b/drivers/isdn/hisax/netjet.c
@@ -0,0 +1,1108 @@
+/* $Id: netjet.c,v 1.3 1998/02/12 23:08:05 keil Exp $
+
+ * netjet.c low level stuff for Traverse Technologie NETJet ISDN cards
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to Traverse Technologie Australia for documents and informations
+ *
+ *
+ * $Log: netjet.c,v $
+ * Revision 1.3 1998/02/12 23:08:05 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.2 1998/02/02 13:32:06 keil
+ * New
+ *
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/interrupt.h>
+#define fcstab ppp_crc16_table
+#include <linux/ppp_defs.h>
+extern __u16 ppp_crc16_table[256]; /* from ppp code */
+
+extern const char *CardType[];
+
+const char *NETjet_revision = "$Revision: 1.3 $";
+
+#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_DMA_SIZE 512
+
+#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
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+ long flags;
+ u_char ret;
+
+ save_flags(flags);
+ cli();
+ cs->hw.njet.auxd &= 0xfc;
+ cs->hw.njet.auxd |= (offset>>4) & 3;
+ byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+ ret = bytein(cs->hw.njet.isac + ((offset & 0xf)<<2));
+ restore_flags(flags);
+ return(ret);
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ cs->hw.njet.auxd &= 0xfc;
+ cs->hw.njet.auxd |= (offset>>4) & 3;
+ byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+ byteout(cs->hw.njet.isac + ((offset & 0xf)<<2), value);
+ restore_flags(flags);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
+{
+ cs->hw.njet.auxd &= 0xfc;
+ byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+ insb(cs->hw.njet.isac, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
+{
+ cs->hw.njet.auxd &= 0xfc;
+ byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+ outsb(cs->hw.njet.isac, data, size);
+}
+
+void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill)
+{
+ u_int mask=0x000000ff, val = 0, *p=pos;
+ u_int i;
+
+ val |= fill;
+ if (chan) {
+ val <<= 8;
+ mask <<= 8;
+ }
+ mask ^= 0xffffffff;
+ for (i=0; i<cnt; i++) {
+ *p &= mask;
+ *p++ |= val;
+ if (p > bcs->hw.tiger.s_end)
+ p = bcs->hw.tiger.send;
+ }
+}
+
+void
+mode_tiger(struct BCState *bcs, int mode, int bc)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ char tmp[64];
+
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "Tiger mode %d bchan %d/%d",
+ mode, bc, bcs->channel);
+ debugl1(cs, tmp);
+ }
+ bcs->mode = mode;
+ bcs->channel = bc;
+ switch (mode) {
+ case (L1_MODE_NULL):
+ fill_mem(bcs, bcs->hw.tiger.send,
+ NETJET_DMA_SIZE, bc, 0xff);
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "Tiger stat rec %d/%d send %d",
+ bcs->hw.tiger.r_tot, bcs->hw.tiger.r_err,
+ bcs->hw.tiger.s_tot);
+ debugl1(cs, tmp);
+ }
+ if ((cs->bcs[0].mode == L1_MODE_NULL) &&
+ (cs->bcs[1].mode == L1_MODE_NULL)) {
+ cs->hw.njet.dmactrl = 0;
+ byteout(cs->hw.njet.base + NETJET_DMACTRL,
+ cs->hw.njet.dmactrl);
+ byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
+ }
+ break;
+ case (L1_MODE_TRANS):
+ break;
+ case (L1_MODE_HDLC):
+ fill_mem(bcs, bcs->hw.tiger.send,
+ NETJET_DMA_SIZE, bc, 0xff);
+ bcs->hw.tiger.r_state = HDLC_ZERO_SEARCH;
+ bcs->hw.tiger.r_tot = 0;
+ bcs->hw.tiger.r_bitcnt = 0;
+ bcs->hw.tiger.r_one = 0;
+ bcs->hw.tiger.r_err = 0;
+ bcs->hw.tiger.s_tot = 0;
+ if (! cs->hw.njet.dmactrl) {
+ fill_mem(bcs, bcs->hw.tiger.send,
+ NETJET_DMA_SIZE, !bc, 0xff);
+ cs->hw.njet.dmactrl = 1;
+ byteout(cs->hw.njet.base + NETJET_DMACTRL,
+ cs->hw.njet.dmactrl);
+ byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0x3f);
+ }
+ bcs->hw.tiger.sendp = bcs->hw.tiger.send;
+ bcs->hw.tiger.free = NETJET_DMA_SIZE;
+ test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
+ break;
+ }
+ if (cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "tiger: set %x %x %x %x/%x pulse=%d",
+ bytein(cs->hw.njet.base + NETJET_DMACTRL),
+ bytein(cs->hw.njet.base + NETJET_IRQMASK0),
+ bytein(cs->hw.njet.base + NETJET_IRQSTAT0),
+ 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));
+ debugl1(cs, tmp);
+ }
+}
+
+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;
+ int i=count,j;
+ u_char *p = buf;
+
+ t += sprintf(t, "tiger %s(%4d)", s, count);
+ while (i>0) {
+ if (i>16)
+ j=16;
+ else
+ j=i;
+ QuickHex(t, p, j);
+ debugl1(cs, tmp);
+ p += j;
+ i -= j;
+ t = tmp;
+ t += sprintf(t, "tiger %s ", s);
+ }
+}
+
+#define MAKE_RAW_BYTE for (j=0; j<8; j++) { \
+ bitcnt++;\
+ s_val >>= 1;\
+ if (val & 1) {\
+ s_one++;\
+ s_val |= 0x80;\
+ } else {\
+ s_one = 0;\
+ s_val &= 0x7f;\
+ }\
+ if (bitcnt==8) {\
+ bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\
+ bitcnt = 0;\
+ }\
+ if (s_one == 5) {\
+ s_val >>= 1;\
+ s_val &= 0x7f;\
+ bitcnt++;\
+ s_one = 0;\
+ }\
+ if (bitcnt==8) {\
+ bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\
+ bitcnt = 0;\
+ }\
+ val >>= 1;\
+ }
+
+static void make_raw_data(struct BCState *bcs) {
+ register u_int i,s_cnt=0;
+ register u_char j;
+ register u_char val;
+ register u_char s_one = 0;
+ register u_char s_val = 0;
+ register u_char bitcnt = 0;
+ u_int fcs;
+ char tmp[64];
+
+
+ bcs->hw.tiger.sendbuf[s_cnt++] = HDLC_FLAG_VALUE;
+ fcs = PPP_INITFCS;
+ for (i=0; i<bcs->hw.tiger.tx_skb->len; i++) {
+ val = bcs->hw.tiger.tx_skb->data[i];
+ fcs = PPP_FCS (fcs, val);
+ MAKE_RAW_BYTE;
+ }
+ fcs ^= 0xffff;
+ val = fcs & 0xff;
+ MAKE_RAW_BYTE;
+ val = (fcs>>8) & 0xff;
+ MAKE_RAW_BYTE;
+ val = HDLC_FLAG_VALUE;
+ for (j=0; j<8; j++) {
+ bitcnt++;
+ s_val >>= 1;
+ if (val & 1)
+ s_val |= 0x80;
+ else
+ s_val &= 0x7f;
+ if (bitcnt==8) {
+ bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
+ bitcnt = 0;
+ }
+ val >>= 1;
+ }
+ if (bcs->cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp,"tiger make_raw: in %d out %d.%d",
+ bcs->hw.tiger.tx_skb->len, s_cnt, bitcnt);
+ debugl1(bcs->cs,tmp);
+ }
+ if (bitcnt) {
+ while (8>bitcnt++) {
+ s_val >>= 1;
+ s_val |= 0x80;
+ }
+ bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
+ }
+ bcs->hw.tiger.sendcnt = s_cnt;
+ bcs->tx_cnt -= bcs->hw.tiger.tx_skb->len;
+ bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf;
+}
+
+static void got_frame(struct BCState *bcs, int count) {
+ struct sk_buff *skb;
+
+ if (!(skb = dev_alloc_skb(count)))
+ printk(KERN_WARNING "TIGER: receive out of memory\n");
+ else {
+ memcpy(skb_put(skb, count), bcs->hw.tiger.rcvbuf, count);
+ skb_queue_tail(&bcs->rqueue, skb);
+ }
+ bcs->event |= 1 << B_RCVBUFREADY;
+ queue_task(&bcs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+
+ if (bcs->cs->debug & L1_DEB_RECEIVE_FRAME)
+ printframe(bcs->cs, bcs->hw.tiger.rcvbuf, count, "rec");
+}
+
+
+
+static void read_raw(struct BCState *bcs, u_int *buf, int cnt){
+ int i;
+ register u_char j;
+ register u_char val;
+ u_int *pend = bcs->hw.tiger.rec +NETJET_DMA_SIZE -1;
+ register u_char state = bcs->hw.tiger.r_state;
+ register u_char r_one = bcs->hw.tiger.r_one;
+ register u_char r_val = bcs->hw.tiger.r_val;
+ register u_int bitcnt = bcs->hw.tiger.r_bitcnt;
+ u_int *p = buf;
+ char tmp[64];
+
+ for (i=0;i<cnt;i++) {
+ val = bcs->channel ? ((*p>>8) & 0xff) : (*p & 0xff);
+ p++;
+ if (p > pend)
+ p = bcs->hw.tiger.rec;
+ if (val == 0xff) {
+ state = HDLC_ZERO_SEARCH;
+ bcs->hw.tiger.r_tot++;
+ bitcnt = 0;
+ r_one = 0;
+ continue;
+ }
+ for (j=0;j<8;j++) {
+ if (state == HDLC_ZERO_SEARCH) {
+ if (val & 1) {
+ r_one++;
+ } else {
+ r_one=0;
+ state= HDLC_FLAG_SEARCH;
+ if (bcs->cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp,"tiger read_raw: zBit(%d,%d,%d) %x",
+ bcs->hw.tiger.r_tot,i,j,val);
+ debugl1(bcs->cs,tmp);
+ }
+ }
+ } else if (state == HDLC_FLAG_SEARCH) {
+ if (val & 1) {
+ r_one++;
+ if (r_one>6) {
+ state=HDLC_ZERO_SEARCH;
+ }
+ } else {
+ if (r_one==6) {
+ bitcnt=0;
+ r_val=0;
+ state=HDLC_FLAG_FOUND;
+ if (bcs->cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp,"tiger read_raw: flag(%d,%d,%d) %x",
+ bcs->hw.tiger.r_tot,i,j,val);
+ debugl1(bcs->cs,tmp);
+ }
+ }
+ r_one=0;
+ }
+ } else if (state == HDLC_FLAG_FOUND) {
+ if (val & 1) {
+ r_one++;
+ if (r_one>6) {
+ state=HDLC_ZERO_SEARCH;
+ } else {
+ r_val >>= 1;
+ r_val |= 0x80;
+ bitcnt++;
+ }
+ } else {
+ if (r_one==6) {
+ bitcnt=0;
+ r_val=0;
+ r_one=0;
+ val >>= 1;
+ continue;
+ } else if (r_one!=5) {
+ r_val >>= 1;
+ r_val &= 0x7f;
+ bitcnt++;
+ }
+ r_one=0;
+ }
+ if ((state != HDLC_ZERO_SEARCH) &&
+ !(bitcnt & 7)) {
+ state=HDLC_FRAME_FOUND;
+ bcs->hw.tiger.r_fcs = PPP_INITFCS;
+ bcs->hw.tiger.rcvbuf[0] = r_val;
+ bcs->hw.tiger.r_fcs = PPP_FCS (bcs->hw.tiger.r_fcs, r_val);
+ if (bcs->cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp,"tiger read_raw: byte1(%d,%d,%d) rval %x val %x i %x",
+ bcs->hw.tiger.r_tot,i,j,r_val,val,
+ bcs->cs->hw.njet.irqstat0);
+ debugl1(bcs->cs,tmp);
+ }
+ }
+ } else if (state == HDLC_FRAME_FOUND) {
+ if (val & 1) {
+ r_one++;
+ if (r_one>6) {
+ state=HDLC_ZERO_SEARCH;
+ bitcnt=0;
+ } else {
+ r_val >>= 1;
+ r_val |= 0x80;
+ bitcnt++;
+ }
+ } else {
+ if (r_one==6) {
+ r_val=0;
+ r_one=0;
+ bitcnt++;
+ if (bitcnt & 7) {
+ debugl1(bcs->cs, "tiger: frame not byte aligned");
+ state=HDLC_FLAG_SEARCH;
+ bcs->hw.tiger.r_err++;
+ } else {
+ if (bcs->cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp,"tiger frame end(%d,%d): fcs(%x) i %x",
+ i,j,bcs->hw.tiger.r_fcs, bcs->cs->hw.njet.irqstat0);
+ debugl1(bcs->cs, tmp);
+ }
+ if (bcs->hw.tiger.r_fcs == PPP_GOODFCS) {
+ got_frame(bcs, (bitcnt>>3)-3);
+ } else
+ if (bcs->cs->debug) {
+ debugl1(bcs->cs, "tiger FCS error");
+ printframe(bcs->cs, bcs->hw.tiger.rcvbuf,
+ (bitcnt>>3)-1, "rec");
+ bcs->hw.tiger.r_err++;
+ }
+ state=HDLC_FLAG_FOUND;
+ }
+ bitcnt=0;
+ } else if (r_one==5) {
+ val >>= 1;
+ r_one=0;
+ continue;
+ } else {
+ r_val >>= 1;
+ r_val &= 0x7f;
+ bitcnt++;
+ }
+ r_one=0;
+ }
+ if ((state == HDLC_FRAME_FOUND) &&
+ !(bitcnt & 7)) {
+ if ((bitcnt>>3)>=HSCX_BUFMAX) {
+ debugl1(bcs->cs, "tiger: frame to big");
+ r_val=0;
+ state=HDLC_FLAG_SEARCH;
+ bcs->hw.tiger.r_err++;
+ } else {
+ bcs->hw.tiger.rcvbuf[(bitcnt>>3)-1] = r_val;
+ bcs->hw.tiger.r_fcs =
+ PPP_FCS (bcs->hw.tiger.r_fcs, r_val);
+ }
+ }
+ }
+ val >>= 1;
+ }
+ bcs->hw.tiger.r_tot++;
+ }
+ bcs->hw.tiger.r_state = state;
+ bcs->hw.tiger.r_one = r_one;
+ bcs->hw.tiger.r_val = r_val;
+ bcs->hw.tiger.r_bitcnt = bitcnt;
+}
+
+static void read_tiger(struct IsdnCardState *cs) {
+ u_int *p;
+ int cnt = NETJET_DMA_SIZE/2;
+
+ if (cs->hw.njet.irqstat0 & 4)
+ p = cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE - 1;
+ else
+ p = cs->bcs[0].hw.tiger.rec + cnt - 1;
+ if (cs->bcs[0].mode == L1_MODE_HDLC)
+ read_raw(cs->bcs, p, cnt);
+ if (cs->bcs[1].mode == L1_MODE_HDLC)
+ read_raw(cs->bcs + 1, p, cnt);
+ cs->hw.njet.irqstat0 &= 0xf3;
+}
+
+static void write_raw(struct BCState *bcs, u_int *buf, int cnt);
+
+static void fill_dma(struct BCState *bcs)
+{
+ char tmp[64];
+ register u_int *p, *sp;
+ register int cnt;
+
+ if (!bcs->hw.tiger.tx_skb)
+ return;
+ if (bcs->cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp,"tiger fill_dma1: c%d %4x", bcs->channel,
+ bcs->Flag);
+ debugl1(bcs->cs,tmp);
+ }
+ if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag))
+ return;
+ make_raw_data(bcs);
+ if (bcs->cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp,"tiger fill_dma2: c%d %4x", bcs->channel,
+ bcs->Flag);
+ debugl1(bcs->cs,tmp);
+ }
+ if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
+ write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free);
+ } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) {
+ p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR));
+ sp = bcs->hw.tiger.sendp;
+ if (p == bcs->hw.tiger.s_end)
+ p = bcs->hw.tiger.send -1;
+ if (sp == bcs->hw.tiger.s_end)
+ sp = bcs->hw.tiger.send -1;
+ cnt = p - sp;
+ if (cnt <0) {
+ write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free);
+ } else {
+ p++;
+ cnt++;
+ if (p > bcs->hw.tiger.s_end)
+ p = bcs->hw.tiger.send;
+ p++;
+ cnt++;
+ if (p > bcs->hw.tiger.s_end)
+ p = bcs->hw.tiger.send;
+ write_raw(bcs, p, bcs->hw.tiger.free - cnt);
+ }
+ } else if (test_and_clear_bit(BC_FLG_EMPTY, &bcs->Flag)) {
+ p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR));
+ cnt = bcs->hw.tiger.s_end - p;
+ if (cnt < 2) {
+ p = bcs->hw.tiger.send + 1;
+ cnt = NETJET_DMA_SIZE/2 - 2;
+ } else {
+ p++;
+ p++;
+ if (cnt <= (NETJET_DMA_SIZE/2))
+ cnt += NETJET_DMA_SIZE/2;
+ cnt--;
+ cnt--;
+ }
+ write_raw(bcs, p, cnt);
+ }
+ if (bcs->cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp,"tiger fill_dma3: c%d %4x", bcs->channel,
+ bcs->Flag);
+ debugl1(bcs->cs,tmp);
+ }
+}
+
+static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
+ u_int mask, val, *p=buf;
+ u_int i, s_cnt;
+ char tmp[64];
+
+ if (cnt <= 0)
+ return;
+ if (test_bit(BC_FLG_BUSY, &bcs->Flag)) {
+ if (bcs->hw.tiger.sendcnt> cnt) {
+ s_cnt = cnt;
+ bcs->hw.tiger.sendcnt -= cnt;
+ } else {
+ s_cnt = bcs->hw.tiger.sendcnt;
+ bcs->hw.tiger.sendcnt = 0;
+ }
+ if (bcs->channel)
+ mask = 0xffff00ff;
+ else
+ mask = 0xffffff00;
+ for (i=0; i<s_cnt; i++) {
+ val = bcs->channel ? ((bcs->hw.tiger.sp[i] <<8) & 0xff00) :
+ (bcs->hw.tiger.sp[i]);
+ *p &= mask;
+ *p++ |= val;
+ if (p>bcs->hw.tiger.s_end)
+ p = bcs->hw.tiger.send;
+ }
+ bcs->hw.tiger.s_tot += s_cnt;
+ if (bcs->cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp,"tiger write_raw: c%d %x-%x %d/%d %d %x", bcs->channel,
+ (u_int)buf, (u_int)p, s_cnt, cnt, bcs->hw.tiger.sendcnt,
+ bcs->cs->hw.njet.irqstat0);
+ debugl1(bcs->cs,tmp);
+ }
+ if (bcs->cs->debug & L1_DEB_HSCX_FIFO)
+ printframe(bcs->cs, bcs->hw.tiger.sp, s_cnt, "snd");
+ bcs->hw.tiger.sp += s_cnt;
+ bcs->hw.tiger.sendp = p;
+ if (!bcs->hw.tiger.sendcnt) {
+ if (!bcs->hw.tiger.tx_skb) {
+ sprintf(tmp,"tiger write_raw: NULL skb s_cnt %d", s_cnt);
+ debugl1(bcs->cs, tmp);
+ } else {
+ if (bcs->st->lli.l1writewakeup &&
+ (PACKET_NOACK != bcs->hw.tiger.tx_skb->pkt_type))
+ bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.tiger.tx_skb->len);
+ dev_kfree_skb(bcs->hw.tiger.tx_skb);
+ bcs->hw.tiger.tx_skb = NULL;
+ }
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ bcs->hw.tiger.free = cnt - s_cnt;
+ if (bcs->hw.tiger.free > (NETJET_DMA_SIZE/2))
+ test_and_set_bit(BC_FLG_HALF, &bcs->Flag);
+ else {
+ test_and_clear_bit(BC_FLG_HALF, &bcs->Flag);
+ test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag);
+ }
+ if ((bcs->hw.tiger.tx_skb = skb_dequeue(&bcs->squeue))) {
+ fill_dma(bcs);
+ } else {
+ mask ^= 0xffffffff;
+ if (s_cnt < cnt) {
+ for (i=s_cnt; i<cnt;i++) {
+ *p++ |= mask;
+ if (p>bcs->hw.tiger.s_end)
+ p = bcs->hw.tiger.send;
+ }
+ if (bcs->cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "tiger write_raw: fill rest %d",
+ cnt - s_cnt);
+ debugl1(bcs->cs,tmp);
+ }
+ }
+ bcs->event |= 1 << B_XMTBUFREADY;
+ queue_task(&bcs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ }
+ } else if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
+ test_and_set_bit(BC_FLG_HALF, &bcs->Flag);
+ fill_mem(bcs, buf, cnt, bcs->channel, 0xff);
+ bcs->hw.tiger.free += cnt;
+ if (bcs->cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp,"tiger write_raw: fill half");
+ debugl1(bcs->cs,tmp);
+ }
+ } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) {
+ test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
+ fill_mem(bcs, buf, cnt, bcs->channel, 0xff);
+ if (bcs->cs->debug & L1_DEB_HSCX) {
+ sprintf(tmp,"tiger write_raw: fill full");
+ debugl1(bcs->cs,tmp);
+ }
+ }
+}
+
+static void write_tiger(struct IsdnCardState *cs) {
+ u_int *p, cnt = NETJET_DMA_SIZE/2;
+
+ if (cs->hw.njet.irqstat0 & 1)
+ p = cs->bcs[0].hw.tiger.send + NETJET_DMA_SIZE - 1;
+ else
+ p = cs->bcs[0].hw.tiger.send + cnt - 1;
+ if (cs->bcs[0].mode == L1_MODE_HDLC)
+ write_raw(cs->bcs, p, cnt);
+ if (cs->bcs[1].mode == L1_MODE_HDLC)
+ write_raw(cs->bcs + 1, p, cnt);
+ cs->hw.njet.irqstat0 &= 0xfc;
+}
+
+static void
+tiger_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ long flags;
+
+ switch (pr) {
+ case (PH_DATA_REQ):
+ save_flags(flags);
+ cli();
+ if (st->l1.bcs->hw.tiger.tx_skb) {
+ skb_queue_tail(&st->l1.bcs->squeue, skb);
+ restore_flags(flags);
+ } else {
+ st->l1.bcs->hw.tiger.tx_skb = skb;
+ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+ restore_flags(flags);
+ }
+ break;
+ case (PH_PULL_IND):
+ if (st->l1.bcs->hw.tiger.tx_skb) {
+ printk(KERN_WARNING "tiger_l2l1: this shouldn't happen\n");
+ break;
+ }
+ save_flags(flags);
+ cli();
+ st->l1.bcs->hw.tiger.tx_skb = skb;
+ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+ restore_flags(flags);
+ break;
+ case (PH_PULL_REQ):
+ if (!st->l1.bcs->hw.tiger.tx_skb) {
+ test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ st->l1.l1l2(st, PH_PULL_CNF, NULL);
+ } else
+ test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ }
+}
+
+void
+close_tigerstate(struct BCState *bcs)
+{
+ struct sk_buff *skb;
+
+ mode_tiger(bcs, 0, 0);
+ if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+ if (bcs->hw.tiger.rcvbuf) {
+ kfree(bcs->hw.tiger.rcvbuf);
+ bcs->hw.tiger.rcvbuf = NULL;
+ }
+ if (bcs->hw.tiger.sendbuf) {
+ kfree(bcs->hw.tiger.sendbuf);
+ bcs->hw.tiger.sendbuf = NULL;
+ }
+ while ((skb = skb_dequeue(&bcs->rqueue))) {
+ dev_kfree_skb(skb);
+ }
+ while ((skb = skb_dequeue(&bcs->squeue))) {
+ dev_kfree_skb(skb);
+ }
+ if (bcs->hw.tiger.tx_skb) {
+ dev_kfree_skb(bcs->hw.tiger.tx_skb);
+ bcs->hw.tiger.tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ }
+ }
+}
+
+static int
+open_tigerstate(struct IsdnCardState *cs, int bc)
+{
+ struct BCState *bcs = cs->bcs + bc;
+
+ if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+ if (!(bcs->hw.tiger.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_KERNEL))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for tiger.rcvbuf\n");
+ return (1);
+ }
+ if (!(bcs->hw.tiger.sendbuf = kmalloc(RAW_BUFMAX, GFP_KERNEL))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for tiger.sendbuf\n");
+ return (1);
+ }
+ skb_queue_head_init(&bcs->rqueue);
+ skb_queue_head_init(&bcs->squeue);
+ }
+ bcs->hw.tiger.tx_skb = NULL;
+ bcs->hw.tiger.sendcnt = 0;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ bcs->event = 0;
+ bcs->tx_cnt = 0;
+ return (0);
+}
+
+static void
+tiger_manl1(struct PStack *st, int pr,
+ void *arg)
+{
+ switch (pr) {
+ case (PH_ACTIVATE_REQ):
+ test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc);
+ st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
+ break;
+ case (PH_DEACTIVATE_REQ):
+ if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
+ mode_tiger(st->l1.bcs, 0, 0);
+ test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ break;
+ }
+}
+
+int
+setstack_tiger(struct PStack *st, struct BCState *bcs)
+{
+ if (open_tigerstate(st->l1.hardware, bcs->channel))
+ return (-1);
+ st->l1.bcs = bcs;
+ st->l2.l2l1 = tiger_l2l1;
+ st->ma.manl1 = tiger_manl1;
+ setstack_manager(st);
+ bcs->st = st;
+ return (0);
+}
+
+
+__initfunc(void
+inittiger(struct IsdnCardState *cs))
+{
+ char tmp[128];
+
+ if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_SIZE * sizeof(unsigned int),
+ GFP_KERNEL | GFP_DMA))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for tiger.send\n");
+ return;
+ }
+ cs->bcs[0].hw.tiger.s_irq = cs->bcs[0].hw.tiger.send + NETJET_DMA_SIZE/2 - 1;
+ cs->bcs[0].hw.tiger.s_end = cs->bcs[0].hw.tiger.send + NETJET_DMA_SIZE - 1;
+ cs->bcs[1].hw.tiger.send = cs->bcs[0].hw.tiger.send;
+ cs->bcs[1].hw.tiger.s_irq = cs->bcs[0].hw.tiger.s_irq;
+ cs->bcs[1].hw.tiger.s_end = cs->bcs[0].hw.tiger.s_end;
+
+ memset(cs->bcs[0].hw.tiger.send, 0xff, NETJET_DMA_SIZE * sizeof(unsigned int));
+ sprintf(tmp, "tiger: send buf %x - %x", (u_int)cs->bcs[0].hw.tiger.send,
+ (u_int)(cs->bcs[0].hw.tiger.send + NETJET_DMA_SIZE - 1));
+ debugl1(cs, tmp);
+ outl(virt_to_bus(cs->bcs[0].hw.tiger.send),
+ cs->hw.njet.base + NETJET_DMA_READ_START);
+ outl(virt_to_bus(cs->bcs[0].hw.tiger.s_irq),
+ cs->hw.njet.base + NETJET_DMA_READ_IRQ);
+ outl(virt_to_bus(cs->bcs[0].hw.tiger.s_end),
+ cs->hw.njet.base + NETJET_DMA_READ_END);
+ if (!(cs->bcs[0].hw.tiger.rec = kmalloc(NETJET_DMA_SIZE * sizeof(unsigned int),
+ GFP_KERNEL | GFP_DMA))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for tiger.rec\n");
+ return;
+ }
+ sprintf(tmp, "tiger: rec buf %x - %x", (u_int)cs->bcs[0].hw.tiger.rec,
+ (u_int)(cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE - 1));
+ debugl1(cs, tmp);
+ cs->bcs[1].hw.tiger.rec = cs->bcs[0].hw.tiger.rec;
+ memset(cs->bcs[0].hw.tiger.rec, 0xff, NETJET_DMA_SIZE * sizeof(unsigned int));
+ outl(virt_to_bus(cs->bcs[0].hw.tiger.rec),
+ cs->hw.njet.base + NETJET_DMA_WRITE_START);
+ outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE/2 - 1),
+ cs->hw.njet.base + NETJET_DMA_WRITE_IRQ);
+ outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE - 1),
+ cs->hw.njet.base + NETJET_DMA_WRITE_END);
+ sprintf(tmp, "tiger: dmacfg %x/%x pulse=%d",
+ inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
+ inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
+ bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
+ debugl1(cs, tmp);
+ cs->hw.njet.last_is0 = 0;
+ cs->bcs[0].BC_SetStack = setstack_tiger;
+ cs->bcs[1].BC_SetStack = setstack_tiger;
+ cs->bcs[0].BC_Close = close_tigerstate;
+ cs->bcs[1].BC_Close = close_tigerstate;
+}
+
+void
+releasetiger(struct IsdnCardState *cs)
+{
+ if (cs->bcs[0].hw.tiger.send) {
+ kfree(cs->bcs[0].hw.tiger.send);
+ cs->bcs[0].hw.tiger.send = NULL;
+ }
+ if (cs->bcs[1].hw.tiger.send) {
+ cs->bcs[1].hw.tiger.send = NULL;
+ }
+ if (cs->bcs[0].hw.tiger.rec) {
+ kfree(cs->bcs[0].hw.tiger.rec);
+ cs->bcs[0].hw.tiger.rec = NULL;
+ }
+ if (cs->bcs[1].hw.tiger.rec) {
+ cs->bcs[1].hw.tiger.rec = NULL;
+ }
+}
+
+static void
+netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val, sval, stat = 1;
+ char tmp[128];
+
+ 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) {
+ sprintf(tmp, "tiger: i1 %x %x", sval, val);
+ debugl1(cs, tmp);
+ }
+ if (val) {
+ isac_interrupt(cs, val);
+ stat |= 2;
+ }
+ }
+ if ((cs->hw.njet.irqstat0 = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) {
+/* sprintf(tmp, "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));
+ debugl1(cs, tmp);
+*/
+ if (cs->hw.njet.last_is0 & cs->hw.njet.irqstat0 & 0xf) {
+ sprintf(tmp, "tiger: ist0 %x->%x irq lost",
+ cs->hw.njet.last_is0, cs->hw.njet.irqstat0);
+ debugl1(cs, tmp);
+ }
+ cs->hw.njet.last_is0 = cs->hw.njet.irqstat0;
+/* 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 & 0x0c)
+ read_tiger(cs);
+ if (cs->hw.njet.irqstat0 & 0x03)
+ write_tiger(cs);
+ }
+/* 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);
+ }
+*/ if (stat & 2) {
+ WriteISAC(cs, ISAC_MASK, 0xFF);
+ WriteISAC(cs, ISAC_MASK, 0x0);
+ }
+}
+
+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);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */
+ schedule();
+ cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
+ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */
+ schedule();
+ 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)
+{
+ byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
+ byteout(cs->hw.njet.base + NETJET_IRQMASK1, 0);
+ releasetiger(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_SETIRQ:
+ return(request_irq(cs->irq, &netjet_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs));
+ case CARD_INIT:
+ inittiger(cs);
+ clear_pending_isac_ints(cs);
+ initisac(cs);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
+}
+
+
+
+static int pci_index __initdata = 0;
+
+__initfunc(int
+setup_netjet(struct IsdnCard *card))
+{
+ int bytecnt;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+#if CONFIG_PCI
+ u_char pci_bus, pci_device_fn, pci_irq;
+ u_int pci_ioaddr, found;
+#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);
+#if CONFIG_PCI
+ found = 0;
+ for (; pci_index < 0xff; pci_index++) {
+ if (pcibios_find_device(PCI_VENDOR_TRAVERSE_TECH,
+ PCI_NETJET_ID, pci_index, &pci_bus, &pci_device_fn)
+ == PCIBIOS_SUCCESSFUL)
+ found = 1;
+ else
+ break;
+ /* get IRQ */
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq);
+
+ /* get IO address */
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ if (found)
+ break;
+ }
+ if (!found) {
+ printk(KERN_WARNING "NETjet: No PCI card found\n");
+ return(0);
+ }
+ if (!pci_irq) {
+ printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n");
+ return(0);
+ }
+ if (!pci_ioaddr) {
+ printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ pci_ioaddr &= ~3; /* remove io/mem flag */
+ cs->hw.njet.base = pci_ioaddr;
+ cs->hw.njet.auxa = pci_ioaddr + NETJET_AUXDATA;
+ cs->hw.njet.isac = pci_ioaddr | NETJET_ISAC_OFF;
+ cs->irq = pci_irq;
+ 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;
+ ISACVersion(cs, "NETjet:");
+ return (1);
+}
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
new file mode 100644
index 000000000..59a8a94e3
--- /dev/null
+++ b/drivers/isdn/hisax/niccy.c
@@ -0,0 +1,354 @@
+/* $Id: niccy.c,v 1.2 1998/02/11 17:31:04 keil Exp $
+
+ * niccy.c low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
+ * compatible (SAGEM cybermodem)
+ *
+ * Author Karsten Keil
+ *
+ * Thanks to Dr. Neuhaus and SAGEM for informations
+ *
+ * $Log: niccy.c,v $
+ * Revision 1.2 1998/02/11 17:31:04 keil
+ * new file
+ *
+ *
+ *
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+#include <linux/pci.h>
+#include <linux/bios32.h>
+
+extern const char *CardType[];
+const char *niccy_revision = "$Revision: 1.2 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define ISAC_PCI_DATA 0
+#define HSCX_PCI_DATA 1
+#define ISAC_PCI_ADDR 2
+#define HSCX_PCI_ADDR 3
+#define ISAC_PNP 0
+#define HSCX_PNP 1
+
+/* SUB Types */
+#define NICCY_PNP 1
+#define NICCY_PCI 2
+
+/* PCI stuff */
+#define PCI_VENDOR_DR_NEUHAUS 0x1267
+#define PCI_NICCY_ID 0x1016
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+ register u_char ret;
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(ale, off);
+ ret = bytein(adr);
+ restore_flags(flags);
+ return (ret);
+}
+
+static inline void
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+ /* fifo read without cli because it's allready done */
+
+ byteout(ale, off);
+ insb(adr, data, size);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(ale, off);
+ byteout(adr, data);
+ restore_flags(flags);
+}
+
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+ /* fifo write without cli because it's allready done */
+ byteout(ale, off);
+ outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+ return (readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+ return (readreg(cs->hw.niccy.hscx_ale,
+ cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+ writereg(cs->hw.niccy.hscx_ale,
+ cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value);
+}
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.niccy.hscx_ale, \
+ cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.niccy.hscx_ale, \
+ cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0), data)
+
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.niccy.hscx_ale, \
+ cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.niccy.hscx_ale, \
+ cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val, stat = 0;
+
+ if (!cs) {
+ printk(KERN_WARNING "Niccy: Spurious interrupt!\n");
+ return;
+ }
+ val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
+ Start_HSCX:
+ if (val) {
+ hscx_int_main(cs, val);
+ stat |= 1;
+ }
+ val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
+ Start_ISAC:
+ if (val) {
+ isac_interrupt(cs, val);
+ stat |= 2;
+ }
+ val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
+ if (val) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX IntStat after IntRoutine");
+ goto Start_HSCX;
+ }
+ val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
+ if (val) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ISAC IntStat after IntRoutine");
+ goto Start_ISAC;
+ }
+ if (stat & 1) {
+ writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF);
+ writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0xFF);
+ writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0);
+ writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0);
+ }
+ if (stat & 2) {
+ writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0);
+ }
+}
+
+void
+release_io_niccy(struct IsdnCardState *cs)
+{
+ if (cs->subtyp == NICCY_PCI)
+ release_region(cs->hw.niccy.isac, 4);
+ else {
+ release_region(cs->hw.niccy.isac, 2);
+ release_region(cs->hw.niccy.isac_ale, 2);
+ }
+}
+
+static void
+niccy_reset(struct IsdnCardState *cs)
+{
+ // No reset procedure known
+}
+
+static int
+niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ niccy_reset(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_niccy(cs);
+ return(0);
+ case CARD_SETIRQ:
+ return(request_irq(cs->irq, &niccy_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs));
+ case CARD_INIT:
+ clear_pending_isac_ints(cs);
+ clear_pending_hscx_ints(cs);
+ initisac(cs);
+ inithscx(cs);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
+}
+
+static int pci_index __initdata = 0;
+
+__initfunc(int
+setup_niccy(struct IsdnCard *card))
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, niccy_revision);
+ printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_NICCY)
+ return (0);
+
+ if (card->para[1]) {
+ cs->hw.niccy.isac = card->para[1] + ISAC_PNP;
+ cs->hw.niccy.hscx = card->para[1] + HSCX_PNP;
+ cs->hw.niccy.isac_ale = card->para[2] + ISAC_PNP;
+ cs->hw.niccy.hscx_ale = card->para[2] + HSCX_PNP;
+ cs->hw.niccy.cfg_reg = 0;
+ cs->subtyp = NICCY_PNP;
+ cs->irq = card->para[0];
+ if (check_region((cs->hw.niccy.isac), 2)) {
+ printk(KERN_WARNING
+ "HiSax: %s data port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.niccy.isac,
+ cs->hw.niccy.isac + 1);
+ return (0);
+ } else
+ request_region(cs->hw.niccy.isac, 2, "niccy data");
+ if (check_region((cs->hw.niccy.isac_ale), 2)) {
+ printk(KERN_WARNING
+ "HiSax: %s address port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.niccy.isac_ale,
+ cs->hw.niccy.isac_ale + 1);
+ release_region(cs->hw.niccy.isac, 2);
+ return (0);
+ } else
+ request_region(cs->hw.niccy.isac_ale, 2, "niccy addr");
+ } else {
+#if CONFIG_PCI
+ u_char pci_bus, pci_device_fn, pci_irq;
+ u_int pci_ioaddr;
+
+ cs->subtyp = 0;
+ for (; pci_index < 0xff; pci_index++) {
+ if (pcibios_find_device(PCI_VENDOR_DR_NEUHAUS,
+ PCI_NICCY_ID, pci_index, &pci_bus, &pci_device_fn)
+ == PCIBIOS_SUCCESSFUL)
+ cs->subtyp = NICCY_PCI;
+ else
+ break;
+ /* get IRQ */
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq);
+
+ /* get IO address */
+ /* if it won't work try the other PCI addresses
+ * PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_5
+ */
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_2, &pci_ioaddr);
+ if (cs->subtyp)
+ break;
+ }
+ if (!cs->subtyp) {
+ printk(KERN_WARNING "Niccy: No PCI card found\n");
+ return(0);
+ }
+ if (!pci_irq) {
+ printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
+ return(0);
+ }
+
+ if (!pci_ioaddr) {
+ printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ pci_ioaddr &= ~3; /* remove io/mem flag */
+ cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
+ cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR;
+ cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA;
+ cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR;
+ cs->irq = pci_irq;
+ if (check_region((cs->hw.niccy.isac), 4)) {
+ printk(KERN_WARNING
+ "HiSax: %s data port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.niccy.isac,
+ cs->hw.niccy.isac + 4);
+ return (0);
+ } else
+ request_region(cs->hw.niccy.isac, 4, "niccy");
+#else
+ printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n");
+ printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n");
+ return (0);
+#endif /* CONFIG_PCI */
+ }
+ printk(KERN_INFO
+ "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n",
+ CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI",
+ cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale);
+ niccy_reset(cs);
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ cs->BC_Read_Reg = &ReadHSCX;
+ cs->BC_Write_Reg = &WriteHSCX;
+ cs->BC_Send_Data = &hscx_fill_fifo;
+ cs->cardmsg = &niccy_card_msg;
+ ISACVersion(cs, "Niccy:");
+ if (HscxVersion(cs, "Niccy:")) {
+ printk(KERN_WARNING
+ "Niccy: wrong HSCX versions check IO address\n");
+ release_io_niccy(cs);
+ return (0);
+ }
+ return (1);
+}
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
index 1e1ee4772..a0ba3645a 100644
--- a/drivers/isdn/hisax/q931.c
+++ b/drivers/isdn/hisax/q931.c
@@ -1,4 +1,4 @@
-/* $Id: q931.c,v 1.5 1997/04/06 22:56:43 keil Exp $
+/* $Id: q931.c,v 1.6 1997/07/27 21:09:44 keil Exp $
* q931.c code to decode ITU Q.931 call control messages
*
@@ -14,6 +14,9 @@
*
*
* $Log: q931.c,v $
+ * Revision 1.6 1997/07/27 21:09:44 keil
+ * move functions to isdnl3.c
+ *
* Revision 1.5 1997/04/06 22:56:43 keil
* Some cosmetic changes
*
@@ -37,44 +40,6 @@
#include "hisax.h"
#include "l3_1tr6.h"
-u_char *
-findie(u_char * p, int size, u_char ie, int wanted_set)
-{
- int l, codeset, maincodeset;
- u_char *pend = p + size;
-
- /* skip protocol discriminator, callref and message type */
- p++;
- l = (*p++) & 0xf;
- p += l;
- p++;
- codeset = 0;
- maincodeset = 0;
- /* while there are bytes left... */
- while (p < pend) {
- if ((*p & 0xf0) == 0x90) {
- codeset = *p & 0x07;
- if (!(*p & 0x08))
- maincodeset = codeset;
- }
- if (*p & 0x80)
- p++;
- else {
- if (codeset == wanted_set) {
- if (*p == ie)
- return (p);
- if (*p > ie)
- return (NULL);
- }
- p++;
- l = *p++;
- p += l;
- codeset = maincodeset;
- }
- }
- return (NULL);
-}
-
void
iecpy(u_char * dest, u_char * iestart, int ieoffset)
{
@@ -88,14 +53,6 @@ iecpy(u_char * dest, u_char * iestart, int ieoffset)
*dest++ = '\0';
}
-int
-getcallref(u_char * p)
-{
- p++; /* prot discr */
- p++; /* callref length */
- return (*p); /* assuming one-byte callref */
-}
-
/*
* According to Table 4-2/Q.931
*/
diff --git a/drivers/isdn/hisax/rawhdlc.c b/drivers/isdn/hisax/rawhdlc.c
new file mode 100644
index 000000000..16938bc98
--- /dev/null
+++ b/drivers/isdn/hisax/rawhdlc.c
@@ -0,0 +1,539 @@
+/* $Id: rawhdlc.c,v 1.2 1998/02/09 10:53:51 keil Exp $
+
+ * rawhdlc.c support routines for cards that don't support HDLC
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Brent Baccala <baccala@FreeSoft.org>
+ *
+ *
+ * Some passive ISDN cards, such as the Traverse NETJet and the AMD 7930,
+ * don't perform HDLC encapsulation over the B channel. Drivers for
+ * such cards use support routines in this file to perform B channel HDLC.
+ *
+ * Bit-synchronous HDLC encapsulation is a means of encapsulating packets
+ * over a continuously transmitting serial communications link.
+ * It looks like this:
+ *
+ * 11111111101111110...........0111111011111111111
+ * iiiiiiiiiffffffffdddddddddddffffffffiiiiiiiiiii
+ *
+ * i = idle f = flag d = data
+ *
+ * When idle, the channel sends a continuous string of ones (mark
+ * idle; illustrated), or a continuous string of flag characters (flag
+ * idle). The beginning of a data frame is marked by a flag character
+ * (01111110), then comes the actual data, followed by another flag
+ * character, after which another frame may be sent immediately (a
+ * single flag may serve as both the end of one frame and the start of
+ * the next), or the link may return to idle. Obviously, the flag
+ * character can not appear anywhere in the data (or a false
+ * end-of-frame would occur), so the transmitter performs
+ * "bit-stuffing" - inserting a zero bit after every five one bits,
+ * irregardless of the original bit after the five ones. Byte
+ * ordering is irrelevent at this point - the data is treated as a
+ * string of bits, not bytes. Since no more than 5 ones may now occur
+ * in a row, the flag sequence, with its 6 ones, is unique.
+ *
+ * Upon reception, a zero bit that occur after 5 one bits is simply
+ * discarded. A series of 6 one bits is end-of-frame, and a series of
+ * 7 one bits is an abort. Once bit-stuffing has been corrected for,
+ * an integer number of bytes should now be present. The last two
+ * of these bytes form the Frame Check Sequence, a CRC that is verified
+ * and then discarded. Note that bit-stuffing is performed on the FCS
+ * just as if it were regular data.
+ *
+ *
+ *
+ * int make_raw_hdlc_data(u_char *src, u_int slen,
+ * u_char *dst, u_int dsize)
+ *
+ * Used for transmission. Copies slen bytes from src to dst, performing
+ * HDLC encapsulation (flag bytes, bit-stuffing, CRC) in the process.
+ * dsize is size of destination buffer, and should be at least
+ * ((6*slen)/5)+5 bytes to ensure adequate space will be available.
+ * Function returns length (in bytes) of valid destination buffer, or
+ * 0 upon destination overflow.
+ *
+ * void init_hdlc_state(struct hdlc_state *stateptr, int mode)
+ *
+ * Initializes hdlc_state structure before first call to read_raw_hdlc_data
+ *
+ * mode = 0: Sane mode
+ * mode = 1/2:
+ * Insane mode; NETJet use a shared unsigned int memory block (
+ * with busmaster DMA), the bit pattern of every word is
+ * <8 B1> <8 B2> <8 Mon> <2 D> <4 C/I> <MX> <MR>
+ * according to Siemens IOM-2 interface, so we have to handle
+ * the src buffer as unsigned int and have to shift/mask the
+ * B-channel bytes.
+ * mode 1 -> B1 mode 2 -> B2 data is used
+ *
+ * int read_raw_hdlc_data(struct hdlc_state *saved_state,
+ * u_char *src, u_int slen,
+ * u_char *dst, u_int dsize)
+ *
+ * Used for reception. Scans source buffer bit-by-bit looking for
+ * valid HDLC frames, which are copied to destination buffer. HDLC
+ * state information is stored in a structure, which allows this
+ * function to process frames spread across several blocks of raw
+ * HDLC data. Part of the state information is bit offsets into
+ * the source and destination buffers.
+ *
+ * A return value >0 indicates the length of a valid frame, now
+ * stored in the destination buffer. In this case, the source
+ * buffer might not be completely processed, so this function should
+ * be called again with the same source buffer, possibly with a
+ * different destination buffer.
+ *
+ * A return value of zero indicates that the source buffer was
+ * completely processed without finding a valid end-of-packet;
+ * however, we might be in the middle of packet reception, so
+ * the function should be called again with the next block of
+ * raw HDLC data and the same destination buffer. It is NOT
+ * permitted to change the destination buffer in this case,
+ * since data may already have begun to be stored there.
+ *
+ * A return value of -1 indicates some kind of error - destination
+ * buffer overflow, CRC check failed, frame not a multiple of 8
+ * bits. Destination buffer probably contains invalid data, which
+ * should be discarded. Call function again with same source buffer
+ * and a new (or same) destination buffer.
+ *
+ * Suggested calling sequence:
+ *
+ * init_hdlc_state(...);
+ * for (EACH_RAW_DATA_BLOCK) {
+ * while (len = read_raw_hdlc_data(...)) {
+ * if (len == -1) DISCARD_FRAME;
+ * else PROCESS_FRAME;
+ * }
+ * }
+ *
+ *
+ * Test the code in this file as follows:
+ * gcc -DDEBUGME -o rawhdlctest rawhdlc.c
+ * ./rawhdlctest < rawdata
+ *
+ * The file "rawdata" can be easily generated from a HISAX B-channel
+ * hex dump (CF CF CF 02 ...) using the following perl script:
+ *
+ * while(<>) {
+ * @hexlist = split ' ';
+ * while ($hexstr = shift(@hexlist)) {
+ * printf "%c", hex($hexstr);
+ * }
+ * }
+ *
+ */
+
+#ifdef DEBUGME
+#include <stdio.h>
+#endif
+
+#include <linux/types.h>
+#include <linux/ppp_defs.h>
+#include "rawhdlc.h"
+
+/* There's actually an identical copy of this table in the PPP code
+ * (ppp_crc16_table), but I don't want this code dependant on PPP
+ */
+
+// static
+__u16 fcstab[256] =
+{
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+#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
+
+
+#define MAKE_RAW_BYTE for (j=0; j<8; j++) { \
+ bitcnt++;\
+ out_val >>= 1;\
+ if (val & 1) {\
+ s_one++;\
+ out_val |= 0x80;\
+ } else {\
+ s_one = 0;\
+ out_val &= 0x7f;\
+ }\
+ if (bitcnt==8) {\
+ if (d_cnt == dsize) return 0;\
+ dst[d_cnt++] = out_val;\
+ bitcnt = 0;\
+ }\
+ if (s_one == 5) {\
+ out_val >>= 1;\
+ out_val &= 0x7f;\
+ bitcnt++;\
+ s_one = 0;\
+ }\
+ if (bitcnt==8) {\
+ if (d_cnt == dsize) return 0;\
+ dst[d_cnt++] = out_val;\
+ bitcnt = 0;\
+ }\
+ val >>= 1;\
+ }
+
+/* Optimization suggestion: If needed, this function could be
+ * dramatically sped up using a state machine. Each state would
+ * correspond to having seen N one bits, and being offset M bits into
+ * the current output byte. N ranges from 0 to 4, M from 0 to 7, so
+ * we need 5*8 = 35 states. Each state would have a table with 256
+ * entries, one for each input character. Each entry would contain
+ * three output characters, an output state, an a byte increment
+ * that's either 1 or 2. All this could fit in four bytes; so we need
+ * 4 bytes * 256 characters = 1 KB for each state (35 KB total). Zero
+ * the output buffer before you start. For each character in your
+ * input, you look it up in the current state's table and get three
+ * bytes to be or'ed into the output at the current byte offset, and
+ * an byte increment to move your pointer forward. A simple Perl
+ * script could generate the tables. Given HDLC semantics, probably
+ * would be better to set output to all 1s, then use ands instead of ors.
+ * A smaller state machine could operate on nibbles instead of bytes.
+ * A state machine for 32-bit architectures could use word offsets
+ * instead of byte offsets, requiring 5*32 = 160 states; probably
+ * best to work on nibbles in such a case.
+ */
+
+
+int make_raw_hdlc_data(u_char *src, u_int slen, u_char *dst, u_int dsize)
+{
+ register u_int i,d_cnt=0;
+ register u_char j;
+ register u_char val;
+ register u_char s_one = 0;
+ register u_char out_val = 0;
+ register u_char bitcnt = 0;
+ u_int fcs;
+
+
+ dst[d_cnt++] = HDLC_FLAG_VALUE;
+ fcs = PPP_INITFCS;
+ for (i=0; i<slen; i++) {
+ val = src[i];
+ fcs = PPP_FCS (fcs, val);
+ MAKE_RAW_BYTE;
+ }
+ fcs ^= 0xffff;
+ val = fcs & 0xff;
+ MAKE_RAW_BYTE;
+ val = (fcs>>8) & 0xff;
+ MAKE_RAW_BYTE;
+ val = HDLC_FLAG_VALUE;
+ for (j=0; j<8; j++) {
+ bitcnt++;
+ out_val >>= 1;
+ if (val & 1)
+ out_val |= 0x80;
+ else
+ out_val &= 0x7f;
+ if (bitcnt==8) {
+ if (d_cnt == dsize) return 0;
+ dst[d_cnt++] = out_val;
+ bitcnt = 0;
+ }
+ val >>= 1;
+ }
+ if (bitcnt) {
+ while (8>bitcnt++) {
+ out_val >>= 1;
+ out_val |= 0x80;
+ }
+ if (d_cnt == dsize) return 0;
+ dst[d_cnt++] = out_val;
+ }
+
+ return d_cnt;
+}
+
+void init_hdlc_state(struct hdlc_state *stateptr, int mode)
+{
+ stateptr->state = HDLC_ZERO_SEARCH;
+ stateptr->r_one = 0;
+ stateptr->r_val = 0;
+ stateptr->o_bitcnt = 0;
+ stateptr->i_bitcnt = 0;
+ stateptr->insane_mode = mode;
+}
+
+/* Optimization suggestion: A similar state machine could surely
+ * be developed for this function as well.
+ */
+
+int read_raw_hdlc_data(struct hdlc_state *saved_state,
+ u_char *src, u_int slen, u_char *dst, u_int dsize)
+{
+ int retval=0;
+ register u_char val;
+ register u_char state = saved_state->state;
+ register u_char r_one = saved_state->r_one;
+ register u_char r_val = saved_state->r_val;
+ register u_int o_bitcnt = saved_state->o_bitcnt;
+ register u_int i_bitcnt = saved_state->i_bitcnt;
+ register u_int fcs = saved_state->fcs;
+ register u_int *isrc = (u_int *) src;
+
+ /* Use i_bitcnt (bit offset into source buffer) to reload "val"
+ * in case we're starting up again partway through a source buffer
+ */
+
+ if ((i_bitcnt >> 3) < slen) {
+ if (saved_state->insane_mode==1) {
+ val = isrc[(i_bitcnt >> 3)] & 0xff;
+ } else if (saved_state->insane_mode==2) {
+ val = (isrc[i_bitcnt >> 3] >>8) & 0xff;
+ } else {
+ val = src[i_bitcnt >> 3];
+ }
+ val >>= i_bitcnt & 7;
+ }
+
+ /* One bit per loop. Keep going until we've got something to
+ * report (retval != 0), or we exhaust the source buffer
+ */
+
+ while ((retval == 0) && ((i_bitcnt >> 3) < slen)) {
+ if ((i_bitcnt & 7) == 0) {
+ if (saved_state->insane_mode==1) {
+ val = isrc[(i_bitcnt >> 3)] & 0xff;
+ } else if (saved_state->insane_mode==2) {
+ val = (isrc[i_bitcnt >> 3] >>8) & 0xff;
+ } else {
+ val = src[i_bitcnt >> 3];
+ }
+#ifdef DEBUGME
+ printf("Input byte %d: 0x%2x\n", i_bitcnt>>3, val);
+#endif
+ if (val == 0xff) {
+ state = HDLC_ZERO_SEARCH;
+ o_bitcnt = 0;
+ r_one = 0;
+ i_bitcnt += 8;
+ continue;
+ }
+ }
+
+#ifdef DEBUGME
+ /* printf("Data bit=%d (%d/%d)\n", val&1, i_bitcnt>>3, i_bitcnt&7);*/
+#endif
+
+ if (state == HDLC_ZERO_SEARCH) {
+ if (val & 1) {
+ r_one++;
+ } else {
+ r_one=0;
+ state= HDLC_FLAG_SEARCH;
+ }
+ } else if (state == HDLC_FLAG_SEARCH) {
+ if (val & 1) {
+ r_one++;
+ if (r_one>6) {
+ state=HDLC_ZERO_SEARCH;
+ }
+ } else {
+ if (r_one==6) {
+ o_bitcnt=0;
+ r_val=0;
+ state=HDLC_FLAG_FOUND;
+ }
+ r_one=0;
+ }
+ } else if (state == HDLC_FLAG_FOUND) {
+ if (val & 1) {
+ r_one++;
+ if (r_one>6) {
+ state=HDLC_ZERO_SEARCH;
+ } else {
+ r_val >>= 1;
+ r_val |= 0x80;
+ o_bitcnt++;
+ }
+ } else {
+ if (r_one==6) {
+ o_bitcnt=0;
+ r_val=0;
+ r_one=0;
+ i_bitcnt++;
+ val >>= 1;
+ continue;
+ } else if (r_one!=5) {
+ r_val >>= 1;
+ r_val &= 0x7f;
+ o_bitcnt++;
+ }
+ r_one=0;
+ }
+ if ((state != HDLC_ZERO_SEARCH) &&
+ !(o_bitcnt & 7)) {
+#ifdef DEBUGME
+ printf("HDLC_FRAME_FOUND at i_bitcnt:%d\n",i_bitcnt);
+#endif
+ state=HDLC_FRAME_FOUND;
+ fcs = PPP_INITFCS;
+ dst[0] = r_val;
+ fcs = PPP_FCS (fcs, r_val);
+ }
+ } else if (state == HDLC_FRAME_FOUND) {
+ if (val & 1) {
+ r_one++;
+ if (r_one>6) {
+ state=HDLC_ZERO_SEARCH;
+ o_bitcnt=0;
+ } else {
+ r_val >>= 1;
+ r_val |= 0x80;
+ o_bitcnt++;
+ }
+ } else {
+ if (r_one==6) {
+ r_val=0;
+ r_one=0;
+ o_bitcnt++;
+ if (o_bitcnt & 7) {
+ /* Alignment error */
+#ifdef DEBUGME
+ printf("Alignment error\n");
+#endif
+ state=HDLC_FLAG_SEARCH;
+ retval = -1;
+ } else if (fcs==PPP_GOODFCS) {
+ /* Valid frame */
+ state=HDLC_FLAG_FOUND;
+ retval = (o_bitcnt>>3)-3;
+ } else {
+ /* CRC error */
+#ifdef DEBUGME
+ printf("CRC error; fcs was 0x%x, should have been 0x%x\n", fcs, PPP_GOODFCS);
+#endif
+ state=HDLC_FLAG_FOUND;
+ retval = -1;
+ }
+ } else if (r_one==5) {
+ r_one=0;
+ i_bitcnt++;
+ val >>= 1;
+ continue;
+ } else {
+ r_val >>= 1;
+ r_val &= 0x7f;
+ o_bitcnt++;
+ }
+ r_one=0;
+ }
+ if ((state == HDLC_FRAME_FOUND) &&
+ !(o_bitcnt & 7)) {
+ if ((o_bitcnt>>3)>=dsize) {
+ /* Buffer overflow error */
+#ifdef DEBUGME
+ printf("Buffer overflow error\n");
+#endif
+ r_val=0;
+ state=HDLC_FLAG_SEARCH;
+ retval = -1;
+ } else {
+ dst[(o_bitcnt>>3)-1] = r_val;
+ fcs = PPP_FCS (fcs, r_val);
+#ifdef DEBUGME
+ printf("Output byte %d: 0x%02x; FCS 0x%04x\n", (o_bitcnt>>3)-1, r_val, fcs);
+#endif
+ }
+ }
+ }
+ i_bitcnt ++;
+ val >>= 1;
+ }
+
+ /* We exhausted the source buffer before anything else happened
+ * (retval==0). Reset i_bitcnt in expectation of a new source
+ * buffer. Other, we either had an error or a valid frame, so
+ * reset o_bitcnt in expectation of a new destination buffer.
+ */
+
+ if (retval == 0) {
+ i_bitcnt = 0;
+ } else {
+ o_bitcnt = 0;
+ }
+
+ saved_state->state = state;
+ saved_state->r_one = r_one;
+ saved_state->r_val = r_val;
+ saved_state->fcs = fcs;
+ saved_state->o_bitcnt = o_bitcnt;
+ saved_state->i_bitcnt = i_bitcnt;
+
+ return (retval);
+}
+
+
+
+#ifdef DEBUGME
+
+char buffer[1024];
+char obuffer[1024];
+
+main()
+{
+ int buflen=0;
+ int len;
+ struct hdlc_state hdlc_state;
+
+ while((buffer[buflen] = getc(stdin)) != EOF && buflen<1024) buflen++;
+
+ printf("buflen = %d\n", buflen);
+
+ init_hdlc_state(&hdlc_state, 0);
+
+ while (len = read_raw_hdlc_data(&hdlc_state,buffer,buflen,obuffer,1024)) {
+ if (len == -1) printf("Error @ byte %d/bit %d\n",
+ hdlc_state.i_bitcnt>>3, hdlc_state.i_bitcnt & 7);
+ else {
+ printf("Frame received: len %d\n", len);
+ }
+ }
+
+ printf("Done\n");
+}
+
+#endif
diff --git a/drivers/isdn/hisax/rawhdlc.h b/drivers/isdn/hisax/rawhdlc.h
new file mode 100644
index 000000000..d946fa0b3
--- /dev/null
+++ b/drivers/isdn/hisax/rawhdlc.h
@@ -0,0 +1,26 @@
+/* $Id: rawhdlc.h,v 1.2 1998/02/09 10:53:53 keil Exp $
+
+ * rawhdlc.h support routines for cards that don't support HDLC
+ *
+ * Author Brent Baccala <baccala@FreeSoft.org>
+ *
+ */
+
+#ifndef RAWHDLC_H
+struct hdlc_state {
+ char insane_mode;
+ u_char state;
+ u_char r_one;
+ u_char r_val;
+ u_int o_bitcnt;
+ u_int i_bitcnt;
+ u_int fcs;
+};
+
+
+int make_raw_hdlc_data(u_char *src, u_int slen, u_char *dst, u_int dsize);
+void init_hdlc_state(struct hdlc_state *stateptr, int mode);
+int read_raw_hdlc_data(struct hdlc_state *saved_state,
+ u_char *src, u_int slen, u_char *dst, u_int dsize);
+#define RAWHDLC_H
+#endif
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
new file mode 100644
index 000000000..40dc8e622
--- /dev/null
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -0,0 +1,356 @@
+/* $Id: sedlbauer.c,v 1.6 1998/02/09 18:46:06 keil Exp $
+
+ * sedlbauer.c low level stuff for Sedlbauer cards
+ * includes Support for the Sedlbauer Speed Star
+ * derived from the original file dynalink.c from Karsten Keil
+ *
+ * Copyright (C) 1997,1998 Marcus Niemann (for the modifications to
+ * the original file dynalink.c)
+ *
+ * Author Marcus Niemann (niemann@www-bib.fh-bielefeld.de)
+ *
+ * Thanks to Karsten Keil
+ * Sedlbauer AG for informations
+ * Edgar Toernig
+ *
+ * $Log: sedlbauer.c,v $
+ * Revision 1.6 1998/02/09 18:46:06 keil
+ * Support for Sedlbauer PCMCIA (Marcus Niemann)
+ *
+ * Revision 1.5 1998/02/02 13:29:45 keil
+ * fast io
+ *
+ * Revision 1.4 1997/11/08 21:35:52 keil
+ * new l1 init
+ *
+ * Revision 1.3 1997/11/06 17:09:28 keil
+ * New 2.1 init code
+ *
+ * Revision 1.2 1997/10/29 18:55:52 keil
+ * changes for 2.1.60 (irq2dev_map)
+ *
+ * Revision 1.1 1997/09/11 17:32:04 keil
+ * new
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+
+const char *Sedlbauer_revision = "$Revision: 1.6 $";
+
+const char *Sedlbauer_Types[] =
+{"None", "Speed Card", "Speed Win", "Speed Star"};
+
+#define SEDL_SPEED_CARD 1
+#define SEDL_SPEED_WIN 2
+#define SEDL_SPEED_STAR 3
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define SEDL_RESET_ON 0
+#define SEDL_RESET_OFF 1
+#define SEDL_ISAC 2
+#define SEDL_HSCX 3
+#define SEDL_ADR 4
+
+#define SEDL_PCMCIA_RESET 0
+#define SEDL_PCMCIA_ISAC 1
+#define SEDL_PCMCIA_HSCX 2
+#define SEDL_PCMCIA_ADR 4
+
+#define SEDL_RESET 0x3 /* same as DOS driver */
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+ register u_char ret;
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(ale, off);
+ ret = bytein(adr);
+ restore_flags(flags);
+ return (ret);
+}
+
+static inline void
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+ /* fifo read without cli because it's allready done */
+
+ byteout(ale, off);
+ insb(adr, data, size);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(ale, off);
+ byteout(adr, data);
+ restore_flags(flags);
+}
+
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+ /* fifo write without cli because it's allready done */
+ byteout(ale, off);
+ outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+ return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+ return (readreg(cs->hw.sedl.adr,
+ cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+ writereg(cs->hw.sedl.adr,
+ cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0), value);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.sedl.adr, \
+ cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.sedl.adr, \
+ cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0), data)
+
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.sedl.adr, \
+ cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.sedl.adr, \
+ cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val, stat = 0;
+
+ if (!cs) {
+ printk(KERN_WARNING "Sedlbauer: Spurious interrupt!\n");
+ return;
+ }
+
+ if ((cs->typ == ISDN_CTYPE_SEDLBAUER_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;
+ }
+
+ val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
+ Start_HSCX:
+ if (val) {
+ hscx_int_main(cs, val);
+ stat |= 1;
+ }
+ val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
+ Start_ISAC:
+ if (val) {
+ isac_interrupt(cs, val);
+ stat |= 2;
+ }
+ val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
+ if (val) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX IntStat after IntRoutine");
+ goto Start_HSCX;
+ }
+ val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
+ if (val) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ISAC IntStat after IntRoutine");
+ goto Start_ISAC;
+ }
+ if (stat & 1) {
+ writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0xFF);
+ writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0xFF);
+ writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0x0);
+ writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0x0);
+ }
+ if (stat & 2) {
+ writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0);
+ }
+}
+
+void
+release_io_sedlbauer(struct IsdnCardState *cs)
+{
+ int bytecnt = 8;
+
+ if (cs->hw.sedl.cfg_reg)
+ release_region(cs->hw.sedl.cfg_reg, bytecnt);
+}
+
+static void
+reset_sedlbauer(struct IsdnCardState *cs)
+{
+ long flags;
+
+ if (cs->typ != ISDN_CTYPE_SEDLBAUER_PCMCIA) {
+ byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */
+ save_flags(flags);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ restore_flags(flags);
+ }
+}
+
+static int
+Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ reset_sedlbauer(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_sedlbauer(cs);
+ return(0);
+ case CARD_SETIRQ:
+ return(request_irq(cs->irq, &sedlbauer_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs));
+ case CARD_INIT:
+ clear_pending_isac_ints(cs);
+ clear_pending_hscx_ints(cs);
+ initisac(cs);
+ inithscx(cs);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
+}
+
+__initfunc(int
+setup_sedlbauer(struct IsdnCard *card))
+{
+ int bytecnt;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, Sedlbauer_revision);
+ printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ == ISDN_CTYPE_SEDLBAUER) {
+ cs->subtyp = SEDL_SPEED_CARD;
+ } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) {
+ cs->subtyp = SEDL_SPEED_STAR;
+ } else
+ return (0);
+
+ bytecnt = 8;
+ cs->hw.sedl.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ if (cs->subtyp == SEDL_SPEED_STAR) {
+ cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_ADR;
+ cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_ISAC;
+ cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_HSCX;
+ cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_RESET;
+ cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_RESET;
+ } else {
+ cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_ADR;
+ cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAC;
+ cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX;
+ cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_RESET_ON;
+ cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_RESET_OFF;
+ }
+
+ /* In case of the sedlbauer pcmcia card, this region is in use,
+ reserved for us by the card manager. So we do not check it
+ here, it would fail. */
+ if (cs->typ != ISDN_CTYPE_SEDLBAUER_PCMCIA &&
+ check_region((cs->hw.sedl.cfg_reg), bytecnt)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.sedl.cfg_reg,
+ cs->hw.sedl.cfg_reg + bytecnt);
+ return (0);
+ } else {
+ request_region(cs->hw.sedl.cfg_reg, bytecnt, "sedlbauer isdn");
+ }
+
+ printk(KERN_INFO
+ "Sedlbauer: defined at 0x%x IRQ %d\n",
+ cs->hw.sedl.cfg_reg,
+ cs->irq);
+ printk(KERN_WARNING
+ "Sedlbauer %s uses ports 0x%x-0x%x\n",
+ Sedlbauer_Types[cs->subtyp],
+ cs->hw.sedl.cfg_reg,
+ cs->hw.sedl.cfg_reg + bytecnt);
+
+ printk(KERN_INFO "Sedlbauer: resetting card\n");
+ reset_sedlbauer(cs);
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ cs->BC_Read_Reg = &ReadHSCX;
+ cs->BC_Write_Reg = &WriteHSCX;
+ cs->BC_Send_Data = &hscx_fill_fifo;
+ cs->cardmsg = &Sedl_card_msg;
+ ISACVersion(cs, "Sedlbauer:");
+ if (HscxVersion(cs, "Sedlbauer:")) {
+ printk(KERN_WARNING
+ "Sedlbauer: wrong HSCX versions check IO address\n");
+ release_io_sedlbauer(cs);
+ return (0);
+ }
+ return (1);
+}
diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c
new file mode 100644
index 000000000..cb867a13f
--- /dev/null
+++ b/drivers/isdn/hisax/sportster.c
@@ -0,0 +1,291 @@
+/* $Id: sportster.c,v 1.5 1998/02/02 13:29:46 keil Exp $
+
+ * sportster.c low level stuff for USR Sportster internal TA
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation
+ *
+ * $Log: sportster.c,v $
+ * Revision 1.5 1998/02/02 13:29:46 keil
+ * fast io
+ *
+ * Revision 1.4 1997/11/08 21:35:52 keil
+ * new l1 init
+ *
+ * Revision 1.3 1997/11/06 17:09:29 keil
+ * New 2.1 init code
+ *
+ * Revision 1.2 1997/10/29 18:51:18 keil
+ * New files
+ *
+ * Revision 1.1.2.1 1997/10/17 22:10:58 keil
+ * new files on 2.0
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+const char *sportster_revision = "$Revision: 1.5 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define SPORTSTER_ISAC 0xC000
+#define SPORTSTER_HSCXA 0x0000
+#define SPORTSTER_HSCXB 0x4000
+#define SPORTSTER_RES_IRQ 0x8000
+#define SPORTSTER_RESET 0x80
+#define SPORTSTER_INTE 0x40
+
+static inline int
+calc_off(unsigned int base, unsigned int off)
+{
+ return(base + ((off & 0xfc)<<8) + ((off & 3)<<1));
+}
+
+static inline void
+read_fifo(unsigned int adr, u_char * data, int size)
+{
+ insb(adr, data, size);
+}
+
+static void
+write_fifo(unsigned int adr, u_char * data, int size)
+{
+ outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+ return (bytein(calc_off(cs->hw.spt.isac, offset)));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ byteout(calc_off(cs->hw.spt.isac, offset), value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ read_fifo(cs->hw.spt.isac, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ write_fifo(cs->hw.spt.isac, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+ return (bytein(calc_off(cs->hw.spt.hscx[hscx], offset)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+ byteout(calc_off(cs->hw.spt.hscx[hscx], offset), value);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) bytein(calc_off(cs->hw.spt.hscx[nr], reg))
+#define WRITEHSCX(cs, nr, reg, data) byteout(calc_off(cs->hw.spt.hscx[nr], reg), data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+sportster_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+
+ if (!cs) {
+ printk(KERN_WARNING "Sportster: Spurious interrupt!\n");
+ return;
+ }
+ val = READHSCX(cs, 1, HSCX_ISTA);
+ Start_HSCX:
+ if (val)
+ hscx_int_main(cs, val);
+ val = ReadISAC(cs, ISAC_ISTA);
+ Start_ISAC:
+ if (val)
+ isac_interrupt(cs, val);
+ val = READHSCX(cs, 1, HSCX_ISTA);
+ if (val) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX IntStat after IntRoutine");
+ goto Start_HSCX;
+ }
+ val = ReadISAC(cs, ISAC_ISTA);
+ if (val) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ISAC IntStat after IntRoutine");
+ goto Start_ISAC;
+ }
+ /* get a new irq impulse if there any pending */
+ bytein(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ +1);
+}
+
+void
+release_io_sportster(struct IsdnCardState *cs)
+{
+ int i, adr;
+
+ byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, 0);
+ for (i=0; i<64; i++) {
+ adr = cs->hw.spt.cfg_reg + i *1024;
+ release_region(adr, 8);
+ }
+}
+
+void
+reset_sportster(struct IsdnCardState *cs)
+{
+ long flags;
+
+ cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */
+ byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
+ save_flags(flags);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */
+ byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ restore_flags(flags);
+}
+
+static int
+Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ reset_sportster(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_sportster(cs);
+ return(0);
+ case CARD_SETIRQ:
+ return(request_irq(cs->irq, &sportster_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs));
+ case CARD_INIT:
+ clear_pending_isac_ints(cs);
+ clear_pending_hscx_ints(cs);
+ initisac(cs);
+ inithscx(cs);
+ cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */
+ byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
+}
+
+__initfunc(int
+get_io_range(struct IsdnCardState *cs))
+{
+ int i, j, adr;
+
+ for (i=0;i<64;i++) {
+ adr = cs->hw.spt.cfg_reg + i *1024;
+ if (check_region(adr, 8)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[cs->typ], adr, adr + 8);
+ break;
+ } else
+ request_region(adr, 8, "sportster");
+ }
+ if (i==64)
+ return(1);
+ else {
+ for (j=0; j<i; j++) {
+ adr = cs->hw.spt.cfg_reg + j *1024;
+ release_region(adr, 8);
+ }
+ return(0);
+ }
+}
+
+__initfunc(int
+setup_sportster(struct IsdnCard *card))
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, sportster_revision);
+ printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_SPORTSTER)
+ return (0);
+
+ cs->hw.spt.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ if (!get_io_range(cs))
+ return (0);
+ cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC;
+ cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA;
+ cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB;
+
+ switch(cs->irq) {
+ case 5: cs->hw.spt.res_irq = 1;
+ break;
+ case 7: cs->hw.spt.res_irq = 2;
+ break;
+ case 10:cs->hw.spt.res_irq = 3;
+ break;
+ case 11:cs->hw.spt.res_irq = 4;
+ break;
+ case 12:cs->hw.spt.res_irq = 5;
+ break;
+ case 14:cs->hw.spt.res_irq = 6;
+ break;
+ case 15:cs->hw.spt.res_irq = 7;
+ break;
+ default:release_io_sportster(cs);
+ printk(KERN_WARNING "Sportster: wrong IRQ\n");
+ return(0);
+ }
+ reset_sportster(cs);
+ printk(KERN_INFO
+ "HiSax: %s config irq:%d cfg:0x%X\n",
+ CardType[cs->typ], cs->irq,
+ cs->hw.spt.cfg_reg);
+
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ cs->BC_Read_Reg = &ReadHSCX;
+ cs->BC_Write_Reg = &WriteHSCX;
+ cs->BC_Send_Data = &hscx_fill_fifo;
+ cs->cardmsg = &Sportster_card_msg;
+ ISACVersion(cs, "Sportster:");
+ if (HscxVersion(cs, "Sportster:")) {
+ printk(KERN_WARNING
+ "Sportster: wrong HSCX versions check IO address\n");
+ release_io_sportster(cs);
+ return (0);
+ }
+ return (1);
+}
diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c
index d97595938..a52078746 100644
--- a/drivers/isdn/hisax/tei.c
+++ b/drivers/isdn/hisax/tei.c
@@ -1,4 +1,4 @@
-/* $Id: tei.c,v 1.8 1997/04/07 22:59:08 keil Exp $
+/* $Id: tei.c,v 2.7 1998/02/12 23:08:11 keil Exp $
* Author Karsten Keil (keil@temic-ech.spacenet.de)
* based on the teles driver from Jan den Ouden
@@ -7,52 +7,112 @@
* Fritz Elfert
*
* $Log: tei.c,v $
- * Revision 1.8 1997/04/07 22:59:08 keil
- * GFP_KERNEL --> GFP_ATOMIC
+ * Revision 2.7 1998/02/12 23:08:11 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
*
- * Revision 1.7 1997/04/06 22:54:03 keil
- * Using SKB's
+ * Revision 2.6 1998/02/02 13:41:42 keil
+ * fix MDL_ASSIGN for PtP
*
- * Revision 1.6 1997/02/09 00:25:12 keil
- * new interface handling, one interface per card
+ * Revision 2.5 1997/11/06 17:09:12 keil
+ * New 2.1 init code
*
- * Revision 1.5 1997/01/27 15:57:51 keil
- * cosmetics
+ * Revision 2.4 1997/10/29 19:04:46 keil
+ * changes for 2.1
*
- * Revision 1.4 1997/01/21 22:32:44 keil
- * Tei verify request
+ * Revision 2.3 1997/10/01 09:21:43 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
*
- * Revision 1.3 1997/01/04 13:45:02 keil
- * cleanup,adding remove tei request (thanks to Sim Yskes)
+ * Revision 2.2 1997/07/31 19:24:39 keil
+ * fixed a warning
*
- * Revision 1.2 1996/12/08 19:52:39 keil
- * minor debug fix
+ * Revision 2.1 1997/07/31 11:50:16 keil
+ * ONE TEI and FIXED TEI handling
*
- * Revision 1.1 1996/10/13 20:04:57 keil
- * Initial revision
+ * Revision 2.0 1997/07/27 21:13:30 keil
+ * New TEI managment
*
+ * Revision 1.9 1997/06/26 11:18:02 keil
+ * New managment
*
+ * Revision 1.8 1997/04/07 22:59:08 keil
+ * GFP_KERNEL --> GFP_ATOMIC
+ *
+ * Revision 1.7 1997/04/06 22:54:03 keil
+ * Using SKB's
+ *
+ * Old log removed/ KKe
*
*/
#define __NO_VERSION__
#include "hisax.h"
+#include "isdnl2.h"
+#include <linux/random.h>
-extern struct IsdnCard cards[];
-extern int nrcards;
+const char *tei_revision = "$Revision: 2.7 $";
-const char *tei_revision = "$Revision: 1.8 $";
+#define ID_REQUEST 1
+#define ID_ASSIGNED 2
+#define ID_DENIED 3
+#define ID_CHK_REQ 4
+#define ID_CHK_RES 5
+#define ID_REMOVE 6
+#define ID_VERIFY 7
-static struct PStack *
-findces(struct PStack *st, int ces)
+#define TEI_ENTITY_ID 0xf
+
+static
+struct Fsm teifsm =
+{NULL, 0, 0, NULL, NULL};
+
+void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb);
+
+enum {
+ ST_TEI_NOP,
+ ST_TEI_IDREQ,
+ ST_TEI_IDVERIFY,
+};
+
+#define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1)
+
+static char *strTeiState[] =
{
- struct PStack *ptr = *(st->l1.stlistp);
+ "ST_TEI_NOP",
+ "ST_TEI_IDREQ",
+ "ST_TEI_IDVERIFY",
+};
- while (ptr)
- if (ptr->l2.ces == ces)
- return (ptr);
- else
- ptr = ptr->next;
- return (NULL);
+enum {
+ EV_IDREQ,
+ EV_ASSIGN,
+ EV_DENIED,
+ EV_CHKREQ,
+ EV_REMOVE,
+ EV_VERIFY,
+ EV_T202,
+};
+
+#define TEI_EVENT_COUNT (EV_T202+1)
+
+static char *strTeiEvent[] =
+{
+ "EV_IDREQ",
+ "EV_ASSIGN",
+ "EV_DENIED",
+ "EV_CHKREQ",
+ "EV_REMOVE",
+ "EV_VERIFY",
+ "EV_T202",
+};
+
+unsigned int
+random_ri(void)
+{
+ unsigned int x;
+
+ get_random_bytes(&x, sizeof(x));
+ return (x & 0xffff);
}
static struct PStack *
@@ -72,246 +132,357 @@ findtei(struct PStack *st, int tei)
}
static void
-mdl_unit_data_res(struct PStack *st, unsigned int ri, u_char mt, u_char ai)
+put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei)
{
struct sk_buff *skb;
u_char *bp;
- if (!(skb = alloc_skb(6 + MAX_HEADER_LEN, GFP_ATOMIC))) {
+ if (!(skb = alloc_skb(8, GFP_ATOMIC))) {
printk(KERN_WARNING "HiSax: No skb for TEI manager\n");
return;
}
- skb_reserve(skb, MAX_HEADER_LEN);
+ bp = skb_put(skb, 3);
+ bp[0] = (TEI_SAPI << 2);
+ bp[1] = (GROUP_TEI << 1) | 0x1;
+ bp[2] = UI;
bp = skb_put(skb, 5);
- bp[0] = 0xf;
+ bp[0] = TEI_ENTITY_ID;
bp[1] = ri >> 8;
bp[2] = ri & 0xff;
- bp[3] = mt;
- bp[4] = (ai << 1) | 1;
- st->l3.l3l2(st, DL_UNIT_DATA, skb);
+ bp[3] = m_id;
+ bp[4] = (tei << 1) | 1;
+ st->l2.l2l1(st, PH_DATA_REQ, skb);
}
static void
-mdl_unit_data_ind(struct PStack *st, unsigned int ri, u_char mt, u_char ai)
+tei_id_request(struct FsmInst *fi, int event, void *arg)
{
- unsigned int tces;
- struct PStack *otsp, *ptr;
+ struct PStack *st = fi->userdata;
char tmp[64];
- switch (mt) {
- case (2):
- tces = ri;
- if (st->l3.debug) {
- sprintf(tmp, "identity assign ces %d ai %d", tces, ai);
- st->l2.l2m.printdebug(&st->l2.l2m, tmp);
- }
- if ((otsp = findces(st, tces))) {
- if (st->l3.debug) {
- sprintf(tmp, "ces %d --> tei %d", tces, ai);
- st->l2.l2m.printdebug(&st->l2.l2m, tmp);
- }
- otsp->ma.teil2(otsp, MDL_ASSIGN, (void *) (int) ai);
- }
- break;
- case (3):
- tces = ri;
- if (st->l3.debug) {
- sprintf(tmp, "identity denied for ces %d ai %d", tces, ai);
- st->l2.l2m.printdebug(&st->l2.l2m, tmp);
- }
- if ((otsp = findces(st, tces))) {
- if (st->l3.debug) {
- sprintf(tmp, "ces %d denied tei %d", tces, ai);
- st->l2.l2m.printdebug(&st->l2.l2m, tmp);
- }
- otsp->l2.tei = 255;
- otsp->l2.ces = randomces();
- otsp->ma.teil2(otsp, MDL_REMOVE, 0);
- }
- break;
- case (4):
- if (st->l3.debug) {
- sprintf(tmp, "checking identity for %d", ai);
- st->l2.l2m.printdebug(&st->l2.l2m, tmp);
- }
- if (ai == 0x7f) {
- ptr = *(st->l1.stlistp);
- while (ptr) {
- if ((ptr->l2.tei & 0x7f) != 0x7f) {
- if (st->l3.debug) {
- sprintf(tmp, "check response for ces %d with tei %d",
- ptr->l2.ces, ptr->l2.tei);
- st->l2.l2m.printdebug(&st->l2.l2m, tmp);
- }
- /* send identity check response (user->network) */
- mdl_unit_data_res(st, ptr->l2.ces, 5, ptr->l2.tei);
- }
- ptr = ptr->next;
- }
- } else {
- otsp = findtei(st, ai);
- if (!otsp)
- break;
- if (st->l3.debug) {
- sprintf(tmp, "check response for ces %d with tei %d",
- otsp->l2.ces, otsp->l2.tei);
- st->l2.l2m.printdebug(&st->l2.l2m, tmp);
- }
- /* send identity check response (user->network) */
- mdl_unit_data_res(st, otsp->l2.ces, 5, otsp->l2.tei);
- }
- break;
- case (6):
- if (st->l3.debug) {
- sprintf(tmp, "removal for %d", ai);
- st->l2.l2m.printdebug(&st->l2.l2m, tmp);
- }
- if (ai == 0x7f) {
- ptr = *(st->l1.stlistp);
- while (ptr) {
- if ((ptr->l2.tei & 0x7f) != 0x7f) {
- if (st->l3.debug) {
- sprintf(tmp, "rem ces %d with tei %d",
- ptr->l2.ces, ptr->l2.tei);
- st->l2.l2m.printdebug(&st->l2.l2m, tmp);
- }
- ptr->ma.teil2(ptr, MDL_REMOVE, 0);
- }
- ptr = ptr->next;
- }
- } else {
- otsp = findtei(st, ai);
- if (!otsp)
- break;
- if (st->l3.debug) {
- sprintf(tmp, "rem ces %d with tei %d",
- otsp->l2.ces, otsp->l2.tei);
- st->l2.l2m.printdebug(&st->l2.l2m, tmp);
- }
- otsp->ma.teil2(otsp, MDL_REMOVE, 0);
- }
- break;
- default:
- if (st->l3.debug) {
- sprintf(tmp, "message unknown %d ai %d", mt, ai);
- st->l2.l2m.printdebug(&st->l2.l2m, tmp);
- }
+ if (st->l2.tei != -1) {
+ sprintf(tmp, "assign request for allready asigned tei %d",
+ st->l2.tei);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ return;
+ }
+ st->ma.ri = random_ri();
+ if (st->ma.debug) {
+ sprintf(tmp, "assign request ri %d", st->ma.ri);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
}
+ put_tei_msg(st, ID_REQUEST, st->ma.ri, 127);
+ FsmChangeState(&st->ma.tei_m, ST_TEI_IDREQ);
+ FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 1);
+ st->ma.N202 = 3;
}
-void
-tei_handler(struct PStack *st,
- u_char pr, struct sk_buff *skb)
+static void
+tei_id_assign(struct FsmInst *fi, int event, void *arg)
{
- u_char *bp;
- unsigned int data;
- char tmp[32];
+ struct PStack *ost, *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ struct IsdnCardState *cs;
+ int ri, tei;
+ char tmp[64];
- switch (pr) {
- case (MDL_ASSIGN):
- data = (unsigned int) skb;
- if (st->l3.debug) {
- sprintf(tmp, "ces %d assign request", data);
- st->l2.l2m.printdebug(&st->l2.l2m, tmp);
- }
- mdl_unit_data_res(st, data, 1, 127);
- break;
- case (MDL_VERIFY):
- data = (unsigned int) skb;
- if (st->l3.debug) {
- sprintf(tmp, "%d id verify request", data);
- st->l2.l2m.printdebug(&st->l2.l2m, tmp);
- }
- mdl_unit_data_res(st, 0, 7, data);
- break;
- case (DL_UNIT_DATA):
- bp = skb->data;
- if (bp[0] != 0xf) {
- /* wrong management entity identifier, ignore */
- /* shouldn't ibh be released??? */
- printk(KERN_WARNING "tei handler wrong entity id %x\n", bp[0]);
- } else
- mdl_unit_data_ind(st, (bp[1] << 8) | bp[2], bp[3], bp[4] >> 1);
- SET_SKB_FREE(skb);
- dev_kfree_skb(skb);
- break;
- default:
- break;
+ ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
+ tei = skb->data[4] >> 1;
+ if (st->ma.debug) {
+ sprintf(tmp, "identity assign ri %d tei %d", ri, tei);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ }
+ if ((ost = findtei(st, tei))) { /* same tei is in use */
+ if (ri != ost->ma.ri) {
+ sprintf(tmp, "possible duplicate assignment tei %d", tei);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ ost->l2.l2tei(ost, MDL_ERROR_REQ, NULL);
+ }
+ } else if (ri == st->ma.ri) {
+ FsmDelTimer(&st->ma.t202, 1);
+ FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
+ st->ma.manl2(st, MDL_ASSIGN_REQ, (void *) (int) tei);
+ cs = (struct IsdnCardState *) st->l1.hardware;
+ cs->cardmsg(cs, MDL_ASSIGN_REQ, NULL);
}
}
-unsigned int
-randomces(void)
+static void
+tei_id_denied(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ int ri, tei;
+ char tmp[64];
+
+ ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
+ tei = skb->data[4] >> 1;
+ if (st->ma.debug) {
+ sprintf(tmp, "identity denied ri %d tei %d", ri, tei);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ }
+}
+
+static void
+tei_id_chk_req(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ int tei;
+ char tmp[64];
+
+ tei = skb->data[4] >> 1;
+ if (st->ma.debug) {
+ sprintf(tmp, "identity check req tei %d", tei);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ }
+ if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
+ FsmDelTimer(&st->ma.t202, 4);
+ FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
+ put_tei_msg(st, ID_CHK_RES, random_ri(), st->l2.tei);
+ }
+}
+
+static void
+tei_id_remove(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ struct IsdnCardState *cs;
+ int tei;
+ char tmp[64];
+
+ tei = skb->data[4] >> 1;
+ if (st->ma.debug) {
+ sprintf(tmp, "identity remove tei %d", tei);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ }
+ if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
+ FsmDelTimer(&st->ma.t202, 5);
+ FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
+ st->ma.manl2(st, MDL_REMOVE_REQ, 0);
+ cs = (struct IsdnCardState *) st->l1.hardware;
+ cs->cardmsg(cs, MDL_REMOVE_REQ, NULL);
+ }
+}
+
+static void
+tei_id_verify(struct FsmInst *fi, int event, void *arg)
{
- int x = jiffies & 0xffff;
+ struct PStack *st = fi->userdata;
+ char tmp[64];
- return (x);
+ if (st->ma.debug) {
+ sprintf(tmp, "id verify request for tei %d", st->l2.tei);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ }
+ put_tei_msg(st, ID_VERIFY, 0, st->l2.tei);
+ FsmChangeState(&st->ma.tei_m, ST_TEI_IDVERIFY);
+ FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 2);
+ st->ma.N202 = 2;
}
static void
-tei_man(struct PStack *sp, int i, void *v)
+tei_id_req_tout(struct FsmInst *fi, int event, void *arg)
{
+ struct PStack *st = fi->userdata;
+ char tmp[64];
+ struct IsdnCardState *cs;
- printk(KERN_DEBUG "tei_man\n");
+ if (--st->ma.N202) {
+ st->ma.ri = random_ri();
+ if (st->ma.debug) {
+ sprintf(tmp, "assign req(%d) ri %d",
+ 4 - st->ma.N202, st->ma.ri);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ }
+ put_tei_msg(st, ID_REQUEST, st->ma.ri, 127);
+ FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3);
+ } else {
+ sprintf(tmp, "assign req failed");
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ st->ma.manl2(st, MDL_ERROR_IND, 0);
+ cs = (struct IsdnCardState *) st->l1.hardware;
+ cs->cardmsg(cs, MDL_REMOVE_REQ, NULL);
+ FsmChangeState(fi, ST_TEI_NOP);
+ }
+}
+
+static void
+tei_id_ver_tout(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ char tmp[64];
+ struct IsdnCardState *cs;
+
+ if (--st->ma.N202) {
+ if (st->ma.debug) {
+ sprintf(tmp, "id verify req(%d) for tei %d",
+ 3 - st->ma.N202, st->l2.tei);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ }
+ put_tei_msg(st, ID_VERIFY, 0, st->l2.tei);
+ FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 4);
+ } else {
+ sprintf(tmp, "verify req for tei %d failed", st->l2.tei);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ st->ma.manl2(st, MDL_REMOVE_REQ, 0);
+ cs = (struct IsdnCardState *) st->l1.hardware;
+ cs->cardmsg(cs, MDL_REMOVE_REQ, NULL);
+ FsmChangeState(fi, ST_TEI_NOP);
+ }
+}
+
+static void
+tei_l1l2(struct PStack *st, int pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int mt;
+ char tmp[64];
+
+ if (pr == PH_DATA_IND) {
+ if (skb->len < 3) {
+ sprintf(tmp, "short mgr frame %d/3", skb->len);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ } else if (((skb->data[0] >> 2) != TEI_SAPI) ||
+ ((skb->data[1] >> 1) != GROUP_TEI)) {
+ sprintf(tmp, "wrong mgr sapi/tei %x/%x",
+ skb->data[0], skb->data[1]);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ } else if ((skb->data[2] & 0xef) != UI) {
+ sprintf(tmp, "mgr frame is not ui %x",
+ skb->data[2]);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ } else {
+ skb_pull(skb, 3);
+ if (skb->len < 5) {
+ sprintf(tmp, "short mgr frame %d/5", skb->len);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ } else if (skb->data[0] != TEI_ENTITY_ID) {
+ /* wrong management entity identifier, ignore */
+ sprintf(tmp, "tei handler wrong entity id %x\n",
+ skb->data[0]);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ } else {
+ mt = skb->data[3];
+ if (mt == ID_ASSIGNED)
+ FsmEvent(&st->ma.tei_m, EV_ASSIGN, skb);
+ else if (mt == ID_DENIED)
+ FsmEvent(&st->ma.tei_m, EV_DENIED, skb);
+ else if (mt == ID_CHK_REQ)
+ FsmEvent(&st->ma.tei_m, EV_CHKREQ, skb);
+ else if (mt == ID_REMOVE)
+ FsmEvent(&st->ma.tei_m, EV_REMOVE, skb);
+ else {
+ sprintf(tmp, "tei handler wrong mt %x\n",
+ mt);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ }
+ }
+ }
+ } else {
+ sprintf(tmp, "tei handler wrong pr %x\n", pr);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ }
+ dev_kfree_skb(skb);
}
static void
tei_l2tei(struct PStack *st, int pr, void *arg)
{
- struct IsdnCardState *sp = st->l1.hardware;
+ switch (pr) {
+ case (MDL_ASSIGN_IND):
+#ifdef TEI_FIXED
+ if (st->ma.debug) {
+ char tmp[64];
+ sprintf(tmp, "fixed assign tei %d", TEI_FIXED);
+ st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+ }
+ st->ma.manl2(st, MDL_ASSIGN_REQ, (void *) (int) TEI_FIXED);
+#else
+ FsmEvent(&st->ma.tei_m, EV_IDREQ, arg);
+#endif
+ break;
+ case (MDL_ERROR_REQ):
+ FsmEvent(&st->ma.tei_m, EV_VERIFY, arg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+tei_debug(struct FsmInst *fi, char *s)
+{
+ struct PStack *st = fi->userdata;
+ char tm[32], str[256];
- tei_handler(sp->teistack, pr, arg);
+ jiftime(tm, jiffies);
+ sprintf(str, "%s Tei %s\n", tm, s);
+ HiSax_putstatus(st->l1.hardware, str);
}
void
setstack_tei(struct PStack *st)
{
st->l2.l2tei = tei_l2tei;
+ st->ma.T202 = 2000; /* T202 2000 milliseconds */
+ st->l1.l1tei = tei_l1l2;
+ st->ma.debug = 1;
+ st->ma.tei_m.fsm = &teifsm;
+ st->ma.tei_m.state = ST_TEI_NOP;
+ st->ma.tei_m.debug = 1;
+ st->ma.tei_m.userdata = st;
+ st->ma.tei_m.userint = 0;
+ st->ma.tei_m.printdebug = tei_debug;
+ FsmInitTimer(&st->ma.tei_m, &st->ma.t202);
}
void
init_tei(struct IsdnCardState *sp, int protocol)
{
- struct PStack *st;
- char tmp[128];
-
- st = (struct PStack *) kmalloc(sizeof(struct PStack), GFP_ATOMIC);
- setstack_HiSax(st, sp);
- st->l2.extended = !0;
- st->l2.laptype = LAPD;
- st->l2.window = 1;
- st->l2.orig = !0;
- st->protocol = protocol;
-/*
- * the following is not necessary for tei mng. (broadcast only)
- */
- st->l2.t200 = 500; /* 500 milliseconds */
- st->l2.n200 = 4; /* try 4 times */
- st->l2.sap = 63;
- st->l2.tei = 127;
+}
+
+void
+release_tei(struct IsdnCardState *cs)
+{
+ struct PStack *st = cs->stlist;
- sprintf(tmp, "Card %d tei", sp->cardnr + 1);
- setstack_isdnl2(st, tmp);
- st->l2.debug = 0;
- st->l3.debug = 0;
+ while (st) {
+ FsmDelTimer(&st->ma.t202, 1);
+ st = st->next;
+ }
+}
- st->ma.manl2(st, MDL_NOTEIPROC, NULL);
+static struct FsmNode TeiFnList[] HISAX_INITDATA =
+{
+ {ST_TEI_NOP, EV_IDREQ, tei_id_request},
+ {ST_TEI_NOP, EV_VERIFY, tei_id_verify},
+ {ST_TEI_NOP, EV_REMOVE, tei_id_remove},
+ {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req},
+ {ST_TEI_IDREQ, EV_T202, tei_id_req_tout},
+ {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign},
+ {ST_TEI_IDREQ, EV_DENIED, tei_id_denied},
+ {ST_TEI_IDVERIFY, EV_T202, tei_id_ver_tout},
+ {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove},
+ {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req},
+};
- st->l2.l2l3 = (void *) tei_handler;
- st->l1.l1man = tei_man;
- st->l2.l2man = tei_man;
- st->l4.l2writewakeup = NULL;
+#define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode))
- HiSax_addlist(sp, st);
- sp->teistack = st;
+HISAX_INITFUNC(void
+TeiNew(void))
+{
+ teifsm.state_count = TEI_STATE_COUNT;
+ teifsm.event_count = TEI_EVENT_COUNT;
+ teifsm.strEvent = strTeiEvent;
+ teifsm.strState = strTeiState;
+ FsmNew(&teifsm, TeiFnList, TEI_FN_COUNT);
}
void
-release_tei(struct IsdnCardState *sp)
+TeiFree(void)
{
- struct PStack *st = sp->teistack;
-
- HiSax_rmlist(sp, st);
- kfree((void *) st);
+ FsmFree(&teifsm);
}
diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c
new file mode 100644
index 000000000..d86dd79a4
--- /dev/null
+++ b/drivers/isdn/hisax/teleint.c
@@ -0,0 +1,363 @@
+/* $Id: teleint.c,v 1.5 1998/02/02 13:40:47 keil Exp $
+
+ * teleint.c low level stuff for TeleInt isdn cards
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: teleint.c,v $
+ * Revision 1.5 1998/02/02 13:40:47 keil
+ * fast io
+ *
+ * Revision 1.4 1997/11/08 21:35:53 keil
+ * new l1 init
+ *
+ * Revision 1.3 1997/11/06 17:09:30 keil
+ * New 2.1 init code
+ *
+ * Revision 1.2 1997/10/29 18:55:53 keil
+ * changes for 2.1.60 (irq2dev_map)
+ *
+ * Revision 1.1 1997/09/11 17:32:32 keil
+ * new
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hfc_2bs0.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+
+const char *TeleInt_revision = "$Revision: 1.5 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+ register u_char ret;
+ int max_delay = 2000;
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(ale, off);
+ ret = HFC_BUSY & bytein(ale);
+ while (ret && --max_delay)
+ ret = HFC_BUSY & bytein(ale);
+ if (!max_delay) {
+ printk(KERN_WARNING "TeleInt Busy not inaktive\n");
+ restore_flags(flags);
+ return (0);
+ }
+ ret = bytein(adr);
+ restore_flags(flags);
+ return (ret);
+}
+
+static inline void
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+ register u_char ret;
+ int max_delay = 2000;
+ byteout(ale, off);
+
+ ret = HFC_BUSY & bytein(ale);
+ while (ret && --max_delay)
+ ret = HFC_BUSY & bytein(ale);
+ if (!max_delay) {
+ printk(KERN_WARNING "TeleInt Busy not inaktive\n");
+ return;
+ }
+ insb(adr, data, size);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+ register u_char ret;
+ int max_delay = 2000;
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(ale, off);
+ ret = HFC_BUSY & bytein(ale);
+ while (ret && --max_delay)
+ ret = HFC_BUSY & bytein(ale);
+ if (!max_delay) {
+ printk(KERN_WARNING "TeleInt Busy not inaktive\n");
+ restore_flags(flags);
+ return;
+ }
+ byteout(adr, data);
+ restore_flags(flags);
+}
+
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+ register u_char ret;
+ int max_delay = 2000;
+
+ /* fifo write without cli because it's allready done */
+ byteout(ale, off);
+ ret = HFC_BUSY & bytein(ale);
+ while (ret && --max_delay)
+ ret = HFC_BUSY & bytein(ale);
+ if (!max_delay) {
+ printk(KERN_WARNING "TeleInt Busy not inaktive\n");
+ return;
+ }
+ outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+ cs->hw.hfc.cip = offset;
+ return (readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ cs->hw.hfc.cip = offset;
+ writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ cs->hw.hfc.cip = 0;
+ readfifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ cs->hw.hfc.cip = 0;
+ writefifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size);
+}
+
+static u_char
+ReadHFC(struct IsdnCardState *cs, int data, u_char reg)
+{
+ register u_char ret;
+
+ if (data) {
+ cs->hw.hfc.cip = reg;
+ byteout(cs->hw.hfc.addr | 1, reg);
+ ret = bytein(cs->hw.hfc.addr);
+ if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) {
+ char tmp[32];
+ sprintf(tmp, "hfc RD %02x %02x", reg, ret);
+ debugl1(cs, tmp);
+ }
+ } else
+ ret = bytein(cs->hw.hfc.addr | 1);
+ return (ret);
+}
+
+static void
+WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value)
+{
+ byteout(cs->hw.hfc.addr | 1, reg);
+ cs->hw.hfc.cip = reg;
+ if (data)
+ byteout(cs->hw.hfc.addr, value);
+ if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) {
+ char tmp[32];
+ sprintf(tmp, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value);
+ debugl1(cs, tmp);
+ }
+}
+
+static void
+TeleInt_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val, stat = 0;
+
+ if (!cs) {
+ printk(KERN_WARNING "TeleInt: Spurious interrupt!\n");
+ return;
+ }
+ val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA);
+ Start_ISAC:
+ if (val) {
+ isac_interrupt(cs, val);
+ stat |= 2;
+ }
+ val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA);
+ if (val) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ISAC IntStat after IntRoutine");
+ goto Start_ISAC;
+ }
+ if (stat & 2) {
+ writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0xFF);
+ writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0x0);
+ }
+}
+
+static void
+TeleInt_Timer(struct IsdnCardState *cs)
+{
+ int stat = 0;
+
+ if (cs->bcs[0].mode) {
+ stat |= 1;
+ main_irq_hfc(&cs->bcs[0]);
+ }
+ if (cs->bcs[1].mode) {
+ stat |= 2;
+ main_irq_hfc(&cs->bcs[1]);
+ }
+ cs->hw.hfc.timer.expires = jiffies + 1;
+ add_timer(&cs->hw.hfc.timer);
+}
+
+void
+release_io_TeleInt(struct IsdnCardState *cs)
+{
+ del_timer(&cs->hw.hfc.timer);
+ releasehfc(cs);
+ if (cs->hw.hfc.addr)
+ release_region(cs->hw.hfc.addr, 2);
+}
+
+static void
+reset_TeleInt(struct IsdnCardState *cs)
+{
+ long flags;
+
+ printk(KERN_INFO "TeleInt: resetting card\n");
+ cs->hw.hfc.cirm |= HFC_RESET;
+ byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset On */
+ save_flags(flags);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 3;
+ schedule();
+ cs->hw.hfc.cirm &= ~HFC_RESET;
+ byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ restore_flags(flags);
+}
+
+static int
+TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ reset_TeleInt(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_TeleInt(cs);
+ return(0);
+ case CARD_SETIRQ:
+ return(request_irq(cs->irq, &TeleInt_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs));
+ case CARD_INIT:
+ inithfc(cs);
+ clear_pending_isac_ints(cs);
+ initisac(cs);
+ cs->hw.hfc.timer.expires = jiffies + 1;
+ add_timer(&cs->hw.hfc.timer);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
+}
+
+__initfunc(int
+setup_TeleInt(struct IsdnCard *card))
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, TeleInt_revision);
+ printk(KERN_INFO "HiSax: TeleInt driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_TELEINT)
+ return (0);
+
+ cs->hw.hfc.addr = card->para[1] & 0x3fe;
+ cs->irq = card->para[0];
+ cs->hw.hfc.cirm = HFC_CIRM;
+ cs->hw.hfc.isac_spcr = 0x00;
+ cs->hw.hfc.cip = 0;
+ cs->hw.hfc.ctmt = HFC_CTMT | HFC_CLTIMER;
+ cs->bcs[0].hw.hfc.send = NULL;
+ cs->bcs[1].hw.hfc.send = NULL;
+ cs->hw.hfc.fifosize = 7 * 1024 + 512;
+ cs->hw.hfc.timer.function = (void *) TeleInt_Timer;
+ cs->hw.hfc.timer.data = (long) cs;
+ init_timer(&cs->hw.hfc.timer);
+ if (check_region((cs->hw.hfc.addr), 2)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.hfc.addr,
+ cs->hw.hfc.addr + 2);
+ return (0);
+ } else {
+ request_region(cs->hw.hfc.addr, 2, "TeleInt isdn");
+ }
+ /* HW IO = IO */
+ byteout(cs->hw.hfc.addr, cs->hw.hfc.addr & 0xff);
+ byteout(cs->hw.hfc.addr | 1, ((cs->hw.hfc.addr & 0x300) >> 8) | 0x54);
+ switch (cs->irq) {
+ case 3:
+ cs->hw.hfc.cirm |= HFC_INTA;
+ break;
+ case 4:
+ cs->hw.hfc.cirm |= HFC_INTB;
+ break;
+ case 5:
+ cs->hw.hfc.cirm |= HFC_INTC;
+ break;
+ case 7:
+ cs->hw.hfc.cirm |= HFC_INTD;
+ break;
+ case 10:
+ cs->hw.hfc.cirm |= HFC_INTE;
+ break;
+ case 11:
+ cs->hw.hfc.cirm |= HFC_INTF;
+ break;
+ default:
+ printk(KERN_WARNING "TeleInt: wrong IRQ\n");
+ release_io_TeleInt(cs);
+ return (0);
+ }
+ byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);
+ byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.ctmt);
+
+ printk(KERN_INFO
+ "TeleInt: defined at 0x%x IRQ %d\n",
+ cs->hw.hfc.addr,
+ cs->irq);
+
+ reset_TeleInt(cs);
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ cs->BC_Read_Reg = &ReadHFC;
+ cs->BC_Write_Reg = &WriteHFC;
+ cs->cardmsg = &TeleInt_card_msg;
+ ISACVersion(cs, "TeleInt:");
+ return (1);
+}
diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c
index 6aaba70d3..7cd173154 100644
--- a/drivers/isdn/hisax/teles0.c
+++ b/drivers/isdn/hisax/teles0.c
@@ -1,4 +1,4 @@
-/* $Id: teles0.c,v 1.8 1997/04/13 19:54:04 keil Exp $
+/* $Id: teles0.c,v 2.6 1998/02/03 23:27:47 keil Exp $
* teles0.c low level stuff for Teles Memory IO isdn cards
* based on the teles driver from Jan den Ouden
@@ -10,71 +10,73 @@
* Beat Doebeli
*
* $Log: teles0.c,v $
- * Revision 1.8 1997/04/13 19:54:04 keil
- * Change in IRQ check delay for SMP
+ * Revision 2.6 1998/02/03 23:27:47 keil
+ * IRQ 9
*
- * Revision 1.7 1997/04/06 22:54:04 keil
- * Using SKB's
+ * Revision 2.5 1998/02/02 13:29:47 keil
+ * fast io
*
- * Revision 1.6 1997/01/27 15:52:18 keil
- * SMP proof,cosmetics
+ * Revision 2.4 1997/11/08 21:35:54 keil
+ * new l1 init
*
- * Revision 1.5 1997/01/21 22:25:59 keil
- * cleanups
+ * Revision 2.3 1997/11/06 17:09:31 keil
+ * New 2.1 init code
*
- * Revision 1.4 1996/11/05 19:41:27 keil
- * more changes for 2.1
+ * Revision 2.2 1997/10/29 18:55:57 keil
+ * changes for 2.1.60 (irq2dev_map)
*
- * Revision 1.3 1996/10/30 10:22:58 keil
- * Changes for 2.1 kernels
+ * Revision 2.1 1997/07/27 21:47:10 keil
+ * new interface structures
*
- * Revision 1.2 1996/10/27 22:08:34 keil
- * cosmetic changes
+ * Revision 2.0 1997/06/26 11:02:43 keil
+ * New Layer and card interface
*
- * Revision 1.1 1996/10/13 20:04:58 keil
- * Initial revision
+ * Revision 1.8 1997/04/13 19:54:04 keil
+ * Change in IRQ check delay for SMP
*
+ * Revision 1.7 1997/04/06 22:54:04 keil
+ * Using SKB's
*
+ * removed old log info /KKe
*
*/
#define __NO_VERSION__
-#include "siemens.h"
#include "hisax.h"
-#include "teles0.h"
#include "isdnl1.h"
-#include <linux/kernel_stat.h>
+#include "isac.h"
+#include "hscx.h"
extern const char *CardType[];
-const char *teles0_revision = "$Revision: 1.8 $";
+const char *teles0_revision = "$Revision: 2.6 $";
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
static inline u_char
readisac(unsigned int adr, u_char off)
{
- return readb(adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off);
+ return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off);
}
static inline void
writeisac(unsigned int adr, u_char off, u_char data)
{
- writeb(data, adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off);
+ writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off);
}
static inline u_char
readhscx(unsigned int adr, int hscx, u_char off)
{
- return readb(adr + (hscx ? 0x1e0 : 0x1a0) +
+ return readb(adr + (hscx ? 0x1c0 : 0x180) +
((off & 1) ? 0x1ff : 0) + off);
}
static inline void
writehscx(unsigned int adr, int hscx, u_char off, u_char data)
{
- writeb(data, adr + (hscx ? 0x1e0 : 0x1a0) +
+ writeb(data, adr + (hscx ? 0x1c0 : 0x180) +
((off & 1) ? 0x1ff : 0) + off);
}
@@ -87,7 +89,7 @@ read_fifo_isac(unsigned int adr, u_char * data, int size)
data[i] = readb(ad);
}
-static void
+static inline void
write_fifo_isac(unsigned int adr, u_char * data, int size)
{
register int i;
@@ -113,745 +115,204 @@ write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
for (i = 0; i < size; i++)
writeb(data[i], ad);
}
-static inline void
-waitforCEC(int adr, int hscx)
-{
- int to = 50;
-
- while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "Teles0: waitforCEC timeout\n");
-}
+/* Interface functions */
-static inline void
-waitforXFW(int adr, int hscx)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
{
- int to = 50;
-
- while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "Teles0: waitforXFW timeout\n");
+ return (readisac(cs->hw.teles0.membase, offset));
}
-static inline void
-writehscxCMDR(int adr, int hscx, u_char data)
-{
- long flags;
-
- save_flags(flags);
- cli();
- waitforCEC(adr, hscx);
- writehscx(adr, hscx, HSCX_CMDR, data);
- restore_flags(flags);
-}
-
-/*
- * fast interrupt here
- */
-
-
static void
-hscxreport(struct IsdnCardState *sp, int hscx)
-{
- printk(KERN_DEBUG "HSCX %d\n", hscx);
- printk(KERN_DEBUG "ISTA %x\n", readhscx(sp->membase, hscx, HSCX_ISTA));
- printk(KERN_DEBUG "STAR %x\n", readhscx(sp->membase, hscx, HSCX_STAR));
- printk(KERN_DEBUG "EXIR %x\n", readhscx(sp->membase, hscx, HSCX_EXIR));
-}
-
-void
-teles0_report(struct IsdnCardState *sp)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
- printk(KERN_DEBUG "ISAC\n");
- printk(KERN_DEBUG "ISTA %x\n", readisac(sp->membase, ISAC_ISTA));
- printk(KERN_DEBUG "STAR %x\n", readisac(sp->membase, ISAC_STAR));
- printk(KERN_DEBUG "EXIR %x\n", readisac(sp->membase, ISAC_EXIR));
- hscxreport(sp, 0);
- hscxreport(sp, 1);
+ writeisac(cs->hw.teles0.membase, offset, value);
}
-/*
- * HSCX stuff goes here
- */
-
static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
- u_char *ptr;
- struct IsdnCardState *sp = hsp->sp;
- long flags;
-
- if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
- debugl1(sp, "hscx_empty_fifo");
-
- if (hsp->rcvidx + count > HSCX_BUFMAX) {
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "hscx_empty_fifo: incoming packet too large");
- writehscxCMDR(sp->membase, hsp->hscx, 0x80);
- hsp->rcvidx = 0;
- return;
- }
- ptr = hsp->rcvbuf + hsp->rcvidx;
- hsp->rcvidx += count;
- save_flags(flags);
- cli();
- read_fifo_hscx(sp->membase, hsp->hscx, ptr, count);
- writehscxCMDR(sp->membase, hsp->hscx, 0x80);
- restore_flags(flags);
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "hscx_empty_fifo %c cnt %d",
- hsp->hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ read_fifo_isac(cs->hw.teles0.membase, data, size);
}
static void
-hscx_fill_fifo(struct HscxState *hsp)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
- struct IsdnCardState *sp = hsp->sp;
- int more, count;
- u_char *ptr;
- long flags;
-
- if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
- debugl1(sp, "hscx_fill_fifo");
-
- if (!hsp->tx_skb)
- return;
- if (hsp->tx_skb->len <= 0)
- return;
-
- more = (hsp->mode == 1) ? 1 : 0;
- if (hsp->tx_skb->len > 32) {
- more = !0;
- count = 32;
- } else
- count = hsp->tx_skb->len;
-
- waitforXFW(sp->membase, hsp->hscx);
- save_flags(flags);
- cli();
- ptr = hsp->tx_skb->data;
- skb_pull(hsp->tx_skb, count);
- hsp->tx_cnt -= count;
- hsp->count += count;
- write_fifo_hscx(sp->membase, hsp->hscx, ptr, count);
- writehscxCMDR(sp->membase, hsp->hscx, more ? 0x8 : 0xa);
- restore_flags(flags);
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "hscx_fill_fifo %c cnt %d",
- hsp->hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ write_fifo_isac(cs->hw.teles0.membase, data, size);
}
-static inline void
-hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
- u_char r;
- struct HscxState *hsp = sp->hs + hscx;
- struct sk_buff *skb;
- int count;
- char tmp[32];
-
- if (!hsp->init)
- return;
-
- if (val & 0x80) { /* RME */
-
- r = readhscx(sp->membase, hsp->hscx, HSCX_RSTA);
- if ((r & 0xf0) != 0xa0) {
- if (!r & 0x80)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "HSCX invalid frame");
- if ((r & 0x40) && hsp->mode)
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX RDO mode=%d",
- hsp->mode);
- debugl1(sp, tmp);
- }
- if (!r & 0x20)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "HSCX CRC error");
- writehscxCMDR(sp->membase, hsp->hscx, 0x80);
- } else {
- count = readhscx(sp->membase, hsp->hscx, HSCX_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- hscx_empty_fifo(hsp, count);
- if ((count = hsp->rcvidx - 1) > 0) {
- if (!(skb = dev_alloc_skb(count)))
- printk(KERN_WARNING "AVM: receive out of memory\n");
- else {
- memcpy(skb_put(skb, count), hsp->rcvbuf, count);
- skb_queue_tail(&hsp->rqueue, skb);
- }
- }
- }
- hsp->rcvidx = 0;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- hscx_empty_fifo(hsp, 32);
- if (hsp->mode == 1) {
- /* receive audio data */
- if (!(skb = dev_alloc_skb(32)))
- printk(KERN_WARNING "AVM: receive out of memory\n");
- else {
- memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
- skb_queue_tail(&hsp->rqueue, skb);
- }
- hsp->rcvidx = 0;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- }
- if (val & 0x10) { /* XPR */
- if (hsp->tx_skb)
- if (hsp->tx_skb->len) {
- hscx_fill_fifo(hsp);
- return;
- } else {
- SET_SKB_FREE(hsp->tx_skb);
- dev_kfree_skb(hsp->tx_skb);
- hsp->count = 0;
- if (hsp->st->l4.l1writewakeup)
- hsp->st->l4.l1writewakeup(hsp->st);
- hsp->tx_skb = NULL;
- }
- if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
- hsp->count = 0;
- hscx_fill_fifo(hsp);
- } else
- hscx_sched_event(hsp, HSCX_XMTBUFREADY);
- }
+ return (readhscx(cs->hw.teles0.membase, hscx, offset));
}
-/*
- * ISAC stuff goes here
- */
-
static void
-isac_empty_fifo(struct IsdnCardState *sp, int count)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
- u_char *ptr;
- long flags;
-
- if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
- debugl1(sp, "isac_empty_fifo");
-
- if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
- if (sp->debug & L1_DEB_WARN) {
- char tmp[40];
- sprintf(tmp, "isac_empty_fifo overrun %d",
- sp->rcvidx + count);
- debugl1(sp, tmp);
- }
- writeisac(sp->membase, ISAC_CMDR, 0x80);
- sp->rcvidx = 0;
- return;
- }
- ptr = sp->rcvbuf + sp->rcvidx;
- sp->rcvidx += count;
- save_flags(flags);
- cli();
- read_fifo_isac(sp->membase, ptr, count);
- writeisac(sp->membase, ISAC_CMDR, 0x80);
- restore_flags(flags);
- if (sp->debug & L1_DEB_ISAC_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "isac_empty_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ writehscx(cs->hw.teles0.membase, hscx, offset, value);
}
-static void
-isac_fill_fifo(struct IsdnCardState *sp)
-{
- int count, more;
- u_char *ptr;
- long flags;
-
- if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
- debugl1(sp, "isac_fill_fifo");
-
- if (!sp->tx_skb)
- return;
-
- count = sp->tx_skb->len;
- if (count <= 0)
- return;
-
- more = 0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- save_flags(flags);
- cli();
- ptr = sp->tx_skb->data;
- skb_pull(sp->tx_skb, count);
- sp->tx_cnt += count;
- write_fifo_isac(sp->membase, ptr, count);
- writeisac(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa);
- restore_flags(flags);
- if (sp->debug & L1_DEB_ISAC_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "isac_fill_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
-}
-
-static void
-ph_command(struct IsdnCardState *sp, unsigned int command)
-{
- if (sp->debug & L1_DEB_ISAC) {
- char tmp[32];
- sprintf(tmp, "ph_command %d", command);
- debugl1(sp, tmp);
- }
- writeisac(sp->membase, ISAC_CIX0, (command << 2) | 3);
-}
-
-static inline void
-isac_interrupt(struct IsdnCardState *sp, u_char val)
-{
- u_char exval;
- struct sk_buff *skb;
- unsigned int count;
- char tmp[32];
-
- if (sp->debug & L1_DEB_ISAC) {
- sprintf(tmp, "ISAC interrupt %x", val);
- debugl1(sp, tmp);
- }
- if (val & 0x80) { /* RME */
- exval = readisac(sp->membase, ISAC_RSTA);
- if ((exval & 0x70) != 0x20) {
- if (exval & 0x40)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC RDO");
- if (!exval & 0x20)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC CRC error");
- writeisac(sp->membase, ISAC_CMDR, 0x80);
- } else {
- count = readisac(sp->membase, ISAC_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- isac_empty_fifo(sp, count);
- if ((count = sp->rcvidx) > 0) {
- if (!(skb = alloc_skb(count, GFP_ATOMIC)))
- printk(KERN_WARNING "AVM: D receive out of memory\n");
- else {
- memcpy(skb_put(skb, count), sp->rcvbuf, count);
- skb_queue_tail(&sp->rq, skb);
- }
- }
- }
- sp->rcvidx = 0;
- isac_sched_event(sp, ISAC_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- isac_empty_fifo(sp, 32);
- }
- if (val & 0x20) { /* RSC */
- /* never */
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC RSC interrupt");
- }
- if (val & 0x10) { /* XPR */
- if (sp->tx_skb)
- if (sp->tx_skb->len) {
- isac_fill_fifo(sp);
- goto afterXPR;
- } else {
- SET_SKB_FREE(sp->tx_skb);
- dev_kfree_skb(sp->tx_skb);
- sp->tx_cnt = 0;
- sp->tx_skb = NULL;
- }
- if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
- sp->tx_cnt = 0;
- isac_fill_fifo(sp);
- } else
- isac_sched_event(sp, ISAC_XMTBUFREADY);
- }
- afterXPR:
- if (val & 0x04) { /* CISQ */
- sp->ph_state = (readisac(sp->membase, ISAC_CIX0) >> 2)
- & 0xf;
- if (sp->debug & L1_DEB_ISAC) {
- sprintf(tmp, "l1state %d", sp->ph_state);
- debugl1(sp, tmp);
- }
- isac_new_ph(sp);
- }
- if (val & 0x02) { /* SIN */
- /* never */
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC SIN interrupt");
- }
- if (val & 0x01) { /* EXI */
- exval = readisac(sp->membase, ISAC_EXIR);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "ISAC EXIR %02x", exval);
- debugl1(sp, tmp);
- }
- }
-}
+/*
+ * fast interrupt HSCX stuff goes here
+ */
-static inline void
-hscx_int_main(struct IsdnCardState *sp, u_char val)
-{
+#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg)
+#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
- u_char exval;
- struct HscxState *hsp;
- char tmp[32];
-
-
- if (val & 0x01) {
- hsp = sp->hs + 1;
- exval = readhscx(sp->membase, 1, HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (hsp->tx_skb) {
- skb_push(hsp->tx_skb, hsp->count);
- hsp->tx_cnt += hsp->count;
- hsp->count = 0;
- }
- writehscxCMDR(sp->membase, hsp->hscx, 0x01);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
- debugl1(sp, tmp);
- }
- }
- } else if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX B EXIR %x", exval);
- debugl1(sp, tmp);
- }
- }
- if (val & 0xf8) {
- if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX B interrupt %x", val);
- debugl1(sp, tmp);
- }
- hscx_interrupt(sp, val, 1);
- }
- if (val & 0x02) {
- hsp = sp->hs;
- exval = readhscx(sp->membase, 0, HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (hsp->tx_skb) {
- skb_push(hsp->tx_skb, hsp->count);
- hsp->tx_cnt += hsp->count;
- hsp->count = 0;
- }
- writehscxCMDR(sp->membase, hsp->hscx, 0x01);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
- debugl1(sp, tmp);
- }
- }
- } else if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX A EXIR %x", exval);
- debugl1(sp, tmp);
- }
- }
- if (val & 0x04) {
- exval = readhscx(sp->membase, 0, HSCX_ISTA);
- if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX A interrupt %x", exval);
- debugl1(sp, tmp);
- }
- hscx_interrupt(sp, exval, 0);
- }
-}
+#include "hscx_irq.c"
static void
-telesS0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
- struct IsdnCardState *sp;
+ struct IsdnCardState *cs = dev_id;
u_char val, stat = 0;
+ int count = 0;
- sp = (struct IsdnCardState *) dev_id;
-
- if (!sp) {
+ if (!cs) {
printk(KERN_WARNING "Teles0: Spurious interrupt!\n");
return;
}
- val = readhscx(sp->membase, 1, HSCX_ISTA);
+ val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
Start_HSCX:
if (val) {
- hscx_int_main(sp, val);
+ hscx_int_main(cs, val);
stat |= 1;
}
- val = readisac(sp->membase, ISAC_ISTA);
+ val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
Start_ISAC:
if (val) {
- isac_interrupt(sp, val);
+ isac_interrupt(cs, val);
stat |= 2;
}
- val = readhscx(sp->membase, 1, HSCX_ISTA);
- if (val) {
- if (sp->debug & L1_DEB_HSCX)
- debugl1(sp, "HSCX IntStat after IntRoutine");
+ count++;
+ val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
+ if (val && count < 20) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
- val = readisac(sp->membase, ISAC_ISTA);
- if (val) {
- if (sp->debug & L1_DEB_ISAC)
- debugl1(sp, "ISAC IntStat after IntRoutine");
+ val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
+ if (val && count < 20) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
if (stat & 1) {
- writehscx(sp->membase, 0, HSCX_MASK, 0xFF);
- writehscx(sp->membase, 1, HSCX_MASK, 0xFF);
- writehscx(sp->membase, 0, HSCX_MASK, 0x0);
- writehscx(sp->membase, 1, HSCX_MASK, 0x0);
+ writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
+ writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
+ writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
+ writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
}
if (stat & 2) {
- writeisac(sp->membase, ISAC_MASK, 0xFF);
- writeisac(sp->membase, ISAC_MASK, 0x0);
+ writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
+ writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
}
}
-
-static void
-initisac(struct IsdnCardState *sp)
-{
- unsigned int adr = sp->membase;
-
- /* 16.0 IOM 1 Mode */
- writeisac(adr, ISAC_MASK, 0xff);
- writeisac(adr, ISAC_ADF2, 0x0);
- writeisac(adr, ISAC_SPCR, 0xa);
- writeisac(adr, ISAC_ADF1, 0x2);
- writeisac(adr, ISAC_STCR, 0x70);
- writeisac(adr, ISAC_MODE, 0xc9);
- writeisac(adr, ISAC_CMDR, 0x41);
- writeisac(adr, ISAC_CIX0, (1 << 2) | 3);
- writeisac(adr, ISAC_MASK, 0xff);
- writeisac(adr, ISAC_MASK, 0x0);
-}
-
-static void
-modehscx(struct HscxState *hs, int mode, int ichan)
-{
- struct IsdnCardState *sp = hs->sp;
- int hscx = hs->hscx;
-
- if (sp->debug & L1_DEB_HSCX) {
- char tmp[40];
- sprintf(tmp, "hscx %c mode %d ichan %d",
- 'A' + hscx, mode, ichan);
- debugl1(sp, tmp);
- }
- hs->mode = mode;
- writehscx(sp->membase, hscx, HSCX_CCR1, 0x85);
- writehscx(sp->membase, hscx, HSCX_XAD1, 0xFF);
- writehscx(sp->membase, hscx, HSCX_XAD2, 0xFF);
- writehscx(sp->membase, hscx, HSCX_RAH2, 0xFF);
- writehscx(sp->membase, hscx, HSCX_XBCH, 0x0);
-
- /* Switch IOM 1 SSI */
- if (hscx == 0)
- ichan = 1 - ichan;
-
- switch (mode) {
- case (0):
- writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx(sp->membase, hscx, HSCX_TSAX, 0xff);
- writehscx(sp->membase, hscx, HSCX_TSAR, 0xff);
- writehscx(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx(sp->membase, hscx, HSCX_RCCR, 7);
- writehscx(sp->membase, hscx, HSCX_MODE, 0x84);
- break;
- case (1):
- if (ichan == 0) {
- writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx(sp->membase, hscx, HSCX_TSAX, 0x7);
- writehscx(sp->membase, hscx, HSCX_TSAR, 0x7);
- writehscx(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx(sp->membase, hscx, HSCX_RCCR, 7);
- } else {
- writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx(sp->membase, hscx, HSCX_TSAX, 0x3);
- writehscx(sp->membase, hscx, HSCX_TSAR, 0x3);
- writehscx(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx(sp->membase, hscx, HSCX_RCCR, 7);
- }
- writehscx(sp->membase, hscx, HSCX_MODE, 0xe4);
- writehscx(sp->membase, hscx, HSCX_CMDR, 0x41);
- break;
- case (2):
- if (ichan == 0) {
- writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx(sp->membase, hscx, HSCX_TSAX, 0x7);
- writehscx(sp->membase, hscx, HSCX_TSAR, 0x7);
- writehscx(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx(sp->membase, hscx, HSCX_RCCR, 7);
- } else {
- writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx(sp->membase, hscx, HSCX_TSAX, 0x3);
- writehscx(sp->membase, hscx, HSCX_TSAR, 0x3);
- writehscx(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx(sp->membase, hscx, HSCX_RCCR, 7);
- }
- writehscx(sp->membase, hscx, HSCX_MODE, 0x8c);
- writehscx(sp->membase, hscx, HSCX_CMDR, 0x41);
- break;
- }
- writehscx(sp->membase, hscx, HSCX_ISTA, 0x00);
-}
-
void
-release_io_teles0(struct IsdnCard *card)
+release_io_teles0(struct IsdnCardState *cs)
{
- if (card->sp->cfg_reg)
- release_region(card->sp->cfg_reg, 8);
+ if (cs->hw.teles0.cfg_reg)
+ release_region(cs->hw.teles0.cfg_reg, 8);
}
-static void
-clear_pending_ints(struct IsdnCardState *sp)
+static int
+reset_teles0(struct IsdnCardState *cs)
{
- int val;
- char tmp[64];
+ u_char cfval;
+ long flags;
- val = readhscx(sp->membase, 1, HSCX_ISTA);
- sprintf(tmp, "HSCX B ISTA %x", val);
- debugl1(sp, tmp);
- if (val & 0x01) {
- val = readhscx(sp->membase, 1, HSCX_EXIR);
- sprintf(tmp, "HSCX B EXIR %x", val);
- debugl1(sp, tmp);
- } else if (val & 0x02) {
- val = readhscx(sp->membase, 0, HSCX_EXIR);
- sprintf(tmp, "HSCX A EXIR %x", val);
- debugl1(sp, tmp);
- }
- val = readhscx(sp->membase, 0, HSCX_ISTA);
- sprintf(tmp, "HSCX A ISTA %x", val);
- debugl1(sp, tmp);
- val = readhscx(sp->membase, 1, HSCX_STAR);
- sprintf(tmp, "HSCX B STAR %x", val);
- debugl1(sp, tmp);
- val = readhscx(sp->membase, 0, HSCX_STAR);
- sprintf(tmp, "HSCX A STAR %x", val);
- debugl1(sp, tmp);
- val = readisac(sp->membase, ISAC_STAR);
- sprintf(tmp, "ISAC STAR %x", val);
- debugl1(sp, tmp);
- val = readisac(sp->membase, ISAC_MODE);
- sprintf(tmp, "ISAC MODE %x", val);
- debugl1(sp, tmp);
- val = readisac(sp->membase, ISAC_ADF2);
- sprintf(tmp, "ISAC ADF2 %x", val);
- debugl1(sp, tmp);
- val = readisac(sp->membase, ISAC_ISTA);
- sprintf(tmp, "ISAC ISTA %x", val);
- debugl1(sp, tmp);
- if (val & 0x01) {
- val = readisac(sp->membase, ISAC_EXIR);
- sprintf(tmp, "ISAC EXIR %x", val);
- debugl1(sp, tmp);
- } else if (val & 0x04) {
- val = readisac(sp->membase, ISAC_CIR0);
- sprintf(tmp, "ISAC CIR0 %x", val);
- debugl1(sp, tmp);
+ save_flags(flags);
+ sti();
+ if (cs->hw.teles0.cfg_reg) {
+ switch (cs->irq) {
+ case 2:
+ case 9:
+ cfval = 0x00;
+ break;
+ case 3:
+ cfval = 0x02;
+ break;
+ case 4:
+ cfval = 0x04;
+ break;
+ case 5:
+ cfval = 0x06;
+ break;
+ case 10:
+ cfval = 0x08;
+ break;
+ case 11:
+ cfval = 0x0A;
+ break;
+ case 12:
+ cfval = 0x0C;
+ break;
+ case 15:
+ cfval = 0x0E;
+ break;
+ default:
+ return(1);
+ }
+ cfval |= ((cs->hw.teles0.membase >> 9) & 0xF0);
+ byteout(cs->hw.teles0.cfg_reg + 4, cfval);
+ HZDELAY(HZ / 10 + 1);
+ byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1);
+ HZDELAY(HZ / 10 + 1);
}
- writeisac(sp->membase, ISAC_MASK, 0);
- writeisac(sp->membase, ISAC_CMDR, 0x41);
+ writeb(0, cs->hw.teles0.membase + 0x80);
+ HZDELAY(HZ / 5 + 1);
+ writeb(1, cs->hw.teles0.membase + 0x80);
+ HZDELAY(HZ / 5 + 1);
+ restore_flags(flags);
+ return(0);
}
-int
-initteles0(struct IsdnCardState *sp)
+static int
+Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
- int ret;
- int loop = 0;
- char tmp[40];
-
- sp->counter = kstat_irqs(sp->irq);
- sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
- debugl1(sp, tmp);
- clear_pending_ints(sp);
- ret = get_irq(sp->cardnr, &telesS0_interrupt);
- if (ret) {
- initisac(sp);
- sp->modehscx(sp->hs, 0, 0);
- sp->modehscx(sp->hs + 1, 0, 0);
- while (loop++ < 10) {
- /* At least 1-3 irqs must happen
- * (one from HSCX A, one from HSCX B, 3rd from ISAC)
- */
- if (kstat_irqs(sp->irq) > sp->counter)
- break;
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + 1;
- schedule();
- }
- sprintf(tmp, "IRQ %d count %d", sp->irq,
- kstat_irqs(sp->irq));
- debugl1(sp, tmp);
- if (kstat_irqs(sp->irq) == sp->counter) {
- printk(KERN_WARNING
- "Teles0: IRQ(%d) getting no interrupts during init\n",
- sp->irq);
- free_irq(sp->irq, sp);
- return (0);
- }
- }
- return (ret);
+ switch (mt) {
+ case CARD_RESET:
+ reset_teles0(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_teles0(cs);
+ return(0);
+ case CARD_SETIRQ:
+ return(request_irq(cs->irq, &teles0_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs));
+ case CARD_INIT:
+ clear_pending_isac_ints(cs);
+ clear_pending_hscx_ints(cs);
+ initisac(cs);
+ inithscx(cs);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
}
-int
-setup_teles0(struct IsdnCard *card)
+__initfunc(int
+setup_teles0(struct IsdnCard *card))
{
- u_char cfval, val, verA, verB;
- struct IsdnCardState *sp = card->sp;
- long flags;
+ u_char val;
+ struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, teles0_revision);
- printk(KERN_NOTICE "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp));
- if ((sp->typ != ISDN_CTYPE_16_0) && (sp->typ != ISDN_CTYPE_8_0))
+ printk(KERN_INFO "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp));
+ if ((cs->typ != ISDN_CTYPE_16_0) && (cs->typ != ISDN_CTYPE_8_0))
return (0);
- if (sp->typ == ISDN_CTYPE_16_0)
- sp->cfg_reg = card->para[2];
+ if (cs->typ == ISDN_CTYPE_16_0)
+ cs->hw.teles0.cfg_reg = card->para[2];
else /* 8.0 */
- sp->cfg_reg = 0;
+ cs->hw.teles0.cfg_reg = 0;
if (card->para[1] < 0x10000) {
card->para[1] <<= 4;
@@ -859,110 +320,69 @@ setup_teles0(struct IsdnCard *card)
"Teles0: membase configured DOSish, assuming 0x%lx\n",
(unsigned long) card->para[1]);
}
- sp->membase = card->para[1];
- sp->irq = card->para[0];
- if (sp->cfg_reg) {
- if (check_region((sp->cfg_reg), 8)) {
+ cs->hw.teles0.membase = card->para[1];
+ cs->irq = card->para[0];
+ if (cs->hw.teles0.cfg_reg) {
+ if (check_region((cs->hw.teles0.cfg_reg), 8)) {
printk(KERN_WARNING
"HiSax: %s config port %x-%x already in use\n",
CardType[card->typ],
- sp->cfg_reg,
- sp->cfg_reg + 8);
+ cs->hw.teles0.cfg_reg,
+ cs->hw.teles0.cfg_reg + 8);
return (0);
} else {
- request_region(sp->cfg_reg, 8, "teles cfg");
+ request_region(cs->hw.teles0.cfg_reg, 8, "teles cfg");
}
}
- switch (sp->irq) {
- case 2:
- cfval = 0x00;
- break;
- case 3:
- cfval = 0x02;
- break;
- case 4:
- cfval = 0x04;
- break;
- case 5:
- cfval = 0x06;
- break;
- case 10:
- cfval = 0x08;
- break;
- case 11:
- cfval = 0x0A;
- break;
- case 12:
- cfval = 0x0C;
- break;
- case 15:
- cfval = 0x0E;
- break;
- default:
- cfval = 0x00;
- break;
- }
- cfval |= ((card->para[1] >> 9) & 0xF0);
- if (sp->cfg_reg) {
- if ((val = bytein(sp->cfg_reg + 0)) != 0x51) {
+ if (cs->hw.teles0.cfg_reg) {
+ if ((val = bytein(cs->hw.teles0.cfg_reg + 0)) != 0x51) {
printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
- sp->cfg_reg + 0, val);
- release_region(sp->cfg_reg, 8);
+ cs->hw.teles0.cfg_reg + 0, val);
+ release_region(cs->hw.teles0.cfg_reg, 8);
return (0);
}
- if ((val = bytein(sp->cfg_reg + 1)) != 0x93) {
+ if ((val = bytein(cs->hw.teles0.cfg_reg + 1)) != 0x93) {
printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
- sp->cfg_reg + 1, val);
- release_region(sp->cfg_reg, 8);
+ cs->hw.teles0.cfg_reg + 1, val);
+ release_region(cs->hw.teles0.cfg_reg, 8);
return (0);
}
- val = bytein(sp->cfg_reg + 2); /* 0x1e=without AB
- * 0x1f=with AB
- * 0x1c 16.3 ???
- */
+ val = bytein(cs->hw.teles0.cfg_reg + 2); /* 0x1e=without AB
+ * 0x1f=with AB
+ * 0x1c 16.3 ???
+ */
if (val != 0x1e && val != 0x1f) {
printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
- sp->cfg_reg + 2, val);
- release_region(sp->cfg_reg, 8);
+ cs->hw.teles0.cfg_reg + 2, val);
+ release_region(cs->hw.teles0.cfg_reg, 8);
return (0);
}
- save_flags(flags);
- byteout(sp->cfg_reg + 4, cfval);
- sti();
- HZDELAY(HZ / 10 + 1);
- byteout(sp->cfg_reg + 4, cfval | 1);
- HZDELAY(HZ / 10 + 1);
- restore_flags(flags);
}
- printk(KERN_NOTICE
- "HiSax: %s config irq:%d mem:%x cfg:%x\n",
- CardType[sp->typ], sp->irq,
- sp->membase, sp->cfg_reg);
- verA = readhscx(sp->membase, 0, HSCX_VSTR) & 0xf;
- verB = readhscx(sp->membase, 1, HSCX_VSTR) & 0xf;
- printk(KERN_INFO "Teles0: HSCX version A: %s B: %s\n",
- HscxVersion(verA), HscxVersion(verB));
- val = readisac(sp->membase, ISAC_RBCH);
- printk(KERN_INFO "Teles0: ISAC %s\n",
- ISACVersion(val));
-
- if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
+ /* 16.0 and 8.0 designed for IOM1 */
+ test_and_set_bit(HW_IOM1, &cs->HW_Flags);
+ printk(KERN_INFO
+ "HiSax: %s config irq:%d mem:0x%X cfg:0x%X\n",
+ CardType[cs->typ], cs->irq,
+ cs->hw.teles0.membase, cs->hw.teles0.cfg_reg);
+ if (reset_teles0(cs)) {
+ printk(KERN_WARNING "Teles0: wrong IRQ\n");
+ release_io_teles0(cs);
+ return (0);
+ }
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ cs->BC_Read_Reg = &ReadHSCX;
+ cs->BC_Write_Reg = &WriteHSCX;
+ cs->BC_Send_Data = &hscx_fill_fifo;
+ cs->cardmsg = &Teles_card_msg;
+ ISACVersion(cs, "Teles0:");
+ if (HscxVersion(cs, "Teles0:")) {
printk(KERN_WARNING
"Teles0: wrong HSCX versions check IO/MEM addresses\n");
- release_io_teles0(card);
+ release_io_teles0(cs);
return (0);
}
- save_flags(flags);
- writeb(0, sp->membase + 0x80);
- sti();
- HZDELAY(HZ / 5 + 1);
- writeb(1, sp->membase + 0x80);
- HZDELAY(HZ / 5 + 1);
- restore_flags(flags);
-
- sp->modehscx = &modehscx;
- sp->ph_command = &ph_command;
- sp->hscx_fill_fifo = &hscx_fill_fifo;
- sp->isac_fill_fifo = &isac_fill_fifo;
return (1);
}
diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
index 4b92e5ab7..261d054fb 100644
--- a/drivers/isdn/hisax/teles3.c
+++ b/drivers/isdn/hisax/teles3.c
@@ -1,4 +1,4 @@
-/* $Id: teles3.c,v 1.11 1997/04/13 19:54:05 keil Exp $
+/* $Id: teles3.c,v 2.7 1998/02/02 13:29:48 keil Exp $
* teles3.c low level stuff for Teles 16.3 & PNP isdn cards
*
@@ -11,6 +11,30 @@
* Beat Doebeli
*
* $Log: teles3.c,v $
+ * Revision 2.7 1998/02/02 13:29:48 keil
+ * fast io
+ *
+ * Revision 2.6 1997/11/13 16:22:44 keil
+ * COMPAQ_ISA reset
+ *
+ * Revision 2.5 1997/11/12 15:01:25 keil
+ * COMPAQ_ISA changes
+ *
+ * Revision 2.4 1997/11/08 21:35:56 keil
+ * new l1 init
+ *
+ * Revision 2.3 1997/11/06 17:09:33 keil
+ * New 2.1 init code
+ *
+ * Revision 2.2 1997/10/29 18:55:59 keil
+ * changes for 2.1.60 (irq2dev_map)
+ *
+ * Revision 2.1 1997/07/27 21:47:12 keil
+ * new interface structures
+ *
+ * Revision 2.0 1997/06/26 11:02:46 keil
+ * New Layer and card interface
+ *
* Revision 1.11 1997/04/13 19:54:05 keil
* Change in IRQ check delay for SMP
*
@@ -35,36 +59,20 @@
* Revision 1.6 1997/01/27 15:52:55 keil
* SMP proof,cosmetics, PCMCIA added
*
- * Revision 1.5 1997/01/21 22:28:32 keil
- * cleanups
- *
- * Revision 1.4 1996/12/14 21:05:41 keil
- * Reset for 16.3 PnP
- *
- * Revision 1.3 1996/11/05 19:56:54 keil
- * debug output fixed
- *
- * Revision 1.2 1996/10/27 22:09:15 keil
- * cosmetic changes
- *
- * Revision 1.1 1996/10/13 20:04:59 keil
- * Initial revision
- *
- *
+ * removed old log info /KKe
*
*/
#define __NO_VERSION__
-#include "siemens.h"
#include "hisax.h"
-#include "teles3.h"
+#include "isac.h"
+#include "hscx.h"
#include "isdnl1.h"
-#include <linux/kernel_stat.h>
extern const char *CardType[];
-const char *teles3_revision = "$Revision: 1.11 $";
+const char *teles3_revision = "$Revision: 2.7 $";
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
static inline u_char
readreg(unsigned int adr, u_char off)
@@ -82,953 +90,410 @@ writereg(unsigned int adr, u_char off, u_char data)
static inline void
read_fifo(unsigned int adr, u_char * data, int size)
{
- insb(adr + 0x1e, data, size);
+ insb(adr, data, size);
}
static void
write_fifo(unsigned int adr, u_char * data, int size)
{
- outsb(adr + 0x1e, data, size);
+ outsb(adr, data, size);
}
-static inline void
-waitforCEC(int adr)
-{
- int to = 50;
+/* Interface functions */
- while ((readreg(adr, HSCX_STAR) & 0x04) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "Teles3: waitforCEC timeout\n");
-}
-
-
-static inline void
-waitforXFW(int adr)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
{
- int to = 50;
-
- while ((!(readreg(adr, HSCX_STAR) & 0x44) == 0x40) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "Teles3: waitforXFW timeout\n");
+ return (readreg(cs->hw.teles3.isac, offset));
}
-static inline void
-writehscxCMDR(int adr, u_char data)
-{
- long flags;
-
- save_flags(flags);
- cli();
- waitforCEC(adr);
- writereg(adr, HSCX_CMDR, data);
- restore_flags(flags);
-}
-
-/*
- * fast interrupt here
- */
-
-static void
-hscxreport(struct IsdnCardState *sp, int hscx)
-{
- printk(KERN_DEBUG "HSCX %d\n", hscx);
- printk(KERN_DEBUG "ISTA %x\n", readreg(sp->hscx[hscx], HSCX_ISTA));
- printk(KERN_DEBUG "STAR %x\n", readreg(sp->hscx[hscx], HSCX_STAR));
- printk(KERN_DEBUG "EXIR %x\n", readreg(sp->hscx[hscx], HSCX_EXIR));
-}
-
-void
-teles3_report(struct IsdnCardState *sp)
-{
- printk(KERN_DEBUG "ISAC\n");
- printk(KERN_DEBUG "ISTA %x\n", readreg(sp->isac, ISAC_ISTA));
- printk(KERN_DEBUG "STAR %x\n", readreg(sp->isac, ISAC_STAR));
- printk(KERN_DEBUG "EXIR %x\n", readreg(sp->isac, ISAC_EXIR));
- hscxreport(sp, 0);
- hscxreport(sp, 1);
-}
-
-/*
- * HSCX stuff goes here
- */
static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
- u_char *ptr;
- struct IsdnCardState *sp = hsp->sp;
- long flags;
-
- if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
- debugl1(sp, "hscx_empty_fifo");
-
- if (hsp->rcvidx + count > HSCX_BUFMAX) {
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "hscx_empty_fifo: incoming packet too large");
- writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
- hsp->rcvidx = 0;
- return;
- }
- ptr = hsp->rcvbuf + hsp->rcvidx;
- hsp->rcvidx += count;
- save_flags(flags);
- cli();
- read_fifo(sp->hscx[hsp->hscx], ptr, count);
- writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
- restore_flags(flags);
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "hscx_empty_fifo %c cnt %d",
- hsp->hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ writereg(cs->hw.teles3.isac, offset, value);
}
static void
-hscx_fill_fifo(struct HscxState *hsp)
-{
- struct IsdnCardState *sp = hsp->sp;
- int more, count;
- u_char *ptr;
- long flags;
-
- if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
- debugl1(sp, "hscx_fill_fifo");
-
- if (!hsp->tx_skb)
- return;
- if (hsp->tx_skb->len <= 0)
- return;
-
- more = (hsp->mode == 1) ? 1 : 0;
- if (hsp->tx_skb->len > 32) {
- more = !0;
- count = 32;
- } else
- count = hsp->tx_skb->len;
-
- waitforXFW(sp->hscx[hsp->hscx]);
- save_flags(flags);
- cli();
- ptr = hsp->tx_skb->data;
- skb_pull(hsp->tx_skb, count);
- hsp->tx_cnt -= count;
- hsp->count += count;
- write_fifo(sp->hscx[hsp->hscx], ptr, count);
- writehscxCMDR(sp->hscx[hsp->hscx], more ? 0x8 : 0xa);
- restore_flags(flags);
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "hscx_fill_fifo %c cnt %d",
- hsp->hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
-}
-
-static inline void
-hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
- u_char r;
- struct HscxState *hsp = sp->hs + hscx;
- struct sk_buff *skb;
- int count;
- char tmp[32];
-
- if (!hsp->init)
- return;
-
- if (val & 0x80) { /* RME */
-
- r = readreg(sp->hscx[hsp->hscx], HSCX_RSTA);
- if ((r & 0xf0) != 0xa0) {
- if (!r & 0x80)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "HSCX invalid frame");
- if ((r & 0x40) && hsp->mode)
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX RDO mode=%d",
- hsp->mode);
- debugl1(sp, tmp);
- }
- if (!r & 0x20)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "HSCX CRC error");
- writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
- } else {
- count = readreg(sp->hscx[hsp->hscx], HSCX_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- hscx_empty_fifo(hsp, count);
- if ((count = hsp->rcvidx - 1) > 0) {
- if (!(skb = dev_alloc_skb(count)))
- printk(KERN_WARNING "AVM: receive out of memory\n");
- else {
- memcpy(skb_put(skb, count), hsp->rcvbuf, count);
- skb_queue_tail(&hsp->rqueue, skb);
- }
- }
- }
- hsp->rcvidx = 0;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- hscx_empty_fifo(hsp, 32);
- if (hsp->mode == 1) {
- /* receive audio data */
- if (!(skb = dev_alloc_skb(32)))
- printk(KERN_WARNING "AVM: receive out of memory\n");
- else {
- memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
- skb_queue_tail(&hsp->rqueue, skb);
- }
- hsp->rcvidx = 0;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- }
- if (val & 0x10) { /* XPR */
- if (hsp->tx_skb)
- if (hsp->tx_skb->len) {
- hscx_fill_fifo(hsp);
- return;
- } else {
- SET_SKB_FREE(hsp->tx_skb);
- dev_kfree_skb(hsp->tx_skb);
- hsp->count = 0;
- if (hsp->st->l4.l1writewakeup)
- hsp->st->l4.l1writewakeup(hsp->st);
- hsp->tx_skb = NULL;
- }
- if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
- hsp->count = 0;
- hscx_fill_fifo(hsp);
- } else
- hscx_sched_event(hsp, HSCX_XMTBUFREADY);
- }
+ read_fifo(cs->hw.teles3.isacfifo, data, size);
}
-/*
- * ISAC stuff goes here
- */
-
static void
-isac_empty_fifo(struct IsdnCardState *sp, int count)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
- u_char *ptr;
- long flags;
-
- if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
- if (sp->debug & L1_DEB_ISAC)
- debugl1(sp, "isac_empty_fifo");
-
- if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
- if (sp->debug & L1_DEB_WARN) {
- char tmp[40];
- sprintf(tmp, "isac_empty_fifo overrun %d",
- sp->rcvidx + count);
- debugl1(sp, tmp);
- }
- writereg(sp->isac, ISAC_CMDR, 0x80);
- sp->rcvidx = 0;
- return;
- }
- ptr = sp->rcvbuf + sp->rcvidx;
- sp->rcvidx += count;
- save_flags(flags);
- cli();
- read_fifo(sp->isac, ptr, count);
- writereg(sp->isac, ISAC_CMDR, 0x80);
- restore_flags(flags);
- if (sp->debug & L1_DEB_ISAC_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "isac_empty_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ write_fifo(cs->hw.teles3.isacfifo, data, size);
}
-static void
-isac_fill_fifo(struct IsdnCardState *sp)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
- int count, more;
- u_char *ptr;
- long flags;
-
- if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
- debugl1(sp, "isac_fill_fifo");
-
- if (!sp->tx_skb)
- return;
-
- count = sp->tx_skb->len;
- if (count <= 0)
- return;
-
- more = 0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- save_flags(flags);
- cli();
- ptr = sp->tx_skb->data;
- skb_pull(sp->tx_skb, count);
- sp->tx_cnt += count;
- write_fifo(sp->isac, ptr, count);
- writereg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa);
- restore_flags(flags);
- if (sp->debug & L1_DEB_ISAC_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "isac_fill_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ return (readreg(cs->hw.teles3.hscx[hscx], offset));
}
static void
-ph_command(struct IsdnCardState *sp, unsigned int command)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
- if (sp->debug & L1_DEB_ISAC) {
- char tmp[32];
- sprintf(tmp, "ph_command %d", command);
- debugl1(sp, tmp);
- }
- writereg(sp->isac, ISAC_CIX0, (command << 2) | 3);
+ writereg(cs->hw.teles3.hscx[hscx], offset, value);
}
+/*
+ * fast interrupt HSCX stuff goes here
+ */
-static inline void
-isac_interrupt(struct IsdnCardState *sp, u_char val)
-{
- u_char exval;
- struct sk_buff *skb;
- unsigned int count;
- char tmp[32];
-
- if (sp->debug & L1_DEB_ISAC) {
- sprintf(tmp, "ISAC interrupt %x", val);
- debugl1(sp, tmp);
- }
- if (val & 0x80) { /* RME */
- exval = readreg(sp->isac, ISAC_RSTA);
- if ((exval & 0x70) != 0x20) {
- if (exval & 0x40)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC RDO");
- if (!exval & 0x20)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC CRC error");
- writereg(sp->isac, ISAC_CMDR, 0x80);
- } else {
- count = readreg(sp->isac, ISAC_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- isac_empty_fifo(sp, count);
- if ((count = sp->rcvidx) > 0) {
- if (!(skb = alloc_skb(count, GFP_ATOMIC)))
- printk(KERN_WARNING "AVM: D receive out of memory\n");
- else {
- memcpy(skb_put(skb, count), sp->rcvbuf, count);
- skb_queue_tail(&sp->rq, skb);
- }
- }
- }
- sp->rcvidx = 0;
- isac_sched_event(sp, ISAC_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- isac_empty_fifo(sp, 32);
- }
- if (val & 0x20) { /* RSC */
- /* never */
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC RSC interrupt");
- }
- if (val & 0x10) { /* XPR */
- if (sp->tx_skb)
- if (sp->tx_skb->len) {
- isac_fill_fifo(sp);
- goto afterXPR;
- } else {
- SET_SKB_FREE(sp->tx_skb);
- dev_kfree_skb(sp->tx_skb);
- sp->tx_cnt = 0;
- sp->tx_skb = NULL;
- }
- if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
- sp->tx_cnt = 0;
- isac_fill_fifo(sp);
- } else
- isac_sched_event(sp, ISAC_XMTBUFREADY);
- }
- afterXPR:
- if (val & 0x04) { /* CISQ */
- sp->ph_state = (readreg(sp->isac, ISAC_CIX0) >> 2)
- & 0xf;
- if (sp->debug & L1_DEB_ISAC) {
- sprintf(tmp, "l1state %d", sp->ph_state);
- debugl1(sp, tmp);
- }
- isac_new_ph(sp);
- }
- if (val & 0x02) { /* SIN */
- /* never */
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC SIN interrupt");
- }
- if (val & 0x01) { /* EXI */
- exval = readreg(sp->isac, ISAC_EXIR);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "ISAC EXIR %02x", exval);
- debugl1(sp, tmp);
- }
- }
-}
-
-static inline void
-hscx_int_main(struct IsdnCardState *sp, u_char val)
-{
-
- u_char exval;
- struct HscxState *hsp;
- char tmp[32];
+#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.hscx[nr], reg)
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.hscx[nr], reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
-
- if (val & 0x01) {
- hsp = sp->hs + 1;
- exval = readreg(sp->hscx[1], HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (hsp->tx_skb) {
- skb_push(hsp->tx_skb, hsp->count);
- hsp->tx_cnt += hsp->count;
- hsp->count = 0;
- }
- writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
- debugl1(sp, tmp);
- }
- }
- } else if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX B EXIR %x", exval);
- debugl1(sp, tmp);
- }
- }
- if (val & 0xf8) {
- if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX B interrupt %x", val);
- debugl1(sp, tmp);
- }
- hscx_interrupt(sp, val, 1);
- }
- if (val & 0x02) {
- hsp = sp->hs;
- exval = readreg(sp->hscx[0], HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (hsp->tx_skb) {
- skb_push(hsp->tx_skb, hsp->count);
- hsp->tx_cnt += hsp->count;
- hsp->count = 0;
- }
- writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
- debugl1(sp, tmp);
- }
- }
- } else if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX A EXIR %x", exval);
- debugl1(sp, tmp);
- }
- }
- if (val & 0x04) {
- exval = readreg(sp->hscx[0], HSCX_ISTA);
- if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX A interrupt %x", exval);
- debugl1(sp, tmp);
- }
- hscx_interrupt(sp, exval, 0);
- }
-}
+#include "hscx_irq.c"
static void
teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
#define MAXCOUNT 20
- struct IsdnCardState *sp;
+ struct IsdnCardState *cs = dev_id;
u_char val, stat = 0;
int count = 0;
- sp = (struct IsdnCardState *) dev_id;
-
- if (!sp) {
+ if (!cs) {
printk(KERN_WARNING "Teles: Spurious interrupt!\n");
return;
}
- val = readreg(sp->hscx[1], HSCX_ISTA);
+ val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
Start_HSCX:
if (val) {
- hscx_int_main(sp, val);
+ hscx_int_main(cs, val);
stat |= 1;
}
- val = readreg(sp->isac, ISAC_ISTA);
+ val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
Start_ISAC:
if (val) {
- isac_interrupt(sp, val);
+ isac_interrupt(cs, val);
stat |= 2;
}
count++;
- val = readreg(sp->hscx[1], HSCX_ISTA);
+ val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
if (val && count < MAXCOUNT) {
- if (sp->debug & L1_DEB_HSCX)
- debugl1(sp, "HSCX IntStat after IntRoutine");
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
- val = readreg(sp->isac, ISAC_ISTA);
+ val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
if (val && count < MAXCOUNT) {
- if (sp->debug & L1_DEB_ISAC)
- debugl1(sp, "ISAC IntStat after IntRoutine");
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
if (count >= MAXCOUNT)
printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count);
if (stat & 1) {
- writereg(sp->hscx[0], HSCX_MASK, 0xFF);
- writereg(sp->hscx[1], HSCX_MASK, 0xFF);
- writereg(sp->hscx[0], HSCX_MASK, 0x0);
- writereg(sp->hscx[1], HSCX_MASK, 0x0);
+ writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
+ writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
+ writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
+ writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
}
if (stat & 2) {
- writereg(sp->isac, ISAC_MASK, 0xFF);
- writereg(sp->isac, ISAC_MASK, 0x0);
+ writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0);
}
}
-
-static void
-initisac(struct IsdnCardState *sp)
-{
- unsigned int adr = sp->isac;
-
- /* 16.3 IOM 2 Mode */
- writereg(adr, ISAC_MASK, 0xff);
- writereg(adr, ISAC_ADF2, 0x80);
- writereg(adr, ISAC_SQXR, 0x2f);
- writereg(adr, ISAC_SPCR, 0x0);
- writereg(adr, ISAC_ADF1, 0x2);
- writereg(adr, ISAC_STCR, 0x70);
- writereg(adr, ISAC_MODE, 0xc9);
- writereg(adr, ISAC_TIMR, 0x0);
- writereg(adr, ISAC_ADF1, 0x0);
- writereg(adr, ISAC_CMDR, 0x41);
- writereg(adr, ISAC_CIX0, (1 << 2) | 3);
- writereg(adr, ISAC_MASK, 0xff);
- writereg(adr, ISAC_MASK, 0x0);
-}
-
-static void
-modehscx(struct HscxState *hs, int mode, int ichan)
-{
- struct IsdnCardState *sp = hs->sp;
- int hscx = hs->hscx;
-
- if (sp->debug & L1_DEB_HSCX) {
- char tmp[40];
- sprintf(tmp, "hscx %c mode %d ichan %d",
- 'A' + hscx, mode, ichan);
- debugl1(sp, tmp);
- }
- hs->mode = mode;
- writereg(sp->hscx[hscx], HSCX_CCR1, 0x85);
- writereg(sp->hscx[hscx], HSCX_XAD1, 0xFF);
- writereg(sp->hscx[hscx], HSCX_XAD2, 0xFF);
- writereg(sp->hscx[hscx], HSCX_RAH2, 0xFF);
- writereg(sp->hscx[hscx], HSCX_XBCH, 0x0);
- writereg(sp->hscx[hscx], HSCX_RLCR, 0x0);
-
- switch (mode) {
- case (0):
- writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
- writereg(sp->hscx[hscx], HSCX_TSAX, 0xff);
- writereg(sp->hscx[hscx], HSCX_TSAR, 0xff);
- writereg(sp->hscx[hscx], HSCX_XCCR, 7);
- writereg(sp->hscx[hscx], HSCX_RCCR, 7);
- writereg(sp->hscx[hscx], HSCX_MODE, 0x84);
- break;
- case (1):
- if (ichan == 0) {
- writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
- writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
- writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
- writereg(sp->hscx[hscx], HSCX_XCCR, 7);
- writereg(sp->hscx[hscx], HSCX_RCCR, 7);
- } else {
- writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
- writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
- writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
- writereg(sp->hscx[hscx], HSCX_XCCR, 7);
- writereg(sp->hscx[hscx], HSCX_RCCR, 7);
- }
- writereg(sp->hscx[hscx], HSCX_MODE, 0xe4);
- writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
- break;
- case (2):
- if (ichan == 0) {
- writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
- writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
- writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
- writereg(sp->hscx[hscx], HSCX_XCCR, 7);
- writereg(sp->hscx[hscx], HSCX_RCCR, 7);
- } else {
- writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
- writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
- writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
- writereg(sp->hscx[hscx], HSCX_XCCR, 7);
- writereg(sp->hscx[hscx], HSCX_RCCR, 7);
- }
- writereg(sp->hscx[hscx], HSCX_MODE, 0x8c);
- writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
- break;
- }
- writereg(sp->hscx[hscx], HSCX_ISTA, 0x00);
-}
-
inline static void
-release_ioregs(struct IsdnCard *card, int mask)
+release_ioregs(struct IsdnCardState *cs, int mask)
{
if (mask & 1)
- release_region(card->sp->isac, 32);
+ release_region(cs->hw.teles3.isac + 32, 32);
if (mask & 2)
- release_region(card->sp->hscx[0], 32);
+ release_region(cs->hw.teles3.hscx[0] + 32, 32);
if (mask & 4)
- release_region(card->sp->hscx[1], 32);
+ release_region(cs->hw.teles3.hscx[1] + 32, 32);
}
void
-release_io_teles3(struct IsdnCard *card)
+release_io_teles3(struct IsdnCardState *cs)
{
- if (card->sp->typ == ISDN_CTYPE_TELESPCMCIA)
- release_region(card->sp->hscx[0], 97);
+ if (cs->typ == ISDN_CTYPE_TELESPCMCIA)
+ release_region(cs->hw.teles3.cfg_reg, 97);
else {
- if (card->sp->cfg_reg)
- release_region(card->sp->cfg_reg, 8);
- release_ioregs(card, 0x7);
+ if (cs->hw.teles3.cfg_reg)
+ if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+ release_region(cs->hw.teles3.cfg_reg, 1);
+ } else {
+ release_region(cs->hw.teles3.cfg_reg, 8);
+ }
+ release_ioregs(cs, 0x7);
}
}
-static void
-clear_pending_ints(struct IsdnCardState *sp)
+static int
+reset_teles3(struct IsdnCardState *cs)
{
- int val;
- char tmp[64];
-
- val = readreg(sp->hscx[1], HSCX_ISTA);
- sprintf(tmp, "HSCX B ISTA %x", val);
- debugl1(sp, tmp);
- if (val & 0x01) {
- val = readreg(sp->hscx[1], HSCX_EXIR);
- sprintf(tmp, "HSCX B EXIR %x", val);
- debugl1(sp, tmp);
- } else if (val & 0x02) {
- val = readreg(sp->hscx[0], HSCX_EXIR);
- sprintf(tmp, "HSCX A EXIR %x", val);
- debugl1(sp, tmp);
- }
- val = readreg(sp->hscx[0], HSCX_ISTA);
- sprintf(tmp, "HSCX A ISTA %x", val);
- debugl1(sp, tmp);
- val = readreg(sp->hscx[1], HSCX_STAR);
- sprintf(tmp, "HSCX B STAR %x", val);
- debugl1(sp, tmp);
- val = readreg(sp->hscx[0], HSCX_STAR);
- sprintf(tmp, "HSCX A STAR %x", val);
- debugl1(sp, tmp);
- val = readreg(sp->isac, ISAC_STAR);
- sprintf(tmp, "ISAC STAR %x", val);
- debugl1(sp, tmp);
- val = readreg(sp->isac, ISAC_MODE);
- sprintf(tmp, "ISAC MODE %x", val);
- debugl1(sp, tmp);
- val = readreg(sp->isac, ISAC_ADF2);
- sprintf(tmp, "ISAC ADF2 %x", val);
- debugl1(sp, tmp);
- val = readreg(sp->isac, ISAC_ISTA);
- sprintf(tmp, "ISAC ISTA %x", val);
- debugl1(sp, tmp);
- if (val & 0x01) {
- val = readreg(sp->isac, ISAC_EXIR);
- sprintf(tmp, "ISAC EXIR %x", val);
- debugl1(sp, tmp);
- } else if (val & 0x04) {
- val = readreg(sp->isac, ISAC_CIR0);
- sprintf(tmp, "ISAC CIR0 %x", val);
- debugl1(sp, tmp);
+ long flags;
+ u_char irqcfg;
+
+ if (cs->typ != ISDN_CTYPE_TELESPCMCIA) {
+ if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
+ switch (cs->irq) {
+ case 2:
+ case 9:
+ irqcfg = 0x00;
+ break;
+ case 3:
+ irqcfg = 0x02;
+ break;
+ case 4:
+ irqcfg = 0x04;
+ break;
+ case 5:
+ irqcfg = 0x06;
+ break;
+ case 10:
+ irqcfg = 0x08;
+ break;
+ case 11:
+ irqcfg = 0x0A;
+ break;
+ case 12:
+ irqcfg = 0x0C;
+ break;
+ case 15:
+ irqcfg = 0x0E;
+ break;
+ default:
+ return(1);
+ }
+ save_flags(flags);
+ byteout(cs->hw.teles3.cfg_reg + 4, irqcfg);
+ sti();
+ HZDELAY(HZ / 10 + 1);
+ byteout(cs->hw.teles3.cfg_reg + 4, irqcfg | 1);
+ HZDELAY(HZ / 10 + 1);
+ restore_flags(flags);
+ } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+ save_flags(flags);
+ byteout(cs->hw.teles3.cfg_reg, 0xff);
+ HZDELAY(2);
+ byteout(cs->hw.teles3.cfg_reg, 0x00);
+ HZDELAY(2);
+ restore_flags(flags);
+ } else {
+ /* Reset off for 16.3 PnP , thanks to Georg Acher */
+ save_flags(flags);
+ byteout(cs->hw.teles3.isac + 0x3c, 0);
+ HZDELAY(2);
+ byteout(cs->hw.teles3.isac + 0x3c, 1);
+ HZDELAY(2);
+ restore_flags(flags);
+ }
}
- writereg(sp->isac, ISAC_MASK, 0);
- writereg(sp->isac, ISAC_CMDR, 0x41);
+ return(0);
}
-int
-initteles3(struct IsdnCardState *sp)
+static int
+Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
- int ret;
- int loop = 0;
- char tmp[40];
-
- sp->counter = kstat_irqs(sp->irq);
- sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
- debugl1(sp, tmp);
- clear_pending_ints(sp);
- ret = get_irq(sp->cardnr, &teles3_interrupt);
- if (ret) {
- initisac(sp);
- sp->modehscx(sp->hs, 0, 0);
- writereg(sp->hscx[sp->hs->hscx], HSCX_CMDR, 0x01);
- sp->modehscx(sp->hs + 1, 0, 0);
- writereg(sp->hscx[(sp->hs + 1)->hscx], HSCX_CMDR, 0x01);
- while (loop++ < 10) {
- /* At least 1-3 irqs must happen
- * (one from HSCX A, one from HSCX B, 3rd from ISAC)
- */
- if (kstat_irqs(sp->irq) > sp->counter)
- break;
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + 1;
- schedule();
- }
- sprintf(tmp, "IRQ %d count %d loop %d", sp->irq,
- kstat_irqs(sp->irq), loop);
- debugl1(sp, tmp);
- if (kstat_irqs(sp->irq) <= sp->counter) {
- printk(KERN_WARNING
- "Teles3: IRQ(%d) getting no interrupts during init\n",
- sp->irq);
- free_irq(sp->irq, sp);
- return (0);
- }
- }
- return (ret);
+ switch (mt) {
+ case CARD_RESET:
+ reset_teles3(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_teles3(cs);
+ return(0);
+ case CARD_SETIRQ:
+ return(request_irq(cs->irq, &teles3_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs));
+ case CARD_INIT:
+ clear_pending_isac_ints(cs);
+ clear_pending_hscx_ints(cs);
+ initisac(cs);
+ inithscx(cs);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
}
-int
-setup_teles3(struct IsdnCard *card)
+__initfunc(int
+setup_teles3(struct IsdnCard *card))
{
- u_char cfval = 0, val, verA, verB;
- struct IsdnCardState *sp = card->sp;
- long flags;
+ u_char val;
+ struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, teles3_revision);
- printk(KERN_NOTICE "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp));
- if ((sp->typ != ISDN_CTYPE_16_3) && (sp->typ != ISDN_CTYPE_PNP)
- && (sp->typ != ISDN_CTYPE_TELESPCMCIA))
+ printk(KERN_INFO "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp));
+ if ((cs->typ != ISDN_CTYPE_16_3) && (cs->typ != ISDN_CTYPE_PNP)
+ && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA))
return (0);
- if (sp->typ == ISDN_CTYPE_16_3) {
- sp->cfg_reg = card->para[1];
- switch (sp->cfg_reg) {
+ if (cs->typ == ISDN_CTYPE_16_3) {
+ cs->hw.teles3.cfg_reg = card->para[1];
+ switch (cs->hw.teles3.cfg_reg) {
case 0x180:
case 0x280:
case 0x380:
- sp->cfg_reg |= 0xc00;
+ cs->hw.teles3.cfg_reg |= 0xc00;
break;
}
- sp->isac = sp->cfg_reg - 0x400;
- sp->hscx[0] = sp->cfg_reg - 0xc00;
- sp->hscx[1] = sp->cfg_reg - 0x800;
- } else if (sp->typ == ISDN_CTYPE_TELESPCMCIA) {
- sp->cfg_reg = 0;
- sp->hscx[0] = card->para[1];
- sp->hscx[1] = card->para[1] + 0x20;
- sp->isac = card->para[1] + 0x40;
- } else { /* PNP */
- sp->cfg_reg = 0;
- sp->isac = card->para[1];
- sp->hscx[0] = card->para[2];
- sp->hscx[1] = card->para[2] + 0x20;
- }
- sp->irq = card->para[0];
- if (sp->typ == ISDN_CTYPE_TELESPCMCIA) {
- if (check_region((sp->hscx[0]), 97)) {
+ cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420;
+ cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20;
+ cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820;
+ } else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
+ cs->hw.teles3.cfg_reg = card->para[1];
+ cs->hw.teles3.hscx[0] = card->para[1] - 0x20;
+ cs->hw.teles3.hscx[1] = card->para[1];
+ cs->hw.teles3.isac = card->para[1] + 0x20;
+ } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+ cs->hw.teles3.cfg_reg = card->para[3];
+ cs->hw.teles3.isac = card->para[2] - 32;
+ cs->hw.teles3.hscx[0] = card->para[1] - 32;
+ cs->hw.teles3.hscx[1] = card->para[1];
+ } else { /* PNP */
+ cs->hw.teles3.cfg_reg = 0;
+ cs->hw.teles3.isac = card->para[1] - 32;
+ cs->hw.teles3.hscx[0] = card->para[2] - 32;
+ cs->hw.teles3.hscx[1] = card->para[2];
+ }
+ cs->irq = card->para[0];
+ cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
+ cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
+ cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
+ if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
+ if (check_region((cs->hw.teles3.cfg_reg), 97)) {
printk(KERN_WARNING
"HiSax: %s ports %x-%x already in use\n",
- CardType[sp->typ],
- sp->hscx[0],
- sp->hscx[0] + 96);
+ CardType[cs->typ],
+ cs->hw.teles3.cfg_reg,
+ cs->hw.teles3.cfg_reg + 96);
return (0);
} else
- request_region(sp->hscx[0], 97, "HiSax Teles PCMCIA");
+ request_region(cs->hw.teles3.hscx[0], 97, "HiSax Teles PCMCIA");
} else {
- if (sp->cfg_reg) {
- if (check_region((sp->cfg_reg), 8)) {
- printk(KERN_WARNING
- "HiSax: %s config port %x-%x already in use\n",
- CardType[card->typ],
- sp->cfg_reg,
- sp->cfg_reg + 8);
- return (0);
+ if (cs->hw.teles3.cfg_reg) {
+ if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+ if (check_region((cs->hw.teles3.cfg_reg), 1)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x already in use\n",
+ CardType[card->typ],
+ cs->hw.teles3.cfg_reg);
+ return (0);
+ } else
+ request_region(cs->hw.teles3.cfg_reg, 1, "teles3 cfg");
} else {
- request_region(sp->cfg_reg, 8, "teles3 cfg");
+ if (check_region((cs->hw.teles3.cfg_reg), 8)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.teles3.cfg_reg,
+ cs->hw.teles3.cfg_reg + 8);
+ return (0);
+ } else
+ request_region(cs->hw.teles3.cfg_reg, 8, "teles3 cfg");
}
}
- if (check_region((sp->isac), 32)) {
+ if (check_region((cs->hw.teles3.isac + 32), 32)) {
printk(KERN_WARNING
"HiSax: %s isac ports %x-%x already in use\n",
- CardType[sp->typ],
- sp->isac,
- sp->isac + 32);
- if (sp->cfg_reg) {
- release_region(sp->cfg_reg, 8);
- }
+ CardType[cs->typ],
+ cs->hw.teles3.isac + 32,
+ cs->hw.teles3.isac + 64);
+ if (cs->hw.teles3.cfg_reg)
+ if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+ release_region(cs->hw.teles3.cfg_reg, 1);
+ } else {
+ release_region(cs->hw.teles3.cfg_reg, 8);
+ }
return (0);
- } else {
- request_region(sp->isac, 32, "HiSax isac");
- }
- if (check_region((sp->hscx[0]), 32)) {
+ } else
+ request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac");
+ if (check_region((cs->hw.teles3.hscx[0] + 32), 32)) {
printk(KERN_WARNING
"HiSax: %s hscx A ports %x-%x already in use\n",
- CardType[sp->typ],
- sp->hscx[0],
- sp->hscx[0] + 32);
- if (sp->cfg_reg) {
- release_region(sp->cfg_reg, 8);
- }
- release_ioregs(card, 1);
+ CardType[cs->typ],
+ cs->hw.teles3.hscx[0] + 32,
+ cs->hw.teles3.hscx[0] + 64);
+ if (cs->hw.teles3.cfg_reg)
+ if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+ release_region(cs->hw.teles3.cfg_reg, 1);
+ } else {
+ release_region(cs->hw.teles3.cfg_reg, 8);
+ }
+ release_ioregs(cs, 1);
return (0);
- } else {
- request_region(sp->hscx[0], 32, "HiSax hscx A");
- }
- if (check_region((sp->hscx[1]), 32)) {
+ } else
+ request_region(cs->hw.teles3.hscx[0] + 32, 32, "HiSax hscx A");
+ if (check_region((cs->hw.teles3.hscx[1] + 32), 32)) {
printk(KERN_WARNING
"HiSax: %s hscx B ports %x-%x already in use\n",
- CardType[sp->typ],
- sp->hscx[1],
- sp->hscx[1] + 32);
- if (sp->cfg_reg) {
- release_region(sp->cfg_reg, 8);
- }
- release_ioregs(card, 3);
+ CardType[cs->typ],
+ cs->hw.teles3.hscx[1] + 32,
+ cs->hw.teles3.hscx[1] + 64);
+ if (cs->hw.teles3.cfg_reg)
+ if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+ release_region(cs->hw.teles3.cfg_reg, 1);
+ } else {
+ release_region(cs->hw.teles3.cfg_reg, 8);
+ }
+ release_ioregs(cs, 3);
return (0);
- } else {
- request_region(sp->hscx[1], 32, "HiSax hscx B");
- }
- switch (sp->irq) {
- case 2:
- cfval = 0x00;
- break;
- case 3:
- cfval = 0x02;
- break;
- case 4:
- cfval = 0x04;
- break;
- case 5:
- cfval = 0x06;
- break;
- case 10:
- cfval = 0x08;
- break;
- case 11:
- cfval = 0x0A;
- break;
- case 12:
- cfval = 0x0C;
- break;
- case 15:
- cfval = 0x0E;
- break;
- default:
- cfval = 0x00;
- break;
- }
+ } else
+ request_region(cs->hw.teles3.hscx[1] + 32, 32, "HiSax hscx B");
}
- if (sp->cfg_reg) {
- if ((val = bytein(sp->cfg_reg + 0)) != 0x51) {
+ if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
+ if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) {
printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
- sp->cfg_reg + 0, val);
- release_io_teles3(card);
+ cs->hw.teles3.cfg_reg + 0, val);
+ release_io_teles3(cs);
return (0);
}
- if ((val = bytein(sp->cfg_reg + 1)) != 0x93) {
+ if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) {
printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
- sp->cfg_reg + 1, val);
- release_io_teles3(card);
+ cs->hw.teles3.cfg_reg + 1, val);
+ release_io_teles3(cs);
return (0);
}
- val = bytein(sp->cfg_reg + 2); /* 0x1e=without AB
- * 0x1f=with AB
- * 0x1c 16.3 ???
- * 0x46 16.3 with AB + Video (Teles-Vision)
- */
- if (val != 0x46 && val != 0x1c && val != 0x1e && val != 0x1f) {
+ val = bytein(cs->hw.teles3.cfg_reg + 2);/* 0x1e=without AB
+ * 0x1f=with AB
+ * 0x1c 16.3 ???
+ * 0x39 16.3 1.1
+ * 0x46 16.3 with AB + Video (Teles-Vision)
+ */
+ if (val != 0x46 && val != 0x39 && val != 0x1c && val != 0x1e && val != 0x1f) {
printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
- sp->cfg_reg + 2, val);
- release_io_teles3(card);
+ cs->hw.teles3.cfg_reg + 2, val);
+ release_io_teles3(cs);
return (0);
}
- save_flags(flags);
- byteout(sp->cfg_reg + 4, cfval);
- sti();
- HZDELAY(HZ / 10 + 1);
- byteout(sp->cfg_reg + 4, cfval | 1);
- HZDELAY(HZ / 10 + 1);
- restore_flags(flags);
- } else {
- /* Reset off for 16.3 PnP , thanks to Georg Acher */
- save_flags(flags);
- byteout(sp->isac + 0x1c, 1);
- HZDELAY(2);
- restore_flags(flags);
}
- printk(KERN_NOTICE
- "HiSax: %s config irq:%d isac:%x cfg:%x\n",
- CardType[sp->typ], sp->irq,
- sp->isac, sp->cfg_reg);
- printk(KERN_NOTICE
- "HiSax: hscx A:%x hscx B:%x\n",
- sp->hscx[0], sp->hscx[1]);
- verA = readreg(sp->hscx[0], HSCX_VSTR) & 0xf;
- verB = readreg(sp->hscx[1], HSCX_VSTR) & 0xf;
- printk(KERN_INFO "Teles3: HSCX version A: %s B: %s\n",
- HscxVersion(verA), HscxVersion(verB));
- val = readreg(sp->isac, ISAC_RBCH);
- printk(KERN_INFO "Teles3: ISAC %s\n",
- ISACVersion(val));
- if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
+ printk(KERN_INFO
+ "HiSax: %s config irq:%d isac:0x%X cfg:0x%X\n",
+ CardType[cs->typ], cs->irq,
+ cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg);
+ printk(KERN_INFO
+ "HiSax: hscx A:0x%X hscx B:0x%X\n",
+ cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32);
+
+ if (reset_teles3(cs)) {
+ printk(KERN_WARNING "Teles3: wrong IRQ\n");
+ release_io_teles3(cs);
+ return (0);
+ }
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ cs->BC_Read_Reg = &ReadHSCX;
+ cs->BC_Write_Reg = &WriteHSCX;
+ cs->BC_Send_Data = &hscx_fill_fifo;
+ cs->cardmsg = &Teles_card_msg;
+ ISACVersion(cs, "Teles3:");
+ if (HscxVersion(cs, "Teles3:")) {
printk(KERN_WARNING
"Teles3: wrong HSCX versions check IO address\n");
- release_io_teles3(card);
+ release_io_teles3(cs);
return (0);
}
- sp->modehscx = &modehscx;
- sp->ph_command = &ph_command;
- sp->hscx_fill_fifo = &hscx_fill_fifo;
- sp->isac_fill_fifo = &isac_fill_fifo;
return (1);
}
diff --git a/drivers/isdn/hisax/teles3c.c b/drivers/isdn/hisax/teles3c.c
new file mode 100644
index 000000000..848c46be9
--- /dev/null
+++ b/drivers/isdn/hisax/teles3c.c
@@ -0,0 +1,199 @@
+/* $Id: teles3c.c,v 1.2 1998/02/02 13:27:07 keil Exp $
+
+ * teles3c.c low level stuff for teles 16.3c
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: teles3c.c,v $
+ * Revision 1.2 1998/02/02 13:27:07 keil
+ * New
+ *
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hfc_2bds0.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+
+const char *teles163c_revision = "$Revision: 1.2 $";
+
+static void
+t163c_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val, stat;
+ char tmp[32];
+
+ if (!cs) {
+ printk(KERN_WARNING "teles3c: Spurious interrupt!\n");
+ return;
+ }
+ if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) &
+ (stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) {
+ val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1);
+ if (cs->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "teles3c: stat(%02x) s1(%02x)", stat, val);
+ debugl1(cs, tmp);
+ }
+ hfc2bds0_interrupt(cs, val);
+ } else {
+ if (cs->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "teles3c: irq_no_irq stat(%02x)", stat);
+ debugl1(cs, tmp);
+ }
+ }
+}
+
+static void
+t163c_Timer(struct IsdnCardState *cs)
+{
+ cs->hw.hfcD.timer.expires = jiffies + 75;
+ /* WD RESET */
+/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt | 0x80);
+ add_timer(&cs->hw.hfcD.timer);
+*/
+}
+
+void
+release_io_t163c(struct IsdnCardState *cs)
+{
+ release2bds0(cs);
+ del_timer(&cs->hw.hfcD.timer);
+ if (cs->hw.hfcD.addr)
+ release_region(cs->hw.hfcD.addr, 2);
+}
+
+static void
+reset_t163c(struct IsdnCardState *cs)
+{
+ long flags;
+
+ printk(KERN_INFO "teles3c: resetting card\n");
+ cs->hw.hfcD.cirm = HFCD_RESET | HFCD_MEM8K;
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */
+ save_flags(flags);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 3;
+ schedule();
+ cs->hw.hfcD.cirm = HFCD_MEM8K;
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ cs->hw.hfcD.cirm |= HFCD_INTB;
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* INT B */
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e);
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */
+ cs->hw.hfcD.ctmt = HFCD_TIM25 | HFCD_AUTO_TIMER;
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
+ cs->hw.hfcD.int_m2 = HFCD_IRQ_ENABLE;
+ cs->hw.hfcD.int_m1 = HFCD_INTS_B1TRANS | HFCD_INTS_B2TRANS |
+ HFCD_INTS_DTRANS | HFCD_INTS_B1REC | HFCD_INTS_B2REC |
+ HFCD_INTS_DREC | HFCD_INTS_L1STATE;
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1);
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2);
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */
+ udelay(10);
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */
+ cs->hw.hfcD.mst_m = 0;
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, HFCD_MASTER); /* HFC Master */
+ cs->hw.hfcD.sctrl = 0;
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl);
+ restore_flags(flags);
+}
+
+static int
+t163c_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ long flags;
+ char tmp[32];
+
+ if (cs->debug & L1_DEB_ISAC) {
+
+ sprintf(tmp, "teles3c: card_msg %x", mt);
+ debugl1(cs, tmp);
+ }
+ switch (mt) {
+ case CARD_RESET:
+ reset_t163c(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_t163c(cs);
+ return(0);
+ case CARD_SETIRQ:
+ cs->hw.hfcD.timer.expires = jiffies + 75;
+ add_timer(&cs->hw.hfcD.timer);
+ return(request_irq(cs->irq, &t163c_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs));
+ case CARD_INIT:
+ init2bds0(cs);
+ save_flags(flags);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + (80*HZ)/1000;
+ schedule();
+ cs->hw.hfcD.ctmt |= HFCD_TIM800;
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+ restore_flags(flags);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
+}
+
+__initfunc(int
+setup_t163c(struct IsdnCard *card))
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, teles163c_revision);
+ printk(KERN_INFO "HiSax: Teles 16.3c driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_TELES3C)
+ return (0);
+ cs->debug = 0xff;
+ cs->hw.hfcD.addr = card->para[1] & 0xfffe;
+ cs->irq = card->para[0];
+ cs->hw.hfcD.cip = 0;
+ cs->hw.hfcD.int_s1 = 0;
+ cs->hw.hfcD.send = NULL;
+ cs->bcs[0].hw.hfc.send = NULL;
+ cs->bcs[1].hw.hfc.send = NULL;
+ cs->hw.hfcD.bfifosize = 1024 + 512;
+ cs->hw.hfcD.dfifosize = 512;
+ cs->ph_state = 0;
+ cs->hw.hfcD.fifo = 255;
+ if (check_region((cs->hw.hfcD.addr), 2)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.hfcD.addr,
+ cs->hw.hfcD.addr + 2);
+ return (0);
+ } else {
+ request_region(cs->hw.hfcD.addr, 2, "teles3c isdn");
+ }
+ /* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */
+ outb(0x00, cs->hw.hfcD.addr);
+ outb(0x56, cs->hw.hfcD.addr | 1);
+ printk(KERN_INFO
+ "teles3c: defined at 0x%x IRQ %d HZ %d\n",
+ cs->hw.hfcD.addr,
+ cs->irq, HZ);
+
+ set_cs_func(cs);
+ cs->hw.hfcD.timer.function = (void *) t163c_Timer;
+ cs->hw.hfcD.timer.data = (long) cs;
+ init_timer(&cs->hw.hfcD.timer);
+ reset_t163c(cs);
+ cs->cardmsg = &t163c_card_msg;
+ return (1);
+}
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
index 0d839512d..2cc0e17f4 100644
--- a/drivers/isdn/icn/icn.c
+++ b/drivers/isdn/icn/icn.c
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.44 1997/03/30 16:51:26 calle Exp $
+/* $Id: icn.c,v 1.49 1998/02/13 11:14:15 keil Exp $
* ISDN low-level module for the ICN active ISDN-Card.
*
@@ -19,6 +19,25 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: icn.c,v $
+ * Revision 1.49 1998/02/13 11:14:15 keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.48 1997/10/10 15:56:14 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ *
+ * Revision 1.47 1997/10/01 09:21:51 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.46 1997/08/21 22:38:33 fritz
+ * Fixed a typo.
+ *
+ * Revision 1.45 1997/06/21 10:42:06 fritz
+ * Added availability to select leased mode on only one channel.
+ *
* Revision 1.44 1997/03/30 16:51:26 calle
* changed calls to copy_from_user/copy_to_user and removed verify_area
* were possible.
@@ -190,7 +209,7 @@
#undef MAP_DEBUG
static char
-*revision = "$Revision: 1.44 $";
+*revision = "$Revision: 1.49 $";
static int icn_addcard(int, char *, char *);
@@ -205,10 +224,20 @@ icn_free_queue(icn_card * card, int channel)
{
struct sk_buff_head *queue = &card->spqueue[channel];
struct sk_buff *skb;
+ unsigned long flags;
while ((skb = skb_dequeue(queue)))
dev_kfree_skb(skb);
+ save_flags(flags);
+ cli();
+ card->xlen[channel] = 0;
card->sndcount[channel] = 0;
+ if (card->xskb[channel]) {
+ card->xskb[channel] = NULL;
+ restore_flags(flags);
+ dev_kfree_skb(card->xskb[channel]);
+ } else
+ restore_flags(flags);
}
/* Put a value into a shift-register, highest bit first.
@@ -440,12 +469,14 @@ icn_pollbchan_send(int channel, icn_card * card)
struct sk_buff *skb;
isdn_ctrl cmd;
- if (!(card->sndcount[channel] ||
+ if (!(card->sndcount[channel] || card->xskb[channel] ||
skb_queue_len(&card->spqueue[channel])))
return;
if (icn_trymaplock_channel(card, mch)) {
- while (sbfree && (card->sndcount[channel] ||
- skb_queue_len(&card->spqueue[channel]))) {
+ while (sbfree &&
+ (card->sndcount[channel] ||
+ skb_queue_len(&card->spqueue[channel]) ||
+ card->xskb[channel])) {
save_flags(flags);
cli();
if (card->xmit_lock[channel]) {
@@ -454,7 +485,19 @@ icn_pollbchan_send(int channel, icn_card * card)
}
card->xmit_lock[channel]++;
restore_flags(flags);
- skb = skb_dequeue(&card->spqueue[channel]);
+ skb = card->xskb[channel];
+ if (!skb) {
+ skb = skb_dequeue(&card->spqueue[channel]);
+ if (skb) {
+ /* Pop ACK-flag off skb.
+ * Store length to xlen.
+ */
+ if (*(skb_pull(skb,1)))
+ card->xlen[channel] = skb->len;
+ else
+ card->xlen[channel] = 0;
+ }
+ }
if (!skb)
break;
if (skb->len > ICN_FRAGSIZE) {
@@ -471,13 +514,22 @@ icn_pollbchan_send(int channel, icn_card * card)
sbnext; /* switch to next buffer */
icn_maprelease_channel(card, mch & 2);
if (!skb->len) {
- dev_kfree_skb(skb);
- cmd.command = ISDN_STAT_BSENT;
- cmd.driver = card->myid;
- cmd.arg = channel;
- card->interface.statcallb(&cmd);
- } else
- skb_queue_head(&card->spqueue[channel], skb);
+ save_flags(flags);
+ cli();
+ if (card->xskb[channel]) {
+ card->xskb[channel] = NULL;
+ restore_flags(flags);
+ dev_kfree_skb(skb);
+ } else
+ restore_flags(flags);
+ if (card->xlen[channel]) {
+ cmd.command = ISDN_STAT_BSENT;
+ cmd.driver = card->myid;
+ cmd.arg = channel;
+ cmd.parm.length = card->xlen[channel];
+ card->interface.statcallb(&cmd);
+ }
+ }
card->xmit_lock[channel] = 0;
if (!icn_trymaplock_channel(card, mch))
break;
@@ -557,12 +609,11 @@ static icn_stat icn_stat_table[] =
* This routine is called periodically via timer.
*/
-static int
+static void
icn_parse_status(u_char * status, int channel, icn_card * card)
{
icn_stat *s = icn_stat_table;
int action = -1;
- int dflag = 0;
unsigned long flags;
isdn_ctrl cmd;
@@ -575,7 +626,7 @@ icn_parse_status(u_char * status, int channel, icn_card * card)
s++;
}
if (action == -1)
- return 0;
+ return;
cmd.driver = card->myid;
cmd.arg = channel;
switch (action) {
@@ -591,7 +642,6 @@ icn_parse_status(u_char * status, int channel, icn_card * card)
cli();
card->rcvidx[channel] = 0;
restore_flags(flags);
- dflag |= (channel + 1);
break;
case 3:
{
@@ -645,7 +695,6 @@ icn_parse_status(u_char * status, int channel, icn_card * card)
strncpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num) - 1);
break;
case 8:
- dflag = 3;
card->flags &= ~ICN_FLAGS_B1ACTIVE;
icn_free_queue(card, 0);
save_flags(flags);
@@ -675,7 +724,7 @@ icn_parse_status(u_char * status, int channel, icn_card * card)
break;
}
card->interface.statcallb(&cmd);
- return dflag;
+ return;
}
static void
@@ -701,7 +750,6 @@ icn_polldchan(unsigned long data)
icn_card *card = (icn_card *) data;
int mch = card->secondhalf ? 2 : 0;
int avail = 0;
- int dflag = 0;
int left;
u_char c;
int ch;
@@ -722,7 +770,7 @@ icn_polldchan(unsigned long data)
card->imsg[1] <= '2' && card->imsg[2] == ';') {
ch = (card->imsg[1] - '0') - 1;
p = &card->imsg[3];
- dflag |= icn_parse_status(p, ch, card);
+ icn_parse_status(p, ch, card);
} else {
p = card->imsg;
if (!strncmp(p, "DRV1.", 5)) {
@@ -771,10 +819,6 @@ icn_polldchan(unsigned long data)
cmd.arg = avail;
card->interface.statcallb(&cmd);
}
- if (dflag & 1)
- card->interface.rcvcallb(card->myid, 0, card->rcvbuf[0], 0);
- if (dflag & 2)
- card->interface.rcvcallb(card->myid, 1, card->rcvbuf[1], 0);
if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
if (!(card->flags & ICN_FLAGS_RBTIMER)) {
/* schedule b-channel polling */
@@ -807,7 +851,7 @@ icn_polldchan(unsigned long data)
*/
static int
-icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card)
+icn_sendbuf(int channel, int ack, struct sk_buff *skb, icn_card * card)
{
int len = skb->len;
unsigned long flags;
@@ -827,6 +871,10 @@ icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card)
cli();
nskb = skb_clone(skb, GFP_ATOMIC);
if (nskb) {
+ /* Push ACK flag as one
+ * byte in front of data.
+ */
+ *(skb_push(nskb, 1)) = ack?1:0;
skb_queue_tail(&card->spqueue[channel], nskb);
dev_kfree_skb(skb);
} else
@@ -1382,7 +1430,8 @@ icn_command(isdn_ctrl * c, icn_card * card)
}
current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
schedule();
- sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n");
+ sprintf(cbuf, "00;FV2ON\n01;EAZ%c\n02;EAZ%c\n",
+ (a & 1)?'1':'C', (a & 2)?'2':'C');
i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
printk(KERN_INFO
"icn: (%s) Leased-line mode enabled\n",
@@ -1638,14 +1687,14 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel)
}
static int
-if_sendbuf(int id, int channel, struct sk_buff *skb)
+if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
{
icn_card *card = icn_findcard(id);
if (card) {
if (!card->flags & ICN_FLAGS_RUNNING)
return -ENODEV;
- return (icn_sendbuf(channel, skb, card));
+ return (icn_sendbuf(channel, ack, skb, card));
}
printk(KERN_ERR
"icn: if_sendbuf called with invalid driverId!\n");
@@ -1669,6 +1718,7 @@ icn_initcard(int port, char *id)
}
memset((char *) card, 0, sizeof(icn_card));
card->port = port;
+ card->interface.hl_hdrlen = 1;
card->interface.channels = ICN_BCH;
card->interface.maxbufsize = 4000;
card->interface.command = if_command;
@@ -1781,11 +1831,7 @@ icn_init(void)
dev.firstload = 1;
/* No symbols to export, hide all symbols */
-#if (LINUX_VERSION_CODE < 0x020111)
- register_symtab(NULL);
-#else
EXPORT_NO_SYMBOLS;
-#endif
if ((p = strchr(revision, ':'))) {
strcpy(rev, p + 1);
diff --git a/drivers/isdn/icn/icn.h b/drivers/isdn/icn/icn.h
index 991d57e4d..3bd2819ce 100644
--- a/drivers/isdn/icn/icn.h
+++ b/drivers/isdn/icn/icn.h
@@ -1,4 +1,4 @@
-/* $Id: icn.h,v 1.26 1997/02/14 12:23:16 fritz Exp $
+/* $Id: icn.h,v 1.28 1997/10/10 15:56:18 fritz Exp $
* ISDN lowlevel-module for the ICN active ISDN-Card.
*
@@ -19,6 +19,16 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: icn.h,v $
+ * Revision 1.28 1997/10/10 15:56:18 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ *
+ * Revision 1.27 1997/10/01 09:21:56 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
* Revision 1.26 1997/02/14 12:23:16 fritz
* Added support for new insmod parameter handling.
*
@@ -265,6 +275,9 @@ typedef struct icn_card {
char *msg_buf_read; /* Readpointer for statusbuffer */
char *msg_buf_end; /* Pointer to end of statusbuffer */
int sndcount[ICN_BCH]; /* Byte-counters for B-Ch.-send */
+ int xlen[ICN_BCH]; /* Byte-counters/Flags for sent-ACK */
+ struct sk_buff *xskb[ICN_BCH];
+ /* Current transmitted skb */
struct sk_buff_head
spqueue[ICN_BCH]; /* Sendqueue */
char regname[35]; /* Name used for request_region */
@@ -303,7 +316,6 @@ static char *icn_id = "\0";
static char *icn_id2 = "\0";
#ifdef MODULE
-#if (LINUX_VERSION_CODE > 0x020111)
MODULE_AUTHOR("Fritz Elfert");
MODULE_PARM(portbase, "i");
MODULE_PARM_DESC(portbase, "Port adress of first card");
@@ -314,7 +326,6 @@ MODULE_PARM_DESC(icn_id, "ID-String of first card");
MODULE_PARM(icn_id2, "s");
MODULE_PARM_DESC(icn_id2, "ID-String of first card, second S0 (4B only)");
#endif
-#endif
#endif /* __KERNEL__ */
diff --git a/drivers/isdn/isdn_audio.c b/drivers/isdn/isdn_audio.c
index 84da94294..d097366ed 100644
--- a/drivers/isdn/isdn_audio.c
+++ b/drivers/isdn/isdn_audio.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_audio.c,v 1.8 1997/03/02 14:29:16 fritz Exp $
+/* $Id: isdn_audio.c,v 1.10 1998/02/20 17:09:40 fritz Exp $
* Linux ISDN subsystem, audio conversion and compression (linklevel).
*
@@ -20,6 +20,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_audio.c,v $
+ * Revision 1.10 1998/02/20 17:09:40 fritz
+ * Changes for recent kernels.
+ *
+ * Revision 1.9 1997/10/01 09:20:25 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
* Revision 1.8 1997/03/02 14:29:16 fritz
* More ttyI related cleanup.
*
@@ -53,7 +61,7 @@
#include "isdn_audio.h"
#include "isdn_common.h"
-char *isdn_audio_revision = "$Revision: 1.8 $";
+char *isdn_audio_revision = "$Revision: 1.10 $";
/*
* Misc. lookup-tables.
@@ -531,7 +539,6 @@ isdn_audio_goertzel(int *sample, modem_info * info)
info->line);
return;
}
- SET_SKB_FREE(skb);
result = (int *) skb_put(skb, sizeof(int) * NCOEFF);
for (k = 0; k < NCOEFF; k++) {
sk = sk1 = sk2 = 0;
diff --git a/drivers/isdn/isdn_cards.c b/drivers/isdn/isdn_cards.c
index c7f4e8b08..30a4a7703 100644
--- a/drivers/isdn/isdn_cards.c
+++ b/drivers/isdn/isdn_cards.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_cards.c,v 1.6 1997/04/23 18:56:03 fritz Exp $
+/* $Id: isdn_cards.c,v 1.7 1998/02/20 17:24:28 fritz Exp $
* Linux ISDN subsystem, initialization for non-modularized drivers.
*
@@ -19,6 +19,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_cards.c,v $
+ * Revision 1.7 1998/02/20 17:24:28 fritz
+ * Added ACT2000 init.
+ *
* Revision 1.6 1997/04/23 18:56:03 fritz
* Old Teles driver removed, Changed doc and scripts accordingly.
*
@@ -82,4 +85,7 @@ isdn_cards_init(void)
capi_init();
capidrv_init();
#endif
+#if CONFIG_ISDN_DRV_ACT2000
+ act2000_init();
+#endif
}
diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
index c97c7781c..3f4953f06 100644
--- a/drivers/isdn/isdn_common.c
+++ b/drivers/isdn/isdn_common.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.44 1997/05/27 15:17:23 fritz Exp $
+/* $Id: isdn_common.c,v 1.55 1998/02/23 23:35:32 fritz Exp $
* Linux ISDN subsystem, common used functions (linklevel).
*
@@ -21,6 +21,55 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.c,v $
+ * Revision 1.55 1998/02/23 23:35:32 fritz
+ * Eliminated some compiler warnings.
+ *
+ * Revision 1.54 1998/02/22 19:44:19 fritz
+ * Bugfixes and improvements regarding V.110, V.110 now running.
+ *
+ * Revision 1.53 1998/02/20 17:18:05 fritz
+ * Changes for recent kernels.
+ * Added common stub for sending commands to lowlevel.
+ * Added V.110.
+ *
+ * Revision 1.52 1998/01/31 22:05:57 keil
+ * Lots of changes for X.25 support:
+ * Added generic support for connection-controlling encapsulation protocols
+ * Added support of BHUP status message
+ * Added support for additional p_encap X25IFACE
+ * Added support for kernels >= 2.1.72
+ *
+ * Revision 1.51 1998/01/31 19:17:29 calle
+ * merged changes from and for 2.1.82
+ *
+ * Revision 1.50 1997/12/12 06:12:11 calle
+ * moved EXPORT_SYMBOL(register_isdn) from isdn_syms.c to isdn_common.c
+ *
+ * Revision 1.49 1997/11/06 17:16:52 keil
+ * Sync to 2.1.62 changes
+ *
+ * Revision 1.48 1997/11/02 23:55:50 keil
+ * Andi Kleen's changes for 2.1.60
+ * without it the isdninfo and isdnctrl devices won't work
+ *
+ * Revision 1.47 1997/10/09 21:28:46 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ * New L1 error status (not yet in use).
+ * Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.46 1997/10/01 09:20:27 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.45 1997/08/21 23:11:41 fritz
+ * Added changes for kernels >= 2.1.45
+ *
* Revision 1.44 1997/05/27 15:17:23 fritz
* Added changes for recent 2.1.x kernels:
* changed return type of isdn_close
@@ -197,12 +246,9 @@
*/
#include <linux/config.h>
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
-#if (LINUX_VERSION_CODE >= 0x020117)
#include <linux/poll.h>
-#endif
#include <linux/isdn.h>
#include "isdn_common.h"
#include "isdn_tty.h"
@@ -211,6 +257,7 @@
#ifdef CONFIG_ISDN_AUDIO
#include "isdn_audio.h"
#endif
+#include "isdn_v110.h"
#include "isdn_cards.h"
/* Debugflags */
@@ -218,7 +265,7 @@
isdn_dev *dev = (isdn_dev *) 0;
-static char *isdn_revision = "$Revision: 1.44 $";
+static char *isdn_revision = "$Revision: 1.55 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
@@ -232,6 +279,7 @@ extern char *isdn_audio_revision;
#else
static char *isdn_audio_revision = ": none $";
#endif
+extern char *isdn_v110_revision;
static int isdn_writebuf_stub(int, int, const u_char *, int, int);
@@ -260,13 +308,6 @@ isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
}
#endif
-static __inline void
-isdn_trash_skb(struct sk_buff *skb)
-{
- SET_SKB_FREE(skb);
- kfree_skb(skb);
-}
-
static void
isdn_free_queue(struct sk_buff_head *queue)
{
@@ -277,7 +318,7 @@ isdn_free_queue(struct sk_buff_head *queue)
cli();
if (skb_queue_len(queue))
while ((skb = skb_dequeue(queue)))
- isdn_trash_skb(skb);
+ dev_kfree_skb(skb);
restore_flags(flags);
}
@@ -294,6 +335,7 @@ isdn_dc2minor(int di, int ch)
static int isdn_timer_cnt1 = 0;
static int isdn_timer_cnt2 = 0;
static int isdn_timer_cnt3 = 0;
+static int isdn_timer_cnt4 = 0;
static void
isdn_timer_funct(ulong dummy)
@@ -323,6 +365,11 @@ isdn_timer_funct(ulong dummy)
if (tf & ISDN_TIMER_MODEMRING)
isdn_tty_modem_ring();
}
+ if (++isdn_timer_cnt4 > ISDN_TIMER_KEEPINT) {
+ isdn_timer_cnt4 = 0;
+ if (tf & ISDN_TIMER_KEEPALIVE)
+ isdn_net_slarp_out();
+ }
#if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP)
if (tf & ISDN_TIMER_IPPP)
isdn_ppp_timer_timeout();
@@ -374,22 +421,71 @@ isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
int i;
if ((i = isdn_dc2minor(di, channel)) == -1) {
- isdn_trash_skb(skb);
+ dev_kfree_skb(skb);
return;
}
/* Update statistics */
dev->ibytes[i] += skb->len;
+
/* First, try to deliver data to network-device */
if (isdn_net_rcv_skb(i, skb))
return;
+
+ /* V.110 handling
+ * makes sense for async streams only, so it is
+ * called after possible net-device delivery.
+ */
+ if (dev->v110[i]) {
+ atomic_inc(&dev->v110use[i]);
+ skb = isdn_v110_decode(dev->v110[i], skb);
+ atomic_dec(&dev->v110use[i]);
+ if (!skb)
+ return;
+ }
+
/* No network-device found, deliver to tty or raw-channel */
- SET_SKB_FREE(skb);
if (skb->len) {
if (isdn_tty_rcv_skb(i, di, channel, skb))
return;
wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
} else
- isdn_trash_skb(skb);
+ dev_kfree_skb(skb);
+}
+
+/*
+ * Intercept command from Linklevel to Lowlevel.
+ * If layer 2 protocol is V.110 and this is not supported by current
+ * lowlevel-driver, use driver's transparent mode and handle V.110 in
+ * linklevel instead.
+ */
+int
+isdn_command(isdn_ctrl *cmd)
+{
+ if (cmd->command == ISDN_CMD_SETL2) {
+ int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
+ unsigned long l2prot = (cmd->arg >> 8) & 255;
+ unsigned long features = (dev->drv[cmd->driver]->interface->features
+ >> ISDN_FEATURE_L2_SHIFT) &
+ ISDN_FEATURE_L2_MASK;
+ unsigned long l2_feature = (1 << l2prot);
+
+ switch (l2prot) {
+ case ISDN_PROTO_L2_V11096:
+ case ISDN_PROTO_L2_V11019:
+ case ISDN_PROTO_L2_V11038:
+ /* If V.110 requested, but not supported by
+ * HL-driver, set emulator-flag and change
+ * Layer-2 to transparent
+ */
+ if (!(features & l2_feature)) {
+ dev->v110emu[idx] = l2prot;
+ cmd->arg = (cmd->arg & 255) |
+ (ISDN_PROTO_L2_TRANS << 8);
+ } else
+ dev->v110emu[idx] = 0;
+ }
+ }
+ return dev->drv[cmd->driver]->interface->command(cmd);
}
void
@@ -403,7 +499,7 @@ isdn_all_eaz(int di, int ch)
cmd.arg = ch;
cmd.command = ISDN_CMD_SETEAZ;
cmd.parm.num[0] = '\0';
- (void) dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
}
static int
@@ -424,7 +520,9 @@ isdn_status_callback(isdn_ctrl * c)
return -1;
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return 0;
- if (isdn_net_stat_callback(i, c->command))
+ if (isdn_net_stat_callback(i, c))
+ return 0;
+ if (isdn_v110_stat_callback(i, c))
return 0;
if (isdn_tty_stat_callback(i, c))
return 0;
@@ -456,14 +554,14 @@ isdn_status_callback(isdn_ctrl * c)
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_HANGUP;
- dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
return 0;
}
/* Try to find a network-interface which will accept incoming call */
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_LOCK;
- dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
r = isdn_net_find_icall(di, c->arg, i, c->parm.setup);
switch (r) {
case 0:
@@ -476,7 +574,7 @@ isdn_status_callback(isdn_ctrl * c)
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_HANGUP;
- dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
retval = 2;
}
break;
@@ -486,7 +584,7 @@ isdn_status_callback(isdn_ctrl * c)
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_ACCEPTD;
- dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
retval = 1;
break;
case 2: /* For calling back, first reject incoming call ... */
@@ -496,7 +594,7 @@ isdn_status_callback(isdn_ctrl * c)
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_HANGUP;
- dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
if (r == 3)
break;
/* Fall through */
@@ -509,7 +607,7 @@ isdn_status_callback(isdn_ctrl * c)
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_UNLOCK;
- dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
}
return retval;
break;
@@ -522,7 +620,8 @@ isdn_status_callback(isdn_ctrl * c)
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return 0;
if (strcmp(c->parm.num, "0"))
- isdn_net_stat_callback(i, c->command);
+ isdn_net_stat_callback(i, c);
+ isdn_tty_stat_callback(i, c);
break;
case ISDN_STAT_CAUSE:
#ifdef ISDN_DEBUG_STATCALLB
@@ -541,14 +640,15 @@ isdn_status_callback(isdn_ctrl * c)
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return 0;
/* Find any net-device, waiting for D-channel setup */
- if (isdn_net_stat_callback(i, c->command))
+ if (isdn_net_stat_callback(i, c))
break;
+ isdn_v110_stat_callback(i, c);
/* Find any ttyI, waiting for D-channel setup */
if (isdn_tty_stat_callback(i, c)) {
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_ACCEPTB;
- dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
break;
}
break;
@@ -563,8 +663,9 @@ isdn_status_callback(isdn_ctrl * c)
dev->drv[di]->flags &= ~(1 << (c->arg));
isdn_info_update();
/* Signal hangup to network-devices */
- if (isdn_net_stat_callback(i, c->command))
+ if (isdn_net_stat_callback(i, c))
break;
+ isdn_v110_stat_callback(i, c);
if (isdn_tty_stat_callback(i, c))
break;
break;
@@ -579,8 +680,9 @@ isdn_status_callback(isdn_ctrl * c)
return 0;
dev->drv[di]->flags |= (1 << (c->arg));
isdn_info_update();
- if (isdn_net_stat_callback(i, c->command))
+ if (isdn_net_stat_callback(i, c))
break;
+ isdn_v110_stat_callback(i, c);
if (isdn_tty_stat_callback(i, c))
break;
break;
@@ -594,6 +696,12 @@ isdn_status_callback(isdn_ctrl * c)
return 0;
dev->drv[di]->flags &= ~(1 << (c->arg));
isdn_info_update();
+#ifdef CONFIG_ISDN_X25
+ /* Signal hangup to network-devices */
+ if (isdn_net_stat_callback(i, c))
+ break;
+#endif
+ isdn_v110_stat_callback(i, c);
if (isdn_tty_stat_callback(i, c))
break;
break;
@@ -605,7 +713,7 @@ isdn_status_callback(isdn_ctrl * c)
#endif
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return 0;
- if (isdn_net_stat_callback(i, c->command))
+ if (isdn_net_stat_callback(i, c))
break;
if (isdn_tty_stat_callback(i, c))
break;
@@ -636,6 +744,8 @@ isdn_status_callback(isdn_ctrl * c)
isdn_info_update();
restore_flags(flags);
return 0;
+ case ISDN_STAT_L1ERR:
+ break;
default:
return -1;
}
@@ -752,7 +862,7 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user
ISDN_AUDIO_SKB_LOCK(skb) = 0;
#endif
skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
- isdn_trash_skb(skb);
+ dev_kfree_skb(skb);
} else {
/* Not yet emptied this buff, so it
* must stay in the queue, for further calls
@@ -848,8 +958,8 @@ isdn_info_update(void)
wake_up_interruptible(&(dev->info_waitq));
}
-static RWTYPE
-isdn_read(struct file *file, char *buf, RWARG count, loff_t *off)
+static ssize_t
+isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
{
uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
int len = 0;
@@ -857,6 +967,9 @@ isdn_read(struct file *file, char *buf, RWARG count, loff_t *off)
int drvidx;
int chidx;
+ if (off != &file->f_pos)
+ return -ESPIPE;
+
if (minor == ISDN_MINOR_STATUS) {
char *p;
if (!file->private_data) {
@@ -922,18 +1035,22 @@ isdn_read(struct file *file, char *buf, RWARG count, loff_t *off)
return -ENODEV;
}
-static LSTYPE isdn_lseek(struct file *file, LSARG offset, int orig)
+static loff_t
+isdn_lseek(struct file *file, loff_t offset, int orig)
{
return -ESPIPE;
}
-static RWTYPE
-isdn_write(struct file *file, const char *buf, RWARG count, loff_t * off)
+static ssize_t
+isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
{
uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
int drvidx;
int chidx;
+ if (off != &file->f_pos)
+ return -ESPIPE;
+
if (minor == ISDN_MINOR_STATUS)
return -EPERM;
if (!dev->drivers)
@@ -972,41 +1089,6 @@ isdn_write(struct file *file, const char *buf, RWARG count, loff_t * off)
return -ENODEV;
}
-#if (LINUX_VERSION_CODE < 0x020117)
-static int
-isdn_select(struct inode *inode, struct file *file, int type, select_table * st)
-{
- uint minor = MINOR(inode->i_rdev);
- int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-
- if (minor == ISDN_MINOR_STATUS) {
- if (file->private_data)
- return 1;
- else {
- if (st)
- select_wait(&(dev->info_waitq), st);
- return 0;
- }
- }
- if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
- if (drvidx < 0)
- return -ENODEV;
- if (dev->drv[drvidx]->stavail)
- return 1;
- else {
- if (st)
- select_wait(&(dev->drv[drvidx]->st_waitq), st);
- return 0;
- }
- return 1;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX)
- return (isdn_ppp_select(minor - ISDN_MINOR_PPP, file, type, st));
-#endif
- return -ENODEV;
-}
-#else
static unsigned int
isdn_poll(struct file *file, poll_table * wait)
{
@@ -1041,7 +1123,6 @@ isdn_poll(struct file *file, poll_table * wait)
printk(KERN_ERR "isdn_common: isdn_poll 2 -> what the hell\n");
return POLLERR;
}
-#endif
static int
isdn_set_allcfg(char *src)
@@ -1055,7 +1136,7 @@ isdn_set_allcfg(char *src)
if ((ret = isdn_net_rmall()))
return ret;
if ((ret = copy_from_user((char *) &i, src, sizeof(int))))
- return ret;
+ return ret;
save_flags(flags);
cli();
src += sizeof(int);
@@ -1082,7 +1163,7 @@ isdn_set_allcfg(char *src)
restore_flags(flags);
return ret;
}
- GET_USER(phone.phone[phone_len], src++);
+ get_user(phone.phone[phone_len], src++);
if ((phone.phone[phone_len] == ' ') ||
(phone.phone[phone_len] == '\0')) {
if (phone_len) {
@@ -1122,28 +1203,30 @@ isdn_get_allcfg(char *dest)
cli();
p = dev->netdev;
while (p) {
+ isdn_net_local *lp = p->local;
+
if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 200))) {
restore_flags(flags);
return ret;
}
- strcpy(cfg.eaz, p->local.msn);
- cfg.exclusive = p->local.exclusive;
- if (p->local.pre_device >= 0) {
- sprintf(cfg.drvid, "%s,%d", dev->drvid[p->local.pre_device],
- p->local.pre_channel);
+ strcpy(cfg.eaz, lp->msn);
+ cfg.exclusive = lp->exclusive;
+ if (lp->pre_device >= 0) {
+ sprintf(cfg.drvid, "%s,%d", dev->drvid[lp->pre_device],
+ lp->pre_channel);
} else
cfg.drvid[0] = '\0';
- cfg.onhtime = p->local.onhtime;
- cfg.charge = p->local.charge;
- cfg.l2_proto = p->local.l2_proto;
- cfg.l3_proto = p->local.l3_proto;
- cfg.p_encap = p->local.p_encap;
- cfg.secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0;
- cfg.callback = (p->local.flags & ISDN_NET_CALLBACK) ? 1 : 0;
- cfg.chargehup = (p->local.hupflags & ISDN_CHARGEHUP) ? 1 : 0;
- cfg.ihup = (p->local.hupflags & ISDN_INHUP) ? 1 : 0;
- cfg.chargeint = p->local.chargeint;
- if (copy_to_user(dest, p->local.name, 10)) {
+ cfg.onhtime = lp->onhtime;
+ cfg.charge = lp->charge;
+ cfg.l2_proto = lp->l2_proto;
+ cfg.l3_proto = lp->l3_proto;
+ cfg.p_encap = lp->p_encap;
+ cfg.secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
+ cfg.callback = (lp->flags & ISDN_NET_CALLBACK) ? 1 : 0;
+ cfg.chargehup = (lp->hupflags & ISDN_CHARGEHUP) ? 1 : 0;
+ cfg.ihup = (lp->hupflags & ISDN_INHUP) ? 1 : 0;
+ cfg.chargeint = lp->chargeint;
+ if (copy_to_user(dest, lp->name, 10)) {
restore_flags(flags);
return -EFAULT;
}
@@ -1153,14 +1236,14 @@ isdn_get_allcfg(char *dest)
return -EFAULT;
}
dest += sizeof(cfg);
- strcpy(phone.name, p->local.name);
+ strcpy(phone.name, lp->name);
phone.outgoing = 0;
if ((ret = isdn_net_getphones(&phone, dest)) < 0) {
restore_flags(flags);
return ret;
} else
dest += ret;
- strcpy(phone.name, p->local.name);
+ strcpy(phone.name, lp->name);
phone.outgoing = 1;
if ((ret = isdn_net_getphones(&phone, dest)) < 0) {
restore_flags(flags);
@@ -1343,9 +1426,9 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
/* Force hangup of a network-interface */
if (!arg)
return -EINVAL;
- if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
- return ret;
- return isdn_net_force_hangup(name);
+ if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+ return ret;
+ return isdn_net_force_hangup(name);
break;
#endif /* CONFIG_NETDEVICES */
case IIOCSETVER:
@@ -1366,7 +1449,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
int i;
char *p;
if ((ret = copy_from_user((char *) &iocts, (char *) arg,
- sizeof(isdn_ioctl_struct))))
+ sizeof(isdn_ioctl_struct))))
return ret;
if (strlen(iocts.drvid)) {
if ((p = strchr(iocts.drvid, ',')))
@@ -1440,7 +1523,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
if ((ret = copy_from_user(dev->mdm.info[i].emu.profile, p,
- ISDN_MODEM_ANZREG)))
+ ISDN_MODEM_ANZREG)))
return ret;
p += ISDN_MODEM_ANZREG;
if ((ret = copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)))
@@ -1482,7 +1565,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
while (1) {
if ((ret = verify_area(VERIFY_READ, p, 1)))
return ret;
- GET_USER(bname[j], p++);
+ get_user(bname[j], p++);
switch (bname[j]) {
case '\0':
loop = 0;
@@ -1554,7 +1637,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
c.command = ISDN_CMD_IOCTL;
c.arg = cmd;
memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
- ret = dev->drv[drvidx]->interface->command(&c);
+ ret = isdn_command(&c);
memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
if ((copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct))))
return -EFAULT;
@@ -1616,7 +1699,7 @@ isdn_open(struct inode *ino, struct file *filep)
return -ENODEV;
c.command = ISDN_CMD_LOCK;
c.driver = drvidx;
- (void) dev->drv[drvidx]->interface->command(&c);
+ isdn_command(&c);
MOD_INC_USE_COUNT;
return 0;
}
@@ -1627,7 +1710,7 @@ isdn_open(struct inode *ino, struct file *filep)
c.command = ISDN_CMD_LOCK;
c.driver = drvidx;
MOD_INC_USE_COUNT;
- (void) dev->drv[drvidx]->interface->command(&c);
+ isdn_command(&c);
return 0;
}
#ifdef CONFIG_ISDN_PPP
@@ -1641,7 +1724,7 @@ isdn_open(struct inode *ino, struct file *filep)
return -ENODEV;
}
-static CLOSETYPE
+static int
isdn_close(struct inode *ino, struct file *filep)
{
uint minor = MINOR(ino->i_rdev);
@@ -1659,39 +1742,39 @@ isdn_close(struct inode *ino, struct file *filep)
else
dev->infochain = (infostruct *) (p->next);
kfree(p);
- return CLOSEVAL;
+ return 0;
}
q = p;
p = (infostruct *) (p->next);
}
printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
- return CLOSEVAL;
+ return 0;
}
if (minor < ISDN_MINOR_CTRL) {
drvidx = isdn_minor2drv(minor);
if (drvidx < 0)
- return CLOSEVAL;
+ return 0;
c.command = ISDN_CMD_UNLOCK;
c.driver = drvidx;
- (void) dev->drv[drvidx]->interface->command(&c);
- return CLOSEVAL;
+ isdn_command(&c);
+ return 0;
}
if (minor <= ISDN_MINOR_CTRLMAX) {
drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
if (drvidx < 0)
- return CLOSEVAL;
+ return 0;
if (dev->profd == current)
dev->profd = NULL;
c.command = ISDN_CMD_UNLOCK;
c.driver = drvidx;
- (void) dev->drv[drvidx]->interface->command(&c);
- return CLOSEVAL;
+ isdn_command(&c);
+ return 0;
}
#ifdef CONFIG_ISDN_PPP
if (minor <= ISDN_MINOR_PPPMAX)
isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
#endif
- return CLOSEVAL;
+ return 0;
}
static struct file_operations isdn_fops =
@@ -1700,11 +1783,7 @@ static struct file_operations isdn_fops =
isdn_read,
isdn_write,
NULL, /* isdn_readdir */
-#if (LINUX_VERSION_CODE < 0x020117)
- isdn_select, /* isdn_select */
-#else
isdn_poll, /* isdn_poll */
-#endif
isdn_ioctl, /* isdn_ioctl */
NULL, /* isdn_mmap */
isdn_open,
@@ -1731,6 +1810,8 @@ isdn_map_eaz2msn(char *msn, int di)
* Find an unused ISDN-channel, whose feature-flags match the
* given L2- and L3-protocols.
*/
+#define L2V (~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038))
+
int
isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
,int pre_chan)
@@ -1738,11 +1819,18 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
int i;
ulong flags;
ulong features;
+ ulong vfeatures;
isdn_ctrl cmd;
save_flags(flags);
cli();
- features = (1 << l2_proto) | (0x100 << l3_proto);
+ features = ((1 << l2_proto) | (0x10000 << l3_proto));
+ vfeatures = (((1 << l2_proto) | (0x10000 << l3_proto)) &
+ ~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038));
+ /* If Layer-2 protocol is V.110, accept drivers with
+ * transparent feature even if these don't support V.110
+ * because we can emulate this in linklevel.
+ */
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
if (USG_NONE(dev->usage[i]) &&
(dev->drvmap[i] != -1)) {
@@ -1751,7 +1839,9 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
((pre_dev != d) || (pre_chan != dev->chanmap[i])))
continue;
if ((dev->drv[d]->running)) {
- if ((dev->drv[d]->interface->features & features) == features) {
+ if (((dev->drv[d]->interface->features & features) == features) ||
+ (((dev->drv[d]->interface->features & vfeatures) == vfeatures) &&
+ (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) {
if ((pre_dev < 0) || (pre_chan < 0)) {
dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
dev->usage[i] |= usage;
@@ -1759,7 +1849,7 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
cmd.driver = d;
cmd.arg = 0;
cmd.command = ISDN_CMD_LOCK;
- (void) dev->drv[d]->interface->command(&cmd);
+ isdn_command(&cmd);
restore_flags(flags);
return i;
} else {
@@ -1770,7 +1860,7 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
cmd.driver = d;
cmd.arg = 0;
cmd.command = ISDN_CMD_LOCK;
- (void) dev->drv[d]->interface->command(&cmd);
+ isdn_command(&cmd);
restore_flags(flags);
return i;
}
@@ -1808,7 +1898,7 @@ isdn_free_channel(int di, int ch, int usage)
cmd.arg = ch;
cmd.command = ISDN_CMD_UNLOCK;
restore_flags(flags);
- (void) dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
return;
}
restore_flags(flags);
@@ -1837,31 +1927,6 @@ isdn_unexclusive_channel(int di, int ch)
}
/*
- * receive callback handler for drivers not supporting sk_buff's.
- * Parameters:
- *
- * di = Driver-Index.
- * channel = Number of B-Channel (0...)
- * buf = pointer to packet-data
- * len = Length of packet-data
- *
- */
-static void
-isdn_receive_callback(int drvidx, int chan, u_char * buf, int len)
-{
- struct sk_buff *skb;
-
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return;
- skb = dev_alloc_skb(len);
- if (skb) {
- memcpy(skb_put(skb, len), buf, len);
- isdn_receive_skb_callback(drvidx, chan, skb);
- } else
- printk(KERN_WARNING "isdn: rcv alloc_skb failed, packet dropped.\n");
-}
-
-/*
* writebuf replacement for SKB_ABLE drivers
*/
static int
@@ -1869,60 +1934,69 @@ isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len,
int user)
{
int ret;
+ int hl = dev->drv[drvidx]->interface->hl_hdrlen;
+ struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC);
- if (dev->drv[drvidx]->interface->writebuf)
- ret = dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf,
- len, user);
- else {
- struct sk_buff *skb;
-
- skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len,
- GFP_ATOMIC);
- if (skb == NULL)
- return 0;
-
- skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen);
- SET_SKB_FREE(skb);
-
- if (user)
- copy_from_user(skb_put(skb, len), buf, len);
- else
- memcpy(skb_put(skb, len), buf, len);
+ if (!skb)
+ return 0;
+ skb_reserve(skb, hl);
+ if (user)
+ copy_from_user(skb_put(skb, len), buf, len);
+ else
+ memcpy(skb_put(skb, len), buf, len);
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx,
- chan, skb);
- if (ret <= 0)
- kfree_skb(skb);
- }
+ ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
+ if (ret <= 0)
+ dev_kfree_skb(skb);
if (ret > 0)
dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
return ret;
}
/*
- * writebuf_skb replacement for NON SKB_ABLE drivers
- * If lowlevel-device does not support supports skbufs, use
- * standard send-routine, else sind directly.
- *
* Return: length of data on success, -ERRcode on failure.
*/
-
int
-isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff *skb)
+isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
{
int ret;
- int len = skb->len; /* skb pointer no longer valid after free */
-
- if (dev->drv[drvidx]->interface->writebuf_skb)
- ret = dev->drv[drvidx]->interface->
- writebuf_skb(drvidx, chan, skb);
- else {
- if ((ret = dev->drv[drvidx]->interface->
- writebuf(drvidx, chan, skb->data, skb->len, 0)) == len)
+ struct sk_buff *nskb = NULL;
+ int v110_ret = skb->len;
+ int idx = isdn_dc2minor(drvidx, chan);
+
+ if (dev->v110[idx]) {
+ atomic_inc(&dev->v110use[idx]);
+ nskb = isdn_v110_encode(dev->v110[idx], skb);
+ atomic_dec(&dev->v110use[idx]);
+ if (!nskb)
+ return 0;
+ v110_ret = *((int *)nskb->data);
+ skb_pull(nskb, sizeof(int));
+ if (!nskb->len) {
+ dev_kfree_skb(nskb);
dev_kfree_skb(skb);
- }
- if (ret > 0)
- dev->obytes[isdn_dc2minor(drvidx, chan)] += len;
+ return v110_ret;
+ }
+ /* V.110 must always be acknowledged */
+ ack = 1;
+ ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb);
+ } else
+ ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
+ if (ret > 0) {
+ dev->obytes[idx] += ret;
+ if (dev->v110[idx]) {
+ atomic_inc(&dev->v110use[idx]);
+ dev->v110[idx]->skbuser++;
+ atomic_dec(&dev->v110use[idx]);
+ dev_kfree_skb(skb);
+ /* For V.110 return unencoded data length */
+ ret = v110_ret;
+ if (ret == skb->len)
+ dev_kfree_skb(skb);
+ }
+ } else
+ if (dev->v110[idx])
+ dev_kfree_skb(nskb);
return ret;
}
@@ -1930,6 +2004,8 @@ isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff *skb)
* Low-level-driver registration
*/
+EXPORT_SYMBOL(register_isdn);
+
int
register_isdn(isdn_if * i)
{
@@ -1951,7 +2027,7 @@ register_isdn(isdn_if * i)
ISDN_MAX_CHANNELS);
return 0;
}
- if ((!i->writebuf_skb) && (!i->writebuf)) {
+ if (!i->writebuf_skb) {
printk(KERN_WARNING "register_isdn: No write routine given.\n");
return 0;
}
@@ -2019,7 +2095,6 @@ register_isdn(isdn_if * i)
i->channels = drvidx;
i->rcvcallb_skb = isdn_receive_skb_callback;
- i->rcvcallb = isdn_receive_callback;
i->statcallb = isdn_status_callback;
if (!strlen(i->id))
sprintf(i->id, "line%d", drvidx);
@@ -2078,11 +2153,7 @@ int
isdn_init(void)
{
int i;
- char irev[50];
- char trev[50];
- char nrev[50];
- char prev[50];
- char arev[50];
+ char tmprev[50];
sti();
if (!(dev = (isdn_dev *) kmalloc(sizeof(isdn_dev), GFP_KERNEL))) {
@@ -2126,18 +2197,18 @@ isdn_init(void)
}
#endif /* CONFIG_ISDN_PPP */
- isdn_export_syms();
-
- strcpy(irev, isdn_revision);
- strcpy(trev, isdn_tty_revision);
- strcpy(nrev, isdn_net_revision);
- strcpy(prev, isdn_ppp_revision);
- strcpy(arev, isdn_audio_revision);
- printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(irev));
- printk("%s/", isdn_getrev(trev));
- printk("%s/", isdn_getrev(nrev));
- printk("%s/", isdn_getrev(prev));
- printk("%s", isdn_getrev(arev));
+ strcpy(tmprev, isdn_revision);
+ printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
+ strcpy(tmprev, isdn_tty_revision);
+ printk("%s/", isdn_getrev(tmprev));
+ strcpy(tmprev, isdn_net_revision);
+ printk("%s/", isdn_getrev(tmprev));
+ strcpy(tmprev, isdn_ppp_revision);
+ printk("%s/", isdn_getrev(tmprev));
+ strcpy(tmprev, isdn_audio_revision);
+ printk("%s/", isdn_getrev(tmprev));
+ strcpy(tmprev, isdn_v110_revision);
+ printk("%s", isdn_getrev(tmprev));
#ifdef MODULE
printk(" loaded\n");
diff --git a/drivers/isdn/isdn_common.h b/drivers/isdn/isdn_common.h
index d0df7fe79..b9d5df715 100644
--- a/drivers/isdn/isdn_common.h
+++ b/drivers/isdn/isdn_common.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.h,v 1.6 1997/02/28 02:32:44 fritz Exp $
+/* $Id: isdn_common.h,v 1.9 1998/02/20 17:19:01 fritz Exp $
* header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel).
*
@@ -21,6 +21,24 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.h,v $
+ * Revision 1.9 1998/02/20 17:19:01 fritz
+ * Added common stub for sending commands to lowlevel.
+ *
+ * Revision 1.8 1997/10/09 21:28:49 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ * New L1 error status (not yet in use).
+ * Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.7 1997/10/01 09:20:30 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
* Revision 1.6 1997/02/28 02:32:44 fritz
* Cleanup: Moved some tty related stuff from isdn_common.c
* to isdn_tty.c
@@ -61,6 +79,7 @@ extern void isdn_MOD_INC_USE_COUNT(void);
extern void isdn_MOD_DEC_USE_COUNT(void);
extern void isdn_free_channel(int di, int ch, int usage);
extern void isdn_all_eaz(int di, int ch);
+extern int isdn_command(isdn_ctrl *);
extern int isdn_dc2minor(int di, int ch);
extern void isdn_info_update(void);
extern char *isdn_map_eaz2msn(char *msn, int di);
@@ -69,13 +88,8 @@ extern void isdn_unexclusive_channel(int di, int ch);
extern int isdn_getnum(char **);
extern int isdn_readbchan(int, int, u_char *, u_char *, int, int);
extern int isdn_get_free_channel(int, int, int, int, int);
-extern int isdn_writebuf_skb_stub(int, int, struct sk_buff *);
+extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
extern int register_isdn(isdn_if * i);
-#if (LINUX_VERSION_CODE < 0x020111)
-extern void isdn_export_syms(void);
-#else
-#define isdn_export_syms()
-#endif
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
extern void isdn_dumppkt(char *, u_char *, int, int);
#endif
diff --git a/drivers/isdn/isdn_concap.c b/drivers/isdn/isdn_concap.c
new file mode 100644
index 000000000..0d9abb226
--- /dev/null
+++ b/drivers/isdn/isdn_concap.c
@@ -0,0 +1,108 @@
+/* $Id: isdn_concap.c,v 1.2 1998/01/31 22:49:21 keil Exp $
+
+ * Stuff to support the concap_proto by isdn4linux. isdn4linux - specific
+ * stuff goes here. Stuff that depends only on the concap protocol goes to
+ * another -- protocol specific -- source file.
+ *
+ * $Log: isdn_concap.c,v $
+ * Revision 1.2 1998/01/31 22:49:21 keil
+ * correct comments
+ *
+ * Revision 1.1 1998/01/31 22:27:57 keil
+ * New files from Henner Eisen for X.25 support
+ *
+ */
+
+
+#include <linux/isdn.h>
+#include "isdn_x25iface.h"
+#include "isdn_net.h"
+#include <linux/concap.h>
+#include "isdn_concap.h"
+
+/* The declaration of this (or a plublic variant thereof) should really go
+ in linux/isdn.h. But we really need it here (and isdn_ppp, like us, also
+ refers to that private function currently owned by isdn_net.c) */
+extern int isdn_net_force_dial_lp(isdn_net_local *);
+
+
+/* The following set of device service operations are for encapsulation
+ protocols that require for reliable datalink sematics. That means:
+
+ - before any data is to be submitted the connection must explicitly
+ be set up.
+ - after the successful set up of the connection is signalled the
+ connection is considered to be reliably up.
+
+ Auto-dialing ist not compatible with this requirements. Thus, auto-dialing
+ is completely bypassed.
+
+ It might be possible to implement a (non standardized) datalink protocol
+ that provides a reliable data link service while using some auto dialing
+ mechanism. Such a protocol would need an auxiliary channel (i.e. user-user-
+ signaling on the D-channel) while the B-channel is down.
+ */
+
+
+int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
+{
+ int tmp;
+ struct device *ndev = concap -> net_dev;
+ isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+
+ IX25DEBUG( "isdn_concap_dl_data_req: %s \n", concap->net_dev->name);
+ lp->huptimer = 0;
+ tmp=isdn_net_send_skb(ndev, lp, skb);
+ IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, tmp);
+ return tmp;
+}
+
+
+int isdn_concap_dl_connect_req(struct concap_proto *concap)
+{
+ struct device *ndev = concap -> net_dev;
+ isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+ int ret;
+ IX25DEBUG( "isdn_concap_dl_connect_req: %s \n", ndev -> name);
+
+ /* dial ... */
+ ret = isdn_net_force_dial_lp( lp );
+ if ( ret ) IX25DEBUG("dialing failed\n");
+ return 0;
+}
+
+int isdn_concap_dl_disconn_req(struct concap_proto *concap)
+{
+ IX25DEBUG( "isdn_concap_dl_disconn_req: %s \n", concap -> net_dev -> name);
+
+ isdn_net_hangup( concap -> net_dev );
+ return 0;
+}
+
+struct concap_device_ops isdn_concap_reliable_dl_dops = {
+ &isdn_concap_dl_data_req,
+ &isdn_concap_dl_connect_req,
+ &isdn_concap_dl_disconn_req
+};
+
+struct concap_device_ops isdn_concap_demand_dial_dops = {
+ NULL, /* set this first entry to something like &isdn_net_start_xmit,
+ but the entry part of the current isdn_net_start_xmit must be
+ separated first. */
+ /* no connection control for demand dial semantics */
+ NULL,
+ NULL,
+};
+
+/* The following should better go into a dedicated source file such that
+ this sourcefile does not need to include any protocol specific header
+ files. For now:
+ */
+struct concap_proto * isdn_concap_new( int encap )
+{
+ switch ( encap ) {
+ case ISDN_NET_ENCAP_X25IFACE:
+ return isdn_x25iface_proto_new();
+ }
+ return NULL;
+}
diff --git a/drivers/isdn/isdn_concap.h b/drivers/isdn/isdn_concap.h
new file mode 100644
index 000000000..722f8ee33
--- /dev/null
+++ b/drivers/isdn/isdn_concap.h
@@ -0,0 +1,7 @@
+/* $Id: isdn_concap.h,v 1.2 1998/01/31 22:49:21 keil Exp $
+ */
+extern struct concap_device_ops isdn_concap_reliable_dl_dops;
+extern struct concap_device_ops isdn_concap_demand_dial_dops;
+extern struct concap_proto * isdn_concap_new( int );
+
+
diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c
index c44fcc74a..46b460370 100644
--- a/drivers/isdn/isdn_net.c
+++ b/drivers/isdn/isdn_net.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.44 1997/05/27 15:17:26 fritz Exp $
+/* $Id: isdn_net.c,v 1.55 1998/02/23 19:38:22 fritz Exp $
* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
@@ -21,6 +21,54 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.c,v $
+ * Revision 1.55 1998/02/23 19:38:22 fritz
+ * Corrected check for modified feature-flags.
+ *
+ * Revision 1.54 1998/02/20 17:15:07 fritz
+ * Changes for recent kernels.
+ * Ugly workaround for adjusting Ethernet frames with recent kernels.
+ * replaced direct calls to lowlevel-driver command by common hook.
+ *
+ * Revision 1.53 1998/01/31 22:05:54 keil
+ * Lots of changes for X.25 support:
+ * Added generic support for connection-controlling encapsulation protocols
+ * Added support of BHUP status message
+ * Added support for additional p_encap X25IFACE
+ * Added support for kernels >= 2.1.72
+ *
+ * Revision 1.52 1998/01/31 19:29:51 calle
+ * Merged changes from and for 2.1.82, not tested only compiled ...
+ *
+ * Revision 1.51 1997/10/09 21:28:50 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ * New L1 error status (not yet in use).
+ * Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.50 1997/10/01 09:20:32 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.49 1997/08/21 14:38:13 fritz
+ * Bugfix: Did not compile without SyncPPP.
+ *
+ * Revision 1.48 1997/06/22 11:57:15 fritz
+ * Added ability to adjust slave triggerlevel.
+ *
+ * Revision 1.47 1997/06/21 10:52:05 fritz
+ * Removed wrong SET_SKB_FREE in isdn_net_send_skb()
+ *
+ * Revision 1.46 1997/06/17 13:05:24 hipp
+ * Applied Eric's underflow-patches (slightly modified)
+ *
+ * Revision 1.45 1997/06/10 16:24:22 hipp
+ * hard_header changes for syncPPP (now behaves like RAWIP)
+ *
* Revision 1.44 1997/05/27 15:17:26 fritz
* Added changes for recent 2.1.x kernels:
* changed return type of isdn_close
@@ -196,16 +244,18 @@
#include <linux/isdn.h>
#include <net/arp.h>
#include <net/icmp.h>
-#if (LINUX_VERSION_CODE >= 0x020117)
-#include <linux/poll.h>
+#ifndef DEV_NUMBUFFS
+#include <net/pkt_sched.h>
#endif
+#include <linux/inetdevice.h>
#include "isdn_common.h"
#include "isdn_net.h"
#ifdef CONFIG_ISDN_PPP
#include "isdn_ppp.h"
#endif
-#ifndef DEV_NUMBUFFS
-#include <net/pkt_sched.h>
+#ifdef CONFIG_ISDN_X25
+#include <linux/concap.h>
+#include "isdn_concap.h"
#endif
/* Prototypes */
@@ -218,7 +268,7 @@ static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
static void dev_purge_queues(struct device *dev); /* move this to net/core/dev.c */
#endif
-char *isdn_net_revision = "$Revision: 1.44 $";
+char *isdn_net_revision = "$Revision: 1.55 $";
/*
* Code for raw-networking over ISDN
@@ -229,22 +279,28 @@ isdn_net_unreachable(struct device *dev, struct sk_buff *skb, char *reason)
{
printk(KERN_DEBUG "isdn_net: %s: %s, send ICMP\n",
dev->name, reason);
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0
-#if (LINUX_VERSION_CODE < 0x02010f) /* 2.1.15 */
- ,dev
-#endif
- );
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
}
static void
isdn_net_reset(struct device *dev)
{
+#ifdef CONFIG_ISDN_X25
+ struct concap_device_ops * dops =
+ ( (isdn_net_local *) dev->priv ) -> dops;
+ struct concap_proto * cprot =
+ ( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
+#endif
ulong flags;
save_flags(flags);
cli(); /* Avoid glitch on writes to CMD regs */
dev->interrupt = 0;
dev->tbusy = 0;
+#ifdef CONFIG_ISDN_X25
+ if( cprot && cprot -> pops && dops )
+ cprot -> pops -> restart ( cprot, dev, dops );
+#endif
restore_flags(flags);
}
@@ -254,14 +310,22 @@ isdn_net_open(struct device *dev)
{
int i;
struct device *p;
+ struct in_device *in_dev;
isdn_net_reset(dev);
dev->start = 1;
- /* Fill in the MAC-level header. */
+ /* Fill in the MAC-level header (not needed, but for compatibility... */
for (i = 0; i < ETH_ALEN - sizeof(u32); i++)
dev->dev_addr[i] = 0xfc;
- memset(&(dev->dev_addr[i]), 0, sizeof(u32));
-
+ if ((in_dev = dev->ip_ptr) != NULL) {
+ /*
+ * Any address will do - we take the first
+ */
+ struct in_ifaddr *ifa = in_dev->ifa_list;
+ if (ifa != NULL)
+ memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
+ }
+
/* If this interface has slaves, start them also */
if ((p = (((isdn_net_local *) dev->priv)->slave))) {
@@ -356,7 +420,7 @@ isdn_net_autohup()
anymore = 0;
while (p) {
- isdn_net_local *l = (isdn_net_local *) & (p->local);
+ isdn_net_local *l = p->local;
if ((jiffies - last_jiffies) == 0)
l->cps = l->transcount;
else
@@ -405,18 +469,24 @@ isdn_net_autohup()
* Return: 1 = Event handled, 0 = not for us or unknown Event.
*/
int
-isdn_net_stat_callback(int idx, int cmd)
+isdn_net_stat_callback(int idx, isdn_ctrl *c)
{
isdn_net_dev *p = dev->st_netdev[idx];
-
+ int cmd = c->command;
+
if (p) {
- isdn_net_local *lp = &(p->local);
+ isdn_net_local *lp = p->local;
+#ifdef CONFIG_ISDN_X25
+ struct concap_proto *cprot = lp -> netdev -> cprot;
+ struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
+#endif
switch (cmd) {
case ISDN_STAT_BSENT:
/* A packet has successfully been sent out */
if ((lp->flags & ISDN_NET_CONNECTED) &&
(!lp->dialstate)) {
lp->stats.tx_packets++;
+ lp->stats.tx_bytes += c->parm.length;
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) {
struct device *mdev;
if (lp->master)
@@ -449,6 +519,16 @@ isdn_net_stat_callback(int idx, int cmd)
break;
case ISDN_STAT_DHUP:
/* Either D-Channel-hangup or error during dialout */
+#ifdef CONFIG_ISDN_X25
+ /* If we are not connencted then dialing had
+ failed. If there are generic encap protocol
+ receiver routines signal the closure of
+ the link*/
+
+ if( !(lp->flags & ISDN_NET_CONNECTED)
+ && pops && pops -> disconn_ind )
+ pops -> disconn_ind(cprot);
+#endif /* CONFIG_ISDN_X25 */
if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
lp->flags &= ~ISDN_NET_CONNECTED;
if (lp->first_skb) {
@@ -475,6 +555,18 @@ isdn_net_stat_callback(int idx, int cmd)
return 1;
}
break;
+#ifdef CONFIG_ISDN_X25
+ case ISDN_STAT_BHUP:
+ /* B-Channel-hangup */
+ /* try if there are generic encap protocol
+ receiver routines and signal the closure of
+ the link */
+ if( pops && pops -> disconn_ind ){
+ pops -> disconn_ind(cprot);
+ return 1;
+ }
+ break;
+#endif /* CONFIG_ISDN_X25 */
case ISDN_STAT_BCONN:
/* B-Channel is up */
switch (lp->dialstate) {
@@ -492,6 +584,8 @@ isdn_net_stat_callback(int idx, int cmd)
dev->rx_netdev[idx] = p;
lp->dialstate = 0;
isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1);
+ if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
+ isdn_timer_ctrl(ISDN_TIMER_KEEPALIVE, 1);
printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
/* If first Chargeinfo comes before B-Channel connect,
* we correct the timestamp here.
@@ -504,7 +598,15 @@ isdn_net_stat_callback(int idx, int cmd)
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
isdn_ppp_wakeup_daemon(lp);
#endif
+#ifdef CONFIG_ISDN_X25
+ /* try if there are generic concap receiver routines */
+ if( pops )
+ if( pops->connect_ind)
+ pops->connect_ind(cprot);
+
+#endif /* CONFIG_ISDN_X25 */
if (lp->first_skb) {
+
if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
lp->first_skb = NULL;
}
@@ -573,11 +675,13 @@ isdn_net_dial(void)
isdn_ctrl cmd;
while (p) {
+ isdn_net_local *lp = p->local;
+
#ifdef ISDN_DEBUG_NET_DIAL
- if (p->local.dialstate)
- printk(KERN_DEBUG "%s: dialstate=%d\n", p->local.name, p->local.dialstate);
+ if (lp->dialstate)
+ printk(KERN_DEBUG "%s: dialstate=%d\n", lp->name, lp->dialstate);
#endif
- switch (p->local.dialstate) {
+ switch (lp->dialstate) {
case 0:
/* Nothing to do for this interface */
break;
@@ -587,132 +691,133 @@ isdn_net_dial(void)
*/
save_flags(flags);
cli();
- p->local.dial = p->local.phone[1];
+ lp->dial = lp->phone[1];
restore_flags(flags);
- if (!p->local.dial) {
+ if (!lp->dial) {
printk(KERN_WARNING "%s: phone number deleted?\n",
- p->local.name);
+ lp->name);
isdn_net_hangup(&p->dev);
break;
}
anymore = 1;
- p->local.dialstate++;
+ lp->dialstate++;
/* Fall through */
case 2:
/* Prepare dialing. Clear EAZ, then set EAZ. */
- cmd.driver = p->local.isdn_device;
- cmd.arg = p->local.isdn_channel;
+ cmd.driver = lp->isdn_device;
+ cmd.arg = lp->isdn_channel;
cmd.command = ISDN_CMD_CLREAZ;
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
- sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(p->local.msn, cmd.driver));
+ isdn_command(&cmd);
+ sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver));
cmd.command = ISDN_CMD_SETEAZ;
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
- p->local.dialretry = 0;
+ isdn_command(&cmd);
+ lp->dialretry = 0;
anymore = 1;
- p->local.dialstate++;
+ lp->dialstate++;
/* Falls through */
case 3:
/* Setup interface, dial current phone-number, switch to next number.
* If list of phone-numbers is exhausted, increment
* retry-counter.
*/
- cmd.driver = p->local.isdn_device;
+ cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_SETL2;
- cmd.arg = p->local.isdn_channel + (p->local.l2_proto << 8);
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
- cmd.driver = p->local.isdn_device;
+ cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
+ isdn_command(&cmd);
+ cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_SETL3;
- cmd.arg = p->local.isdn_channel + (p->local.l3_proto << 8);
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
- cmd.driver = p->local.isdn_device;
- cmd.arg = p->local.isdn_channel;
+ cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
+ isdn_command(&cmd);
+ cmd.driver = lp->isdn_device;
+ cmd.arg = lp->isdn_channel;
save_flags(flags);
cli();
- if (!p->local.dial) {
+ if (!lp->dial) {
restore_flags(flags);
printk(KERN_WARNING "%s: phone number deleted?\n",
- p->local.name);
+ lp->name);
isdn_net_hangup(&p->dev);
break;
}
- if (!strcmp(p->local.dial->num, "LEASED")) {
+ if (!strcmp(lp->dial->num, "LEASED")) {
restore_flags(flags);
- p->local.dialstate = 4;
- printk(KERN_INFO "%s: Open leased line ...\n", p->local.name);
+ lp->dialstate = 4;
+ printk(KERN_INFO "%s: Open leased line ...\n", lp->name);
} else {
- sprintf(cmd.parm.setup.phone, "%s", p->local.dial->num);
+ sprintf(cmd.parm.setup.phone, "%s", lp->dial->num);
/*
* Switch to next number or back to start if at end of list.
*/
- if (!(p->local.dial = (isdn_net_phone *) p->local.dial->next)) {
- p->local.dial = p->local.phone[1];
- p->local.dialretry++;
+ if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) {
+ lp->dial = lp->phone[1];
+ lp->dialretry++;
}
restore_flags(flags);
+ cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_DIAL;
cmd.parm.setup.si1 = 7;
cmd.parm.setup.si2 = 0;
sprintf(cmd.parm.setup.eazmsn, "%s",
- isdn_map_eaz2msn(p->local.msn, cmd.driver));
- i = isdn_dc2minor(p->local.isdn_device, p->local.isdn_channel);
+ isdn_map_eaz2msn(lp->msn, cmd.driver));
+ i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel);
if (i >= 0) {
strcpy(dev->num[i], cmd.parm.setup.phone);
isdn_info_update();
}
- printk(KERN_INFO "%s: dialing %d %s...\n", p->local.name,
- p->local.dialretry - 1, cmd.parm.setup.phone);
- p->local.dtimer = 0;
+ printk(KERN_INFO "%s: dialing %d %s...\n", lp->name,
+ lp->dialretry - 1, cmd.parm.setup.phone);
+ lp->dtimer = 0;
#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dial: d=%d c=%d\n", p->local.isdn_device,
- p->local.isdn_channel);
+ printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device,
+ lp->isdn_channel);
#endif
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
+ isdn_command(&cmd);
}
- p->local.huptimer = 0;
- p->local.outgoing = 1;
- if (p->local.chargeint) {
- p->local.hupflags |= ISDN_HAVECHARGE;
- p->local.hupflags &= ~ISDN_WAITCHARGE;
+ lp->huptimer = 0;
+ lp->outgoing = 1;
+ if (lp->chargeint) {
+ lp->hupflags |= ISDN_HAVECHARGE;
+ lp->hupflags &= ~ISDN_WAITCHARGE;
} else {
- p->local.hupflags |= ISDN_WAITCHARGE;
- p->local.hupflags &= ~ISDN_HAVECHARGE;
+ lp->hupflags |= ISDN_WAITCHARGE;
+ lp->hupflags &= ~ISDN_HAVECHARGE;
}
anymore = 1;
- p->local.dialstate =
- (p->local.cbdelay &&
- (p->local.flags & ISDN_NET_CBOUT)) ? 12 : 4;
+ lp->dialstate =
+ (lp->cbdelay &&
+ (lp->flags & ISDN_NET_CBOUT)) ? 12 : 4;
break;
case 4:
/* Wait for D-Channel-connect.
* If timeout and max retries not
* reached, switch back to state 3.
*/
- if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
- if (p->local.dialretry < p->local.dialmax) {
- p->local.dialstate = 3;
+ if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
+ if (lp->dialretry < lp->dialmax) {
+ lp->dialstate = 3;
} else
isdn_net_hangup(&p->dev);
anymore = 1;
break;
case 5:
/* Got D-Channel-Connect, send B-Channel-request */
- cmd.driver = p->local.isdn_device;
- cmd.arg = p->local.isdn_channel;
+ cmd.driver = lp->isdn_device;
+ cmd.arg = lp->isdn_channel;
cmd.command = ISDN_CMD_ACCEPTB;
anymore = 1;
- p->local.dtimer = 0;
- p->local.dialstate++;
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
+ lp->dtimer = 0;
+ lp->dialstate++;
+ isdn_command(&cmd);
break;
case 6:
/* Wait for B- or D-Channel-connect. If timeout,
* switch back to state 3.
*/
#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer2: %d\n", p->local.dtimer);
+ printk(KERN_DEBUG "dialtimer2: %d\n", lp->dtimer);
#endif
- if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
- p->local.dialstate = 3;
+ if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
+ lp->dialstate = 3;
anymore = 1;
break;
case 7:
@@ -720,69 +825,69 @@ isdn_net_dial(void)
* then wait for D-Channel-connect
*/
#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer);
+ printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
#endif
- cmd.driver = p->local.isdn_device;
+ cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_SETL2;
- cmd.arg = p->local.isdn_channel + (p->local.l2_proto << 8);
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
- cmd.driver = p->local.isdn_device;
+ cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
+ isdn_command(&cmd);
+ cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_SETL3;
- cmd.arg = p->local.isdn_channel + (p->local.l3_proto << 8);
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
- if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT15)
+ cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
+ isdn_command(&cmd);
+ if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15)
isdn_net_hangup(&p->dev);
else {
anymore = 1;
- p->local.dialstate++;
+ lp->dialstate++;
}
break;
case 9:
/* Got incoming D-Channel-Connect, send B-Channel-request */
- cmd.driver = p->local.isdn_device;
- cmd.arg = p->local.isdn_channel;
+ cmd.driver = lp->isdn_device;
+ cmd.arg = lp->isdn_channel;
cmd.command = ISDN_CMD_ACCEPTB;
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
+ isdn_command(&cmd);
anymore = 1;
- p->local.dtimer = 0;
- p->local.dialstate++;
+ lp->dtimer = 0;
+ lp->dialstate++;
break;
case 8:
case 10:
/* Wait for B- or D-channel-connect */
#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer);
+ printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
#endif
- if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
+ if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
isdn_net_hangup(&p->dev);
else
anymore = 1;
break;
case 11:
/* Callback Delay */
- if (p->local.dtimer++ > p->local.cbdelay)
- p->local.dialstate = 1;
+ if (lp->dtimer++ > lp->cbdelay)
+ lp->dialstate = 1;
anymore = 1;
break;
case 12:
/* Remote does callback. Hangup after cbdelay, then wait for incoming
* call (in state 4).
*/
- if (p->local.dtimer++ > p->local.cbdelay) {
- printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->local.name);
- p->local.dtimer = 0;
- p->local.dialstate = 4;
- cmd.driver = p->local.isdn_device;
+ if (lp->dtimer++ > lp->cbdelay) {
+ printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name);
+ lp->dtimer = 0;
+ lp->dialstate = 4;
+ cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_HANGUP;
- cmd.arg = p->local.isdn_channel;
- (void) dev->drv[cmd.driver]->interface->command(&cmd);
- isdn_all_eaz(p->local.isdn_device, p->local.isdn_channel);
+ cmd.arg = lp->isdn_channel;
+ isdn_command(&cmd);
+ isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
}
anymore = 1;
break;
default:
printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
- p->local.dialstate, p->local.name);
+ lp->dialstate, lp->name);
}
p = (isdn_net_dev *) p->next;
}
@@ -797,6 +902,10 @@ isdn_net_hangup(struct device *d)
{
isdn_net_local *lp = (isdn_net_local *) d->priv;
isdn_ctrl cmd;
+#ifdef CONFIG_ISDN_X25
+ struct concap_proto *cprot = lp -> netdev -> cprot;
+ struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
+#endif
if (lp->flags & ISDN_NET_CONNECTED) {
lp->flags &= ~ISDN_NET_CONNECTED;
@@ -804,10 +913,18 @@ isdn_net_hangup(struct device *d)
#ifdef CONFIG_ISDN_PPP
isdn_ppp_free(lp);
#endif
+#ifdef CONFIG_ISDN_X25
+ /* try if there are generic encap protocol
+ receiver routines and signal the closure of
+ the link */
+ if( pops && pops -> disconn_ind )
+ pops -> disconn_ind(cprot);
+#endif /* CONFIG_ISDN_X25 */
+
cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_HANGUP;
cmd.arg = lp->isdn_channel;
- (void) dev->drv[cmd.driver]->interface->command(&cmd);
+ isdn_command(&cmd);
printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge);
isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
}
@@ -820,28 +937,43 @@ typedef struct {
} ip_ports;
static void
-isdn_net_log_packet(u_char * buf, isdn_net_local * lp)
+isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
{
- u_char *p = buf;
- unsigned short proto = ETH_P_IP;
+ u_char *p = skb->nh.raw; /* hopefully, this was set correctly */
+ unsigned short proto = ntohs(skb->protocol);
int data_ofs;
ip_ports *ipp;
char addinfo[100];
addinfo[0] = '\0';
- switch (lp->p_encap) {
- case ISDN_NET_ENCAP_IPTYP:
- proto = ntohs(*(unsigned short *) &buf[0]);
- p = &buf[2];
- break;
- case ISDN_NET_ENCAP_ETHER:
- proto = ntohs(*(unsigned short *) &buf[12]);
- p = &buf[14];
- break;
- case ISDN_NET_ENCAP_CISCOHDLC:
- proto = ntohs(*(unsigned short *) &buf[2]);
- p = &buf[4];
- break;
+ /* This check stolen from 2.1.72 dev_queue_xmit_nit() */
+ if (skb->nh.raw < skb->data || skb->nh.raw >= skb->tail) {
+ /* fall back to old isdn_net_log_packet method() */
+ char * buf = skb->data;
+
+ printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->name);
+ p = buf;
+ proto = ETH_P_IP;
+ switch (lp->p_encap) {
+ case ISDN_NET_ENCAP_IPTYP:
+ proto = ntohs(*(unsigned short *) &buf[0]);
+ p = &buf[2];
+ break;
+ case ISDN_NET_ENCAP_ETHER:
+ proto = ntohs(*(unsigned short *) &buf[12]);
+ p = &buf[14];
+ break;
+ case ISDN_NET_ENCAP_CISCOHDLC:
+ proto = ntohs(*(unsigned short *) &buf[2]);
+ p = &buf[4];
+ break;
+#ifdef CONFIG_ISDN_PPP
+ case ISDN_NET_ENCAP_SYNCPPP:
+ proto = ntohs(skb->protocol);
+ p = &buf[IPPP_MAX_HEADER];
+ break;
+#endif
+ }
}
data_ofs = ((p[0] & 15) * 4);
switch (proto) {
@@ -891,7 +1023,7 @@ isdn_net_log_packet(u_char * buf, isdn_net_local * lp)
/*
* Generic routine to send out an skbuf.
- * If lowlevel-device does not support supports skbufs, use
+ * If lowlevel-device does not support support skbufs, use
* standard send-routine, else send directly.
*
* Return: 0 on success, !0 on failure.
@@ -904,14 +1036,13 @@ isdn_net_send_skb(struct device *ndev, isdn_net_local * lp,
int ret;
int len = skb->len; /* save len */
- ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb);
+ ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
if (ret == len) {
lp->transcount += len;
clear_bit(0, (void *) &(ndev->tbusy));
return 0;
}
if (ret < 0) {
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
lp->stats.tx_errors++;
clear_bit(0, (void *) &(ndev->tbusy));
@@ -945,7 +1076,7 @@ isdn_net_xmit(struct device *ndev, isdn_net_local * lp, struct sk_buff *skb)
#endif
/* Reset hangup-timeout */
lp->huptimer = 0;
- if (lp->cps > 7000) {
+ if (lp->cps > lp->triggercps) {
/* Device overloaded */
/*
@@ -988,35 +1119,64 @@ isdn_net_xmit(struct device *ndev, isdn_net_local * lp, struct sk_buff *skb)
return ret;
}
+static void
+isdn_net_adjust_hdr(struct sk_buff *skb, struct device *dev)
+{
+ isdn_net_local *lp = (isdn_net_local *) dev->priv;
+ if (!skb)
+ return;
+ if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
+ ulong pullsize = (ulong)skb->nh.raw - (ulong)skb->data - ETH_HLEN;
+ if (pullsize)
+ skb_pull(skb, pullsize);
+ }
+}
+
/*
* Try sending a packet.
* If this interface isn't connected to a ISDN-Channel, find a free channel,
* and start dialing.
*/
-int
+static int
isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
{
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+#ifdef CONFIG_ISDN_X25
+ struct concap_proto * cprot = lp -> netdev -> cprot;
+#endif
if (ndev->tbusy) {
if (jiffies - ndev->trans_start < (2 * HZ))
return 1;
if (!lp->dialstate)
lp->stats.tx_errors++;
- ndev->tbusy = 0;
ndev->trans_start = jiffies;
}
- if (skb == NULL) {
- return 0;
- }
- /* Avoid timer-based retransmission conflicts. */
- if (test_and_set_bit(0, (void *) &ndev->tbusy) != 0)
- printk(KERN_WARNING
- "%s: Transmitter access conflict.\n",
- ndev->name);
- else {
- u_char *buf = skb->data;
+ ndev->tbusy = 1; /* left instead of obsolete test_and_set_bit() */
+#ifdef CONFIG_ISDN_X25
+/* At this point hard_start_xmit() passes control to the encapsulation
+ protocol (if present).
+ For X.25 auto-dialing is completly bypassed because:
+ - It does not conform with the semantics of a reliable datalink
+ service as needed by X.25 PLP.
+ - I don't want that the interface starts dialing when the network layer
+ sends a message which requests to disconnect the lapb link (or if it
+ sends any other message not resulting in data transmission).
+ Instead, dialing will be initiated by the encapsulation protocol entity
+ when a dl_establish request is received from the upper layer.
+*/
+ if( cprot ) {
+ return cprot -> pops -> encap_and_xmit ( cprot , skb);
+ } else
+#endif
+ /* auto-dialing xmit function */
+ {
+#ifdef ISDN_DEBUG_NET_DUMP
+ u_char *buf;
+#endif
+ isdn_net_adjust_hdr(skb, ndev);
#ifdef ISDN_DEBUG_NET_DUMP
+ buf = skb->data;
isdn_dumppkt("S:", buf, skb->len, 40);
#endif
if (!(lp->flags & ISDN_NET_CONNECTED)) {
@@ -1033,24 +1193,15 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
lp->pre_device,
lp->pre_channel)) < 0) {
restore_flags(flags);
-#if 0
- printk(KERN_WARNING
- "isdn_net_start_xmit: No channel for %s\n",
- ndev->name);
- /* we probably should drop the skb here and return 0 to omit
- 'socket destroy delayed' messages */
- return 1;
-#else
isdn_net_unreachable(ndev, skb,
"No channel");
dev_kfree_skb(skb);
ndev->tbusy = 0;
return 0;
-#endif
}
/* Log packet, which triggered dialing */
if (dev->net_verbose)
- isdn_net_log_packet(buf, lp);
+ isdn_net_log_skb(skb, lp);
lp->dialstate = 1;
lp->flags |= ISDN_NET_CONNECTED;
/* Connect interface with channel */
@@ -1114,12 +1265,26 @@ static int
isdn_net_close(struct device *dev)
{
struct device *p;
+#ifdef CONFIG_ISDN_X25
+ struct concap_proto * cprot =
+ ( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
+ /* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name ); */
+#endif
+#ifdef CONFIG_ISDN_X25
+ if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
+#endif
dev->tbusy = 1;
dev->start = 0;
if ((p = (((isdn_net_local *) dev->priv)->slave))) {
/* If this interface has slaves, stop them also */
while (p) {
+#ifdef CONFIG_ISDN_X25
+ cprot = ( (isdn_net_local *) p->priv )
+ -> netdev -> cprot;
+ if( cprot && cprot -> pops )
+ cprot -> pops -> close( cprot );
+#endif
isdn_net_hangup(p);
p->tbusy = 1;
p->start = 0;
@@ -1156,6 +1321,7 @@ isdn_net_type_trans(struct sk_buff *skb, struct device *dev)
struct ethhdr *eth;
unsigned char *rawp;
+ skb->mac.raw = skb->data;
skb_pull(skb, ETH_HLEN);
eth = skb->mac.ethernet;
@@ -1170,7 +1336,7 @@ isdn_net_type_trans(struct sk_buff *skb, struct device *dev)
* so don't forget to remove it.
*/
- else if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
+ else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) {
if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
skb->pkt_type = PACKET_OTHERHOST;
}
@@ -1193,6 +1359,97 @@ isdn_net_type_trans(struct sk_buff *skb, struct device *dev)
return htons(ETH_P_802_2);
}
+static void
+isdn_net_slarp_send(isdn_net_local *lp, int is_reply)
+{
+ unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
+ struct sk_buff *skb = dev_alloc_skb(hl + sizeof(cisco_hdr) + sizeof(cisco_slarp));
+ unsigned long t = (jiffies / HZ * 1000000);
+ int len;
+ cisco_hdr *ch;
+ cisco_slarp *s;
+
+ if (!skb) {
+ printk(KERN_WARNING
+ "%s: Could not allocate SLARP reply\n", lp->name);
+ return;
+ }
+ skb_reserve(skb, hl);
+ ch = (cisco_hdr *)skb_put(skb, sizeof(cisco_hdr));
+ ch->addr = CISCO_ADDR_UNICAST;
+ ch->ctrl = 0;
+ ch->type = htons(CISCO_TYPE_SLARP);
+ s = (cisco_slarp *)skb_put(skb, sizeof(cisco_slarp));
+ if (is_reply) {
+ s->code = htonl(CISCO_SLARP_REPLY);
+ memset(&s->slarp.reply.ifaddr, 0, sizeof(__u32));
+ memset(&s->slarp.reply.netmask, 0, sizeof(__u32));
+ } else {
+ lp->cisco_myseq++;
+ s->code = htonl(CISCO_SLARP_KEEPALIVE);
+ s->slarp.keepalive.my_seq = htonl(lp->cisco_myseq);
+ s->slarp.keepalive.your_seq = htonl(lp->cisco_yourseq);
+ }
+ s->rel = 0xffff;
+ s->t1 = t >> 16;
+ s->t0 = t & 0xffff;
+ len = skb->len;
+ if (isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 0, skb) != len)
+ dev_kfree_skb(skb);
+}
+
+static void
+isdn_net_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
+{
+ cisco_slarp *s = (cisco_slarp *)skb->data;
+
+ switch (ntohl(s->code)) {
+ case CISCO_SLARP_REQUEST:
+ isdn_net_slarp_send(lp, 1);
+ break;
+ case CISCO_SLARP_REPLY:
+ /* Ignore replies */
+ break;
+ case CISCO_SLARP_KEEPALIVE:
+ lp->cisco_yourseq = s->slarp.keepalive.my_seq;
+ if (ntohl(s->slarp.keepalive.my_seq == lp->cisco_myseq)) {
+ if (lp->cisco_loop++ == 2) {
+ printk(KERN_WARNING "%s: Keepalive Loop\n",
+ lp->name);
+ lp->cisco_myseq ^= jiffies;
+ }
+ } else
+ lp->cisco_loop = 0;
+ break;
+ }
+ kfree_skb(skb);
+}
+
+/*
+ * Called every 10 sec. via timer-interrupt if
+ * any network-interface has Cisco-Keepalive-Encapsulation
+ * and is online.
+ * Send Keepalive-Packet and re-schedule.
+ */
+void
+isdn_net_slarp_out(void)
+{
+ isdn_net_dev *p = dev->netdev;
+ int anymore = 0;
+
+ while (p) {
+ isdn_net_local *l = p->local;
+ if ((l->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) &&
+ (l->flags & ISDN_NET_CONNECTED) &&
+ (!l->dialstate) ) {
+ anymore = 1;
+ isdn_net_slarp_send(l, 0);
+ }
+ p = (isdn_net_dev *) p->next;
+ }
+ isdn_timer_ctrl(ISDN_TIMER_KEEPALIVE, anymore);
+}
+
/*
* Got a packet from ISDN-Channel.
*/
@@ -1200,23 +1457,19 @@ static void
isdn_net_receive(struct device *ndev, struct sk_buff *skb)
{
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
-#ifdef CONFIG_ISDN_PPP
isdn_net_local *olp = lp; /* original 'lp' */
+#ifdef CONFIG_ISDN_PPP
int proto = PPP_PROTOCOL(skb->data);
#endif
+#ifdef CONFIG_ISDN_X25
+ struct concap_proto *cprot = lp -> netdev -> cprot;
+#endif
+ cisco_hdr *ch;
lp->transcount += skb->len;
- lp->stats.rx_packets++;
-#ifdef CONFIG_ISDN_PPP
- /*
- * If encapsulation is syncppp, don't reset
- * huptimer on LCP packets.
- */
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP ||
- (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && proto != PPP_LCP))
-#endif
- lp->huptimer = 0;
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes += skb->len;
if (lp->master) {
/* Bundling: If device is a slave-device, deliver to master, also
* handle master's statistics and hangup-timeout
@@ -1224,16 +1477,9 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
ndev = lp->master;
lp = (isdn_net_local *) ndev->priv;
lp->stats.rx_packets++;
-#ifdef CONFIG_ISDN_PPP
- /*
- * If encapsulation is syncppp, don't reset
- * huptimer on LCP packets.
- */
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP ||
- (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && proto != PPP_LCP))
-#endif
- lp->huptimer = 0;
+ lp->stats.rx_bytes += skb->len;
}
+
skb->dev = ndev;
skb->pkt_type = PACKET_HOST;
skb->mac.raw = skb->data;
@@ -1243,22 +1489,61 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
switch (lp->p_encap) {
case ISDN_NET_ENCAP_ETHER:
/* Ethernet over ISDN */
+ olp->huptimer = 0;
+ lp->huptimer = 0;
skb->protocol = isdn_net_type_trans(skb, ndev);
break;
case ISDN_NET_ENCAP_UIHDLC:
/* HDLC with UI-frame (for ispa with -h1 option) */
+ olp->huptimer = 0;
+ lp->huptimer = 0;
skb_pull(skb, 2);
/* Fall through */
case ISDN_NET_ENCAP_RAWIP:
/* RAW-IP without MAC-Header */
+ olp->huptimer = 0;
+ lp->huptimer = 0;
skb->protocol = htons(ETH_P_IP);
break;
+ case ISDN_NET_ENCAP_CISCOHDLCK:
+ ch = (cisco_hdr *)skb->data;
+ if ((ch->addr != CISCO_ADDR_UNICAST) &&
+ (ch->addr != CISCO_ADDR_BROADCAST) ) {
+ printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n",
+ lp->name, ch->addr);
+ kfree_skb(skb);
+ return;
+ }
+ if (ch->ctrl != 0) {
+ printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n",
+ lp->name, ch->ctrl);
+ kfree_skb(skb);
+ return;
+ }
+ switch (ntohs(ch->type)) {
+ case CISCO_TYPE_INET:
+ skb_pull(skb, 4);
+ skb->protocol = htons(ETH_P_IP);
+ break;
+ case CISCO_TYPE_SLARP:
+ skb_pull(skb, 4);
+ isdn_net_slarp_in(olp, skb);
+ return;
+ default:
+ printk(KERN_WARNING "%s: Unknown Cisco type 0x%04x\n",
+ lp->name, ch->type);
+ kfree_skb(skb);
+ return;
+ }
+ break;
case ISDN_NET_ENCAP_CISCOHDLC:
/* CISCO-HDLC IP with type field and fake I-frame-header */
skb_pull(skb, 2);
/* Fall through */
case ISDN_NET_ENCAP_IPTYP:
/* IP with type field */
+ olp->huptimer = 0;
+ lp->huptimer = 0;
skb->protocol = *(unsigned short *) &(skb->data[0]);
skb_pull(skb, 2);
if (*(unsigned short *) skb->data == 0xFFFF)
@@ -1266,10 +1551,26 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
break;
#ifdef CONFIG_ISDN_PPP
case ISDN_NET_ENCAP_SYNCPPP:
+ /*
+ * If encapsulation is syncppp, don't reset
+ * huptimer on LCP packets.
+ */
+ if (proto != PPP_LCP) {
+ olp->huptimer = 0;
+ lp->huptimer = 0;
+ }
isdn_ppp_receive(lp->netdev, olp, skb);
return;
#endif
default:
+#ifdef CONFIG_ISDN_X25
+ /* try if there are generic sync_device receiver routines */
+ if(cprot) if(cprot -> pops)
+ if( cprot -> pops -> data_ind){
+ cprot -> pops -> data_ind(cprot,skb);
+ return;
+ };
+#endif /* CONFIG_ISDN_X25 */
printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
lp->name);
kfree_skb(skb);
@@ -1290,7 +1591,7 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb)
isdn_net_dev *p = dev->rx_netdev[idx];
if (p) {
- isdn_net_local *lp = &p->local;
+ isdn_net_local *lp = p->local;
if ((lp->flags & ISDN_NET_CONNECTED) &&
(!lp->dialstate)) {
isdn_net_receive(&p->dev, skb);
@@ -1329,15 +1630,15 @@ my_eth_header(struct sk_buff *skb, struct device *dev, unsigned short type,
* Anyway, the loopback-device should never use this function...
*/
- if (dev->flags & IFF_LOOPBACK) {
+ if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
memset(eth->h_dest, 0, dev->addr_len);
- return (dev->hard_header_len);
+ return ETH_HLEN /*(dev->hard_header_len)*/;
}
if (daddr) {
memcpy(eth->h_dest, daddr, dev->addr_len);
- return dev->hard_header_len;
+ return ETH_HLEN /*dev->hard_header_len*/;
}
- return -dev->hard_header_len;
+ return -ETH_HLEN /*dev->hard_header_len*/;
}
/*
@@ -1356,6 +1657,13 @@ isdn_net_header(struct sk_buff *skb, struct device *dev, unsigned short type,
case ISDN_NET_ENCAP_ETHER:
len = my_eth_header(skb, dev, type, daddr, saddr, plen);
break;
+#ifdef CONFIG_ISDN_PPP
+ case ISDN_NET_ENCAP_SYNCPPP:
+ /* stick on a fake header to keep fragmentation code happy. */
+ len = IPPP_MAX_HEADER;
+ skb_push(skb,len);
+ break;
+#endif
case ISDN_NET_ENCAP_RAWIP:
printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n");
len = 0;
@@ -1377,43 +1685,21 @@ isdn_net_header(struct sk_buff *skb, struct device *dev, unsigned short type,
*((ushort *) & skb->data[2]) = htons(type);
len = 4;
break;
+#ifdef CONFIG_ISDN_X25
+ default:
+ /* try if there are generic concap protocol routines */
+ if( lp-> netdev -> cprot ){
+ printk(KERN_WARNING "isdn_net_header called with concap_proto!\n");
+ len = 0;
+ break;
+ }
+ break;
+#endif /* CONFIG_ISDN_X25 */
}
return len;
}
/* We don't need to send arp, because we have point-to-point connections. */
-#if (LINUX_VERSION_CODE < 0x02010F)
-static int
-isdn_net_rebuild_header(void *buff, struct device *dev, unsigned long dst,
- struct sk_buff *skb)
-{
- isdn_net_local *lp = dev->priv;
- int ret = 0;
-
- if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
- struct ethhdr *eth = (struct ethhdr *) buff;
-
- /*
- * Only ARP/IP is currently supported
- */
-
- if (eth->h_proto != htons(ETH_P_IP)) {
- printk(KERN_WARNING
- "isdn_net: %s don't know how to resolve type %d addresses?\n",
- dev->name, (int) eth->h_proto);
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
- return 0;
- }
- /*
- * Try to get ARP to resolve the header.
- */
-#ifdef CONFIG_INET
- ret = arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb) ? 1 : 0;
-#endif
- }
- return ret;
-}
-#else
static int
isdn_net_rebuild_header(struct sk_buff *skb)
{
@@ -1439,12 +1725,12 @@ isdn_net_rebuild_header(struct sk_buff *skb)
* Try to get ARP to resolve the header.
*/
#ifdef CONFIG_INET
- ret = arp_find(eth->h_dest, skb) ? 1 : 0;
+ ret = arp_find(eth->h_dest, skb);
#endif
}
return ret;
}
-#endif
+
/*
* Interface-setup. (called just after registering a new interface)
*/
@@ -1465,21 +1751,13 @@ isdn_net_init(struct device *ndev)
return -ENODEV;
}
ether_setup(ndev);
-#if (LINUX_VERSION_CODE < 0x02010F)
- lp->org_hcb = ndev->header_cache_bind;
-#else
lp->org_hhc = ndev->hard_header_cache;
-#endif
lp->org_hcu = ndev->header_cache_update;
/* Setup the generic properties */
ndev->hard_header = NULL;
-#if (LINUX_VERSION_CODE < 0x02010F)
- ndev->header_cache_bind = NULL;
-#else
ndev->hard_header_cache = NULL;
-#endif
ndev->header_cache_update = NULL;
ndev->mtu = 1500;
ndev->flags = IFF_NOARP|IFF_POINTOPOINT;
@@ -1599,13 +1877,13 @@ isdn_net_swapbind(int drvidx)
#endif
p = dev->netdev;
while (p) {
- if (p->local.pre_device == drvidx)
- switch (p->local.pre_channel) {
+ if (p->local->pre_device == drvidx)
+ switch (p->local->pre_channel) {
case 0:
- p->local.pre_channel = 1;
+ p->local->pre_channel = 1;
break;
case 1:
- p->local.pre_channel = 0;
+ p->local->pre_channel = 0;
break;
}
p = (isdn_net_dev *) p->next;
@@ -1676,6 +1954,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
/* Accept only calls with Si1 = 7 (Data-Transmission) */
if (si1 != 7) {
+ restore_flags(flags);
if (dev->net_verbose > 1)
printk(KERN_INFO "isdn_net: Service-Indicator not 7, ignored\n");
return 0;
@@ -1689,6 +1968,8 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
#endif
swapped = 0;
while (p) {
+ isdn_net_local *lp = p->local;
+
/* If last check has triggered as binding-swap, revert it */
switch (swapped) {
case 2:
@@ -1699,25 +1980,25 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
break;
}
swapped = 0;
- if (!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz))
+ if (!strcmp(isdn_map_eaz2msn(lp->msn, di), eaz))
ematch = 1;
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
- p->local.name, p->local.msn, p->local.flags, p->local.dialstate);
+ lp->name, lp->msn, lp->flags, lp->dialstate);
#endif
- if ((!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz)) && /* EAZ is matching */
- (((!(p->local.flags & ISDN_NET_CONNECTED)) && /* but not connected */
+ if ((!strcmp(isdn_map_eaz2msn(lp->msn, di), eaz)) && /* EAZ is matching */
+ (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */
(USG_NONE(dev->usage[idx]))) || /* and ch. unused or */
- ((((p->local.dialstate == 4) || (p->local.dialstate == 12)) && /* if dialing */
- (!(p->local.flags & ISDN_NET_CALLBACK))) /* but no callback */
+ ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */
+ (!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */
))) {
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n",
- p->local.pre_device, p->local.pre_channel);
+ lp->pre_device, lp->pre_channel);
#endif
if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) {
- if ((p->local.pre_channel != ch) ||
- (p->local.pre_device != di)) {
+ if ((lp->pre_channel != ch) ||
+ (lp->pre_device != di)) {
/* Here we got a problem:
* If using an ICN-Card, an incoming call is always signaled on
* on the first channel of the card, if both channels are
@@ -1741,8 +2022,8 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
#endif
/* Yes, swap bindings only, if the original
* binding is bound to channel 1 of this driver */
- if ((p->local.pre_device == di) &&
- (p->local.pre_channel == 1)) {
+ if ((lp->pre_device == di) &&
+ (lp->pre_channel == 1)) {
isdn_net_swapbind(di);
swapped = 1;
} else {
@@ -1764,8 +2045,8 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
printk(KERN_DEBUG "n_fi: final check\n");
#endif
if ((dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) &&
- ((p->local.pre_channel != ch) ||
- (p->local.pre_device != di))) {
+ ((lp->pre_channel != ch) ||
+ (lp->pre_device != di))) {
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: final check failed\n");
#endif
@@ -1786,16 +2067,15 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: match2\n");
#endif
- n = p->local.phone[0];
- if (p->local.flags & ISDN_NET_SECURE) {
+ n = lp->phone[0];
+ if (lp->flags & ISDN_NET_SECURE) {
while (n) {
if (isdn_net_wildmat(nr, n->num))
break;
n = (isdn_net_phone *) n->next;
}
}
- if (n || (!(p->local.flags & ISDN_NET_SECURE))) {
- isdn_net_local *lp = &(p->local);
+ if (n || (!(lp->flags & ISDN_NET_SECURE))) {
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: match3\n");
#endif
@@ -1804,7 +2084,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
*/
if (!p->dev.start) {
restore_flags(flags);
- printk(KERN_INFO "%s: incoming call, if down -> rejected\n",
+ printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
lp->name);
return 3;
}
@@ -1872,12 +2152,12 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
eaz);
/* if this interface is dialing, it does it probably on a different
device, so free this device */
- if ((p->local.dialstate == 4) || (p->local.dialstate == 12)) {
+ if ((lp->dialstate == 4) || (lp->dialstate == 12)) {
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
isdn_ppp_free(lp);
#endif
- isdn_free_channel(p->local.isdn_device, p->local.isdn_channel,
+ isdn_free_channel(lp->isdn_device, lp->isdn_channel,
ISDN_USAGE_NET);
}
dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
@@ -1885,16 +2165,16 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
strcpy(dev->num[idx], nr);
isdn_info_update();
dev->st_netdev[idx] = lp->netdev;
- p->local.isdn_device = di;
- p->local.isdn_channel = ch;
- p->local.ppp_slot = -1;
- p->local.flags |= ISDN_NET_CONNECTED;
- p->local.dialstate = 7;
- p->local.dtimer = 0;
- p->local.outgoing = 0;
- p->local.huptimer = 0;
- p->local.hupflags |= ISDN_WAITCHARGE;
- p->local.hupflags &= ~ISDN_HAVECHARGE;
+ lp->isdn_device = di;
+ lp->isdn_channel = ch;
+ lp->ppp_slot = -1;
+ lp->flags |= ISDN_NET_CONNECTED;
+ lp->dialstate = 7;
+ lp->dtimer = 0;
+ lp->outgoing = 0;
+ lp->huptimer = 0;
+ lp->hupflags |= ISDN_WAITCHARGE;
+ lp->hupflags &= ~ISDN_HAVECHARGE;
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
if (isdn_ppp_bind(lp) < 0) {
@@ -1926,7 +2206,7 @@ isdn_net_findif(char *name)
isdn_net_dev *p = dev->netdev;
while (p) {
- if (!strcmp(p->local.name, name))
+ if (!strcmp(p->local->name, name))
return p;
p = (isdn_net_dev *) p->next;
}
@@ -1989,7 +2269,7 @@ isdn_net_force_dial(char *name)
if (!p)
return -ENODEV;
- return (isdn_net_force_dial_lp(&p->local));
+ return (isdn_net_force_dial_lp(p->local));
}
/*
@@ -2010,20 +2290,25 @@ isdn_net_new(char *name, struct device *master)
return NULL;
}
memset(netdev, 0, sizeof(isdn_net_dev));
+ if (!(netdev->local = (isdn_net_local *) kmalloc(sizeof(isdn_net_local), GFP_KERNEL))) {
+ printk(KERN_WARNING "isdn_net: Could not allocate device locals\n");
+ return NULL;
+ }
+ memset(netdev->local, 0, sizeof(isdn_net_local));
if (name == NULL)
- strcpy(netdev->local.name, " ");
+ strcpy(netdev->local->name, " ");
else
- strcpy(netdev->local.name, name);
- netdev->dev.name = netdev->local.name;
- netdev->dev.priv = &netdev->local;
+ strcpy(netdev->local->name, name);
+ netdev->dev.name = netdev->local->name;
+ netdev->dev.priv = netdev->local;
netdev->dev.init = isdn_net_init;
- netdev->local.p_encap = ISDN_NET_ENCAP_RAWIP;
+ netdev->local->p_encap = ISDN_NET_ENCAP_RAWIP;
if (master) {
/* Device shall be a slave */
struct device *p = (((isdn_net_local *) master->priv)->slave);
struct device *q = master;
- netdev->local.master = master;
+ netdev->local->master = master;
/* Put device at end of slave-chain */
while (p) {
q = p;
@@ -2037,41 +2322,43 @@ isdn_net_new(char *name, struct device *master)
/* Device shall be a master */
if (register_netdev(&netdev->dev) != 0) {
printk(KERN_WARNING "isdn_net: Could not register net-device\n");
+ kfree(netdev->local);
kfree(netdev);
return NULL;
}
}
- netdev->local.magic = ISDN_NET_MAGIC;
+ netdev->local->magic = ISDN_NET_MAGIC;
#ifdef CONFIG_ISDN_PPP
netdev->mp_last = NULL; /* mpqueue is empty */
netdev->ib.next_num = 0;
netdev->ib.last = NULL;
#endif
- netdev->queue = &netdev->local;
- netdev->local.last = &netdev->local;
- netdev->local.netdev = netdev;
- netdev->local.next = &netdev->local;
-
- netdev->local.isdn_device = -1;
- netdev->local.isdn_channel = -1;
- netdev->local.pre_device = -1;
- netdev->local.pre_channel = -1;
- netdev->local.exclusive = -1;
- netdev->local.ppp_slot = -1;
- netdev->local.pppbind = -1;
- netdev->local.sav_skb = NULL;
- netdev->local.first_skb = NULL;
- netdev->local.l2_proto = ISDN_PROTO_L2_X75I;
- netdev->local.l3_proto = ISDN_PROTO_L3_TRANS;
- netdev->local.slavedelay = 10 * HZ;
- netdev->local.srobin = &netdev->dev;
- netdev->local.hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
- netdev->local.onhtime = 10; /* Default hangup-time for saving costs
+ netdev->queue = netdev->local;
+ netdev->local->last = netdev->local;
+ netdev->local->netdev = netdev;
+ netdev->local->next = netdev->local;
+
+ netdev->local->isdn_device = -1;
+ netdev->local->isdn_channel = -1;
+ netdev->local->pre_device = -1;
+ netdev->local->pre_channel = -1;
+ netdev->local->exclusive = -1;
+ netdev->local->ppp_slot = -1;
+ netdev->local->pppbind = -1;
+ netdev->local->sav_skb = NULL;
+ netdev->local->first_skb = NULL;
+ netdev->local->l2_proto = ISDN_PROTO_L2_X75I;
+ netdev->local->l3_proto = ISDN_PROTO_L3_TRANS;
+ netdev->local->triggercps = 6000;
+ netdev->local->slavedelay = 10 * HZ;
+ netdev->local->srobin = &netdev->dev;
+ netdev->local->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
+ netdev->local->onhtime = 10; /* Default hangup-time for saving costs
of those who forget configuring this */
- netdev->local.dialmax = 1;
- netdev->local.flags = ISDN_NET_CBHUP; /* Hangup before Callback */
- netdev->local.cbdelay = 25; /* Wait 5 secs before Callback */
+ netdev->local->dialmax = 1;
+ netdev->local->flags = ISDN_NET_CBHUP; /* Hangup before Callback */
+ netdev->local->cbdelay = 25; /* Wait 5 secs before Callback */
/* Put into to netdev-chain */
netdev->next = (void *) dev->netdev;
dev->netdev = netdev;
@@ -2095,7 +2382,7 @@ isdn_net_newslave(char *parm)
if (!(n = isdn_net_findif(parm)))
return NULL;
/* Master must be a real interface, not a slave */
- if (n->local.master)
+ if (n->local->master)
return NULL;
/* Master must not be started yet */
if (n->dev.start)
@@ -2120,10 +2407,15 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
int drvidx;
int chidx;
char drvid[25];
-
+#ifdef CONFIG_ISDN_X25
+ ulong flags;
+#endif
if (p) {
+ isdn_net_local *lp = p->local;
+
/* See if any registered driver supports the features we want */
- features = (1 << cfg->l2_proto) | (256 << cfg->l3_proto);
+ features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
+ ((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT);
for (i = 0; i < ISDN_MAX_DRIVERS; i++)
if (dev->drv[i])
if ((dev->drv[i]->interface->features & features) == features)
@@ -2132,22 +2424,68 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
printk(KERN_WARNING "isdn_net: No driver with selected features\n");
return -ENODEV;
}
- if (p->local.p_encap != cfg->p_encap)
+ if (lp->p_encap != cfg->p_encap){
+#ifdef CONFIG_ISDN_X25
+ struct concap_proto * cprot = p -> cprot;
+#endif
if (p->dev.start) {
printk(KERN_WARNING
"%s: cannot change encap when if is up\n",
- p->local.name);
+ lp->name);
return -EBUSY;
}
- if (cfg->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
+#ifdef CONFIG_ISDN_X25
+ /* delete old encapsulation protocol if present ... */
+ save_flags(flags);
+ cli(); /* avoid races with incoming events trying to
+ call cprot->pops methods */
+ if( cprot && cprot -> pops )
+ cprot -> pops -> proto_del ( cprot );
+ p -> cprot = NULL;
+ lp -> dops = NULL;
+ restore_flags(flags);
+ /* ... , prepare for configuration of new one ... */
+ switch ( cfg -> p_encap ){
+ case ISDN_NET_ENCAP_X25IFACE:
+ lp -> dops = &isdn_concap_reliable_dl_dops;
+ }
+ /* ... and allocate new one ... */
+ p -> cprot = isdn_concap_new( cfg -> p_encap );
+ /* p -> cprot == NULL now if p_encap is not supported
+ by means of the concap_proto mechanism */
+ /* the protocol is not configured yet; this will
+ happen later when isdn_net_reset() is called */
+#endif
+ }
+ switch ( cfg->p_encap ) {
+ case ISDN_NET_ENCAP_SYNCPPP:
#ifndef CONFIG_ISDN_PPP
printk(KERN_WARNING "%s: SyncPPP support not configured\n",
- p->local.name);
+ lp->name);
return -EINVAL;
#else
p->dev.type = ARPHRD_PPP; /* change ARP type */
p->dev.addr_len = 0;
#endif
+ break;
+ case ISDN_NET_ENCAP_X25IFACE:
+#ifndef CONFIG_ISDN_X25
+ printk(KERN_WARNING "%s: isdn-x25 support not configured\n",
+ p->local->name);
+ return -EINVAL;
+#else
+ p->dev.type = ARPHRD_X25; /* change ARP type */
+ p->dev.addr_len = 0;
+#endif
+ break;
+ default:
+ if( cfg->p_encap >= 0 &&
+ cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP )
+ break;
+ printk(KERN_WARNING
+ "%s: encapsulation protocol %d not supported\n",
+ p->local->name, cfg->p_encap);
+ return -EINVAL;
}
if (strlen(cfg->drvid)) {
/* A bind has been requested ... */
@@ -2175,20 +2513,20 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
return -ENODEV;
} else {
/* Parameters are valid, so get them */
- drvidx = p->local.pre_device;
- chidx = p->local.pre_channel;
+ drvidx = lp->pre_device;
+ chidx = lp->pre_channel;
}
if (cfg->exclusive > 0) {
int flags;
/* If binding is exclusive, try to grab the channel */
save_flags(flags);
- if ((i = isdn_get_free_channel(ISDN_USAGE_NET, p->local.l2_proto,
- p->local.l3_proto,
+ if ((i = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto,
+ lp->l3_proto,
drvidx,
chidx)) < 0) {
/* Grab failed, because desired channel is in use */
- p->local.exclusive = -1;
+ lp->exclusive = -1;
restore_flags(flags);
return -EBUSY;
}
@@ -2196,93 +2534,82 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
dev->usage[i] = ISDN_USAGE_EXCLUSIVE;
isdn_info_update();
restore_flags(flags);
- p->local.exclusive = i;
+ lp->exclusive = i;
} else {
/* Non-exclusive binding or unbind. */
- p->local.exclusive = -1;
- if ((p->local.pre_device != -1) && (cfg->exclusive == -1)) {
- isdn_unexclusive_channel(p->local.pre_device, p->local.pre_channel);
- isdn_free_channel(p->local.pre_device, p->local.pre_channel, ISDN_USAGE_NET);
+ lp->exclusive = -1;
+ if ((lp->pre_device != -1) && (cfg->exclusive == -1)) {
+ isdn_unexclusive_channel(lp->pre_device, lp->pre_channel);
+ isdn_free_channel(lp->pre_device, lp->pre_channel, ISDN_USAGE_NET);
drvidx = -1;
chidx = -1;
}
}
- strcpy(p->local.msn, cfg->eaz);
- p->local.pre_device = drvidx;
- p->local.pre_channel = chidx;
- p->local.onhtime = cfg->onhtime;
- p->local.charge = cfg->charge;
- p->local.l2_proto = cfg->l2_proto;
- p->local.l3_proto = cfg->l3_proto;
- p->local.cbdelay = cfg->cbdelay;
- p->local.dialmax = cfg->dialmax;
- p->local.slavedelay = cfg->slavedelay * HZ;
- p->local.pppbind = cfg->pppbind;
+ strcpy(lp->msn, cfg->eaz);
+ lp->pre_device = drvidx;
+ lp->pre_channel = chidx;
+ lp->onhtime = cfg->onhtime;
+ lp->charge = cfg->charge;
+ lp->l2_proto = cfg->l2_proto;
+ lp->l3_proto = cfg->l3_proto;
+ lp->cbdelay = cfg->cbdelay;
+ lp->dialmax = cfg->dialmax;
+ lp->triggercps = cfg->triggercps;
+ lp->slavedelay = cfg->slavedelay * HZ;
+ lp->pppbind = cfg->pppbind;
if (cfg->secure)
- p->local.flags |= ISDN_NET_SECURE;
+ lp->flags |= ISDN_NET_SECURE;
else
- p->local.flags &= ~ISDN_NET_SECURE;
+ lp->flags &= ~ISDN_NET_SECURE;
if (cfg->cbhup)
- p->local.flags |= ISDN_NET_CBHUP;
+ lp->flags |= ISDN_NET_CBHUP;
else
- p->local.flags &= ~ISDN_NET_CBHUP;
+ lp->flags &= ~ISDN_NET_CBHUP;
switch (cfg->callback) {
case 0:
- p->local.flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
+ lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
break;
case 1:
- p->local.flags |= ISDN_NET_CALLBACK;
- p->local.flags &= ~ISDN_NET_CBOUT;
+ lp->flags |= ISDN_NET_CALLBACK;
+ lp->flags &= ~ISDN_NET_CBOUT;
break;
case 2:
- p->local.flags |= ISDN_NET_CBOUT;
- p->local.flags &= ~ISDN_NET_CALLBACK;
+ lp->flags |= ISDN_NET_CBOUT;
+ lp->flags &= ~ISDN_NET_CALLBACK;
break;
}
if (cfg->chargehup)
- p->local.hupflags |= ISDN_CHARGEHUP;
+ lp->hupflags |= ISDN_CHARGEHUP;
else
- p->local.hupflags &= ~ISDN_CHARGEHUP;
+ lp->hupflags &= ~ISDN_CHARGEHUP;
if (cfg->ihup)
- p->local.hupflags |= ISDN_INHUP;
+ lp->hupflags |= ISDN_INHUP;
else
- p->local.hupflags &= ~ISDN_INHUP;
+ lp->hupflags &= ~ISDN_INHUP;
if (cfg->chargeint > 10) {
- p->local.hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE;
- p->local.chargeint = cfg->chargeint * HZ;
+ lp->hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE;
+ lp->chargeint = cfg->chargeint * HZ;
}
- if (cfg->p_encap != p->local.p_encap) {
+ if (cfg->p_encap != lp->p_encap) {
if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
p->dev.hard_header = NULL;
-#if (LINUX_VERSION_CODE < 0x02010F)
- p->dev.header_cache_bind = NULL;
-#else
p->dev.hard_header_cache = NULL;
-#endif
p->dev.header_cache_update = NULL;
p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
} else {
p->dev.hard_header = isdn_net_header;
if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
-#if (LINUX_VERSION_CODE < 0x02010F)
- p->dev.header_cache_bind = p->local.org_hcb;
-#else
- p->dev.hard_header_cache = p->local.org_hhc;
-#endif
- p->dev.header_cache_update = p->local.org_hcu;
+ p->dev.hard_header_cache = lp->org_hhc;
+ p->dev.header_cache_update = lp->org_hcu;
p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
} else {
-#if (LINUX_VERSION_CODE < 0x02010F)
- p->dev.header_cache_bind = NULL;
-#else
p->dev.hard_header_cache = NULL;
-#endif
p->dev.header_cache_update = NULL;
p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
}
}
}
- p->local.p_encap = cfg->p_encap;
+ lp->p_encap = cfg->p_encap;
return 0;
}
return -ENODEV;
@@ -2297,39 +2624,42 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
isdn_net_dev *p = isdn_net_findif(cfg->name);
if (p) {
- strcpy(cfg->eaz, p->local.msn);
- cfg->exclusive = p->local.exclusive;
- if (p->local.pre_device >= 0) {
- sprintf(cfg->drvid, "%s,%d", dev->drvid[p->local.pre_device],
- p->local.pre_channel);
+ isdn_net_local *lp = p->local;
+
+ strcpy(cfg->eaz, lp->msn);
+ cfg->exclusive = lp->exclusive;
+ if (lp->pre_device >= 0) {
+ sprintf(cfg->drvid, "%s,%d", dev->drvid[lp->pre_device],
+ lp->pre_channel);
} else
cfg->drvid[0] = '\0';
- cfg->onhtime = p->local.onhtime;
- cfg->charge = p->local.charge;
- cfg->l2_proto = p->local.l2_proto;
- cfg->l3_proto = p->local.l3_proto;
- cfg->p_encap = p->local.p_encap;
- cfg->secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0;
+ cfg->onhtime = lp->onhtime;
+ cfg->charge = lp->charge;
+ cfg->l2_proto = lp->l2_proto;
+ cfg->l3_proto = lp->l3_proto;
+ cfg->p_encap = lp->p_encap;
+ cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
cfg->callback = 0;
- if (p->local.flags & ISDN_NET_CALLBACK)
+ if (lp->flags & ISDN_NET_CALLBACK)
cfg->callback = 1;
- if (p->local.flags & ISDN_NET_CBOUT)
+ if (lp->flags & ISDN_NET_CBOUT)
cfg->callback = 2;
- cfg->cbhup = (p->local.flags & ISDN_NET_CBHUP) ? 1 : 0;
- cfg->chargehup = (p->local.hupflags & 4) ? 1 : 0;
- cfg->ihup = (p->local.hupflags & 8) ? 1 : 0;
- cfg->cbdelay = p->local.cbdelay;
- cfg->dialmax = p->local.dialmax;
- cfg->slavedelay = p->local.slavedelay / HZ;
- cfg->chargeint = (p->local.hupflags & ISDN_CHARGEHUP) ?
- (p->local.chargeint / HZ) : 0;
- cfg->pppbind = p->local.pppbind;
- if (p->local.slave)
- strcpy(cfg->slave, ((isdn_net_local *) p->local.slave->priv)->name);
+ cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0;
+ cfg->chargehup = (lp->hupflags & 4) ? 1 : 0;
+ cfg->ihup = (lp->hupflags & 8) ? 1 : 0;
+ cfg->cbdelay = lp->cbdelay;
+ cfg->dialmax = lp->dialmax;
+ cfg->triggercps = lp->triggercps;
+ cfg->slavedelay = lp->slavedelay / HZ;
+ cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ?
+ (lp->chargeint / HZ) : 0;
+ cfg->pppbind = lp->pppbind;
+ if (lp->slave)
+ strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name);
else
cfg->slave[0] = '\0';
- if (p->local.master)
- strcpy(cfg->master, ((isdn_net_local *) p->local.master->priv)->name);
+ if (lp->master)
+ strcpy(cfg->master, ((isdn_net_local *) lp->master->priv)->name);
else
cfg->master[0] = '\0';
return 0;
@@ -2352,8 +2682,8 @@ isdn_net_addphone(isdn_net_ioctl_phone * phone)
if (!(n = (isdn_net_phone *) kmalloc(sizeof(isdn_net_phone), GFP_KERNEL)))
return -ENOMEM;
strcpy(n->num, phone->phone);
- n->next = p->local.phone[phone->outgoing & 1];
- p->local.phone[phone->outgoing & 1] = n;
+ n->next = p->local->phone[phone->outgoing & 1];
+ p->local->phone[phone->outgoing & 1] = n;
return 0;
}
return -ENODEV;
@@ -2378,7 +2708,7 @@ isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
save_flags(flags);
cli();
inout &= 1;
- for (n = p->local.phone[inout]; n; n = n->next) {
+ for (n = p->local->phone[inout]; n; n = n->next) {
if (more) {
put_user(' ', phones++);
count++;
@@ -2413,16 +2743,16 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone)
if (p) {
save_flags(flags);
cli();
- n = p->local.phone[inout];
+ n = p->local->phone[inout];
m = NULL;
while (n) {
if (!strcmp(n->num, phone->phone)) {
- if (p->local.dial == n)
- p->local.dial = n->next;
+ if (p->local->dial == n)
+ p->local->dial = n->next;
if (m)
m->next = n->next;
else
- p->local.phone[inout] = n->next;
+ p->local->phone[inout] = n->next;
kfree(n);
return 0;
}
@@ -2449,15 +2779,15 @@ isdn_net_rmallphone(isdn_net_dev * p)
save_flags(flags);
cli();
for (i = 0; i < 2; i++) {
- n = p->local.phone[i];
+ n = p->local->phone[i];
while (n) {
m = n->next;
kfree(n);
n = m;
}
- p->local.phone[i] = NULL;
+ p->local->phone[i] = NULL;
}
- p->local.dial = NULL;
+ p->local->dial = NULL;
restore_flags(flags);
return 0;
}
@@ -2472,9 +2802,9 @@ isdn_net_force_hangup(char *name)
struct device *q;
if (p) {
- if (p->local.isdn_device < 0)
+ if (p->local->isdn_device < 0)
return 1;
- q = p->local.slave;
+ q = p->local->slave;
/* If this interface has slaves, do a hangup for them also. */
while (q) {
isdn_net_hangup(q);
@@ -2496,7 +2826,7 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
save_flags(flags);
cli();
- if (p->local.master) {
+ if (p->local->master) {
/* If it's a slave, it may be removed even if it is busy. However
* it has to be hung up first.
*/
@@ -2507,30 +2837,37 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
restore_flags(flags);
return -EBUSY;
}
+#ifdef CONFIG_ISDN_X25
+ if( p -> cprot && p -> cprot -> pops )
+ p -> cprot -> pops -> proto_del ( p -> cprot );
+#endif
/* Free all phone-entries */
isdn_net_rmallphone(p);
/* If interface is bound exclusive, free channel-usage */
- if (p->local.exclusive != -1)
- isdn_unexclusive_channel(p->local.pre_device, p->local.pre_channel);
- if (p->local.master) {
+ if (p->local->exclusive != -1)
+ isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel);
+ if (p->local->master) {
/* It's a slave-device, so update master's slave-pointer if necessary */
- if (((isdn_net_local *) (p->local.master->priv))->slave == &p->dev)
- ((isdn_net_local *) (p->local.master->priv))->slave = p->local.slave;
- } else
+ if (((isdn_net_local *) (p->local->master->priv))->slave == &p->dev)
+ ((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave;
+ } else {
/* Unregister only if it's a master-device */
+ p->dev.hard_header_cache = p->local->org_hhc;
+ p->dev.header_cache_update = p->local->org_hcu;
unregister_netdev(&p->dev);
+ }
/* Unlink device from chain */
if (q)
q->next = p->next;
else
dev->netdev = p->next;
- if (p->local.slave) {
+ if (p->local->slave) {
/* If this interface has a slave, remove it also */
- char *slavename = ((isdn_net_local *) (p->local.slave->priv))->name;
+ char *slavename = ((isdn_net_local *) (p->local->slave->priv))->name;
isdn_net_dev *n = dev->netdev;
q = NULL;
while (n) {
- if (!strcmp(n->local.name, slavename)) {
+ if (!strcmp(n->local->name, slavename)) {
isdn_net_realrm(n, q);
break;
}
@@ -2543,6 +2880,7 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
restore_flags(flags);
+ kfree(p->local);
kfree(p);
return 0;
@@ -2561,7 +2899,7 @@ isdn_net_rm(char *name)
p = dev->netdev;
q = NULL;
while (p) {
- if (!strcmp(p->local.name, name))
+ if (!strcmp(p->local->name, name))
return (isdn_net_realrm(p, q));
q = p;
p = (isdn_net_dev *) p->next;
@@ -2585,7 +2923,7 @@ isdn_net_rmall(void)
save_flags(flags);
cli();
while (dev->netdev) {
- if (!dev->netdev->local.master) {
+ if (!dev->netdev->local->master) {
/* Remove master-devices only, slaves get removed with their master */
if ((ret = isdn_net_realrm(dev->netdev, NULL))) {
restore_flags(flags);
diff --git a/drivers/isdn/isdn_net.h b/drivers/isdn/isdn_net.h
index 56df21081..19a084dd2 100644
--- a/drivers/isdn/isdn_net.h
+++ b/drivers/isdn/isdn_net.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.h,v 1.5 1997/02/10 20:12:47 fritz Exp $
+/* $Id: isdn_net.h,v 1.6 1997/10/09 21:28:54 fritz Exp $
* header for Linux ISDN subsystem, network related functions (linklevel).
*
@@ -21,6 +21,16 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.h,v $
+ * Revision 1.6 1997/10/09 21:28:54 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ * New L1 error status (not yet in use).
+ * Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
* Revision 1.5 1997/02/10 20:12:47 fritz
* Changed interface for reporting incoming calls.
*
@@ -45,11 +55,46 @@
#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */
#define ISDN_MANCHARGE 16 /* Charge Interval manually set */
+/*
+ * Definitions for Cisco-HDLC header.
+ */
+
+typedef struct cisco_hdr {
+ __u8 addr; /* unicast/broadcast */
+ __u8 ctrl; /* Always 0 */
+ __u16 type; /* IP-typefield */
+} cisco_hdr;
+
+typedef struct cisco_slarp {
+ __u32 code; /* SLREQ/SLREPLY/KEEPALIVE */
+ union {
+ struct {
+ __u32 ifaddr; /* My interface address */
+ __u32 netmask; /* My interface netmask */
+ } reply;
+ struct {
+ __u32 my_seq; /* Packet sequence number */
+ __u32 your_seq;
+ } keepalive;
+ } slarp;
+ __u16 rel; /* Always 0xffff */
+ __u16 t1; /* Uptime in usec >> 16 */
+ __u16 t0; /* Uptime in usec & 0xffff */
+} cisco_slarp;
+
+#define CISCO_ADDR_UNICAST 0x0f
+#define CISCO_ADDR_BROADCAST 0x8f
+#define CISCO_TYPE_INET 0x0800
+#define CISCO_TYPE_SLARP 0x8035
+#define CISCO_SLARP_REPLY 0
+#define CISCO_SLARP_REQUEST 1
+#define CISCO_SLARP_KEEPALIVE 2
+
extern char *isdn_net_new(char *, struct device *);
extern char *isdn_net_newslave(char *);
extern int isdn_net_rm(char *);
extern int isdn_net_rmall(void);
-extern int isdn_net_stat_callback(int, int);
+extern int isdn_net_stat_callback(int, isdn_ctrl *);
extern int isdn_net_setcfg(isdn_net_ioctl_cfg *);
extern int isdn_net_getcfg(isdn_net_ioctl_cfg *);
extern int isdn_net_addphone(isdn_net_ioctl_phone *);
@@ -65,3 +110,4 @@ extern isdn_net_dev *isdn_net_findif(char *);
extern int isdn_net_send_skb(struct device *, isdn_net_local *,
struct sk_buff *);
extern int isdn_net_rcv_skb(int, struct sk_buff *);
+extern void isdn_net_slarp_out(void);
diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c
index 0f29e340a..a4a45d9ea 100644
--- a/drivers/isdn/isdn_ppp.c
+++ b/drivers/isdn/isdn_ppp.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.27 1997/03/30 16:51:17 calle Exp $
+/* $Id: isdn_ppp.c,v 1.33 1998/02/20 17:11:54 fritz Exp $
*
* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
@@ -19,6 +19,37 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_ppp.c,v $
+ * Revision 1.33 1998/02/20 17:11:54 fritz
+ * Changes for recent kernels.
+ *
+ * Revision 1.32 1998/01/31 19:29:55 calle
+ * Merged changes from and for 2.1.82, not tested only compiled ...
+ *
+ * Revision 1.31 1997/10/09 21:29:01 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ * New L1 error status (not yet in use).
+ * Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.30 1997/10/01 09:20:38 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.29 1997/08/21 23:11:44 fritz
+ * Added changes for kernels >= 2.1.45
+ *
+ * Revision 1.28 1997/06/17 13:05:57 hipp
+ * Applied Eric's underflow-patches (slightly modified)
+ * more compression changes (but disabled at the moment)
+ * changed one copy_to_user() to run with enabled IRQs
+ * a few MP changes
+ * changed 'proto' handling in the isdn_ppp receive code
+ *
* Revision 1.27 1997/03/30 16:51:17 calle
* changed calls to copy_from_user/copy_to_user and removed verify_area
* were possible.
@@ -128,9 +159,7 @@
#include <linux/module.h>
#include <linux/version.h>
#include <linux/isdn.h>
-#if (LINUX_VERSION_CODE >= 0x020117)
#include <linux/poll.h>
-#endif
#include "isdn_common.h"
#include "isdn_ppp.h"
#include "isdn_net.h"
@@ -148,6 +177,12 @@ static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,
struct sk_buff *skb, int proto);
static int isdn_ppp_if_get_unit(char *namebuf);
static int isdn_ppp_set_compressor(struct ippp_struct *is,int num);
+static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
+ struct ippp_struct *,struct ippp_struct *);
+static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp,
+ struct sk_buff *skb);
+static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
+ struct ippp_struct *is,struct ippp_struct *master,int type);
#ifdef CONFIG_ISDN_MPP
static int isdn_ppp_bundle(struct ippp_struct *, int unit);
@@ -160,7 +195,7 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
static void isdn_ppp_free_mpqueue(isdn_net_dev *);
#endif
-char *isdn_ppp_revision = "$Revision: 1.27 $";
+char *isdn_ppp_revision = "$Revision: 1.33 $";
static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
static struct isdn_ppp_compressor *ipc_head = NULL;
@@ -267,7 +302,7 @@ isdn_ppp_bind(isdn_net_local * lp)
char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */
memset(exclusive, 0, ISDN_MAX_CHANNELS);
while (net_dev) { /* step through net devices to find exclusive minors */
- isdn_net_local *lp = &net_dev->local;
+ isdn_net_local *lp = net_dev->local;
if (lp->pppbind >= 0)
exclusive[lp->pppbind] = 1;
net_dev = net_dev->next;
@@ -382,7 +417,12 @@ isdn_ppp_open(int min, struct file *file)
if (is->debug & 0x1)
printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state);
+ /* compression stuff */
is->compressor = NULL;
+ is->decomp_stat = is->comp_stat = NULL;
+ is->link_compressor = NULL;
+ is->link_decomp_stat = is->link_comp_stat = NULL;
+
is->lp = NULL;
is->mp_seqno = 0; /* MP sequence number */
is->pppcfg = 0; /* ppp configuration */
@@ -644,50 +684,6 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
return 0;
}
-#if (LINUX_VERSION_CODE < 0x020117)
-int
-isdn_ppp_select(int min, struct file *file, int type, select_table * st)
-{
- struct ippp_buf_queue *bf,
- *bl;
- unsigned long flags;
- struct ippp_struct *is;
-
- is = file->private_data;
-
- if (is->debug & 0x2)
- printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n", min, type);
-
- if (!(is->state & IPPP_OPEN))
- return -EINVAL;
-
- switch (type) {
- case SEL_IN:
- save_flags(flags);
- cli();
- bl = is->last;
- bf = is->first;
- /*
- * if IPPP_NOBLOCK is set we return even if we have nothing to read
- */
- if (bf->next == bl && !(is->state & IPPP_NOBLOCK)) {
- select_wait(&is->wq, st);
- restore_flags(flags);
- return 0;
- }
- is->state &= ~IPPP_NOBLOCK;
- restore_flags(flags);
- return 1;
- case SEL_OUT:
- /* we're always ready to send .. */
- return 1;
- case SEL_EX:
- select_wait(&is->wq1, st);
- return 0;
- }
- return 1;
-}
-#else
unsigned int
isdn_ppp_poll(struct file *file, poll_table * wait)
{
@@ -700,7 +696,8 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
is = file->private_data;
if (is->debug & 0x2)
- printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", MINOR(file->f_dentry->d_inode->i_rdev));
+ printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
+ MINOR(file->f_dentry->d_inode->i_rdev));
poll_wait(file, &is->wq, wait);
@@ -725,8 +722,6 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
restore_flags(flags);
return mask;
}
-#endif
-
/*
* fill up isdn_ppp_read() queue ..
@@ -798,31 +793,35 @@ isdn_ppp_read(int min, struct file *file, char *buf, int count)
struct ippp_buf_queue *b;
int r;
unsigned long flags;
+ unsigned char *save_buf;
is = file->private_data;
if (!(is->state & IPPP_OPEN))
return 0;
+ if ((r = verify_area(VERIFY_WRITE, (void *) buf, count)))
+ return r;
+
save_flags(flags);
cli();
b = is->first->next;
- if (!b->buf) {
+ save_buf = b->buf;
+ if (!save_buf) {
restore_flags(flags);
return -EAGAIN;
}
if (b->len < count)
count = b->len;
- if ((r = copy_to_user(buf, b->buf, count))) {
- restore_flags(flags);
- return r;
- }
- kfree(b->buf);
b->buf = NULL;
is->first = b;
+
restore_flags(flags);
+ copy_to_user(buf, save_buf, count);
+ kfree(save_buf);
+
return count;
}
@@ -872,14 +871,13 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
return count;
}
- SET_SKB_FREE(skb);
if (copy_from_user(skb_put(skb, count), buf, count))
return -EFAULT;
if (is->debug & 0x40) {
printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
isdn_ppp_frame_log("xmit", skb->data, skb->len, 32);
}
- if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb)) != count) {
+ if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb)) != count) {
if (lp->sav_skb) {
dev_kfree_skb(lp->sav_skb);
printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", cnt, count);
@@ -935,45 +933,65 @@ isdn_ppp_cleanup(void)
}
/*
+ * get the PPP protocol header and pull skb
+ */
+static int isdn_ppp_strip_proto(struct sk_buff *skb)
+{
+ int proto;
+ if (skb->data[0] & 0x1) {
+ proto = skb->data[0];
+ skb_pull(skb, 1); /* protocol ID is only 8 bit */
+ } else {
+ proto = ((int) skb->data[0] << 8) + skb->data[1];
+ skb_pull(skb, 2);
+ }
+ return proto;
+}
+
+
+/*
* handler for incoming packets on a syncPPP interface
*/
-void
-isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb)
+void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb)
{
struct ippp_struct *is;
+ int proto;
+
is = ippp_table[lp->ppp_slot];
if (is->debug & 0x4) {
printk(KERN_DEBUG "ippp_receive: len: %d\n", (int) skb->len);
isdn_ppp_frame_log("receive", skb->data, skb->len, 32);
}
- if (net_dev->local.master) {
+ if (net_dev->local->master) {
printk(KERN_WARNING "isdn_ppp_receice: net_dev != master\n");
- net_dev = ((isdn_net_local *) net_dev->local.master->priv)->netdev;
+ net_dev = ((isdn_net_local *) net_dev->local->master->priv)->netdev;
}
if (skb->data[0] == 0xff && skb->data[1] == 0x03)
skb_pull(skb, 2);
else if (is->pppcfg & SC_REJ_COMP_AC) {
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
return; /* discard it silently */
}
+
+ proto = isdn_ppp_strip_proto(skb);
+
#ifdef CONFIG_ISDN_MPP
if (!(is->mpppcfg & SC_REJ_MP_PROT)) {
- int proto;
int sqno_end;
- if (skb->data[0] & 0x1) {
- proto = skb->data[0];
- skb_pull(skb, 1); /* protocol ID is only 8 bit */
- } else {
- proto = ((int) skb->data[0] << 8) + skb->data[1];
- skb_pull(skb, 2);
+
+ if(proto == PPP_LINK_COMP) {
+ printk(KERN_DEBUG "received single link compressed frame\n");
+ skb = isdn_ppp_decompress(skb,is,NULL);
+ if(!skb)
+ return;
+ proto = isdn_ppp_strip_proto(skb);
}
+
if (proto == PPP_MP) {
isdn_net_local *lpq;
- long sqno,
- min_sqno,
- tseq;
+ long sqno, min_sqno, tseq;
+
u_char BEbyte = skb->data[0];
if (is->debug & 0x8)
printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_slot, proto,
@@ -987,6 +1005,10 @@ isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *sk
skb_pull(skb, 2);
}
+ /*
+ * new sequence number lower than last number? (this is only allowed
+ * for overflow case)
+ */
if ((tseq = is->last_link_seqno) >= sqno) {
int range = is->range;
if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */
@@ -995,9 +1017,14 @@ isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *sk
sqno += range;
is->last_link_seqno = sqno;
}
- } else
+ } else {
+ /* here, we should also add an redundancy check */
is->last_link_seqno = sqno;
+ }
+ /*
+ * step over all links to find lowest link number
+ */
for (min_sqno = LONG_MAX, lpq = net_dev->queue;;) {
long lls = ippp_table[lpq->ppp_slot]->last_link_seqno;
if (lls >= 0 && lls < min_sqno)
@@ -1006,11 +1033,14 @@ isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *sk
if (lpq == net_dev->queue)
break;
}
- if (min_sqno >= ippp_table[lpq->ppp_slot]->range) { /* OK, every link overflowed */
- int mask = ippp_table[lpq->ppp_slot]->range - 1; /* range is a power of 2 */
-#if 0
- isdn_ppp_cleanup_queue(net_dev, min_sqno);
-#endif
+
+ /*
+ * for the case, that the last frame numbers of all
+ * links are overflowed: mask/reduce the sequenece number to
+ * 'normal' numbering.
+ */
+ if (min_sqno >= ippp_table[lpq->ppp_slot]->range) {
+ int mask = ippp_table[lpq->ppp_slot]->range-1; /* range is power of two, so a mask will do the job */
isdn_ppp_mask_queue(net_dev, mask);
net_dev->ib.next_num &= mask;
{
@@ -1064,7 +1094,6 @@ isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *sk
if (!q) {
net_dev->ib.modify = 0;
printk(KERN_WARNING "ippp/MPPP: Bad! Can't alloc sq node!\n");
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
return; /* discard */
}
@@ -1093,7 +1122,8 @@ isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *sk
* packet was 'in order' .. push it higher
*/
net_dev->ib.next_num = sqno_end + 1;
- isdn_ppp_push_higher(net_dev, lp, skb, -1);
+ proto = isdn_ppp_strip_proto(skb);
+ isdn_ppp_push_higher(net_dev, lp, skb, proto);
}
isdn_ppp_cleanup_sqqueue(net_dev, lp, min_sqno);
net_dev->ib.modify = 0;
@@ -1102,7 +1132,7 @@ isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *sk
isdn_ppp_push_higher(net_dev, lp, skb, proto);
} else
#endif
- isdn_ppp_push_higher(net_dev, lp, skb, -1);
+ isdn_ppp_push_higher(net_dev, lp, skb, proto);
}
/*
@@ -1115,19 +1145,21 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
struct device *dev = &net_dev->dev;
struct ippp_struct *is = ippp_table[lp->ppp_slot];
- if (proto < 0) { /* MP, oder normales Paket bei REJ_MP, MP Pakete gehen bei REJ zum pppd */
- if (skb->data[0] & 0x01) { /* is it odd? */
- proto = (unsigned char) skb->data[0];
- skb_pull(skb, 1); /* protocol ID is only 8 bit */
- } else {
- proto = ((int) (unsigned char) skb->data[0] << 8) + (unsigned char) skb->data[1];
- skb_pull(skb, 2);
- }
- }
if (is->debug & 0x10) {
printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
isdn_ppp_frame_log("rpush", skb->data, skb->len, 32);
}
+
+ if(proto == PPP_COMP) {
+ if(!lp->master)
+ skb = isdn_ppp_decompress(skb,is,is);
+ else
+ skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot]);
+ if(!skb)
+ return;
+ proto = isdn_ppp_strip_proto(skb);
+ }
+
switch (proto) {
case PPP_IPX: /* untested */
if (is->debug & 0x20)
@@ -1140,10 +1172,9 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
case PPP_VJC_UNCOMP:
if (is->debug & 0x20)
printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
- if (slhc_remember(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
+ if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
- net_dev->local.stats.rx_dropped++;
- SET_SKB_FREE(skb);
+ net_dev->local->stats.rx_dropped++;
dev_kfree_skb(skb);
return;
}
@@ -1164,11 +1195,9 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
int pkt_len;
skb = dev_alloc_skb(skb_old->len + 40);
- SET_SKB_FREE(skb_old);
-
if (!skb) {
printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
- net_dev->local.stats.rx_dropped++;
+ net_dev->local->stats.rx_dropped++;
dev_kfree_skb(skb_old);
return;
}
@@ -1176,11 +1205,10 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
skb_put(skb, skb_old->len + 40);
memcpy(skb->data, skb_old->data, skb_old->len);
skb->mac.raw = skb->data;
- pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp,
+ pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
skb->data, skb_old->len);
dev_kfree_skb(skb_old);
if (pkt_len < 0) {
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
lp->stats.rx_dropped++;
return;
@@ -1191,20 +1219,21 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
#else
printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n");
lp->stats.rx_dropped++;
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
return;
#endif
break;
+ case PPP_CCP:
+ isdn_ppp_receive_ccp(net_dev,lp,skb);
+ /* fall through */
default:
isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
return;
}
netif_rx(skb);
- /* net_dev->local.stats.rx_packets++; *//* done in isdn_net.c */
+ /* net_dev->local->stats.rx_packets++; *//* done in isdn_net.c */
/* Reset hangup-timer */
lp->huptimer = 0;
@@ -1212,6 +1241,24 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
}
/*
+ * isdn_ppp_skb_push ..
+ * checks whether we have enough space at the beginning of the SKB
+ * and allocs a new SKB if necessary
+ */
+static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
+{
+ struct sk_buff *skb = *skb_p;
+
+ if(skb_headroom(skb) < len) {
+ printk(KERN_ERR "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len);
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+ return skb_push(skb,len);
+}
+
+
+/*
* send ppp frame .. we expect a PIDCOMPressable proto --
* (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
*
@@ -1223,12 +1270,10 @@ int
isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
{
struct device *mdev = ((isdn_net_local *) (dev->priv))->master; /* get master (for redundancy) */
- isdn_net_local *lp,
- *mlp;
+ isdn_net_local *lp,*mlp;
isdn_net_dev *nd;
unsigned int proto = PPP_IP; /* 0x21 */
- struct ippp_struct *ipt,
- *ipts;
+ struct ippp_struct *ipt,*ipts;
if (mdev)
mlp = (isdn_net_local *) (mdev->priv);
@@ -1250,6 +1295,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
printk(KERN_INFO "%s: IP frame delayed.\n", dev->name);
return 1;
}
+
switch (ntohs(skb->protocol)) {
case ETH_P_IP:
proto = PPP_IP;
@@ -1297,11 +1343,18 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
* after this line .. requeueing in the device queue is no longer allowed!!!
*/
+ /* Pull off the fake header we stuck on earlier to keep
+ * the fragemntation code happy.
+ * this will break the ISDN_SYNCPPP_READDRESS hack a few lines
+ * above. So, enabling this is no longer allowed
+ */
+ skb_pull(skb,IPPP_MAX_HEADER);
+
if (ipt->debug & 0x4)
printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
#ifdef CONFIG_ISDN_PPP_VJ
- if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes .. but this check again */
+ if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */
struct sk_buff *new_skb;
new_skb = dev_alloc_skb(skb->len);
@@ -1310,14 +1363,13 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
int pktlen;
new_skb->dev = skb->dev;
- SET_SKB_FREE(new_skb);
skb_put(new_skb, skb->len);
buf = skb->data;
pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
&buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
- if (buf != skb->data) { /* copied to new buffer ??? (btw: WHY must slhc copy it?? *sigh*) */
+ if (buf != skb->data) {
if (new_skb->data != buf)
printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
dev_kfree_skb(skb);
@@ -1339,6 +1391,11 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
}
#endif
+ /*
+ * normal or bundle compression
+ */
+ skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0);
+
if (ipt->debug & 0x24)
printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
@@ -1349,13 +1406,17 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
ipts->mp_seqno++;
nd->queue = nd->queue->next;
if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
- unsigned char *data = skb_push(skb, 3);
+ unsigned char *data = isdn_ppp_skb_push(&skb, 3);
+ if(!data)
+ return 0;
mp_seqno &= 0xfff;
- data[0] = MP_BEGIN_FRAG | MP_END_FRAG | (mp_seqno >> 8); /* (B)egin & (E)ndbit .. */
+ data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
data[1] = mp_seqno & 0xff;
data[2] = proto; /* PID compression */
} else {
- unsigned char *data = skb_push(skb, 5);
+ unsigned char *data = isdn_ppp_skb_push(&skb, 5);
+ if(!data)
+ return 0;
data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
data[2] = (mp_seqno >> 8) & 0xff;
@@ -1365,17 +1426,29 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
proto = PPP_MP; /* MP Protocol, 0x003d */
}
#endif
+
+ /*
+ * 'link' compression
+ */
+ skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1);
+
if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) {
- unsigned char *data = skb_push(skb,1);
+ unsigned char *data = isdn_ppp_skb_push(&skb,1);
+ if(!data)
+ return 0;
data[0] = proto & 0xff;
}
else {
- unsigned char *data = skb_push(skb,2);
+ unsigned char *data = isdn_ppp_skb_push(&skb,2);
+ if(!data)
+ return 0;
data[0] = (proto >> 8) & 0xff;
data[1] = proto & 0xff;
}
if(!(ipt->pppcfg & SC_COMP_AC)) {
- unsigned char *data = skb_push(skb,2);
+ unsigned char *data = isdn_ppp_skb_push(&skb,2);
+ if(!data)
+ return 0;
data[0] = 0xff; /* All Stations */
data[1] = 0x03; /* Unnumbered information */
}
@@ -1406,10 +1479,8 @@ isdn_ppp_free_sqqueue(isdn_net_dev * p)
p->ib.sq = NULL;
while (q) {
struct sqqueue *qn = q->next;
- if (q->skb) {
- SET_SKB_FREE(q->skb);
+ if (q->skb)
dev_kfree_skb(q->skb);
- }
kfree(q);
q = qn;
}
@@ -1424,7 +1495,6 @@ isdn_ppp_free_mpqueue(isdn_net_dev * p)
while (q) {
struct mpqueue *ql = q->next;
- SET_SKB_FREE(q->skb);
dev_kfree_skb(q->skb);
kfree(q);
q = ql;
@@ -1599,7 +1669,6 @@ isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff **skb, int BEbyte, long
if (!(*skb)) {
while (q) {
struct mpqueue *ql = q->next;
- SET_SKB_FREE(q->skb);
dev_kfree_skb(q->skb);
kfree(q);
q = ql;
@@ -1612,7 +1681,6 @@ isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff **skb, int BEbyte, long
struct mpqueue *ql = q->next;
memcpy((*skb)->data + cnt, q->skb->data, q->skb->len);
cnt += q->skb->len;
- SET_SKB_FREE(q->skb);
dev_kfree_skb(q->skb);
kfree(q);
q = ql;
@@ -1632,13 +1700,15 @@ isdn_ppp_cleanup_sqqueue(isdn_net_dev * net_dev, isdn_net_local * lp, long min_s
struct sqqueue *q;
while ((q = net_dev->ib.sq) && (q->sqno_start == net_dev->ib.next_num || q->sqno_end <= min_sqno)) {
+ int proto;
if (q->sqno_start != net_dev->ib.next_num) {
printk(KERN_DEBUG "ippp: MP, stepping over missing frame: %ld\n", net_dev->ib.next_num);
#ifdef CONFIG_ISDN_PPP_VJ
- slhc_toss(ippp_table[net_dev->local.ppp_slot]->slcomp);
+ slhc_toss(ippp_table[net_dev->local->ppp_slot]->slcomp);
#endif
}
- isdn_ppp_push_higher(net_dev, lp, q->skb, -1);
+ proto = isdn_ppp_strip_proto(q->skb);
+ isdn_ppp_push_higher(net_dev, lp, q->skb, proto);
net_dev->ib.sq = q->next;
net_dev->ib.next_num = q->sqno_end + 1;
kfree(q);
@@ -1663,32 +1733,30 @@ isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
struct mpqueue *ql,
*q = dev->mp_last;
- while (q) {
- if (q->sqno < min_sqno) {
- if (q->BEbyte & MP_END_FRAG) {
- printk(KERN_DEBUG "ippp: freeing stale packet!\n");
- if ((dev->mp_last = q->next))
- q->next->last = NULL;
- while (q) {
- ql = q->last;
- SET_SKB_FREE(q->skb);
- dev_kfree_skb(q->skb);
- kfree(q);
+ while(q && (q->sqno < min_sqno) ) {
+ if ( (q->BEbyte & MP_END_FRAG) ||
+ (q->next && (q->next->sqno <= min_sqno) && (q->next->BEbyte & MP_BEGIN_FRAG)) ) {
+ printk(KERN_DEBUG "ippp: freeing stale packet(s), min_sq: %ld!\n",min_sqno);
+ if ((dev->mp_last = q->next))
+ q->next->last = NULL;
+ while (q) {
+ ql = q->last;
+ printk(KERN_DEBUG "ippp, freeing packet with sqno: %ld\n",q->sqno);
+ dev_kfree_skb(q->skb);
+ kfree(q);
#ifdef CONFIG_ISDN_PPP_VJ
- toss = 1;
+ toss = 1;
#endif
- q = ql;
- }
- q = dev->mp_last;
- } else
- q = q->next;
+ q = ql;
+ }
+ q = dev->mp_last;
} else
- break;
+ q = q->next;
}
#ifdef CONFIG_ISDN_PPP_VJ
/* did we free a stale frame ? */
if (toss)
- slhc_toss(ippp_table[dev->local.ppp_slot]->slcomp);
+ slhc_toss(ippp_table[dev->local->ppp_slot]->slcomp);
#endif
}
@@ -1708,7 +1776,7 @@ isdn_ppp_timer_timeout(void)
*qn;
while (net_dev) {
- isdn_net_local *lp = &net_dev->local;
+ isdn_net_local *lp = net_dev->local;
if (net_dev->ib.modify || lp->master) { /* interface locked or slave? */
net_dev = net_dev->next;
continue;
@@ -1728,7 +1796,8 @@ isdn_ppp_timer_timeout(void)
net_dev->ib.next_num = q->sqno_end + 1;
q->next = NULL;
for (; ql;) {
- isdn_ppp_push_higher(net_dev, lp, ql->skb, -1);
+ int proto = isdn_ppp_strip_proto(ql->skb);
+ isdn_ppp_push_higher(net_dev, lp, ql->skb, proto);
qn = ql->next;
kfree(ql);
ql = qn;
@@ -1804,7 +1873,7 @@ isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
case SIOCGPPPVER:
r = (char *) ifr->ifr_ifru.ifru_data;
len = strlen(PPP_VERSION) + 1;
- error = copy_to_user(r, PPP_VERSION, len);
+ error = copy_to_user(r, PPP_VERSION, len);
break;
case SIOCGPPPSTATS:
error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
@@ -1853,7 +1922,7 @@ isdn_ppp_dial_slave(char *name)
if (!(ndev = isdn_net_findif(name)))
return 1;
- lp = &ndev->local;
+ lp = ndev->local;
if (!(lp->flags & ISDN_NET_CONNECTED))
return 5;
@@ -1884,7 +1953,7 @@ isdn_ppp_hangup_slave(char *name)
if (!(ndev = isdn_net_findif(name)))
return 1;
- lp = &ndev->local;
+ lp = ndev->local;
if (!(lp->flags & ISDN_NET_CONNECTED))
return 5;
@@ -1905,6 +1974,128 @@ isdn_ppp_hangup_slave(char *name)
#endif
}
+/*
+ * PPP compression stuff
+ */
+static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master)
+{
+#if 1
+ printk(KERN_ERR "compression not included!\n");
+ dev_kfree_skb(skb);
+ return NULL;
+#else
+ if(!master) {
+ /*
+ * single link compression
+ */
+ if(!is->link_compressor) {
+ printk(KERN_ERR "ippp: no (link) compressor defined!\n");
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+ if(!is->link_decomp_stat) {
+ printk(KERN_DEBUG "ippp: initialize link compressor\n");
+ }
+/*
+ -> decompress link
+*/
+ }
+ else {
+ /*
+ * 'normal' or bundle-compression
+ */
+ if(!master->compressor) {
+ printk(KERN_ERR "ippp: no (link) compressor defined!\n");
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+ if(!master->decomp_stat) {
+#if 0
+ master->decomp_stat = (master->compressor->decomp_alloc)( .. );
+#endif
+ printk(KERN_DEBUG "ippp: initialize compressor\n");
+ }
+ }
+
+ return skb;
+#endif
+}
+
+/*
+ * compress a frame
+ * type=0: normal/bundle compression
+ * =1: link compression
+ * returns original skb if we haven't compressed the frame
+ * and a new skb pointer if we've done it
+ */
+static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
+ struct ippp_struct *is,struct ippp_struct *master,int type)
+{
+#if 1
+ return skb_in;
+#else
+ int ret;
+ int new_proto;
+ struct isdn_ppp_compressor *compressor;
+ void *stat;
+ struct sk_buff *skb_out;
+
+ if(type) { /* type=1 => Link compression */
+ compressor = is->link_compressor;
+ stat = is->link_comp_stat;
+ new_proto = PPP_LINK_COMP;
+ }
+ else {
+ if(!master) {
+ compressor = is->compressor;
+ stat = is->comp_stat;
+ }
+ else {
+ compressor = master->compressor;
+ stat = master->comp_stat;
+ }
+ new_proto = PPP_COMP;
+ }
+
+ if(!compressor) {
+ printk(KERN_ERR "No compressor set!\n");
+ return skb_in;
+ }
+ if(!stat) {
+ /* init here ? */
+ return skb_in;
+ }
+
+ skb_out = dev_alloc_skb(skb_in->len);
+ if(!skb_out)
+ return skb_in;
+
+ ret = (compressor->compress)(stat,skb_in,skb_out,*proto);
+ if(!ret) {
+ dev_kfree_skb(skb_out);
+ return skb_in;
+ }
+
+ dev_kfree_skb(skb_in);
+ *proto = new_proto;
+ return skb_out;
+#endif
+
+}
+
+/*
+ * we received a CCP frame ..
+ * not a clean solution, but we SHOULD handle a few cased in the kernel
+ */
+static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
+ struct sk_buff *skb)
+{
+#if 0
+ printk(KERN_DEBUG "isdn_ppp_receive_cpp: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ skb->data[0],skb->data[1],skb->data[2],skb->data[3],
+ skb->data[4],skb->data[5],skb->data[6],skb->data[7] );
+#endif
+}
int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
{
@@ -1937,6 +2128,7 @@ static int isdn_ppp_set_compressor(struct ippp_struct *is,int num)
if(ipc->num == num) {
return 0;
is->compressor = ipc;
+ is->link_compressor = ipc;
}
ipc = ipc->next;
}
diff --git a/drivers/isdn/isdn_ppp.h b/drivers/isdn/isdn_ppp.h
index 11184b8c0..0e05af08b 100644
--- a/drivers/isdn/isdn_ppp.h
+++ b/drivers/isdn/isdn_ppp.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.h,v 1.9 1997/02/11 18:32:59 fritz Exp $
+/* $Id: isdn_ppp.h,v 1.12 1998/01/31 22:07:48 keil Exp $
* header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
@@ -19,6 +19,21 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_ppp.h,v $
+ * Revision 1.12 1998/01/31 22:07:48 keil
+ * changes for newer kernels
+ *
+ * Revision 1.11 1997/10/01 09:20:44 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.10 1997/06/17 13:06:00 hipp
+ * Applied Eric's underflow-patches (slightly modified)
+ * more compression changes (but disabled at the moment)
+ * changed one copy_to_user() to run with enabled IRQs
+ * a few MP changes
+ * changed 'proto' handling in the isdn_ppp receive code
+ *
* Revision 1.9 1997/02/11 18:32:59 fritz
* Bugfix in isdn_ppp_free_mpqueue().
*
@@ -63,11 +78,7 @@ extern int isdn_ppp_bind(isdn_net_local *);
extern int isdn_ppp_xmit(struct sk_buff *, struct device *);
extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
extern int isdn_ppp_dev_ioctl(struct device *, struct ifreq *, int);
-#if (LINUX_VERSION_CODE < 0x020117)
-extern int isdn_ppp_select(int, struct file *, int, select_table *);
-#else
-extern unsigned int isdn_ppp_poll(struct file *, poll_table *);
-#endif
+extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *);
extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
extern void isdn_ppp_release(int, struct file *);
extern int isdn_ppp_dial_slave(char *);
@@ -78,3 +89,7 @@ extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
#define IPPP_CLOSEWAIT 0x04
#define IPPP_NOBLOCK 0x08
#define IPPP_ASSIGNED 0x10
+
+#define IPPP_MAX_HEADER 10
+
+
diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c
index 0929dbc26..fd976ff50 100644
--- a/drivers/isdn/isdn_tty.c
+++ b/drivers/isdn/isdn_tty.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.41 1997/05/27 15:17:31 fritz Exp $
+/* $Id: isdn_tty.c,v 1.47 1998/02/22 19:44:14 fritz Exp $
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
*
@@ -20,6 +20,35 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_tty.c,v $
+ * Revision 1.47 1998/02/22 19:44:14 fritz
+ * Bugfixes and improvements regarding V.110, V.110 now running.
+ *
+ * Revision 1.46 1998/02/20 17:23:08 fritz
+ * Changes for recent kernels.
+ * Merged in contributions by Thomas Pfeiffer (V.110 T.70+ Extended FAX stuff)
+ * Added symbolic constants for Modem-Registers.
+ *
+ * Revision 1.45 1998/01/31 22:07:49 keil
+ * changes for newer kernels
+ *
+ * Revision 1.44 1998/01/31 19:30:02 calle
+ * Merged changes from and for 2.1.82, not tested only compiled ...
+ *
+ * Revision 1.43 1997/10/09 21:29:04 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ * New L1 error status (not yet in use).
+ * Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.42 1997/10/01 09:20:49 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
* Revision 1.41 1997/05/27 15:17:31 fritz
* Added changes for recent 2.1.x kernels:
* changed return type of isdn_close
@@ -199,6 +228,8 @@
#define VBUFX (VBUF/16)
#endif
+#define FIX_FILE_TRANSFER
+
/* Prototypes */
static int isdn_tty_edit_at(const char *, int, modem_info *, int);
@@ -223,12 +254,63 @@ static int bit2si[8] =
static int si2bit[8] =
{4, 1, 4, 4, 4, 4, 4, 4};
-char *isdn_tty_revision = "$Revision: 1.41 $";
+char *isdn_tty_revision = "$Revision: 1.47 $";
#define DLE 0x10
#define ETX 0x03
#define DC4 0x14
+/*
+ * Definition of some special Registers of AT-Emulator
+ */
+#define REG_RINGATA 0
+#define REG_RINGCNT 1
+#define REG_ESC 2
+#define REG_CR 3
+#define REG_LF 4
+#define REG_BS 5
+
+#define REG_RESP 12
+#define BIT_RESP 1
+#define REG_RESPNUM 12
+#define BIT_RESPNUM 2
+#define REG_ECHO 12
+#define BIT_ECHO 4
+#define REG_DCD 12
+#define BIT_DCD 8
+#define REG_CTS 12
+#define BIT_CTS 16
+#define REG_DTRR 12
+#define BIT_DTRR 32
+#define REG_DSR 12
+#define BIT_DSR 64
+#define REG_CPPP 12
+#define BIT_CPPP 128
+
+#define REG_DELXMT 13
+#define BIT_DELXMT 1
+#define REG_T70 13
+#define BIT_T70 2
+#define BIT_T70_EXT 32
+#define REG_DTRHUP 13
+#define BIT_DTRHUP 4
+#define REG_RESPXT 13
+#define BIT_RESPXT 8
+#define REG_CIDONCE 13
+#define BIT_CIDONCE 16
+#define REG_RUNG 13
+#define BIT_RUNG 64
+
+#define REG_L2PROT 14
+#define REG_L3PROT 15
+#define REG_PSIZE 16
+#define REG_WSIZE 17
+#define REG_SI1 18
+#define REG_SI2 19
+#define REG_SI1I 20
+#define REG_PLAN 21
+#define REG_SCREEN 22
+
/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
* to stuff incoming data directly into a tty's flip-buffer. This
* is done to speed up tty-receiving if the receive-queue is empty.
@@ -272,10 +354,9 @@ isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
#ifdef CONFIG_ISDN_AUDIO
}
#endif
- if (info->emu.mdmreg[12] & 128)
+ if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
tty->flip.flag_buf_ptr[len - 1] = 0xff;
queue_task(&tty->flip.tqueue, &tq_timer);
- SET_SKB_FREE(skb);
kfree_skb(skb);
return 1;
}
@@ -319,7 +400,7 @@ isdn_tty_readmodem(void)
tty->flip.char_buf_ptr,
tty->flip.flag_buf_ptr, c, 0);
/* CISCO AsyncPPP Hack */
- if (!(info->emu.mdmreg[12] & 128))
+ if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
memset(tty->flip.flag_buf_ptr, 0, r);
tty->flip.count += r;
tty->flip.flag_buf_ptr += r;
@@ -371,19 +452,26 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
#endif
) {
/* If Modem not listening, drop data */
- SET_SKB_FREE(skb);
kfree_skb(skb);
return 1;
}
- if (info->emu.mdmreg[13] & 2)
- /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
- if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
- skb_pull(skb, 4);
+ if (info->emu.mdmreg[REG_T70] & BIT_T70) {
+ if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT) {
+ /* T.70 decoding: throw away the T.70 header (2 or 4 bytes) */
+ if (skb->data[0] == 3) /* pure data packet -> 4 byte headers */
+ skb_pull(skb, 4);
+ else
+ if (skb->data[0] == 1) /* keepalive packet -> 2 byte hdr */
+ skb_pull(skb, 2);
+ } else
+ /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
+ if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
+ skb_pull(skb, 4);
+ }
#ifdef CONFIG_ISDN_AUDIO
if (skb_headroom(skb) < sizeof(isdn_audio_skb)) {
printk(KERN_WARNING
"isdn_audio: insufficient skb_headroom, dropping\n");
- SET_SKB_FREE(skb);
kfree_skb(skb);
return 1;
}
@@ -454,16 +542,12 @@ isdn_tty_cleanup_xmit(modem_info * info)
save_flags(flags);
cli();
if (skb_queue_len(&info->xmit_queue))
- while ((skb = skb_dequeue(&info->xmit_queue))) {
- SET_SKB_FREE(skb);
+ while ((skb = skb_dequeue(&info->xmit_queue)))
kfree_skb(skb);
- }
#ifdef CONFIG_ISDN_AUDIO
if (skb_queue_len(&info->dtmf_queue))
- while ((skb = skb_dequeue(&info->dtmf_queue))) {
- SET_SKB_FREE(skb);
+ while ((skb = skb_dequeue(&info->dtmf_queue)))
kfree_skb(skb);
- }
#endif
restore_flags(flags);
}
@@ -479,7 +563,7 @@ isdn_tty_tint(modem_info * info)
return;
len = skb->len;
if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
- info->isdn_channel, skb)) == len) {
+ info->isdn_channel, 1, skb)) == len) {
struct tty_struct *tty = info->tty;
info->send_outstanding++;
info->msr |= UART_MSR_CTS;
@@ -492,7 +576,6 @@ isdn_tty_tint(modem_info * info)
}
if (slen < 0) {
/* Error: no channel, already shutdown, or wrong parameter */
- SET_SKB_FREE(skb);
dev_kfree_skb(skb);
return;
}
@@ -590,7 +673,7 @@ isdn_tty_end_vrx(const char *buf, int c, int from_user)
while (c--) {
if (from_user)
- GET_USER(ch, buf);
+ get_user(ch, buf);
else
ch = *buf;
if ((ch != 0x11) && (ch != 0x13))
@@ -640,7 +723,7 @@ isdn_tty_senddown(modem_info * info)
restore_flags(flags);
return;
}
- if ((info->emu.mdmreg[12] & 0x10) != 0)
+ if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0)
info->msr &= ~UART_MSR_CTS;
info->lsr &= ~UART_LSR_TEMT;
if (info->isdn_driver < 0) {
@@ -710,10 +793,13 @@ isdn_tty_senddown(modem_info * info)
}
}
#endif /* CONFIG_ISDN_AUDIO */
- SET_SKB_FREE(skb);
- if (info->emu.mdmreg[13] & 2)
+ if (info->emu.mdmreg[REG_T70] & BIT_T70) {
/* Add T.70 simplified header */
- memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
+ if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT)
+ memcpy(skb_push(skb, 2), "\1\0", 2);
+ else
+ memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
+ }
skb_queue_tail(&info->xmit_queue, skb);
}
@@ -761,27 +847,27 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
{
int usg = ISDN_USAGE_MODEM;
int si = 7;
- int l2 = m->mdmreg[14];
+ int l2 = m->mdmreg[REG_L2PROT];
isdn_ctrl cmd;
ulong flags;
int i;
int j;
for (j = 7; j >= 0; j--)
- if (m->mdmreg[18] & (1 << j)) {
+ if (m->mdmreg[REG_SI1] & (1 << j)) {
si = bit2si[j];
break;
}
#ifdef CONFIG_ISDN_AUDIO
if (si == 1) {
- l2 = 4;
+ l2 = ISDN_PROTO_L2_TRANS;
usg = ISDN_USAGE_VOICE;
}
#endif
- m->mdmreg[20] = si2bit[si];
+ m->mdmreg[REG_SI1I] = si2bit[si];
save_flags(flags);
cli();
- i = isdn_get_free_channel(usg, l2, m->mdmreg[15], -1, -1);
+ i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
if (i < 0) {
restore_flags(flags);
isdn_tty_modem_result(6, info);
@@ -798,32 +884,32 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.command = ISDN_CMD_CLREAZ;
- dev->drv[info->isdn_driver]->interface->command(&cmd);
+ isdn_command(&cmd);
strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETEAZ;
- dev->drv[info->isdn_driver]->interface->command(&cmd);
+ isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL2;
info->last_l2 = l2;
cmd.arg = info->isdn_channel + (l2 << 8);
- dev->drv[info->isdn_driver]->interface->command(&cmd);
+ isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
- dev->drv[info->isdn_driver]->interface->command(&cmd);
+ cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
+ isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
sprintf(cmd.parm.setup.phone, "%s", n);
sprintf(cmd.parm.setup.eazmsn, "%s",
isdn_map_eaz2msn(m->msn, info->isdn_driver));
cmd.parm.setup.si1 = si;
- cmd.parm.setup.si2 = m->mdmreg[19];
+ cmd.parm.setup.si2 = m->mdmreg[REG_SI2];
cmd.command = ISDN_CMD_DIAL;
info->dialing = 1;
strcpy(dev->num[i], n);
isdn_info_update();
- dev->drv[info->isdn_driver]->interface->command(&cmd);
+ isdn_command(&cmd);
}
}
@@ -865,6 +951,9 @@ isdn_tty_modem_hup(modem_info * info, int local)
info->adpcmr = NULL;
}
#endif
+ if ((info->msr & UART_MSR_RI) &&
+ (info->emu.mdmreg[REG_RUNG] & BIT_RUNG))
+ isdn_tty_modem_result(12, info);
info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
info->lsr |= UART_LSR_TEMT;
if (info->isdn_driver >= 0) {
@@ -872,11 +961,11 @@ isdn_tty_modem_hup(modem_info * info, int local)
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_HANGUP;
cmd.arg = info->isdn_channel;
- dev->drv[info->isdn_driver]->interface->command(&cmd);
+ isdn_command(&cmd);
}
isdn_all_eaz(info->isdn_driver, info->isdn_channel);
- info->emu.mdmreg[1] = 0;
- usage = (info->emu.mdmreg[20] == 1) ?
+ info->emu.mdmreg[REG_RINGCNT] = 0;
+ usage = (info->emu.mdmreg[REG_SI1I] == 1) ?
ISDN_USAGE_VOICE : ISDN_USAGE_MODEM;
isdn_free_channel(info->isdn_driver, info->isdn_channel,
usage);
@@ -937,7 +1026,7 @@ isdn_tty_change_speed(modem_info * info)
isdn_tty_modem_ncarrier(info);
} else {
info->mcr &= ~UART_MCR_DTR;
- if (info->emu.mdmreg[13] & 4) {
+ if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "Mhup in changespeed\n");
#endif
@@ -1020,7 +1109,7 @@ isdn_tty_shutdown(modem_info * info)
info->msr &= ~UART_MSR_RI;
if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
- if (info->emu.mdmreg[13] & 4) {
+ if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
isdn_tty_modem_reset_regs(info, 0);
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
@@ -1047,8 +1136,8 @@ isdn_tty_shutdown(modem_info * info)
static int
isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count)
{
- int c,
- total = 0;
+ int c;
+ int total = 0;
ulong flags;
modem_info *info = (modem_info *) tty->driver_data;
@@ -1074,7 +1163,7 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
#ifdef CONFIG_ISDN_AUDIO
if (!info->vonline)
#endif
- isdn_tty_check_esc(buf, m->mdmreg[2], c,
+ isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
&(m->pluscount),
&(m->lastplus),
from_user);
@@ -1116,7 +1205,7 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
} else
#endif
info->xmit_count += c;
- if (m->mdmreg[13] & 1) {
+ if (m->mdmreg[REG_DELXMT] & BIT_DELXMT) {
isdn_tty_senddown(info);
isdn_tty_tint(info);
}
@@ -1304,7 +1393,7 @@ isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
uint arg;
int pre_dtr;
- GET_USER(arg, (uint *) value);
+ get_user(arg, (uint *) value);
switch (cmd) {
case TIOCMBIS:
#ifdef ISDN_DEBUG_MODEM_IOCTL
@@ -1327,7 +1416,7 @@ isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
}
if (arg & TIOCM_DTR) {
info->mcr &= ~UART_MCR_DTR;
- if (info->emu.mdmreg[13] & 4) {
+ if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
isdn_tty_modem_reset_regs(info, 0);
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "Mhup in TIOCMBIC\n");
@@ -1348,7 +1437,7 @@ isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
| ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
if (pre_dtr |= (info->mcr & UART_MCR_DTR)) {
if (!(info->mcr & UART_MCR_DTR)) {
- if (info->emu.mdmreg[13] & 4) {
+ if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
isdn_tty_modem_reset_regs(info, 0);
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "Mhup in TIOCMSET\n");
@@ -1414,7 +1503,7 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
if (error)
return error;
- GET_USER(arg, (ulong *) arg);
+ get_user(arg, (ulong *) arg);
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
@@ -1443,7 +1532,6 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
return error;
else
return isdn_tty_get_lsr_info(info, (uint *) arg);
-
default:
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
@@ -1823,10 +1911,10 @@ static void
isdn_tty_modem_reset_regs(modem_info * info, int force)
{
atemu *m = &info->emu;
- if ((m->mdmreg[12] & 32) || force) {
+ if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) {
memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG);
memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
- info->xmit_size = m->mdmreg[16] * 16;
+ info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
}
#ifdef CONFIG_ISDN_AUDIO
isdn_tty_modem_reset_vpar(m);
@@ -1881,6 +1969,7 @@ isdn_tty_modem_init(void)
m->tty_modem.stop = NULL;
m->tty_modem.start = NULL;
m->tty_modem.hangup = isdn_tty_hangup;
+ m->tty_modem.driver_name = "isdn_tty";
/*
* The callout device is just like normal device except for
* major number and the subtype code.
@@ -1905,7 +1994,7 @@ isdn_tty_modem_init(void)
sprintf(info->last_num, "none");
info->last_dir = 0;
info->last_lhup = 1;
- info->last_l2 = 0;
+ info->last_l2 = -1;
info->last_si = 0;
isdn_tty_reset_profile(&info->emu);
isdn_tty_modem_reset_regs(info, 1);
@@ -1927,7 +2016,7 @@ isdn_tty_modem_init(void)
#ifdef CONFIG_ISDN_AUDIO
skb_queue_head_init(&info->dtmf_queue);
#endif
- if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_SIZE + 5, GFP_KERNEL))) {
+ if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) {
printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
return -3;
}
@@ -1977,12 +2066,12 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
#ifdef ISDN_DEBUG_MODEM_ICALL
printk(KERN_DEBUG "m_fi: i=%d msn=%s mmsn=%s mreg18=%d mreg19=%d\n", i,
info->emu.msn, isdn_map_eaz2msn(info->emu.msn, di),
- info->emu.mdmreg[18], info->emu.mdmreg[19]);
+ info->emu.mdmreg[REG_SI1], info->emu.mdmreg[REG_SI2]);
#endif
if ((!strcmp(isdn_map_eaz2msn(info->emu.msn, di),
- eaz)) && /* EAZ is matching */
- (info->emu.mdmreg[18] & si2bit[si1]) && /* SI1 is matching */
- ((info->emu.mdmreg[19] == si2) || !si2)) { /* SI2 is matching or 0 */
+ eaz)) && /* EAZ is matching */
+ (info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */
+ (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */
idx = isdn_dc2minor(di, ch);
#ifdef ISDN_DEBUG_MODEM_ICALL
printk(KERN_DEBUG "m_fi: match1\n");
@@ -1990,7 +2079,10 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
info->flags, info->isdn_driver, info->isdn_channel,
dev->usage[idx]);
#endif
- if ((info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
+ if (
+#ifndef FIX_FILE_TRANSFER
+ (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
+#endif
(info->isdn_driver == -1) &&
(info->isdn_channel == -1) &&
(USG_NONE(dev->usage[idx]))) {
@@ -2001,9 +2093,9 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
dev->usage[idx] |= (si1 == 1) ? ISDN_USAGE_VOICE : ISDN_USAGE_MODEM;
strcpy(dev->num[idx], nr);
- info->emu.mdmreg[20] = si2bit[si1];
- info->emu.mdmreg[21] = setup.plan;
- info->emu.mdmreg[22] = setup.screen;
+ info->emu.mdmreg[REG_SI1I] = si2bit[si1];
+ info->emu.mdmreg[REG_PLAN] = setup.plan;
+ info->emu.mdmreg[REG_SCREEN] = setup.screen;
isdn_info_update();
restore_flags(flags);
printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
@@ -2029,12 +2121,20 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
{
int mi;
modem_info *info;
+ char *e;
if (i < 0)
return 0;
if ((mi = dev->m_idx[i]) >= 0) {
info = &dev->mdm.info[mi];
switch (c->command) {
+ case ISDN_STAT_CINF:
+ printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num);
+ info->emu.charge = (unsigned) simple_strtoul(c->parm.num, &e, 10);
+ if (e == c->parm.num)
+ info->emu.charge = 0;
+
+ break;
case ISDN_STAT_BSENT:
#ifdef ISDN_TTY_STAT_DEBUG
printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line);
@@ -2093,6 +2193,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
*/
if (TTY_IS_ACTIVE(info)) {
info->msr |= UART_MSR_DCD;
+ info->emu.charge = 0;
if (info->dialing) {
info->dialing = 0;
info->last_dir = 1;
@@ -2184,13 +2285,13 @@ isdn_tty_at_cout(char *msg, modem_info * info)
for (p = msg; *p; p++) {
switch (*p) {
case '\r':
- c = m->mdmreg[3];
+ c = m->mdmreg[REG_CR];
break;
case '\n':
- c = m->mdmreg[4];
+ c = m->mdmreg[REG_LF];
break;
case '\b':
- c = m->mdmreg[5];
+ c = m->mdmreg[REG_BS];
break;
default:
c = *p;
@@ -2293,14 +2394,14 @@ isdn_tty_modem_result(int code, modem_info * info)
static char *msg[] =
{"OK", "CONNECT", "RING", "NO CARRIER", "ERROR",
"CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
- "RINGING", "NO MSN/EAZ", "VCON"};
+ "RINGING", "NO MSN/EAZ", "VCON", "RUNG"};
ulong flags;
char s[10];
switch (code) {
case 2:
- m->mdmreg[1]++; /* RING */
- if (m->mdmreg[1] == m->mdmreg[0])
+ m->mdmreg[REG_RINGCNT]++; /* RING */
+ if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA])
/* Automatically accept incoming call */
isdn_tty_cmd_ATA(info);
break;
@@ -2313,7 +2414,7 @@ isdn_tty_modem_result(int code, modem_info * info)
#endif
save_flags(flags);
cli();
- m->mdmreg[1] = 0;
+ m->mdmreg[REG_RINGCNT] = 0;
del_timer(&info->nc_timer);
info->ncarrier = 0;
if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
@@ -2356,15 +2457,19 @@ isdn_tty_modem_result(int code, modem_info * info)
info->online = 1;
break;
}
- if (m->mdmreg[12] & 1) {
+ if (m->mdmreg[REG_RESP] & BIT_RESP) {
/* Show results */
isdn_tty_at_cout("\r\n", info);
- if (m->mdmreg[12] & 2) {
+ if (m->mdmreg[REG_RESPNUM] & BIT_RESPNUM) {
/* Show numeric results */
sprintf(s, "%d", code);
isdn_tty_at_cout(s, info);
} else {
- if ((code == 2) && (!(m->mdmreg[13] & 16))) {
+ if ((code == 2) &&
+ (m->mdmreg[REG_RUNG] & BIT_RUNG) &&
+ (m->mdmreg[REG_RINGCNT] > 1))
+ return;
+ if ((code == 2) && (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE))) {
isdn_tty_at_cout("CALLER NUMBER: ", info);
isdn_tty_at_cout(dev->num[info->drv_index], info);
isdn_tty_at_cout("\r\n", info);
@@ -2373,7 +2478,8 @@ isdn_tty_modem_result(int code, modem_info * info)
switch (code) {
case 2:
/* Print CID only once, _after_ 1.st RING */
- if ((m->mdmreg[13] & 16) && (m->mdmreg[1] == 1)) {
+ if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) &&
+ (m->mdmreg[REG_RINGCNT] == 1)) {
isdn_tty_at_cout("\r\n", info);
isdn_tty_at_cout("CALLER NUMBER: ", info);
isdn_tty_at_cout(dev->num[info->drv_index], info);
@@ -2383,18 +2489,39 @@ isdn_tty_modem_result(int code, modem_info * info)
case 6:
case 7:
case 8:
- m->mdmreg[1] = 0;
+ m->mdmreg[REG_RINGCNT] = 0;
/* Append Cause-Message if enabled */
- if (m->mdmreg[13] & 8) {
+ if (m->mdmreg[REG_RESPXT] & BIT_RESPXT) {
sprintf(s, "/%s", info->last_cause);
isdn_tty_at_cout(s, info);
}
break;
case 5:
/* Append Protocol to CONNECT message */
- isdn_tty_at_cout((m->mdmreg[14] != 3) ? "/X.75" : "/HDLC", info);
- if (m->mdmreg[13] & 2)
+ switch (m->mdmreg[REG_L2PROT]) {
+ case ISDN_PROTO_L2_X75I:
+ case ISDN_PROTO_L2_X75UI:
+ case ISDN_PROTO_L2_X75BUI:
+ isdn_tty_at_cout("/X.75", info);
+ break;
+ case ISDN_PROTO_L2_HDLC:
+ isdn_tty_at_cout("/HDLC", info);
+ break;
+ case ISDN_PROTO_L2_V11096:
+ isdn_tty_at_cout("/V110/9600", info);
+ break;
+ case ISDN_PROTO_L2_V11019:
+ isdn_tty_at_cout("/V110/19200", info);
+ break;
+ case ISDN_PROTO_L2_V11038:
+ isdn_tty_at_cout("/V110/38400", info);
+ break;
+ }
+ if (m->mdmreg[REG_T70] & BIT_T70) {
isdn_tty_at_cout("/T.70", info);
+ if (m->mdmreg[REG_T70] & BIT_T70_EXT)
+ isdn_tty_at_cout("+", info);
+ }
break;
}
}
@@ -2479,16 +2606,25 @@ isdn_tty_report(modem_info * info)
isdn_tty_at_cout(" Layer-2 Protocol: ", info);
switch (info->last_l2) {
case ISDN_PROTO_L2_X75I:
- isdn_tty_at_cout("x75i", info);
+ isdn_tty_at_cout("X.75i", info);
break;
case ISDN_PROTO_L2_X75UI:
- isdn_tty_at_cout("x75ui", info);
+ isdn_tty_at_cout("X.75ui", info);
break;
case ISDN_PROTO_L2_X75BUI:
- isdn_tty_at_cout("x75bui", info);
+ isdn_tty_at_cout("X.75bui", info);
break;
case ISDN_PROTO_L2_HDLC:
- isdn_tty_at_cout("hdlc", info);
+ isdn_tty_at_cout("HDLC", info);
+ break;
+ case ISDN_PROTO_L2_V11096:
+ isdn_tty_at_cout("V.110 9600 Baud", info);
+ break;
+ case ISDN_PROTO_L2_V11019:
+ isdn_tty_at_cout("V.110 19200 Baud", info);
+ break;
+ case ISDN_PROTO_L2_V11038:
+ isdn_tty_at_cout("V.110 38400 Baud", info);
break;
case ISDN_PROTO_L2_TRANS:
isdn_tty_at_cout("transparent", info);
@@ -2497,7 +2633,12 @@ isdn_tty_report(modem_info * info)
isdn_tty_at_cout("unknown", info);
break;
}
- isdn_tty_at_cout((m->mdmreg[13] & 2) ? "/t.70\r\n" : "\r\n", info);
+ if (m->mdmreg[REG_T70] & BIT_T70) {
+ isdn_tty_at_cout("/T.70", info);
+ if (m->mdmreg[REG_T70] & BIT_T70_EXT)
+ isdn_tty_at_cout("+", info);
+ }
+ isdn_tty_at_cout("\r\n", info);
isdn_tty_at_cout(" Service: ", info);
switch (info->last_si) {
case 1:
@@ -2535,30 +2676,36 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
/* &B - Set Buffersize */
p[0]++;
i = isdn_getnum(p);
- if ((i < 0) || (i > ISDN_SERIAL_XMIT_SIZE))
+ if ((i < 0) || (i > ISDN_SERIAL_XMIT_MAX))
PARSE_ERROR1;
#ifdef CONFIG_ISDN_AUDIO
- if ((m->mdmreg[18] & 1) && (i > VBUF))
+ if ((m->mdmreg[REG_SI1] & 1) && (i > VBUF))
PARSE_ERROR1;
#endif
- m->mdmreg[16] = i / 16;
- info->xmit_size = m->mdmreg[16] * 16;
+ m->mdmreg[REG_PSIZE] = i / 16;
+ info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
+ switch (m->mdmreg[REG_L2PROT]) {
+ case ISDN_PROTO_L2_V11096:
+ case ISDN_PROTO_L2_V11019:
+ case ISDN_PROTO_L2_V11038:
+ info->xmit_size /= 10;
+ }
break;
case 'D':
/* &D - Set DCD-Low-behavior */
p[0]++;
switch (isdn_getnum(p)) {
case 0:
- m->mdmreg[13] &= ~4;
- m->mdmreg[12] &= ~32;
+ m->mdmreg[REG_DTRHUP] &= ~BIT_DTRHUP;
+ m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
break;
case 2:
- m->mdmreg[13] |= 4;
- m->mdmreg[12] &= ~32;
+ m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
+ m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
break;
case 3:
- m->mdmreg[13] |= 4;
- m->mdmreg[12] |= 32;
+ m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
+ m->mdmreg[REG_DTRR] |= BIT_DTRR;
break;
default:
PARSE_ERROR1
@@ -2575,12 +2722,46 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
isdn_tty_reset_profile(m);
isdn_tty_modem_reset_regs(info, 1);
break;
+ case 'R':
+ /* &R - Set V.110 bitrate adaption */
+ p[0]++;
+ i = isdn_getnum(p);
+ switch (i) {
+ case 0:
+ /* Switch off V.110, back to X.75 */
+ m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
+ m->mdmreg[REG_SI2] = 0;
+ info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
+ break;
+ case 9600:
+ m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11096;
+ m->mdmreg[REG_SI2] = 197;
+ info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
+ break;
+ case 19200:
+ m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11019;
+ m->mdmreg[REG_SI2] = 199;
+ info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
+ break;
+ case 38400:
+ m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11038;
+ m->mdmreg[REG_SI2] = 198; /* no existing standard for this */
+ info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ /* Switch off T.70 */
+ m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
+ /* Set Service 7 */
+ m->mdmreg[REG_SI1] |= 4;
+ break;
case 'S':
/* &S - Set Windowsize */
p[0]++;
i = isdn_getnum(p);
if ((i > 0) && (i < 9))
- m->mdmreg[17] = i;
+ m->mdmreg[REG_WSIZE] = i;
else
PARSE_ERROR1;
break;
@@ -2610,19 +2791,27 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
}
break;
case 'X':
- /* &X - Switch to BTX-Mode */
+ /* &X - Switch to BTX-Mode and T.70 */
p[0]++;
switch (isdn_getnum(p)) {
case 0:
- m->mdmreg[13] &= ~2;
- info->xmit_size = m->mdmreg[16] * 16;
+ m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
+ info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
break;
case 1:
- m->mdmreg[13] |= 2;
- m->mdmreg[14] = 0;
+ m->mdmreg[REG_T70] |= BIT_T70;
+ m->mdmreg[REG_T70] &= ~BIT_T70_EXT;
+ m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
+ info->xmit_size = 112;
+ m->mdmreg[REG_SI1] = 4;
+ m->mdmreg[REG_SI2] = 0;
+ break;
+ case 2:
+ m->mdmreg[REG_T70] |= (BIT_T70 | BIT_T70_EXT);
+ m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
info->xmit_size = 112;
- m->mdmreg[18] = 4;
- m->mdmreg[19] = 0;
+ m->mdmreg[REG_SI1] = 4;
+ m->mdmreg[REG_SI2] = 0;
break;
default:
PARSE_ERROR1;
@@ -2639,22 +2828,28 @@ isdn_tty_check_ats(int mreg, int mval, modem_info * info, atemu * m)
{
/* Some plausibility checks */
switch (mreg) {
- case 14:
- if (mval > ISDN_PROTO_L2_TRANS)
+ case REG_L2PROT:
+ if (mval > ISDN_PROTO_L2_MAX)
return 1;
break;
- case 16:
- if ((mval * 16) > ISDN_SERIAL_XMIT_SIZE)
+ case REG_PSIZE:
+ if ((mval * 16) > ISDN_SERIAL_XMIT_MAX)
return 1;
#ifdef CONFIG_ISDN_AUDIO
- if ((m->mdmreg[18] & 1) && (mval > VBUFX))
+ if ((m->mdmreg[REG_SI1] & 1) && (mval > VBUFX))
return 1;
#endif
info->xmit_size = mval * 16;
+ switch (m->mdmreg[REG_L2PROT]) {
+ case ISDN_PROTO_L2_V11096:
+ case ISDN_PROTO_L2_V11019:
+ case ISDN_PROTO_L2_V11038:
+ info->xmit_size /= 10;
+ }
break;
- case 20:
- case 21:
- case 22:
+ case REG_SI1I:
+ case REG_PLAN:
+ case REG_SCREEN:
/* readonly registers */
return 1;
}
@@ -2741,31 +2936,31 @@ isdn_tty_cmd_ATA(modem_info * info)
/* Accept incoming call */
info->last_dir = 0;
strcpy(info->last_num, dev->num[info->drv_index]);
- m->mdmreg[1] = 0;
+ m->mdmreg[REG_RINGCNT] = 0;
info->msr &= ~UART_MSR_RI;
- l2 = m->mdmreg[14];
+ l2 = m->mdmreg[REG_L2PROT];
#ifdef CONFIG_ISDN_AUDIO
/* If more than one bit set in reg18, autoselect Layer2 */
- if ((m->mdmreg[18] & m->mdmreg[20]) != m->mdmreg[18]) {
- if (m->mdmreg[20] == 1)
- l2 = 4;
+ if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) {
+ if (m->mdmreg[REG_SI1I] == 1)
+ l2 = ISDN_PROTO_L2_TRANS;
else
- l2 = 0;
+ l2 = ISDN_PROTO_L2_X75I;
}
#endif
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL2;
cmd.arg = info->isdn_channel + (l2 << 8);
info->last_l2 = l2;
- dev->drv[info->isdn_driver]->interface->command(&cmd);
+ isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
- dev->drv[info->isdn_driver]->interface->command(&cmd);
+ cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
+ isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.command = ISDN_CMD_ACCEPTD;
- dev->drv[info->isdn_driver]->interface->command(&cmd);
+ isdn_command(&cmd);
} else
isdn_tty_modem_result(8, info);
}
@@ -2787,7 +2982,7 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
case '?':
p[0]++;
sprintf(rs, "\r\n%d",
- (m->mdmreg[18] & 1) ? 8 : 0);
+ (m->mdmreg[REG_SI1] & 1) ? 8 : 0);
isdn_tty_at_cout(rs, info);
break;
case '=':
@@ -2795,18 +2990,22 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
switch (*p[0]) {
case '0':
p[0]++;
- m->mdmreg[18] = 4;
+ m->mdmreg[REG_SI1] = 4;
info->xmit_size =
- m->mdmreg[16] * 16;
+ m->mdmreg[REG_PSIZE] * 16;
+ break;
+ case '2':
+ printk(KERN_DEBUG "isdn_tty: FCLASS=2\n");
+ p[0]++;
break;
case '8':
p[0]++;
- m->mdmreg[18] = 5;
+ m->mdmreg[REG_SI1] = 5;
info->xmit_size = VBUF;
break;
case '?':
p[0]++;
- isdn_tty_at_cout("\r\n0,8",
+ isdn_tty_at_cout("\r\n0,2,8",
info);
break;
default:
@@ -2824,7 +3023,7 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
case '?':
p[0]++;
sprintf(rs, "\r\n%d",
- m->mdmreg[0]);
+ m->mdmreg[REG_RINGATA]);
isdn_tty_at_cout(rs, info);
break;
case '=':
@@ -2832,13 +3031,100 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
par = isdn_getnum(p);
if ((par < 0) || (par > 255))
PARSE_ERROR1;
- m->mdmreg[0] = par;
+ m->mdmreg[REG_RINGATA] = par;
break;
default:
PARSE_ERROR1;
}
return 0;
}
+ if (!strncmp(p[0], "TBC=", 4)) { /* UNKLAR !! */
+ p[0] += 4;
+ printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]);
+ switch (*p[0]) {
+ case '0':
+ p[0]++;
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+ if (!strncmp(p[0], "BOR=", 4)) { /* UNKLAR !! */
+ p[0] += 4;
+ printk(KERN_DEBUG "isdn_tty: Fax FBOR=%c\n", *p[0]);
+ switch (*p[0]) {
+ case '0':
+ p[0]++;
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+ if (!strncmp(p[0], "DCC=", 4)) { /* SETUP irgendwie !! */
+ int i, val[]={0,0,0,0,0,0,0,0};
+
+ p[0] += 4;
+ if (*p[0] == '?') {
+ isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0,1),(0),(0),(0-7)",info);
+ p[0]++;
+ } else {
+ for (i=0; (*p[0]>='0') && (*p[0]<='9'); i++) {
+ val[i] = *p[0] - 48;
+ p[0]++;
+ if (*p[0] == ',')
+ p[0]++;
+ }
+ printk(KERN_DEBUG "isdn_tty: Fax Setup values=%d,%d,%d,%d,%d,%d,%d,%d\n",
+ val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
+ }
+ return 0;
+ }
+ if (!strncmp(p[0], "LID=", 4)) { /* set sender ID !! */
+ char senderID[80];
+ int i;
+
+ p[0] += 4;
+ if (*p[0] =='"')
+ p[0]++;
+ for(i=0; (*p[0]) && (*p[0] != '"'); i++)
+ senderID[i] = *p[0]++;
+ senderID[i] = 0;
+ if (*p[0] =='"')
+ p[0]++;
+ printk(KERN_DEBUG "isdn_tty: Fax sender=>%s<\n", senderID);
+ return 0;
+ }
+ if (!strncmp(p[0], "MFR?", 4)) {
+ p[0] += 4;
+ printk(KERN_DEBUG "isdn_tty: FMFR?\n");
+ isdn_tty_at_cout("\r\nISDNfax", info);
+ return 0;
+ }
+ if (!strncmp(p[0], "MDL?", 4)) {
+ p[0] += 4;
+ printk(KERN_DEBUG "isdn_tty: FMDL?\n");
+ isdn_tty_at_cout("\r\nAVM-B1", info);
+ return 0;
+ }
+ if (!strncmp(p[0], "AP=?", 4)) {
+ p[0] += 4;
+ printk(KERN_DEBUG "isdn_tty: FAP=?\n");
+ return 0;
+ }
+ if (!strncmp(p[0], "PHCTO=", 6)) {
+ /* beim trace mit dem zyxel folgt der wert 30 ;*/
+ p[0] += 6;
+ printk(KERN_DEBUG "isdn_tty: FPHCTO=%s\n", p[0]);
+ return 0;
+ }
+ if (!strncmp(p[0], "CR=", 3)) {
+ p[0] += 3;
+ printk(KERN_DEBUG "isdn_tty: FCR=%s\n", p[0]);
+ return 0;
+ }
+ printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]);
PARSE_ERROR1;
}
@@ -3110,10 +3396,10 @@ isdn_tty_parse_at(modem_info * info)
p++;
switch (isdn_getnum(&p)) {
case 0:
- m->mdmreg[12] &= ~4;
+ m->mdmreg[REG_ECHO] &= ~BIT_ECHO;
break;
case 1:
- m->mdmreg[12] |= 4;
+ m->mdmreg[REG_ECHO] |= BIT_ECHO;
break;
default:
PARSE_ERROR;
@@ -3149,6 +3435,11 @@ isdn_tty_parse_at(modem_info * info)
p++;
isdn_tty_report(info);
break;
+ case '3':
+ p++;
+ sprintf(ds, "\r\n%d", info->emu.charge);
+ isdn_tty_at_cout(ds, info);
+ break;
default:
}
break;
@@ -3166,10 +3457,10 @@ isdn_tty_parse_at(modem_info * info)
p++;
switch (isdn_getnum(&p)) {
case 0:
- m->mdmreg[12] |= 1;
+ m->mdmreg[REG_RESP] |= BIT_RESP;
break;
case 1:
- m->mdmreg[12] &= ~1;
+ m->mdmreg[REG_RESP] &= ~BIT_RESP;
break;
default:
PARSE_ERROR;
@@ -3186,10 +3477,10 @@ isdn_tty_parse_at(modem_info * info)
p++;
switch (isdn_getnum(&p)) {
case 0:
- m->mdmreg[12] |= 2;
+ m->mdmreg[REG_RESP] |= BIT_RESPNUM;
break;
case 1:
- m->mdmreg[12] &= ~2;
+ m->mdmreg[REG_RESP] &= ~BIT_RESPNUM;
break;
default:
PARSE_ERROR;
@@ -3210,7 +3501,7 @@ isdn_tty_parse_at(modem_info * info)
return;
break;
case 'V':
- if (!(m->mdmreg[18] & 1))
+ if (!(m->mdmreg[REG_SI1] & 1))
PARSE_ERROR;
p++;
if (isdn_tty_cmd_PLUSV(&p, info))
@@ -3261,14 +3552,14 @@ isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
for (cnt = count; cnt > 0; p++, cnt--) {
if (user)
- GET_USER(c, p);
+ get_user(c, p);
else
c = *p;
total++;
- if (c == m->mdmreg[3] || c == m->mdmreg[4]) {
+ if (c == m->mdmreg[REG_CR] || c == m->mdmreg[REG_LF]) {
/* Separator (CR oder LF) */
m->mdmcmd[m->mdmcmdl] = 0;
- if (m->mdmreg[12] & 4) {
+ if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
eb[0] = c;
eb[1] = 0;
isdn_tty_at_cout(eb, info);
@@ -3278,18 +3569,18 @@ isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
m->mdmcmdl = 0;
continue;
}
- if (c == m->mdmreg[5] && m->mdmreg[5] < 128) {
+ if (c == m->mdmreg[REG_BS] && m->mdmreg[REG_BS] < 128) {
/* Backspace-Funktion */
if ((m->mdmcmdl > 2) || (!m->mdmcmdl)) {
if (m->mdmcmdl)
m->mdmcmdl--;
- if (m->mdmreg[12] & 4)
+ if (m->mdmreg[REG_ECHO] & BIT_ECHO)
isdn_tty_at_cout("\b", info);
}
continue;
}
if (cmdchar(c)) {
- if (m->mdmreg[12] & 4) {
+ if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
eb[0] = c;
eb[1] = 0;
isdn_tty_at_cout(eb, info);
diff --git a/drivers/isdn/isdn_v110.c b/drivers/isdn/isdn_v110.c
new file mode 100644
index 000000000..ae62378b8
--- /dev/null
+++ b/drivers/isdn/isdn_v110.c
@@ -0,0 +1,645 @@
+/* $Id: isdn_v110.c,v 1.2 1998/02/22 19:44:25 fritz Exp $
+
+ * Linux ISDN subsystem, V.110 related functions (linklevel).
+ *
+ * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: isdn_v110.c,v $
+ * Revision 1.2 1998/02/22 19:44:25 fritz
+ * Bugfixes and improvements regarding V.110, V.110 now running.
+ *
+ * Revision 1.1 1998/02/20 17:32:09 fritz
+ * First checkin (not yet completely functionable).
+ *
+ */
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+
+#include <linux/isdn.h>
+#include "isdn_v110.h"
+
+#undef ISDN_V110_DEBUG
+
+char *isdn_v110_revision = "$Revision: 1.2 $";
+
+#define V110_38400 255
+#define V110_19200 15
+#define V110_9600 3
+
+/* Die folgenden Daten sind fertig kodierte Matrizen, jeweils
+ als online und offline matrix für 9600, 19200 und 38400
+ */
+static unsigned char V110_OnMatrix_9600[] =
+{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
+ 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd,
+ 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
+ 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd};
+
+static unsigned char V110_OffMatrix_9600[] =
+{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+static unsigned char V110_OnMatrix_19200[] =
+{0xf0, 0xf0, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7,
+ 0xfd, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7};
+
+static unsigned char V110_OffMatrix_19200[] =
+{0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+static unsigned char V110_OnMatrix_38400[] =
+{0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0xfd, 0x7f, 0x7f, 0x7f, 0x7f};
+
+static unsigned char V110_OffMatrix_38400[] =
+{0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff};
+
+
+/* FlipBits dreht die Reihenfolge von jeweils keylen bits in einem byte um.
+ Aus der Bitreihenfolge 76543210 werden bei keylen=4 die bits 45670123,
+ bei keylen=2 die bits 67452301. Dies ist notwendig, weil die reihenfolge
+ auf der isdn-leitung falsch herum ist.
+ */
+
+static __inline unsigned char
+FlipBits(unsigned char c, int keylen)
+{
+ unsigned char b = c;
+ unsigned char bit = 128;
+ int i;
+ int j;
+ int hunks = (8 / keylen);
+
+ c = 0;
+ for (i = 0; i < hunks; i++) {
+ for (j = 0; j < keylen; j++) {
+ if (b & (bit >> j))
+ c |= bit >> (keylen - j - 1);
+ }
+ bit >>= keylen;
+ }
+ return c;
+}
+
+
+/* isdn_v110_open allocates and initializes private V.110 data
+ * structures and returns a pointer to these.
+ */
+static isdn_v110_stream *
+isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
+{
+ int i;
+ isdn_v110_stream *v;
+
+ if ((v = kmalloc(sizeof(isdn_v110_stream), GFP_KERNEL)) == NULL)
+ return NULL;
+ memset(v, 0, sizeof(isdn_v110_stream));
+ v->key = key;
+ v->nbits = 0;
+ for (i = 0; key & (1 << i); i++)
+ v->nbits++;
+
+ v->nbytes = 8 / v->nbits;
+ v->decodelen = 0;
+
+ switch (key) {
+ case V110_38400:
+ v->OnlineFrame = V110_OnMatrix_38400;
+ v->OfflineFrame = V110_OffMatrix_38400;
+ break;
+ case V110_19200:
+ v->OnlineFrame = V110_OnMatrix_19200;
+ v->OfflineFrame = V110_OffMatrix_19200;
+ break;
+ default:
+ v->OnlineFrame = V110_OnMatrix_9600;
+ v->OfflineFrame = V110_OffMatrix_9600;
+ break;
+ }
+ v->framelen = v->nbytes * 10;
+ v->SyncInit = 5;
+ v->introducer = 0;
+ v->dbit = 1;
+ v->b = 0;
+ v->skbres = hdrlen;
+ v->maxsize = maxsize - hdrlen;
+ if ((v->encodebuf = kmalloc(maxsize, GFP_KERNEL)) == NULL) {
+ kfree(v);
+ return NULL;
+ }
+ return v;
+}
+
+/* isdn_v110_close frees private V.110 data structures */
+static void
+isdn_v110_close(isdn_v110_stream * v)
+{
+ if (v == NULL)
+ return;
+#ifdef ISDN_V110_DEBUG
+ printk(KERN_DEBUG "v110 close\n");
+#if 0
+ printk(KERN_DEBUG "isdn_v110_close: nbytes=%d\n", v->nbytes);
+ printk(KERN_DEBUG "isdn_v110_close: nbits=%d\n", v->nbits);
+ printk(KERN_DEBUG "isdn_v110_close: key=%d\n", v->key);
+ printk(KERN_DEBUG "isdn_v110_close: SyncInit=%d\n", v->SyncInit);
+ printk(KERN_DEBUG "isdn_v110:close: decodelen=%d\n", v->decodelen);
+ printk(KERN_DEBUG "isdn_v110_close: framelen=%d\n", v->framelen);
+#endif
+#endif
+ kfree(v->encodebuf);
+ kfree(v);
+}
+
+
+/* ValidHeaderBytes prüft, wieviele bytes in v->decodebuf gültig sind */
+
+static int
+ValidHeaderBytes(isdn_v110_stream * v)
+{
+ int i;
+ for (i = 0; (i < v->decodelen) && (i < v->nbytes); i++)
+ if ((v->decodebuf[i] & v->key) != 0)
+ break;
+ return i;
+}
+
+/* SyncHeader schiebt den decodebuf pointer auf den nächsten gültigen header */
+
+static void
+SyncHeader(isdn_v110_stream * v)
+{
+ unsigned char *rbuf = v->decodebuf;
+ int len = v->decodelen;
+
+ if (len == 0)
+ return;
+ for (rbuf++, len--; len > 0; len--, rbuf++) /* such den SyncHeader in buf ! */
+ if ((*rbuf & v->key) == 0) /* erstes byte gefunden ? */
+ break; /* jupp! */
+ if (len)
+ memcpy(v->decodebuf, rbuf, len);
+
+ v->decodelen = len;
+#ifdef ISDN_V110_DEBUG
+ printk(KERN_DEBUG "isdn_v110: Header resync\n");
+#endif
+}
+
+/* DecodeMatrix takes n (n>=1) matrices (v110 frames, 10 bytes) where
+ len is the number of matrix-lines. len must be a multiple of 10, i.e.
+ only complete matices must be given.
+ From these, netto data is extracted and returned in buf. The return-value
+ is the bytecount of the decoded data.
+ */
+static int
+DecodeMatrix(isdn_v110_stream * v, unsigned char *m, int len, unsigned char *buf)
+{
+ int line = 0;
+ int buflen = 0;
+ int mbit = 64;
+ int introducer = v->introducer;
+ int dbit = v->dbit;
+ unsigned char b = v->b;
+
+ while (line < len) { /* sind schon alle matrizenzeilen abgearbeitet? */
+ if ((line % 10) == 0) { /* die 0. zeile der matrix ist immer null ! */
+ if (m[line] != 0x00) { /* nicht 0 ? dann fehler! */
+#ifdef ISDN_V110_DEBUG
+ printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad Header\n");
+#endif
+
+/*
+ dann einen return zu machen, ist auch irgendwie nicht das richtige! :-(
+ v->introducer = 0; v->dbit = 1; v->b = 0;
+ return buflen; anzahl schon erzeugter daten zurückgeben!
+ */
+ }
+ line++; /* sonst die nächste matrixzeile nehmen */
+ continue;
+ } else if ((line % 10) == 5) { /* in zeile 5 stehen nur e-bits ! */
+ if ((m[line] & 0x70) != 0x30) { /* 011 muß am anfang stehen! */
+#ifdef ISDN_V110_DEBUG
+ printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad 5th line\n");
+#endif
+/* dann einen return zu machen, ist auch irgendwie nicht das richtige! :-(
+ v->introducer = 0; v->dbit = 1; v->b = 0;
+ return buflen;
+ */
+ }
+ line++; /* alles klar, nächste zeile */
+ continue;
+ } else if (!introducer) { /* every byte starts with 10 (stopbit, startbit) */
+ introducer = (m[line] & mbit) ? 0 : 1; /* aktuelles bit der matrix */
+ next_byte:
+ if (mbit > 2) { /* war es das letzte bit dieser matrixzeile ? */
+ mbit >>= 1; /* nein, nimm das nächste in dieser zeile */
+ continue;
+ } /* sonst links in der nächsten zeile anfangen */
+ mbit = 64;
+ line++;
+ continue;
+ } else { /* sonst müssen wir ein datenbit setzen */
+ if (m[line] & mbit) /* war das bit in der matrix gesetzt ? */
+ b |= dbit; /* ja, dann setz es auch im datenbyte */
+ else
+ b &= dbit - 1; /* nein, lösch bit im datenbyte */
+ if (dbit < 128) /* haben wir schon ein ganzes byte voll ? */
+ dbit <<= 1; /* nein, auf zum nächsten datenbit */
+ else { /* ein ganzes datenbyte ist voll */
+ buf[buflen++] = b; /* byte in den output buffer kopieren */
+ introducer = b = 0; /* Init der Introsequenz und des datenbytes */
+ dbit = 1; /* als nächstes suchen wir das nullte bit */
+ }
+ goto next_byte; /* suche das nächste bit in der matrix */
+ }
+ }
+ v->introducer = introducer;
+ v->dbit = dbit;
+ v->b = b;
+ return buflen; /* return anzahl der bytes im output buffer */
+}
+
+/* DecodeStream erhält vom input stream V110 kodierte Daten, die zu den
+ V110 frames zusammengepackt werden müssen. Die Daten können an diese
+ Schnittstelle so übergeben werden, wie sie von der Leitung kommen, ohne
+ darauf achten zu müssen, das frames usw. eingehalten werden.
+ */
+struct sk_buff *
+isdn_v110_decode(isdn_v110_stream * v, struct sk_buff *skb)
+{
+ int i;
+ int j;
+ int len;
+ unsigned char *v110_buf;
+ unsigned char *rbuf;
+
+ if (!skb) {
+ printk(KERN_WARNING "isdn_v110_decode called with NULL skb!\n");
+ return NULL;
+ }
+ rbuf = skb->data;
+ len = skb->len;
+ if (v == NULL) {
+ /* invalid handle, no chance to proceed */
+ printk(KERN_WARNING "isdn_v110_decode called with NULL stream!\n");
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+ if (v->decodelen == 0) /* cache empty? */
+ for (; len > 0; len--, rbuf++) /* scan for SyncHeader in buf */
+ if ((*rbuf & v->key) == 0)
+ break; /* found first byte */
+ if (len == 0) {
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+ /* copy new data to decode-buffer */
+ memcpy(&(v->decodebuf[v->decodelen]), rbuf, len);
+ v->decodelen += len;
+ ReSync:
+ if (v->decodelen < v->nbytes) { /* got a new header ? */
+ dev_kfree_skb(skb);
+ return NULL; /* no, try later */
+ }
+ if (ValidHeaderBytes(v) != v->nbytes) { /* ist es ein ungültiger header ? */
+ SyncHeader(v); /* nein, such einen header */
+ goto ReSync;
+ }
+ len = (v->decodelen - (v->decodelen % (10 * v->nbytes))) / v->nbytes;
+ if ((v110_buf = kmalloc(len, GFP_ATOMIC)) == NULL) {
+ printk(KERN_WARNING "isdn_v110_decode: Couldn't allocate v110_buf\n");
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+ for (i = 0; i < len; i++) {
+ v110_buf[i] = 0;
+ for (j = 0; j < v->nbytes; j++)
+ v110_buf[i] |= (v->decodebuf[(i * v->nbytes) + j] & v->key) << (8 - ((j + 1) * v->nbits));
+ v110_buf[i] = FlipBits(v110_buf[i], v->nbits);
+ }
+ v->decodelen = (v->decodelen % (10 * v->nbytes));
+ memcpy(v->decodebuf, &(v->decodebuf[len * v->nbytes]), v->decodelen);
+
+ skb_trim(skb, DecodeMatrix(v, v110_buf, len, skb->data));
+ kfree(v110_buf);
+ if (skb->len)
+ return skb;
+ else {
+ kfree_skb(skb);
+ return NULL;
+ }
+}
+
+/* EncodeMatrix takes input data in buf, len is the bytecount.
+ Data is encoded into v110 frames in m. Return value is the number of
+ matrix-lines generated.
+ */
+static int
+EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
+{
+ int line = 0;
+ int i = 0;
+ int mbit = 128;
+ int dbit = 1;
+ int introducer = 3;
+ int ibit[] = {0, 1, 1};
+
+ while ((i < len) && (line < mlen)) { /* solange noch input da ist */
+ switch (line % 10) { /* in welcher matrixzeile sind wir ? */
+ case 0:
+ m[line++] = 0x00; /* zeile 0 ist immer 0 */
+ mbit = 128; /* und es geht mit dem 7. bit weiter */
+ break;
+ case 5:
+ m[line++] = 0xbf; /* zeile 5 ist immer 10111111 */
+ mbit = 128; /* und es geht mit dem 7. bit weiter */
+ break;
+ }
+ if (line >= mlen) {
+ printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
+ return line;
+ }
+ next_bit:
+ switch (mbit) { /* ganz linkes oder rechtes bit ? */
+ case 1:
+ line++; /* ganz rechts ! dann in die nächste */
+ if (line >= mlen) {
+ printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
+ return line;
+ }
+ case 128:
+ m[line] = 128; /* ganz links byte auf 1000000 setzen */
+ mbit = 64; /* aktuelles bit in der matrixzeile */
+ continue;
+ }
+ if (introducer) { /* 110 sequenz setzen ? */
+ introducer--; /* ein digit weniger setzen */
+ m[line] |= ibit[introducer] ? mbit : 0; /* entsprechendes bit setzen */
+ mbit >>= 1; /* bit der matrixzeile >> 1 */
+ goto next_bit; /* und dort weiter machen */
+ } /* else datenbits in die matrix packen! */
+ m[line] |= (buf[i] & dbit) ? mbit : 0; /* datenbit in matrix setzen */
+ if (dbit == 128) { /* war es das letzte datenbit ? */
+ dbit = 1; /* dann mach beim nächsten weiter */
+ i++; /* nächste datenbyte des input buffers */
+ if (i < len) /* war es schon das letzte ? */
+ introducer = 3; /* nein, schreib den introducer 110 */
+ else { /* war das letzte datenbyte ! */
+ m[line] |= (mbit - 1) & 0xfe; /* setz restliche bits der zeile auf 1 */
+ break;
+ }
+ } else /* nicht das letzte datenbit */
+ dbit <<= 1; /* dann gehe zum nächsten datenbit */
+ mbit >>= 1; /* und setz bit der matrix weiter */
+ goto next_bit;
+
+ }
+ /* evtl. noch restliche zeilen in der matrix generieren... */
+ if ((line) && ((line + 10) < mlen))
+ switch (++line % 10) {
+ case 1:
+ m[line++] = 0xfe;
+ case 2:
+ m[line++] = 0xfe;
+ case 3:
+ m[line++] = 0xfe;
+ case 4:
+ m[line++] = 0xfe;
+ case 5:
+ m[line++] = 0xbf;
+ case 6:
+ m[line++] = 0xfe;
+ case 7:
+ m[line++] = 0xfe;
+ case 8:
+ m[line++] = 0xfe;
+ case 9:
+ m[line++] = 0xfe;
+ }
+ return line; /* soviele matrixzeilen sind es */
+}
+
+/*
+ * Build a sync frame.
+ */
+static struct sk_buff *
+isdn_v110_sync(isdn_v110_stream *v)
+{
+ struct sk_buff *skb;
+
+ if (v == NULL) {
+ /* invalid handle, no chance to proceed */
+ printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
+ return NULL;
+ }
+ if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
+ skb_reserve(skb, v->skbres);
+ memcpy(skb_put(skb, v->framelen), v->OfflineFrame, v->framelen);
+ }
+ return skb;
+}
+
+/*
+ * Build an idle frame.
+ */
+static struct sk_buff *
+isdn_v110_idle(isdn_v110_stream *v)
+{
+ struct sk_buff *skb;
+
+ if (v == NULL) {
+ /* invalid handle, no chance to proceed */
+ printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
+ return NULL;
+ }
+ if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
+ skb_reserve(skb, v->skbres);
+ memcpy(skb_put(skb, v->framelen), v->OnlineFrame, v->framelen);
+ }
+ return skb;
+}
+
+struct sk_buff *
+isdn_v110_encode(isdn_v110_stream * v, struct sk_buff *skb)
+{
+ int i;
+ int j;
+ int rlen;
+ int mlen;
+ int olen;
+ int size;
+ int sval1;
+ int sval2;
+ int nframes;
+ unsigned char *v110buf;
+ unsigned char *rbuf;
+ struct sk_buff *nskb;
+
+ if (v == NULL) {
+ /* invalid handle, no chance to proceed */
+ printk(KERN_WARNING "isdn_v110_encode called with NULL stream!\n");
+ return NULL;
+ }
+ if (!skb) {
+ /* invalid skb, no chance to proceed */
+ printk(KERN_WARNING "isdn_v110_encode called with NULL skb!\n");
+ return NULL;
+ }
+ rlen = skb->len;
+ nframes = (rlen + 3) / 4;
+ v110buf = v->encodebuf;
+ if ((nframes * 40) > v->maxsize) {
+ size = v->maxsize;
+ rlen = v->maxsize / 40;
+ } else
+ size = nframes * 40;
+ if (!(nskb = dev_alloc_skb(size + v->skbres + sizeof(int)))) {
+ printk(KERN_WARNING "isdn_v110_encode: Couldn't alloc skb\n");
+ return NULL;
+ }
+ skb_reserve(nskb, v->skbres + sizeof(int));
+ if (skb->len == 0) {
+ memcpy(skb_put(nskb, v->framelen), v->OnlineFrame, v->framelen);
+ *((int *)skb_push(nskb, sizeof(int))) = 0;
+ return nskb;
+ }
+ mlen = EncodeMatrix(skb->data, rlen, v110buf, size);
+ /* jetzt noch jeweils 2 oder 4 bits auf den output stream verteilen! */
+ rbuf = skb_put(nskb, size);
+ olen = 0;
+ sval1 = 8 - v->nbits;
+ sval2 = v->key << sval1;
+ for (i = 0; i < mlen; i++) {
+ v110buf[i] = FlipBits(v110buf[i], v->nbits);
+ for (j = 0; j < v->nbytes; j++) {
+ if (size--)
+ *rbuf++ = ~v->key | (((v110buf[i] << (j * v->nbits)) & sval2) >> sval1);
+ else {
+ printk(KERN_WARNING "isdn_v110_encode: buffers full!\n");
+ goto buffer_full;
+ }
+ olen++;
+ }
+ }
+buffer_full:
+ skb_trim(nskb, olen);
+ *((int *)skb_push(nskb, sizeof(int))) = rlen;
+ return nskb;
+}
+
+int
+isdn_v110_stat_callback(int idx, isdn_ctrl * c)
+{
+ isdn_v110_stream *v = NULL;
+ int i;
+ int ret;
+
+ if (idx < 0)
+ return 0;
+ switch (c->command) {
+ case ISDN_STAT_BSENT:
+ /* Keep the send-queue of the driver filled
+ * with frames:
+ * If number of outstanding frames < 3,
+ * send down an Idle-Frame (or an Sync-Frame, if
+ * v->SyncInit != 0).
+ */
+ if (!(v = dev->v110[idx]))
+ return 0;
+ atomic_inc(&dev->v110use[idx]);
+ if (v->skbidle > 0) {
+ v->skbidle--;
+ ret = 1;
+ } else {
+ if (v->skbuser > 0)
+ v->skbuser--;
+ ret = 0;
+ }
+ for (i = v->skbuser + v->skbidle; i < 2; i++) {
+ struct sk_buff *skb;
+ if (v->SyncInit > 0)
+ skb = isdn_v110_sync(v);
+ else
+ skb = isdn_v110_idle(v);
+ if (skb) {
+ if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
+ dev_kfree_skb(skb);
+ break;
+ } else {
+ if (v->SyncInit)
+ v->SyncInit--;
+ v->skbidle++;
+ }
+ } else
+ break;
+ }
+ atomic_dec(&dev->v110use[idx]);
+ return ret;
+ case ISDN_STAT_DHUP:
+ case ISDN_STAT_BHUP:
+ while (1) {
+ atomic_inc(&dev->v110use[idx]);
+ if (atomic_dec_and_test(&dev->v110use[idx])) {
+ isdn_v110_close(dev->v110[idx]);
+ dev->v110[idx] = NULL;
+ break;
+ }
+ sti();
+ }
+ break;
+ case ISDN_STAT_BCONN:
+ if (dev->v110emu[idx] && (dev->v110[idx] == NULL)) {
+ int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen;
+ int maxsize = dev->drv[c->driver]->interface->maxbufsize;
+ atomic_inc(&dev->v110use[idx]);
+ switch (dev->v110emu[idx]) {
+ case ISDN_PROTO_L2_V11096:
+ dev->v110[idx] = isdn_v110_open(V110_9600, hdrlen, maxsize);
+ break;
+ case ISDN_PROTO_L2_V11019:
+ dev->v110[idx] = isdn_v110_open(V110_19200, hdrlen, maxsize);
+ break;
+ case ISDN_PROTO_L2_V11038:
+ dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize);
+ break;
+ default:
+ }
+ if ((v = dev->v110[idx])) {
+ while (v->SyncInit) {
+ struct sk_buff *skb = isdn_v110_sync(v);
+ if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
+ dev_kfree_skb(skb);
+ /* Unable to send, try later */
+ break;
+ }
+ v->SyncInit--;
+ v->skbidle++;
+ }
+ } else
+ printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx);
+ atomic_dec(&dev->v110use[idx]);
+ }
+ break;
+ default:
+ return 0;
+ }
+ return 0;
+}
diff --git a/drivers/isdn/isdn_v110.h b/drivers/isdn/isdn_v110.h
new file mode 100644
index 000000000..9ab5a93f3
--- /dev/null
+++ b/drivers/isdn/isdn_v110.h
@@ -0,0 +1,45 @@
+/* $Id: isdn_v110.h,v 1.1 1998/02/20 17:32:11 fritz Exp $
+
+ * Linux ISDN subsystem, V.110 related functions (linklevel).
+ *
+ * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: isdn_v110.h,v $
+ * Revision 1.1 1998/02/20 17:32:11 fritz
+ * First checkin (not yet completely functionable).
+ *
+ */
+#ifndef _isdn_v110_h_
+#define _isdn_v110_h_
+
+/* isdn_v110_encode erhält len Nettodaten in buf, kodiert diese und liefert
+ das Ergebnis wieder in buf. Wieviele Bytes kodiert wurden wird als
+ return zurück gegeben. Diese Daten können dann 1:1 auf die Leitung
+ gegeben werden.
+*/
+extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *);
+
+/* isdn_v110_decode erhält vom input stream V110 kodierte Daten, die zu den
+ V110 frames zusammengepackt werden müssen. Die Daten können an diese
+ Schnittstelle so übergeben werden, wie sie von der Leitung kommen, ohne
+ darauf achten zu müssen, das frames usw. eingehalten werden.
+ */
+extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
+
+extern int isdn_v110_stat_callback(int, isdn_ctrl *);
+
+#endif
diff --git a/drivers/isdn/isdn_x25iface.c b/drivers/isdn/isdn_x25iface.c
new file mode 100644
index 000000000..17d291cdf
--- /dev/null
+++ b/drivers/isdn/isdn_x25iface.c
@@ -0,0 +1,340 @@
+/* $Id: isdn_x25iface.c,v 1.3 1998/02/20 17:25:20 fritz Exp $
+ * stuff needed to support the Linux X.25 PLP code on top of devices that
+ * can provide a lab_b service using the concap_proto mechanism.
+ * This module supports a network interface wich provides lapb_sematics
+ * -- as defined in ../../Documentation/networking/x25-iface.txt -- to
+ * the upper layer and assumes that the lower layer provides a reliable
+ * data link service by means of the the concap_device_ops callbacks.
+ *
+ * Only protocol specific stuff goes here. Device specific stuff
+ * goes to another -- device related -- concap_proto support source file.
+ *
+ * $Log: isdn_x25iface.c,v $
+ * Revision 1.3 1998/02/20 17:25:20 fritz
+ * Changes for recent kernels.
+ *
+ * Revision 1.2 1998/01/31 22:49:22 keil
+ * correct comments
+ *
+ * Revision 1.1 1998/01/31 22:27:58 keil
+ * New files from Henner Eisen for X.25 support
+ *
+ */
+
+/* #include <linux/isdn.h> */
+#include <linux/netdevice.h>
+#include <linux/concap.h>
+#include <linux/wanrouter.h>
+#include "isdn_x25iface.h"
+
+/* for debugging messages not to cause an oops when device pointer is NULL*/
+#define MY_DEVNAME(dev) ( (dev) ? (dev)->name : "DEVICE UNSPECIFIED" )
+
+
+typedef struct isdn_x25iface_proto_data {
+ int magic;
+ enum wan_states state;
+ /* Private stuff, not to be accessed via proto_data. We provide the
+ other storage for the concap_proto instance here as well,
+ enabling us to allocate both with just one kmalloc(): */
+ struct concap_proto priv;
+} ix25_pdata_t;
+
+
+
+/* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */
+void isdn_x25iface_proto_del( struct concap_proto * );
+int isdn_x25iface_proto_close( struct concap_proto * );
+int isdn_x25iface_proto_restart( struct concap_proto *,
+ struct device *,
+ struct concap_device_ops *);
+int isdn_x25iface_xmit( struct concap_proto *, struct sk_buff * );
+int isdn_x25iface_receive( struct concap_proto *, struct sk_buff * );
+int isdn_x25iface_connect_ind( struct concap_proto * );
+int isdn_x25iface_disconn_ind( struct concap_proto * );
+
+
+static struct concap_proto_ops ix25_pops = {
+ &isdn_x25iface_proto_new,
+ &isdn_x25iface_proto_del,
+ &isdn_x25iface_proto_restart,
+ &isdn_x25iface_proto_close,
+ &isdn_x25iface_xmit,
+ &isdn_x25iface_receive,
+ &isdn_x25iface_connect_ind,
+ &isdn_x25iface_disconn_ind
+};
+
+/* error message helper fuction */
+static void illegal_state_warn( unsigned state, unsigned char firstbyte)
+{
+ printk( KERN_WARNING "isdn_x25iface: firstbyte %x illegal in"
+ "current state %d\n",firstbyte, state );
+}
+
+/* check protocol data field for consistency */
+static int pdata_is_bad( ix25_pdata_t * pda ){
+
+ if( pda && pda -> magic == ISDN_X25IFACE_MAGIC ) return 0;
+ printk( KERN_WARNING
+ "isdn_x25iface_xxx: illegal pointer to proto data\n" );
+ return 1;
+}
+
+/* create a new x25 interface protocol instance
+ */
+struct concap_proto * isdn_x25iface_proto_new()
+{
+ ix25_pdata_t * tmp = kmalloc(sizeof(ix25_pdata_t),GFP_KERNEL);
+ IX25DEBUG("isdn_x25iface_proto_new\n");
+ if( tmp ){
+ tmp -> magic = ISDN_X25IFACE_MAGIC;
+ tmp -> state = WAN_UNCONFIGURED;
+ /* private data space used to hold the concap_proto data.
+ Only to be accessed via the returned pointer */
+ tmp -> priv.dops = NULL;
+ tmp -> priv.net_dev = NULL;
+ tmp -> priv.pops = &ix25_pops;
+ tmp -> priv.flags = 0;
+ tmp -> priv.proto_data = tmp;
+ return( &(tmp -> priv) );
+ }
+ return NULL;
+};
+
+/* close the x25iface encapsulation protocol
+ */
+int isdn_x25iface_proto_close(struct concap_proto *cprot){
+
+ ix25_pdata_t *tmp;
+ int ret = 0;
+ ulong flags;
+
+ if( ! cprot ){
+ printk( KERN_ERR "isdn_x25iface_proto_close: "
+ "invalid concap_proto pointer\n" );
+ return -1;
+ }
+ IX25DEBUG( "isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot -> net_dev) );
+ save_flags(flags);
+ cli(); /* avoid races with incoming events calling pops methods while
+ cprot members are inconsistent */
+ cprot -> dops = NULL;
+ cprot -> net_dev = NULL;
+ tmp = cprot -> proto_data;
+ if( pdata_is_bad( tmp ) ){
+ ret = -1;
+ } else {
+ tmp -> state = WAN_UNCONFIGURED;
+ }
+ restore_flags(flags);
+
+ return ret;
+}
+
+/* Delete the x25iface encapsulation protocol instance
+ */
+void isdn_x25iface_proto_del(struct concap_proto *cprot){
+
+ ix25_pdata_t * tmp;
+
+ IX25DEBUG( "isdn_x25iface_proto_del \n" );
+ if( ! cprot ){
+ printk( KERN_ERR "isdn_x25iface_proto_del: "
+ "concap_proto pointer is NULL\n" );
+ return;
+ }
+ tmp = cprot -> proto_data;
+ if( tmp == NULL ){
+ printk( KERN_ERR "isdn_x25iface_proto_del: inconsistent "
+ "proto_data pointer (maybe already deleted?)\n");
+ return;
+ }
+ /* close if the protocol is still open */
+ if( cprot -> dops ) isdn_x25iface_proto_close(cprot);
+ /* freeing the storage should be sufficient now. But some additional
+ settings might help to catch wild pointer bugs */
+ tmp -> magic = 0;
+ cprot -> proto_data = NULL;
+
+ kfree( tmp );
+ return;
+}
+
+/* (re-)initialize the data structures for x25iface encapsulation
+ */
+int isdn_x25iface_proto_restart(struct concap_proto *cprot,
+ struct device *ndev,
+ struct concap_device_ops *dops)
+{
+ ix25_pdata_t * pda = cprot -> proto_data ;
+ ulong flags;
+
+ IX25DEBUG( "isdn_x25iface_proto_restart %s \n", MY_DEVNAME(ndev) );
+
+ if ( pdata_is_bad( pda ) ) return -1;
+
+ if( !( dops && dops -> data_req && dops -> connect_req
+ && dops -> disconn_req ) ){
+ printk( KERN_WARNING "isdn_x25iface_restart: required dops"
+ " missing\n" );
+ isdn_x25iface_proto_close(cprot);
+ return -1;
+ }
+ save_flags(flags);
+ cli(); /* avoid races with incoming events calling pops methods while
+ cprot members are inconsistent */
+ cprot -> net_dev = ndev;
+ cprot -> pops = &ix25_pops;
+ cprot -> dops = dops;
+ pda -> state = WAN_DISCONNECTED;
+ restore_flags(flags);
+ return 0;
+}
+
+/* deliver a dl_data frame received from i4l HL driver to the network layer
+ */
+int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
+{
+ IX25DEBUG( "isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev) );
+ if ( ( (ix25_pdata_t*) (cprot->proto_data) )
+ -> state == WAN_CONNECTED ){
+ skb -> dev = cprot -> net_dev;
+ skb -> protocol = htons(ETH_P_X25);
+ skb -> pkt_type = PACKET_HOST;
+ if( skb_push(skb, 1)){
+ skb -> data[0]=0x00;
+ skb -> mac.raw = skb -> data;
+ netif_rx(skb);
+ return 0;
+ }
+ }
+ printk(KERN_WARNING "isdn_x25iface_receive %s: not connected, skb dropped\n", MY_DEVNAME(cprot->net_dev) );
+ dev_kfree_skb(skb);
+ return -1;
+}
+
+/* a connection set up is indicated by lower layer
+ */
+int isdn_x25iface_connect_ind(struct concap_proto *cprot)
+{
+ struct sk_buff * skb = dev_alloc_skb(1);
+ enum wan_states *state_p
+ = &( ( (ix25_pdata_t*) (cprot->proto_data) ) -> state);
+ IX25DEBUG( "isdn_x25iface_connect_ind %s \n"
+ , MY_DEVNAME(cprot->net_dev) );
+ if( *state_p == WAN_UNCONFIGURED ){
+ printk(KERN_WARNING
+ "isdn_x25iface_connect_ind while unconfigured %s\n"
+ , MY_DEVNAME(cprot->net_dev) );
+ return -1;
+ }
+ *state_p = WAN_CONNECTED;
+ if( skb ){
+ *( skb_put(skb, 1) ) = 0x01;
+ skb -> mac.raw = skb -> data;
+ skb -> dev = cprot -> net_dev;
+ skb -> protocol = htons(ETH_P_X25);
+ skb -> pkt_type = PACKET_HOST;
+ netif_rx(skb);
+ return 0;
+ } else {
+ printk(KERN_WARNING "isdn_x25iface_connect_ind: "
+ " out of memory -- disconnecting\n");
+ cprot -> dops -> disconn_req(cprot);
+ return -1;
+ }
+}
+
+/* a disconnect is indicated by lower layer
+ */
+int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
+{
+ struct sk_buff *skb;
+ enum wan_states *state_p
+ = &( ( (ix25_pdata_t*) (cprot->proto_data) ) -> state);
+ IX25DEBUG( "isdn_x25iface_disconn_ind %s \n", MY_DEVNAME(cprot -> net_dev) );
+ if( *state_p == WAN_UNCONFIGURED ){
+ printk(KERN_WARNING
+ "isdn_x25iface_disconn_ind while unconfigured\n");
+ return -1;
+ }
+ if(! cprot -> net_dev) return -1;
+ *state_p = WAN_DISCONNECTED;
+ skb = dev_alloc_skb(1);
+ if( skb ){
+ *( skb_put(skb, 1) ) = 0x02;
+ skb -> mac.raw = skb -> data;
+ skb -> dev = cprot -> net_dev;
+ skb -> protocol = htons(ETH_P_X25);
+ skb -> pkt_type = PACKET_HOST;
+ netif_rx(skb);
+ return 0;
+ } else {
+ printk(KERN_WARNING "isdn_x25iface_disconn_ind:"
+ " out of memory\n");
+ return -1;
+ }
+}
+
+/* process a frame handed over to us from linux network layer. First byte
+ semantics as defined in ../../Documentation/networking/x25-iface.txt
+ */
+int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
+{
+ unsigned char firstbyte = skb->data[0];
+ unsigned *state =
+ &( ( (ix25_pdata_t*) (cprot -> proto_data) ) -> state );
+ int ret = 0;
+ IX25DEBUG( "isdn_x25iface_xmit: %s first=%x state=%d \n", MY_DEVNAME(cprot -> net_dev), firstbyte, *state );
+ switch ( firstbyte ){
+ case 0x00: /* dl_data request */
+ if( *state == WAN_CONNECTED ){
+ skb_pull(skb, 1);
+ cprot -> net_dev -> trans_start = jiffies;
+ ret = ( cprot -> dops -> data_req(cprot, skb) );
+ /* prepare for future retransmissions */
+ if( ret ) skb_push(skb,1);
+ return ret;
+ }
+ illegal_state_warn( *state, firstbyte );
+ break;
+ case 0x01: /* dl_connect request */
+ if( *state == WAN_DISCONNECTED ){
+ *state = WAN_CONNECTING;
+ cprot -> dops -> connect_req(cprot);
+ } else {
+ illegal_state_warn( *state, firstbyte );
+ }
+ break;
+ case 0x02: /* dl_disconnect request */
+ switch ( *state ){
+ case WAN_DISCONNECTED:
+ /* Should not happen. However, give upper layer a
+ chance to recover from inconstistency but don't
+ trust the lower layer sending the disconn_confirm
+ when already disconnected */
+ printk(KERN_WARNING "isdn_x25iface_xmit: disconnect "
+ " requested while disconnected\n" );
+ isdn_x25iface_disconn_ind(cprot);
+ break; /* prevent infinite loops */
+ case WAN_CONNECTING:
+ case WAN_CONNECTED:
+ *state = WAN_DISCONNECTED;
+ cprot -> dops -> disconn_req(cprot);
+ break;
+ default:
+ illegal_state_warn( *state, firstbyte );
+ }
+ break;
+ case 0x03: /* changing lapb parameters requested */
+ printk(KERN_WARNING "isdn_x25iface_xmit: setting of lapb"
+ " options not yet supported\n");
+ break;
+ default:
+ printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal"
+ " first byte %x ignored:\n", firstbyte);
+ }
+ dev_kfree_skb(skb);
+ return 0;
+}
diff --git a/drivers/isdn/isdn_x25iface.h b/drivers/isdn/isdn_x25iface.h
new file mode 100644
index 000000000..146eeefff
--- /dev/null
+++ b/drivers/isdn/isdn_x25iface.h
@@ -0,0 +1,32 @@
+/* $Id: isdn_x25iface.h,v 1.2 1998/01/31 22:49:23 keil Exp $
+ */
+#ifndef _LINUX_ISDN_X25IFACE_H
+#define _LINUX_ISDN_X25IFACE_H
+
+#define ISDN_X25IFACE_MAGIC 0x1e75a2b9
+/* #define DEBUG_ISDN_X25 if you want isdn_x25 debugging messages */
+#ifdef DEBUG_ISDN_X25
+# define IX25DEBUG(fmt,args...) printk(KERN_DEBUG fmt , ## args)
+#else
+# define IX25DEBUG(fmt,args...)
+#endif
+
+#include <linux/skbuff.h>
+#include <linux/wanrouter.h>
+#include <linux/isdn.h>
+#include <linux/concap.h>
+
+extern struct concap_proto_ops * isdn_x25iface_concap_proto_ops_pt;
+extern struct concap_proto * isdn_x25iface_proto_new(void);
+
+
+
+#endif
+
+
+
+
+
+
+
+
diff --git a/drivers/isdn/isdnloop/.cvsignore b/drivers/isdn/isdnloop/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/drivers/isdn/isdnloop/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/drivers/isdn/isdnloop/Makefile b/drivers/isdn/isdnloop/Makefile
new file mode 100644
index 000000000..588d80760
--- /dev/null
+++ b/drivers/isdn/isdnloop/Makefile
@@ -0,0 +1,11 @@
+L_OBJS :=
+M_OBJS :=
+
+ifeq ($(CONFIG_ISDN_DRV_LOOP),y)
+ L_OBJS += isdnloop.o
+else
+ M_OBJS += isdnloop.o
+endif
+
+include $(TOPDIR)/Rules.make
+
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
new file mode 100644
index 000000000..0235ccb59
--- /dev/null
+++ b/drivers/isdn/isdnloop/isdnloop.c
@@ -0,0 +1,1620 @@
+/* $Id: isdnloop.c,v 1.4 1998/02/24 21:39:05 he Exp $
+
+ * ISDN low-level module implementing a dummy loop driver.
+ *
+ * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: isdnloop.c,v $
+ * Revision 1.4 1998/02/24 21:39:05 he
+ * L2_PROT_X25DTE / DCE
+ * additional state 17 and new internal signal messages "BCON_I"
+ * (for reliable connect confirmation primitive as needed by x.25 upper layer)
+ * Changes for new LL-HL interface
+ *
+ * Revision 1.3 1998/02/20 17:33:30 fritz
+ * Changes for recent kernels.
+ *
+ * Revision 1.2 1997/10/01 09:22:03 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.1 1997/03/24 23:02:04 fritz
+ * Added isdnloop driver.
+ *
+ */
+
+#include <linux/config.h>
+#include "isdnloop.h"
+
+static char
+*revision = "$Revision: 1.4 $";
+
+static int isdnloop_addcard(char *);
+
+/*
+ * Free queue completely.
+ *
+ * Parameter:
+ * card = pointer to card struct
+ * channel = channel number
+ */
+static void
+isdnloop_free_queue(isdnloop_card * card, int channel)
+{
+ struct sk_buff_head *queue = &card->bqueue[channel];
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(queue)))
+ dev_kfree_skb(skb);
+ card->sndcount[channel] = 0;
+}
+
+/*
+ * Send B-Channel data to another virtual card.
+ * This routine is called via timer-callback from isdnloop_pollbchan().
+ *
+ * Parameter:
+ * card = pointer to card struct.
+ * ch = channel number (0-based)
+ */
+static void
+isdnloop_bchan_send(isdnloop_card * card, int ch)
+{
+ isdnloop_card *rcard = card->rcard[ch];
+ int rch = card->rch[ch], len, ack;
+ struct sk_buff *skb;
+ isdn_ctrl cmd;
+
+ while (card->sndcount[ch]) {
+ if ((skb = skb_dequeue(&card->bqueue[ch]))) {
+ len = skb->len;
+ card->sndcount[ch] -= len;
+ ack = *(skb->head); /* used as scratch area */
+ cmd.driver = card->myid;
+ cmd.arg = ch;
+ if (rcard){
+ rcard->interface.rcvcallb_skb(rcard->myid, rch, skb);
+ } else {
+ printk(KERN_WARNING "isdnloop: no rcard, skb dropped\n");
+ dev_kfree_skb(skb);
+
+ cmd.command = ISDN_STAT_L1ERR;
+ cmd.parm.errcode = ISDN_STAT_L1ERR_SEND;
+ card->interface.statcallb(&cmd);
+ };
+ cmd.command = ISDN_STAT_BSENT;
+ cmd.parm.length = len;
+ if ( ack ) card->interface.statcallb(&cmd);
+ } else
+ card->sndcount[ch] = 0;
+ }
+}
+
+/*
+ * Send/Receive Data to/from the B-Channel.
+ * This routine is called via timer-callback.
+ * It schedules itself while any B-Channel is open.
+ *
+ * Parameter:
+ * data = pointer to card struct, set by kernel timer.data
+ */
+static void
+isdnloop_pollbchan(unsigned long data)
+{
+ isdnloop_card *card = (isdnloop_card *) data;
+ unsigned long flags;
+
+ if (card->flags & ISDNLOOP_FLAGS_B1ACTIVE)
+ isdnloop_bchan_send(card, 0);
+ if (card->flags & ISDNLOOP_FLAGS_B2ACTIVE)
+ isdnloop_bchan_send(card, 1);
+ if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) {
+ /* schedule b-channel polling again */
+ save_flags(flags);
+ cli();
+ card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
+ add_timer(&card->rb_timer);
+ card->flags |= ISDNLOOP_FLAGS_RBTIMER;
+ restore_flags(flags);
+ } else
+ card->flags &= ~ISDNLOOP_FLAGS_RBTIMER;
+}
+
+/*
+ * Parse ICN-type setup string and fill fields of setup-struct
+ * with parsed data.
+ *
+ * Parameter:
+ * setup = setup string, format: [caller-id],si1,si2,[called-id]
+ * cmd = pointer to struct to be filled.
+ */
+static void
+isdnloop_parse_setup(char *setup, isdn_ctrl * cmd)
+{
+ char *t = setup;
+ char *s = strpbrk(t, ",");
+
+ *s++ = '\0';
+ strncpy(cmd->parm.setup.phone, t, sizeof(cmd->parm.setup.phone));
+ s = strpbrk(t = s, ",");
+ *s++ = '\0';
+ if (!strlen(t))
+ cmd->parm.setup.si1 = 0;
+ else
+ cmd->parm.setup.si1 = simple_strtoul(t, NULL, 10);
+ s = strpbrk(t = s, ",");
+ *s++ = '\0';
+ if (!strlen(t))
+ cmd->parm.setup.si2 = 0;
+ else
+ cmd->parm.setup.si2 =
+ simple_strtoul(t, NULL, 10);
+ strncpy(cmd->parm.setup.eazmsn, s, sizeof(cmd->parm.setup.eazmsn));
+ cmd->parm.setup.plan = 0;
+ cmd->parm.setup.screen = 0;
+}
+
+typedef struct isdnloop_stat {
+ char *statstr;
+ int command;
+ int action;
+} isdnloop_stat;
+/* *INDENT-OFF* */
+static isdnloop_stat isdnloop_stat_table[] =
+{
+ {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */
+ {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */
+ {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */
+ {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */
+ {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */
+ {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */
+ {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */
+ {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */
+ {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */
+ {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */
+ {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */
+ {"NO D-CHAN", ISDN_STAT_NODCH, 0}, /* No D-channel available */
+ {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
+ {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */
+ {"E_L1: ACTIVATION FAILED",
+ ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
+ {NULL, 0, -1}
+};
+/* *INDENT-ON* */
+
+
+/*
+ * Parse Status message-strings from virtual card.
+ * Depending on status, call statcallb for sending messages to upper
+ * levels. Also set/reset B-Channel active-flags.
+ *
+ * Parameter:
+ * status = status string to parse.
+ * channel = channel where message comes from.
+ * card = card where message comes from.
+ */
+static void
+isdnloop_parse_status(u_char * status, int channel, isdnloop_card * card)
+{
+ isdnloop_stat *s = isdnloop_stat_table;
+ int action = -1;
+ isdn_ctrl cmd;
+
+ while (s->statstr) {
+ if (!strncmp(status, s->statstr, strlen(s->statstr))) {
+ cmd.command = s->command;
+ action = s->action;
+ break;
+ }
+ s++;
+ }
+ if (action == -1)
+ return;
+ cmd.driver = card->myid;
+ cmd.arg = channel;
+ switch (action) {
+ case 1:
+ /* BCON_x */
+ card->flags |= (channel) ?
+ ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE;
+ break;
+ case 2:
+ /* BDIS_x */
+ card->flags &= ~((channel) ?
+ ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE);
+ isdnloop_free_queue(card, channel);
+ break;
+ case 3:
+ /* DCAL_I and DSCA_I */
+ isdnloop_parse_setup(status + 6, &cmd);
+ break;
+ case 4:
+ /* FCALL */
+ sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
+ sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1);
+ cmd.parm.setup.si1 = 7;
+ cmd.parm.setup.si2 = 0;
+ cmd.parm.setup.plan = 0;
+ cmd.parm.setup.screen = 0;
+ break;
+ case 5:
+ /* CIF */
+ strncpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num) - 1);
+ break;
+ case 6:
+ /* AOC */
+ sprintf(cmd.parm.num, "%d",
+ (int) simple_strtoul(status + 7, NULL, 16));
+ break;
+ case 7:
+ /* CAU */
+ status += 3;
+ if (strlen(status) == 4)
+ sprintf(cmd.parm.num, "%s%c%c",
+ status + 2, *status, *(status + 1));
+ else
+ strncpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num) - 1);
+ break;
+ case 8:
+ /* Misc Errors on L1 and L2 */
+ card->flags &= ~ISDNLOOP_FLAGS_B1ACTIVE;
+ isdnloop_free_queue(card, 0);
+ cmd.arg = 0;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = 0;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ cmd.command = ISDN_STAT_BHUP;
+ card->flags &= ~ISDNLOOP_FLAGS_B2ACTIVE;
+ isdnloop_free_queue(card, 1);
+ cmd.arg = 1;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = 1;
+ cmd.driver = card->myid;
+ break;
+ }
+ card->interface.statcallb(&cmd);
+}
+
+/*
+ * Store a cwcharacter into ringbuffer for reading from /dev/isdnctrl
+ *
+ * Parameter:
+ * card = pointer to card struct.
+ * c = char to store.
+ */
+static void
+isdnloop_putmsg(isdnloop_card * card, unsigned char c)
+{
+ ulong flags;
+
+ save_flags(flags);
+ cli();
+ *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
+ if (card->msg_buf_write == card->msg_buf_read) {
+ if (++card->msg_buf_read > card->msg_buf_end)
+ card->msg_buf_read = card->msg_buf;
+ }
+ if (card->msg_buf_write > card->msg_buf_end)
+ card->msg_buf_write = card->msg_buf;
+ restore_flags(flags);
+}
+
+/*
+ * Poll a virtual cards message queue.
+ * If there are new status-replies from the card, copy them to
+ * ringbuffer for reading on /dev/isdnctrl and call
+ * isdnloop_parse_status() for processing them. Watch for special
+ * Firmware bootmessage and parse it, to get the D-Channel protocol.
+ * If there are B-Channels open, initiate a timer-callback to
+ * isdnloop_pollbchan().
+ * This routine is called periodically via timer interrupt.
+ *
+ * Parameter:
+ * data = pointer to card struct
+ */
+static void
+isdnloop_polldchan(unsigned long data)
+{
+ isdnloop_card *card = (isdnloop_card *) data;
+ struct sk_buff *skb;
+ int avail;
+ int left;
+ u_char c;
+ int ch;
+ int flags;
+ u_char *p;
+ isdn_ctrl cmd;
+
+ if ((skb = skb_dequeue(&card->dqueue)))
+ avail = skb->len;
+ else
+ avail = 0;
+ for (left = avail; left > 0; left--) {
+ c = *skb->data;
+ skb_pull(skb, 1);
+ isdnloop_putmsg(card, c);
+ card->imsg[card->iptr] = c;
+ if (card->iptr < 59)
+ card->iptr++;
+ if (!skb->len) {
+ avail++;
+ isdnloop_putmsg(card, '\n');
+ card->imsg[card->iptr] = 0;
+ card->iptr = 0;
+ if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
+ card->imsg[1] <= '2' && card->imsg[2] == ';') {
+ ch = (card->imsg[1] - '0') - 1;
+ p = &card->imsg[3];
+ isdnloop_parse_status(p, ch, card);
+ } else {
+ p = card->imsg;
+ if (!strncmp(p, "DRV1.", 5)) {
+ printk(KERN_INFO "isdnloop: (%s) %s\n", CID, p);
+ if (!strncmp(p + 7, "TC", 2)) {
+ card->ptype = ISDN_PTYPE_1TR6;
+ card->interface.features |= ISDN_FEATURE_P_1TR6;
+ printk(KERN_INFO
+ "isdnloop: (%s) 1TR6-Protocol loaded and running\n", CID);
+ }
+ if (!strncmp(p + 7, "EC", 2)) {
+ card->ptype = ISDN_PTYPE_EURO;
+ card->interface.features |= ISDN_FEATURE_P_EURO;
+ printk(KERN_INFO
+ "isdnloop: (%s) Euro-Protocol loaded and running\n", CID);
+ }
+ continue;
+
+ }
+ }
+ }
+ }
+ if (avail) {
+ cmd.command = ISDN_STAT_STAVAIL;
+ cmd.driver = card->myid;
+ cmd.arg = avail;
+ card->interface.statcallb(&cmd);
+ }
+ if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE))
+ if (!(card->flags & ISDNLOOP_FLAGS_RBTIMER)) {
+ /* schedule b-channel polling */
+ card->flags |= ISDNLOOP_FLAGS_RBTIMER;
+ save_flags(flags);
+ cli();
+ del_timer(&card->rb_timer);
+ card->rb_timer.function = isdnloop_pollbchan;
+ card->rb_timer.data = (unsigned long) card;
+ card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
+ add_timer(&card->rb_timer);
+ restore_flags(flags);
+ }
+ /* schedule again */
+ save_flags(flags);
+ cli();
+ card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD;
+ add_timer(&card->st_timer);
+ restore_flags(flags);
+}
+
+/*
+ * Append a packet to the transmit buffer-queue.
+ *
+ * Parameter:
+ * channel = Number of B-channel
+ * skb = packet to send.
+ * card = pointer to card-struct
+ * Return:
+ * Number of bytes transferred, -E??? on error
+ */
+static int
+isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card * card)
+{
+ int len = skb->len;
+ unsigned long flags;
+ struct sk_buff *nskb;
+
+ if (len > 4000) {
+ printk(KERN_WARNING
+ "isdnloop: Send packet too large\n");
+ return -EINVAL;
+ }
+ if (len) {
+ if (!(card->flags & (channel) ? ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE))
+ return 0;
+ if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE)
+ return 0;
+ save_flags(flags);
+ cli();
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ if (nskb) {
+ skb_queue_tail(&card->bqueue[channel], nskb);
+ dev_kfree_skb(skb);
+ } else
+ len = 0;
+ card->sndcount[channel] += len;
+ restore_flags(flags);
+ }
+ return len;
+}
+
+/*
+ * Read the messages from the card's ringbuffer
+ *
+ * Parameter:
+ * buf = pointer to buffer.
+ * len = number of bytes to read.
+ * user = flag, 1: called from userlevel 0: called from kernel.
+ * card = pointer to card struct.
+ * Return:
+ * number of bytes actually transferred.
+ */
+static int
+isdnloop_readstatus(u_char * buf, int len, int user, isdnloop_card * card)
+{
+ int count;
+ u_char *p;
+
+ for (p = buf, count = 0; count < len; p++, count++) {
+ if (card->msg_buf_read == card->msg_buf_write)
+ return count;
+ if (user)
+ put_user(*card->msg_buf_read++, p);
+ else
+ *p = *card->msg_buf_read++;
+ if (card->msg_buf_read > card->msg_buf_end)
+ card->msg_buf_read = card->msg_buf;
+ }
+ return count;
+}
+
+/*
+ * Simulate a card's response by appending it to the cards
+ * message queue.
+ *
+ * Parameter:
+ * card = pointer to card struct.
+ * s = pointer to message-string.
+ * ch = channel: 0 = generic messages, 1 and 2 = D-channel messages.
+ * Return:
+ * 0 on success, 1 on memory squeeze.
+ */
+static int
+isdnloop_fake(isdnloop_card * card, char *s, int ch)
+{
+ struct sk_buff *skb;
+ int len = strlen(s) + ((ch >= 0) ? 3 : 0);
+
+ if (!(skb = dev_alloc_skb(len))) {
+ printk(KERN_WARNING "isdnloop: Out of memory in isdnloop_fake\n");
+ return 1;
+ }
+ if (ch >= 0)
+ sprintf(skb_put(skb, 3), "%02d;", ch);
+ memcpy(skb_put(skb, strlen(s)), s, strlen(s));
+ skb_queue_tail(&card->dqueue, skb);
+ return 0;
+}
+/* *INDENT-OFF* */
+static isdnloop_stat isdnloop_cmd_table[] =
+{
+ {"BCON_R", 0, 1}, /* B-Channel connect */
+ {"BCON_I", 0, 17}, /* B-Channel connect ind */
+ {"BDIS_R", 0, 2}, /* B-Channel disconnect */
+ {"DDIS_R", 0, 3}, /* D-Channel disconnect */
+ {"DCON_R", 0, 16}, /* D-Channel connect */
+ {"DSCA_R", 0, 4}, /* Dial 1TR6-SPV */
+ {"DCAL_R", 0, 5}, /* Dial */
+ {"EAZC", 0, 6}, /* Clear EAZ listener */
+ {"EAZ", 0, 7}, /* Set EAZ listener */
+ {"SEEAZ", 0, 8}, /* Get EAZ listener */
+ {"MSN", 0, 9}, /* Set/Clear MSN listener */
+ {"MSALL", 0, 10}, /* Set multi MSN listeners */
+ {"SETSIL", 0, 11}, /* Set SI list */
+ {"SEESIL", 0, 12}, /* Get SI list */
+ {"SILC", 0, 13}, /* Clear SI list */
+ {"LOCK", 0, -1}, /* LOCK channel */
+ {"UNLOCK", 0, -1}, /* UNLOCK channel */
+ {"FV2ON", 1, 14}, /* Leased mode on */
+ {"FV2OFF", 1, 15}, /* Leased mode off */
+ {NULL, 0, -1}
+};
+/* *INDENT-ON* */
+
+
+/*
+ * Simulate an error-response from a card.
+ *
+ * Parameter:
+ * card = pointer to card struct.
+ */
+static void
+isdnloop_fake_err(isdnloop_card * card)
+{
+ char buf[60];
+
+ sprintf(buf, "E%s", card->omsg);
+ isdnloop_fake(card, buf, -1);
+ isdnloop_fake(card, "NAK", -1);
+}
+
+static u_char ctable_eu[] =
+{0x00, 0x11, 0x01, 0x12};
+static u_char ctable_1t[] =
+{0x00, 0x3b, 0x01, 0x3a};
+
+/*
+ * Assemble a simplified cause message depending on the
+ * D-channel protocol used.
+ *
+ * Parameter:
+ * card = pointer to card struct.
+ * loc = location: 0 = local, 1 = remote.
+ * cau = cause: 1 = busy, 2 = nonexistent callerid, 3 = no user responding.
+ * Return:
+ * Pointer to buffer containing the assembled message.
+ */
+static char *
+isdnloop_unicause(isdnloop_card * card, int loc, int cau)
+{
+ static char buf[6];
+
+ switch (card->ptype) {
+ case ISDN_PTYPE_EURO:
+ sprintf(buf, "E%02X%02X", (loc) ? 4 : 2, ctable_eu[cau]);
+ break;
+ case ISDN_PTYPE_1TR6:
+ sprintf(buf, "%02X44", ctable_1t[cau]);
+ break;
+ default:
+ return ("0000");
+ }
+ return (buf);
+}
+
+/*
+ * Release a virtual connection. Called from timer interrupt, when
+ * called party did not respond.
+ *
+ * Parameter:
+ * card = pointer to card struct.
+ * ch = channel (0-based)
+ */
+static void
+isdnloop_atimeout(isdnloop_card * card, int ch)
+{
+ unsigned long flags;
+ char buf[60];
+
+ save_flags(flags);
+ cli();
+ if (card->rcard) {
+ isdnloop_fake(card->rcard[ch], "DDIS_I", card->rch[ch] + 1);
+ card->rcard[ch]->rcard[card->rch[ch]] = NULL;
+ card->rcard[ch] = NULL;
+ }
+ isdnloop_fake(card, "DDIS_I", ch + 1);
+ /* No user responding */
+ sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 3));
+ isdnloop_fake(card, buf, ch + 1);
+ restore_flags(flags);
+}
+
+/*
+ * Wrapper for isdnloop_atimeout().
+ */
+static void
+isdnloop_atimeout0(unsigned long data)
+{
+ isdnloop_card *card = (isdnloop_card *) data;
+ isdnloop_atimeout(card, 0);
+}
+
+/*
+ * Wrapper for isdnloop_atimeout().
+ */
+static void
+isdnloop_atimeout1(unsigned long data)
+{
+ isdnloop_card *card = (isdnloop_card *) data;
+ isdnloop_atimeout(card, 1);
+}
+
+/*
+ * Install a watchdog for a user, not responding.
+ *
+ * Parameter:
+ * card = pointer to card struct.
+ * ch = channel to watch for.
+ */
+static void
+isdnloop_start_ctimer(isdnloop_card * card, int ch)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ init_timer(&card->c_timer[ch]);
+ card->c_timer[ch].expires = jiffies + ISDNLOOP_TIMER_ALERTWAIT;
+ if (ch)
+ card->c_timer[ch].function = isdnloop_atimeout1;
+ else
+ card->c_timer[ch].function = isdnloop_atimeout0;
+ card->c_timer[ch].data = (unsigned long) card;
+ add_timer(&card->c_timer[ch]);
+ restore_flags(flags);
+}
+
+/*
+ * Kill a pending channel watchdog.
+ *
+ * Parameter:
+ * card = pointer to card struct.
+ * ch = channel (0-based).
+ */
+static void
+isdnloop_kill_ctimer(isdnloop_card * card, int ch)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ del_timer(&card->c_timer[ch]);
+ restore_flags(flags);
+}
+
+static u_char si2bit[] =
+{0, 1, 0, 0, 0, 2, 0, 4, 0, 0};
+static u_char bit2si[] =
+{1, 5, 7};
+
+/*
+ * Try finding a listener for an outgoing call.
+ *
+ * Parameter:
+ * card = pointer to calling card.
+ * p = pointer to ICN-type setup-string.
+ * lch = channel of calling card.
+ * cmd = pointer to struct to be filled when parsing setup.
+ * Return:
+ * 0 = found match, alerting should happen.
+ * 1 = found matching number but it is busy.
+ * 2 = no matching listener.
+ * 3 = found matching number but SI does not match.
+ */
+static int
+isdnloop_try_call(isdnloop_card * card, char *p, int lch, isdn_ctrl * cmd)
+{
+ isdnloop_card *cc = cards;
+ unsigned long flags;
+ int ch;
+ int num_match;
+ int i;
+ char *e;
+ char nbuf[32];
+
+ isdnloop_parse_setup(p, cmd);
+ while (cc) {
+ for (ch = 0; ch < 2; ch++) {
+ /* Exclude ourself */
+ if ((cc == card) && (ch == lch))
+ continue;
+ num_match = 0;
+ switch (cc->ptype) {
+ case ISDN_PTYPE_EURO:
+ for (i = 0; i < 3; i++)
+ if (!(strcmp(cc->s0num[i], cmd->parm.setup.phone)))
+ num_match = 1;
+ break;
+ case ISDN_PTYPE_1TR6:
+ e = cc->eazlist[ch];
+ while (*e) {
+ sprintf(nbuf, "%s%c", cc->s0num[0], *e);
+ if (!(strcmp(nbuf, cmd->parm.setup.phone)))
+ num_match = 1;
+ e++;
+ }
+ }
+ if (num_match) {
+ save_flags(flags);
+ cli();
+ /* channel idle? */
+ if (!(cc->rcard[ch])) {
+ /* Check SI */
+ if (!(si2bit[cmd->parm.setup.si1] & cc->sil[ch])) {
+ restore_flags(flags);
+ return 3;
+ }
+ /* ch is idle, si and number matches */
+ cc->rcard[ch] = card;
+ cc->rch[ch] = lch;
+ card->rcard[lch] = cc;
+ card->rch[lch] = ch;
+ restore_flags(flags);
+ return 0;
+ } else {
+ restore_flags(flags);
+ /* num matches, but busy */
+ if (ch == 1)
+ return 1;
+ }
+ }
+ }
+ cc = cc->next;
+ }
+ return 2;
+}
+
+/*
+ * Depending on D-channel protocol and caller/called, modify
+ * phone number.
+ *
+ * Parameter:
+ * card = pointer to card struct.
+ * phone = pointer phone number.
+ * caller = flag: 1 = caller, 0 = called.
+ * Return:
+ * pointer to new phone number.
+ */
+static char *
+isdnloop_vstphone(isdnloop_card * card, char *phone, int caller)
+{
+ int i;
+ static char nphone[30];
+
+ switch (card->ptype) {
+ case ISDN_PTYPE_EURO:
+ if (caller) {
+ for (i = 0; i < 2; i++)
+ if (!(strcmp(card->s0num[i], phone)))
+ return (phone);
+ return (card->s0num[0]);
+ }
+ return (phone);
+ break;
+ case ISDN_PTYPE_1TR6:
+ if (caller) {
+ sprintf(nphone, "%s%c", card->s0num[0], phone[0]);
+ return (nphone);
+ } else
+ return (&phone[strlen(phone) - 1]);
+ break;
+ }
+ return ("\0");
+}
+
+/*
+ * Parse an ICN-type command string sent to the 'card'.
+ * Perform misc. actions depending on the command.
+ *
+ * Parameter:
+ * card = pointer to card struct.
+ */
+static void
+isdnloop_parse_cmd(isdnloop_card * card)
+{
+ char *p = card->omsg;
+ isdn_ctrl cmd;
+ char buf[60];
+ isdnloop_stat *s = isdnloop_cmd_table;
+ int action = -1;
+ int i;
+ int ch;
+
+ if ((card->omsg[0] != '0') && (card->omsg[2] != ';')) {
+ isdnloop_fake_err(card);
+ return;
+ }
+ ch = card->omsg[1] - '0';
+ if ((ch < 0) || (ch > 2)) {
+ isdnloop_fake_err(card);
+ return;
+ }
+ p += 3;
+ while (s->statstr) {
+ if (!strncmp(p, s->statstr, strlen(s->statstr))) {
+ action = s->action;
+ if (s->command && (ch != 0)) {
+ isdnloop_fake_err(card);
+ return;
+ }
+ break;
+ }
+ s++;
+ }
+ if (action == -1)
+ return;
+ switch (action) {
+ case 1:
+ /* 0x;BCON_R */
+ if (card->rcard[ch - 1]) {
+ isdnloop_fake(card->rcard[ch - 1], "BCON_I",
+ card->rch[ch - 1] + 1);
+ }
+ break;
+ case 17:
+ /* 0x;BCON_I */
+ if (card->rcard[ch - 1]) {
+ isdnloop_fake(card->rcard[ch - 1], "BCON_C",
+ card->rch[ch - 1] + 1);
+ }
+ break;
+ case 2:
+ /* 0x;BDIS_R */
+ isdnloop_fake(card, "BDIS_C", ch);
+ if (card->rcard[ch - 1]) {
+ isdnloop_fake(card->rcard[ch - 1], "BDIS_I",
+ card->rch[ch - 1] + 1);
+ }
+ break;
+ case 16:
+ /* 0x;DCON_R */
+ isdnloop_kill_ctimer(card, ch - 1);
+ if (card->rcard[ch - 1]) {
+ isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]);
+ isdnloop_fake(card->rcard[ch - 1], "DCON_C",
+ card->rch[ch - 1] + 1);
+ isdnloop_fake(card, "DCON_C", ch);
+ }
+ break;
+ case 3:
+ /* 0x;DDIS_R */
+ isdnloop_kill_ctimer(card, ch - 1);
+ if (card->rcard[ch - 1]) {
+ isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]);
+ isdnloop_fake(card->rcard[ch - 1], "DDIS_I",
+ card->rch[ch - 1] + 1);
+ card->rcard[ch - 1] = NULL;
+ }
+ isdnloop_fake(card, "DDIS_C", ch);
+ break;
+ case 4:
+ /* 0x;DSCA_Rdd,yy,zz,oo */
+ if (card->ptype != ISDN_PTYPE_1TR6) {
+ isdnloop_fake_err(card);
+ return;
+ }
+ /* Fall through */
+ case 5:
+ /* 0x;DCAL_Rdd,yy,zz,oo */
+ p += 6;
+ switch (isdnloop_try_call(card, p, ch - 1, &cmd)) {
+ case 0:
+ /* Alerting */
+ sprintf(buf, "D%s_I%s,%02d,%02d,%s",
+ (action == 4) ? "SCA" : "CAL",
+ isdnloop_vstphone(card, cmd.parm.setup.eazmsn, 1),
+ cmd.parm.setup.si1,
+ cmd.parm.setup.si2,
+ isdnloop_vstphone(card->rcard[ch],
+ cmd.parm.setup.phone, 0));
+ isdnloop_fake(card->rcard[ch - 1], buf, card->rch[ch - 1] + 1);
+ /* Fall through */
+ case 3:
+ /* si1 does not match, dont alert but start timer */
+ isdnloop_start_ctimer(card, ch - 1);
+ break;
+ case 1:
+ /* Remote busy */
+ isdnloop_fake(card, "DDIS_I", ch);
+ sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 1));
+ isdnloop_fake(card, buf, ch);
+ break;
+ case 2:
+ /* No such user */
+ isdnloop_fake(card, "DDIS_I", ch);
+ sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 2));
+ isdnloop_fake(card, buf, ch);
+ break;
+ }
+ break;
+ case 6:
+ /* 0x;EAZC */
+ card->eazlist[ch - 1][0] = '\0';
+ break;
+ case 7:
+ /* 0x;EAZ */
+ p += 3;
+ strcpy(card->eazlist[ch - 1], p);
+ break;
+ case 8:
+ /* 0x;SEEAZ */
+ sprintf(buf, "EAZ-LIST: %s", card->eazlist[ch - 1]);
+ isdnloop_fake(card, buf, ch + 1);
+ break;
+ case 9:
+ /* 0x;MSN */
+ break;
+ case 10:
+ /* 0x;MSNALL */
+ break;
+ case 11:
+ /* 0x;SETSIL */
+ p += 6;
+ i = 0;
+ while (strchr("0157", *p)) {
+ if (i)
+ card->sil[ch - 1] |= si2bit[*p - '0'];
+ i = (*p++ == '0');
+ }
+ if (*p)
+ isdnloop_fake_err(card);
+ break;
+ case 12:
+ /* 0x;SEESIL */
+ sprintf(buf, "SIN-LIST: ");
+ p = buf + 10;
+ for (i = 0; i < 3; i++)
+ if (card->sil[ch - 1] & (1 << i))
+ p += sprintf(p, "%02d", bit2si[i]);
+ isdnloop_fake(card, buf, ch + 1);
+ break;
+ case 13:
+ /* 0x;SILC */
+ card->sil[ch - 1] = 0;
+ break;
+ case 14:
+ /* 00;FV2ON */
+ break;
+ case 15:
+ /* 00;FV2OFF */
+ break;
+ }
+}
+
+/*
+ * Put command-strings into the of the 'card'. In reality, execute them
+ * right in place by calling isdnloop_parse_cmd(). Also copy every
+ * command to the read message ringbuffer, preceeding it with a '>'.
+ * These mesagges can be read at /dev/isdnctrl.
+ *
+ * Parameter:
+ * buf = pointer to command buffer.
+ * len = length of buffer data.
+ * user = flag: 1 = called form userlevel, 0 called from kernel.
+ * card = pointer to card struct.
+ * Return:
+ * number of bytes transfered (currently always equals len).
+ */
+static int
+isdnloop_writecmd(const u_char * buf, int len, int user, isdnloop_card * card)
+{
+ int xcount = 0;
+ int ocount = 1;
+ isdn_ctrl cmd;
+
+ while (len) {
+ int count = MIN(255, len);
+ u_char *p;
+ u_char msg[0x100];
+
+ if (user)
+ copy_from_user(msg, buf, count);
+ else
+ memcpy(msg, buf, count);
+ isdnloop_putmsg(card, '>');
+ for (p = msg; count > 0; count--, p++) {
+ len--;
+ xcount++;
+ isdnloop_putmsg(card, *p);
+ card->omsg[card->optr] = *p;
+ if (*p == '\n') {
+ card->omsg[card->optr] = '\0';
+ card->optr = 0;
+ isdnloop_parse_cmd(card);
+ if (len) {
+ isdnloop_putmsg(card, '>');
+ ocount++;
+ }
+ } else {
+ if (card->optr < 59)
+ card->optr++;
+ }
+ ocount++;
+ }
+ }
+ cmd.command = ISDN_STAT_STAVAIL;
+ cmd.driver = card->myid;
+ cmd.arg = ocount;
+ card->interface.statcallb(&cmd);
+ return xcount;
+}
+
+/*
+ * Delete card's pending timers, send STOP to linklevel
+ */
+static void
+isdnloop_stopcard(isdnloop_card * card)
+{
+ unsigned long flags;
+ isdn_ctrl cmd;
+
+ save_flags(flags);
+ cli();
+ if (card->flags & ISDNLOOP_FLAGS_RUNNING) {
+ card->flags &= ~ISDNLOOP_FLAGS_RUNNING;
+ del_timer(&card->st_timer);
+ del_timer(&card->rb_timer);
+ del_timer(&card->c_timer[0]);
+ del_timer(&card->c_timer[1]);
+ cmd.command = ISDN_STAT_STOP;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ }
+ restore_flags(flags);
+}
+
+/*
+ * Stop all cards before unload.
+ */
+static void
+isdnloop_stopallcards(void)
+{
+ isdnloop_card *p = cards;
+
+ while (p) {
+ isdnloop_stopcard(p);
+ p = p->next;
+ }
+}
+
+/*
+ * Start a 'card'. Simulate card's boot message and set the phone
+ * number(s) of the virtual 'S0-Interface'. Install D-channel
+ * poll timer.
+ *
+ * Parameter:
+ * card = pointer to card struct.
+ * sdefp = pointer to struct holding ioctl parameters.
+ * Return:
+ * 0 on success, -E??? otherwise.
+ */
+static int
+isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp)
+{
+ unsigned long flags;
+ isdnloop_sdef sdef;
+ int i;
+
+ if (card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -EBUSY;
+ copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef));
+ save_flags(flags);
+ cli();
+ switch (sdef.ptype) {
+ case ISDN_PTYPE_EURO:
+ if (isdnloop_fake(card, "DRV1.23EC-Q.931-CAPI-CNS-BASIS-20.02.96",
+ -1)) {
+ restore_flags(flags);
+ return -ENOMEM;
+ }
+ card->sil[0] = card->sil[1] = 4;
+ if (isdnloop_fake(card, "TEI OK", 0)) {
+ restore_flags(flags);
+ return -ENOMEM;
+ }
+ for (i = 0; i < 3; i++)
+ strcpy(card->s0num[i], sdef.num[i]);
+ break;
+ case ISDN_PTYPE_1TR6:
+ if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95",
+ -1)) {
+ restore_flags(flags);
+ return -ENOMEM;
+ }
+ card->sil[0] = card->sil[1] = 4;
+ if (isdnloop_fake(card, "TEI OK", 0)) {
+ restore_flags(flags);
+ return -ENOMEM;
+ }
+ strcpy(card->s0num[0], sdef.num[0]);
+ card->s0num[1][0] = '\0';
+ card->s0num[2][0] = '\0';
+ break;
+ default:
+ restore_flags(flags);
+ printk(KERN_WARNING "isdnloop: Illegal D-channel protocol %d\n",
+ sdef.ptype);
+ return -EINVAL;
+ }
+ init_timer(&card->st_timer);
+ card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD;
+ card->st_timer.function = isdnloop_polldchan;
+ card->st_timer.data = (unsigned long) card;
+ add_timer(&card->st_timer);
+ card->flags |= ISDNLOOP_FLAGS_RUNNING;
+ restore_flags(flags);
+ return 0;
+}
+
+/*
+ * Main handler for commands sent by linklevel.
+ */
+static int
+isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
+{
+ ulong a;
+ int i;
+ char cbuf[60];
+ isdn_ctrl cmd;
+ isdnloop_cdef cdef;
+
+ switch (c->command) {
+ case ISDN_CMD_IOCTL:
+ memcpy(&a, c->parm.num, sizeof(ulong));
+ switch (c->arg) {
+ case ISDNLOOP_IOCTL_DEBUGVAR:
+ return (ulong) card;
+ case ISDNLOOP_IOCTL_STARTUP:
+ if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(isdnloop_sdef))))
+ return i;
+ return (isdnloop_start(card, (isdnloop_sdef *) a));
+ break;
+ case ISDNLOOP_IOCTL_ADDCARD:
+ if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(isdnloop_cdef))))
+ return i;
+ copy_from_user((char *) &cdef, (char *) a, sizeof(cdef));
+ return (isdnloop_addcard(cdef.id1));
+ break;
+ case ISDNLOOP_IOCTL_LEASEDCFG:
+ if (a) {
+ if (!card->leased) {
+ card->leased = 1;
+ while (card->ptype == ISDN_PTYPE_UNKNOWN) {
+ current->timeout = jiffies + 10;
+ schedule();
+ }
+ current->timeout = jiffies + 10;
+ schedule();
+ sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n");
+ i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+ printk(KERN_INFO
+ "isdnloop: (%s) Leased-line mode enabled\n",
+ CID);
+ cmd.command = ISDN_STAT_RUN;
+ cmd.driver = card->myid;
+ cmd.arg = 0;
+ card->interface.statcallb(&cmd);
+ }
+ } else {
+ if (card->leased) {
+ card->leased = 0;
+ sprintf(cbuf, "00;FV2OFF\n");
+ i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+ printk(KERN_INFO
+ "isdnloop: (%s) Leased-line mode disabled\n",
+ CID);
+ cmd.command = ISDN_STAT_RUN;
+ cmd.driver = card->myid;
+ cmd.arg = 0;
+ card->interface.statcallb(&cmd);
+ }
+ }
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case ISDN_CMD_DIAL:
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ if (card->leased)
+ break;
+ if ((c->arg & 255) < ISDNLOOP_BCH) {
+ char *p;
+ char dial[50];
+ char dcode[4];
+
+ a = c->arg;
+ p = c->parm.setup.phone;
+ if (*p == 's' || *p == 'S') {
+ /* Dial for SPV */
+ p++;
+ strcpy(dcode, "SCA");
+ } else
+ /* Normal Dial */
+ strcpy(dcode, "CAL");
+ strcpy(dial, p);
+ sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
+ dcode, dial, c->parm.setup.si1,
+ c->parm.setup.si2, c->parm.setup.eazmsn);
+ i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+ }
+ break;
+ case ISDN_CMD_ACCEPTD:
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ if (c->arg < ISDNLOOP_BCH) {
+ a = c->arg + 1;
+ cbuf[0] = 0;
+ switch (card->l2_proto[a - 1]) {
+ case ISDN_PROTO_L2_X75I:
+ sprintf(cbuf, "%02d;BX75\n", (int) a);
+ break;
+#ifdef CONFIG_ISDN_X25
+ case ISDN_PROTO_L2_X25DTE:
+ sprintf(cbuf, "%02d;BX2T\n", (int) a);
+ break;
+ case ISDN_PROTO_L2_X25DCE:
+ sprintf(cbuf, "%02d;BX2C\n", (int) a);
+ break;
+#endif
+ case ISDN_PROTO_L2_HDLC:
+ sprintf(cbuf, "%02d;BTRA\n", (int) a);
+ break;
+ }
+ if (strlen(cbuf))
+ i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+ sprintf(cbuf, "%02d;DCON_R\n", (int) a);
+ i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+ }
+ break;
+ case ISDN_CMD_ACCEPTB:
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ if (c->arg < ISDNLOOP_BCH) {
+ a = c->arg + 1;
+ switch (card->l2_proto[a - 1]) {
+ case ISDN_PROTO_L2_X75I:
+ sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
+ break;
+#ifdef CONFIG_ISDN_X25
+ case ISDN_PROTO_L2_X25DTE:
+ sprintf(cbuf, "%02d;BCON_R,BX2T\n", (int) a);
+ break;
+ case ISDN_PROTO_L2_X25DCE:
+ sprintf(cbuf, "%02d;BCON_R,BX2C\n", (int) a);
+ break;
+#endif
+ case ISDN_PROTO_L2_HDLC:
+ sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
+ break;
+ default:
+ sprintf(cbuf, "%02d;BCON_R\n", (int) a);
+ }
+ printk(KERN_DEBUG "isdnloop writecmd '%s'\n", cbuf);
+ i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+ break;
+ case ISDN_CMD_HANGUP:
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ if (c->arg < ISDNLOOP_BCH) {
+ a = c->arg + 1;
+ sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
+ i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+ }
+ break;
+ case ISDN_CMD_SETEAZ:
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ if (card->leased)
+ break;
+ if (c->arg < ISDNLOOP_BCH) {
+ a = c->arg + 1;
+ if (card->ptype == ISDN_PTYPE_EURO) {
+ sprintf(cbuf, "%02d;MS%s%s\n", (int) a,
+ c->parm.num[0] ? "N" : "ALL", c->parm.num);
+ } else
+ sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
+ c->parm.num[0] ? c->parm.num : "0123456789");
+ i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+ }
+ break;
+ case ISDN_CMD_CLREAZ:
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ if (card->leased)
+ break;
+ if (c->arg < ISDNLOOP_BCH) {
+ a = c->arg + 1;
+ if (card->ptype == ISDN_PTYPE_EURO)
+ sprintf(cbuf, "%02d;MSNC\n", (int) a);
+ else
+ sprintf(cbuf, "%02d;EAZC\n", (int) a);
+ i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+ }
+ break;
+ case ISDN_CMD_SETL2:
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ if ((c->arg & 255) < ISDNLOOP_BCH) {
+ a = c->arg;
+ switch (a >> 8) {
+ case ISDN_PROTO_L2_X75I:
+ sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
+ break;
+#ifdef CONFIG_ISDN_X25
+ case ISDN_PROTO_L2_X25DTE:
+ sprintf(cbuf, "%02d;BX2T\n", (int) (a & 255) + 1);
+ break;
+ case ISDN_PROTO_L2_X25DCE:
+ sprintf(cbuf, "%02d;BX2C\n", (int) (a & 255) + 1);
+ break;
+#endif
+ case ISDN_PROTO_L2_HDLC:
+ sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+ card->l2_proto[a & 255] = (a >> 8);
+ }
+ break;
+ case ISDN_CMD_GETL2:
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ if ((c->arg & 255) < ISDNLOOP_BCH)
+ return card->l2_proto[c->arg & 255];
+ else
+ return -ENODEV;
+ case ISDN_CMD_SETL3:
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ return 0;
+ case ISDN_CMD_GETL3:
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ if ((c->arg & 255) < ISDNLOOP_BCH)
+ return ISDN_PROTO_L3_TRANS;
+ else
+ return -ENODEV;
+ case ISDN_CMD_GETEAZ:
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ break;
+ case ISDN_CMD_SETSIL:
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ break;
+ case ISDN_CMD_GETSIL:
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ break;
+ case ISDN_CMD_LOCK:
+ MOD_INC_USE_COUNT;
+ break;
+ case ISDN_CMD_UNLOCK:
+ MOD_DEC_USE_COUNT;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Find card with given driverId
+ */
+static inline isdnloop_card *
+isdnloop_findcard(int driverid)
+{
+ isdnloop_card *p = cards;
+
+ while (p) {
+ if (p->myid == driverid)
+ return p;
+ p = p->next;
+ }
+ return (isdnloop_card *) 0;
+}
+
+/*
+ * Wrapper functions for interface to linklevel
+ */
+static int
+if_command(isdn_ctrl * c)
+{
+ isdnloop_card *card = isdnloop_findcard(c->driver);
+
+ if (card)
+ return (isdnloop_command(c, card));
+ printk(KERN_ERR
+ "isdnloop: if_command called with invalid driverId!\n");
+ return -ENODEV;
+}
+
+static int
+if_writecmd(const u_char * buf, int len, int user, int id, int channel)
+{
+ isdnloop_card *card = isdnloop_findcard(id);
+
+ if (card) {
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ return (isdnloop_writecmd(buf, len, user, card));
+ }
+ printk(KERN_ERR
+ "isdnloop: if_writecmd called with invalid driverId!\n");
+ return -ENODEV;
+}
+
+static int
+if_readstatus(u_char * buf, int len, int user, int id, int channel)
+{
+ isdnloop_card *card = isdnloop_findcard(id);
+
+ if (card) {
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ return (isdnloop_readstatus(buf, len, user, card));
+ }
+ printk(KERN_ERR
+ "isdnloop: if_readstatus called with invalid driverId!\n");
+ return -ENODEV;
+}
+
+static int
+if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
+{
+ isdnloop_card *card = isdnloop_findcard(id);
+
+ if (card) {
+ if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ return -ENODEV;
+ /* ack request stored in skb scratch area */
+ *(skb->head) = ack;
+ return (isdnloop_sendbuf(channel, skb, card));
+ }
+ printk(KERN_ERR
+ "isdnloop: if_sendbuf called with invalid driverId!\n");
+ return -ENODEV;
+}
+
+/*
+ * Allocate a new card-struct, initialize it
+ * link it into cards-list and register it at linklevel.
+ */
+static isdnloop_card *
+isdnloop_initcard(char *id)
+{
+ isdnloop_card *card;
+ int i;
+
+ if (!(card = (isdnloop_card *) kmalloc(sizeof(isdnloop_card), GFP_KERNEL))) {
+ printk(KERN_WARNING
+ "isdnloop: (%s) Could not allocate card-struct.\n", id);
+ return (isdnloop_card *) 0;
+ }
+ memset((char *) card, 0, sizeof(isdnloop_card));
+ card->interface.channels = ISDNLOOP_BCH;
+ card->interface.hl_hdrlen = 1; /* scratch area for storing ack flag*/
+ card->interface.maxbufsize = 4000;
+ card->interface.command = if_command;
+ card->interface.writebuf_skb = if_sendbuf;
+ card->interface.writecmd = if_writecmd;
+ card->interface.readstat = if_readstatus;
+ card->interface.features = ISDN_FEATURE_L2_X75I |
+#ifdef CONFIG_ISDN_X25
+ ISDN_FEATURE_L2_X25DTE |
+ ISDN_FEATURE_L2_X25DCE |
+#endif
+ ISDN_FEATURE_L2_HDLC |
+ ISDN_FEATURE_L3_TRANS |
+ ISDN_FEATURE_P_UNKNOWN;
+ card->ptype = ISDN_PTYPE_UNKNOWN;
+ strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
+ card->msg_buf_write = card->msg_buf;
+ card->msg_buf_read = card->msg_buf;
+ card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
+ for (i = 0; i < ISDNLOOP_BCH; i++) {
+ card->l2_proto[i] = ISDN_PROTO_L2_X75I;
+ skb_queue_head_init(&card->bqueue[i]);
+ }
+ skb_queue_head_init(&card->dqueue);
+ card->next = cards;
+ cards = card;
+ if (!register_isdn(&card->interface)) {
+ cards = cards->next;
+ printk(KERN_WARNING
+ "isdnloop: Unable to register %s\n", id);
+ kfree(card);
+ return (isdnloop_card *) 0;
+ }
+ card->myid = card->interface.channels;
+ return card;
+}
+
+static int
+isdnloop_addcard(char *id1)
+{
+ ulong flags;
+ isdnloop_card *card;
+
+ save_flags(flags);
+ cli();
+ if (!(card = isdnloop_initcard(id1))) {
+ restore_flags(flags);
+ return -EIO;
+ }
+ restore_flags(flags);
+ printk(KERN_INFO
+ "isdnloop: (%s) virtual card added\n",
+ card->interface.id);
+ return 0;
+}
+
+#ifdef MODULE
+#define isdnloop_init init_module
+#else
+void
+isdnloop_setup(char *str, int *ints)
+{
+ static char sid[20];
+
+ if (strlen(str)) {
+ strcpy(sid, str);
+ isdnloop_id = sid;
+ }
+}
+#endif
+
+int
+isdnloop_init(void)
+{
+ char *p;
+ char rev[10];
+
+ /* No symbols to export, hide all symbols */
+ EXPORT_NO_SYMBOLS;
+
+ if ((p = strchr(revision, ':'))) {
+ strcpy(rev, p + 1);
+ p = strchr(rev, '$');
+ *p = 0;
+ } else
+ strcpy(rev, " ??? ");
+ printk(KERN_NOTICE "isdnloop-ISDN-driver Rev%s\n", rev);
+ return (isdnloop_addcard(isdnloop_id));
+}
+
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+ isdn_ctrl cmd;
+ isdnloop_card *card = cards;
+ isdnloop_card *last;
+ int i;
+
+ isdnloop_stopallcards();
+ while (card) {
+ cmd.command = ISDN_STAT_UNLOAD;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ for (i = 0; i < ISDNLOOP_BCH; i++)
+ isdnloop_free_queue(card, i);
+ card = card->next;
+ }
+ card = cards;
+ while (card) {
+ struct sk_buff *skb;
+
+ last = card;
+ while ((skb = skb_dequeue(&card->dqueue)))
+ dev_kfree_skb(skb);
+ card = card->next;
+ kfree(last);
+ }
+ printk(KERN_NOTICE "isdnloop-ISDN-driver unloaded\n");
+}
+#endif
diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h
new file mode 100644
index 000000000..cacd686d7
--- /dev/null
+++ b/drivers/isdn/isdnloop/isdnloop.h
@@ -0,0 +1,144 @@
+/* $Id: isdnloop.h,v 1.2 1997/10/01 09:22:07 fritz Exp $
+
+ * Loopback lowlevel module for testing of linklevel.
+ *
+ * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: isdnloop.h,v $
+ * Revision 1.2 1997/10/01 09:22:07 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.1 1997/03/24 23:02:05 fritz
+ * Added isdnloop driver.
+ *
+ */
+
+#ifndef isdnloop_h
+#define isdnloop_h
+
+#define ISDNLOOP_IOCTL_DEBUGVAR 0
+#define ISDNLOOP_IOCTL_ADDCARD 1
+#define ISDNLOOP_IOCTL_LEASEDCFG 2
+#define ISDNLOOP_IOCTL_STARTUP 3
+
+/* Struct for adding new cards */
+typedef struct isdnloop_cdef {
+ char id1[10];
+} isdnloop_cdef;
+
+/* Struct for configuring cards */
+typedef struct isdnloop_sdef {
+ int ptype;
+ char num[3][20];
+} isdnloop_sdef;
+
+#if defined(__KERNEL__) || defined(__DEBUGVAR__)
+
+#ifdef __KERNEL__
+/* Kernel includes */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/isdnif.h>
+
+#endif /* __KERNEL__ */
+
+#define ISDNLOOP_FLAGS_B1ACTIVE 1 /* B-Channel-1 is open */
+#define ISDNLOOP_FLAGS_B2ACTIVE 2 /* B-Channel-2 is open */
+#define ISDNLOOP_FLAGS_RUNNING 4 /* Cards driver activated */
+#define ISDNLOOP_FLAGS_RBTIMER 8 /* scheduling of B-Channel-poll */
+#define ISDNLOOP_TIMER_BCREAD 1 /* B-Channel poll-cycle */
+#define ISDNLOOP_TIMER_DCREAD (HZ/2) /* D-Channel poll-cycle */
+#define ISDNLOOP_TIMER_ALERTWAIT (10*HZ) /* Alert timeout */
+#define ISDNLOOP_MAX_SQUEUE 65536 /* Max. outstanding send-data */
+#define ISDNLOOP_BCH 2 /* channels per card */
+
+/*
+ * Per card driver data
+ */
+typedef struct isdnloop_card {
+ struct isdnloop_card *next; /* Pointer to next device struct */
+ struct isdnloop_card
+ *rcard[ISDNLOOP_BCH]; /* Pointer to 'remote' card */
+ int rch[ISDNLOOP_BCH]; /* 'remote' channel */
+ int myid; /* Driver-Nr. assigned by linklevel */
+ int leased; /* Flag: This Adapter is connected */
+ /* to a leased line */
+ int sil[ISDNLOOP_BCH]; /* SI's to listen for */
+ char eazlist[ISDNLOOP_BCH][11];
+ /* EAZ's to listen for */
+ char s0num[3][20]; /* 1TR6 base-number or MSN's */
+ unsigned short flags; /* Statusflags */
+ int ptype; /* Protocol type (1TR6 or Euro) */
+ struct timer_list st_timer; /* Timer for Status-Polls */
+ struct timer_list rb_timer; /* Timer for B-Channel-Polls */
+ struct timer_list
+ c_timer[ISDNLOOP_BCH]; /* Timer for Alerting */
+ int l2_proto[ISDNLOOP_BCH]; /* Current layer-2-protocol */
+ isdn_if interface; /* Interface to upper layer */
+ int iptr; /* Index to imsg-buffer */
+ char imsg[60]; /* Internal buf for status-parsing */
+ int optr; /* Index to omsg-buffer */
+ char omsg[60]; /* Internal buf for cmd-parsing */
+ char msg_buf[2048]; /* Buffer for status-messages */
+ char *msg_buf_write; /* Writepointer for statusbuffer */
+ char *msg_buf_read; /* Readpointer for statusbuffer */
+ char *msg_buf_end; /* Pointer to end of statusbuffer */
+ int sndcount[ISDNLOOP_BCH]; /* Byte-counters for B-Ch.-send */
+ struct sk_buff_head
+ bqueue[ISDNLOOP_BCH]; /* B-Channel queues */
+ struct sk_buff_head dqueue; /* D-Channel queue */
+} isdnloop_card;
+
+/*
+ * Main driver data
+ */
+#ifdef __KERNEL__
+static isdnloop_card *cards = (isdnloop_card *) 0;
+static char *isdnloop_id = "\0";
+
+#ifdef MODULE
+MODULE_AUTHOR("Fritz Elfert");
+MODULE_PARM(isdnloop_id, "s");
+MODULE_PARM_DESC(isdnloop_id, "ID-String of first card");
+#endif
+
+#endif /* __KERNEL__ */
+
+/* Utility-Macros */
+
+#define CID (card->interface.id)
+#define MIN(a,b) ((a<b)?a:b)
+#define MAX(a,b) ((a>b)?a:b)
+
+#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
+#endif /* isdnloop_h */
diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c
index 790da8792..ed681f375 100644
--- a/drivers/isdn/pcbit/capi.c
+++ b/drivers/isdn/pcbit/capi.c
@@ -147,9 +147,6 @@ int capi_conn_resp(struct pcbit_chan* chan, struct sk_buff **skb)
return -1;
}
- SET_SKB_FREE((*skb));
-
-
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
*(skb_put(*skb, 1)) = 0x01; /* ACCEPT_CALL */
*(skb_put(*skb, 1)) = 0;
@@ -170,8 +167,6 @@ int capi_conn_active_req(struct pcbit_chan* chan, struct sk_buff **skb)
return -1;
}
- SET_SKB_FREE((*skb));
-
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
#ifdef DEBUG
@@ -200,8 +195,6 @@ int capi_conn_active_resp(struct pcbit_chan* chan, struct sk_buff **skb)
return -1;
}
- SET_SKB_FREE((*skb));
-
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
return 2;
@@ -222,8 +215,6 @@ int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
return -1;
}
- SET_SKB_FREE((*skb));
-
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
/* Layer2 protocol */
@@ -285,8 +276,6 @@ int capi_activate_transp_req(struct pcbit_chan *chan, struct sk_buff **skb)
return -1;
}
- SET_SKB_FREE((*skb));
-
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
@@ -338,8 +327,6 @@ int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb)
return -1;
}
- SET_SKB_FREE((*skb));
-
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
*(skb_put(*skb, 1)) = chan->layer2link;
@@ -357,8 +344,6 @@ int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause)
return -1;
}
- SET_SKB_FREE((*skb));
-
*((ushort*) skb_put(*skb, 2) ) = callref;
*(skb_put(*skb, 1)) = 2; /* Cause.Length = 2; */
@@ -382,8 +367,6 @@ int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb)
return -1;
}
- SET_SKB_FREE((*skb));
-
*((ushort*) skb_put(*skb, 2)) = chan->callref;
return 2;
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
index cacb714be..43c36fa9e 100644
--- a/drivers/isdn/pcbit/drv.c
+++ b/drivers/isdn/pcbit/drv.c
@@ -61,7 +61,7 @@ static char* pcbit_devname[MAX_PCBIT_CARDS] = {
int pcbit_command(isdn_ctrl* ctl);
int pcbit_stat(u_char* buf, int len, int user, int, int);
-int pcbit_xmit(int driver, int chan, struct sk_buff *skb);
+int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb);
int pcbit_writecmd(const u_char*, int, int, int, int);
static int set_protocol_running(struct pcbit_dev * dev);
@@ -164,7 +164,6 @@ int pcbit_init_dev(int board, int mem_base, int irq)
ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS );
dev_if->writebuf_skb = pcbit_xmit;
- dev_if->writebuf = NULL;
dev_if->hl_hdrlen = 10;
dev_if->maxbufsize = MAXBUFSIZE;
@@ -330,7 +329,7 @@ static void pcbit_block_timer(unsigned long data)
}
#endif
-int pcbit_xmit(int driver, int chnum, struct sk_buff *skb)
+int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb)
{
ushort hdrlen;
int refnum, len;
@@ -731,8 +730,6 @@ void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg,
#endif
}
- SET_SKB_FREE(skb);
-
kfree_skb(skb);
}
diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c
index 0ccb2b7c9..8283b7367 100644
--- a/drivers/isdn/pcbit/layer2.c
+++ b/drivers/isdn/pcbit/layer2.c
@@ -380,10 +380,8 @@ pcbit_receive(struct pcbit_dev *dev)
return;
#else
/* discard previous queued frame */
- if (dev->read_frame->skb) {
- SET_SKB_FREE(dev->read_frame->skb);
+ if (dev->read_frame->skb)
kfree_skb(dev->read_frame->skb);
- }
kfree(dev->read_frame);
dev->read_frame = NULL;
#endif
@@ -648,10 +646,8 @@ pcbit_l2_err_recover(unsigned long data)
dev->w_busy = dev->r_busy = 1;
if (dev->read_frame) {
- if (dev->read_frame->skb) {
- SET_SKB_FREE(dev->read_frame->skb);
+ if (dev->read_frame->skb)
kfree_skb(dev->read_frame->skb);
- }
kfree(dev->read_frame);
dev->read_frame = NULL;
}
diff --git a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c
index 34f8fc1c5..33aee3360 100644
--- a/drivers/isdn/pcbit/module.c
+++ b/drivers/isdn/pcbit/module.c
@@ -35,10 +35,8 @@ extern void pcbit_terminate(int board);
extern int pcbit_init_dev(int board, int mem_base, int irq);
#ifdef MODULE
-#if (LINUX_VERSION_CODE > 0x020111)
MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i");
MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i");
-#endif
#define pcbit_init init_module
#endif
@@ -87,11 +85,7 @@ int pcbit_init(void)
}
/* No symbols to export, hide all symbols */
-#if (LINUX_VERSION_CODE < 0x020111)
- register_symtab(NULL);
-#else
EXPORT_NO_SYMBOLS;
-#endif
return 0;
}
diff --git a/drivers/isdn/sc/.cvsignore b/drivers/isdn/sc/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/drivers/isdn/sc/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/drivers/isdn/sc/debug.c b/drivers/isdn/sc/debug.c
index 3a814de93..c5312cd83 100644
--- a/drivers/isdn/sc/debug.c
+++ b/drivers/isdn/sc/debug.c
@@ -1,5 +1,5 @@
/*
- * $Id: debug.c,v 1.2 1996/11/20 17:49:50 fritz Exp $
+ * $Id: debug.c,v 1.3 1997/10/01 09:22:20 fritz Exp $
* Copyright (C) 1996 SpellCaster Telecommunications Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -29,13 +29,8 @@
#define NULL 0x0
-#if LINUX_VERSION_CODE < 66363 /* Linux 1.3.59 there was a change to interrupts */
- #define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d)
- #define FREE_IRQ(a,b) free_irq(a)
-#else
- #define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
- #define FREE_IRQ(a,b) free_irq(a,b)
-#endif
+#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
+#define FREE_IRQ(a,b) free_irq(a,b)
inline char *strcpy(char *, const char *);
diff --git a/drivers/isdn/sc/event.c b/drivers/isdn/sc/event.c
index 3452cbf36..23cd53f07 100644
--- a/drivers/isdn/sc/event.c
+++ b/drivers/isdn/sc/event.c
@@ -1,5 +1,5 @@
/*
- * $Id: event.c,v 1.3 1997/02/11 22:53:41 fritz Exp $
+ * $Id: event.c,v 1.4 1997/10/09 22:30:58 fritz Exp $
* Copyright (C) 1996 SpellCaster Telecommunications Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -62,10 +62,16 @@ int indicate_status(int card, int event,ulong Channel,char *Data)
if (Data != NULL){
pr_debug("%s: Event data: %s\n", adapter[card]->devicename,
Data);
- if (event == ISDN_STAT_ICALL)
- memcpy(&cmd.parm.setup, Data, sizeof(cmd.parm.setup));
- else
- strcpy(cmd.parm.num, Data);
+ switch (event) {
+ case ISDN_STAT_BSENT:
+ memcpy(&cmd.parm.length, Data, sizeof(cmd.parm.length));
+ break;
+ case ISDN_STAT_ICALL:
+ memcpy(&cmd.parm.setup, Data, sizeof(cmd.parm.setup));
+ break;
+ default:
+ strcpy(cmd.parm.num, Data);
+ }
}
cmd.command = event;
diff --git a/drivers/isdn/sc/hardware.h b/drivers/isdn/sc/hardware.h
index 4a7698225..b0f07ac3c 100644
--- a/drivers/isdn/sc/hardware.h
+++ b/drivers/isdn/sc/hardware.h
@@ -16,6 +16,11 @@
this, you must also change the number
of elements in io, irq, and ram to
match. Initialized in init.c */
+/*
+extern unsigned int io[];
+extern unsigned char irq[];
+extern unsigned long ram[];
+*/
#define SIGNATURE 0x87654321 /* Board reset signature */
#define SIG_OFFSET 0x1004 /* Where to find signature in shared RAM */
diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
index c9eb24035..d34dd03b9 100644
--- a/drivers/isdn/sc/init.c
+++ b/drivers/isdn/sc/init.c
@@ -20,7 +20,7 @@ static int sup_irq[] = { 11, 10, 9, 5, 12, 14, 7, 3, 4, 6 };
#define MAX_IRQS 10
extern void interrupt_handler(int, void *, struct pt_regs *);
-extern int sndpkt(int, int, struct sk_buff *);
+extern int sndpkt(int, int, int, struct sk_buff *);
extern int command(isdn_ctrl *);
extern int indicate_status(int, int, ulong, char*);
extern int reset(int);
@@ -38,12 +38,10 @@ int irq_supported(int irq_x)
}
#ifdef MODULE
-#if (LINUX_VERSION_CODE > 0x020111)
MODULE_PARM(io, "1-4i");
MODULE_PARM(irq, "1-4i");
MODULE_PARM(ram, "1-4i");
MODULE_PARM(do_reset, "i");
-#endif
#define init_sc init_module
#else
/*
diff --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c
index 6b5b369e3..25964752b 100644
--- a/drivers/isdn/sc/interrupt.c
+++ b/drivers/isdn/sc/interrupt.c
@@ -1,5 +1,5 @@
/*
- * $Id: interrupt.c,v 1.3 1997/02/11 22:53:43 fritz Exp $
+ * $Id: interrupt.c,v 1.4 1998/01/31 22:10:52 keil Exp $
* Copyright (C) 1996 SpellCaster Telecommunications Inc.
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/isdn/sc/message.c b/drivers/isdn/sc/message.c
index e104fada6..2cbdcdae8 100644
--- a/drivers/isdn/sc/message.c
+++ b/drivers/isdn/sc/message.c
@@ -1,5 +1,5 @@
/*
- * $Id: message.c,v 1.2 1996/11/20 17:49:54 fritz Exp $
+ * $Id: message.c,v 1.3 1998/01/31 22:10:55 keil Exp $
* Copyright (C) 1996 SpellCaster Telecommunications Inc.
*
* message.c - functions for sending and receiving control messages
@@ -33,7 +33,6 @@
#include "hardware.h"
#include "message.h"
#include "card.h"
-#include <asm/io.h>
extern board *adapter[];
extern unsigned int cinst;
@@ -203,7 +202,7 @@ int sendmessage(int card,
* wait for an empty slot in the queue
*/
while (!(inb(adapter[card]->ioport[FIFO_STATUS]) & WF_NOT_FULL))
- __SLOW_DOWN_IO;
+ udelay(1);
/*
* Disable interrupts and map in shared memory
diff --git a/drivers/isdn/sc/packet.c b/drivers/isdn/sc/packet.c
index 563d1821d..d75cb04d7 100644
--- a/drivers/isdn/sc/packet.c
+++ b/drivers/isdn/sc/packet.c
@@ -1,5 +1,5 @@
/*
- * $Id: packet.c,v 1.2 1996/11/20 17:49:55 fritz Exp $
+ * $Id: packet.c,v 1.4 1998/02/12 23:08:50 keil Exp $
* Copyright (C) 1996 SpellCaster Telecommunications Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -36,7 +36,7 @@ extern board *adapter[];
extern unsigned int cinst;
extern int get_card_from_id(int);
-extern int indicate_status(int, int,ulong,char*);
+extern int indicate_status(int, int,ulong, char*);
extern void *memcpy_toshmem(int, void *, const void *, size_t);
extern void *memcpy_fromshmem(int, void *, const void *, size_t);
extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
@@ -47,6 +47,7 @@ int sndpkt(int devId, int channel, struct sk_buff *data)
LLData ReqLnkWrite;
int status;
int card;
+ unsigned long len;
card = get_card_from_id(devId);
@@ -89,6 +90,7 @@ int sndpkt(int devId, int channel, struct sk_buff *data)
status = sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkWrite,
channel+1, sizeof(LLData), (unsigned int*)&ReqLnkWrite);
+ len = data->len;
if(status) {
pr_debug("%s: Failed to send packet, status = %d\n", adapter[card]->devicename, status);
return -1;
@@ -101,9 +103,9 @@ int sndpkt(int devId, int channel, struct sk_buff *data)
adapter[card]->channel[channel].next_sendbuf;
pr_debug("%s: Packet sent successfully\n", adapter[card]->devicename);
dev_kfree_skb(data);
- indicate_status(card,ISDN_STAT_BSENT,channel,NULL);
+ indicate_status(card,ISDN_STAT_BSENT,channel, (char *)&len);
}
- return data->len;
+ return len;
}
void rcvpkt(int card, RspMessage *rcvmsg)